Search code examples
pythonargumentsode

function model() missing 1 required positional argument


I'm trying to estimate two parameter values A and B of an ODE using curve_fit, and then fit the solution to this ODE to my data set, plotting the results.

My code:

def model(I,t,A,B):
    dIdt = A*(2000 - I) + B*(2000 - I)*(I/2000)
    return dIdt

xData = # this is an np.array of my x values
yData = # this is an np.array of my y values
plt.plot(xData, yData, 'r.-', label='experimental-data')   #This part of the code seems to work

initialGuess = [1.0,1.0]    
popt, pcov = curve_fit(model, xData, yData, initialGuess)  #This is where the error is
print(popt)
xFit = np.arange(0.0, 5.0, 0.01)
I0 = 0
t = np.linspace(0,60)
I = odeint(model,I0,t)                                     #This is where i integrate the ODE to obtain I(t).

plt.plot(xFit, I(xFit, *popt), 'r', label='fit params: a=%5.3f, b=%5.3f' % tuple(popt))
plt.xlabel('x')
plt.ylabel('y')
plt.legend()
plt.show()

The error I am getting is

model() missing 1 required positional argument: 'B'.

I roughly understand what's going on: my model() function takes in 4 arguments at the beginning: I,t,A and B. However, somewhere along the line, the code only recognizes these first 3 arguments, and leaves out B. I am not sure how to fix this.

I have tried a few things:

  1. taking out the 'initialGuess' from the error line, so that there are 3 arguments in the curve_fit line , and this gave me a new error

Improper input: N=3 must not exceed M=1

which makes me think, that the initialGuess entry isn't the problem.

  1. Changed model in the error line to model(), which gave me the error model() missing 4 required positional arguments: 'I', 't', 'A', and 'B'

  2. Working off this, I changed model to model(I,t,A,B), which ends up giving me name 'A' is not defined

And now I am lost.

All of these errors are happening in the same line, so I've tried changing things in there, but perhaps I am missing something else. Most of the online sources that touch on this error mention having to instantiate a class instance, but I'm unsure what this means in this context, I have not defined a class in the code.

I hope I've made my confusion clear, any guidance would be appreciated.


Solution

  • Perform curve_fit from scipy.optimize with model function (see https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.curve_fit.html):

    import matplotlib.pyplot as plt
    import numpy as np
    from scipy.optimize import curve_fit
    
    
    def model(i, a, b):
        return a * (2_000 - i)\
               + b * (2_000 - i)\
               * (i / 2_000)
    
    
    xData = np.array(range(10))
    yData = model(xData, 1, 1)
    
    initialGuess = [1.0, 1.0]
    
    popt, pcov = curve_fit(f=model,
                           xdata=xData,
                           ydata=yData,
                           p0=initialGuess
                           )
    print(popt)
    

    Returns:

    [1. 1.]
    

    Next, Perform integration using odeint from scipy.integrate:

    from scipy.integrate import odeint
    
    xFit = np.arange(0.0, 5.0, 0.1)
    I0 = 0
    t = np.linspace(0, 60)
    a, b = 1, 1
    
    
    def model(i, t, a, b):
        return a * (2_000 - i)\
               + b * (2_000 - i)\
               * (i / 2_000)
    
    
    I = odeint(model, I0, t, args=(a, b))
    plt.plot(xFit, I[:, 0], 'b', label= 'fit params: a=%5.3f, b=%5.3f' % tuple(popt))
    plt.xlabel('x')
    plt.ylabel('y')
    plt.legend()
    plt.show()
    

    Reveals the plot (see https://docs.scipy.org/doc/scipy/reference/generated/scipy.integrate.odeint.html): enter image description here