Changeset 949aa2c in sasview for src/sans


Ignore:
Timestamp:
Jun 3, 2014 6:13:26 PM (10 years ago)
Author:
pkienzle
Branches:
master, ESS_GUI, ESS_GUI_Docs, ESS_GUI_batch_fitting, ESS_GUI_bumps_abstraction, ESS_GUI_iss1116, ESS_GUI_iss879, ESS_GUI_iss959, ESS_GUI_opencl, ESS_GUI_ordering, ESS_GUI_sync_sascalc, costrafo411, magnetic_scatt, release-4.1.1, release-4.1.2, release-4.2.2, release_4.0.1, ticket-1009, ticket-1094-headless, ticket-1242-2d-resolution, ticket-1243, ticket-1249, ticket885, unittest-saveload
Children:
f8940db
Parents:
35086c3 (diff), eb9fc6d (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

merge from trunk to bumps

Location:
src/sans
Files:
3 added
14 edited

Legend:

Unmodified
Added
Removed
  • src/sans/fit/AbstractFitEngine.py

    r6c00702 rbf5e985  
    33#import logging 
    44import sys 
     5import math 
    56import numpy 
    6 import math 
    7 import park 
     7 
    88from sans.dataloader.data_info import Data1D 
    99from sans.dataloader.data_info import Data2D 
    10 _SMALLVALUE = 1.0e-10     
    11      
    12 class SansParameter(park.Parameter): 
    13     """ 
    14     SANS model parameters for use in the PARK fitting service. 
    15     The parameter attribute value is redirected to the underlying 
    16     parameter value in the SANS model. 
    17     """ 
    18     def __init__(self, name, model, data): 
    19         """ 
    20             :param name: the name of the model parameter 
    21             :param model: the sans model to wrap as a park model 
    22         """ 
    23         park.Parameter.__init__(self, name) 
    24         self._model, self._name = model, name 
    25         self.data = data 
    26         self.model = model 
    27         #set the value for the parameter of the given name 
    28         self.set(model.getParam(name)) 
    29           
    30     def _getvalue(self): 
    31         """ 
    32         override the _getvalue of park parameter 
    33          
    34         :return value the parameter associates with self.name 
    35          
    36         """ 
    37         return self._model.getParam(self.name) 
    38      
    39     def _setvalue(self, value): 
    40         """ 
    41         override the _setvalue pf park parameter 
    42          
    43         :param value: the value to set on a given parameter 
    44          
    45         """ 
    46         self._model.setParam(self.name, value) 
    47          
    48     value = property(_getvalue, _setvalue) 
    49      
    50     def _getrange(self): 
    51         """ 
    52         Override _getrange of park parameter 
    53         return the range of parameter 
    54         """ 
    55         #if not  self.name in self._model.getDispParamList(): 
    56         lo, hi = self._model.details[self.name][1:3] 
    57         if lo is None: lo = -numpy.inf 
    58         if hi is None: hi = numpy.inf 
    59         if lo > hi: 
    60             raise ValueError, "wrong fit range for parameters" 
    61          
    62         return lo, hi 
    63      
    64     def get_name(self): 
    65         """ 
    66         """ 
    67         return self._getname() 
    68      
    69     def _setrange(self, r): 
    70         """ 
    71         override _setrange of park parameter 
    72          
    73         :param r: the value of the range to set 
    74          
    75         """ 
    76         self._model.details[self.name][1:3] = r 
    77     range = property(_getrange, _setrange) 
    78      
    79      
    80 class Model(park.Model): 
    81     """ 
    82     PARK wrapper for SANS models. 
     10_SMALLVALUE = 1.0e-10 
     11 
     12# Note: duplicated from park 
     13class FitHandler(object): 
     14    """ 
     15    Abstract interface for fit thread handler. 
     16 
     17    The methods in this class are called by the optimizer as the fit 
     18    progresses. 
     19 
     20    Note that it is up to the optimizer to call the fit handler correctly, 
     21    reporting all status changes and maintaining the 'done' flag. 
     22    """ 
     23    done = False 
     24    """True when the fit job is complete""" 
     25    result = None 
     26    """The current best result of the fit""" 
     27 
     28    def improvement(self): 
     29        """ 
     30        Called when a result is observed which is better than previous 
     31        results from the fit. 
     32 
     33        result is a FitResult object, with parameters, #calls and fitness. 
     34        """ 
     35    def error(self, msg): 
     36        """ 
     37        Model had an error; print traceback 
     38        """ 
     39    def progress(self, current, expected): 
     40        """ 
     41        Called each cycle of the fit, reporting the current and the 
     42        expected amount of work.   The meaning of these values is 
     43        optimizer dependent, but they can be converted into a percent 
     44        complete using (100*current)//expected. 
     45 
     46        Progress is updated each iteration of the fit, whatever that 
     47        means for the particular optimization algorithm.  It is called 
     48        after any calls to improvement for the iteration so that the 
     49        update handler can control I/O bandwidth by suppressing 
     50        intermediate improvements until the fit is complete. 
     51        """ 
     52    def finalize(self): 
     53        """ 
     54        Fit is complete; best results are reported 
     55        """ 
     56    def abort(self): 
     57        """ 
     58        Fit was aborted. 
     59        """ 
     60 
     61    # TODO: not sure how these are used, but they are needed for running the fit 
     62    def update_fit(self, last=False): pass 
     63    def set_result(self, result=None): self.result = result 
     64 
     65class Model: 
     66    """ 
     67    Fit wrapper for SANS models. 
    8368    """ 
    8469    def __init__(self, sans_model, sans_data=None, **kw): 
    8570        """ 
    8671        :param sans_model: the sans model to wrap using park interface 
    87          
    88         """ 
    89         park.Model.__init__(self, **kw) 
     72 
     73        """ 
    9074        self.model = sans_model 
    9175        self.name = sans_model.name 
    9276        self.data = sans_data 
    93         #list of parameters names 
    94         self.sansp = sans_model.getParamList() 
    95         #list of park parameter 
    96         self.parkp = [SansParameter(p, sans_model, sans_data) for p in self.sansp] 
    97         #list of parameter set 
    98         self.parameterset = park.ParameterSet(sans_model.name, pars=self.parkp) 
    99         self.pars = [] 
    100    
     77 
    10178    def get_params(self, fitparams): 
    10279        """ 
    10380        return a list of value of paramter to fit 
    104          
     81 
    10582        :param fitparams: list of paramaters name to fit 
    106          
    107         """ 
    108         list_params = [] 
    109         self.pars = [] 
    110         self.pars = fitparams 
    111         for item in fitparams: 
    112             for element in self.parkp: 
    113                 if element.name == str(item): 
    114                     list_params.append(element.value) 
    115         return list_params 
    116      
     83 
     84        """ 
     85        return [self.model.getParam(k) for k in fitparams] 
     86 
    11787    def set_params(self, paramlist, params): 
    11888        """ 
    11989        Set value for parameters to fit 
    120          
     90 
    12191        :param params: list of value for parameters to fit 
    122          
    123         """ 
    124         try: 
    125             for i in range(len(self.parkp)): 
    126                 for j in range(len(paramlist)): 
    127                     if self.parkp[i].name == paramlist[j]: 
    128                         self.parkp[i].value = params[j] 
    129                         self.model.setParam(self.parkp[i].name, params[j]) 
    130         except: 
    131             raise 
    132    
     92 
     93        """ 
     94        for k,v in zip(paramlist, params): 
     95            self.model.setParam(k,v) 
     96 
     97    def set(self, **kw): 
     98        self.set_params(*zip(*kw.items())) 
     99 
    133100    def eval(self, x): 
    134101        """ 
    135102            Override eval method of park model. 
    136          
     103 
    137104            :param x: the x value used to compute a function 
    138105        """ 
     
    141108        except: 
    142109            raise 
    143          
     110 
    144111    def eval_derivs(self, x, pars=[]): 
    145112        """ 
     
    154121        instead of calling eval. 
    155122        """ 
    156         return [] 
    157  
    158      
     123        raise NotImplementedError('no derivatives available') 
     124 
     125    def __call__(self, x): 
     126        return self.eval(x) 
     127 
    159128class FitData1D(Data1D): 
    160129    """ 
     
    185154        """ 
    186155        Data1D.__init__(self, x=x, y=y, dx=dx, dy=dy) 
     156        self.num_points = len(x) 
    187157        self.sans_data = data 
    188158        self.smearer = smearer 
     
    251221        """ 
    252222        return self.qmin, self.qmax 
    253          
     223 
     224    def size(self): 
     225        """ 
     226        Number of measurement points in data set after masking, etc. 
     227        """ 
     228        return len(self.x) 
     229 
    254230    def residuals(self, fn): 
    255231        """ 
     
    293269    def __init__(self, sans_data2d, data=None, err_data=None): 
    294270        Data2D.__init__(self, data=data, err_data=err_data) 
    295         """ 
    296             Data can be initital with a data (sans plottable) 
    297             or with vectors. 
    298         """ 
     271        # Data can be initialized with a sans plottable or with vectors. 
    299272        self.res_err_image = [] 
     273        self.num_points = 0 # will be set by set_data 
    300274        self.idx = [] 
    301275        self.qmin = None 
     
    339313        self.idx = (self.idx) & (self.mask) 
    340314        self.idx = (self.idx) & (numpy.isfinite(self.data)) 
     315        self.num_points = numpy.sum(self.idx) 
    341316 
    342317    def set_smearer(self, smearer): 
     
    372347        """ 
    373348        return self.qmin, self.qmax 
    374       
     349 
     350    def size(self): 
     351        """ 
     352        Number of measurement points in data set after masking, etc. 
     353        """ 
     354        return numpy.sum(self.idx) 
     355 
    375356    def residuals(self, fn): 
    376357        """ 
     
    409390 
    410391 
    411 class SansAssembly: 
    412     """ 
    413     Sans Assembly class a class wrapper to be call in optimizer.leastsq method 
    414     """ 
    415     def __init__(self, paramlist, model=None, data=None, fitresult=None, 
    416                  handler=None, curr_thread=None, msg_q=None): 
    417         """ 
    418         :param Model: the model wrapper fro sans -model 
    419         :param Data: the data wrapper for sans data 
    420          
    421         """ 
    422         self.model = model 
    423         self.data = data 
    424         self.paramlist = paramlist 
    425         self.msg_q = msg_q 
    426         self.curr_thread = curr_thread 
    427         self.handler = handler 
    428         self.fitresult = fitresult 
    429         self.res = [] 
    430         self.true_res = [] 
    431         self.func_name = "Functor" 
    432         self.theory = None 
    433          
    434     def chisq(self): 
    435         """ 
    436         Calculates chi^2 
    437          
    438         :param params: list of parameter values 
    439          
    440         :return: chi^2 
    441          
    442         """ 
    443         total = 0 
    444         for item in self.true_res: 
    445             total += item * item 
    446         if len(self.true_res) == 0: 
    447             return None 
    448         return total / len(self.true_res) 
    449      
    450     def __call__(self, params): 
    451         """ 
    452             Compute residuals 
    453             :param params: value of parameters to fit 
    454         """ 
    455         #import thread 
    456         self.model.set_params(self.paramlist, params) 
    457         #print "params", params 
    458         self.true_res, theory = self.data.residuals(self.model.eval) 
    459         self.theory = copy.deepcopy(theory) 
    460         # check parameters range 
    461         if self.check_param_range(): 
    462             # if the param value is outside of the bound 
    463             # just silent return res = inf 
    464             return self.res 
    465         self.res = self.true_res 
    466          
    467         if self.fitresult is not None: 
    468             self.fitresult.set_model(model=self.model) 
    469             self.fitresult.residuals = self.true_res 
    470             self.fitresult.iterations += 1 
    471             self.fitresult.theory = theory 
    472             
    473             #fitness = self.chisq(params=params) 
    474             fitness = self.chisq() 
    475             self.fitresult.pvec = params 
    476             self.fitresult.set_fitness(fitness=fitness) 
    477             if self.msg_q is not None: 
    478                 self.msg_q.put(self.fitresult) 
    479                  
    480             if self.handler is not None: 
    481                 self.handler.set_result(result=self.fitresult) 
    482                 self.handler.update_fit() 
    483  
    484             if self.curr_thread != None: 
    485                 try: 
    486                     self.curr_thread.isquit() 
    487                 except: 
    488                     #msg = "Fitting: Terminated...       Note: Forcing to stop " 
    489                     #msg += "fitting may cause a 'Functor error message' " 
    490                     #msg += "being recorded in the log file....." 
    491                     #self.handler.stop(msg) 
    492                     raise 
    493           
    494         return self.res 
    495      
    496     def check_param_range(self): 
    497         """ 
    498         Check the lower and upper bound of the parameter value 
    499         and set res to the inf if the value is outside of the 
    500         range 
    501         :limitation: the initial values must be within range. 
    502         """ 
    503  
    504         #time.sleep(0.01) 
    505         is_outofbound = False 
    506         # loop through the fit parameters 
    507         for p in self.model.parameterset: 
    508             param_name = p.get_name() 
    509             if param_name in self.paramlist: 
    510                  
    511                 # if the range was defined, check the range 
    512                 if numpy.isfinite(p.range[0]): 
    513                     if p.value == 0: 
    514                         # This value works on Scipy 
    515                         # Do not change numbers below 
    516                         value = _SMALLVALUE 
    517                     else: 
    518                         value = p.value 
    519                     # For leastsq, it needs a bit step back from the boundary 
    520                     val = p.range[0] - value * _SMALLVALUE 
    521                     if p.value < val: 
    522                         self.res *= 1e+6 
    523                          
    524                         is_outofbound = True 
    525                         break 
    526                 if numpy.isfinite(p.range[1]): 
    527                     # This value works on Scipy 
    528                     # Do not change numbers below 
    529                     if p.value == 0: 
    530                         value = _SMALLVALUE 
    531                     else: 
    532                         value = p.value 
    533                     # For leastsq, it needs a bit step back from the boundary 
    534                     val = p.range[1] + value * _SMALLVALUE 
    535                     if p.value > val: 
    536                         self.res *= 1e+6 
    537                         is_outofbound = True 
    538                         break 
    539  
    540         return is_outofbound 
    541      
    542      
     392 
    543393class FitEngine: 
    544394    def __init__(self): 
     
    546396        Base class for scipy and park fit engine 
    547397        """ 
    548         #List of parameter names to fit 
    549         self.param_list = [] 
    550398        #Dictionnary of fitArrange element (fit problems) 
    551399        self.fit_arrange_dict = {} 
     
    571419         
    572420        """ 
    573         if model == None: 
    574             raise ValueError, "AbstractFitEngine: Need to set model to fit" 
    575          
    576         new_model = model 
     421        if not pars: 
     422            raise ValueError("no fitting parameters") 
     423 
     424        if model is None: 
     425            raise ValueError("no model to fit") 
     426 
    577427        if not issubclass(model.__class__, Model): 
    578             new_model = Model(model, data) 
    579          
    580         if len(constraints) > 0: 
    581             for constraint in constraints: 
    582                 name, value = constraint 
    583                 try: 
    584                     new_model.parameterset[str(name)].set(str(value)) 
    585                 except: 
    586                     msg = "Fit Engine: Error occurs when setting the constraint" 
    587                     msg += " %s for parameter %s " % (value, name) 
    588                     raise ValueError, msg 
    589                  
    590         if len(pars) > 0: 
    591             temp = [] 
    592             for item in pars: 
    593                 if item in new_model.model.getParamList(): 
    594                     temp.append(item) 
    595                     self.param_list.append(item) 
    596                 else: 
    597                      
    598                     msg = "wrong parameter %s used " % str(item) 
    599                     msg += "to set model %s. Choose " % str(new_model.model.name) 
    600                     msg += "parameter name within %s" % \ 
    601                                 str(new_model.model.getParamList()) 
    602                     raise ValueError, msg 
    603                
    604             #A fitArrange is already created but contains data_list only at id 
    605             if self.fit_arrange_dict.has_key(id): 
    606                 self.fit_arrange_dict[id].set_model(new_model) 
    607                 self.fit_arrange_dict[id].pars = pars 
    608             else: 
    609             #no fitArrange object has been create with this id 
    610                 fitproblem = FitArrange() 
    611                 fitproblem.set_model(new_model) 
    612                 fitproblem.pars = pars 
    613                 self.fit_arrange_dict[id] = fitproblem 
    614                 vals = [] 
    615                 for name in pars: 
    616                     vals.append(new_model.model.getParam(name)) 
    617                 self.fit_arrange_dict[id].vals = vals 
    618         else: 
    619             raise ValueError, "park_integration:missing parameters" 
    620      
     428            model = Model(model, data) 
     429 
     430        sasmodel = model.model 
     431        available_parameters = sasmodel.getParamList() 
     432        for p in pars: 
     433            if p not in available_parameters: 
     434                raise ValueError("parameter %s not available in model %s; use one of [%s] instead" 
     435                                 %(p, sasmodel.name, ", ".join(available_parameters))) 
     436 
     437        if id not in self.fit_arrange_dict: 
     438            self.fit_arrange_dict[id] = FitArrange() 
     439 
     440        self.fit_arrange_dict[id].set_model(model) 
     441        self.fit_arrange_dict[id].pars = pars 
     442        self.fit_arrange_dict[id].vals = [sasmodel.getParam(name) for name in pars] 
     443        self.fit_arrange_dict[id].constraints = constraints 
     444 
    621445    def set_data(self, data, id, smearer=None, qmin=None, qmax=None): 
    622446        """ 
     
    700524        self.vals = [] 
    701525        self.selected = 0 
    702          
     526 
    703527    def set_model(self, model): 
    704528        """ 
     
    752576        """ 
    753577        return self.selected 
    754      
    755      
    756 IS_MAC = True 
    757 if sys.platform.count("win32") > 0: 
    758     IS_MAC = False 
    759  
    760578 
    761579class FResult(object): 
     
    765583    def __init__(self, model=None, param_list=None, data=None): 
    766584        self.calls = None 
    767         self.pars = [] 
    768585        self.fitness = None 
    769586        self.chisqr = None 
     
    776593        self.residuals = [] 
    777594        self.index = [] 
    778         self.parameters = None 
    779         self.is_mac = IS_MAC 
    780595        self.model = model 
    781596        self.data = data 
     
    803618        if self.pvec == None and self.model is None and self.param_list is None: 
    804619            return "No results" 
    805         n = len(self.model.parameterset) 
    806          
    807         result_param = zip(xrange(n), self.model.parameterset) 
    808         msg1 = ["[Iteration #: %s ]" % self.iterations] 
    809         msg3 = ["=== goodness of fit: %s ===" % (str(self.fitness))] 
    810         if not self.is_mac: 
    811             msg2 = ["P%-3d  %s......|.....%s" % \ 
    812                 (p[0], p[1], p[1].value)\ 
    813                   for p in result_param if p[1].name in self.param_list] 
    814             msg = msg1 + msg3 + msg2 
    815         else: 
    816             msg = msg1 + msg3 
    817         msg = "\n".join(msg) 
    818         return msg 
     620 
     621        sasmodel = self.model.model 
     622        pars = enumerate(sasmodel.getParamList()) 
     623        msg1 = "[Iteration #: %s ]" % self.iterations 
     624        msg3 = "=== goodness of fit: %s ===" % (str(self.fitness)) 
     625        msg2 = ["P%-3d  %s......|.....%s" % (i, v, sasmodel.getParam(v)) 
     626                for i,v in pars if v in self.param_list] 
     627        msg = [msg1, msg3] + msg2 
     628        return "\n".join(msg) 
    819629     
    820630    def print_summary(self): 
    821631        """ 
    822632        """ 
    823         print self 
     633        print str(self) 
  • src/sans/fit/Fitting.py

    r5777106 re3efa6b3  
    88from sans.fit.ScipyFitting import ScipyFit 
    99from sans.fit.ParkFitting import ParkFit 
     10from sans.fit.BumpsFitting import BumpsFit 
    1011 
     12ENGINES={ 
     13    'scipy': ScipyFit, 
     14    'park': ParkFit, 
     15    'bumps': BumpsFit, 
     16} 
    1117 
    1218class Fit(object): 
     
    2632         
    2733    """   
    28     def __init__(self, engine='scipy'): 
     34    def __init__(self, engine='scipy', *args, **kw): 
    2935        """ 
    3036        """ 
     
    3238        self._engine = None 
    3339        self.fitter_id = None 
    34         self.set_engine(engine) 
     40        self.set_engine(engine, *args, **kw) 
    3541           
    3642    def __setattr__(self, name, value): 
     
    4955            self.__dict__[name] = value 
    5056                 
    51     def set_engine(self, word): 
     57    def set_engine(self, word, *args, **kw): 
    5258        """ 
    5359        Select the type of Fit  
     
    5965              
    6066        """ 
    61         if word == "scipy": 
    62             self._engine = ScipyFit() 
    63         elif word == "park": 
    64             self._engine = ParkFit() 
    65         else: 
    66             raise ValueError, "enter the keyword scipy or park" 
     67        try: 
     68            self._engine = ENGINES[word](*args, **kw) 
     69        except KeyError, exc: 
     70            raise KeyError("fit engine should be one of scipy, park or bumps") 
    6771 
    6872    def fit(self, msg_q=None, q=None, handler=None,  
  • src/sans/fit/Loader.py

    r5777106 r6fe5100  
    88    This class is loading values from given file or value giving by the user 
    99    """ 
    10      
    1110    def __init__(self, x=None, y=None, dx=None, dy=None): 
     11        raise NotImplementedError("a code search shows that this code is not active, and you are not seeing this message") 
    1212        # variable to store loaded values 
    1313        self.x = x 
  • src/sans/fit/ParkFitting.py

    r9d6d5ba r8d074d9  
    2424from sans.fit.AbstractFitEngine import FitEngine 
    2525from sans.fit.AbstractFitEngine import FResult 
    26    
     26 
     27class SansParameter(park.Parameter): 
     28    """ 
     29    SANS model parameters for use in the PARK fitting service. 
     30    The parameter attribute value is redirected to the underlying 
     31    parameter value in the SANS model. 
     32    """ 
     33    def __init__(self, name, model, data): 
     34        """ 
     35            :param name: the name of the model parameter 
     36            :param model: the sans model to wrap as a park model 
     37        """ 
     38        park.Parameter.__init__(self, name) 
     39        #self._model, self._name = model, name 
     40        self.data = data 
     41        self.model = model 
     42        #set the value for the parameter of the given name 
     43        self.set(model.getParam(name)) 
     44 
     45        # TODO: model is missing parameter ranges for dispersion parameters 
     46        if name not in model.details: 
     47            #print "setting details for",name 
     48            model.details[name] = ["", None, None] 
     49 
     50    def _getvalue(self): 
     51        """ 
     52        override the _getvalue of park parameter 
     53 
     54        :return value the parameter associates with self.name 
     55 
     56        """ 
     57        return self.model.getParam(self.name) 
     58 
     59    def _setvalue(self, value): 
     60        """ 
     61        override the _setvalue pf park parameter 
     62 
     63        :param value: the value to set on a given parameter 
     64 
     65        """ 
     66        self.model.setParam(self.name, value) 
     67 
     68    value = property(_getvalue, _setvalue) 
     69 
     70    def _getrange(self): 
     71        """ 
     72        Override _getrange of park parameter 
     73        return the range of parameter 
     74        """ 
     75        #if not  self.name in self._model.getDispParamList(): 
     76        lo, hi = self.model.details[self.name][1:3] 
     77        if lo is None: lo = -numpy.inf 
     78        if hi is None: hi = numpy.inf 
     79        if lo > hi: 
     80            raise ValueError, "wrong fit range for parameters" 
     81 
     82        return lo, hi 
     83 
     84    def get_name(self): 
     85        """ 
     86        """ 
     87        return self._getname() 
     88 
     89    def _setrange(self, r): 
     90        """ 
     91        override _setrange of park parameter 
     92 
     93        :param r: the value of the range to set 
     94 
     95        """ 
     96        self.model.details[self.name][1:3] = r 
     97    range = property(_getrange, _setrange) 
     98 
     99 
     100class ParkModel(park.Model): 
     101    """ 
     102    PARK wrapper for SANS models. 
     103    """ 
     104    def __init__(self, sans_model, sans_data=None, **kw): 
     105        """ 
     106        :param sans_model: the sans model to wrap using park interface 
     107 
     108        """ 
     109        park.Model.__init__(self, **kw) 
     110        self.model = sans_model 
     111        self.name = sans_model.name 
     112        self.data = sans_data 
     113        #list of parameters names 
     114        self.sansp = sans_model.getParamList() 
     115        #list of park parameter 
     116        self.parkp = [SansParameter(p, sans_model, sans_data) for p in self.sansp] 
     117        #list of parameter set 
     118        self.parameterset = park.ParameterSet(sans_model.name, pars=self.parkp) 
     119        self.pars = [] 
     120 
     121    def get_params(self, fitparams): 
     122        """ 
     123        return a list of value of paramter to fit 
     124 
     125        :param fitparams: list of paramaters name to fit 
     126 
     127        """ 
     128        list_params = [] 
     129        self.pars = fitparams 
     130        for item in fitparams: 
     131            for element in self.parkp: 
     132                if element.name == str(item): 
     133                    list_params.append(element.value) 
     134        return list_params 
     135 
     136    def set_params(self, paramlist, params): 
     137        """ 
     138        Set value for parameters to fit 
     139 
     140        :param params: list of value for parameters to fit 
     141 
     142        """ 
     143        try: 
     144            for i in range(len(self.parkp)): 
     145                for j in range(len(paramlist)): 
     146                    if self.parkp[i].name == paramlist[j]: 
     147                        self.parkp[i].value = params[j] 
     148                        self.model.setParam(self.parkp[i].name, params[j]) 
     149        except: 
     150            raise 
     151 
     152    def eval(self, x): 
     153        """ 
     154            Override eval method of park model. 
     155 
     156            :param x: the x value used to compute a function 
     157        """ 
     158        try: 
     159            return self.model.evalDistribution(x) 
     160        except: 
     161            raise 
     162 
     163    def eval_derivs(self, x, pars=[]): 
     164        """ 
     165        Evaluate the model and derivatives wrt pars at x. 
     166 
     167        pars is a list of the names of the parameters for which derivatives 
     168        are desired. 
     169 
     170        This method needs to be specialized in the model to evaluate the 
     171        model function.  Alternatively, the model can implement is own 
     172        version of residuals which calculates the residuals directly 
     173        instead of calling eval. 
     174        """ 
     175        return [] 
     176 
     177 
    27178class SansFitResult(fitresult.FitResult): 
    28179    def __init__(self, *args, **kwrds): 
     
    244395        return fitpars 
    245396     
    246     def all_results(self, result): 
     397    def extend_results_with_calculated_parameters(self, result): 
    247398        """ 
    248399        Extend result from the fit with the calculated parameters. 
     
    292443                # dividing residuals by N in order to be consistent with Scipy 
    293444                m.chisq = numpy.sum(m.residuals**2/N)  
    294                 resid.append(m.weight*m.residuals/math.sqrt(N)) 
     445                resid.append(m.weight*m.residuals) 
    295446        self.residuals = numpy.hstack(resid) 
    296447        N = len(self.residuals) 
    297448        self.degrees_of_freedom = N-k if N>k else 1 
    298449        self.chisq = numpy.sum(self.residuals**2) 
    299         return self.chisq 
     450        return self.chisq/self.degrees_of_freedom 
    300451     
    301452class ParkFit(FitEngine): 
     
    354505            if fproblem.get_to_fit() == 1: 
    355506                fitproblems.append(fproblem) 
    356         if len(fitproblems) == 0:  
     507        if len(fitproblems) == 0: 
    357508            raise RuntimeError, "No Assembly scheduled for Park fitting." 
    358             return 
    359509        for item in fitproblems: 
    360             parkmodel = item.get_model() 
     510            model = item.get_model() 
     511            parkmodel = ParkModel(model.model, model.data) 
     512            parkmodel.pars = item.pars 
    361513            if reset_flag: 
    362514                # reset the initial value; useful for batch 
     
    364516                    ind = item.pars.index(name) 
    365517                    parkmodel.model.setParam(name, item.vals[ind]) 
     518 
     519            # set the constraints into the model 
     520            for p,v in item.constraints: 
     521                parkmodel.parameterset[str(p)].set(str(v)) 
    366522             
    367523            for p in parkmodel.parameterset: 
    368524                ## does not allow status change for constraint parameters 
    369525                if p.status != 'computed': 
    370                     if p.get_name()in item.pars: 
     526                    if p.get_name() in item.pars: 
    371527                        ## make parameters selected for  
    372528                        #fit will be between boundaries 
     
    383539    def fit(self, msg_q=None,  
    384540            q=None, handler=None, curr_thread=None,  
    385                                         ftol=1.49012e-8, reset_flag=False): 
     541            ftol=1.49012e-8, reset_flag=False): 
    386542        """ 
    387543        Performs fit with park.fit module.It can  perform fit with one model 
     
    407563        localfit = SansFitSimplex() 
    408564        localfit.ftol = ftol 
    409          
     565        localfit.xtol = 1e-6 
     566 
    410567        # See `park.fitresult.FitHandler` for details. 
    411568        fitter = SansFitMC(localfit=localfit, start_points=1) 
     
    416573        try: 
    417574            result = fit.fit(self.problem, fitter=fitter, handler=handler) 
    418             self.problem.all_results(result) 
     575            self.problem.extend_results_with_calculated_parameters(result) 
    419576             
    420577        except LinAlgError: 
    421578            raise ValueError, "SVD did not converge" 
     579 
     580        if result is None: 
     581            raise RuntimeError("park did not return a fit result") 
    422582     
    423583        for m in self.problem.parts: 
     
    427587            small_result.theory = theory 
    428588            small_result.residuals = residuals 
    429             small_result.pvec = [] 
    430             small_result.cov = [] 
    431             small_result.stderr = [] 
    432             small_result.param_list = [] 
    433             small_result.residuals = m.residuals 
    434             if result is not None: 
    435                 for p in result.parameters: 
    436                     if p.data.name == small_result.data.name and \ 
    437                             p.model.name == small_result.model.name: 
    438                         small_result.index = m.data.idx 
    439                         small_result.fitness = result.fitness 
    440                         small_result.pvec.append(p.value) 
    441                         small_result.stderr.append(p.stderr) 
    442                         name_split = p.name.split('.') 
    443                         name = name_split[1].strip() 
    444                         if len(name_split) > 2: 
    445                             name += '.' + name_split[2].strip() 
    446                         small_result.param_list.append(name) 
     589            small_result.index = m.data.idx 
     590            small_result.fitness = result.fitness 
     591 
     592            # Extract the parameters that are part of this model; make sure 
     593            # they match the fitted parameters for this model, and place them 
     594            # in the same order as they occur in the model. 
     595            pars = {} 
     596            for p in result.parameters: 
     597                #if p.data.name == small_result.data.name and 
     598                if p.model.name == small_result.model.name: 
     599                    model_name, par_name = p.name.split('.', 1) 
     600                    pars[par_name] = (p.value, p.stderr) 
     601            #assert len(pars.keys()) == len(m.model.pars) 
     602            v,dv = zip(*[pars[p] for p in m.model.pars]) 
     603            small_result.pvec = v 
     604            small_result.stderr = dv 
     605            small_result.param_list = m.model.pars 
     606 
     607            # normalize chisq by degrees of freedom 
     608            dof = len(small_result.residuals)-len(small_result.pvec) 
     609            small_result.fitness = numpy.sum(residuals**2)/dof 
     610 
    447611            result_list.append(small_result)     
    448612        if q != None: 
  • src/sans/fit/ScipyFitting.py

    r5777106 r8d074d9  
    1  
    2  
    31""" 
    42ScipyFitting module contains FitArrange , ScipyFit, 
     
    64simple fit with scipy optimizer. 
    75""" 
     6import sys 
     7import copy 
    88 
    99import numpy  
    10 import sys 
    11  
    1210 
    1311from sans.fit.AbstractFitEngine import FitEngine 
    14 from sans.fit.AbstractFitEngine import SansAssembly 
    15 from sans.fit.AbstractFitEngine import FitAbort 
    16 from sans.fit.AbstractFitEngine import Model 
    17 from sans.fit.AbstractFitEngine import FResult  
     12from sans.fit.AbstractFitEngine import FResult 
     13 
     14class SansAssembly: 
     15    """ 
     16    Sans Assembly class a class wrapper to be call in optimizer.leastsq method 
     17    """ 
     18    def __init__(self, paramlist, model=None, data=None, fitresult=None, 
     19                 handler=None, curr_thread=None, msg_q=None): 
     20        """ 
     21        :param Model: the model wrapper fro sans -model 
     22        :param Data: the data wrapper for sans data 
     23 
     24        """ 
     25        self.model = model 
     26        self.data = data 
     27        self.paramlist = paramlist 
     28        self.msg_q = msg_q 
     29        self.curr_thread = curr_thread 
     30        self.handler = handler 
     31        self.fitresult = fitresult 
     32        self.res = [] 
     33        self.true_res = [] 
     34        self.func_name = "Functor" 
     35        self.theory = None 
     36 
     37    def chisq(self): 
     38        """ 
     39        Calculates chi^2 
     40 
     41        :param params: list of parameter values 
     42 
     43        :return: chi^2 
     44 
     45        """ 
     46        total = 0 
     47        for item in self.true_res: 
     48            total += item * item 
     49        if len(self.true_res) == 0: 
     50            return None 
     51        return total / (len(self.true_res) - len(self.paramlist)) 
     52 
     53    def __call__(self, params): 
     54        """ 
     55            Compute residuals 
     56            :param params: value of parameters to fit 
     57        """ 
     58        #import thread 
     59        self.model.set_params(self.paramlist, params) 
     60        #print "params", params 
     61        self.true_res, theory = self.data.residuals(self.model.eval) 
     62        self.theory = copy.deepcopy(theory) 
     63        # check parameters range 
     64        if self.check_param_range(): 
     65            # if the param value is outside of the bound 
     66            # just silent return res = inf 
     67            return self.res 
     68        self.res = self.true_res 
     69 
     70        if self.fitresult is not None: 
     71            self.fitresult.set_model(model=self.model) 
     72            self.fitresult.residuals = self.true_res 
     73            self.fitresult.iterations += 1 
     74            self.fitresult.theory = theory 
     75 
     76            #fitness = self.chisq(params=params) 
     77            fitness = self.chisq() 
     78            self.fitresult.pvec = params 
     79            self.fitresult.set_fitness(fitness=fitness) 
     80            if self.msg_q is not None: 
     81                self.msg_q.put(self.fitresult) 
     82 
     83            if self.handler is not None: 
     84                self.handler.set_result(result=self.fitresult) 
     85                self.handler.update_fit() 
     86 
     87            if self.curr_thread != None: 
     88                try: 
     89                    self.curr_thread.isquit() 
     90                except: 
     91                    #msg = "Fitting: Terminated...       Note: Forcing to stop " 
     92                    #msg += "fitting may cause a 'Functor error message' " 
     93                    #msg += "being recorded in the log file....." 
     94                    #self.handler.stop(msg) 
     95                    raise 
     96 
     97        return self.res 
     98 
     99    def check_param_range(self): 
     100        """ 
     101        Check the lower and upper bound of the parameter value 
     102        and set res to the inf if the value is outside of the 
     103        range 
     104        :limitation: the initial values must be within range. 
     105        """ 
     106 
     107        #time.sleep(0.01) 
     108        is_outofbound = False 
     109        # loop through the fit parameters 
     110        model = self.model.model 
     111        for p in self.paramlist: 
     112            value = model.getParam(p) 
     113            low,high = model.details[p][1:3] 
     114            if low is not None and numpy.isfinite(low): 
     115                if p.value == 0: 
     116                    # This value works on Scipy 
     117                    # Do not change numbers below 
     118                    value = _SMALLVALUE 
     119                # For leastsq, it needs a bit step back from the boundary 
     120                val = low - value * _SMALLVALUE 
     121                if value < val: 
     122                    self.res *= 1e+6 
     123                    is_outofbound = True 
     124                    break 
     125            if high is not None and numpy.isfinite(high): 
     126                # This value works on Scipy 
     127                # Do not change numbers below 
     128                if value == 0: 
     129                    value = _SMALLVALUE 
     130                # For leastsq, it needs a bit step back from the boundary 
     131                val = high + value * _SMALLVALUE 
     132                if value > val: 
     133                    self.res *= 1e+6 
     134                    is_outofbound = True 
     135                    break 
     136 
     137        return is_outofbound 
    18138 
    19139class ScipyFit(FitEngine): 
     
    50170        """ 
    51171        FitEngine.__init__(self) 
    52         self.fit_arrange_dict = {} 
    53         self.param_list = [] 
    54172        self.curr_thread = None 
    55173    #def fit(self, *args, **kw): 
     
    68186            msg = "Scipy can't fit more than a single fit problem at a time." 
    69187            raise RuntimeError, msg 
    70             return 
    71         elif len(fitproblem) == 0 :  
     188        elif len(fitproblem) == 0 : 
    72189            raise RuntimeError, "No Assembly scheduled for Scipy fitting." 
    73             return 
    74190        model = fitproblem[0].get_model() 
    75191        if reset_flag: 
     
    87203         
    88204        # Check the initial value if it is within range 
    89         self._check_param_range(model) 
     205        _check_param_range(model.model, self.param_list) 
    90206         
    91         result = FResult(model=model, data=data, param_list=self.param_list) 
    92         result.pars = fitproblem[0].pars 
     207        result = FResult(model=model.model, data=data, param_list=self.param_list) 
    93208        result.fitter_id = self.fitter_id 
    94209        if handler is not None: 
    95210            handler.set_result(result=result) 
     211        functor = SansAssembly(paramlist=self.param_list, 
     212                               model=model, 
     213                               data=data, 
     214                               handler=handler, 
     215                               fitresult=result, 
     216                               curr_thread=curr_thread, 
     217                               msg_q=msg_q) 
    96218        try: 
    97219            # This import must be here; otherwise it will be confused when more 
     
    99221            from scipy import optimize 
    100222             
    101             functor = SansAssembly(paramlist=self.param_list,  
    102                                    model=model,  
    103                                    data=data, 
    104                                     handler=handler, 
    105                                     fitresult=result, 
    106                                      curr_thread=curr_thread, 
    107                                      msg_q=msg_q) 
    108223            out, cov_x, _, mesg, success = optimize.leastsq(functor, 
    109224                                            model.get_params(self.param_list), 
    110                                                     ftol=ftol, 
    111                                                     full_output=1) 
     225                                            ftol=ftol, 
     226                                            full_output=1) 
    112227        except: 
    113228            if hasattr(sys, 'last_type') and sys.last_type == KeyboardInterrupt: 
     
    142257 
    143258         
    144     def _check_param_range(self, model): 
    145         """ 
    146         Check parameter range and set the initial value inside  
    147         if it is out of range. 
    148          
    149         : model: park model object 
    150         """ 
    151         is_outofbound = False 
    152         # loop through parameterset 
    153         for p in model.parameterset:         
    154             param_name = p.get_name() 
    155             # proceed only if the parameter name is in the list of fitting 
    156             if param_name in self.param_list: 
    157                 # if the range was defined, check the range 
    158                 if numpy.isfinite(p.range[0]): 
    159                     if p.value <= p.range[0]:  
    160                         # 10 % backing up from the border if not zero 
    161                         # for Scipy engine to work properly. 
    162                         shift = self._get_zero_shift(p.range[0]) 
    163                         new_value = p.range[0] + shift 
    164                         p.value =  new_value 
    165                         is_outofbound = True 
    166                 if numpy.isfinite(p.range[1]): 
    167                     if p.value >= p.range[1]: 
    168                         shift = self._get_zero_shift(p.range[1]) 
    169                         # 10 % backing up from the border if not zero 
    170                         # for Scipy engine to work properly. 
    171                         new_value = p.range[1] - shift 
    172                         # Check one more time if the new value goes below 
    173                         # the low bound, If so, re-evaluate the value  
    174                         # with the mean of the range. 
    175                         if numpy.isfinite(p.range[0]): 
    176                             if new_value < p.range[0]: 
    177                                 new_value = (p.range[0] + p.range[1]) / 2.0 
    178                         # Todo:  
    179                         # Need to think about when both min and max are same. 
    180                         p.value =  new_value 
    181                         is_outofbound = True 
    182                          
    183         return is_outofbound 
    184      
    185     def _get_zero_shift(self, range): 
    186         """ 
    187         Get 10% shift of the param value = 0 based on the range value 
    188          
    189         : param range: min or max value of the bounds 
    190         """ 
    191         if range == 0: 
    192             shift = 0.1 
    193         else: 
    194             shift = 0.1 * range 
    195              
    196         return shift 
    197      
     259def _check_param_range(model, param_list): 
     260    """ 
     261    Check parameter range and set the initial value inside 
     262    if it is out of range. 
     263 
     264    : model: park model object 
     265    """ 
     266    # loop through parameterset 
     267    for p in param_list: 
     268        value = model.getParam(p) 
     269        low,high = model.details.setdefault(p,["",None,None])[1:3] 
     270        # if the range was defined, check the range 
     271        if low is not None and value <= low: 
     272            value = low + _get_zero_shift(low) 
     273        if high is not None and value > high: 
     274            value = high - _get_zero_shift(high) 
     275            # Check one more time if the new value goes below 
     276            # the low bound, If so, re-evaluate the value 
     277            # with the mean of the range. 
     278            if low is not None and value < low: 
     279                value = 0.5 * (low+high) 
     280        model.setParam(p, value) 
     281 
     282def _get_zero_shift(limit): 
     283    """ 
     284    Get 10% shift of the param value = 0 based on the range value 
     285 
     286    : param range: min or max value of the bounds 
     287    """ 
     288    return 0.1 * (limit if limit != 0.0 else 1.0) 
     289 
    198290     
    199291#def profile(fn, *args, **kw): 
  • src/sans/fit/__init__.py

    r5777106 r6fe5100  
     1from .AbstractFitEngine import FitHandler 
  • src/sans/perspectives/fitting/basepage.py

    r116e1a7 rbf5e985  
    9696        self.num_points = None 
    9797        ## default fitengine type 
    98         self.engine_type = 'scipy' 
     98        self.engine_type = 'bumps' 
    9999        ## smear default 
    100100        self.current_smearer = None 
     
    835835            infor = "warning" 
    836836        else: 
    837             msg = "Error was occured " 
    838             msg += ": No valid parameter values to paste from the clipboard..." 
     837            msg = "Error occured: " 
     838            msg += "No valid parameter values to paste from the clipboard..." 
    839839            infor = "error" 
    840840            wx.PostEvent(self._manager.parent, 
     
    21832183                else: 
    21842184                    tcrtl.SetBackgroundColour("pink") 
    2185                     msg = "Model Error:wrong value entered: %s" % sys.exc_value 
     2185                    msg = "Model Error: wrong value entered: %s" % sys.exc_value 
    21862186                    wx.PostEvent(self.parent, StatusEvent(status=msg)) 
    21872187                    return 
    21882188            except: 
    21892189                tcrtl.SetBackgroundColour("pink") 
    2190                 msg = "Model Error:wrong value entered: %s" % sys.exc_value 
     2190                msg = "Model Error: wrong value entered: %s" % sys.exc_value 
    21912191                wx.PostEvent(self.parent, StatusEvent(status=msg)) 
    21922192                return 
     
    21992199                        #is_modified = True 
    22002200                else: 
    2201                     msg = "Cannot Plot :No npts in that Qrange!!!  " 
     2201                    msg = "Cannot plot: No points in Q range!!!  " 
    22022202                    wx.PostEvent(self.parent, StatusEvent(status=msg)) 
    22032203        else: 
    22042204            tcrtl.SetBackgroundColour("pink") 
    2205             msg = "Model Error:wrong value entered!!!" 
     2205            msg = "Model Error: wrong value entered!!!" 
    22062206            wx.PostEvent(self.parent, StatusEvent(status=msg)) 
    22072207        self.save_current_state() 
     
    22402240                else: 
    22412241                    tcrtl.SetBackgroundColour("pink") 
    2242                     msg = "Model Error:wrong value entered: %s" % sys.exc_value 
     2242                    msg = "Model Error: wrong value entered: %s" % sys.exc_value 
    22432243                    wx.PostEvent(self._manager.parent, StatusEvent(status=msg)) 
    22442244                    return 
    22452245            except: 
    22462246                tcrtl.SetBackgroundColour("pink") 
    2247                 msg = "Model Error:wrong value entered: %s" % sys.exc_value 
     2247                msg = "Model Error: wrong value entered: %s" % sys.exc_value 
    22482248                wx.PostEvent(self._manager.parent, StatusEvent(status=msg)) 
    22492249                return 
     
    22562256                        is_modified = True 
    22572257                else: 
    2258                     msg = "Cannot Plot :No npts in that Qrange!!!  " 
     2258                    msg = "Cannot Plot: No points in Q range!!!  " 
    22592259                    wx.PostEvent(self._manager.parent, StatusEvent(status=msg)) 
    22602260        else: 
    22612261            tcrtl.SetBackgroundColour("pink") 
    2262             msg = "Model Error:wrong value entered!!!" 
     2262            msg = "Model Error: wrong value entered!!!" 
    22632263            wx.PostEvent(self._manager.parent, StatusEvent(status=msg)) 
    22642264        self.save_current_state() 
     
    24312431                self.qmax.SetBackgroundColour("pink") 
    24322432                self.qmax.Refresh() 
    2433                 msg = "Npts of Data Error :" 
    2434                 msg += "No or too little npts of %s." % data.name 
     2433                msg = "Data Error: " 
     2434                msg += "Too few points in %s." % data.name 
    24352435                wx.PostEvent(self._manager.parent, StatusEvent(status=msg)) 
    24362436                self.fitrange = False 
     
    24662466                self.qmax.SetBackgroundColour("pink") 
    24672467                self.qmax.Refresh() 
    2468                 msg = "Npts of Data Error :" 
    2469                 msg += "No or too little npts of %s." % data.name 
     2468                msg = "Data Error: " 
     2469                msg += "Too few points in %s." % data.name 
    24702470                wx.PostEvent(self._manager.parent, StatusEvent(status=msg)) 
    24712471                self.fitrange = False 
     
    25182518                                            
    25192519                        except: 
    2520                             msg = "Wrong Fit parameter range entered " 
     2520                            msg = "Wrong fit parameter range entered" 
    25212521                            wx.PostEvent(self._manager.parent, 
    25222522                                         StatusEvent(status=msg)) 
     
    29862986            self.qmin.SetValue(str(self.qmin_x)) 
    29872987            self.qmax.SetValue(str(self.qmax_x)) 
    2988             self.set_npts2fit() 
     2988            self.show_npts2fit() 
    29892989            # At this point, some button and variables satatus (disabled?) 
    29902990            # should be checked such as color that should be reset to 
     
    38743874        to fit if implemented 
    38753875        """ 
    3876     def set_npts2fit(self): 
     3876    def show_npts2fit(self): 
    38773877        """ 
    38783878        setValue Npts for fitting if implemented 
  • src/sans/perspectives/fitting/console.py

    r5777106 r35086c3  
    55import time 
    66import wx 
    7 import park 
    8 from park.fitresult import FitHandler 
     7from sans.fit import FitHandler 
    98 
    109class ConsoleUpdate(FitHandler): 
     
    8887        Print result object 
    8988        """ 
    90         msg = " \n %s \n" % self.result.__str__() 
     89        msg = " \n %s \n" % str(self.result) 
    9190        wx.PostEvent(self.parent, StatusEvent(status=msg)) 
    9291                      
     
    129128             
    130129         
    131     def update_fit(self, msg="", last=False): 
     130    def update_fit(self, last=False): 
    132131        """ 
    133132        """ 
     
    136135        self.update_duration = t1 
    137136        self.fit_duration += self.elapsed_time 
    138         str_time = time.strftime("%a, %d %b %Y %H:%M:%S ", time.localtime(t1)) 
    139         UPDATE_INTERVAL = 0.5 
     137        str_time = time.strftime("%Y-%m-%d %H:%M:%S ", time.localtime(t1)) 
     138        UPDATE_INTERVAL = 5.0 
    140139        u_flag = False 
    141140        if self.fit_duration >= UPDATE_INTERVAL: 
    142141            self.fit_duration = 0 
    143142            u_flag = True 
    144         if not last: 
    145             msg += "Fit Updates ... %s \n" % str_time     
    146         else: 
    147             msg += "Final updates ........." 
     143        msg = str_time 
    148144        if u_flag or last: 
    149145            if self.result is not None: 
     
    164160                msg +=  str(self.result) 
    165161                msg += "\n" 
    166                 if not last: 
    167                     msg += "About %s s elapsed......... \n" % \ 
    168                                             str (UPDATE_INTERVAL) 
    169162            else: 
    170163                msg += "No result available\n" 
  • src/sans/perspectives/fitting/fit_thread.py

    ra855fec re3efa6b3  
    1818     
    1919    def __init__(self,  
    20                   fn, 
    21                   page_id, 
    22                    handler, 
    23                     batch_outputs, 
    24                     batch_inputs=None,              
    25                   pars=None, 
     20                 fn, 
     21                 page_id, 
     22                 handler, 
     23                 batch_outputs, 
     24                 batch_inputs=None, 
     25                 pars=None, 
    2626                 completefn = None, 
    2727                 updatefn   = None, 
     
    3030                 ftol       = None, 
    3131                 reset_flag = False): 
    32         CalcThread.__init__(self,completefn, 
     32        CalcThread.__init__(self, 
     33                 completefn, 
    3334                 updatefn, 
    3435                 yieldtime, 
     
    8081                list_map_get_attr.append(map_getattr) 
    8182            #from multiprocessing import Pool 
    82             inputs = zip(list_map_get_attr,self.fitter, list_fit_function, 
    83                           list_q, list_q, list_handler,list_curr_thread,list_ftol, 
     83            inputs = zip(list_map_get_attr, self.fitter, list_fit_function, 
     84                         list_q, list_q, list_handler,list_curr_thread,list_ftol, 
    8485                         list_reset_flag) 
    8586            result =  map(map_apply, inputs) 
     
    8788            self.complete(result=result, 
    8889                          batch_inputs=self.batch_inputs, 
    89                            batch_outputs=self.batch_outputs, 
     90                          batch_outputs=self.batch_outputs, 
    9091                          page_id=self.page_id, 
    9192                          pars = self.pars, 
  • src/sans/perspectives/fitting/fitpage.py

    rd44648e rbf5e985  
    661661                          wx.EXPAND | wx.ADJUST_MINSIZE, 0) 
    662662         
    663         if self.engine_type == "park": 
    664             self.text_disp_max.Show(True) 
    665             self.text_disp_min.Show(True) 
     663        self.text_disp_max.Show(True) 
     664        self.text_disp_min.Show(True) 
    666665 
    667666        for item in self.model.dispersion.keys(): 
     
    738737                                          wx.EXPAND | wx.ADJUST_MINSIZE, 0) 
    739738 
    740                         if self.engine_type == "park": 
    741                             ctl3.Show(True) 
    742                             ctl4.Show(True) 
     739                        ctl3.Show(True) 
     740                        ctl4.Show(True) 
    743741                                                               
    744742                    elif p == "npts": 
     
    10051003            return 
    10061004 
    1007         if len(self._manager.fit_thread_list) > 0 and\ 
    1008                     self._manager._fit_engine != "park" and\ 
    1009                     self._manager.sim_page != None and \ 
    1010                     self._manager.sim_page.uid == self.uid: 
     1005        if (len(self._manager.fit_thread_list) > 0 
     1006                and self._manager._fit_engine not in ("park","bumps") 
     1007                and self._manager.sim_page != None 
     1008                and self._manager.sim_page.uid == self.uid): 
    10111009            msg = "The FitEnging will be set to 'ParkMC'\n" 
    10121010            msg += " to fit with more than one data set..." 
     
    12681266        if check_float(tcrtl): 
    12691267            flag = self._onparamEnter_helper() 
    1270             self.set_npts2fit() 
     1268            self.show_npts2fit() 
    12711269            if self.fitrange: 
    12721270                temp_smearer = None 
     
    14681466                    #self.data.mask = index_data 
    14691467                    #self.Npts_fit.SetValue(str(len(self.data.mask))) 
    1470                     self.set_npts2fit() 
     1468                    self.show_npts2fit() 
    14711469            else: 
    14721470                index_data = ((self.qmin_x <= self.data.x) & \ 
     
    17661764            # try re draw the model plot if it exists 
    17671765            self._draw_model() 
    1768             self.set_npts2fit() 
     1766            self.show_npts2fit() 
    17691767        elif self.model == None: 
    17701768            self.panel.MakeModal(False) 
    17711769            event.Skip() 
    1772             self.set_npts2fit() 
     1770            self.show_npts2fit() 
    17731771            msg = "No model is found on updating MASK in the model plot... " 
    17741772            wx.PostEvent(self._manager.parent, StatusEvent(status=msg)) 
     
    20562054        return npts2fit 
    20572055 
    2058     def set_npts2fit(self): 
     2056    def show_npts2fit(self): 
    20592057        """ 
    20602058        setValue Npts for fitting 
     
    20682066        return self.tcChi.GetValue() 
    20692067         
    2070     def get_param_list(self): 
    2071         """ 
    2072         :return self.param_toFit: list containing  references to TextCtrl 
    2073             checked.Theses TextCtrl will allow reference to parameters to fit. 
    2074          
    2075         :raise: if return an empty list of parameter fit will nnote work 
    2076             properly so raise ValueError,"missing parameter to fit" 
    2077         """ 
    2078         if self.param_toFit != []: 
    2079             return self.param_toFit 
    2080         else: 
    2081             msg = "missing parameters to fit" 
    2082             wx.MessageBox(msg, 'warning') 
    2083             return False 
    2084        
    20852068    def onsetValues(self, chisqr, p_name, out, cov): 
    20862069        """ 
     
    21082091        if chisqr != None and numpy.isfinite(chisqr): 
    21092092            #format chi2 
    2110             if self.engine_type == "park": 
    2111                 npt_fit = float(self.get_npts2fit()) 
    21122093            chi2 = format_number(chisqr, True) 
    21132094            self.tcChi.SetValue(chi2) 
  • src/sans/perspectives/fitting/fitpanel.py

    rb6a181b reff93b8  
    6464        self.sim_page = None 
    6565        self.batch_page = None 
    66         self.fit_engine_type = "scipy" 
     66        self.fit_engine_type = "bumps" 
    6767        ## get the state of a page 
    6868        self.Bind(basepage.EVT_PAGE_INFO, self._onGetstate) 
  • src/sans/perspectives/fitting/fitproblem.py

    r5777106 r5bf0331  
    454454        return self.itervalues() 
    455455     
    456     def  set_result(self, result, fid): 
     456    def set_result(self, result, fid): 
    457457        """ 
    458458        """ 
  • src/sans/perspectives/fitting/fitting.py

    r767514a rbf5e985  
    3636from .fitproblem import FitProblemDictionary 
    3737from .fitpanel import FitPanel 
     38from .resultpanel import ResultPanel, PlotResultEvent 
     39 
    3840from .fit_thread import FitThread 
    3941from .pagestate import Reader 
     
    4244from sans.perspectives.calculator.model_editor import EditorWindow 
    4345from sans.guiframe.gui_manager import MDIFrame 
     46 
     47# TODO: remove globals from interface to bumps options! 
     48# Default bumps to use the levenberg-marquardt optimizer 
     49import bumps.fitters 
     50bumps.fitters.FIT_DEFAULT = 'lm' 
    4451 
    4552MAX_NBR_DATA = 4 
     
    7885        # Start with a good default 
    7986        self.elapsed = 0.022 
    80         # the type of optimizer selected, park or scipy 
    81         self.fitter = None 
    8287        self.fit_panel = None 
    83         #let fit ready 
    84         self.fitproblem_count = None 
    8588        #Flag to let the plug-in know that it is running stand alone 
    8689        self.standalone = True 
     
    8891        self.closed_page_dict = {} 
    8992        ## Fit engine 
    90         self._fit_engine = 'scipy' 
     93        self._fit_engine = 'bumps' 
    9194        self._gui_engine = None 
    9295        ## Relative error desired in the sum of squares (float); scipy only 
     
    111114        self.scipy_id = wx.NewId() 
    112115        self.park_id = wx.NewId() 
     116        self.bumps_id = wx.NewId() 
    113117        self.menu1 = None 
    114118        self.new_model_frame = None 
     
    198202        wx.EVT_MENU(owner, self.park_id, self._onset_engine_park) 
    199203         
    200         self.menu1.FindItemById(self.scipy_id).Check(True) 
    201         self.menu1.FindItemById(self.park_id).Check(False) 
     204        bumps_help = "Bumps: fitting and uncertainty analysis. More in Help window...." 
     205        self.menu1.AppendCheckItem(self.bumps_id, "Bumps fit", 
     206                                   bumps_help) 
     207        wx.EVT_MENU(owner, self.bumps_id, self._onset_engine_bumps) 
     208         
     209        self.menu1.FindItemById(self.scipy_id).Check(self._fit_engine=="scipy") 
     210        self.menu1.FindItemById(self.park_id).Check(self._fit_engine=="park") 
     211        self.menu1.FindItemById(self.bumps_id).Check(self._fit_engine=="bumps") 
    202212        self.menu1.AppendSeparator() 
    203213        self.id_tol = wx.NewId() 
     
    207217                                   ftol_help) 
    208218        wx.EVT_MENU(owner, self.id_tol, self.show_ftol_dialog) 
     219 
     220        self.id_bumps_options = wx.NewId() 
     221        bopts_help = "Bumps fitting options" 
     222        self.menu1.Append(self.id_bumps_options, 'Bumps &Options', bopts_help) 
     223        wx.EVT_MENU(owner, self.id_bumps_options, self.on_bumps_options) 
     224        self.bumps_options_menu = self.menu1.FindItemById(self.id_bumps_options) 
     225        self.bumps_options_menu.Enable(True) 
     226 
     227        self.id_result_panel = wx.NewId() 
     228        self.menu1.Append(self.id_result_panel, "Fit Results", "Show fit results panel") 
     229        wx.EVT_MENU(owner, self.id_result_panel, lambda ev: self.result_frame.Show()) 
    209230        self.menu1.AppendSeparator() 
    210231         
     
    511532        self.perspective = [] 
    512533        self.perspective.append(self.fit_panel.window_name) 
     534 
     535        self.result_frame = MDIFrame(self.parent, None, ResultPanel.window_caption, (220, 200)) 
     536        self.result_panel = ResultPanel(parent=self.result_frame, manager=self) 
     537        self.perspective.append(self.result_panel.window_name) 
    513538        
    514539        #index number to create random model name 
     
    525550        #Send the fitting panel to guiframe 
    526551        self.mypanels.append(self.fit_panel) 
     552        self.mypanels.append(self.result_panel) 
    527553        return self.mypanels 
    528554     
     
    818844                         StatusEvent(status=msg, info='warning')) 
    819845        dialog.Destroy() 
     846 
     847    def on_bumps_options(self, event=None): 
     848        from bumps.gui.fit_dialog import OpenFitOptions 
     849        OpenFitOptions() 
    820850 
    821851    def stop_fit(self, uid): 
     
    951981        :param uid: id related to the panel currently calling this fit function. 
    952982        """ 
    953         flag = True 
    954         ##  count the number of fitproblem schedule to fit 
    955         fitproblem_count = 0 
    956         for value in self.page_finder.values(): 
    957             if value.get_scheduled() == 1: 
    958                 fitproblem_count += 1 
    959         self._gui_engine = self._return_engine_type() 
    960         self.fitproblem_count = fitproblem_count 
    961         if self._fit_engine == "park": 
    962             engineType = "Simultaneous Fit" 
     983        if uid is None: raise RuntimeError("no page to fit") # Should never happen 
     984 
     985        # Remember the user selected fit engine before the fit.  Simultaneous 
     986        # fitting may change the selected engine, so it needs to be restored 
     987        # when the fit is complete. 
     988        self._gui_engine = self._fit_engine 
     989 
     990        sim_page_uid = getattr(self.sim_page, 'uid', None) 
     991        batch_page_uid = getattr(self.batch_page, 'uid', None) 
     992 
     993        if uid == sim_page_uid: 
     994            fit_type = 'simultaneous' 
     995        elif uid == batch_page_uid: 
     996            fit_type = 'combined_batch' 
    963997        else: 
    964             engineType = "Single Fit" 
     998            fit_type = 'single' 
     999 
     1000        # if constrained fit, don't use scipy leastsq directly 
     1001        if fit_type == 'simultaneous': 
     1002            if self._fit_engine not in ("park","bumps"): 
     1003                self._on_change_engine(engine='bumps') 
     1004 
     1005 
    9651006        fitter_list = [] 
    9661007        sim_fitter = None 
    967         is_single_fit = True 
    968         batch_on = False 
    969         if self.sim_page is not None and self.sim_page.uid == uid: 
     1008        if fit_type == 'simultaneous': 
    9701009            #simulatanous fit only one engine need to be created 
    971             ## if simultaneous fit change automatically the engine to park 
    972             self._on_change_engine(engine='park') 
    9731010            sim_fitter = Fit(self._fit_engine) 
    9741011            sim_fitter.fitter_id = self.sim_page.uid 
    9751012            fitter_list.append(sim_fitter) 
    976             is_single_fit = False 
    977             batch_on = self.sim_page.batch_on 
    978              
    979         self.fitproblem_count = fitproblem_count 
    980         if self._fit_engine == "park": 
    981             engineType = "Simultaneous Fit" 
    982         else: 
    983             engineType = "Single Fit" 
    984          
     1013 
    9851014        self.current_pg = None 
    9861015        list_page_id = [] 
    9871016        fit_id = 0 
    988         batch_inputs = {} 
    989         batch_outputs = {} 
    990         for page_id, value in self.page_finder.iteritems(): 
     1017        for page_id, page_info in self.page_finder.iteritems(): 
    9911018            # For simulfit (uid give with None), do for-loop 
    9921019            # if uid is specified (singlefit), do it only on the page. 
    993             if engineType == "Single Fit": 
    994                 #combine more than 1 batch page on single mode 
    995                 if self.batch_page is None or self.batch_page.uid != uid: 
    996                     if page_id != uid: 
    997                         continue 
     1020            if page_id in (sim_page_uid, batch_page_uid): continue 
     1021            if fit_type == "single" and page_id != uid: continue 
     1022 
    9981023            try: 
    999                 if value.get_scheduled() == 1: 
    1000                     value.nbr_residuals_computed = 0 
    1001                     #Get list of parameters name to fit 
    1002                     pars = [] 
    1003                     templist = [] 
     1024                if page_info.get_scheduled() == 1: 
     1025                    page_info.nbr_residuals_computed = 0 
    10041026                    page = self.fit_panel.get_page_by_id(page_id) 
    10051027                    self.set_fit_weight(uid=page.uid, 
    10061028                                     flag=page.get_weight_flag(), 
    10071029                                     is2d=page._is_2D()) 
    1008                     templist = page.get_param_list() 
    1009                     flag = page._update_paramv_on_fit() 
    1010                     if not flag: 
     1030                    if not page.param_toFit: 
     1031                        msg = "No fitting parameters for %s"%page.window_caption 
     1032                        wx.PostEvent(page.parent.parent, 
     1033                                     StatusEvent(status=msg, info="error", 
     1034                                                 type="stop")) 
     1035                        return False 
     1036                    if not page._update_paramv_on_fit(): 
    10111037                        msg = "Fitting range or parameter values are" 
    10121038                        msg += " invalid in %s" % \ 
     
    10151041                                     StatusEvent(status=msg, info="error", 
    10161042                                     type="stop")) 
    1017                         return flag 
    1018                     for element in templist: 
    1019                         name = str(element[1]) 
    1020                         pars.append(name) 
    1021                     fitproblem_list = value.values() 
     1043                        return False 
     1044 
     1045                    pars = [str(element[1]) for element in page.param_toFit] 
     1046                    fitproblem_list = page_info.values() 
    10221047                    for fitproblem in  fitproblem_list: 
    10231048                        if sim_fitter is None: 
    10241049                            fitter = Fit(self._fit_engine) 
    10251050                            fitter.fitter_id = page_id 
    1026                             self._fit_helper(fitproblem=fitproblem, 
    1027                                              pars=pars, 
    1028                                              fitter=fitter, 
    1029                                              fit_id=fit_id, 
    1030                                              batch_inputs=batch_inputs, 
    1031                                              batch_outputs=batch_outputs) 
    10321051                            fitter_list.append(fitter) 
    10331052                        else: 
    10341053                            fitter = sim_fitter 
    1035                             self._fit_helper(fitproblem=fitproblem, 
     1054                        self._add_problem_to_fit(fitproblem=fitproblem, 
    10361055                                             pars=pars, 
    10371056                                             fitter=fitter, 
    1038                                              fit_id=fit_id, 
    1039                                              batch_inputs=batch_inputs, 
    1040                                              batch_outputs=batch_outputs) 
     1057                                             fit_id=fit_id) 
    10411058                        fit_id += 1 
    10421059                    list_page_id.append(page_id) 
    1043                     current_page_id = page_id 
    1044                     value.clear_model_param() 
     1060                    page_info.clear_model_param() 
    10451061            except KeyboardInterrupt: 
    1046                 flag = True 
    10471062                msg = "Fitting terminated" 
    10481063                wx.PostEvent(self.parent, StatusEvent(status=msg, info="info", 
    10491064                                                      type="stop")) 
    1050                 return flag 
     1065                return True 
    10511066            except: 
    1052                 flag = False 
    1053                 msg = "%s error: %s" % (engineType, sys.exc_value) 
     1067                msg = "Fitting error: %s" % str(sys.exc_value) 
    10541068                wx.PostEvent(self.parent, StatusEvent(status=msg, info="error", 
    10551069                                                      type="stop")) 
    1056                 return flag 
     1070                return False 
    10571071        ## If a thread is already started, stop it 
    10581072        #if self.calc_fit!= None and self.calc_fit.isrunning(): 
     
    10661080                                improvement_delta=0.1) 
    10671081        self._mac_sleep(0.2) 
    1068         ## perform single fit 
    1069         try: 
     1082 
     1083        # batch fit 
     1084        batch_inputs = {} 
     1085        batch_outputs = {} 
     1086        if fit_type == "simultaneous": 
     1087            page = self.sim_page 
     1088        elif fit_type == "combined_batch": 
     1089            page = self.batch_page 
     1090        else: 
    10701091            page = self.fit_panel.get_page_by_id(uid) 
    1071             batch_on = page.batch_on 
    1072         except: 
    1073             try: 
    1074                 #if the id cannot be found then  we deal with a self.sim_page 
    1075                 #or a self.batch_page 
    1076                 if self.sim_page is not None and uid == self.sim_page.uid: 
    1077                     batch_on = self.sim_page.batch_on 
    1078                 if self.batch_page is not None and uid == self.batch_page.uid: 
    1079                     batch_on = self.batch_page.batch_on 
    1080             except: 
    1081                 batch_on = False 
    1082  
    1083         # batch fit 
    1084         if batch_on: 
     1092        if page.batch_on: 
    10851093            calc_fit = FitThread(handler=handler, 
    10861094                                 fn=fitter_list, 
     
    10931101                                 reset_flag=self.batch_reset_flag) 
    10941102        else: 
    1095             # single fit: not batch and not simul fit 
    1096             if not is_single_fit: 
    1097                 current_page_id = self.sim_page.uid 
    10981103            ## Perform more than 1 fit at the time 
    10991104            calc_fit = FitThread(handler=handler, 
     
    11051110                                    completefn=self._fit_completed, 
    11061111                                    ftol=self.ftol) 
    1107         self.fit_thread_list[current_page_id] = calc_fit 
     1112        #self.fit_thread_list[current_page_id] = calc_fit 
     1113        self.fit_thread_list[uid] = calc_fit 
    11081114        calc_fit.queue() 
     1115        calc_fit.ready(2.5) 
    11091116        msg = "Fitting is in progress..." 
    11101117        wx.PostEvent(self.parent, StatusEvent(status=msg, type="progress")) 
    11111118         
    1112         self.ready_fit(calc_fit=calc_fit) 
    1113         return flag 
    1114      
    1115     def ready_fit(self, calc_fit): 
    1116         """ 
    1117         Ready for another fit 
    1118         """ 
    1119         if self.fitproblem_count != None and self.fitproblem_count > 1: 
    1120             calc_fit.ready(2.5) 
    1121         else: 
    1122             time.sleep(0.4) 
    1123              
     1119        return True 
     1120 
    11241121    def remove_plot(self, uid, fid=None, theory=False): 
    11251122        """ 
     
    12611258                self.page_finder[uid].schedule_tofit(value) 
    12621259                 
    1263     def _fit_helper(self, fitproblem, pars, fitter, fit_id, 
    1264                     batch_inputs, batch_outputs): 
     1260    def _add_problem_to_fit(self, fitproblem, pars, fitter, fit_id): 
    12651261        """ 
    12661262        Create and set fit engine with series of data and model 
     
    15711567        wx.PostEvent(self.parent, StatusEvent(status=msg, info="info", 
    15721568                                                      type="stop")) 
     1569        wx.PostEvent(self.result_panel, PlotResultEvent(result=result)) 
    15731570        # reset fit_engine if changed by simul_fit 
    15741571        if self._fit_engine != self._gui_engine: 
     
    16821679        self._on_change_engine('scipy') 
    16831680        
     1681    def _onset_engine_bumps(self, event): 
     1682        """  
     1683        set engine to bumps 
     1684        """ 
     1685        self._on_change_engine('bumps') 
     1686        
    16841687    def _on_slicer_event(self, event): 
    16851688        """ 
     
    17141717                break 
    17151718     
    1716     def _return_engine_type(self): 
    1717         """ 
    1718         return the current type of engine 
    1719         """ 
    1720         return self._fit_engine 
    1721       
    17221719    def _on_change_engine(self, engine='park'): 
    17231720        """ 
     
    17331730            self.menu1.FindItemById(self.park_id).Check(True) 
    17341731            self.menu1.FindItemById(self.scipy_id).Check(False) 
     1732            self.menu1.FindItemById(self.bumps_id).Check(False) 
     1733        elif engine == "scipy": 
     1734            self.menu1.FindItemById(self.park_id).Check(False) 
     1735            self.menu1.FindItemById(self.scipy_id).Check(True) 
     1736            self.menu1.FindItemById(self.bumps_id).Check(False) 
    17351737        else: 
    17361738            self.menu1.FindItemById(self.park_id).Check(False) 
    1737             self.menu1.FindItemById(self.scipy_id).Check(True) 
     1739            self.menu1.FindItemById(self.scipy_id).Check(False) 
     1740            self.menu1.FindItemById(self.bumps_id).Check(True) 
    17381741        ## post a message to status bar 
    17391742        msg = "Engine set to: %s" % self._fit_engine 
  • src/sans/perspectives/fitting/simfitpage.py

    r5777106 rbf5e985  
    138138                self.Layout() 
    139139                break 
    140         self._onAdd_constraint(None) 
     140 
     141        #self._onAdd_constraint(None) 
    141142              
    142143    def onFit(self, event): 
     
    152153        ## making sure all parameters content a constraint 
    153154        ## validity of the constraint expression is own by fit engine 
    154         if self.parent._manager._fit_engine != "park" and flag: 
     155        if self.parent._manager._fit_engine not in ("park","bumps") and flag: 
    155156            msg = "The FitEnging will be set to 'Park' fit engine\n" 
    156157            msg += " for the simultaneous fit..." 
     
    378379        box_description = wx.StaticBox(self, -1,"Easy Setup ") 
    379380        boxsizer = wx.StaticBoxSizer(box_description, wx.HORIZONTAL)      
    380         sizer_constraint = wx.BoxSizer(wx.HORIZONTAL|wx.LEFT|wx.RIGHT|wx.EXPAND) 
     381        sizer_constraint = wx.BoxSizer(wx.HORIZONTAL) 
    381382        self.model_cbox_left = wx.ComboBox(self, -1, style=wx.CB_READONLY) 
    382383        self.model_cbox_left.Clear() 
     
    814815                         
    815816                    for fid in self.page_finder[id].iterkeys(): 
    816                         self.page_finder[id].set_model_param(param, 
    817                                                         constraint, fid=fid) 
     817                        # wrap in param/constraint in str() to remove unicode 
     818                        self.page_finder[id].set_model_param(str(param), 
     819                                                        str(constraint), fid=fid) 
    818820                    break 
    819821        return True 
Note: See TracChangeset for help on using the changeset viewer.