klassez 0.2.2.dev0__tar.gz → 0.3.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {klassez-0.2.2.dev0 → klassez-0.3.1}/PKG-INFO +2 -1
- {klassez-0.2.2.dev0 → klassez-0.3.1}/docs/requirements.txt +1 -0
- {klassez-0.2.2.dev0 → klassez-0.3.1}/klassez/Spectra.py +198 -22
- {klassez-0.2.2.dev0 → klassez-0.3.1}/klassez/__init__.py +1 -1
- {klassez-0.2.2.dev0 → klassez-0.3.1}/klassez/fit.py +4 -2
- {klassez-0.2.2.dev0 → klassez-0.3.1}/klassez/misc.py +143 -46
- {klassez-0.2.2.dev0 → klassez-0.3.1}/klassez/processing.py +68 -7
- {klassez-0.2.2.dev0 → klassez-0.3.1}/klassez/sim.py +95 -76
- {klassez-0.2.2.dev0 → klassez-0.3.1}/klassez/tables/gamma.dic +0 -0
- {klassez-0.2.2.dev0 → klassez-0.3.1}/klassez.egg-info/PKG-INFO +2 -1
- {klassez-0.2.2.dev0 → klassez-0.3.1}/klassez.egg-info/requires.txt +1 -0
- {klassez-0.2.2.dev0 → klassez-0.3.1}/pyproject.toml +1 -0
- {klassez-0.2.2.dev0 → klassez-0.3.1}/test/T1_90.procs +0 -0
- {klassez-0.2.2.dev0 → klassez-0.3.1}/test/T2_10.procs +0 -0
- {klassez-0.2.2.dev0 → klassez-0.3.1}/LICENSE.txt +0 -0
- {klassez-0.2.2.dev0 → klassez-0.3.1}/MANIFEST.in +0 -0
- {klassez-0.2.2.dev0 → klassez-0.3.1}/README.md +0 -0
- {klassez-0.2.2.dev0 → klassez-0.3.1}/docs/Makefile +0 -0
- {klassez-0.2.2.dev0 → klassez-0.3.1}/docs/make.bat +0 -0
- {klassez-0.2.2.dev0 → klassez-0.3.1}/klassez/anal.py +0 -0
- {klassez-0.2.2.dev0 → klassez-0.3.1}/klassez/config.py +0 -0
- {klassez-0.2.2.dev0 → klassez-0.3.1}/klassez/figures.py +0 -0
- {klassez-0.2.2.dev0 → klassez-0.3.1}/klassez/gui.py +0 -0
- {klassez-0.2.2.dev0 → klassez-0.3.1}/klassez/tables/nuclei_jeol.dic +0 -0
- {klassez-0.2.2.dev0 → klassez-0.3.1}/klassez/tables/xterm_colors +0 -0
- {klassez-0.2.2.dev0 → klassez-0.3.1}/klassez.egg-info/SOURCES.txt +0 -0
- {klassez-0.2.2.dev0 → klassez-0.3.1}/klassez.egg-info/dependency_links.txt +0 -0
- {klassez-0.2.2.dev0 → klassez-0.3.1}/klassez.egg-info/top_level.txt +0 -0
- {klassez-0.2.2.dev0 → klassez-0.3.1}/setup.cfg +0 -0
- {klassez-0.2.2.dev0 → klassez-0.3.1}/test/T1_0.00.procs +0 -0
- {klassez-0.2.2.dev0 → klassez-0.3.1}/test/T1_10.00.procs +0 -0
- {klassez-0.2.2.dev0 → klassez-0.3.1}/test/T1_180.00.procs +0 -0
- {klassez-0.2.2.dev0 → klassez-0.3.1}/test/T1_90.00.procs +0 -0
- {klassez-0.2.2.dev0 → klassez-0.3.1}/test/T2_10.00.procs +0 -0
- {klassez-0.2.2.dev0 → klassez-0.3.1}/test/acqus_1D +0 -0
- {klassez-0.2.2.dev0 → klassez-0.3.1}/test/acqus_1D.fvf +0 -0
- {klassez-0.2.2.dev0 → klassez-0.3.1}/test/acqus_1D.procs +0 -0
- {klassez-0.2.2.dev0 → klassez-0.3.1}/test/acqus_2D +0 -0
- {klassez-0.2.2.dev0 → klassez-0.3.1}/test/acqus_2D.procs +0 -0
- {klassez-0.2.2.dev0 → klassez-0.3.1}/test/cnvg +0 -0
- {klassez-0.2.2.dev0 → klassez-0.3.1}/test/fit_1D.py +0 -0
- {klassez-0.2.2.dev0 → klassez-0.3.1}/test/read_process_1D.py +0 -0
- {klassez-0.2.2.dev0 → klassez-0.3.1}/test/read_process_2D.py +0 -0
- {klassez-0.2.2.dev0 → klassez-0.3.1}/test/test.log +0 -0
- {klassez-0.2.2.dev0 → klassez-0.3.1}/test/test.py +0 -0
- {klassez-0.2.2.dev0 → klassez-0.3.1}/test/test_1D_fit.fvf +0 -0
- {klassez-0.2.2.dev0 → klassez-0.3.1}/test/test_1D_fit.ivf +0 -0
- {klassez-0.2.2.dev0 → klassez-0.3.1}/test/test_1D_fit_R1.png +0 -0
- {klassez-0.2.2.dev0 → klassez-0.3.1}/test/test_1D_fit_R2.png +0 -0
- {klassez-0.2.2.dev0 → klassez-0.3.1}/test/test_1D_fit_full.png +0 -0
- {klassez-0.2.2.dev0 → klassez-0.3.1}/test/test_1D_fit_rhist.png +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: klassez
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.1
|
|
4
4
|
Summary: A collection of functions for NMR data handling
|
|
5
5
|
Author: Letizia Fiorucci
|
|
6
6
|
Author-email: Francesco Bruno <bruno@cerm.unifi.it>
|
|
@@ -22,6 +22,7 @@ Requires-Dist: seaborn
|
|
|
22
22
|
Requires-Dist: nmrglue
|
|
23
23
|
Requires-Dist: matplotlib>=3.8
|
|
24
24
|
Requires-Dist: csaps
|
|
25
|
+
Requires-Dist: pyyaml
|
|
25
26
|
Provides-Extra: jeolproc
|
|
26
27
|
Requires-Dist: jeol_parser; extra == "jeolproc"
|
|
27
28
|
Provides-Extra: docs
|
|
@@ -128,7 +128,7 @@ class Spectrum_1D:
|
|
|
128
128
|
isexp : bool
|
|
129
129
|
True if this is an experimental dataset, False if it is simulated
|
|
130
130
|
spect : str
|
|
131
|
-
Data file format. Allowed: ``'bruker'``, ``'varian'``, ``'magritek'``, ``'oxford'``, ``'jeol'``
|
|
131
|
+
Data file format. Allowed: ``'bruker'``, ``'varian'``, ``'magritek'``, ``'oxford'``, ``'jeol'``, ``'nana'``
|
|
132
132
|
|
|
133
133
|
Returns
|
|
134
134
|
-------
|
|
@@ -412,6 +412,7 @@ class Spectrum_1D:
|
|
|
412
412
|
:func:`klassez.processing.apk`
|
|
413
413
|
"""
|
|
414
414
|
|
|
415
|
+
q = deepcopy(self.S)
|
|
415
416
|
self.S, (p0, p1) = processing.apk(self.ppm, self.S, self.acqus['SFO1'], alpha, winsize, ap1)
|
|
416
417
|
|
|
417
418
|
if update:
|
|
@@ -594,7 +595,7 @@ class Spectrum_1D:
|
|
|
594
595
|
def write_acqus(self, other_dir=None):
|
|
595
596
|
"""
|
|
596
597
|
Write the acqus dictionary in a file named ``<self.filename>.acqus``.
|
|
597
|
-
Calls :func:`klassez.misc.
|
|
598
|
+
Calls :func:`klassez.misc.write_acqus`
|
|
598
599
|
|
|
599
600
|
Parameters
|
|
600
601
|
----------
|
|
@@ -607,13 +608,13 @@ class Spectrum_1D:
|
|
|
607
608
|
|
|
608
609
|
.. seealso::
|
|
609
610
|
|
|
610
|
-
:func:`klassez.misc.
|
|
611
|
+
:func:`klassez.misc.write_acqus`
|
|
611
612
|
"""
|
|
612
613
|
if other_dir:
|
|
613
|
-
path = Path(other_dir) / f'{self.filename}
|
|
614
|
+
path = Path(other_dir) / f'{self.filename}'
|
|
614
615
|
else:
|
|
615
|
-
path = self.datadir / f'{self.filename}
|
|
616
|
-
misc.
|
|
616
|
+
path = self.datadir / f'{self.filename}'
|
|
617
|
+
misc.write_acqus(self.acqus, filename=path, ext='acqus')
|
|
617
618
|
|
|
618
619
|
def write_procs(self, other_dir=None):
|
|
619
620
|
"""
|
|
@@ -632,7 +633,7 @@ class Spectrum_1D:
|
|
|
632
633
|
path = Path(other_dir) / f'{self.filename}'
|
|
633
634
|
else:
|
|
634
635
|
path = self.datadir / f'{self.filename}'
|
|
635
|
-
|
|
636
|
+
misc.write_yml(self.procs, path, ext='procs')
|
|
636
637
|
|
|
637
638
|
def read_procs(self, other_dir=None):
|
|
638
639
|
"""
|
|
@@ -653,10 +654,10 @@ class Spectrum_1D:
|
|
|
653
654
|
Dictionary of processing parameters
|
|
654
655
|
"""
|
|
655
656
|
if other_dir:
|
|
656
|
-
path = Path(other_dir) / f'{self.filename}
|
|
657
|
+
path = Path(other_dir) / f'{self.filename}'
|
|
657
658
|
else:
|
|
658
|
-
path = self.datadir / f'{self.filename}
|
|
659
|
-
procs =
|
|
659
|
+
path = self.datadir / f'{self.filename}'
|
|
660
|
+
procs = misc.read_yml(path.with_suffix('.procs'))
|
|
660
661
|
# Check if it was read correctly
|
|
661
662
|
if isinstance(procs, dict):
|
|
662
663
|
return procs
|
|
@@ -1276,7 +1277,11 @@ class Spectrum_2D:
|
|
|
1276
1277
|
self.datadir, self.filename = misc.get_datadir_filename(in_file, isexp)
|
|
1277
1278
|
|
|
1278
1279
|
if isexp is False: # Simulate the data
|
|
1279
|
-
|
|
1280
|
+
if isinstance(in_file, dict): # using the provided dictionary
|
|
1281
|
+
self.acqus = deepcopy(in_file)
|
|
1282
|
+
else: # or building it from the file
|
|
1283
|
+
self.acqus = sim.load_sim_2D(in_file)
|
|
1284
|
+
# Generate the FID
|
|
1280
1285
|
self.acqus['FnMODE'] = 'States-TPPI'
|
|
1281
1286
|
self.acqus['GRPDLY'] = 0
|
|
1282
1287
|
self.fid = sim.sim_2D(in_file, pv=pv) # Read the FID
|
|
@@ -2006,7 +2011,7 @@ class Spectrum_2D:
|
|
|
2006
2011
|
def write_acqus(self, other_dir=None):
|
|
2007
2012
|
"""
|
|
2008
2013
|
Write the ``acqus`` dictionary in a file named "filename.acqus".
|
|
2009
|
-
Calls :func:`klassez.misc.
|
|
2014
|
+
Calls :func:`klassez.misc.write_acqus`
|
|
2010
2015
|
|
|
2011
2016
|
Parameters
|
|
2012
2017
|
----------
|
|
@@ -2019,14 +2024,14 @@ class Spectrum_2D:
|
|
|
2019
2024
|
|
|
2020
2025
|
.. seealso::
|
|
2021
2026
|
|
|
2022
|
-
:func:`klassez.misc.
|
|
2027
|
+
:func:`klassez.misc.write_acqus`
|
|
2023
2028
|
"""
|
|
2024
2029
|
if other_dir:
|
|
2025
2030
|
path = Path(other_dir) / f'{self.filename}'
|
|
2026
2031
|
else:
|
|
2027
2032
|
path = self.datadir / f'{self.filename}'
|
|
2028
2033
|
|
|
2029
|
-
misc.
|
|
2034
|
+
misc.write_acqus(self.acqus, filename=path, ext='acqus')
|
|
2030
2035
|
|
|
2031
2036
|
def write_procs(self, other_dir=None):
|
|
2032
2037
|
"""
|
|
@@ -2045,7 +2050,7 @@ class Spectrum_2D:
|
|
|
2045
2050
|
path = Path(other_dir) / f'{self.filename}'
|
|
2046
2051
|
else:
|
|
2047
2052
|
path = self.datadir / f'{self.filename}'
|
|
2048
|
-
|
|
2053
|
+
misc.write_yml(self.procs, path, ext='procs')
|
|
2049
2054
|
|
|
2050
2055
|
def read_procs(self, other_dir=None):
|
|
2051
2056
|
"""
|
|
@@ -2066,10 +2071,10 @@ class Spectrum_2D:
|
|
|
2066
2071
|
Dictionary of processing parameters
|
|
2067
2072
|
"""
|
|
2068
2073
|
if other_dir:
|
|
2069
|
-
path = Path(other_dir) / f'{self.filename}
|
|
2074
|
+
path = Path(other_dir) / f'{self.filename}'
|
|
2070
2075
|
else:
|
|
2071
|
-
path = self.datadir / f'{self.filename}
|
|
2072
|
-
procs =
|
|
2076
|
+
path = self.datadir / f'{self.filename}'
|
|
2077
|
+
procs = misc.read_yml(path.with_suffix('.procs'))
|
|
2073
2078
|
# Check if it was read correctly
|
|
2074
2079
|
if isinstance(procs, dict):
|
|
2075
2080
|
return procs
|
|
@@ -2200,6 +2205,7 @@ class Spectrum_2D:
|
|
|
2200
2205
|
label = f'{a:.2f}:{b:.2f}'
|
|
2201
2206
|
# Compute the trace
|
|
2202
2207
|
f2 = anal.get_trace(self.rr, self.ppm_f2, self.ppm_f1, a, b, column=False)
|
|
2208
|
+
f2 = processing.hilbert(f2)
|
|
2203
2209
|
# Store it
|
|
2204
2210
|
self.trf2[label] = f2
|
|
2205
2211
|
self.Trf2[label] = pSpectrum_1D(f2, acqus=misc.split_acqus_2D(self.acqus)[1], procs=misc.split_procs_2D(self.procs)[1], istrace=True, filename=f'T2_{label}')
|
|
@@ -2839,6 +2845,79 @@ class Pseudo_2D(Spectrum_2D):
|
|
|
2839
2845
|
|
|
2840
2846
|
return values
|
|
2841
2847
|
|
|
2848
|
+
def adjph_rw(self, auto=True, alpha=3, winsize=50, ap1=True, from_procs=True, update=True):
|
|
2849
|
+
"""
|
|
2850
|
+
Performs automatic phase correction of each transient independently.
|
|
2851
|
+
The values are saved in ``self.procs['phtr']``.
|
|
2852
|
+
|
|
2853
|
+
Parameters
|
|
2854
|
+
----------
|
|
2855
|
+
auto : bool
|
|
2856
|
+
``True`` for using :func:`klassez.processing.apk`, ``False`` to phase each transient manually.
|
|
2857
|
+
alpha : float
|
|
2858
|
+
Factor that multiplies the std of the spectrum to set the threshold
|
|
2859
|
+
winsize : float
|
|
2860
|
+
Minimum size of the window that can contain peaks /Hz
|
|
2861
|
+
ap1 : bool
|
|
2862
|
+
``True`` to adjust both zero and first order, ``False`` for only phase zero
|
|
2863
|
+
from_procs : bool
|
|
2864
|
+
If ``True``, uses the values in ``self.procs['phtr']``
|
|
2865
|
+
update : bool
|
|
2866
|
+
Choose if to update the ``procs`` dictionary or not
|
|
2867
|
+
|
|
2868
|
+
Returns
|
|
2869
|
+
-------
|
|
2870
|
+
phases : 2darray
|
|
2871
|
+
Employed values for each transient, in the form ``[p0, p1, pivot]``.
|
|
2872
|
+
|
|
2873
|
+
|
|
2874
|
+
.. seealso::
|
|
2875
|
+
|
|
2876
|
+
:func:`klassez.processing.apk`
|
|
2877
|
+
|
|
2878
|
+
:func:`klassez.processing.adjph_rowwise`
|
|
2879
|
+
"""
|
|
2880
|
+
newS = deepcopy(self.S)
|
|
2881
|
+
# If there is not the correct key in procs, act like from_procs is False
|
|
2882
|
+
if 'phtr' not in self.procs:
|
|
2883
|
+
from_procs = False
|
|
2884
|
+
|
|
2885
|
+
if from_procs:
|
|
2886
|
+
# Key found
|
|
2887
|
+
print('Phase correction row-wise applied with values from procs.', c='violet')
|
|
2888
|
+
# Copy to avoid conflict when calling write_procs at the end with update=True
|
|
2889
|
+
phases = np.asarray(deepcopy(self.procs['phtr']))
|
|
2890
|
+
|
|
2891
|
+
for k, transient in enumerate(self.S):
|
|
2892
|
+
# Unpack the values
|
|
2893
|
+
p0, p1, pv = phases[k]
|
|
2894
|
+
# Apply the correction
|
|
2895
|
+
newS[k], *_ = processing.ps(transient, self.ppm_f2, p0=p0, p1=p1, pivot=pv)
|
|
2896
|
+
|
|
2897
|
+
elif auto: # from_procs = False and auto = True
|
|
2898
|
+
# Calls the correct function in processing
|
|
2899
|
+
newS, phases = processing.adjph_rowwise(self.ppm_f2, self.S, self.acqus['SFO1'],
|
|
2900
|
+
alpha=alpha, winsize=winsize, ap1=ap1)
|
|
2901
|
+
|
|
2902
|
+
else: # from_procs = False and auto = False
|
|
2903
|
+
# Placeholder
|
|
2904
|
+
phases = []
|
|
2905
|
+
for k, transient in enumerate(self.S):
|
|
2906
|
+
print(f'Phasing transient {k+1} of {self.S.shape[0]}', c='violet')
|
|
2907
|
+
# Call manual phase correction in interactive panel
|
|
2908
|
+
newS[k], values = processing.ps(transient, self.ppm_f2)
|
|
2909
|
+
phases.append(values)
|
|
2910
|
+
# Make array to avoid conflict
|
|
2911
|
+
phases = np.asarray(phases)
|
|
2912
|
+
|
|
2913
|
+
self.S = newS
|
|
2914
|
+
if update:
|
|
2915
|
+
# Add/replace the key in procs and write the file
|
|
2916
|
+
self.procs['phtr'] = np.array([vvv for vvv in phases.tolist()])
|
|
2917
|
+
self.write_procs()
|
|
2918
|
+
|
|
2919
|
+
return phases
|
|
2920
|
+
|
|
2842
2921
|
def pknl(self):
|
|
2843
2922
|
"""
|
|
2844
2923
|
Reverses the effect of the digital filter by applying a first order phase correction.
|
|
@@ -2916,6 +2995,7 @@ class Pseudo_2D(Spectrum_2D):
|
|
|
2916
2995
|
label = f'{a:.2f}:{b:.2f}'
|
|
2917
2996
|
# Compute the trace
|
|
2918
2997
|
f2 = anal.get_trace(self.rr, self.ppm_f2, self.ppm_f1, a, b, column=False)
|
|
2998
|
+
f2 = processing.hilbert(f2)
|
|
2919
2999
|
# Store it
|
|
2920
3000
|
self.trf2[label] = f2
|
|
2921
3001
|
self.Trf2[label] = pSpectrum_1D(f2, acqus=self.acqus, procs=self.procs, istrace=True)
|
|
@@ -3867,7 +3947,7 @@ class DOSY_T1:
|
|
|
3867
3947
|
path = Path(other_dir) / f'{self.filename}'
|
|
3868
3948
|
else:
|
|
3869
3949
|
path = self.datadir / f'{self.filename}'
|
|
3870
|
-
|
|
3950
|
+
misc.write_yml(self.procs, path, ext='procs')
|
|
3871
3951
|
|
|
3872
3952
|
def read_procs(self, other_dir=None):
|
|
3873
3953
|
"""
|
|
@@ -3891,7 +3971,7 @@ class DOSY_T1:
|
|
|
3891
3971
|
path = Path(other_dir) / f'{self.filename}.procs'
|
|
3892
3972
|
else:
|
|
3893
3973
|
path = self.datadir / f'{self.filename}.procs'
|
|
3894
|
-
procs =
|
|
3974
|
+
procs = misc.read_yml(path.with_suffix('.procs'))
|
|
3895
3975
|
# Check if it was read correctly
|
|
3896
3976
|
if isinstance(procs, dict):
|
|
3897
3977
|
return procs
|
|
@@ -3996,7 +4076,7 @@ class DOSY_T1:
|
|
|
3996
4076
|
figures.plot_p3D(x_f1, x_f2, idx_scale, self.S.real, dim=dim, Neg=Neg,
|
|
3997
4077
|
name=name, X_label=X_label, Y_label=Y_label, lvl0=lvl0)
|
|
3998
4078
|
|
|
3999
|
-
def integrate(self, filename=None):
|
|
4079
|
+
def integrate(self, filename=None, keys=None):
|
|
4000
4080
|
"""
|
|
4001
4081
|
Create the attribute ``self.D`` as ``klassez.fit.DosyFit_pp3D``, and integrate the planes along the `31` direction.
|
|
4002
4082
|
|
|
@@ -4004,6 +4084,8 @@ class DOSY_T1:
|
|
|
4004
4084
|
----------
|
|
4005
4085
|
filename : str or None
|
|
4006
4086
|
Custom filename for data and plots. If ``None``, ``self.filename`` is used.
|
|
4087
|
+
keys : list of str
|
|
4088
|
+
Keys that identify the regions to integrate. If None, the integration is performed interactively through GUI
|
|
4007
4089
|
|
|
4008
4090
|
Returns
|
|
4009
4091
|
-------
|
|
@@ -4017,4 +4099,98 @@ class DOSY_T1:
|
|
|
4017
4099
|
if filename is None:
|
|
4018
4100
|
filename = self.filename
|
|
4019
4101
|
filename = Path(filename)
|
|
4020
|
-
self.D = fit.DosyFit_pp3D(self, datadir=filename, filename=filename)
|
|
4102
|
+
self.D = fit.DosyFit_pp3D(self, datadir=filename, filename=filename, keys=keys)
|
|
4103
|
+
|
|
4104
|
+
|
|
4105
|
+
class DOSY_SSel(DOSY_T1):
|
|
4106
|
+
"""
|
|
4107
|
+
Class: 3D DOSY spectrum
|
|
4108
|
+
|
|
4109
|
+
It should be acquired with the sequence described in
|
|
4110
|
+
`Novakovic M. et al. (2025), Nature Communications, 16(1), 4628`_,
|
|
4111
|
+
Supporting Information, Figure 12a.
|
|
4112
|
+
This sequence, adapted in the pulse program ``stebpgp1s193D.rav``,
|
|
4113
|
+
evolves the big delta (``d20``) in dimension F2 and the gradient strength according to
|
|
4114
|
+
the `difflist` in dimension F1.
|
|
4115
|
+
This sequence is actually equivalent to acquiring separate DOSY with different ``d20``.
|
|
4116
|
+
|
|
4117
|
+
|
|
4118
|
+
.. _Novakovic M. et al. (2025), Nature Communications, 16(1), 4628: https://www.nature.com/articles/s41467-025-59759-2
|
|
4119
|
+
|
|
4120
|
+
Attributes
|
|
4121
|
+
----------
|
|
4122
|
+
datadir : str
|
|
4123
|
+
Path to the input file/dataset directory
|
|
4124
|
+
filename : str
|
|
4125
|
+
Base of the name of the file, without extensions
|
|
4126
|
+
fid : 3darray
|
|
4127
|
+
FID
|
|
4128
|
+
acqus : dict
|
|
4129
|
+
Dictionary of acqusition parameters
|
|
4130
|
+
ngdic : dict
|
|
4131
|
+
Created only if it is an experimental spectrum. Generated by :func:`nmrglue.<spectrometer>.read`, contains all the information on the spectrometer and on the spectrum.
|
|
4132
|
+
procs : dict
|
|
4133
|
+
Dictionary of processing parameters
|
|
4134
|
+
S : 3darray
|
|
4135
|
+
Complex (or hypercomplex, depending on ``FnMODE``) spectrum
|
|
4136
|
+
x_f1 : 1darray
|
|
4137
|
+
gradient list
|
|
4138
|
+
x_f2 : 1darray
|
|
4139
|
+
big delta list
|
|
4140
|
+
freq_f2 : 1darray
|
|
4141
|
+
Frequency scale of the direct dimension, in Hz
|
|
4142
|
+
ppm_f2 : 1darray
|
|
4143
|
+
ppm scale of the direct dimension
|
|
4144
|
+
"""
|
|
4145
|
+
|
|
4146
|
+
def __init__(self, in_file):
|
|
4147
|
+
"""
|
|
4148
|
+
Initialize the class.
|
|
4149
|
+
|
|
4150
|
+
Parameters
|
|
4151
|
+
----------
|
|
4152
|
+
in_file : str
|
|
4153
|
+
path to file to read, or to the folder of the spectrum
|
|
4154
|
+
"""
|
|
4155
|
+
self.datadir, self.filename = misc.get_datadir_filename(in_file, isexp=True)
|
|
4156
|
+
|
|
4157
|
+
with warnings.catch_warnings(): # Suppress errors due to CONVDTA in TopSpin
|
|
4158
|
+
warnings.simplefilter("ignore")
|
|
4159
|
+
# Read the data, acquisition parameters...
|
|
4160
|
+
dic, data = ng.bruker.read(in_file, cplex=True)
|
|
4161
|
+
self.ngdic = dic
|
|
4162
|
+
self.fid = data
|
|
4163
|
+
self.acqus = misc.makeacqus_pp3D(dic)
|
|
4164
|
+
self.fid = np.reshape(self.fid, (self.acqus['TD1'], self.acqus['TD2'], -1))
|
|
4165
|
+
self.acqus['BYTORDA'] = dic['acqus']['BYTORDA']
|
|
4166
|
+
self.acqus['DTYPA'] = dic['acqus']['DTYPA']
|
|
4167
|
+
|
|
4168
|
+
del dic
|
|
4169
|
+
del data
|
|
4170
|
+
|
|
4171
|
+
# Get group delay points
|
|
4172
|
+
try:
|
|
4173
|
+
self.acqus['GRPDLY'] = int(self.ngdic['acqus']['GRPDLY'])
|
|
4174
|
+
except Exception:
|
|
4175
|
+
self.acqus['GRPDLY'] = 0
|
|
4176
|
+
|
|
4177
|
+
# Load the difflist
|
|
4178
|
+
self.x_f1 = np.loadtxt(self.datadir / 'difflist')
|
|
4179
|
+
self.label_f1 = r'Gradient /G cm$^{-1}$'
|
|
4180
|
+
|
|
4181
|
+
# Load the F2 list
|
|
4182
|
+
# It should be the only file in lists/vd/ but we do not know its name
|
|
4183
|
+
fqlistpath = next((self.datadir / 'lists' / 'f1').iterdir())
|
|
4184
|
+
# Print a notification
|
|
4185
|
+
print(f'Found {fqlistpath} to be imported as FQLIST', c='tab:blue')
|
|
4186
|
+
# Actual loading and storage in an attribute
|
|
4187
|
+
fqlist = np.loadtxt(fqlistpath)
|
|
4188
|
+
self.x_f2 = fqlist
|
|
4189
|
+
self.label_f2 = 'Freq /Hz'
|
|
4190
|
+
|
|
4191
|
+
# Procs dictionary
|
|
4192
|
+
if (self.datadir / self.filename).with_suffix('.procs').exists():
|
|
4193
|
+
self.procs = self.read_procs()
|
|
4194
|
+
else:
|
|
4195
|
+
self.procs = self._default_procs(self.acqus)
|
|
4196
|
+
self.write_procs()
|
|
@@ -5830,7 +5830,7 @@ class DosyFit_pp3D(fit.DosyFit):
|
|
|
5830
5830
|
Same structure and shape of ``self.i_guess``
|
|
5831
5831
|
|
|
5832
5832
|
"""
|
|
5833
|
-
def __init__(self, S, datadir=None, filename=None):
|
|
5833
|
+
def __init__(self, S, datadir=None, filename=None, keys=None):
|
|
5834
5834
|
"""
|
|
5835
5835
|
Initialize the class.
|
|
5836
5836
|
This function will slice ``S`` along the DOSY dimension (`31`) and store the planes in the ``self.planes`` attribute.
|
|
@@ -5845,6 +5845,8 @@ class DosyFit_pp3D(fit.DosyFit):
|
|
|
5845
5845
|
Custom path where to save files and figures. If ``None``, *./``filename``* is created
|
|
5846
5846
|
filename : str
|
|
5847
5847
|
Custom filename for files and figures. If ``None``, ``S.filename`` is used.
|
|
5848
|
+
keys : list of str
|
|
5849
|
+
Keys that identify the regions to integrate. If None, the integration is performed interactively through GUI
|
|
5848
5850
|
"""
|
|
5849
5851
|
# Filename
|
|
5850
5852
|
if filename is None: # Same name of the input dataset
|
|
@@ -5871,7 +5873,7 @@ class DosyFit_pp3D(fit.DosyFit):
|
|
|
5871
5873
|
self.planes = [S.getplane(k, dim='31') for k in range(len(S.x_f2))]
|
|
5872
5874
|
|
|
5873
5875
|
# Compute the integrals for all the planes
|
|
5874
|
-
self.integrate_planes()
|
|
5876
|
+
self.integrate_planes(keys=keys)
|
|
5875
5877
|
|
|
5876
5878
|
def integrate_planes(self, keys=None, use_bas=False):
|
|
5877
5879
|
"""
|
|
@@ -8,6 +8,7 @@ import scipy.io.wavfile as WF
|
|
|
8
8
|
import math
|
|
9
9
|
import warnings
|
|
10
10
|
import scipy.linalg as slinalg
|
|
11
|
+
import yaml
|
|
11
12
|
from copy import deepcopy
|
|
12
13
|
from pathlib import Path
|
|
13
14
|
|
|
@@ -74,7 +75,7 @@ def read_fid_acqus_1D(in_file, spect='bruker'):
|
|
|
74
75
|
in_file : str or Path
|
|
75
76
|
Path where to find the data
|
|
76
77
|
spect : str
|
|
77
|
-
Data format. Valid options are: ``'bruker'``, ``'varian'``, ``'magritek'``, ``'oxford'``, ``'jeol'``
|
|
78
|
+
Data format. Valid options are: ``'bruker'``, ``'varian'``, ``'magritek'``, ``'oxford'``, ``'jeol'``, ``'nana'``
|
|
78
79
|
|
|
79
80
|
Returns
|
|
80
81
|
-------
|
|
@@ -129,6 +130,13 @@ def read_fid_acqus_1D(in_file, spect='bruker'):
|
|
|
129
130
|
data = cplx[0] + 1j*cplx[1]
|
|
130
131
|
return data, acqus, dic
|
|
131
132
|
|
|
133
|
+
def read_nana(path):
|
|
134
|
+
""" .dx files nanalysis """
|
|
135
|
+
dic, cplx = ng.jcampdx.read(path)
|
|
136
|
+
acqus = misc.makeacqus_1D_nana(dic)
|
|
137
|
+
data = cplx[0] + 1j*cplx[1]
|
|
138
|
+
return data, acqus, dic
|
|
139
|
+
|
|
132
140
|
def read_jeol(path):
|
|
133
141
|
""" Jeol files """
|
|
134
142
|
dic = jeol_parser.parse(path)
|
|
@@ -158,6 +166,8 @@ def read_fid_acqus_1D(in_file, spect='bruker'):
|
|
|
158
166
|
fid, acqus, ngdic = read_magritek(in_file)
|
|
159
167
|
case 'oxford':
|
|
160
168
|
fid, acqus, ngdic = read_oxford(in_file)
|
|
169
|
+
case 'nana':
|
|
170
|
+
fid, acqus, ngdic = read_nana(in_file)
|
|
161
171
|
case 'jeol':
|
|
162
172
|
fid, acqus, ngdic = read_jeol(in_file)
|
|
163
173
|
case _:
|
|
@@ -166,10 +176,11 @@ def read_fid_acqus_1D(in_file, spect='bruker'):
|
|
|
166
176
|
# Add the file version to acqus
|
|
167
177
|
acqus['spect'] = spect
|
|
168
178
|
# Look for group delay points: if there are not, put it to 0
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
179
|
+
if 'GRPDLY' not in acqus.keys():
|
|
180
|
+
try:
|
|
181
|
+
acqus['GRPDLY'] = int(ngdic['acqus']['GRPDLY'])
|
|
182
|
+
except Exception:
|
|
183
|
+
acqus['GRPDLY'] = 0
|
|
173
184
|
|
|
174
185
|
return fid, acqus, ngdic
|
|
175
186
|
|
|
@@ -339,6 +350,7 @@ def makeacqus_1D_spinsolve(dic):
|
|
|
339
350
|
def makeacqus_1D_oxford(dic):
|
|
340
351
|
"""
|
|
341
352
|
Given a NMRGLUE dictionary from a 1D spectrum (generated by :func:`nmrglue.jcampdx.read`), this function builds the acqus file with only the "important" parameters.
|
|
353
|
+
For Oxford Instruments benchtop NMR.
|
|
342
354
|
|
|
343
355
|
Parameters
|
|
344
356
|
----------
|
|
@@ -371,6 +383,41 @@ def makeacqus_1D_oxford(dic):
|
|
|
371
383
|
return acqus
|
|
372
384
|
|
|
373
385
|
|
|
386
|
+
def makeacqus_1D_nana(dic):
|
|
387
|
+
"""
|
|
388
|
+
Given a NMRGLUE dictionary from a 1D spectrum (generated by :func:`nmrglue.jcampdx.read`), this function builds the acqus file with only the "important" parameters.
|
|
389
|
+
For NANALYSIS benctop NMR
|
|
390
|
+
|
|
391
|
+
Parameters
|
|
392
|
+
----------
|
|
393
|
+
dic : dict
|
|
394
|
+
NMRglue dictionary returned by ng.jcampdx.read
|
|
395
|
+
|
|
396
|
+
Returns
|
|
397
|
+
-------
|
|
398
|
+
acqus : dict
|
|
399
|
+
Dictionary with only few parameters
|
|
400
|
+
"""
|
|
401
|
+
acqus = {}
|
|
402
|
+
|
|
403
|
+
acqus['nuc'] = dic['.OBSERVENUCLEUS'][-1].replace('^', '')
|
|
404
|
+
acqus['SFO1'] = eval(dic['$SFO1'][-1])
|
|
405
|
+
acqus['SW'] = eval(dic['$SWH'][-1])
|
|
406
|
+
acqus['TD'] = int(eval(dic['$TD'][-1]) // 2) # Fuckin' Nana
|
|
407
|
+
acqus['o1'] = eval(dic['$O1'][-1])
|
|
408
|
+
|
|
409
|
+
acqus['SWp'] = acqus['SW'] / np.abs(acqus['SFO1'])
|
|
410
|
+
acqus['B0'] = acqus['SFO1'] / sim.gamma[acqus['nuc']]
|
|
411
|
+
acqus['o1p'] = acqus['o1'] / acqus['SFO1']
|
|
412
|
+
acqus['dw'] = 1 / acqus['SW']
|
|
413
|
+
acqus['t1'] = np.linspace(0, acqus['TD']*acqus['dw'], acqus['TD'])
|
|
414
|
+
acqus['AQ'] = acqus['t1'][-1]
|
|
415
|
+
acqus['fidres'] = 1 / (acqus['TD'] * acqus['dw'])
|
|
416
|
+
|
|
417
|
+
acqus['GRPDLY'] = - eval(dic['$GRPDLY'][-1])
|
|
418
|
+
return acqus
|
|
419
|
+
|
|
420
|
+
|
|
374
421
|
def makeacqus_1D_jeol(dic):
|
|
375
422
|
"""
|
|
376
423
|
Given a dictionary from a 1D spectrum (generated by ``jeol_parser.parse``), this function builds the acqus file with only the "important" parameters.
|
|
@@ -496,7 +543,7 @@ def makeacqus_pp3D(dic):
|
|
|
496
543
|
return acqus
|
|
497
544
|
|
|
498
545
|
|
|
499
|
-
def
|
|
546
|
+
def write_acqus(acqus, filename='sim_in', ext='acqus'):
|
|
500
547
|
"""
|
|
501
548
|
Writes the input file for a simulated spectrum, basing on a dictionary of parameters.
|
|
502
549
|
|
|
@@ -504,51 +551,29 @@ def write_acqus_1D(acqus, path='sim_in_1D'):
|
|
|
504
551
|
----------
|
|
505
552
|
acqus : dict
|
|
506
553
|
The dictionary containing the parameters for the simulation
|
|
507
|
-
|
|
554
|
+
filename : str
|
|
508
555
|
Directory where the file will be saved.
|
|
556
|
+
ext : str
|
|
557
|
+
Extension of the filename
|
|
509
558
|
"""
|
|
510
|
-
|
|
511
|
-
keylist = acqus.keys()
|
|
512
|
-
for key in keylist:
|
|
513
|
-
if key[:1] == 't':
|
|
514
|
-
pass
|
|
515
|
-
else:
|
|
516
|
-
if isinstance(acqus[key], (list, tuple)):
|
|
517
|
-
f.write('{}\t'.format(key))
|
|
518
|
-
for w in acqus[key]:
|
|
519
|
-
f.write('{}, '.format(w))
|
|
520
|
-
f.write('\n')
|
|
521
|
-
else:
|
|
522
|
-
f.write('{}\t{}\n'.format(key, acqus[key]))
|
|
523
|
-
|
|
524
|
-
f.close()
|
|
559
|
+
path = Path(filename)
|
|
525
560
|
|
|
561
|
+
# Remove the acquistion timescales as they can be recomputed easily
|
|
562
|
+
exclude = ['t1', 't2', 't3']
|
|
563
|
+
acqus_to_write = {key: value for key, value in acqus.items()
|
|
564
|
+
if key not in exclude}
|
|
526
565
|
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
566
|
+
# If there are the parameters for the simulated peaks, move them at the end
|
|
567
|
+
if 'shifts' in acqus.keys():
|
|
568
|
+
move = ['shifts', 'fwhm', 'amplitudes', 'b', 'phases', 'mult', 'Jconst', ]
|
|
569
|
+
reordered = {k: v for k, v in acqus_to_write.items()
|
|
570
|
+
if k not in move}
|
|
571
|
+
for key in move:
|
|
572
|
+
if key in acqus_to_write:
|
|
573
|
+
reordered[key] = acqus_to_write[key]
|
|
574
|
+
acqus_to_write = reordered
|
|
530
575
|
|
|
531
|
-
|
|
532
|
-
----------
|
|
533
|
-
acqus : dict
|
|
534
|
-
The dictionary containing the parameters for the simulation
|
|
535
|
-
path : str, optional
|
|
536
|
-
Directory where the file will be saved.
|
|
537
|
-
"""
|
|
538
|
-
f = open(path, 'w')
|
|
539
|
-
keylist = acqus.keys()
|
|
540
|
-
for key in keylist:
|
|
541
|
-
if key[:1] == 't':
|
|
542
|
-
pass
|
|
543
|
-
else:
|
|
544
|
-
if isinstance(acqus[key], (list, tuple)):
|
|
545
|
-
f.write('{}\t'.format(key))
|
|
546
|
-
for w in acqus[key]:
|
|
547
|
-
f.write('{}, '.format(w))
|
|
548
|
-
f.write('\n')
|
|
549
|
-
else:
|
|
550
|
-
f.write('{}\t{}\n'.format(key, acqus[key]))
|
|
551
|
-
f.close()
|
|
576
|
+
misc.write_yml(acqus_to_write, path, ext, sort_keys=False)
|
|
552
577
|
|
|
553
578
|
|
|
554
579
|
def calcres(fqscale):
|
|
@@ -1901,3 +1926,75 @@ def get_extent(data):
|
|
|
1901
1926
|
``max(data) - min(data)``
|
|
1902
1927
|
"""
|
|
1903
1928
|
return np.max(data) - np.min(data)
|
|
1929
|
+
|
|
1930
|
+
|
|
1931
|
+
def safe_convert(obj):
|
|
1932
|
+
"""
|
|
1933
|
+
Transforms strange pythonic objects like
|
|
1934
|
+
numpy arrays and scalars into something writable.
|
|
1935
|
+
"""
|
|
1936
|
+
# Called in loop in order to work also for nested objects
|
|
1937
|
+
if isinstance(obj, dict): # for dictionaries
|
|
1938
|
+
return {k: safe_convert(v) for k, v in obj.items()}
|
|
1939
|
+
if isinstance(obj, (list, tuple, set)): # for lists
|
|
1940
|
+
return [safe_convert(v) for v in obj]
|
|
1941
|
+
if isinstance(obj, np.ndarray): # for arrays
|
|
1942
|
+
return safe_convert(obj.tolist())
|
|
1943
|
+
if isinstance(obj, np.generic): # for np.float64 and similar
|
|
1944
|
+
return obj.item()
|
|
1945
|
+
return obj
|
|
1946
|
+
|
|
1947
|
+
|
|
1948
|
+
def write_yml(obj, filename, ext='yml', sort_keys=True):
|
|
1949
|
+
"""
|
|
1950
|
+
Write ``obj`` in a yml-styled text file, with one entry per line.
|
|
1951
|
+
|
|
1952
|
+
Parameters
|
|
1953
|
+
----------
|
|
1954
|
+
obj : list or dict
|
|
1955
|
+
Object to write
|
|
1956
|
+
filename : str or Path
|
|
1957
|
+
Path for the file to write
|
|
1958
|
+
ext : str
|
|
1959
|
+
Extension of the filename
|
|
1960
|
+
sort_keys : bool
|
|
1961
|
+
``False`` to keep the insertion order
|
|
1962
|
+
|
|
1963
|
+
Returns
|
|
1964
|
+
-------
|
|
1965
|
+
None
|
|
1966
|
+
|
|
1967
|
+
.. seealso::
|
|
1968
|
+
|
|
1969
|
+
:func:`klassez.misc.read_yml`
|
|
1970
|
+
|
|
1971
|
+
"""
|
|
1972
|
+
|
|
1973
|
+
# Convert if str, then add/replace correct extension
|
|
1974
|
+
path = Path(filename).with_suffix(f'.{ext}')
|
|
1975
|
+
# Open file and write
|
|
1976
|
+
with path.open('w') as f:
|
|
1977
|
+
# default_flow_style if True writes all obj in only one line
|
|
1978
|
+
yaml.safe_dump(misc.safe_convert(obj), f,
|
|
1979
|
+
default_flow_style=False,
|
|
1980
|
+
sort_keys=sort_keys)
|
|
1981
|
+
|
|
1982
|
+
|
|
1983
|
+
def read_yml(filename):
|
|
1984
|
+
"""
|
|
1985
|
+
Reads a yml-styled text file.
|
|
1986
|
+
|
|
1987
|
+
Parameters
|
|
1988
|
+
----------
|
|
1989
|
+
filename : str or Path
|
|
1990
|
+
Path to the file to be read
|
|
1991
|
+
|
|
1992
|
+
Returns
|
|
1993
|
+
-------
|
|
1994
|
+
obj : object
|
|
1995
|
+
Read file
|
|
1996
|
+
"""
|
|
1997
|
+
path = Path(filename)
|
|
1998
|
+
with path.open('r') as f:
|
|
1999
|
+
obj = yaml.safe_load(f)
|
|
2000
|
+
return obj
|
|
@@ -2701,7 +2701,7 @@ def rpbc(data, split_imag=False, n=5, basl_method='huber', basl_thresh=0.2, basl
|
|
|
2701
2701
|
|
|
2702
2702
|
:func:`klassez.fit.SINC_phase`
|
|
2703
2703
|
|
|
2704
|
-
:func:`klassez.
|
|
2704
|
+
:func:`klassez.fit.polyn_basl`
|
|
2705
2705
|
|
|
2706
2706
|
:class:`klassez.fit.CostFunc`
|
|
2707
2707
|
"""
|
|
@@ -2881,14 +2881,15 @@ def align(ppm_scale, data, lims, u_off=0.5, ref_idx=0):
|
|
|
2881
2881
|
|
|
2882
2882
|
# Circular-shift the spectrum (first shift then abs)
|
|
2883
2883
|
roll_s = np.abs(processing.roll_dirac(s, ppm_scale, par['u']))
|
|
2884
|
-
# Compute its integral
|
|
2885
|
-
int_roll_s = processing.integral(roll_s)
|
|
2886
2884
|
|
|
2887
2885
|
# Normalize the spectra in the calibration region
|
|
2888
2886
|
A, _ = fit.fit_int(s_ref_abs, roll_s, q=0)
|
|
2889
2887
|
roll_s *= A
|
|
2890
|
-
|
|
2891
|
-
int_roll_s
|
|
2888
|
+
# Compute its integral
|
|
2889
|
+
int_roll_s = processing.integral(roll_s)
|
|
2890
|
+
if 0:
|
|
2891
|
+
A_int, _ = fit.fit_int(int_s_ref, int_roll_s, q=0)
|
|
2892
|
+
int_roll_s *= A_int
|
|
2892
2893
|
|
|
2893
2894
|
# Compute the residuals
|
|
2894
2895
|
res = s_ref_abs - roll_s
|
|
@@ -3430,6 +3431,10 @@ def apk(ppm, data, SFO1, alpha=3, winsize=50, ap1=True, seethrough=False):
|
|
|
3430
3431
|
|
|
3431
3432
|
# -----------------------------------------------------------------------------------
|
|
3432
3433
|
|
|
3434
|
+
if not np.iscomplexobj(data):
|
|
3435
|
+
# TODO warning
|
|
3436
|
+
data = processing.hilbert(data)
|
|
3437
|
+
|
|
3433
3438
|
# Get the peak-only regions
|
|
3434
3439
|
slices, _ = processing.mask_sgn_basl(ppm, data, SFO1, alpha, winsize)
|
|
3435
3440
|
|
|
@@ -3448,7 +3453,11 @@ def apk(ppm, data, SFO1, alpha=3, winsize=50, ap1=True, seethrough=False):
|
|
|
3448
3453
|
plt.show()
|
|
3449
3454
|
|
|
3450
3455
|
# Smooth the data with a 5 Hz gaussian filter
|
|
3451
|
-
|
|
3456
|
+
fqscale = misc.ppm2freq(ppm, SFO1)
|
|
3457
|
+
# Minimum must be 1 pt width otherwise error div by 0
|
|
3458
|
+
fw_min_width = misc.calcres(fqscale)
|
|
3459
|
+
fw = max(fw_min_width, misc.hz2pt(fqscale, 5))
|
|
3460
|
+
gbdata = processing.smooth_g(data, 1/fw)
|
|
3452
3461
|
# Phase each region independently with only p0
|
|
3453
3462
|
p0s = phase0(gbdata, slices)
|
|
3454
3463
|
|
|
@@ -3491,7 +3500,7 @@ def apk(ppm, data, SFO1, alpha=3, winsize=50, ap1=True, seethrough=False):
|
|
|
3491
3500
|
p1 = 0
|
|
3492
3501
|
|
|
3493
3502
|
# Apply the correction
|
|
3494
|
-
datap, *_ = processing.ps(data, p0=p0, p1=p1)
|
|
3503
|
+
datap, *_ = processing.ps(data, ppm, p0=p0, p1=p1)
|
|
3495
3504
|
|
|
3496
3505
|
print('APK: p0: {:.3f}, p1: {:.3f}\n'.format(p0, p1), c='violet')
|
|
3497
3506
|
|
|
@@ -4338,3 +4347,55 @@ def roll_dirac(y, x, off=0, onfid=False):
|
|
|
4338
4347
|
y_t_roll = y_t * dirac_t
|
|
4339
4348
|
y_roll = processing.ft(y_t_roll)
|
|
4340
4349
|
return y_roll
|
|
4350
|
+
|
|
4351
|
+
|
|
4352
|
+
def adjph_rowwise(ppm, data, SFO1, alpha=3, winsize=50, ap1=True):
|
|
4353
|
+
"""
|
|
4354
|
+
Performs automatic phase correction of a pseudo_2D dataset, with :func:`klassez.processing.apk`, each row independently.
|
|
4355
|
+
Returns the phased spectrum and the employed values.
|
|
4356
|
+
|
|
4357
|
+
Parameters
|
|
4358
|
+
----------
|
|
4359
|
+
ppm : 1darray
|
|
4360
|
+
ppm scale of the spectrum
|
|
4361
|
+
data : 2darray
|
|
4362
|
+
Spectrum
|
|
4363
|
+
SFO1 : float
|
|
4364
|
+
Nucleus' Larmor frequency /MHz
|
|
4365
|
+
alpha : float
|
|
4366
|
+
Factor that multiplies the std of the spectrum to set the threshold
|
|
4367
|
+
winsize : float
|
|
4368
|
+
Minimum size of the window that can contain peaks /Hz
|
|
4369
|
+
ap1 : bool
|
|
4370
|
+
True to adjust both zero and first order, False for only phase zero
|
|
4371
|
+
|
|
4372
|
+
Returns
|
|
4373
|
+
-------
|
|
4374
|
+
new_data : 2darray
|
|
4375
|
+
Phased spectrum
|
|
4376
|
+
phases : 2darray
|
|
4377
|
+
Employed values for phasing, in the form ``[p0, p1, pivot]``
|
|
4378
|
+
|
|
4379
|
+
.. seealso::
|
|
4380
|
+
|
|
4381
|
+
:func:`klassez.processing.apk`
|
|
4382
|
+
"""
|
|
4383
|
+
# Make a shallow copy while checking to have the imaginary part
|
|
4384
|
+
if np.iscomplexobj(data):
|
|
4385
|
+
new_data = deepcopy(data)
|
|
4386
|
+
else:
|
|
4387
|
+
warnings.warn('data is not complex. Performing Hilbert transform.', stacklevel=3)
|
|
4388
|
+
new_data = processing.hilbert(data)
|
|
4389
|
+
|
|
4390
|
+
# Placeholder
|
|
4391
|
+
phases = []
|
|
4392
|
+
# Start the loop
|
|
4393
|
+
for k, transient in enumerate(new_data):
|
|
4394
|
+
print(f'Phasing transient {k+1} of {new_data.shape[0]}', c='violet')
|
|
4395
|
+
# Call apk for each transient and save the values
|
|
4396
|
+
new_data[k], values = processing.apk(ppm, transient, SFO1, alpha=alpha, winsize=winsize, ap1=ap1)
|
|
4397
|
+
phases.append(values)
|
|
4398
|
+
|
|
4399
|
+
# apk uses as pivot the mean of the ppm scale --> add this info
|
|
4400
|
+
phases = np.column_stack([phases, [round(np.mean(ppm), 3) for w in range(data.shape[0])]])
|
|
4401
|
+
return new_data, phases
|
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
import sys
|
|
4
4
|
import numpy as np
|
|
5
|
-
|
|
5
|
+
from copy import deepcopy
|
|
6
|
+
import re
|
|
7
|
+
import ast
|
|
6
8
|
from importlib.resources import open_text, files
|
|
7
9
|
from pathlib import Path
|
|
8
10
|
from scipy import special
|
|
@@ -120,13 +122,13 @@ def multiplet(u, Int, m='s', J=[]):
|
|
|
120
122
|
return u_in, I_in
|
|
121
123
|
|
|
122
124
|
|
|
123
|
-
def load_sim_1D(
|
|
125
|
+
def load_sim_1D(filename):
|
|
124
126
|
"""
|
|
125
127
|
Creates a dictionary from the spectral parameters listed in the input file.
|
|
126
128
|
|
|
127
129
|
Parameters
|
|
128
130
|
----------
|
|
129
|
-
|
|
131
|
+
filename : str
|
|
130
132
|
Path to the input file location
|
|
131
133
|
|
|
132
134
|
Returns
|
|
@@ -134,51 +136,56 @@ def load_sim_1D(File):
|
|
|
134
136
|
dic : dict
|
|
135
137
|
Dictionary of the parameters, ready to be read from the simulation functions.
|
|
136
138
|
"""
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
139
|
+
# Remove tabulations because they kill everything
|
|
140
|
+
path = Path(filename)
|
|
141
|
+
text = path.read_text()
|
|
142
|
+
if '\t' in text:
|
|
143
|
+
text = text.replace('\t', 4*' ')
|
|
144
|
+
with path.open('w') as f:
|
|
145
|
+
f.write(text)
|
|
146
|
+
|
|
147
|
+
# Make the dictionary
|
|
148
|
+
dic = misc.read_yml(path)
|
|
149
|
+
# Correct aliases
|
|
150
|
+
alias = {'shifts': 'cs', 'fwhm': 'lw', 'amplitudes': 'A', 'b': 'x_g',
|
|
151
|
+
'phases': 'ph', 'mult': 'm', 'Jconst': 'J', }
|
|
152
|
+
newdic = deepcopy(dic)
|
|
153
|
+
for key, item in alias.items():
|
|
154
|
+
if item in dic:
|
|
155
|
+
newdic[key] = dic[item]
|
|
156
|
+
newdic.pop(item)
|
|
157
|
+
dic = newdic
|
|
158
|
+
|
|
159
|
+
# Check if the mandatory keys are all there
|
|
160
|
+
for key in ['shifts', 'fwhm', 'amplitudes']:
|
|
161
|
+
if key not in dic:
|
|
162
|
+
raise NameError(f'Missing {key} in the input file.')
|
|
163
|
+
# Add the non-mandatory keys if missing with default values
|
|
164
|
+
defaults = {'b': 0, 'phases': 0, 'mult': 's', 'Jconst': 0, }
|
|
165
|
+
for key in alias:
|
|
166
|
+
# Check if there is
|
|
167
|
+
if key in dic:
|
|
168
|
+
if key == 'mult':
|
|
169
|
+
# ddd --> "ddd" so that ast.literal_eval does not raise error
|
|
170
|
+
if isinstance(dic[key], str):
|
|
171
|
+
dic[key] = re.sub(r'[^\[\],\s]+', r'"\g<0>"', dic[key])
|
|
172
|
+
# Convert a string into a list
|
|
173
|
+
dic[key] = list(ast.literal_eval(f'{dic[key]}'))
|
|
174
|
+
elif key in defaults:
|
|
175
|
+
# Use default value
|
|
176
|
+
dic[key] = [defaults[key] for w in range(len(dic['amplitudes']))]
|
|
177
|
+
|
|
178
|
+
# Compute extra
|
|
174
179
|
dic['B0'] = np.abs(dic['B0']) * np.sign(sim.gamma[dic['nuc']])
|
|
175
|
-
dic['TD'] = int(dic['TD'])
|
|
176
180
|
dic['SFO1'] = dic['B0'] * sim.gamma[dic['nuc']]
|
|
181
|
+
dic['o1'] = dic['o1p'] * dic['SFO1']
|
|
182
|
+
if isinstance(dic['TD'], str):
|
|
183
|
+
dic['TD'] = eval(dic['TD'])
|
|
184
|
+
dic['TD'] = int(dic['TD'])
|
|
177
185
|
dic['SW'] = dic['SWp'] * np.abs(dic['SFO1'])
|
|
178
186
|
dic['dw'] = 1/dic['SW']
|
|
179
187
|
dic['t1'] = np.linspace(0, dic['TD']*dic['dw'], dic['TD'])
|
|
180
188
|
dic['AQ'] = dic['t1'][-1]
|
|
181
|
-
dic['o1'] = dic['o1p'] * dic['SFO1']
|
|
182
189
|
|
|
183
190
|
return dic
|
|
184
191
|
|
|
@@ -211,8 +218,8 @@ def sim_1D(File, pv=False):
|
|
|
211
218
|
shifts = np.array(in_file['shifts']) # Chemical shift /ppm
|
|
212
219
|
amplitudes = in_file['amplitudes'] # Relative intensity of the signals
|
|
213
220
|
fwhm = np.array(in_file['fwhm']) # Full width at half maximum of the signals
|
|
214
|
-
b = in_file['b'] # Fraction of gaussianity of the FID
|
|
215
|
-
phases = in_file['phases']
|
|
221
|
+
b = np.array(in_file['b']) # Fraction of gaussianity of the FID
|
|
222
|
+
phases = np.array(in_file['phases']) * np.pi / 180 # Convert to radians
|
|
216
223
|
|
|
217
224
|
freq = misc.ppm2freq(shifts, B0=in_file['SFO1'], o1p=in_file['o1p']) # peaks center frequency
|
|
218
225
|
|
|
@@ -229,13 +236,13 @@ def sim_1D(File, pv=False):
|
|
|
229
236
|
return fid
|
|
230
237
|
|
|
231
238
|
|
|
232
|
-
def load_sim_2D(
|
|
239
|
+
def load_sim_2D(filename, states=True):
|
|
233
240
|
"""
|
|
234
241
|
Creates a dictionary from the spectral parameters listed in the input file.
|
|
235
242
|
|
|
236
243
|
Parameters
|
|
237
244
|
----------
|
|
238
|
-
|
|
245
|
+
filename : str
|
|
239
246
|
Path to the input file location
|
|
240
247
|
states : bool
|
|
241
248
|
If FnMODE is States or States-TPPI, set it to True to get the correct timescale.
|
|
@@ -245,36 +252,48 @@ def load_sim_2D(File, states=True):
|
|
|
245
252
|
dic : dict
|
|
246
253
|
Dictionary of the parameters, ready to be read from the simulation functions.
|
|
247
254
|
"""
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
255
|
+
# Remove tabulations because they kill everything
|
|
256
|
+
path = Path(filename)
|
|
257
|
+
text = path.read_text()
|
|
258
|
+
if '\t' in text:
|
|
259
|
+
text = text.replace('\t', 4*' ')
|
|
260
|
+
with path.open('w') as f:
|
|
261
|
+
f.write(text)
|
|
262
|
+
|
|
263
|
+
# Make the dictionary
|
|
264
|
+
dic = misc.read_yml(path)
|
|
265
|
+
|
|
266
|
+
# Correct aliases
|
|
267
|
+
alias = {'shifts_f1': 'csf1', 'shifts_f2': 'csf2',
|
|
268
|
+
'fwhm_f1': 'lwf1', 'fwhm_f2': 'lwf2',
|
|
269
|
+
'amplitudes': 'A', 'b': 'x_g', }
|
|
270
|
+
newdic = deepcopy(dic)
|
|
271
|
+
for key, item in alias.items():
|
|
272
|
+
if item in dic:
|
|
273
|
+
newdic[key] = dic[item]
|
|
274
|
+
newdic.pop(item)
|
|
275
|
+
dic = newdic
|
|
276
|
+
|
|
277
|
+
# Check if the mandatory keys are all there
|
|
278
|
+
for key in ['shifts_f1', 'shifts_f2',
|
|
279
|
+
'fwhm_f1', 'fwhm_f2', 'amplitudes']:
|
|
280
|
+
if key not in dic:
|
|
281
|
+
raise NameError(f'Missing {key} in the input file.')
|
|
282
|
+
# Add the non-mandatory keys if missing with default values
|
|
283
|
+
defaults = {'b': 0, }
|
|
284
|
+
for key in alias:
|
|
285
|
+
# Check if there is
|
|
286
|
+
if key in dic:
|
|
287
|
+
# Convert a string into a list
|
|
288
|
+
dic[key] = list(ast.literal_eval(f'{dic[key]}'))
|
|
289
|
+
elif key in defaults:
|
|
290
|
+
# Use default value
|
|
291
|
+
dic[key] = [defaults[key] for w in range(len(dic['amplitudes']))]
|
|
292
|
+
|
|
293
|
+
for key in ['TD1', 'TD2']:
|
|
294
|
+
if isinstance(dic[key], str):
|
|
295
|
+
dic[key] = eval(dic[key])
|
|
296
|
+
dic[key] = int(dic[key])
|
|
278
297
|
dic['SFO1'] = dic['B0'] * sim.gamma[dic['nuc1']] # Larmor frequency /MHz
|
|
279
298
|
dic['SFO2'] = dic['B0'] * sim.gamma[dic['nuc2']] # Larmor frequency /MHz
|
|
280
299
|
dic['SW1'] = np.abs(dic['SW1p'] * dic['SFO1']) # spectral width
|
|
File without changes
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: klassez
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.1
|
|
4
4
|
Summary: A collection of functions for NMR data handling
|
|
5
5
|
Author: Letizia Fiorucci
|
|
6
6
|
Author-email: Francesco Bruno <bruno@cerm.unifi.it>
|
|
@@ -22,6 +22,7 @@ Requires-Dist: seaborn
|
|
|
22
22
|
Requires-Dist: nmrglue
|
|
23
23
|
Requires-Dist: matplotlib>=3.8
|
|
24
24
|
Requires-Dist: csaps
|
|
25
|
+
Requires-Dist: pyyaml
|
|
25
26
|
Provides-Extra: jeolproc
|
|
26
27
|
Requires-Dist: jeol_parser; extra == "jeolproc"
|
|
27
28
|
Provides-Extra: docs
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|