doc added; reading of isochronal bds
This commit is contained in:
@@ -0,0 +1,9 @@
|
|||||||
|
.. examples-index:
|
||||||
|
|
||||||
|
.. _gallery:
|
||||||
|
|
||||||
|
========
|
||||||
|
Examples
|
||||||
|
========
|
||||||
|
|
||||||
|
This page contains example plots. Click on any image to see the full image and source code.
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
.. _distribution_examples:
|
||||||
|
|
||||||
|
.. _distribution-examples-index:
|
||||||
|
|
||||||
|
Distribution of correlation times
|
||||||
|
=================================
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
"""
|
||||||
|
=========
|
||||||
|
Cole-Cole
|
||||||
|
=========
|
||||||
|
|
||||||
|
Example for Cole-Cole distributions
|
||||||
|
"""
|
||||||
|
import matplotlib.pyplot as plt
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
from nmreval.distributions import ColeCole
|
||||||
|
|
||||||
|
x = np.logspace(-5, 5, num=101)
|
||||||
|
|
||||||
|
cc = ColeCole
|
||||||
|
|
||||||
|
alpha_CC = [0.3, 0.5, 0.7]
|
||||||
|
|
||||||
|
fig, axes = plt.subplots(2, 3, constrained_layout=True)
|
||||||
|
|
||||||
|
lines = []
|
||||||
|
for a in alpha_CC:
|
||||||
|
axes[0, 0].plot(np.log10(x), cc.correlation(x, 1, a))
|
||||||
|
axes[1, 0].plot(np.log10(x), np.log10(cc.specdens(x, 1, a)))
|
||||||
|
axes[0, 1].plot(np.log10(x), np.log10(cc.susceptibility(x, 1, a).real))
|
||||||
|
axes[1, 1].plot(np.log10(x), np.log10(cc.susceptibility(x, 1, a).imag))
|
||||||
|
l, = axes[0, 2].plot(np.log10(x), cc.distribution(x, 1, a),
|
||||||
|
label=rf'$\alpha={a}$')
|
||||||
|
lines.append(l)
|
||||||
|
|
||||||
|
fig_titles = ('Correlation function', 'Susceptibility (real)', 'Distribution',
|
||||||
|
'Spectral density', 'Susceptibility (imag)')
|
||||||
|
fig_xlabel = (r'$\log(t/\tau_\mathrm{HN})$', r'$\log(\omega\tau_\mathrm{HN})$',
|
||||||
|
r'$\log(\tau/\tau_\mathrm{HN})$', r'$\log(\omega\tau_\mathrm{HN})$',
|
||||||
|
r'$\log(\omega\tau_\mathrm{HN})$')
|
||||||
|
fig_ylabel = (r'$C(t)$', r"$\log(\chi'(\omega))$", r'$G(\ln\tau)$',
|
||||||
|
r'$\log(J(\omega))$', r"$\log(\chi''(\omega))$")
|
||||||
|
|
||||||
|
for title, xlabel, ylabel, ax in zip(fig_titles, fig_xlabel, fig_ylabel, axes.ravel()):
|
||||||
|
ax.set_title(title)
|
||||||
|
ax.set_xlabel(xlabel)
|
||||||
|
ax.set_ylabel(ylabel)
|
||||||
|
|
||||||
|
labels = [l.get_label() for l in lines]
|
||||||
|
leg = fig.legend(lines, labels, loc='center left', bbox_to_anchor=(1.05, 0.50),
|
||||||
|
bbox_transform=axes[1, 1].transAxes)
|
||||||
|
|
||||||
|
fig.delaxes(axes[1, 2])
|
||||||
|
|
||||||
|
plt.show()
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
"""
|
||||||
|
=============
|
||||||
|
Cole-Davidson
|
||||||
|
=============
|
||||||
|
|
||||||
|
Example for Cole-Davidson distributions
|
||||||
|
"""
|
||||||
|
import matplotlib.pyplot as plt
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
from nmreval.distributions import ColeDavidson
|
||||||
|
|
||||||
|
x = np.logspace(-5, 5, num=101)
|
||||||
|
|
||||||
|
cd = ColeDavidson
|
||||||
|
|
||||||
|
gamma_CD = [0.3, 0.5, 0.7]
|
||||||
|
|
||||||
|
fig, axes = plt.subplots(2, 3, constrained_layout=True)
|
||||||
|
|
||||||
|
lines = []
|
||||||
|
for g in gamma_CD:
|
||||||
|
axes[0, 0].plot(np.log10(x), cd.correlation(x, 1, g))
|
||||||
|
axes[1, 0].plot(np.log10(x), np.log10(cd.specdens(x, 1, g)))
|
||||||
|
axes[0, 1].plot(np.log10(x), np.log10(cd.susceptibility(x, 1, g).real))
|
||||||
|
axes[1, 1].plot(np.log10(x), np.log10(cd.susceptibility(x, 1, g).imag))
|
||||||
|
l, = axes[0, 2].plot(np.log10(x), cd.distribution(x, 1, g),
|
||||||
|
label=rf'$\gamma={g}$')
|
||||||
|
lines.append(l)
|
||||||
|
|
||||||
|
fig_titles = ('Correlation function', 'Susceptibility (real)', 'Distribution',
|
||||||
|
'Spectral density', 'Susceptibility (imag)')
|
||||||
|
fig_xlabel = (r'$\log(t/\tau_\mathrm{CD})$', r'$\log(\omega\tau_\mathrm{CD})$',
|
||||||
|
r'$\log(\tau/\tau_\mathrm{CD})$', r'$\log(\omega\tau_\mathrm{CD})$',
|
||||||
|
r'$\log(\omega\tau_\mathrm{CD})$')
|
||||||
|
fig_ylabel = (r'$C(t)$', r"$\log(\chi'(\omega))$", r'$G(\ln\tau)$',
|
||||||
|
r'$\log(J(\omega))$', r"$\log(\chi''(\omega))$")
|
||||||
|
|
||||||
|
for title, xlabel, ylabel, ax in zip(fig_titles, fig_xlabel, fig_ylabel, axes.ravel()):
|
||||||
|
ax.set_title(title)
|
||||||
|
ax.set_xlabel(xlabel)
|
||||||
|
ax.set_ylabel(ylabel)
|
||||||
|
|
||||||
|
labels = [l.get_label() for l in lines]
|
||||||
|
leg = fig.legend(lines, labels, loc='center left', bbox_to_anchor=(1.05, 0.50),
|
||||||
|
bbox_transform=axes[1, 1].transAxes)
|
||||||
|
|
||||||
|
fig.delaxes(axes[1, 2])
|
||||||
|
|
||||||
|
plt.show()
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
"""
|
||||||
|
================
|
||||||
|
Havriliak-Negami
|
||||||
|
================
|
||||||
|
|
||||||
|
Example for Havriliak-Negami distributions
|
||||||
|
"""
|
||||||
|
from itertools import product
|
||||||
|
|
||||||
|
import matplotlib.pyplot as plt
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
from nmreval.distributions import HavriliakNegami
|
||||||
|
|
||||||
|
x = np.logspace(-5, 5, num=101)
|
||||||
|
|
||||||
|
hn = HavriliakNegami
|
||||||
|
|
||||||
|
alpha_CC = [0.4, 0.8]
|
||||||
|
gamma_CD = [0.3, 0.7]
|
||||||
|
|
||||||
|
fig, axes = plt.subplots(2, 3, constrained_layout=True)
|
||||||
|
|
||||||
|
lines = []
|
||||||
|
for a, g in product(alpha_CC, gamma_CD):
|
||||||
|
axes[0, 0].plot(np.log10(x), hn.correlation(x, 1, a, g))
|
||||||
|
axes[1, 0].plot(np.log10(x), np.log10(hn.specdens(x, 1, a, g)))
|
||||||
|
axes[0, 1].plot(np.log10(x), np.log10(hn.susceptibility(x, 1, a, g).real))
|
||||||
|
axes[1, 1].plot(np.log10(x), np.log10(hn.susceptibility(x, 1, a, g).imag))
|
||||||
|
l, = axes[0, 2].plot(np.log10(x), hn.distribution(x, 1, a, g),
|
||||||
|
label=rf'$\alpha={a}, \gamma={g}$')
|
||||||
|
lines.append(l)
|
||||||
|
|
||||||
|
fig_titles = ('Correlation function', 'Susceptibility (real)', 'Distribution',
|
||||||
|
'Spectral density', 'Susceptibility (imag)')
|
||||||
|
fig_xlabel = (r'$\log(t/\tau_\mathrm{HN})$', r'$\log(\omega\tau_\mathrm{HN})$',
|
||||||
|
r'$\log(\tau/\tau_\mathrm{HN})$', r'$\log(\omega\tau_\mathrm{HN})$',
|
||||||
|
r'$\log(\omega\tau_\mathrm{HN})$')
|
||||||
|
fig_ylabel = (r'$C(t)$', r"$\log(\chi'(\omega))$", r'$G(\ln\tau)$',
|
||||||
|
r'$\log(J(\omega))$', r"$\log(\chi''(\omega))$")
|
||||||
|
|
||||||
|
for title, xlabel, ylabel, ax in zip(fig_titles, fig_xlabel, fig_ylabel, axes.ravel()):
|
||||||
|
ax.set_title(title)
|
||||||
|
ax.set_xlabel(xlabel)
|
||||||
|
ax.set_ylabel(ylabel)
|
||||||
|
|
||||||
|
labels = [l.get_label() for l in lines]
|
||||||
|
leg = fig.legend(lines, labels, loc='center left', bbox_to_anchor=(1.05, 0.50),
|
||||||
|
bbox_transform=axes[1, 1].transAxes)
|
||||||
|
|
||||||
|
fig.delaxes(axes[1, 2])
|
||||||
|
|
||||||
|
plt.show()
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
"""
|
||||||
|
=========================
|
||||||
|
Kohlrausch-Williams-Watts
|
||||||
|
=========================
|
||||||
|
|
||||||
|
Example for KWW distributions
|
||||||
|
"""
|
||||||
|
import matplotlib.pyplot as plt
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
from nmreval.distributions import KWW
|
||||||
|
|
||||||
|
x = np.logspace(-5, 5, num=101)
|
||||||
|
|
||||||
|
kww = KWW
|
||||||
|
|
||||||
|
beta_KWW = [0.3, 0.5, 0.7]
|
||||||
|
|
||||||
|
fig, axes = plt.subplots(2, 3, constrained_layout=True)
|
||||||
|
|
||||||
|
lines = []
|
||||||
|
for b in beta_KWW:
|
||||||
|
axes[0, 0].plot(np.log10(x), kww.correlation(x, 1, b))
|
||||||
|
axes[1, 0].plot(np.log10(x), np.log10(kww.specdens(x, 1, b)))
|
||||||
|
axes[0, 1].plot(np.log10(x), np.log10(kww.susceptibility(x, 1, b).real))
|
||||||
|
axes[1, 1].plot(np.log10(x), np.log10(kww.susceptibility(x, 1, b).imag))
|
||||||
|
l, = axes[0, 2].plot(np.log10(x), kww.distribution(x, 1, b),
|
||||||
|
label=rf'$\beta={b}$')
|
||||||
|
lines.append(l)
|
||||||
|
|
||||||
|
fig_titles = ('Correlation function', 'Susceptibility (real)', 'Distribution',
|
||||||
|
'Spectral density', 'Susceptibility (imag)')
|
||||||
|
fig_xlabel = (r'$\log(t/\tau_\mathrm{KWW})$', r'$\log(\omega\tau_\mathrm{KWW})$',
|
||||||
|
r'$\log(\tau/\tau_\mathrm{KWW})$', r'$\log(\omega\tau_\mathrm{KWW})$',
|
||||||
|
r'$\log(\omega\tau_\mathrm{KWW})$')
|
||||||
|
fig_ylabel = (r'$C(t)$', r"$\log(\chi'(\omega))$", r'$G(\ln\tau)$',
|
||||||
|
r'$\log(J(\omega))$', r"$\log(\chi''(\omega))$")
|
||||||
|
|
||||||
|
for title, xlabel, ylabel, ax in zip(fig_titles, fig_xlabel, fig_ylabel, axes.ravel()):
|
||||||
|
ax.set_title(title)
|
||||||
|
ax.set_xlabel(xlabel)
|
||||||
|
ax.set_ylabel(ylabel)
|
||||||
|
|
||||||
|
labels = [l.get_label() for l in lines]
|
||||||
|
leg = fig.legend(lines, labels, loc='center left', bbox_to_anchor=(1.05, 0.50),
|
||||||
|
bbox_transform=axes[1, 1].transAxes)
|
||||||
|
|
||||||
|
fig.delaxes(axes[1, 2])
|
||||||
|
|
||||||
|
plt.show()
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
"""
|
||||||
|
============
|
||||||
|
Log-Gaussian
|
||||||
|
============
|
||||||
|
|
||||||
|
Example for Log-Gaussian distributions
|
||||||
|
"""
|
||||||
|
import matplotlib.pyplot as plt
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
from nmreval.distributions import LogGaussian
|
||||||
|
|
||||||
|
x = np.logspace(-5, 5, num=101)
|
||||||
|
|
||||||
|
lg = LogGaussian
|
||||||
|
|
||||||
|
sigma_lg = [1, 3, 5]
|
||||||
|
|
||||||
|
fig, axes = plt.subplots(2, 3, constrained_layout=True)
|
||||||
|
|
||||||
|
lines = []
|
||||||
|
for s in sigma_lg:
|
||||||
|
axes[0, 0].plot(np.log10(x), lg.correlation(x, 1, s))
|
||||||
|
axes[1, 0].plot(np.log10(x), np.log10(lg.specdens(x, 1, s)))
|
||||||
|
axes[0, 1].plot(np.log10(x), np.log10(lg.susceptibility(x, 1, s).real))
|
||||||
|
axes[1, 1].plot(np.log10(x), np.log10(lg.susceptibility(x, 1, s).imag))
|
||||||
|
l, = axes[0, 2].plot(np.log10(x), lg.distribution(x, 1, s),
|
||||||
|
label=rf'$\sigma={s}$')
|
||||||
|
lines.append(l)
|
||||||
|
|
||||||
|
fig_titles = ('Correlation function', 'Susceptibility (real)', 'Distribution',
|
||||||
|
'Spectral density', 'Susceptibility (imag)')
|
||||||
|
fig_xlabel = (r'$\log(t/\tau_\mathrm{LG})$', r'$\log(\omega\tau_\mathrm{LG})$',
|
||||||
|
r'$\log(\tau/\tau_\mathrm{LG})$', r'$\log(\omega\tau_\mathrm{LG})$',
|
||||||
|
r'$\log(\omega\tau_\mathrm{LG})$')
|
||||||
|
fig_ylabel = (r'$C(t)$', r"$\log(\chi'(\omega))$", r'$G(\ln\tau)$',
|
||||||
|
r'$\log(J(\omega))$', r"$\log(\chi''(\omega))$")
|
||||||
|
|
||||||
|
for title, xlabel, ylabel, ax in zip(fig_titles, fig_xlabel, fig_ylabel, axes.ravel()):
|
||||||
|
ax.set_title(title)
|
||||||
|
ax.set_xlabel(xlabel)
|
||||||
|
ax.set_ylabel(ylabel)
|
||||||
|
|
||||||
|
labels = [l.get_label() for l in lines]
|
||||||
|
leg = fig.legend(lines, labels, loc='center left', bbox_to_anchor=(1.05, 0.50),
|
||||||
|
bbox_transform=axes[1, 1].transAxes)
|
||||||
|
|
||||||
|
fig.delaxes(axes[1, 2])
|
||||||
|
|
||||||
|
plt.show()
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
.. _nmr_examples:
|
||||||
|
|
||||||
|
.. _nmr-examples-index:
|
||||||
|
|
||||||
|
NMR specifics
|
||||||
|
=============
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
"""
|
||||||
|
=======================
|
||||||
|
Spin-lattice relaxation
|
||||||
|
=======================
|
||||||
|
|
||||||
|
Example for
|
||||||
|
"""
|
||||||
|
import numpy as np
|
||||||
|
from matplotlib import pyplot as plt
|
||||||
|
|
||||||
|
from nmreval.distributions import ColeDavidson
|
||||||
|
from nmreval.nmr import Relaxation, RelaxationEvaluation
|
||||||
|
from nmreval.nmr.coupling import Quadrupolar
|
||||||
|
from nmreval.utils.constants import kB
|
||||||
|
|
||||||
|
# Define temperature range
|
||||||
|
inv_temp = np.linspace(3, 9, num=30)
|
||||||
|
temperature = 1000/inv_temp
|
||||||
|
|
||||||
|
# spectral density parameter
|
||||||
|
ea = 0.45
|
||||||
|
tau = 1e-21 * np.exp(ea / kB / temperature)
|
||||||
|
gamma_cd = 0.1
|
||||||
|
|
||||||
|
# interaction parameter
|
||||||
|
omega = 2*np.pi*46e6
|
||||||
|
delta = 120e3
|
||||||
|
eta = 0
|
||||||
|
|
||||||
|
r = Relaxation()
|
||||||
|
r.set_distribution(ColeDavidson) # the only parameter that has to be set beforehand
|
||||||
|
|
||||||
|
t1_values = r.t1(omega, tau, gamma_cd, mode='bpp',
|
||||||
|
prefactor=Quadrupolar.relax(delta, eta))
|
||||||
|
# add noise
|
||||||
|
rng = np.random.default_rng(123456789)
|
||||||
|
noisy = (rng.random(t1_values.size)-0.5) * 0.5 * t1_values + t1_values
|
||||||
|
|
||||||
|
# set parameter and data
|
||||||
|
r_eval = RelaxationEvaluation()
|
||||||
|
r_eval.set_distribution(ColeDavidson)
|
||||||
|
r_eval.set_coupling(Quadrupolar, (delta, eta))
|
||||||
|
r_eval.data(temperature, noisy)
|
||||||
|
r_eval.omega = omega
|
||||||
|
|
||||||
|
t1_min_data, _ = r_eval.calculate_t1_min() # second argument is None
|
||||||
|
t1_min_inter, line = r_eval.calculate_t1_min(interpolate=1, trange=(160, 195), use_log=True)
|
||||||
|
|
||||||
|
fig, ax = plt.subplots()
|
||||||
|
ax.semilogy(1000/t1_min_data[0], t1_min_data[1], 'rx', label='Data minimum')
|
||||||
|
ax.semilogy(1000/t1_min_inter[0], t1_min_inter[1], 'r+', label='Parabola')
|
||||||
|
ax.semilogy(1000/line[0], line[1])
|
||||||
|
|
||||||
|
found_gamma, found_height = r_eval.get_increase(t1_min_inter[1], idx=0, mode='distribution')
|
||||||
|
print(found_gamma)
|
||||||
|
|
||||||
|
plt.axhline(found_height)
|
||||||
|
plt.show()
|
||||||
|
|
||||||
|
#%%
|
||||||
|
# Now we found temperature and height of the minimum we can calculate the correlation time
|
||||||
|
|
||||||
|
plt.semilogy(1000/temperature, tau)
|
||||||
|
tau_from_t1, opts = r_eval.correlation_from_t1()
|
||||||
|
print(opts)
|
||||||
|
plt.semilogy(1000/tau_from_t1[:, 0], tau_from_t1[:, 1], 'o')
|
||||||
|
plt.show()
|
||||||
|
Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 46 KiB |
|
Before Width: | Height: | Size: 600 KiB After Width: | Height: | Size: 600 KiB |
@@ -0,0 +1,14 @@
|
|||||||
|
:mod:`{{ module | escape }}`.{{ objname }}
|
||||||
|
{{ underline }}==================
|
||||||
|
|
||||||
|
.. currentmodule:: {{ module }}
|
||||||
|
|
||||||
|
.. autoclass:: {{ objname }}
|
||||||
|
:members:
|
||||||
|
:inherited-members:
|
||||||
|
|
||||||
|
.. include:: {{ fullname }}.examples
|
||||||
|
|
||||||
|
.. raw:: html
|
||||||
|
|
||||||
|
<div class="clearer"></div>
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
.. automodule:: nmreval.data
|
||||||
|
:no-members:
|
||||||
|
:no-inherited-members:
|
||||||
|
:no-special-members:
|
||||||
|
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
.. automodule:: nmreval.distributions
|
||||||
|
:no-members:
|
||||||
|
:no-inherited-members:
|
||||||
|
:no-special-members:
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
=========
|
||||||
|
Reference
|
||||||
|
=========
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:caption: Table of contents
|
||||||
|
:maxdepth: 1
|
||||||
|
:glob:
|
||||||
|
|
||||||
|
data
|
||||||
|
models
|
||||||
|
distributions
|
||||||
|
nmr
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
.. automodule:: nmreval.models
|
||||||
|
:no-members:
|
||||||
|
:no-inherited-members:
|
||||||
|
:no-special-members:
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
.. automodule:: nmreval.nmr
|
||||||
|
:no-members:
|
||||||
|
:no-inherited-members:
|
||||||
|
:no-special-members:
|
||||||
@@ -10,6 +10,7 @@
|
|||||||
# add these directories to sys.path here. If the directory is relative to the
|
# add these directories to sys.path here. If the directory is relative to the
|
||||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||||
#
|
#
|
||||||
|
import os
|
||||||
import sys
|
import sys
|
||||||
import sphinx_bootstrap_theme
|
import sphinx_bootstrap_theme
|
||||||
sys.path.append('/autohome/dominik/nmreval')
|
sys.path.append('/autohome/dominik/nmreval')
|
||||||
@@ -43,8 +44,46 @@ extensions = [
|
|||||||
'sphinx.ext.napoleon',
|
'sphinx.ext.napoleon',
|
||||||
'sphinx.ext.viewcode',
|
'sphinx.ext.viewcode',
|
||||||
'sphinx.ext.intersphinx',
|
'sphinx.ext.intersphinx',
|
||||||
|
'sphinx_gallery.gen_gallery',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
# configuration for intersphinx
|
||||||
|
intersphinx_mapping = {
|
||||||
|
'numpy': ('https://numpy.org/doc/stable/', None),
|
||||||
|
'python': ('https://docs.python.org/3/', None),
|
||||||
|
'scipy': ('https://docs.scipy.org/doc/scipy/', None),
|
||||||
|
'PyQt': ('https://www.riverbankcomputing.com/static/Docs/PyQt5/', None),
|
||||||
|
'matplotlib': ('https://matplotlib.org/stable', None),
|
||||||
|
}
|
||||||
|
|
||||||
|
# autodoc options
|
||||||
|
autodoc_typehints = 'none'
|
||||||
|
autodoc_class_signature = 'separated'
|
||||||
|
autoclass_content = 'class'
|
||||||
|
autodoc_member_order = 'groupwise'
|
||||||
|
# autodoc_default_options = {'members': False, 'inherited-members': False}
|
||||||
|
|
||||||
|
# autosummay options
|
||||||
|
autosummary_generate = True
|
||||||
|
|
||||||
|
# spinx-gallery
|
||||||
|
sphinx_gallery_conf = {
|
||||||
|
'examples_dirs': '../examples', # path to your example scripts
|
||||||
|
'gallery_dirs': ['gallery'], # path to where to save gallery generated output
|
||||||
|
'backreferences_dir': os.path.join('api', 'generated'), # directory where function/class granular galleries are stored
|
||||||
|
'doc_module': 'nmreval', # Modules for which function/class level galleries are created.
|
||||||
|
'reference_url': {
|
||||||
|
'nmreval': None, # The module you locally document uses None
|
||||||
|
},
|
||||||
|
'download_all_examples': False,
|
||||||
|
'plot_gallery': True,
|
||||||
|
'inspect_global_variables': False,
|
||||||
|
'remove_config_comments': True,
|
||||||
|
'min_reported_time': 10000000000,
|
||||||
|
'show_memory': False,
|
||||||
|
'show_signature': False,
|
||||||
|
}
|
||||||
|
|
||||||
# The suffix(es) of source filenames.
|
# The suffix(es) of source filenames.
|
||||||
# You can specify multiple suffix as a list of string:
|
# You can specify multiple suffix as a list of string:
|
||||||
#
|
#
|
||||||
@@ -115,30 +154,15 @@ todo_include_todos = False
|
|||||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||||
# a list of builtin themes.
|
# a list of builtin themes.
|
||||||
#
|
#
|
||||||
# html_theme = 'bootstrap'
|
|
||||||
html_theme = 'pydata_sphinx_theme'
|
html_theme = 'pydata_sphinx_theme'
|
||||||
|
|
||||||
# Theme options are theme-specific and customize the look and feel of a theme
|
# Theme options are theme-specific and customize the look and feel of a theme
|
||||||
# further. For a list of options available for each theme, see the
|
# further. For a list of options available for each theme, see the
|
||||||
# documentation.
|
# documentation.
|
||||||
#
|
|
||||||
# html_theme_options = {
|
|
||||||
# # 'source_link_position': "footer",
|
|
||||||
# 'bootswatch_theme': "cosmo",
|
|
||||||
# 'navbar_title': "Welcome to hell",
|
|
||||||
# 'navbar_sidebarrel': True,
|
|
||||||
# 'nosidebar': False,
|
|
||||||
# 'body_max_width': '100%',
|
|
||||||
# 'navbar_links': [
|
|
||||||
# ('User guide', 'user_guide/index'),
|
|
||||||
# ('References', 'api/index'),
|
|
||||||
# ],
|
|
||||||
# }
|
|
||||||
html_theme_options = {
|
html_theme_options = {
|
||||||
'collapse_navigation': False,
|
'collapse_navigation': False,
|
||||||
'show_prev_next': False,
|
'show_prev_next': False,
|
||||||
'navbar_end': ['navbar-icon-links.html', 'search-field.html'],
|
'navbar_end': ['navbar-icon-links.html', 'search-field.html'],
|
||||||
'show_toc_level': 3
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# Add any paths that contain custom themes here, relative to this directory.
|
# Add any paths that contain custom themes here, relative to this directory.
|
||||||
@@ -396,29 +420,3 @@ epub_exclude_files = ['search.html']
|
|||||||
# If false, no index is generated.
|
# If false, no index is generated.
|
||||||
#
|
#
|
||||||
# epub_use_index = True
|
# epub_use_index = True
|
||||||
|
|
||||||
|
|
||||||
# configuration for intersphinx
|
|
||||||
intersphinx_mapping = {
|
|
||||||
'Pillow': ('https://pillow.readthedocs.io/en/stable/', None),
|
|
||||||
'cycler': ('https://matplotlib.org/cycler/', None),
|
|
||||||
'dateutil': ('https://dateutil.readthedocs.io/en/stable/', None),
|
|
||||||
'ipykernel': ('https://ipykernel.readthedocs.io/en/latest/', None),
|
|
||||||
'numpy': ('https://numpy.org/doc/stable/', None),
|
|
||||||
'pandas': ('https://pandas.pydata.org/pandas-docs/stable/', None),
|
|
||||||
'pytest': ('https://pytest.org/en/stable/', None),
|
|
||||||
'python': ('https://docs.python.org/3/', None),
|
|
||||||
'scipy': ('https://docs.scipy.org/doc/scipy/', None),
|
|
||||||
'tornado': ('https://www.tornadoweb.org/en/stable/', None),
|
|
||||||
'xarray': ('https://xarray.pydata.org/en/stable/', None),
|
|
||||||
'PyQt': ('https://www.riverbankcomputing.com/static/Docs/PyQt5/', None),
|
|
||||||
}
|
|
||||||
|
|
||||||
# autodoc options
|
|
||||||
autodoc_typehints = 'none'
|
|
||||||
autodoc_class_signature = 'separated'
|
|
||||||
autoclass_content = 'class'
|
|
||||||
|
|
||||||
# autosummay options
|
|
||||||
autosummary_generate = True
|
|
||||||
|
|
||||||
@@ -0,0 +1,179 @@
|
|||||||
|
:orphan:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.. _sphx_glr_gallery:
|
||||||
|
|
||||||
|
.. examples-index:
|
||||||
|
|
||||||
|
.. _gallery:
|
||||||
|
|
||||||
|
========
|
||||||
|
Examples
|
||||||
|
========
|
||||||
|
|
||||||
|
This page contains example plots. Click on any image to see the full image and source code.
|
||||||
|
|
||||||
|
|
||||||
|
.. raw:: html
|
||||||
|
|
||||||
|
<div class="sphx-glr-clear"></div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.. _sphx_glr_gallery_distribution:
|
||||||
|
|
||||||
|
.. _distribution_examples:
|
||||||
|
|
||||||
|
.. _distribution-examples-index:
|
||||||
|
|
||||||
|
Distribution of correlation times
|
||||||
|
=================================
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.. raw:: html
|
||||||
|
|
||||||
|
<div class="sphx-glr-thumbcontainer" tooltip="Example for KWW distributions">
|
||||||
|
|
||||||
|
.. only:: html
|
||||||
|
|
||||||
|
.. figure:: /gallery/distribution/images/thumb/sphx_glr_plot_KWW_thumb.png
|
||||||
|
:alt: Kohlrausch-Williams-Watts
|
||||||
|
|
||||||
|
:ref:`sphx_glr_gallery_distribution_plot_KWW.py`
|
||||||
|
|
||||||
|
.. raw:: html
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:hidden:
|
||||||
|
|
||||||
|
/gallery/distribution/plot_KWW
|
||||||
|
|
||||||
|
.. raw:: html
|
||||||
|
|
||||||
|
<div class="sphx-glr-thumbcontainer" tooltip="Example for Cole-Cole distributions">
|
||||||
|
|
||||||
|
.. only:: html
|
||||||
|
|
||||||
|
.. figure:: /gallery/distribution/images/thumb/sphx_glr_plot_ColeCole_thumb.png
|
||||||
|
:alt: Cole-Cole
|
||||||
|
|
||||||
|
:ref:`sphx_glr_gallery_distribution_plot_ColeCole.py`
|
||||||
|
|
||||||
|
.. raw:: html
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:hidden:
|
||||||
|
|
||||||
|
/gallery/distribution/plot_ColeCole
|
||||||
|
|
||||||
|
.. raw:: html
|
||||||
|
|
||||||
|
<div class="sphx-glr-thumbcontainer" tooltip="Example for Log-Gaussian distributions">
|
||||||
|
|
||||||
|
.. only:: html
|
||||||
|
|
||||||
|
.. figure:: /gallery/distribution/images/thumb/sphx_glr_plot_LogGaussian_thumb.png
|
||||||
|
:alt: Log-Gaussian
|
||||||
|
|
||||||
|
:ref:`sphx_glr_gallery_distribution_plot_LogGaussian.py`
|
||||||
|
|
||||||
|
.. raw:: html
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:hidden:
|
||||||
|
|
||||||
|
/gallery/distribution/plot_LogGaussian
|
||||||
|
|
||||||
|
.. raw:: html
|
||||||
|
|
||||||
|
<div class="sphx-glr-thumbcontainer" tooltip="Example for Cole-Davidson distributions">
|
||||||
|
|
||||||
|
.. only:: html
|
||||||
|
|
||||||
|
.. figure:: /gallery/distribution/images/thumb/sphx_glr_plot_ColeDavidson_thumb.png
|
||||||
|
:alt: Cole-Davidson
|
||||||
|
|
||||||
|
:ref:`sphx_glr_gallery_distribution_plot_ColeDavidson.py`
|
||||||
|
|
||||||
|
.. raw:: html
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:hidden:
|
||||||
|
|
||||||
|
/gallery/distribution/plot_ColeDavidson
|
||||||
|
|
||||||
|
.. raw:: html
|
||||||
|
|
||||||
|
<div class="sphx-glr-thumbcontainer" tooltip="Example for Havriliak-Negami distributions">
|
||||||
|
|
||||||
|
.. only:: html
|
||||||
|
|
||||||
|
.. figure:: /gallery/distribution/images/thumb/sphx_glr_plot_HavriliakNegami_thumb.png
|
||||||
|
:alt: Havriliak-Negami
|
||||||
|
|
||||||
|
:ref:`sphx_glr_gallery_distribution_plot_HavriliakNegami.py`
|
||||||
|
|
||||||
|
.. raw:: html
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:hidden:
|
||||||
|
|
||||||
|
/gallery/distribution/plot_HavriliakNegami
|
||||||
|
.. raw:: html
|
||||||
|
|
||||||
|
<div class="sphx-glr-clear"></div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.. _sphx_glr_gallery_nmr:
|
||||||
|
|
||||||
|
.. _nmr_examples:
|
||||||
|
|
||||||
|
.. _nmr-examples-index:
|
||||||
|
|
||||||
|
NMR specifics
|
||||||
|
=============
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.. raw:: html
|
||||||
|
|
||||||
|
<div class="sphx-glr-thumbcontainer" tooltip="Example for">
|
||||||
|
|
||||||
|
.. only:: html
|
||||||
|
|
||||||
|
.. figure:: /gallery/nmr/images/thumb/sphx_glr_plot_RelaxationEvaluation_thumb.png
|
||||||
|
:alt: Spin-lattice relaxation
|
||||||
|
|
||||||
|
:ref:`sphx_glr_gallery_nmr_plot_RelaxationEvaluation.py`
|
||||||
|
|
||||||
|
.. raw:: html
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:hidden:
|
||||||
|
|
||||||
|
/gallery/nmr/plot_RelaxationEvaluation
|
||||||
|
.. raw:: html
|
||||||
|
|
||||||
|
<div class="sphx-glr-clear"></div>
|
||||||
|
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
'/autohome/dominik/nmreval/doc/_build/html/index.html', (0, 6969)
|
||||||
|
'/autohome/dominik/nmreval/doc/_build/html/_static/documentation_options.js', (7168, 364)
|
||||||
|
'/autohome/dominik/nmreval/doc/_build/html/searchindex.js', (7680, 29280)
|
||||||
Binary file not shown.
@@ -0,0 +1,3 @@
|
|||||||
|
'/autohome/dominik/nmreval/doc/_build/html/index.html', (0, 6969)
|
||||||
|
'/autohome/dominik/nmreval/doc/_build/html/_static/documentation_options.js', (7168, 364)
|
||||||
|
'/autohome/dominik/nmreval/doc/_build/html/searchindex.js', (7680, 29280)
|
||||||
@@ -3,17 +3,15 @@
|
|||||||
You can adapt this file completely to your liking, but it should at least
|
You can adapt this file completely to your liking, but it should at least
|
||||||
contain the root `toctree` directive.
|
contain the root `toctree` directive.
|
||||||
|
|
||||||
###################################
|
#####################
|
||||||
NMREval documentation
|
NMREval documentation
|
||||||
###################################
|
#####################
|
||||||
|
|
||||||
.. toctree::
|
.. toctree::
|
||||||
:maxdepth: 1
|
:maxdepth: 1
|
||||||
|
|
||||||
user_guide/index
|
user_guide/index
|
||||||
|
gallery/index
|
||||||
nmr/index
|
|
||||||
|
|
||||||
api/index
|
api/index
|
||||||
|
|
||||||
|
|
||||||
|
Before Width: | Height: | Size: 59 KiB After Width: | Height: | Size: 59 KiB |
@@ -1,25 +0,0 @@
|
|||||||
{{ fullname | escape | underline }}
|
|
||||||
|
|
||||||
|
|
||||||
.. currentmodule:: {{ module }}
|
|
||||||
|
|
||||||
|
|
||||||
{% if objtype in ['class'] %}
|
|
||||||
|
|
||||||
Inheritance diagram
|
|
||||||
|
|
||||||
.. inheritance-diagram:: {{ objname }}
|
|
||||||
:parts: 1
|
|
||||||
|
|
||||||
{{ objtype }}
|
|
||||||
|
|
||||||
.. auto{{ objtype }}:: {{ objname }}
|
|
||||||
:special-members: __call__
|
|
||||||
:members:
|
|
||||||
:undoc-members:
|
|
||||||
|
|
||||||
{% else %}
|
|
||||||
.. auto{{ objtype }}:: {{ objname }}
|
|
||||||
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
**************
|
|
||||||
Data container
|
|
||||||
**************
|
|
||||||
|
|
||||||
.. automodule:: nmreval.data
|
|
||||||
:no-members:
|
|
||||||
:no-undoc-members:
|
|
||||||
|
|
||||||
|
|
||||||
.. contents:: Table of Contents
|
|
||||||
:depth: 3
|
|
||||||
:local:
|
|
||||||
:backlinks: entry
|
|
||||||
|
|
||||||
|
|
||||||
.. autosummary::
|
|
||||||
:toctree: generated/
|
|
||||||
:template: autosummary.rst
|
|
||||||
:nosignatures:
|
|
||||||
|
|
||||||
nmreval.data.Points
|
|
||||||
nmreval.data.Signal
|
|
||||||
nmreval.data.BDS
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
nmreval.data.BDS
|
|
||||||
================
|
|
||||||
|
|
||||||
|
|
||||||
.. currentmodule:: nmreval.data
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Inheritance diagram
|
|
||||||
|
|
||||||
.. inheritance-diagram:: BDS
|
|
||||||
:parts: 1
|
|
||||||
|
|
||||||
class
|
|
||||||
|
|
||||||
.. autoclass:: BDS
|
|
||||||
:special-members: __call__
|
|
||||||
:members:
|
|
||||||
:undoc-members:
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
nmreval.data.Points
|
|
||||||
===================
|
|
||||||
|
|
||||||
|
|
||||||
.. currentmodule:: nmreval.data
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Inheritance diagram
|
|
||||||
|
|
||||||
.. inheritance-diagram:: Points
|
|
||||||
:parts: 1
|
|
||||||
|
|
||||||
class
|
|
||||||
|
|
||||||
.. autoclass:: Points
|
|
||||||
:special-members: __call__
|
|
||||||
:members:
|
|
||||||
:undoc-members:
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
nmreval.data.Signal
|
|
||||||
===================
|
|
||||||
|
|
||||||
|
|
||||||
.. currentmodule:: nmreval.data
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Inheritance diagram
|
|
||||||
|
|
||||||
.. inheritance-diagram:: Signal
|
|
||||||
:parts: 1
|
|
||||||
|
|
||||||
class
|
|
||||||
|
|
||||||
.. autoclass:: Signal
|
|
||||||
:special-members: __call__
|
|
||||||
:members:
|
|
||||||
:undoc-members:
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
==========
|
|
||||||
References
|
|
||||||
==========
|
|
||||||
|
|
||||||
.. toctree::
|
|
||||||
:caption: Table of contents
|
|
||||||
:maxdepth: 2
|
|
||||||
:glob:
|
|
||||||
|
|
||||||
data.rst
|
|
||||||
models/index.rst
|
|
||||||
distributions/index.rst
|
|
||||||
@@ -1,3 +1,20 @@
|
|||||||
|
"""
|
||||||
|
====================================
|
||||||
|
Data container (:mod:`nmreval.data`)
|
||||||
|
====================================
|
||||||
|
|
||||||
|
.. autosummary::
|
||||||
|
:toctree: generated/
|
||||||
|
:nosignatures:
|
||||||
|
|
||||||
|
Points
|
||||||
|
Signal
|
||||||
|
FID
|
||||||
|
Spectrum
|
||||||
|
BDS
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
from .points import Points
|
from .points import Points
|
||||||
from .signals import Signal
|
from .signals import Signal
|
||||||
from .bds import BDS
|
from .bds import BDS
|
||||||
|
|||||||
+7
-6
@@ -15,10 +15,11 @@ class BDS(Signal):
|
|||||||
def __init__(self, x, y, **kwargs: Any):
|
def __init__(self, x, y, **kwargs: Any):
|
||||||
super().__init__(x, y, **kwargs)
|
super().__init__(x, y, **kwargs)
|
||||||
|
|
||||||
if np.all(self._x > 0) and not np.allclose(np.diff(self._x), self._x[1]-self._x[0]):
|
if len(self._x) > 1:
|
||||||
self.dx = self.x[1] / self.x[0]
|
if np.all(self._x > 0) and np.allclose(self._x[1:]/self._x[:-1], self._x[1]/self._x[0]):
|
||||||
else:
|
self.dx = self.x[1] / self.x[0]
|
||||||
self.dx = self._x[1] - self._x[0]
|
else:
|
||||||
|
self.dx = self._x[1] - self._x[0]
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
return f"{self.meta['mode']}: {self.name}"
|
return f"{self.meta['mode']}: {self.name}"
|
||||||
@@ -32,10 +33,10 @@ class BDS(Signal):
|
|||||||
window_length (int)
|
window_length (int)
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Points
|
Points:
|
||||||
New Points instance with
|
New Points instance with
|
||||||
|
|
||||||
References:
|
Reference:
|
||||||
Wübbenhorst, M.; van Turnhout, J.: Analysis of complex dielectric spectra.
|
Wübbenhorst, M.; van Turnhout, J.: Analysis of complex dielectric spectra.
|
||||||
I. One-dimensional derivative techniques and three-dimensional modelling.
|
I. One-dimensional derivative techniques and three-dimensional modelling.
|
||||||
J. Non-Cryst. Solid. 305 (2002) https://doi.org/10.1016/s0022-3093(02)01086-4
|
J. Non-Cryst. Solid. 305 (2002) https://doi.org/10.1016/s0022-3093(02)01086-4
|
||||||
|
|||||||
+33
-10
@@ -7,6 +7,9 @@ from .signals import Signal
|
|||||||
|
|
||||||
|
|
||||||
class FID(Signal):
|
class FID(Signal):
|
||||||
|
"""
|
||||||
|
Extensions if :class:`Signal` for NMR timesignals
|
||||||
|
"""
|
||||||
def __init__(self, x, y, **kwargs):
|
def __init__(self, x, y, **kwargs):
|
||||||
super().__init__(x, y, **kwargs)
|
super().__init__(x, y, **kwargs)
|
||||||
|
|
||||||
@@ -16,7 +19,16 @@ class FID(Signal):
|
|||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f"FID: {self.name}"
|
return f"FID: {self.name}"
|
||||||
|
|
||||||
def baseline(self, percentage=0.12):
|
def baseline(self, percentage: float = 0.12):
|
||||||
|
"""
|
||||||
|
Substract
|
||||||
|
|
||||||
|
Args:
|
||||||
|
percentage:
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
|
||||||
|
"""
|
||||||
self._y -= self._y[int(-percentage * self.length):].mean()
|
self._y -= self._y[int(-percentage * self.length):].mean()
|
||||||
|
|
||||||
return self
|
return self
|
||||||
@@ -51,7 +63,7 @@ class FID(Signal):
|
|||||||
|
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def fourier(self):
|
def fourier(self) -> 'Spectrum':
|
||||||
ft = np.fft.fftshift(np.fft.fft(self._y)) / self.dx
|
ft = np.fft.fftshift(np.fft.fft(self._y)) / self.dx
|
||||||
freq = np.fft.fftshift(np.fft.fftfreq(self.length, self.dx))
|
freq = np.fft.fftshift(np.fft.fftfreq(self.length, self.dx))
|
||||||
|
|
||||||
@@ -63,9 +75,15 @@ class FID(Signal):
|
|||||||
def fft_depake(self, scale: bool = False):
|
def fft_depake(self, scale: bool = False):
|
||||||
"""
|
"""
|
||||||
Calculate deconvoluted Pake spectra
|
Calculate deconvoluted Pake spectra
|
||||||
M.A. McCabe, S.R. Wassail:
|
|
||||||
Rapid deconvolution of NMR powder spectra by weighted fast Fourier transformation,
|
Args:
|
||||||
SSNMR (1997), Vol.10, Nr.1-2, pp. 53-61,
|
scale (bool):
|
||||||
|
|
||||||
|
Reference:
|
||||||
|
M.A. McCabe, S.R. Wassail:
|
||||||
|
Rapid deconvolution of NMR powder spectra by weighted fast Fourier transformation,
|
||||||
|
SSNMR (1997), Vol.10, Nr.1-2, pp. 53-61
|
||||||
|
|
||||||
"""
|
"""
|
||||||
_y = self._y + 0
|
_y = self._y + 0
|
||||||
# Perform FFT depaking
|
# Perform FFT depaking
|
||||||
@@ -102,8 +120,9 @@ class FID(Signal):
|
|||||||
self._y_err = np.std(self._y[-int(0.1*self.length):])/1.41
|
self._y_err = np.std(self._y[-int(0.1*self.length):])/1.41
|
||||||
return self._y_err * np.ones(self.length)
|
return self._y_err * np.ones(self.length)
|
||||||
|
|
||||||
def shift(self, points: Union[str, float], mode: str = 'pts'):
|
def shift(self, points: int, mode: str = 'pts') -> None:
|
||||||
"""
|
"""
|
||||||
|
Shift y values to new x indexes
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
points : shift value,
|
points : shift value,
|
||||||
@@ -113,13 +132,17 @@ class FID(Signal):
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
if mode == 'pts':
|
if mode == 'pts':
|
||||||
super().shift(points)
|
super().shift(int(points))
|
||||||
else:
|
else:
|
||||||
pts = int(points//self.dx)
|
pts = int(points//self.dx)
|
||||||
super().shift(pts)
|
super().shift(pts)
|
||||||
|
|
||||||
|
|
||||||
class Spectrum(Signal):
|
class Spectrum(Signal):
|
||||||
|
"""
|
||||||
|
Extension of :class:`Signal` for NMR spectra
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(self, x, y, dx=None, **kwargs):
|
def __init__(self, x, y, dx=None, **kwargs):
|
||||||
super().__init__(x, y, **kwargs)
|
super().__init__(x, y, **kwargs)
|
||||||
if dx is None:
|
if dx is None:
|
||||||
@@ -139,7 +162,7 @@ class Spectrum(Signal):
|
|||||||
|
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def fourier(self):
|
def fourier(self) -> FID:
|
||||||
ft = np.fft.ifft(np.fft.ifftshift(self._y * self.dx))
|
ft = np.fft.ifft(np.fft.ifftshift(self._y * self.dx))
|
||||||
t = np.arange(len(ft))*self.dx
|
t = np.arange(len(ft))*self.dx
|
||||||
shifted = np.fft.ifftshift(self._x)[0]
|
shifted = np.fft.ifftshift(self._x)[0]
|
||||||
@@ -172,8 +195,8 @@ class Spectrum(Signal):
|
|||||||
|
|
||||||
return self._y_err * np.ones(self.length)
|
return self._y_err * np.ones(self.length)
|
||||||
|
|
||||||
def shift(self, points, mode='pts'):
|
def shift(self, points: int, mode: str = 'pts'):
|
||||||
if mode == 'pts':
|
if mode == 'pts':
|
||||||
super().shift(points)
|
super().shift(int(points))
|
||||||
else:
|
else:
|
||||||
return self
|
return self
|
||||||
|
|||||||
+23
-5
@@ -412,11 +412,15 @@ class Points:
|
|||||||
def diff(self, log: bool = False, limits: Optional[Tuple[float, float]] = None) -> PointLike:
|
def diff(self, log: bool = False, limits: Optional[Tuple[float, float]] = None) -> PointLike:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
Calculate first derivate :math:`dy/dx` or :math:`dy/d(\ln x)`.
|
||||||
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
log:
|
log (bool) : Flag if derivative is with respect to ln(x) instead of x. Default is `False`.
|
||||||
limits:
|
limits (tuple, optional): Range `(xmin, xmax)` which is differentiated.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
|
Copy of set with new y values.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -430,6 +434,8 @@ class Points:
|
|||||||
else:
|
else:
|
||||||
new_data.y = np.gradient(new_data.y, new_data.x)
|
new_data.y = np.gradient(new_data.y, new_data.x)
|
||||||
|
|
||||||
|
new_data.remove(np.argwhere(np.isnan(new_data.y)))
|
||||||
|
|
||||||
return new_data
|
return new_data
|
||||||
|
|
||||||
def magnitude(self) -> PointLike:
|
def magnitude(self) -> PointLike:
|
||||||
@@ -530,6 +536,8 @@ class Points:
|
|||||||
|
|
||||||
def shift(self, points: int) -> PointLike:
|
def shift(self, points: int) -> PointLike:
|
||||||
"""
|
"""
|
||||||
|
Shift indexes of y values.
|
||||||
|
|
||||||
Move y values `points` indexes, remove invalid indexes and fill remaining with zeros
|
Move y values `points` indexes, remove invalid indexes and fill remaining with zeros
|
||||||
Negative `points` shift to the left, positive `points` shift to the right
|
Negative `points` shift to the left, positive `points` shift to the right
|
||||||
|
|
||||||
@@ -558,11 +566,21 @@ class Points:
|
|||||||
|
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def sort(self, axis=0):
|
def sort(self, axis: str = 'x') -> PointLike:
|
||||||
if axis == 0:
|
"""
|
||||||
|
Sort data in increased order.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
axis (str, {`x`, `y`}) : Axis that determines new order. Default is `x`
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
if axis == 'x':
|
||||||
sort_order = np.argsort(self._x)
|
sort_order = np.argsort(self._x)
|
||||||
else:
|
elif axis == 'y':
|
||||||
sort_order = np.argsort(self._y)
|
sort_order = np.argsort(self._y)
|
||||||
|
else:
|
||||||
|
raise ValueError('Unknown sort axis, use `x` or `y`.')
|
||||||
self._x = self._x[sort_order]
|
self._x = self._x[sort_order]
|
||||||
self._y = self._y[sort_order]
|
self._y = self._y[sort_order]
|
||||||
self._y_err = self._y_err[sort_order]
|
self._y_err = self._y_err[sort_order]
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ from .points import Points
|
|||||||
|
|
||||||
class Signal(Points):
|
class Signal(Points):
|
||||||
"""
|
"""
|
||||||
Extension of Points for complex y values.
|
Extension of :class:`Points` for complex y values.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, x, y, **kwargs):
|
def __init__(self, x, y, **kwargs):
|
||||||
@@ -18,7 +18,10 @@ class Signal(Points):
|
|||||||
|
|
||||||
super().__init__(x, y, **kwargs)
|
super().__init__(x, y, **kwargs)
|
||||||
|
|
||||||
self.dx = kwargs.get('dx', abs(self._x[1] - self._x[0]))
|
if len(self._x) > 1:
|
||||||
|
self.dx = kwargs.get('dx', abs(self._x[1] - self._x[0]))
|
||||||
|
else:
|
||||||
|
self.dx = 0
|
||||||
self.meta.update({'phase': [], 'shift': 0})
|
self.meta.update({'phase': [], 'shift': 0})
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
|
|||||||
@@ -1,3 +1,25 @@
|
|||||||
|
"""
|
||||||
|
=================================================================
|
||||||
|
Distributions of correlation times (:mod:`nmreval.distributions`)
|
||||||
|
=================================================================
|
||||||
|
|
||||||
|
Each class provides a distribution of correlation times, correlation
|
||||||
|
function, spectral density, susceptibility, and calculation of different
|
||||||
|
types of correlation times.
|
||||||
|
|
||||||
|
.. autosummary::
|
||||||
|
:toctree: generated/
|
||||||
|
:template: autosummary/class_with_attributes.rst
|
||||||
|
:nosignatures:
|
||||||
|
|
||||||
|
Debye
|
||||||
|
ColeCole
|
||||||
|
ColeDavidson
|
||||||
|
HavriliakNegami
|
||||||
|
KWW
|
||||||
|
LogGaussian
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
from .havriliaknegami import HavriliakNegami
|
from .havriliaknegami import HavriliakNegami
|
||||||
from .colecole import ColeCole
|
from .colecole import ColeCole
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
import abc
|
import abc
|
||||||
from warnings import warn
|
from typing import Any, Union
|
||||||
|
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
|
from nmreval.lib.utils import ArrayLike
|
||||||
|
|
||||||
|
|
||||||
class Distribution(abc.ABC):
|
class Distribution(abc.ABC):
|
||||||
name = 'Abstract distribution'
|
name = 'Abstract distribution'
|
||||||
@@ -15,7 +18,12 @@ class Distribution(abc.ABC):
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def distribution(taus, tau0, *args):
|
def distribution(tau, tau0, *args):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
@abc.abstractmethod
|
||||||
|
def correlation(t, tau, *args):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@@ -24,13 +32,8 @@ class Distribution(abc.ABC):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def specdens(cls, omega, tau, *args):
|
def specdens(cls, omega: ArrayLike, tau: ArrayLike, *args: Any) -> Union[np.ndarray, float]:
|
||||||
return -cls.susceptibility(omega, tau, *args).imag / omega
|
return cls.susceptibility(omega, tau, *args).imag / omega
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
@abc.abstractmethod
|
|
||||||
def correlation(t, tau0, *args):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def mean_value(cls, *args, mode='mean'):
|
def mean_value(cls, *args, mode='mean'):
|
||||||
@@ -43,6 +46,27 @@ class Distribution(abc.ABC):
|
|||||||
|
|
||||||
return args[0]
|
return args[0]
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def mean(*args):
|
||||||
|
return args[0]
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def logmean(*args):
|
||||||
|
"""
|
||||||
|
Return mean logarithmic tau
|
||||||
|
|
||||||
|
Args:
|
||||||
|
*args:
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
|
||||||
|
"""
|
||||||
|
return np.log(args[0])
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def max(*args):
|
||||||
|
return args[0]
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def convert(cls, *args, from_='raw', to_='mean'):
|
def convert(cls, *args, from_='raw', to_='mean'):
|
||||||
if from_ == to_:
|
if from_ == to_:
|
||||||
@@ -62,24 +86,3 @@ class Distribution(abc.ABC):
|
|||||||
return raw
|
return raw
|
||||||
else:
|
else:
|
||||||
return cls.mean_value(raw, *args[1:], mode=to_)
|
return cls.mean_value(raw, *args[1:], mode=to_)
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def logmean(*args):
|
|
||||||
"""
|
|
||||||
Return mean logarithmic tau
|
|
||||||
|
|
||||||
Args:
|
|
||||||
*args:
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
|
|
||||||
"""
|
|
||||||
return np.log(args[0])
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def mean(*args):
|
|
||||||
return args[0]
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def max(*args):
|
|
||||||
return args[0]
|
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
from .base import Distribution
|
from .base import Distribution
|
||||||
|
from ..lib.utils import ArrayLike
|
||||||
|
from ..lib.decorator import adjust_dims
|
||||||
from ..math.mittagleffler import mlf
|
from ..math.mittagleffler import mlf
|
||||||
|
|
||||||
|
|
||||||
@@ -13,7 +15,7 @@ class ColeCole(Distribution):
|
|||||||
bounds = [(0, 1)]
|
bounds = [(0, 1)]
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def distribution(taus, tau0, alpha):
|
def distribution(tau, tau0, alpha):
|
||||||
"""
|
"""
|
||||||
Distribution of correlation times
|
Distribution of correlation times
|
||||||
|
|
||||||
@@ -21,32 +23,33 @@ class ColeCole(Distribution):
|
|||||||
G(\ln\\tau) = \\frac{1}{2\pi} \\frac{\\sin(\\pi\\alpha)}{\cosh[\\alpha\ln(\\tau/\\tau_0)] + \cos(\\alpha \pi))}
|
G(\ln\\tau) = \\frac{1}{2\pi} \\frac{\\sin(\\pi\\alpha)}{\cosh[\\alpha\ln(\\tau/\\tau_0)] + \cos(\\alpha \pi))}
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
taus:
|
tau:
|
||||||
tau0:
|
tau0:
|
||||||
alpha:
|
alpha:
|
||||||
"""
|
"""
|
||||||
z = np.log(taus/tau0)
|
z = np.log(tau/tau0)
|
||||||
return np.sin(np.pi*alpha)/(np.cosh(z*alpha) + np.cos(alpha*np.pi))/(2*np.pi)
|
return np.sin(np.pi*alpha)/(np.cosh(z*alpha) + np.cos(alpha*np.pi))/(2*np.pi)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def susceptibility(omega, tau, alpha):
|
@adjust_dims
|
||||||
"""
|
def susceptibility(omega: ArrayLike, tau: ArrayLike, alpha: float) -> ArrayLike:
|
||||||
Susceptibility
|
r"""
|
||||||
|
Complex susceptibility
|
||||||
|
|
||||||
.. math::
|
.. math::
|
||||||
\chi(\omega, \\tau, \\alpha) = \\frac{1}{1-(i\omega\\tau_0)^\\alpha}
|
\chi(\omega, \tau, \alpha) = \frac{1}{[1-(i\omega\tau)^\alpha]}
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
omega:
|
omega (array-like): Frequency axis in 1/s (not Hz).
|
||||||
tau:
|
tau (array-like): Correlation times :math:`\tau_\text{CC}` in s.
|
||||||
alpha:
|
alpha (float): Shape parameter.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
_tau = np.atleast_1d(tau)
|
val = 1/(1+(1j*omega*tau)**alpha)
|
||||||
_omega = np.atleast_1d(omega)
|
return np.conjugate(val)
|
||||||
val = 1/(1+(1j*_omega[:, None]*_tau[None, :])**alpha)
|
|
||||||
return np.conjugate(val).squeeze()
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
@adjust_dims
|
||||||
def specdens(omega, tau, alpha):
|
def specdens(omega, tau, alpha):
|
||||||
"""
|
"""
|
||||||
Spectral density
|
Spectral density
|
||||||
@@ -59,12 +62,11 @@ class ColeCole(Distribution):
|
|||||||
tau:
|
tau:
|
||||||
alpha:
|
alpha:
|
||||||
"""
|
"""
|
||||||
_tau = np.atleast_1d(tau)
|
omtau = (omega*tau)**alpha
|
||||||
_omega = np.atleast_1d(omega)
|
|
||||||
omtau = (_omega*_tau)**alpha
|
|
||||||
return np.sin(alpha*np.pi/2) * omtau / (1 + omtau**2 + 2*np.cos(alpha*np.pi/2)*omtau) / omega
|
return np.sin(alpha*np.pi/2) * omtau / (1 + omtau**2 + 2*np.cos(alpha*np.pi/2)*omtau) / omega
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
@adjust_dims
|
||||||
def correlation(t, tau0, alpha):
|
def correlation(t, tau0, alpha):
|
||||||
"""
|
"""
|
||||||
Correlation function :math:`C(t)`
|
Correlation function :math:`C(t)`
|
||||||
@@ -80,26 +82,3 @@ class ColeCole(Distribution):
|
|||||||
alpha:
|
alpha:
|
||||||
"""
|
"""
|
||||||
return mlf(-(t/tau0)**alpha, alpha)
|
return mlf(-(t/tau0)**alpha, alpha)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
import matplotlib.pyplot as plt
|
|
||||||
|
|
||||||
x = np.logspace(-3, 3, num=61)
|
|
||||||
|
|
||||||
fig, ax = plt.subplots(2, 2)
|
|
||||||
ax[0, 0].set_title('Distribution')
|
|
||||||
ax[0, 1].set_title('Correlation func.')
|
|
||||||
ax[1, 0].set_title('Spectral density')
|
|
||||||
ax[1, 1].set_title('Susceptibility')
|
|
||||||
|
|
||||||
for a in [0.4, 0.6, 0.8]:
|
|
||||||
ax[0, 0].loglog(x, ColeCole.distribution(x, 1, a))
|
|
||||||
ax[0, 1].semilogx(x, ColeCole.correlation(x, 1, a))
|
|
||||||
ax[1, 0].loglog(x, ColeCole.specdens(x, 1, a))
|
|
||||||
g = ax[1, 1].loglog(x, ColeCole.susceptibility(x, 1, a).imag)
|
|
||||||
ax[1, 1].loglog(x, ColeCole.susceptibility(x, 1, a).real, '--', color=g[0].get_color())
|
|
||||||
|
|
||||||
fig.tight_layout()
|
|
||||||
|
|
||||||
plt.show()
|
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ import numpy as np
|
|||||||
from scipy.special import psi, gammaincc
|
from scipy.special import psi, gammaincc
|
||||||
|
|
||||||
from .base import Distribution
|
from .base import Distribution
|
||||||
|
from ..lib.decorator import adjust_dims
|
||||||
|
from ..lib.utils import ArrayLike
|
||||||
from ..utils.constants import Eu
|
from ..utils.constants import Eu
|
||||||
|
|
||||||
|
|
||||||
@@ -16,22 +18,50 @@ class ColeDavidson(Distribution):
|
|||||||
bounds = [(0, 1)]
|
bounds = [(0, 1)]
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def susceptibility(omega, tau, gamma):
|
def distribution(tau, tau0, gamma):
|
||||||
"""
|
"""
|
||||||
Susceptibility
|
Distribution of correlation times
|
||||||
|
|
||||||
.. math::
|
.. math::
|
||||||
\chi(\omega, \\tau, \\gamma) = \\frac{1}{(1-i\omega\\tau_0)^\\gamma}
|
G(\ln\\tau) =
|
||||||
|
\\begin{cases}
|
||||||
|
\\frac{\sin(\pi\gamma)}{\pi} \\Big(\\frac{\\tau}{\\tau_0 - \\tau}\\Big)^\gamma & \\tau < \\tau_0 \\\\
|
||||||
|
0 & \\text{else}
|
||||||
|
\end{cases}
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
omega:
|
|
||||||
tau:
|
tau:
|
||||||
|
tau0:
|
||||||
gamma:
|
gamma:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
ratio = tau0/tau
|
||||||
|
|
||||||
|
ret_val = np.zeros_like(ratio)
|
||||||
|
ret_val[ratio > 1] = np.sin(np.pi*gamma) / np.pi * (1 / (ratio[ratio>1] - 1))**gamma
|
||||||
|
|
||||||
|
return ret_val
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
@adjust_dims
|
||||||
|
def susceptibility(omega: ArrayLike, tau: ArrayLike, gamma: float) -> ArrayLike:
|
||||||
|
r"""
|
||||||
|
Complex susceptibility
|
||||||
|
|
||||||
|
.. math::
|
||||||
|
\chi(\omega, \tau, \alpha, \gamma) = \frac{1}{[1-i\omega\tau]^\gamma}
|
||||||
|
|
||||||
|
Args:
|
||||||
|
omega (array-like): Frequency axis in 1/s (not Hz).
|
||||||
|
tau (array-like): Correlation times in s.
|
||||||
|
gamma (float): Shape parameter.
|
||||||
|
|
||||||
|
"""
|
||||||
return (1/(1+1j*omega*tau)**gamma).conjugate()
|
return (1/(1+1j*omega*tau)**gamma).conjugate()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def specdens(omega, tau,gamma):
|
@adjust_dims
|
||||||
|
def specdens(omega, tau, gamma):
|
||||||
"""
|
"""
|
||||||
Spectral density
|
Spectral density
|
||||||
|
|
||||||
@@ -43,15 +73,12 @@ class ColeDavidson(Distribution):
|
|||||||
tau:
|
tau:
|
||||||
gamma:
|
gamma:
|
||||||
"""
|
"""
|
||||||
gam = gamma
|
omtau = omega*tau
|
||||||
_w = np.atleast_1d(omega)
|
|
||||||
_t = np.atleast_1d(tau)
|
|
||||||
omtau = _w[:, None] * _t[None, :]
|
|
||||||
|
|
||||||
ret_val = np.sin(gam*np.arctan2(omtau, 1)) / (1 + omtau**2)**(gam/2.) / _w[:, None]
|
ret_val = np.sin(gamma*np.arctan2(omtau, 1)) / (1 + omtau**2)**(gamma/2.) / omega
|
||||||
ret_val[_w == 0, :] = gam*_t
|
ret_val[np.argwhere(omega == 0)] = gamma*tau
|
||||||
|
|
||||||
return np.squeeze(ret_val)
|
return ret_val
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def mean(tau, gamma):
|
def mean(tau, gamma):
|
||||||
@@ -113,33 +140,8 @@ class ColeDavidson(Distribution):
|
|||||||
return tau/np.tan(np.pi/(2*gamma+2))
|
return tau/np.tan(np.pi/(2*gamma+2))
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def distribution(tau, tau0, gamma):
|
@adjust_dims
|
||||||
"""
|
def correlation(t, tau, gamma):
|
||||||
Distribution of correlation times
|
|
||||||
|
|
||||||
.. math::
|
|
||||||
G(\ln\\tau) =
|
|
||||||
\\begin{cases}
|
|
||||||
\\frac{\sin(\pi\gamma)}{\pi} \\Big(\\frac{\\tau}{\\tau_0 - \\tau}\\Big)^\gamma & \\tau < \\tau_0 \\\\
|
|
||||||
0 & \\text{else}
|
|
||||||
\end{cases}
|
|
||||||
|
|
||||||
Args:
|
|
||||||
tau:
|
|
||||||
tau0:
|
|
||||||
gamma:
|
|
||||||
"""
|
|
||||||
|
|
||||||
if isinstance(tau, numbers.Number):
|
|
||||||
return np.sin(np.pi*gamma) / np.pi * (1 / (tau0/tau - 1))**gamma if tau < tau0 else 0
|
|
||||||
|
|
||||||
ret_val = np.zeros_like(tau)
|
|
||||||
ret_val[tau < tau0] = np.sin(np.pi*gamma) / np.pi * (1 / (tau0/tau[tau < tau0] - 1))**gamma
|
|
||||||
|
|
||||||
return ret_val
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def correlation(t, tau0, gamma):
|
|
||||||
r"""
|
r"""
|
||||||
Correlation function
|
Correlation function
|
||||||
|
|
||||||
@@ -153,14 +155,14 @@ class ColeDavidson(Distribution):
|
|||||||
|
|
||||||
Args:
|
Args:
|
||||||
t:
|
t:
|
||||||
tau0:
|
tau:
|
||||||
gamma:
|
gamma:
|
||||||
|
|
||||||
References:
|
References:
|
||||||
R. Hilfer: H-function representations for stretched exponential relaxation and non-Debye susceptibilities in glassy systems. Phys. Rev. E (2002) https://doi.org/10.1103/PhysRevE.65.061510
|
R. Hilfer: H-function representations for stretched exponential relaxation and non-Debye susceptibilities in glassy systems. Phys. Rev. E (2002) https://doi.org/10.1103/PhysRevE.65.061510
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return gammaincc(gamma, t / tau0)
|
return gammaincc(gamma, t / tau)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|||||||
@@ -3,28 +3,44 @@ import numbers
|
|||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
from .base import Distribution
|
from .base import Distribution
|
||||||
|
from ..lib.decorator import adjust_dims
|
||||||
|
from ..lib.utils import ArrayLike
|
||||||
|
|
||||||
|
|
||||||
class Debye(Distribution):
|
class Debye(Distribution):
|
||||||
name = 'Debye'
|
name = 'Debye'
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def correlation(t, tau0, *args):
|
def distribution(tau: ArrayLike, tau0: float) -> ArrayLike:
|
||||||
return np.exp(-t/tau0)
|
if isinstance(tau, numbers.Number):
|
||||||
|
return 1 if tau == tau0 else 0
|
||||||
|
|
||||||
@staticmethod
|
ret_val = np.zeros_like(tau)
|
||||||
def susceptibility(omega, tau0, *args):
|
ret_val[tau == tau0] = 1.
|
||||||
return 1/(1 + 1j*omega*tau0)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def specdens(omega, tau0, *args):
|
|
||||||
return tau0 / (1 + (omega*tau0)**2)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def distribution(taus, tau0, *args):
|
|
||||||
if isinstance(taus, numbers.Number):
|
|
||||||
return 1 if taus == tau0 else 0
|
|
||||||
|
|
||||||
ret_val = np.zeros_like(taus)
|
|
||||||
ret_val[np.argmin(abs(taus - tau0))] = 1
|
|
||||||
return ret_val
|
return ret_val
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
@adjust_dims
|
||||||
|
def correlation(t, tau, *args):
|
||||||
|
return np.exp(-t/tau)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
@adjust_dims
|
||||||
|
def susceptibility(omega: ArrayLike, tau: ArrayLike) -> ArrayLike:
|
||||||
|
r"""
|
||||||
|
Complex susceptibility
|
||||||
|
|
||||||
|
.. math::
|
||||||
|
\chi(\omega, \tau) = \frac{1}{1-i\omega\tau}
|
||||||
|
|
||||||
|
Args:
|
||||||
|
omega (array-like): Frequency axis in 1/s (not Hz).
|
||||||
|
tau (array-like): Correlation times in s.
|
||||||
|
|
||||||
|
"""
|
||||||
|
return 1/(1 - 1j*omega*tau)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
@adjust_dims
|
||||||
|
def specdens(omega: ArrayLike, tau: ArrayLike) -> ArrayLike:
|
||||||
|
return tau / (1 + (omega*tau)**2)
|
||||||
|
|||||||
@@ -1,14 +1,18 @@
|
|||||||
|
from typing import Union
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from scipy.special import psi
|
from scipy.special import psi
|
||||||
|
|
||||||
from .base import Distribution
|
from .base import Distribution
|
||||||
|
from ..lib.utils import ArrayLike
|
||||||
|
from ..lib.decorator import adjust_dims
|
||||||
from ..math.mittagleffler import mlf
|
from ..math.mittagleffler import mlf
|
||||||
from ..utils import Eu
|
from ..utils import Eu
|
||||||
|
|
||||||
|
|
||||||
class HavriliakNegami(Distribution):
|
class HavriliakNegami(Distribution):
|
||||||
"""
|
"""
|
||||||
Functions based on Cole-Davidson distribution
|
Functions based on Havriliak-Negami distribution
|
||||||
"""
|
"""
|
||||||
|
|
||||||
name = 'Havriliak-Negami'
|
name = 'Havriliak-Negami'
|
||||||
@@ -16,51 +20,31 @@ class HavriliakNegami(Distribution):
|
|||||||
bounds = [(0, 1), (0, 1)]
|
bounds = [(0, 1), (0, 1)]
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def correlation(t, tau0, alpha, gamma):
|
def distribution(tau: ArrayLike, tau0: float, alpha: float, gamma: float) -> ArrayLike:
|
||||||
r"""
|
r"""
|
||||||
Correlation function
|
Distribution of correlation times :math:`G(\ln\tau)`.
|
||||||
|
|
||||||
.. math::
|
.. math::
|
||||||
C(t, \tau_0, \alpha, \gamma) = 1 - \left(\frac{t}{\tau_0}\right)^{\alpha\gamma} \text{E}_{\alpha,\alpha\gamma+1}^\gamma\left[-\left(\frac{t}{\tau_0}\right)^\alpha\right]
|
G(\ln\tau) = \frac{(\tau/\tau_0)^{\alpha\gamma}
|
||||||
|
\sin\left\lbrace\gamma\arctan\left[\frac{\sin\alpha\pi}{(\tau/\tau_0)^\alpha + \cos\alpha\pi}\right] \right\rbrace}{\pi\left[1+2(\tau/\tau_0)^\alpha\cos\alpha\pi + (\tau/\tau_0)^{2\gamma}\right]}
|
||||||
with incomplete Gamma function
|
|
||||||
|
|
||||||
.. math::
|
|
||||||
\Gamma(\gamma, t/\tau_0) = \frac{1}{\Gamma(\gamma)}\int_{t/\tau_0}^\infty x^{\gamma-1}\text{e}^{-x}\,\mathrm{d}x
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
t:
|
tau (array_like) :
|
||||||
tau0:
|
tau0 (array-like) :
|
||||||
alpha:
|
alpha:
|
||||||
gamma:
|
gamma:
|
||||||
|
|
||||||
References:
|
Returns:
|
||||||
R. Hilfer: H-function representations for stretched exponential relaxation and non-Debye susceptibilities in glassy systems. Phys. Rev. E (2002) https://doi.org/10.1103/PhysRevE.65.061510
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return 1 - (t/tau0)**(alpha*gamma) * mlf(-(t/tau0)**alpha, alpha, alpha*gamma+1, gamma)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def susceptibility(omega, tau, alpha, gamma):
|
|
||||||
return np.conjugate(1/(1 + (1j*omega[:, None]*tau[None, :])**alpha)**gamma).squeeze()
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def specdens(omega, tau, alpha, gamma):
|
|
||||||
omtau = (omega[:, None]*tau[None, :])**alpha
|
|
||||||
|
|
||||||
zaehler = np.sin(gamma * np.arctan2(omtau*np.sin(0.5*alpha*np.pi), 1 + omtau*np.cos(0.5*alpha*np.pi)))
|
|
||||||
nenner = (1 + 2*omtau * np.cos(0.5*alpha*np.pi) + omtau**2)**(0.5*gamma)
|
|
||||||
|
|
||||||
return ((1 / omega) * (zaehler/nenner)).squeeze()
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def distribution(tau, tau0, alpha, gamma):
|
|
||||||
if alpha == 1:
|
if alpha == 1:
|
||||||
from .coledavidson import ColeDavidson
|
from .coledavidson import ColeDavidson
|
||||||
return ColeDavidson.distribution(tau, tau0, gamma)
|
return ColeDavidson.distribution(tau, tau0, gamma)
|
||||||
|
|
||||||
elif gamma == 1:
|
elif gamma == 1:
|
||||||
from .colecole import ColeCole
|
from .colecole import ColeCole
|
||||||
return ColeCole.distribution(tau, tau0, alpha)
|
return ColeCole.distribution(tau, tau0, alpha)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
_y = tau/tau0
|
_y = tau/tau0
|
||||||
om_y = (1 + 2*np.cos(np.pi*alpha)*(_y**alpha) + _y**(2*alpha))**(-gamma/2)
|
om_y = (1 + 2*np.cos(np.pi*alpha)*(_y**alpha) + _y**(2*alpha))**(-gamma/2)
|
||||||
@@ -69,11 +53,104 @@ class HavriliakNegami(Distribution):
|
|||||||
return np.sin(gamma*theta_y) * om_y * (_y**(alpha*gamma)) / np.pi
|
return np.sin(gamma*theta_y) * om_y * (_y**(alpha*gamma)) / np.pi
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def max(tau, alpha, gamma):
|
@adjust_dims
|
||||||
return tau*(np.sin(0.5*np.pi*alpha*gamma/(gamma+1)) / np.sin(0.5*np.pi*alpha/(gamma+1)))**(1/alpha)
|
def correlation(t: ArrayLike, tau: ArrayLike, alpha: float, gamma: float) -> ArrayLike:
|
||||||
|
r"""
|
||||||
|
Correlation function
|
||||||
|
|
||||||
|
.. math::
|
||||||
|
C(t, \tau_\text{HN}, \alpha, \gamma) = 1 - \left(\frac{t}{\tau_\text{HN}}\right)^{\alpha\gamma}
|
||||||
|
\text{E}_{\alpha,\alpha\gamma+1}^\gamma\left[-\left(\frac{t}{\tau_\text{HN}}\right)^\alpha\right]
|
||||||
|
|
||||||
|
with three-parameter Mittag-Leffler function
|
||||||
|
|
||||||
|
.. math::
|
||||||
|
\text{E}_{a,b}^g (z) = \frac{1}{\Gamma(g)} \sum_{k=0}^\infty \frac{\Gamma(g+k) z^k}{k!\Gamma(ak+b)}
|
||||||
|
|
||||||
|
Args:
|
||||||
|
t (array-like): Time axis in s.
|
||||||
|
tau (array-like): Correlation times :math:`\tau_\text{HN}` in s.
|
||||||
|
alpha (float): Cole-Cole shape parameter.
|
||||||
|
gamma (float): Cole-Davidson shape parameter.
|
||||||
|
|
||||||
|
References:
|
||||||
|
R. Garrappa: Models of dielectric relaxation based on completely monotone functions.
|
||||||
|
Frac. Calc Appl. Anal. 19 (2016) https://arxiv.org/abs/1611.04028
|
||||||
|
|
||||||
|
"""
|
||||||
|
return 1 - (t/tau)**(alpha*gamma) * mlf(-(t/tau)**alpha, alpha, alpha*gamma+1, gamma)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def logmean(tau, alpha, gamma):
|
@adjust_dims
|
||||||
|
def susceptibility(omega: ArrayLike, tau: ArrayLike, alpha: float, gamma: float) -> Union[np.ndarray, complex]:
|
||||||
|
r"""
|
||||||
|
Complex susceptibility
|
||||||
|
|
||||||
|
.. math::
|
||||||
|
\chi(\omega, \tau, \alpha, \gamma) = \frac{1}{[1-(i\omega\tau)^\alpha]^\gamma}
|
||||||
|
|
||||||
|
Args:
|
||||||
|
omega (array-like): Frequency axis in 1/s (not Hz).
|
||||||
|
tau (array-like): Correlation times in s.
|
||||||
|
alpha (float): Shape parameter.
|
||||||
|
gamma (float): Even more shape parameter.
|
||||||
|
|
||||||
|
"""
|
||||||
|
return np.conjugate(1/(1 + (1j*omega*tau)**alpha)**gamma)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
@adjust_dims
|
||||||
|
def specdens(omega: ArrayLike, tau: ArrayLike, alpha: float, gamma: float) -> Union[np.ndarray, float]:
|
||||||
|
r"""
|
||||||
|
Spectral density :math:`J(\omega)`
|
||||||
|
|
||||||
|
.. math::
|
||||||
|
J(\omega) = \frac{\sin\left\lbrace \gamma\arctan\left[ \frac{(\omega\tau)^\alpha\sin(\alpha\pi/2)}{1+(\omega\tau)^\alpha\cos(\alpha\pi/2)} \right] \right\rbrace}
|
||||||
|
{\omega \left[ 1+(\omega\tau)^\alpha \cos(\alpha\pi/2) + (\omega\tau)^{2\alpha} \right]^{\gamma/2}}
|
||||||
|
|
||||||
|
Args:
|
||||||
|
omega (array-like): Frequency axis in 1/s (not Hz).
|
||||||
|
tau (array-like): Correlation times in s.
|
||||||
|
alpha (float): Cole-Cole shape parameter.
|
||||||
|
gamma (float): Cole-Davidson shape parameter.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
|
||||||
|
"""
|
||||||
|
omtau = (omega*tau)**alpha
|
||||||
|
|
||||||
|
zaehler = np.sin(gamma * np.arctan2(omtau*np.sin(0.5*alpha*np.pi), 1 + omtau*np.cos(0.5*alpha*np.pi)))
|
||||||
|
nenner = (1 + 2*omtau * np.cos(0.5*alpha*np.pi) + omtau**2)**(0.5*gamma)
|
||||||
|
|
||||||
|
result = (1 / omega) * (zaehler/nenner)
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def mean(tau: ArrayLike, alpha: float, gamma: float) -> Union[np.ndarray, float]:
|
||||||
|
r"""
|
||||||
|
|
||||||
|
.. math::
|
||||||
|
\langle \tau \rangle \approx \tau_\text{HN} \alpha \gamma
|
||||||
|
|
||||||
|
This is an approximation given in `[1]`_
|
||||||
|
|
||||||
|
Args:
|
||||||
|
tau (array-like): Function parameter in s.
|
||||||
|
alpha (float): Shape parameter.
|
||||||
|
gamma (float): Even more shape parameter.
|
||||||
|
|
||||||
|
Reference:
|
||||||
|
_`[1]` Bauer, Th., Köhler, M., Lunkenheimer, P., Angell, C.A.:
|
||||||
|
Relaxation dynamics and ionic conductivity in a fragile plastic crystal.
|
||||||
|
J. Chem. Phys. 133, 144509 (2010). https://doi.org/10.1063/1.3487521
|
||||||
|
|
||||||
|
|
||||||
|
"""
|
||||||
|
return tau * alpha*gamma
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def logmean(tau: ArrayLike, alpha: float, gamma: float) -> ArrayLike:
|
||||||
r"""
|
r"""
|
||||||
Calculate mean logarithm of tau
|
Calculate mean logarithm of tau
|
||||||
|
|
||||||
@@ -82,25 +159,12 @@ class HavriliakNegami(Distribution):
|
|||||||
|
|
||||||
Args:
|
Args:
|
||||||
tau:
|
tau:
|
||||||
alpha:
|
alpha (float):
|
||||||
gamma:
|
gamma (float):
|
||||||
|
|
||||||
Returns:
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return np.log(tau) + (psi(gamma)+Eu)/alpha
|
return np.log(tau) + (psi(gamma)+Eu)/alpha
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def mean(tau, alpha, gamma):
|
def max(tau: ArrayLike, alpha: float, gamma: float) -> ArrayLike:
|
||||||
# approximation according to Th. Bauer et al., J. Chem. Phys. 133, 144509 (2010).
|
return tau*(np.sin(0.5*np.pi*alpha*gamma/(gamma+1)) / np.sin(0.5*np.pi*alpha/(gamma+1)))**(1/alpha)
|
||||||
return tau * alpha*gamma
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
import matplotlib.pyplot as plt
|
|
||||||
|
|
||||||
x = np.logspace(-7, 3)
|
|
||||||
y = HavriliakNegami.correlation(x, 1, 0.8, 0.26)
|
|
||||||
|
|
||||||
plt.semilogx(x, y)
|
|
||||||
plt.show()
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import numpy as np
|
|||||||
from scipy.interpolate import interp1d
|
from scipy.interpolate import interp1d
|
||||||
from scipy.special import gamma
|
from scipy.special import gamma
|
||||||
|
|
||||||
|
from nmreval.lib.decorator import adjust_dims
|
||||||
from .base import Distribution
|
from .base import Distribution
|
||||||
from ..math.kww import kww_cos, kww_sin
|
from ..math.kww import kww_cos, kww_sin
|
||||||
from ..utils.constants import Eu
|
from ..utils.constants import Eu
|
||||||
@@ -13,52 +14,52 @@ class KWW(Distribution):
|
|||||||
boounds = [(0, 1)]
|
boounds = [(0, 1)]
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def distribution(taus, tau, *args):
|
def distribution(taus, tau, beta):
|
||||||
b = args[0]
|
if not (0.1 <= beta <= 0.9):
|
||||||
assert 0.1 <= b <= 0.9
|
raise ValueError('KWW distribution is only defined between 0.1 and 0.9')
|
||||||
b_supp = [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9]
|
b_supp = [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9]
|
||||||
B_supp = [0.145, 0.197, 0.243, 0.285, 0.382, 0.306, 0.360, 0.435, 0.700]
|
B_supp = [0.145, 0.197, 0.243, 0.285, 0.382, 0.306, 0.360, 0.435, 0.700]
|
||||||
C_supp = [0.89, 0.50, 0.35, 0.25, 0, 0.13, 0.22, 0.4015, 0.32]
|
C_supp = [0.89, 0.50, 0.35, 0.25, 0, 0.13, 0.22, 0.4015, 0.32]
|
||||||
|
|
||||||
B = interp1d(b_supp, B_supp)(b)
|
B = interp1d(b_supp, B_supp)(beta)
|
||||||
C = interp1d(b_supp, C_supp)(b)
|
C = interp1d(b_supp, C_supp)(beta)
|
||||||
|
|
||||||
tt = tau/taus
|
tt = tau/taus
|
||||||
|
|
||||||
delta = b * abs(b-0.5) / (1-b)
|
delta = beta * abs(beta-0.5) / (1-beta)
|
||||||
if b > 0.5:
|
if beta > 0.5:
|
||||||
f = 1 + C * tt**delta
|
f = 1 + C * tt**delta
|
||||||
else:
|
else:
|
||||||
f = 1 / (1 + C * tt**delta)
|
f = 1 / (1 + C * tt**delta)
|
||||||
ret_val = tau * B * np.exp(-(1-b) * b**(b/(1-b)) / tt**(b/(1-b))) / tt**((1-0.5*b)/(1-b))
|
ret_val = tau * B * np.exp(-(1-beta) * beta**(beta/(1-beta)) / tt**(beta/(1-beta))) / tt**((1-0.5*beta)/(1-beta))
|
||||||
|
|
||||||
return ret_val * f / taus
|
return ret_val * f / taus
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def correlation(t, tau, *args):
|
@adjust_dims
|
||||||
return np.exp(-(t/tau)**args[0])
|
def correlation(t, tau, beta):
|
||||||
|
return np.exp(-(t/tau)**beta)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def susceptibility(omega, tau, *args):
|
@adjust_dims
|
||||||
return 1-omega*kww_sin(omega, tau, args[0]) + 1j*omega*kww_cos(omega, tau, args[0])
|
def susceptibility(omega, tau, beta):
|
||||||
|
return 1-omega*kww_sin(omega, tau, beta) + 1j*omega*kww_cos(omega, tau, beta)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def specdens(omega, tau, *args):
|
@adjust_dims
|
||||||
return kww_cos(omega, tau, args[0])
|
def specdens(omega, tau, beta):
|
||||||
|
return kww_cos(omega, tau, beta)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def mean(*args):
|
def mean(tau, beta):
|
||||||
tau, beta = args
|
|
||||||
return tau/beta * gamma(1 / beta)
|
return tau/beta * gamma(1 / beta)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def logmean(*args):
|
def logmean(tau, beta):
|
||||||
tau, beta = args
|
|
||||||
return (1-1/beta) * Eu + np.log(tau)
|
return (1-1/beta) * Eu + np.log(tau)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def max(*args):
|
def max(tau, beta):
|
||||||
tau, beta = args
|
|
||||||
return (1.7851 - 0.87052*beta - 0.028836*beta**2 + 0.11391*beta**3) * tau
|
return (1.7851 - 0.87052*beta - 0.028836*beta**2 + 0.11391*beta**3) * tau
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,9 @@ from multiprocessing import Pool, cpu_count
|
|||||||
from itertools import product
|
from itertools import product
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
|
from nmreval.lib.decorator import adjust_dims
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from scipy.integrate import simpson
|
from scipy.integrate import simpson
|
||||||
except ImportError:
|
except ImportError:
|
||||||
@@ -25,8 +28,7 @@ class LogGaussian(Distribution):
|
|||||||
return np.exp(-0.5*(np.log(tau/tau0)/sigma)**2)/np.sqrt(2*np.pi)/sigma
|
return np.exp(-0.5*(np.log(tau/tau0)/sigma)**2)/np.sqrt(2*np.pi)/sigma
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def correlation(t, tau0, *args):
|
def correlation(t, tau0, sigma: float):
|
||||||
sigma = args[0]
|
|
||||||
_t = np.atleast_1d(t)
|
_t = np.atleast_1d(t)
|
||||||
_tau = np.atleast_1d(tau0)
|
_tau = np.atleast_1d(tau0)
|
||||||
|
|
||||||
@@ -40,8 +42,7 @@ class LogGaussian(Distribution):
|
|||||||
return ret_val.squeeze()
|
return ret_val.squeeze()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def susceptibility(omega, tau0, *args):
|
def susceptibility(omega, tau0, sigma: float):
|
||||||
sigma = args[0]
|
|
||||||
_omega = np.atleast_1d(omega)
|
_omega = np.atleast_1d(omega)
|
||||||
_tau = np.atleast_1d(tau0)
|
_tau = np.atleast_1d(tau0)
|
||||||
|
|
||||||
@@ -56,8 +57,7 @@ class LogGaussian(Distribution):
|
|||||||
return ret_val.squeeze()
|
return ret_val.squeeze()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def specdens(omega, tau0, *args):
|
def specdens(omega, tau0, sigma):
|
||||||
sigma = args[0]
|
|
||||||
_omega = np.atleast_1d(omega)
|
_omega = np.atleast_1d(omega)
|
||||||
_tau = np.atleast_1d(tau0)
|
_tau = np.atleast_1d(tau0)
|
||||||
|
|
||||||
@@ -78,7 +78,7 @@ class LogGaussian(Distribution):
|
|||||||
|
|
||||||
def _integrate_process_1(args):
|
def _integrate_process_1(args):
|
||||||
omega_i, tau_j, sigma = args
|
omega_i, tau_j, sigma = args
|
||||||
area = quad(_integrand_freq_imag_high, 0, 50, args=(omega_i, tau_j, sigma))[0]
|
area, _ = quad(_integrand_freq_imag_high, 0, 50, args=(omega_i, tau_j, sigma))
|
||||||
area += quad(_integrand_freq_imag_low, -50, 0, args=(omega_i, tau_j, sigma))[0]
|
area += quad(_integrand_freq_imag_low, -50, 0, args=(omega_i, tau_j, sigma))[0]
|
||||||
|
|
||||||
return area
|
return area
|
||||||
@@ -102,7 +102,9 @@ def _integrand_time(u, t, tau, sigma):
|
|||||||
return LogGaussian.distribution(uu, tau, sigma) * np.exp(-t/uu)
|
return LogGaussian.distribution(uu, tau, sigma) * np.exp(-t/uu)
|
||||||
|
|
||||||
|
|
||||||
|
# integrands
|
||||||
def _integrand_freq_imag_low(u, omega, tau, sigma):
|
def _integrand_freq_imag_low(u, omega, tau, sigma):
|
||||||
|
# integrand
|
||||||
uu = np.exp(u)
|
uu = np.exp(u)
|
||||||
return LogGaussian.distribution(uu, tau, sigma) * omega * uu / (1 + (omega*uu)**2)
|
return LogGaussian.distribution(uu, tau, sigma) * omega * uu / (1 + (omega*uu)**2)
|
||||||
|
|
||||||
|
|||||||
@@ -2,14 +2,12 @@
|
|||||||
|
|
||||||
# Form implementation generated from reading ui file 'resources/_ui/basewindow.ui'
|
# Form implementation generated from reading ui file 'resources/_ui/basewindow.ui'
|
||||||
#
|
#
|
||||||
# Created by: PyQt5 UI code generator 5.12.3
|
# Created by: PyQt5 UI code generator 5.9.2
|
||||||
#
|
#
|
||||||
# WARNING! All changes made in this file will be lost!
|
# WARNING! All changes made in this file will be lost!
|
||||||
|
|
||||||
|
|
||||||
from PyQt5 import QtCore, QtGui, QtWidgets
|
from PyQt5 import QtCore, QtGui, QtWidgets
|
||||||
|
|
||||||
|
|
||||||
class Ui_BaseWindow(object):
|
class Ui_BaseWindow(object):
|
||||||
def setupUi(self, BaseWindow):
|
def setupUi(self, BaseWindow):
|
||||||
BaseWindow.setObjectName("BaseWindow")
|
BaseWindow.setObjectName("BaseWindow")
|
||||||
@@ -461,6 +459,9 @@ class Ui_BaseWindow(object):
|
|||||||
self.toolBar.addAction(self.actionSave)
|
self.toolBar.addAction(self.actionSave)
|
||||||
self.toolBar.addSeparator()
|
self.toolBar.addSeparator()
|
||||||
self.toolBar.addAction(self.actionMouse_behaviour)
|
self.toolBar.addAction(self.actionMouse_behaviour)
|
||||||
|
self.toolBar.addSeparator()
|
||||||
|
self.toolBar.addAction(self.actionPrevious)
|
||||||
|
self.toolBar.addAction(self.actionNext_window)
|
||||||
self.toolbar_edit.addAction(self.action_calc)
|
self.toolbar_edit.addAction(self.action_calc)
|
||||||
self.toolbar_edit.addAction(self.action_mean_t1)
|
self.toolbar_edit.addAction(self.action_mean_t1)
|
||||||
self.toolbar_edit.addAction(self.actionShift)
|
self.toolbar_edit.addAction(self.actionShift)
|
||||||
@@ -598,6 +599,7 @@ class Ui_BaseWindow(object):
|
|||||||
self.actionLife.setText(_translate("BaseWindow", "Life..."))
|
self.actionLife.setText(_translate("BaseWindow", "Life..."))
|
||||||
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"))
|
||||||
|
|
||||||
from ..data.datawidget.datawidget import DataWidget
|
from ..data.datawidget.datawidget import DataWidget
|
||||||
from ..data.point_select import PointSelectWidget
|
from ..data.point_select import PointSelectWidget
|
||||||
from ..data.signaledit.editsignalwidget import EditSignalWidget
|
from ..data.signaledit.editsignalwidget import EditSignalWidget
|
||||||
|
|||||||
@@ -2,19 +2,19 @@
|
|||||||
|
|
||||||
# Form implementation generated from reading ui file 'resources/_ui/bdsdialog.ui'
|
# Form implementation generated from reading ui file 'resources/_ui/bdsdialog.ui'
|
||||||
#
|
#
|
||||||
# Created by: PyQt5 UI code generator 5.12.3
|
# Created by: PyQt5 UI code generator 5.9.2
|
||||||
#
|
#
|
||||||
# WARNING! All changes made in this file will be lost!
|
# WARNING! All changes made in this file will be lost!
|
||||||
|
|
||||||
|
|
||||||
from PyQt5 import QtCore, QtGui, QtWidgets
|
from PyQt5 import QtCore, QtGui, QtWidgets
|
||||||
|
|
||||||
|
|
||||||
class Ui_Dialog(object):
|
class Ui_Dialog(object):
|
||||||
def setupUi(self, Dialog):
|
def setupUi(self, Dialog):
|
||||||
Dialog.setObjectName("Dialog")
|
Dialog.setObjectName("Dialog")
|
||||||
Dialog.resize(400, 319)
|
Dialog.resize(544, 443)
|
||||||
self.gridLayout = QtWidgets.QGridLayout(Dialog)
|
self.gridLayout = QtWidgets.QGridLayout(Dialog)
|
||||||
|
self.gridLayout.setContentsMargins(3, 3, 3, 3)
|
||||||
|
self.gridLayout.setSpacing(3)
|
||||||
self.gridLayout.setObjectName("gridLayout")
|
self.gridLayout.setObjectName("gridLayout")
|
||||||
self.listWidget = QtWidgets.QListWidget(Dialog)
|
self.listWidget = QtWidgets.QListWidget(Dialog)
|
||||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.MinimumExpanding)
|
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.MinimumExpanding)
|
||||||
@@ -23,7 +23,66 @@ class Ui_Dialog(object):
|
|||||||
sizePolicy.setHeightForWidth(self.listWidget.sizePolicy().hasHeightForWidth())
|
sizePolicy.setHeightForWidth(self.listWidget.sizePolicy().hasHeightForWidth())
|
||||||
self.listWidget.setSizePolicy(sizePolicy)
|
self.listWidget.setSizePolicy(sizePolicy)
|
||||||
self.listWidget.setObjectName("listWidget")
|
self.listWidget.setObjectName("listWidget")
|
||||||
self.gridLayout.addWidget(self.listWidget, 1, 0, 1, 1)
|
self.gridLayout.addWidget(self.listWidget, 1, 0, 2, 1)
|
||||||
|
self.groupBox_2 = QtWidgets.QGroupBox(Dialog)
|
||||||
|
self.groupBox_2.setObjectName("groupBox_2")
|
||||||
|
self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.groupBox_2)
|
||||||
|
self.verticalLayout_3.setContentsMargins(3, 3, 3, 3)
|
||||||
|
self.verticalLayout_3.setSpacing(3)
|
||||||
|
self.verticalLayout_3.setObjectName("verticalLayout_3")
|
||||||
|
self.freq_button = QtWidgets.QRadioButton(self.groupBox_2)
|
||||||
|
self.freq_button.setChecked(True)
|
||||||
|
self.freq_button.setObjectName("freq_button")
|
||||||
|
self.buttonGroup = QtWidgets.QButtonGroup(Dialog)
|
||||||
|
self.buttonGroup.setObjectName("buttonGroup")
|
||||||
|
self.buttonGroup.addButton(self.freq_button)
|
||||||
|
self.verticalLayout_3.addWidget(self.freq_button)
|
||||||
|
self.temp_button = QtWidgets.QRadioButton(self.groupBox_2)
|
||||||
|
self.temp_button.setObjectName("temp_button")
|
||||||
|
self.buttonGroup.addButton(self.temp_button)
|
||||||
|
self.verticalLayout_3.addWidget(self.temp_button)
|
||||||
|
self.gridLayout.addWidget(self.groupBox_2, 1, 1, 1, 1)
|
||||||
|
self.groupBox = QtWidgets.QGroupBox(Dialog)
|
||||||
|
self.groupBox.setObjectName("groupBox")
|
||||||
|
self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.groupBox)
|
||||||
|
self.verticalLayout_2.setContentsMargins(3, 3, 3, 3)
|
||||||
|
self.verticalLayout_2.setSpacing(3)
|
||||||
|
self.verticalLayout_2.setObjectName("verticalLayout_2")
|
||||||
|
self.eps_checkBox = QtWidgets.QCheckBox(self.groupBox)
|
||||||
|
self.eps_checkBox.setChecked(True)
|
||||||
|
self.eps_checkBox.setObjectName("eps_checkBox")
|
||||||
|
self.verticalLayout_2.addWidget(self.eps_checkBox)
|
||||||
|
self.modul_checkBox = QtWidgets.QCheckBox(self.groupBox)
|
||||||
|
self.modul_checkBox.setObjectName("modul_checkBox")
|
||||||
|
self.verticalLayout_2.addWidget(self.modul_checkBox)
|
||||||
|
self.cond_checkBox = QtWidgets.QCheckBox(self.groupBox)
|
||||||
|
self.cond_checkBox.setObjectName("cond_checkBox")
|
||||||
|
self.verticalLayout_2.addWidget(self.cond_checkBox)
|
||||||
|
self.loss_checkBox = QtWidgets.QCheckBox(self.groupBox)
|
||||||
|
self.loss_checkBox.setObjectName("loss_checkBox")
|
||||||
|
self.verticalLayout_2.addWidget(self.loss_checkBox)
|
||||||
|
self.line = QtWidgets.QFrame(self.groupBox)
|
||||||
|
self.line.setFrameShape(QtWidgets.QFrame.HLine)
|
||||||
|
self.line.setFrameShadow(QtWidgets.QFrame.Sunken)
|
||||||
|
self.line.setObjectName("line")
|
||||||
|
self.verticalLayout_2.addWidget(self.line)
|
||||||
|
self.cap_checkBox = QtWidgets.QCheckBox(self.groupBox)
|
||||||
|
self.cap_checkBox.setObjectName("cap_checkBox")
|
||||||
|
self.verticalLayout_2.addWidget(self.cap_checkBox)
|
||||||
|
self.temp_checkBox = QtWidgets.QCheckBox(self.groupBox)
|
||||||
|
self.temp_checkBox.setObjectName("temp_checkBox")
|
||||||
|
self.verticalLayout_2.addWidget(self.temp_checkBox)
|
||||||
|
self.time_checkBox = QtWidgets.QCheckBox(self.groupBox)
|
||||||
|
self.time_checkBox.setObjectName("time_checkBox")
|
||||||
|
self.verticalLayout_2.addWidget(self.time_checkBox)
|
||||||
|
spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
|
||||||
|
self.verticalLayout_2.addItem(spacerItem)
|
||||||
|
self.gridLayout.addWidget(self.groupBox, 2, 1, 1, 1)
|
||||||
|
self.buttonBox = QtWidgets.QDialogButtonBox(Dialog)
|
||||||
|
self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
|
||||||
|
self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok)
|
||||||
|
self.buttonBox.setObjectName("buttonBox")
|
||||||
|
self.gridLayout.addWidget(self.buttonBox, 3, 0, 1, 2)
|
||||||
self.label = QtWidgets.QLabel(Dialog)
|
self.label = QtWidgets.QLabel(Dialog)
|
||||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Maximum)
|
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Maximum)
|
||||||
sizePolicy.setHorizontalStretch(0)
|
sizePolicy.setHorizontalStretch(0)
|
||||||
@@ -31,46 +90,31 @@ class Ui_Dialog(object):
|
|||||||
sizePolicy.setHeightForWidth(self.label.sizePolicy().hasHeightForWidth())
|
sizePolicy.setHeightForWidth(self.label.sizePolicy().hasHeightForWidth())
|
||||||
self.label.setSizePolicy(sizePolicy)
|
self.label.setSizePolicy(sizePolicy)
|
||||||
self.label.setObjectName("label")
|
self.label.setObjectName("label")
|
||||||
self.gridLayout.addWidget(self.label, 0, 0, 1, 1)
|
self.gridLayout.addWidget(self.label, 0, 0, 1, 2)
|
||||||
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.setObjectName("label_2")
|
|
||||||
self.gridLayout.addWidget(self.label_2, 0, 1, 1, 1)
|
|
||||||
self.verticalLayout = QtWidgets.QVBoxLayout()
|
|
||||||
self.verticalLayout.setObjectName("verticalLayout")
|
|
||||||
self.eps_checkBox = QtWidgets.QCheckBox(Dialog)
|
|
||||||
self.eps_checkBox.setChecked(True)
|
|
||||||
self.eps_checkBox.setObjectName("eps_checkBox")
|
|
||||||
self.verticalLayout.addWidget(self.eps_checkBox)
|
|
||||||
self.modul_checkBox = QtWidgets.QCheckBox(Dialog)
|
|
||||||
self.modul_checkBox.setObjectName("modul_checkBox")
|
|
||||||
self.verticalLayout.addWidget(self.modul_checkBox)
|
|
||||||
self.cond_checkBox = QtWidgets.QCheckBox(Dialog)
|
|
||||||
self.cond_checkBox.setObjectName("cond_checkBox")
|
|
||||||
self.verticalLayout.addWidget(self.cond_checkBox)
|
|
||||||
spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
|
|
||||||
self.verticalLayout.addItem(spacerItem)
|
|
||||||
self.gridLayout.addLayout(self.verticalLayout, 1, 1, 1, 1)
|
|
||||||
self.buttonBox = QtWidgets.QDialogButtonBox(Dialog)
|
|
||||||
self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
|
|
||||||
self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok)
|
|
||||||
self.buttonBox.setObjectName("buttonBox")
|
|
||||||
self.gridLayout.addWidget(self.buttonBox, 2, 0, 1, 2)
|
|
||||||
|
|
||||||
self.retranslateUi(Dialog)
|
self.retranslateUi(Dialog)
|
||||||
self.buttonBox.accepted.connect(Dialog.accept)
|
self.buttonBox.accepted.connect(Dialog.accept)
|
||||||
self.buttonBox.rejected.connect(Dialog.reject)
|
self.buttonBox.rejected.connect(Dialog.reject)
|
||||||
QtCore.QMetaObject.connectSlotsByName(Dialog)
|
QtCore.QMetaObject.connectSlotsByName(Dialog)
|
||||||
|
Dialog.setTabOrder(self.freq_button, self.temp_button)
|
||||||
|
Dialog.setTabOrder(self.temp_button, self.eps_checkBox)
|
||||||
|
Dialog.setTabOrder(self.eps_checkBox, self.modul_checkBox)
|
||||||
|
Dialog.setTabOrder(self.modul_checkBox, self.cond_checkBox)
|
||||||
|
Dialog.setTabOrder(self.cond_checkBox, self.listWidget)
|
||||||
|
|
||||||
def retranslateUi(self, Dialog):
|
def retranslateUi(self, Dialog):
|
||||||
_translate = QtCore.QCoreApplication.translate
|
_translate = QtCore.QCoreApplication.translate
|
||||||
Dialog.setWindowTitle(_translate("Dialog", "Read BDS data"))
|
Dialog.setWindowTitle(_translate("Dialog", "Read BDS data"))
|
||||||
self.label.setText(_translate("Dialog", "Found temperatures"))
|
self.groupBox_2.setTitle(_translate("Dialog", "X Axis"))
|
||||||
self.label_2.setText(_translate("Dialog", "Read as:"))
|
self.freq_button.setText(_translate("Dialog", "Frequency"))
|
||||||
|
self.temp_button.setText(_translate("Dialog", "Temperature"))
|
||||||
|
self.groupBox.setTitle(_translate("Dialog", "Y Axis"))
|
||||||
self.eps_checkBox.setText(_translate("Dialog", "Permittivity ε"))
|
self.eps_checkBox.setText(_translate("Dialog", "Permittivity ε"))
|
||||||
self.modul_checkBox.setText(_translate("Dialog", "Modulus 1/ε"))
|
self.modul_checkBox.setText(_translate("Dialog", "Modulus 1/ε"))
|
||||||
self.cond_checkBox.setText(_translate("Dialog", "Conductivity iεω"))
|
self.cond_checkBox.setText(_translate("Dialog", "Conductivity iεω"))
|
||||||
|
self.loss_checkBox.setText(_translate("Dialog", "Loss factor tan(δ)"))
|
||||||
|
self.cap_checkBox.setText(_translate("Dialog", "Capacity"))
|
||||||
|
self.temp_checkBox.setText(_translate("Dialog", "Meas. temperature"))
|
||||||
|
self.time_checkBox.setText(_translate("Dialog", "Meas. time"))
|
||||||
|
self.label.setText(_translate("Dialog", "Found entries"))
|
||||||
|
|
||||||
|
|||||||
@@ -599,10 +599,13 @@ class SignalContainer(ExperimentContainer):
|
|||||||
|
|
||||||
if isinstance(self._data, BDS):
|
if isinstance(self._data, BDS):
|
||||||
self.mode = 'bds'
|
self.mode = 'bds'
|
||||||
|
|
||||||
if sym_kwargs['symbol'] is None and line_kwargs['style'] is None:
|
if sym_kwargs['symbol'] is None and line_kwargs['style'] is None:
|
||||||
sym_kwargs['symbol'] = next(PointContainer.symbols)
|
if len(self._data) <= 91:
|
||||||
line_kwargs['style'] = LineStyle.No
|
sym_kwargs['symbol'] = next(PointContainer.symbols)
|
||||||
|
line_kwargs['style'] = LineStyle.No
|
||||||
|
else:
|
||||||
|
line_kwargs['style'] = LineStyle.Solid
|
||||||
|
sym_kwargs['symbol'] = SymbolStyle.No
|
||||||
|
|
||||||
elif isinstance(self._data, Signal):
|
elif isinstance(self._data, Signal):
|
||||||
if line_kwargs['style'] is None and sym_kwargs['symbol'] is None:
|
if line_kwargs['style'] is None and sym_kwargs['symbol'] is None:
|
||||||
@@ -617,7 +620,7 @@ class SignalContainer(ExperimentContainer):
|
|||||||
raise TypeError('Unknown class %s, should be FID, Spectrum, or BDS.' % type(self._data))
|
raise TypeError('Unknown class %s, should be FID, Spectrum, or BDS.' % type(self._data))
|
||||||
|
|
||||||
for mode in ['real', 'imag']:
|
for mode in ['real', 'imag']:
|
||||||
if mode == 'imag':
|
if mode == 'imag' and line_kwargs['style'] != LineStyle.No:
|
||||||
line_kwargs['style'] = LineStyle.Dashed
|
line_kwargs['style'] = LineStyle.Dashed
|
||||||
self.setSymbol(mode=mode, **sym_kwargs)
|
self.setSymbol(mode=mode, **sym_kwargs)
|
||||||
self.setLine(mode=mode, **line_kwargs)
|
self.setLine(mode=mode, **line_kwargs)
|
||||||
|
|||||||
@@ -591,6 +591,8 @@ class QGraphWindow(QtWidgets.QGraphicsView, Ui_GraphWindow):
|
|||||||
if item_dic:
|
if item_dic:
|
||||||
dic['items'].append(item_dic)
|
dic['items'].append(item_dic)
|
||||||
|
|
||||||
|
print(dic)
|
||||||
|
|
||||||
return dic
|
return dic
|
||||||
|
|
||||||
def get_state(self) -> dict:
|
def get_state(self) -> dict:
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
from ...io.bds_reader import BDSReader
|
from nmreval.io.bds_reader import BDSReader
|
||||||
|
from nmreval.gui_qt.Qt import QtCore, QtWidgets
|
||||||
from ..Qt import QtCore, QtWidgets
|
from nmreval.gui_qt._py.bdsdialog import Ui_Dialog
|
||||||
from .._py.bdsdialog import Ui_Dialog
|
|
||||||
|
|
||||||
|
|
||||||
class QBDSReader(QtWidgets.QDialog, Ui_Dialog):
|
class QBDSReader(QtWidgets.QDialog, Ui_Dialog):
|
||||||
@@ -11,22 +10,39 @@ class QBDSReader(QtWidgets.QDialog, Ui_Dialog):
|
|||||||
def __init__(self, fname: str = None, parent=None):
|
def __init__(self, fname: str = None, parent=None):
|
||||||
super().__init__(parent=parent)
|
super().__init__(parent=parent)
|
||||||
self.setupUi(self)
|
self.setupUi(self)
|
||||||
|
self.reader = None
|
||||||
|
self.fname = fname
|
||||||
|
|
||||||
if fname is not None:
|
if self.fname is not None:
|
||||||
self.reader = BDSReader(fname)
|
self.reader = BDSReader(fname)
|
||||||
self.setup_gui()
|
self.setup_gui()
|
||||||
|
|
||||||
def __call__(self, fname: str):
|
def __call__(self, fname: str):
|
||||||
self.reader = BDSReader(fname)
|
self.reader = BDSReader(fname)
|
||||||
|
self.fname = fname
|
||||||
self.setup_gui()
|
self.setup_gui()
|
||||||
|
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def setup_gui(self):
|
def setup_gui(self):
|
||||||
self.listWidget.clear()
|
self.listWidget.clear()
|
||||||
|
self.label.setText(f'Found entries for {self.reader.fname.name}')
|
||||||
|
|
||||||
for temp in self.reader.set_temp:
|
self.make_list(True)
|
||||||
item = QtWidgets.QListWidgetItem(str(temp))
|
|
||||||
|
@QtCore.pyqtSlot(QtWidgets.QAbstractButton, name='on_buttonGroup_buttonClicked')
|
||||||
|
def change_list(self, bttn: QtWidgets.QAbstractButton):
|
||||||
|
self.make_list(bttn == self.freq_button)
|
||||||
|
|
||||||
|
def make_list(self, use_freq: bool) -> None:
|
||||||
|
self.listWidget.clear()
|
||||||
|
if use_freq:
|
||||||
|
secondary = self.reader.set_temp
|
||||||
|
else:
|
||||||
|
secondary = self.reader.frequencies
|
||||||
|
|
||||||
|
for x2 in secondary:
|
||||||
|
item = QtWidgets.QListWidgetItem(f'{x2:.8g}')
|
||||||
item.setFlags(QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsUserCheckable | QtCore.Qt.ItemIsSelectable)
|
item.setFlags(QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsUserCheckable | QtCore.Qt.ItemIsSelectable)
|
||||||
item.setCheckState(QtCore.Qt.Checked)
|
item.setCheckState(QtCore.Qt.Checked)
|
||||||
self.listWidget.addItem(item)
|
self.listWidget.addItem(item)
|
||||||
@@ -34,19 +50,26 @@ class QBDSReader(QtWidgets.QDialog, Ui_Dialog):
|
|||||||
def accept(self):
|
def accept(self):
|
||||||
data = []
|
data = []
|
||||||
|
|
||||||
temps = []
|
x2 = []
|
||||||
for i in range(self.listWidget.count()):
|
for i in range(self.listWidget.count()):
|
||||||
item = self.listWidget.item(i)
|
item = self.listWidget.item(i)
|
||||||
if item.checkState() == QtCore.Qt.Checked:
|
if item.checkState() == QtCore.Qt.Checked:
|
||||||
temps.append(i)
|
x2.append(i)
|
||||||
|
|
||||||
for (mode, cb) in [('epsilon', self.eps_checkBox),
|
xmode = 'freq' if self.freq_button.isChecked() else 'temp'
|
||||||
('sigma', self.cond_checkBox),
|
|
||||||
('modulus', self.modul_checkBox)]:
|
|
||||||
|
|
||||||
|
for (mode, cb) in [
|
||||||
|
('epsilon', self.eps_checkBox),
|
||||||
|
('sigma', self.cond_checkBox),
|
||||||
|
('modulus', self.modul_checkBox),
|
||||||
|
('capacity', self.cap_checkBox),
|
||||||
|
('time', self.time_checkBox),
|
||||||
|
('sample_temp', self.temp_checkBox),
|
||||||
|
('loss_factor', self.loss_checkBox)
|
||||||
|
]:
|
||||||
if cb.checkState() == QtCore.Qt.Checked:
|
if cb.checkState() == QtCore.Qt.Checked:
|
||||||
values = self.reader.export(mode=mode)
|
values = self.reader.export(ymode=mode, xmode=xmode)
|
||||||
for t in temps:
|
for t in x2:
|
||||||
data.append(values[t])
|
data.append(values[t])
|
||||||
|
|
||||||
self.data_read.emit(data)
|
self.data_read.emit(data)
|
||||||
@@ -60,7 +83,8 @@ if __name__ == '__main__':
|
|||||||
app = QtWidgets.QApplication(sys.argv)
|
app = QtWidgets.QApplication(sys.argv)
|
||||||
|
|
||||||
reader = QBDSReader()
|
reader = QBDSReader()
|
||||||
reader('/autohome/dominik/nmreval/testdata/ZWEITECHANCE_EGD4H2O.EPS')
|
# reader('/autohome/dominik/nmreval/testdata/ZWEITECHANCE_EGD4H2O.EPS')
|
||||||
|
# reader('/autohome/dominik/nmreval/testdata/MZ-ME/CHLOROFORM_2017-02-06.EPS')
|
||||||
|
reader('/autohome/dominik/nmreval/testdata/SBA_5P4NM_ISOCHRON_150-300K_18-03-22.EPS')
|
||||||
reader.show()
|
reader.show()
|
||||||
sys.exit(app.exec())
|
sys.exit(app.exec())
|
||||||
|
|
||||||
|
|||||||
@@ -127,13 +127,13 @@ def pgitem_to_dic(item):
|
|||||||
item_dic['symbolcolor'] = Colors.Black
|
item_dic['symbolcolor'] = Colors.Black
|
||||||
else:
|
else:
|
||||||
item_dic['symbol'] = SymbolStyle.from_str(opts['symbol'])
|
item_dic['symbol'] = SymbolStyle.from_str(opts['symbol'])
|
||||||
item_dic['symbolcolor'] = Colors.from_rgb(*opts['symbolBrush'].color().getRgbF()[:3])
|
item_dic['symbolcolor'] = Colors.from_rgb(*opts['symbolBrush'].color().getRgbF()[:3], normed=True)
|
||||||
|
|
||||||
pen = opts['pen']
|
pen = opts['pen']
|
||||||
|
|
||||||
if pen is not None:
|
if pen is not None:
|
||||||
item_dic['linestyle'] = LineStyle(pen.style())
|
item_dic['linestyle'] = LineStyle(pen.style())
|
||||||
item_dic['linecolor'] = Colors.from_rgb(*pen.color().getRgbF()[:3])
|
item_dic['linecolor'] = Colors.from_rgb(*pen.color().getRgbF()[:3], normed=True)
|
||||||
item_dic['linewidth'] = pen.widthF()
|
item_dic['linewidth'] = pen.widthF()
|
||||||
else:
|
else:
|
||||||
item_dic['linestyle'] = LineStyle.No
|
item_dic['linestyle'] = LineStyle.No
|
||||||
|
|||||||
@@ -186,10 +186,7 @@ class SelectionWidget(QtWidgets.QWidget):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def value(self):
|
def value(self):
|
||||||
try:
|
return {self.argname: self.options[self.comboBox.currentText()]}
|
||||||
return float(self.options[str(self.comboBox.currentText())])
|
|
||||||
except ValueError:
|
|
||||||
return str(self.options[str(self.comboBox.currentText())])
|
|
||||||
|
|
||||||
def get_parameter(self):
|
def get_parameter(self):
|
||||||
return str(self.comboBox.currentText())
|
return str(self.comboBox.currentText())
|
||||||
|
|||||||
@@ -562,7 +562,7 @@ class NMRMainWindow(QtWidgets.QMainWindow, Ui_BaseWindow):
|
|||||||
|
|
||||||
self.management.skip_points(**dial.get_arguments())
|
self.management.skip_points(**dial.get_arguments())
|
||||||
|
|
||||||
@QtCore.pyqtSlot(str, name='on_action_coup_calc_triggered')
|
@QtCore.pyqtSlot(name='on_action_coup_calc_triggered')
|
||||||
def coupling_dialog(self):
|
def coupling_dialog(self):
|
||||||
dialog = QCoupCalcDialog(self)
|
dialog = QCoupCalcDialog(self)
|
||||||
dialog.show()
|
dialog.show()
|
||||||
|
|||||||
@@ -977,10 +977,10 @@ class UpperManagement(QtCore.QObject):
|
|||||||
sd.convert(_x, *sd_param, from_=opts['tau_type'], to_='raw')
|
sd.convert(_x, *sd_param, from_=opts['tau_type'], to_='raw')
|
||||||
|
|
||||||
relax = Relaxation()
|
relax = Relaxation()
|
||||||
relax.distribution(sd, parameter=sd_param, keywords=opts['sd_param'][1])
|
relax.set_distribution(sd, parameter=sd_param, keywords=opts['sd_param'][1])
|
||||||
|
|
||||||
cp_param = [self.data[p].y.real if isinstance(p, str) else p for p in opts['cp_param'][0]]
|
cp_param = [self.data[p].y.real if isinstance(p, str) else p for p in opts['cp_param'][0]]
|
||||||
relax.coupling(opts['coup'], parameter=cp_param, keywords=opts['cp_param'][1])
|
relax.set_coupling(opts['coup'], parameter=cp_param, keywords=opts['cp_param'][1])
|
||||||
|
|
||||||
if opts['out'] == 't1':
|
if opts['out'] == 't1':
|
||||||
y = relax.t1(x2, _x)
|
y = relax.t1(x2, _x)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
from ...nmr.couplings import *
|
from ...nmr.coupling import *
|
||||||
from ...utils.text import convert
|
from ...utils.text import convert
|
||||||
|
|
||||||
from ..Qt import QtWidgets, QtCore
|
from ..Qt import QtWidgets, QtCore
|
||||||
@@ -11,7 +11,7 @@ class QCoupCalcDialog(QtWidgets.QDialog, Ui_coupling_calc_dialog):
|
|||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
self.setupUi(self)
|
self.setupUi(self)
|
||||||
|
|
||||||
self.cp = [Quadrupolar, QuadrupolarQCC, Czjzek, HeteroDipolar, HomoDipolar]
|
self.cp = [Quadrupolar, Czjzek, HeteroDipolar, HomoDipolar]
|
||||||
for cp in self.cp:
|
for cp in self.cp:
|
||||||
self.comboBox.addItem(cp.name)
|
self.comboBox.addItem(cp.name)
|
||||||
|
|
||||||
@@ -62,7 +62,7 @@ class QCoupCalcDialog(QtWidgets.QDialog, Ui_coupling_calc_dialog):
|
|||||||
for pp in self._coupling_parameter:
|
for pp in self._coupling_parameter:
|
||||||
p.append(pp.value)
|
p.append(pp.value)
|
||||||
|
|
||||||
self.label.setText('Coupling constant: %.8g' % self.cp[self.comboBox.currentIndex()].func(*p))
|
self.label.setText('Coupling constant: %.8g' % self.cp[self.comboBox.currentIndex()].relax(*p))
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
from typing import List, Tuple
|
from typing import List, Tuple
|
||||||
|
|
||||||
from ...nmr.couplings import *
|
from ...nmr.coupling import *
|
||||||
from ...distributions import ColeCole, ColeDavidson, HavriliakNegami
|
from ...distributions import ColeCole, ColeDavidson, HavriliakNegami
|
||||||
from ...utils import pi
|
from ...utils import pi
|
||||||
from ...utils.text import convert
|
from ...utils.text import convert
|
||||||
@@ -20,7 +20,7 @@ class QRelaxCalc(QtWidgets.QDialog, Ui_Dialog):
|
|||||||
self.graphs = {}
|
self.graphs = {}
|
||||||
|
|
||||||
self.specdens = [ColeCole, ColeDavidson, HavriliakNegami]
|
self.specdens = [ColeCole, ColeDavidson, HavriliakNegami]
|
||||||
self.coupling = [Quadrupolar, QuadrupolarQCC, Czjzek, HomoDipolar]
|
self.coupling = [Quadrupolar, Czjzek, HomoDipolar]
|
||||||
self.tau_parameter = []
|
self.tau_parameter = []
|
||||||
|
|
||||||
for line_edit in [self.ea_lineEdit, self.tau0_lineEdit, self.start_lineEdit, self.stop_lineEdit,
|
for line_edit in [self.ea_lineEdit, self.tau0_lineEdit, self.start_lineEdit, self.stop_lineEdit,
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ from pyqtgraph import mkBrush, mkPen
|
|||||||
from ..lib.pg_objects import PlotItem
|
from ..lib.pg_objects import PlotItem
|
||||||
from ...data.points import Points
|
from ...data.points import Points
|
||||||
from ...nmr.relaxation import RelaxationEvaluation
|
from ...nmr.relaxation import RelaxationEvaluation
|
||||||
from ...nmr.couplings import *
|
from ...nmr.coupling import *
|
||||||
from ...distributions import *
|
from ...distributions import *
|
||||||
|
|
||||||
from ..Qt import QtCore, QtWidgets, QtGui
|
from ..Qt import QtCore, QtWidgets, QtGui
|
||||||
@@ -37,7 +37,7 @@ class QT1Widget(QtWidgets.QDialog, Ui_t1dialog):
|
|||||||
self.specdens_combobox.currentIndexChanged.connect(self.update_specdens)
|
self.specdens_combobox.currentIndexChanged.connect(self.update_specdens)
|
||||||
|
|
||||||
self.cp_parameter = []
|
self.cp_parameter = []
|
||||||
self.coupling = [Quadrupolar, QuadrupolarQCC, Czjzek, HomoDipolar, Constant]
|
self.coupling = [Quadrupolar, Czjzek, HomoDipolar, Constant]
|
||||||
for i in self.coupling:
|
for i in self.coupling:
|
||||||
self.coupling_combobox.addItem(i.name)
|
self.coupling_combobox.addItem(i.name)
|
||||||
self.coupling_combobox.currentIndexChanged.connect(self.update_coupling)
|
self.coupling_combobox.currentIndexChanged.connect(self.update_coupling)
|
||||||
@@ -116,7 +116,7 @@ class QT1Widget(QtWidgets.QDialog, Ui_t1dialog):
|
|||||||
self.verticalLayout_3.addWidget(_temp)
|
self.verticalLayout_3.addWidget(_temp)
|
||||||
self.sd_parameter.append(_temp)
|
self.sd_parameter.append(_temp)
|
||||||
|
|
||||||
self.t1calculator.distribution(self.sdmodels[idx])
|
self.t1calculator.set_distribution(self.sdmodels[idx])
|
||||||
self.update_model()
|
self.update_model()
|
||||||
|
|
||||||
@QtCore.pyqtSlot()
|
@QtCore.pyqtSlot()
|
||||||
@@ -159,6 +159,7 @@ class QT1Widget(QtWidgets.QDialog, Ui_t1dialog):
|
|||||||
_temp.valueChanged.connect(self.update_coupling_parameter)
|
_temp.valueChanged.connect(self.update_coupling_parameter)
|
||||||
_temp.stateChanged.connect(self.update_coupling_parameter)
|
_temp.stateChanged.connect(self.update_coupling_parameter)
|
||||||
self.cp_parameter.append(_temp)
|
self.cp_parameter.append(_temp)
|
||||||
|
print(self.cp_parameter)
|
||||||
|
|
||||||
if self.coupling[idx].choice is not None:
|
if self.coupling[idx].choice is not None:
|
||||||
for (name, kw_name, opts) in self.coupling[idx].choice:
|
for (name, kw_name, opts) in self.coupling[idx].choice:
|
||||||
@@ -172,10 +173,14 @@ class QT1Widget(QtWidgets.QDialog, Ui_t1dialog):
|
|||||||
@QtCore.pyqtSlot()
|
@QtCore.pyqtSlot()
|
||||||
def update_coupling_parameter(self):
|
def update_coupling_parameter(self):
|
||||||
new_p = []
|
new_p = []
|
||||||
|
new_kw = {}
|
||||||
for pp in self.cp_parameter:
|
for pp in self.cp_parameter:
|
||||||
new_p.append(pp.value)
|
if isinstance(pp, FormWidget):
|
||||||
|
new_p.append(pp.value)
|
||||||
|
else:
|
||||||
|
new_kw.update(pp.value)
|
||||||
new_coupling = self.coupling[self.coupling_combobox.currentIndex()]
|
new_coupling = self.coupling[self.coupling_combobox.currentIndex()]
|
||||||
self.t1calculator.coupling(new_coupling)
|
self.t1calculator.set_coupling(new_coupling, parameter=new_p, keywords=new_kw)
|
||||||
|
|
||||||
self.update_model()
|
self.update_model()
|
||||||
|
|
||||||
@@ -253,30 +258,33 @@ class QT1Widget(QtWidgets.QDialog, Ui_t1dialog):
|
|||||||
'Only one can be determined from a minimum.')
|
'Only one can be determined from a minimum.')
|
||||||
return
|
return
|
||||||
|
|
||||||
notfix = ()
|
notfix = None
|
||||||
|
var_idx = 0
|
||||||
if not all(sd_fix):
|
if not all(sd_fix):
|
||||||
notfix = ('distribution', sd_fix.index(False))
|
notfix = 'distribution'
|
||||||
|
var_idx = sd_fix.index(False)
|
||||||
|
|
||||||
if not all(cp_fix):
|
if not all(cp_fix):
|
||||||
notfix = ('coupling', cp_fix.index(False))
|
notfix = 'coupling'
|
||||||
|
var_idx = cp_fix.index(False)
|
||||||
|
|
||||||
if not np.isfinite(self.t1calculator.t1min[1]):
|
if not np.isfinite(self.t1calculator.t1min[1]):
|
||||||
return
|
return
|
||||||
|
|
||||||
mini = np.nan
|
|
||||||
with busy_cursor():
|
with busy_cursor():
|
||||||
calc_stretching, mini = self.t1calculator.increase(notfix, height=self.minimum[1],
|
calc_stretching, mini = self.t1calculator.get_increase(height=self.minimum[1],
|
||||||
omega=2*np.pi*self.frequency,
|
idx=var_idx, mode=notfix,
|
||||||
dist_parameter=sd_args, prefactor=cp_args,
|
omega=2*np.pi*self.frequency,
|
||||||
coupling_kwargs=cp_kwargs)
|
dist_parameter=sd_args, prefactor=cp_args,
|
||||||
|
coupling_kwargs=cp_kwargs)
|
||||||
|
|
||||||
self.label_t1min.setText(f'{mini:.4g} s')
|
self.label_t1min.setText(f'{mini:.4g} s')
|
||||||
|
|
||||||
if notfix:
|
if notfix:
|
||||||
forms = self.sd_parameter if notfix[0] == 'distribution' else self.cp_parameter
|
forms = self.sd_parameter if notfix == 'distribution' else self.cp_parameter
|
||||||
forms[notfix[1]].blockSignals(True)
|
forms[var_idx].blockSignals(True)
|
||||||
forms[notfix[1]].value = f'{calc_stretching:.4g}'
|
forms[var_idx].value = f'{calc_stretching:.4g}'
|
||||||
forms[notfix[1]].blockSignals(False)
|
forms[var_idx].blockSignals(False)
|
||||||
|
|
||||||
@QtCore.pyqtSlot(name='on_calc_pushButton_clicked')
|
@QtCore.pyqtSlot(name='on_calc_pushButton_clicked')
|
||||||
def calculate_correlations(self):
|
def calculate_correlations(self):
|
||||||
@@ -317,7 +325,7 @@ class QT1Widget(QtWidgets.QDialog, Ui_t1dialog):
|
|||||||
cp_args.append(p.value)
|
cp_args.append(p.value)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
# SelectionWidget has no isChecked()
|
# SelectionWidget has no isChecked()
|
||||||
cp_kwargs[p.argname] = p.value
|
cp_kwargs.update(p.value)
|
||||||
|
|
||||||
return cp_args, cp_kwargs, cp_fix
|
return cp_args, cp_kwargs, cp_fix
|
||||||
|
|
||||||
|
|||||||
+85
-66
@@ -2,10 +2,11 @@ import re
|
|||||||
import struct
|
import struct
|
||||||
import warnings
|
import warnings
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from typing import List
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
from ..data.signals import Signal
|
from ..data import BDS, Points
|
||||||
|
|
||||||
MAGIC_RE = re.compile(b'NOVOCONTROL DK-RESULTS')
|
MAGIC_RE = re.compile(b'NOVOCONTROL DK-RESULTS')
|
||||||
|
|
||||||
@@ -27,6 +28,9 @@ class BDSReader:
|
|||||||
|
|
||||||
return self
|
return self
|
||||||
|
|
||||||
|
def __getitem__(self, val):
|
||||||
|
return self.opts[val]
|
||||||
|
|
||||||
def _parse_file(self):
|
def _parse_file(self):
|
||||||
self.opts = {}
|
self.opts = {}
|
||||||
with self.fname.open(mode='rb') as f:
|
with self.fname.open(mode='rb') as f:
|
||||||
@@ -43,7 +47,7 @@ class BDSReader:
|
|||||||
f.seek(1, 1)
|
f.seek(1, 1)
|
||||||
self.opts['electrode thickness'] = struct.unpack('f', f.read(4))[0]
|
self.opts['electrode thickness'] = struct.unpack('f', f.read(4))[0]
|
||||||
|
|
||||||
self.opts['parameter'] += struct.unpack('3f', f.read(12))
|
self.opts['parameter'] += struct.unpack('3f', f.read(12)) # 1, 0.05, 0.06, 0.02
|
||||||
|
|
||||||
f.seek(2, 1)
|
f.seek(2, 1)
|
||||||
self.opts['capacity'] = struct.unpack('f', f.read(4))[0]
|
self.opts['capacity'] = struct.unpack('f', f.read(4))[0]
|
||||||
@@ -56,43 +60,51 @@ class BDSReader:
|
|||||||
self.opts['C_0'] = (self.opts['area']-self.opts['spacer area']) / self.opts['thickness'] * 8.8541878128e-12
|
self.opts['C_0'] = (self.opts['area']-self.opts['spacer area']) / self.opts['thickness'] * 8.8541878128e-12
|
||||||
|
|
||||||
f.seek(158)
|
f.seek(158)
|
||||||
name_length = struct.unpack('b', f.read(1))[0]
|
name_length = struct.unpack('i', f.read(4))[0]
|
||||||
|
|
||||||
f.seek(164)
|
f.seek(2, 1)
|
||||||
b = f.read(name_length)
|
b = f.read(name_length)
|
||||||
self.opts['name'] = str(struct.unpack(f'<{name_length}s', b)[0][:-1], encoding='utf-8')
|
self.opts['name'] = str(struct.unpack(f'<{name_length}s', b)[0][:-1], encoding='utf-8')
|
||||||
|
|
||||||
_ = struct.unpack('h', f.read(2))
|
_ = struct.unpack('h', f.read(2))
|
||||||
freq_values_length = struct.unpack('b', f.read(1))[0]
|
freq_values_length = struct.unpack('i', f.read(4))[0]
|
||||||
|
|
||||||
f.seek(7, 1)
|
f.seek(4, 1)
|
||||||
self.x = np.empty(freq_values_length)
|
self.x = np.empty(freq_values_length)
|
||||||
for freqs in range(freq_values_length):
|
for freqs in range(freq_values_length):
|
||||||
self.x[freqs] = struct.unpack('f', f.read(4))[0]
|
(self.x[freqs],) = struct.unpack('f', f.read(4))
|
||||||
|
|
||||||
_ = struct.unpack('h', f.read(2))
|
_ = struct.unpack('h', f.read(2)) # TODO if no temperature set this is not 400 and rest breaks
|
||||||
length_temps = struct.unpack('b', f.read(1))[0]
|
length_temps = struct.unpack('i', f.read(4))[0]
|
||||||
|
|
||||||
f.seek(7, 1)
|
f.seek(4, 1)
|
||||||
self.opts['temperatures'] = np.array(struct.unpack('f' * length_temps, f.read(4*length_temps)))
|
self.opts['temperatures'] = np.array(struct.unpack('f' * length_temps, f.read(4*length_temps)))
|
||||||
|
|
||||||
f.seek(110, 1)
|
f.seek(110, 1)
|
||||||
date_length = (struct.unpack('b', f.read(1)))[0]
|
date_length = (struct.unpack('i', f.read(4)))[0]
|
||||||
|
|
||||||
f.seek(5, 1)
|
f.seek(2, 1)
|
||||||
self.opts['date'] = str(struct.unpack(f'<{date_length}s', f.read(date_length))[0][:-1],
|
self.opts['date'] = str(struct.unpack(f'<{date_length}s', f.read(date_length))[0][:-1],
|
||||||
encoding='utf-8')
|
encoding='utf-8')
|
||||||
|
|
||||||
f.seek(47, 1)
|
f.seek(47, 1)
|
||||||
# there are 9 different values per frequency and temperature
|
|
||||||
|
|
||||||
_y = []
|
_y = []
|
||||||
actual_temps_length = 0
|
actual_temps_length = 0
|
||||||
read_length = 9 * freq_values_length
|
read_length = 9 * freq_values_length # per entry 9 * 4 byte
|
||||||
while True:
|
while True:
|
||||||
|
# catch error if measurement was aborted
|
||||||
try:
|
try:
|
||||||
_y += struct.unpack('f' * read_length, f.read(4*read_length))
|
y_i = struct.unpack('f' * read_length, f.read(4*read_length))
|
||||||
|
if any([y_ii != 0.0 for y_ii in y_i[-3:]]):
|
||||||
|
# the last three should be zero
|
||||||
|
break
|
||||||
|
|
||||||
|
_y += y_i
|
||||||
actual_temps_length += 1
|
actual_temps_length += 1
|
||||||
|
if actual_temps_length == length_temps:
|
||||||
|
break
|
||||||
|
|
||||||
except struct.error:
|
except struct.error:
|
||||||
break
|
break
|
||||||
|
|
||||||
@@ -100,79 +112,86 @@ class BDSReader:
|
|||||||
warnings.warn('Number of set temperatures does not match number of data points')
|
warnings.warn('Number of set temperatures does not match number of data points')
|
||||||
|
|
||||||
_y = np.array(_y).reshape((actual_temps_length, freq_values_length, 9))
|
_y = np.array(_y).reshape((actual_temps_length, freq_values_length, 9))
|
||||||
|
print(_y.shape)
|
||||||
|
print(f.tell())
|
||||||
# last 3 entries are zero, save only 6
|
# last 3 entries are zero, save only 6
|
||||||
|
# Z.imag*omega), Z.real, meas.time, meas. temp., ac voltage, dc voltage
|
||||||
self.y = np.transpose(_y[:, :, :6], (2, 0, 1))
|
self.y = np.transpose(_y[:, :, :6], (2, 0, 1))
|
||||||
|
|
||||||
def export(self, mode='epsilon') -> list:
|
def export(self, ymode: str = 'epsilon', xmode: str = 'freq') -> List[BDS]:
|
||||||
if mode == 'epsilon':
|
y = getattr(self, ymode)()
|
||||||
eps = self.epsilon()
|
|
||||||
elif mode == 'sigma':
|
|
||||||
eps = self.sigma()
|
|
||||||
elif mode == 'modulus':
|
|
||||||
eps = self.modulus()
|
|
||||||
else:
|
|
||||||
raise ValueError(f'Unknown mode {mode}, not "epsilon", "sigma", or "modulus".')
|
|
||||||
|
|
||||||
ret_val = []
|
|
||||||
|
|
||||||
useful_info = {
|
useful_info = {
|
||||||
'voltage': self.opts['voltage'],
|
'voltage': self.opts['voltage'],
|
||||||
'diameter': self.opts['diameter'],
|
'diameter': self.opts['diameter'],
|
||||||
'area': self.opts['area'],
|
'area': self.opts['area'],
|
||||||
'thickness': self.opts['thickness'],
|
'thickness': self.opts['thickness'],
|
||||||
'mode': mode
|
'mode': ymode
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, temps in enumerate(self.temperature):
|
if xmode == 'freq':
|
||||||
ret_val.append(Signal(x=self.frequencies, y=eps[0][i, :] + 1j*eps[1][i, :],
|
fmt = '.2f'
|
||||||
name=f'{temps:.2f}', value=temps, **useful_info))
|
x2 = self.temperature
|
||||||
|
x = self.frequencies
|
||||||
|
|
||||||
|
elif xmode == 'temp':
|
||||||
|
fmt = '.2f'
|
||||||
|
x2 = self.frequencies
|
||||||
|
x = self.temperature
|
||||||
|
y = y.T
|
||||||
|
|
||||||
|
else:
|
||||||
|
raise ValueError(f'Unknown mode {xmode!r}, use `freq` or `temp`.')
|
||||||
|
|
||||||
|
ret_val = []
|
||||||
|
for i, label in enumerate(x2):
|
||||||
|
y_i = y[i]
|
||||||
|
if np.allclose(y_i.imag, 0):
|
||||||
|
ret_val.append(Points(x=x, y=y_i,
|
||||||
|
name=f'{label:{fmt}}', value=label, **useful_info))
|
||||||
|
else:
|
||||||
|
ret_val.append(BDS(x=x, y=y_i,
|
||||||
|
name=f'{label:{fmt}}', value=label, **useful_info))
|
||||||
|
|
||||||
return ret_val
|
return ret_val
|
||||||
|
|
||||||
def __getitem__(self, val):
|
def capacity(self):
|
||||||
return self.opts[val]
|
# NOTE: nobody ever used edge correction, so we ignore this option entirely
|
||||||
|
return self.y[0] - self.opts['capacity'] - 1j / self.y[1] / (self.frequencies*2*np.pi)
|
||||||
|
|
||||||
|
def sample_temp(self):
|
||||||
|
return self.y[2]
|
||||||
|
|
||||||
|
def time(self):
|
||||||
|
return self.y[3]
|
||||||
|
|
||||||
|
def sigma(self):
|
||||||
|
# sigma^* = i * omega * eps_0 * (eps^* - 1)
|
||||||
|
conv = 0.01 * 8.8541878128e-12 * 2*np.pi*self.x # factor 0.01: sigma in S/cm
|
||||||
|
return conv * (self.epsilon() - 1)
|
||||||
|
|
||||||
|
def epsilon(self):
|
||||||
|
# eps^* = Cp^* d/A/eps_0
|
||||||
|
c = self.capacity()
|
||||||
|
return (c.real - 1j * c.imag) / self.opts['C_0']
|
||||||
|
|
||||||
|
def modulus(self):
|
||||||
|
# M^* = 1/eps^*
|
||||||
|
return np.conjugate(1/self.epsilon())
|
||||||
|
|
||||||
|
def loss_factor(self):
|
||||||
|
eps = self.epsilon()
|
||||||
|
|
||||||
|
return eps.imag / eps.real
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def set_temp(self):
|
def set_temp(self):
|
||||||
return self.opts['temperatures'][:len(self.temperature)]
|
return self.opts['temperatures'][:len(self.temperature)]
|
||||||
|
|
||||||
@property
|
|
||||||
def probe_temp(self):
|
|
||||||
return self.y[2]
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def temperature(self):
|
def temperature(self):
|
||||||
return self.probe_temp.mean(axis=1)
|
return self.sample_temp().mean(axis=1)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def frequencies(self):
|
def frequencies(self):
|
||||||
return self.x
|
return self.x
|
||||||
|
|
||||||
def capacity(self):
|
|
||||||
# NOTE: nobody ever used edge correction, so we ignore this option entirely
|
|
||||||
return self.y[0] - self.opts['capacity'], -1./self.y[1] / (self.frequencies*2*np.pi)
|
|
||||||
|
|
||||||
def voltage(self):
|
|
||||||
return self.y[5]
|
|
||||||
|
|
||||||
def sigma(self):
|
|
||||||
# sigma^* = i * omega * eps_0 * (eps^* - 1)
|
|
||||||
eps_r, eps_i = self.epsilon()
|
|
||||||
conv = 0.01 * 8.8541878128e-12 * 2*np.pi*self.x # factor 0.01: sigma in S/cm
|
|
||||||
return conv * eps_i, conv * (eps_r-1)
|
|
||||||
|
|
||||||
def epsilon(self):
|
|
||||||
# eps^* = Cp^* d/A/eps_0
|
|
||||||
cr, ci = self.capacity()
|
|
||||||
return cr / self.opts['C_0'], -ci / self.opts['C_0']
|
|
||||||
|
|
||||||
def modulus(self):
|
|
||||||
# M^* = 1/eps^*
|
|
||||||
eps_r, eps_i = self.epsilon()
|
|
||||||
magn = eps_r ** 2 + eps_i ** 2
|
|
||||||
return eps_r / magn, eps_i / magn
|
|
||||||
|
|
||||||
def loss_factor(self):
|
|
||||||
eps_r, eps_i = self.epsilon()
|
|
||||||
|
|
||||||
return eps_i / eps_r, None
|
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
from functools import wraps
|
||||||
|
from typing import Callable
|
||||||
|
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
|
||||||
|
def adjust_dims(func) -> Callable:
|
||||||
|
|
||||||
|
@wraps(func)
|
||||||
|
def wrapper(*args, **kwargs):
|
||||||
|
"""
|
||||||
|
ALlow outer product for omega*tau and remove redundant dimension afterwards
|
||||||
|
"""
|
||||||
|
x1, x2, *rest = args
|
||||||
|
|
||||||
|
x1 = np.asanyarray(x1)
|
||||||
|
x2 = np.asanyarray(x2)
|
||||||
|
|
||||||
|
if len(x1.shape) > 1 or len(x2.shape) > 1:
|
||||||
|
raise ValueError('Only numbers or 1d-arrays are supported')
|
||||||
|
|
||||||
|
result = func(x1[..., None], x2[None, ...], *rest, **kwargs)
|
||||||
|
if result.ndim == 1:
|
||||||
|
return result[0]
|
||||||
|
else:
|
||||||
|
return result.squeeze()
|
||||||
|
|
||||||
|
return wrapper
|
||||||
|
#
|
||||||
|
# return func
|
||||||
@@ -3,7 +3,6 @@ from typing import TypeVar
|
|||||||
from ..math.mittagleffler import mlf
|
from ..math.mittagleffler import mlf
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
ArrayLike = TypeVar('ArrayLike')
|
ArrayLike = TypeVar('ArrayLike')
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+17
-19
@@ -19,7 +19,8 @@ def _kww_low(w, beta, kappa):
|
|||||||
|
|
||||||
ln_w = np.log(w[:, np.newaxis])
|
ln_w = np.log(w[:, np.newaxis])
|
||||||
ln_a_k = scipy.special.gammaln((k+1) / beta) - scipy.special.gammaln(k+1) + k*ln_w
|
ln_a_k = scipy.special.gammaln((k+1) / beta) - scipy.special.gammaln(k+1) + k*ln_w
|
||||||
a_k = np.exp(ln_a_k)
|
with np.errstate(over='ignore'):
|
||||||
|
a_k = np.exp(ln_a_k)
|
||||||
|
|
||||||
y_n = (sign * a_k).cumsum(axis=1)
|
y_n = (sign * a_k).cumsum(axis=1)
|
||||||
y_n = np.nan_to_num(y_n)
|
y_n = np.nan_to_num(y_n)
|
||||||
@@ -45,7 +46,7 @@ def kwws_low(w, beta):
|
|||||||
|
|
||||||
def _kww_high(w, beta, kappa):
|
def _kww_high(w, beta, kappa):
|
||||||
if beta < 0.1 or beta > 2.0:
|
if beta < 0.1 or beta > 2.0:
|
||||||
raise ValueError("invalid call to kww_hig: beta out of range")
|
raise ValueError("invalid call to kww_high: beta out of range")
|
||||||
|
|
||||||
ln_omega = np.log(w[:, np.newaxis])
|
ln_omega = np.log(w[:, np.newaxis])
|
||||||
k = np.atleast_2d(np.arange(kappa, __max_terms+kappa))
|
k = np.atleast_2d(np.arange(kappa, __max_terms+kappa))
|
||||||
@@ -89,7 +90,7 @@ def kwwc_high(w, beta):
|
|||||||
def _kww_mid(w, beta, kappa):
|
def _kww_mid(w, beta, kappa):
|
||||||
if beta < 0.1 or beta > 2.0:
|
if beta < 0.1 or beta > 2.0:
|
||||||
raise ValueError("invalid call to kww_mid: beta out of range")
|
raise ValueError("invalid call to kww_mid: beta out of range")
|
||||||
elif any(w < 0):
|
elif np.any(w < 0):
|
||||||
raise ValueError("invalid call to kww_mid: w out of range")
|
raise ValueError("invalid call to kww_mid: w out of range")
|
||||||
|
|
||||||
if kappa and beta == 2:
|
if kappa and beta == 2:
|
||||||
@@ -203,19 +204,19 @@ def _kwws_lim_hig(b):
|
|||||||
|
|
||||||
|
|
||||||
def kww_cos(w, tau, beta):
|
def kww_cos(w, tau, beta):
|
||||||
r"""
|
"""
|
||||||
Calculate \int_0^\infty dt cos(w*t) exp(-(t/tau)^beta)
|
|
||||||
:param w: array-like
|
Args:
|
||||||
:param tau: float
|
w:
|
||||||
:param beta: float; 0.1 < beta <= 2
|
tau:
|
||||||
:return: array (w.shape)
|
beta:
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
|
||||||
"""
|
"""
|
||||||
# check input data
|
# check input data
|
||||||
if beta < 0.1:
|
if not (0.1 <= beta <= 2.):
|
||||||
raise ValueError("kww: beta smaller than 0.1")
|
raise ValueError('KWW beta is not inside range 0.1-2')
|
||||||
|
|
||||||
if beta > 2.0:
|
|
||||||
raise ValueError("kww: beta larger than 2.0")
|
|
||||||
|
|
||||||
if beta == 1:
|
if beta == 1:
|
||||||
return tau/(1 + (w*tau)**2)
|
return tau/(1 + (w*tau)**2)
|
||||||
@@ -246,11 +247,8 @@ def kww_cos(w, tau, beta):
|
|||||||
# \int_0^\infty dt sin(w*t) exp(-(t/tau)^beta)
|
# \int_0^\infty dt sin(w*t) exp(-(t/tau)^beta)
|
||||||
def kww_sin(w, tau, beta):
|
def kww_sin(w, tau, beta):
|
||||||
# check input data
|
# check input data
|
||||||
if beta < 0.1:
|
if not (0.1 <= beta <= 2.):
|
||||||
raise ValueError("kww: beta smaller than 0.1")
|
raise ValueError('KWW beta is not inside range 0.1-2')
|
||||||
|
|
||||||
if beta > 2.0:
|
|
||||||
raise ValueError("kww: beta larger than 2.0")
|
|
||||||
|
|
||||||
if beta == 1:
|
if beta == 1:
|
||||||
return w*tau**2/(1+(w*tau)**2)
|
return w*tau**2/(1+(w*tau)**2)
|
||||||
|
|||||||
@@ -1,10 +1,13 @@
|
|||||||
from numbers import Number
|
from numbers import Number
|
||||||
|
from typing import TypeVar, Union
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from math import sqrt, log, exp, ceil
|
from math import sqrt, log, exp, ceil
|
||||||
|
|
||||||
from scipy.special import gamma
|
from scipy.special import gamma
|
||||||
|
|
||||||
|
T = TypeVar('T')
|
||||||
|
|
||||||
__all__ = ['mlf']
|
__all__ = ['mlf']
|
||||||
|
|
||||||
# calculate Mittag-Leffler based on MATLAB code
|
# calculate Mittag-Leffler based on MATLAB code
|
||||||
@@ -13,7 +16,7 @@ __all__ = ['mlf']
|
|||||||
# SIAM Journal of Numerical Analysis, 2015, 53(3), 1350-1369
|
# SIAM Journal of Numerical Analysis, 2015, 53(3), 1350-1369
|
||||||
|
|
||||||
|
|
||||||
def mlf(z, a: float, b: float = 1, g: float = 1):
|
def mlf(z: T, a: float, b: float = 1, g: float = 1) -> T:
|
||||||
if b == 1 and gamma == 1:
|
if b == 1 and gamma == 1:
|
||||||
if a == 0:
|
if a == 0:
|
||||||
return 1 / (1 - z)
|
return 1 / (1 - z)
|
||||||
@@ -27,15 +30,16 @@ def mlf(z, a: float, b: float = 1, g: float = 1):
|
|||||||
|
|
||||||
if isinstance(z, Number):
|
if isinstance(z, Number):
|
||||||
return _mlf_single(z, a, b, g)
|
return _mlf_single(z, a, b, g)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
ret_val = np.zeros_like(z)
|
ret_val = np.zeros(z.size)
|
||||||
for i, zz in enumerate(z):
|
for i, zz in enumerate(z.ravel()):
|
||||||
ret_val[i] = _mlf_single(zz, a, b, g)
|
ret_val[i] = _mlf_single(zz, a, b, g)
|
||||||
|
|
||||||
return ret_val
|
return ret_val.reshape(z.shape)
|
||||||
|
|
||||||
|
|
||||||
def _mlf_single(z, a, b, g):
|
def _mlf_single(z: Union[int, float, complex], a: float, b: float, g: float):
|
||||||
if abs(z) < 1.0e-15:
|
if abs(z) < 1.0e-15:
|
||||||
ret_val = 1 / gamma(b)
|
ret_val = 1 / gamma(b)
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -1,3 +1,26 @@
|
|||||||
|
"""
|
||||||
|
=============
|
||||||
|
Fit functions
|
||||||
|
=============
|
||||||
|
|
||||||
|
.. currentmodule:: nmreval.models
|
||||||
|
|
||||||
|
.. autosummary::
|
||||||
|
:toctree: generated
|
||||||
|
:nosignatures:
|
||||||
|
:template: autosummary/class_with_attributes.rst
|
||||||
|
|
||||||
|
Constant
|
||||||
|
Linear
|
||||||
|
Parabola
|
||||||
|
PowerLaw
|
||||||
|
PowerLawCross
|
||||||
|
ExpFunc
|
||||||
|
MittagLeffler
|
||||||
|
Log
|
||||||
|
Sine
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
from .basic import *
|
from .basic import *
|
||||||
from .relaxation import *
|
from .relaxation import *
|
||||||
|
|||||||
+35
-21
@@ -1,42 +1,44 @@
|
|||||||
|
"""
|
||||||
|
***************
|
||||||
|
Basic functions
|
||||||
|
***************
|
||||||
|
|
||||||
|
Simple basic functions
|
||||||
|
"""
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
|
from ..lib.utils import ArrayLike
|
||||||
from ..math.mittagleffler import mlf
|
from ..math.mittagleffler import mlf
|
||||||
|
|
||||||
|
|
||||||
class Constant:
|
class Constant:
|
||||||
"""
|
"""
|
||||||
Constant
|
A boring constant line.
|
||||||
|
|
||||||
.. math::
|
|
||||||
y = c\cdot x
|
|
||||||
|
|
||||||
Args:
|
|
||||||
x (array_like): Input values
|
|
||||||
c (float): constant
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
type = 'Basic'
|
type = 'Basic'
|
||||||
name = 'Constant'
|
name = 'Constant'
|
||||||
equation = 'C'
|
equation = 'C'
|
||||||
params = ['C']
|
params = ['C']
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def func(x, c: float):
|
def func(x: ArrayLike, c: float) -> ArrayLike:
|
||||||
|
"""
|
||||||
|
Constant
|
||||||
|
|
||||||
|
.. math::
|
||||||
|
y = c \cdot x
|
||||||
|
|
||||||
|
Args:
|
||||||
|
x (array-like): Input values
|
||||||
|
c (float): constant
|
||||||
|
"""
|
||||||
return c*np.ones(len(x))
|
return c*np.ones(len(x))
|
||||||
|
|
||||||
|
|
||||||
class Linear:
|
class Linear:
|
||||||
"""
|
"""
|
||||||
Straight line.
|
Slightly more exciting line
|
||||||
|
|
||||||
.. math::
|
|
||||||
y = m\cdot x + t
|
|
||||||
|
|
||||||
Args:
|
|
||||||
x (array_like): Input values
|
|
||||||
m (float): Slope
|
|
||||||
t (float): Intercept
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
type = 'Basic'
|
type = 'Basic'
|
||||||
name = 'Straight line'
|
name = 'Straight line'
|
||||||
@@ -44,7 +46,19 @@ class Linear:
|
|||||||
params = ['m', 't']
|
params = ['m', 't']
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def func(x, m: float, t: float):
|
def func(x: ArrayLike, m: float, t: float) -> ArrayLike:
|
||||||
|
"""
|
||||||
|
Straight line.
|
||||||
|
|
||||||
|
.. math::
|
||||||
|
y = m\cdot x + t
|
||||||
|
|
||||||
|
Args:
|
||||||
|
x (array_like): Input values
|
||||||
|
m (float): Slope
|
||||||
|
t (float): Intercept
|
||||||
|
|
||||||
|
"""
|
||||||
return m*x + t
|
return m*x + t
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
import numpy as np
|
import numpy as np
|
||||||
from numpy import trapz
|
try:
|
||||||
|
from scipy.integrate import simpson
|
||||||
|
except ImportError:
|
||||||
|
from scipy.integrate import simps as simpson
|
||||||
|
from numpy import pi
|
||||||
|
|
||||||
from ..math.orientations import zcw_spherical as crystallites
|
from ..math.orientations import zcw_spherical as crystallites
|
||||||
|
|
||||||
@@ -29,21 +33,22 @@ class Pake:
|
|||||||
_x -= 0.5*_x[-1]
|
_x -= 0.5*_x[-1]
|
||||||
|
|
||||||
if broad == 'l':
|
if broad == 'l':
|
||||||
apd = 2 * sigma / (4 * _x**2 + sigma**2) / np.pi
|
apd = 2 * sigma / (4 * _x**2 + sigma**2) / pi
|
||||||
else:
|
else:
|
||||||
apd = np.exp(-4 * np.log(2) * (_x/sigma)**2) * 2 * np.sqrt(np.log(2) / np.pi) / sigma
|
apd = np.exp(-4 * np.log(2) * (_x/sigma)**2) * 2 * np.sqrt(np.log(2) / pi) / sigma
|
||||||
|
|
||||||
ret_val = np.convolve(s, apd, mode='same')
|
ret_val = np.convolve(s, apd, mode='same')
|
||||||
|
|
||||||
else:
|
else:
|
||||||
ret_val = s
|
ret_val = s
|
||||||
|
|
||||||
omega_1 = np.pi/2/t_pulse
|
omega_1 = pi/2/t_pulse
|
||||||
attn = omega_1 * np.sin(t_pulse*np.sqrt(omega_1**2+0.5*(2*np.pi*x)**2)) / np.sqrt(omega_1**2+(np.pi*x)**2)
|
attn = omega_1 * np.sin(t_pulse*np.sqrt(omega_1**2+0.5*(2*pi*x)**2)) / \
|
||||||
|
np.sqrt(omega_1**2+(np.pi*x)**2)
|
||||||
|
|
||||||
ret_val *= attn
|
ret_val *= attn
|
||||||
|
|
||||||
return c * ret_val / trapz(ret_val, x)
|
return c * ret_val / simpson(ret_val, x)
|
||||||
|
|
||||||
|
|
||||||
class CSA:
|
class CSA:
|
||||||
@@ -69,14 +74,14 @@ class CSA:
|
|||||||
_x = np.arange(len(x)) * (x[1] - x[0])
|
_x = np.arange(len(x)) * (x[1] - x[0])
|
||||||
_x -= 0.5 * _x[-1]
|
_x -= 0.5 * _x[-1]
|
||||||
if broad == 'l':
|
if broad == 'l':
|
||||||
apd = 2 * sigma / (4*_x**2 + sigma**2) / np.pi
|
apd = 2 * sigma / (4*_x**2 + sigma**2) / pi
|
||||||
else:
|
else:
|
||||||
apd = np.exp(-4 * np.log(2) * (_x / sigma) ** 2) * 2 * np.sqrt(np.log(2) / np.pi) / sigma
|
apd = np.exp(-4 * np.log(2) * (_x / sigma) ** 2) * 2 * np.sqrt(np.log(2) / pi) / sigma
|
||||||
ret_val = np.convolve(s, apd, mode='same')
|
ret_val = np.convolve(s, apd, mode='same')
|
||||||
else:
|
else:
|
||||||
ret_val = s
|
ret_val = s
|
||||||
|
|
||||||
return c * ret_val / trapz(ret_val, x)
|
return c * ret_val / simpson(ret_val, x)
|
||||||
|
|
||||||
|
|
||||||
class SecCentralLine:
|
class SecCentralLine:
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
"""
|
||||||
|
=========================================
|
||||||
|
NMR specific methods (:mod:`nmreval.nmr`)
|
||||||
|
=========================================
|
||||||
|
|
||||||
|
Each class provides a distribution of correlation times, correlation
|
||||||
|
function, spectral density, susceptibility, and calculation of different
|
||||||
|
types of correlation times.
|
||||||
|
|
||||||
|
.. currentmodule:: nmreval.nmr
|
||||||
|
|
||||||
|
Relaxation
|
||||||
|
**********
|
||||||
|
|
||||||
|
Calculate spin-lattice and spin-spin relaxation, and evaluate T1 minima for correlation times.
|
||||||
|
|
||||||
|
.. autosummary::
|
||||||
|
:toctree: generated/
|
||||||
|
:nosignatures:
|
||||||
|
|
||||||
|
Relaxation
|
||||||
|
RelaxationEvaluation
|
||||||
|
|
||||||
|
Coupling constants (:mod:`nmreval.nmr.coupling`)
|
||||||
|
************************************************
|
||||||
|
|
||||||
|
.. autosummary::
|
||||||
|
:toctree: generated/
|
||||||
|
:template: autosummary/class_with_attributes.rst
|
||||||
|
:nosignatures:
|
||||||
|
|
||||||
|
~coupling.Quadrupolar
|
||||||
|
~coupling.HeteroDipolar
|
||||||
|
~coupling.HomoDipolar
|
||||||
|
~coupling.CSA
|
||||||
|
~coupling.Constant
|
||||||
|
~coupling.Czjzek
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
from .relaxation import Relaxation, RelaxationEvaluation
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,236 @@
|
|||||||
|
"""
|
||||||
|
NMR coupling values
|
||||||
|
===================
|
||||||
|
|
||||||
|
This is a compilation of NMR prefactors for calculation of relaxation times.
|
||||||
|
A note of caution is
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
import abc
|
||||||
|
from math import log
|
||||||
|
from collections import OrderedDict
|
||||||
|
|
||||||
|
from ..utils.constants import gamma_full, hbar_joule, pi, gamma, mu0
|
||||||
|
|
||||||
|
|
||||||
|
__all__ = ['Quadrupolar', 'Czjzek', 'HeteroDipolar',
|
||||||
|
'HomoDipolar', 'Constant', 'CSA']
|
||||||
|
|
||||||
|
|
||||||
|
class Coupling(metaclass=abc.ABCMeta):
|
||||||
|
name = 'coupling'
|
||||||
|
parameter = None
|
||||||
|
choice = None
|
||||||
|
unit = None
|
||||||
|
equation = ''
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
@abc.abstractmethod
|
||||||
|
def relax(*args, **kwargs):
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
|
||||||
|
class Quadrupolar(Coupling):
|
||||||
|
""" Quadrupolar interaction
|
||||||
|
"""
|
||||||
|
|
||||||
|
name = 'Quadrupolar'
|
||||||
|
parameter = [r'\delta/C_{q}', r'\eta']
|
||||||
|
unit = ['Hz', '']
|
||||||
|
equation = r'3/50 \pi^{2} C_{q}^{2} (1+\eta^{2}/3) (2I+3)/(I^{2}(2I-1))'
|
||||||
|
choice = [
|
||||||
|
('Spin', 'spin', OrderedDict([('1', 1), ('3/2', 1.5), ('2', 2), ('5/2', 2.5)])),
|
||||||
|
('Type', 'is_delta', {'Anisotropy': True, 'QCC': False})
|
||||||
|
]
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def relax(value: float, eta: float, spin: float = 1, is_delta: bool = True) -> float:
|
||||||
|
r"""Calculates prefactor for quadrupolar relaxation
|
||||||
|
|
||||||
|
.. math::
|
||||||
|
\frac{3}{200} (2\pi C_q)^2 \left(1+\frac{\eta^{2}}{3}\right) \frac{2I+3}{I^{2}(2I-1)}
|
||||||
|
|
||||||
|
If input is given as anisotropy :math:`\delta` then :math:`C_q` is calculated via
|
||||||
|
|
||||||
|
.. math::
|
||||||
|
C_q = \delta \frac{4I(2I-1)}{3(2m-1)}
|
||||||
|
|
||||||
|
where `m` is 1 for integer spin and 3/2 else.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
value (float): Quadrupolar coupling constant in Hz.
|
||||||
|
eta (float): Asymmetry parameter
|
||||||
|
spin (float): Spin `I`. Default is 1.
|
||||||
|
is_delta (bool): If True, uses value as anisotropy :math:`\delta` else as QCC. Default is True.
|
||||||
|
|
||||||
|
"""
|
||||||
|
m = 1 if (2*spin) % 2 == 0 else 1.5
|
||||||
|
if is_delta:
|
||||||
|
value *= 4*spin*(2*spin-1) / (3*(2*m-1))
|
||||||
|
|
||||||
|
return 0.06 * (2*spin+3) * (pi*value)**2 * (1 + eta**2 / 3) / (spin**2 * (2*spin-1))
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def convert(in_value: float, to: str = 'aniso', spin: float = 1) -> float:
|
||||||
|
r"""Convert between QCC and anisotropy.
|
||||||
|
|
||||||
|
Relation between quadrupole coupling constant :math:`C_q` and anisotropy :math:`\delta` is given by
|
||||||
|
|
||||||
|
.. math::
|
||||||
|
\delta = \frac{3(2m-1)}{4I(2I-1)} C_q
|
||||||
|
|
||||||
|
where `m` is 1 for integer spin and 3/2 else.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
in_value (float): Input value
|
||||||
|
to (str, {`aniso`, `qcc`}): Direction of conversion. Default is `aniso`
|
||||||
|
spin (float): Spin number `I`. Default is 1.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Converted value
|
||||||
|
"""
|
||||||
|
if to not in ['aniso', 'qcc']:
|
||||||
|
raise ValueError(f'Cannot convert to {to} use `aniso` or `qcc`')
|
||||||
|
|
||||||
|
m = 1 if (2 * spin) % 2 == 0 else 1.5
|
||||||
|
fac = 4 * spin * (2 * spin - 1) / (3 * (2 * m - 1))
|
||||||
|
if to == 'delta':
|
||||||
|
return in_value * fac
|
||||||
|
else:
|
||||||
|
return in_value / fac
|
||||||
|
|
||||||
|
|
||||||
|
class HomoDipolar(Coupling):
|
||||||
|
"""Homonuclear dipolar coupling"""
|
||||||
|
|
||||||
|
name = 'Homonuclear Dipolar'
|
||||||
|
parameter = ['r']
|
||||||
|
unit = ['m']
|
||||||
|
choice = [
|
||||||
|
(r'\gamma', 'nucleus', {k: k for k in gamma}),
|
||||||
|
('Spin', 'spin', OrderedDict([('1/2', 0.5), ('1', 1), ('3/2', 1.5), ('2', 2), ('5/2', 2.5), ('3', 3)])),
|
||||||
|
]
|
||||||
|
equation = r'2/5 [\mu_{0}/(4\pi) \hbar \gamma^{2}/r^{3}]^{2} I(I+1)'
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def relax(r: float, nucleus: str = '1H', spin: float = 0.5) -> float:
|
||||||
|
"""Calculate prefactor for homonuclear dipolar relaxation.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
r (float): Distance in m.
|
||||||
|
nucleus (str): Name of isotope. Default is `1H`
|
||||||
|
spin (float): Spin `I` of isotope. Default is 1/2
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
if nucleus not in gamma_full:
|
||||||
|
raise KeyError(f'Unknown nucleus {nucleus}')
|
||||||
|
|
||||||
|
try:
|
||||||
|
coupling = mu0 / (4*pi) * hbar_joule * gamma_full[nucleus]**2 / (r+1e-34)**3
|
||||||
|
except ZeroDivisionError:
|
||||||
|
return 1e318
|
||||||
|
|
||||||
|
coupling **= 2
|
||||||
|
coupling *= 2 * spin * (spin+1) / 5
|
||||||
|
|
||||||
|
return coupling
|
||||||
|
|
||||||
|
|
||||||
|
class HeteroDipolar(Coupling):
|
||||||
|
"""Heteronuclear dipolar coupling"""
|
||||||
|
|
||||||
|
name = 'Heteronuclear Dipolar'
|
||||||
|
parameter = ['r']
|
||||||
|
unit = ['m']
|
||||||
|
choice = [
|
||||||
|
(r'\gamma_{1}', 'nucleus1', {k: k for k in gamma}),
|
||||||
|
(r'\gamma_{2}', 'nucleus2', {k: k for k in gamma}),
|
||||||
|
('Spin', 'spin', dict([('1/2', 0.5), ('1', 1), ('3/2', 1.5), ('2', 2), ('5/2', 2.5), ('3', 3)]))
|
||||||
|
]
|
||||||
|
equation = r'2/15 [\mu_{0}/(4\pi) \hbar \gamma^{2}/r^{3}]^{2} I(I+1)'
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def relax(r: float, nucleus1: str = '1H', nucleus2: str = '19F', spin: float = 0.5) -> float:
|
||||||
|
r"""Calculate prefactor for feteronuclear dipolar relaxation.
|
||||||
|
|
||||||
|
.. math::
|
||||||
|
\frac{2}{15} \left(\frac{\mu_0}{4\pi} \hbar \frac{\gamma_1 \gamma_2}{r^3} \right)^2 S(S+1)
|
||||||
|
|
||||||
|
Args:
|
||||||
|
r (float): Distance in m.
|
||||||
|
nucleus1 (str): Name of observed isotope. Default is `1H`
|
||||||
|
nucleus2 (str): Name of coupled isotope. Default is `19F`
|
||||||
|
spin (float): Spin `S` of the coupled isotope. Default is 1/2
|
||||||
|
|
||||||
|
"""
|
||||||
|
if nucleus1 not in gamma_full:
|
||||||
|
raise KeyError(f'Unknown nucleus {nucleus1}')
|
||||||
|
|
||||||
|
if nucleus2 not in gamma_full:
|
||||||
|
raise KeyError(f'Unknown nucleus {nucleus2}')
|
||||||
|
|
||||||
|
try:
|
||||||
|
coupling = mu0 / (4*pi) * hbar_joule * gamma_full[nucleus1]*gamma_full[nucleus2] / r**3
|
||||||
|
except ZeroDivisionError:
|
||||||
|
return 1e318
|
||||||
|
|
||||||
|
coupling **= 2
|
||||||
|
coupling *= 2 * spin * (spin+1) / 15
|
||||||
|
|
||||||
|
return coupling
|
||||||
|
|
||||||
|
|
||||||
|
class Czjzek(Coupling):
|
||||||
|
name = 'Czjzek'
|
||||||
|
parameter = [r'\Sigma']
|
||||||
|
unit = ['Hz']
|
||||||
|
choice = [('Spin', 'spin', {'1': 1, '3/2': 1.5, '5/2': 2.5, '7/2': 3.5})]
|
||||||
|
equation = r'3/[20log(2)] \pi^{2} \Sigma^{2} (2I+3)/(I^{2}(2I-1))'
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def relax(fwhm, spin=1):
|
||||||
|
return 3*(2+spin+3) * pi**2 * fwhm**2 / 20 / log(2) / spin**2 / (2*spin-1)
|
||||||
|
|
||||||
|
|
||||||
|
class Constant(Coupling):
|
||||||
|
name = 'Constant'
|
||||||
|
parameter = ['C']
|
||||||
|
equation = 'C'
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def relax(c):
|
||||||
|
return c
|
||||||
|
|
||||||
|
|
||||||
|
class CSA(Coupling):
|
||||||
|
"""Chemical shift anisotropy"""
|
||||||
|
|
||||||
|
name = 'CSA'
|
||||||
|
equation = r'2/15 \Delta\sigma^{2} (1+\eta^{2}/2)'
|
||||||
|
parameter = [r'\Delta\sigma', '\eta']
|
||||||
|
unit = ['ppm', '']
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def relax(sigma: float, eta: float) -> float:
|
||||||
|
r"""Relaxation prefactor for chemical shift anisotropy.
|
||||||
|
|
||||||
|
.. math::
|
||||||
|
C = \frac{2}{15} \Delta\sigma^2 \left(1+\frac{\eta^2}{3}\right)
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
The influence of the external magnetic field is missing here but
|
||||||
|
is multiplied in :func:`~nmreval.nmr.Relaxation.t1_csa`
|
||||||
|
|
||||||
|
Args:
|
||||||
|
sigma: Anisotropy (in ppm)
|
||||||
|
eta: Asymmetry parameter
|
||||||
|
|
||||||
|
Reference:
|
||||||
|
Spiess, H.W.: Rotation of Molecules and Nuclear Spin Relaxation.
|
||||||
|
In: NMR - Basic principles and progress, Vol. 15, (Springer, 1978)
|
||||||
|
https://doi.org/10.1007/978-3-642-66961-3_2
|
||||||
|
|
||||||
|
"""
|
||||||
|
return 2 * sigma**2 * (1+eta**2 / 3) / 15
|
||||||
@@ -1,102 +0,0 @@
|
|||||||
from math import log
|
|
||||||
from collections import OrderedDict
|
|
||||||
|
|
||||||
from ..utils.constants import pi, gamma, mu0, hbar
|
|
||||||
|
|
||||||
|
|
||||||
__all__ = ['Quadrupolar', 'QuadrupolarQCC', 'Czjzek', 'HeteroDipolar', 'HomoDipolar', 'Constant']
|
|
||||||
|
|
||||||
|
|
||||||
class Coupling(object):
|
|
||||||
name = 'coupling'
|
|
||||||
parameter = None
|
|
||||||
choice = None
|
|
||||||
unit = None
|
|
||||||
equation = ''
|
|
||||||
|
|
||||||
|
|
||||||
class Quadrupolar(Coupling):
|
|
||||||
name = 'Quadrupolar'
|
|
||||||
parameter = [r'\delta', r'\eta']
|
|
||||||
unit = ['Hz', '']
|
|
||||||
equation = r'24 (2I-1)(2I+3) / (25(6m+3)^{2}) (1+\eta^2/3) \pi^{2} \delta^{2}'
|
|
||||||
choice = [('Spin', 'spin', OrderedDict([('1', 1), ('3/2', 1.5), ('2', 2),
|
|
||||||
('5/2', 2.5), ('3', 3), ('7/2', 3.5)]))]
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def func(delta, eta, spin=1):
|
|
||||||
m = 0 if (2*spin) % 2 == 0 else 0.5
|
|
||||||
return 24*(2*spin-1)*(2*spin+3) * pi**2 * delta**2 * (1+eta**2 / 3) / 25 / (6*m+3)**2
|
|
||||||
|
|
||||||
|
|
||||||
class QuadrupolarQCC(Coupling):
|
|
||||||
name = 'Quadrupolar (QCC)'
|
|
||||||
parameter = ['C_{Q}', r'\eta']
|
|
||||||
unit = ['Hz', '']
|
|
||||||
choice = [('Spin', 'spin', {'1': 1, '3/2': 1.5, '5/2': 2.5, '7/2': 3.5})]
|
|
||||||
equation = r'3/50 \pi^{2} C_{Q}^{2} (1+\eta^{2}/3) (2I+3)/(I^{2}(2I-1))'
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def func(cq, eta, spin=1):
|
|
||||||
return 0.06 * (2*spin+3)*pi**2 * cq**2 * (1+eta**2 / 3) / spin**2 / (2*spin-1)
|
|
||||||
|
|
||||||
|
|
||||||
class Czjzek(Coupling):
|
|
||||||
name = 'Czjzek'
|
|
||||||
parameter = [r'\Sigma']
|
|
||||||
unit = ['Hz']
|
|
||||||
choice = [('Spin', 'spin', {'1': 1, '3/2': 1.5, '5/2': 2.5, '7/2': 3.5})]
|
|
||||||
equation = r'3/[20log(2)] \pi^{2} \Sigma^{2} (2I+3)/(I^{2}(2I-1))'
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def func(fwhm, spin=1):
|
|
||||||
return 3*(2+spin+3) * pi**2 * fwhm**2 / 20 / log(2) / spin**2 / (2*spin-1)
|
|
||||||
|
|
||||||
|
|
||||||
class HeteroDipolar(Coupling):
|
|
||||||
name = 'Heteronuclear Dipolar'
|
|
||||||
parameter = ['r']
|
|
||||||
unit = ['m']
|
|
||||||
choice = [(r'\gamma_{1}', 'nucleus1', {k: k for k in gamma.keys()}),
|
|
||||||
(r'\gamma_{2}', 'nucleus2', {k: k for k in gamma.keys()})]
|
|
||||||
equation = r'1/10 * [\mu_{0}/(4\pi) * \hbar * \gamma_{1}\gamma_{2}/r^{3}]^{2}'
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def func(r, nucleus1='1H', nucleus2='19F'):
|
|
||||||
if nucleus1 not in gamma:
|
|
||||||
raise KeyError('Unknown nucleus {}'.format(nucleus1))
|
|
||||||
if nucleus2 not in gamma:
|
|
||||||
raise KeyError('Unknown nucleus {}'.format(nucleus2))
|
|
||||||
|
|
||||||
coupling = mu0 / (4*pi) * hbar*gamma[nucleus1]*gamma[nucleus2] / (r+1e-34)**3
|
|
||||||
coupling **= 2
|
|
||||||
|
|
||||||
return 0.1 * coupling
|
|
||||||
|
|
||||||
|
|
||||||
class HomoDipolar(Coupling):
|
|
||||||
name = 'Homonuclear Dipolar'
|
|
||||||
parameter = ['r']
|
|
||||||
unit = ['m']
|
|
||||||
choice = [(r'\gamma', 'nucleus', {k: k for k in gamma.keys()})]
|
|
||||||
equation = r'3/10 * [\mu_{0}/(4\pi) * \hbar * \gamma^{2}/r^{3}]^{2}'
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def func(r, nucleus='1H'):
|
|
||||||
if nucleus not in gamma:
|
|
||||||
raise KeyError('Unknown nucleus {}'.format(nucleus))
|
|
||||||
|
|
||||||
coupling = mu0 / (4*pi) * hbar * gamma[nucleus]**2 / (r+1e-34)**3
|
|
||||||
coupling **= 2
|
|
||||||
|
|
||||||
return 0.3 * coupling
|
|
||||||
|
|
||||||
|
|
||||||
class Constant(Coupling):
|
|
||||||
name = 'Constant'
|
|
||||||
parameter = ['C']
|
|
||||||
equation = 'C'
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def func(c):
|
|
||||||
return c
|
|
||||||
+514
-177
@@ -1,6 +1,12 @@
|
|||||||
from numbers import Number
|
"""
|
||||||
|
Relaxation
|
||||||
|
==========
|
||||||
|
|
||||||
|
Classes to calculate spin-lattice and spin-spin relaxation, as well as to evaluate T1 data and calculate correlation times
|
||||||
|
"""
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Tuple
|
from typing import Any, Optional, Tuple, Type, Union
|
||||||
from warnings import warn
|
from warnings import warn
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
@@ -8,138 +14,417 @@ from scipy.interpolate import interp1d, Akima1DInterpolator
|
|||||||
from scipy.optimize import minimize
|
from scipy.optimize import minimize
|
||||||
|
|
||||||
from nmreval.lib.utils import ArrayLike
|
from nmreval.lib.utils import ArrayLike
|
||||||
|
from .coupling import Coupling
|
||||||
|
from ..distributions.base import Distribution
|
||||||
from ..distributions.debye import Debye as Debye
|
from ..distributions.debye import Debye as Debye
|
||||||
|
from ..utils import gamma_full
|
||||||
|
|
||||||
|
|
||||||
class Relaxation:
|
class Relaxation:
|
||||||
def __init__(self, distribution=None):
|
"""
|
||||||
self._distribution = distribution
|
Class to calculate relaxation times.
|
||||||
self._dist_parameter = ()
|
"""
|
||||||
|
|
||||||
|
def __init__(self, distribution: Type[Distribution] = None):
|
||||||
|
self.distribution = distribution
|
||||||
|
self.dist_parameter = ()
|
||||||
self._dist_kw = {}
|
self._dist_kw = {}
|
||||||
|
|
||||||
self._coupling = None
|
self.coupling = None
|
||||||
self._coup_parameter = ()
|
self.coup_parameter = []
|
||||||
self._coup_kw = {}
|
self.coup_kw = {}
|
||||||
|
|
||||||
self._prefactor = 1.
|
self.prefactor = 1.
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
if self._distribution is not None:
|
if self.distribution is not None:
|
||||||
return str(self._distribution.name)
|
return str(self.distribution.name)
|
||||||
else:
|
else:
|
||||||
return super().__repr__()
|
return super().__repr__()
|
||||||
|
|
||||||
def coupling(self, coupling, parameter: list = None, keywords: dict = None):
|
def set_coupling(self, coupling: Union[float, Type[Coupling]],
|
||||||
self._coupling = coupling
|
parameter: Union[tuple, list] = None, keywords: dict = None):
|
||||||
|
|
||||||
if parameter is not None:
|
if parameter is not None:
|
||||||
self._coup_parameter = parameter
|
self.coup_parameter = parameter
|
||||||
|
|
||||||
if keywords is not None:
|
if keywords is not None:
|
||||||
self._coup_kw = keywords
|
self.coup_kw = keywords
|
||||||
|
|
||||||
if isinstance(self._coupling, Number):
|
if isinstance(coupling, float):
|
||||||
self._prefactor = self._coupling
|
self.prefactor = coupling
|
||||||
|
elif issubclass(coupling, Coupling):
|
||||||
|
self.coupling = coupling
|
||||||
|
if self.coup_kw is None:
|
||||||
|
raise ValueError('Coupling is missing parameter')
|
||||||
|
self.prefactor = self.coupling.relax(*self.coup_parameter, **self.coup_kw)
|
||||||
else:
|
else:
|
||||||
try:
|
raise ValueError(f'`coupling` is not number or of type `Coupling`, found {coupling!r}')
|
||||||
self._prefactor = self._coupling.func(*self._coup_parameter, **self._coup_kw)
|
|
||||||
except TypeError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
def distribution(self, dist, parameter=None, keywords=None):
|
def set_distribution(self, dist: Type[Distribution], parameter: Union[tuple, list] = None, keywords: dict = None):
|
||||||
self._distribution = dist
|
self.distribution = dist
|
||||||
|
|
||||||
if parameter is not None:
|
if parameter is not None:
|
||||||
self._dist_parameter = parameter
|
self.dist_parameter = parameter
|
||||||
|
|
||||||
if keywords is not None:
|
if keywords is not None:
|
||||||
self._dist_kw = keywords
|
self._dist_kw = keywords
|
||||||
|
|
||||||
def t1(self, omega, tau, *args, mode='bpp', **kwargs):
|
def t1(self, omega: ArrayLike, tau: ArrayLike, *specdens_args: Any,
|
||||||
# defaults to BPP
|
mode: str = 'bpp', **kwargs) -> Union[np.ndarray, float]:
|
||||||
if mode == 'bpp':
|
r"""
|
||||||
return self.t1_bpp(omega, tau, *args, **kwargs)
|
Convenience function
|
||||||
elif mode == 'dipolar':
|
|
||||||
return self.t1_dipolar(omega, tau, *args, **kwargs)
|
|
||||||
else:
|
|
||||||
raise AttributeError(f'Unknown mode {mode}. Use either "bpp" or "dipolar".')
|
|
||||||
|
|
||||||
def t1_dipolar(self, omega: ArrayLike, tau: ArrayLike, *args,
|
|
||||||
inverse: bool = True, prefactor: float = None, **kwargs) -> ArrayLike:
|
|
||||||
"""
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
omega:
|
omega (array-like): Frequency in 1/s (not Hz)
|
||||||
tau:
|
tau (array-like): Correlation times in s
|
||||||
*args:
|
*specdens_args: Additional parameter for spectral density.
|
||||||
inverse:
|
If given this will replace previously set arguments during calculation
|
||||||
prefactor:
|
mode (str, {`bpp`, `dipolar`, `csa`}): Type of relaxation
|
||||||
|
|
||||||
|
- `bpp` : Homonuclear dipolar/quadrupolar interaction :func:`(see here) <nmreval.nmr.Relaxation.t1_bpp>`
|
||||||
|
- `dipolar` : Heteronuclear dipolar interaction :func:`(see here) <nmreval.nmr.Relaxation.t1_dipolar>`
|
||||||
|
- `csa` : Chemical shift interaction :func:`(see here) <nmreval.nmr.Relaxation.t1_csa>`
|
||||||
|
|
||||||
|
Default is `bpp`
|
||||||
|
|
||||||
**kwargs:
|
**kwargs:
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
|
float or ndarray:
|
||||||
|
A k by n array where k is length of ``omega`` and n is length of ``tau``.
|
||||||
|
If both are of length 1 a number is returned instead of array.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
try:
|
if mode not in ['bpp', 'dipolar', 'csa']:
|
||||||
omega_2 = kwargs['omega_coup']
|
raise ValueError(f'Unknown mode {mode} not `bpp`, `dipolar`, `csa`.')
|
||||||
except KeyError:
|
|
||||||
if kwargs.get('gamma_obs', False):
|
# defaults to BPP
|
||||||
omega_2 = kwargs['gamma_coup'] / kwargs['gamma_obs'] * omega
|
if mode == 'bpp':
|
||||||
else:
|
return self.t1_bpp(omega, tau, *specdens_args, **kwargs)
|
||||||
raise AttributeError('Unknown second frequency.')
|
elif mode == 'dipolar':
|
||||||
|
return self.t1_dipolar(omega, tau, *specdens_args, **kwargs)
|
||||||
|
|
||||||
|
def t1_dipolar(self, omega: ArrayLike, tau: ArrayLike, *specdens_args: Any, inverse: bool = True,
|
||||||
|
prefactor: float = None, omega_coup: ArrayLike = None,
|
||||||
|
gamma_coup: str = None, gamma_obs: str = None) -> Union[np.ndarray, float]:
|
||||||
|
r"""Calculate T1 under heteronuclear dipolar coupling.
|
||||||
|
|
||||||
|
.. math::
|
||||||
|
\frac{1}{T_1} = C [3J(\omega_I) + 6J(\omega_I + \omega_I) + J(\omega_I - \omega_S)]
|
||||||
|
|
||||||
|
Args:
|
||||||
|
omega (array-like): Frequency in 1/s (not Hz)
|
||||||
|
tau (array-like): Correlation times in s
|
||||||
|
*specdens_args: Additional parameter for spectral density.
|
||||||
|
If given this will replace previously set arguments during calculation
|
||||||
|
inverse (bool): Function returs relaxation time if True else relaxation rate. Default is `True`
|
||||||
|
prefactor (float, optional): If given it is used as prefactor `C`
|
||||||
|
instead of previously set coupling prefactor.
|
||||||
|
omega_coup (array-like, optional): Frequency of coupled isotope must be of same shape as omega.
|
||||||
|
gamma_obs (str, optional): Name of observed isotope ('1H', '23Na', ...).
|
||||||
|
Values is used if `omega_coup` is None.
|
||||||
|
gamma_coup (str, optional): Name of coupled isotope ('1H', '23Na', ...).
|
||||||
|
Values is used if `omega_coup` is None.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
float or ndarray:
|
||||||
|
A k by n array where k is length of ``omega`` and n is length of ``tau``.
|
||||||
|
If both are of length 1 a number is returned instead of array.
|
||||||
|
|
||||||
|
"""
|
||||||
|
omega = np.asanyarray(omega)
|
||||||
|
|
||||||
|
if omega_coup is not None:
|
||||||
|
omega_coup = np.asanyarray(omega_coup)
|
||||||
|
if omega.shape != omega_coup.shape:
|
||||||
|
raise ValueError('omega and omega_coup have not same shape')
|
||||||
|
omega_2 = omega_coup
|
||||||
|
elif (gamma_coup is not None) and (gamma_obs is not None):
|
||||||
|
omega_2 = gamma_full[gamma_coup] / gamma_full[gamma_obs] * omega
|
||||||
|
else:
|
||||||
|
raise AttributeError('Unknown second frequency. Set `omega_coup`, or `gamma_coup` and `gamma_obs`')
|
||||||
|
|
||||||
if prefactor is None:
|
if prefactor is None:
|
||||||
prefactor = self._prefactor
|
prefactor = self.prefactor
|
||||||
|
|
||||||
if len(args) == 0:
|
if len(specdens_args) == 0:
|
||||||
args = self._dist_parameter
|
specdens_args = self.dist_parameter
|
||||||
|
|
||||||
rate = prefactor * (3 * self._distribution.specdens(omega, tau, *args) +
|
rate = prefactor * (self.distribution.specdens(omega - omega_2, tau, *specdens_args) +
|
||||||
self._distribution.specdens(np.abs(omega - omega_2), tau, *args) +
|
3 * self.distribution.specdens(omega, tau, *specdens_args) +
|
||||||
6 * self._distribution.specdens(omega + omega_2, tau, *args))
|
6 * self.distribution.specdens(omega + omega_2, tau, *specdens_args)) / 2
|
||||||
if inverse:
|
if inverse:
|
||||||
return 1 / rate
|
return 1 / rate
|
||||||
else:
|
else:
|
||||||
return rate
|
return rate
|
||||||
|
|
||||||
def t1_bpp(self, omega, tau, *args, inverse=True, prefactor=None, **kwargs):
|
def t1_bpp(self, omega: ArrayLike, tau: ArrayLike, *specdens_args: Any,
|
||||||
|
inverse: bool = True, prefactor: float = None) -> Union[np.ndarray, float]:
|
||||||
|
r"""Calculate T1 under homonuclear dipolar coupling or quadrupolar coupling.
|
||||||
|
|
||||||
|
.. math::
|
||||||
|
\frac{1}{T_1} = C [J(\omega) + 4J(2\omega)]
|
||||||
|
|
||||||
|
Args:
|
||||||
|
omega (array-like): Frequency in 1/s (not Hz)
|
||||||
|
tau (array-like): Correlation times in s
|
||||||
|
*specdens_args: Additional parameter for spectral density.
|
||||||
|
If given this will replace previously set arguments during calculation
|
||||||
|
inverse (bool): Function returs relaxation time if True else relaxation rate. Default is `True`
|
||||||
|
prefactor (float, optional): If given it is used as prefactor `C`
|
||||||
|
instead of previously set coupling prefactor.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
float or ndarray:
|
||||||
|
A k by n array where k is length of ``omega`` and n is length of ``tau``.
|
||||||
|
If both are of length 1 a number is returned instead of array.
|
||||||
|
|
||||||
|
"""
|
||||||
if prefactor is None:
|
if prefactor is None:
|
||||||
prefactor = self._prefactor
|
prefactor = self.prefactor
|
||||||
|
|
||||||
if len(args) == 0:
|
if len(specdens_args) == 0:
|
||||||
args = self._dist_parameter
|
specdens_args = self.dist_parameter
|
||||||
|
|
||||||
rate = prefactor * (self._distribution.specdens(omega, tau, *args) +
|
rate = prefactor * (self.distribution.specdens(omega, tau, *specdens_args) +
|
||||||
4*self._distribution.specdens(2*omega, tau, *args))
|
4 * self.distribution.specdens(2 * omega, tau, *specdens_args))
|
||||||
if inverse:
|
if inverse:
|
||||||
return 1. / rate
|
return 1. / rate
|
||||||
else:
|
else:
|
||||||
return rate
|
return rate
|
||||||
|
|
||||||
def t1_rho(self, omega, tau, omega_rf, *args, inverse=True, prefactor=None, **kwargs):
|
def t1_csa(self, omega: ArrayLike, tau: ArrayLike, *specdens_args: Any,
|
||||||
|
inverse: bool = True, prefactor: float = None) -> Union[np.ndarray, float]:
|
||||||
|
r"""Calculate T1 under chemical shift anisotropy.
|
||||||
|
|
||||||
|
.. math::
|
||||||
|
\frac{1}{T_1} = C \omega^2 [J(\omega)]
|
||||||
|
|
||||||
|
This relation disregards antisymmetric CSA contributions
|
||||||
|
|
||||||
|
Args:
|
||||||
|
omega (array-like): Frequency in 1/s (not Hz)
|
||||||
|
tau (array-like): Correlation times in s
|
||||||
|
*specdens_args: Additional parameter for spectral density.
|
||||||
|
If given this will replace previously set arguments during calculation
|
||||||
|
inverse (bool): Function returs relaxation time if True else relaxation rate. Default is `True`
|
||||||
|
prefactor (float, optional): If given it is used as prefactor `C`
|
||||||
|
instead of previously set coupling prefactor.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
float or ndarray:
|
||||||
|
A k by n array where k is length of ``omega`` and n is length of ``tau``.
|
||||||
|
If both are of length 1 a number is returned instead of array.
|
||||||
|
|
||||||
|
"""
|
||||||
if prefactor is None:
|
if prefactor is None:
|
||||||
prefactor = self._prefactor
|
prefactor = self.prefactor
|
||||||
|
|
||||||
if len(args) == 0:
|
if len(specdens_args) == 0:
|
||||||
args = self._dist_parameter
|
specdens_args = self.dist_parameter
|
||||||
|
|
||||||
rate = prefactor * (10 * self._distribution.specdens(omega, tau, *args) +
|
rate = prefactor * (self.distribution.specdens(omega, tau, *specdens_args) +
|
||||||
4 * self._distribution.specdens(2 * omega, tau, *args) +
|
4 * self.distribution.specdens(2 * omega, tau, *specdens_args))
|
||||||
6 * self._distribution.specdens(omega_rf, tau, *args))
|
|
||||||
if inverse:
|
if inverse:
|
||||||
return 1. / rate
|
return 1. / rate
|
||||||
else:
|
else:
|
||||||
return rate
|
return rate
|
||||||
|
|
||||||
def t2(self, omega, tau, *args, inverse=True, prefactor=None, **kwargs):
|
def t1q(self, omega: ArrayLike, tau: ArrayLike, *specdens_args: Any,
|
||||||
|
inverse: bool = True, prefactor: float = None) -> Union[np.ndarray, float]:
|
||||||
|
r"""Calculate T1q for homonuclear dipolar coupling or quadrupolar coupling (I=1).
|
||||||
|
|
||||||
|
.. math::
|
||||||
|
\frac{1}{T_{1q}} = 3 C J(\omega)
|
||||||
|
|
||||||
|
Args:
|
||||||
|
omega (array-like): Frequency in 1/s (not Hz)
|
||||||
|
tau (array-like): Correlation times in s
|
||||||
|
*specdens_args: Additional parameter for spectral density.
|
||||||
|
If given this will replace previously set arguments during calculation
|
||||||
|
inverse (bool): Function returs relaxation time if True else relaxation rate. Default is `True`
|
||||||
|
prefactor (float, optional): If given it is used as prefactor `C`
|
||||||
|
instead of previously set coupling prefactor.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
float or ndarray:
|
||||||
|
A k by n array where k is length of ``omega`` and n is length of ``tau``.
|
||||||
|
If both are of length 1 a number is returned instead of array.
|
||||||
|
|
||||||
|
"""
|
||||||
if prefactor is None:
|
if prefactor is None:
|
||||||
prefactor = self._prefactor / 2.
|
prefactor = self.prefactor
|
||||||
|
|
||||||
if len(args) == 0:
|
if len(specdens_args) == 0:
|
||||||
args = self._dist_parameter
|
specdens_args = self.dist_parameter
|
||||||
|
|
||||||
rate = prefactor * (3 * self._distribution.specdens(0, tau, *args) +
|
rate = 3 * prefactor * self.distribution.specdens(omega, tau, *specdens_args)
|
||||||
5 * self._distribution.specdens(omega, tau, *args) +
|
if inverse:
|
||||||
2 * self._distribution.specdens(2 * omega, tau, *args))
|
return 1. / rate
|
||||||
|
else:
|
||||||
|
return rate
|
||||||
|
|
||||||
|
def t1_rho(self, omega: ArrayLike, tau: ArrayLike, omega_rf: float, *specdens_args: Any,
|
||||||
|
inverse: bool = True, prefactor: float = None):
|
||||||
|
r"""Calculate T1rho for homonuclear dipolar coupling or quadrupolar coupling.
|
||||||
|
|
||||||
|
.. math::
|
||||||
|
\frac{1}{T_{1\rho}} = \frac{C}{2} [5J(\omega) + 2J(2\omega) + 3J(2\omega_{RF})]
|
||||||
|
|
||||||
|
Args:
|
||||||
|
omega (array-like): Frequency in 1/s (not Hz).
|
||||||
|
tau (array-like): Correlation times in s.
|
||||||
|
omega_rf (float): Frequency of RF lock IN 1/s.
|
||||||
|
*specdens_args: Additional parameter for spectral density.
|
||||||
|
If given this will replace previously set arguments during calculation
|
||||||
|
inverse (bool): Function returs relaxation time if True else relaxation rate. Default is `True`
|
||||||
|
prefactor (float, optional): If given it is used as prefactor `C`
|
||||||
|
instead of previously set coupling prefactor.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
float or ndarray:
|
||||||
|
A k by n array where k is length of ``omega`` and n is length of ``tau``.
|
||||||
|
If both are of length 1 a number is returned instead of array.
|
||||||
|
|
||||||
|
"""
|
||||||
|
if prefactor is None:
|
||||||
|
prefactor = self.prefactor
|
||||||
|
|
||||||
|
if len(specdens_args) == 0:
|
||||||
|
specdens_args = self.dist_parameter
|
||||||
|
|
||||||
|
rate = prefactor * (5 * self.distribution.specdens(omega, tau, *specdens_args) +
|
||||||
|
2 * self.distribution.specdens(2 * omega, tau, *specdens_args) +
|
||||||
|
3 * self.distribution.specdens(2 * omega_rf, tau, *specdens_args)) / 2
|
||||||
|
if inverse:
|
||||||
|
return 1. / rate
|
||||||
|
else:
|
||||||
|
return rate
|
||||||
|
|
||||||
|
def t2_bpp(self, omega: ArrayLike, tau: ArrayLike, *specdens_args: Any,
|
||||||
|
inverse: bool = True, prefactor: float = None) -> Union[np.ndarray, float]:
|
||||||
|
r"""Calculate T2 under homonuclear dipolar coupling or quadrupolar coupling.
|
||||||
|
|
||||||
|
.. math::
|
||||||
|
\frac{1}{T_2} = \frac{C}{2} [3J() + 5J(2\omega) + 3J(2\omega)]
|
||||||
|
|
||||||
|
Args:
|
||||||
|
omega (array-like): Frequency in 1/s (not Hz)
|
||||||
|
tau (array-like): Correlation times in s
|
||||||
|
*specdens_args (optional): Additional parameter for spectral density.
|
||||||
|
If given this will replace previously set arguments during calculation
|
||||||
|
inverse (bool): Function returs relaxation time if True else relaxation rate. Default is `True`
|
||||||
|
prefactor (float, optional): If given it is used as prefactor `C`
|
||||||
|
instead of previously set coupling prefactor.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
float or ndarray:
|
||||||
|
A k by n array where k is length of ``omega`` and n is length of ``tau``.
|
||||||
|
If both are of length 1 a number is returned instead of array.
|
||||||
|
|
||||||
|
"""
|
||||||
|
if prefactor is None:
|
||||||
|
prefactor = self.prefactor
|
||||||
|
|
||||||
|
if len(specdens_args) == 0:
|
||||||
|
specdens_args = self.dist_parameter
|
||||||
|
|
||||||
|
rate = prefactor * (3 * self.distribution.specdens(0, tau, *specdens_args) +
|
||||||
|
5 * self.distribution.specdens(omega, tau, *specdens_args) +
|
||||||
|
2 * self.distribution.specdens(2 * omega, tau, *specdens_args)) / 2
|
||||||
|
if inverse:
|
||||||
|
return 1. / rate
|
||||||
|
else:
|
||||||
|
return rate
|
||||||
|
|
||||||
|
def t2_dipolar(self, omega: ArrayLike, tau: ArrayLike, *specdens_args: Any,
|
||||||
|
inverse: bool = True, prefactor: float = None, omega_coup: ArrayLike = None,
|
||||||
|
gamma_coup: str = None, gamma_obs: str = None) -> Union[np.ndarray, float]:
|
||||||
|
r"""Calculate T2 under heteronuclear dipolar coupling.
|
||||||
|
|
||||||
|
.. math::
|
||||||
|
\frac{1}{T_2} = \frac{C}{2} [4J(0) + J(\omega_I - \omega_I) + 3J(\omega_S) + 6J(\omega_I) + 6J(\omega_I + \omega_I)]
|
||||||
|
|
||||||
|
Args:
|
||||||
|
omega (array-like): Frequency in 1/s (not Hz)
|
||||||
|
tau (array-like): Correlation times in s
|
||||||
|
*specdens_args (optional): Additional parameter for spectral density.
|
||||||
|
If given this will replace previously set arguments during calculation
|
||||||
|
inverse (bool): Function returs relaxation time if True else relaxation rate. Default is `True`
|
||||||
|
prefactor (float, optional): If given it is used as prefactor `C`
|
||||||
|
instead of previously set coupling prefactor.
|
||||||
|
omega_coup (array-like, optional): Frequency of coupled isotope must be of same shape as omega.
|
||||||
|
gamma_obs (str, optional): Name of observed isotope ('1H', '23Na', ...).
|
||||||
|
Values is used if `omega_coup` is None.
|
||||||
|
gamma_coup (str, optional): Name of coupled isotope ('1H', '23Na', ...).
|
||||||
|
Values is used if `omega_coup` is None.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
float or ndarray:
|
||||||
|
A k by n array where k is length of ``omega`` and n is length of ``tau``.
|
||||||
|
If both are of length 1 a number is returned instead of array.
|
||||||
|
|
||||||
|
"""
|
||||||
|
omega = np.asanyarray(omega)
|
||||||
|
|
||||||
|
if omega_coup is not None:
|
||||||
|
omega_coup = np.asanyarray(omega_coup)
|
||||||
|
if omega.shape != omega_coup.shape:
|
||||||
|
raise ValueError('omega and omega_coup have not same shape')
|
||||||
|
omega_2 = omega_coup
|
||||||
|
elif (gamma_coup is not None) and (gamma_obs is not None):
|
||||||
|
omega_2 = gamma_full[gamma_coup] / gamma_full[gamma_obs] * omega
|
||||||
|
else:
|
||||||
|
raise AttributeError('Unknown second frequency. Set `omega_coup`, or `gamma_coup` and `gamma_obs`')
|
||||||
|
|
||||||
|
if prefactor is None:
|
||||||
|
prefactor = self.prefactor
|
||||||
|
|
||||||
|
if len(specdens_args) == 0:
|
||||||
|
specdens_args = self.dist_parameter
|
||||||
|
|
||||||
|
rate = prefactor * (4 * self.distribution.specdens(0, tau, *specdens_args) +
|
||||||
|
self.distribution.specdens(omega - omega_2, tau, *specdens_args) +
|
||||||
|
3 * self.distribution.specdens(omega_2, tau, *specdens_args) +
|
||||||
|
6 * self.distribution.specdens(omega, tau, *specdens_args) +
|
||||||
|
6 * self.distribution.specdens(omega + omega_2, tau, *specdens_args)) / 2.
|
||||||
|
|
||||||
|
if inverse:
|
||||||
|
return 1. / rate
|
||||||
|
else:
|
||||||
|
return rate
|
||||||
|
|
||||||
|
def t2_csa(self, omega: ArrayLike, tau: ArrayLike, *specdens_args: Any,
|
||||||
|
inverse: bool = True, prefactor: float = None) -> Union[np.ndarray, float]:
|
||||||
|
r"""Calculate T1 under chemical shift anisotropy.
|
||||||
|
|
||||||
|
.. math::
|
||||||
|
\frac{1}{T_2} = \frac{C}{2} \omega^2 \bigl[J(0) + \frac{4}{3}J(\omega)\bigr]
|
||||||
|
|
||||||
|
Args:
|
||||||
|
omega (array-like): Frequency in 1/s (not Hz)
|
||||||
|
tau (array-like): Correlation times in s
|
||||||
|
*specdens_args (optional): Additional parameter for spectral density.
|
||||||
|
If given this will replace previously set arguments during calculation
|
||||||
|
inverse (bool): Function returs relaxation time if True else relaxation rate. Default is `True`
|
||||||
|
prefactor (float, optional): If given it is used as prefactor `C`
|
||||||
|
instead of previously set coupling prefactor.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
float or ndarray:
|
||||||
|
A k by n array where k is length of ``omega`` and n is length of ``tau``.
|
||||||
|
If both are of length 1 a number is returned instead of array.
|
||||||
|
|
||||||
|
"""
|
||||||
|
if prefactor is None:
|
||||||
|
prefactor = self.prefactor
|
||||||
|
|
||||||
|
if len(specdens_args) == 0:
|
||||||
|
specdens_args = self.dist_parameter
|
||||||
|
|
||||||
|
rate = prefactor * (self.distribution.specdens(0, tau, *specdens_args) +
|
||||||
|
4 / 3 * self.distribution.specdens(omega, tau, *specdens_args)) / 2.
|
||||||
if inverse:
|
if inverse:
|
||||||
return 1. / rate
|
return 1. / rate
|
||||||
else:
|
else:
|
||||||
@@ -158,60 +443,31 @@ class RelaxationEvaluation(Relaxation):
|
|||||||
self.y = None
|
self.y = None
|
||||||
|
|
||||||
def data(self, temp, t1):
|
def data(self, temp, t1):
|
||||||
temp = np.asarray(temp)
|
temp = np.asanyarray(temp)
|
||||||
t1 = np.asarray(t1)
|
t1 = np.asanyarray(t1)
|
||||||
sortidx = temp.argsort()
|
sortidx = temp.argsort()
|
||||||
self.x = temp[sortidx]
|
self.x = temp[sortidx]
|
||||||
self.y = t1[sortidx]
|
self.y = t1[sortidx]
|
||||||
self.calculate_t1_min()
|
self.calculate_t1_min()
|
||||||
|
|
||||||
def calculate_t1_min(self, interpolate: int = None, trange=None):
|
def get_increase(self, height: float = None, idx: int = 0, mode: str = None, omega: float = None,
|
||||||
min_index = np.argmin(self.y)
|
dist_parameter: Union[tuple, list] = None, prefactor: Union[tuple, list, float] = None,
|
||||||
t1_min = (self.x[min_index], self.y[min_index])
|
coupling_kwargs: dict = None):
|
||||||
parabola = None
|
"""
|
||||||
self._interpolate_range = (None, None)
|
Determine a single parameter from a T1 minimum
|
||||||
|
|
||||||
if interpolate is not None:
|
Args:
|
||||||
if interpolate not in [0, 1, 2, 3]:
|
height (float, optional): Height of T1 minimum
|
||||||
raise ValueError(f'Unknown interpolation value {interpolate}')
|
mode (str, {`distribution`, `prefactor`}, optional): If given,
|
||||||
|
idx (int): Default is 0.
|
||||||
|
omega (float, optional): Larmor frequency (in 1/s)
|
||||||
|
dist_parameter (tuple, optional):
|
||||||
|
prefactor (tuple, float, optional):
|
||||||
|
coupling_kwargs (dict, optional):
|
||||||
|
|
||||||
if interpolate != 0:
|
Returns:
|
||||||
if trange is None:
|
|
||||||
left_b = max(min_index-2, 0)
|
|
||||||
right_b = min(len(self.x), min_index+3)
|
|
||||||
else:
|
|
||||||
left_b = np.argmin(np.abs(self.x-trange[0]))
|
|
||||||
right_b = np.argmin(np.abs(self.x-trange[1]))+1
|
|
||||||
|
|
||||||
temp_range = self.x[left_b:right_b]
|
"""
|
||||||
t1_range = self.y[left_b:right_b]
|
|
||||||
|
|
||||||
try:
|
|
||||||
x_inter = np.linspace(temp_range[0], temp_range[-1], num=51)
|
|
||||||
|
|
||||||
if interpolate == 1:
|
|
||||||
i_func = np.poly1d(np.polyfit(temp_range, t1_range, 2))
|
|
||||||
elif interpolate == 2:
|
|
||||||
i_func = interp1d(temp_range, t1_range, kind='cubic')
|
|
||||||
else:
|
|
||||||
i_func = Akima1DInterpolator(temp_range, t1_range)
|
|
||||||
|
|
||||||
y_inter = i_func(x_inter)
|
|
||||||
t1_min = (x_inter[np.argmin(y_inter)], y_inter[np.argmin(y_inter)])
|
|
||||||
self._interpolate = i_func
|
|
||||||
parabola = (x_inter, y_inter)
|
|
||||||
self._interpolate_range = (temp_range[0], temp_range[-1])
|
|
||||||
|
|
||||||
except IndexError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
self.t1min = t1_min
|
|
||||||
|
|
||||||
return t1_min, parabola
|
|
||||||
|
|
||||||
def increase(self, variable: Tuple[str, int], height: float = None, omega: float = None,
|
|
||||||
dist_parameter: list = None, prefactor=None,
|
|
||||||
coupling_kwargs=None):
|
|
||||||
|
|
||||||
stretching = mini = np.nan
|
stretching = mini = np.nan
|
||||||
if height is None:
|
if height is None:
|
||||||
@@ -224,44 +480,62 @@ class RelaxationEvaluation(Relaxation):
|
|||||||
omega = self.omega
|
omega = self.omega
|
||||||
|
|
||||||
if prefactor is None:
|
if prefactor is None:
|
||||||
prefactor = self._prefactor
|
prefactor = self.prefactor
|
||||||
|
|
||||||
if dist_parameter is None:
|
if dist_parameter is None:
|
||||||
dist_parameter = self._dist_parameter
|
dist_parameter = self.dist_parameter
|
||||||
|
|
||||||
tau_lims = np.log10(1/omega)-3, np.log10(1/omega)+3
|
if coupling_kwargs is None:
|
||||||
|
coupling_kwargs = self.coup_kw
|
||||||
|
|
||||||
if not variable:
|
tau_lims = np.log10(1 / omega) - 3, np.log10(1 / omega) + 3
|
||||||
if isinstance(prefactor, list):
|
|
||||||
|
if mode is None:
|
||||||
|
# nothing is variable -> just calculate minimum for given parameter
|
||||||
|
if isinstance(prefactor, (tuple, list)):
|
||||||
if coupling_kwargs is None:
|
if coupling_kwargs is None:
|
||||||
coupling_kwargs = self._coup_kw
|
coupling_kwargs = self.coup_kw
|
||||||
prefactor = self._coupling.func(*prefactor, **coupling_kwargs)
|
prefactor = self.coupling.relax(*prefactor, **coupling_kwargs)
|
||||||
|
|
||||||
return stretching, np.min(self.t1(omega, np.logspace(*tau_lims, num=1001),
|
return stretching, np.min(self.t1(omega, np.logspace(*tau_lims, num=1001),
|
||||||
*dist_parameter, prefactor=prefactor, inverse=True))
|
*dist_parameter, prefactor=prefactor, inverse=True))
|
||||||
|
|
||||||
if variable[0] == 'distribution':
|
if mode == 'distribution':
|
||||||
if isinstance(self._distribution, Debye):
|
# width parameter of spectral density is variable
|
||||||
return 1.
|
|
||||||
|
if isinstance(self.distribution, Debye):
|
||||||
|
# Debye is easy
|
||||||
|
return 1., np.min(self.t1(omega, np.logspace(*tau_lims, num=1001),
|
||||||
|
*dist_parameter, prefactor=prefactor, inverse=True))
|
||||||
|
|
||||||
|
if isinstance(prefactor, (list, tuple)):
|
||||||
|
# calculate prefactor from coupling
|
||||||
|
if self.coupling is None:
|
||||||
|
raise ValueError('Coupling must be set before evaluation of T1 min')
|
||||||
|
|
||||||
if isinstance(prefactor, list):
|
|
||||||
if coupling_kwargs is None:
|
if coupling_kwargs is None:
|
||||||
coupling_kwargs = self._coup_kw
|
coupling_kwargs = self.coup_kw
|
||||||
prefactor = self._coupling.func(*prefactor, **coupling_kwargs)
|
|
||||||
|
prefactor = self.coupling.relax(*prefactor, **coupling_kwargs)
|
||||||
|
|
||||||
use_fmin = True
|
use_fmin = True
|
||||||
if self._distribution.name in ['KWW', 'Cole-Davidson', 'Cole-Cole', 'Log-Gaussian']:
|
if self.distribution.name in ['KWW', 'Cole-Davidson', 'Cole-Cole', 'Log-Gaussian']:
|
||||||
|
# using precalculated values is faster than actual calculation, especially KWW and LG
|
||||||
from importlib.resources import path
|
from importlib.resources import path
|
||||||
with path('resources.nmr', 'T1_min.npz') as fp:
|
with path('resources.nmr', 'T1_min.npz') as fp:
|
||||||
if fp.exists():
|
if fp.exists():
|
||||||
t1min_table = np.load(str(fp))[self._distribution.name.replace('-', '_')]
|
t1min_table = np.load(str(fp))[self.distribution.name.replace('-', '_')]
|
||||||
|
|
||||||
debye_min = omega / 1.42517571908650 / prefactor # Zahl kommt von Wolfram alpha
|
debye_min = omega / 1.42517571908650 / prefactor # Zahl kommt von Wolfram alpha
|
||||||
ratio = height / debye_min
|
ratio = height / debye_min
|
||||||
stretching = t1min_table[np.argmin(np.abs(t1min_table[:, 1]-ratio)), 0]
|
stretching = t1min_table[np.argmin(np.abs(t1min_table[:, 1] - ratio)), 0]
|
||||||
|
|
||||||
use_fmin = False
|
use_fmin = False
|
||||||
|
dist_parameter = [stretching]
|
||||||
|
|
||||||
if use_fmin:
|
if use_fmin:
|
||||||
|
# use for untabulated spectral densities or if something went wrong
|
||||||
|
#
|
||||||
def _f(_x, p, ii):
|
def _f(_x, p, ii):
|
||||||
p[ii] = _x[0]
|
p[ii] = _x[0]
|
||||||
t1_calc = np.min(self.t1(omega, np.logspace(*tau_lims, num=1001), *p,
|
t1_calc = np.min(self.t1(omega, np.logspace(*tau_lims, num=1001), *p,
|
||||||
@@ -269,40 +543,100 @@ class RelaxationEvaluation(Relaxation):
|
|||||||
|
|
||||||
return np.abs(t1_calc - height)
|
return np.abs(t1_calc - height)
|
||||||
|
|
||||||
stretching = minimize(_f, np.array([dist_parameter[variable[1]]]),
|
stretching = minimize(_f, np.array([dist_parameter[idx]]),
|
||||||
args=(dist_parameter, variable[1]),
|
args=(dist_parameter, idx),
|
||||||
method='Nelder-Mead').x[0]
|
method='Nelder-Mead').x[0]
|
||||||
|
dist_parameter[idx] = stretching
|
||||||
|
|
||||||
|
elif mode == 'coupling':
|
||||||
|
# variable is somewhere in the prefcotor
|
||||||
|
|
||||||
elif variable[0] == 'coupling':
|
|
||||||
t1_no_coup = np.min(self.t1(omega, np.logspace(*tau_lims, num=1001),
|
t1_no_coup = np.min(self.t1(omega, np.logspace(*tau_lims, num=1001),
|
||||||
*dist_parameter, prefactor=1))
|
*dist_parameter, prefactor=1))
|
||||||
|
|
||||||
if isinstance(prefactor, list):
|
if isinstance(prefactor, (tuple, list)):
|
||||||
def _f(_x, p, ii):
|
prefactor = list(prefactor)
|
||||||
p[ii] = _x
|
|
||||||
return np.abs(t1_no_coup/height - self._coupling.func(*p, **coupling_kwargs)[0])
|
def _f(_x, p, ii):
|
||||||
|
p[ii] = _x[0]
|
||||||
|
return np.abs(t1_no_coup / height - self.coupling.relax(*p, **coupling_kwargs))
|
||||||
|
|
||||||
|
stretching = minimize(_f, np.array([prefactor[idx]]),
|
||||||
|
args=(prefactor, idx)).x[0]
|
||||||
|
|
||||||
stretching = minimize(_f, np.array([prefactor[variable[1]]]),
|
|
||||||
args=(prefactor, variable[1])).x[0]
|
|
||||||
else:
|
else:
|
||||||
stretching = t1_no_coup / height
|
stretching = t1_no_coup / height
|
||||||
|
|
||||||
else:
|
else:
|
||||||
raise ValueError('Use "distribution" or "coupling" to set parameter')
|
raise ValueError('Use `distribution` or `coupling` to set parameter')
|
||||||
|
|
||||||
if stretching:
|
if stretching:
|
||||||
self._prefactor = prefactor
|
self.prefactor = prefactor
|
||||||
self._dist_parameter = dist_parameter
|
self.dist_parameter = dist_parameter
|
||||||
if isinstance(prefactor, list):
|
if isinstance(prefactor, (tuple, list)):
|
||||||
self._coup_parameter = prefactor
|
self.coup_parameter = prefactor
|
||||||
mini = np.min(self.t1(omega, np.logspace(*tau_lims, num=1001), *self._dist_parameter,
|
self.prefactor = self.coupling.relax(*self.coup_parameter, **self.coup_kw)
|
||||||
prefactor=self._prefactor))
|
else:
|
||||||
|
self.prefactor = prefactor
|
||||||
|
mini = np.min(self.t1(omega, np.logspace(*tau_lims, num=1001), *self.dist_parameter,
|
||||||
|
prefactor=self.prefactor))
|
||||||
|
|
||||||
return stretching, mini
|
return stretching, mini
|
||||||
|
|
||||||
def correlation_from_t1(self, mode: str = 'raw', interpolate=False, omega=None,
|
def calculate_t1_min(self, interpolate: int = None, trange: Tuple[float, float] = None, use_log: bool = False) -> \
|
||||||
dist_parameter: list = None, prefactor: float = None,
|
Tuple[Tuple[float, float], Optional[Tuple[np.ndarray, np.ndarray]]]:
|
||||||
coupling_param: list = None, coupling_kwargs: dict = None):
|
min_index = np.argmin(self.y)
|
||||||
|
t1_min = (self.x[min_index], self.y[min_index])
|
||||||
|
parabola = None
|
||||||
|
self._interpolate_range = (None, None)
|
||||||
|
|
||||||
|
if interpolate is not None:
|
||||||
|
if interpolate not in [0, 1, 2, 3]:
|
||||||
|
raise ValueError(f'Unknown interpolation value {interpolate}')
|
||||||
|
|
||||||
|
if interpolate != 0:
|
||||||
|
if trange is None:
|
||||||
|
left_b = max(min_index - 2, 0)
|
||||||
|
right_b = min(len(self.x), min_index + 3)
|
||||||
|
else:
|
||||||
|
left_b = np.argmin(np.abs(self.x - trange[0]))
|
||||||
|
right_b = np.argmin(np.abs(self.x - trange[1])) + 1
|
||||||
|
|
||||||
|
temp_range = self.x[left_b:right_b]
|
||||||
|
t1_range = self.y[left_b:right_b]
|
||||||
|
if use_log:
|
||||||
|
t1_range = np.log10(t1_range)
|
||||||
|
|
||||||
|
try:
|
||||||
|
x_inter = np.linspace(temp_range[0], temp_range[-1], num=51)
|
||||||
|
|
||||||
|
if interpolate == 1:
|
||||||
|
i_func = np.poly1d(np.polyfit(temp_range, t1_range, 2))
|
||||||
|
elif interpolate == 2:
|
||||||
|
i_func = interp1d(temp_range, t1_range, kind='cubic')
|
||||||
|
else:
|
||||||
|
i_func = Akima1DInterpolator(temp_range, t1_range)
|
||||||
|
|
||||||
|
if use_log:
|
||||||
|
y_inter = 10**i_func(x_inter)
|
||||||
|
else:
|
||||||
|
y_inter = i_func(x_inter)
|
||||||
|
t1_min = (x_inter[np.argmin(y_inter)], y_inter[np.argmin(y_inter)])
|
||||||
|
self._interpolate = i_func
|
||||||
|
parabola = (x_inter, y_inter)
|
||||||
|
self._interpolate_range = (temp_range[0], temp_range[-1])
|
||||||
|
t1_min = x_inter[np.argmin(y_inter)], y_inter[np.argmin(y_inter)]
|
||||||
|
|
||||||
|
except IndexError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
self.t1min = t1_min
|
||||||
|
|
||||||
|
return t1_min, parabola
|
||||||
|
|
||||||
|
def correlation_from_t1(self, mode: str = 'raw', interpolate: bool = False, omega: float = None,
|
||||||
|
dist_parameter: Union[float, list, tuple] = None, prefactor: Union[float, tuple, list] = None,
|
||||||
|
coupling_param: list = None, coupling_kwargs: dict = None) -> Tuple[np.ndarray, dict]:
|
||||||
|
|
||||||
if self.x is None:
|
if self.x is None:
|
||||||
raise ValueError('Temperature is not set')
|
raise ValueError('Temperature is not set')
|
||||||
@@ -317,40 +651,40 @@ class RelaxationEvaluation(Relaxation):
|
|||||||
|
|
||||||
if prefactor is None:
|
if prefactor is None:
|
||||||
if coupling_kwargs is None:
|
if coupling_kwargs is None:
|
||||||
coupling_kwargs = self._coup_kw
|
coupling_kwargs = self.coup_kw
|
||||||
|
|
||||||
if coupling_param is None:
|
if coupling_param is None:
|
||||||
prefactor = self._prefactor
|
prefactor = self.prefactor
|
||||||
else:
|
else:
|
||||||
prefactor = self._coupling.func(*coupling_param, **coupling_kwargs)
|
prefactor = self.coupling.relax(*coupling_param, **coupling_kwargs)
|
||||||
|
|
||||||
if dist_parameter is None:
|
if dist_parameter is None:
|
||||||
dist_parameter = self._dist_parameter
|
dist_parameter = self.dist_parameter
|
||||||
|
|
||||||
fast_idx = self.x > self.t1min[0]
|
fast_idx = self.x > self.t1min[0]
|
||||||
|
|
||||||
slow_t1 = self.y[~fast_idx]
|
slow_t1 = self.y[~fast_idx]
|
||||||
slow_temp = self.x[~fast_idx]
|
slow_temp = self.x[~fast_idx]
|
||||||
|
|
||||||
correlation_times = np.ones(self.x.shape)
|
correlation_times = np.ones_like(self.x)
|
||||||
offset = len(slow_t1)
|
offset = len(slow_t1)
|
||||||
|
|
||||||
base_taus = np.logspace(-10, -7, num=1001)
|
base_taus = np.logspace(-10, -7, num=1001)
|
||||||
min_tau = base_taus[np.argmin(self.t1(omega, base_taus, *dist_parameter, prefactor=prefactor))]
|
min_tau = base_taus[np.argmin(self.t1(omega, base_taus, *dist_parameter, prefactor=prefactor))]
|
||||||
|
|
||||||
taus = np.geomspace(min_tau, 100.*min_tau, num=501)
|
taus = np.geomspace(min_tau, 100. * min_tau, num=501)
|
||||||
current_t1 = self.t1(omega, taus, *dist_parameter, prefactor=prefactor)
|
current_t1 = self.t1(omega, taus, *dist_parameter, prefactor=prefactor)
|
||||||
|
|
||||||
for i in range(1, len(slow_t1)+1):
|
for i in range(1, len(slow_t1) + 1):
|
||||||
t1_i = slow_t1[-i]
|
t1_i = slow_t1[-i]
|
||||||
|
|
||||||
if interpolate and self._interpolate is not None:
|
if interpolate and self._interpolate is not None:
|
||||||
if slow_temp[-i] >= self._interpolate_range[0]:
|
if slow_temp[-i] >= self._interpolate_range[0]:
|
||||||
t1_i = self._interpolate(slow_temp[-i])
|
t1_i = self._interpolate(slow_temp[-i])
|
||||||
|
|
||||||
if min(current_t1) > t1_i:
|
if np.min(current_t1) > t1_i:
|
||||||
warn('Correlation time could not be calculated')
|
warn('Correlation time could not be calculated')
|
||||||
correlation_times[offset-i] = taus[0]
|
correlation_times[offset - i] = taus[0]
|
||||||
continue
|
continue
|
||||||
|
|
||||||
cross_idx = np.where(np.diff(np.sign(current_t1 - t1_i)))[0]
|
cross_idx = np.where(np.diff(np.sign(current_t1 - t1_i)))[0]
|
||||||
@@ -359,13 +693,13 @@ class RelaxationEvaluation(Relaxation):
|
|||||||
current_t1 = self.t1(omega, taus, *dist_parameter, prefactor=prefactor)
|
current_t1 = self.t1(omega, taus, *dist_parameter, prefactor=prefactor)
|
||||||
cross_idx = np.where(np.diff(np.sign(current_t1 - t1_i)))[0]
|
cross_idx = np.where(np.diff(np.sign(current_t1 - t1_i)))[0]
|
||||||
|
|
||||||
lamb = (t1_i - current_t1[cross_idx]) / (current_t1[cross_idx+1]-current_t1[cross_idx])
|
lamb = (t1_i - current_t1[cross_idx]) / (current_t1[cross_idx + 1] - current_t1[cross_idx])
|
||||||
correlation_times[offset-i] = (taus[cross_idx+1] * lamb + (1 - lamb) * taus[cross_idx])[0]
|
correlation_times[offset - i] = (taus[cross_idx + 1] * lamb + (1 - lamb) * taus[cross_idx])[0]
|
||||||
|
|
||||||
fast_t1 = self.y[fast_idx]
|
fast_t1 = self.y[fast_idx]
|
||||||
fast_temp = self.x[fast_idx]
|
fast_temp = self.x[fast_idx]
|
||||||
|
|
||||||
taus = np.geomspace(0.01*min_tau, min_tau, num=501)
|
taus = np.geomspace(0.01 * min_tau, min_tau, num=501)
|
||||||
current_t1 = self.t1(omega, taus, *dist_parameter, prefactor=prefactor)
|
current_t1 = self.t1(omega, taus, *dist_parameter, prefactor=prefactor)
|
||||||
|
|
||||||
for i in range(len(fast_t1)):
|
for i in range(len(fast_t1)):
|
||||||
@@ -376,8 +710,8 @@ class RelaxationEvaluation(Relaxation):
|
|||||||
t1_i = self._interpolate(fast_temp[i])
|
t1_i = self._interpolate(fast_temp[i])
|
||||||
|
|
||||||
if current_t1[-1] > t1_i:
|
if current_t1[-1] > t1_i:
|
||||||
correlation_times[offset+i] = taus[-1]
|
correlation_times[offset + i] = taus[-1]
|
||||||
warn('Correlation time could not be calculated')
|
warn(f'Correlation time for {correlation_times[offset + i]} could not be calculated')
|
||||||
continue
|
continue
|
||||||
|
|
||||||
cross_idx = np.where(np.diff(np.sign(current_t1 - t1_i)))[0]
|
cross_idx = np.where(np.diff(np.sign(current_t1 - t1_i)))[0]
|
||||||
@@ -386,19 +720,22 @@ class RelaxationEvaluation(Relaxation):
|
|||||||
current_t1 = self.t1(omega, taus, *dist_parameter, prefactor=prefactor)
|
current_t1 = self.t1(omega, taus, *dist_parameter, prefactor=prefactor)
|
||||||
cross_idx = np.where(np.diff(np.sign(current_t1 - t1_i)))[0]
|
cross_idx = np.where(np.diff(np.sign(current_t1 - t1_i)))[0]
|
||||||
|
|
||||||
lamb = (t1_i - current_t1[cross_idx]) / (current_t1[cross_idx+1]-current_t1[cross_idx])
|
lamb = (t1_i - current_t1[cross_idx]) / (current_t1[cross_idx + 1] - current_t1[cross_idx])
|
||||||
correlation_times[offset+i] = (taus[cross_idx+1] * lamb + (1-lamb) * taus[cross_idx])[0]
|
correlation_times[offset + i] = (taus[cross_idx + 1] * lamb + (1 - lamb) * taus[cross_idx])[0]
|
||||||
|
|
||||||
opts = {'distribution': (self._distribution.name, dist_parameter),
|
opts = {'distribution': (self.distribution.name, dist_parameter),
|
||||||
'coupling': (self._coupling.name, coupling_param, coupling_kwargs),
|
'frequency': omega / 2 / np.pi}
|
||||||
'frequency': omega/2/np.pi}
|
if self.coupling is not None:
|
||||||
|
opts['coupling'] = (self.coupling.name, self.prefactor, coupling_param, coupling_kwargs)
|
||||||
|
else:
|
||||||
|
opts['coupling'] = (self.prefactor,)
|
||||||
|
|
||||||
return np.c_[self.x, self._distribution.mean_value(correlation_times, *dist_parameter, mode=mode)], opts
|
return np.c_[self.x, self.distribution.mean_value(correlation_times, *dist_parameter, mode=mode)], opts
|
||||||
|
|
||||||
def _create_minimum_file(self, filename):
|
def _create_minimum_file(self, filename):
|
||||||
x = np.geomspace(0.1, 1, num=10001)
|
x = np.geomspace(0.1, 1, num=10001)
|
||||||
with Path(filename).open('w') as f:
|
with Path(filename).open('w') as f:
|
||||||
f.write('#broadening\tT1_min/min_Debye\n')
|
f.write('# broadening\tT1_min/min_Debye\n')
|
||||||
for i, a in enumerate(np.geomspace(0.1, 10, num=10000)):
|
for i, a in enumerate(np.geomspace(0.1, 10, num=10000)):
|
||||||
alpha = a
|
alpha = a
|
||||||
t1_i = self.t1_bpp(1, x, alpha)
|
t1_i = self.t1_bpp(1, x, alpha)
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ __all__ = ['NA', 'kb_joule', 'h_joule', 'hbar_joule',
|
|||||||
NA = 6.02214076e23
|
NA = 6.02214076e23
|
||||||
kb_joule = 1.380649e-23
|
kb_joule = 1.380649e-23
|
||||||
e = 1.602176634e-19
|
e = 1.602176634e-19
|
||||||
h_joule = 6.62607015e-23
|
h_joule = 6.62606896e-34
|
||||||
mu0 = 1.256637062124e-6
|
mu0 = 1.256637062124e-6
|
||||||
epsilon0 = 8.8541878128e-12
|
epsilon0 = 8.8541878128e-12
|
||||||
|
|
||||||
@@ -38,7 +38,7 @@ spintxt = """\
|
|||||||
9Be 3/2 100 -3.759666 5.288
|
9Be 3/2 100 -3.759666 5.288
|
||||||
10B 3 19.9 2.8746786 8.459
|
10B 3 19.9 2.8746786 8.459
|
||||||
11B 3/2 80.1 8.5847044 4.059
|
11B 3/2 80.1 8.5847044 4.059
|
||||||
13C 1/2 1.07 6.728 284
|
13C 1/2 1.07 6.728284
|
||||||
14N 1 99.632 1.9337792 2.044
|
14N 1 99.632 1.9337792 2.044
|
||||||
15N 1/2 0.368 -2.71261804
|
15N 1/2 0.368 -2.71261804
|
||||||
17O 5/2 0.038 -3.62808 -2.558
|
17O 5/2 0.038 -3.62808 -2.558
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ small_greek = [
|
|||||||
r'\f{Symbol}s\f{} \f{Symbol}t\f{} \f{Symbol}u\f{} \f{Symbol}f\f{} \f{Symbol}c\f{} \f{Symbol}y\f{} '
|
r'\f{Symbol}s\f{} \f{Symbol}t\f{} \f{Symbol}u\f{} \f{Symbol}f\f{} \f{Symbol}c\f{} \f{Symbol}y\f{} '
|
||||||
r'\f{Symbol}w\f{}',
|
r'\f{Symbol}w\f{}',
|
||||||
'alpha beta gamma delta epsilon zeta eta theta iota kappa lambda mu nu ' # plain
|
'alpha beta gamma delta epsilon zeta eta theta iota kappa lambda mu nu ' # plain
|
||||||
'xi omicron pi rho sigma sigma tau ypsilon phi chi psi omega'
|
'xi omicron pi rho sigma sigma tau ypsilon phi chi psi omega',
|
||||||
]
|
]
|
||||||
big_greek = [
|
big_greek = [
|
||||||
r'\Alpha \Beta \Gamma \Delta \Epsilon \Zeta \Eta \Theta \Iota \Kappa \Lambda \Mu ' # tex
|
r'\Alpha \Beta \Gamma \Delta \Epsilon \Zeta \Eta \Theta \Iota \Kappa \Lambda \Mu ' # tex
|
||||||
@@ -28,7 +28,7 @@ big_greek = [
|
|||||||
r'\f{Symbol}N\f{} \f{Symbol}X\f{} \f{Symbol}O\f{} \f{Symbol}P\f{} \f{Symbol}R\f{} \f{Symbol}S\f{} '
|
r'\f{Symbol}N\f{} \f{Symbol}X\f{} \f{Symbol}O\f{} \f{Symbol}P\f{} \f{Symbol}R\f{} \f{Symbol}S\f{} '
|
||||||
r'\f{Symbol}T\f{} \f{Symbol}Y\f{} \f{Symbol}F\f{} \f{Symbol}C\f{} \f{Symbol}U\f{} \f{Symbol}W\f{}',
|
r'\f{Symbol}T\f{} \f{Symbol}Y\f{} \f{Symbol}F\f{} \f{Symbol}C\f{} \f{Symbol}U\f{} \f{Symbol}W\f{}',
|
||||||
'Alpha Beta Gamma Delta Epsilon Zeta Eta Theta Iota Kappa Lambda Mu ' # plain
|
'Alpha Beta Gamma Delta Epsilon Zeta Eta Theta Iota Kappa Lambda Mu ' # plain
|
||||||
'Nu Xi Omicron Pi Rho Sigma Tau Ypsilon Phi Chi Psi Omega'
|
'Nu Xi Omicron Pi Rho Sigma Tau Ypsilon Phi Chi Psi Omega',
|
||||||
]
|
]
|
||||||
special_chars = [
|
special_chars = [
|
||||||
r'\infty \int \sum \langle \rangle \pm \perp \para \leftarrow \rightarrow \leftrightarrow \cdot \hbar',
|
r'\infty \int \sum \langle \rangle \pm \perp \para \leftarrow \rightarrow \leftrightarrow \cdot \hbar',
|
||||||
@@ -36,13 +36,13 @@ special_chars = [
|
|||||||
r'\f{Symbol}¥\f{} \f{Symbol}ò\f{} \f{Symbol}å\f{} \f{Symbol}á\f{} \f{Symbol}ñ\f{} \f{Symbol}±\f{} '
|
r'\f{Symbol}¥\f{} \f{Symbol}ò\f{} \f{Symbol}å\f{} \f{Symbol}á\f{} \f{Symbol}ñ\f{} \f{Symbol}±\f{} '
|
||||||
r'\f{Symbol}^\f{} \f{Symbol}||\f{} \f{Symbol}¬\f{} \f{Symbol}®\f{} \f{Symbol}«\f{} \f{Symbol}×\f{Symbol} '
|
r'\f{Symbol}^\f{} \f{Symbol}||\f{} \f{Symbol}¬\f{} \f{Symbol}®\f{} \f{Symbol}«\f{} \f{Symbol}×\f{Symbol} '
|
||||||
r'h\h{-0.6}\v{0.3}-\v{-0.3}\h{0.3}',
|
r'h\h{-0.6}\v{0.3}-\v{-0.3}\h{0.3}',
|
||||||
'infty int sum < > +- perp para <- -> <-> * hbar'
|
r'infty int sum < > \+- perp para <- -> <-> \* hbar',
|
||||||
]
|
]
|
||||||
funcs = [
|
funcs = [
|
||||||
r'\exp \log \ln \sin \cos \tan',
|
r'\exp \log \ln \sin \cos \tan',
|
||||||
'exp log ln sin cos tan',
|
'exp log ln sin cos tan',
|
||||||
'exp log ln sin cos tan',
|
'exp log ln sin cos tan',
|
||||||
'exp log ln sin cos tan'
|
'exp log ln sin cos tan',
|
||||||
]
|
]
|
||||||
delims = [
|
delims = [
|
||||||
[(r'_{', r'}'), (r'<sub>', r'</sub>'), (r'\\s', r'\\N'), (r'_{', r'}')],
|
[(r'_{', r'}'), (r'<sub>', r'</sub>'), (r'\\s', r'\\N'), (r'_{', r'}')],
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
matplotlib
|
||||||
|
numpy
|
||||||
|
scipy
|
||||||
|
pyqtgraph
|
||||||
|
bsddb3
|
||||||
|
h5py
|
||||||
|
PyQt5
|
||||||
|
|
||||||
@@ -353,6 +353,9 @@
|
|||||||
<addaction name="actionSave"/>
|
<addaction name="actionSave"/>
|
||||||
<addaction name="separator"/>
|
<addaction name="separator"/>
|
||||||
<addaction name="actionMouse_behaviour"/>
|
<addaction name="actionMouse_behaviour"/>
|
||||||
|
<addaction name="separator"/>
|
||||||
|
<addaction name="actionPrevious"/>
|
||||||
|
<addaction name="actionNext_window"/>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QToolBar" name="toolbar_edit">
|
<widget class="QToolBar" name="toolbar_edit">
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
|
|||||||
+188
-73
@@ -6,15 +6,30 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>400</width>
|
<width>544</width>
|
||||||
<height>319</height>
|
<height>443</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
<string>Read BDS data</string>
|
<string>Read BDS data</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QGridLayout" name="gridLayout">
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
<item row="1" column="0">
|
<property name="leftMargin">
|
||||||
|
<number>3</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>3</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>3</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>3</number>
|
||||||
|
</property>
|
||||||
|
<property name="spacing">
|
||||||
|
<number>3</number>
|
||||||
|
</property>
|
||||||
|
<item row="1" column="0" rowspan="2">
|
||||||
<widget class="QListWidget" name="listWidget">
|
<widget class="QListWidget" name="listWidget">
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
<sizepolicy hsizetype="Expanding" vsizetype="MinimumExpanding">
|
<sizepolicy hsizetype="Expanding" vsizetype="MinimumExpanding">
|
||||||
@@ -24,74 +39,150 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="0" column="0">
|
|
||||||
<widget class="QLabel" name="label">
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Found temperatures</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="0" column="1">
|
|
||||||
<widget class="QLabel" name="label_2">
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Read as:</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="1" column="1">
|
<item row="1" column="1">
|
||||||
<layout class="QVBoxLayout" name="verticalLayout">
|
<widget class="QGroupBox" name="groupBox_2">
|
||||||
<item>
|
<property name="title">
|
||||||
<widget class="QCheckBox" name="eps_checkBox">
|
<string>X Axis</string>
|
||||||
<property name="text">
|
</property>
|
||||||
<string>Permittivity ε</string>
|
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||||
</property>
|
<property name="spacing">
|
||||||
<property name="checked">
|
<number>3</number>
|
||||||
<bool>true</bool>
|
</property>
|
||||||
</property>
|
<property name="leftMargin">
|
||||||
</widget>
|
<number>3</number>
|
||||||
</item>
|
</property>
|
||||||
<item>
|
<property name="topMargin">
|
||||||
<widget class="QCheckBox" name="modul_checkBox">
|
<number>3</number>
|
||||||
<property name="text">
|
</property>
|
||||||
<string>Modulus 1/ε</string>
|
<property name="rightMargin">
|
||||||
</property>
|
<number>3</number>
|
||||||
</widget>
|
</property>
|
||||||
</item>
|
<property name="bottomMargin">
|
||||||
<item>
|
<number>3</number>
|
||||||
<widget class="QCheckBox" name="cond_checkBox">
|
</property>
|
||||||
<property name="text">
|
<item>
|
||||||
<string>Conductivity iεω</string>
|
<widget class="QRadioButton" name="freq_button">
|
||||||
</property>
|
<property name="text">
|
||||||
</widget>
|
<string>Frequency</string>
|
||||||
</item>
|
</property>
|
||||||
<item>
|
<property name="checked">
|
||||||
<spacer name="verticalSpacer">
|
<bool>true</bool>
|
||||||
<property name="orientation">
|
</property>
|
||||||
<enum>Qt::Vertical</enum>
|
<attribute name="buttonGroup">
|
||||||
</property>
|
<string notr="true">buttonGroup</string>
|
||||||
<property name="sizeHint" stdset="0">
|
</attribute>
|
||||||
<size>
|
</widget>
|
||||||
<width>20</width>
|
</item>
|
||||||
<height>40</height>
|
<item>
|
||||||
</size>
|
<widget class="QRadioButton" name="temp_button">
|
||||||
</property>
|
<property name="text">
|
||||||
</spacer>
|
<string>Temperature</string>
|
||||||
</item>
|
</property>
|
||||||
</layout>
|
<attribute name="buttonGroup">
|
||||||
|
<string notr="true">buttonGroup</string>
|
||||||
|
</attribute>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="2" column="0" colspan="2">
|
<item row="2" column="1">
|
||||||
|
<widget class="QGroupBox" name="groupBox">
|
||||||
|
<property name="title">
|
||||||
|
<string>Y Axis</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||||
|
<property name="spacing">
|
||||||
|
<number>3</number>
|
||||||
|
</property>
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>3</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>3</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>3</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>3</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="eps_checkBox">
|
||||||
|
<property name="text">
|
||||||
|
<string>Permittivity ε</string>
|
||||||
|
</property>
|
||||||
|
<property name="checked">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="modul_checkBox">
|
||||||
|
<property name="text">
|
||||||
|
<string>Modulus 1/ε</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="cond_checkBox">
|
||||||
|
<property name="text">
|
||||||
|
<string>Conductivity iεω</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="loss_checkBox">
|
||||||
|
<property name="text">
|
||||||
|
<string>Loss factor tan(δ)</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="Line" name="line">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="cap_checkBox">
|
||||||
|
<property name="text">
|
||||||
|
<string>Capacity</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="temp_checkBox">
|
||||||
|
<property name="text">
|
||||||
|
<string>Meas. temperature</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="time_checkBox">
|
||||||
|
<property name="text">
|
||||||
|
<string>Meas. time</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="verticalSpacer_2">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>40</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="0" colspan="2">
|
||||||
<widget class="QDialogButtonBox" name="buttonBox">
|
<widget class="QDialogButtonBox" name="buttonBox">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
<enum>Qt::Horizontal</enum>
|
<enum>Qt::Horizontal</enum>
|
||||||
@@ -101,8 +192,29 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item row="0" column="0" colspan="2">
|
||||||
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Found entries</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
|
<tabstops>
|
||||||
|
<tabstop>freq_button</tabstop>
|
||||||
|
<tabstop>temp_button</tabstop>
|
||||||
|
<tabstop>eps_checkBox</tabstop>
|
||||||
|
<tabstop>modul_checkBox</tabstop>
|
||||||
|
<tabstop>cond_checkBox</tabstop>
|
||||||
|
<tabstop>listWidget</tabstop>
|
||||||
|
</tabstops>
|
||||||
<resources/>
|
<resources/>
|
||||||
<connections>
|
<connections>
|
||||||
<connection>
|
<connection>
|
||||||
@@ -112,8 +224,8 @@
|
|||||||
<slot>accept()</slot>
|
<slot>accept()</slot>
|
||||||
<hints>
|
<hints>
|
||||||
<hint type="sourcelabel">
|
<hint type="sourcelabel">
|
||||||
<x>248</x>
|
<x>254</x>
|
||||||
<y>254</y>
|
<y>411</y>
|
||||||
</hint>
|
</hint>
|
||||||
<hint type="destinationlabel">
|
<hint type="destinationlabel">
|
||||||
<x>157</x>
|
<x>157</x>
|
||||||
@@ -128,8 +240,8 @@
|
|||||||
<slot>reject()</slot>
|
<slot>reject()</slot>
|
||||||
<hints>
|
<hints>
|
||||||
<hint type="sourcelabel">
|
<hint type="sourcelabel">
|
||||||
<x>316</x>
|
<x>322</x>
|
||||||
<y>260</y>
|
<y>411</y>
|
||||||
</hint>
|
</hint>
|
||||||
<hint type="destinationlabel">
|
<hint type="destinationlabel">
|
||||||
<x>286</x>
|
<x>286</x>
|
||||||
@@ -138,4 +250,7 @@
|
|||||||
</hints>
|
</hints>
|
||||||
</connection>
|
</connection>
|
||||||
</connections>
|
</connections>
|
||||||
|
<buttongroups>
|
||||||
|
<buttongroup name="buttonGroup"/>
|
||||||
|
</buttongroups>
|
||||||
</ui>
|
</ui>
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Reference in New Issue
Block a user