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

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

minor change

  • Property mode set to 100644
File size: 32.1 KB
RevLine 
[f3d51f6]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
[4a5de6f]6import sys
[f3d51f6]7import wx
[aa4b8379]8import logging
[f3d51f6]9from sans.guitools.plottables import Data1D, Theory1D
10from sans.guicomm.events import NewPlotEvent, StatusEvent   
11import math, numpy
12from sans.pr.invertor import Invertor
13
[2a92852]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)"
[aa4b8379]19
20import wx.lib
21(NewPrFileEvent, EVT_PR_FILE) = wx.lib.newevent.NewEvent()
22
23
[f3d51f6]24class Plugin:
25   
[b659551]26    DEFAULT_ALPHA = 0.0001
27    DEFAULT_NFUNC = 10
28    DEFAULT_DMAX  = 140.0
29   
[f3d51f6]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
[b659551]44        self.alpha      = self.DEFAULT_ALPHA
45        self.nfunc      = self.DEFAULT_NFUNC
46        self.max_length = self.DEFAULT_DMAX
[634f1cf]47        self.q_min      = None
48        self.q_max      = None
[a4bd2ac]49        self.has_bck    = False
[2a92852]50        self.slit_height = 0
51        self.slit_width  = 0
[f3d51f6]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
[aa4b8379]57        self.iq_data_shown = False
[f3d51f6]58       
59        ## Current invertor
60        self.invertor    = None
[3fd1ebc]61        self.pr          = None
[feb21d8]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
[f3d51f6]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
[b659551]74        ## Number of P(r) points to display on the output plot
75        self._pr_npts = 51
[aa4b8379]76        ## Flag to let the plug-in know that it is running standalone
77        self.standalone = True
[feb21d8]78        self._normalize_output = False
79        self._scale_output_unity = False
[aa4b8379]80       
81        # Log startup
82        logging.info("Pr(r) plug-in started")
83       
84       
[f3d51f6]85
86    def populate_menu(self, id, owner):
87        """
88            Create a menu for the plug-in
89        """
[7cb0353]90        return []
[f3d51f6]91   
[119a11d]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   
[f3d51f6]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)
[b659551]147        new_plot = Data1D(pr.x, pr.y, dy=pr.err)
[f3d51f6]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       
[b659551]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       
[f3d51f6]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               
[634f1cf]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)
[f3d51f6]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)
[2a92852]234        new_plot.name = IQ_FIT_LABEL
[f3d51f6]235        new_plot.xaxis("\\rm{Q}", 'A^{-1}')
236        new_plot.yaxis("\\rm{Intensity} ","cm^{-1}")
237        #new_plot.group_id = "test group"
[9b85e93]238        wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot, title="I(q)"))
[f3d51f6]239       
[2a92852]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       
[f3d51f6]261       
[b659551]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()
[feb21d8]272            self.show_pr(self._last_out, self._last_pr, self._last_cov)
[b659551]273        else:
274            dialog.Destroy()
[f3d51f6]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)
[b659551]285        x = pylab.arange(0.0, pr.d_max, pr.d_max/self._pr_npts)
[f3d51f6]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
[feb21d8]292        pmax = 0.0
[dfb58f8]293        cov2 = numpy.ascontiguousarray(cov)
294       
[f3d51f6]295        for i in range(len(x)):
[dfb58f8]296            if cov2==None:
[f3d51f6]297                value = pr.pr(out, x[i])
298            else:
[dfb58f8]299                (value, dy[i]) = pr.pr_err(out, cov2, x[i])
[660b1e6]300            sum += value*pr.d_max/len(x)
[f3d51f6]301           
[feb21d8]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
[f3d51f6]314       
[dfb58f8]315        if cov2==None:
[f3d51f6]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               
[b659551]335    def load(self, path = "sphere_60_q0_2.txt"):
[f3d51f6]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)
[b659551]341        scale    = None
342        min_err  = 0.0
[f3d51f6]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])
[b659551]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                       
[4a5de6f]362                    data_x = numpy.append(data_x, x)
363                    data_y = numpy.append(data_y, y)
[b659551]364                    data_err = numpy.append(data_err, err)
[f3d51f6]365                except:
[b659551]366                    pass
[f3d51f6]367                   
[357b79b]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                       
[b659551]374        return data_x, data_y, data_err     
[f3d51f6]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
[660b1e6]385    def get_context_menu(self, graph=None):
[f3d51f6]386        """
387            Get the context menu items available for P(r)
[660b1e6]388            @param graph: the Graph object to which we attach the context menu
[f3d51f6]389            @return: a list of menu items with call-back function
390        """
[660b1e6]391        # Look whether this Graph contains P(r) data
[aa4b8379]392        #if graph.selected_plottable==IQ_DATA_LABEL:
[660b1e6]393        for item in graph.plottables:
[aa4b8379]394            if item.name==PR_FIT_LABEL:
[feb21d8]395                m_list = [["Add P(r) data", "Load a data file and display it on this plot", self._on_add_data],
[b659551]396                       ["Change number of P(r) points", "Change the number of points on the P(r) output", self._on_pr_npts]]
[aa4b8379]397
[900c787]398                if self._scale_output_unity==True or self._normalize_output==True:
399                    m_list.append(["Disable P(r) scaling", 
400                                   "Let the output P(r) keep the scale of the data", 
401                                   self._on_disable_scaling])
[feb21d8]402               
403                if self._scale_output_unity==False:
404                    m_list.append(["Scale P_max(r) to unity", 
405                                   "Scale P(r) so that its maximum is 1", 
406                                   self._on_scale_unity])
407                   
408                if self._normalize_output==False:
409                    m_list.append(["Normalize P(r) to unity", 
410                                   "Normalize the integral of P(r) to 1", 
411                                   self._on_normalize])
412                   
413                return m_list
414                #return [["Add P(r) data", "Load a data file and display it on this plot", self._on_add_data],
415                #       ["Change number of P(r) points", "Change the number of points on the P(r) output", self._on_pr_npts]]
416
[aa4b8379]417            elif item.name==graph.selected_plottable:
418                return [["Compute P(r)", "Compute P(r) from distribution", self._on_context_inversion]]     
[660b1e6]419               
[aa4b8379]420        return []
[660b1e6]421
[feb21d8]422    def _on_disable_scaling(self, evt):
423        """
424            Disable P(r) scaling
425            @param evt: Menu event
426        """
427        self._normalize_output = False
428        self._scale_output_unity = False
429        self.show_pr(self._last_out, self._last_pr, self._last_cov)
430       
431    def _on_normalize(self, evt):
432        """
433            Switch normalization ON/OFF
434            @param evt: Menu event
435        """
436        self._normalize_output = True
437        self._scale_output_unity = False
438           
439        self.show_pr(self._last_out, self._last_pr, self._last_cov)
440       
441    def _on_scale_unity(self, evt):
442        """
443            Switch normalization ON/OFF
444            @param evt: Menu event
445        """
446        self._scale_output_unity = True
447        self._normalize_output = False
448           
449        self.show_pr(self._last_out, self._last_pr, self._last_cov)
450       
[660b1e6]451    def _on_add_data(self, evt):
452        """
453            Add a data curve to the plot
454            WARNING: this will be removed once guiframe.plotting has its full functionality
455        """
456        path = self.choose_file()
457        if path==None:
458            return
459       
460        x, y, err = self.parent.load_ascii_1D(path)
461       
[b659551]462        #new_plot = Data1D(x, y, dy=err)
463        new_plot = Theory1D(x, y)
[660b1e6]464        new_plot.name = "P_{loaded}(r)"
465        new_plot.xaxis("\\rm{r}", 'A')
466        new_plot.yaxis("\\rm{P(r)} ","cm^{-3}")
467           
468        wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot, title="P(r) fit"))
469       
470       
[f3d51f6]471
472    def start_thread(self):
473        from pr_thread import CalcPr
474        from copy import deepcopy
475       
476        # If a thread is already started, stop it
477        if self.calc_thread != None and self.calc_thread.isrunning():
478            self.calc_thread.stop()
479               
480        pr = self.pr.clone()
481        self.calc_thread = CalcPr(pr, self.nfunc, error_func=self._thread_error, completefn=self._completed, updatefn=None)
482        self.calc_thread.queue()
483        self.calc_thread.ready(2.5)
484   
485    def _thread_error(self, error):
486        wx.PostEvent(self.parent, StatusEvent(status=error))
487   
[32dffae4]488    def _estimate_completed(self, alpha, message, elapsed):
[f3d51f6]489        """
490            Parameter estimation completed,
491            display the results to the user
492            @param alpha: estimated best alpha
493            @param elapsed: computation time
494        """
495        # Save useful info
496        self.elapsed = elapsed
497        self.control_panel.alpha_estimate = alpha
[32dffae4]498        if not message==None:
499            wx.PostEvent(self.parent, StatusEvent(status=str(message)))
[35adaf6]500           
501        self.perform_estimateNT()
502   
503
504   
505    def _estimateNT_completed(self, nterms, alpha, message, elapsed):
506        """
507            Parameter estimation completed,
508            display the results to the user
509            @param alpha: estimated best alpha
510            @param nterms: estimated number of terms
511            @param elapsed: computation time
512        """
513        # Save useful info
514        self.elapsed = elapsed
515        self.control_panel.nterms_estimate = nterms
516        self.control_panel.alpha_estimate = alpha
517        if not message==None:
518            wx.PostEvent(self.parent, StatusEvent(status=str(message)))
[f3d51f6]519   
520    def _completed(self, out, cov, pr, elapsed):
521        """
522            Method called with the results when the inversion
523            is done
524           
525            @param out: output coefficient for the base functions
526            @param cov: covariance matrix
527            @param pr: Invertor instance
528            @param elapsed: time spent computing
529        """
[dfb58f8]530        from copy import deepcopy
[f3d51f6]531        # Save useful info
532        self.elapsed = elapsed
[feb21d8]533        # Keep a copy of the last result
534        self._last_pr  = pr.clone()
535        self._last_out = out
536        self._last_cov = cov
537       
[b659551]538        # Save Pr invertor
539        self.pr = pr
540       
[d6113849]541        #message = "Computation completed in %g seconds [chi2=%g]" % (elapsed, pr.chi2)
542        #wx.PostEvent(self.parent, StatusEvent(status=message))
[f3d51f6]543
[dfb58f8]544        cov = numpy.ascontiguousarray(cov)
545
[f3d51f6]546        # Show result on control panel
547        self.control_panel.chi2 = pr.chi2
548        self.control_panel.elapsed = elapsed
549        self.control_panel.oscillation = pr.oscillations(out)
550        #print "OSCILL", pr.oscillations(out)
[d6113849]551        #print "PEAKS:", pr.get_peaks(out)
[dfb58f8]552        self.control_panel.positive = pr.get_positive(out)
553        self.control_panel.pos_err  = pr.get_pos_err(out, cov)
[a4bd2ac]554        self.control_panel.rg = pr.rg(out)
555        self.control_panel.iq0 = pr.iq0(out)
556        self.control_panel.bck = pr.background
[f3d51f6]557       
558        for i in range(len(out)):
559            try:
560                print "%d: %g +- %g" % (i, out[i], math.sqrt(math.fabs(cov[i][i])))
561            except: 
[b659551]562                print sys.exc_value
[f3d51f6]563                print "%d: %g +- ?" % (i, out[i])       
564       
565        # Make a plot of I(q) data
[aa4b8379]566        if False:
567            new_plot = Data1D(self.pr.x, self.pr.y, dy=self.pr.err)
568            new_plot.name = "I_{obs}(q)"
569            new_plot.xaxis("\\rm{Q}", 'A^{-1}')
570            new_plot.yaxis("\\rm{Intensity} ","cm^{-1}")
571            #new_plot.group_id = "test group"
572            wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot, title="Iq"))
[f3d51f6]573               
574        # Show I(q) fit
575        self.show_iq(out, self.pr)
576       
577        # Show P(r) fit
[dfb58f8]578        x_values, x_range = self.show_pr(out, self.pr, cov) 
[f3d51f6]579       
580        # Popup result panel
581        #result_panel = InversionResults(self.parent, -1, style=wx.RAISED_BORDER)
582       
[2a92852]583    def show_data(self, path=None, reset=False):
584        """
585            Show data read from a file
586            @param path: file path
587            @param reset: if True all other plottables will be cleared
588        """
589       
590       
[660b1e6]591        if not path==None:
592            self._create_file_pr(path) 
593             
594        # Make a plot of I(q) data
[357b79b]595        if self.pr.err==None:
596            new_plot = Theory1D(self.pr.x, self.pr.y)
597        else:
598            new_plot = Data1D(self.pr.x, self.pr.y, dy=self.pr.err)
[660b1e6]599        new_plot.name = "I_{obs}(q)"
600        new_plot.xaxis("\\rm{Q}", 'A^{-1}')
601        new_plot.yaxis("\\rm{Intensity} ","cm^{-1}")
[aa4b8379]602        new_plot.interactive = True
[660b1e6]603        #new_plot.group_id = "test group"
[2a92852]604        wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot, title="I(q)", reset=reset))
[660b1e6]605       
[aa4b8379]606        # Get Q range
607        self.control_panel.q_min = self.pr.x.min()
608        self.control_panel.q_max = self.pr.x.max()
609           
610
[660b1e6]611       
[2a92852]612    def setup_plot_inversion(self, alpha, nfunc, d_max, q_min=None, q_max=None, 
613                             bck=False, height=0, width=0):
[f3d51f6]614        self.alpha = alpha
615        self.nfunc = nfunc
616        self.max_length = d_max
[634f1cf]617        self.q_min = q_min
618        self.q_max = q_max
[a4bd2ac]619        self.has_bck = bck
[2a92852]620        self.slit_height = height
621        self.slit_width  = width
[f3d51f6]622       
[4a5de6f]623        try:
[2a92852]624            pr = self._create_plot_pr()
625            if not pr==None:
626                self.pr = pr
627                self.perform_inversion()
[4a5de6f]628        except:
629            wx.PostEvent(self.parent, StatusEvent(status=sys.exc_value))
[f3d51f6]630
[2a92852]631    def estimate_plot_inversion(self, alpha, nfunc, d_max, q_min=None, q_max=None, 
632                                bck=False, height=0, width=0):
[f3d51f6]633        self.alpha = alpha
634        self.nfunc = nfunc
635        self.max_length = d_max
[634f1cf]636        self.q_min = q_min
637        self.q_max = q_max
[a4bd2ac]638        self.has_bck = bck
[2a92852]639        self.slit_height = height
640        self.slit_width  = width
[f3d51f6]641       
[4a5de6f]642        try:
[2a92852]643            pr = self._create_plot_pr()
644            if not pr==None:
645                self.pr = pr
646                self.perform_estimate()
[4a5de6f]647        except:
648            wx.PostEvent(self.parent, StatusEvent(status=sys.exc_value))           
[f3d51f6]649
[2a92852]650    def _create_plot_pr(self, estimate=False):
[f3d51f6]651        """
652            Create and prepare invertor instance from
653            a plottable data set.
654            @param path: path of the file to read in
655        """
656        # Get the data from the chosen data set and perform inversion
657        pr = Invertor()
658        pr.d_max = self.max_length
659        pr.alpha = self.alpha
[634f1cf]660        pr.q_min = self.q_min
661        pr.q_max = self.q_max
[f3d51f6]662        pr.x = self.current_plottable.x
663        pr.y = self.current_plottable.y
[a4bd2ac]664        pr.has_bck = self.has_bck
[2a92852]665        pr.slit_height = self.slit_height
666        pr.slit_width = self.slit_width
[f3d51f6]667       
668        # Fill in errors if none were provided
669        if self.current_plottable.dy == None:
670            print "no error", self.current_plottable.name
671            y = numpy.zeros(len(pr.y))
672            for i in range(len(pr.y)):
673                y[i] = math.sqrt(pr.y[i])
674            pr.err = y
675        else:
676            pr.err = self.current_plottable.dy
[2a92852]677       
678        #self.pr = pr
679        return pr
[f3d51f6]680
681         
[2a92852]682    def setup_file_inversion(self, alpha, nfunc, d_max, path, q_min=None, q_max=None, 
683                             bck=False, height=0, width=0):
[f3d51f6]684        self.alpha = alpha
685        self.nfunc = nfunc
686        self.max_length = d_max
[634f1cf]687        self.q_min = q_min
688        self.q_max = q_max
[a4bd2ac]689        self.has_bck = bck
[2a92852]690        self.slit_height = height
691        self.slit_width  = width
[f3d51f6]692       
[4a5de6f]693        try:
[2a92852]694            pr = self._create_file_pr(path)
695            if not pr==None:
696                self.pr = pr
[4a5de6f]697                self.perform_inversion()
698        except:
699            wx.PostEvent(self.parent, StatusEvent(status=sys.exc_value))
[f3d51f6]700         
[2a92852]701    def estimate_file_inversion(self, alpha, nfunc, d_max, path, q_min=None, q_max=None, 
702                                bck=False, height=0, width=0):
[f3d51f6]703        self.alpha = alpha
704        self.nfunc = nfunc
705        self.max_length = d_max
[634f1cf]706        self.q_min = q_min
707        self.q_max = q_max
[a4bd2ac]708        self.has_bck = bck
[2a92852]709        self.slit_height = height
710        self.slit_width  = width
[f3d51f6]711       
[4a5de6f]712        try:
[2a92852]713            pr = self._create_file_pr(path)
714            if not pr==None:
715                self.pr = pr
[4a5de6f]716                self.perform_estimate()
717        except:
718            wx.PostEvent(self.parent, StatusEvent(status=sys.exc_value))
719               
[f3d51f6]720         
721    def _create_file_pr(self, path):
722        """
723            Create and prepare invertor instance from
724            a file data set.
725            @param path: path of the file to read in
726        """
[357b79b]727        from sans.guiframe.data_loader import load_ascii_1D
728        import numpy
[f3d51f6]729        # Load data
730        if os.path.isfile(path):
[357b79b]731           
[f3d51f6]732            x, y, err = self.load(path)
[357b79b]733            #x, y, err = load_ascii_1D(path)
734           
735            # If we have not errors, add statistical errors
736            if err==None:
737                err = numpy.zeros(len(y))
738                for i in range(len(y)):
739                    err[i] = math.sqrt( math.fabs(y[i]) )
740                message = "The loaded file had no error bars, statistical errors are assumed."
741                wx.PostEvent(self.parent, StatusEvent(status=message))
742            else:
743                wx.PostEvent(self.parent, StatusEvent(status=''))
[f3d51f6]744           
745            # Get the data from the chosen data set and perform inversion
746            pr = Invertor()
747            pr.d_max = self.max_length
748            pr.alpha = self.alpha
[634f1cf]749            pr.q_min = self.q_min
750            pr.q_max = self.q_max
[f3d51f6]751            pr.x = x
752            pr.y = y
753            pr.err = err
[a4bd2ac]754            pr.has_bck = self.has_bck
[2a92852]755            pr.slit_height = self.slit_height
756            pr.slit_width = self.slit_width
757            return pr
758            #self.pr = pr
759            #return True
760        #return False
761        return None
[f3d51f6]762       
763    def perform_estimate(self):
764        from pr_thread import EstimatePr
765        from copy import deepcopy
766       
767        # If a thread is already started, stop it
768        if self.estimation_thread != None and self.estimation_thread.isrunning():
769            self.estimation_thread.stop()
770               
771        pr = self.pr.clone()
772        self.estimation_thread = EstimatePr(pr, self.nfunc, error_func=self._thread_error, 
773                                            completefn = self._estimate_completed, 
774                                            updatefn   = None)
775        self.estimation_thread.queue()
776        self.estimation_thread.ready(2.5)
[35adaf6]777   
778    def perform_estimateNT(self):
779        from pr_thread import EstimateNT
780        from copy import deepcopy
781       
782        # If a thread is already started, stop it
783        if self.estimation_thread != None and self.estimation_thread.isrunning():
784            self.estimation_thread.stop()
785               
786        pr = self.pr.clone()
[2a92852]787        # Skip the slit settings for the estimation
788        # It slows down the application and it doesn't change the estimates
789        pr.slit_height = 0.0
790        pr.slit_width  = 0.0
[35adaf6]791        self.estimation_thread = EstimateNT(pr, self.nfunc, error_func=self._thread_error, 
792                                            completefn = self._estimateNT_completed, 
793                                            updatefn   = None)
794        self.estimation_thread.queue()
795        self.estimation_thread.ready(2.5)
[f3d51f6]796       
797    def perform_inversion(self):
798       
799        # Time estimate
800        #estimated = self.elapsed*self.nfunc**2
[2a92852]801        #message = "Computation time may take up to %g seconds" % self.elapsed
802        #wx.PostEvent(self.parent, StatusEvent(status=message))
[f3d51f6]803       
804        # Start inversion thread
805        self.start_thread()
806        return
807       
808        out, cov = self.pr.lstsq(self.nfunc)
809       
810        # Save useful info
811        self.elapsed = self.pr.elapsed
812       
813        for i in range(len(out)):
814            try:
815                print "%d: %g +- %g" % (i, out[i], math.sqrt(math.fabs(cov[i][i])))
816            except: 
817                print "%d: %g +- ?" % (i, out[i])       
818       
819       
820       
821        # Make a plot of I(q) data
822        new_plot = Data1D(self.pr.x, self.pr.y, dy=self.pr.err)
823        new_plot.name = "I_{obs}(q)"
824        new_plot.xaxis("\\rm{Q}", 'A^{-1}')
825        new_plot.yaxis("\\rm{Intensity} ","cm^{-1}")
826        wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot, title="Iq"))
827               
828        # Show I(q) fit
829        self.show_iq(out, self.pr)
830       
831        # Show P(r) fit
832        x_values, x_range = self.show_pr(out, self.pr, cov=cov)
833       
834       
835         
836    def _on_context_inversion(self, event):
837        panel = event.GetEventObject()
838
839        from inversion_panel import InversionDlg
840       
841        # If we have more than one displayed plot, make the user choose
[aa4b8379]842        if len(panel.plots)>1 and panel.graph.selected_plottable in panel.plots:
843            dataset = panel.graph.selected_plottable
844            if False:
845                dialog = InversionDlg(None, -1, "P(r) Inversion", panel.plots, pars=False)
846                dialog.set_content(self.last_data, self.nfunc, self.alpha, self.max_length)
847                if dialog.ShowModal() == wx.ID_OK:
848                    dataset = dialog.get_content()
849                    dialog.Destroy()
850                else:
851                    dialog.Destroy()
852                    return
[f3d51f6]853        elif len(panel.plots)==1:
854            dataset = panel.plots.keys()[0]
855        else:
856            print "Error: No data is available"
857            return
858       
859        # Store a reference to the current plottable
[3fd1ebc]860        # If we have a suggested value, use it.
861        try:
862            estimate = float(self.control_panel.alpha_estimate)
863            self.control_panel.alpha = estimate
864        except:
865            self.control_panel.alpha = self.alpha
866            print "No estimate yet"
867            pass
[d6113849]868        try:
869            estimate = int(self.control_panel.nterms_estimate)
870            self.control_panel.nfunc = estimate
871        except:
872            self.control_panel.nfunc = self.nfunc
873            print "No estimate yet"
874            pass
[3fd1ebc]875       
[f3d51f6]876        self.current_plottable = panel.plots[dataset]
877        self.control_panel.plotname = dataset
[d6113849]878        #self.control_panel.nfunc = self.nfunc
[f3d51f6]879        self.control_panel.d_max = self.max_length
880        self.parent.set_perspective(self.perspective)
[aa4b8379]881        self.control_panel._on_invert(None)
[f3d51f6]882           
883    def get_panels(self, parent):
884        """
885            Create and return a list of panel objects
886        """
887        from inversion_panel import InversionControl
888       
889        self.parent = parent
[aa4b8379]890        self.control_panel = InversionControl(self.parent, -1, 
891                                              style=wx.RAISED_BORDER,
892                                              standalone=self.standalone)
[f3d51f6]893        self.control_panel.set_manager(self)
894        self.control_panel.nfunc = self.nfunc
895        self.control_panel.d_max = self.max_length
896        self.control_panel.alpha = self.alpha
897       
898        self.perspective = []
899        self.perspective.append(self.control_panel.window_name)
[aa4b8379]900       
901        self.parent.Bind(EVT_PR_FILE, self._on_new_file)
902       
[f3d51f6]903        return [self.control_panel]
904   
[aa4b8379]905    def _on_new_file(self, evt):
906        """
907            Called when the application manager posted an
908            EVT_PR_FILE event. Just prompt the control
909            panel to load a new data file.
910        """
911        self.control_panel._change_file(None)
912   
[f3d51f6]913    def get_perspective(self):
914        """
915            Get the list of panel names for this perspective
916        """
917        return self.perspective
918   
919    def on_perspective(self, event):
920        """
921            Call back function for the perspective menu item.
922            We notify the parent window that the perspective
923            has changed.
924        """
925        self.parent.set_perspective(self.perspective)
926   
927    def post_init(self):
928        """
929            Post initialization call back to close the loose ends
930            [Somehow openGL needs this call]
931        """
[32dffae4]932        self.parent.set_perspective(self.perspective)
[35adaf6]933 
934if __name__ == "__main__":
935    i = Plugin()
936    print i.perform_estimateNT()
937   
938   
939   
[660b1e6]940   
Note: See TracBrowser for help on using the repository browser.