source: sasview/fittingview/src/sans/perspectives/fitting/pagestate.py @ 8f5b34a

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 8f5b34a was 0483fd48, checked in by Jae Cho <jhjcho@…>, 13 years ago

removed file:// for img

  • Property mode set to 100644
File size: 68.2 KB
Line 
1
2
3################################################################################
4#This software was developed by the University of Tennessee as part of the
5#Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
6#project funded by the US National Science Foundation.
7#
8#See the license text in license.txt
9#
10#copyright 2009, University of Tennessee
11################################################################################
12
13import time
14import os
15import sys
16import copy
17import logging
18import numpy
19
20import xml.dom.minidom
21from xml.dom.minidom import parse
22from lxml import etree
23
24import sans.dataloader
25from sans.dataloader.readers.cansas_reader import Reader as CansasReader
26from sans.dataloader.readers.cansas_reader import get_content, write_node
27from sans.dataloader.data_info import Data2D, Detector
28
29#Information to read/write state as xml
30FITTING_NODE_NAME = 'fitting_plug_in'
31CANSAS_NS = "cansas1d/1.0"
32
33list_of_data_attributes = [["is_data", "is_data", "bool"],
34                      ["group_id", "data_group_id", "string"],
35                      ["data_name", "data_name", "string"],
36                      ["data_id", "data_id", "string"],
37                      ["name", "name", "string"],
38                      ["data_name", "data_name", "string"]]
39list_of_state_attributes = [["engine_type", "engine_type", "string"],
40                       ["qmin", "qmin", "float"],
41                      ["qmax", "qmax", "float"],
42                      ["npts", "npts", "float"],
43                      ["shape_rbutton", "shape_rbutton", "bool"],
44                      ["shape_indep_rbutton", "shape_indep_rbutton", "bool"],
45                      ["plugin_rbutton", "plugin_rbutton","bool"],
46                      ["struct_rbutton", "struct_rbutton", "bool"],
47                      ["formfactorcombobox", "formfactorcombobox", "float"],
48                      ["structurecombobox", "structurecombobox", "float"],
49                      ["multi_factor","multi_factor","float"],
50                      ["enable_smearer","enable_smearer","bool"],
51                      ["disable_smearer","disable_smearer","bool"],
52                      ["pinhole_smearer","pinhole_smearer","bool"],
53                      ["slit_smearer","slit_smearer","bool"],
54                      ["enable_disp","enable_disp","bool"],
55                      ["disable_disp","disable_disp","bool"],
56                      ["dI_noweight","dI_noweight","bool"],
57                      ["dI_didata","dI_didata","bool"],
58                      ["dI_sqrdata","dI_sqrdata","bool"],
59                      ["dI_idata","dI_idata","bool"],
60                      ["enable2D","enable2D","bool"],
61                      ["cb1","cb1","bool"],
62                      ["tcChi","tcChi","float"],
63                      ["smearer", "smearer", "float"],
64                      ["smear_type","smear_type", "string"],
65                      ["dq_l", "dq_l", "string"],
66                      ["dq_r","dq_r", "string"]]
67
68list_of_model_attributes = [["values", "values"],
69                            ["weights", "weights"]]
70
71list_of_obj_dic =  [["disp_obj_dict", "_disp_obj_dict", "string"]]
72
73list_of_state_parameters = [["parameters", "parameters"] , 
74                            ["str_parameters", "str_parameters"] ,                     
75                            ["orientation_parameters", "orientation_params"],
76                            ["dispersity_parameters", "orientation_params_disp"],
77                            ["fixed_param", "fixed_param"],                     
78                            ["fittable_param","fittable_param"]]
79list_of_data_2d_attr = [["xmin", "xmin","float"],
80                        ["xmax","xmax","float"],
81                        ["ymin","ymin","float"],
82                        ["ymax","ymax","float"],
83                        ["_xaxis","_xaxis", "string"],
84                        ["_xunit", "_xunit", "string"],
85                        ["_yaxis","_yaxis","string"],
86                        ["_yunit","_yunit","string"],
87                        ["_zaxis","_zaxis","string"],
88                        ["_zunit","_zunit","string"]]
89list_of_data2d_values = [["qx_data","qx_data","float"],
90                         ["qy_data","qy_data","float"],
91                         ["dqx_data","dqx_data","float"],
92                         ["dqy_data","dqy_data","float"],
93                         ["data","data","float"],
94                         ["q_data","q_data","float"],
95                         ["err_data","err_data","float"],
96                         ["mask","mask","bool"]]
97
98def parse_entry_helper( node, item):
99    """
100    Create a numpy list from value extrated from the node
101   
102    :param node: node from each the value is stored
103    :param item: list name of three strings.the two first are name of data
104        attribute and the third one is the type of the value of that
105        attribute. type can be string, float, bool, etc.
106   
107    : return: numpy array
108    """
109    if node is not None:
110        if item[2] == "string":
111            return str(node.get(item[0]).strip())
112        elif item[2] == "bool":
113            try:
114                return node.get(item[0]).strip() == "True"
115               
116            except:
117                return None
118        else:
119            try:
120                return float(node.get(item[0]))
121            except:
122                return None
123           
124           
125class PageState(object):
126    """
127    Contains information to reconstruct a page of the fitpanel.
128    """
129    def __init__(self, parent=None, model=None, data=None):
130       
131        """
132        Initialize the current state
133       
134        :param model: a selected model within a page
135        :param data:
136       
137        """
138        self.file = None
139        #Time of state creation
140        self.timestamp = time.time()
141        ## Data member to store the dispersion object created
142        self._disp_obj_dict = {}
143        #------------------------
144        #Data used for fitting
145        self.data = data
146        # model data
147        self.theory_data = None
148        #Is 2D
149        self.is_2D = False
150        self.images = None
151       
152        #save additional information on data that dataloader.reader does not read
153        self.is_data = None
154        self.data_name = ""
155
156        if self.data is not None:
157            self.data_name = self.data.name
158        self.data_id = None
159        if self.data is not None and hasattr(self.data, "id"):
160            self.data_id = self.data.id
161        self.data_group_id = None
162        if self.data is not None and hasattr(self.data, "group_id"):
163            self.data_group_id = self.data.group_id
164       
165        ## reset True change the state of exsiting button
166        self.reset = False
167       
168        #engine type
169        self.engine_type = None
170        # flag to allow data2D plot
171        self.enable2D = False
172        # model on which the fit would be performed
173        self.model = model
174        #list of process done to model
175        self.process = []
176        #fit page manager
177        self.manager = None
178        #Store the parent of this panel parent
179        # For this application fitpanel is the parent
180        self.parent  = parent
181        # Event_owner is the owner of model event
182        self.event_owner = None
183        ##page name
184        self.page_name = ""
185        # Contains link between  model ,all its parameters, and panel organization
186        self.parameters = []
187        # String parameter list that can not be fitted
188        self.str_parameters = []
189        # Contains list of parameters that cannot be fitted and reference to
190        #panel objects
191        self.fixed_param = []
192        # Contains list of parameters with dispersity and reference to
193        #panel objects
194        self.fittable_param = []
195        ## orientation parameters
196        self.orientation_params = []
197        ## orientation parmaters for gaussian dispersity
198        self.orientation_params_disp = []
199        ## smearer info
200        self.smearer = None
201        self.smear_type = None
202        self.dq_l = None
203        self.dq_r = None
204
205        #list of dispersion paramaters
206        self.disp_list =[]
207        if self.model is not None:
208            self.disp_list = self.model.getDispParamList()
209
210        self.disp_cb_dict = {}
211        self.values = {}
212        self.weights = {}
213                   
214        #contains link between a model and selected parameters to fit
215        self.param_toFit = []
216        ##dictionary of model type and model class
217        self.model_list_box = None
218        ## save the state of the context menu
219        self.saved_states = {}
220        ## save selection of combobox
221        self.formfactorcombobox = None
222        self.structurecombobox  = None
223
224        ## radio box to select type of model
225        self.shape_rbutton = False
226        self.shape_indep_rbutton = False
227        self.struct_rbutton = False
228        self.plugin_rbutton = False
229        ## the indice of the current selection
230        self.disp_box = 0
231        ## Qrange
232        ## Q range
233        self.qmin = 0.001
234        self.qmax = 0.1
235        #reset data range
236        self.qmax_x = None
237        self.qmin_x = None
238       
239        self.npts = None
240        self.name = ""
241        self.multi_factor = None
242        ## enable smearering state
243        self.enable_smearer = False
244        self.disable_smearer = True
245        self.pinhole_smearer = False
246        self.slit_smearer   = False
247        # weighting options
248        self.dI_noweight = False
249        self.dI_didata = True
250        self.dI_sqrdata = False
251        self.dI_idata   = False
252        ## disperity selection
253        self.enable_disp = False
254        self.disable_disp = True
255       
256        ## state of selected all check button
257        self.cb1 = False
258        ## store value of chisqr
259        self.tcChi = None
260   
261    def clone(self):
262        """
263        Create a new copy of the current object
264        """
265        model = None
266        if self.model is not None:
267            model = self.model.clone()
268            model.name = self.model.name
269        obj = PageState(self.parent, model=model)
270        obj.file = copy.deepcopy(self.file)
271        obj.data = copy.deepcopy(self.data)
272        if self.data is not None:
273            self.data_name = self.data.name
274        obj.data_name = self.data_name
275        obj.is_data = self.is_data
276        obj.model_list_box = copy.deepcopy(self.model_list_box)
277        obj.engine_type = copy.deepcopy(self.engine_type)
278       
279        obj.formfactorcombobox = self.formfactorcombobox
280        obj.structurecombobox  = self.structurecombobox 
281       
282        obj.shape_rbutton = self.shape_rbutton
283        obj.shape_indep_rbutton = self.shape_indep_rbutton
284        obj.struct_rbutton = self.struct_rbutton
285        obj.plugin_rbutton = self.plugin_rbutton
286       
287        obj.manager = self.manager
288        obj.event_owner = self.event_owner
289        obj.disp_list = copy.deepcopy(self.disp_list)
290       
291        obj.enable2D = copy.deepcopy(self.enable2D)
292        obj.parameters = copy.deepcopy(self.parameters)
293        obj.str_parameters = copy.deepcopy(self.str_parameters)
294        obj.fixed_param = copy.deepcopy(self.fixed_param)
295        obj.fittable_param = copy.deepcopy(self.fittable_param)
296        obj.orientation_params =  copy.deepcopy(self.orientation_params)
297        obj.orientation_params_disp =  copy.deepcopy(self.orientation_params_disp)
298        obj.enable_disp = copy.deepcopy(self.enable_disp)
299        obj.disable_disp = copy.deepcopy(self.disable_disp)
300        obj.tcChi = self.tcChi
301 
302        if len(self._disp_obj_dict)>0:
303            for k , v in self._disp_obj_dict.iteritems():
304                obj._disp_obj_dict[k]= v
305        if len(self.disp_cb_dict)>0:
306            for k , v in self.disp_cb_dict.iteritems():
307                obj.disp_cb_dict[k]= v
308        if len(self.values)>0: 
309            for k , v in self.values.iteritems():       
310                obj.values[k] = v
311        if len(self.weights)>0: 
312            for k , v in self.weights.iteritems():       
313                obj.weights[k] = v
314        obj.enable_smearer = copy.deepcopy(self.enable_smearer)
315        obj.disable_smearer = copy.deepcopy(self.disable_smearer)
316        obj.pinhole_smearer = copy.deepcopy(self.pinhole_smearer)
317        obj.slit_smearer = copy.deepcopy(self.slit_smearer)
318        obj.smear_type = copy.deepcopy(self.smear_type)
319        obj.dI_noweight = copy.deepcopy(self.dI_noweight)
320        obj.dI_didata = copy.deepcopy(self.dI_didata)
321        obj.dI_sqrdata = copy.deepcopy(self.dI_sqrdata)
322        obj.dI_idata = copy.deepcopy(self.dI_idata)
323        obj.dq_l = copy.deepcopy(self.dq_l)
324        obj.dq_r = copy.deepcopy(self.dq_r)
325
326        obj.disp_box = copy.deepcopy(self.disp_box)
327        obj.qmin = copy.deepcopy(self.qmin)
328        obj.qmax = copy.deepcopy(self.qmax)
329        obj.multi_factor = self.multi_factor
330        obj.npts = copy.deepcopy(self.npts )
331        obj.cb1 = copy.deepcopy(self.cb1)
332        obj.smearer = copy.deepcopy(self.smearer)
333       
334        for name, state in self.saved_states.iteritems():
335            copy_name = copy.deepcopy(name)
336            copy_state = state.clone()
337            obj.saved_states[copy_name]= copy_state
338        return obj
339   
340    def _repr_helper(self, list, rep):
341        """
342        Helper method to print a state
343        """
344        for item in list:
345            rep += "parameter name: %s \n"%str(item[1])
346            rep += "value: %s\n"%str(item[2])
347            rep += "selected: %s\n"%str(item[0])
348            rep += "error displayed : %s \n"%str(item[4][0])
349            rep += "error value:%s \n"%str(item[4][1])
350            rep += "minimum displayed : %s \n"%str(item[5][0])
351            rep += "minimum value : %s \n"%str(item[5][1])
352            rep += "maximum displayed : %s \n"%str(item[6][0])
353            rep += "maximum value : %s \n"%str(item[6][1])
354            rep += "parameter unit: %s\n\n"%str(item[7])
355        return rep
356   
357    def __repr__(self):
358        """
359        output string for printing
360        """
361        rep = "\nState name: %s\n"%self.file
362        t = time.localtime(self.timestamp)
363        time_str = time.strftime("%b %d %Y %H;%M;%S ", t)
364
365        rep += "State created: %s\n"%time_str
366        rep += "State form factor combobox selection: %s\n"%self.formfactorcombobox
367        rep += "State structure factor combobox selection: %s\n"%self.structurecombobox
368        rep += "is data : %s\n"%self.is_data
369        rep += "data's name : %s\n"%self.data_name
370        rep += "data's id : %s\n"%self.data_id
371        if self.model != None:
372            rep += "model name : %s\n"% self.model.__class__.__name__
373        else:
374            rep += "model name : None\n"
375        rep += "model type (form factor) selected: %s\n"%self.shape_rbutton
376        rep += "multi_factor : %s\n"% str(self.multi_factor)
377        rep += "model type (shape independent) selected: %s\n"%self.shape_indep_rbutton
378        rep += "model type (structure factor) selected: %s\n"%self.struct_rbutton
379        rep += "model type (plug-in ) selected: %s\n"%self.plugin_rbutton
380        rep += "data : %s\n"% str(self.data)
381        rep += "Plotting Range: min: %s, max: %s, steps: %s\n"%(str(self.qmin),
382                                                str(self.qmax),str(self.npts))
383        rep += "Dispersion selection : %s\n"%str(self.disp_box)
384        rep += "Smearing enable : %s\n"%str(self.enable_smearer)
385        rep += "Smearing disable : %s\n"%str(self.disable_smearer)
386        rep += "Pinhole smearer enable : %s\n"%str(self.pinhole_smearer)
387        rep += "Slit smearer enable : %s\n"%str(self.slit_smearer)
388        rep += "Dispersity enable : %s\n"%str(self.enable_disp)
389        rep += "Dispersity disable : %s\n"%str(self.disable_disp)
390        rep += "Slit smearer enable: %s\n"%str(self.slit_smearer)
391       
392        rep += "dI_noweight : %s\n"%str(self.dI_noweight)
393        rep += "dI_didata : %s\n"%str(self.dI_didata)
394        rep += "dI_sqrdata : %s\n"%str(self.dI_sqrdata)
395        rep += "dI_idata : %s\n"%str(self.dI_idata)
396       
397       
398        rep += "2D enable : %s\n"%str(self.enable2D)
399        rep += "All parameters checkbox selected: %s\n"%(self.cb1)
400        rep += "Value of Chisqr : %s\n"%str(self.tcChi)
401        rep += "Smear object : %s\n"%str(self.smearer)
402        rep += "Smear type : %s\n"%(self.smear_type)
403        rep += "dq_l  : %s\n"%self.dq_l
404        rep += "dq_r  : %s\n"%self.dq_r
405       
406        rep += "model  : %s\n\n"% str(self.model)
407        temp_parameters = []
408        temp_fittable_param = []
409        if self.data.__class__.__name__ == "Data2D":
410            self.is_2D = True
411        else:
412            self.is_2D = False
413        if self.data is not None:
414            if not self.is_2D:
415                for item in self.parameters:
416                    if not item in self.orientation_params:
417                        temp_parameters.append(item)
418                for item in self.fittable_param:
419                    if not item in self.orientation_params_disp:
420                        temp_fittable_param.append(item)
421            else:
422                temp_parameters = self.parameters
423                temp_fittable_param = self.fittable_param
424               
425            rep += "number parameters(self.parameters): %s\n"%len(temp_parameters)
426            rep = self._repr_helper( list=temp_parameters, rep=rep)
427            rep += "number str_parameters(self.str_parameters): %s\n"%len(self.str_parameters)
428            rep = self._repr_helper( list=self.str_parameters, rep=rep) 
429            rep += "number fittable_param(self.fittable_param): %s\n"%len(temp_fittable_param)
430            rep = self._repr_helper( list=temp_fittable_param, rep=rep) 
431            """
432            if is_2D:
433                rep += "number orientation parameters"
434                rep += "(self.orientation_params): %s\n"%len(self.orientation_params)
435                rep = self._repr_helper( list=self.orientation_params, rep=rep)
436                rep += "number dispersity parameters"
437                rep += "(self.orientation_params_disp): %s\n"%len(self.orientation_params_disp)
438                rep = self._repr_helper( list=self.orientation_params_disp, rep=rep)
439            """
440        return rep
441
442    def set_report_string(self):
443        """
444        Get the values (strings) from __str__ for report
445        """
446        # Dictionary of teh report strings
447        repo_time = ""
448        model_name = ""
449        title = ""
450        title_name = ""
451        file_name = ""
452        param_string = ""
453        paramval_string = ""
454        chi2_string = ""
455        multi_factor_string = ""
456        q_range = ""
457        strings = self.__repr__()
458        lines = strings.split('\n')
459
460        # get all string values from __str__()
461        for line in lines:
462            value = ""
463            content = line.split(":")
464            name = content[0]
465            try:
466                value = content[1]
467            except:
468                pass
469            if name.count("State created"):
470                repo_time = "" + value
471            if name.count("parameter name"):
472                val_name = value.split(".")
473                if len(val_name) > 1:
474                    if val_name[1].count("width"):
475                        param_string += value + ','
476                    else:
477                        continue
478                else:
479                    param_string += value + ','
480            if name == "value":
481                param_string += value + ','
482            if name == "error value":
483                param_string += value + ','
484            if name == "parameter unit":
485                param_string += value + ':' 
486            if name == "Value of Chisqr ":
487                chi2 = ("Chi2/Npts = " + value)
488                chi2_string = CENTRE % chi2
489            if name == "multi_factor ":
490                muti_factor = ("muti_factor = " + value)
491                muti_factor_string = CENTRE % muti_factor
492            if name == "Title":
493                if len(value.strip()) == 0:
494                    continue
495                title = value + " [" + repo_time + "]"
496                title_name = HEADER % title
497            if name == "data ":
498                try:
499                    file = ("File name:" + content[2])
500                    file_name = CENTRE % file
501                    if len(title) == 0:
502                        title = content[2] + " [" + repo_time + "]"
503                        title_name = HEADER % title
504                except:
505                    pass
506            if name == "model name ":
507                try:
508                    modelname = "Model name:" + content[1]
509                except:
510                    modelname = "Model name:" + " NAN"
511                model_name = CENTRE %  modelname
512                 
513            if name == "Plotting Range":
514                try:
515                    q_range = content[1] + " = " + content[2] \
516                            + " = " + content[3].split(",")[0]
517                    q_name = ("Q Range:    " + q_range)
518                    q_range = CENTRE % q_name
519                except:
520                    pass
521        paramval = ""
522        for lines in param_string.split(":"): 
523            line = lines.split(",")
524            if len(lines) > 0: 
525                param = line[0] 
526                param += " = " + line[1]
527                if len(line[2].split()) > 0 and not line[2].count("None"):
528                    param += " +- " + line[2]
529                if len(line[3].split()) > 0 and not line[3].count("None"):
530                    param += " " + line[3]
531                if not paramval.count(param):
532                    paramval +=  param + "\n"
533                    paramval_string += CENTRE % param + "\n"
534       
535        text_string = "\n\n\n" + title + "\n\n" + file + \
536                              "\n" + q_name + \
537                              "\n" + chi2 + \
538                              "\n\n" + paramval
539       
540        title_name = self._check_html_format(title_name)
541        file_name = self._check_html_format(file_name)
542        title = self._check_html_format(title)
543                                 
544        html_string = title_name + "\n" + file_name + \
545                                   "\n" + model_name +\
546                                   "\n" + q_range + \
547                                   "\n" + chi2_string + \
548                                   "\n" + ELINE + \
549                                   "\n" + paramval_string + \
550                                   "\n" + ELINE + \
551                                   "\n" + FEET_1 % title + \
552                                   "\n" + FEET_2
553                                                                     
554        return html_string, text_string, title
555   
556    def _check_html_format(self, name):
557        """
558        Check string '%' for html format
559        """
560        if name.count('%'):
561            name = name.replace('%', '&#37')
562       
563        return name
564   
565   
566    def report(self, figs=None, canvases=None):
567        """
568        Invoke report dialog panel
569       
570        : param figs: list of pylab figures [list]
571        """
572        from report_dialog import ReportDialog
573        # get the strings for report
574        html_str, text_str, title = self.set_report_string()
575        # Allow 2 figures to append
576        if len(figs) == 1:
577            add_str = FEET_3
578        elif len(figs) == 2:
579            add_str = ELINE
580            add_str += FEET_2 % ("%s") 
581            add_str += ELINE
582            add_str += FEET_3
583        elif len(figs) > 2:
584            add_str = ELINE
585            add_str += FEET_2 % ("%s") 
586            add_str += ELINE
587            add_str += FEET_2 % ("%s") 
588            add_str += ELINE
589            add_str += FEET_3
590        else:
591            add_str = ""
592
593        # final report html strings
594        report_str = html_str % ("%s") + add_str
595
596        # make plot image
597        images = self.set_plot_state(figs, canvases)
598        report_list = [report_str, text_str, images ]
599        dialog = ReportDialog(report_list, None, -1, "")
600        dialog.ShowModal()
601       
602   
603    def _toXML_helper(self, list, element, newdoc):
604        """
605        Helper method to create xml file for saving state
606        """
607        for item in list:
608            sub_element = newdoc.createElement('parameter')
609            sub_element.setAttribute('name', str(item[1]))
610            sub_element.setAttribute('value', str(item[2]))
611            sub_element.setAttribute('selected_to_fit', str(item[0]))
612            sub_element.setAttribute('error_displayed', str(item[4][0]))
613            sub_element.setAttribute('error_value', str(item[4][1]))
614            sub_element.setAttribute('minimum_displayed', str(item[5][0]))
615            sub_element.setAttribute('minimum_value', str(item[5][1]))
616            sub_element.setAttribute('maximum_displayed', str(item[6][0]))
617            sub_element.setAttribute('maximum_value', str(item[6][1]))
618            sub_element.setAttribute('unit', str(item[7]))
619            element.appendChild(sub_element)
620       
621    def toXML(self, file="fitting_state.fitv", doc=None, entry_node=None):
622        """
623        Writes the state of the InversionControl panel to file, as XML.
624       
625        Compatible with standalone writing, or appending to an
626        already existing XML document. In that case, the XML document
627        is required. An optional entry node in the XML document may also be given.
628       
629        :param file: file to write to
630        :param doc: XML document object [optional]
631        :param entry_node: XML node within the XML document at which we will append the data [optional]
632       
633        """
634        from xml.dom.minidom import getDOMImplementation
635
636        # Check whether we have to write a standalone XML file
637        if doc is None:
638            impl = getDOMImplementation()
639            doc_type = impl.createDocumentType(FITTING_NODE_NAME, "1.0", "1.0")     
640            newdoc = impl.createDocument(None, FITTING_NODE_NAME, doc_type)
641            top_element = newdoc.documentElement
642        else:
643            # We are appending to an existing document
644            newdoc = doc
645            top_element = newdoc.createElement(FITTING_NODE_NAME)
646            if entry_node is None:
647                newdoc.documentElement.appendChild(top_element)
648            else:
649                entry_node.appendChild(top_element)
650           
651        attr = newdoc.createAttribute("version")
652        attr.nodeValue = '1.0'
653        top_element.setAttributeNode(attr)
654       
655        # File name
656        element = newdoc.createElement("filename")
657        if self.file is not None:
658            element.appendChild(newdoc.createTextNode(str(self.file)))
659        else:
660            element.appendChild(newdoc.createTextNode(str(file)))
661        top_element.appendChild(element)
662       
663        element = newdoc.createElement("timestamp")
664        element.appendChild(newdoc.createTextNode(time.ctime(self.timestamp)))
665        attr = newdoc.createAttribute("epoch")
666        attr.nodeValue = str(self.timestamp)
667        element.setAttributeNode(attr)
668        top_element.appendChild(element)
669        # Inputs
670        inputs = newdoc.createElement("Attributes")
671        top_element.appendChild(inputs)
672       
673
674        if self.data is not None and hasattr(self.data, "group_id"):
675            self.data_group_id = self.data.group_id
676        if self.data is not None and hasattr(self.data, "is_data"):
677            self.is_data = self.data.is_data
678        if self.data is not None:
679            self.data_name = self.data.name
680        if self.data is not None and hasattr(self.data, "id"):
681            self.data_id = self.data.id
682       
683        for item in list_of_data_attributes:
684            element = newdoc.createElement(item[0])
685            exec "element.setAttribute(item[0], str(self.%s))" % (item[1])
686            inputs.appendChild(element)   
687       
688        for item in list_of_state_attributes:
689            element = newdoc.createElement(item[0])
690            exec "element.setAttribute(item[0], str(self.%s))" % (item[1])
691            inputs.appendChild(element)
692           
693        # For self.values ={ disp_param_name: [vals,...],...}   
694        # and for self.weights ={ disp_param_name: [weights,...],...} 
695        for item in list_of_model_attributes:
696            element = newdoc.createElement(item[0])
697            exec "list = self.%s" % item[1]
698            for key, value in list.iteritems():
699                sub_element = newdoc.createElement(key)
700                sub_element.setAttribute('name', str(key))
701                for val in value:
702                    com = "sub_element.appendChild"
703                    com += "(newdoc.createTextNode(str(%s)))"
704                    exec com % val
705                   
706                element.appendChild(sub_element) 
707            inputs.appendChild(element)
708       
709        # Create doc for the dictionary of self._disp_obj_dic
710        for item in list_of_obj_dic:
711             element = newdoc.createElement(item[0])
712             exec "list = self.%s" % item[1]
713             for key, val in list.iteritems():
714                 value = repr(val)
715                 sub_element = newdoc.createElement(key)
716                 sub_element.setAttribute('name', str(key))
717                 sub_element.setAttribute('value', str(value))
718                 element.appendChild(sub_element) 
719             inputs.appendChild(element)   
720                 
721        for item in list_of_state_parameters:
722            element = newdoc.createElement(item[0])
723            com = "self._toXML_helper(list=self.%s,"
724            com += " element=element, newdoc=newdoc)"
725            exec com % item[1]                       
726            inputs.appendChild(element)
727       
728        # Save the file
729        if doc is None:
730            fd = open(file, 'w')
731            fd.write(newdoc.toprettyxml())
732            fd.close()
733            return None
734        else:
735            return newdoc.toprettyxml()
736       
737    def _fromXML_helper(self, node, list):
738        """
739        Helper function to write state to xml
740        """
741        for item in node:
742            try:
743                name = item.get('name')
744            except:
745                name = None
746            try:
747                value = item.get('value')
748            except:
749                value = None
750            try:
751                selected_to_fit = (item.get('selected_to_fit') == "True")
752            except:
753                selected_to_fit = None
754            try:
755                error_displayed = (item.get('error_displayed') == "True")
756            except:
757                error_displayed = None
758            try: 
759                error_value = item.get('error_value')
760            except:
761                error_value = None
762            try:
763                minimum_displayed = (item.get('minimum_displayed')== "True")
764            except:
765                minimum_displayed = None
766            try:
767                minimum_value = item.get('minimum_value')
768            except:
769                minimum_value = None
770            try:
771                maximum_displayed = (item.get('maximum_displayed') == "True")
772            except:
773                maximum_displayed = None
774            try:
775                maximum_value = item.get('maximum_value')
776            except:
777                maximum_value = None
778            try:
779                unit = item.get('unit')
780            except:
781                unit = None
782            list.append([selected_to_fit, name, value, "+/-",
783                         [error_displayed, error_value],
784                         [minimum_displayed,minimum_value],
785                         [maximum_displayed,maximum_value], unit])
786       
787    def fromXML(self, file=None, node=None):
788        """
789        Load fitting state from a file
790       
791        :param file: .fitv file
792        :param node: node of a XML document to read from
793       
794        """
795        if file is not None:
796            msg = "PageState no longer supports non-CanSAS"
797            msg += " format for fitting files"
798            raise RuntimeError, msg
799           
800        if node.get('version')and node.get('version') == '1.0':
801           
802            # Get file name
803            entry = get_content('ns:filename', node)
804            if entry is not None:
805                self.file = entry.text.strip()
806               
807            # Get time stamp
808            entry = get_content('ns:timestamp', node)
809            if entry is not None and entry.get('epoch'):
810                try:
811                    self.timestamp = float(entry.get('epoch'))
812                except:
813                    msg = "PageState.fromXML: Could not"
814                    msg += " read timestamp\n %s" % sys.exc_value
815                    logging.error(msg)
816           
817            # Parse fitting attributes
818            entry = get_content('ns:Attributes', node)
819            for item in list_of_data_attributes:
820                node = get_content('ns:%s'%item[0], entry)
821                try:
822                    exec "self.%s = parse_entry_helper(node, item)" % item[0]
823                   
824                except:
825                    raise
826
827            if entry is not None:
828               
829                for item in list_of_state_attributes:
830                    node = get_content('ns:%s' % item[0], entry)
831                    try:
832                        exec "self.%s = parse_entry_helper(node, item)" % \
833                                                                str(item[0])
834                    except:
835                        raise
836                   
837                for item in list_of_state_parameters:
838                    node = get_content("ns:%s" % item[0], entry)
839                    exec "self._fromXML_helper(node=node, list=self.%s)" % \
840                                                                    item[1]
841               
842                # Recover _disp_obj_dict from xml file   
843                self._disp_obj_dict = {}   
844                for item in list_of_obj_dic:
845                    # Get node
846                    node = get_content("ns:%s" % item[0], entry)
847                    for attr in node:
848                        name = attr.get('name')
849                        val  = attr.get('value')
850                        value = val.split(" instance")[0]
851                        disp_name = value.split("<")[1]
852                        try:
853                            # Try to recover disp_model object from strings
854                            com  = "from sans.models.dispersion_models "
855                            com += "import %s as disp"
856                            com_name = disp_name.split(".")[3]
857                            exec com % com_name
858                            disp_model = disp()
859                            exec "self.%s['%s'] = com_name" % (item[1], name)
860                        except:
861                            pass
862                       
863                # get self.values and self.weights dic. if exists   
864                for item in list_of_model_attributes:
865                    node = get_content("ns:%s" % item[0], entry)
866                    dic = {}
867                    list = []
868                    for par in node:
869                        name = par.get('name')
870                        values = par.text.split('\n')
871                        # Get lines only with numbers
872                        for line in values:
873                            try:
874                                val= float(line)
875                                list.append(val) 
876                            except:
877                                # pass if line is empty (it happens)
878                                pass
879                    dic[name] = numpy.array(list)
880                    exec "self.%s = dic" % item[1]
881                   
882    def set_plot_state(self, figs, canvases):
883        """
884        Build image state that wx.html understand
885        by plotting, putting it into wx.FileSystem image object
886
887        """
888        images = []
889        # some imports
890        import wx
891
892        # Reset memory
893        self.imgRAM = None
894        wx.MemoryFSHandler()
895       
896        # For no figures in the list, prepare empty plot
897        if figs == None or len(figs) == 0:
898            figs = [None]
899           
900        # Loop over the list of figures   
901        # use wx.MemoryFSHandler
902        self.imgRAM = wx.MemoryFSHandler() 
903        for fig in figs:
904            if figs != None:
905                #fig.set_facecolor('w')
906                ind = figs.index(fig)
907                canvas = canvases[ind]
908               
909            #bmp = wx.BitmapDataObject()
910            #bmp.SetBitmap(canvas.bitmap)
911            #store the image in wx.FileSystem Object
912            wx.FileSystem.AddHandler(wx.MemoryFSHandler())
913           
914            # index of the fig
915            ind = figs.index(fig)
916           
917            #AddFile, image can be retrieved with 'memory:filename'
918            self.imgRAM.AddFile('img_fit%s.png' % ind , 
919                                canvas.bitmap, wx.BITMAP_TYPE_PNG)
920           
921            #append figs
922            images.append(fig)
923           
924        return images
925
926class Reader(CansasReader):
927    """
928    Class to load a .fitv fitting file
929    """
930    ## File type
931    type_name = "Fitting"
932   
933    ## Wildcards
934    type = ["Fitting files (*.fitv)|*.fitv"
935            "SANSView file (*.svs)|*.svs"]
936    ## List of allowed extensions
937    ext=['.fitv', '.FITV', '.svs', 'SVS']   
938   
939    def __init__(self, call_back=None, cansas=True):
940        CansasReader.__init__(self)
941        """
942        Initialize the call-back method to be called
943        after we load a file
944       
945        :param call_back: call-back method
946        :param cansas:  True = files will be written/read in CanSAS format
947                        False = write CanSAS format
948           
949        """
950        ## Call back method to be executed after a file is read
951        self.call_back = call_back
952        ## CanSAS format flag
953        self.cansas = cansas
954        self.state = None
955    def get_state(self):
956        return self.state
957       
958    def read(self, path):
959        """
960        Load a new P(r) inversion state from file
961       
962        :param path: file path
963       
964        """
965        if self.cansas == True:
966            return self._read_cansas(path)
967     
968    def _data2d_to_xml_doc(self, datainfo):
969        """
970        Create an XML document to contain the content of a Data2D
971       
972        :param datainfo: Data2D object
973       
974        """
975        if not issubclass(datainfo.__class__, Data2D):
976            raise RuntimeError, "The cansas writer expects a Data2D instance"
977       
978        doc = xml.dom.minidom.Document()
979        main_node = doc.createElement("SASroot")
980        main_node.setAttribute("version", self.version)
981        main_node.setAttribute("xmlns", "cansas1d/%s" % self.version)
982        main_node.setAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance")
983        main_node.setAttribute("xsi:schemaLocation", "cansas1d/%s http://svn.smallangles.net/svn/canSAS/1dwg/trunk/cansas1d.xsd" % self.version)
984       
985        doc.appendChild(main_node)
986       
987        entry_node = doc.createElement("SASentry")
988        main_node.appendChild(entry_node)
989       
990        write_node(doc, entry_node, "Title", datainfo.title)
991        if datainfo is not None:
992            write_node(doc, entry_node, "data_class", datainfo.__class__.__name__)
993        for item in datainfo.run:
994            runname = {}
995            if datainfo.run_name.has_key(item) and len(str(datainfo.run_name[item]))>1:
996                runname = {'name': datainfo.run_name[item] }
997            write_node(doc, entry_node, "Run", item, runname)
998        # Data info
999        new_node = doc.createElement("SASdata")
1000        entry_node.appendChild(new_node)
1001        for item in list_of_data_2d_attr:
1002            element = doc.createElement(item[0])
1003            exec "element.setAttribute(item[0], str(datainfo.%s))"%(item[1])
1004            new_node.appendChild(element)
1005           
1006        for item in list_of_data2d_values:
1007            root_node = doc.createElement(item[0])
1008            new_node.appendChild(root_node)
1009           
1010            exec "temp_list = datainfo.%s"%item[1]
1011
1012            if temp_list is None or len(temp_list)== 0:
1013                element = doc.createElement(item[0])
1014                exec "element.appendChild(doc.createTextNode(str(%s)))"%temp_list
1015                root_node.appendChild(element)
1016            else:
1017                for value in temp_list:
1018                    element = doc.createElement(item[0])
1019                    exec "element.setAttribute(item[0], str(%s))"%value
1020                    root_node.appendChild(element)
1021       
1022        # Sample info
1023        sample = doc.createElement("SASsample")
1024        if datainfo.sample.name is not None:
1025            sample.setAttribute("name", str(datainfo.sample.name))
1026        entry_node.appendChild(sample)
1027        write_node(doc, sample, "ID", str(datainfo.sample.ID))
1028        write_node(doc, sample, "thickness", datainfo.sample.thickness, {"unit":datainfo.sample.thickness_unit})
1029        write_node(doc, sample, "transmission", datainfo.sample.transmission)
1030        write_node(doc, sample, "temperature", datainfo.sample.temperature, {"unit":datainfo.sample.temperature_unit})
1031       
1032        for item in datainfo.sample.details:
1033            write_node(doc, sample, "details", item)
1034       
1035        pos = doc.createElement("position")
1036        written = write_node(doc, pos, "x", datainfo.sample.position.x, {"unit":datainfo.sample.position_unit})
1037        written = written | write_node(doc, pos, "y", datainfo.sample.position.y, {"unit":datainfo.sample.position_unit})
1038        written = written | write_node(doc, pos, "z", datainfo.sample.position.z, {"unit":datainfo.sample.position_unit})
1039        if written == True:
1040            sample.appendChild(pos)
1041       
1042        ori = doc.createElement("orientation")
1043        written = write_node(doc, ori, "roll",  datainfo.sample.orientation.x, {"unit":datainfo.sample.orientation_unit})
1044        written = written | write_node(doc, ori, "pitch", datainfo.sample.orientation.y, {"unit":datainfo.sample.orientation_unit})
1045        written = written | write_node(doc, ori, "yaw",   datainfo.sample.orientation.z, {"unit":datainfo.sample.orientation_unit})
1046        if written == True:
1047            sample.appendChild(ori)
1048       
1049        # Instrument info
1050        instr = doc.createElement("SASinstrument")
1051        entry_node.appendChild(instr)
1052       
1053        write_node(doc, instr, "name", datainfo.instrument)
1054       
1055        #   Source
1056        source = doc.createElement("SASsource")
1057        if datainfo.source.name is not None:
1058            source.setAttribute("name", str(datainfo.source.name))
1059        instr.appendChild(source)
1060       
1061        write_node(doc, source, "radiation", datainfo.source.radiation)
1062        write_node(doc, source, "beam_shape", datainfo.source.beam_shape)
1063        size = doc.createElement("beam_size")
1064        if datainfo.source.beam_size_name is not None:
1065            size.setAttribute("name", str(datainfo.source.beam_size_name))
1066        written = write_node(doc, size, "x", datainfo.source.beam_size.x, {"unit":datainfo.source.beam_size_unit})
1067        written = written | write_node(doc, size, "y", datainfo.source.beam_size.y, {"unit":datainfo.source.beam_size_unit})
1068        written = written | write_node(doc, size, "z", datainfo.source.beam_size.z, {"unit":datainfo.source.beam_size_unit})
1069        if written == True:
1070            source.appendChild(size)
1071           
1072        write_node(doc, source, "wavelength", datainfo.source.wavelength, {"unit":datainfo.source.wavelength_unit})
1073        write_node(doc, source, "wavelength_min", datainfo.source.wavelength_min, {"unit":datainfo.source.wavelength_min_unit})
1074        write_node(doc, source, "wavelength_max", datainfo.source.wavelength_max, {"unit":datainfo.source.wavelength_max_unit})
1075        write_node(doc, source, "wavelength_spread", datainfo.source.wavelength_spread, {"unit":datainfo.source.wavelength_spread_unit})
1076       
1077        #   Collimation
1078        for item in datainfo.collimation:
1079            coll = doc.createElement("SAScollimation")
1080            if item.name is not None:
1081                coll.setAttribute("name", str(item.name))
1082            instr.appendChild(coll)
1083           
1084            write_node(doc, coll, "length", item.length, {"unit":item.length_unit})
1085           
1086            for apert in item.aperture:
1087                ap = doc.createElement("aperture")
1088                if apert.name is not None:
1089                    ap.setAttribute("name", str(apert.name))
1090                if apert.type is not None:
1091                    ap.setAttribute("type", str(apert.type))
1092                coll.appendChild(ap)
1093               
1094                write_node(doc, ap, "distance", apert.distance, {"unit":apert.distance_unit})
1095               
1096                size = doc.createElement("size")
1097                if apert.size_name is not None:
1098                    size.setAttribute("name", str(apert.size_name))
1099                written = write_node(doc, size, "x", apert.size.x, {"unit":apert.size_unit})
1100                written = written | write_node(doc, size, "y", apert.size.y, {"unit":apert.size_unit})
1101                written = written | write_node(doc, size, "z", apert.size.z, {"unit":apert.size_unit})
1102                if written == True:
1103                    ap.appendChild(size)
1104
1105        #   Detectors
1106        for item in datainfo.detector:
1107            det = doc.createElement("SASdetector")
1108            written = write_node(doc, det, "name", item.name)
1109            written = written | write_node(doc, det, "SDD", item.distance, {"unit":item.distance_unit})
1110            written = written | write_node(doc, det, "slit_length", item.slit_length, {"unit":item.slit_length_unit})
1111            if written == True:
1112                instr.appendChild(det)
1113           
1114            off = doc.createElement("offset")
1115            written = write_node(doc, off, "x", item.offset.x, {"unit":item.offset_unit})
1116            written = written | write_node(doc, off, "y", item.offset.y, {"unit":item.offset_unit})
1117            written = written | write_node(doc, off, "z", item.offset.z, {"unit":item.offset_unit})
1118            if written == True:
1119                det.appendChild(off)
1120           
1121            center = doc.createElement("beam_center")
1122            written = write_node(doc, center, "x", item.beam_center.x, {"unit":item.beam_center_unit})
1123            written = written | write_node(doc, center, "y", item.beam_center.y, {"unit":item.beam_center_unit})
1124            written = written | write_node(doc, center, "z", item.beam_center.z, {"unit":item.beam_center_unit})
1125            if written == True:
1126                det.appendChild(center)
1127               
1128            pix = doc.createElement("pixel_size")
1129            written = write_node(doc, pix, "x", item.pixel_size.x, {"unit":item.pixel_size_unit})
1130            written = written | write_node(doc, pix, "y", item.pixel_size.y, {"unit":item.pixel_size_unit})
1131            written = written | write_node(doc, pix, "z", item.pixel_size.z, {"unit":item.pixel_size_unit})
1132            if written == True:
1133                det.appendChild(pix)
1134               
1135            ori = doc.createElement("orientation")
1136            written = write_node(doc, ori, "roll",  item.orientation.x, {"unit":item.orientation_unit})
1137            written = written | write_node(doc, ori, "pitch", item.orientation.y, {"unit":item.orientation_unit})
1138            written = written | write_node(doc, ori, "yaw",   item.orientation.z, {"unit":item.orientation_unit})
1139            if written == True:
1140                det.appendChild(ori)
1141               
1142        # Processes info
1143        for item in datainfo.process:
1144            node = doc.createElement("SASprocess")
1145            entry_node.appendChild(node)
1146
1147            write_node(doc, node, "name", item.name)
1148            write_node(doc, node, "date", item.date)
1149            write_node(doc, node, "description", item.description)
1150            for term in item.term:
1151                value = term['value']
1152                del term['value']
1153                write_node(doc, node, "term", value, term)
1154            for note in item.notes:
1155                write_node(doc, node, "SASprocessnote", note)
1156        # Return the document, and the SASentry node associated with
1157        # the data we just wrote
1158        return doc, entry_node
1159   
1160    def _parse_state(self, entry):
1161        """
1162        Read a fit result from an XML node
1163       
1164        :param entry: XML node to read from
1165       
1166        :return: PageState object
1167        """
1168        # Create an empty state
1169        state = None   
1170        # Locate the P(r) node
1171        try:
1172            nodes = entry.xpath('ns:%s' % FITTING_NODE_NAME, namespaces={'ns': CANSAS_NS})
1173            if nodes !=[]:
1174                # Create an empty state
1175                state =  PageState()
1176                state.fromXML(node=nodes[0])
1177        except:
1178            logging.info("XML document does not contain fitting information.\n %s" % sys.exc_value)
1179           
1180        return state
1181   
1182   
1183                   
1184    def _parse_entry(self, dom):
1185        """
1186        Parse a SASentry
1187       
1188        :param node: SASentry node
1189       
1190        :return: Data1D/Data2D object
1191       
1192        """
1193        node = dom.xpath('ns:data_class', namespaces={'ns': CANSAS_NS})
1194        if not node or node[0].text.lstrip().rstrip() != "Data2D":
1195            return CansasReader._parse_entry(self, dom)
1196       
1197        #Parse 2D
1198        data_info = Data2D()
1199       
1200        # Look up title     
1201        self._store_content('ns:Title', dom, 'title', data_info)
1202       
1203        # Look up run number   
1204        nodes = dom.xpath('ns:Run', namespaces={'ns': CANSAS_NS})
1205        for item in nodes:   
1206            if item.text is not None:
1207                value = item.text.strip()
1208                if len(value) > 0:
1209                    data_info.run.append(value)
1210                    if item.get('name') is not None:
1211                        data_info.run_name[value] = item.get('name')
1212                           
1213        # Look up instrument name             
1214        self._store_content('ns:SASinstrument/ns:name', dom, 'instrument', data_info)
1215
1216        # Notes
1217        note_list = dom.xpath('ns:SASnote', namespaces={'ns': CANSAS_NS})
1218        for note in note_list:
1219            try:
1220                if note.text is not None:
1221                    note_value = note.text.strip()
1222                    if len(note_value) > 0:
1223                        data_info.notes.append(note_value)
1224            except:
1225                err_mess = "cansas_reader.read: error processing entry notes\n  %s" % sys.exc_value
1226                self.errors.append(err_mess)
1227                logging.error(err_mess)
1228       
1229        # Sample info ###################
1230        entry = get_content('ns:SASsample', dom)
1231        if entry is not None:
1232            data_info.sample.name = entry.get('name')
1233           
1234        self._store_content('ns:SASsample/ns:ID', 
1235                     dom, 'ID', data_info.sample)                   
1236        self._store_float('ns:SASsample/ns:thickness', 
1237                     dom, 'thickness', data_info.sample)
1238        self._store_float('ns:SASsample/ns:transmission', 
1239                     dom, 'transmission', data_info.sample)
1240        self._store_float('ns:SASsample/ns:temperature', 
1241                     dom, 'temperature', data_info.sample)
1242       
1243        nodes = dom.xpath('ns:SASsample/ns:details', namespaces={'ns': CANSAS_NS})
1244        for item in nodes:
1245            try:
1246                if item.text is not None:
1247                    detail_value = item.text.strip()
1248                    if len(detail_value) > 0:
1249                        data_info.sample.details.append(detail_value)
1250            except:
1251                err_mess = "cansas_reader.read: error processing sample details\n  %s" % sys.exc_value
1252                self.errors.append(err_mess)
1253                logging.error(err_mess)
1254       
1255        # Position (as a vector)
1256        self._store_float('ns:SASsample/ns:position/ns:x', 
1257                     dom, 'position.x', data_info.sample)         
1258        self._store_float('ns:SASsample/ns:position/ns:y', 
1259                     dom, 'position.y', data_info.sample)         
1260        self._store_float('ns:SASsample/ns:position/ns:z', 
1261                     dom, 'position.z', data_info.sample)         
1262       
1263        # Orientation (as a vector)
1264        self._store_float('ns:SASsample/ns:orientation/ns:roll', 
1265                     dom, 'orientation.x', data_info.sample)         
1266        self._store_float('ns:SASsample/ns:orientation/ns:pitch', 
1267                     dom, 'orientation.y', data_info.sample)         
1268        self._store_float('ns:SASsample/ns:orientation/ns:yaw', 
1269                     dom, 'orientation.z', data_info.sample)         
1270       
1271        # Source info ###################
1272        entry = get_content('ns:SASinstrument/ns:SASsource', dom)
1273        if entry is not None:
1274            data_info.source.name = entry.get('name')
1275       
1276        self._store_content('ns:SASinstrument/ns:SASsource/ns:radiation', 
1277                     dom, 'radiation', data_info.source)                   
1278        self._store_content('ns:SASinstrument/ns:SASsource/ns:beam_shape', 
1279                     dom, 'beam_shape', data_info.source)                   
1280        self._store_float('ns:SASinstrument/ns:SASsource/ns:wavelength', 
1281                     dom, 'wavelength', data_info.source)         
1282        self._store_float('ns:SASinstrument/ns:SASsource/ns:wavelength_min', 
1283                     dom, 'wavelength_min', data_info.source)         
1284        self._store_float('ns:SASinstrument/ns:SASsource/ns:wavelength_max', 
1285                     dom, 'wavelength_max', data_info.source)         
1286        self._store_float('ns:SASinstrument/ns:SASsource/ns:wavelength_spread', 
1287                     dom, 'wavelength_spread', data_info.source)   
1288       
1289        # Beam size (as a vector)   
1290        entry = get_content('ns:SASinstrument/ns:SASsource/ns:beam_size', dom)
1291        if entry is not None:
1292            data_info.source.beam_size_name = entry.get('name')
1293           
1294        self._store_float('ns:SASinstrument/ns:SASsource/ns:beam_size/ns:x', 
1295                     dom, 'beam_size.x', data_info.source)   
1296        self._store_float('ns:SASinstrument/ns:SASsource/ns:beam_size/ns:y', 
1297                     dom, 'beam_size.y', data_info.source)   
1298        self._store_float('ns:SASinstrument/ns:SASsource/ns:beam_size/ns:z', 
1299                     dom, 'beam_size.z', data_info.source)   
1300       
1301        # Collimation info ###################
1302        nodes = dom.xpath('ns:SASinstrument/ns:SAScollimation', namespaces={'ns': CANSAS_NS})
1303        for item in nodes:
1304            collim = Collimation()
1305            if item.get('name') is not None:
1306                collim.name = item.get('name')
1307            self._store_float('ns:length', item, 'length', collim) 
1308           
1309            # Look for apertures
1310            apert_list = item.xpath('ns:aperture', namespaces={'ns': CANSAS_NS})
1311            for apert in apert_list:
1312                aperture =  Aperture()
1313               
1314                # Get the name and type of the aperture
1315                aperture.name = apert.get('name')
1316                aperture.type = apert.get('type')
1317                   
1318                self._store_float('ns:distance', apert, 'distance', aperture)   
1319               
1320                entry = get_content('ns:size', apert)
1321                if entry is not None:
1322                    aperture.size_name = entry.get('name')
1323               
1324                self._store_float('ns:size/ns:x', apert, 'size.x', aperture)   
1325                self._store_float('ns:size/ns:y', apert, 'size.y', aperture)   
1326                self._store_float('ns:size/ns:z', apert, 'size.z', aperture)
1327               
1328                collim.aperture.append(aperture)
1329               
1330            data_info.collimation.append(collim)
1331       
1332        # Detector info ######################
1333        nodes = dom.xpath('ns:SASinstrument/ns:SASdetector', namespaces={'ns': CANSAS_NS})
1334        for item in nodes:
1335           
1336            detector = Detector()
1337           
1338            self._store_content('ns:name', item, 'name', detector)
1339            self._store_float('ns:SDD', item, 'distance', detector)   
1340           
1341            # Detector offset (as a vector)
1342            self._store_float('ns:offset/ns:x', item, 'offset.x', detector)   
1343            self._store_float('ns:offset/ns:y', item, 'offset.y', detector)   
1344            self._store_float('ns:offset/ns:z', item, 'offset.z', detector)   
1345           
1346            # Detector orientation (as a vector)
1347            self._store_float('ns:orientation/ns:roll',  item, 'orientation.x', detector)   
1348            self._store_float('ns:orientation/ns:pitch', item, 'orientation.y', detector)   
1349            self._store_float('ns:orientation/ns:yaw',   item, 'orientation.z', detector)   
1350           
1351            # Beam center (as a vector)
1352            self._store_float('ns:beam_center/ns:x', item, 'beam_center.x', detector)   
1353            self._store_float('ns:beam_center/ns:y', item, 'beam_center.y', detector)   
1354            self._store_float('ns:beam_center/ns:z', item, 'beam_center.z', detector)   
1355           
1356            # Pixel size (as a vector)
1357            self._store_float('ns:pixel_size/ns:x', item, 'pixel_size.x', detector)   
1358            self._store_float('ns:pixel_size/ns:y', item, 'pixel_size.y', detector)   
1359            self._store_float('ns:pixel_size/ns:z', item, 'pixel_size.z', detector)   
1360           
1361            self._store_float('ns:slit_length', item, 'slit_length', detector)
1362           
1363            data_info.detector.append(detector)   
1364
1365        # Processes info ######################
1366        nodes = dom.xpath('ns:SASprocess', namespaces={'ns': CANSAS_NS})
1367        for item in nodes:
1368            process = Process()
1369            self._store_content('ns:name', item, 'name', process)
1370            self._store_content('ns:date', item, 'date', process)
1371            self._store_content('ns:description', item, 'description', process)
1372           
1373            term_list = item.xpath('ns:term', namespaces={'ns': CANSAS_NS})
1374            for term in term_list:
1375                try:
1376                    term_attr = {}
1377                    for attr in term.keys():
1378                        term_attr[attr] = term.get(attr).strip()
1379                    if term.text is not None:
1380                        term_attr['value'] = term.text.strip()
1381                        process.term.append(term_attr)
1382                except:
1383                    err_mess = "cansas_reader.read: error processing process term\n  %s" % sys.exc_value
1384                    self.errors.append(err_mess)
1385                    logging.error(err_mess)
1386           
1387            note_list = item.xpath('ns:SASprocessnote', namespaces={'ns': CANSAS_NS})
1388            for note in note_list:
1389                if note.text is not None:
1390                    process.notes.append(note.text.strip())
1391           
1392            data_info.process.append(process)
1393           
1394           
1395        # Data info ######################
1396        nodes = dom.xpath('ns:SASdata', namespaces={'ns': CANSAS_NS})
1397        if len(nodes)>1:
1398            raise RuntimeError, "CanSAS reader is not compatible with multiple SASdata entries"
1399       
1400        for entry in nodes:
1401            for item in list_of_data_2d_attr:
1402                #get node
1403                node = get_content('ns:%s'%item[0], entry)
1404                exec "data_info.%s = parse_entry_helper(node, item)"%(item[1])
1405                   
1406            for item in list_of_data2d_values:
1407                field = get_content('ns:%s'%item[0], entry)
1408                list = []
1409                if field is not None:
1410                    list = [parse_entry_helper(node, item) for node in field]
1411                exec "data_info.%s = numpy.array(list)"%item[0]
1412       
1413        return data_info
1414
1415    def _read_cansas(self, path):
1416        """
1417        Load data and P(r) information from a CanSAS XML file.
1418       
1419        :param path: file path
1420       
1421        :return: Data1D object if a single SASentry was found,
1422                    or a list of Data1D objects if multiple entries were found,
1423                    or None of nothing was found
1424                   
1425        :raise RuntimeError: when the file can't be opened
1426        :raise ValueError: when the length of the data vectors are inconsistent
1427       
1428        """
1429        output = []
1430        basename  = os.path.basename(path)
1431        root, extension = os.path.splitext(basename)
1432        ext = extension.lower()
1433        try:
1434            if os.path.isfile(path):
1435               
1436                #TODO: eventually remove the check for .xml once
1437                # the P(r) writer/reader is truly complete.
1438                if  ext in self.ext or \
1439                    ext == '.xml':
1440                   
1441                    tree = etree.parse(path, parser=etree.ETCompatXMLParser())
1442                    # Check the format version number
1443                    # Specifying the namespace will take care of the file format version
1444                    root = tree.getroot()
1445                    entry_list = root.xpath('ns:SASentry', namespaces={'ns': CANSAS_NS})
1446                    for entry in entry_list:   
1447                        try:
1448                            sas_entry = self._parse_entry(entry)
1449                        except:
1450                            raise
1451                        fitstate = self._parse_state(entry)
1452                       
1453                        #state could be None when .svs file is loaded
1454                        #in this case, skip appending to output
1455                        if fitstate != None:
1456                            sas_entry.meta_data['fitstate'] = fitstate
1457                            sas_entry.filename = fitstate.file
1458                            output.append(sas_entry)
1459            else:
1460                self.call_back(format=ext)
1461                raise RuntimeError, "%s is not a file" % path
1462
1463            # Return output consistent with the loader's api
1464            if len(output)==0:
1465                self.call_back(state=None, datainfo=None,format=ext)
1466                return None
1467            else:
1468                for ind in range(len(output)):
1469                    # Call back to post the new state
1470                    state = output[ind].meta_data['fitstate']
1471                    t = time.localtime(state.timestamp)
1472                    time_str = time.strftime("%b %d %H:%M", t)
1473                    # Check that no time stamp is already appended
1474                    max_char = state.file.find("[")
1475                    if max_char < 0:
1476                        max_char = len(state.file)
1477                    original_fname = state.file[0:max_char]
1478                    state.file = original_fname +' [' + time_str + ']'
1479                   
1480                       
1481                    if state is not None and state.is_data is not None:
1482                        exec 'output[%d].is_data = state.is_data'% ind
1483                     
1484                    output[ind].filename = state.file
1485                    state.data = output[ind]
1486                    state.data.name = output[ind].filename #state.data_name
1487                    state.data.id = state.data_id
1488                    if state.is_data is not None:
1489                        state.data.is_data = state.is_data
1490                    if output[ind].run_name is not None and len(output[ind].run_name) != 0 :
1491                        name = output[ind].run_name
1492                    else: 
1493                        name=original_fname
1494                    state.data.group_id = name
1495                    #store state in fitting
1496                    self.call_back(state=state, datainfo=output[ind],format=ext)
1497                    self.state= state
1498                return output
1499             
1500        except:
1501            self.call_back(format=ext)
1502            #self.state= state
1503            raise
1504           
1505    def write(self, filename, datainfo=None, fitstate=None):
1506        """
1507        Write the content of a Data1D as a CanSAS XML file only for standalone
1508       
1509        :param filename: name of the file to write
1510        :param datainfo: Data1D object
1511        :param fitstate: PageState object
1512       
1513        """
1514        # Sanity check
1515        if self.cansas == True:
1516           
1517            # Add fitting information to the XML document
1518            doc = self.write_toXML(datainfo, fitstate)
1519            # Write the XML document
1520            fd = open(filename, 'w')
1521            fd.write(doc.toprettyxml())
1522            fd.close()
1523        else:
1524            fitstate.toXML(file=filename)
1525       
1526    def write_toXML(self, datainfo=None, state=None):
1527        """
1528        Write toXML, a helper for write() , could be used by guimanager._on_save()
1529       
1530        : return: xml doc
1531        """
1532
1533        if state.data is None:
1534            data = sans.dataloader.data_info.Data1D(x=[], y=[]) 
1535        else: 
1536            #make sure title and data run is filled up.
1537            if state.data.title == None or state.data.title=='': state.data.title = state.data.name
1538            if state.data.run_name == None or state.data.run_name=={}: 
1539                state.data.run = [str(state.data.name)]
1540                state.data.run_name[0] = state.data.name
1541   
1542            if issubclass(state.data.__class__, sans.dataloader.data_info.Data1D):
1543
1544                data = state.data
1545                doc, sasentry = self._to_xml_doc(data)
1546            else:
1547                data = state.data
1548                doc, sasentry = self._data2d_to_xml_doc(data)
1549           
1550
1551        if state is not None:
1552            state.toXML(doc=doc, file=data.name, entry_node=sasentry)
1553           
1554        return doc
1555   
1556# Simple html report templet 
1557HEADER = "<html>\n"
1558HEADER += "<head>\n"
1559HEADER += "<meta http-equiv=Content-Type content='text/html; "
1560HEADER += "charset=windows-1252'> \n"
1561HEADER += "<meta name=Generator >\n"
1562HEADER += "</head>\n"
1563HEADER += "<body lang=EN-US>\n"
1564HEADER += "<div class=WordSection1>\n"
1565HEADER += "<p class=MsoNormal><b><span ><center>"
1566HEADER += "%s</center></span></center></b></p>"
1567HEADER += "<p class=MsoNormal>&nbsp;</p>"
1568PARA = "<p class=MsoNormal> %s \n"
1569PARA += "</p>"
1570CENTRE = "<p class=MsoNormal><center> %s \n"
1571CENTRE += "</center></p>"
1572FEET_1 = \
1573"""
1574<p class=MsoNormal>&nbsp;</p>
1575<p class=MsoNormal><b><span ><center> Graph</span></center></b></p>
1576<p class=MsoNormal>&nbsp;</p> 
1577<center> 
1578<br>Model Computation<br> 
1579<br>Data: "%s"<br> 
1580"""
1581FEET_2 = \
1582"""
1583<img src="%s" > 
1584</img>
1585"""
1586FEET_3 = \
1587"""
1588</center>
1589</div>
1590</body>
1591</html>
1592"""
1593ELINE = "<p class=MsoNormal>&nbsp;</p>"
1594
1595if __name__ == "__main__":
1596    state = PageState(parent=None)
1597    #state.toXML()
1598    """
1599   
1600    file = open("test_state", "w")
1601    pickle.dump(state, file)
1602    print pickle.dumps(state)
1603    state.data_name = "hello---->"
1604    pickle.dump(state, file)
1605    file = open("test_state", "r")
1606    new_state= pickle.load(file)
1607    print "new state", new_state
1608    new_state= pickle.load(file)
1609    print "new state", new_state
1610    #print "state", state
1611    """
1612    import bsddb
1613    import pickle
1614    db= bsddb.btopen('file_state.db', 'c')
1615    val = (pickle.dumps(state), "hello", "hi")
1616    db['state1']= pickle.dumps(val)
1617    print pickle.loads(db['state1'])
1618    state.data_name = "hello---->22"
1619    db['state2']= pickle.dumps(state)
1620    state.data_name = "hello---->2"
1621    db['state3']= pickle.dumps(state)
1622    del db['state3']
1623    state.data_name = "hello---->3"
1624    db['state4']= pickle.dumps(state)
1625    new_state = pickle.loads(db['state1'])
1626    #print db.last()
1627    db.set_location('state2')
1628    state.data_name = "hello---->5"
1629    db['aastate5']= pickle.dumps(state)
1630    db.keys().sort()
1631    print pickle.loads(db['state2'])
1632 
1633    db.close()
Note: See TracBrowser for help on using the repository browser.