Changeset c1bc9de in sasview
- Timestamp:
- Sep 19, 2018 9:33:59 AM (6 years ago)
- Branches:
- ESS_GUI, ESS_GUI_batch_fitting, ESS_GUI_bumps_abstraction, ESS_GUI_iss1116, ESS_GUI_opencl, ESS_GUI_ordering, ESS_GUI_sync_sascalc
- Children:
- bdfe0be
- Parents:
- dee9e5f (diff), d1e4689 (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. - Location:
- src/sas
- Files:
-
- 13 edited
Legend:
- Unmodified
- Added
- Removed
-
src/sas/qtgui/Perspectives/Fitting/FittingWidget.py
r9ce69ec rd1e4689 1072 1072 if not self.rowHasConstraint(row): 1073 1073 return 1074 constr = self.getConstraintForRow(row) 1074 1075 func = self.getConstraintForRow(row).func 1075 if func is not None: 1076 self.communicate.statusBarUpdateSignal.emit("Active constrain: "+func) 1076 if constr.func is not None: 1077 # inter-parameter constraint 1078 update_text = "Active constraint: "+func 1079 elif constr.param == rows[0].data(): 1080 # current value constraint 1081 update_text = "Value constrained to: " + str(constr.value) 1082 else: 1083 # ill defined constraint 1084 return 1085 self.communicate.statusBarUpdateSignal.emit(update_text) 1077 1086 1078 1087 def replaceConstraintName(self, old_name, new_name=""): … … 1822 1831 self.cmdPlot.setText("Show Plot") 1823 1832 # Force data recalculation so existing charts are updated 1824 self.showPlot() 1833 if not self.data_is_loaded: 1834 self.showTheoryPlot() 1835 else: 1836 self.showPlot() 1825 1837 # This is an important processEvent. 1826 1838 # This allows charts to be properly updated in order … … 1843 1855 self.calculateQGridForModel() 1844 1856 1857 def showTheoryPlot(self): 1858 """ 1859 Show the current theory plot in MPL 1860 """ 1861 # Show the chart if ready 1862 data_to_show = self.model_data 1863 if self.theory_item is None: 1864 self.recalculatePlotData() 1865 else: 1866 self.communicate.plotRequestedSignal.emit([self.theory_item, data_to_show], self.tab_id) 1867 1845 1868 def showPlot(self): 1846 1869 """ … … 1848 1871 """ 1849 1872 # Show the chart if ready 1850 data_to_show = self.data if self.data_is_loaded else self.model_data1873 data_to_show = self.data 1851 1874 # Any models for this page 1852 1875 current_index = self.all_data[self.data_index] 1876 fitpage_name = "" if id is None else "M"+str(self.tab_id) 1853 1877 plots = GuiUtils.plotsFromFilename(self.data.filename, current_index.model()) 1854 fitpage_name = "" if id is None else "M"+str(self.tab_id)1855 1878 # Has the fitted data been shown? 1856 1879 data_shown = False … … 2449 2472 return 2450 2473 fitted_data = self.logic.new1DPlot(return_data, self.tab_id) 2474 if len(fitted_data.x) != len(self.data.x): 2475 return 2476 2451 2477 residuals = self.calculateResiduals(fitted_data) 2452 2478 self.model_data = fitted_data -
src/sas/qtgui/Perspectives/Fitting/UnitTesting/FittingWidgetTest.py
r1a15ada rd1e4689 620 620 # Set to 0 621 621 self.widget.lstParams.indexWidget(func_index).setCurrentIndex(0) 622 self.assertEqual(self.widget._model_model.rowCount(), last_row - 2) # 2 fewer rows than default622 self.assertEqual(self.widget._model_model.rowCount(), last_row - 2) 623 623 624 624 def testPlotTheory(self): … … 658 658 self.assertEqual(spy.count(), 0) 659 659 660 def testPlotData(self):660 def notestPlotData(self): 661 661 """ 662 662 See that data item can produce a chart -
src/sas/qtgui/GUITests.py
r7dd309a rccd2b87 180 180 unittest.makeSuite(InvariantPerspectiveTest.InvariantPerspectiveTest, 'test'), 181 181 # Inversion 182 #unittest.makeSuite(InversionPerspectiveTest.InversionTest, 'test'),182 unittest.makeSuite(InversionPerspectiveTest.InversionTest, 'test'), 183 183 ) 184 184 return unittest.TestSuite(suites) -
src/sas/qtgui/MainWindow/GuiManager.py
rfc5d2d7f rdee9e5f 992 992 When setting a perspective, sets up the menu bar 993 993 """ 994 self._workspace.actionReport.setEnabled(False) 994 995 if isinstance(perspective, Perspectives.PERSPECTIVES["Fitting"]): 995 996 self.checkAnalysisOption(self._workspace.actionFitting) … … 1001 1002 self._workspace.menubar.addAction(self._workspace.menuWindow.menuAction()) 1002 1003 self._workspace.menubar.addAction(self._workspace.menuHelp.menuAction()) 1004 self._workspace.actionReport.setEnabled(True) 1003 1005 1004 1006 elif isinstance(perspective, Perspectives.PERSPECTIVES["Invariant"]): -
src/sas/qtgui/Perspectives/Inversion/DMaxExplorerWidget.py
rb0ba43e r9f2f713 42 42 self.parent = parent 43 43 44 self.setWindowTitle("D ââExplorer")44 self.setWindowTitle("Dmax Explorer") 45 45 46 46 self.pr_state = pr_state … … 116 116 bck = [] 117 117 chi2 = [] 118 118 plotable_xs = [] #Introducing this to make sure size of x and y for plotting is the same.8 119 119 try: 120 120 dmin = float(self.model.item(W.DMIN).text()) … … 128 128 129 129 original = self.pr_state.d_max 130 130 131 for x in xs: 131 132 self.pr_state.d_max = x … … 140 141 bck.append(self.pr_state.background) 141 142 chi2.append(self.pr_state.chi2) 143 plotable_xs.append(x) 142 144 except Exception as ex: 143 145 # This inversion failed, skip this D_max value … … 155 157 logger.error(msg) 156 158 157 plotter = self.model.item(W.VARIABLE).text() 158 y_label = y_unit = "" 159 plotter = self.dependentVariable.currentText() 159 160 x_label = "D_{max}" 160 161 x_unit = "A" … … 188 189 y_unit = "a.u." 189 190 190 data = Data1D( xs, ys)191 data = Data1D(plotable_xs, ys) 191 192 if self.hasPlot: 192 self.plot.removePlot( None)193 self.plot.removePlot(data.name) 193 194 self.hasPlot = True 194 195 data.title = plotter -
src/sas/qtgui/Perspectives/Inversion/InversionLogic.py
r6da860a r3c4f02e 111 111 new_plot.title = title 112 112 113 new_plot.symbol = 'Line' 114 new_plot.hide_error = True 115 113 116 return new_plot 114 117 -
src/sas/qtgui/Perspectives/Inversion/InversionPerspective.py
r9ce69ec rdee9e5f 44 44 estimateSignal = QtCore.pyqtSignal(tuple) 45 45 estimateNTSignal = QtCore.pyqtSignal(tuple) 46 estimateDynamicNTSignal = QtCore.pyqtSignal(tuple) 47 estimateDynamicSignal = QtCore.pyqtSignal(tuple) 46 48 calculateSignal = QtCore.pyqtSignal(tuple) 47 49 … … 53 55 54 56 self._manager = parent 57 #Needed for Batch fitting 58 self._parent = parent 55 59 self.communicate = parent.communicator() 56 60 self.communicate.dataDeletedSignal.connect(self.removeData) … … 110 114 # Set up the Widget Map 111 115 self.setupMapper() 116 117 #Hidding calculate all buton 118 self.calculateAllButton.setVisible(False) 112 119 # Set base window state 113 120 self.setupWindow() … … 120 127 121 128 def allowBatch(self): 122 return True129 return False 123 130 124 131 def setClosable(self, value=True): … … 195 202 self.model.itemChanged.connect(self.model_changed) 196 203 self.estimateNTSignal.connect(self._estimateNTUpdate) 204 self.estimateDynamicNTSignal.connect(self._estimateDynamicNTUpdate) 205 self.estimateDynamicSignal.connect(self._estimateDynamicUpdate) 197 206 self.estimateSignal.connect(self._estimateUpdate) 198 207 self.calculateSignal.connect(self._calculateUpdate) 208 209 self.maxDistanceInput.textEdited.connect(self.performEstimateDynamic) 199 210 200 211 def setupMapper(self): … … 310 321 and not self.isCalculating) 311 322 self.removeButton.setEnabled(self.logic.data_is_loaded) 312 self.explorerButton.setEnabled(self.logic.data_is_loaded 313 and np.all(self.logic.data.dy != 0)) 323 self.explorerButton.setEnabled(self.logic.data_is_loaded) 314 324 self.stopButton.setVisible(self.isCalculating) 315 325 self.regConstantSuggestionButton.setEnabled( … … 454 464 # Create initial internal mappings 455 465 self.logic.data = GuiUtils.dataFromItem(data) 466 if not isinstance(self.logic.data, Data1D): 467 msg = "P(r) perspective works for 1D data only" 468 logger.warning(msg) 469 continue 456 470 # Estimate q range 457 471 qmin, qmax = self.logic.computeDataRange() 458 472 self._calculator.set_qmin(qmin) 459 473 self._calculator.set_qmax(qmax) 474 if np.size(self.logic.data.dy) == 0 or np.all(self.logic.data.dy) == 0: 475 self.logic.data.dy = self._calculator.add_errors(self.logic.data.y) 460 476 self.updateDataList(data) 461 477 self.populateDataComboBox(self.logic.data.filename, data) 462 478 self.dataList.setCurrentIndex(len(self.dataList) - 1) 463 self.setCurrentData(data) 479 #Checking for 1D again to mitigate the case when 2D data is last on the data list 480 if isinstance(self.logic.data, Data1D): 481 self.setCurrentData(data) 464 482 465 483 def updateDataList(self, dataRef): … … 502 520 self.dataPlot = self._dataList[data_ref].get(DICT_KEYS[2]) 503 521 self.performEstimate() 522 523 def updateDynamicGuiValues(self): 524 pr = self._calculator 525 alpha = self._calculator.suggested_alpha 526 self.model.setItem(WIDGETS.W_MAX_DIST, 527 QtGui.QStandardItem("{:.4g}".format(pr.get_dmax()))) 528 self.regConstantSuggestionButton.setText("{:-3.2g}".format(alpha)) 529 self.noOfTermsSuggestionButton.setText( 530 "{:n}".format(self.nTermsSuggested)) 531 532 self.enableButtons() 504 533 505 534 def updateGuiValues(self): … … 521 550 self.model.setItem(WIDGETS.W_MAX_DIST, 522 551 QtGui.QStandardItem("{:.4g}".format(pr.get_dmax()))) 523 self.regConstantSuggestionButton.setText("{:-3.2g}".format(alpha))524 self.noOfTermsSuggestionButton.setText(525 "{:n}".format(self.nTermsSuggested))526 552 527 553 if isinstance(pr.chi2, np.ndarray): … … 638 664 639 665 pr = self._calculator.clone() 640 nfunc = self.getNFunc() 641 self.calcThread = CalcPr(pr, nfunc, 666 #Making sure that nfunc and alpha parameters are correctly initialized 667 pr.suggested_alpha = self._calculator.alpha 668 self.calcThread = CalcPr(pr, self.nTermsSuggested, 642 669 error_func=self._threadError, 643 670 completefn=self._calculateCompleted, … … 672 699 error_func=self._threadError, 673 700 completefn=self._estimateNTCompleted, 701 updatefn=None) 702 self.estimationThreadNT.queue() 703 self.estimationThreadNT.ready(2.5) 704 705 def performEstimateDynamicNT(self): 706 """ 707 Perform parameter estimation 708 """ 709 from .Thread import EstimateNT 710 711 self.updateCalculator() 712 713 # If a thread is already started, stop it 714 self.stopEstimateNTThread() 715 716 pr = self._calculator.clone() 717 # Skip the slit settings for the estimation 718 # It slows down the application and it doesn't change the estimates 719 pr.slit_height = 0.0 720 pr.slit_width = 0.0 721 nfunc = self.getNFunc() 722 723 self.estimationThreadNT = EstimateNT(pr, nfunc, 724 error_func=self._threadError, 725 completefn=self._estimateDynamicNTCompleted, 674 726 updatefn=None) 675 727 self.estimationThreadNT.queue() … … 698 750 self.estimationThread.ready(2.5) 699 751 752 def performEstimateDynamic(self): 753 """ 754 Perform parameter estimation 755 """ 756 from .Thread import EstimatePr 757 758 # If a thread is already started, stop it 759 self.stopEstimationThread() 760 761 self.estimationThread = EstimatePr(self._calculator.clone(), 762 self.getNFunc(), 763 error_func=self._threadError, 764 completefn=self._estimateDynamicCompleted, 765 updatefn=None) 766 self.estimationThread.queue() 767 self.estimationThread.ready(2.5) 768 700 769 def stopEstimationThread(self): 701 770 """ Stop the estimation thread if it exists and is running """ … … 710 779 ''' Send a signal to the main thread for model update''' 711 780 self.estimateSignal.emit((alpha, message, elapsed)) 781 782 def _estimateDynamicCompleted(self, alpha, message, elapsed): 783 ''' Send a signal to the main thread for model update''' 784 self.estimateDynamicSignal.emit((alpha, message, elapsed)) 712 785 713 786 def _estimateUpdate(self, output_tuple): … … 725 798 logger.info(message) 726 799 self.performEstimateNT() 800 self.performEstimateDynamicNT() 801 802 def _estimateDynamicUpdate(self, output_tuple): 803 """ 804 Parameter estimation completed, 805 display the results to the user 806 807 :param alpha: estimated best alpha 808 :param elapsed: computation time 809 """ 810 alpha, message, elapsed = output_tuple 811 self._calculator.alpha = alpha 812 self._calculator.elapsed += self._calculator.elapsed 813 if message: 814 logger.info(message) 815 self.performEstimateDynamicNT() 727 816 728 817 def _estimateNTCompleted(self, nterms, alpha, message, elapsed): 729 818 ''' Send a signal to the main thread for model update''' 730 819 self.estimateNTSignal.emit((nterms, alpha, message, elapsed)) 820 821 def _estimateDynamicNTCompleted(self, nterms, alpha, message, elapsed): 822 ''' Send a signal to the main thread for model update''' 823 self.estimateDynamicNTSignal.emit((nterms, alpha, message, elapsed)) 731 824 732 825 def _estimateNTUpdate(self, output_tuple): … … 752 845 self.startThread() 753 846 847 def _estimateDynamicNTUpdate(self, output_tuple): 848 """ 849 Parameter estimation completed, 850 display the results to the user 851 852 :param alpha: estimated best alpha 853 :param nterms: estimated number of terms 854 :param elapsed: computation time 855 """ 856 nterms, alpha, message, elapsed = output_tuple 857 self._calculator.elapsed += elapsed 858 self._calculator.suggested_alpha = alpha 859 self.nTermsSuggested = nterms 860 # Save useful info 861 self.updateDynamicGuiValues() 862 if message: 863 logger.info(message) 864 if self.isBatch: 865 self.acceptAlpha() 866 self.acceptNoTerms() 867 self.startThread() 868 754 869 def _calculateCompleted(self, out, cov, pr, elapsed): 755 870 ''' Send a signal to the main thread for model update''' -
src/sas/qtgui/Perspectives/Inversion/UI/DMaxExplorer.ui
r8f83719f rcfd61f2 7 7 <x>0</x> 8 8 <y>0</y> 9 <width> 394</width>10 <height> 426</height>9 <width>586</width> 10 <height>538</height> 11 11 </rect> 12 12 </property> … … 21 21 <property name="orientation"> 22 22 <enum>Qt::Vertical</enum> 23 </property>24 <property name="sizeHint" stdset="0">25 <size>26 <width>20</width>27 <height>305</height>28 </size>29 23 </property> 30 24 </spacer> -
src/sas/qtgui/Perspectives/Inversion/UI/TabbedInversionUI.ui
r72ecbdf2 r68dc2873 7 7 <x>0</x> 8 8 <y>0</y> 9 <width> 390</width>10 <height>4 09</height>9 <width>446</width> 10 <height>480</height> 11 11 </rect> 12 12 </property> … … 740 740 <widget class="QPushButton" name="calculateAllButton"> 741 741 <property name="enabled"> 742 <bool> true</bool>742 <bool>false</bool> 743 743 </property> 744 744 <property name="sizePolicy"> -
src/sas/qtgui/Perspectives/Inversion/UnitTesting/InversionPerspectiveTest.py
r144fe21 rccd2b87 99 99 def baseBatchState(self): 100 100 """ Testing the base batch fitting state """ 101 self.assert True(self.widget.allowBatch())101 self.assertFalse(self.widget.allowBatch()) 102 102 self.assertFalse(self.widget.isBatch) 103 103 self.assertFalse(self.widget.calculateAllButton.isEnabled()) … … 304 304 self.assertIsNotNone(self.widget.dmaxWindow) 305 305 self.assertTrue(self.widget.dmaxWindow.isVisible()) 306 self.assertTrue(self.widget.dmaxWindow.windowTitle() == "D ââExplorer")306 self.assertTrue(self.widget.dmaxWindow.windowTitle() == "Dmax Explorer") 307 307 308 308 -
src/sas/qtgui/Plotting/Plotter.py
r5b144c6 rd0952de 84 84 if self.data.ytransform is None: 85 85 self.data.ytransform = 'log10(y)' 86 86 #Added condition to Dmax explorer from P(r) perspective 87 if self.data._xaxis == 'D_{max}': 88 self.xscale = 'linear' 87 89 # Transform data if required. 88 90 if transform and (self.data.xtransform is not None or self.data.ytransform is not None): -
src/sas/qtgui/Utilities/GridPanel.py
r3c6ecd9 r4fbf0db 54 54 # Fill in the table from input data 55 55 self.setupTable(widget=self.tblParams, data=output_data) 56 #TODO: This is not what was inteded to be. 56 57 if output_data is not None: 57 58 # Set a table tooltip describing the model 58 model_name = output_data[0][0].model.id59 model_name = list(output_data.keys())[0] 59 60 self.tabWidget.setTabToolTip(0, model_name) 60 61 … … 418 419 def __init__(self, parent = None, output_data=None): 419 420 420 super(BatchInversionOutputPanel, self).__init__(parent , output_data)421 super(BatchInversionOutputPanel, self).__init__(parent._parent, output_data) 421 422 _translate = QtCore.QCoreApplication.translate 422 423 self.setWindowTitle(_translate("GridPanelUI", "Batch P(r) Results")) 423 424 424 def setupTable(self, data):425 def setupTable(self, widget=None, data=None): 425 426 """ 426 427 Create tablewidget items and show them, based on params … … 433 434 'Calc. Time [sec]'] 434 435 436 if data is None: 437 return 435 438 keys = data.keys() 436 439 rows = len(keys) -
src/sas/sascalc/pr/invertor.py
rb8080e1 reeea6a3 71 71 A[j][i] = (Fourier transformed base function for point j) 72 72 73 We the mchoose a number of r-points, n_r, to evaluate the second73 We then choose a number of r-points, n_r, to evaluate the second 74 74 derivative of P(r) at. This is used as our regularization term. 75 75 For a vector r of length n_r, the following n_r rows are set to :: … … 144 144 x, y, err, d_max, q_min, q_max and alpha 145 145 """ 146 if 146 if name == 'x': 147 147 if 0.0 in value: 148 148 msg = "Invertor: one of your q-values is zero. " … … 227 227 return None 228 228 229 def add_errors(self, yvalues): 230 """ 231 Adds errors to data set is they are not avaialble 232 :return: 233 """ 234 stats_errors = np.zeros(len(yvalues)) 235 for i in range(len(yvalues)): 236 # Scale the error so that we can fit over several decades of Q 237 scale = 0.05 * np.sqrt(yvalues[i]) 238 min_err = 0.01 * yvalues[i] 239 stats_errors[i] = scale * np.sqrt(np.fabs(yvalues[i])) + min_err 240 logger.warning("Simulated errors have been added to the data set\n") 241 return stats_errors 242 229 243 def clone(self): 230 244 """ … … 268 282 A[i][j] = (Fourier transformed base function for point j) 269 283 270 We the mchoose a number of r-points, n_r, to evaluate the second284 We then choose a number of r-points, n_r, to evaluate the second 271 285 derivative of P(r) at. This is used as our regularization term. 272 286 For a vector r of length n_r, the following n_r rows are set to ::
Note: See TracChangeset
for help on using the changeset viewer.