Changeset 277257f in sasview for src/sas/sasgui/perspectives/calculator/model_editor.py
- Timestamp:
- Jul 5, 2017 3:28:55 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, magnetic_scatt, release-4.2.2, ticket-1009, ticket-1094-headless, ticket-1242-2d-resolution, ticket-1243, ticket-1249, ticket885, unittest-saveload
- Children:
- 1386b2f
- Parents:
- 251ef684
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
src/sas/sasgui/perspectives/calculator/model_editor.py
r65f3930 r277257f 31 31 import re 32 32 import logging 33 import datetime 34 33 35 from wx.py.editwindow import EditWindow 36 34 37 from sas.sasgui.guiframe.documentation_window import DocumentationWindow 38 35 39 from .pyconsole import show_model_output, check_model 36 40 37 41 logger = logging.getLogger(__name__) 38 39 42 40 43 if sys.platform.count("win32") > 0: … … 78 81 a Modal Dialog. 79 82 80 :TODO the buil din compiler currently balks at when it tries to import83 :TODO the built in compiler currently balks at when it tries to import 81 84 a model whose name contains spaces or symbols (such as + ... underscore 82 85 should be fine). Have fixed so the editor cannot save such a file name … … 336 339 list_fnames = os.listdir(self.plugin_dir) 337 340 # fake existing regular model name list 338 m_list = [model + ".py" for model in self.model_list]341 m_list = [model.name + ".py" for model in self.model_list] 339 342 list_fnames.append(m_list) 340 343 if t_fname in list_fnames and title != mname: … … 855 858 exec "float(math.%s)" % item 856 859 self.math_combo.Append(str(item)) 857 except :860 except Exception: 858 861 self.math_combo.Append(str(item) + "()") 859 862 self.math_combo.Bind(wx.EVT_COMBOBOX, self._on_math_select) … … 980 983 msg = "Name exists already." 981 984 982 # Prepare the messagebox985 # 983 986 if self.base is not None and not msg: 984 987 self.base.update_custom_combo() 985 # Passed exception in import test as it will fail for sasmodels.sasview_model class986 # Should add similar test for new style?987 Model = None988 try:989 exec "from %s import Model" % name990 except:991 logger.error(sys.exc_value)992 988 993 989 # Prepare the messagebox … … 1020 1016 :param func_str: content of func; Strings 1021 1017 """ 1022 try: 1023 out_f = open(fname, 'w') 1024 except: 1025 raise 1026 # Prepare the content of the function 1027 lines = CUSTOM_TEMPLATE.split('\n') 1028 1029 has_scipy = func_str.count("scipy.") 1030 if has_scipy: 1031 lines.insert(0, 'import scipy') 1032 1033 # Think about 2D later 1034 #self.is_2d = func_str.count("#self.ndim = 2") 1035 #line_2d = '' 1036 #if self.is_2d: 1037 # line_2d = CUSTOM_2D_TEMP.split('\n') 1038 1039 # Also think about test later 1040 #line_test = TEST_TEMPLATE.split('\n') 1041 #local_params = '' 1042 #spaces = ' '#8spaces 1043 spaces4 = ' '*4 1044 spaces13 = ' '*13 1045 spaces16 = ' '*16 1018 out_f = open(fname, 'w') 1019 1020 out_f.write(CUSTOM_TEMPLATE % { 1021 'name': name, 1022 'title': 'User model for ' + name, 1023 'description': desc_str, 1024 'date': datetime.datetime.now().strftime('%YYYY-%mm-%dd'), 1025 }) 1026 1027 # Write out parameters 1046 1028 param_names = [] # to store parameter names 1047 has_scipy = func_str.count("scipy.") 1048 if has_scipy: 1049 lines.insert(0, 'import scipy') 1050 1051 # write function here 1052 for line in lines: 1053 # The location where to put the strings is 1054 # hard-coded in the template as shown below. 1055 out_f.write(line + '\n') 1056 if line.count('#name'): 1057 out_f.write('name = "%s" \n' % name) 1058 elif line.count('#title'): 1059 out_f.write('title = "User model for %s"\n' % name) 1060 elif line.count('#description'): 1061 out_f.write('description = "%s"\n' % desc_str) 1062 elif line.count('#parameters'): 1063 out_f.write('parameters = [ \n') 1064 for param_line in param_str.split('\n'): 1065 p_line = param_line.lstrip().rstrip() 1066 if p_line: 1067 pname, pvalue = self.get_param_helper(p_line) 1068 param_names.append(pname) 1069 out_f.write("%s['%s', '', %s, [-numpy.inf, numpy.inf], '', ''],\n" % (spaces16, pname, pvalue)) 1070 for param_line in pd_param_str.split('\n'): 1071 p_line = param_line.lstrip().rstrip() 1072 if p_line: 1073 pname, pvalue = self.get_param_helper(p_line) 1074 param_names.append(pname) 1075 out_f.write("%s['%s', '', %s, [-numpy.inf, numpy.inf], 'volume', ''],\n" % (spaces16, pname, pvalue)) 1076 out_f.write('%s]\n' % spaces13) 1077 1078 # No form_volume or ER available in simple model editor 1079 out_f.write('def form_volume(*arg): \n') 1080 out_f.write(' return 1.0 \n') 1081 out_f.write('\n') 1082 out_f.write('def ER(*arg): \n') 1083 out_f.write(' return 1.0 \n') 1084 1085 # function to compute 1086 out_f.write('\n') 1087 out_f.write('def Iq(x ') 1088 for name in param_names: 1089 out_f.write(', %s' % name) 1090 out_f.write('):\n') 1029 pd_params = [] 1030 out_f.write('parameters = [ \n') 1031 out_f.write('# ["name", "units", default, [lower, upper], "type", "description"],\n') 1032 for pname, pvalue in self.get_param_helper(param_str): 1033 param_names.append(pname) 1034 out_f.write(" ['%s', '', %s, [-inf, inf], '', ''],\n" 1035 % (pname, pvalue)) 1036 for pname, pvalue in self.get_param_helper(pd_param_str): 1037 param_names.append(pname) 1038 pd_params.append(pname) 1039 out_f.write(" ['%s', '', %s, [-inf, inf], 'volume', ''],\n" 1040 % (pname, pvalue)) 1041 out_f.write(' ]\n') 1042 1043 # Write out function definition 1044 out_f.write('def Iq(%s):\n' % ', '.join(['x'] + param_names)) 1045 out_f.write(' """Absolute scattering"""\n') 1046 if "scipy." in func_str: 1047 out_f.write(' import scipy') 1048 if "numpy." in func_str: 1049 out_f.write(' import numpy') 1050 if "np." in func_str: 1051 out_f.write(' import numpy as np') 1091 1052 for func_line in func_str.split('\n'): 1092 1053 out_f.write('%s%s\n' % (spaces4, func_line)) 1093 1094 Iqxy_string = 'return Iq(numpy.sqrt(x**2+y**2) ' 1095 1054 out_f.write('## uncomment the following if Iq works for vector x\n') 1055 out_f.write('#Iq.vectorized = True\n') 1056 1057 # If polydisperse, create place holders for form_volume, ER and VR 1058 if pd_params: 1059 out_f.write('\n') 1060 out_f.write(CUSTOM_TEMPLATE_PD % {'args': ', '.join(pd_params)}) 1061 1062 # Create place holder for Iqxy 1096 1063 out_f.write('\n') 1097 out_f.write('def Iqxy(x, y ') 1098 for name in param_names: 1099 out_f.write(', %s' % name) 1100 Iqxy_string += ', ' + name 1101 out_f.write('):\n') 1102 Iqxy_string += ')' 1103 out_f.write('%s%s\n' % (spaces4, Iqxy_string)) 1064 out_f.write('#def Iqxy(%s):\n' % ', '.join(["x", "y"] + param_names)) 1065 out_f.write('# """Absolute scattering of oriented particles."""\n') 1066 out_f.write('# ...\n') 1067 out_f.write('# return oriented_form(x, y, args)\n') 1068 out_f.write('## uncomment the following if Iqxy works for vector x, y\n') 1069 out_f.write('#Iqxy.vectorized = True\n') 1104 1070 1105 1071 out_f.close() 1106 1072 1107 def get_param_helper(self, line): 1108 """ 1109 Get string in line to define the params dictionary 1110 1111 :param line: one line of string got from the param_str 1112 """ 1113 items = line.split(";") 1114 for item in items: 1115 name = item.split("=")[0].lstrip().rstrip() 1116 try: 1117 value = item.split("=")[1].lstrip().rstrip() 1118 float(value) 1119 except: 1120 value = 1.0 # default 1121 1122 return name, value 1073 def get_param_helper(self, param_str): 1074 """ 1075 yield a sequence of name, value pairs for the parameters in param_str 1076 1077 Parameters can be defined by one per line by name=value, or multiple 1078 on the same line by separating the pairs by semicolon or comma. The 1079 value is optional and defaults to "1.0". 1080 """ 1081 for line in param_str.replace(';', ',').split('\n'): 1082 for item in line.split(','): 1083 parts = item.plit('=') 1084 name = parts[0].strip() 1085 value = parts[1] if len(parts) > 0 else '1.0' 1086 if name: 1087 yield name, value 1123 1088 1124 1089 def set_function_helper(self, line): … … 1154 1119 running "file:///...." 1155 1120 1156 :param evt: Triggers on clicking the help button1157 """1121 :param evt: Triggers on clicking the help button 1122 """ 1158 1123 1159 1124 _TreeLocation = "user/sasgui/perspectives/fitting/fitting_help.html" … … 1198 1163 ## Templates for plugin models 1199 1164 1200 CUSTOM_TEMPLATE = """ 1165 CUSTOM_TEMPLATE = '''\ 1166 r""" 1167 Definition 1168 ---------- 1169 1170 Calculates %(name)s. 1171 1172 %(description)s 1173 1174 References 1175 ---------- 1176 1177 Authorship and Verification 1178 --------------------------- 1179 1180 * **Author:** --- **Date:** %(date)s 1181 * **Last Modified by:** --- **Date:** %(date)s 1182 * **Last Reviewed by:** --- **Date:** %(date)s 1183 """ 1184 1201 1185 from math import * 1202 import os 1203 import sys 1204 import numpy 1205 1206 #name 1207 1208 #title 1209 1210 #description 1211 1212 #parameters 1213 1214 """ 1215 1216 CUSTOM_2D_TEMP = """ 1217 def run(self, x=0.0, y=0.0): 1218 if x.__class__.__name__ == 'list': 1219 x_val = x[0] 1220 y_val = y[0]*0.0 1221 return self.function(x_val, y_val) 1222 elif x.__class__.__name__ == 'tuple': 1223 msg = "Tuples are not allowed as input to BaseComponent models" 1224 raise ValueError, msg 1225 else: 1226 return self.function(x, 0.0) 1227 def runXY(self, x=0.0, y=0.0): 1228 if x.__class__.__name__ == 'list': 1229 return self.function(x, y) 1230 elif x.__class__.__name__ == 'tuple': 1231 msg = "Tuples are not allowed as input to BaseComponent models" 1232 raise ValueError, msg 1233 else: 1234 return self.function(x, y) 1235 def evalDistribution(self, qdist): 1236 if qdist.__class__.__name__ == 'list': 1237 msg = "evalDistribution expects a list of 2 ndarrays" 1238 if len(qdist)!=2: 1239 raise RuntimeError, msg 1240 if qdist[0].__class__.__name__ != 'ndarray': 1241 raise RuntimeError, msg 1242 if qdist[1].__class__.__name__ != 'ndarray': 1243 raise RuntimeError, msg 1244 v_model = numpy.vectorize(self.runXY, otypes=[float]) 1245 iq_array = v_model(qdist[0], qdist[1]) 1246 return iq_array 1247 elif qdist.__class__.__name__ == 'ndarray': 1248 v_model = numpy.vectorize(self.runXY, otypes=[float]) 1249 iq_array = v_model(qdist) 1250 return iq_array 1251 """ 1252 TEST_TEMPLATE = """ 1253 ###################################################################### 1254 ## THIS IS FOR TEST. DO NOT MODIFY THE FOLLOWING LINES!!!!!!!!!!!!!!!! 1255 if __name__ == "__main__": 1256 m= Model() 1257 out1 = m.runXY(0.0) 1258 out2 = m.runXY(0.01) 1259 isfine1 = numpy.isfinite(out1) 1260 isfine2 = numpy.isfinite(out2) 1261 print "Testing the value at Q = 0.0:" 1262 print out1, " : finite? ", isfine1 1263 print "Testing the value at Q = 0.01:" 1264 print out2, " : finite? ", isfine2 1265 if isfine1 and isfine2: 1266 print "===> Simple Test: Passed!" 1267 else: 1268 print "===> Simple Test: Failed!" 1269 """ 1186 from numpy import inf 1187 1188 name = "%(name)s" 1189 title = "%(title)s" 1190 description = """%(description)s""" 1191 1192 ''' 1193 1194 CUSTOM_TEMPLATE_PD = '''\ 1195 def form_volume(%(args)s): 1196 """ 1197 Volume of the particles used to compute absolute scattering intensity 1198 and to weight polydisperse parameter contributions. 1199 """ 1200 return 0.0 1201 1202 def ER(%(args)s): 1203 """ 1204 Effective radius of particles to be used when computing structure factors. 1205 1206 Input parameters are vectors ranging over the mesh of polydispersity values. 1207 """ 1208 return 0.0 1209 1210 def VR(%(args)s): 1211 """ 1212 Volume ratio of particles to be used when computing structure factors. 1213 1214 Input parameters are vectors ranging over the mesh of polydispersity values. 1215 """ 1216 return 1.0 1217 ''' 1218 1270 1219 SUM_TEMPLATE = """ 1271 1220 # A sample of an experimental model function for Sum/Multiply(Pmodel1,Pmodel2) … … 1592 1541 main_app = wx.App() 1593 1542 main_frame = TextDialog(id=1, model_list=["SphereModel", "CylinderModel"], 1594 plugin_dir='../fitting/plugin_models')1543 plugin_dir='../fitting/plugin_models') 1595 1544 main_frame.ShowModal() 1596 1545 main_app.MainLoop()
Note: See TracChangeset
for help on using the changeset viewer.