Fit Using Inequality ConstraintΒΆ

Sometimes specifying boundaries using min and max are not sufficient, and more complicated (inequality) constraints are needed. In the example below the center of the Lorentzian peak is constrained to be between 0-5 away from the center of the Gaussian peak.

See also: https://lmfit.github.io/lmfit-py/constraints.html#using-inequality-constraints

import matplotlib.pyplot as plt
import numpy as np

from lmfit import Minimizer, Parameters, report_fit
from lmfit.lineshapes import gaussian, lorentzian


def residual(pars, x, data):
    model = (gaussian(x, pars['amp_g'], pars['cen_g'], pars['wid_g']) +
             lorentzian(x, pars['amp_l'], pars['cen_l'], pars['wid_l']))
    return model - data

Generate the simulated data using a Gaussian and Lorentzian line shape:

np.random.seed(0)
x = np.linspace(0, 20.0, 601)

data = (gaussian(x, 21, 6.1, 1.2) + lorentzian(x, 10, 9.6, 1.3) +
        np.random.normal(scale=0.1, size=x.size))

Create the fitting parameters and set an inequality constraint for cen_l. First, we add a new fitting parameter peak_split, which can take values between 0 and 5. Afterwards, we constrain the value for cen_l using the expression to be 'peak_split+cen_g':

pfit = Parameters()
pfit.add(name='amp_g', value=10)
pfit.add(name='amp_l', value=10)
pfit.add(name='cen_g', value=5)
pfit.add(name='peak_split', value=2.5, min=0, max=5, vary=True)
pfit.add(name='cen_l', expr='peak_split+cen_g')
pfit.add(name='wid_g', value=1)
pfit.add(name='wid_l', expr='wid_g')

mini = Minimizer(residual, pfit, fcn_args=(x, data))
out = mini.leastsq()
best_fit = data + out.residual

Performing a fit, here using the leastsq algorithm, gives the following fitting results:

report_fit(out.params)

Out:

[[Variables]]
    amp_g:       21.2722837 +/- 0.05138760 (0.24%) (init = 10)
    amp_l:       9.46504191 +/- 0.05445416 (0.58%) (init = 10)
    cen_g:       6.10496394 +/- 0.00334614 (0.05%) (init = 5)
    peak_split:  3.52163535 +/- 0.01004618 (0.29%) (init = 2.5)
    cen_l:       9.62659929 +/- 0.01066173 (0.11%) == 'peak_split+cen_g'
    wid_g:       1.21434950 +/- 0.00327315 (0.27%) (init = 1)
    wid_l:       1.21434950 +/- 0.00327315 (0.27%) == 'wid_g'
[[Correlations]] (unreported correlations are < 0.100)
    C(amp_g, wid_g)      =  0.620
    C(amp_g, peak_split) =  0.380
    C(peak_split, wid_g) =  0.344
    C(amp_g, amp_l)      = -0.295
    C(amp_l, cen_g)      = -0.276
    C(amp_g, cen_g)      =  0.194
    C(amp_l, wid_g)      = -0.165
    C(cen_g, wid_g)      =  0.155

and figure:

plt.plot(x, data, 'bo')
plt.plot(x, best_fit, 'r--', label='best fit')
plt.legend(loc='best')
plt.show()
../_images/sphx_glr_example_fit_with_inequality_001.png

Out:

/Users/Newville/Codes/lmfit-py/examples/example_fit_with_inequality.py:61: UserWarning: Matplotlib is currently using agg, which is a non-GUI backend, so cannot show the figure.
  plt.show()

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

Gallery generated by Sphinx-Gallery