From: W. Trevor King Date: Thu, 28 Apr 2011 11:49:26 +0000 (-0400) Subject: Adapt to handle scipy.optimize.leastsq for scipy >= 0.8.0. X-Git-Url: http://git.tremily.us/?p=hooke.git;a=commitdiff_plain;h=67bb9b2891c9ac09a6e4f0c1776b8a448051227e Adapt to handle scipy.optimize.leastsq for scipy >= 0.8.0. For single-parameter fitting, leastsq() used to return the fitted parameter as a float. Now it returns it as a length-one array. With this commit, Hooke should work with either case. --- diff --git a/hooke/plugin/polymer_fit.py b/hooke/plugin/polymer_fit.py index 7105e57..4447ca7 100644 --- a/hooke/plugin/polymer_fit.py +++ b/hooke/plugin/polymer_fit.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2008-2010 Alberto Gomez-Casado +# Copyright (C) 2008-2011 Alberto Gomez-Casado # Fabrizio Benedetti # Massimo Sandal # W. Trevor King @@ -244,7 +244,7 @@ class FJC (ModelFitter): >>> info['Kuhn length (m)'] = 2*a >>> model = FJC(d_data, info=info, rescale=True) - >>> L = model.fit(outqueue=outqueue) + >>> L, = model.fit(outqueue=outqueue) >>> fit_info = outqueue.get(block=False) >>> print L # doctest: +ELLIPSIS 3.199...e-08 @@ -340,11 +340,9 @@ class FJC (ModelFitter): def fit(self, *args, **kwargs): params = super(FJC, self).fit(*args, **kwargs) - if is_iterable(params): - params[0] = self.L(params[0]) # convert Lp -> L + params[0] = self.L(params[0]) # convert Lp -> L + if len(params) > 1: params[1] = abs(params[1]) # take the absolute value of `a` - else: # params is a float - params = self.L(params) # convert Lp -> L return params def guess_initial_params(self, outqueue=None): @@ -507,7 +505,7 @@ class FJC_PEG (ModelFitter): >>> info['Kuhn length (m)'] = 2*kwargs['a'] >>> model = FJC_PEG(d_data, info=info, rescale=True) - >>> N = model.fit(outqueue=outqueue) + >>> N, = model.fit(outqueue=outqueue) >>> fit_info = outqueue.get(block=False) >>> print N # doctest: +ELLIPSIS 96.931... @@ -613,11 +611,9 @@ class FJC_PEG (ModelFitter): def fit(self, *args, **kwargs): params = super(FJC_PEG, self).fit(*args, **kwargs) - if is_iterable(params): - params[0] = self.L(params[0]) # convert Nr -> N + params[0] = self.L(params[0]) # convert Nr -> N + if len(params) > 1: params[1] = abs(params[1]) # take the absolute value of `a` - else: # params is a float - params = self.L(params) # convert Nr -> N return params def guess_initial_params(self, outqueue=None): @@ -726,7 +722,7 @@ class WLC (ModelFitter): >>> info['persistence length (m)'] = 2*p >>> model = WLC(d_data, info=info, rescale=True) - >>> L = model.fit(outqueue=outqueue) + >>> L, = model.fit(outqueue=outqueue) >>> fit_info = outqueue.get(block=False) >>> print L # doctest: +ELLIPSIS 3.318...e-08 @@ -822,11 +818,9 @@ class WLC (ModelFitter): def fit(self, *args, **kwargs): params = super(WLC, self).fit(*args, **kwargs) - if is_iterable(params): - params[0] = self.L(params[0]) # convert Lp -> L + params[0] = self.L(params[0]) # convert Lp -> L + if len(params) > 1: params[1] = abs(params[1]) # take the absolute value of `p` - else: # params is a float - params = self.L(params) # convert Lp -> L return params def guess_initial_params(self, outqueue=None): diff --git a/hooke/util/fit.py b/hooke/util/fit.py index 0a97135..6267341 100644 --- a/hooke/util/fit.py +++ b/hooke/util/fit.py @@ -1,4 +1,4 @@ -# Copyright (C) 2010 W. Trevor King +# Copyright (C) 2010-2011 W. Trevor King # # This file is part of Hooke. # @@ -20,8 +20,13 @@ """ from numpy import arange, ndarray +from scipy import __version__ as _scipy_version from scipy.optimize import leastsq -import scipy.optimize + +_strings = _scipy_version.split('.') +# Don't convert third string to an integer in case of (for example) '0.7.2rc3' +_SCIPY_VERSION = (int(_strings[0]), int(_strings[1]), _strings[2]) +del _strings class PoorFit (ValueError): @@ -128,6 +133,25 @@ class ModelFitter (object): 7.000 >>> print '%.3f' % offset -32.890 + + Test single-parameter models: + + >>> class SingleParameterModel (LinearModel): + ... '''Simple linear model. + ... ''' + ... def model(self, params): + ... return super(SingleParameterModel, self).model([params[0], 0.]) + ... def guess_initial_params(self, outqueue=None): + ... return super(SingleParameterModel, self + ... ).guess_initial_params(outqueue)[:1] + ... def guess_scale(self, params, outqueue=None): + ... return super(SingleParameterModel, self + ... ).guess_scale([params[0], 0.], outqueue)[:1] + >>> data = 20*numpy.sin(arange(1000)) + 7.*arange(1000) + >>> m = SingleParameterModel(data) + >>> slope, = m.fit(outqueue=outqueue) + >>> print '%.3f' % slope + 7.000 """ def __init__(self, *args, **kwargs): self.set_data(*args, **kwargs) @@ -233,13 +257,13 @@ class ModelFitter (object): params,cov,info,mesg,ier = leastsq( func=self.residual, x0=active_params, full_output=True, diag=scale, **kwargs) + if len(initial_params) == 1 and _SCIPY_VERSION < (0, 8, '0'): + # params is a float for scipy < 0.8.0. Convert to list. + params = [params] if self._rescale == True: active_params = params - if len(initial_params) == 1: # params is a float - params = params * self._param_scale_factors[0] - else: - params = [p*s for p,s in zip(params, - self._param_scale_factors)] + params = [p*s for p,s in zip(params, + self._param_scale_factors)] else: active_params = params if outqueue != None: