source: sasview/sansview/perspectives/fitting/fitpage.py @ fe9c19b4

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 fe9c19b4 was 7975f2b, checked in by Jae Cho <jhjcho@…>, 15 years ago

correction of chi2 value from park, cleaned unnecessary calculation, reduced mac crash by placing sleep(0.5) between layouts.

  • Property mode set to 100644
File size: 62.9 KB
RevLine 
[d1e0473]1
2
[c77d859]3import sys
4import wx
5import wx.lib.newevent
6import numpy
7import copy
8import math
[7975f2b]9import time
[c77d859]10from sans.models.dispersion_models import ArrayDispersion, GaussianDispersion
11
12from sans.guicomm.events import StatusEvent   
[7975f2b]13from sans.guiframe.utils import format_number,check_float,check_value
14 
[b787e68c]15## event to post model to fit to fitting plugins
[c77d859]16(ModelEventbox, EVT_MODEL_BOX) = wx.lib.newevent.NewEvent()
[b787e68c]17
18## event to know the selected fit engine
[77e23a2]19(FitterTypeEvent, EVT_FITTER_TYPE)   = wx.lib.newevent.NewEvent()
[34a0c17]20(FitStopEvent, EVT_FIT_STOP)   = wx.lib.newevent.NewEvent()
[eda428b]21_BOX_WIDTH = 76
[c77d859]22
23import basepage
24from basepage import BasicPage
[b787e68c]25from basepage import PageInfoEvent
[997131a]26from DataLoader.qsmearing import smear_selection
[c77d859]27
28class FitPage(BasicPage):
29    """
30        FitPanel class contains fields allowing to display results when
31        fitting  a model and one data
32        @note: For Fit to be performed the user should check at least one parameter
33        on fit Panel window.
34 
35    """
[7975f2b]36   
[cfc0913]37    def __init__(self,parent, page_info):
38        BasicPage.__init__(self, parent, page_info)
[7975f2b]39
[c77d859]40        """
41            Initialization of the Panel
42        """
43        ## fit page does not content npts txtcrtl
44        self.npts=None
[2b63df0]45        ## thread for compute Chisqr
46        self.calc_Chisqr=None
[dcf29d7]47        ## default fitengine type
[707436d]48        self.engine_type = None
[edd166b]49       
[b787e68c]50        ## draw sizer
[c77d859]51        self._fill_datainfo_sizer()
[da26c1a]52       
[c77d859]53        self._fill_model_sizer( self.sizer1)
[7ad6ff5]54 
[cfc0913]55        self._fill_range_sizer() 
[fbf4bf8]56        #self._on_select_model(event=None)
[997131a]57        if self.data !=None:
58            self.smearer = smear_selection( self.data )
[847091f]59            if self.smearer ==None:
60                self.enable_smearer.Disable()
61                self.disable_smearer.Disable()
[edd166b]62        self.disp_cb_dict = {}
[cfc0913]63        ## to update the panel according to the fit engine type selected
[77e23a2]64        self.Bind(EVT_FITTER_TYPE,self._on_engine_change)
[34a0c17]65        self.Bind(EVT_FIT_STOP,self._on_fit_complete)
[c69b6d5]66
[34a0c17]67    def _on_fit_complete(self, event):
68        """
69            When fit is complete ,reset the fit button label.
70        """
71        #self.btFit.SetLabel("Fit")
72        #self.btFit.Unbind(event=wx.EVT_BUTTON, id=self.btFit.GetId())
73        #self.btFit.Bind(event=wx.EVT_BUTTON, handler=self._onFit,id=self.btFit.GetId())
74        pass
75       
76       
[77e23a2]77    def _on_engine_change(self, event):
78        """
79            get an event containing the current name of the fit engine type
80            @param event: FitterTypeEvent containing  the name of the current engine
81        """
[dcf29d7]82        self.engine_type = event.type
[77e23a2]83        if len(self.parameters)==0:
[edd166b]84            self.Layout()
[77e23a2]85            return
[ad6dd4c]86        if event.type =="park":
87            self.btFit.SetLabel("Fit")
[6d91073]88
[77e23a2]89        for item in self.parameters:
[920a6e5]90            if event.type =="scipy" :
[60132ef]91                item[5].SetValue("")
[77e23a2]92                item[5].Hide()
[60132ef]93                item[6].SetValue("")
[77e23a2]94                item[6].Hide()
95                self.text2_min.Hide()
96                self.text2_max.Hide()
[7975f2b]97
[77e23a2]98            else:
99                item[5].Show(True)
100                item[6].Show(True)
101                self.text2_min.Show(True)
102                self.text2_max.Show(True)
[920a6e5]103        for item in self.fittable_param:
104            if item[5]!=None and item[6]!=None and not item in self.orientation_params_disp:
105                if event.type =="scipy" and not item in self.orientation_params:
[c5cd3b9]106                    item[5].SetValue("")
107                    item[5].Hide()
108                    item[6].SetValue("")
109                    item[6].Hide()
110                    self.text2_min.Hide()
111                    self.text2_max.Hide()
[920a6e5]112                    self.text_disp_min.Hide()
113                    self.text_disp_max.Hide()
[c5cd3b9]114                else:
115                    item[5].Show(True)
116                    item[6].Show(True)
117                    self.text2_min.Show(True)
118                    self.text2_max.Show(True)
[920a6e5]119                    self.text_disp_min.Show(True)
120                    self.text_disp_max.Show(True)
[c5cd3b9]121           
[920a6e5]122        for item in self.orientation_params:
[c5cd3b9]123            if item[5]!=None and item[6]!=None:
124                if event.type =="scipy" or self.data.__class__.__name__ !="Data2D":
125                    item[5].SetValue("")
126                    item[5].Hide()
127                    item[6].SetValue("")
128                    item[6].Hide()
129                else:
130                    item[5].Show(True)
131                    item[6].Show(True)
[920a6e5]132                   
133        for item in self.orientation_params_disp:         
134            if item[5]!=None and item[6]!=None:
135                if event.type =="scipy" or self.data.__class__.__name__ !="Data2D":
136                    item[5].SetValue("")
137                    item[5].Hide()
138                    item[6].SetValue("")
139                    item[6].Hide()
140                else:
141                    item[5].Show(True)
142                    item[6].Show(True)
[6d91073]143        self.Layout()
[7975f2b]144        self.Refresh()
145
[c77d859]146    def _fill_range_sizer(self):
147        """
148            Fill the sizer containing the plotting range
149            add  access to npts
150        """
[ff8f99b]151        title = "Fitting"
152        box_description_range = wx.StaticBox(self, -1,str(title))
153        boxsizer_range = wx.StaticBoxSizer(box_description_range, wx.VERTICAL)
154
[1ae3fe1]155        sizer_fit = wx.GridSizer(1, 1,0, 0)
[c77d859]156   
[e3a76c8]157        self.btFit = wx.Button(self,wx.NewId(),'Fit', size=(80,23))
[c77d859]158        self.btFit.Bind(wx.EVT_BUTTON, self._onFit,id= self.btFit.GetId())
159        self.btFit.SetToolTipString("Perform fit.")
[2d5f7a1]160     
[c77d859]161       
162        sizer_fit.Add((5,5),1, wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 5)       
[9170547]163        sizer_fit.Add(self.btFit,0, wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 35) 
[ff8f99b]164        sizer_fit.Layout()
[c77d859]165        sizer_smearer = wx.BoxSizer(wx.HORIZONTAL)
166        #Filling the sizer containing instruments smearing info.
167        self.disable_smearer = wx.RadioButton(self, -1, 'No', style=wx.RB_GROUP)
168        self.enable_smearer = wx.RadioButton(self, -1, 'Yes')
169        self.Bind(wx.EVT_RADIOBUTTON, self.onSmear, id=self.disable_smearer.GetId())
170        self.Bind(wx.EVT_RADIOBUTTON, self.onSmear, id=self.enable_smearer.GetId())
[ff8f99b]171        self.disable_smearer.SetValue(True)
[c77d859]172       
173        sizer_smearer.Add(wx.StaticText(self,-1,'Instrument Smearing? '))
174        sizer_smearer.Add((10, 10))
175        sizer_smearer.Add( self.enable_smearer )
176        sizer_smearer.Add((10,10))
177        sizer_smearer.Add( self.disable_smearer )
[7b0fd65]178        #Display Chi^2/dof
[e3a76c8]179        sizer_smearer.Add((78,10))
[7b0fd65]180        box_description= wx.StaticBox(self, -1,'Chi2/dof')
181        boxsizer1 = wx.StaticBoxSizer(box_description, wx.VERTICAL)
[9170547]182        boxsizer1.SetMinSize((80,-1))
[2b63df0]183        temp_smearer = None
184        if self.enable_smearer.GetValue():
185            temp_smearer= self.smearer
186       
187        self.tcChi    =  wx.StaticText(self, -1, "-", style=wx.ALIGN_LEFT)
188         
[7b0fd65]189        boxsizer1.Add( self.tcChi )   
190        sizer_smearer.Add( boxsizer1 )
191               
192        #Set sizer for Fitting section
[ff8f99b]193        self._set_range_sizer( title=title,box_sizer=boxsizer_range, object1=sizer_smearer, object= sizer_fit)
[7975f2b]194
[c77d859]195    def _fill_datainfo_sizer(self):
196        """
197            fill sizer 0 with data info
198        """
199        self.sizer0.Clear(True)
200        ## no loaded data , don't fill the sizer
201        if self.data== None:
202            self.sizer0.Layout()
203            return
204       
[fa58441]205        box_description= wx.StaticBox(self, -1, 'Data')
[c77d859]206        boxsizer1 = wx.StaticBoxSizer(box_description, wx.VERTICAL)
207        #----------------------------------------------------------
208        sizer_data = wx.GridSizer(3, 3,5, 5)
209        #Filling the sizer containing data related fields
210        DataSource  =wx.StaticText(self, -1,str(self.data.name))
211
[fa58441]212        sizer_data.Add(wx.StaticText(self, -1, 'Source Name : '))
[c77d859]213        sizer_data.Add(DataSource )
[2a5bba7]214        sizer_data.Add( (0,5) )
[c77d859]215       
216        #---------sizer 2 draw--------------------------------
217        #set maximum range for x in linear scale
218        if not hasattr(self.data,"data"): #Display only for 1D data fit
219            # Minimum value of data   
[813334e]220            data_min = min(self.data.x)
[c77d859]221            # Maximum value of data 
[813334e]222            data_max = max(self.data.x)
[7b0fd65]223            text4_3 = wx.StaticText(self, -1, 'Total Q Range (1/A)',
[c77d859]224                                     style=wx.ALIGN_LEFT)
225            sizer_data.Add( text4_3 )
[813334e]226            sizer_data.Add(wx.StaticText(self, -1, "Min : %s"%str(data_min)))
227            sizer_data.Add(wx.StaticText(self, -1, "Max : %s"%str(data_max)))
[c77d859]228           
229        else:
[813334e]230            ## Minimum value of data
231            data_min= 0
232            x= max(math.fabs(self.data.xmin), math.fabs(self.data.xmax)) 
233            y= max(math.fabs(self.data.ymin), math.fabs(self.data.ymax))
234            ## Maximum value of data 
235            data_max = math.sqrt(x*x + y*y)
236         
[d2d0cfdf]237            #For qmin and qmax, do not use format_number
238            #.(If do, qmin and max could be different from what is in the data.)
[d1e0473]239            text4_3 = wx.StaticText(self, -1, "Total Q Range (1/A)",
[c77d859]240                                     style=wx.ALIGN_LEFT)
241            sizer_data.Add( text4_3 )
[813334e]242            sizer_data.Add(wx.StaticText(self, -1, "Min : %s"%str(data_min)))
243            sizer_data.Add(wx.StaticText(self, -1, "Max : %s"%str(data_max)))
244        ## set q range to plot
245        self.qmin_x= data_min
246        self.qmax_x= data_max
247
[c77d859]248        boxsizer1.Add(sizer_data)
249        #------------------------------------------------------------
250        self.sizer0.Add(boxsizer1,0, wx.EXPAND | wx.ALL, 10)
251        self.sizer0.Layout()
[813334e]252       
[c77d859]253    def _fill_model_sizer(self, sizer):
254        """
255            fill sizer containing model info
256        """
[7ad6ff5]257        ##Add model function Details button in fitpanel.
[ff8f99b]258        ##The following 3 lines are for Mac. Let JHC know before modifying...
259        title = "Model"
260        box_description= wx.StaticBox(self, -1,str(title))
261        boxsizer1 = wx.StaticBoxSizer(box_description, wx.VERTICAL)
262         
[7ad6ff5]263        id = wx.NewId()
[e3a76c8]264        self.model_help =wx.Button(self,id,'Details', size=(80,23))
[7ad6ff5]265        self.model_help.Bind(wx.EVT_BUTTON, self.on_model_help_clicked,id=id)
266        self.model_help.SetToolTipString("Model Function Help")
[7b0fd65]267       
[7ad6ff5]268        ## class base method  to add view 2d button   
[ff8f99b]269        self._set_model_sizer(sizer=sizer, box_sizer=boxsizer1, title="Model",object=self.model_help )   
[7ad6ff5]270
[c77d859]271   
[30d103a]272    def _set_sizer_dispersion(self, dispersity):
[c77d859]273        """
274            draw sizer with gaussian dispersity parameters
275        """
276        self.fittable_param=[]
277        self.fixed_param=[]
[60132ef]278        self.orientation_params_disp=[]
[920a6e5]279
[c77d859]280        self.sizer4_4.Clear(True)
281        if self.model==None:
282            ##no model is selected
283            return
284        if not self.enable_disp.GetValue():
285            ## the user didn't select dispersity display
286            return 
[b421b1a]287           
[376916c]288        self._reset_dispersity()
[b421b1a]289       
[376916c]290        # Create the dispersion objects
291        for item in self.model.dispersion.keys():
[30d103a]292            #disp_model =  GaussianDispersion()
293            disp_model = dispersity()
[376916c]294            self._disp_obj_dict[item] = disp_model
295            self.model.set_dispersion(item, disp_model)
[c477b31]296            self.state._disp_obj_dict[item]= disp_model
[376916c]297
[b421b1a]298
[c77d859]299        ix=0
300        iy=1
301        disp = wx.StaticText(self, -1, 'Names')
302        self.sizer4_4.Add(disp,( iy, ix),(1,1), 
303                           wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
304        ix += 1 
[a720d1f]305        values = wx.StaticText(self, -1, 'Sigmas (STD)')
[c77d859]306        self.sizer4_4.Add(values,( iy, ix),(1,1), wx.EXPAND|wx.ADJUST_MINSIZE, 0)
307        ix +=2 
[920a6e5]308        self.text_disp_1 = wx.StaticText(self, -1, '')
[c77d859]309        self.sizer4_4.Add( self.text_disp_1,(iy, ix),(1,1),\
310                            wx.EXPAND|wx.ADJUST_MINSIZE, 0) 
311        self.text_disp_1.Hide()
[920a6e5]312       
313       
314        ix +=1 
315        self.text_disp_min = wx.StaticText(self, -1, 'Min')
316        self.sizer4_4.Add(self.text_disp_min,(iy, ix),(1,1),\
317                            wx.EXPAND|wx.ADJUST_MINSIZE, 0) 
318        self.text_disp_min.Hide()
319        ix +=1 
320        self.text_disp_max = wx.StaticText(self, -1, 'Max')
321        self.sizer4_4.Add(self.text_disp_max,(iy, ix),(1,1),\
322                            wx.EXPAND|wx.ADJUST_MINSIZE, 0) 
323        self.text_disp_max.Hide()
324                       
325       
[c77d859]326        ix += 1 
327        npts = wx.StaticText(self, -1, 'Npts')
328        self.sizer4_4.Add(npts,( iy, ix),(1,1), wx.EXPAND|wx.ADJUST_MINSIZE, 0)
329        ix += 1 
330        nsigmas = wx.StaticText(self, -1, 'Nsigmas')
331        self.sizer4_4.Add(nsigmas,( iy, ix),(1,1), wx.EXPAND|wx.ADJUST_MINSIZE, 0)
[920a6e5]332       
333        if self.engine_type=="park":
334            self.text_disp_max.Show(True)
335            self.text_disp_min.Show(True)
[6dc9ad8]336
[c77d859]337        for item in self.model.dispersion.keys():
[780d095]338            if not item in self.model.orientation_params:
[edd166b]339                if not self.disp_cb_dict.has_key(item):
340                    self.disp_cb_dict[item]= None
[780d095]341                name1=item+".width"
342                name2=item+".npts"
343                name3=item+".nsigmas"
[c99a6c5]344                if not self.model.details.has_key(name1):
[b421b1a]345                    self.model.details [name1] = ["",None,None] 
[c99a6c5]346
[780d095]347                iy += 1
348                for p in self.model.dispersion[item].keys(): 
349       
350                    if p=="width":
351                        ix = 0
352                        cb = wx.CheckBox(self, -1, name1, (10, 10))
353                        wx.EVT_CHECKBOX(self, cb.GetId(), self.select_param)
354                        self.sizer4_4.Add( cb,( iy, ix),(1,1), 
355                                           wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
356                        ix = 1
357                        value= self.model.getParam(name1)
[7975f2b]358                        ctl1 = self.ModelTextCtrl(self, -1, size=(_BOX_WIDTH,20),
[c77d859]359                                            style=wx.TE_PROCESS_ENTER)
[780d095]360                        ctl1.SetValue(str (format_number(value)))
361                        self.sizer4_4.Add(ctl1, (iy,ix),(1,1),wx.EXPAND)
362                        ## text to show error sign
363                        ix = 2
364                        text2=wx.StaticText(self, -1, '+/-')
365                        self.sizer4_4.Add(text2,(iy, ix),(1,1),
366                                          wx.EXPAND|wx.ADJUST_MINSIZE, 0)
367                        text2.Hide() 
[b421b1a]368
[780d095]369                        ix = 3
[c13b8cc]370                        ctl2 = wx.TextCtrl(self, -1, size=(_BOX_WIDTH,20), style=0)
[eacf1d66]371                 
[780d095]372                        self.sizer4_4.Add(ctl2, (iy,ix),(1,1), wx.EXPAND|wx.ADJUST_MINSIZE, 0)
[eacf1d66]373                     
[b421b1a]374                        ctl2.Hide()
[eacf1d66]375
[920a6e5]376                        ix = 4
[7975f2b]377                        ctl3 = self.ModelTextCtrl(self, -1, size=(_BOX_WIDTH/2,20), style=wx.TE_PROCESS_ENTER,
[e2f7b92]378                                                       kill_focus_callback = self._onparamRangeEnter,
[7975f2b]379                                                       text_enter_callback = self._onparamRangeEnter)
[eacf1d66]380
[920a6e5]381                        self.sizer4_4.Add(ctl3, (iy,ix),(1,1), wx.EXPAND|wx.ADJUST_MINSIZE, 0)
382                        ctl3.Hide()
383               
384                        ix = 5
[7975f2b]385                        ctl4 = self.ModelTextCtrl(self, -1, size=(_BOX_WIDTH/2,20), style=wx.TE_PROCESS_ENTER,
[e2f7b92]386                                                       kill_focus_callback = self._onparamRangeEnter,
[7975f2b]387                                                       text_enter_callback = self._onparamRangeEnter)
[920a6e5]388                        self.sizer4_4.Add(ctl4, (iy,ix),(1,1), wx.EXPAND|wx.ADJUST_MINSIZE, 0)
[eacf1d66]389
[920a6e5]390                        ctl4.Hide()
391                       
392                        if self.engine_type=="park":
393                            ctl3.Show(True)
394                            ctl4.Show(True)
395                                         
[780d095]396                        self.fittable_param.append([cb,name1,ctl1,text2,
[c99a6c5]397                                                    ctl2, ctl3, ctl4,None])                   
[920a6e5]398                   
[780d095]399                    elif p=="npts":
[920a6e5]400                            ix = 6
[780d095]401                            value= self.model.getParam(name2)
[7975f2b]402                            Tctl = self.ModelTextCtrl(self, -1, size=(_BOX_WIDTH/2,20),
[780d095]403                                                style=wx.TE_PROCESS_ENTER)
404                           
405                            Tctl.SetValue(str (format_number(value)))
406                            self.sizer4_4.Add(Tctl, (iy,ix),(1,1),
407                                               wx.EXPAND|wx.ADJUST_MINSIZE, 0)
408                            self.fixed_param.append([None,name2, Tctl,None,None,
409                                                      None, None,None])
410                    elif p=="nsigmas":
[920a6e5]411                            ix = 7
[780d095]412                            value= self.model.getParam(name3)
[7975f2b]413                            Tct2 = self.ModelTextCtrl(self, -1, size=(_BOX_WIDTH/2,20),
[780d095]414                                                style=wx.TE_PROCESS_ENTER)
[c985bef]415                            Tct2.SetValue(str (format_number(value)))
416                            self.sizer4_4.Add(Tct2, (iy,ix),(1,1),
[780d095]417                                               wx.EXPAND|wx.ADJUST_MINSIZE, 0)
418                            ix +=1
419                            self.sizer4_4.Add((20,20), (iy,ix),(1,1),
420                                               wx.EXPAND|wx.ADJUST_MINSIZE, 0)
421                           
[c985bef]422                            self.fixed_param.append([None,name3, Tct2
[920a6e5]423                                                     ,None,None,None, None,None])
424                           
[780d095]425        ix =0
426        iy +=1 
427        self.sizer4_4.Add((20,20),(iy,ix),(1,1), wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15) 
428        for item in self.model.dispersion.keys():
429            if  item in self.model.orientation_params:
[edd166b]430                if not self.disp_cb_dict.has_key(item):
431                    self.disp_cb_dict[item]= None
[780d095]432                name1=item+".width"
433                name2=item+".npts"
434                name3=item+".nsigmas"
[c99a6c5]435                if not self.model.details.has_key(name1):
[b421b1a]436                    self.model.details [name1] = ["",None,None]                 
437 
438
[780d095]439                iy += 1
440                for p in self.model.dispersion[item].keys(): 
441       
442                    if p=="width":
443                        ix = 0
444                        cb = wx.CheckBox(self, -1, name1, (10, 10))
445                        wx.EVT_CHECKBOX(self, cb.GetId(), self.select_param)
446                        self.sizer4_4.Add( cb,( iy, ix),(1,1), 
447                                           wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
448                        if self.data.__class__.__name__ =="Data2D":
[6dc9ad8]449                            cb.Show(True)
[c99a6c5]450                        elif cb.IsShown():
[6dc9ad8]451                            cb.Hide()
[780d095]452                        ix = 1
453                        value= self.model.getParam(name1)
[7975f2b]454                        ctl1 = self.ModelTextCtrl(self, -1, size=(_BOX_WIDTH,20),
[c77d859]455                                            style=wx.TE_PROCESS_ENTER)
[780d095]456                        ctl1.SetValue(str (format_number(value)))
457                        if self.data.__class__.__name__ =="Data2D":
[6dc9ad8]458                            ctl1.Show(True)
[c99a6c5]459                        elif ctl1.IsShown():
[6dc9ad8]460                            ctl1.Hide()
[780d095]461                        self.sizer4_4.Add(ctl1, (iy,ix),(1,1),wx.EXPAND)
462                        ## text to show error sign
463                        ix = 2
464                        text2=wx.StaticText(self, -1, '+/-')
465                        self.sizer4_4.Add(text2,(iy, ix),(1,1),
466                                          wx.EXPAND|wx.ADJUST_MINSIZE, 0)
467                        text2.Hide() 
[b421b1a]468
[780d095]469                        ix = 3
[c13b8cc]470                        ctl2 = wx.TextCtrl(self, -1, size=(_BOX_WIDTH,20), style=0)
[b421b1a]471                   
[780d095]472                        self.sizer4_4.Add(ctl2, (iy,ix),(1,1), wx.EXPAND|wx.ADJUST_MINSIZE, 0)
[b421b1a]473                        ctl2.Hide()
[920a6e5]474                           
475                        ix = 4
[7975f2b]476                        ctl3 = self.ModelTextCtrl(self, -1, size=(_BOX_WIDTH/2,20), style=wx.TE_PROCESS_ENTER,
[920a6e5]477                                                       kill_focus_callback = self._onparamRangeEnter,
[7975f2b]478                                                       text_enter_callback = self._onparamRangeEnter)
[eacf1d66]479
[920a6e5]480                        self.sizer4_4.Add(ctl3, (iy,ix),(1,1), wx.EXPAND|wx.ADJUST_MINSIZE, 0)
[c99a6c5]481
[920a6e5]482                        ctl3.Hide()
483               
484                        ix = 5
[7975f2b]485                        ctl4 = self.ModelTextCtrl(self, -1, size=(_BOX_WIDTH/2,20), style=wx.TE_PROCESS_ENTER,
[920a6e5]486                                                       kill_focus_callback = self._onparamRangeEnter,
[7975f2b]487                                                       text_enter_callback = self._onparamRangeEnter)
[920a6e5]488                        self.sizer4_4.Add(ctl4, (iy,ix),(1,1), wx.EXPAND|wx.ADJUST_MINSIZE, 0)
489                        ctl4.Hide()
[c99a6c5]490                        #if self.data.__class__.__name__ =="Data2D":
491                            #ctl4.Enable(True)
492                        #elif ctl4.Shown():
493                            #ctl4.Hide()
[920a6e5]494                       
495                        if self.engine_type=="park" and self.data.__class__.__name__ =="Data2D":
496                            ctl3.Show(True)
[c99a6c5]497                            ctl4.Show(True) 
[920a6e5]498                           
499                           
500                           
501                           
[780d095]502                        self.fittable_param.append([cb,name1,ctl1,text2,
[920a6e5]503                                                    ctl2, ctl3, ctl4,None])
[60132ef]504                        self.orientation_params_disp.append([cb,name1,ctl1,text2,
[920a6e5]505                                                    ctl2, ctl3, ctl4,None])
[780d095]506                    elif p=="npts":
[920a6e5]507                            ix = 6
[780d095]508                            value= self.model.getParam(name2)
[7975f2b]509                            Tctl = self.ModelTextCtrl(self, -1, size=(_BOX_WIDTH/2,20),
[780d095]510                                                style=wx.TE_PROCESS_ENTER)
511                           
512                            Tctl.SetValue(str (format_number(value)))
513                            if self.data.__class__.__name__ =="Data2D":
[6dc9ad8]514                                Tctl.Show(True)
[780d095]515                            else:
[6dc9ad8]516                                Tctl.Hide()
[780d095]517                            self.sizer4_4.Add(Tctl, (iy,ix),(1,1),
518                                               wx.EXPAND|wx.ADJUST_MINSIZE, 0)
519                            self.fixed_param.append([None,name2, Tctl,None,None,
520                                                      None, None,None])
[60132ef]521                            self.orientation_params_disp.append([None,name2, Tctl,None,None,
[780d095]522                                                      None, None,None])
523                    elif p=="nsigmas":
[920a6e5]524                            ix = 7
[780d095]525                            value= self.model.getParam(name3)
[7975f2b]526                            Tct2 = self.ModelTextCtrl(self, -1, size=(_BOX_WIDTH/2,20),
[780d095]527                                                style=wx.TE_PROCESS_ENTER)
[c985bef]528                            Tct2.SetValue(str (format_number(value)))
[780d095]529                            if self.data.__class__.__name__ =="Data2D":
[c985bef]530                                Tct2.Show(True)
[780d095]531                            else:
[c985bef]532                                Tct2.Hide()
533                            self.sizer4_4.Add(Tct2, (iy,ix),(1,1),
[780d095]534                                               wx.EXPAND|wx.ADJUST_MINSIZE, 0)
535                            ix +=1
[7975f2b]536
[c985bef]537                            self.fixed_param.append([None,name3, Tct2
[780d095]538                                                     ,None,None, None, None,None])   
[920a6e5]539                                                       
[c985bef]540                            self.orientation_params_disp.append([None,name3, Tct2
[1c1436d]541                                                     ,None,None, None, None,None])
[edd166b]542        """
[c99a6c5]543        #Display units text on panel
[b421b1a]544        for item in self.model.dispersion.keys():
545            name = item +".width" 
[edd166b]546        """
[b421b1a]547        self.state.disp_cb_dict = copy.deepcopy(self.disp_cb_dict) 
548         
[71f0373]549        self.state.model = self.model.clone() 
[240b9966]550         ## save state into
[4043c96]551        self.state.cb1 = self.cb1.GetValue()
[920a6e5]552        self._copy_parameters_state(self.parameters, self.state.parameters)
[240b9966]553        self._copy_parameters_state(self.orientation_params_disp,
554                                     self.state.orientation_params_disp)
555        self._copy_parameters_state(self.fittable_param, self.state.fittable_param)
556        self._copy_parameters_state(self.fixed_param, self.state.fixed_param)
[d40a9cd]557
558
[c77d859]559        wx.PostEvent(self.parent, StatusEvent(status=\
560                        " Selected Distribution: Gaussian"))   
[c13b8cc]561        ix =0 
[c77d859]562        iy +=1 
[7975f2b]563
[71f0373]564        self.Layout()
[7975f2b]565
566
[c77d859]567    def _onFit(self, event):     
568        """
569            Allow to fit
570        """
[c13b8cc]571        #make sure all parameter values are updated.
[7975f2b]572       
[c13b8cc]573        flag = self._update_paramv_on_fit() #check_value( self.qmin, self.qmax)
[acd0bda3]574               
[c77d859]575        if not flag:
576            msg= "Fitting range invalid"
577            wx.PostEvent(self.parent.parent, StatusEvent(status= msg ))
578            return 
579       
580        if len(self.param_toFit) <= 0:
581            msg= "Select at least one parameter to fit"
582            wx.PostEvent(self.parent.parent, StatusEvent(status= msg ))
583            return 
[7975f2b]584     
585
586        self.select_param(event =None)
[acd0bda3]587       
[c99a6c5]588        #Clear errors if exist from previous fitting
[edd166b]589        #self._clear_Err_on_Fit()
[d0ce2c30]590
[c13b8cc]591        # Remove or do not allow fitting on the Q=0 point, especially when y(q=0)=None at x[0].         
[1c1436d]592        self.qmin_x = float(self.qmin.GetValue())
[c13b8cc]593        self.qmax_x = float( self.qmax.GetValue())
[6f023e8]594        self.manager._reset_schedule_problem( value=0)
[ca7a626]595        self.manager.schedule_for_fit( value=1,page=self,fitproblem =None) 
596        self.manager.set_fit_range(page= self,qmin= self.qmin_x, qmax= self.qmax_x)
[ad6dd4c]597       
[c77d859]598        #single fit
[ca7a626]599        self.manager.onFit()
[ad6dd4c]600        ## allow stopping the fit
[34a0c17]601        #if self.engine_type=="scipy":
602        #    self.btFit.SetLabel("Stop")
603        #    self.btFit.Unbind(event=wx.EVT_BUTTON, id= self.btFit.GetId())
604        #    self.btFit.Bind(event= wx.EVT_BUTTON, handler=self._StopFit, id=self.btFit.GetId())
605        #else:
606        #    self.btFit.SetLabel("Fit")
607        #    self.btFit.Bind(event= wx.EVT_BUTTON, handler=self._onFit, id=self.btFit.GetId())
[7975f2b]608           
[5f9a6b1]609
[c77d859]610       
[ad6dd4c]611    def _StopFit(self, event):
612        """
613            Stop fit
614        """
615        self.btFit.SetLabel("Fit")
616        if self.engine_type=="scipy":
617            self.manager.stop_fit()
[34a0c17]618        self.btFit.Unbind(event=wx.EVT_BUTTON, id=self.btFit.GetId())
619        self.btFit.Bind(event=wx.EVT_BUTTON, handler=self._onFit,id=self.btFit.GetId())
[7975f2b]620       
[ad6dd4c]621           
[c77d859]622    def _on_select_model(self, event): 
623        """
624             call back for model selection
625        """   
[59a7f2d]626        self._on_select_model_helper() 
[70c57ebf]627        self.set_model_param_sizer(self.model)                   
[b421b1a]628       
[3b605bb]629        self.enable_disp.SetValue(False)
630        self.disable_disp.SetValue(True)
[4043c96]631        try:
632            self.set_dispers_sizer()
633        except:
634            pass
[70c57ebf]635        if self.model !=None:
636            try:
637                temp_smear= None
638                if self.enable_smearer.GetValue():
639                    temp_smear= self.smearer
640                self.compute_chisqr(temp_smear)
641            except:
642                ## error occured on chisqr computation
643                pass
[2a2af47]644            ## set smearing value whether or not the data contain the smearing info
645            self.manager.set_smearer(smearer=temp_smear, qmin= float(self.qmin_x),
646                                     qmax= float(self.qmax_x)) 
[70c57ebf]647            evt = ModelEventbox(model=self.model)
[c99a6c5]648            wx.PostEvent(self.event_owner, evt) 
[4043c96]649           
[848a2ef]650        self.btFit.SetFocus() 
[240b9966]651        self.state.enable_disp = self.enable_disp.GetValue()
652        self.state.disable_disp = self.disable_disp.GetValue()
[4043c96]653   
[3b9e023]654        self.state.structurecombobox = self.structurebox.GetCurrentSelection()
655        self.state.formfactorcombobox = self.formfactorbox.GetCurrentSelection()
[077809c]656     
[3b9e023]657       
[3595309d]658        if event !=None:
[3a37fe0]659            #self._undo.Enable(True)
[3595309d]660            ## post state to fit panel
661            event = PageInfoEvent(page = self)
662            wx.PostEvent(self.parent, event) 
[330573d]663     
[e2f7b92]664               
[dd5949d]665    def _onparamEnter(self,event):
666        """
667            when enter value on panel redraw model according to changed
668        """
[7975f2b]669        flag = False
[69bee6d]670        tcrtl= event.GetEventObject()
[7975f2b]671
[edd166b]672        #Clear msg if previously shown.
673        msg= ""
674        wx.PostEvent(self.parent.parent, StatusEvent(status = msg ))
[c99a6c5]675
[7975f2b]676        if check_float(tcrtl):
677            flag = self._onparamEnter_helper()
678            if flag:
679                temp_smearer = None
680                if self.enable_smearer.GetValue():
681                    temp_smearer= self.smearer
682                self.compute_chisqr(smearer= temp_smearer)
683   
684                ## new state posted
685                if self.state_change:
686                    #self._undo.Enable(True)
687                    event = PageInfoEvent(page = self)
688                    wx.PostEvent(self.parent, event)
[77f6a8b]689                self.state_change= False
[7975f2b]690            self.save_current_state()
[69bee6d]691        else:
[7975f2b]692            self.save_current_state()
[69bee6d]693            msg= "Cannot Plot :Must enter a number!!!  "
694            wx.PostEvent(self.parent.parent, StatusEvent(status = msg ))
695            return 
[cfc0913]696       
[e2f7b92]697
698    def _onparamRangeEnter(self, event):
[920a6e5]699        """
700            Check validity of value enter in the parameters range field
701        """
[edd166b]702       
[920a6e5]703        tcrtl= event.GetEventObject()
[edd166b]704        #Clear msg if previously shown.
705        msg= ""
706        wx.PostEvent(self.parent.parent, StatusEvent(status = msg ))
707        # Flag to register when a parameter has changed.
708        is_modified = False
[920a6e5]709        if tcrtl.GetValue().lstrip().rstrip()!="":
710            try:
711                value = float(tcrtl.GetValue())
712                tcrtl.SetBackgroundColour(wx.WHITE)
[edd166b]713                self._check_value_enter(self.fittable_param ,is_modified)
714                self._check_value_enter(self.parameters ,is_modified) 
[920a6e5]715            except:
716                tcrtl.SetBackgroundColour("pink")
[edd166b]717                msg= "Model Error:wrong value entered : %s"% sys.exc_value
718                wx.PostEvent(self.parent.parent, StatusEvent(status = msg ))
719                return 
[920a6e5]720        else:
721           tcrtl.SetBackgroundColour(wx.WHITE)
[e2f7b92]722           
[edd166b]723        #self._undo.Enable(True)
724        self.save_current_state()
725        event = PageInfoEvent(page = self)
726        wx.PostEvent(self.parent, event)
727        self.state_change= False
[7975f2b]728        self._sleep4sec()
[c69b6d5]729        self.Layout()
[7975f2b]730        #self.Refresh()               
[c69b6d5]731
[edd166b]732       
733    def _clear_Err_on_Fit(self):
734        """
735            hide the error text control shown
736            after fitting
737        """
738       
739        if hasattr(self,"text2_3"):
740            self.text2_3.Hide()
741
742        if len(self.parameters)>0:
743            for item in self.parameters:
744                #Skip t ifhe angle parameters if 1D data
745                if self.data.__class__.__name__ !="Data2D":
746                    if item in self.orientation_params:
747                        continue
748                if item in self.param_toFit:
749                    continue
750                ## hide statictext +/-   
751                if item[3]!=None and item[3].IsShown():
752                    item[3].Hide()
753                ## hide textcrtl  for error after fit
754                if item[4]!=None and item[4].IsShown():                   
755                    item[4].Hide()
[7975f2b]756 
[edd166b]757        if len(self.fittable_param)>0:
758            for item in self.fittable_param:
759                #Skip t ifhe angle parameters if 1D data
760                if self.data.__class__.__name__ !="Data2D":
761                    if item in self.orientation_params:
762                        continue
763                if item in self.param_toFit:
764                    continue
765                ## hide statictext +/-   
766                if item[3]!=None and item[3].IsShown():
767                    item[3].Hide()
768                ## hide textcrtl  for error after fit
769                if item[4]!=None and item[4].IsShown():
770                    item[4].Hide()
771        return       
[920a6e5]772               
[882a912]773       
774    def set_data(self, data ):
775        """
776            reset the current data
777        """
778        if data ==None:
779            return 
780        self.data =data
781        self.state.data= data
782        self._fill_datainfo_sizer()
783       
[240b9966]784    def reset_page(self, state,first=False):
[a074145]785        """
786            reset the state
787        """
788        self.reset_page_helper(state)
[b421b1a]789        import sans.guiframe.gui_manager
[f20767b]790        evt = ModelEventbox(model=state.model)
[edd166b]791        wx.PostEvent(self.event_owner, evt) 
792   
793        if self.engine_type != None:
794            self.manager._on_change_engine(engine=self.engine_type)
[7975f2b]795
[edd166b]796        self.select_param(event = None) 
797        #Save state_fit
[c985bef]798        self.save_current_state_fit()
[7975f2b]799        self._lay_out()
[c985bef]800        self.Refresh()
[edd166b]801       
[2140e68]802    def get_range(self):
803        """
804            return the fitting range
805        """
[c9a4377]806        return float(self.qmin_x) , float(self.qmax_x)
[7975f2b]807   
808    def get_npts2fit(self):
809        """
810            return numbers of data points within qrange
811            Note: This is for Park where chi2 is not normalized by Npts of fit
812        """
813        npts2fit = 0
814        qmin,qmax = self.get_range()
815        if self.data.__class__.__name__ =="Data2D":
816            for qx in self.data.x_bins:
817                for qy in self.data.y_bins:
818                   if math.sqrt((qx*qx)+(qy*qy)) >= qmin \
819                         and math.sqrt((qx*qx)+(qy*qy)) <= qmax:
820                       npts2fit += 1
821        else:
822            for qx in self.data.x:
823                   if qx >= qmin and qx <= qmax:
824                       npts2fit += 1
825        return npts2fit
826
[c69b6d5]827
828    def get_chi2(self):
829        """
830            return the current chi2
831        """
832        return self.tcChi.GetLabel()
[c77d859]833       
834    def get_param_list(self):
835        """
836            @return self.param_toFit: list containing  references to TextCtrl
837            checked.Theses TextCtrl will allow reference to parameters to fit.
838            @raise: if return an empty list of parameter fit will nnote work
839            properly so raise ValueError,"missing parameter to fit"
840        """
841        if self.param_toFit !=[]:
842            return self.param_toFit
843        else:
844            raise ValueError,"missing parameter to fit"   
845     
[6d91073]846    def onsetValues(self,chisqr,p_name, out,cov):
[c77d859]847        """
848            Build the panel from the fit result
849            @param chisqr:Value of the goodness of fit metric
[6d91073]850            @p_name: the name of parameters
[c77d859]851            @param out:list of parameter with the best value found during fitting
852            @param cov:Covariance matrix
853       
854        """
[edd166b]855        if out == None or not numpy.isfinite(chisqr):
856            raise ValueError,"Fit error occured..." 
857       
858        is_modified = False
859        has_error = False   
[7975f2b]860       
861        #Hide textctrl boxes of errors.
[edd166b]862        self._clear_Err_on_Fit()   
[7975f2b]863       
864        #Check if chi2 is finite
865        if chisqr != None or numpy.isfinite(chisqr):
[c69b6d5]866        #format chi2
[7975f2b]867            npt_fit = float(self.get_npts2fit())   
868            if self.engine_type == "park" and npt_fit > 0:   
869                chisqr =chisqr/npt_fit   
870            chi2 = format_number(chisqr)   
871            self.tcChi.SetLabel(chi2)   
872            self.tcChi.Refresh()   
873        else:
874            self.tcChi.SetLabel("-")
[c13b8cc]875       
[edd166b]876        #Hide error title
877        if self.text2_3.IsShown():
878            self.text2_3.Hide()
879     
[e473e4f5]880        try:
881            n = self.disp_box.GetCurrentSelection()
882            dispersity= self.disp_box.GetClientData(n)
[7975f2b]883            if dispersity !=None and self.enable_disp.GetValue():
884                name= dispersity.__name__
885                if name == "GaussianDispersion":
886                    if hasattr(self,"text_disp_1" ):
887                        if self.text_disp_1 !=None:
888                            self.text_disp_1.Hide()
[e473e4f5]889        except:
[7975f2b]890            dispersty = None
[e473e4f5]891            pass
[c77d859]892        #set the panel when fit result are float not list
[c99a6c5]893        if out.__class__== numpy.float64:
[c77d859]894            self.param_toFit[0][2].SetValue(format_number(out))
[0a518e4c]895           
[c69b6d5]896            if self.param_toFit[0][4].IsShown:
897                self.param_toFit[0][4].Hide()
[c77d859]898            if cov !=None :
899                self.text2_3.Show(True)
[e473e4f5]900                try:
[7975f2b]901                    if dispersity !=None:
902                        name= dispersity.__name__
903                        if name == "GaussianDispersion" and self.enable_disp.GetValue():
904                            if hasattr(self,"text_disp_1" ):
905                                if self.text_disp_1 !=None:
906                                    self.text_disp_1.Show(True)
[e473e4f5]907                except:
908                    pass
[c99a6c5]909
[ad6dd4c]910                if cov[0]==None or  not numpy.isfinite(cov[0]): 
[c69b6d5]911                    if self.param_toFit[0][3].IsShown:
912                        self.param_toFit[0][3].Hide()
[7975f2b]913                else:                   
914                    self.param_toFit[0][3].Show(True)               
[69bee6d]915                    self.param_toFit[0][4].Show(True)
[c69b6d5]916                    self.param_toFit[0][4].SetValue(format_number(cov[0]))
[ffb838f]917                    has_error = True
[c77d859]918        else:
[edd166b]919
[c69b6d5]920            i = 0
[c77d859]921            #Set the panel when fit result are list
[7975f2b]922            for item in self.param_toFit:     
[edd166b]923                if len(item)>5 and item != None:     
924                    ## reset error value to initial state
[7975f2b]925                    item[3].Hide()
926                    item[4].Hide()
927                   
[edd166b]928                    for ind in range(len(out)):
929                       
930                        if item[1] == p_name[ind]:
931                            break       
[7975f2b]932                    if len(out)<=len(self.param_toFit) and out[ind] !=None:   
933                        val_out = format_number(out[ind])                 
934                        item[2].SetValue(val_out)
[c99a6c5]935
[7975f2b]936                    if(cov !=None):
[edd166b]937                       
938                        try:
[7975f2b]939                            if dispersity !=None:
940                                name= dispersity.__name__
941                                if name == "GaussianDispersion" and self.enable_disp.GetValue():
942                                    if hasattr(self,"text_disp_1" ):
943                                        if self.text_disp_1!=None:
944                                            if not self.text_disp_1.IsShown():
945                                                self.text_disp_1.Show(True)
[edd166b]946                        except:
947                            pass   
948                   
[7975f2b]949                        if cov[ind]!=None :
950                            if numpy.isfinite(float(cov[ind])):
951                                val_err = format_number(cov[ind])
952                                item[3].Show(True)
953                                item[4].Show(True)
954                                item[4].SetValue(val_err)
955
956                                has_error = True
[edd166b]957                    i += 1         
[c99a6c5]958        #Show error title when any errors displayed
[b421b1a]959        if has_error: 
[c99a6c5]960            if not self.text2_3.IsShown():
[edd166b]961                self.text2_3.Show(True) 
[7975f2b]962               
963        ## save current state 
964        self.save_current_state()         
965        #plot model
966        self._draw_model()   
967        self._lay_out()     
968        #PostStatusEvent     
969        msg="Fit completed! "
970        wx.PostEvent(self.manager.parent, StatusEvent(status=msg))
971     
[c69b6d5]972
[c77d859]973    def onSmear(self, event):
974        """
975            Create a smear object that will change the way residuals
976            are compute when fitting
977        """
[2a2af47]978        if self.model ==None:
979            msg="Need model and data to smear plot"
980            wx.PostEvent(self.manager.parent, StatusEvent(status=\
981                            "Smear: %s"%msg))
982            return
[3370922]983        temp_smearer = None
[c77d859]984        if self.enable_smearer.GetValue():
[997131a]985            temp_smearer= self.smearer
[c77d859]986            if hasattr(self.data,"dxl"):
987                msg= ": Resolution smearing parameters"
988            if hasattr(self.data,"dxw"):
989                msg= ": Slit smearing parameters"
[997131a]990            if self.smearer ==None:
[c77d859]991                wx.PostEvent(self.manager.parent, StatusEvent(status=\
992                            "Data contains no smearing information"))
993            else:
994                wx.PostEvent(self.manager.parent, StatusEvent(status=\
995                            "Data contains smearing information %s"%msg))
[3370922]996       
[fb8daaaf]997        ## set smearing value whether or not the data contain the smearing info
[3370922]998        self.manager.set_smearer(smearer=temp_smearer, qmin= float(self.qmin_x),
[2b63df0]999                                     qmax= float(self.qmax_x)) 
[875f1a2]1000        ##Calculate chi2
[997131a]1001        self.compute_chisqr(smearer= temp_smearer) 
[5582a9f1]1002       
1003        self.state.enable_smearer=  self.enable_smearer.GetValue()
1004        self.state.disable_smearer=self.disable_smearer.GetValue()
[847091f]1005   
[2b63df0]1006    def complete_chisqr(self, output, elapsed=None): 
1007        """
1008            print result chisqr
1009        """
1010        try:
[077809c]1011            if output ==None:
1012                output= "-"
[edd166b]1013
[ba95543]1014            self.tcChi.SetLabel(str(format_number(output)))
[0aeabc6]1015           
1016            self.sizer5.Layout()
[edd166b]1017            self.state.tcChi =self.tcChi
[5582a9f1]1018         
[2b63df0]1019        except:
[0aeabc6]1020            pass
[2b63df0]1021       
1022       
1023    def compute_chisqr1D(self, smearer=None):
1024        """
1025            Compute chisqr for 1D
1026        """
1027        try:
1028            self.qmin_x = float(self.qmin.GetValue())
1029            self.qmax_x = float(self.qmax.GetValue())
1030            ##return residuals within self.qmin_x and self.qmax_x
1031            from gui_thread import CalcChisqr1D
1032            ## If a thread is already started, stop it
1033            if self.calc_Chisqr!= None and self.calc_Chisqr.isrunning():
1034                self.calc_Chisqr.stop()
1035               
[077809c]1036            self.calc_Chisqr= CalcChisqr1D( data1d= self.data,
[2b63df0]1037                                            model= self.model,
1038                                            smearer=smearer,
1039                                            qmin=self.qmin_x,
1040                                            qmax=self.qmax_x,
1041                                            completefn = self.complete_chisqr,
1042                                            updatefn   = None)
1043   
1044            self.calc_Chisqr.queue()
1045           
1046        except:
1047            raise ValueError," Could not compute Chisqr for %s Model 2D: "%self.model.name
1048           
1049           
1050   
1051       
[b787e68c]1052       
[c77d859]1053    def compute_chisqr2D(self):
1054        """
1055            compute chi square given a model and data 2D and set the value
1056            to the tcChi txtcrl
1057        """
[2b63df0]1058        try:
1059            self.qmin_x = float(self.qmin.GetValue())
1060            self.qmax_x = float(self.qmax.GetValue())
1061           
1062            ##return residuals within self.qmin_x and self.qmax_x
1063            from gui_thread import CalcChisqr2D
1064            ## If a thread is already started, stop it
1065            if self.calc_Chisqr!= None and self.calc_Chisqr.isrunning():
1066                self.calc_Chisqr.stop()
[0aeabc6]1067           
[077809c]1068            self.calc_Chisqr= CalcChisqr2D( data2d= self.data,
[2b63df0]1069                                            model= self.model,
1070                                            qmin= self.qmin_x,
1071                                            qmax = self.qmax_x,
1072                                            completefn = self.complete_chisqr,
1073                                            updatefn   = None)
[c77d859]1074   
[2b63df0]1075            self.calc_Chisqr.queue()
1076         
1077        except:
[077809c]1078           raise
[2b63df0]1079
[c77d859]1080       
[997131a]1081    def compute_chisqr(self , smearer=None):
[c77d859]1082        """
1083            compute chi square given a model and data 1D and set the value
1084            to the tcChi txtcrl
1085        """
1086        flag = check_value( self.qmin, self.qmax)
1087        if flag== True:
1088            try:
1089                if hasattr(self.data,"data"):
1090                    self.compute_chisqr2D()
1091                    return
1092                else:
[2b63df0]1093                    self.compute_chisqr1D(smearer=smearer)
1094                    return
[c77d859]1095            except:
[077809c]1096                wx.PostEvent(self.parent.parent, StatusEvent(status=\
[2b63df0]1097                            "Chisqr Error: %s"% sys.exc_value))
[a8088d7]1098                return 
[c77d859]1099           
1100   
1101    def select_all_param(self,event): 
1102        """
1103             set to true or false all checkBox given the main checkbox value cb1
[d1e0473]1104        """           
1105
[c77d859]1106        self.param_toFit=[]
1107        if  self.parameters !=[]:
[998b6b8]1108            if  self.cb1.GetValue():
[c77d859]1109                for item in self.parameters:
[3fef0a8]1110                    ## for data2D select all to fit
1111                    if self.data.__class__.__name__=="Data2D":
[c77d859]1112                        item[0].SetValue(True)
1113                        self.param_toFit.append(item )
[3fef0a8]1114                    else:
1115                        ## for 1D all parameters except orientation
1116                        if not item in self.orientation_params:
1117                            item[0].SetValue(True)
1118                            self.param_toFit.append(item )
1119                if len(self.fittable_param)>0:
1120                    for item in self.fittable_param:
1121                        if self.data.__class__.__name__=="Data2D":
1122                            item[0].SetValue(True)
1123                            self.param_toFit.append(item )
1124                        else:
1125                            ## for 1D all parameters except orientation
[513115c]1126                            if not item in self.orientation_params_disp:
[3fef0a8]1127                                item[0].SetValue(True)
1128                                self.param_toFit.append(item )
[c77d859]1129            else:
1130                for item in self.parameters:
1131                    item[0].SetValue(False)
1132                for item in self.fittable_param:
1133                    item[0].SetValue(False)
1134                self.param_toFit=[]
[330573d]1135           
[52cac46]1136        self.save_current_state_fit() 
[3595309d]1137        if event !=None:
[3a37fe0]1138            #self._undo.Enable(True)
[3595309d]1139            ## post state to fit panel
1140            event = PageInfoEvent(page = self)
1141            wx.PostEvent(self.parent, event) 
1142     
[c77d859]1143               
1144               
1145    def select_param(self,event):
1146        """
1147            Select TextCtrl  checked for fitting purpose and stores them
1148            in  self.param_toFit=[] list
1149        """
1150        self.param_toFit=[]
1151        for item in self.parameters:
[edd166b]1152            #Skip t ifhe angle parameters if 1D data
1153            if self.data.__class__.__name__ !="Data2D":
1154                if item in self.orientation_params:
1155                    continue
[c77d859]1156            #Select parameters to fit for list of primary parameters
[998b6b8]1157            if item[0].GetValue():
[c77d859]1158                if not (item in self.param_toFit):
1159                    self.param_toFit.append(item ) 
1160            else:
1161                #remove parameters from the fitting list
1162                if item in self.param_toFit:
1163                    self.param_toFit.remove(item)
[edd166b]1164
[c77d859]1165        #Select parameters to fit for list of fittable parameters with dispersion         
1166        for item in self.fittable_param:
[edd166b]1167            #Skip t ifhe angle parameters if 1D data
1168            if self.data.__class__.__name__ !="Data2D":
1169                if item in self.orientation_params:
1170                    continue
[998b6b8]1171            if item[0].GetValue():
[c77d859]1172                if not (item in self.param_toFit):
1173                    self.param_toFit.append(item) 
1174            else:
1175                #remove parameters from the fitting list
1176                if item in self.param_toFit:
[edd166b]1177                    self.param_toFit.remove(item)
1178
1179        #Calculate num. of angle parameters
1180        if self.data.__class__.__name__ =="Data2D": 
1181            len_orient_para = 0
1182        else:
1183            len_orient_para = len(self.orientation_params)  #assume even len
1184        #Total num. of angle parameters
1185        if len(self.fittable_param) > 0:
1186            len_orient_para *= 2
[c77d859]1187        #Set the value of checkbox that selected every checkbox or not           
[edd166b]1188        if len(self.parameters)+len(self.fittable_param)-len_orient_para ==len(self.param_toFit):
[c77d859]1189            self.cb1.SetValue(True)
1190        else:
1191            self.cb1.SetValue(False)
[52cac46]1192        self.save_current_state_fit()
[3595309d]1193        if event !=None:
[3a37fe0]1194            #self._undo.Enable(True)
[3595309d]1195            ## post state to fit panel
1196            event = PageInfoEvent(page = self)
1197            wx.PostEvent(self.parent, event) 
1198     
[c77d859]1199   
1200       
[77e23a2]1201    def set_model_param_sizer(self, model):
[c77d859]1202        """
1203            Build the panel from the model content
1204            @param model: the model selected in combo box for fitting purpose
1205        """
1206        self.sizer3.Clear(True)
1207        self.parameters = []
1208        self.param_toFit=[]
1209        self.fittable_param=[]
1210        self.fixed_param=[]
[780d095]1211        self.orientation_params=[]
[60132ef]1212        self.orientation_params_disp=[]
[c77d859]1213       
1214        if model ==None:
1215            self.sizer3.Layout()
[08ba57d]1216            self.SetScrollbars(20,20,25,65)
[c77d859]1217            return
[707436d]1218        ## the panel is drawn using the current value of the fit engine
1219        if self.engine_type==None and self.manager !=None:
1220            self.engine_type= self.manager._return_engine_type()
[c99a6c5]1221
[707436d]1222           
[c77d859]1223        box_description= wx.StaticBox(self, -1,str("Model Parameters"))
1224        boxsizer1 = wx.StaticBoxSizer(box_description, wx.VERTICAL)
1225        sizer = wx.GridBagSizer(5,5)
1226        ## save the current model
1227        self.model = model
1228           
1229        keys = self.model.getParamList()
1230        #list of dispersion paramaters
1231        self.disp_list=self.model.getDispParamList()
[b421b1a]1232
[c77d859]1233        keys.sort()
1234   
[6dc9ad8]1235        iy = 0
[c77d859]1236        ix = 0
1237        self.cb1 = wx.CheckBox(self, -1,"Select all", (10, 10))
1238        wx.EVT_CHECKBOX(self, self.cb1.GetId(), self.select_all_param)
1239        self.cb1.SetValue(False)
1240       
1241        sizer.Add(self.cb1,(iy, ix),(1,1),\
[eda428b]1242                             wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 5)
[c77d859]1243        ix +=1
1244        self.text2_2 = wx.StaticText(self, -1, 'Values')
1245        sizer.Add(self.text2_2,(iy, ix),(1,1),\
1246                            wx.EXPAND|wx.ADJUST_MINSIZE, 0)
1247        ix +=2 
1248        self.text2_3 = wx.StaticText(self, -1, 'Errors')
1249        sizer.Add(self.text2_3,(iy, ix),(1,1),\
1250                            wx.EXPAND|wx.ADJUST_MINSIZE, 0) 
1251        self.text2_3.Hide()
1252        ix +=1 
1253        self.text2_min = wx.StaticText(self, -1, 'Min')
1254        sizer.Add(self.text2_min,(iy, ix),(1,1),\
1255                            wx.EXPAND|wx.ADJUST_MINSIZE, 0) 
1256        self.text2_min.Hide()
1257        ix +=1 
1258        self.text2_max = wx.StaticText(self, -1, 'Max')
1259        sizer.Add(self.text2_max,(iy, ix),(1,1),\
1260                            wx.EXPAND|wx.ADJUST_MINSIZE, 0) 
1261        self.text2_max.Hide()
[6fdfc8f]1262        ix += 1
1263        self.text2_4 = wx.StaticText(self, -1, '[Units]')
1264        sizer.Add(self.text2_4,(iy, ix),(1,1),\
1265                            wx.EXPAND|wx.ADJUST_MINSIZE, 0) 
1266        self.text2_4.Hide()
[dcf29d7]1267        if self.engine_type=="park":
1268            self.text2_max.Show(True)
1269            self.text2_min.Show(True)
[b421b1a]1270       
[c77d859]1271        for item in keys:
[780d095]1272            if not item in self.disp_list and not item in self.model.orientation_params:
[b421b1a]1273               
1274                ##prepare a spot to store errors
1275                if not self.model.details.has_key(item):
1276                    self.model.details [item] = ["",None,None] 
1277         
[c77d859]1278                iy += 1
1279                ix = 0
1280                ## add parameters name with checkbox for selecting to fit
1281                cb = wx.CheckBox(self, -1, item )
1282                cb.SetValue(False)
1283                wx.EVT_CHECKBOX(self, cb.GetId(), self.select_param)
1284                sizer.Add( cb,( iy, ix),(1,1),
[eda428b]1285                             wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 5)
[d1e0473]1286               
[c77d859]1287                ## add parameter value
1288                ix += 1
1289                value= self.model.getParam(item)
[7975f2b]1290                ctl1 = self.ModelTextCtrl(self, -1, size=(_BOX_WIDTH,20),
[c77d859]1291                                    style=wx.TE_PROCESS_ENTER)
1292               
[77e23a2]1293                ctl1.SetValue(format_number(value))
[c77d859]1294                sizer.Add(ctl1, (iy,ix),(1,1), wx.EXPAND)
1295                ## text to show error sign
1296                ix += 1
1297                text2=wx.StaticText(self, -1, '+/-')
1298                sizer.Add(text2,(iy, ix),(1,1),\
1299                                wx.EXPAND|wx.ADJUST_MINSIZE, 0) 
1300                text2.Hide() 
1301                ix += 1
[c13b8cc]1302                ctl2 = wx.TextCtrl(self, -1, size=(_BOX_WIDTH,20), style=0)
[c77d859]1303                sizer.Add(ctl2, (iy,ix),(1,1), wx.EXPAND|wx.ADJUST_MINSIZE, 0)
[b421b1a]1304                ctl2.Hide()
[c77d859]1305               
1306                ix += 1
[7975f2b]1307                ctl3 = self.ModelTextCtrl(self, -1, size=(_BOX_WIDTH/2,20), style=wx.TE_PROCESS_ENTER,
[e2f7b92]1308                                               kill_focus_callback = self._onparamRangeEnter,
[7975f2b]1309                                               text_enter_callback = self._onparamRangeEnter)
[eacf1d66]1310     
[c77d859]1311                sizer.Add(ctl3, (iy,ix),(1,1), wx.EXPAND|wx.ADJUST_MINSIZE, 0)
1312                ctl3.Hide()
[77e23a2]1313       
[c77d859]1314                ix += 1
[7975f2b]1315                ctl4 = self.ModelTextCtrl(self, -1, size=(_BOX_WIDTH/2,20), style=wx.TE_PROCESS_ENTER,
[e2f7b92]1316                                               kill_focus_callback = self._onparamRangeEnter,
[7975f2b]1317                                               text_enter_callback = self._onparamRangeEnter)
[c77d859]1318                sizer.Add(ctl4, (iy,ix),(1,1), wx.EXPAND|wx.ADJUST_MINSIZE, 0)
[eacf1d66]1319     
[c77d859]1320                ctl4.Hide()
[edd166b]1321
[dcf29d7]1322                if self.engine_type=="park":
1323                    ctl3.Show(True)
1324                    ctl4.Show(True)
[6fdfc8f]1325                ix +=1
1326                # Units
[7975f2b]1327                if self.model.details.has_key(item):
[6fdfc8f]1328                    units = wx.StaticText(self, -1, self.model.details[item][0], style=wx.ALIGN_LEFT)
[7975f2b]1329                else:
[6fdfc8f]1330                    units = wx.StaticText(self, -1, "", style=wx.ALIGN_LEFT)
1331                sizer.Add(units, (iy,ix),(1,1),  wx.EXPAND|wx.ADJUST_MINSIZE, 0)
[dcf29d7]1332                   
[c77d859]1333                ##[cb state, name, value, "+/-", error of fit, min, max , units]
1334                self.parameters.append([cb,item, ctl1,
[240b9966]1335                                        text2,ctl2, ctl3, ctl4,units])
[2d5f7a1]1336             
[c77d859]1337        iy+=1
[2a5bba7]1338        sizer.Add((10,10),(iy,ix),(1,1), wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
[5af5183]1339       
[f20767b]1340        # type can be either Guassian or Array
[5b53a5c]1341        if len(self.model.dispersion.values())>0:
1342            type= self.model.dispersion.values()[0]["type"]
1343        else:
1344            type = "Gaussian"
[6dc9ad8]1345           
1346        iy += 1
1347        ix = 0
1348        #Add tile for orientational angle
1349        for item in keys:
1350            if item in self.model.orientation_params:       
1351                orient_angle = wx.StaticText(self, -1, '[For 2D only]:')
1352                sizer.Add(orient_angle,(iy, ix),(1,1), wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15) 
1353                if not self.data.__class__.__name__ =="Data2D":
1354                    orient_angle.Hide()
1355                else:
1356                    orient_angle.Show(True)
1357                break
[5b53a5c]1358     
[f20767b]1359        #For Gaussian only
1360        if type.lower() != "array":
1361            for item in self.model.orientation_params:
1362                if not item in self.disp_list:
[c13b8cc]1363                    ##prepare a spot to store min max
1364                    if not self.model.details.has_key(item):
1365                        self.model.details [item] = ["",None,None] 
1366                         
[f20767b]1367                    iy += 1
1368                    ix = 0
1369                    ## add parameters name with checkbox for selecting to fit
1370                    cb = wx.CheckBox(self, -1, item )
1371                    cb.SetValue(False)
1372                    wx.EVT_CHECKBOX(self, cb.GetId(), self.select_param)
1373                    if self.data.__class__.__name__ =="Data2D":
[6dc9ad8]1374                        cb.Show(True)
[f20767b]1375                    else:
[6dc9ad8]1376                        cb.Hide()
[f20767b]1377                    sizer.Add( cb,( iy, ix),(1,1),
1378                                 wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 5)
1379   
1380                    ## add parameter value
1381                    ix += 1
1382                    value= self.model.getParam(item)
[7975f2b]1383                    ctl1 = self.ModelTextCtrl(self, -1, size=(_BOX_WIDTH,20),
[f20767b]1384                                        style=wx.TE_PROCESS_ENTER)
[780d095]1385                   
[f20767b]1386                    ctl1.SetValue(format_number(value))
1387                    if self.data.__class__.__name__ =="Data2D":
[c5cd3b9]1388                        ctl1.Show(True)
[f20767b]1389                    else:
[c5cd3b9]1390                        ctl1.Hide()
[f20767b]1391                    sizer.Add(ctl1, (iy,ix),(1,1), wx.EXPAND)
1392                    ## text to show error sign
1393                    ix += 1
1394                    text2=wx.StaticText(self, -1, '+/-')
1395                    sizer.Add(text2,(iy, ix),(1,1),\
1396                                    wx.EXPAND|wx.ADJUST_MINSIZE, 0) 
1397                    text2.Hide() 
1398                    ix += 1
[c13b8cc]1399                    ctl2 = wx.TextCtrl(self, -1, size=(_BOX_WIDTH,20), style=0)
[e2f7b92]1400                   
[f20767b]1401                    sizer.Add(ctl2, (iy,ix),(1,1), wx.EXPAND|wx.ADJUST_MINSIZE, 0)
1402                    ctl2.Hide()
[e2f7b92]1403                   
[c99a6c5]1404                   
[f20767b]1405                    ix += 1
[7975f2b]1406                    ctl3 = self.ModelTextCtrl(self, -1, size=(_BOX_WIDTH/2,20), style=wx.TE_PROCESS_ENTER,
[f20767b]1407                                                   kill_focus_callback = self._onparamRangeEnter,
[7975f2b]1408                                                   text_enter_callback = self._onparamRangeEnter)
[eacf1d66]1409               
[f20767b]1410                    sizer.Add(ctl3, (iy,ix),(1,1), wx.EXPAND|wx.ADJUST_MINSIZE, 0)
1411                    ctl3.Hide()
[edd166b]1412                    #if self.data.__class__.__name__ =="Data2D":
1413                    #    ctl3.Show(True)
[c99a6c5]1414                     
[edd166b]1415                    #else:
1416                    #    ctl3.Hide()
[c99a6c5]1417               
[f20767b]1418                    ix += 1
[7975f2b]1419                    ctl4 = self.ModelTextCtrl(self, -1, size=(_BOX_WIDTH/2,20), style=wx.TE_PROCESS_ENTER,
[f20767b]1420                                                   kill_focus_callback = self._onparamRangeEnter,
[7975f2b]1421                                                   text_enter_callback = self._onparamRangeEnter)
[f20767b]1422                    sizer.Add(ctl4, (iy,ix),(1,1), wx.EXPAND|wx.ADJUST_MINSIZE, 0)
[eacf1d66]1423                   
[f20767b]1424                    ctl4.Hide()
[edd166b]1425                   
1426                    if self.engine_type =="park" and self.data.__class__.__name__ =="Data2D":                     
[f20767b]1427                        ctl3.Show(True)
1428                        ctl4.Show(True)
[c5cd3b9]1429                   
[f20767b]1430                    ix +=1
1431                    # Units
[7975f2b]1432                    if self.model.details.has_key(item):
[f20767b]1433                        units = wx.StaticText(self, -1, self.model.details[item][0], style=wx.ALIGN_LEFT)
[7975f2b]1434                    else:
[f20767b]1435                        units = wx.StaticText(self, -1, "", style=wx.ALIGN_LEFT)
1436                    if self.data.__class__.__name__ =="Data2D":
[6dc9ad8]1437                        units.Show(True)
[c99a6c5]1438                   
[f20767b]1439                    else:
[6dc9ad8]1440                        units.Hide()
[c99a6c5]1441                   
[f20767b]1442                    sizer.Add(units, (iy,ix),(1,1),  wx.EXPAND|wx.ADJUST_MINSIZE, 0)
[7975f2b]1443                                         
[f20767b]1444                    ##[cb state, name, value, "+/-", error of fit, min, max , units]
1445                    self.parameters.append([cb,item, ctl1,
1446                                            text2,ctl2, ctl3, ctl4,units])
1447                    self.orientation_params.append([cb,item, ctl1,
1448                                            text2,ctl2, ctl3, ctl4,units])
[780d095]1449             
1450        iy+=1
[c77d859]1451       
1452        #Display units text on panel
1453        for item in keys:   
[7975f2b]1454            if self.model.details.has_key(item):
[c77d859]1455                self.text2_4.Show()
[7975f2b]1456
[52cac46]1457        #self.state.cb1 = self.cb1.GetValue()       
1458        #self._copy_parameters_state(self.orientation_params,
1459        #                             self.state.orientation_params)
1460        #self._copy_parameters_state(self.orientation_params_disp,
1461        #                             self.state.orientation_params_disp)
1462        #self._copy_parameters_state(self.parameters, self.state.parameters)
1463        #self._copy_parameters_state(self.fittable_param, self.state.fittable_param)
1464        #self._copy_parameters_state(self.fixed_param, self.state.fixed_param)
[b421b1a]1465 
[52cac46]1466        self.save_current_state_fit()
[240b9966]1467        boxsizer1.Add(sizer)
[c77d859]1468        self.sizer3.Add(boxsizer1,0, wx.EXPAND | wx.ALL, 10)
1469        self.sizer3.Layout()
[330573d]1470        self.Layout()
1471        self.Refresh()
[08ba57d]1472        self.SetScrollbars(20,20,25,65)
[52cac46]1473
1474
[c77d859]1475       
1476class HelpWindow(wx.Frame):
1477    def __init__(self, parent, id, title):
1478        wx.Frame.__init__(self, parent, id, title, size=(570, 400))
1479       
1480        from sans.models.CylinderModel import CylinderModel
1481        model = CylinderModel()
[2d5f7a1]1482       
[c77d859]1483        from danse.common.plottools.plottables import Data1D
1484        data= Data1D(x=[1,2], y=[3,4], dy=[0.1, 0,1])
1485   
[cfc0913]1486        from fitpanel import PageInfo
[c77d859]1487        myinfo = PageInfo(self,  model, data=data )
1488       
1489        ## add data
1490       
1491        from models import ModelList
1492        mylist= ModelList()
1493
1494        from sans.models.SphereModel import SphereModel
1495        from sans.models.SquareWellStructure import SquareWellStructure
1496        from sans.models.DebyeModel import DebyeModel
1497        from sans.models.LineModel import LineModel
1498        name= "shapes"
1499        list1= [SphereModel]
1500        mylist.set_list( name, list1)
1501       
1502        name= "Shape-independent"
1503        list1= [DebyeModel]
1504        mylist.set_list( name, list1)
1505       
1506        name= "Structure Factors"
1507        list1= [SquareWellStructure]
1508        mylist.set_list( name, list1)
1509       
1510        name= "Added models"
1511        list1= [LineModel]
1512        mylist.set_list( name, list1)
1513       
1514        myinfo.model_list_box = mylist.get_list()
1515       
1516        self.page = FitPage(self, myinfo) 
1517       
1518        self.Centre()
1519        self.Show(True)
[eacf1d66]1520 
[c77d859]1521if __name__=="__main__":
1522    app = wx.App()
1523    HelpWindow(None, -1, 'HelpWindow')
1524    app.MainLoop()
1525               
Note: See TracBrowser for help on using the repository browser.