Changeset 0595bb7 in sasview


Ignore:
Timestamp:
Jan 10, 2018 5:15:53 AM (4 years ago)
Author:
Piotr Rozyczko <rozyczko@…>
Branches:
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
Children:
eae226b
Parents:
7fd20fc
git-author:
Piotr Rozyczko <rozyczko@…> (12/24/17 10:42:41)
git-committer:
Piotr Rozyczko <rozyczko@…> (01/10/18 05:15:53)
Message:

Constraint validator - initial implementation + tests. SASVIEW-844

Files:
1 added
4 edited

Legend:

Unmodified
Added
Removed
  • installers/installer_generator.py

    • Property mode changed from 100644 to 100755
  • src/sas/qtgui/GUITests.py

    r50bfab0 r0595bb7  
    5656from Perspectives.Fitting.UnitTesting import FitPageTest 
    5757from Perspectives.Fitting.UnitTesting import FittingOptionsTest 
     58from Perspectives.Fitting.UnitTesting import MultiConstraintTest 
     59 
    5860#  Invariant 
    5961from Perspectives.Invariant.UnitTesting import InvariantPerspectiveTest 
    6062from Perspectives.Invariant.UnitTesting import InvariantDetailsTest 
    61 #  Inversion 
    62 from Perspectives.Inversion.UnitTesting import InversionPerspectiveTest 
    63  
    6463 
    6564def suite(): 
     
    114113        unittest.makeSuite(FitPageTest.FitPageTest,                       'test'), 
    115114        unittest.makeSuite(FittingOptionsTest.FittingOptionsTest,         'test'), 
     115        unittest.makeSuite(MultiConstraintTest.MultiConstraintTest,       'test'), 
    116116        #  Invariant 
    117117        unittest.makeSuite(InvariantPerspectiveTest.InvariantPerspectiveTest,  'test'), 
  • src/sas/qtgui/Perspectives/Fitting/FittingWidget.py

    r7fd20fc r0595bb7  
    8080    Main widget for selecting form and structure factor models 
    8181    """ 
     82    constraintAddedSignal = QtCore.pyqtSignal(list) 
    8283    def __init__(self, parent=None, data=None, tab_id=1): 
    8384 
     
    452453        # Respond to change in parameters from the UI 
    453454        self._model_model.itemChanged.connect(self.onMainParamsChange) 
     455        self.constraintAddedSignal.connect(self.modifyViewOnConstraint) 
    454456        self._poly_model.itemChanged.connect(self.onPolyModelChange) 
    455457        self._magnet_model.itemChanged.connect(self.onMagnetModelChange) 
     
    506508 
    507509        # Define the callbacks 
    508         self.actionConstrain.triggered.connect(self.addConstraint) 
    509         self.actionMutualMultiConstrain.triggered.connect(self.showMultiConstrain) 
     510        self.actionConstrain.triggered.connect(self.addSimpleConstraint) 
     511        self.actionMutualMultiConstrain.triggered.connect(self.showMultiConstraint) 
    510512        self.actionSelect.triggered.connect(self.selectParameters) 
    511513        self.actionDeselect.triggered.connect(self.deselectParameters) 
    512514        return menu 
    513515 
    514     def showMultiConstrain(self): 
     516    def showMultiConstraint(self): 
    515517        """ 
    516518        Show the constraint widget and receive the expression 
    517519        """ 
    518520        from sas.qtgui.Perspectives.Fitting.MultiConstraint import MultiConstraint 
    519         params_list = [s.data() for s in self.lstParams.selectionModel().selectedRows()] 
     521        from .Constraints import Constraint 
     522        selected_rows = self.lstParams.selectionModel().selectedRows() 
     523 
     524        params_list = [s.data() for s in selected_rows] 
    520525        mc_widget = MultiConstraint(self, params=params_list) 
    521526        mc_widget.exec_() 
    522         constraint = mc_widget.txtConstraint.text() 
     527        constraint = Constraint() 
     528        c_text = mc_widget.txtConstraint.text() 
    523529        # Pass the constraint to the parser 
     530 
    524531        self.communicate.statusBarUpdateSignal.emit('Constraints added') 
     532        # Change the colour of the row 
    525533        pass 
    526534 
    527     def addConstraint(self): 
     535    def modifyViewOnConstraint(self, row): 
     536        """ 
     537        Add visual cues that the parameter is constrained 
     538        """ 
     539        value = self._model_model.item(row, 1).text() 
     540        # Set min/max to the value constrained 
     541        self._model_model.item(row,2).setText(value) 
     542        self._model_model.item(row,3).setText(value) 
     543        font = QtGui.QFont() 
     544        font.setItalic(True) 
     545        brush = QtGui.QBrush(QtGui.QColor('blue')) 
     546        self._model_model.blockSignals(True) 
     547        # Modify font and foreground of affected rows 
     548        for column in range(0, self._model_model.columnCount()): 
     549            self._model_model.item(row, column).setForeground(brush) 
     550            self._model_model.item(row, column).setFont(font) 
     551            self._model_model.item(row, column).setEditable(False) 
     552        self._model_model.blockSignals(False) 
     553 
     554    def addSimpleConstraint(self): 
    528555        """ 
    529556        Adds a constraint on a single parameter. 
    530557        """ 
     558        from .Constraints import Constraint 
     559        for row in self.selectedParameters(): 
     560            param = self._model_model.item(row, 0).text() 
     561            value = self._model_model.item(row, 1).text() 
     562            constraint = Constraint(param=param, value=value) 
     563            item = QtGui.QStandardItem() 
     564            item.setData(constraint) 
     565            self._model_model.item(row, 1).setChild(0, item) 
     566            #self.constraintAddedSignal.emit([row]) 
     567            self.modifyViewOnConstraint(row) 
    531568        self.communicate.statusBarUpdateSignal.emit('Constraint added') 
    532569        pass 
  • src/sas/qtgui/Perspectives/Fitting/MultiConstraint.py

    • Property mode changed from 100755 to 100644
    r7fd20fc r0595bb7  
    22Widget for parameter constraints. 
    33""" 
     4from numpy import * 
     5 
    46from PyQt5 import QtCore 
    57from PyQt5 import QtGui 
     
    2325        self.setupTooltip() 
    2426 
     27        # Set param text control to the second parameter passed 
     28        self.txtConstraint.setText(self.params[1]) 
     29 
    2530        self.cmdOK.clicked.connect(self.accept) 
    2631        self.cmdRevert.clicked.connect(self.revert) 
     32        self.txtConstraint.editingFinished.connect(self.validateFormula) 
    2733 
    2834    def revert(self): 
     
    5258        self.txtConstraint.setToolTip(tooltip) 
    5359 
    54         pass 
     60    def validateFormula(self): 
     61        """ 
     62        Add visual cues when formula is incorrect 
     63        """ 
     64        formula_is_valid = False 
     65        formula_is_valid = self.validateConstraint(self.txtConstraint.text()) 
     66        if not formula_is_valid: 
     67            self.cmdOK.setEnabled(False) 
     68            self.txtConstraint.setStyleSheet("QLineEdit {background-color: red;}") 
     69        else: 
     70            self.cmdOK.setEnabled(True) 
     71            self.txtConstraint.setStyleSheet("QLineEdit {background-color: white;}") 
    5572 
     73    def validateConstraint(self, constraint_text): 
     74        """ 
     75        Ensure the constraint has proper form 
     76        """ 
     77        # 0. none or empty 
     78        if not constraint_text or not isinstance(constraint_text, str): 
     79            return False 
     80 
     81        param_str = str(self.params[1]) 
     82        constraint_text = constraint_text.strip() 
     83 
     84        # 1. just the parameter 
     85        if param_str == constraint_text: 
     86            return True 
     87 
     88        # 2. ensure the text contains parameter name 
     89        parameter_string_start = constraint_text.find(param_str) 
     90        has_parameter_name = (parameter_string_start > -1) 
     91        if not has_parameter_name: 
     92            return False 
     93        parameter_string_end = parameter_string_start + len(param_str) 
     94 
     95        # 3. parameter name should be a separate word, but can have "()[]*+-/" around 
     96        valid_neighbours = "()[]*+-/ " 
     97        has_only_parameter = False 
     98        start_loc = parameter_string_start -1 
     99        end_loc = parameter_string_end 
     100        if not any([constraint_text[start_loc] == char for char in valid_neighbours]): 
     101            return False 
     102        if end_loc < len(constraint_text): 
     103            if not any([constraint_text[end_loc] == char for char in valid_neighbours]): 
     104                return False 
     105 
     106        # 4. replace parameter name with "1" and try to evaluate the expression 
     107        try: 
     108            expression_to_evaluate = constraint_text.replace(param_str, "1.0") 
     109            eval(expression_to_evaluate) 
     110        except Exception: 
     111            # Too many cases to cover individually, just a blanket 
     112            # Exception should be sufficient 
     113            # Note that in current numpy things like sqrt(-1) don't 
     114            # raise but just return warnings 
     115            return False 
     116 
     117        return True 
     118 
     119 
     120 
Note: See TracChangeset for help on using the changeset viewer.