.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "fitting/1D_fitting/plot_3_Na2SiO3.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_3_Na2SiO3.py: ¹⁷O MAS NMR of crystalline Na₂SiO₃ (2nd order quad) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. GENERATED FROM PYTHON SOURCE LINES 7-18 In this example, we illustrate the use of the mrsimulator objects to - create a quadrupolar 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:`^{17}\text{O}` MAS NMR spectrum of :math:`\text{Na}_{2}\text{SiO}_{3}` [#f5]_. Start by importing the relevant modules. .. GENERATED FROM PYTHON SOURCE LINES 18-30 .. 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 BlochDecayCTSpectrum 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 32-38 Import the dataset ------------------ Import the experimental dataset. We use dataset file serialized with the CSDM file-format, using the `csdmpy `_ module. .. GENERATED FROM PYTHON SOURCE LINES 38-59 .. code-block:: default filename = "https://ssnmr.org/sites/default/files/mrsimulator/Na2SiO3_O17.csdf" experiment = cp.load(filename) # standard deviation of noise from the dataset sigma = 1.931335 # 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(100, -50) plt.grid() plt.tight_layout() plt.show() .. image-sg:: /fitting/1D_fitting/images/sphx_glr_plot_3_Na2SiO3_001.png :alt: plot 3 Na2SiO3 :srcset: /fitting/1D_fitting/images/sphx_glr_plot_3_Na2SiO3_001.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 60-66 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 66-83 .. code-block:: default O1 = Site( isotope="17O", isotropic_chemical_shift=60.0, # in ppm, quadrupolar=SymmetricTensor(Cq=4.2e6, eta=0.5), # Cq in Hz ) O2 = Site( isotope="17O", isotropic_chemical_shift=40.0, # in ppm, quadrupolar=SymmetricTensor(Cq=2.4e6, eta=0.0), # Cq in Hz ) spin_systems = [ SpinSystem(sites=[O1], abundance=50, name="O1"), SpinSystem(sites=[O2], abundance=50, name="O2"), ] .. GENERATED FROM PYTHON SOURCE LINES 84-95 **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 central transition selective 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 95-115 .. code-block:: default # get the count, spectral_width, and reference_offset information from the experiment. spectral_dims = get_spectral_dimensions(experiment) MAS_CT = BlochDecayCTSpectrum( channels=["17O"], magnetic_flux_density=9.395, # in T rotor_frequency=14000, # 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 for the given method. Since the method and the number of spin systems remain # the same during the least-squares fit, 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_CT.get_transition_pathways(sys) .. GENERATED FROM PYTHON SOURCE LINES 116-117 **Step 3:** Create the Simulator object and add the method and spin system objects. .. GENERATED FROM PYTHON SOURCE LINES 117-121 .. code-block:: default sim = Simulator(spin_systems=spin_systems, methods=[MAS_CT]) sim.config.decompose_spectrum = "spin_system" sim.run() .. GENERATED FROM PYTHON SOURCE LINES 122-124 **Step 4:** Create a SignalProcessor class object and apply the post-simulation signal processor operations. .. GENERATED FROM PYTHON SOURCE LINES 124-134 .. code-block:: default processor = sp.SignalProcessor( operations=[ sp.IFFT(), sp.apodization.Gaussian(FWHM="100 Hz"), sp.FFT(), sp.Scale(factor=200.0), ] ) processed_dataset = processor.apply_operations(dataset=sim.methods[0].simulation).real .. GENERATED FROM PYTHON SOURCE LINES 135-136 **Step 5:** The plot of the dataset and the guess spectrum. .. GENERATED FROM PYTHON SOURCE LINES 136-147 .. 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) ax.set_xlim(100, -50) plt.legend() plt.grid() plt.tight_layout() plt.show() .. image-sg:: /fitting/1D_fitting/images/sphx_glr_plot_3_Na2SiO3_002.png :alt: plot 3 Na2SiO3 :srcset: /fitting/1D_fitting/images/sphx_glr_plot_3_Na2SiO3_002.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 148-160 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 fitting. 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`, that considerably simplifies the LMFIT parameters generation process. **Step 6:** Create a list of parameters. .. GENERATED FROM PYTHON SOURCE LINES 160-162 .. code-block:: default params = sf.make_LMFIT_params(sim, processor) .. GENERATED FROM PYTHON SOURCE LINES 163-170 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 of the two spin systems and constrain it to the initial value of 50% each, and constrain `eta=0` for spin system at index 1. .. GENERATED FROM PYTHON SOURCE LINES 170-175 .. code-block:: default params.pop("sys_0_abundance") params.pop("sys_1_abundance") params["sys_1_site_0_quadrupolar_eta"].vary = False 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_Gaussian_FWHM 100 -inf inf True None SP_0_operation_3_Scale_factor 200 -inf inf True None sys_0_site_0_isotropic_chemical_shift 60 -inf inf True None sys_0_site_0_quadrupolar_Cq 4.2e+06 -inf inf True None sys_0_site_0_quadrupolar_eta 0.5 0 1 True None sys_1_site_0_isotropic_chemical_shift 40 -inf inf True None sys_1_site_0_quadrupolar_Cq 2.4e+06 -inf inf True None sys_1_site_0_quadrupolar_eta 0 0 1 False None None .. GENERATED FROM PYTHON SOURCE LINES 176-182 **Step 7:** Perform 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 182-186 .. 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 evals1206
# data points4096
# variables7
chi-square 18809.7394
reduced chi-square 4.60008301
Akaike info crit. 6257.79454
Bayesian info crit. 6302.01891

Variables

name value standard error relative error initial value min max vary
sys_0_site_0_isotropic_chemical_shift 63.5827831 0.15636850 (0.25%) 60.0 -inf inf True
sys_0_site_0_quadrupolar_Cq 4272623.28 7206.73573 (0.17%) 4200000.0 -inf inf True
sys_0_site_0_quadrupolar_eta 0.52521011 0.00394863 (0.75%) 0.5 0.00000000 1.00000000 True
sys_1_site_0_isotropic_chemical_shift 39.3485477 0.02273955 (0.06%) 40.0 -inf inf True
sys_1_site_0_quadrupolar_Cq 2400519.88 2103.00507 (0.09%) 2400000.0 -inf inf True
sys_1_site_0_quadrupolar_eta 0.00000000 0.00000000 0.0 0.00000000 1.00000000 False
SP_0_operation_1_Gaussian_FWHM 176.965463 1.63287276 (0.92%) 100.0 -inf inf True
SP_0_operation_3_Scale_factor 234.761487 0.51827455 (0.22%) 200.0 -inf inf True

Correlations (unreported correlations are < 0.100)

sys_0_site_0_isotropic_chemical_shiftsys_0_site_0_quadrupolar_Cq0.9057
sys_1_site_0_isotropic_chemical_shiftsys_1_site_0_quadrupolar_Cq0.8314
sys_0_site_0_quadrupolar_etasys_1_site_0_isotropic_chemical_shift0.5494
sys_0_site_0_quadrupolar_etasys_1_site_0_quadrupolar_Cq0.3950
sys_0_site_0_quadrupolar_etaSP_0_operation_1_Gaussian_FWHM-0.3831
sys_0_site_0_quadrupolar_CqSP_0_operation_3_Scale_factor0.3776
sys_0_site_0_isotropic_chemical_shiftSP_0_operation_3_Scale_factor0.3409
sys_1_site_0_isotropic_chemical_shiftSP_0_operation_1_Gaussian_FWHM-0.3267
SP_0_operation_1_Gaussian_FWHMSP_0_operation_3_Scale_factor0.2788
sys_0_site_0_isotropic_chemical_shiftsys_1_site_0_isotropic_chemical_shift-0.2743
sys_0_site_0_quadrupolar_Cqsys_1_site_0_isotropic_chemical_shift-0.2719
sys_0_site_0_isotropic_chemical_shiftSP_0_operation_1_Gaussian_FWHM0.2635
sys_1_site_0_quadrupolar_CqSP_0_operation_1_Gaussian_FWHM-0.2593
sys_0_site_0_quadrupolar_Cqsys_0_site_0_quadrupolar_eta-0.2573
sys_0_site_0_quadrupolar_CqSP_0_operation_1_Gaussian_FWHM0.2564
sys_0_site_0_quadrupolar_Cqsys_1_site_0_quadrupolar_Cq-0.1895
sys_0_site_0_isotropic_chemical_shiftsys_1_site_0_quadrupolar_Cq-0.1846
sys_0_site_0_isotropic_chemical_shiftsys_0_site_0_quadrupolar_eta-0.1354


.. GENERATED FROM PYTHON SOURCE LINES 187-188 **Step 8:** The plot of the fit and the measurement dataset. .. GENERATED FROM PYTHON SOURCE LINES 188-205 .. 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) ax.set_xlabel("$^{17}$O frequency / ppm") ax.set_xlim(100, -50) plt.legend() plt.grid() plt.tight_layout() plt.show() .. image-sg:: /fitting/1D_fitting/images/sphx_glr_plot_3_Na2SiO3_003.png :alt: plot 3 Na2SiO3 :srcset: /fitting/1D_fitting/images/sphx_glr_plot_3_Na2SiO3_003.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 206-211 .. [#f5] T. M. Clark, P. Florian, J. F. Stebbins, and P. J. Grandinetti, An :math:`^{17}\text{O}` NMR Investigation of Crystalline Sodium Metasilicate: Implications for the Determination of Local Structure in Alkali Silicates, J. Phys. Chem. B. 2001, **105**, 12257-12265. `DOI: 10.1021/jp011289p `_ .. rst-class:: sphx-glr-timing **Total running time of the script:** ( 0 minutes 19.703 seconds) .. _sphx_glr_download_fitting_1D_fitting_plot_3_Na2SiO3.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_3_Na2SiO3.py ` .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: plot_3_Na2SiO3.ipynb ` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_