Changeset f182f93 in sasview for src/sas/qtgui/Perspectives/Fitting
- Timestamp:
- Apr 5, 2017 10:44:27 AM (8 years ago)
- 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:
- 454670d
- Parents:
- 116260a
- Location:
- src/sas/qtgui/Perspectives/Fitting
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
src/sas/qtgui/Perspectives/Fitting/FittingUtilities.py
r7d077d1 rf182f93 55 55 item1 = QtGui.QStandardItem(item_name) 56 56 item1.setCheckable(True) 57 item_err = QtGui.QStandardItem() 57 58 # check for polydisp params 58 59 if param.polydisperse: … … 94 95 # TODO: the error column. 95 96 # Either add a proxy model or a custom view delegate 96 #item_err = QtGui.QStandardItem()97 item 3= QtGui.QStandardItem(str(param.limits[0]))98 item 4= QtGui.QStandardItem(str(param.limits[1]))99 item 5= QtGui.QStandardItem(param.units)100 model.appendRow([item1, item2, item 3, item4, item5])97 item_err = QtGui.QStandardItem() 98 item4 = QtGui.QStandardItem(str(param.limits[0])) 99 item5 = QtGui.QStandardItem(str(param.limits[1])) 100 item6 = QtGui.QStandardItem(param.units) 101 model.appendRow([item1, item2, item4, item5, item6]) 101 102 102 103 def addCheckedListToModel(model, param_list): … … 118 119 model.setHeaderData(3, QtCore.Qt.Horizontal, QtCore.QVariant("Max")) 119 120 model.setHeaderData(4, QtCore.Qt.Horizontal, QtCore.QVariant("[Units]")) 121 122 def addErrorHeadersToModel(model): 123 """ 124 Adds predefined headers to the model 125 """ 126 model.setHeaderData(0, QtCore.Qt.Horizontal, QtCore.QVariant("Parameter")) 127 model.setHeaderData(1, QtCore.Qt.Horizontal, QtCore.QVariant("Value")) 128 model.setHeaderData(2, QtCore.Qt.Horizontal, QtCore.QVariant("Error")) 129 model.setHeaderData(3, QtCore.Qt.Horizontal, QtCore.QVariant("Min")) 130 model.setHeaderData(4, QtCore.Qt.Horizontal, QtCore.QVariant("Max")) 131 model.setHeaderData(5, QtCore.Qt.Horizontal, QtCore.QVariant("[Units]")) 120 132 121 133 def addPolyHeadersToModel(model): … … 316 328 str(reference_data.filename) + "]" 317 329 residuals.title = residuals.name 330 residuals.ytransform = 'y' 331 318 332 # when 2 data have the same id override the 1 st plotted 319 333 # include the last part if keeping charts for separate models is required -
src/sas/qtgui/Perspectives/Fitting/FittingWidget.py
r9f25bce rf182f93 15 15 from sasmodels import modelinfo 16 16 from sasmodels.sasview_model import load_standard_models 17 from sas.sascalc.fit.BumpsFitting import BumpsFit as Fit 18 from sas.sasgui.perspectives.fitting.fit_thread import FitThread 17 19 18 20 from sas.sasgui.guiframe.CategoryInstaller import CategoryInstaller … … 62 64 # Dictionary of {model name: model class} for the current category 63 65 self.models = {} 66 # Parameters to fit 67 self.parameters_to_fit = None 64 68 65 69 # Which tab is this widget displayed in? … … 68 72 # Which shell is being currently displayed? 69 73 self.current_shell_displayed = 0 74 self.has_error_column = False 70 75 71 76 # Range parameters … … 256 261 self.cbStructureFactor.setCurrentIndex(0) 257 262 263 # Reset parameters to fit 264 self.parameters_to_fit = None 265 258 266 # SasModel -> QModel 259 267 self.SASModelToQModel(model) … … 350 358 Perform fitting on the current data 351 359 """ 352 # TODO: everything here 353 #self.calculate1DForModel() 354 #calc_fit = FitThread(handler=handler, 355 # fn=fitter_list, 356 # batch_inputs=batch_inputs, 357 # batch_outputs=batch_outputs, 358 # page_id=list_page_id, 359 # updatefn=handler.update_fit, 360 # completefn=self._fit_completed) 361 360 fitter = Fit() 361 362 # Data going in 363 data = self.logic.data 364 model = self.kernel_module 365 qmin = self.q_range_min 366 qmax = self.q_range_max 367 params_to_fit = self.parameters_to_fit 368 369 # These should be updating somehow? 370 fit_id = 0 371 constraints = [] 372 smearer = None 373 page_id = [210] 374 handler = None 375 batch_inputs = {} 376 batch_outputs = {} 377 list_page_id = [page_id] 378 #--------------------------------- 379 380 # Parameterize the fitter 381 fitter.set_model(model, fit_id, params_to_fit, data=data, 382 constraints=constraints) 383 fitter.set_data(data=data, id=fit_id, smearer=smearer, qmin=qmin, 384 qmax=qmax) 385 fitter.select_problem_for_fit(id=fit_id, value=1) 386 387 fitter.fitter_id = page_id 388 389 # Create the fitting thread, based on the fitter 390 calc_fit = FitThread(handler=handler, 391 fn=[fitter], 392 batch_inputs=batch_inputs, 393 batch_outputs=batch_outputs, 394 page_id=list_page_id, 395 updatefn=self.updateFit, 396 completefn=None) 397 398 # start the trhrhread 399 calc_thread = threads.deferToThread(calc_fit.compute) 400 calc_thread.addCallback(self.fitComplete) 401 402 #disable the Fit button 403 self.cmdFit.setText("Calculating...") 404 self.cmdFit.setEnabled(False) 405 406 def updateFit(self): 407 """ 408 """ 409 print "UPDATE FIT" 362 410 pass 411 412 def fitComplete(self, result): 413 """ 414 Receive and display fitting results 415 416 "result" is a tuple of actual result list and the fit time in seconds 417 """ 418 #re-enable the Fit button 419 self.cmdFit.setText("Fit") 420 self.cmdFit.setEnabled(True) 421 res_list = result[0] 422 res = res_list[0] 423 if res.fitness is None or \ 424 not numpy.isfinite(res.fitness) or \ 425 numpy.any(res.pvec == None) or \ 426 not numpy.all(numpy.isfinite(res.pvec)): 427 msg = "Fitting did not converge!!!" 428 logging.error(msg) 429 return 430 431 elapsed = result[1] 432 msg = "Fitting completed successfully in: %s s.\n" % GuiUtils.formatNumber(elapsed) 433 434 self.communicate.statusBarUpdateSignal.emit(msg) 435 436 fitness = res.fitness 437 param_list = res.param_list 438 param_values = res.pvec 439 param_stderr = res.stderr 440 from itertools import izip 441 # TODO: add errors to the dict so they can propagate to the view 442 params_and_errors = zip(param_values, param_stderr) 443 param_dict = dict(izip(param_list, params_and_errors)) 444 445 # Dictionary of fitted parameter: value, error 446 # e.g. param_dic = {"sld":(1.703, 0.0034), "length":(33.455, -0.0983)} 447 self.updateModelFromList(param_dict) 448 449 # Read only value - we can get away by just printing it here 450 chi2_repr = GuiUtils.formatNumber(fitness, high=True) 451 self.lblChi2Value.setText(chi2_repr) 452 453 pass 454 455 def iterateOverModel(self, func): 456 """ 457 Take func and throw it inside the model row loop 458 """ 459 #assert isinstance(func, function) 460 for row_i in xrange(self._model_model.rowCount()): 461 func(row_i) 462 463 def updateModelFromList(self, param_dict): 464 """ 465 Update the model with new parameters, create the errors column 466 """ 467 assert isinstance(param_dict, dict) 468 if not dict: 469 return 470 471 def updateValues(row_i): 472 # Utility function for main model update 473 param_name = str(self._model_model.item(row_i, 0).text()) 474 if param_name not in param_dict.keys(): 475 return 476 # modify the param value 477 self._model_model.item(row_i, 1).setText(str(param_dict[param_name][0])) 478 if self.has_error_column: 479 self._model_model.item(row_i, 2).setText(str(param_dict[param_name][1])) 480 481 def createColumn(row_i): 482 # Utility function for error column update 483 item = QtGui.QStandardItem() 484 for param_name in param_dict.keys(): 485 if str(self._model_model.item(row_i, 0).text()) != param_name: 486 continue 487 error_repr = GuiUtils.formatNumber(param_dict[param_name][1], high=True) 488 item.setText(error_repr) 489 error_column.append(item) 490 491 self.iterateOverModel(updateValues) 492 493 if self.has_error_column: 494 return 495 496 error_column = [] 497 self.iterateOverModel(createColumn) 498 499 self.has_error_column = True 500 self._model_model.insertColumn(2, error_column) 501 FittingUtilities.addErrorHeadersToModel(self._model_model) 502 363 503 364 504 def onPlot(self): … … 370 510 self.calculateQGridForModel() 371 511 372 #def onNpts(self, text):373 512 def onNpts(self): 374 513 """ … … 387 526 self.onPlot() 388 527 389 #def onMinRange(self, text):390 528 def onMinRange(self): 391 529 """ … … 405 543 self.onPlot() 406 544 407 #def onMaxRange(self, text):408 545 def onMaxRange(self): 409 546 """ … … 537 674 structure_parameters = modelinfo.make_parameter_table(getattr(structure_module, 'parameters', [])) 538 675 FittingUtilities.addSimpleParametersToModel(structure_parameters, self._model_model) 676 # Set the error column width to 0 677 self.lstParams.setColumnWidth(2, 20) 539 678 # Update the counter used for multishell display 540 679 self._last_model_row = self._model_model.rowCount() … … 565 704 """ 566 705 model_column = item.column() 706 707 if model_column == 0: 708 self.checkboxSelected(item) 709 return 710 567 711 model_row = item.row() 568 712 name_index = self._model_model.index(model_row, 0) 569 570 if model_column == 0:571 # Assure we're dealing with checkboxes572 if not item.isCheckable():573 return574 status = item.checkState()575 # If multiple rows selected - toggle all of them576 rows = [s.row() for s in self.lstParams.selectionModel().selectedRows()]577 578 # Switch off signaling from the model to avoid multiple calls579 self._model_model.blockSignals(True)580 # Convert to proper indices and set requested enablement581 items = [self._model_model.item(row, 0).setCheckState(status) for row in rows]582 self._model_model.blockSignals(False)583 return584 713 585 714 # Extract changed value. Assumes proper validation by QValidator/Delegate … … 588 717 property_name = str(self._model_model.headerData(1, model_column).toPyObject()) # Value, min, max, etc. 589 718 590 # print "%s(%s) => %d" % (parameter_name, property_name, value)591 719 self.kernel_module.params[parameter_name] = value 592 720 593 721 # min/max to be changed in self.kernel_module.details[parameter_name] = ['Ang', 0.0, inf] 594 595 722 # magnetic params in self.kernel_module.details['M0:parameter_name'] = value 596 723 # multishell params in self.kernel_module.details[??] = value … … 598 725 # Force the chart update 599 726 self.onPlot() 727 728 def checkboxSelected(self, item): 729 # Assure we're dealing with checkboxes 730 if not item.isCheckable(): 731 return 732 status = item.checkState() 733 734 def isChecked(row): 735 return self._model_model.item(row, 0).checkState() == QtCore.Qt.Checked 736 737 def isCheckable(row): 738 return self._model_model.item(row, 0).isCheckable() 739 740 # If multiple rows selected - toggle all of them, filtering uncheckable 741 rows = [s.row() for s in self.lstParams.selectionModel().selectedRows() if isCheckable(s.row())] 742 743 # Switch off signaling from the model to avoid recursion 744 self._model_model.blockSignals(True) 745 # Convert to proper indices and set requested enablement 746 items = [self._model_model.item(row, 0).setCheckState(status) for row in rows] 747 self._model_model.blockSignals(False) 748 749 # update the list of parameters to fit 750 self.parameters_to_fit = [str(self._model_model.item(row_index, 0).text()) 751 for row_index in xrange(self._model_model.rowCount()) 752 if isChecked(row_index)] 600 753 601 754 def nameForFittedData(self, name): … … 714 867 chi2 = FittingUtilities.calculateChi2(fitted_data, self.logic.data) 715 868 # Update the control 716 self.lblChi2Value.setText(GuiUtils.formatNumber(chi2, high=True)) 869 chi2_repr = "---" if chi2 is None else GuiUtils.formatNumber(chi2, high=True) 870 #self.lblChi2Value.setText(GuiUtils.formatNumber(chi2, high=True)) 871 self.lblChi2Value.setText(chi2_repr) 717 872 718 873 # Plot residuals if actual data -
src/sas/qtgui/Perspectives/Fitting/UI/FittingWidgetUI.ui
rb1e36a3 rf182f93 432 432 <string>None</string> 433 433 </property> 434 <property name="checked"> 435 <bool>true</bool> 436 </property> 434 437 </widget> 435 438 </item> … … 489 492 <widget class="QComboBox" name="comboBox_4"> 490 493 <property name="currentIndex"> 491 <number> 2</number>494 <number>0</number> 492 495 </property> 493 496 <item>
Note: See TracChangeset
for help on using the changeset viewer.