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()
example fit with inequality

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

Gallery generated by Sphinx-Gallery