pythonscipynancurve-fittinglmfit

Error: generating of Nan Values by curve fitting with lmfit/scipy


I have the function and the data:

from lmfit import Model
from matplotlib import pyplot as plt
import numpy as np

def second_order(x, k_a, k_d):

   r = 1e-5
   s = 1e-5
   q = 10
   t = 51.1

   a = k_a * (r + s) + k_d
   b = np.sqrt(a**2 - 4*k_a**2*r*s)
   y = (2*k_a*r*s) / (a + b*((np.exp(b*x)+1)/(np.exp(b*x)-1)))
   return q + t * (y / r)

x = [0.005, 0.05, 0.1, 0.15, 0.2, 0.23274, 0.3, 0.35851, 0.4, 0.45, 0.47881, 0.55, 0.57861, 0.64559, 0.7, 0.75, 0.811, 0.85, 0.87116, 0.95, 1.01743, 1.05, 1.07758, 1.15, 1.2, 1.25, 1.3, 1.35, 1.4, 1.45, 1.5, 1.55, 1.6, 1.65, 1.7, 1.75, 1.8, 1.85, 1.9, 1.95, 2.0, 2.05, 2.1, 2.15, 2.2, 2.25, 2.3, 2.35, 2.4, 2.45, 2.5, 2.55, 2.6, 2.65, 2.7, 2.75, 2.8, 2.85, 2.9, 2.95, 3.0, 3.05, 3.1, 3.15, 3.2, 3.25, 3.3, 3.35, 3.4, 3.45, 3.5, 3.55, 3.6, 3.65, 3.7, 3.75, 3.8, 3.85, 3.9, 3.95, 4.0, 4.05, 4.1, 4.15, 4.2, 4.25, 4.3, 4.35, 4.4, 4.45, 4.5, 4.55, 4.6, 4.65, 4.7, 4.75, 4.8, 4.85, 4.9, 4.95, 5.0]
y = [10.5, 14.7, 18.9, 22.6, 25.9, 29.4, 31.6, 33.4, 36.1, 38.1, 39.8, 41.5, 42.9, 44.7, 45.6, 46.8, 47.2, 48.7, 49.7, 50.4, 50.6, 51.8, 52.5, 53.0, 53.3, 54.5, 53.8, 55.8, 55.3, 54.7, 55.7, 56.5, 56.1, 57.2, 56.6, 57.7, 56.8, 58.1, 57.8, 57.5, 59.0, 57.6, 58.8, 58.3, 58.8, 58.5, 59.2, 58.4, 59.0, 59.9, 59.1, 58.7, 59.2, 59.1, 59.6, 59.6, 59.2, 60.6, 59.1, 60.2, 59.4, 60.1, 59.4, 60.1, 59.9, 59.3, 60.6, 59.3, 60.4, 59.1, 60.7, 60.3, 59.4, 60.5, 59.4, 60.3, 59.2, 60.6, 58.8, 61.0, 59.2, 60.6, 59.5, 60.4, 59.5, 61.0, 58.6, 60.2, 59.9, 60.4, 59.5, 60.8, 60.0, 59.3, 60.4, 59.3, 61.1, 59.5, 60.2, 59.3, 60.9]


gmodel = Model(second_order)
print('parameter names: {}'.format(gmodel.param_names))
print('independent variables: {}'.format(gmodel.independent_vars))

result = gmodel.fit(y,x=x,k_a = 10, k_d = 10)

print(result.fit_report())

The data range for x is between 0.005 and 5, the range of y is between 10 and 60. I always get the error:

The model function generated NaN values and the fit aborted! Please check your model function and/or set boundaries on parameters where applicable. In cases like this, using "nan_policy='omit'" will probably not work.

I am not sure if it has something to do with an overflow by the exp() function? I also excluded the first point at 0 to prevent a division through 0.


Solution

  • Here are a few things to check:

    First: are you certain that the argument of np.sqrt() can not ever be negative? I don't think you are doing anything to actively prevent that from happening.

    Second: are you certain that the argument of np.exp() can not ever be greater than ~710? That will generate np.inf which will also halt the fit but is usually easier to deal with than np.nan as the meaning is clearer. You might just put an upper bound on b so that b*x.max() < 705, perhaps just with

    b = min(705/x.max(), np.sqrt(a**2 - 4*k_a**2*r*s))