.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "fitting/1D_fitting/plot_1_31P_Na2PO4_MAS.py" .. LINE NUMBERS ARE GIVEN BELOW. .. only:: html .. note:: :class: sphx-glr-download-link-note Click :ref:`here ` to download the full example code .. rst-class:: sphx-glr-example-title .. _sphx_glr_fitting_1D_fitting_plot_1_31P_Na2PO4_MAS.py: ³¹P MAS NMR of crystalline Na2PO4 (CSA) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. GENERATED FROM PYTHON SOURCE LINES 7-20 In this example, we illustrate the use of the mrsimulator objects to - create a CSA fitting model using Simulator and SignalProcessor objects, - use the fitting model to perform a least-squares analysis, and - extract the fitting parameters from the model. We use the `LMFIT `_ library to fit the spectrum. The following example shows the least-squares fitting procedure applied to the :math:`^{31}\text{P}` MAS NMR spectrum of :math:`\text{Na}_{2}\text{PO}_{4}`. The following experimental dataset is a part of DMFIT [#f1]_ examples. We thank Dr. Dominique Massiot for sharing the dataset. Start by importing the relevant modules. .. GENERATED FROM PYTHON SOURCE LINES 20-32 .. code-block:: default import csdmpy as cp import matplotlib.pyplot as plt from lmfit import Minimizer from mrsimulator import Simulator, SpinSystem, Site from mrsimulator.method.lib import BlochDecaySpectrum from mrsimulator import signal_processor as sp from mrsimulator.utils import spectral_fitting as sf from mrsimulator.utils import get_spectral_dimensions from mrsimulator.spin_system.tensors import SymmetricTensor .. GENERATED FROM PYTHON SOURCE LINES 34-40 Import the dataset ------------------ Import the experimental data. We use dataset file serialized with the CSDM file-format, using the `csdmpy `_ module. .. GENERATED FROM PYTHON SOURCE LINES 40-62 .. code-block:: default host = "https://nmr.cemhti.cnrs-orleans.fr/Dmfit/Help/csdm/" filename = "31P Phosphate 6kHz.csdf" experiment = cp.load(host + filename) # standard deviation of noise from the dataset sigma = 1.523217 # For spectral fitting, we only focus on the real part of the complex dataset experiment = experiment.real # Convert the dimension coordinates from Hz to ppm. experiment.x[0].to("ppm", "nmr_frequency_ratio") # plot of the dataset. plt.figure(figsize=(4.25, 3.0)) ax = plt.subplot(projection="csdm") ax.plot(experiment, color="black", linewidth=0.5, label="Experiment") ax.set_xlim(150, -150) plt.grid() plt.tight_layout() plt.show() .. image-sg:: /fitting/1D_fitting/images/sphx_glr_plot_1_31P_Na2PO4_MAS_001.png :alt: plot 1 31P Na2PO4 MAS :srcset: /fitting/1D_fitting/images/sphx_glr_plot_1_31P_Na2PO4_MAS_001.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 63-69 Create a fitting model ---------------------- A fitting model is a composite of ``Simulator`` and ``SignalProcessor`` objects. **Step 1:** Create initial guess sites and spin systems .. GENERATED FROM PYTHON SOURCE LINES 69-77 .. code-block:: default P_31 = Site( isotope="31P", isotropic_chemical_shift=5.0, # in ppm, shielding_symmetric=SymmetricTensor(zeta=-80, eta=0.5), # zeta in Hz ) spin_systems = [SpinSystem(sites=[P_31])] .. GENERATED FROM PYTHON SOURCE LINES 78-90 **Step 2:** Create the method object. Create an appropriate method object that closely resembles the technique used in acquiring the experimental dataset. The attribute values of this method must meet the experimental conditions, including the acquisition channels, the magnetic flux density, rotor angle, rotor frequency, and the spectral/spectroscopic dimension. In the following example, we set up a Bloch decay spectrum method where the spectral/spectroscopic dimension information, i.e., count, spectral_width, and the reference_offset, is extracted from the CSDM dimension metadata using the :func:`~mrsimulator.utils.get_spectral_dimensions` utility function. The remaining attribute values are set to the experimental conditions. .. GENERATED FROM PYTHON SOURCE LINES 90-110 .. code-block:: default # get the count, spectral_width, and reference_offset information from the experiment. spectral_dims = get_spectral_dimensions(experiment) MAS = BlochDecaySpectrum( channels=["31P"], magnetic_flux_density=9.395, # in T rotor_frequency=6000, # in Hz spectral_dimensions=spectral_dims, experiment=experiment, # experimental dataset ) # A method object queries every spin system for a list of transition pathways that are # relevant to the given method. Since the method and the number of spin systems remains # unchanged during the least-squares analysis, a one-time query is sufficient. To avoid # querying for the transition pathways at every iteration in a least-squares fitting, # evaluate the transition pathways once and store it as follows for sys in spin_systems: sys.transition_pathways = MAS.get_transition_pathways(sys) .. GENERATED FROM PYTHON SOURCE LINES 111-112 **Step 3:** Create the Simulator object and add the method and spin system objects. .. GENERATED FROM PYTHON SOURCE LINES 112-115 .. code-block:: default sim = Simulator(spin_systems=spin_systems, methods=[MAS]) sim.run() .. GENERATED FROM PYTHON SOURCE LINES 116-118 **Step 4:** Create a SignalProcessor class object and apply the post-simulation signal processing operations. .. GENERATED FROM PYTHON SOURCE LINES 118-129 .. code-block:: default processor = sp.SignalProcessor( operations=[ sp.IFFT(), sp.apodization.Exponential(FWHM="0.3 kHz"), sp.FFT(), sp.Scale(factor=300), sp.baseline.ConstantOffset(offset=-2), ] ) processed_dataset = processor.apply_operations(dataset=sim.methods[0].simulation).real .. GENERATED FROM PYTHON SOURCE LINES 130-131 **Step 5:** The plot of the dataset and the guess spectrum. .. GENERATED FROM PYTHON SOURCE LINES 131-142 .. code-block:: default plt.figure(figsize=(4.25, 3.0)) ax = plt.subplot(projection="csdm") ax.plot(experiment, color="black", linewidth=0.5, label="Experiment") ax.plot(processed_dataset, linewidth=2, alpha=0.6, label="Guess Spectrum") ax.set_xlim(150, -150) plt.legend() plt.grid() plt.tight_layout() plt.show() .. image-sg:: /fitting/1D_fitting/images/sphx_glr_plot_1_31P_Na2PO4_MAS_002.png :alt: plot 1 31P Na2PO4 MAS :srcset: /fitting/1D_fitting/images/sphx_glr_plot_1_31P_Na2PO4_MAS_002.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 143-159 Least-squares minimization with LMFIT ------------------------------------- Once you have a fitting model, you need to create the list of parameters to use in the least-squares minimization. For this, you may use the `Parameters `_ class from *LMFIT*, as described in the previous example. Here, we make use of a utility function, :func:`~mrsimulator.utils.spectral_fitting.make_LMFIT_params`, to simplifies the LMFIT parameters generation process. By default, the function only creates parameters from the SpinSystem and SignalProcessor objects. Often, in spectrum with sidebands, spinning speed may not be accurately known; and is, therefore, included as a fitting parameter. To include a keyword from the method object, use the *include* argument of the function, as follows, **Step 6:** Create a list of parameters. .. GENERATED FROM PYTHON SOURCE LINES 159-161 .. code-block:: default params = sf.make_LMFIT_params(sim, processor, include={"rotor_frequency"}) .. GENERATED FROM PYTHON SOURCE LINES 162-168 The `make_LMFIT_params` parses the instances of the ``Simulator`` and the ``PostSimulator`` objects for parameters and returns a LMFIT `Parameters` object. **Customize the Parameters:** You may customize the parameters list, ``params``, as desired. Here, we remove the abundance parameter. .. GENERATED FROM PYTHON SOURCE LINES 168-171 .. code-block:: default params.pop("sys_0_abundance") print(params.pretty_print(columns=["value", "min", "max", "vary", "expr"])) .. rst-class:: sphx-glr-script-out Out: .. code-block:: none Name Value Min Max Vary Expr SP_0_operation_1_Exponential_FWHM 0.3 -inf inf True None SP_0_operation_3_Scale_factor 300 -inf inf True None SP_0_operation_4_ConstantOffset_offset -2 -inf inf True None mth_0_rotor_frequency 6000 5900 6100 True None sys_0_site_0_isotropic_chemical_shift 5 -inf inf True None sys_0_site_0_shielding_symmetric_eta 0.5 0 1 True None sys_0_site_0_shielding_symmetric_zeta -80 -inf inf True None None .. GENERATED FROM PYTHON SOURCE LINES 172-178 **Step 7:** Perform the least-squares minimization. For the user's convenience, we also provide a utility function, :func:`~mrsimulator.utils.spectral_fitting.LMFIT_min_function`, for evaluating the difference vector between the simulation and experiment, based on the parameters update. You may use this function directly as the argument of the LMFIT Minimizer class, as follows, .. GENERATED FROM PYTHON SOURCE LINES 178-182 .. code-block:: default minner = Minimizer(sf.LMFIT_min_function, params, fcn_args=(sim, processor, sigma)) result = minner.minimize() result .. raw:: html

Fit Statistics

fitting methodleastsq
# function evals99
# data points2048
# variables7
chi-square 2364.72004
reduced chi-square 1.15860855
Akaike info crit. 308.494070
Bayesian info crit. 347.866403

Variables

name value standard error relative error initial value min max vary
sys_0_site_0_isotropic_chemical_shift 7.57609591 0.00347983 (0.05%) 5.0 -inf inf True
sys_0_site_0_shielding_symmetric_zeta -88.1880932 0.20973028 (0.24%) -80.0 -inf inf True
sys_0_site_0_shielding_symmetric_eta 0.45591108 0.01141672 (2.50%) 0.5 0.00000000 1.00000000 True
mth_0_rotor_frequency 6012.45936 0.80710569 (0.01%) 6000.0 5900.00000 6100.00000 True
SP_0_operation_1_Exponential_FWHM 0.27280282 0.00163466 (0.60%) 0.3 -inf inf True
SP_0_operation_3_Scale_factor 268.854046 1.20048569 (0.45%) 300.0 -inf inf True
SP_0_operation_4_ConstantOffset_offset -1.65291839 0.03734295 (2.26%) -2.0 -inf inf True

Correlations (unreported correlations are < 0.100)

SP_0_operation_1_Exponential_FWHMSP_0_operation_3_Scale_factor0.6643
sys_0_site_0_shielding_symmetric_zetasys_0_site_0_shielding_symmetric_eta0.3620
SP_0_operation_3_Scale_factorSP_0_operation_4_ConstantOffset_offset-0.2423
sys_0_site_0_shielding_symmetric_etaSP_0_operation_3_Scale_factor0.2274
sys_0_site_0_shielding_symmetric_zetaSP_0_operation_3_Scale_factor-0.2254
sys_0_site_0_isotropic_chemical_shiftmth_0_rotor_frequency0.2033
SP_0_operation_1_Exponential_FWHMSP_0_operation_4_ConstantOffset_offset-0.1610
sys_0_site_0_shielding_symmetric_zetamth_0_rotor_frequency-0.1084


.. GENERATED FROM PYTHON SOURCE LINES 183-184 **Step 8:** The plot of the fit, measurement, and residuals. .. GENERATED FROM PYTHON SOURCE LINES 184-201 .. code-block:: default # Best fit spectrum best_fit = sf.bestfit(sim, processor)[0].real residuals = sf.residuals(sim, processor)[0].real plt.figure(figsize=(4.25, 3.0)) ax = plt.subplot(projection="csdm") ax.plot(experiment, color="black", linewidth=0.5, label="Experiment") ax.plot(residuals, color="gray", linewidth=0.5, label="Residual") ax.plot(best_fit, linewidth=2, alpha=0.6, label="Best Fit") ax.set_xlabel(r"$^{31}$P frequency / ppm") ax.set_xlim(150, -150) plt.legend() plt.grid() plt.tight_layout() plt.show() .. image-sg:: /fitting/1D_fitting/images/sphx_glr_plot_1_31P_Na2PO4_MAS_003.png :alt: plot 1 31P Na2PO4 MAS :srcset: /fitting/1D_fitting/images/sphx_glr_plot_1_31P_Na2PO4_MAS_003.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 202-206 .. [#f1] D.Massiot, F.Fayon, M.Capron, I.King, S.Le Calvé, B.Alonso, J.O.Durand, B.Bujoli, Z.Gan, G.Hoatson, 'Modelling one and two-dimensional solid-state NMR spectra.', Magn. Reson. Chem. **40** 70-76 (2002) `DOI: 10.1002/mrc.984 `_ .. rst-class:: sphx-glr-timing **Total running time of the script:** ( 0 minutes 2.882 seconds) .. _sphx_glr_download_fitting_1D_fitting_plot_1_31P_Na2PO4_MAS.py: .. only :: html .. container:: sphx-glr-footer :class: sphx-glr-footer-example .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: plot_1_31P_Na2PO4_MAS.py ` .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: plot_1_31P_Na2PO4_MAS.ipynb ` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_