* Imported more recent function fitting facility from Cr2 project.
This commit is contained in:
276
math/fitting/funcs_simple.py
Normal file
276
math/fitting/funcs_simple.py
Normal file
@@ -0,0 +1,276 @@
|
||||
#
|
||||
# wpylib.math.fitting.funcs_simple module
|
||||
# Created: 20150520
|
||||
# Wirawan Purwanto
|
||||
#
|
||||
# Imported 20150520 from Cr2_analysis_cbs.py
|
||||
# (dated 20141017, CVS rev 1.143).
|
||||
#
|
||||
|
||||
"""
|
||||
wpylib.math.fitting.funcs_simple module
|
||||
A library of simple f(x) functions for fitting
|
||||
|
||||
For use with OO-style x-y curve fitting interface.
|
||||
"""
|
||||
|
||||
import numpy
|
||||
|
||||
|
||||
# Some simple function fitting--to aid fitting the complex ones later
|
||||
|
||||
def fit_linear(x, y):
|
||||
"""Warning: the ansatz for fitting is
|
||||
C[0] + C[1]*x
|
||||
so I have to reverse the order of fit parameters.
|
||||
"""
|
||||
rslt = numpy.polyfit(x, y, 1, full=True)
|
||||
return (rslt[0][::-1],) + rslt
|
||||
|
||||
|
||||
def fit_harm(x, y):
|
||||
"""Do a quadratic fit using poly fit and return it in terms of coeffs
|
||||
like this one:
|
||||
|
||||
C0 + 0.5 * C1 * (x - C2)**2
|
||||
|
||||
=> 0.5*C1*x**2 - C1*C2*x + (C0 + 0.5 * C1 * C2**2)
|
||||
|
||||
Polyfit gives:
|
||||
a * x**2 + b * x + c
|
||||
|
||||
Equating the two, we get:
|
||||
|
||||
C1 = 2 * a
|
||||
C2 = -b/C1
|
||||
C0 = c - 0.5*C1*C2**2
|
||||
|
||||
This function returns the recast parameters plus the original
|
||||
fit output.
|
||||
"""
|
||||
rslt = numpy.polyfit(x, y, 2, full=True)
|
||||
|
||||
(a,b,c) = rslt[0]
|
||||
C1 = 2*a
|
||||
C2 = -b/C1
|
||||
C0 = c - 0.5*C1*C2**2
|
||||
|
||||
return ((C0,C1,C2),) + rslt
|
||||
|
||||
|
||||
|
||||
# fit_func-style functional ansatz
|
||||
|
||||
class const_fit_func(fit_func_base):
|
||||
"""Constant function object.
|
||||
For use with fit_func function on a PEC.
|
||||
|
||||
Functional form:
|
||||
|
||||
C[0]
|
||||
|
||||
Coefficients:
|
||||
* C[0] = the constant sought
|
||||
"""
|
||||
dim = 1 # a function with 1-D domain
|
||||
param_names = ('c')
|
||||
def __call__(self, C, x):
|
||||
from numpy import exp
|
||||
y = C[0]
|
||||
self.func_call_hook(C, x, y)
|
||||
return y
|
||||
def Guess_xy(self, x, y):
|
||||
self.guess_params = (numpy.average(y),)
|
||||
return self.guess_params
|
||||
|
||||
|
||||
class linear_fit_func(fit_func_base):
|
||||
"""Linear function object.
|
||||
For use with fit_func function.
|
||||
|
||||
Functional form:
|
||||
|
||||
a + b * x
|
||||
|
||||
Coefficients:
|
||||
* C[0] = a
|
||||
* C[1] = b
|
||||
"""
|
||||
dim = 1 # a function with 1-D domain
|
||||
param_names = ('a', 'b')
|
||||
def __call__(self, C, x):
|
||||
y = C[0] + C[1] * x[0]
|
||||
self.func_call_hook(C, x, y)
|
||||
return y
|
||||
def Guess_xy(self, x, y):
|
||||
fit_rslt = fit_linear(x[0], y)
|
||||
self.guess_params = tuple(fit_rslt[0])
|
||||
return self.guess_params
|
||||
|
||||
|
||||
class linear_leastsq_fit_func(linear_fit_func):
|
||||
def fit(self, x, y, dy=None, fit_opts=None, Funct_hook=None, Guess=None):
|
||||
from wpylib.math.fitting.linear import linregr2d_SZ
|
||||
# Changed from:
|
||||
# rslt = fit_linear_weighted(x,y,dy)
|
||||
# to:
|
||||
rslt = (x, y, sigma=None)
|
||||
|
||||
self.last_fit = rslt[1]
|
||||
# Retrofit for API compatibility: not necessarily meaningful
|
||||
self.guess_params = rslt[0]
|
||||
return rslt[0]
|
||||
|
||||
|
||||
class exp_fit_func(fit_func_base):
|
||||
"""Exponential function object.
|
||||
For use with fit_func function.
|
||||
|
||||
Functional form:
|
||||
|
||||
C[0] * (exp(C[1] * (x - C[2]))
|
||||
|
||||
Coefficients:
|
||||
* C[0] = amplitude
|
||||
* C[1] = damping factor
|
||||
* C[2] = offset
|
||||
"""
|
||||
dim = 1 # a function with 1-D domain
|
||||
param_names = ['A', 'B', 'x0']
|
||||
A_guess = -2.62681
|
||||
B_guess = -9.05046
|
||||
x0_guess = 1.57327
|
||||
def __call__(self, C, x):
|
||||
from numpy import exp
|
||||
A, B, x0 = self.get_params(C, *(self.param_names))
|
||||
y = A * exp(B * (x[0] - x0))
|
||||
self.func_call_hook(C, x, y)
|
||||
return y
|
||||
def Guess_xy(self, x, y):
|
||||
from numpy import abs
|
||||
#y_abs = abs(y)
|
||||
# can do linear fit to guess the params,
|
||||
# but how to separate A and B*x0, I don't know.
|
||||
#imin = numpy.argmin(y)
|
||||
self.guess_params = (self.A_guess, self.B_guess, self.x0_guess)
|
||||
return self.guess_params
|
||||
|
||||
|
||||
class expm_fit_func(exp_fit_func):
|
||||
"""Similar to exp_fit_func but the exponent is always negative.
|
||||
"""
|
||||
def __call__(self, C, x):
|
||||
from numpy import exp,abs
|
||||
A, B, x0 = self.get_params(C, *(self.param_names))
|
||||
y = A * exp(-abs(B) * (x[0] - x0))
|
||||
self.func_call_hook(C, x, y)
|
||||
return y
|
||||
|
||||
|
||||
class powx_fit_func(fit_func_base):
|
||||
"""Power of x function object.
|
||||
For use with fit_func function.
|
||||
|
||||
Functional form:
|
||||
|
||||
C[0] * ((x - C[2])**C[1])
|
||||
|
||||
Coefficients:
|
||||
* C[0] = amplitude
|
||||
* C[1] = exponent (< 0)
|
||||
* C[2] = offset
|
||||
"""
|
||||
dim = 1 # a function with 1-D domain
|
||||
param_names = ['A', 'B', 'x0']
|
||||
A_guess = -2.62681
|
||||
B_guess = -9.05046
|
||||
x0_guess = 1.57327
|
||||
def __call__(self, C, x):
|
||||
from numpy import exp
|
||||
A, B, x0 = self.get_params(C, *(self.param_names))
|
||||
y = A * (x[0] - x0)**B
|
||||
self.func_call_hook(C, x, y)
|
||||
return y
|
||||
def Guess_xy(self, x, y):
|
||||
from numpy import abs
|
||||
#y_abs = abs(y)
|
||||
# can do linear fit to guess the params,
|
||||
# but how to separate A and B*x0, I don't know.
|
||||
#imin = numpy.argmin(y)
|
||||
self.guess_params = (self.A_guess, self.B_guess, self.x0_guess)
|
||||
return self.guess_params
|
||||
|
||||
|
||||
class invx_fit_func(powx_fit_func):
|
||||
"""Inverse of x function object that leads to 0 as x->infinity.
|
||||
For use with fit_func function.
|
||||
|
||||
Functional form:
|
||||
|
||||
C[0] * ((x - C[2])**C[1])
|
||||
|
||||
Specialized for CBX1 extrapolation
|
||||
Coefficients:
|
||||
* C[0] = amplitude (< 0)
|
||||
* C[1] = exponent (< 0)
|
||||
* C[2] = offset (> 0)
|
||||
"""
|
||||
"""
|
||||
/home/wirawan/Work/GAFQMC/expt/qmc/Cr2/CBS-TZ-QZ/UHF-CBS/20140128/Exp-CBX1.d/fit-invx.plt
|
||||
|
||||
Iteration 154
|
||||
WSSR : 0.875715 delta(WSSR)/WSSR : -9.96404e-06
|
||||
delta(WSSR) : -8.72566e-06 limit for stopping : 1e-05
|
||||
lambda : 0.00174063
|
||||
|
||||
resultant parameter values
|
||||
|
||||
A = -29.7924
|
||||
B = -13.2967
|
||||
x0 = 0.399396
|
||||
|
||||
After 154 iterations the fit converged.
|
||||
final sum of squares of residuals : 0.875715
|
||||
rel. change during last iteration : -9.96404e-06
|
||||
|
||||
degrees of freedom (FIT_NDF) : 2
|
||||
rms of residuals (FIT_STDFIT) = sqrt(WSSR/ndf) : 0.661708
|
||||
variance of residuals (reduced chisquare) = WSSR/ndf : 0.437858
|
||||
|
||||
Final set of parameters Asymptotic Standard Error
|
||||
======================= ==========================
|
||||
|
||||
A = -29.7924 +/- 8027 (2.694e+04%)
|
||||
B = -13.2967 +/- 196.1 (1474%)
|
||||
x0 = 0.399396 +/- 21.4 (5357%)
|
||||
|
||||
|
||||
correlation matrix of the fit parameters:
|
||||
|
||||
A B x0
|
||||
A 1.000
|
||||
B 1.000 1.000
|
||||
x0 1.000 1.000 1.000
|
||||
|
||||
For some reason the fit code in python gives:
|
||||
A,B,x0 = (-7028.1498486021028, -16.916447508009664, 2.2572321406455487e-06)
|
||||
but they fit almost exactly the same in the region 1.8 <= r <= 3.0.
|
||||
|
||||
"""
|
||||
A_guess = -29.7924
|
||||
B_guess = -13.2967
|
||||
x0_guess = 0.399396
|
||||
def __init__(self):
|
||||
from lmfit import Parameters
|
||||
self.fit_method = "lmfit:leastsq"
|
||||
p = Parameters()
|
||||
p.add_many(
|
||||
# (Name, Value, Vary, Min, Max, Expr)
|
||||
('A', -2.6, True, -1e6, -1e-9, None),
|
||||
('B', -2.0, True, None, -1e-9, None),
|
||||
('x0', 1.9, True, 1e-6, None, None),
|
||||
# The values are just a placeholder. They will be set later.
|
||||
)
|
||||
self.Params = p
|
||||
|
||||
|
||||
Reference in New Issue
Block a user