source: sasview/park_integration/AbstractFitEngine.py @ 162d7a2

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 162d7a2 was 189be4e, checked in by Jae Cho <jhjcho@…>, 15 years ago

fixed fitting error on theory curve

  • Property mode set to 100644
File size: 24.1 KB
RevLine 
[aa36f96]1
2
[72c7d31]3import logging, sys
[54c21f50]4import park,numpy,math, copy
[1e3169c]5from DataLoader.data_info import Data1D
6from DataLoader.data_info import Data2D
[aa36f96]7
[48882d1]8class SansParameter(park.Parameter):
9    """
[aa36f96]10    SANS model parameters for use in the PARK fitting service.
11    The parameter attribute value is redirected to the underlying
12    parameter value in the SANS model.
[48882d1]13    """
14    def __init__(self, name, model):
[ca6d914]15        """
[aa36f96]16        :param name: the name of the model parameter
17        :param model: the sans model to wrap as a park model
18       
[ca6d914]19        """
20        self._model, self._name = model,name
21        #set the value for the parameter of the given name
22        self.set(model.getParam(name))
[48882d1]23         
[ca6d914]24    def _getvalue(self):
25        """
[aa36f96]26        override the _getvalue of park parameter
27       
28        :return value the parameter associates with self.name
29       
[ca6d914]30        """
31        return self._model.getParam(self.name)
[48882d1]32   
[ca6d914]33    def _setvalue(self,value):
34        """
[aa36f96]35        override the _setvalue pf park parameter
36       
37        :param value: the value to set on a given parameter
38       
[ca6d914]39        """
[48882d1]40        self._model.setParam(self.name, value)
41       
42    value = property(_getvalue,_setvalue)
43   
44    def _getrange(self):
[ca6d914]45        """
[aa36f96]46        Override _getrange of park parameter
47        return the range of parameter
[ca6d914]48        """
[920a6e5]49        #if not  self.name in self._model.getDispParamList():
[12b76cf]50        lo,hi = self._model.details[self.name][1:3]
[920a6e5]51        if lo is None: lo = -numpy.inf
52        if hi is None: hi = numpy.inf
53        #else:
54            #lo,hi = self._model.details[self.name][1:]
55            #if lo is None: lo = -numpy.inf
56            #if hi is None: hi = numpy.inf
[05f14dd]57        if lo >= hi:
58            raise ValueError,"wrong fit range for parameters"
59       
[48882d1]60        return lo,hi
61   
62    def _setrange(self,r):
[ca6d914]63        """
[aa36f96]64        override _setrange of park parameter
65       
66        :param r: the value of the range to set
67       
[ca6d914]68        """
[12b76cf]69        self._model.details[self.name][1:3] = r
[48882d1]70    range = property(_getrange,_setrange)
[a9e04aa]71   
72class Model(park.Model):
[48882d1]73    """
[aa36f96]74    PARK wrapper for SANS models.
[48882d1]75    """
[388309d]76    def __init__(self, sans_model, **kw):
[ca6d914]77        """
[aa36f96]78        :param sans_model: the sans model to wrap using park interface
79       
[ca6d914]80        """
[a9e04aa]81        park.Model.__init__(self, **kw)
[48882d1]82        self.model = sans_model
[ca6d914]83        self.name = sans_model.name
84        #list of parameters names
[48882d1]85        self.sansp = sans_model.getParamList()
[ca6d914]86        #list of park parameter
[48882d1]87        self.parkp = [SansParameter(p,sans_model) for p in self.sansp]
[ca6d914]88        #list of parameterset
[48882d1]89        self.parameterset = park.ParameterSet(sans_model.name,pars=self.parkp)
90        self.pars=[]
[ca6d914]91 
[48882d1]92    def getParams(self,fitparams):
[ca6d914]93        """
[aa36f96]94        return a list of value of paramter to fit
95       
96        :param fitparams: list of paramaters name to fit
97       
[ca6d914]98        """
[48882d1]99        list=[]
100        self.pars=[]
101        self.pars=fitparams
102        for item in fitparams:
103            for element in self.parkp:
104                 if element.name ==str(item):
105                     list.append(element.value)
106        return list
107   
[e71440c]108    def setParams(self,paramlist, params):
[ca6d914]109        """
[aa36f96]110        Set value for parameters to fit
111       
112        :param params: list of value for parameters to fit
113       
[ca6d914]114        """
[e71440c]115        try:
116            for i in range(len(self.parkp)):
117                for j in range(len(paramlist)):
118                    if self.parkp[i].name==paramlist[j]:
119                        self.parkp[i].value = params[j]
120                        self.model.setParam(self.parkp[i].name,params[j])
121        except:
122            raise
[ca6d914]123 
[48882d1]124    def eval(self,x):
[ca6d914]125        """
[aa36f96]126        override eval method of park model.
127       
128        :param x: the x value used to compute a function
129       
[ca6d914]130        """
[d8a2e31]131        try:
[393f0f3]132            return self.model.evalDistribution(x)
[d8a2e31]133        except:
[393f0f3]134            raise
[a9e04aa]135
[b64fa56]136   
[1e3169c]137class FitData1D(Data1D):
138    """
[aa36f96]139    Wrapper class  for SANS data
140    FitData1D inherits from DataLoader.data_info.Data1D. Implements
141    a way to get residuals from data.
[1e3169c]142    """
143    def __init__(self,x, y,dx= None, dy=None, smearer=None):
[ac3041b]144        Data1D.__init__(self, x=numpy.array(x), y=numpy.array(y), dx=dx, dy=dy)
[7d0c1a8]145        """
[aa36f96]146        :param smearer: is an object of class QSmearer or SlitSmearer
147           that will smear the theory data (slit smearing or resolution
148           smearing) when set.
149       
150        The proper way to set the smearing object would be to
151        do the following: ::
152       
[109e60ab]153            from DataLoader.qsmearing import smear_selection
[1e3169c]154            smearer = smear_selection(some_data)
155            fitdata1d = FitData1D( x= [1,3,..,],
156                                    y= [3,4,..,8],
157                                    dx=None,
158                                    dy=[1,2...], smearer= smearer)
[aa36f96]159       
160        :Note: that some_data _HAS_ to be of class DataLoader.data_info.Data1D
[109e60ab]161            Setting it back to None will turn smearing off.
162           
[7d0c1a8]163        """
[b461b6d7]164        self.smearer = smearer
[109e60ab]165       
[189be4e]166        # Check error bar; if no error bar found, set it constant(=1)
167        # TODO: Should provide an option for users to set it like percent, constant, or dy data
168        if dy ==None or dy==[] or dy.all()==0:
169            self.dy= numpy.ones(len(y)) 
170        else:
171            self.dy= numpy.asarray(dy).copy()
172
[109e60ab]173        ## Min Q-value
[4bd557d]174        #Skip the Q=0 point, especially when y(q=0)=None at x[0].
[1e3169c]175        if min (self.x) ==0.0 and self.x[0]==0 and not numpy.isfinite(self.y[0]):
176            self.qmin = min(self.x[self.x!=0])
[773806e]177        else:                             
[1e3169c]178            self.qmin= min (self.x)
[109e60ab]179        ## Max Q-value
[1e3169c]180        self.qmax = max (self.x)
[058b2d7]181       
[72c7d31]182        # Range used for input to smearing
183        self._qmin_unsmeared = self.qmin
184        self._qmax_unsmeared = self.qmax
[fd0d30fd]185        # Identify the bin range for the unsmeared and smeared spaces
186        self.idx = (self.x>=self.qmin) & (self.x <= self.qmax)
187        self.idx_unsmeared = (self.x>=self._qmin_unsmeared) & (self.x <= self._qmax_unsmeared)
188 
[72c7d31]189       
190       
[20d30e9]191    def setFitRange(self,qmin=None,qmax=None):
[7d0c1a8]192        """ to set the fit range"""
[09975cbb]193        # Skip Q=0 point, (especially for y(q=0)=None at x[0]).
[189be4e]194        # ToDo: Find better way to do it.
[1e3169c]195        if qmin==0.0 and not numpy.isfinite(self.y[qmin]):
196            self.qmin = min(self.x[self.x!=0])
[773806e]197        elif qmin!=None:                       
198            self.qmin = qmin           
199
[eef2e0ed]200        if qmax !=None:
201            self.qmax = qmax
[72c7d31]202           
[4bb2917]203        # Determine the range needed in unsmeared-Q to cover
204        # the smeared Q range
[72c7d31]205        self._qmin_unsmeared = self.qmin
206        self._qmax_unsmeared = self.qmax   
207       
[4bb2917]208        self._first_unsmeared_bin = 0
[1e3169c]209        self._last_unsmeared_bin  = len(self.x)-1
[4bb2917]210       
211        if self.smearer!=None:
212            self._first_unsmeared_bin, self._last_unsmeared_bin = self.smearer.get_bin_range(self.qmin, self.qmax)
[1e3169c]213            self._qmin_unsmeared = self.x[self._first_unsmeared_bin]
214            self._qmax_unsmeared = self.x[self._last_unsmeared_bin]
[4bb2917]215           
[fd0d30fd]216        # Identify the bin range for the unsmeared and smeared spaces
217        self.idx = (self.x>=self.qmin) & (self.x <= self.qmax)
[c6d3301]218        self.idx = self.idx & (self.dy!=0)   ## zero error can not participate for fitting
[fd0d30fd]219        self.idx_unsmeared = (self.x>=self._qmin_unsmeared) & (self.x <= self._qmax_unsmeared)
220 
[7d0c1a8]221       
222    def getFitRange(self):
223        """
[aa36f96]224        return the range of data.x to fit
[7d0c1a8]225        """
226        return self.qmin, self.qmax
[72c7d31]227       
[7d0c1a8]228    def residuals(self, fn):
[72c7d31]229        """
[aa36f96]230        Compute residuals.
231       
232        If self.smearer has been set, use if to smear
233        the data before computing chi squared.
234       
235        :param fn: function that return model value
236       
237        :return: residuals
238       
[109e60ab]239        """
240        # Compute theory data f(x)
[fd0d30fd]241        fx= numpy.zeros(len(self.x))
[7e752fe]242        fx[self.idx_unsmeared] = fn(self.x[self.idx_unsmeared])
[fd0d30fd]243       
[d5b488b]244        ## Smear theory data
[109e60ab]245        if self.smearer is not None:
[4bb2917]246            fx = self.smearer(fx, self._first_unsmeared_bin, self._last_unsmeared_bin)
[189be4e]247
[d5b488b]248        ## Sanity check
[fd0d30fd]249        if numpy.size(self.dy)!= numpy.size(fx):
250            raise RuntimeError, "FitData1D: invalid error array %d <> %d" % (numpy.shape(self.dy),
251                                                                              numpy.size(fx))
252                                                                             
253        return (self.y[self.idx]-fx[self.idx])/self.dy[self.idx]
[72c7d31]254     
[7d0c1a8]255    def residuals_deriv(self, model, pars=[]):
256        """
[aa36f96]257        :return: residuals derivatives .
258       
259        :note: in this case just return empty array
260       
[7d0c1a8]261        """
262        return []
263   
264   
[1e3169c]265class FitData2D(Data2D):
[7d0c1a8]266    """ Wrapper class  for SANS data """
[150144d]267    def __init__(self,sans_data2d ,data=None, err_data=None):
[1e3169c]268        Data2D.__init__(self, data= data, err_data= err_data)
[7d0c1a8]269        """
[aa36f96]270        Data can be initital with a data (sans plottable)
271        or with vectors.
[7d0c1a8]272        """
[1e3169c]273        self.res_err_image=[]
274        self.index_model=[]
275        self.qmin= None
276        self.qmax= None
[f72333f]277        self.smearer = None
[1e3169c]278        self.set_data(sans_data2d )
[f72333f]279
[1e3169c]280       
[027e8f2]281    def set_data(self, sans_data2d, qmin=None, qmax=None ):
[1e3169c]282        """
[aa36f96]283        Determine the correct qx_data and qy_data within range to fit
[1e3169c]284        """
[83195f7]285        self.data     = sans_data2d.data
286        self.err_data = sans_data2d.err_data
287        self.qx_data = sans_data2d.qx_data
288        self.qy_data = sans_data2d.qy_data
289        self.mask       = sans_data2d.mask
290
291        x_max = max(math.fabs(sans_data2d.xmin), math.fabs(sans_data2d.xmax))
292        y_max = max(math.fabs(sans_data2d.ymin), math.fabs(sans_data2d.ymax))
[20d30e9]293       
294        ## fitting range
[027e8f2]295        if qmin == None:
296            self.qmin = 1e-16
297        if qmax == None:
298            self.qmax = math.sqrt(x_max*x_max +y_max*y_max)
[70bf68c]299        ## new error image for fitting purpose
[da58fcc]300        if self.err_data== None or self.err_data ==[]:
[36bc34e]301            self.res_err_data= numpy.ones(len(self.data))
[70bf68c]302        else:
[da58fcc]303            self.res_err_data = copy.deepcopy(self.err_data)
[9e8c150]304        #self.res_err_data[self.res_err_data==0]=1
[d8a2e31]305       
[83195f7]306        self.radius= numpy.sqrt(self.qx_data**2 + self.qy_data**2)
307       
308        # Note: mask = True: for MASK while mask = False for NOT to mask
309        self.index_model = ((self.qmin <= self.radius)&(self.radius<= self.qmax))
[36bc34e]310        self.index_model = (self.index_model) & (self.mask)
311        self.index_model = (self.index_model) & (numpy.isfinite(self.data))
[f72333f]312       
313    def set_smearer(self,smearer): 
314        """
[aa36f96]315        Set smearer
[f72333f]316        """
317        if smearer == None:
318            return
319        self.smearer = smearer
320        self.smearer.set_index(self.index_model)
321        self.smearer.get_data()
322
[20d30e9]323    def setFitRange(self,qmin=None,qmax=None):
[7d0c1a8]324        """ to set the fit range"""
[773806e]325        if qmin==0.0:
326            self.qmin = 1e-16
327        elif qmin!=None:                       
328            self.qmin = qmin           
[eef2e0ed]329        if qmax!=None:
[83195f7]330            self.qmax= qmax       
331        self.radius= numpy.sqrt(self.qx_data**2 + self.qy_data**2)
332        self.index_model = ((self.qmin <= self.radius)&(self.radius<= self.qmax))
[36bc34e]333        self.index_model = (self.index_model) &(self.mask)
334        self.index_model = (self.index_model) & (numpy.isfinite(self.data))
[9e8c150]335        self.index_model = (self.index_model) & (self.res_err_data!=0)
[aa36f96]336       
[7d0c1a8]337    def getFitRange(self):
338        """
[aa36f96]339        return the range of data.x to fit
[7d0c1a8]340        """
[20d30e9]341        return self.qmin, self.qmax
[7d0c1a8]342     
[d8a2e31]343    def residuals(self, fn): 
[83195f7]344        """
[aa36f96]345        return the residuals
[f72333f]346        """ 
347        if self.smearer != None:
348            fn.set_index(self.index_model)
349            # Get necessary data from self.data and set the data for smearing
350            fn.get_data()
351
352            gn = fn.get_value() 
353        else:
354            gn = fn([self.qx_data[self.index_model],self.qy_data[self.index_model]])
[83195f7]355        # use only the data point within ROI range
[f72333f]356        res=(self.data[self.index_model] - gn)/self.res_err_data[self.index_model]
[83195f7]357        return res
[0e51519]358       
[7d0c1a8]359    def residuals_deriv(self, model, pars=[]):
360        """
[aa36f96]361        :return: residuals derivatives .
362       
363        :note: in this case just return empty array
364       
[7d0c1a8]365        """
366        return []
[48882d1]367   
[4bd557d]368class FitAbort(Exception):
369    """
[aa36f96]370    Exception raise to stop the fit
[4bd557d]371    """
[aa36f96]372    #print"Creating fit abort Exception"
[4bd557d]373
374
[70bf68c]375class SansAssembly:
[ca6d914]376    """
[aa36f96]377    Sans Assembly class a class wrapper to be call in optimizer.leastsq method
[ca6d914]378    """
[e0072082]379    def __init__(self, paramlist, model=None , data=None, fitresult=None,
380                 handler=None, curr_thread=None):
[ca6d914]381        """
[aa36f96]382        :param Model: the model wrapper fro sans -model
383        :param Data: the data wrapper for sans data
384       
[ca6d914]385        """
[e0072082]386        self.model = model
387        self.data  = data
388        self.paramlist = paramlist
389        self.curr_thread = curr_thread
390        self.handler = handler
391        self.fitresult = fitresult
392        self.res = []
393        self.func_name = "Functor"
394       
[48882d1]395    def chisq(self, params):
396        """
[aa36f96]397        Calculates chi^2
398       
399        :param params: list of parameter values
400       
401        :return: chi^2
402       
[48882d1]403        """
404        sum = 0
405        for item in self.res:
406            sum += item*item
[4bd557d]407        if len(self.res)==0:
408            return None
[26cb768]409        return sum/ len(self.res)
[20d30e9]410   
[48882d1]411    def __call__(self,params):
[ca6d914]412        """
[aa36f96]413        Compute residuals
414       
415        :param params: value of parameters to fit
416       
[ca6d914]417        """
[681f0dc]418        #import thread
[e71440c]419        self.model.setParams(self.paramlist,params)
[48882d1]420        self.res= self.data.residuals(self.model.eval)
[e0072082]421        if self.fitresult is not None and  self.handler is not None:
422            self.fitresult.set_model(model=self.model)
[90c9cdf]423            fitness = self.chisq(params=params)
424            self.fitresult.set_fitness(fitness=fitness)
[e0072082]425            self.handler.set_result(result=self.fitresult)
426            self.handler.update_fit()
427       
[255306e]428        #if self.curr_thread != None :
429        #    try:
430        #        self.curr_thread.isquit()
431        #    except:
432        #        raise FitAbort,"stop leastsqr optimizer"   
[48882d1]433        return self.res
434   
[4c718654]435class FitEngine:
[ee5b04c]436    def __init__(self):
[ca6d914]437        """
[aa36f96]438        Base class for scipy and park fit engine
[ca6d914]439        """
440        #List of parameter names to fit
[ee5b04c]441        self.paramList=[]
[ca6d914]442        #Dictionnary of fitArrange element (fit problems)
443        self.fitArrangeDict={}
444       
[4c718654]445    def _concatenateData(self, listdata=[]):
446        """ 
[aa36f96]447        _concatenateData method concatenates each fields of all data
448        contains ins listdata.
449       
450        :param listdata: list of data
451       
452        :return Data: Data is wrapper class for sans plottable. it is created with all parameters
453            of data concatenanted
454           
455        :raise: if listdata is empty  will return None
456        :raise: if data in listdata don't contain dy field ,will create an error
[4c718654]457            during fitting
[aa36f96]458           
[4c718654]459        """
[109e60ab]460        #TODO: we have to refactor the way we handle data.
461        # We should move away from plottables and move towards the Data1D objects
462        # defined in DataLoader. Data1D allows data manipulations, which should be
463        # used to concatenate.
464        # In the meantime we should switch off the concatenation.
465        #if len(listdata)>1:
466        #    raise RuntimeError, "FitEngine._concatenateData: Multiple data files is not currently supported"
467        #return listdata[0]
468       
[4c718654]469        if listdata==[]:
470            raise ValueError, " data list missing"
471        else:
472            xtemp=[]
473            ytemp=[]
474            dytemp=[]
[48882d1]475            self.mini=None
476            self.maxi=None
[4c718654]477               
[7d0c1a8]478            for item in listdata:
479                data=item.data
[48882d1]480                mini,maxi=data.getFitRange()
481                if self.mini==None and self.maxi==None:
482                    self.mini=mini
483                    self.maxi=maxi
484                else:
485                    if mini < self.mini:
486                        self.mini=mini
487                    if self.maxi < maxi:
488                        self.maxi=maxi
489                       
490                   
[4c718654]491                for i in range(len(data.x)):
492                    xtemp.append(data.x[i])
493                    ytemp.append(data.y[i])
494                    if data.dy is not None and len(data.dy)==len(data.y):   
495                        dytemp.append(data.dy[i])
496                    else:
[ee5b04c]497                        raise RuntimeError, "Fit._concatenateData: y-errors missing"
[20d30e9]498            data= Data(x=xtemp,y=ytemp,dy=dytemp)
[48882d1]499            data.setFitRange(self.mini, self.maxi)
500            return data
[ca6d914]501       
502       
[aa36f96]503    def set_model(self, model, Uid, pars=[], constraints=[]):
[ca6d914]504        """
[aa36f96]505        set a model on a given uid in the fit engine.
506       
507        :param model: sans.models type
508        :param Uid: is the key of the fitArrange dictionary where model is
509                saved as a value
510        :param pars: the list of parameters to fit
511        :param constraints: list of
512            tuple (name of parameter, value of parameters)
513            the value of parameter must be a string to constraint 2 different
514            parameters.
515            Example: 
516            we want to fit 2 model M1 and M2 both have parameters A and B.
517            constraints can be:
518             constraints = [(M1.A, M2.B+2), (M1.B= M2.A *5),...,]
519           
520             
521        :note: pars must contains only name of existing model's parameters
522       
[ca6d914]523        """
[fd6b789]524        if model == None:
525            raise ValueError, "AbstractFitEngine: Need to set model to fit"
[393f0f3]526       
527        new_model= model
528        if not issubclass(model.__class__, Model):
529            new_model= Model(model)
[fd6b789]530       
531        if len(constraints)>0:
532            for constraint in constraints:
533                name, value = constraint
534                try:
535                    new_model.parameterset[ str(name)].set( str(value) )
536                except:
537                    msg= "Fit Engine: Error occurs when setting the constraint"
538                    msg += " %s for parameter %s "%(value, name)
539                    raise ValueError, msg
540               
[f44dbc7]541        if len(pars) >0:
[fd6b789]542            temp=[]
543            for item in pars:
544                if item in new_model.model.getParamList():
545                    temp.append(item)
546                    self.paramList.append(item)
547                else:
548                   
549                    msg = "wrong parameter %s used"%str(item)
550                    msg += "to set model %s. Choose"%str(new_model.model.name)
551                    msg += "parameter name within %s"%str(new_model.model.getParamList())
552                    raise ValueError,msg
553             
[6831a99]554            #A fitArrange is already created but contains dList only at Uid
[ca6d914]555            if self.fitArrangeDict.has_key(Uid):
[fd6b789]556                self.fitArrangeDict[Uid].set_model(new_model)
[aed7c57]557                self.fitArrangeDict[Uid].pars= pars
[6831a99]558            else:
559            #no fitArrange object has been create with this Uid
[48882d1]560                fitproblem = FitArrange()
[fd6b789]561                fitproblem.set_model(new_model)
[aed7c57]562                fitproblem.pars= pars
[ca6d914]563                self.fitArrangeDict[Uid] = fitproblem
[aed7c57]564               
[d4b0687]565        else:
[6831a99]566            raise ValueError, "park_integration:missing parameters"
[48882d1]567   
[20d30e9]568    def set_data(self,data,Uid,smearer=None,qmin=None,qmax=None):
[aa36f96]569        """
570        Receives plottable, creates a list of data to fit,set data
571        in a FitArrange object and adds that object in a dictionary
572        with key Uid.
573       
574        :param data: data added
575        :param Uid: unique key corresponding to a fitArrange object with data
576       
[ca6d914]577        """
[f2817bb]578        if data.__class__.__name__=='Data2D':
[1e3169c]579            fitdata=FitData2D(sans_data2d=data, data=data.data, err_data= data.err_data)
[f8ce013]580        else:
[1e3169c]581            fitdata=FitData1D(x=data.x, y=data.y , dx= data.dx,dy=data.dy,smearer=smearer)
[393f0f3]582       
[20d30e9]583        fitdata.setFitRange(qmin=qmin,qmax=qmax)
[d4b0687]584        #A fitArrange is already created but contains model only at Uid
[ca6d914]585        if self.fitArrangeDict.has_key(Uid):
[f8ce013]586            self.fitArrangeDict[Uid].add_data(fitdata)
[d4b0687]587        else:
588        #no fitArrange object has been create with this Uid
589            fitproblem= FitArrange()
[f8ce013]590            fitproblem.add_data(fitdata)
[ca6d914]591            self.fitArrangeDict[Uid]=fitproblem   
[20d30e9]592   
[d4b0687]593    def get_model(self,Uid):
594        """
[aa36f96]595       
596        :param Uid: Uid is key in the dictionary containing the model to return
597       
598        :return:  a model at this uid or None if no FitArrange element was created
[d4b0687]599            with this Uid
[aa36f96]600           
[d4b0687]601        """
[ca6d914]602        if self.fitArrangeDict.has_key(Uid):
603            return self.fitArrangeDict[Uid].get_model()
[d4b0687]604        else:
605            return None
606   
607    def remove_Fit_Problem(self,Uid):
608        """remove   fitarrange in Uid"""
[ca6d914]609        if self.fitArrangeDict.has_key(Uid):
610            del self.fitArrangeDict[Uid]
[a9e04aa]611           
612    def select_problem_for_fit(self,Uid,value):
613        """
[aa36f96]614        select a couple of model and data at the Uid position in dictionary
615        and set in self.selected value to value
616       
617        :param value: the value to allow fitting.
618                can only have the value one or zero
619               
[a9e04aa]620        """
621        if self.fitArrangeDict.has_key(Uid):
622             self.fitArrangeDict[Uid].set_to_fit( value)
[eef2e0ed]623             
[a9e04aa]624    def get_problem_to_fit(self,Uid):
625        """
[aa36f96]626        return the self.selected value of the fit problem of Uid
627       
628        :param Uid: the Uid of the problem
629       
[a9e04aa]630        """
631        if self.fitArrangeDict.has_key(Uid):
632             self.fitArrangeDict[Uid].get_to_fit()
[4c718654]633   
[d4b0687]634class FitArrange:
635    def __init__(self):
636        """
[aa36f96]637        Class FitArrange contains a set of data for a given model
638        to perform the Fit.FitArrange must contain exactly one model
639        and at least one data for the fit to be performed.
640       
641        model: the model selected by the user
642        Ldata: a list of data what the user wants to fit
[d4b0687]643           
644        """
645        self.model = None
646        self.dList =[]
[aed7c57]647        self.pars=[]
[a9e04aa]648        #self.selected  is zero when this fit problem is not schedule to fit
649        #self.selected is 1 when schedule to fit
650        self.selected = 0
[d4b0687]651       
652    def set_model(self,model):
653        """
[aa36f96]654        set_model save a copy of the model
655       
656        :param model: the model being set
657       
[d4b0687]658        """
659        self.model = model
660       
661    def add_data(self,data):
662        """
[aa36f96]663        add_data fill a self.dList with data to fit
664       
665        :param data: Data to add in the list 
666       
[d4b0687]667        """
668        if not data in self.dList:
669            self.dList.append(data)
670           
671    def get_model(self):
[aa36f96]672        """
673       
674        :return: saved model
675       
676        """
[d4b0687]677        return self.model   
678     
679    def get_data(self):
[aa36f96]680        """
681       
682        :return: list of data dList
683       
684        """
[7d0c1a8]685        #return self.dList
686        return self.dList[0] 
[d4b0687]687     
688    def remove_data(self,data):
689        """
[aa36f96]690        Remove one element from the list
691       
692        :param data: Data to remove from dList
693       
[d4b0687]694        """
695        if data in self.dList:
696            self.dList.remove(data)
[aa36f96]697           
[a9e04aa]698    def set_to_fit (self, value=0):
699        """
[aa36f96]700        set self.selected to 0 or 1  for other values raise an exception
701       
702        :param value: integer between 0 or 1
703       
[a9e04aa]704        """
705        self.selected= value
706       
707    def get_to_fit(self):
708        """
[aa36f96]709        return self.selected value
[a9e04aa]710        """
711        return self.selected
Note: See TracBrowser for help on using the repository browser.