Changeset 04a269f in sasview


Ignore:
Timestamp:
Mar 28, 2019 8:54:29 AM (6 months ago)
Author:
ibressler
Branches:
ESS_GUI_bumps_abstraction
Children:
740a738
Parents:
aa47ea5
git-author:
Ingo Breßler <dev@…> (03/28/19 08:51:02)
git-committer:
Ingo Breßler <dev@…> (03/28/19 08:54:29)
Message:

FittingOptions?: using new FittingMethods? structure, updated FittingPerspective?

  • tested, should work fine
  • reading/writing bumps config now isolated in separate methods, will be handled by subclasses in the next step
Location:
src/sas/qtgui/Perspectives/Fitting
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • src/sas/qtgui/Perspectives/Fitting/FittingOptions.py

    raa47ea5 r04a269f  
    2020# Set the default optimizer 
    2121 
     22def configToBumps(fittingMethod): 
     23    """ 
     24    Writes the user settings of given fitting method back to be bumps module where it is used 
     25    once the 'fit' button is hit in the GUI. 
     26    """ 
     27#    assert isinstance(fittingMethod, FittingMethod) # FIXME once FittingMethod is known here 
     28    # self.config.values[self.current_fitter_id][option] = new_value 
     29    fitConfig = bumps.options.FIT_CONFIG 
     30    fitConfig.selected_id = fittingMethod.shortName 
     31    for param in fittingMethod.params.values(): 
     32        fitConfig.values[fittingMethod.shortName][param.shortName] = param.value 
     33 
     34def parse_int(value): 
     35    """ 
     36    Converts user input to integer numbers. (from bumps) 
     37    """ 
     38    float_value = float(value) 
     39    if int(float_value) != float_value: 
     40        raise ValueError("integer expected") 
     41    return int(float_value) 
     42 
     43class ChoiceList(object): 
     44    """ 
     45    Validates user input for a distinct number of options. 
     46    """ 
     47    def __init__(self, *choices): 
     48        self.choices = choices 
     49    def __call__(self, value): 
     50        if not value in self.choices: 
     51            raise ValueError('invalid option "%s": use %s' 
     52                    % (value, '|'.join(self.choices))) 
     53        else: 
     54            return value 
     55 
    2256class FittingMethodParameter: 
     57    """ 
     58    Descriptive meta data of a single parameter of an optimizer. 
     59    """ 
    2360    _shortName = None 
    2461    _longName = None 
     
    122159        return [fm.shortName for fm in self._methods.values()] 
    123160 
    124     def __getitem__(self, name): 
    125         return self._methods[name] 
     161    def __getitem__(self, longName): 
     162        return self._methods[longName] 
    126163 
    127164    @property 
     
    152189    fit_option_changed = QtCore.pyqtSignal(str) 
    153190    # storing of fitting methods here for now, dependencies might indicate a better place later 
    154     fittingMethods = None 
     191    _fittingMethods = None 
     192 
     193    @property 
     194    def fittingMethods(self): 
     195        return self._fittingMethods 
    155196 
    156197    def __init__(self, parent=None, config=None): 
     
    168209 
    169210        # Fill up the algorithm combo, based on what BUMPS says is available 
    170         self.fittingMethods = FittingMethods() 
     211        self._fittingMethods = FittingMethods() 
    171212        # option 1: hardcode the list of bumps fitting methods according to forms 
    172213        # option 2: create forms dynamically based on selected fitting methods 
     
    202243    def assignValidators(self): 
    203244        """ 
    204         Use options.FIT_FIELDS to assert which line edit gets what validator 
    205         """ 
    206         for option in bumps.options.FIT_FIELDS.keys(): 
    207             (f_name, f_type) = bumps.options.FIT_FIELDS[option] 
     245        Sets the appropriate validators to the line edits as defined by FittingMethodParameter 
     246        """ 
     247        fm = self.fittingMethods[str(self.currentOptimizer)] 
     248        for param in fm.params.values(): 
    208249            validator = None 
    209             if type(f_type) == types.FunctionType: 
     250            if type(param.type) == types.FunctionType: 
    210251                validator = QtGui.QIntValidator() 
    211252                validator.setBottom(0) 
    212             elif f_type == float: 
     253            elif param.type == float: 
    213254                validator = GuiUtils.DoubleValidator() 
    214255                validator.setBottom(0) 
    215256            else: 
    216257                continue 
    217             for fitter_id in self.fittingMethods.ids: 
    218                 line_edit = self.widgetFromOption(str(option), current_fitter=str(fitter_id)) 
    219                 if hasattr(line_edit, 'setValidator') and validator is not None: 
    220                     line_edit.setValidator(validator) 
    221                     line_edit.textChanged.connect(self.check_state) 
    222                     line_edit.textChanged.emit(line_edit.text()) 
     258            line_edit = self.paramWidget(fm, param.shortName) 
     259            if hasattr(line_edit, 'setValidator') and validator is not None: 
     260                line_edit.setValidator(validator) 
     261                line_edit.textChanged.connect(self.check_state) 
     262                line_edit.textChanged.emit(line_edit.text()) 
    223263 
    224264    def check_state(self, *args, **kwargs): 
     
    240280        """ 
    241281        # Find the algorithm ID from name 
    242         selectedName = str(self.cbAlgorithm.currentText()) 
     282        selectedName = str(self.currentOptimizer) 
    243283        if selectedName in self.fittingMethods.longNames: 
    244284            self.current_fitter_id = self.fittingMethods[selectedName].shortName 
     
    268308        self.stackedWidget.setCurrentIndex(index_for_this_id) 
    269309 
    270         self.updateWidgetFromBumps(self.current_fitter_id) 
     310        self.updateWidgetFromConfig() 
    271311 
    272312        self.assignValidators() 
     
    278318        self.previous_index = index 
    279319 
     320    def paramWidget(self, fittingMethod, paramShortName): 
     321        """ 
     322        Returns the widget associated to a FittingMethodParameter. 
     323        """ 
     324        if paramShortName not in fittingMethod.params: 
     325            return None 
     326        widget_name = 'self.'+paramShortName+'_'+fittingMethod.shortName 
     327        widget = None 
     328        try: 
     329            widget = eval(widget_name) 
     330        except AttributeError: 
     331            pass 
     332        return widget 
     333 
    280334    def onApply(self): 
    281335        """ 
    282336        Update the fitter object 
    283337        """ 
    284         options = self.config.values[self.current_fitter_id] 
    285         for option in options.keys(): 
    286             # Find the widget name of the option 
    287             # e.g. 'samples' for 'dream' is 'self.samples_dream' 
    288             widget_name = 'self.'+option+'_'+self.current_fitter_id 
    289             try: 
    290                 line_edit = eval(widget_name) 
    291             except AttributeError: 
    292                 # Skip bumps monitors 
    293                 continue 
     338        fm = self.fittingMethods[str(self.currentOptimizer)] 
     339        for param in fm.params.values(): 
     340            line_edit = self.paramWidget(fm, param.shortName) 
    294341            if line_edit is None or not isinstance(line_edit, QtWidgets.QLineEdit): 
    295342                continue 
     
    299346                tooltip = "<html><b>Please enter valid values in all fields.</html>" 
    300347                QtWidgets.QToolTip.showText(line_edit.mapToGlobal( 
    301                     QtCore.QPoint(line_edit.rect().right(), line_edit.rect().bottom() + 2)), tooltip) 
     348                    QtCore.QPoint(line_edit.rect().right(), line_edit.rect().bottom() + 2)), 
     349                    tooltip) 
    302350                return 
    303351 
    304         # Notify the perspective, so the window title is updated 
    305         self.fit_option_changed.emit(self.cbAlgorithm.currentText()) 
    306  
    307         def bumpsUpdate(option): 
    308             """ 
    309             Utility method for bumps state update 
    310             """ 
    311             widget = self.widgetFromOption(option) 
     352        # update config values from widgets before any notification is sent 
     353        for param in fm.params.values(): 
     354            widget = self.paramWidget(fm, param.shortName) 
    312355            if widget is None: 
    313                 return 
     356                continue 
    314357            try: 
    315358                if isinstance(widget, QtWidgets.QComboBox): 
     
    320363                    except ValueError: 
    321364                        new_value = float(widget.text()) 
    322                 #new_value = widget.currentText() if isinstance(widget, QtWidgets.QComboBox) \ 
    323                 #    else float(widget.text()) 
    324                 self.config.values[self.current_fitter_id][option] = new_value 
     365                fm.params[param.shortName].value = new_value 
    325366            except ValueError: 
    326367                # Don't update bumps if widget has bad data 
    327368                self.reject 
    328369 
    329         # Update the BUMPS singleton 
    330         [bumpsUpdate(o) for o in self.config.values[self.current_fitter_id].keys()] 
     370        # Notify the perspective, so the window title is updated 
     371        self.fit_option_changed.emit(self.cbAlgorithm.currentText()) 
     372        configToBumps(fm) # write the current settings to bumps module 
    331373        self.close() 
    332374 
     
    345387        webbrowser.open('file://' + os.path.realpath(help_location)) 
    346388 
    347     def widgetFromOption(self, option_id, current_fitter=None): 
    348         """ 
    349         returns widget's element linked to the given option_id 
    350         """ 
    351         if current_fitter is None: 
    352             current_fitter = self.current_fitter_id 
    353         if option_id not in list(bumps.options.FIT_FIELDS.keys()): return None 
    354         option = option_id + '_' + current_fitter 
    355         if not hasattr(self, option): return None 
    356         return eval('self.' + option) 
    357  
    358     def getResults(self): 
     389    @property 
     390    def currentOptimizer(self): 
    359391        """ 
    360392        Sends back the current choice of parameters 
    361393        """ 
    362         algorithm = self.cbAlgorithm.currentText() 
    363         return algorithm 
    364  
    365     def updateWidgetFromBumps(self, fitter_id): 
     394        return self.cbAlgorithm.currentText() 
     395 
     396    def updateWidgetFromConfig(self): 
    366397        """ 
    367398        Given the ID of the current optimizer, fetch the values 
    368399        and update the widget 
    369400        """ 
    370         options = self.config.values[fitter_id] 
    371         for option in options.keys(): 
     401        fm = self.fittingMethods[str(self.currentOptimizer)] 
     402        for param in fm.params.values(): 
    372403            # Find the widget name of the option 
    373404            # e.g. 'samples' for 'dream' is 'self.samples_dream' 
    374             widget_name = 'self.'+option+'_'+fitter_id 
    375             if option not in bumps.options.FIT_FIELDS: 
    376                 return 
    377             if isinstance(bumps.options.FIT_FIELDS[option][1], bumps.options.ChoiceList): 
     405            widget_name = 'self.'+param.shortName+'_'+(fm.shortName) 
     406            if isinstance(param.type, ChoiceList): 
    378407                control = eval(widget_name) 
    379                 control.setCurrentIndex(control.findText(str(options[option]))) 
     408                control.setCurrentIndex(control.findText(str(param.value))) 
    380409            else: 
    381                 eval(widget_name).setText(str(options[option])) 
    382  
    383         pass 
     410                eval(widget_name).setText(str(param.value)) 
     411 
  • src/sas/qtgui/Perspectives/Fitting/FittingPerspective.py

    r14e1ff0 r04a269f  
    3939        self.maxIndex = 1 
    4040 
    41         # The default optimizer 
    42         self.optimizer = 'Levenberg-Marquardt' 
    43  
    4441        # Dataset index -> Fitting tab mapping 
    4542        self.dataToFitTab = {} 
     
    7269 
    7370        # Fit options - uniform for all tabs 
    74         self.fit_options = options.FIT_CONFIG 
    75         self.fit_options_widget = FittingOptions(self, config=self.fit_options) 
    76         self.fit_options.selected_id = fitters.LevenbergMarquardtFit.id 
     71        self.fit_options_widget = FittingOptions(self) 
     72        # The default optimizer 
     73        self.optimizer = self.fit_options_widget.currentOptimizer 
    7774 
    7875        # Listen to GUI Manager signal updating fit options 
     
    9592        Update the window title with the current optimizer name 
    9693        """ 
    97         self.optimizer = self.fit_options.selected_name 
    9894        self.setWindowTitle('Fit panel - Active Fitting Optimizer: %s' % self.optimizer) 
    9995 
     
    368364        React to the fitting algorithm change by modifying window title 
    369365        """ 
    370         fitter = [f.id for f in options.FITTERS if f.name == str(fit_engine)][0] 
     366        self.optimizer = self.fit_options_widget.currentOptimizer 
    371367        # set the optimizer 
    372         self.fit_options.selected_id = str(fitter) 
    373368        # Update the title 
    374369        self.updateWindowTitle() 
Note: See TracChangeset for help on using the changeset viewer.