Changeset 0268aed in sasview for src/sas/qtgui/Perspectives/Fitting/FittingWidget.py
- Timestamp:
- Mar 29, 2017 10:02:34 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:
- 7d077d1
- Parents:
- 6fd4e36
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
src/sas/qtgui/Perspectives/Fitting/FittingWidget.py
r6fd4e36 r0268aed 183 183 self.lblStructure.setEnabled(True) 184 184 185 def updateQRange(self): 186 """ 187 Updates Q Range display 188 """ 189 if self.data_is_loaded: 190 self.q_range_min, self.q_range_max, self.npts = self.logic.computeDataRange() 191 # set Q range labels on the main tab 192 self.lblMinRangeDef.setText(str(self.q_range_min)) 193 self.lblMaxRangeDef.setText(str(self.q_range_max)) 194 # set Q range labels on the options tab 195 self.txtMaxRange.setText(str(self.q_range_max)) 196 self.txtMinRange.setText(str(self.q_range_min)) 197 self.txtNpts.setText(str(self.npts)) 185 def togglePoly(self, isChecked): 186 """ 187 Enable/disable the polydispersity tab 188 """ 189 self.tabFitting.setTabEnabled(TAB_POLY, isChecked) 190 191 def toggleMagnetism(self, isChecked): 192 """ 193 Enable/disable the magnetism tab 194 """ 195 self.tabFitting.setTabEnabled(TAB_MAGNETISM, isChecked) 196 197 def toggle2D(self, isChecked): 198 """ 199 Enable/disable the controls dependent on 1D/2D data instance 200 """ 201 self.chkMagnetism.setEnabled(isChecked) 202 self.is2D = isChecked 198 203 199 204 def initializeControls(self): … … 242 247 #self._magnet_model.itemChanged.connect(self.onMagneticModelChange) 243 248 244 def setDefaultStructureCombo(self): 245 """ 246 Fill in the structure factors combo box with defaults 247 """ 248 structure_factor_list = self.master_category_dict.pop(CATEGORY_STRUCTURE) 249 factors = [factor[0] for factor in structure_factor_list] 250 factors.insert(0, STRUCTURE_DEFAULT) 251 self.cbStructureFactor.clear() 252 self.cbStructureFactor.addItems(sorted(factors)) 249 def onSelectModel(self): 250 """ 251 Respond to select Model from list event 252 """ 253 model = str(self.cbModel.currentText()) 254 255 # Reset structure factor 256 self.cbStructureFactor.setCurrentIndex(0) 257 258 # SasModel -> QModel 259 self.SASModelToQModel(model) 260 261 if self.data_is_loaded: 262 self.calculateQGridForModel() 263 else: 264 # Create default datasets if no data passed 265 self.createDefaultDataset() 266 267 def onSelectStructureFactor(self): 268 """ 269 Select Structure Factor from list 270 """ 271 model = str(self.cbModel.currentText()) 272 category = str(self.cbCategory.currentText()) 273 structure = str(self.cbStructureFactor.currentText()) 274 if category == CATEGORY_STRUCTURE: 275 model = None 276 self.SASModelToQModel(model, structure_factor=structure) 253 277 254 278 def onSelectCategory(self): … … 287 311 # Populate the models combobox 288 312 self.cbModel.addItems(sorted([model for (model, _) in model_list])) 289 290 def createDefaultDataset(self):291 """292 Generate default Dataset 1D/2D for the given model293 """294 # Create default datasets if no data passed295 if self.is2D:296 qmax = self.q_range_max/numpy.sqrt(2)297 qstep = self.npts298 self.logic.createDefault2dData(qmax, qstep, self.tab_id)299 else:300 interval = numpy.linspace(start=self.q_range_min, stop=self.q_range_max,301 num=self.npts, endpoint=True)302 self.logic.createDefault1dData(interval, self.tab_id)303 304 def onSelectModel(self):305 """306 Respond to select Model from list event307 """308 model = str(self.cbModel.currentText())309 310 # Reset structure factor311 self.cbStructureFactor.setCurrentIndex(0)312 313 # SasModel -> QModel314 self.SASModelToQModel(model)315 316 if self.data_is_loaded:317 self.calculateQGridForModel()318 else:319 # Create default datasets if no data passed320 self.createDefaultDataset()321 322 def onSelectStructureFactor(self):323 """324 Select Structure Factor from list325 """326 model = str(self.cbModel.currentText())327 category = str(self.cbCategory.currentText())328 structure = str(self.cbStructureFactor.currentText())329 if category == CATEGORY_STRUCTURE:330 model = None331 self.SASModelToQModel(model, structure_factor=structure)332 333 def readCategoryInfo(self):334 """335 Reads the categories in from file336 """337 self.master_category_dict = defaultdict(list)338 self.by_model_dict = defaultdict(list)339 self.model_enabled_dict = defaultdict(bool)340 341 categorization_file = CategoryInstaller.get_user_file()342 if not os.path.isfile(categorization_file):343 categorization_file = CategoryInstaller.get_default_file()344 with open(categorization_file, 'rb') as cat_file:345 self.master_category_dict = json.load(cat_file)346 self.regenerateModelDict()347 348 # Load the model dict349 models = load_standard_models()350 for model in models:351 self.models[model.name] = model352 353 def regenerateModelDict(self):354 """355 Regenerates self.by_model_dict which has each model name as the356 key and the list of categories belonging to that model357 along with the enabled mapping358 """359 self.by_model_dict = defaultdict(list)360 for category in self.master_category_dict:361 for (model, enabled) in self.master_category_dict[category]:362 self.by_model_dict[model].append(category)363 self.model_enabled_dict[model] = enabled364 365 def addBackgroundToModel(self, model):366 """367 Adds background parameter with default values to the model368 """369 assert isinstance(model, QtGui.QStandardItemModel)370 checked_list = ['background', '0.001', '-inf', 'inf', '1/cm']371 FittingUtilities.addCheckedListToModel(model, checked_list)372 373 def addScaleToModel(self, model):374 """375 Adds scale parameter with default values to the model376 """377 assert isinstance(model, QtGui.QStandardItemModel)378 checked_list = ['scale', '1.0', '0.0', 'inf', '']379 FittingUtilities.addCheckedListToModel(model, checked_list)380 381 def SASModelToQModel(self, model_name, structure_factor=None):382 """383 Setting model parameters into table based on selected category384 """385 # TODO - modify for structure factor-only choice386 387 # Crete/overwrite model items388 self._model_model.clear()389 390 kernel_module = generate.load_kernel_module(model_name)391 self.model_parameters = modelinfo.make_parameter_table(getattr(kernel_module, 'parameters', []))392 393 # Instantiate the current sasmodel394 self.kernel_module = self.models[model_name]()395 396 # Explicitly add scale and background with default values397 self.addScaleToModel(self._model_model)398 self.addBackgroundToModel(self._model_model)399 400 # Update the QModel401 FittingUtilities.addParametersToModel(self.model_parameters, self._model_model)402 # Update the counter used for multishell display403 self._last_model_row = self._model_model.rowCount()404 405 FittingUtilities.addHeadersToModel(self._model_model)406 407 # Add structure factor408 if structure_factor is not None and structure_factor != "None":409 structure_module = generate.load_kernel_module(structure_factor)410 structure_parameters = modelinfo.make_parameter_table(getattr(structure_module, 'parameters', []))411 FittingUtilities.addSimpleParametersToModel(structure_parameters, self._model_model)412 # Update the counter used for multishell display413 self._last_model_row = self._model_model.rowCount()414 else:415 self.addStructureFactor()416 417 # Multishell models need additional treatment418 self.addExtraShells()419 420 # Add polydispersity to the model421 self.setPolyModel()422 # Add magnetic parameters to the model423 self.setMagneticModel()424 425 # Adjust the table cells width426 self.lstParams.resizeColumnToContents(0)427 self.lstParams.setSizePolicy(QtGui.QSizePolicy.MinimumExpanding, QtGui.QSizePolicy.Expanding)428 429 # Now we claim the model has been loaded430 self.model_is_loaded = True431 432 # Update Q Ranges433 self.updateQRange()434 313 435 314 def onPolyModelChange(self, item): … … 467 346 pass # debug anchor 468 347 469 def updateParamsFromModel(self, item):470 """471 Callback method for updating the sasmodel parameters with the GUI values472 """473 model_column = item.column()474 model_row = item.row()475 name_index = self._model_model.index(model_row, 0)476 477 if model_column == 0:478 # Assure we're dealing with checkboxes479 if not item.isCheckable():480 return481 status = item.checkState()482 # If multiple rows selected - toggle all of them483 rows = [s.row() for s in self.lstParams.selectionModel().selectedRows()]484 485 # Switch off signaling from the model to avoid multiple calls486 self._model_model.blockSignals(True)487 # Convert to proper indices and set requested enablement488 items = [self._model_model.item(row, 0).setCheckState(status) for row in rows]489 self._model_model.blockSignals(False)490 return491 492 # Extract changed value. Assumes proper validation by QValidator/Delegate493 value = float(item.text())494 parameter_name = str(self._model_model.data(name_index).toPyObject()) # sld, background etc.495 property_name = str(self._model_model.headerData(1, model_column).toPyObject()) # Value, min, max, etc.496 497 # print "%s(%s) => %d" % (parameter_name, property_name, value)498 self.kernel_module.params[parameter_name] = value499 500 # min/max to be changed in self.kernel_module.details[parameter_name] = ['Ang', 0.0, inf]501 502 # magnetic params in self.kernel_module.details['M0:parameter_name'] = value503 # multishell params in self.kernel_module.details[??] = value504 505 def nameForFittedData(self, name):506 """507 Generate name for the current fit508 """509 if self.is2D:510 name += "2d"511 name = "M%i [%s]" % (self.tab_id, name)512 return name513 514 def createNewIndex(self, fitted_data):515 """516 Create a model or theory index with passed Data1D/Data2D517 """518 if self.data_is_loaded:519 self.updateModelIndex(fitted_data)520 else:521 self.createTheoryIndex(fitted_data)522 523 def updateModelIndex(self, fitted_data):524 """525 Update a QStandardModelIndex containing model data526 """527 name = self.nameForFittedData(self.logic.data.filename)528 fitted_data.title = name529 fitted_data.name = name530 # Make this a line531 fitted_data.symbol = 'Line'532 # Notify the GUI manager so it can update the main model in DataExplorer533 GuiUtils.updateModelItemWithPlot(self._index, QtCore.QVariant(fitted_data), name)534 535 def createTheoryIndex(self, fitted_data):536 """537 Create a QStandardModelIndex containing model data538 """539 name = self.nameForFittedData(self.kernel_module.name)540 fitted_data.title = name541 fitted_data.name = name542 fitted_data.filename = name543 # Notify the GUI manager so it can create the theory model in DataExplorer544 new_item = GuiUtils.createModelItemWithPlot(QtCore.QVariant(fitted_data), name=name)545 self.communicate.updateTheoryFromPerspectiveSignal.emit(new_item)546 547 348 def onFit(self): 548 349 """ … … 551 352 # TODO: everything here 552 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 553 362 pass 554 363 … … 600 409 # set Q range labels on the main tab 601 410 self.lblMaxRangeDef.setText(str(self.q_range_max)) 411 412 def setDefaultStructureCombo(self): 413 """ 414 Fill in the structure factors combo box with defaults 415 """ 416 structure_factor_list = self.master_category_dict.pop(CATEGORY_STRUCTURE) 417 factors = [factor[0] for factor in structure_factor_list] 418 factors.insert(0, STRUCTURE_DEFAULT) 419 self.cbStructureFactor.clear() 420 self.cbStructureFactor.addItems(sorted(factors)) 421 422 def createDefaultDataset(self): 423 """ 424 Generate default Dataset 1D/2D for the given model 425 """ 426 # Create default datasets if no data passed 427 if self.is2D: 428 qmax = self.q_range_max/numpy.sqrt(2) 429 qstep = self.npts 430 self.logic.createDefault2dData(qmax, qstep, self.tab_id) 431 else: 432 interval = numpy.linspace(start=self.q_range_min, stop=self.q_range_max, 433 num=self.npts, endpoint=True) 434 self.logic.createDefault1dData(interval, self.tab_id) 435 436 def readCategoryInfo(self): 437 """ 438 Reads the categories in from file 439 """ 440 self.master_category_dict = defaultdict(list) 441 self.by_model_dict = defaultdict(list) 442 self.model_enabled_dict = defaultdict(bool) 443 444 categorization_file = CategoryInstaller.get_user_file() 445 if not os.path.isfile(categorization_file): 446 categorization_file = CategoryInstaller.get_default_file() 447 with open(categorization_file, 'rb') as cat_file: 448 self.master_category_dict = json.load(cat_file) 449 self.regenerateModelDict() 450 451 # Load the model dict 452 models = load_standard_models() 453 for model in models: 454 self.models[model.name] = model 455 456 def regenerateModelDict(self): 457 """ 458 Regenerates self.by_model_dict which has each model name as the 459 key and the list of categories belonging to that model 460 along with the enabled mapping 461 """ 462 self.by_model_dict = defaultdict(list) 463 for category in self.master_category_dict: 464 for (model, enabled) in self.master_category_dict[category]: 465 self.by_model_dict[model].append(category) 466 self.model_enabled_dict[model] = enabled 467 468 def addBackgroundToModel(self, model): 469 """ 470 Adds background parameter with default values to the model 471 """ 472 assert isinstance(model, QtGui.QStandardItemModel) 473 checked_list = ['background', '0.001', '-inf', 'inf', '1/cm'] 474 FittingUtilities.addCheckedListToModel(model, checked_list) 475 476 def addScaleToModel(self, model): 477 """ 478 Adds scale parameter with default values to the model 479 """ 480 assert isinstance(model, QtGui.QStandardItemModel) 481 checked_list = ['scale', '1.0', '0.0', 'inf', ''] 482 FittingUtilities.addCheckedListToModel(model, checked_list) 483 484 def updateQRange(self): 485 """ 486 Updates Q Range display 487 """ 488 if self.data_is_loaded: 489 self.q_range_min, self.q_range_max, self.npts = self.logic.computeDataRange() 490 # set Q range labels on the main tab 491 self.lblMinRangeDef.setText(str(self.q_range_min)) 492 self.lblMaxRangeDef.setText(str(self.q_range_max)) 493 # set Q range labels on the options tab 494 self.txtMaxRange.setText(str(self.q_range_max)) 495 self.txtMinRange.setText(str(self.q_range_min)) 496 self.txtNpts.setText(str(self.npts)) 497 498 def SASModelToQModel(self, model_name, structure_factor=None): 499 """ 500 Setting model parameters into table based on selected category 501 """ 502 # TODO - modify for structure factor-only choice 503 504 # Crete/overwrite model items 505 self._model_model.clear() 506 507 kernel_module = generate.load_kernel_module(model_name) 508 self.model_parameters = modelinfo.make_parameter_table(getattr(kernel_module, 'parameters', [])) 509 510 # Instantiate the current sasmodel 511 self.kernel_module = self.models[model_name]() 512 513 # Explicitly add scale and background with default values 514 self.addScaleToModel(self._model_model) 515 self.addBackgroundToModel(self._model_model) 516 517 # Update the QModel 518 FittingUtilities.addParametersToModel(self.model_parameters, self._model_model) 519 # Update the counter used for multishell display 520 self._last_model_row = self._model_model.rowCount() 521 522 FittingUtilities.addHeadersToModel(self._model_model) 523 524 # Add structure factor 525 if structure_factor is not None and structure_factor != "None": 526 structure_module = generate.load_kernel_module(structure_factor) 527 structure_parameters = modelinfo.make_parameter_table(getattr(structure_module, 'parameters', [])) 528 FittingUtilities.addSimpleParametersToModel(structure_parameters, self._model_model) 529 # Update the counter used for multishell display 530 self._last_model_row = self._model_model.rowCount() 531 else: 532 self.addStructureFactor() 533 534 # Multishell models need additional treatment 535 self.addExtraShells() 536 537 # Add polydispersity to the model 538 self.setPolyModel() 539 # Add magnetic parameters to the model 540 self.setMagneticModel() 541 542 # Adjust the table cells width 543 self.lstParams.resizeColumnToContents(0) 544 self.lstParams.setSizePolicy(QtGui.QSizePolicy.MinimumExpanding, QtGui.QSizePolicy.Expanding) 545 546 # Now we claim the model has been loaded 547 self.model_is_loaded = True 548 549 # Update Q Ranges 550 self.updateQRange() 551 552 def updateParamsFromModel(self, item): 553 """ 554 Callback method for updating the sasmodel parameters with the GUI values 555 """ 556 model_column = item.column() 557 model_row = item.row() 558 name_index = self._model_model.index(model_row, 0) 559 560 if model_column == 0: 561 # Assure we're dealing with checkboxes 562 if not item.isCheckable(): 563 return 564 status = item.checkState() 565 # If multiple rows selected - toggle all of them 566 rows = [s.row() for s in self.lstParams.selectionModel().selectedRows()] 567 568 # Switch off signaling from the model to avoid multiple calls 569 self._model_model.blockSignals(True) 570 # Convert to proper indices and set requested enablement 571 items = [self._model_model.item(row, 0).setCheckState(status) for row in rows] 572 self._model_model.blockSignals(False) 573 return 574 575 # Extract changed value. Assumes proper validation by QValidator/Delegate 576 value = float(item.text()) 577 parameter_name = str(self._model_model.data(name_index).toPyObject()) # sld, background etc. 578 property_name = str(self._model_model.headerData(1, model_column).toPyObject()) # Value, min, max, etc. 579 580 # print "%s(%s) => %d" % (parameter_name, property_name, value) 581 self.kernel_module.params[parameter_name] = value 582 583 # min/max to be changed in self.kernel_module.details[parameter_name] = ['Ang', 0.0, inf] 584 585 # magnetic params in self.kernel_module.details['M0:parameter_name'] = value 586 # multishell params in self.kernel_module.details[??] = value 587 588 def nameForFittedData(self, name): 589 """ 590 Generate name for the current fit 591 """ 592 if self.is2D: 593 name += "2d" 594 name = "M%i [%s]" % (self.tab_id, name) 595 return name 596 597 def createNewIndex(self, fitted_data): 598 """ 599 Create a model or theory index with passed Data1D/Data2D 600 """ 601 if self.data_is_loaded: 602 if not fitted_data.name: 603 name = self.nameForFittedData(self.data.filename) 604 fitted_data.title = name 605 fitted_data.name = name 606 fitted_data.filename = name 607 self.updateModelIndex(fitted_data) 608 else: 609 name = self.nameForFittedData(self.kernel_module.name) 610 fitted_data.title = name 611 fitted_data.name = name 612 fitted_data.filename = name 613 fitted_data.symbol = "Line" 614 self.createTheoryIndex(fitted_data) 615 616 def updateModelIndex(self, fitted_data): 617 """ 618 Update a QStandardModelIndex containing model data 619 """ 620 if fitted_data.name is None: 621 name = self.nameForFittedData(self.logic.data.filename) 622 fitted_data.title = name 623 fitted_data.name = name 624 else: 625 name = fitted_data.name 626 # Make this a line if no other defined 627 if fitted_data.symbol is None: 628 fitted_data.symbol = 'Line' 629 # Notify the GUI manager so it can update the main model in DataExplorer 630 GuiUtils.updateModelItemWithPlot(self._index, QtCore.QVariant(fitted_data), name) 631 632 def createTheoryIndex(self, fitted_data): 633 """ 634 Create a QStandardModelIndex containing model data 635 """ 636 if fitted_data.name is None: 637 name = self.nameForFittedData(self.kernel_module.name) 638 fitted_data.title = name 639 fitted_data.name = name 640 fitted_data.filename = name 641 else: 642 name = fitted_data.name 643 # Notify the GUI manager so it can create the theory model in DataExplorer 644 new_item = GuiUtils.createModelItemWithPlot(QtCore.QVariant(fitted_data), name=name) 645 self.communicate.updateTheoryFromPerspectiveSignal.emit(new_item) 602 646 603 647 def methodCalculateForData(self): … … 636 680 Plot the current 1D data 637 681 """ 638 fitted_ data= self.logic.new1DPlot(return_data)639 self.calculateResiduals( self.logic.new1DPlot(return_data))682 fitted_plot = self.logic.new1DPlot(return_data) 683 self.calculateResiduals(fitted_plot) 640 684 641 685 def complete2D(self, return_data): … … 657 701 self.lblChi2Value.setText(GuiUtils.formatNumber(chi2, high=True)) 658 702 659 # TODO: plot residuals660 #self._plot_residuals(page_id=page_id, data=current_data,661 # fid=fid,662 # weight=weight, index=index)703 # Plot residuals if actual data 704 if self.data_is_loaded: 705 residuals_plot = FittingUtilities.plotResiduals(self.data, fitted_data) 706 self.createNewIndex(residuals_plot) 663 707 664 708 def calcException(self, etype, value, tb): … … 790 834 self.current_shell_displayed = index 791 835 792 def togglePoly(self, isChecked):793 """794 Enable/disable the polydispersity tab795 """796 self.tabFitting.setTabEnabled(TAB_POLY, isChecked)797 798 def toggleMagnetism(self, isChecked):799 """800 Enable/disable the magnetism tab801 """802 self.tabFitting.setTabEnabled(TAB_MAGNETISM, isChecked)803 804 def toggle2D(self, isChecked):805 """806 Enable/disable the controls dependent on 1D/2D data instance807 """808 self.chkMagnetism.setEnabled(isChecked)809 self.is2D = isChecked810
Note: See TracChangeset
for help on using the changeset viewer.