<jupyter_start><jupyter_text>⁸⁷Rb 2D QMAT NMR of Rb₂SO₄ The following is an illustration for fitting 2D QMAT/QPASS datasets. The exampledataset is a $^{87}\text{Rb}$ 2D QMAT spectrum of $\text{Rb}_2\text{SO}_4$from Walder `et al.` [f1]_<jupyter_code>import numpy as np
import csdmpy as cp
import matplotlib.pyplot as plt
from lmfit import Minimizer

from mrsimulator import Simulator, SpinSystem, Site
from mrsimulator.methods import SSB2D
from mrsimulator import signal_processing as sp
from mrsimulator.utils import spectral_fitting as sf
from mrsimulator.utils import get_spectral_dimensions<jupyter_output><empty_output><jupyter_text>Import the dataset<jupyter_code>filename = "https://sandbox.zenodo.org/record/834704/files/Rb2SO4_QMAT.csdf"
qmat_data = cp.load(filename)

# standard deviation of noise from the dataset
sigma = 6.530634

# For the spectral fitting, we only focus on the real part of the complex dataset.
qmat_data = qmat_data.real

# Convert the coordinates along each dimension from Hz to ppm.
_ = [item.to("ppm", "nmr_frequency_ratio") for item in qmat_data.dimensions]

# plot of the dataset.
max_amp = qmat_data.max()
levels = (np.arange(31) + 0.15) * max_amp / 32  # contours are drawn at these levels.
options = dict(levels=levels, alpha=1, linewidths=0.5)  # plot options

plt.figure(figsize=(8, 3.5))
ax = plt.subplot(projection="csdm")
ax.contour(qmat_data.T, colors="k", **options)
ax.set_xlim(200, -200)
ax.set_ylim(75, -120)
plt.grid()
plt.tight_layout()
plt.show()<jupyter_output><empty_output><jupyter_text>Create a fitting model**Guess model**Create a guess list of spin systems.<jupyter_code>Rb_1 = Site(
    isotope="87Rb",
    isotropic_chemical_shift=16,  # in ppm
    quadrupolar={"Cq": 5.5e6, "eta": 0.1},  # Cq in Hz
)
Rb_2 = Site(
    isotope="87Rb",
    isotropic_chemical_shift=40,  # in ppm
    quadrupolar={"Cq": 2.1e6, "eta": 0.95},  # Cq in Hz
)

spin_systems = [SpinSystem(sites=[s]) for s in [Rb_1, Rb_2]]<jupyter_output><empty_output><jupyter_text>**Method**Create the SSB2D method.<jupyter_code># Get the spectral dimension parameters from the experiment.
spectral_dims = get_spectral_dimensions(qmat_data)

PASS = SSB2D(
    channels=["87Rb"],
    magnetic_flux_density=9.395,  # in T
    rotor_frequency=2604,  # in Hz
    spectral_dimensions=spectral_dims,
    experiment=qmat_data,  # add the measurement to the method.
)

# Optimize the script by pre-setting the transition pathways for each spin system from
# the method.
for sys in spin_systems:
    sys.transition_pathways = PASS.get_transition_pathways(sys)<jupyter_output><empty_output><jupyter_text>**Guess Spectrum**<jupyter_code># Simulation
# ----------
sim = Simulator(spin_systems=spin_systems, methods=[PASS])
sim.run()

# Post Simulation Processing
# --------------------------
processor = sp.SignalProcessor(
    operations=[
        # Lorentzian convolution along the isotropic dimensions.
        sp.FFT(axis=0),
        sp.apodization.Gaussian(FWHM="50 Hz"),
        sp.IFFT(axis=0),
        sp.Scale(factor=1e4),
    ]
)
processed_data = processor.apply_operations(data=sim.methods[0].simulation).real

# Plot of the guess Spectrum
# --------------------------
plt.figure(figsize=(8, 3.5))
ax = plt.subplot(projection="csdm")
ax.contour(qmat_data.T, colors="k", **options)
ax.contour(processed_data.T, colors="r", linestyles="--", **options)
ax.set_xlim(200, -200)
ax.set_ylim(75, -120)
plt.grid()
plt.tight_layout()
plt.show()<jupyter_output><empty_output><jupyter_text>Least-squares minimization with LMFITUse the :func:`~mrsimulator.utils.spectral_fitting.make_LMFIT_params` for a quicksetup of the fitting parameters.<jupyter_code>params = sf.make_LMFIT_params(sim, processor)
print(params.pretty_print(columns=["value", "min", "max", "vary", "expr"]))<jupyter_output><empty_output><jupyter_text>**Solve the minimizer using LMFIT**<jupyter_code>minner = Minimizer(sf.LMFIT_min_function, params, fcn_args=(sim, processor, sigma))
result = minner.minimize()
result<jupyter_output><empty_output><jupyter_text>The best fit solution<jupyter_code>best_fit = sf.bestfit(sim, processor)[0]

# Plot of the best fit solution
plt.figure(figsize=(8, 3.5))
ax = plt.subplot(projection="csdm")
ax.contour(qmat_data.T, colors="k", **options)
ax.contour(best_fit.T, colors="r", linestyles="--", **options)
ax.set_xlim(200, -200)
ax.set_ylim(75, -120)
plt.grid()
plt.tight_layout()
plt.show()<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.14108631958530538, 'fraction_numerical': 0.02681992337164751, 'mean_word_length': 5.295035460992908, 'pattern_counts': {'":': 4, '<': 33, '<?xml version=': 0, '>': 33, 'https://': 1, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '8', 'dir': 'jupyter-structured-clean-dedup', 'id': '427264', 'license': 'BSD-3-Clause', 'n_tokens_mistral': 1739, 'n_tokens_neox': 1610, 'n_words': 356, 'path': 'docs/notebooks/fitting/2D_fitting/plot_1_Rb2SO4_QMAT.ipynb', 'repo_name': 'pjgrandinetti/mrsimulator', 'size': '4437'}