source: sasview/invariantview/perspectives/invariant/invariant_state.py @ 68d48fa

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 68d48fa was 68d48fa, checked in by Jae Cho <jhjcho@…>, 13 years ago

minor fixes on report format

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