source: sasview/prview/perspectives/pr/pr.py @ feb21d8

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 feb21d8 was feb21d8, checked in by Mathieu Doucet <doucetm@…>, 16 years ago

Added various scaling choices

  • Property mode set to 100644
File size: 32.0 KB
Line 
1#TODO: Use simview to generate P(r) and I(q) pairs in sansview.
2# Make sure the option of saving each curve is available
3# Use the I(q) curve as input and compare the output to P(r)
4
5import os
6import sys
7import wx
8import logging
9from sans.guitools.plottables import Data1D, Theory1D
10from sans.guicomm.events import NewPlotEvent, StatusEvent   
11import math, numpy
12from sans.pr.invertor import Invertor
13
14PR_FIT_LABEL       = "P_{fit}(r)"
15PR_LOADED_LABEL    = "P_{loaded}(r)"
16IQ_DATA_LABEL      = "I_{obs}(q)"
17IQ_FIT_LABEL       = "I_{fit}(q)"
18IQ_SMEARED_LABEL   = "I_{smeared}(q)"
19
20import wx.lib
21(NewPrFileEvent, EVT_PR_FILE) = wx.lib.newevent.NewEvent()
22
23
24class Plugin:
25   
26    DEFAULT_ALPHA = 0.0001
27    DEFAULT_NFUNC = 10
28    DEFAULT_DMAX  = 140.0
29   
30    def __init__(self):
31        ## Plug-in name
32        self.sub_menu = "Pr inversion"
33       
34        ## Reference to the parent window
35        self.parent = None
36       
37        ## Simulation window manager
38        self.simview = None
39       
40        ## List of panels for the simulation perspective (names)
41        self.perspective = []
42       
43        ## State data
44        self.alpha      = self.DEFAULT_ALPHA
45        self.nfunc      = self.DEFAULT_NFUNC
46        self.max_length = self.DEFAULT_DMAX
47        self.q_min      = None
48        self.q_max      = None
49        self.has_bck    = False
50        self.slit_height = 0
51        self.slit_width  = 0
52        ## Remember last plottable processed
53        self.last_data  = "sphere_60_q0_2.txt"
54        ## Time elapsed for last computation [sec]
55        # Start with a good default
56        self.elapsed = 0.022
57        self.iq_data_shown = False
58       
59        ## Current invertor
60        self.invertor    = None
61        self.pr          = None
62        # Copy of the last result in case we need to display it.
63        self._last_pr    = None
64        self._last_out   = None
65        self._last_cov   = None
66        ## Calculation thread
67        self.calc_thread = None
68        ## Estimation thread
69        self.estimation_thread = None
70        ## Result panel
71        self.control_panel = None
72        ## Currently views plottable
73        self.current_plottable = None
74        ## Number of P(r) points to display on the output plot
75        self._pr_npts = 51
76        ## Flag to let the plug-in know that it is running standalone
77        self.standalone = True
78        self._normalize_output = False
79        self._scale_output_unity = False
80       
81        # Log startup
82        logging.info("Pr(r) plug-in started")
83       
84       
85
86    def populate_menu(self, id, owner):
87        """
88            Create a menu for the plug-in
89        """
90        return []
91   
92    def help(self, evt):
93        """
94            Show a general help dialog.
95            TODO: replace the text with a nice image
96        """
97        from inversion_panel import HelpDialog
98        dialog = HelpDialog(None, -1)
99        if dialog.ShowModal() == wx.ID_OK:
100            dialog.Destroy()
101        else:
102            dialog.Destroy()
103   
104    def _fit_pr(self, evt):
105        from sans.pr.invertor import Invertor
106        import numpy
107        import pylab
108        import math
109        from sans.guicomm.events import NewPlotEvent           
110        from sans.guitools.plottables import Data1D, Theory1D
111       
112        # Generate P(r) for sphere
113        radius = 60.0
114        d_max  = 2*radius
115       
116       
117        r = pylab.arange(0.01, d_max, d_max/51.0)
118        M = len(r)
119        y = numpy.zeros(M)
120        pr_err = numpy.zeros(M)
121       
122        sum = 0.0
123        for j in range(M):
124            value = self.pr_theory(r[j], radius)
125            sum += value
126            y[j] = value
127            pr_err[j] = math.sqrt(y[j])
128
129           
130        y = y/sum*d_max/len(r)
131
132
133
134        # Perform fit
135        pr = Invertor()
136        pr.d_max = d_max
137        pr.alpha = 0
138        pr.x = r
139        pr.y = y
140        pr.err = pr_err
141        out, cov = pr.pr_fit()
142        for i in range(len(out)):
143            print "%g +- %g" % (out[i], math.sqrt(cov[i][i]))
144
145
146        # Show input P(r)
147        new_plot = Data1D(pr.x, pr.y, dy=pr.err)
148        new_plot.name = "P_{obs}(r)"
149        new_plot.xaxis("\\rm{r}", 'A')
150        new_plot.yaxis("\\rm{P(r)} ","cm^{-3}")
151        wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot, title="Pr"))
152
153        # Show P(r) fit
154        self.show_pr(out, pr)
155       
156        # Show I(q) fit
157        q = pylab.arange(0.001, 0.1, 0.01/51.0)
158        self.show_iq(out, pr, q)
159       
160       
161    def show_shpere(self, x, radius=70.0, x_range=70.0):
162        import numpy
163        import pylab
164        import math
165        from sans.guicomm.events import NewPlotEvent           
166        from sans.guitools.plottables import Data1D, Theory1D
167        # Show P(r)
168        y_true = numpy.zeros(len(x))
169
170        sum_true = 0.0
171        for i in range(len(x)):
172            y_true[i] = self.pr_theory(x[i], radius)           
173            sum_true += y_true[i]
174           
175        y_true = y_true/sum_true*x_range/len(x)
176       
177        # Show the theory P(r)
178        new_plot = Theory1D(x, y_true)
179        new_plot.name = "P_{true}(r)"
180        new_plot.xaxis("\\rm{r}", 'A')
181        new_plot.yaxis("\\rm{P(r)} ","cm^{-3}")
182       
183       
184        #Put this call in plottables/guitools   
185        wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot, title="Sphere P(r)"))
186       
187    def get_npts(self):
188        """
189            Returns the number of points in the I(q) data
190        """
191        try:
192            return len(self.pr.x)
193        except:
194            return 0
195       
196    def show_iq(self, out, pr, q=None):
197        import numpy
198        import pylab
199        import math
200        from sans.guicomm.events import NewPlotEvent           
201        from sans.guitools.plottables import Data1D, Theory1D
202
203        qtemp = pr.x
204        if not q==None:
205            qtemp = q
206
207        # Make a plot
208        maxq = -1
209        for q_i in qtemp:
210            if q_i>maxq:
211                maxq=q_i
212               
213        minq = 0.001
214       
215        # Check for user min/max
216        if not pr.q_min==None:
217            minq = pr.q_min
218        if not pr.q_max==None:
219            maxq = pr.q_max
220               
221        x = pylab.arange(minq, maxq, maxq/301.0)
222        y = numpy.zeros(len(x))
223        err = numpy.zeros(len(x))
224        for i in range(len(x)):
225            value = pr.iq(out, x[i])
226            y[i] = value
227            try:
228                err[i] = math.sqrt(math.fabs(value))
229            except:
230                err[i] = 1.0
231                print "Error getting error", value, x[i]
232               
233        new_plot = Theory1D(x, y)
234        new_plot.name = IQ_FIT_LABEL
235        new_plot.xaxis("\\rm{Q}", 'A^{-1}')
236        new_plot.yaxis("\\rm{Intensity} ","cm^{-1}")
237        #new_plot.group_id = "test group"
238        wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot, title="I(q)"))
239       
240        # If we have used slit smearing, plot the smeared I(q) too
241        if pr.slit_width>0 or pr.slit_height>0:
242            x = pylab.arange(minq, maxq, maxq/301.0)
243            y = numpy.zeros(len(x))
244            err = numpy.zeros(len(x))
245            for i in range(len(x)):
246                value = pr.iq_smeared(out, x[i])
247                y[i] = value
248                try:
249                    err[i] = math.sqrt(math.fabs(value))
250                except:
251                    err[i] = 1.0
252                    print "Error getting error", value, x[i]
253                   
254            new_plot = Theory1D(x, y)
255            new_plot.name = IQ_SMEARED_LABEL
256            new_plot.xaxis("\\rm{Q}", 'A^{-1}')
257            new_plot.yaxis("\\rm{Intensity} ","cm^{-1}")
258            #new_plot.group_id = "test group"
259            wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot, title="I(q)"))
260       
261       
262    def _on_pr_npts(self, evt):
263        """
264            Redisplay P(r) with a different number of points
265        """   
266        from inversion_panel import PrDistDialog
267        dialog = PrDistDialog(None, -1)
268        dialog.set_content(self._pr_npts)
269        if dialog.ShowModal() == wx.ID_OK:
270            self._pr_npts= dialog.get_content()
271            dialog.Destroy()
272            self.show_pr(self._last_out, self._last_pr, self._last_cov)
273        else:
274            dialog.Destroy()
275       
276       
277    def show_pr(self, out, pr, cov=None):
278        import numpy
279        import pylab
280        import math
281        from sans.guicomm.events import NewPlotEvent           
282        from sans.guitools.plottables import Data1D, Theory1D
283       
284        # Show P(r)
285        x = pylab.arange(0.0, pr.d_max, pr.d_max/self._pr_npts)
286   
287        y = numpy.zeros(len(x))
288        dy = numpy.zeros(len(x))
289        y_true = numpy.zeros(len(x))
290
291        sum = 0.0
292        pmax = 0.0
293        cov2 = numpy.ascontiguousarray(cov)
294       
295        for i in range(len(x)):
296            if cov2==None:
297                value = pr.pr(out, x[i])
298            else:
299                (value, dy[i]) = pr.pr_err(out, cov2, x[i])
300            sum += value*pr.d_max/len(x)
301           
302            # keep track of the maximum P(r) value
303            if value>pmax:
304                pmax = value
305               
306            y[i] = value
307               
308        if self._normalize_output==True:
309            y = y/sum
310            dy = dy/sum
311        elif self._scale_output_unity==True:
312            y = y/pmax
313            dy = dy/pmax
314       
315        if cov2==None:
316            new_plot = Theory1D(x, y)
317        else:
318            new_plot = Data1D(x, y, dy=dy)
319        new_plot.name = "P_{fit}(r)"
320        new_plot.xaxis("\\rm{r}", 'A')
321        new_plot.yaxis("\\rm{P(r)} ","cm^{-3}")
322           
323        wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot, title="P(r) fit"))
324       
325        return x, pr.d_max
326       
327       
328    def choose_file(self):
329        """
330       
331        """
332        #TODO: this should be in a common module
333        return self.parent.choose_file()
334               
335    def load(self, path = "sphere_60_q0_2.txt"):
336        import numpy, math, sys
337        # Read the data from the data file
338        data_x   = numpy.zeros(0)
339        data_y   = numpy.zeros(0)
340        data_err = numpy.zeros(0)
341        scale    = None
342        min_err  = 0.0
343        if not path == None:
344            input_f = open(path,'r')
345            buff    = input_f.read()
346            lines   = buff.split('\n')
347            for line in lines:
348                try:
349                    toks = line.split()
350                    x = float(toks[0])
351                    y = float(toks[1])
352                    if len(toks)>2:
353                        err = float(toks[2])
354                    else:
355                        if scale==None:
356                            scale = 0.05*math.sqrt(y)
357                            #scale = 0.05/math.sqrt(y)
358                            min_err = 0.01*y
359                        err = scale*math.sqrt(y)+min_err
360                        #err = 0
361                       
362                    data_x = numpy.append(data_x, x)
363                    data_y = numpy.append(data_y, y)
364                    data_err = numpy.append(data_err, err)
365                except:
366                    pass
367                   
368        if not scale==None:
369            message = "The loaded file had no error bars, statistical errors are assumed."
370            wx.PostEvent(self.parent, StatusEvent(status=message))
371        else:
372            wx.PostEvent(self.parent, StatusEvent(status=''))
373                       
374        return data_x, data_y, data_err     
375       
376    def pr_theory(self, r, R):
377        """
378           
379        """
380        if r<=2*R:
381            return 12.0* ((0.5*r/R)**2) * ((1.0-0.5*r/R)**2) * ( 2.0 + 0.5*r/R )
382        else:
383            return 0.0
384
385    def get_context_menu(self, graph=None):
386        """
387            Get the context menu items available for P(r)
388            @param graph: the Graph object to which we attach the context menu
389            @return: a list of menu items with call-back function
390        """
391        # Look whether this Graph contains P(r) data
392        #if graph.selected_plottable==IQ_DATA_LABEL:
393        for item in graph.plottables:
394            if item.name==PR_FIT_LABEL:
395                m_list = [["Add P(r) data", "Load a data file and display it on this plot", self._on_add_data],
396                       ["Change number of P(r) points", "Change the number of points on the P(r) output", self._on_pr_npts]]
397
398                m_list.append(["Disable P(r) scaling", 
399                               "Let the output P(r) keep the scale of the data", 
400                               self._on_disable_scaling])
401               
402                if self._scale_output_unity==False:
403                    m_list.append(["Scale P_max(r) to unity", 
404                                   "Scale P(r) so that its maximum is 1", 
405                                   self._on_scale_unity])
406                   
407                if self._normalize_output==False:
408                    m_list.append(["Normalize P(r) to unity", 
409                                   "Normalize the integral of P(r) to 1", 
410                                   self._on_normalize])
411                   
412                return m_list
413                #return [["Add P(r) data", "Load a data file and display it on this plot", self._on_add_data],
414                #       ["Change number of P(r) points", "Change the number of points on the P(r) output", self._on_pr_npts]]
415
416            elif item.name==graph.selected_plottable:
417                return [["Compute P(r)", "Compute P(r) from distribution", self._on_context_inversion]]     
418               
419        return []
420
421    def _on_disable_scaling(self, evt):
422        """
423            Disable P(r) scaling
424            @param evt: Menu event
425        """
426        self._normalize_output = False
427        self._scale_output_unity = False
428        self.show_pr(self._last_out, self._last_pr, self._last_cov)
429       
430    def _on_normalize(self, evt):
431        """
432            Switch normalization ON/OFF
433            @param evt: Menu event
434        """
435        self._normalize_output = True
436        self._scale_output_unity = False
437           
438        self.show_pr(self._last_out, self._last_pr, self._last_cov)
439       
440    def _on_scale_unity(self, evt):
441        """
442            Switch normalization ON/OFF
443            @param evt: Menu event
444        """
445        self._scale_output_unity = True
446        self._normalize_output = False
447           
448        self.show_pr(self._last_out, self._last_pr, self._last_cov)
449       
450    def _on_add_data(self, evt):
451        """
452            Add a data curve to the plot
453            WARNING: this will be removed once guiframe.plotting has its full functionality
454        """
455        path = self.choose_file()
456        if path==None:
457            return
458       
459        x, y, err = self.parent.load_ascii_1D(path)
460       
461        #new_plot = Data1D(x, y, dy=err)
462        new_plot = Theory1D(x, y)
463        new_plot.name = "P_{loaded}(r)"
464        new_plot.xaxis("\\rm{r}", 'A')
465        new_plot.yaxis("\\rm{P(r)} ","cm^{-3}")
466           
467        wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot, title="P(r) fit"))
468       
469       
470
471    def start_thread(self):
472        from pr_thread import CalcPr
473        from copy import deepcopy
474       
475        # If a thread is already started, stop it
476        if self.calc_thread != None and self.calc_thread.isrunning():
477            self.calc_thread.stop()
478               
479        pr = self.pr.clone()
480        self.calc_thread = CalcPr(pr, self.nfunc, error_func=self._thread_error, completefn=self._completed, updatefn=None)
481        self.calc_thread.queue()
482        self.calc_thread.ready(2.5)
483   
484    def _thread_error(self, error):
485        wx.PostEvent(self.parent, StatusEvent(status=error))
486   
487    def _estimate_completed(self, alpha, message, elapsed):
488        """
489            Parameter estimation completed,
490            display the results to the user
491            @param alpha: estimated best alpha
492            @param elapsed: computation time
493        """
494        # Save useful info
495        self.elapsed = elapsed
496        self.control_panel.alpha_estimate = alpha
497        if not message==None:
498            wx.PostEvent(self.parent, StatusEvent(status=str(message)))
499           
500        self.perform_estimateNT()
501   
502
503   
504    def _estimateNT_completed(self, nterms, alpha, message, elapsed):
505        """
506            Parameter estimation completed,
507            display the results to the user
508            @param alpha: estimated best alpha
509            @param nterms: estimated number of terms
510            @param elapsed: computation time
511        """
512        # Save useful info
513        self.elapsed = elapsed
514        self.control_panel.nterms_estimate = nterms
515        self.control_panel.alpha_estimate = alpha
516        if not message==None:
517            wx.PostEvent(self.parent, StatusEvent(status=str(message)))
518   
519    def _completed(self, out, cov, pr, elapsed):
520        """
521            Method called with the results when the inversion
522            is done
523           
524            @param out: output coefficient for the base functions
525            @param cov: covariance matrix
526            @param pr: Invertor instance
527            @param elapsed: time spent computing
528        """
529        from copy import deepcopy
530        # Save useful info
531        self.elapsed = elapsed
532        # Keep a copy of the last result
533        self._last_pr  = pr.clone()
534        self._last_out = out
535        self._last_cov = cov
536       
537        # Save Pr invertor
538        self.pr = pr
539       
540        #message = "Computation completed in %g seconds [chi2=%g]" % (elapsed, pr.chi2)
541        #wx.PostEvent(self.parent, StatusEvent(status=message))
542
543        cov = numpy.ascontiguousarray(cov)
544
545        # Show result on control panel
546        self.control_panel.chi2 = pr.chi2
547        self.control_panel.elapsed = elapsed
548        self.control_panel.oscillation = pr.oscillations(out)
549        #print "OSCILL", pr.oscillations(out)
550        #print "PEAKS:", pr.get_peaks(out)
551        self.control_panel.positive = pr.get_positive(out)
552        self.control_panel.pos_err  = pr.get_pos_err(out, cov)
553        self.control_panel.rg = pr.rg(out)
554        self.control_panel.iq0 = pr.iq0(out)
555        self.control_panel.bck = pr.background
556       
557        for i in range(len(out)):
558            try:
559                print "%d: %g +- %g" % (i, out[i], math.sqrt(math.fabs(cov[i][i])))
560            except: 
561                print sys.exc_value
562                print "%d: %g +- ?" % (i, out[i])       
563       
564        # Make a plot of I(q) data
565        if False:
566            new_plot = Data1D(self.pr.x, self.pr.y, dy=self.pr.err)
567            new_plot.name = "I_{obs}(q)"
568            new_plot.xaxis("\\rm{Q}", 'A^{-1}')
569            new_plot.yaxis("\\rm{Intensity} ","cm^{-1}")
570            #new_plot.group_id = "test group"
571            wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot, title="Iq"))
572               
573        # Show I(q) fit
574        self.show_iq(out, self.pr)
575       
576        # Show P(r) fit
577        x_values, x_range = self.show_pr(out, self.pr, cov) 
578       
579        # Popup result panel
580        #result_panel = InversionResults(self.parent, -1, style=wx.RAISED_BORDER)
581       
582    def show_data(self, path=None, reset=False):
583        """
584            Show data read from a file
585            @param path: file path
586            @param reset: if True all other plottables will be cleared
587        """
588       
589       
590        if not path==None:
591            self._create_file_pr(path) 
592             
593        # Make a plot of I(q) data
594        if self.pr.err==None:
595            new_plot = Theory1D(self.pr.x, self.pr.y)
596        else:
597            new_plot = Data1D(self.pr.x, self.pr.y, dy=self.pr.err)
598        new_plot.name = "I_{obs}(q)"
599        new_plot.xaxis("\\rm{Q}", 'A^{-1}')
600        new_plot.yaxis("\\rm{Intensity} ","cm^{-1}")
601        new_plot.interactive = True
602        #new_plot.group_id = "test group"
603        wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot, title="I(q)", reset=reset))
604       
605        # Get Q range
606        self.control_panel.q_min = self.pr.x.min()
607        self.control_panel.q_max = self.pr.x.max()
608           
609
610       
611    def setup_plot_inversion(self, alpha, nfunc, d_max, q_min=None, q_max=None, 
612                             bck=False, height=0, width=0):
613        self.alpha = alpha
614        self.nfunc = nfunc
615        self.max_length = d_max
616        self.q_min = q_min
617        self.q_max = q_max
618        self.has_bck = bck
619        self.slit_height = height
620        self.slit_width  = width
621       
622        try:
623            pr = self._create_plot_pr()
624            if not pr==None:
625                self.pr = pr
626                self.perform_inversion()
627        except:
628            wx.PostEvent(self.parent, StatusEvent(status=sys.exc_value))
629
630    def estimate_plot_inversion(self, alpha, nfunc, d_max, q_min=None, q_max=None, 
631                                bck=False, height=0, width=0):
632        self.alpha = alpha
633        self.nfunc = nfunc
634        self.max_length = d_max
635        self.q_min = q_min
636        self.q_max = q_max
637        self.has_bck = bck
638        self.slit_height = height
639        self.slit_width  = width
640       
641        try:
642            pr = self._create_plot_pr()
643            if not pr==None:
644                self.pr = pr
645                self.perform_estimate()
646        except:
647            wx.PostEvent(self.parent, StatusEvent(status=sys.exc_value))           
648
649    def _create_plot_pr(self, estimate=False):
650        """
651            Create and prepare invertor instance from
652            a plottable data set.
653            @param path: path of the file to read in
654        """
655        # Get the data from the chosen data set and perform inversion
656        pr = Invertor()
657        pr.d_max = self.max_length
658        pr.alpha = self.alpha
659        pr.q_min = self.q_min
660        pr.q_max = self.q_max
661        pr.x = self.current_plottable.x
662        pr.y = self.current_plottable.y
663        pr.has_bck = self.has_bck
664        pr.slit_height = self.slit_height
665        pr.slit_width = self.slit_width
666       
667        # Fill in errors if none were provided
668        if self.current_plottable.dy == None:
669            print "no error", self.current_plottable.name
670            y = numpy.zeros(len(pr.y))
671            for i in range(len(pr.y)):
672                y[i] = math.sqrt(pr.y[i])
673            pr.err = y
674        else:
675            pr.err = self.current_plottable.dy
676       
677        #self.pr = pr
678        return pr
679
680         
681    def setup_file_inversion(self, alpha, nfunc, d_max, path, q_min=None, q_max=None, 
682                             bck=False, height=0, width=0):
683        self.alpha = alpha
684        self.nfunc = nfunc
685        self.max_length = d_max
686        self.q_min = q_min
687        self.q_max = q_max
688        self.has_bck = bck
689        self.slit_height = height
690        self.slit_width  = width
691       
692        try:
693            pr = self._create_file_pr(path)
694            if not pr==None:
695                self.pr = pr
696                self.perform_inversion()
697        except:
698            wx.PostEvent(self.parent, StatusEvent(status=sys.exc_value))
699         
700    def estimate_file_inversion(self, alpha, nfunc, d_max, path, q_min=None, q_max=None, 
701                                bck=False, height=0, width=0):
702        self.alpha = alpha
703        self.nfunc = nfunc
704        self.max_length = d_max
705        self.q_min = q_min
706        self.q_max = q_max
707        self.has_bck = bck
708        self.slit_height = height
709        self.slit_width  = width
710       
711        try:
712            pr = self._create_file_pr(path)
713            if not pr==None:
714                self.pr = pr
715                self.perform_estimate()
716        except:
717            wx.PostEvent(self.parent, StatusEvent(status=sys.exc_value))
718               
719         
720    def _create_file_pr(self, path):
721        """
722            Create and prepare invertor instance from
723            a file data set.
724            @param path: path of the file to read in
725        """
726        from sans.guiframe.data_loader import load_ascii_1D
727        import numpy
728        # Load data
729        if os.path.isfile(path):
730           
731            x, y, err = self.load(path)
732            #x, y, err = load_ascii_1D(path)
733           
734            # If we have not errors, add statistical errors
735            if err==None:
736                err = numpy.zeros(len(y))
737                for i in range(len(y)):
738                    err[i] = math.sqrt( math.fabs(y[i]) )
739                message = "The loaded file had no error bars, statistical errors are assumed."
740                wx.PostEvent(self.parent, StatusEvent(status=message))
741            else:
742                wx.PostEvent(self.parent, StatusEvent(status=''))
743           
744            # Get the data from the chosen data set and perform inversion
745            pr = Invertor()
746            pr.d_max = self.max_length
747            pr.alpha = self.alpha
748            pr.q_min = self.q_min
749            pr.q_max = self.q_max
750            pr.x = x
751            pr.y = y
752            pr.err = err
753            pr.has_bck = self.has_bck
754            pr.slit_height = self.slit_height
755            pr.slit_width = self.slit_width
756            return pr
757            #self.pr = pr
758            #return True
759        #return False
760        return None
761       
762    def perform_estimate(self):
763        from pr_thread import EstimatePr
764        from copy import deepcopy
765       
766        # If a thread is already started, stop it
767        if self.estimation_thread != None and self.estimation_thread.isrunning():
768            self.estimation_thread.stop()
769               
770        pr = self.pr.clone()
771        self.estimation_thread = EstimatePr(pr, self.nfunc, error_func=self._thread_error, 
772                                            completefn = self._estimate_completed, 
773                                            updatefn   = None)
774        self.estimation_thread.queue()
775        self.estimation_thread.ready(2.5)
776   
777    def perform_estimateNT(self):
778        from pr_thread import EstimateNT
779        from copy import deepcopy
780       
781        # If a thread is already started, stop it
782        if self.estimation_thread != None and self.estimation_thread.isrunning():
783            self.estimation_thread.stop()
784               
785        pr = self.pr.clone()
786        # Skip the slit settings for the estimation
787        # It slows down the application and it doesn't change the estimates
788        pr.slit_height = 0.0
789        pr.slit_width  = 0.0
790        self.estimation_thread = EstimateNT(pr, self.nfunc, error_func=self._thread_error, 
791                                            completefn = self._estimateNT_completed, 
792                                            updatefn   = None)
793        self.estimation_thread.queue()
794        self.estimation_thread.ready(2.5)
795       
796    def perform_inversion(self):
797       
798        # Time estimate
799        #estimated = self.elapsed*self.nfunc**2
800        #message = "Computation time may take up to %g seconds" % self.elapsed
801        #wx.PostEvent(self.parent, StatusEvent(status=message))
802       
803        # Start inversion thread
804        self.start_thread()
805        return
806       
807        out, cov = self.pr.lstsq(self.nfunc)
808       
809        # Save useful info
810        self.elapsed = self.pr.elapsed
811       
812        for i in range(len(out)):
813            try:
814                print "%d: %g +- %g" % (i, out[i], math.sqrt(math.fabs(cov[i][i])))
815            except: 
816                print "%d: %g +- ?" % (i, out[i])       
817       
818       
819       
820        # Make a plot of I(q) data
821        new_plot = Data1D(self.pr.x, self.pr.y, dy=self.pr.err)
822        new_plot.name = "I_{obs}(q)"
823        new_plot.xaxis("\\rm{Q}", 'A^{-1}')
824        new_plot.yaxis("\\rm{Intensity} ","cm^{-1}")
825        wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot, title="Iq"))
826               
827        # Show I(q) fit
828        self.show_iq(out, self.pr)
829       
830        # Show P(r) fit
831        x_values, x_range = self.show_pr(out, self.pr, cov=cov)
832       
833       
834         
835    def _on_context_inversion(self, event):
836        panel = event.GetEventObject()
837
838        from inversion_panel import InversionDlg
839       
840        # If we have more than one displayed plot, make the user choose
841        if len(panel.plots)>1 and panel.graph.selected_plottable in panel.plots:
842            dataset = panel.graph.selected_plottable
843            if False:
844                dialog = InversionDlg(None, -1, "P(r) Inversion", panel.plots, pars=False)
845                dialog.set_content(self.last_data, self.nfunc, self.alpha, self.max_length)
846                if dialog.ShowModal() == wx.ID_OK:
847                    dataset = dialog.get_content()
848                    dialog.Destroy()
849                else:
850                    dialog.Destroy()
851                    return
852        elif len(panel.plots)==1:
853            dataset = panel.plots.keys()[0]
854        else:
855            print "Error: No data is available"
856            return
857       
858        # Store a reference to the current plottable
859        # If we have a suggested value, use it.
860        try:
861            estimate = float(self.control_panel.alpha_estimate)
862            self.control_panel.alpha = estimate
863        except:
864            self.control_panel.alpha = self.alpha
865            print "No estimate yet"
866            pass
867        try:
868            estimate = int(self.control_panel.nterms_estimate)
869            self.control_panel.nfunc = estimate
870        except:
871            self.control_panel.nfunc = self.nfunc
872            print "No estimate yet"
873            pass
874       
875        self.current_plottable = panel.plots[dataset]
876        self.control_panel.plotname = dataset
877        #self.control_panel.nfunc = self.nfunc
878        self.control_panel.d_max = self.max_length
879        self.parent.set_perspective(self.perspective)
880        self.control_panel._on_invert(None)
881           
882    def get_panels(self, parent):
883        """
884            Create and return a list of panel objects
885        """
886        from inversion_panel import InversionControl
887       
888        self.parent = parent
889        self.control_panel = InversionControl(self.parent, -1, 
890                                              style=wx.RAISED_BORDER,
891                                              standalone=self.standalone)
892        self.control_panel.set_manager(self)
893        self.control_panel.nfunc = self.nfunc
894        self.control_panel.d_max = self.max_length
895        self.control_panel.alpha = self.alpha
896       
897        self.perspective = []
898        self.perspective.append(self.control_panel.window_name)
899       
900        self.parent.Bind(EVT_PR_FILE, self._on_new_file)
901       
902        return [self.control_panel]
903   
904    def _on_new_file(self, evt):
905        """
906            Called when the application manager posted an
907            EVT_PR_FILE event. Just prompt the control
908            panel to load a new data file.
909        """
910        self.control_panel._change_file(None)
911   
912    def get_perspective(self):
913        """
914            Get the list of panel names for this perspective
915        """
916        return self.perspective
917   
918    def on_perspective(self, event):
919        """
920            Call back function for the perspective menu item.
921            We notify the parent window that the perspective
922            has changed.
923        """
924        self.parent.set_perspective(self.perspective)
925   
926    def post_init(self):
927        """
928            Post initialization call back to close the loose ends
929            [Somehow openGL needs this call]
930        """
931        self.parent.set_perspective(self.perspective)
932 
933if __name__ == "__main__":
934    i = Plugin()
935    print i.perform_estimateNT()
936   
937   
938   
939   
Note: See TracBrowser for help on using the repository browser.