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

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

reducing pylint warnings

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