source: sasview/park_integration/ParkFitting.py @ 0f5bc9f

ESS_GUIESS_GUI_DocsESS_GUI_batch_fittingESS_GUI_bumps_abstractionESS_GUI_iss1116ESS_GUI_iss879ESS_GUI_iss959ESS_GUI_openclESS_GUI_orderingESS_GUI_sync_sascalccostrafo411magnetic_scattrelease-4.1.1release-4.1.2release-4.2.2release_4.0.1ticket-1009ticket-1094-headlessticket-1242-2d-resolutionticket-1243ticket-1249ticket885unittest-saveload
Last change on this file since 0f5bc9f was ee5b04c, checked in by Gervaise Alina <gervyh@…>, 16 years ago

comment added

  • Property mode set to 100644
File size: 8.2 KB
RevLine 
[792db7d5]1"""
2    @organization: ParkFitting module contains SansParameter,Model,Data
3    FitArrange, ParkFit,Parameter classes.All listed classes work together to perform a
4    simple fit with park optimizer.
5"""
[7705306]6import time
7import numpy
[792db7d5]8
[7705306]9import park
10from park import fit,fitresult
11from park import assembly
[cf3b781]12from park.fitmc import FitSimplex, FitMC
[7705306]13
14from sans.guitools.plottables import Data1D
15from Loader import Load
[d4b0687]16from AbstractFitEngine import FitEngine, Parameter, FitArrange
[7705306]17class SansParameter(park.Parameter):
18    """
[792db7d5]19        SANS model parameters for use in the PARK fitting service.
20        The parameter attribute value is redirected to the underlying
21        parameter value in the SANS model.
[7705306]22    """
23    def __init__(self, name, model):
24         self._model, self._name = model,name
[9e85792]25         self.set(model.getParam(name))
[792db7d5]26         
[7705306]27    def _getvalue(self): return self._model.getParam(self.name)
[792db7d5]28   
[9e85792]29    def _setvalue(self,value): 
30        self._model.setParam(self.name, value)
[792db7d5]31       
[7705306]32    value = property(_getvalue,_setvalue)
[792db7d5]33   
[7705306]34    def _getrange(self):
35        lo,hi = self._model.details[self.name][1:]
36        if lo is None: lo = -numpy.inf
37        if hi is None: hi = numpy.inf
38        return lo,hi
[792db7d5]39   
[7705306]40    def _setrange(self,r):
41        self._model.details[self.name][1:] = r
42    range = property(_getrange,_setrange)
43
[792db7d5]44
[7705306]45class Model(object):
46    """
47        PARK wrapper for SANS models.
48    """
49    def __init__(self, sans_model):
50        self.model = sans_model
[6b126e8]51        #print "ParkFitting:sans model",self.model
[7705306]52        sansp = sans_model.getParamList()
[6b126e8]53        #print "ParkFitting: sans model parameter list",sansp
[7705306]54        parkp = [SansParameter(p,sans_model) for p in sansp]
[6b126e8]55        #print "ParkFitting: park model parameter ",parkp
[7705306]56        self.parameterset = park.ParameterSet(sans_model.name,pars=parkp)
[792db7d5]57       
[7705306]58    def eval(self,x):
[6b126e8]59        #print "eval",self.parameterset[0].value,self.parameterset[1].value
60        #print "model run ",self.model.run(x)
[7705306]61        return self.model.run(x)
62   
63class Data(object):
64    """ Wrapper class  for SANS data """
[792db7d5]65    def __init__(self,x=None,y=None,dy=None,dx=None,sans_data=None):
66        if not sans_data==None:
67            self.x= sans_data.x
68            self.y= sans_data.y
69            self.dx= sans_data.dx
70            self.dy= sans_data.dy
71        else:
72            if x!=None and y!=None and dy!=None:
73                self.x=x
74                self.y=y
75                self.dx=dx
76                self.dy=dy
77            else:
78                raise ValueError,\
79                "Data is missing x, y or dy, impossible to compute residuals later on"
[7705306]80        self.qmin=None
81        self.qmax=None
82       
83    def setFitRange(self,mini=None,maxi=None):
84        """ to set the fit range"""
85        self.qmin=mini
86        self.qmax=maxi
87       
88    def residuals(self, fn):
[792db7d5]89        """ @param fn: function that return model value
90            @return residuals
91        """
[7705306]92        x,y,dy = [numpy.asarray(v) for v in (self.x,self.y,self.dy)]
93        if self.qmin==None and self.qmax==None: 
[cf3b781]94            self.fx = fn(x)
[7705306]95            return (y - fn(x))/dy
96       
97        else:
[cf3b781]98            self.fx = fn(x[idx])
[7705306]99            idx = x>=self.qmin & x <= self.qmax
100            return (y[idx] - fn(x[idx]))/dy[idx]
101           
102         
103    def residuals_deriv(self, model, pars=[]):
[792db7d5]104        """
105            @return residuals derivatives .
106            @note: in this case just return empty array
107        """
[7705306]108        return []
[d4b0687]109
[792db7d5]110           
[4c718654]111class ParkFit(FitEngine):
[7705306]112    """
[792db7d5]113        ParkFit performs the Fit.This class can be used as follow:
114        #Do the fit Park
115        create an engine: engine = ParkFit()
116        Use data must be of type plottable
117        Use a sans model
118       
119        Add data with a dictionnary of FitArrangeList where Uid is a key and data
120        is saved in FitArrange object.
121        engine.set_data(data,Uid)
122       
123        Set model parameter "M1"= model.name add {model.parameter.name:value}.
124        @note: Set_param() if used must always preceded set_model()
125             for the fit to be performed.
126        engine.set_param( model,"M1", {'A':2,'B':4})
127       
128        Add model with a dictionnary of FitArrangeList{} where Uid is a key and model
129        is save in FitArrange object.
130        engine.set_model(model,Uid)
131       
132        engine.fit return chisqr,[model.parameter 1,2,..],[[err1....][..err2...]]
133        chisqr1, out1, cov1=engine.fit({model.parameter.name:value},qmin,qmax)
134        @note: {model.parameter.name:value} is ignored in fit function since
135        the user should make sure to call set_param himself.
[7705306]136    """
137    def __init__(self,data=[]):
[792db7d5]138        """
139            Creates a dictionary (self.fitArrangeList={})of FitArrange elements
140            with Uid as keys
141        """
[7705306]142        self.fitArrangeList={}
[ee5b04c]143        self.paramList=[]
[37d9521]144       
[4dd63eb]145    def createProblem(self):
[7705306]146        """
[792db7d5]147        Extract sansmodel and sansdata from self.FitArrangelist ={Uid:FitArrange}
148        Create parkmodel and park data ,form a list couple of parkmodel and parkdata
149        create an assembly self.problem=  park.Assembly([(parkmodel,parkdata)])
[7705306]150        """
[7924042]151        print "ParkFitting: In createproblem"
[7705306]152        mylist=[]
[9e85792]153        listmodel=[]
[37d9521]154        i=0
[7705306]155        for k,value in self.fitArrangeList.iteritems():
[9e85792]156            sansmodel=value.get_model()
[792db7d5]157            #wrap sans model
[9e85792]158            parkmodel = Model(sansmodel)
[6b126e8]159            #print "ParkFitting: createproblem: just create a model",parkmodel.parameterset
[9e85792]160            for p in parkmodel.parameterset:
[202f93a]161                #self.param_list.append(p._getname())
[37d9521]162                #if p.isfixed():
163                #print 'parameters',p.name
164                #print "self.paramList",self.paramList
165                if p.isfixed() and p._getname()in self.paramList:
[9e85792]166                    p.set([-numpy.inf,numpy.inf])
[37d9521]167            i+=1   
[7705306]168            Ldata=value.get_data()
[d4b0687]169            x,y,dy=self._concatenateData(Ldata)
[792db7d5]170            #wrap sansdata
[d4b0687]171            parkdata=Data(x,y,dy,None)
[792db7d5]172            couple=(parkmodel,parkdata)
[6b126e8]173            #print "Parkfitting: fitness",couple   
[7705306]174            mylist.append(couple)
[6b126e8]175        #print "mylist",mylist
[cf3b781]176        self.problem =  park.Assembly(mylist)
[792db7d5]177       
[7705306]178   
[4dd63eb]179    def fit(self, qmin=None, qmax=None):
[7705306]180        """
[792db7d5]181            Performs fit with park.fit module.It can  perform fit with one model
182            and a set of data, more than two fit of  one model and sets of data or
183            fit with more than two model associated with their set of data and constraints
184           
185           
186            @param pars: Dictionary of parameter names for the model and their values.
187            @param qmin: The minimum value of data's range to be fit
188            @param qmax: The maximum value of data's range to be fit
189            @note:all parameter are ignored most of the time.Are just there to keep ScipyFit
190            and ParkFit interface the same.
191            @return result.fitness: Value of the goodness of fit metric
192            @return result.pvec: list of parameter with the best value found during fitting
193            @return result.cov: Covariance matrix
[7705306]194        """
[7924042]195        #from numpy.linalg.linalg.LinAlgError import LinAlgError
[6b126e8]196        #print "Parkfitting: fit method probably breaking just right before \
197        #call fit"
[4dd63eb]198        self.createProblem()
[cf3b781]199        pars=self.problem.fit_parameters()
200        self.problem.eval()
[9855699]201        #print "M0.B",self.problem[1].parameterset['B'].value,self.problem[0].parameterset['B'].value
202
[cf3b781]203        localfit = FitSimplex()
204        localfit.ftol = 1e-8
205        fitter = FitMC(localfit=localfit)
[ee5b04c]206       
207        result = fit.fit(self.problem,
208                     fitter=fitter,
209                     handler= fitresult.ConsoleUpdate(improvement_delta=0.1))
210        print "ParkFitting: result",result
211        if result !=None:
[6b126e8]212            #for p in result.parameters:
213            #    print "fit in park fitting", p.name, p.value,p.stderr
214            return result.fitness,result.pvec,result.cov,result
[ee5b04c]215        else:
216            raise ValueError, "SVD did not converge"
217           
218       
[7924042]219       
[7705306]220   
[d4b0687]221   
Note: See TracBrowser for help on using the repository browser.