Source code for pySAXS.models.model

# -*- coding: cp1252 -*-
"""
LIONS_SAXS python routines for small angle xray scattering.
Model class
version 0.1b 04/07/2010
04-07-2010 DC: calculation of residuals corrected in fitBounds
04-07-2010 DC: calculation of chi square corrected
03-07-2010 DC: syntax error on fitBounds corrected
"""


import sys
from string import *
from math import *
#import Numeric
import numpy
from scipy import special as SPspecial
from scipy import stats as SPstats
from scipy import integrate as SPintegrate
from scipy import optimize 
import random
from time import clock
from xml.etree import ElementTree
from pySAXS.tools import xmltools
import pySAXS

[docs]class Model: ''' Model class templates test ''' IntensityFunc=None #function N=0 q=None #q range(x scale) Arg=None #list of parameters Format=None #list of c format istofit=None #list of boolean for fitting name="" #name of the model can be different from the class name Doc="" #list of description for parameters Description="" # description of model Author="LIONS" #name of Author WarningForCalculationTime=False #if calculation time is too high, set to false specific=False #for specific model, set to true def __init__(self,q=None,Arg=[],istofit=None,name=""): if q<>None: self.q=q if (Arg<>[])and (Arg!=None): self.Arg=Arg if name!="": self.name=name #if istofit == none then fit all datas (array of true) if (istofit==None)and (self.istofit==None): self.istofit=Arg if len(Arg)>=0: for i in range(len(Arg)): self.istofit[i]=True def __str__(self): return "Model "+self.name+ " with parameters : "+str(self.Arg) def __repr__(self): return self.__str__()
[docs] def xml(self): ''' return an xml object with name, args, and isTofit <model name='Gaussian'> <par value='0.123' fit='true'>height of gaussian</par> ... </model> ''' #create the root </root><root> root_element = ElementTree.Element("model",name=self.__class__.__name__) for i in range(len(self.Arg)): attrib={'value':str(self.Arg[i]),\ 'fit':str(self.istofit[i]), 'order':str(i)} child = ElementTree.Element("par",attrib) child.text=str(self.Doc[i]) #now append root_element.append(child) return root_element
[docs] def getNumber(self): return self.N
[docs] def setQ(self,q): ''' set the q scale ''' self.q=q
[docs] def getQ(self): ''' get the q scale as a numpy array ''' temp=numpy.zeros(len(self.q),dtype='float') for i in range(len(self.q)): temp[i]=self.q[i] return temp
[docs] def setArg(self,par): ''' set the model parameters ''' self.Arg=par
[docs] def getArg(self): ''' return the model parameters as list ''' temp=list(range(len(self.Arg))) for i in range(len(self.Arg)): temp[i]=self.Arg[i] return temp
[docs] def setIstofit(self,ITF): ''' set istofit varaiable ''' self.istofit=ITF
[docs] def getIstofit(self): temp=list(range(len(self.istofit))) for i in range(len(self.istofit)): temp[i]=self.istofit[i] return temp
[docs] def getIntensity(self): ''' compute the intensity function for the model ''' try: y=self.IntensityFunc(self.q,self.Arg) except: y=numpy.zeros(numpy.shape(self.q)) return y
[docs] def getNoisy(self,randompercent=0.1): ''' return a noisy intensity computed for the model ''' y=self.getIntensity() for i in range(len(self.q)): y[i]=y[i]*(1+((random.random()-0.5)*randompercent)) return y
[docs] def getBoundsFromParam(self,aroundParam=0.2): ''' return bounds of parameters with a percent of aroundParam ''' bounds=[] for i in range(len(self.Arg)): boundsmin=self.Arg[i]*(1-aroundParam) boundsmax=self.Arg[i]*(1+aroundParam) bounds.append((boundsmin,boundsmax)) return bounds
[docs] def residuals(self,par,Iexp,plotexp=0): """ residuals par is the list of the parameters to be fitted """ par_to_fit=self.Arg[:] j=0 for i in range(len(par_to_fit)): if self.istofit[i]==True: par_to_fit[i]=par[j] j+=1 err=(Iexp*self.q**plotexp-self.IntensityFunc(self.q,par_to_fit)*self.q**plotexp) return err
[docs] def residuals_bounds(self,par,Iexp,plotexp=0): """ residuals used for the fit with bounds (arguments for leastsq and fmin.tnc are different) par is the list of the parameters to be fitted """ par_to_fit=self.Arg[:] j=0 for i in range(len(par_to_fit)): if self.istofit[i]==True: par_to_fit[i]=par[j] j+=1 err=numpy.sum((Iexp*self.q**plotexp-self.IntensityFunc(self.q,par_to_fit)*self.q**plotexp)**2) return err
[docs] def chi_carre(self,par,Iexp,plotexp=0): ''' chi_carre par is the list of all parameters (either to be fitted or not) Here the chi square is calculated assuming that the standard deviation equals the function ''' '''par=[] for i in range(len(self.Arg)): if self.istofit[i]==True: par.append(self.Arg[i]) ''' res=self.residuals(par,Iexp,plotexp)**2. i=self.IntensityFunc(self.q,par) chi = numpy.sum(res/i) return chi
[docs] def fit(self,Iexp,plotexp=0,verbose=False): ''' Fit the models with leastsq ''' # params can be not fitted (from istofit) #--produce a new param : param0 param0=[] NF=0 #if many parameters to fit for i in range(len(self.Arg)): if self.istofit[i]: param0.append(self.Arg[i]) NF=NF+1 #print param0 #-- fitting procedure t0=clock() res=optimize.leastsq(self.residuals,param0,args=(Iexp,plotexp),full_output=1) t1=clock() if verbose: print 'Parameters found for the fit= ', res[0], ' in ',t1-t0,'s' print 'Covariance matrix of the parameters',res[1] # results to new params par=self.Arg j=0 for i in range(len(par)): if self.istofit[i]: if NF==1: par[i]=res[0] else: par[i]=res[0][j] #par[i]=res[j] j=j+1 return par
[docs] def fitBounds(self,Iexp,bounds,plotexp=0,verbose=False): ''' fit the model with fmin_tnc with bounds as bounds = [(0.0,10.0)] bounds must have same size than params ''' # params can be not fitted (from istofit) #--produce a new param : param0 # and newbounds #if isttofit is not True, then bounds or params are not taken into acount param0=[] newbounds=[] NF=0 for i in range(len(self.Arg)): if self.istofit[i]==True: param0.append(self.Arg[i]) newbounds.append(bounds[i]) NF=NF+1 #fitting with bounds t0=clock() res, nfeval, rc = optimize.fmin_tnc(self.residuals_bounds, param0, fprime=None, args=([Iexp,plotexp]),\ approx_grad=1, bounds=newbounds, epsilon=1e-08, scale=None, messages=0,\ maxCGit=-1, maxfun=None, eta=-1, stepmx=0, accuracy=0, fmin=0, ftol=-1, rescale=-1) t1=clock() if verbose: print 'Parameters found for the fit= ', res, ' in ',t1-t0,'s' # results to new params par=self.Arg j=0 for i in range(len(par)): if self.istofit[i]==True: if NF==1: par[i]=res else: par[i]=res[j] #par[i]=res[j] j=j+1 return par return message
[docs]def getModelFromXML(element): attrib=element.attrib #print attrib if not(attrib.has_key('name')): return None modelname=attrib['name'] M=getattr(pySAXS.models,modelname)()#create a new model #print "create new model from class :",modelname arg={} istofit={} l=[] for subelement in element: tag=subelement.tag subattrib=subelement.attrib if subattrib.has_key('order'): if subattrib.has_key('value'): arg[subattrib['order']]=float(subattrib['value']) istofit[subattrib['order']]=subattrib['fit'] l.append(subattrib['order']) #here we have a list and a dictionnary l.sort() returnArg=[] returnIsToFit=[] for i in l: returnArg.append(arg[i]) returnIsToFit.append(xmltools.convertText(istofit[i],datatype='bool')) M.Arg=returnArg M.istofit=returnIsToFit #print M return M