Changeset b01ac8f in sasview for src/sas/sasgui/perspectives
- Timestamp:
- Sep 16, 2017 8:26:13 PM (7 years ago)
- Branches:
- master, 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, costrafo411, magnetic_scatt, release-4.2.2, ticket-1009, ticket-1094-headless, ticket-1242-2d-resolution, ticket-1243, ticket-1249, ticket885, unittest-saveload
- Children:
- 7b15990
- Parents:
- a6ee176 (diff), ca383a0 (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/sasgui/perspectives
- Files:
-
- 3 added
- 15 edited
Legend:
- Unmodified
- Added
- Removed
-
src/sas/sasgui/perspectives/calculator/model_editor.py
ra1b8fee r23359ccb 106 106 self.model2_string = "cylinder" 107 107 self.name = 'Sum' + M_NAME 108 self.factor = 'scale_factor'109 108 self._notes = '' 110 109 self._operator = '+' … … 133 132 self.model2_name = str(self.model2.GetValue()) 134 133 self.good_name = True 135 self.fill_op rator_combox()134 self.fill_operator_combox() 136 135 137 136 def _layout_name(self): … … 491 490 a sum or multiply model then create the appropriate string 492 491 """ 493 494 492 name = '' 495 496 493 if operator == '*': 497 494 name = 'Multi' 498 factor = 'BackGround' 499 f_oper = '+' 495 factor = 'background' 500 496 else: 501 497 name = 'Sum' 502 498 factor = 'scale_factor' 503 f_oper = '*' 504 505 self.factor = factor 499 506 500 self._operator = operator 507 self.explanation = " Plugin Model = %s %s (model1 %s model2)\n" % \508 (self.factor, f_oper, self._operator)501 self.explanation = (" Plugin_model = scale_factor * (model_1 {} " 502 "model_2) + background").format(operator) 509 503 self.explanationctr.SetLabel(self.explanation) 510 504 self.name = name + M_NAME 511 505 512 506 513 def fill_op rator_combox(self):507 def fill_operator_combox(self): 514 508 """ 515 509 fill the current combobox with the operator … … 527 521 return [self.model1_name, self.model2_name] 528 522 529 def write_string(self, fname, name1, name2):523 def write_string(self, fname, model1_name, model2_name): 530 524 """ 531 525 Write and Save file … … 533 527 self.fname = fname 534 528 description = self.desc_tcl.GetValue().lstrip().rstrip() 535 if description == '': 536 description = name1 + self._operator + name2 537 text = self._operator_choice.GetValue() 538 if text.count('+') > 0: 539 factor = 'scale_factor' 540 f_oper = '*' 541 default_val = '1.0' 542 else: 543 factor = 'BackGround' 544 f_oper = '+' 545 default_val = '0.0' 546 path = self.fname 547 try: 548 out_f = open(path, 'w') 549 except: 550 raise 551 lines = SUM_TEMPLATE.split('\n') 552 for line in lines: 553 try: 554 if line.count("scale_factor"): 555 line = line.replace('scale_factor', factor) 556 #print "scale_factor", line 557 if line.count("= %s"): 558 out_f.write(line % (default_val) + "\n") 559 elif line.count("import Model as P1"): 560 if self.is_p1_custom: 561 line = line.replace('#', '') 562 out_f.write(line % name1 + "\n") 563 else: 564 out_f.write(line + "\n") 565 elif line.count("import %s as P1"): 566 if not self.is_p1_custom: 567 line = line.replace('#', '') 568 out_f.write(line % (name1) + "\n") 569 else: 570 out_f.write(line + "\n") 571 elif line.count("import Model as P2"): 572 if self.is_p2_custom: 573 line = line.replace('#', '') 574 out_f.write(line % name2 + "\n") 575 else: 576 out_f.write(line + "\n") 577 elif line.count("import %s as P2"): 578 if not self.is_p2_custom: 579 line = line.replace('#', '') 580 out_f.write(line % (name2) + "\n") 581 else: 582 out_f.write(line + "\n") 583 elif line.count("P1 = find_model"): 584 out_f.write(line % (name1) + "\n") 585 elif line.count("P2 = find_model"): 586 out_f.write(line % (name2) + "\n") 587 588 elif line.count("self.description = '%s'"): 589 out_f.write(line % description + "\n") 590 #elif line.count("run") and line.count("%s"): 591 # out_f.write(line % self._operator + "\n") 592 #elif line.count("evalDistribution") and line.count("%s"): 593 # out_f.write(line % self._operator + "\n") 594 elif line.count("return") and line.count("%s") == 2: 595 #print "line return", line 596 out_f.write(line % (f_oper, self._operator) + "\n") 597 elif line.count("out2")and line.count("%s"): 598 out_f.write(line % self._operator + "\n") 599 else: 600 out_f.write(line + "\n") 601 except: 602 raise 603 out_f.close() 604 #else: 605 # msg = "Name exists already." 529 desc_line = '' 530 if description.strip() != '': 531 # Sasmodels generates a description for us. If the user provides 532 # their own description, add a line to overwrite the sasmodels one 533 desc_line = "\nmodel_info.description = '{}'".format(description) 534 name = os.path.splitext(os.path.basename(self.fname))[0] 535 output = SUM_TEMPLATE.format(name=name, model1=model1_name, 536 model2=model2_name, operator=self._operator, desc_line=desc_line) 537 with open(self.fname, 'w') as out_f: 538 out_f.write(output) 606 539 607 540 def compile_file(self, path): … … 643 576 self.name_hsizer = None 644 577 self.name_tcl = None 578 self.overwrite_cb = None 645 579 self.desc_sizer = None 646 580 self.desc_tcl = None … … 657 591 self.warning = "" 658 592 #This does not seem to be used anywhere so commenting out for now 659 # -- PDB 2/26/17 593 # -- PDB 2/26/17 660 594 #self._description = "New Plugin Model" 661 595 self.function_tcl = None … … 689 623 #title name [string] 690 624 name_txt = wx.StaticText(self, -1, 'Function Name : ') 691 overwrite_cb = wx.CheckBox(self, -1, "Overwrite existing plugin model of this name?", (10, 10))692 overwrite_cb.SetValue(False)693 overwrite_cb.SetToolTipString("Overwrite it if already exists?")694 wx.EVT_CHECKBOX(self, overwrite_cb.GetId(), self.on_over_cb)625 self.overwrite_cb = wx.CheckBox(self, -1, "Overwrite existing plugin model of this name?", (10, 10)) 626 self.overwrite_cb.SetValue(False) 627 self.overwrite_cb.SetToolTipString("Overwrite it if already exists?") 628 wx.EVT_CHECKBOX(self, self.overwrite_cb.GetId(), self.on_over_cb) 695 629 self.name_tcl = wx.TextCtrl(self, -1, size=(PANEL_WIDTH * 3 / 5, -1)) 696 630 self.name_tcl.Bind(wx.EVT_TEXT_ENTER, self.on_change_name) … … 700 634 self.name_tcl.SetToolTipString(hint_name) 701 635 self.name_hsizer.AddMany([(self.name_tcl, 0, wx.LEFT | wx.TOP, 0), 702 ( overwrite_cb, 0, wx.LEFT, 20)])636 (self.overwrite_cb, 0, wx.LEFT, 20)]) 703 637 self.name_sizer.AddMany([(name_txt, 0, wx.LEFT | wx.TOP, 10), 704 638 (self.name_hsizer, 0, … … 740 674 self.param_sizer.AddMany([(param_txt, 0, wx.LEFT, 10), 741 675 (self.param_tcl, 1, wx.EXPAND | wx.ALL, 10)]) 742 676 743 677 # Parameters with polydispersity 744 678 pd_param_txt = wx.StaticText(self, -1, 'Fit Parameters requiring ' + \ … … 755 689 self.pd_param_tcl.setDisplayLineNumbers(True) 756 690 self.pd_param_tcl.SetToolTipString(pd_param_tip) 757 691 758 692 self.param_sizer.AddMany([(pd_param_txt, 0, wx.LEFT, 10), 759 693 (self.pd_param_tcl, 1, wx.EXPAND | wx.ALL, 10)]) … … 995 929 info = 'Error' 996 930 color = 'red' 931 self.overwrite_cb.SetValue(True) 932 self.overwrite_name = True 997 933 else: 998 934 self._notes = result … … 1030 966 if has_scipy: 1031 967 lines.insert(0, 'import scipy') 1032 1033 # Think about 2D later 968 969 # Think about 2D later 1034 970 #self.is_2d = func_str.count("#self.ndim = 2") 1035 971 #line_2d = '' 1036 972 #if self.is_2d: 1037 973 # line_2d = CUSTOM_2D_TEMP.split('\n') 1038 1039 # Also think about test later 974 975 # Also think about test later 1040 976 #line_test = TEST_TEMPLATE.split('\n') 1041 977 #local_params = '' … … 1043 979 spaces4 = ' '*4 1044 980 spaces13 = ' '*13 1045 spaces16 = ' '*16 981 spaces16 = ' '*16 1046 982 param_names = [] # to store parameter names 1047 983 has_scipy = func_str.count("scipy.") … … 1055 991 out_f.write(line + '\n') 1056 992 if line.count('#name'): 1057 out_f.write('name = "%s" \n' % name) 993 out_f.write('name = "%s" \n' % name) 1058 994 elif line.count('#title'): 1059 out_f.write('title = "User model for %s"\n' % name) 995 out_f.write('title = "User model for %s"\n' % name) 1060 996 elif line.count('#description'): 1061 out_f.write('description = "%s"\n' % desc_str) 997 out_f.write('description = "%s"\n' % desc_str) 1062 998 elif line.count('#parameters'): 1063 999 out_f.write('parameters = [ \n') … … 1065 1001 p_line = param_line.lstrip().rstrip() 1066 1002 if p_line: 1067 pname, pvalue = self.get_param_helper(p_line)1003 pname, pvalue, desc = self.get_param_helper(p_line) 1068 1004 param_names.append(pname) 1069 out_f.write("%s['%s', '', %s, [-numpy.inf, numpy.inf], '', ' '],\n" % (spaces16, pname, pvalue))1005 out_f.write("%s['%s', '', %s, [-numpy.inf, numpy.inf], '', '%s'],\n" % (spaces16, pname, pvalue, desc)) 1070 1006 for param_line in pd_param_str.split('\n'): 1071 1007 p_line = param_line.lstrip().rstrip() 1072 1008 if p_line: 1073 pname, pvalue = self.get_param_helper(p_line)1009 pname, pvalue, desc = self.get_param_helper(p_line) 1074 1010 param_names.append(pname) 1075 out_f.write("%s['%s', '', %s, [-numpy.inf, numpy.inf], 'volume', ' '],\n" % (spaces16, pname, pvalue))1011 out_f.write("%s['%s', '', %s, [-numpy.inf, numpy.inf], 'volume', '%s'],\n" % (spaces16, pname, pvalue, desc)) 1076 1012 out_f.write('%s]\n' % spaces13) 1077 1013 1078 1014 # No form_volume or ER available in simple model editor 1079 1015 out_f.write('def form_volume(*arg): \n') … … 1082 1018 out_f.write('def ER(*arg): \n') 1083 1019 out_f.write(' return 1.0 \n') 1084 1020 1085 1021 # function to compute 1086 1022 out_f.write('\n') … … 1091 1027 for func_line in func_str.split('\n'): 1092 1028 out_f.write('%s%s\n' % (spaces4, func_line)) 1093 1029 1094 1030 Iqxy_string = 'return Iq(numpy.sqrt(x**2+y**2) ' 1095 1031 1096 1032 out_f.write('\n') 1097 1033 out_f.write('def Iqxy(x, y ') … … 1113 1049 items = line.split(";") 1114 1050 for item in items: 1115 name = item.split("=")[0].lstrip().rstrip() 1051 name = item.split("=")[0].strip() 1052 description = "" 1116 1053 try: 1117 value = item.split("=")[1].lstrip().rstrip() 1054 value = item.split("=")[1].strip() 1055 if value.count("#"): 1056 # If line ends in a comment, remove it before parsing float 1057 index = value.index("#") 1058 description = value[(index + 1):].strip() 1059 value = value[:value.index("#")].strip() 1118 1060 float(value) 1119 except :1061 except ValueError: 1120 1062 value = 1.0 # default 1121 1063 1122 return name, value 1064 return name, value, description 1123 1065 1124 1066 def set_function_helper(self, line): … … 1204 1146 import numpy 1205 1147 1206 #name 1148 #name 1207 1149 1208 1150 #title … … 1210 1152 #description 1211 1153 1212 #parameters 1154 #parameters 1213 1155 1214 1156 """ … … 1269 1211 """ 1270 1212 SUM_TEMPLATE = """ 1271 # A sample of an experimental model function for Sum/Multiply(Pmodel1,Pmodel2) 1272 import os 1273 import sys 1274 import copy 1275 import collections 1276 1277 import numpy 1278 1279 from sas.sascalc.fit.pluginmodel import Model1DPlugin 1280 from sasmodels.sasview_model import find_model 1281 1282 class Model(Model1DPlugin): 1283 name = os.path.splitext(os.path.basename(__file__))[0] 1284 is_multiplicity_model = False 1285 def __init__(self, multiplicity=1): 1286 Model1DPlugin.__init__(self, name='') 1287 P1 = find_model('%s') 1288 P2 = find_model('%s') 1289 p_model1 = P1() 1290 p_model2 = P2() 1291 ## Setting model name model description 1292 self.description = '%s' 1293 if self.name.rstrip().lstrip() == '': 1294 self.name = self._get_name(p_model1.name, p_model2.name) 1295 if self.description.rstrip().lstrip() == '': 1296 self.description = p_model1.name 1297 self.description += p_model2.name 1298 self.fill_description(p_model1, p_model2) 1299 1300 ## Define parameters 1301 self.params = collections.OrderedDict() 1302 1303 ## Parameter details [units, min, max] 1304 self.details = {} 1305 ## Magnetic Panrameters 1306 self.magnetic_params = [] 1307 # non-fittable parameters 1308 self.non_fittable = p_model1.non_fittable 1309 self.non_fittable += p_model2.non_fittable 1310 1311 ##models 1312 self.p_model1= p_model1 1313 self.p_model2= p_model2 1314 1315 1316 ## dispersion 1317 self._set_dispersion() 1318 ## Define parameters 1319 self._set_params() 1320 ## New parameter:scaling_factor 1321 self.params['scale_factor'] = %s 1322 1323 ## Parameter details [units, min, max] 1324 self._set_details() 1325 self.details['scale_factor'] = ['', 0.0, numpy.inf] 1326 1327 1328 #list of parameter that can be fitted 1329 self._set_fixed_params() 1330 1331 ## parameters with orientation 1332 self.orientation_params = [] 1333 for item in self.p_model1.orientation_params: 1334 new_item = "p1_" + item 1335 if not new_item in self.orientation_params: 1336 self.orientation_params.append(new_item) 1337 1338 for item in self.p_model2.orientation_params: 1339 new_item = "p2_" + item 1340 if not new_item in self.orientation_params: 1341 self.orientation_params.append(new_item) 1342 ## magnetic params 1343 self.magnetic_params = [] 1344 for item in self.p_model1.magnetic_params: 1345 new_item = "p1_" + item 1346 if not new_item in self.magnetic_params: 1347 self.magnetic_params.append(new_item) 1348 1349 for item in self.p_model2.magnetic_params: 1350 new_item = "p2_" + item 1351 if not new_item in self.magnetic_params: 1352 self.magnetic_params.append(new_item) 1353 # get multiplicity if model provide it, else 1. 1354 try: 1355 multiplicity1 = p_model1.multiplicity 1356 try: 1357 multiplicity2 = p_model2.multiplicity 1358 except: 1359 multiplicity2 = 1 1360 except: 1361 multiplicity1 = 1 1362 multiplicity2 = 1 1363 ## functional multiplicity of the model 1364 self.multiplicity1 = multiplicity1 1365 self.multiplicity2 = multiplicity2 1366 self.multiplicity_info = [] 1367 1368 def _clone(self, obj): 1369 import copy 1370 obj.params = copy.deepcopy(self.params) 1371 obj.description = copy.deepcopy(self.description) 1372 obj.details = copy.deepcopy(self.details) 1373 obj.dispersion = copy.deepcopy(self.dispersion) 1374 obj.p_model1 = self.p_model1.clone() 1375 obj.p_model2 = self.p_model2.clone() 1376 #obj = copy.deepcopy(self) 1377 return obj 1378 1379 def _get_name(self, name1, name2): 1380 p1_name = self._get_upper_name(name1) 1381 if not p1_name: 1382 p1_name = name1 1383 name = p1_name 1384 name += "_and_" 1385 p2_name = self._get_upper_name(name2) 1386 if not p2_name: 1387 p2_name = name2 1388 name += p2_name 1389 return name 1390 1391 def _get_upper_name(self, name=None): 1392 if name is None: 1393 return "" 1394 upper_name = "" 1395 str_name = str(name) 1396 for index in range(len(str_name)): 1397 if str_name[index].isupper(): 1398 upper_name += str_name[index] 1399 return upper_name 1400 1401 def _set_dispersion(self): 1402 self.dispersion = collections.OrderedDict() 1403 ##set dispersion only from p_model 1404 for name , value in self.p_model1.dispersion.iteritems(): 1405 #if name.lower() not in self.p_model1.orientation_params: 1406 new_name = "p1_" + name 1407 self.dispersion[new_name]= value 1408 for name , value in self.p_model2.dispersion.iteritems(): 1409 #if name.lower() not in self.p_model2.orientation_params: 1410 new_name = "p2_" + name 1411 self.dispersion[new_name]= value 1412 1413 def function(self, x=0.0): 1414 return 0 1415 1416 def getProfile(self): 1417 try: 1418 x,y = self.p_model1.getProfile() 1419 except: 1420 x = None 1421 y = None 1422 1423 return x, y 1424 1425 def _set_params(self): 1426 for name , value in self.p_model1.params.iteritems(): 1427 # No 2D-supported 1428 #if name not in self.p_model1.orientation_params: 1429 new_name = "p1_" + name 1430 self.params[new_name]= value 1431 1432 for name , value in self.p_model2.params.iteritems(): 1433 # No 2D-supported 1434 #if name not in self.p_model2.orientation_params: 1435 new_name = "p2_" + name 1436 self.params[new_name]= value 1437 1438 # Set "scale" as initializing 1439 self._set_scale_factor() 1440 1441 1442 def _set_details(self): 1443 for name ,detail in self.p_model1.details.iteritems(): 1444 new_name = "p1_" + name 1445 #if new_name not in self.orientation_params: 1446 self.details[new_name]= detail 1447 1448 for name ,detail in self.p_model2.details.iteritems(): 1449 new_name = "p2_" + name 1450 #if new_name not in self.orientation_params: 1451 self.details[new_name]= detail 1452 1453 def _set_scale_factor(self): 1454 pass 1455 1456 1457 def setParam(self, name, value): 1458 # set param to this (p1, p2) model 1459 self._setParamHelper(name, value) 1460 1461 ## setParam to p model 1462 model_pre = '' 1463 new_name = '' 1464 name_split = name.split('_', 1) 1465 if len(name_split) == 2: 1466 model_pre = name.split('_', 1)[0] 1467 new_name = name.split('_', 1)[1] 1468 if model_pre == "p1": 1469 if new_name in self.p_model1.getParamList(): 1470 self.p_model1.setParam(new_name, value) 1471 elif model_pre == "p2": 1472 if new_name in self.p_model2.getParamList(): 1473 self.p_model2.setParam(new_name, value) 1474 elif name == 'scale_factor': 1475 self.params['scale_factor'] = value 1476 else: 1477 raise ValueError, "Model does not contain parameter %s" % name 1478 1479 def getParam(self, name): 1480 # Look for dispersion parameters 1481 toks = name.split('.') 1482 if len(toks)==2: 1483 for item in self.dispersion.keys(): 1484 # 2D not supported 1485 if item.lower()==toks[0].lower(): 1486 for par in self.dispersion[item]: 1487 if par.lower() == toks[1].lower(): 1488 return self.dispersion[item][par] 1489 else: 1490 # Look for standard parameter 1491 for item in self.params.keys(): 1492 if item.lower()==name.lower(): 1493 return self.params[item] 1494 return 1495 #raise ValueError, "Model does not contain parameter %s" % name 1496 1497 def _setParamHelper(self, name, value): 1498 # Look for dispersion parameters 1499 toks = name.split('.') 1500 if len(toks)== 2: 1501 for item in self.dispersion.keys(): 1502 if item.lower()== toks[0].lower(): 1503 for par in self.dispersion[item]: 1504 if par.lower() == toks[1].lower(): 1505 self.dispersion[item][par] = value 1506 return 1507 else: 1508 # Look for standard parameter 1509 for item in self.params.keys(): 1510 if item.lower()== name.lower(): 1511 self.params[item] = value 1512 return 1513 1514 raise ValueError, "Model does not contain parameter %s" % name 1515 1516 1517 def _set_fixed_params(self): 1518 self.fixed = [] 1519 for item in self.p_model1.fixed: 1520 new_item = "p1" + item 1521 self.fixed.append(new_item) 1522 for item in self.p_model2.fixed: 1523 new_item = "p2" + item 1524 self.fixed.append(new_item) 1525 1526 self.fixed.sort() 1527 1528 1529 def run(self, x = 0.0): 1530 self._set_scale_factor() 1531 return self.params['scale_factor'] %s \ 1532 (self.p_model1.run(x) %s self.p_model2.run(x)) 1533 1534 def runXY(self, x = 0.0): 1535 self._set_scale_factor() 1536 return self.params['scale_factor'] %s \ 1537 (self.p_model1.runXY(x) %s self.p_model2.runXY(x)) 1538 1539 ## Now (May27,10) directly uses the model eval function 1540 ## instead of the for-loop in Base Component. 1541 def evalDistribution(self, x = []): 1542 self._set_scale_factor() 1543 return self.params['scale_factor'] %s \ 1544 (self.p_model1.evalDistribution(x) %s \ 1545 self.p_model2.evalDistribution(x)) 1546 1547 def set_dispersion(self, parameter, dispersion): 1548 value= None 1549 new_pre = parameter.split("_", 1)[0] 1550 new_parameter = parameter.split("_", 1)[1] 1551 try: 1552 if new_pre == 'p1' and \ 1553 new_parameter in self.p_model1.dispersion.keys(): 1554 value= self.p_model1.set_dispersion(new_parameter, dispersion) 1555 if new_pre == 'p2' and \ 1556 new_parameter in self.p_model2.dispersion.keys(): 1557 value= self.p_model2.set_dispersion(new_parameter, dispersion) 1558 self._set_dispersion() 1559 return value 1560 except: 1561 raise 1562 1563 def fill_description(self, p_model1, p_model2): 1564 description = "" 1565 description += "This model gives the summation or multiplication of" 1566 description += "%s and %s. "% ( p_model1.name, p_model2.name ) 1567 self.description += description 1568 1569 if __name__ == "__main__": 1570 m1= Model() 1571 #m1.setParam("p1_scale", 25) 1572 #m1.setParam("p1_length", 1000) 1573 #m1.setParam("p2_scale", 100) 1574 #m1.setParam("p2_rg", 100) 1575 out1 = m1.runXY(0.01) 1576 1577 m2= Model() 1578 #m2.p_model1.setParam("scale", 25) 1579 #m2.p_model1.setParam("length", 1000) 1580 #m2.p_model2.setParam("scale", 100) 1581 #m2.p_model2.setParam("rg", 100) 1582 out2 = m2.p_model1.runXY(0.01) %s m2.p_model2.runXY(0.01)\n 1583 print "My name is %s."% m1.name 1584 print out1, " = ", out2 1585 if out1 == out2: 1586 print "===> Simple Test: Passed!" 1587 else: 1588 print "===> Simple Test: Failed!" 1213 from sasmodels.core import load_model_info 1214 from sasmodels.sasview_model import make_model_from_info 1215 1216 model_info = load_model_info('{model1}{operator}{model2}') 1217 model_info.name = '{name}'{desc_line} 1218 Model = make_model_from_info(model_info) 1589 1219 """ 1590 1591 1220 if __name__ == "__main__": 1592 1221 # app = wx.PySimpleApp() -
src/sas/sasgui/perspectives/calculator/pyconsole.py
r7432acb r4627657 37 37 Iqxy = model.evalDistribution([qx, qy]) 38 38 39 result = """ 40 Iq(%s) = %s 41 Iqxy(%s, %s) = %s 42 """%(q, Iq, qx, qy, Iqxy) 39 # check the model's unit tests run 40 from sasmodels.model_test import run_one 41 result = run_one(path) 43 42 44 43 return result … … 89 88 ok = wx.Button(self, wx.ID_OK, "OK") 90 89 91 # Mysterious constraint layouts from 90 # Mysterious constraint layouts from 92 91 # https://www.wxpython.org/docs/api/wx.lib.layoutf.Layoutf-class.html 93 92 lc = layoutf.Layoutf('t=t5#1;b=t5#2;l=l5#1;r=r5#1', (self,ok)) -
src/sas/sasgui/perspectives/file_converter/converter_panel.py
red9f872 r19296dc 24 24 from sas.sascalc.file_converter.otoko_loader import OTOKOLoader 25 25 from sas.sascalc.file_converter.bsl_loader import BSLLoader 26 from sas.sascalc.file_converter.ascii2d_loader import ASCII2DLoader 26 27 from sas.sascalc.file_converter.nxcansas_writer import NXcanSASWriter 27 28 from sas.sascalc.dataloader.data_info import Detector … … 35 36 _STATICBOX_WIDTH = 410 36 37 _BOX_WIDTH = 200 37 PANEL_SIZE = 48038 PANEL_SIZE = 520 38 39 FONT_VARIANT = 0 39 40 else: … … 41 42 _STATICBOX_WIDTH = 430 42 43 _BOX_WIDTH = 200 43 PANEL_SIZE = 5 0044 PANEL_SIZE = 540 44 45 FONT_VARIANT = 1 45 46 … … 352 353 w.write(frame_data, output_path) 353 354 355 def convert_2d_data(self, dataset): 356 metadata = self.get_metadata() 357 for key, value in metadata.iteritems(): 358 setattr(dataset[0], key, value) 359 360 w = NXcanSASWriter() 361 w.write(dataset, self.output.GetPath()) 362 354 363 def on_convert(self, event): 355 364 """Called when the Convert button is clicked""" … … 367 376 qdata, iqdata = self.extract_otoko_data(self.q_input.GetPath()) 368 377 self.convert_1d_data(qdata, iqdata) 378 elif self.data_type == 'ascii2d': 379 loader = ASCII2DLoader(self.iq_input.GetPath()) 380 data = loader.load() 381 dataset = [data] # ASCII 2D only ever contains 1 frame 382 self.convert_2d_data(dataset) 369 383 else: # self.data_type == 'bsl' 370 384 dataset = self.extract_bsl_data(self.iq_input.GetPath()) … … 372 386 # Cancelled by user 373 387 return 374 375 metadata = self.get_metadata() 376 for key, value in metadata.iteritems(): 377 setattr(dataset[0], key, value) 378 379 w = NXcanSASWriter() 380 w.write(dataset, self.output.GetPath()) 388 self.convert_2d_data(dataset) 389 381 390 except Exception as ex: 382 391 msg = str(ex) … … 399 408 def validate_inputs(self): 400 409 msg = "You must select a" 401 if self.q_input.GetPath() == '' and self.data_type != 'bsl': 410 if self.q_input.GetPath() == '' and self.data_type != 'bsl' \ 411 and self.data_type != 'ascii2d': 402 412 msg += " Q Axis input file." 403 413 elif self.iq_input.GetPath() == '': … … 472 482 dtype = event.GetEventObject().GetName() 473 483 self.data_type = dtype 474 if dtype == 'bsl' :484 if dtype == 'bsl' or dtype == 'ascii2d': 475 485 self.q_input.SetPath("") 476 486 self.q_input.Disable() … … 500 510 501 511 instructions = ( 502 "Select linked single column 1D ASCII files containing the Q-axis and " 503 "Intensity-axis data, or 1D BSL/OTOKO files, or a 2D BSL/OTOKO file, " 504 "then choose where to save the converted file, and click Convert.\n" 505 "1D ASCII and BSL/OTOKO files can be converted to CanSAS (XML) or " 506 "NXcanSAS (HDF5) formats. 2D BSL/OTOKO files can only be converted to " 507 "the NXcanSAS format.\n" 508 "Metadata can be optionally added for the CanSAS XML format." 512 "If converting a 1D dataset, select linked single-column ASCII files " 513 "containing the Q-axis and intensity-axis data, or a 1D BSL/OTOKO file." 514 " If converting 2D data, select an ASCII file in the ISIS 2D file " 515 "format, or a 2D BSL/OTOKO file. Choose where to save the converted " 516 "file and click convert.\n" 517 "One dimensional ASCII and BSL/OTOKO files can be converted to CanSAS " 518 "(XML) or NXcanSAS (HDF5) formats. Two dimensional datasets can only be" 519 " converted to the NXcanSAS format.\n" 520 "Metadata can also be optionally added to the output file." 509 521 ) 510 522 … … 526 538 wx.ALIGN_CENTER_VERTICAL, 5) 527 539 radio_sizer = wx.BoxSizer(wx.HORIZONTAL) 528 ascii_btn = wx.RadioButton(self, -1, "ASCII ", name="ascii",540 ascii_btn = wx.RadioButton(self, -1, "ASCII 1D", name="ascii", 529 541 style=wx.RB_GROUP) 530 542 ascii_btn.Bind(wx.EVT_RADIOBUTTON, self.datatype_changed) 531 543 radio_sizer.Add(ascii_btn) 544 ascii2d_btn = wx.RadioButton(self, -1, "ASCII 2D", name="ascii2d") 545 ascii2d_btn.Bind(wx.EVT_RADIOBUTTON, self.datatype_changed) 546 radio_sizer.Add(ascii2d_btn) 532 547 otoko_btn = wx.RadioButton(self, -1, "BSL 1D", name="otoko") 533 548 otoko_btn.Bind(wx.EVT_RADIOBUTTON, self.datatype_changed) 534 549 radio_sizer.Add(otoko_btn) 535 input_grid.Add(radio_sizer, (y,1), (1,1), wx.ALL, 5)536 550 bsl_btn = wx.RadioButton(self, -1, "BSL 2D", name="bsl") 537 551 bsl_btn.Bind(wx.EVT_RADIOBUTTON, self.datatype_changed) 538 552 radio_sizer.Add(bsl_btn) 553 input_grid.Add(radio_sizer, (y,1), (1,1), wx.ALL, 5) 539 554 y += 1 540 555 … … 549 564 y += 1 550 565 551 iq_label = wx.StaticText(self, -1, "Intensity -AxisData: ")566 iq_label = wx.StaticText(self, -1, "Intensity Data: ") 552 567 input_grid.Add(iq_label, (y,0), (1,1), wx.ALIGN_CENTER_VERTICAL, 5) 553 568 … … 647 662 648 663 def __init__(self, parent=None, title='File Converter', base=None, 649 manager=None, size=(PANEL_SIZE * 1.05, PANEL_SIZE / 1.1),664 manager=None, size=(PANEL_SIZE * 0.96, PANEL_SIZE * 0.9), 650 665 *args, **kwargs): 651 666 kwargs['title'] = title -
src/sas/sasgui/perspectives/file_converter/file_converter.py
r463e7ffc r94e3572 25 25 Returns a set of menu entries 26 26 """ 27 help_txt = "Convert single column ASCII data to CanSAS format"27 help_txt = "Convert ASCII or BSL/OTOKO data to CanSAS or NXcanSAS formats" 28 28 return [("File Converter", help_txt, self.on_file_converter)] 29 29 -
src/sas/sasgui/perspectives/file_converter/media/file_converter_help.rst
rd73998c r59decb81 18 18 * Single-column ASCII data, with lines that end without any delimiter, 19 19 or with a comma or semi-colon delimiter 20 * 2D `ISIS ASCII formatted 21 <http://www.isis.stfc.ac.uk/instruments/loq/software/ 22 colette-ascii-file-format-descriptions9808.pdf>`_ data 20 23 * `1D BSL/OTOKO format 21 24 <http://www.diamond.ac.uk/Beamlines/Soft-Condensed-Matter/small-angle/ … … 36 39 37 40 1) Select the files containing your Q-axis and Intensity-axis data 38 2) Choose whether the files are in ASCII , 1D BSL/OTOKO or 2D BSL/OTOKO format41 2) Choose whether the files are in ASCII 1D, ASCII 2D, 1D BSL/OTOKO or 2D BSL/OTOKO format 39 42 3) Choose where you would like to save the converted file 40 43 4) Optionally, input some metadata such as sample size, detector name, etc … … 47 50 file, a dialog will appear asking which frames you would like converted. You 48 51 may enter a start frame, end frame & increment, and all frames in that subset 49 will be converted. For example, entering 0, 50 and 10 will convert frames 0, 52 will be converted. For example, entering 0, 50 and 10 will convert frames 0, 50 53 10, 20, 30, 40 & 50. 51 54 … … 56 59 single file, so there is an option in the *Select Frame* dialog to output each 57 60 frame to its own file. The single file option will produce one file with 58 multiple `<SASdata>` elements. The multiple file option will output a separate 59 file with one `<SASdata>` element for each frame. The frame number will also be 61 multiple `<SASdata>` elements. The multiple file option will output a separate 62 file with one `<SASdata>` element for each frame. The frame number will also be 60 63 appended to the file name. 61 64 62 The multiple file option is not available when exporting to NXcanSAS because 65 The multiple file option is not available when exporting to NXcanSAS because 63 66 the HDF5 format is more efficient at handling large amounts of data. 64 67 -
src/sas/sasgui/perspectives/fitting/fitting.py
ra534432 r2d9526d 257 257 toks = os.path.splitext(label) 258 258 path = os.path.join(models.find_plugins_dir(), toks[0]) 259 message = "Are you sure you want to delete the file {}?".format(path) 260 dlg = wx.MessageDialog(self.frame, message, '', wx.YES_NO | wx.ICON_QUESTION) 261 if not dlg.ShowModal() == wx.ID_YES: 262 return 259 263 try: 260 264 for ext in ['.py', '.pyc']: 261 265 p_path = path + ext 266 if ext == '.pyc' and not os.path.isfile(path + ext): 267 # If model is invalid, .pyc file may not exist as model has 268 # never been compiled. Don't try and delete it 269 continue 262 270 os.remove(p_path) 263 271 self.update_custom_combo() … … 361 369 'Add a new model function') 362 370 wx.EVT_MENU(owner, wx_id, self.make_new_model) 363 371 364 372 wx_id = wx.NewId() 365 373 self.edit_model_menu.Append(wx_id, 'Sum|Multi(p1, p2)', … … 383 391 '(Re)Load all models present in user plugin_models folder') 384 392 wx.EVT_MENU(owner, wx_id, self.load_plugin_models) 385 393 386 394 def set_edit_menu_helper(self, owner=None, menu=None): 387 395 """ … … 1734 1742 @param unsmeared_error: data error, rescaled to unsmeared model 1735 1743 """ 1736 1737 number_finite = np.count_nonzero(np.isfinite(y)) 1744 number_finite = np.count_nonzero(np.isfinite(y)) 1738 1745 np.nan_to_num(y) 1739 1746 new_plot = self.create_theory_1D(x, y, page_id, model, data, state, 1740 1747 data_description=model.name, 1741 1748 data_id=str(page_id) + " " + data.name) 1749 plots_to_update = [] # List of plottables that have changed since last calculation 1750 # Create the new theories 1742 1751 if unsmeared_model is not None: 1743 self.create_theory_1D(x, unsmeared_model, page_id, model, data, state, 1752 unsmeared_model_plot = self.create_theory_1D(x, unsmeared_model, 1753 page_id, model, data, state, 1744 1754 data_description=model.name + " unsmeared", 1745 1755 data_id=str(page_id) + " " + data.name + " unsmeared") 1756 plots_to_update.append(unsmeared_model_plot) 1746 1757 1747 1758 if unsmeared_data is not None and unsmeared_error is not None: 1748 self.create_theory_1D(x, unsmeared_data, page_id, model, data, state, 1759 unsmeared_data_plot = self.create_theory_1D(x, unsmeared_data, 1760 page_id, model, data, state, 1749 1761 data_description="Data unsmeared", 1750 1762 data_id="Data " + data.name + " unsmeared", 1751 1763 dy=unsmeared_error) 1752 # Comment this out until we can get P*S models with correctly populated parameters 1753 #if sq_model is not None and pq_model is not None: 1754 # self.create_theory_1D(x, sq_model, page_id, model, data, state, 1755 # data_description=model.name + " S(q)", 1756 # data_id=str(page_id) + " " + data.name + " S(q)") 1757 # self.create_theory_1D(x, pq_model, page_id, model, data, state, 1758 # data_description=model.name + " P(q)", 1759 # data_id=str(page_id) + " " + data.name + " P(q)") 1764 plots_to_update.append(unsmeared_data_plot) 1765 if sq_model is not None and pq_model is not None: 1766 sq_id = str(page_id) + " " + data.name + " S(q)" 1767 sq_plot = self.create_theory_1D(x, sq_model, page_id, model, data, state, 1768 data_description=model.name + " S(q)", 1769 data_id=sq_id) 1770 plots_to_update.append(sq_plot) 1771 pq_id = str(page_id) + " " + data.name + " P(q)" 1772 pq_plot = self.create_theory_1D(x, pq_model, page_id, model, data, state, 1773 data_description=model.name + " P(q)", 1774 data_id=pq_id) 1775 plots_to_update.append(pq_plot) 1776 # Update the P(Q), S(Q) and unsmeared theory plots if they exist 1777 wx.PostEvent(self.parent, NewPlotEvent(plots=plots_to_update, 1778 action='update')) 1760 1779 1761 1780 current_pg = self.fit_panel.get_page_by_id(page_id) … … 1794 1813 msg = "Computing Error: Model did not return any finite value." 1795 1814 wx.PostEvent(self.parent, StatusEvent(status = msg, info="error")) 1796 else: 1815 else: 1797 1816 msg = "Computation completed!" 1798 1817 if number_finite != y.size: … … 1824 1843 that can be plot. 1825 1844 """ 1826 number_finite = np.count_nonzero(np.isfinite(image)) 1845 number_finite = np.count_nonzero(np.isfinite(image)) 1827 1846 np.nan_to_num(image) 1828 1847 new_plot = Data2D(image=image, err_image=data.err_data) … … 1927 1946 ## and may be the cause of other noted instabilities 1928 1947 ## 1929 ## -PDB August 12, 2014 1948 ## -PDB August 12, 2014 1930 1949 while self.calc_2D.isrunning(): 1931 1950 time.sleep(0.1) … … 1969 1988 if (self.calc_1D is not None) and self.calc_1D.isrunning(): 1970 1989 self.calc_1D.stop() 1971 ## stop just raises the flag -- the thread is supposed to 1990 ## stop just raises the flag -- the thread is supposed to 1972 1991 ## then kill itself but cannot. Paul Kienzle came up with 1973 1992 ## this fix to prevent threads from stepping on each other … … 1981 2000 ## a request to stop the computation. 1982 2001 ## It seems thus that the whole thread approach used here 1983 ## May need rethinking 2002 ## May need rethinking 1984 2003 ## 1985 2004 ## -PDB August 12, 2014 … … 2146 2165 residuals.dxw = None 2147 2166 residuals.ytransform = 'y' 2148 # For latter scale changes 2167 # For latter scale changes 2149 2168 residuals.xaxis('\\rm{Q} ', 'A^{-1}') 2150 2169 residuals.yaxis('\\rm{Residuals} ', 'normalized') -
src/sas/sasgui/perspectives/fitting/media/fitting_help.rst
r5295cf5 rca383a0 195 195 the :ref:`Advanced_Plugin_Editor` . 196 196 197 **SasView version 4.2** made it possible to specify whether a plugin created with 198 the *New Plugin Model* dialog is actually a form factor P(Q) or a structure factor 199 S(Q). To do this, simply add one or other of the following lines under the *import* 200 statements. 201 202 For a form factor:: 203 204 form_factor = True 205 206 or for a structure factor:: 207 208 structure_factor = True 209 210 If the plugin is a structure factor it is *also* necessary to add two variables to 211 the parameter list:: 212 213 parameters = [ 214 ['radius_effective', '', 1, [0.0, numpy.inf], 'volume', ''], 215 ['volfraction', '', 1, [0.0, 1.0], '', ''], 216 [...], 217 218 and to the declarations of the functions Iq and Iqxy::: 219 220 def Iq(x , radius_effective, volfraction, ...): 221 222 def Iqxy(x, y, radius_effective, volfraction, ...): 223 224 Such a plugin should then be available in the S(Q) drop-down box on a FitPage (once 225 a P(Q) model has been selected). 226 197 227 Sum|Multi(p1,p2) 198 228 ^^^^^^^^^^^^^^^^ … … 206 236 or:: 207 237 208 Plugin Model = scale_factor * model_1 /* model_2+ background238 Plugin Model = scale_factor * (model1 * model2) + background 209 239 210 240 In the *Easy Sum/Multi Editor* give the new model a function name and brief 211 241 description (to appear under the *Details* button on the *FitPage*). Then select 212 242 two existing models, as p1 and p2, and the required operator, '+' or '*' between 213 them. Finally, click the *Apply* button to generate the model and then click *Close*. 214 215 Any changes to a plugin model generated in this way only become effective *after* it is re-selected from the model drop-down menu on the FitPage. 243 them. Finally, click the *Apply* button to generate and test the model and then click *Close*. 244 245 Any changes to a plugin model generated in this way only become effective *after* it is re-selected 246 from the plugin models drop-down menu on the FitPage. If the model is not listed you can force a 247 recompilation of the plugins by selecting *Fitting* > *Plugin Model Operations* > *Load Plugin Models*. 248 249 **SasView version 4.2** introduced a much simplified and more extensible structure for plugin models 250 generated through the Easy Sum/Multi Editor. For example, the code for a combination of a sphere model 251 with a power law model now looks like this:: 252 253 from sasmodels.core import load_model_info 254 from sasmodels.sasview_model import make_model_from_info 255 256 model_info = load_model_info('sphere+power_law') 257 model_info.name = 'MyPluginModel' 258 model_info.description = 'sphere + power_law' 259 Model = make_model_from_info(model_info) 260 261 To change the models or operators contributing to this plugin it is only necessary to edit the string 262 in the brackets after *load_model_info*, though it would also be a good idea to update the model name 263 and description too!!! 264 265 The model specification string can handle multiple models and combinations of operators (+ or *) which 266 are processed according to normal conventions. Thus 'model1+model2*model3' would be valid and would 267 multiply model2 by model3 before adding model1. In this example, parameters in the *FitPage* would be 268 prefixed A (for model2), B (for model3) and C (for model1). Whilst this might appear a little 269 confusing, unless you were creating a plugin model from multiple instances of the same model the parameter 270 assignments ought to be obvious when you load the plugin. 271 272 If you need to include another plugin model in the model specification string, just prefix the name of 273 that model with *custom*. For instance:: 274 275 sphere+custom.MyPluginModel 276 277 To create a P(Q)*\S(Q) model use the @ symbol instead of * like this:: 278 279 sphere@hardsphere 280 281 This streamlined approach to building complex plugin models from existing library models, or models 282 available on the *Model Marketplace*, also permits the creation of P(Q)*\S(Q) plugin models, something 283 that was not possible in earlier versions of SasView. 216 284 217 285 .. _Advanced_Plugin_Editor: … … 484 552 .. ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ 485 553 554 .. _Batch_Fit_Mode: 555 486 556 Batch Fit Mode 487 557 -------------- … … 636 706 637 707 Example: radius [2 : 5] , radius [10 : 25] 638 639 .. ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ 640 641 .. note:: This help document was last changed by Steve King, 10Oct2016 708 709 .. ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ 710 711 Combined Batch Fit Mode 712 ----------------------- 713 714 The purpose of the Combined Batch Fit is to allow running two or more batch 715 fits in sequence without overwriting the output table of results. This may be 716 of interest for example if one is fitting a series of data sets where there is 717 a shape change occurring in the series that requires changing the model part 718 way through the series; for example a sphere to rod transition. Indeed the 719 regular batch mode does not allow for multiple models and requires all the 720 files in the series to be fit with single model and set of parameters. While 721 it is of course possible to just run part of the series as a batch fit using 722 model one followed by running another batch fit on the rest of the series with 723 model two (and/or model three etc), doing so will overwrite the table of 724 outputs from the previous batch fit(s). This may not be desirable if one is 725 interested in comparing the parameters: for example the sphere radius of set 726 one and the cylinder radius of set two. 727 728 Method 729 ^^^^^^ 730 731 In order to use the *Combined Batch Fit*, first load all the data needed as 732 described in :ref:`Loading_data`. Next start up two or more *BatchPage* fits 733 following the instructions in :ref:`Batch_Fit_Mode` but **DO NOT PRESS FIT**. 734 At this point the *Combine Batch Fit* menu item under the *Fitting menu* should 735 be active (if there is one or no *BatchPage* the menu item will be greyed out 736 and inactive). Clicking on *Combine Batch Fit* will bring up a new panel, 737 similar to the *Const & Simult Fit* panel. In this case there will be a 738 checkbox for each *BatchPage* instead of each *FitPage* that should be included 739 in the fit. Once all are selected, click the Fit button on 740 the *BatchPage* to run each batch fit in *sequence* 741 742 .. image:: combine_batch_page.png 743 744 The batch table will then pop up at the end as for the case of the simple Batch 745 Fitting with the following caveats: 746 747 .. note:: 748 The order matters. The parameters in the table will be taken from the model 749 used in the first *BatchPage* of the list. Any parameters from the 750 second and later *BatchPage* s that have the same name as a parameter in the 751 first will show up allowing for plotting of that parameter across the 752 models. The other parameters will not be available in the grid. 753 .. note:: 754 a corralary of the above is that currently models created as a sum|multiply 755 model will not work as desired because the generated model parameters have a 756 p#_ appended to the beginning and thus radius and p1_radius will not be 757 recognized as the same parameter. 758 759 .. image:: combine_batch_grid.png 760 761 In the example shown above the data is a time series with a shifting peak. 762 The first part of the series was fitted using the *broad_peak* model, while 763 the rest of the data were fit using the *gaussian_peak* model. Unfortunately the 764 time is not listed in the file but the file name contains the information. As 765 described in :ref:`Grid_Window`, a column can be added manually, in this case 766 called time, and the peak position plotted against time. 767 768 .. image:: combine_batch_plot.png 769 770 Note the discontinuity in the peak position. This reflects the fact that the 771 Gaussian fit is a rather poor model for the data and is not actually 772 finding the peak. 773 774 .. ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ 775 776 .. note:: This help document was last changed by Paul Butler, 10 September 777 2017 -
src/sas/sasgui/perspectives/fitting/media/plugin.rst
r72100ee re081946 18 18 * By writing a model from scratch outside of SasView (only recommended for 19 19 code monkeys!) 20 21 **What follows below is quite technical. If you just want a helping hand to get 22 started creating your own models see** :ref:`Adding_your_own_models`. 20 23 21 24 Overview -
src/sas/sasgui/perspectives/fitting/model_thread.py
r7432acb r0f9ea1c 71 71 (self.data.qy_data * self.data.qy_data)) 72 72 73 # For theory, qmax is based on 1d qmax 73 # For theory, qmax is based on 1d qmax 74 74 # so that must be mulitified by sqrt(2) to get actual max for 2d 75 75 index_model = (self.qmin <= radius) & (radius <= self.qmax) … … 91 91 self.data.qy_data[index_model] 92 92 ]) 93 output = np.zeros(len(self.data.qx_data)) 93 # Initialize output to NaN so masked elements do not get plotted. 94 output = np.empty_like(self.data.qx_data) 94 95 # output default is None 95 96 # This method is to distinguish between masked 96 97 #point(nan) and data point = 0. 97 output = output / output98 output[:] = np.NaN 98 99 # set value for self.mask==True, else still None to Plottools 99 100 output[index_model] = value … … 198 199 output[index] = self.model.evalDistribution(self.data.x[index]) 199 200 201 x=self.data.x[index] 202 y=output[index] 200 203 sq_values = None 201 204 pq_values = None 202 s_model = None203 p_model = None204 205 if isinstance(self.model, MultiplicationModel): 205 206 s_model = self.model.s_model 206 207 p_model = self.model.p_model 207 elif hasattr(self.model, "get_composition_models"): 208 p_model, s_model = self.model.get_composition_models() 209 210 if p_model is not None and s_model is not None: 211 sq_values = np.zeros((len(self.data.x))) 212 pq_values = np.zeros((len(self.data.x))) 213 sq_values[index] = s_model.evalDistribution(self.data.x[index]) 214 pq_values[index] = p_model.evalDistribution(self.data.x[index]) 208 sq_values = s_model.evalDistribution(x) 209 pq_values = p_model.evalDistribution(x) 210 elif hasattr(self.model, "calc_composition_models"): 211 results = self.model.calc_composition_models(x) 212 if results is not None: 213 pq_values, sq_values = results 214 215 215 216 216 elapsed = time.time() - self.starttime 217 217 218 self.complete(x= self.data.x[index], y=output[index],218 self.complete(x=x, y=y, 219 219 page_id=self.page_id, 220 220 state=self.state, -
src/sas/sasgui/perspectives/fitting/models.py
r8cec26b rb1c2011 186 186 try: 187 187 model = load_custom_model(path) 188 model.name = PLUGIN_NAME_BASE + model.name 188 if not model.name.count(PLUGIN_NAME_BASE): 189 model.name = PLUGIN_NAME_BASE + model.name 189 190 plugins[model.name] = model 190 191 except Exception: … … 297 298 for name, plug in self.stored_plugins.iteritems(): 298 299 self.model_dictionary[name] = plug 299 300 300 301 self._get_multifunc_models() 301 302 -
src/sas/sasgui/perspectives/fitting/simfitpage.py
r959eb01 ra9f9ca4 1 1 """ 2 Simultaneous fit page2 Simultaneous or Batch fit page 3 3 """ 4 # Note that this is used for both Simultaneous/Constrained fit AND for 5 # combined batch fit. This is done through setting of the batch_on parameter. 6 # There are the a half dozen or so places where an if statement is used as in 7 # if not batch_on: 8 # xxxx 9 # else: 10 # xxxx 11 # This is just wrong but dont have time to fix this go. Proper approach would be 12 # to strip all parts of the code that depend on batch_on and create the top 13 # level class from which a contrained/simultaneous fit page and a combined 14 # batch page inherit. 15 # 16 # 04/09/2017 --PDB 17 4 18 import sys 5 19 from collections import namedtuple … … 400 414 # General Help button 401 415 self.btHelp = wx.Button(self, wx.ID_HELP, 'HELP') 402 self.btHelp.SetToolTipString("Simultaneous/Constrained Fitting help.") 416 if self.batch_on: 417 self.btHelp.SetToolTipString("Combined Batch Fitting help.") 418 else: 419 self.btHelp.SetToolTipString("Simultaneous/Constrained Fitting help.") 403 420 self.btHelp.Bind(wx.EVT_BUTTON, self._on_help) 404 421 … … 527 544 """ 528 545 _TreeLocation = "user/sasgui/perspectives/fitting/fitting_help.html" 529 _PageAnchor = "#simultaneous-fit-mode" 530 _doc_viewer = DocumentationWindow(self, self.ID_DOC, _TreeLocation, 546 if not self.batch_on: 547 _PageAnchor = "#simultaneous-fit-mode" 548 _doc_viewer = DocumentationWindow(self, self.ID_DOC, _TreeLocation, 531 549 _PageAnchor, 532 550 "Simultaneous/Constrained Fitting Help") 551 else: 552 _PageAnchor = "#combined-batch-fit-mode" 553 _doc_viewer = DocumentationWindow(self, self.ID_DOC, _TreeLocation, 554 _PageAnchor, 555 "Combined Batch Fit Help") 533 556 534 557 def set_manager(self, manager): -
src/sas/sasgui/perspectives/pr/inversion_panel.py
r7432acb rcb62bd5 70 70 self.rg_ctl = None 71 71 self.iq0_ctl = None 72 self.bck_chk = None 72 self.bck_value = None 73 self.bck_est_ctl = None 74 self.bck_man_ctl = None 75 self.est_bck = True 76 self.bck_input = None 73 77 self.bck_ctl = None 74 78 … … 312 316 # Read the panel's parameters 313 317 flag, alpha, dmax, nfunc, qmin, \ 314 qmax, height, width = self._read_pars()318 qmax, height, width, bck = self._read_pars() 315 319 316 320 state.nfunc = nfunc … … 326 330 327 331 # Background evaluation checkbox 328 state.estimate_bck = self.bck_chk.IsChecked() 332 state.estimate_bck = self.est_bck 333 state.bck_value = bck 329 334 330 335 # Estimates … … 371 376 self.plot_data.SetValue(str(state.file)) 372 377 373 # Background evaluation checkbox 374 self.bck_chk.SetValue(state.estimate_bck) 378 # Background value 379 self.bck_est_ctl.SetValue(state.estimate_bck) 380 self.bck_man_ctl.SetValue(not state.estimate_bck) 381 if not state.estimate_bck: 382 self.bck_input.Enable() 383 self.bck_input.SetValue(str(state.bck_value)) 384 self.est_bck = state.estimate_bck 385 self.bck_value = state.bck_value 375 386 376 387 # Estimates … … 431 442 wx.EXPAND | wx.LEFT | wx.RIGHT | wx.ADJUST_MINSIZE, 15) 432 443 433 self.bck_chk = wx.CheckBox(self, -1, "Estimate background level") 434 hint_msg = "Check box to let the fit estimate " 435 hint_msg += "the constant background level." 436 self.bck_chk.SetToolTipString(hint_msg) 437 self.bck_chk.Bind(wx.EVT_CHECKBOX, self._on_pars_changed) 444 radio_sizer = wx.GridBagSizer(5, 5) 445 446 self.bck_est_ctl = wx.RadioButton(self, -1, "Estimate background level", 447 name="estimate_bck", style=wx.RB_GROUP) 448 self.bck_man_ctl = wx.RadioButton(self, -1, "Input manual background level", 449 name="manual_bck") 450 451 self.bck_est_ctl.Bind(wx.EVT_RADIOBUTTON, self._on_bck_changed) 452 self.bck_man_ctl.Bind(wx.EVT_RADIOBUTTON, self._on_bck_changed) 453 454 radio_sizer.Add(self.bck_est_ctl, (0,0), (1,1), wx.LEFT | wx.EXPAND) 455 radio_sizer.Add(self.bck_man_ctl, (0,1), (1,1), wx.RIGHT | wx.EXPAND) 456 438 457 iy += 1 439 pars_sizer.Add( self.bck_chk, (iy, 0), (1, 2),458 pars_sizer.Add(radio_sizer, (iy, 0), (1, 2), 440 459 wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15) 460 461 background_label = wx.StaticText(self, -1, "Background: ") 462 self.bck_input = PrTextCtrl(self, -1, style=wx.TE_PROCESS_ENTER, 463 size=(60, 20), value="0.0") 464 self.bck_input.Disable() 465 self.bck_input.Bind(wx.EVT_TEXT, self._read_pars) 466 background_units = wx.StaticText(self, -1, "[A^(-1)]", size=(55, 20)) 467 iy += 1 468 469 background_sizer = wx.GridBagSizer(5, 5) 470 471 background_sizer.Add(background_label, (0, 0), (1,1), 472 wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 23) 473 background_sizer.Add(self.bck_input, (0, 1), (1,1), 474 wx.LEFT | wx.ADJUST_MINSIZE, 5) 475 background_sizer.Add(background_units, (0, 2), (1,1), 476 wx.LEFT | wx.ADJUST_MINSIZE, 5) 477 pars_sizer.Add(background_sizer, (iy, 0), (1, 2), 478 wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15) 479 441 480 boxsizer1.Add(pars_sizer, 0, wx.EXPAND) 442 481 vbox.Add(boxsizer1, (iy_vb, 0), (1, 1), … … 764 803 self._on_pars_changed() 765 804 805 def _on_bck_changed(self, evt=None): 806 self.est_bck = self.bck_est_ctl.GetValue() 807 if self.est_bck: 808 self.bck_input.Disable() 809 else: 810 self.bck_input.Enable() 811 766 812 def _on_pars_changed(self, evt=None): 767 813 """ … … 770 816 scenes. 771 817 """ 772 flag, alpha, dmax, nfunc, qmin, qmax, height, width = self._read_pars() 773 has_bck = self.bck_chk.IsChecked() 818 flag, alpha, dmax, nfunc, qmin, qmax, height, width, bck = self._read_pars() 774 819 775 820 # If the pars are valid, estimate alpha … … 783 828 d_max=dmax, 784 829 q_min=qmin, q_max=qmax, 785 bck=has_bck, 830 est_bck=self.est_bck, 831 bck_val=bck, 786 832 height=height, 787 833 width=width) … … 797 843 height = 0 798 844 width = 0 845 background = 0 799 846 flag = True 800 847 # Read slit height … … 890 937 self.qmax_ctl.Refresh() 891 938 892 return flag, alpha, dmax, nfunc, qmin, qmax, height, width 939 # Read background 940 if not self.est_bck: 941 try: 942 bck_str = self.bck_input.GetValue() 943 if len(bck_str.strip()) == 0: 944 background = 0.0 945 else: 946 background = float(bck_str) 947 self.bck_input.SetBackgroundColour(wx.WHITE) 948 except ValueError: 949 background = 0.0 950 self.bck_input.SetBackgroundColour("pink") 951 self.bck_input.Refresh() 952 953 return flag, alpha, dmax, nfunc, qmin, qmax, height, width, background 893 954 894 955 def _on_explore(self, evt): … … 915 976 # Push it to the manager 916 977 917 flag, alpha, dmax, nfunc, qmin, qmax, height, width = self._read_pars() 918 has_bck = self.bck_chk.IsChecked() 978 flag, alpha, dmax, nfunc, qmin, qmax, height, width, bck = self._read_pars() 919 979 920 980 if flag: … … 928 988 d_max=dmax, 929 989 q_min=qmin, q_max=qmax, 930 bck=has_bck, 990 est_bck=self.est_bck, 991 bck_val = bck, 931 992 height=height, 932 993 width=width) -
src/sas/sasgui/perspectives/pr/inversion_state.py
r7432acb ra0e6b1b 36 36 ["qmin", "qmin"], 37 37 ["qmax", "qmax"], 38 ["estimate_bck", "estimate_bck"]] 38 ["estimate_bck", "estimate_bck"], 39 ["bck_value", "bck_value"]] 39 40 40 41 ## List of P(r) inversion outputs … … 62 63 self.estimate_bck = False 63 64 self.timestamp = time.time() 65 self.bck_value = 0.0 64 66 65 67 # Inversion parameters … … 109 111 state += "Timestamp: %s\n" % self.timestamp 110 112 state += "Estimate bck: %s\n" % str(self.estimate_bck) 113 state += "Bck Value: %s\n" % str(self.bck_value) 111 114 state += "No. terms: %s\n" % str(self.nfunc) 112 115 state += "D_max: %s\n" % str(self.d_max) … … 296 299 self.coefficients.append(float(c)) 297 300 except: 298 # Bad data, skip. We will count the number of 299 # coefficients at the very end and deal with 301 # Bad data, skip. We will count the number of 302 # coefficients at the very end and deal with 300 303 # inconsistencies then. 301 304 pass … … 329 332 cov_row.append(float(c)) 330 333 except: 331 # Bad data, skip. We will count the number of 332 # coefficients at the very end and deal with 334 # Bad data, skip. We will count the number of 335 # coefficients at the very end and deal with 333 336 # inconsistencies then. 334 337 pass … … 461 464 tree = etree.parse(path, parser=etree.ETCompatXMLParser()) 462 465 # Check the format version number 463 # Specifying the namespace will take care of the file 464 #format version 466 # Specifying the namespace will take care of the file 467 #format version 465 468 root = tree.getroot() 466 469 -
src/sas/sasgui/perspectives/pr/media/pr_help.rst
r1221196 r1abd19c 49 49 P(r) inversion requires that the background be perfectly subtracted. This is 50 50 often difficult to do well and thus many data sets will include a background. 51 For those cases, the user should check the "estimate background" box and the 52 module will do its best to estimate it. 51 For those cases, the user should check the "Estimate background level" option 52 and the module will do its best to estimate it. If you know the background value 53 for your data, select the "Input manual background level" option. Note that 54 this value will be treated as having 0 error. 53 55 54 56 The P(r) module is constantly computing in the background what the optimum -
src/sas/sasgui/perspectives/pr/pr.py
ra1b8fee rcb62bd5 68 68 self.q_min = None 69 69 self.q_max = None 70 self.has_bck = False 70 self.est_bck = False 71 self.bck_val = 0 71 72 self.slit_height = 0 72 73 self.slit_width = 0 … … 828 829 self.control_panel.iq0 = pr.iq0(out) 829 830 self.control_panel.bck = pr.background 831 self.control_panel.bck_input.SetValue("{:.2g}".format(pr.background)) 830 832 831 833 # Show I(q) fit … … 907 909 908 910 def setup_plot_inversion(self, alpha, nfunc, d_max, q_min=None, q_max=None, 909 bck=False, height=0, width=0):911 est_bck=False, bck_val=0, height=0, width=0): 910 912 """ 911 913 Set up inversion from plotted data … … 916 918 self.q_min = q_min 917 919 self.q_max = q_max 918 self.has_bck = bck 920 self.est_bck = est_bck 921 self.bck_val = bck_val 919 922 self.slit_height = height 920 923 self.slit_width = width … … 930 933 def estimate_plot_inversion(self, alpha, nfunc, d_max, 931 934 q_min=None, q_max=None, 932 bck=False, height=0, width=0):935 est_bck=False, bck_val=0, height=0, width=0): 933 936 """ 934 937 Estimate parameters from plotted data … … 939 942 self.q_min = q_min 940 943 self.q_max = q_max 941 self.has_bck = bck 944 self.est_bck = est_bck 945 self.bck_val = bck_val 942 946 self.slit_height = height 943 947 self.slit_width = width … … 973 977 pr.x = self.current_plottable.x 974 978 pr.y = self.current_plottable.y 975 pr. has_bck = self.has_bck979 pr.est_bck = self.est_bck 976 980 pr.slit_height = self.slit_height 977 981 pr.slit_width = self.slit_width 982 pr.background = self.bck_val 978 983 979 984 # Keep track of the plot window title to ensure that … … 1019 1024 self.q_min = q_min 1020 1025 self.q_max = q_max 1021 self. has_bck = bck1026 self.est_bck = bck 1022 1027 self.slit_height = height 1023 1028 self.slit_width = width … … 1042 1047 self.q_min = q_min 1043 1048 self.q_max = q_max 1044 self. has_bck = bck1049 self.est_bck = bck 1045 1050 self.slit_height = height 1046 1051 self.slit_width = width … … 1115 1120 pr.y = y 1116 1121 pr.err = err 1117 pr. has_bck = self.has_bck1122 pr.est_bck = self.est_bck 1118 1123 pr.slit_height = self.slit_height 1119 1124 pr.slit_width = self.slit_width
Note: See TracChangeset
for help on using the changeset viewer.