source: sasview/invariantview/perspectives/invariant/invariant_state.py @ 210ff4f

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 210ff4f was 5b03122, checked in by Jae Cho <jhjcho@…>, 14 years ago

removed commented (unused) imports

  • Property mode set to 100644
File size: 30.4 KB
Line 
1import time, os, sys
2import logging
3import copy
4import DataLoader
5from xml.dom.minidom import parse
6from lxml import etree
7from DataLoader.readers.cansas_reader import Reader as CansasReader
8from DataLoader.readers.cansas_reader import get_content
9from sans.guiframe.utils import format_number
10from sans.guiframe.dataFitting import Theory1D, Data1D
11INVNODE_NAME = 'invariant'
12CANSAS_NS = "cansas1d/1.0"
13# default state
14list = {'file': 'None',
15        'compute_num':0,
16        'state_num':0,
17        'is_time_machine':False,
18        'background_tcl':0.0,
19        'scale_tcl':1.0,
20        'contrast_tcl':1.0,
21        'porod_constant_tcl':'',
22        'npts_low_tcl':10,
23        'npts_high_tcl':10,
24        'power_high_tcl':4.0,
25        'power_low_tcl': 4.0,
26        'enable_high_cbox':False,
27        'enable_low_cbox':False,
28        'guinier': True,
29        'power_law_high': False,
30        'power_law_low': False,
31        'fit_enable_high': False,
32        'fit_enable_low': False,
33        'fix_enable_high':True,
34        'fix_enable_low':True,
35        'volume_tcl':'',
36        'volume_err_tcl':'',
37        'surface_tcl':'',
38        'surface_err_tcl':''}
39# list of states: This list will be filled as panel init and the number of states increases
40state_list = {}
41bookmark_list = {}
42# list of input parameters (will be filled up on panel init) used by __str__
43input_list = {'background_tcl':0,
44        'scale_tcl':0,
45        'contrast_tcl':0,
46        'porod_constant_tcl':'',
47        'npts_low_tcl':0,
48        'npts_high_tcl':0,
49        'power_high_tcl':0,
50        'power_low_tcl': 0} 
51# list of output parameters (order sensitive) used by __str__   
52output_list = [["qstar_low",                  "Q* from low Q extrapolation [1/(cm*A)]"],
53               ["qstar_low_err",             "dQ* from low Q extrapolation"],
54               ["qstar_low_percent",  "Q* percent from low Q extrapolation"],
55               ["qstar",                                     "Q* from data [1/(cm*A)]"],
56               ["qstar_err",                                "dQ* from data"],
57               ["qstar_percent",                     "Q* percent from data"],
58               ["qstar_high",                "Q* from high Q extrapolation [1/(cm*A)]"],
59               ["qstar_high_err",           "dQ* from high Q extrapolation"],
60               ["qstar_high_percent", "Q* percent from low Q extrapolation"],
61               ["qstar_total",                                   "total Q* [1/(cm*A)]"],
62               ["qstar_total_err",                              "total dQ*"],
63               ["volume",                                 "volume fraction"],
64               ["volume_err",                       "volume fraction error"],
65               ["surface",                               "specific surface"],
66               ["surface_err",                     "specific surface error"]]
67
68   
69
70class InvariantState(object):
71    """
72    Class to hold the state information of the InversionControl panel.
73    """
74    def __init__(self):
75        """
76        Default values
77        """
78        # Input
79        self.file  = None
80        self.data = Data1D(x=[], y=[], dx=None, dy=None)
81        self.theory_lowQ =  Theory1D(x=[], y=[], dy=None)
82        self.theory_highQ = Theory1D(x=[], y=[], dy=None)
83        #self.is_time_machine = False
84        self.saved_state = list
85        self.state_list = state_list
86        self.bookmark_list = bookmark_list
87        self.input_list = input_list
88        self.output_list = output_list
89       
90        self.compute_num = 0
91        self.state_num = 0
92        self.timestamp = ('00:00:00', '00/00/0000')
93        self.container = None
94        #plot image
95        self.wximbmp = None
96        # report_html strings
97        import sans.perspectives.invariant as invariant
98        path = invariant.get_data_path(media='media')
99        path_report_html= os.path.join(path,"report_template.html")
100        html_template=open(path_report_html,"r")
101        self.template_str = html_template.read()
102        self.report_str = self.template_str
103        #self.report_str_save = None
104        html_template.close()
105       
106
107       
108    def __str__(self):
109        """
110        Pretty print
111           
112        : return: string representing the state
113        """
114        # Input string
115        compute_num = self.saved_state['compute_num']
116        compute_state = self.state_list[str(compute_num)]
117        my_time, date = self.timestamp
118        file_name = self.file
119
120        state_num = int(self.saved_state['state_num'])
121        state = "\n[Invariant computation for %s: "% file_name
122        state += "performed at %s on %s] \n"%(my_time, date)
123        state += "State No.: %d \n"% state_num
124        state += "\n=== Inputs ===\n"
125       
126        # text ctl general inputs ( excluding extrapolation text ctl)
127        for key,value in self.input_list.iteritems(): 
128            if value == '':
129                continue
130            key_split = key.split('_') 
131            max_ind = len(key_split)-1
132            if key_split[max_ind] == 'tcl': 
133                name =""
134                if key_split[1]== 'low' or key_split[1]== 'high':
135                    continue
136                for ind in range(0,max_ind):
137                    name +=" %s"%key_split[ind]
138                state += "%s:   %s\n"% (name.lstrip(" "),value)
139               
140        # other input parameters       
141        extra_lo = compute_state['enable_low_cbox']
142        if compute_state['enable_low_cbox']:
143            if compute_state['guinier']:
144                extra_lo = 'Guinier'
145            else:
146                extra_lo = 'Power law'
147        extra_hi = compute_state['enable_high_cbox']
148        if compute_state['enable_high_cbox']:
149            extra_hi = 'Power law'
150        state += "\nExtrapolation:  High=%s; Low=%s\n" %(extra_hi,extra_lo)   
151        low_off = False
152        high_off = False
153        for key,value in self.input_list.iteritems(): 
154            key_split = key.split('_') 
155            max_ind = len(key_split)-1   
156            if key_split[max_ind] == 'tcl': 
157                name ="" 
158                # check each buttons whether or not ON or OFF
159                if key_split[1]== 'low' or key_split[1]== 'high':
160                    if not compute_state['enable_low_cbox'] and key_split[max_ind-1] == 'low':
161                        low_off = True
162                        continue             
163                    elif not compute_state['enable_high_cbox'] and key_split[max_ind-1]== 'high':
164                        high_off = True
165                        continue
166                    elif extra_lo == 'Guinier' and key_split[0]== 'power' and key_split[max_ind-1]== 'low':
167                        continue
168                    for ind in range(0,max_ind):
169                        name +=" %s"%key_split[ind]
170                    name = name.lstrip(" ")
171                    if name == "power low" :
172                        if compute_state['fix_enable_low']:
173                            name += ' (Fixed)'
174                        else:
175                            name += ' (Fitted)'
176                    if name == "power high" :
177                        if compute_state['fix_enable_high']:
178                            name += ' (Fixed)'
179                        else:
180                            name += ' (Fitted)'
181                    state += "%s:   %s\n"% (name,value)
182        # Outputs
183        state += "\n=== Outputs ==="
184        for item in output_list:
185            item_split = item[0].split('_') 
186            # Exclude the extrapolation that turned off
187            if len(item_split)>1:
188                if low_off and item_split[1] == 'low': continue
189                if high_off and item_split[1] == 'high': continue
190            max_ind = len(item_split)-1
191            value = None
192            try:
193                # Q* outputs
194                exec "value = self.container.%s\n"% item[0]
195            except:
196                # other outputs than Q*
197                name = item[0]+"_tcl"
198                exec "value = self.saved_state['%s']"% name
199               
200            # Exclude the outputs w/''   
201            if value == '': continue   
202           
203            # Error outputs
204            if item_split[max_ind] == 'err':
205                state += "+- %s "%format_number(value)
206               
207            # Percentage outputs
208            elif item_split[max_ind] == 'percent':
209                try:
210                    value = float(value)*100
211                except:
212                    pass
213                state += "(%s %s)"%(format_number(value),'%')
214            # Outputs
215            else:
216                state += "\n%s:   %s "%(item[1],format_number(value,high=True))
217        # Include warning msg
218        state += "\n\nNote:\n" + self.container.warning_msg
219       
220        return state
221
222   
223    def clone_state(self):
224        """
225        deepcopy the state
226        """
227        return copy.deepcopy(self.saved_state)
228   
229
230    def toXML(self, file="inv_state.inv", doc=None, entry_node=None):
231        """
232        Writes the state of the InversionControl panel to file, as XML.
233       
234        Compatible with standalone writing, or appending to an
235        already existing XML document. In that case, the XML document
236        is required. An optional entry node in the XML document may also be given.
237       
238        : param file: file to write to
239        : param doc: XML document object [optional]
240        : param entry_node: XML node within the XML document at which we will append the data [optional]   
241        """
242        from xml.dom.minidom import getDOMImplementation
243        import time
244        timestamp = time.time()
245        # Check whether we have to write a standalone XML file
246        if doc is None:
247            impl = getDOMImplementation()
248       
249            doc_type = impl.createDocumentType(INVNODE_NAME, "1.0", "1.0")     
250       
251            newdoc = impl.createDocument(None, INVNODE_NAME, doc_type)
252            top_element = newdoc.documentElement
253        else:
254            # We are appending to an existing document
255            newdoc = doc
256            top_element = newdoc.createElement(INVNODE_NAME)
257            if entry_node is None:
258                newdoc.documentElement.appendChild(top_element)
259            else:
260                entry_node.appendChild(top_element)
261           
262        attr = newdoc.createAttribute("version")
263        attr.nodeValue = '1.0'
264        top_element.setAttributeNode(attr)
265       
266        # File name
267        element = newdoc.createElement("filename")
268        if self.file is not None:
269            element.appendChild(newdoc.createTextNode(str(self.file)))
270        else:
271            element.appendChild(newdoc.createTextNode(str(file)))
272        top_element.appendChild(element)
273       
274        element = newdoc.createElement("timestamp")
275        element.appendChild(newdoc.createTextNode(time.ctime(timestamp)))
276        attr = newdoc.createAttribute("epoch")
277        attr.nodeValue = str(timestamp)
278        element.setAttributeNode(attr)
279        top_element.appendChild(element)
280       
281        # Current state
282        state = newdoc.createElement("state")
283        top_element.appendChild(state)
284       
285        for name,value in self.saved_state.iteritems():
286            element = newdoc.createElement(str(name))
287            element.appendChild(newdoc.createTextNode(str(value)))
288            state.appendChild(element)
289             
290        # State history list
291        history = newdoc.createElement("history")
292        top_element.appendChild(history)
293       
294        for name, value in self.state_list.iteritems():
295            history_element = newdoc.createElement('state_'+str(name))
296            for state_name,state_value in value.iteritems():
297                state_element = newdoc.createElement(str(state_name))
298                state_element.appendChild(newdoc.createTextNode(str(state_value)))
299                history_element.appendChild(state_element)
300            #history_element.appendChild(state_list_element)
301            history.appendChild(history_element)
302
303        # Bookmarks  bookmark_list[self.bookmark_num] = [my_time,date,state,comp_state]
304        bookmark = newdoc.createElement("bookmark")
305        top_element.appendChild(bookmark)
306        item_list = ['time','date','state','comp_state']
307        for name, value_list in self.bookmark_list.iteritems():
308            element = newdoc.createElement('mark_'+ str(name))
309            time,date,state,comp_state = value_list
310            time_element = newdoc.createElement('time')
311            time_element.appendChild(newdoc.createTextNode(str(value_list[0])))
312            date_element = newdoc.createElement('date')
313            date_element.appendChild(newdoc.createTextNode(str(value_list[1])))
314            state_list_element = newdoc.createElement('state')
315            comp_state_list_element = newdoc.createElement('comp_state')
316            for state_name,state_value in value_list[2].iteritems():
317                state_element = newdoc.createElement(str(state_name))
318                state_element.appendChild(newdoc.createTextNode(str(state_value)))
319                state_list_element.appendChild(state_element)
320            for comp_name,comp_value in value_list[3].iteritems():
321                comp_element = newdoc.createElement(str(comp_name))
322                comp_element.appendChild(newdoc.createTextNode(str(comp_value)))
323                comp_state_list_element.appendChild(comp_element)
324            element.appendChild(time_element)
325            element.appendChild(date_element)
326            element.appendChild(state_list_element)
327            element.appendChild(comp_state_list_element)
328            bookmark.appendChild(element)
329
330        # Save the file
331        if doc is None:
332            fd = open('test000', 'w')
333            fd.write(newdoc.toprettyxml())
334            fd.close()
335            return None
336        else:
337            return newdoc.toprettyxml()
338       
339    def fromXML(self, file=None, node=None):
340        """
341        Load invariant states from a file
342           
343        : param file: .inv file
344        : param node: node of a XML document to read from       
345        """
346        if file is not None:
347            raise RuntimeError, "InvariantSate no longer supports non-CanSAS format for invariant files"
348       
349        if node.get('version')\
350            and node.get('version') == '1.0':
351
352            # Get file name
353            entry = get_content('ns:filename', node)
354            if entry is not None:
355                self.file = entry.text.strip()
356           
357            # Get time stamp
358            entry = get_content('ns:timestamp', node)
359            if entry is not None and entry.get('epoch'):
360                try:
361                    timestamp = (entry.get('epoch'))
362                except:
363                    logging.error("InvariantSate.fromXML: Could not read timestamp\n %s" % sys.exc_value)
364           
365            # Parse bookmarks
366            entry_bookmark = get_content('ns:bookmark', node)
367
368            for ind in range(1,len(entry_bookmark)+1):
369                temp_state = {}
370                temp_bookmark = {}
371                entry = get_content('ns:mark_%s' % ind, entry_bookmark) 
372                               
373                if entry is not None:
374                    time = get_content('ns:time', entry )
375                    val_time = str(time.text.strip())
376                    date = get_content('ns:date', entry )
377                    val_date = str(date.text.strip())
378                    state_entry = get_content('ns:state', entry )
379                    for item in list:
380
381                        input_field = get_content('ns:%s' % item, state_entry )
382                        val = str(input_field.text.strip())
383
384                        if input_field is not None:
385                            try:
386                                exec "temp_state['%s'] = %s"% (item,val)     
387                            except:
388                                exec "temp_state['%s'] = '%s'"% (item,val)
389                           
390                    comp_entry = get_content('ns:comp_state', entry )
391                   
392                    for item in list:
393                        input_field = get_content('ns:%s' % item, comp_entry )
394                        val = str(input_field.text.strip())
395                        if input_field is not None:
396                            try:
397                                exec "temp_bookmark['%s'] = %s"% (item,val)     
398                            except:
399                                exec "temp_bookmark['%s'] = '%s'"% (item,val)
400                    try:
401                        exec "self.bookmark_list[%s] = [val_time,val_date,temp_state,temp_bookmark]"% ind
402
403                    except:
404                        raise "missing components of bookmarks..."
405   
406            # Parse histories
407            entry_history = get_content('ns:history', node)
408
409            for ind in range(0,len(entry_history)):
410                temp_state = {}
411                entry = get_content('ns:state_%s' % ind, entry_history) 
412
413                if entry is not None:
414                    for item in list:
415                        input_field = get_content('ns:%s' % item, entry )
416                        val = str(input_field.text.strip())
417
418                        if input_field is not None:
419                            try:
420                                exec "temp_state['%s'] = %s"% (item,val)         
421                            except:
422                                exec "temp_state['%s'] = '%s'"% (item,val)
423                            finally:
424                                exec "self.state_list['%s'] = temp_state"% ind
425           
426            # Parse current state (ie, saved_state)
427            entry = get_content('ns:state', node)           
428            if entry is not None:
429                for item in list:
430                    input_field = get_content('ns:%s' % item, entry)
431                    val = str(input_field.text.strip())
432                    if input_field is not None:
433                        self.set_saved_state(name=item, value=val)
434
435    def set_report_string(self):
436        """
437        Get the values (strings) from __str__ for report
438        """
439        strings = self.__str__()
440   
441        # default string values
442        for num in range (1,19):
443            exec "s_%s = 'NA'"% str(num)
444        lines = strings.split('\n')
445        # get all string values from __str__()
446        for line in range(0,len(lines)):
447            if line == 1:
448                s_1 = lines[1]
449            elif line == 2:
450                s_2 = lines[2]
451            else:
452                item = lines[line].split(':')
453                item[0] = item[0].strip()
454                if item[0]== "scale":
455                    s_3 = item[1]
456                elif item[0] == "porod constant":
457                    s_4 = item[1]
458                elif item[0] == "background":
459                    s_5 = item[1]
460                elif item[0] == "contrast":
461                    s_6 = item[1]
462                elif item[0] == "Extrapolation":
463                    extra = item[1].split(";")
464                    bool_0 = extra[0].split("=")
465                    bool_1 = extra[1].split("=")
466                    s_7 = " "+bool_0[0]+"Q region = "+bool_0[1]
467                    s_8 = " "+bool_1[0]+"Q region = "+bool_1[1]
468                elif item[0]=="npts low":
469                    s_9 = item[1]
470                elif item[0]=="npts high":
471                    s_10 = item[1]
472                elif item[0] == "volume fraction":
473                    val=item[1].split("+-")[0].strip()
474                    error = item[1].split("+-")[1].strip()
475                    s_17 = val+" &plusmn; "+error
476                elif item[0] == "specific surface":
477                    val=item[1].split("+-")[0].strip()
478                    error = item[1].split("+-")[1].strip()
479                    s_18 = val+" &plusmn; "+error
480                elif item[0].split("(")[0].strip()=="power high":
481                    s_11 = item[0]+" ="+item[1]
482                elif item[0].split("(")[0].strip()=="power low":
483                    s_12 = item[0]+" ="+item[1]
484                elif item[0].split("[")[0].strip()=="Q* from low Q extrapolation":
485                    #looks messy but this way the symbols +_ and % work on html
486                    val=item[1].split("+-")[0].strip()
487                    error = item[1].split("+-")[1].strip()
488                    err = error.split("%")[0].strip()
489                    percent = error.split("%")[1].strip()
490                    s_13 = val+" &plusmn; "+err+"&#37"+percent
491                elif item[0].split("[")[0].strip()=="Q* from data":
492                    val=item[1].split("+-")[0].strip()
493                    error = item[1].split("+-")[1].strip()
494                    err = error.split("%")[0].strip()
495                    percent = error.split("%")[1].strip()
496                    s_14 = val+" &plusmn; "+err+"&#37"+percent
497                elif item[0].split("[")[0].strip()=="Q* from high Q extrapolation":
498                    val=item[1].split("+-")[0].strip()
499                    error = item[1].split("+-")[1].strip()
500                    err = error.split("%")[0].strip()
501                    percent = error.split("%")[1].strip()
502                    s_15 = val+" &plusmn; "+err+"&#37"+percent
503                elif item[0].split("[")[0].strip()=="total Q*":
504                    val=item[1].split("+-")[0].strip()
505                    error = item[1].split("+-")[1].strip()
506                    s_16 = val+" &plusmn; "+error
507                else:
508                    continue
509
510        # make plot image
511        self.set_plot_state(extra_high=bool_0[1],extra_low=bool_1[1])
512        # get ready for report with setting all the html strings
513        self.report_str =  str(self.template_str)% (s_1,s_2,s_3,s_4,s_5,s_6,s_7,s_8,s_9,s_10,s_11,s_12,s_13,s_14,s_15,s_16,s_17,s_18,self.file,"%s")
514
515
516    def set_saved_state(self, name, value):
517        """
518        Set the state list
519                   
520        : param name: name of the state component
521        : param value: value of the state component
522        """
523        rb_list = [['power_law_low','guinier'],['fit_enable_low','fix_enable_low'],['fit_enable_high','fix_enable_high']]
524
525        try:
526            if value == None or value.lstrip().rstrip() =='':
527                exec "self.%s = '%s'" % (name, value)
528                exec "self.saved_state['%s'] = '%s'" %  (name, value)
529            else:
530                exec 'self.%s = %s' % (name, value)
531                exec "self.saved_state['%s'] = %s" %  (name, value)
532
533           
534            # set the count part of radio button clicked False for the saved_state
535            for title,content in rb_list:
536                if name ==  title:
537                    name = content
538                    value = False     
539                elif name == content:
540                    name = title
541                    value = False 
542            exec "self.saved_state['%s'] = '%s'" %  (name, value)     
543            self.state_num = self.saved_state['state_num']
544        except:           
545            pass
546
547    def set_plot_state(self,extra_high=False,extra_low=False):
548        """
549        Build image state that wx.html understand
550        by plotting, putting it into wx.FileSystem image object
551       
552        : extrap_high,extra_low: low/high extrapolations are possible extra-plots
553        """
554        # some imports
555        import wx
556        import matplotlib.pyplot as plt
557        from matplotlib.backends.backend_agg import FigureCanvasAgg
558
559        #we use simple plot, not plotpanel
560        #make matlab figure
561        fig = plt.figure()
562        fig.set_facecolor('w')
563        graph = fig.add_subplot(111)
564
565        #data plot
566        graph.errorbar(self.data.x, self.data.y, yerr=self.data.dy, fmt='o')
567        #low Q extrapolation fit plot
568        if not extra_low == 'False':
569            graph.plot(self.theory_lowQ.x,self.theory_lowQ.y)
570        #high Q extrapolation fit plot
571        if not extra_high == 'False':
572            graph.plot(self.theory_highQ.x,self.theory_highQ.y)
573        graph.set_xscale("log", nonposx='clip')
574        graph.set_yscale("log", nonposy='clip')
575        graph.set_xlabel('$\\rm{Q}(\\AA^{-1})$', fontsize = 12)
576        graph.set_ylabel('$\\rm{Intensity}(cm^{-1})$', fontsize = 12)
577        canvas = FigureCanvasAgg(fig)
578        #actually make image
579        canvas.draw()
580       
581        #make python.Image object
582        #size
583        w,h =canvas.get_width_height()
584        #convert to wx.Image
585        wximg = wx.EmptyImage(w,h)
586        #wxim.SetData(img.convert('RGB').tostring() )
587        wximg.SetData(canvas.tostring_rgb()) 
588        #get the dynamic image for the htmlwindow
589        wximgbmp = wx.BitmapFromImage(wximg)
590        #store the image in wx.FileSystem Object
591        wx.FileSystem.AddHandler(wx.MemoryFSHandler())
592        # use wx.MemoryFSHandler
593        self.imgRAM = wx.MemoryFSHandler()
594        #AddFile, image can be retrieved with 'memory:filename'
595        self.imgRAM.AddFile('img_inv.png',wximgbmp, wx.BITMAP_TYPE_PNG)
596       
597        self.wximgbmp = 'memory:img_inv.png'
598        self.image = fig
599
600class Reader(CansasReader):
601    """
602    Class to load a .inv invariant file
603    """
604    ## File type
605    type_name = "Invariant"
606   
607    ## Wildcards
608    type = ["Invariant file (*.inv)|*.inv"]
609    ## List of allowed extensions
610    ext=['.inv', '.INV'] 
611   
612    def __init__(self, call_back, cansas=True):
613        """
614        Initialize the call-back method to be called
615        after we load a file
616       
617        : param call_back: call-back method
618        : param cansas:  True = files will be written/read in CanSAS format
619                        False = write CanSAS format 
620        """
621        ## Call back method to be executed after a file is read
622        self.call_back = call_back
623        ## CanSAS format flag
624        self.cansas = cansas
625
626    def read(self, path):
627        """
628        Load a new invariant state from file
629       
630        : param path: file path
631        : return: None
632        """
633        if self.cansas==True:
634            return self._read_cansas(path)
635        else:
636            return self._read_standalone(path)
637       
638    def _read_standalone(self, path):
639        """
640        Load a new invariant state from file.
641        The invariant node is assumed to be the top element.
642       
643        : param path: file path
644        : return: None
645        """
646        # Read the new state from file
647        state = InvariantState()
648
649        state.fromXML(file=path)
650       
651        # Call back to post the new state
652        self.call_back(state)
653        return None
654   
655    def _parse_state(self, entry):
656        """
657        Read an invariant result from an XML node
658       
659        : param entry: XML node to read from
660        : return: InvariantState object
661        """
662        # Create an empty state
663        state = InvariantState()
664
665        # Locate the invariant node
666        try:
667            nodes = entry.xpath('ns:%s' % INVNODE_NAME, namespaces={'ns': CANSAS_NS})
668            state.fromXML(node=nodes[0])
669        except:
670            logging.info("XML document does not contain invariant information.\n %s" % sys.exc_value) 
671        return state
672   
673    def _read_cansas(self, path):
674        """
675        Load data and invariant information from a CanSAS XML file.
676       
677        : param path: file path
678        : return: Data1D object if a single SASentry was found,
679                    or a list of Data1D objects if multiple entries were found,
680                    or None of nothing was found
681        : raise RuntimeError: when the file can't be opened
682        : raise ValueError: when the length of the data vectors are inconsistent
683        """
684        output = []
685       
686        if os.path.isfile(path):
687            basename  = os.path.basename(path)
688            root, extension = os.path.splitext(basename)
689           
690            if  extension.lower() in self.ext or \
691                extension.lower() == '.xml':
692                tree = etree.parse(path, parser=etree.ETCompatXMLParser())
693       
694                # Check the format version number
695                # Specifying the namespace will take care of the file format version
696                root = tree.getroot()
697               
698                entry_list = root.xpath('/ns:SASroot/ns:SASentry', namespaces={'ns': CANSAS_NS})
699               
700                for entry in entry_list:
701                   
702                    sas_entry = self._parse_entry(entry)
703                    invstate = self._parse_state(entry)
704                    sas_entry.meta_data['invstate'] = invstate
705
706                    sas_entry.filename = invstate.file
707                    output.append(sas_entry)
708               
709        else:
710            raise RuntimeError, "%s is not a file" % path
711
712        # Return output consistent with the loader's api
713        if len(output)==0:
714            return None
715        elif len(output)==1:
716            # Call back to post the new state
717
718            self.call_back(state=output[0].meta_data['invstate'], datainfo = output[0])
719            return output[0]
720        else:
721            return output               
722   
723   
724    def write(self, filename, datainfo=None, invstate=None):
725        """
726        Write the content of a Data1D as a CanSAS XML file
727       
728        : param filename: name of the file to write
729        : param datainfo: Data1D object
730        : param invstate: InvariantState object
731        """
732
733        # Sanity check
734        if self.cansas == True:
735            if datainfo is None:
736                datainfo = DataLoader.data_info.Data1D(x=[], y=[])   
737            elif not issubclass(datainfo.__class__, DataLoader.data_info.Data1D):
738                raise RuntimeError, "The cansas writer expects a Data1D instance: %s" % str(datainfo.__class__.__name__)
739       
740            # Create basic XML document
741            doc, sasentry = self._to_xml_doc(datainfo)
742       
743            # Add the invariant information to the XML document
744            if invstate is not None:
745                invstate.toXML(doc=doc, entry_node=sasentry)
746       
747            # Write the XML document
748            fd = open(filename, 'w')
749            fd.write(doc.toprettyxml())
750            fd.close()
751        else:
752            invstate.toXML(file=filename)
753       
754   
755   
Note: See TracBrowser for help on using the repository browser.