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

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

update time stemp format in report

  • 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        paramval_string += "<table> <tr>"
523        for lines in param_string.split(":"): 
524            line = lines.split(",")
525            if len(lines) > 0: 
526                param = line[0] 
527                param += " = " + line[1]
528                if len(line[2].split()) > 0 and not line[2].count("None"):
529                    param += " +- " + line[2]
530                if len(line[3].split()) > 0 and not line[3].count("None"):
531                    param += " " + line[3]
532                if not paramval.count(param):
533                    paramval +=  param + "\n"
534                    paramval_string += CENTRE % param + "\n"
535            paramval_string += '</tr>'
536        paramval_string += '</table>'
537        text_string = "\n\n\n" + title + "\n\n" + file + \
538                              "\n" + q_name + \
539                              "\n" + chi2 + \
540                              "\n\n" + paramval
541       
542        title_name = self._check_html_format(title_name)
543        file_name = self._check_html_format(file_name)
544        title = self._check_html_format(title)
545                                 
546        html_string = title_name + "\n" + file_name + \
547                                   "\n" + model_name +\
548                                   "\n" + q_range + \
549                                   "\n" + chi2_string + \
550                                   "\n" + ELINE + \
551                                   "\n" + paramval_string + \
552                                   "\n" + ELINE + \
553                                   "\n" + FEET_1 % title + \
554                                   "\n" + FEET_2
555                                                                     
556        return html_string, text_string, title
557   
558    def _check_html_format(self, name):
559        """
560        Check string '%' for html format
561        """
562        if name.count('%'):
563            name = name.replace('%', '&#37')
564       
565        return name
566   
567   
568    def report(self, figs=None, canvases=None):
569        """
570        Invoke report dialog panel
571       
572        : param figs: list of pylab figures [list]
573        """
574        from report_dialog import ReportDialog
575        # get the strings for report
576        html_str, text_str, title = self.set_report_string()
577        # Allow 2 figures to append
578        if len(figs) == 1:
579            add_str = FEET_3
580        elif len(figs) == 2:
581            add_str = ELINE
582            add_str += FEET_2 % ("%s") 
583            add_str += ELINE
584            add_str += FEET_3
585        elif len(figs) > 2:
586            add_str = ELINE
587            add_str += FEET_2 % ("%s") 
588            add_str += ELINE
589            add_str += FEET_2 % ("%s") 
590            add_str += ELINE
591            add_str += FEET_3
592        else:
593            add_str = ""
594
595        # final report html strings
596        report_str = html_str % ("%s") + add_str
597
598        # make plot image
599        images = self.set_plot_state(figs, canvases)
600        report_list = [report_str, text_str, images ]
601        dialog = ReportDialog(report_list, None, -1, "")
602        dialog.ShowModal()
603       
604   
605    def _toXML_helper(self, list, element, newdoc):
606        """
607        Helper method to create xml file for saving state
608        """
609        for item in list:
610            sub_element = newdoc.createElement('parameter')
611            sub_element.setAttribute('name', str(item[1]))
612            sub_element.setAttribute('value', str(item[2]))
613            sub_element.setAttribute('selected_to_fit', str(item[0]))
614            sub_element.setAttribute('error_displayed', str(item[4][0]))
615            sub_element.setAttribute('error_value', str(item[4][1]))
616            sub_element.setAttribute('minimum_displayed', str(item[5][0]))
617            sub_element.setAttribute('minimum_value', str(item[5][1]))
618            sub_element.setAttribute('maximum_displayed', str(item[6][0]))
619            sub_element.setAttribute('maximum_value', str(item[6][1]))
620            sub_element.setAttribute('unit', str(item[7]))
621            element.appendChild(sub_element)
622       
623    def toXML(self, file="fitting_state.fitv", doc=None, entry_node=None):
624        """
625        Writes the state of the InversionControl panel to file, as XML.
626       
627        Compatible with standalone writing, or appending to an
628        already existing XML document. In that case, the XML document
629        is required. An optional entry node in the XML document may also be given.
630       
631        :param file: file to write to
632        :param doc: XML document object [optional]
633        :param entry_node: XML node within the XML document at which we will append the data [optional]
634       
635        """
636        from xml.dom.minidom import getDOMImplementation
637
638        # Check whether we have to write a standalone XML file
639        if doc is None:
640            impl = getDOMImplementation()
641            doc_type = impl.createDocumentType(FITTING_NODE_NAME, "1.0", "1.0")     
642            newdoc = impl.createDocument(None, FITTING_NODE_NAME, doc_type)
643            top_element = newdoc.documentElement
644        else:
645            # We are appending to an existing document
646            newdoc = doc
647            top_element = newdoc.createElement(FITTING_NODE_NAME)
648            if entry_node is None:
649                newdoc.documentElement.appendChild(top_element)
650            else:
651                entry_node.appendChild(top_element)
652           
653        attr = newdoc.createAttribute("version")
654        attr.nodeValue = '1.0'
655        top_element.setAttributeNode(attr)
656       
657        # File name
658        element = newdoc.createElement("filename")
659        if self.file is not None:
660            element.appendChild(newdoc.createTextNode(str(self.file)))
661        else:
662            element.appendChild(newdoc.createTextNode(str(file)))
663        top_element.appendChild(element)
664       
665        element = newdoc.createElement("timestamp")
666        element.appendChild(newdoc.createTextNode(time.ctime(self.timestamp)))
667        attr = newdoc.createAttribute("epoch")
668        attr.nodeValue = str(self.timestamp)
669        element.setAttributeNode(attr)
670        top_element.appendChild(element)
671        # Inputs
672        inputs = newdoc.createElement("Attributes")
673        top_element.appendChild(inputs)
674       
675
676        if self.data is not None and hasattr(self.data, "group_id"):
677            self.data_group_id = self.data.group_id
678        if self.data is not None and hasattr(self.data, "is_data"):
679            self.is_data = self.data.is_data
680        if self.data is not None:
681            self.data_name = self.data.name
682        if self.data is not None and hasattr(self.data, "id"):
683            self.data_id = self.data.id
684       
685        for item in list_of_data_attributes:
686            element = newdoc.createElement(item[0])
687            exec "element.setAttribute(item[0], str(self.%s))" % (item[1])
688            inputs.appendChild(element)   
689       
690        for item in list_of_state_attributes:
691            element = newdoc.createElement(item[0])
692            exec "element.setAttribute(item[0], str(self.%s))" % (item[1])
693            inputs.appendChild(element)
694           
695        # For self.values ={ disp_param_name: [vals,...],...}   
696        # and for self.weights ={ disp_param_name: [weights,...],...} 
697        for item in list_of_model_attributes:
698            element = newdoc.createElement(item[0])
699            exec "list = self.%s" % item[1]
700            for key, value in list.iteritems():
701                sub_element = newdoc.createElement(key)
702                sub_element.setAttribute('name', str(key))
703                for val in value:
704                    com = "sub_element.appendChild"
705                    com += "(newdoc.createTextNode(str(%s)))"
706                    exec com % val
707                   
708                element.appendChild(sub_element) 
709            inputs.appendChild(element)
710       
711        # Create doc for the dictionary of self._disp_obj_dic
712        for item in list_of_obj_dic:
713             element = newdoc.createElement(item[0])
714             exec "list = self.%s" % item[1]
715             for key, val in list.iteritems():
716                 value = repr(val)
717                 sub_element = newdoc.createElement(key)
718                 sub_element.setAttribute('name', str(key))
719                 sub_element.setAttribute('value', str(value))
720                 element.appendChild(sub_element) 
721             inputs.appendChild(element)   
722                 
723        for item in list_of_state_parameters:
724            element = newdoc.createElement(item[0])
725            com = "self._toXML_helper(list=self.%s,"
726            com += " element=element, newdoc=newdoc)"
727            exec com % item[1]                       
728            inputs.appendChild(element)
729       
730        # Save the file
731        if doc is None:
732            fd = open(file, 'w')
733            fd.write(newdoc.toprettyxml())
734            fd.close()
735            return None
736        else:
737            return newdoc.toprettyxml()
738       
739    def _fromXML_helper(self, node, list):
740        """
741        Helper function to write state to xml
742        """
743        for item in node:
744            try:
745                name = item.get('name')
746            except:
747                name = None
748            try:
749                value = item.get('value')
750            except:
751                value = None
752            try:
753                selected_to_fit = (item.get('selected_to_fit') == "True")
754            except:
755                selected_to_fit = None
756            try:
757                error_displayed = (item.get('error_displayed') == "True")
758            except:
759                error_displayed = None
760            try: 
761                error_value = item.get('error_value')
762            except:
763                error_value = None
764            try:
765                minimum_displayed = (item.get('minimum_displayed')== "True")
766            except:
767                minimum_displayed = None
768            try:
769                minimum_value = item.get('minimum_value')
770            except:
771                minimum_value = None
772            try:
773                maximum_displayed = (item.get('maximum_displayed') == "True")
774            except:
775                maximum_displayed = None
776            try:
777                maximum_value = item.get('maximum_value')
778            except:
779                maximum_value = None
780            try:
781                unit = item.get('unit')
782            except:
783                unit = None
784            list.append([selected_to_fit, name, value, "+/-",
785                         [error_displayed, error_value],
786                         [minimum_displayed,minimum_value],
787                         [maximum_displayed,maximum_value], unit])
788       
789    def fromXML(self, file=None, node=None):
790        """
791        Load fitting state from a file
792       
793        :param file: .fitv file
794        :param node: node of a XML document to read from
795       
796        """
797        if file is not None:
798            msg = "PageState no longer supports non-CanSAS"
799            msg += " format for fitting files"
800            raise RuntimeError, msg
801           
802        if node.get('version')and node.get('version') == '1.0':
803           
804            # Get file name
805            entry = get_content('ns:filename', node)
806            if entry is not None:
807                self.file = entry.text.strip()
808               
809            # Get time stamp
810            entry = get_content('ns:timestamp', node)
811            if entry is not None and entry.get('epoch'):
812                try:
813                    self.timestamp = float(entry.get('epoch'))
814                except:
815                    msg = "PageState.fromXML: Could not"
816                    msg += " read timestamp\n %s" % sys.exc_value
817                    logging.error(msg)
818           
819            # Parse fitting attributes
820            entry = get_content('ns:Attributes', node)
821            for item in list_of_data_attributes:
822                node = get_content('ns:%s'%item[0], entry)
823                try:
824                    exec "self.%s = parse_entry_helper(node, item)" % item[0]
825                   
826                except:
827                    raise
828
829            if entry is not None:
830               
831                for item in list_of_state_attributes:
832                    node = get_content('ns:%s' % item[0], entry)
833                    try:
834                        exec "self.%s = parse_entry_helper(node, item)" % \
835                                                                str(item[0])
836                    except:
837                        raise
838                   
839                for item in list_of_state_parameters:
840                    node = get_content("ns:%s" % item[0], entry)
841                    exec "self._fromXML_helper(node=node, list=self.%s)" % \
842                                                                    item[1]
843               
844                # Recover _disp_obj_dict from xml file   
845                self._disp_obj_dict = {}   
846                for item in list_of_obj_dic:
847                    # Get node
848                    node = get_content("ns:%s" % item[0], entry)
849                    for attr in node:
850                        name = attr.get('name')
851                        val  = attr.get('value')
852                        value = val.split(" instance")[0]
853                        disp_name = value.split("<")[1]
854                        try:
855                            # Try to recover disp_model object from strings
856                            com  = "from sans.models.dispersion_models "
857                            com += "import %s as disp"
858                            com_name = disp_name.split(".")[3]
859                            exec com % com_name
860                            disp_model = disp()
861                            exec "self.%s['%s'] = com_name" % (item[1], name)
862                        except:
863                            pass
864                       
865                # get self.values and self.weights dic. if exists   
866                for item in list_of_model_attributes:
867                    node = get_content("ns:%s" % item[0], entry)
868                    dic = {}
869                    list = []
870                    for par in node:
871                        name = par.get('name')
872                        values = par.text.split('\n')
873                        # Get lines only with numbers
874                        for line in values:
875                            try:
876                                val= float(line)
877                                list.append(val) 
878                            except:
879                                # pass if line is empty (it happens)
880                                pass
881                    dic[name] = numpy.array(list)
882                    exec "self.%s = dic" % item[1]
883                   
884    def set_plot_state(self, figs, canvases):
885        """
886        Build image state that wx.html understand
887        by plotting, putting it into wx.FileSystem image object
888
889        """
890        images = []
891        # some imports
892        import wx
893
894        # Reset memory
895        self.imgRAM = None
896        wx.MemoryFSHandler()
897       
898        # For no figures in the list, prepare empty plot
899        if figs == None or len(figs) == 0:
900            figs = [None]
901           
902        # Loop over the list of figures   
903        # use wx.MemoryFSHandler
904        self.imgRAM = wx.MemoryFSHandler() 
905        for fig in figs:
906            if figs != None:
907                #fig.set_facecolor('w')
908                ind = figs.index(fig)
909                canvas = canvases[ind]
910               
911            #bmp = wx.BitmapDataObject()
912            #bmp.SetBitmap(canvas.bitmap)
913            #store the image in wx.FileSystem Object
914            wx.FileSystem.AddHandler(wx.MemoryFSHandler())
915           
916            # index of the fig
917            ind = figs.index(fig)
918           
919            #AddFile, image can be retrieved with 'memory:filename'
920            self.imgRAM.AddFile('img_fit%s.png' % ind , 
921                                canvas.bitmap, wx.BITMAP_TYPE_PNG)
922           
923            #append figs
924            images.append(fig)
925           
926        return images
927
928class Reader(CansasReader):
929    """
930    Class to load a .fitv fitting file
931    """
932    ## File type
933    type_name = "Fitting"
934   
935    ## Wildcards
936    type = ["Fitting files (*.fitv)|*.fitv"
937            "SANSView file (*.svs)|*.svs"]
938    ## List of allowed extensions
939    ext=['.fitv', '.FITV', '.svs', 'SVS']   
940   
941    def __init__(self, call_back=None, cansas=True):
942        CansasReader.__init__(self)
943        """
944        Initialize the call-back method to be called
945        after we load a file
946       
947        :param call_back: call-back method
948        :param cansas:  True = files will be written/read in CanSAS format
949                        False = write CanSAS format
950           
951        """
952        ## Call back method to be executed after a file is read
953        self.call_back = call_back
954        ## CanSAS format flag
955        self.cansas = cansas
956        self.state = None
957    def get_state(self):
958        return self.state
959       
960    def read(self, path):
961        """
962        Load a new P(r) inversion state from file
963       
964        :param path: file path
965       
966        """
967        if self.cansas == True:
968            return self._read_cansas(path)
969     
970    def _data2d_to_xml_doc(self, datainfo):
971        """
972        Create an XML document to contain the content of a Data2D
973       
974        :param datainfo: Data2D object
975       
976        """
977        if not issubclass(datainfo.__class__, Data2D):
978            raise RuntimeError, "The cansas writer expects a Data2D instance"
979       
980        doc = xml.dom.minidom.Document()
981        main_node = doc.createElement("SASroot")
982        main_node.setAttribute("version", self.version)
983        main_node.setAttribute("xmlns", "cansas1d/%s" % self.version)
984        main_node.setAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance")
985        main_node.setAttribute("xsi:schemaLocation", "cansas1d/%s http://svn.smallangles.net/svn/canSAS/1dwg/trunk/cansas1d.xsd" % self.version)
986       
987        doc.appendChild(main_node)
988       
989        entry_node = doc.createElement("SASentry")
990        main_node.appendChild(entry_node)
991       
992        write_node(doc, entry_node, "Title", datainfo.title)
993        if datainfo is not None:
994            write_node(doc, entry_node, "data_class", datainfo.__class__.__name__)
995        for item in datainfo.run:
996            runname = {}
997            if datainfo.run_name.has_key(item) and len(str(datainfo.run_name[item]))>1:
998                runname = {'name': datainfo.run_name[item] }
999            write_node(doc, entry_node, "Run", item, runname)
1000        # Data info
1001        new_node = doc.createElement("SASdata")
1002        entry_node.appendChild(new_node)
1003        for item in list_of_data_2d_attr:
1004            element = doc.createElement(item[0])
1005            exec "element.setAttribute(item[0], str(datainfo.%s))"%(item[1])
1006            new_node.appendChild(element)
1007           
1008        for item in list_of_data2d_values:
1009            root_node = doc.createElement(item[0])
1010            new_node.appendChild(root_node)
1011           
1012            exec "temp_list = datainfo.%s"%item[1]
1013
1014            if temp_list is None or len(temp_list)== 0:
1015                element = doc.createElement(item[0])
1016                exec "element.appendChild(doc.createTextNode(str(%s)))"%temp_list
1017                root_node.appendChild(element)
1018            else:
1019                for value in temp_list:
1020                    element = doc.createElement(item[0])
1021                    exec "element.setAttribute(item[0], str(%s))"%value
1022                    root_node.appendChild(element)
1023       
1024        # Sample info
1025        sample = doc.createElement("SASsample")
1026        if datainfo.sample.name is not None:
1027            sample.setAttribute("name", str(datainfo.sample.name))
1028        entry_node.appendChild(sample)
1029        write_node(doc, sample, "ID", str(datainfo.sample.ID))
1030        write_node(doc, sample, "thickness", datainfo.sample.thickness, {"unit":datainfo.sample.thickness_unit})
1031        write_node(doc, sample, "transmission", datainfo.sample.transmission)
1032        write_node(doc, sample, "temperature", datainfo.sample.temperature, {"unit":datainfo.sample.temperature_unit})
1033       
1034        for item in datainfo.sample.details:
1035            write_node(doc, sample, "details", item)
1036       
1037        pos = doc.createElement("position")
1038        written = write_node(doc, pos, "x", datainfo.sample.position.x, {"unit":datainfo.sample.position_unit})
1039        written = written | write_node(doc, pos, "y", datainfo.sample.position.y, {"unit":datainfo.sample.position_unit})
1040        written = written | write_node(doc, pos, "z", datainfo.sample.position.z, {"unit":datainfo.sample.position_unit})
1041        if written == True:
1042            sample.appendChild(pos)
1043       
1044        ori = doc.createElement("orientation")
1045        written = write_node(doc, ori, "roll",  datainfo.sample.orientation.x, {"unit":datainfo.sample.orientation_unit})
1046        written = written | write_node(doc, ori, "pitch", datainfo.sample.orientation.y, {"unit":datainfo.sample.orientation_unit})
1047        written = written | write_node(doc, ori, "yaw",   datainfo.sample.orientation.z, {"unit":datainfo.sample.orientation_unit})
1048        if written == True:
1049            sample.appendChild(ori)
1050       
1051        # Instrument info
1052        instr = doc.createElement("SASinstrument")
1053        entry_node.appendChild(instr)
1054       
1055        write_node(doc, instr, "name", datainfo.instrument)
1056       
1057        #   Source
1058        source = doc.createElement("SASsource")
1059        if datainfo.source.name is not None:
1060            source.setAttribute("name", str(datainfo.source.name))
1061        instr.appendChild(source)
1062       
1063        write_node(doc, source, "radiation", datainfo.source.radiation)
1064        write_node(doc, source, "beam_shape", datainfo.source.beam_shape)
1065        size = doc.createElement("beam_size")
1066        if datainfo.source.beam_size_name is not None:
1067            size.setAttribute("name", str(datainfo.source.beam_size_name))
1068        written = write_node(doc, size, "x", datainfo.source.beam_size.x, {"unit":datainfo.source.beam_size_unit})
1069        written = written | write_node(doc, size, "y", datainfo.source.beam_size.y, {"unit":datainfo.source.beam_size_unit})
1070        written = written | write_node(doc, size, "z", datainfo.source.beam_size.z, {"unit":datainfo.source.beam_size_unit})
1071        if written == True:
1072            source.appendChild(size)
1073           
1074        write_node(doc, source, "wavelength", datainfo.source.wavelength, {"unit":datainfo.source.wavelength_unit})
1075        write_node(doc, source, "wavelength_min", datainfo.source.wavelength_min, {"unit":datainfo.source.wavelength_min_unit})
1076        write_node(doc, source, "wavelength_max", datainfo.source.wavelength_max, {"unit":datainfo.source.wavelength_max_unit})
1077        write_node(doc, source, "wavelength_spread", datainfo.source.wavelength_spread, {"unit":datainfo.source.wavelength_spread_unit})
1078       
1079        #   Collimation
1080        for item in datainfo.collimation:
1081            coll = doc.createElement("SAScollimation")
1082            if item.name is not None:
1083                coll.setAttribute("name", str(item.name))
1084            instr.appendChild(coll)
1085           
1086            write_node(doc, coll, "length", item.length, {"unit":item.length_unit})
1087           
1088            for apert in item.aperture:
1089                ap = doc.createElement("aperture")
1090                if apert.name is not None:
1091                    ap.setAttribute("name", str(apert.name))
1092                if apert.type is not None:
1093                    ap.setAttribute("type", str(apert.type))
1094                coll.appendChild(ap)
1095               
1096                write_node(doc, ap, "distance", apert.distance, {"unit":apert.distance_unit})
1097               
1098                size = doc.createElement("size")
1099                if apert.size_name is not None:
1100                    size.setAttribute("name", str(apert.size_name))
1101                written = write_node(doc, size, "x", apert.size.x, {"unit":apert.size_unit})
1102                written = written | write_node(doc, size, "y", apert.size.y, {"unit":apert.size_unit})
1103                written = written | write_node(doc, size, "z", apert.size.z, {"unit":apert.size_unit})
1104                if written == True:
1105                    ap.appendChild(size)
1106
1107        #   Detectors
1108        for item in datainfo.detector:
1109            det = doc.createElement("SASdetector")
1110            written = write_node(doc, det, "name", item.name)
1111            written = written | write_node(doc, det, "SDD", item.distance, {"unit":item.distance_unit})
1112            written = written | write_node(doc, det, "slit_length", item.slit_length, {"unit":item.slit_length_unit})
1113            if written == True:
1114                instr.appendChild(det)
1115           
1116            off = doc.createElement("offset")
1117            written = write_node(doc, off, "x", item.offset.x, {"unit":item.offset_unit})
1118            written = written | write_node(doc, off, "y", item.offset.y, {"unit":item.offset_unit})
1119            written = written | write_node(doc, off, "z", item.offset.z, {"unit":item.offset_unit})
1120            if written == True:
1121                det.appendChild(off)
1122           
1123            center = doc.createElement("beam_center")
1124            written = write_node(doc, center, "x", item.beam_center.x, {"unit":item.beam_center_unit})
1125            written = written | write_node(doc, center, "y", item.beam_center.y, {"unit":item.beam_center_unit})
1126            written = written | write_node(doc, center, "z", item.beam_center.z, {"unit":item.beam_center_unit})
1127            if written == True:
1128                det.appendChild(center)
1129               
1130            pix = doc.createElement("pixel_size")
1131            written = write_node(doc, pix, "x", item.pixel_size.x, {"unit":item.pixel_size_unit})
1132            written = written | write_node(doc, pix, "y", item.pixel_size.y, {"unit":item.pixel_size_unit})
1133            written = written | write_node(doc, pix, "z", item.pixel_size.z, {"unit":item.pixel_size_unit})
1134            if written == True:
1135                det.appendChild(pix)
1136               
1137            ori = doc.createElement("orientation")
1138            written = write_node(doc, ori, "roll",  item.orientation.x, {"unit":item.orientation_unit})
1139            written = written | write_node(doc, ori, "pitch", item.orientation.y, {"unit":item.orientation_unit})
1140            written = written | write_node(doc, ori, "yaw",   item.orientation.z, {"unit":item.orientation_unit})
1141            if written == True:
1142                det.appendChild(ori)
1143               
1144        # Processes info
1145        for item in datainfo.process:
1146            node = doc.createElement("SASprocess")
1147            entry_node.appendChild(node)
1148
1149            write_node(doc, node, "name", item.name)
1150            write_node(doc, node, "date", item.date)
1151            write_node(doc, node, "description", item.description)
1152            for term in item.term:
1153                value = term['value']
1154                del term['value']
1155                write_node(doc, node, "term", value, term)
1156            for note in item.notes:
1157                write_node(doc, node, "SASprocessnote", note)
1158        # Return the document, and the SASentry node associated with
1159        # the data we just wrote
1160        return doc, entry_node
1161   
1162    def _parse_state(self, entry):
1163        """
1164        Read a fit result from an XML node
1165       
1166        :param entry: XML node to read from
1167       
1168        :return: PageState object
1169        """
1170        # Create an empty state
1171        state = None   
1172        # Locate the P(r) node
1173        try:
1174            nodes = entry.xpath('ns:%s' % FITTING_NODE_NAME, namespaces={'ns': CANSAS_NS})
1175            if nodes !=[]:
1176                # Create an empty state
1177                state =  PageState()
1178                state.fromXML(node=nodes[0])
1179        except:
1180            logging.info("XML document does not contain fitting information.\n %s" % sys.exc_value)
1181           
1182        return state
1183   
1184   
1185                   
1186    def _parse_entry(self, dom):
1187        """
1188        Parse a SASentry
1189       
1190        :param node: SASentry node
1191       
1192        :return: Data1D/Data2D object
1193       
1194        """
1195        node = dom.xpath('ns:data_class', namespaces={'ns': CANSAS_NS})
1196        if not node or node[0].text.lstrip().rstrip() != "Data2D":
1197            return CansasReader._parse_entry(self, dom)
1198       
1199        #Parse 2D
1200        data_info = Data2D()
1201       
1202        # Look up title     
1203        self._store_content('ns:Title', dom, 'title', data_info)
1204       
1205        # Look up run number   
1206        nodes = dom.xpath('ns:Run', namespaces={'ns': CANSAS_NS})
1207        for item in nodes:   
1208            if item.text is not None:
1209                value = item.text.strip()
1210                if len(value) > 0:
1211                    data_info.run.append(value)
1212                    if item.get('name') is not None:
1213                        data_info.run_name[value] = item.get('name')
1214                           
1215        # Look up instrument name             
1216        self._store_content('ns:SASinstrument/ns:name', dom, 'instrument', data_info)
1217
1218        # Notes
1219        note_list = dom.xpath('ns:SASnote', namespaces={'ns': CANSAS_NS})
1220        for note in note_list:
1221            try:
1222                if note.text is not None:
1223                    note_value = note.text.strip()
1224                    if len(note_value) > 0:
1225                        data_info.notes.append(note_value)
1226            except:
1227                err_mess = "cansas_reader.read: error processing entry notes\n  %s" % sys.exc_value
1228                self.errors.append(err_mess)
1229                logging.error(err_mess)
1230       
1231        # Sample info ###################
1232        entry = get_content('ns:SASsample', dom)
1233        if entry is not None:
1234            data_info.sample.name = entry.get('name')
1235           
1236        self._store_content('ns:SASsample/ns:ID', 
1237                     dom, 'ID', data_info.sample)                   
1238        self._store_float('ns:SASsample/ns:thickness', 
1239                     dom, 'thickness', data_info.sample)
1240        self._store_float('ns:SASsample/ns:transmission', 
1241                     dom, 'transmission', data_info.sample)
1242        self._store_float('ns:SASsample/ns:temperature', 
1243                     dom, 'temperature', data_info.sample)
1244       
1245        nodes = dom.xpath('ns:SASsample/ns:details', namespaces={'ns': CANSAS_NS})
1246        for item in nodes:
1247            try:
1248                if item.text is not None:
1249                    detail_value = item.text.strip()
1250                    if len(detail_value) > 0:
1251                        data_info.sample.details.append(detail_value)
1252            except:
1253                err_mess = "cansas_reader.read: error processing sample details\n  %s" % sys.exc_value
1254                self.errors.append(err_mess)
1255                logging.error(err_mess)
1256       
1257        # Position (as a vector)
1258        self._store_float('ns:SASsample/ns:position/ns:x', 
1259                     dom, 'position.x', data_info.sample)         
1260        self._store_float('ns:SASsample/ns:position/ns:y', 
1261                     dom, 'position.y', data_info.sample)         
1262        self._store_float('ns:SASsample/ns:position/ns:z', 
1263                     dom, 'position.z', data_info.sample)         
1264       
1265        # Orientation (as a vector)
1266        self._store_float('ns:SASsample/ns:orientation/ns:roll', 
1267                     dom, 'orientation.x', data_info.sample)         
1268        self._store_float('ns:SASsample/ns:orientation/ns:pitch', 
1269                     dom, 'orientation.y', data_info.sample)         
1270        self._store_float('ns:SASsample/ns:orientation/ns:yaw', 
1271                     dom, 'orientation.z', data_info.sample)         
1272       
1273        # Source info ###################
1274        entry = get_content('ns:SASinstrument/ns:SASsource', dom)
1275        if entry is not None:
1276            data_info.source.name = entry.get('name')
1277       
1278        self._store_content('ns:SASinstrument/ns:SASsource/ns:radiation', 
1279                     dom, 'radiation', data_info.source)                   
1280        self._store_content('ns:SASinstrument/ns:SASsource/ns:beam_shape', 
1281                     dom, 'beam_shape', data_info.source)                   
1282        self._store_float('ns:SASinstrument/ns:SASsource/ns:wavelength', 
1283                     dom, 'wavelength', data_info.source)         
1284        self._store_float('ns:SASinstrument/ns:SASsource/ns:wavelength_min', 
1285                     dom, 'wavelength_min', data_info.source)         
1286        self._store_float('ns:SASinstrument/ns:SASsource/ns:wavelength_max', 
1287                     dom, 'wavelength_max', data_info.source)         
1288        self._store_float('ns:SASinstrument/ns:SASsource/ns:wavelength_spread', 
1289                     dom, 'wavelength_spread', data_info.source)   
1290       
1291        # Beam size (as a vector)   
1292        entry = get_content('ns:SASinstrument/ns:SASsource/ns:beam_size', dom)
1293        if entry is not None:
1294            data_info.source.beam_size_name = entry.get('name')
1295           
1296        self._store_float('ns:SASinstrument/ns:SASsource/ns:beam_size/ns:x', 
1297                     dom, 'beam_size.x', data_info.source)   
1298        self._store_float('ns:SASinstrument/ns:SASsource/ns:beam_size/ns:y', 
1299                     dom, 'beam_size.y', data_info.source)   
1300        self._store_float('ns:SASinstrument/ns:SASsource/ns:beam_size/ns:z', 
1301                     dom, 'beam_size.z', data_info.source)   
1302       
1303        # Collimation info ###################
1304        nodes = dom.xpath('ns:SASinstrument/ns:SAScollimation', namespaces={'ns': CANSAS_NS})
1305        for item in nodes:
1306            collim = Collimation()
1307            if item.get('name') is not None:
1308                collim.name = item.get('name')
1309            self._store_float('ns:length', item, 'length', collim) 
1310           
1311            # Look for apertures
1312            apert_list = item.xpath('ns:aperture', namespaces={'ns': CANSAS_NS})
1313            for apert in apert_list:
1314                aperture =  Aperture()
1315               
1316                # Get the name and type of the aperture
1317                aperture.name = apert.get('name')
1318                aperture.type = apert.get('type')
1319                   
1320                self._store_float('ns:distance', apert, 'distance', aperture)   
1321               
1322                entry = get_content('ns:size', apert)
1323                if entry is not None:
1324                    aperture.size_name = entry.get('name')
1325               
1326                self._store_float('ns:size/ns:x', apert, 'size.x', aperture)   
1327                self._store_float('ns:size/ns:y', apert, 'size.y', aperture)   
1328                self._store_float('ns:size/ns:z', apert, 'size.z', aperture)
1329               
1330                collim.aperture.append(aperture)
1331               
1332            data_info.collimation.append(collim)
1333       
1334        # Detector info ######################
1335        nodes = dom.xpath('ns:SASinstrument/ns:SASdetector', namespaces={'ns': CANSAS_NS})
1336        for item in nodes:
1337           
1338            detector = Detector()
1339           
1340            self._store_content('ns:name', item, 'name', detector)
1341            self._store_float('ns:SDD', item, 'distance', detector)   
1342           
1343            # Detector offset (as a vector)
1344            self._store_float('ns:offset/ns:x', item, 'offset.x', detector)   
1345            self._store_float('ns:offset/ns:y', item, 'offset.y', detector)   
1346            self._store_float('ns:offset/ns:z', item, 'offset.z', detector)   
1347           
1348            # Detector orientation (as a vector)
1349            self._store_float('ns:orientation/ns:roll',  item, 'orientation.x', detector)   
1350            self._store_float('ns:orientation/ns:pitch', item, 'orientation.y', detector)   
1351            self._store_float('ns:orientation/ns:yaw',   item, 'orientation.z', detector)   
1352           
1353            # Beam center (as a vector)
1354            self._store_float('ns:beam_center/ns:x', item, 'beam_center.x', detector)   
1355            self._store_float('ns:beam_center/ns:y', item, 'beam_center.y', detector)   
1356            self._store_float('ns:beam_center/ns:z', item, 'beam_center.z', detector)   
1357           
1358            # Pixel size (as a vector)
1359            self._store_float('ns:pixel_size/ns:x', item, 'pixel_size.x', detector)   
1360            self._store_float('ns:pixel_size/ns:y', item, 'pixel_size.y', detector)   
1361            self._store_float('ns:pixel_size/ns:z', item, 'pixel_size.z', detector)   
1362           
1363            self._store_float('ns:slit_length', item, 'slit_length', detector)
1364           
1365            data_info.detector.append(detector)   
1366
1367        # Processes info ######################
1368        nodes = dom.xpath('ns:SASprocess', namespaces={'ns': CANSAS_NS})
1369        for item in nodes:
1370            process = Process()
1371            self._store_content('ns:name', item, 'name', process)
1372            self._store_content('ns:date', item, 'date', process)
1373            self._store_content('ns:description', item, 'description', process)
1374           
1375            term_list = item.xpath('ns:term', namespaces={'ns': CANSAS_NS})
1376            for term in term_list:
1377                try:
1378                    term_attr = {}
1379                    for attr in term.keys():
1380                        term_attr[attr] = term.get(attr).strip()
1381                    if term.text is not None:
1382                        term_attr['value'] = term.text.strip()
1383                        process.term.append(term_attr)
1384                except:
1385                    err_mess = "cansas_reader.read: error processing process term\n  %s" % sys.exc_value
1386                    self.errors.append(err_mess)
1387                    logging.error(err_mess)
1388           
1389            note_list = item.xpath('ns:SASprocessnote', namespaces={'ns': CANSAS_NS})
1390            for note in note_list:
1391                if note.text is not None:
1392                    process.notes.append(note.text.strip())
1393           
1394            data_info.process.append(process)
1395           
1396           
1397        # Data info ######################
1398        nodes = dom.xpath('ns:SASdata', namespaces={'ns': CANSAS_NS})
1399        if len(nodes)>1:
1400            raise RuntimeError, "CanSAS reader is not compatible with multiple SASdata entries"
1401       
1402        for entry in nodes:
1403            for item in list_of_data_2d_attr:
1404                #get node
1405                node = get_content('ns:%s'%item[0], entry)
1406                exec "data_info.%s = parse_entry_helper(node, item)"%(item[1])
1407                   
1408            for item in list_of_data2d_values:
1409                field = get_content('ns:%s'%item[0], entry)
1410                list = []
1411                if field is not None:
1412                    list = [parse_entry_helper(node, item) for node in field]
1413                exec "data_info.%s = numpy.array(list)"%item[0]
1414       
1415        return data_info
1416
1417    def _read_cansas(self, path):
1418        """
1419        Load data and P(r) information from a CanSAS XML file.
1420       
1421        :param path: file path
1422       
1423        :return: Data1D object if a single SASentry was found,
1424                    or a list of Data1D objects if multiple entries were found,
1425                    or None of nothing was found
1426                   
1427        :raise RuntimeError: when the file can't be opened
1428        :raise ValueError: when the length of the data vectors are inconsistent
1429       
1430        """
1431        output = []
1432        basename  = os.path.basename(path)
1433        root, extension = os.path.splitext(basename)
1434        ext = extension.lower()
1435        try:
1436            if os.path.isfile(path):
1437               
1438                #TODO: eventually remove the check for .xml once
1439                # the P(r) writer/reader is truly complete.
1440                if  ext in self.ext or \
1441                    ext == '.xml':
1442                   
1443                    tree = etree.parse(path, parser=etree.ETCompatXMLParser())
1444                    # Check the format version number
1445                    # Specifying the namespace will take care of the file format version
1446                    root = tree.getroot()
1447                    entry_list = root.xpath('ns:SASentry', namespaces={'ns': CANSAS_NS})
1448                    for entry in entry_list:   
1449                        try:
1450                            sas_entry = self._parse_entry(entry)
1451                        except:
1452                            raise
1453                        fitstate = self._parse_state(entry)
1454                       
1455                        #state could be None when .svs file is loaded
1456                        #in this case, skip appending to output
1457                        if fitstate != None:
1458                            sas_entry.meta_data['fitstate'] = fitstate
1459                            sas_entry.filename = fitstate.file
1460                            output.append(sas_entry)
1461            else:
1462                self.call_back(format=ext)
1463                raise RuntimeError, "%s is not a file" % path
1464
1465            # Return output consistent with the loader's api
1466            if len(output)==0:
1467                self.call_back(state=None, datainfo=None,format=ext)
1468                return None
1469            else:
1470                for ind in range(len(output)):
1471                    # Call back to post the new state
1472                    state = output[ind].meta_data['fitstate']
1473                    t = time.localtime(state.timestamp)
1474                    time_str = time.strftime("%b %d %H:%M", t)
1475                    # Check that no time stamp is already appended
1476                    max_char = state.file.find("[")
1477                    if max_char < 0:
1478                        max_char = len(state.file)
1479                    original_fname = state.file[0:max_char]
1480                    state.file = original_fname +' [' + time_str + ']'
1481                   
1482                       
1483                    if state is not None and state.is_data is not None:
1484                        exec 'output[%d].is_data = state.is_data'% ind
1485                     
1486                    output[ind].filename = state.file
1487                    state.data = output[ind]
1488                    state.data.name = output[ind].filename #state.data_name
1489                    state.data.id = state.data_id
1490                    if state.is_data is not None:
1491                        state.data.is_data = state.is_data
1492                    if output[ind].run_name is not None and len(output[ind].run_name) != 0 :
1493                        name = output[ind].run_name
1494                    else: 
1495                        name=original_fname
1496                    state.data.group_id = name
1497                    #store state in fitting
1498                    self.call_back(state=state, datainfo=output[ind],format=ext)
1499                    self.state= state
1500                return output
1501             
1502        except:
1503            self.call_back(format=ext)
1504            #self.state= state
1505            raise
1506           
1507    def write(self, filename, datainfo=None, fitstate=None):
1508        """
1509        Write the content of a Data1D as a CanSAS XML file only for standalone
1510       
1511        :param filename: name of the file to write
1512        :param datainfo: Data1D object
1513        :param fitstate: PageState object
1514       
1515        """
1516        # Sanity check
1517        if self.cansas == True:
1518           
1519            # Add fitting information to the XML document
1520            doc = self.write_toXML(datainfo, fitstate)
1521            # Write the XML document
1522            fd = open(filename, 'w')
1523            fd.write(doc.toprettyxml())
1524            fd.close()
1525        else:
1526            fitstate.toXML(file=filename)
1527       
1528    def write_toXML(self, datainfo=None, state=None):
1529        """
1530        Write toXML, a helper for write() , could be used by guimanager._on_save()
1531       
1532        : return: xml doc
1533        """
1534
1535        if state.data is None:
1536            data = sans.dataloader.data_info.Data1D(x=[], y=[]) 
1537        else: 
1538            #make sure title and data run is filled up.
1539            if state.data.title == None or state.data.title=='': state.data.title = state.data.name
1540            if state.data.run_name == None or state.data.run_name=={}: 
1541                state.data.run = [str(state.data.name)]
1542                state.data.run_name[0] = state.data.name
1543   
1544            if issubclass(state.data.__class__, sans.dataloader.data_info.Data1D):
1545
1546                data = state.data
1547                doc, sasentry = self._to_xml_doc(data)
1548            else:
1549                data = state.data
1550                doc, sasentry = self._data2d_to_xml_doc(data)
1551           
1552
1553        if state is not None:
1554            state.toXML(doc=doc, file=data.name, entry_node=sasentry)
1555           
1556        return doc
1557   
1558# Simple html report templet 
1559HEADER = "<html>\n"
1560HEADER += "<head>\n"
1561HEADER += "<meta http-equiv=Content-Type content='text/html; "
1562HEADER += "charset=windows-1252'> \n"
1563HEADER += "<meta name=Generator >\n"
1564HEADER += "</head>\n"
1565HEADER += "<body lang=EN-US>\n"
1566HEADER += "<div class=WordSection1>\n"
1567HEADER += "<p class=MsoNormal><b><span ><center>"
1568HEADER += "%s</center></span></center></b></p>"
1569HEADER += "<p class=MsoNormal>&nbsp;</p>"
1570PARA = "<p class=MsoNormal> %s \n"
1571PARA += "</p>"
1572CENTRE = "<center> %s \n"
1573CENTRE += "</center>"
1574FEET_1 = \
1575"""
1576<p class=MsoNormal><b><span ><center> Graph</span></center></b></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.