Processing a saturation-recovery relaxation series

This example processes a pseudo-2D series of 1D spectra acquired with a variable recovery delay and fits a simple saturation-recovery model to the dominant resonance.

The bundled Bruker dataset stores the delays in vdlist and the pulse program indicates a CP/MAS saturation-recovery experiment. The example keeps a modest public scope:

  • process the 1D FIDs with explicit SpectroChemPy operations;

  • extract a signal trace from the dominant processed resonance;

  • fit a simple two-parameter recovery model to that trace.

It does not claim replay of vendor processing, nor exact equivalence with the TopSpin fitting tools bundled alongside the dataset.

Requires the official spectrochempy-nmr plugin. Install with: pip install spectrochempy[nmr].

Import API

import spectrochempy as scp

# short version of the unit registry
U = scp.ur

Import a pseudo-2D delay series

dataset = scp.nmr.read("nmrdata/bruker/tests/nmr/relax/100/ser", use_list="vdlist")

Analysing the data

Print dataset summary

dataset

Plot the processed spectra

The vdlist delays become the secondary coordinate of the pseudo-2D series.

ds = dataset.em(lb=15 * U.Hz)
ds = ds.fft()
ds = ds.pk(phc0=-145 * U.deg, phc1=0 * U.deg)
_ = ds.plot(xlim=(100, -50))

Build a signal trace from the dominant resonance

The strongest processed peak in this series sits around 20–22 ppm. We integrate a narrow ppm window around that resonance for each delay.

signal = ds[:, 20.0:45.0].simpson()
_ = signal.plot(marker="^", ls=":")
signal.real

Fit a model

create an Optimize object using a simple leastsq method

fitter = scp.Optimize(log_level="INFO", method="leastsq")

Define the model to fit

def T1_model(t, I0, T1):  # no underscore in parameters names.
    # Simple saturation-recovery model.
    import numpy as np

    I = I0 * (1 - np.exp(-t / T1))
    return I

Add the model to the fitter usermodels as it it not a built-in model

fitter.usermodels = {"T1_model": T1_model}

Define the parameter variables using a script (parameter: value, low_bound, high_bound) no underscore in parameters names.

fitter.script = """
MODEL: T1
shape: T1_model
  $ I0:  1000.0, 1, none
  $ T1:  2.0,    0.1, none
"""

Perform the fit

_ = fitter.fit(signal)
som = fitter.predict()
som

Plot the measured recovery points and the fitted curve separately so the experimental series remains a true scatter plot.

ax = signal.plot_scatter(
    color="tab:blue",
    marker="o",
    markersize=5,
    label="measured signal",
    title="Saturation-recovery fit of the dominant resonance",
)
_ = som.plot(clear=False, color="tab:orange", lw=1.8, label="fitted curve")
_ = ax.legend()

Uncomment the following line to display all figures when running the script directly with Python.

# scp.show()

Total running time of the script: ( 0 minutes 0.000 seconds)