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

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

added custom weighting for single fit

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