I'm attempting to do some curve fitting within a class instance method, and the curve_fit function is giving my class instance method too many arguments.
The code is
"""Class for handling data from heat exchanger experiments."""
def get_flow(pressure_drop, coeff):
"""Sets flow based on coefficient and pressure drop."""
flow = coeff * pressure_drop**0.5
"""Sets experimental flow rate through heat exchanger"""
flow = self.flow_data.flow
pressure_drop = self.flow_data.pressure_drop
popt, pcov = spopt.curve_fit(self.get_flow, pressure_drop, flow)
self.exh.flow_coeff = popt
self.exh.flow_array = ( self.exh.flow_coeff * self.exh.pressure_drop**0.5 )
get_flow() takes exactly 2 arguments (3 given)
spopt.curve_fit(get_flow, pressure_drop, flow)
Unlucky case, and maybe a bug in curve_fit. curve_fit uses inspect to determine the number of starting values, which gets confused or misled if there is an extra
So giving a starting value should avoid the problem, I thought. However, there is also an isscalar(p0) in the condition, I have no idea why, and I think it would be good to report it as a problem or bug:
if p0 is None or isscalar(p0): # determine number of parameters by inspecting the function import inspect args, varargs, varkw, defaults = inspect.getargspec(f)
edit: avoiding the scalar as starting value
>>> np.isscalar() False
means that the example with only 1 parameter works if the starting value is defined as [...], e.g.similar to example below:
An example with two arguments and a given starting value avoids the inspect call, and everything is fine:
import numpy as np from scipy.optimize import curve_fit class MyClass(object): def get_flow(self, pressure_drop, coeff, coeff2): """Sets flow based on coefficient and pressure drop.""" flow = coeff * pressure_drop**0.5 + coeff2 return flow def optimize(self, start_value=None): coeff = 1 pressure_drop = np.arange(20.) flow = coeff * pressure_drop**0.5 + np.random.randn(20) return curve_fit(self.get_flow, pressure_drop, flow, p0=start_value) mc = MyClass() print mc.optimize([2,1]) import inspect args, varargs, varkw, defaults = inspect.getargspec(mc.get_flow) print args, len(args)
EDIT: This bug has been fixed so bound methods can now be passed as the first argument for curve_fit, if you have a sufficiently new version of scipy.
Commit of bug fix submission on github