source: sasview/calculatorview/src/sans/perspectives/calculator/model_editor.py @ f706e09c

ESS_GUIESS_GUI_DocsESS_GUI_batch_fittingESS_GUI_bumps_abstractionESS_GUI_iss1116ESS_GUI_iss879ESS_GUI_iss959ESS_GUI_openclESS_GUI_orderingESS_GUI_sync_sascalccostrafo411magnetic_scattrelease-4.1.1release-4.1.2release-4.2.2release_4.0.1ticket-1009ticket-1094-headlessticket-1242-2d-resolutionticket-1243ticket-1249ticket885unittest-saveload
Last change on this file since f706e09c was b25caad, checked in by Jae Cho <jhjcho@…>, 13 years ago

added 'delete custom model menu'

  • Property mode set to 100644
File size: 32.5 KB
Line 
1
2################################################################################
3#This software was developed by the University of Tennessee as part of the
4#Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
5#project funded by the US National Science Foundation.
6#
7#See the license text in license.txt
8#
9#copyright 2009, University of Tennessee
10################################################################################
11
12
13import wx
14import sys
15import os
16from wx.py.editwindow import EditWindow
17
18if sys.platform.count("win32") > 0:
19    FONT_VARIANT = 0
20    PNL_WIDTH = 460
21    PNL_HITE = 210
22else:
23    FONT_VARIANT = 1
24    PNL_WIDTH = 500
25    PNL_HITE = 250
26
27EDITOR_WIDTH = 800
28EDITOR_HEIGTH = 800
29PANEL_WIDTH = 500
30_BOX_WIDTH = 51
31
32   
33def _compileFile(path):
34    """
35    Compile the file in the path
36    """
37    try:
38        import py_compile
39        py_compile.compile(file=path, doraise=True)
40        return ''
41    except:
42        type, value, traceback = sys.exc_info()
43        return value
44   
45def _deleteFile(path):
46    """
47    Delete file in the path
48    """
49    try:
50        os.remove(path)
51    except:
52        raise
53
54 
55class TextDialog(wx.Dialog):
56    """
57    Dialog for easy custom sum models 
58    """
59    def __init__(self, parent=None, id=None, title='', model_list=[]):
60        """
61        Dialog window popup when selecting 'Easy Custom Sum' on the menu
62        """
63        wx.Dialog.__init__(self, parent=parent, id=id, 
64                           title=title, size=(PNL_WIDTH, PNL_HITE))
65        self.parent = parent
66        #Font
67        self.SetWindowVariant(variant=FONT_VARIANT)
68        # default
69        self.model_list = model_list
70        self.model1_string = "SphereModel"
71        self.model2_string = "CylinderModel"
72        self._build_sizer()
73        self.model1_name = str(self.model1.GetValue())
74        self.model2_name = str(self.model2.GetValue())
75       
76    def _build_sizer(self):
77        """
78        Build gui
79        """
80        _BOX_WIDTH = 195 # combobox width
81        vbox  = wx.BoxSizer(wx.VERTICAL)
82        sizer = wx.GridBagSizer(1, 3)
83        sum_description= wx.StaticBox(self, -1, 'Select', 
84                                       size=(PNL_WIDTH-30, 70))
85        sum_box = wx.StaticBoxSizer(sum_description, wx.VERTICAL)
86        model1_box = wx.BoxSizer(wx.HORIZONTAL)
87        model2_box = wx.BoxSizer(wx.HORIZONTAL)
88        model_vbox = wx.BoxSizer(wx.VERTICAL)
89        self.model1 =  wx.ComboBox(self, -1, style=wx.CB_READONLY)
90        wx.EVT_COMBOBOX(self.model1, -1, self.on_model1)
91        self.model1.SetMinSize((_BOX_WIDTH, -1))
92        self.model1.SetToolTipString("model1")
93        self.model2 =  wx.ComboBox(self, -1, style=wx.CB_READONLY)
94        wx.EVT_COMBOBOX(self.model2, -1, self.on_model2)
95        self.model2.SetMinSize((_BOX_WIDTH, -1))
96        self.model2.SetToolTipString("model2")
97        self._set_model_list()
98       
99         # Buttons on the bottom
100        self.static_line_1 = wx.StaticLine(self, -1)
101        self.okButton = wx.Button(self,wx.ID_OK, 'OK', size=(_BOX_WIDTH/2, 25))
102        self.closeButton = wx.Button(self,wx.ID_CANCEL, 'Cancel', 
103                                     size=(_BOX_WIDTH/2, 25))
104        # Intro
105        explanation  = "  custom model = scale_factor * (model1 + model2)\n"
106        explanation  += "  Note: This will overwrite the previous sum model.\n"
107        model_string = " Model%s (p%s):"
108        vbox.Add(sizer)
109        ix = 0
110        iy = 1
111        sizer.Add(wx.StaticText(self, -1, explanation), (iy, ix),
112                 (1, 1), wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
113        model1_box.Add(wx.StaticText(self,-1, model_string% (1, 1)), -1, 0)
114        model1_box.Add((_BOX_WIDTH-35,10))
115        model1_box.Add(wx.StaticText(self, -1, model_string% (2, 2)), -1, 0)
116        model2_box.Add(self.model1, -1, 0)
117        model2_box.Add((20,10))
118        model2_box.Add(self.model2, -1, 0)
119        model_vbox.Add(model1_box, -1, 0)
120        model_vbox.Add(model2_box, -1, 0)
121        sum_box.Add(model_vbox, -1, 10)
122        iy += 1
123        ix = 0
124        sizer.Add(sum_box, (iy, ix),
125                  (1, 1), wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
126        vbox.Add((10,10))
127        vbox.Add(self.static_line_1, 0, wx.EXPAND, 10)
128        sizer_button = wx.BoxSizer(wx.HORIZONTAL)
129        sizer_button.Add((20, 20), 1, wx.EXPAND|wx.ADJUST_MINSIZE, 0)
130        sizer_button.Add(self.okButton, 0, 
131                         wx.LEFT|wx.RIGHT|wx.ADJUST_MINSIZE, 0)
132        sizer_button.Add(self.closeButton, 0,
133                          wx.LEFT|wx.RIGHT|wx.ADJUST_MINSIZE, 15)       
134        vbox.Add(sizer_button, 0, wx.EXPAND|wx.BOTTOM|wx.TOP, 10)
135        self.SetSizer(vbox)
136        self.Centre()
137                 
138    def _set_model_list(self):
139        """
140        Set the list of models
141        """
142        # list of model names
143        list = self.model_list
144        if len(list) > 1:
145            list.sort()
146        for idx in range(len(list)):
147            self.model1.Append(list[idx],idx) 
148            self.model2.Append(list[idx],idx)
149        self.model1.SetStringSelection(self.model1_string)
150        self.model2.SetStringSelection(self.model2_string)
151           
152    def on_model1(self, event):
153        """
154        Set model1
155        """
156        event.Skip()
157        self.model1_name = str(self.model1.GetValue())
158        self.model1_string = self.model1_name
159           
160    def on_model2(self, event):
161        """
162        Set model2
163        """
164        event.Skip()
165        self.model2_name = str(self.model2.GetValue())
166        self.model2_string = self.model2_name
167 
168    def getText(self):
169        """
170        Returns model name string as list
171        """
172        return [self.model1_name, self.model2_name]
173   
174    def write_string(self, fname, name1, name2):
175        """
176        Write and Save file
177        """
178        try:
179            out_f =  open(fname,'w')
180        except :
181            raise
182        lines = SUM_TEMPLATE.split('\n')
183        for line in lines:
184            if line.count("import %s as P1"):
185                out_f.write(line % (name1, name1) + "\n")
186            elif line.count("import %s as P2"):
187                out_f.write(line % (name2, name2) + "\n")
188            else:
189                out_f.write(line + "\n")
190        out_f.close() 
191       
192    def compile_file(self, path):
193        """
194        Compile the file in the path
195        """
196        _compileFile(path)
197       
198    def delete_file(self, path):
199        """
200        Delete file in the path
201        """
202        _deleteFile(path)
203
204
205class EditorPanel(wx.ScrolledWindow):
206    """
207    Custom model function editor
208    """
209    def __init__(self, parent, base, path, title, *args, **kwds):
210        kwds['name'] = title
211        kwds["size"] = (EDITOR_WIDTH, EDITOR_HEIGTH)
212        kwds["style"]= wx.FULL_REPAINT_ON_RESIZE
213        wx.ScrolledWindow.__init__(self, parent, *args, **kwds)
214        #self.SetupScrolling()
215        self.parent = parent
216        self.base = base
217        self.path = path
218        self.font = wx.SystemSettings_GetFont(wx.SYS_SYSTEM_FONT)
219        self.font.SetPointSize(10)
220        self.reader = None
221        self.name = 'untitled'
222        self.overwrite_name = True
223        self.fname = None
224        self.param_strings = ''
225        self.function_strings = ''
226        self._notes = ""
227        self.warning = ""
228        self._description = "New Custom Model"
229        #self._default_save_location = os.getcwd()
230        self._do_layout()
231        #self.bt_apply.Disable()
232
233             
234    def _define_structure(self):
235        """
236        define initial sizer
237        """
238        #w, h = self.parent.GetSize()
239        self.main_sizer = wx.BoxSizer(wx.VERTICAL)
240        self.name_sizer = wx.BoxSizer(wx.VERTICAL)
241        self.name_hsizer = wx.BoxSizer(wx.HORIZONTAL)
242        self.desc_sizer = wx.BoxSizer(wx.VERTICAL)
243        self.param_sizer = wx.BoxSizer(wx.VERTICAL)
244        self.function_sizer = wx.BoxSizer(wx.VERTICAL)
245        self.button_sizer = wx.BoxSizer(wx.HORIZONTAL)
246       
247    def _layout_name(self):
248        """
249        Do the layout for file/function name related widgets
250        """
251        #title name [string]
252        name_txt = wx.StaticText(self, -1, 'Function Name : ') 
253        overwrite_cb = wx.CheckBox(self, -1, "Overwrite?", (10, 10))
254        overwrite_cb.SetValue(True)
255        overwrite_cb.SetToolTipString("Overwrite it if already exists?")
256        wx.EVT_CHECKBOX(self, overwrite_cb.GetId(), self.on_over_cb)
257        self.name_tcl = wx.TextCtrl(self, -1, size=(PANEL_WIDTH*3/5, -1)) 
258        self.name_tcl.Bind(wx.EVT_TEXT_ENTER, self.on_change_name)
259        self.name_tcl.SetValue('untitled')
260        self.name_tcl.SetFont(self.font)
261        hint_name = "Unique Model Function Name."
262        self.name_tcl.SetToolTipString(hint_name)
263        self.name_hsizer.AddMany([(self.name_tcl, 0, wx.LEFT|wx.TOP, 0),
264                                       (overwrite_cb, 0, wx.LEFT, 20)])
265        self.name_sizer.AddMany([(name_txt, 0, wx.LEFT|wx.TOP, 10),
266                                       (self.name_hsizer, 0, 
267                                        wx.LEFT|wx.TOP|wx.BOTTOM, 10)])
268       
269       
270    def _layout_description(self):
271        """
272        Do the layout for description related widgets
273        """
274        #title name [string]
275        desc_txt = wx.StaticText(self, -1, 'Description (optional) : ') 
276        self.desc_tcl = wx.TextCtrl(self, -1, size=(PANEL_WIDTH*3/5, -1)) 
277        self.desc_tcl.SetValue('')
278        #self.name_tcl.SetFont(self.font)
279        hint_desc = "Write a short description of the model function."
280        self.desc_tcl.SetToolTipString(hint_desc)
281        self.desc_sizer.AddMany([(desc_txt, 0, wx.LEFT|wx.TOP, 10),
282                                       (self.desc_tcl, 0, 
283                                        wx.LEFT|wx.TOP|wx.BOTTOM, 10)])     
284    def _layout_param(self):
285        """
286        Do the layout for parameter related widgets
287        """
288        param_txt = wx.StaticText(self, -1, 'Parameters : ') 
289        param_tip = "#Set the parameters and initial values.\n"
290        param_tip += "#Example:\n"
291        param_tip += "A = 1\nB = 1"
292        #param_txt.SetToolTipString(param_tip)
293        id  = wx.NewId() 
294        self.param_tcl = EditWindow(self, id, wx.DefaultPosition, 
295                            wx.DefaultSize, wx.CLIP_CHILDREN|wx.SUNKEN_BORDER)
296        self.param_tcl.setDisplayLineNumbers(True)
297        self.param_tcl.SetToolTipString(param_tip)
298        self.param_sizer.AddMany([(param_txt, 0, wx.LEFT, 10),
299                        (self.param_tcl, 1, wx.EXPAND|wx.ALL, 10)])
300
301   
302    def _layout_function(self):
303        """
304        Do the layout for function related widgets
305        """
306        function_txt = wx.StaticText(self, -1, 'Function(x) : ') 
307        hint_function = "#Example:\n"
308        hint_function += "new_x = x * math.pi\n"
309        hint_function += "if new_x <= 0:\n"
310        hint_function += "    y = A + B\n"
311        hint_function += "else:\n"
312        hint_function += "    y = A + B * numpy.cos(new_x)\n"
313        hint_function += "return y\n"
314        id  = wx.NewId() 
315        self.function_tcl = EditWindow(self, id, wx.DefaultPosition, 
316                            wx.DefaultSize, wx.CLIP_CHILDREN|wx.SUNKEN_BORDER)
317        self.function_tcl.setDisplayLineNumbers(True)
318        self.function_tcl.SetToolTipString(hint_function)
319        self.function_sizer.Add(function_txt, 0, wx.LEFT, 10)
320        self.function_sizer.Add( self.function_tcl, 1, wx.EXPAND|wx.ALL, 10)
321
322                   
323    def _layout_button(self): 
324        """
325        Do the layout for the button widgets
326        """         
327        self.bt_apply = wx.Button(self, -1, "Apply", size=(_BOX_WIDTH, -1))
328        self.bt_apply.SetToolTipString("Save changes into the imported data.")
329        self.bt_apply.Bind(wx.EVT_BUTTON, self.on_click_apply)
330       
331        self.bt_close = wx.Button(self, -1, 'Close', size=(_BOX_WIDTH, -1))
332        self.bt_close.Bind(wx.EVT_BUTTON, self.on_close)
333        self.bt_close.SetToolTipString("Close this panel.")
334       
335        self.button_sizer.AddMany([(self.bt_apply, 0, 
336                                    wx.LEFT, EDITOR_WIDTH * 0.8),
337                                   (self.bt_close, 0, 
338                                    wx.LEFT|wx.BOTTOM, 15)])
339       
340    def _do_layout(self):
341        """
342        Draw the current panel
343        """
344        self._define_structure()
345        self._layout_name()
346        self._layout_description()
347        self._layout_param()
348        self._layout_function()
349        self._layout_button()
350        self.main_sizer.AddMany([(self.name_sizer, 0, 
351                                        wx.EXPAND|wx.ALL, 5),
352                                 (wx.StaticLine(self), 0, 
353                                       wx.ALL|wx.EXPAND, 5),
354                                 (self.desc_sizer, 0, 
355                                        wx.EXPAND|wx.ALL, 5),
356                                 (wx.StaticLine(self), 0, 
357                                       wx.ALL|wx.EXPAND, 5),
358                                (self.param_sizer, 0,
359                                         wx.EXPAND|wx.ALL, 5),
360                                 (wx.StaticLine(self), 0, 
361                                       wx.ALL|wx.EXPAND, 5),
362                                (self.function_sizer, 1,
363                                         wx.EXPAND|wx.ALL, 5),
364                                 (wx.StaticLine(self), 0, 
365                                       wx.ALL|wx.EXPAND, 5),
366                                (self.button_sizer, 0,
367                                         wx.EXPAND|wx.ALL, 5)])
368        self.SetSizer(self.main_sizer)
369        self.SetAutoLayout(True)
370   
371    def get_notes(self):
372        """
373        return notes
374        """
375        return self._notes
376                 
377    def on_change_name(self, event=None):
378        """
379        Change name
380        """
381        if event is not None:
382            event.Skip()
383        self.name_tcl.SetBackgroundColour('white')
384        self.Refresh()
385   
386    def check_name(self):
387        """
388        Check name if exist already
389        """
390        self.on_change_name(None)
391        plugin_dir = self.path
392        list_fnames = os.listdir(plugin_dir)
393        # function/file name
394        title = self.name_tcl.GetValue().lstrip().rstrip()
395        self.name = title
396        t_fname = title + '.py'
397        if not self.overwrite_name:
398            if t_fname in list_fnames:
399                self.name_tcl.SetBackgroundColour('pink')
400                return False
401        self.fname = os.path.join(plugin_dir, t_fname)
402        self._notes += "Model function name set "
403        self._notes += "to %s. \n" % str(title)
404        return True
405   
406    def on_over_cb(self, event):
407        """
408        Set overwrite name flag on cb event
409        """
410        if event is not None:
411            event.Skip()
412        cb = event.GetEventObject()
413        self.overwrite_name = cb.GetValue()
414       
415    def on_click_apply(self, event):
416        """   
417        Changes are saved in data object imported to edit
418        """
419        #must post event here
420        event.Skip()
421        info = 'Info'
422        # Sort out the errors if occur
423        if self.check_name():
424            description = self.desc_tcl.GetValue()
425            param_str = self.param_tcl.GetText()
426            func_str = self.function_tcl.GetText()
427            # No input for the model function
428            if func_str.lstrip().rstrip():
429                self.write_file(self.fname, description, param_str, func_str)
430                tr_msg = _compileFile(self.fname)
431                msg = tr_msg.__str__()
432                # Compile error
433                if msg:
434                    _deleteFile(self.fname)
435                    msg +=  "\nCompile Failed"
436                else:
437                    msg = ''
438            else:
439                msg = 'Error: Function is not defined.'
440        else:
441            msg = "Name exists already."
442        # Prepare for the messagebox
443        if not msg:
444            if self.base != None:
445                self.base.update_custom_combo()
446            msg = "Successful!!!"
447            info = 'Info'
448        else:
449            info = 'Error'
450            wx.MessageBox(msg, info) 
451        # Send msg to the top window 
452        if self.base != None:
453                from sans.guiframe.events import StatusEvent
454                wx.PostEvent(self.base.parent, StatusEvent(status = msg, 
455                                                      info=info))
456        self.warning = msg
457
458               
459    def write_file(self, fname, desc_str, param_str, func_str): 
460        """
461        Write content in file
462       
463        :param fname: full file path
464        :param desc_str: content of the description strings
465        :param param_str: content of params; Strings 
466        :param func_str: content of func; Strings
467        """ 
468        try:
469            out_f =  open(fname,'w')
470        except :
471            raise
472        lines = CUSTOM_TEMPLATE.split('\n')
473        has_scipy = func_str.count("scipy.")
474        local_params = ''
475        spaces = '        '#8spaces
476        for line in lines:
477            # The location where to put the strings is
478            # hard-coded in the template as shown below.
479            if line.count("#self.params here"):
480                for param_line in param_str.split('\n'):
481                    p_line = param_line.lstrip().rstrip()
482                    if p_line:
483                        p0_line = self.set_param_helper(p_line)
484                        local_params += self.set_function_helper(p_line)
485                        out_f.write(p0_line)
486            elif line.count("#local params here"):
487                if local_params:
488                    out_f.write(local_params)
489            elif line.count("self.description = "):
490                desc = str(desc_str.lstrip().rstrip().replace('\"', ''))
491                if not desc:
492                    desc= self.name
493                out_f.write(line% desc + "\n")
494            elif line.count("#function here"):
495                for func_line in func_str.split('\n'):
496                    f_line = func_line.lstrip().rstrip()
497                    if f_line:
498                        out_f.write(spaces + f_line + "\n")
499                if not func_str:
500                    out_f.write(spaces + 'return y' + "\n")
501            elif line.count("#import scipy?"):
502                if has_scipy:
503                    out_f.write("import scipy" + "\n")
504            elif line.count("name = "):
505                out_f.write(line % self.name + "\n")
506            elif line:
507                out_f.write(line + "\n")
508        out_f.close() 
509   
510    def set_param_helper(self, line):   
511        """
512        Get string in line to define the params dictionary
513       
514        :param line: one line of string got from the param_str
515        """
516        flag = True
517        params_str = ''
518        spaces = '        '#8spaces
519        items = line.split(";")
520        for item in items:
521            name = item.split("=")[0].lstrip().rstrip()
522            value = item.split("=")[1].lstrip().rstrip()
523            try:
524                float(value)
525            except:
526               raise
527            params_str += spaces + "self.params['%s'] = %s\n"% (name, value)
528           
529        return params_str
530
531    def set_function_helper(self, line):   
532        """
533        Get string in line to define the local params
534       
535        :param line: one line of string got from the param_str
536        """
537        flag = True
538        params_str = ''
539        spaces = '        '#8spaces
540        items = line.split(";")
541        for item in items:
542            name = item.split("=")[0].lstrip().rstrip()
543            params_str += spaces + "%s = self.params['%s']\n"% (name, name)
544        return params_str
545   
546    def get_warning(self):
547        """
548        Get the warning msg
549        """
550        return self.warning
551       
552    def on_close(self, event):
553        """
554        leave data as it is and close
555        """
556        self.parent.Close()
557        event.Skip()
558       
559class EditorWindow(wx.Frame):
560    def __init__(self, parent, base, path, title, 
561                 size=(EDITOR_WIDTH, EDITOR_HEIGTH), *args, **kwds):
562        kwds["title"] = title
563        kwds["size"] = size
564        wx.Frame.__init__(self, parent=None, *args, **kwds)
565        self.parent = parent
566        self.panel = EditorPanel(parent=self, base=parent, 
567                                 path=path, title=title)
568        self.Show(True)
569        wx.EVT_CLOSE(self, self.OnClose)
570   
571    def OnClose(self, event): 
572        """
573        On close event
574        """
575        if self.parent != None:
576            self.parent.new_model_frame = None
577        self.Destroy() 
578
579## Templates for custom models
580CUSTOM_TEMPLATE = """
581from sans.models.pluginmodel import Model1DPlugin
582import math
583import numpy
584#import scipy?
585class Model(Model1DPlugin):
586    name = "%s"                             
587    def __init__(self):
588        Model1DPlugin.__init__(self, name=self.name)                                                     
589        #self.params here
590        self.description = "%s"
591        self.set_details()
592    def function(self, x = 0.0):
593        #local params here
594        #function here 
595######################################################################
596## THIS IS FOR TEST. DO NOT MODIFY THE FOLLOWING LINES!!!!!!!!!!!!!!!!       
597if __name__ == "__main__":
598    m= Model()
599    out1 = m.runXY(0.0)
600    out2 = m.runXY(0.01)
601    isfine1 = numpy.isfinite(out1)
602    isfine2 = numpy.isfinite(out2)
603    print "Testing the value at Q = 0.0:"
604    print out1, " : finite? ", isfine1
605    print "Testing the value at Q = 0.01:"
606    print out2, " : finite? ", isfine2
607    if isfine1 and isfine2:
608        print "===> Simple Test: Passed!"
609    else:
610        print "===> Simple Test: Failed!"
611"""       
612       
613SUM_TEMPLATE = """
614# A sample of an experimental model function for Sum(Pmodel1,Pmodel2)
615import copy
616from sans.models.pluginmodel import Model1DPlugin
617# User can change the name of the model (only with single functional model)
618#P1_model:
619from sans.models.%s import %s as P1
620
621#P2_model:
622from sans.models.%s import %s as P2
623
624class Model(Model1DPlugin):
625    name = ""
626    def __init__(self):
627        Model1DPlugin.__init__(self, name='')
628        p_model1 = P1()
629        p_model2 = P2()
630        ## Setting  model name model description
631        self.description=""
632        self.name = self._get_name(p_model1.name, p_model2.name)
633        self.description = p_model1.name
634        self.description += p_model2.name
635        self.fill_description(p_model1, p_model2)
636
637        ## Define parameters
638        self.params = {}
639
640        ## Parameter details [units, min, max]
641        self.details = {}
642       
643        # non-fittable parameters
644        self.non_fittable = p_model1.non_fittable 
645        self.non_fittable += p_model2.non_fittable 
646           
647        ##models
648        self.p_model1= p_model1
649        self.p_model2= p_model2
650       
651       
652        ## dispersion
653        self._set_dispersion()
654        ## Define parameters
655        self._set_params()
656        ## New parameter:Scaling factor
657        self.params['scale_factor'] = 1
658       
659        ## Parameter details [units, min, max]
660        self._set_details()
661        self.details['scale_factor'] = ['', None, None]
662
663       
664        #list of parameter that can be fitted
665        self._set_fixed_params() 
666        ## parameters with orientation
667        for item in self.p_model1.orientation_params:
668            new_item = "p1_" + item
669            if not new_item in self.orientation_params:
670                self.orientation_params.append(new_item)
671           
672        for item in self.p_model2.orientation_params:
673            new_item = "p2_" + item
674            if not new_item in self.orientation_params:
675                self.orientation_params.append(new_item)
676        # get multiplicity if model provide it, else 1.
677        try:
678            multiplicity1 = p_model1.multiplicity
679            try:
680                multiplicity2 = p_model2.multiplicity
681            except:
682                multiplicity2 = 1
683        except:
684            multiplicity1 = 1
685            multiplicity2 = 1
686        ## functional multiplicity of the model
687        self.multiplicity1 = multiplicity1 
688        self.multiplicity2 = multiplicity2   
689        self.multiplicity_info = []   
690       
691    def _clone(self, obj):
692        obj.params     = copy.deepcopy(self.params)
693        obj.description     = copy.deepcopy(self.description)
694        obj.details    = copy.deepcopy(self.details)
695        obj.dispersion = copy.deepcopy(self.dispersion)
696        obj.p_model1  = self.p_model1.clone()
697        obj.p_model2  = self.p_model2.clone()
698        #obj = copy.deepcopy(self)
699        return obj
700   
701    def _get_name(self, name1, name2):
702        name = self._get_upper_name(name1)
703        name += "+"
704        name += self._get_upper_name(name2)
705        return name
706   
707    def _get_upper_name(self, name=None):
708        if name == None:
709            return ""
710        upper_name = ""
711        str_name = str(name)
712        for index in range(len(str_name)):
713            if str_name[index].isupper():
714                upper_name += str_name[index]
715        return upper_name
716       
717    def _set_dispersion(self):
718        ##set dispersion only from p_model
719        for name , value in self.p_model1.dispersion.iteritems():
720            #if name.lower() not in self.p_model1.orientation_params:
721            new_name = "p1_" + name
722            self.dispersion[new_name]= value
723        for name , value in self.p_model2.dispersion.iteritems():
724            #if name.lower() not in self.p_model2.orientation_params:
725            new_name = "p2_" + name
726            self.dispersion[new_name]= value
727           
728    def function(self, x=0.0):
729        return 0
730                               
731    def getProfile(self):
732        try:
733            x,y = self.p_model1.getProfile()
734        except:
735            x = None
736            y = None
737           
738        return x, y
739   
740    def _set_params(self):
741        for name , value in self.p_model1.params.iteritems():
742            # No 2D-supported
743            #if name not in self.p_model1.orientation_params:
744            new_name = "p1_" + name
745            self.params[new_name]= value
746           
747        for name , value in self.p_model2.params.iteritems():
748            # No 2D-supported
749            #if name not in self.p_model2.orientation_params:
750            new_name = "p2_" + name
751            self.params[new_name]= value
752               
753        # Set "scale" as initializing
754        self._set_scale_factor()
755     
756           
757    def _set_details(self):
758        for name ,detail in self.p_model1.details.iteritems():
759            new_name = "p1_" + name
760            #if new_name not in self.orientation_params:
761            self.details[new_name]= detail
762           
763        for name ,detail in self.p_model2.details.iteritems():
764            new_name = "p2_" + name
765            #if new_name not in self.orientation_params:
766            self.details[new_name]= detail
767   
768    def _set_scale_factor(self):
769        pass
770       
771               
772    def setParam(self, name, value):
773        # set param to p1+p2 model
774        self._setParamHelper(name, value)
775       
776        ## setParam to p model
777        model_pre = name.split('_', 1)[0]
778        new_name = name.split('_', 1)[1]
779        if model_pre == "p1":
780            if new_name in self.p_model1.getParamList():
781                self.p_model1.setParam(new_name, value)
782        elif model_pre == "p2":
783             if new_name in self.p_model2.getParamList():
784                self.p_model2.setParam(new_name, value)
785        elif name.lower() == 'scale_factor':
786            self.params['scale_factor'] = value
787        else:
788            raise ValueError, "Model does not contain parameter %s" % name
789           
790    def getParam(self, name):
791        # Look for dispersion parameters
792        toks = name.split('.')
793        if len(toks)==2:
794            for item in self.dispersion.keys():
795                # 2D not supported
796                if item.lower()==toks[0].lower():
797                    for par in self.dispersion[item]:
798                        if par.lower() == toks[1].lower():
799                            return self.dispersion[item][par]
800        else:
801            # Look for standard parameter
802            for item in self.params.keys():
803                if item.lower()==name.lower():
804                    return self.params[item]
805        return 
806        #raise ValueError, "Model does not contain parameter %s" % name
807       
808    def _setParamHelper(self, name, value):
809        # Look for dispersion parameters
810        toks = name.split('.')
811        if len(toks)== 2:
812            for item in self.dispersion.keys():
813                if item.lower()== toks[0].lower():
814                    for par in self.dispersion[item]:
815                        if par.lower() == toks[1].lower():
816                            self.dispersion[item][par] = value
817                            return
818        else:
819            # Look for standard parameter
820            for item in self.params.keys():
821                if item.lower()== name.lower():
822                    self.params[item] = value
823                    return
824           
825        raise ValueError, "Model does not contain parameter %s" % name
826             
827   
828    def _set_fixed_params(self):
829        for item in self.p_model1.fixed:
830            new_item = "p1" + item
831            self.fixed.append(new_item)
832        for item in self.p_model2.fixed:
833            new_item = "p2" + item
834            self.fixed.append(new_item)
835
836        self.fixed.sort()
837               
838                   
839    def run(self, x = 0.0):
840        self._set_scale_factor()
841        return self.params['scale_factor'] * \
842(self.p_model1.run(x) + self.p_model2.run(x))
843   
844    def runXY(self, x = 0.0):
845        self._set_scale_factor()
846        return self.params['scale_factor'] * \
847(self.p_model1.runXY(x) + self.p_model2.runXY(x))
848   
849    ## Now (May27,10) directly uses the model eval function
850    ## instead of the for-loop in Base Component.
851    def evalDistribution(self, x = []):
852        self._set_scale_factor()
853        return self.params['scale_factor'] * \
854(self.p_model1.evalDistribution(x) + \
855self.p_model2.evalDistribution(x))
856
857    def set_dispersion(self, parameter, dispersion):
858        value= None
859        new_pre = parameter.split("_", 1)[0]
860        new_parameter = parameter.split("_", 1)[1]
861        try:
862            if new_pre == 'p1' and \
863new_parameter in self.p_model1.dispersion.keys():
864                value= self.p_model1.set_dispersion(new_parameter, dispersion)
865            if new_pre == 'p2' and \
866new_parameter in self.p_model2.dispersion.keys():
867                value= self.p_model2.set_dispersion(new_parameter, dispersion)
868            self._set_dispersion()
869            return value
870        except:
871            raise
872
873    def fill_description(self, p_model1, p_model2):
874        description = ""
875        description +="This model gives the summation of  %s and %s. "% \
876( p_model1.name, p_model2.name )
877        self.description += description
878       
879if __name__ == "__main__":
880    m1= Model()
881    #m1.setParam("p1_scale", 25) 
882    #m1.setParam("p1_length", 1000)
883    #m1.setParam("p2_scale", 100)
884    #m1.setParam("p2_rg", 100)
885    out1 = m1.runXY(0.01)
886
887    m2= Model()
888    #m2.p_model1.setParam("scale", 25)
889    #m2.p_model1.setParam("length", 1000)
890    #m2.p_model2.setParam("scale", 100)
891    #m2.p_model2.setParam("rg", 100)
892    out2 = m2.p_model1.runXY(0.01) + m2.p_model2.runXY(0.01)
893    print out1, " = ", out2
894    if out1 == out2:
895        print "===> Simple Test: Passed!"
896    else:
897        print "===> Simple Test: Failed!"
898"""
899     
900#if __name__ == "__main__":
901#    app = wx.PySimpleApp()
902#    frame = TextDialog(id=1, model_list=["SphereModel", "CylinderModel"])   
903#    frame.Show(True)
904#    app.MainLoop()             
905
906if __name__ == "__main__":
907    from sans.perspectives.fitting import models
908    dir_path = models.find_plugins_dir()
909    app  = wx.App()
910    window = EditorWindow(parent=None, base=None, path=dir_path, title="AAA")
911    app.MainLoop()         
Note: See TracBrowser for help on using the repository browser.