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

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 0203ade was 2c44cf8, checked in by Jae Cho <jhjcho@…>, 12 years ago

found and fixed broken polydispersity set state/project file

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