source: sasview/sansview/perspectives/fitting/pagestate.py @ 04eb1a4

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 04eb1a4 was 90a7bbd, checked in by Gervaise Alina <gervyh@…>, 14 years ago

working save state

  • Property mode set to 100644
File size: 54.8 KB
RevLine 
[c77d859]1
2
[5062bbf]3################################################################################
4#This software was developed by the University of Tennessee as part of the
5#Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
6#project funded by the US National Science Foundation.
7#
8#See the license text in license.txt
9#
10#copyright 2009, University of Tennessee
11################################################################################
12
[11a7e11]13import time
14import os
15import sys
[6f023e8]16import copy
[11a7e11]17import logging
[df7ed14]18import numpy
[c77d859]19
[35b556d]20import xml.dom.minidom
[11a7e11]21from xml.dom.minidom import parse
22from lxml import etree
23
24import DataLoader
[61cada5]25from DataLoader.readers.cansas_reader import Reader as CansasReader
[e9b12eaf]26from DataLoader.readers.cansas_reader import get_content, write_node
[df7ed14]27from DataLoader.data_info import Data2D, Detector
[61cada5]28
[11a7e11]29#Information to read/write state as xml
[61cada5]30FITTING_NODE_NAME = 'fitting_plug_in'
31CANSAS_NS = "cansas1d/1.0"
32
[26f3dd5]33list_of_data_attributes = [["is_data", "is_data", "bool"],
[61cada5]34                      ["group_id", "data_group_id", "string"],
35                      ["data_name", "data_name", "string"],
36                      ["data_id", "data_id", "string"],
37                      ["name", "name", "string"],
[26f3dd5]38                      ["data_name", "data_name", "string"]]
[e3d1423]39list_of_state_attributes = [["engine_type", "engine_type", "string"],
40                       ["qmin", "qmin", "float"],
[61cada5]41                      ["qmax", "qmax", "float"],
42                      ["npts", "npts", "float"],
43                      ["shape_rbutton", "shape_rbutton", "bool"],
44                      ["shape_indep_rbutton", "shape_indep_rbutton", "bool"],
45                      ["plugin_rbutton", "plugin_rbutton","bool"],
46                      ["struct_rbutton", "struct_rbutton", "bool"],
[0b12abb5]47                      ["formfactorcombobox", "formfactorcombobox", "float"],
48                      ["structurecombobox", "structurecombobox", "float"],
49                      ["disp_box", "disp_box", "float"],
[26f3dd5]50                      ["enable_smearer","enable_smearer","bool"],
51                      ["disable_smearer","disable_smearer","bool"],
52                      ["pinhole_smearer","pinhole_smearer","bool"],
53                      ["slit_smearer","slit_smearer","bool"],
54                      ["enable_disp","enable_disp","bool"],
55                      ["disable_disp","disable_disp","bool"],
56                      ["slit_smearer","slit_smearer","bool"],
57                      ["enable2D","enable2D","bool"],
58                      ["cb1","cb1","bool"],
[5cc7001]59                      ["tcChi","tcChi","float"],
60                     ["smearer", "smearer", "float"],
61                     ["smear_type","smear_type", "string"],
62                     ["dq_l", "dq_l", "string"],
63                     ["dq_r","dq_r", "string"]]
64
[11a7e11]65list_of_model_attributes = [["values", "values"],
66                            ["weights", "weights"]]
67
[fb59ed9]68list_of_state_parameters = [["parameters", "parameters"] , 
69                            ["str_parameters", "str_parameters"] ,                     
[61cada5]70                            ["orientation_parameters", "orientation_params"],
71                            ["dispersity_parameters", "orientation_params_disp"],
72                            ["fixed_param", "fixed_param"],                     
73                            ["fittable_param","fittable_param"]]
[df7ed14]74list_of_data_2d_attr = [["xmin", "xmin","float"],
75                        ["xmax","xmax","float"],
76                        ["ymin","ymin","float"],
77                        ["ymax","ymax","float"],
78                        ["_xaxis","_xaxis", "string"],
79                        ["_xunit", "_xunit", "string"],
80                        ["_yaxis","_yaxis","string"],
81                        ["_yunit","_yunit","string"],
82                        ["_zaxis","_zaxis","string"],
83                        ["_zunit","_zunit","string"]]
84list_of_data2d_values = [["qx_data","qx_data","float"],
85                         ["qy_data","qy_data","float"],
86                         ["dqx_data","dqx_data","float"],
87                         ["dqy_data","dqy_data","float"],
88                         ["data","data","float"],
89                         ["q_data","q_data","float"],
90                         ["err_data","err_data","float"],
91                         ["mask","mask","bool"]]
[61cada5]92
[0b12abb5]93def parse_entry_helper( node, item):
94    """
95    Create a numpy list from value extrated from the node
96   
97    :param node: node from each the value is stored
98    :param item: list name of three strings.the two first are name of data
99        attribute and the third one is the type of the value of that
100        attribute. type can be string, float, bool, etc.
101   
102    : return: numpy array
103    """
104    if node is not None:
105        if item[2] == "string":
106            return str(node.get(item[0]).strip())
107        elif item[2] == "bool":
108            try:
[e3d1423]109                return node.get(item[0]).strip() == "True"
110               
[0b12abb5]111            except:
112                return None
113        else:
114            try:
115                return float(node.get(item[0]))
116            except:
117                return None
118           
119           
[cfc0913]120class PageState(object):
[c77d859]121    """
[5062bbf]122    Contains information to reconstruct a page of the fitpanel.
[c77d859]123    """
[61cada5]124    def __init__(self, parent=None, model=None, data=None):
[c77d859]125       
126        """
[5062bbf]127        Initialize the current state
128       
129        :param model: a selected model within a page
130        :param data:
131       
[c77d859]132        """
[61cada5]133        self.file = None
[11a7e11]134        #Time of state creation
135        self.timestamp = time.time()
[c77d859]136        ## Data member to store the dispersion object created
137        self._disp_obj_dict = {}
[61cada5]138        #------------------------
[c77d859]139        #Data used for fitting
140        self.data = data
[61cada5]141        #save additional information on data that dataloader.reader does not read
142        self.is_data = None
143        self.data_name = ""
144       
145        if self.data is not None:
146            self.data_name = self.data.name
147        self.data_id = None
148        if self.data is not None and hasattr(self.data, "id"):
149            self.data_id = self.data.id
150        self.data_group_id = None
151        if self.data is not None and hasattr(self.data, "group_id"):
152            self.data_group_id = self.data.group_id
[0b12abb5]153       
[61cada5]154        ## reset True change the state of exsiting button
155        self.reset = False
156       
[c99a6c5]157        #engine type
158        self.engine_type = None
[c77d859]159        # flag to allow data2D plot
[cfc0913]160        self.enable2D = False
[c77d859]161        # model on which the fit would be performed
162        self.model = model
[61cada5]163       
[c77d859]164        #fit page manager
165        self.manager = None
166        #Store the parent of this panel parent
167        # For this application fitpanel is the parent
168        self.parent  = parent
169        # Event_owner is the owner of model event
170        self.event_owner = None
[c9a4377]171        ##page name
[cfc0913]172        self.page_name = ""
[c77d859]173        # Contains link between  model ,all its parameters, and panel organization
[61cada5]174        self.parameters = []
[fb59ed9]175        # String parameter list that can not be fitted
176        self.str_parameters = []
[c77d859]177        # Contains list of parameters that cannot be fitted and reference to
178        #panel objects
[61cada5]179        self.fixed_param = []
[c77d859]180        # Contains list of parameters with dispersity and reference to
181        #panel objects
[61cada5]182        self.fittable_param = []
[60132ef]183        ## orientation parameters
[61cada5]184        self.orientation_params = []
[fc6ea43]185        ## orientation parmaters for gaussian dispersity
[61cada5]186        self.orientation_params_disp = []
[3370922]187        ## smearer info
[61cada5]188        self.smearer = None
[7609f1a]189        self.smear_type = None
190        self.dq_l = None
191        self.dq_r = None
192
[c77d859]193        #list of dispersion paramaters
[cfc0913]194        self.disp_list =[]
[61cada5]195        if self.model is not None:
[71f0373]196            self.disp_list = self.model.getDispParamList()
[61cada5]197        self._disp_obj_dict = {}
198        self.disp_cb_dict = {}
199        self.values = []
200        self.weights = []
[dad49a0]201                   
[c77d859]202        #contains link between a model and selected parameters to fit
[61cada5]203        self.param_toFit = []
[a074145]204        ##dictionary of model type and model class
[cfc0913]205        self.model_list_box = None
[a074145]206        ## save the state of the context menu
[61cada5]207        self.saved_states = {}
[240b9966]208        ## save selection of combobox
[3b9e023]209        self.formfactorcombobox = None
210        self.structurecombobox  = None
[240b9966]211        ## radio box to select type of model
212        self.shape_rbutton = False
213        self.shape_indep_rbutton = False
214        self.struct_rbutton = False
215        self.plugin_rbutton = False
[b787e68c]216        ## the indice of the current selection
217        self.disp_box = 0
[c77d859]218        ## Qrange
[cfc0913]219        ## Q range
[61cada5]220        self.qmin = 0.001
221        self.qmax = 0.1
[0b12abb5]222        #reset data range
223        self.qmax_x = None
224        self.qmin_x = None
225       
[cfc0913]226        self.npts = None
[61cada5]227        self.name = ""
[4523b68]228        self.multi_factor = None
[cfc0913]229        ## enable smearering state
230        self.enable_smearer = False
[fc6ea43]231        self.disable_smearer = True
[7609f1a]232        self.pinhole_smearer = False
233        self.slit_smearer   = False
[cfc0913]234        ## disperity selection
[61cada5]235        self.enable_disp = False
236        self.disable_disp = True
[11a7e11]237       
[cfc0913]238        ## state of selected all check button
239        self.cb1 = False
[0aeabc6]240        ## store value of chisqr
[61cada5]241        self.tcChi = None
[240b9966]242   
[6f023e8]243    def clone(self):
[61cada5]244        """
[5062bbf]245        Create a new copy of the current object
[61cada5]246        """
247        model = None
248        if self.model is not None:
[6f023e8]249            model = self.model.clone()
[bb70474]250            model.name = self.model.name
[61cada5]251        obj = PageState(self.parent, model=model)
252        obj.file = copy.deepcopy(self.file)
[6f023e8]253        obj.data = copy.deepcopy(self.data)
[61cada5]254        if self.data is not None:
255            self.data_name = self.data.name
256        obj.data_name = self.data_name
257        obj.is_data = self.is_data
[dcf29d7]258        obj.model_list_box = copy.deepcopy(self.model_list_box)
[c99a6c5]259        obj.engine_type = copy.deepcopy(self.engine_type)
[240b9966]260       
[61cada5]261        obj.formfactorcombobox = self.formfactorcombobox
262        obj.structurecombobox  = self.structurecombobox 
[240b9966]263       
264        obj.shape_rbutton = self.shape_rbutton
265        obj.shape_indep_rbutton = self.shape_indep_rbutton
266        obj.struct_rbutton = self.struct_rbutton
267        obj.plugin_rbutton = self.plugin_rbutton
268       
[dcf29d7]269        obj.manager = self.manager
270        obj.event_owner = self.event_owner
[71f0373]271        obj.disp_list = copy.deepcopy(self.disp_list)
[fc6ea43]272       
[c477b31]273        obj.enable2D = copy.deepcopy(self.enable2D)
[cfc0913]274        obj.parameters = copy.deepcopy(self.parameters)
[fb59ed9]275        obj.str_parameters = copy.deepcopy(self.str_parameters)
[cfc0913]276        obj.fixed_param = copy.deepcopy(self.fixed_param)
277        obj.fittable_param = copy.deepcopy(self.fittable_param)
[60132ef]278        obj.orientation_params =  copy.deepcopy(self.orientation_params)
[fc6ea43]279        obj.orientation_params_disp =  copy.deepcopy(self.orientation_params_disp)
[b787e68c]280        obj.enable_disp = copy.deepcopy(self.enable_disp)
[fc6ea43]281        obj.disable_disp = copy.deepcopy(self.disable_disp)
[0aeabc6]282        obj.tcChi = self.tcChi
283 
[c477b31]284        if len(self._disp_obj_dict)>0:
285            for k , v in self._disp_obj_dict.iteritems():
286                obj._disp_obj_dict[k]= v
[dad49a0]287        if len(self.disp_cb_dict)>0:
288            for k , v in self.disp_cb_dict.iteritems():
289                obj.disp_cb_dict[k]= v
[b421b1a]290               
[dad49a0]291        obj.values = copy.deepcopy(self.values)
292        obj.weights = copy.deepcopy(self.weights)
[b787e68c]293        obj.enable_smearer = copy.deepcopy(self.enable_smearer)
[fc6ea43]294        obj.disable_smearer = copy.deepcopy(self.disable_smearer)
[7609f1a]295        obj.pinhole_smearer = copy.deepcopy(self.pinhole_smearer)
296        obj.slit_smearer = copy.deepcopy(self.slit_smearer)
297        obj.smear_type = copy.deepcopy(self.smear_type)
298        obj.dq_l = copy.deepcopy(self.dq_l)
299        obj.dq_r = copy.deepcopy(self.dq_r)
300
[b787e68c]301        obj.disp_box = copy.deepcopy(self.disp_box)
302        obj.qmin = copy.deepcopy(self.qmin)
303        obj.qmax = copy.deepcopy(self.qmax)
[4523b68]304        obj.multi_factor = copy.deepcopy(self.multi_factor)
[b787e68c]305        obj.npts = copy.deepcopy(self.npts )
306        obj.cb1 = copy.deepcopy(self.cb1)
[3370922]307        obj.smearer = copy.deepcopy(self.smearer)
308       
[a074145]309        for name, state in self.saved_states.iteritems():
310            copy_name = copy.deepcopy(name)
311            copy_state = state.clone()
312            obj.saved_states[copy_name]= copy_state
[6f023e8]313        return obj
[61cada5]314   
315    def _repr_helper(self, list, rep):
316        """
[5062bbf]317        Helper method to print a state
[61cada5]318        """
319        for item in list:
[240b9966]320            rep += "parameter name: %s \n"%str(item[1])
321            rep += "value: %s\n"%str(item[2])
322            rep += "selected: %s\n"%str(item[0])
323            rep += "error displayed : %s \n"%str(item[4][0])
324            rep += "error value:%s \n"%str(item[4][1])
325            rep += "minimum displayed : %s \n"%str(item[5][0])
326            rep += "minimum value : %s \n"%str(item[5][1])
327            rep += "maximum displayed : %s \n"%str(item[6][0])
328            rep += "maximum value : %s \n"%str(item[6][1])
329            rep += "parameter unit: %s\n\n"%str(item[7])
330        return rep
[61cada5]331   
332    def __repr__(self):
[11a7e11]333        """
[5062bbf]334        output string for printing
[11a7e11]335        """
336        rep = "\nState name: %s\n"%self.file
337        t = time.localtime(self.timestamp)
338        time_str = time.strftime("%b %d %H:%M", t)
339        rep += "State created on : %s\n"%time_str
340        rep += "State form factor combobox selection: %s\n"%self.formfactorcombobox
341        rep += "State structure factor combobox selection: %s\n"%self.structurecombobox
342        rep += "is data : %s\n"%self.is_data
343        rep += "data's name : %s\n"%self.data_name
344        rep += "data's id : %s\n"%self.data_id
345        rep += "model type (form factor) selected: %s\n"%self.shape_rbutton
346        rep += "model type (shape independent) selected: %s\n"%self.shape_indep_rbutton
347        rep += "model type (structure factor) selected: %s\n"%self.struct_rbutton
348        rep += "model type (plug-in ) selected: %s\n"%self.plugin_rbutton
349        rep += "data : %s\n"% str(self.data)
350        rep += "Plotting Range: min: %s, max: %s, steps: %s\n"%(str(self.qmin),
351                                                str(self.qmax),str(self.npts))
[0b12abb5]352        rep += "Dispersion selection : %s\n"%str(self.disp_box)
353        rep += "Smearing enable : %s\n"%str(self.enable_smearer)
354        rep += "Smearing disable : %s\n"%str(self.disable_smearer)
355        rep += "Pinhole smearer enable : %s\n"%str(self.pinhole_smearer)
356        rep += "Slit smearer enable : %s\n"%str(self.slit_smearer)
357        rep += "Dispersity enable : %s\n"%str(self.enable_disp)
358        rep += "Dispersity disable : %s\n"%str(self.disable_disp)
359        rep += "Slit smearer enable: %s\n"%str(self.slit_smearer)
360        rep += "2D enable : %s\n"%str(self.enable2D)
361        rep += "All parameters checkbox selected: %s\n"%(self.cb1)
362        rep += "Value of Chisqr : %s\n"%str(self.tcChi)
363        rep += "Smear object : %s\n"%str(self.smearer)
364        rep += "Smear type : %s\n"%(self.smear_type)
365        rep += "dq_l  : %s\n"%self.dq_l
366        rep += "dq_r  : %s\n"%self.dq_r
367       
[11a7e11]368        rep += "model  : %s\n\n"% str(self.model)
369        rep += "number parameters(self.parameters): %s\n"%len(self.parameters)
[3c44c66]370        rep = self._repr_helper( list=self.parameters, rep=rep)
[fb59ed9]371        rep += "number str_parameters(self.str_parameters): %s\n"%len(self.str_parameters)
372        rep = self._repr_helper( list=self.str_parameters, rep=rep)
[11a7e11]373        rep += "number orientation parameters"
374        rep += "(self.orientation_params): %s\n"%len(self.orientation_params)
[3c44c66]375        rep = self._repr_helper( list=self.orientation_params, rep=rep)
[11a7e11]376        rep += "number dispersity parameters"
377        rep += "(self.orientation_params_disp): %s\n"%len(self.orientation_params_disp)
[3c44c66]378        rep = self._repr_helper( list=self.orientation_params_disp, rep=rep)
[0b12abb5]379       
[61cada5]380        return rep
381   
382    def _toXML_helper(self, list, element, newdoc):
383        """
[5062bbf]384        Helper method to create xml file for saving state
[61cada5]385        """
386        for item in list:
387            sub_element = newdoc.createElement('parameter')
388            sub_element.setAttribute('name', str(item[1]))
389            sub_element.setAttribute('value', str(item[2]))
390            sub_element.setAttribute('selected_to_fit', str(item[0]))
391            sub_element.setAttribute('error_displayed', str(item[4][0]))
392            sub_element.setAttribute('error_value', str(item[4][1]))
393            sub_element.setAttribute('minimum_displayed', str(item[5][0]))
394            sub_element.setAttribute('minimum_value', str(item[5][1]))
395            sub_element.setAttribute('maximum_displayed', str(item[6][0]))
396            sub_element.setAttribute('maximum_value', str(item[6][1]))
397            sub_element.setAttribute('unit', str(item[7]))
398            element.appendChild(sub_element)
399       
400    def toXML(self, file="fitting_state.fitv", doc=None, entry_node=None):
401        """
[5062bbf]402        Writes the state of the InversionControl panel to file, as XML.
403       
404        Compatible with standalone writing, or appending to an
405        already existing XML document. In that case, the XML document
406        is required. An optional entry node in the XML document may also be given.
407       
408        :param file: file to write to
409        :param doc: XML document object [optional]
410        :param entry_node: XML node within the XML document at which we will append the data [optional]
411       
[61cada5]412        """
413        from xml.dom.minidom import getDOMImplementation
[71f0373]414
[61cada5]415        # Check whether we have to write a standalone XML file
416        if doc is None:
417            impl = getDOMImplementation()
418            doc_type = impl.createDocumentType(FITTING_NODE_NAME, "1.0", "1.0")     
419            newdoc = impl.createDocument(None, FITTING_NODE_NAME, doc_type)
420            top_element = newdoc.documentElement
421        else:
422            # We are appending to an existing document
423            newdoc = doc
424            top_element = newdoc.createElement(FITTING_NODE_NAME)
425            if entry_node is None:
426                newdoc.documentElement.appendChild(top_element)
427            else:
428                entry_node.appendChild(top_element)
429           
430        attr = newdoc.createAttribute("version")
431        attr.nodeValue = '1.0'
432        top_element.setAttributeNode(attr)
[cfc0913]433       
[61cada5]434        # File name
435        element = newdoc.createElement("filename")
436        if self.file is not None:
437            element.appendChild(newdoc.createTextNode(str(self.file)))
438        else:
439            element.appendChild(newdoc.createTextNode(str(file)))
440        top_element.appendChild(element)
[11a7e11]441       
442        element = newdoc.createElement("timestamp")
443        element.appendChild(newdoc.createTextNode(time.ctime(self.timestamp)))
444        attr = newdoc.createAttribute("epoch")
445        attr.nodeValue = str(self.timestamp)
446        element.setAttributeNode(attr)
447        top_element.appendChild(element)
[61cada5]448        # Inputs
449        inputs = newdoc.createElement("Attributes")
450        top_element.appendChild(inputs)
451       
[0b12abb5]452
[61cada5]453        if self.data is not None and hasattr(self.data, "group_id"):
454            self.data_group_id = self.data.group_id
455        if self.data is not None and hasattr(self.data, "is_data"):
456            self.is_data = self.data.is_data
457        if self.data is not None:
458            self.data_name = self.data.name
459        if self.data is not None and hasattr(self.data, "id"):
460            self.data_id = self.data.id
461       
[26f3dd5]462        for item in list_of_data_attributes:
[0b12abb5]463            element = newdoc.createElement(item[0])
[61cada5]464            exec "element.setAttribute(item[0], str(self.%s))"%(item[1])
[0b12abb5]465            inputs.appendChild(element)   
[26f3dd5]466       
467        for item in list_of_state_attributes:
468            element = newdoc.createElement(item[0])
469            exec "element.setAttribute(item[0], str(self.%s))"%(item[1])
470            inputs.appendChild(element)
[11a7e11]471           
472        for item in list_of_model_attributes:
473            element = newdoc.createElement(item[0])
474            exec "list = self.%s"%item[1]
[e9b12eaf]475            for value in list:
[0b12abb5]476                exec "element.appendChild(newdoc.createTextNode(str(%s)))"%value
[11a7e11]477            inputs.appendChild(element)
478           
[61cada5]479        for item in list_of_state_parameters:
480            element = newdoc.createElement(item[0])
481            exec "self._toXML_helper(list=self.%s, element=element, newdoc=newdoc)"%item[1]                       
482            inputs.appendChild(element)
483       
484        # Save the file
485        if doc is None:
486            fd = open(file, 'w')
487            fd.write(newdoc.toprettyxml())
488            fd.close()
489            return None
490        else:
491            return newdoc.toprettyxml()
492       
493    def _fromXML_helper(self, node, list):
494        """
[5062bbf]495        Helper function to write state to xml
[61cada5]496        """
497        for item in node:
[0b12abb5]498            try:
499                name = item.get('name')
500            except:
501                name = None
502            try:
503                value = item.get('value')
504            except:
505                value = None
506            try:
[3ad91de]507                selected_to_fit = (item.get('selected_to_fit') == "True")
[0b12abb5]508            except:
509                selected_to_fit = None
510            try:
[3ad91de]511                error_displayed = (item.get('error_displayed') == "True")
[0b12abb5]512            except:
513                error_displayed = None
514            try: 
515                error_value = item.get('error_value')
516            except:
517                error_value = None
518            try:
[3ad91de]519                minimum_displayed = (item.get('minimum_displayed')== "True")
[0b12abb5]520            except:
521                minimum_displayed = None
522            try:
523                minimum_value = item.get('minimum_value')
524            except:
525                minimum_value = None
526            try:
[3ad91de]527                maximum_displayed = (item.get('maximum_displayed') == "True")
[0b12abb5]528            except:
529                maximum_displayed = None
530            try:
531                maximum_value = item.get('maximum_value')
532            except:
533                maximum_value = None
534            try:
535                unit = item.get('unit')
536            except:
537                unit = None
[61cada5]538            list.append([selected_to_fit, name, value, "+/-",[error_displayed, error_value],
539                         [minimum_displayed,minimum_value],[maximum_displayed,maximum_value], unit])
[cfc0913]540       
[61cada5]541    def fromXML(self, file=None, node=None):
542        """
[5062bbf]543        Load fitting state from a file
544       
545        :param file: .fitv file
546        :param node: node of a XML document to read from
547       
[61cada5]548        """
549        if file is not None:
[11a7e11]550            msg = "PageState no longer supports non-CanSAS"
551            msg += " format for fitting files"
552            raise RuntimeError, msg
[61cada5]553           
[11a7e11]554        if node.get('version')and node.get('version') == '1.0':
[61cada5]555           
556            # Get file name
557            entry = get_content('ns:filename', node)
558            if entry is not None:
559                self.file = entry.text.strip()
[11a7e11]560               
561            # Get time stamp
562            entry = get_content('ns:timestamp', node)
563            if entry is not None and entry.get('epoch'):
564                try:
565                    self.timestamp = float(entry.get('epoch'))
566                except:
567                    msg = "PageState.fromXML: Could not"
568                    msg += " read timestamp\n %s" % sys.exc_value
569                    logging.error(msg)
570           
[61cada5]571            # Parse fitting attributes
572            entry = get_content('ns:Attributes', node)
[0b12abb5]573            for item in list_of_data_attributes:
574                node = get_content('ns:%s'%item[0], entry)
575                try:
576                    exec "self.%s = parse_entry_helper(node, item)"%item[0]
577                   
578                except:
579                    raise
580           
[61cada5]581            if entry is not None:
[0b12abb5]582               
[61cada5]583                for item in list_of_state_attributes:
[0b12abb5]584                    node = get_content('ns:%s'%item[0], entry)
585                    try:
586                        exec "self.%s = parse_entry_helper(node, item)"%str(item[0])
587                    except:
588                        raise
589                   
[11a7e11]590                for item in list_of_model_attributes:
591                    node = get_content("ns:%s"%item[0], entry)
592                    list = []
593                    for value in node:
594                        try:
595                            list.append(float(value)) 
596                        except:
597                            list.append(None)
598                    exec "self.%s = list"%item[1]
[0b12abb5]599               
[61cada5]600                for item in list_of_state_parameters:
[11a7e11]601                    node = get_content("ns:%s"%item[0], entry)
[0b12abb5]602                    exec "self._fromXML_helper(node=node, list=self.%s)"%item[1]
603                   
[61cada5]604
605class Reader(CansasReader):
606    """
[5062bbf]607    Class to load a .fitv fitting file
[61cada5]608    """
609    ## File type
610    type_name = "Fitting"
611   
612    ## Wildcards
[b35d3d1]613    type = ["Fitting files (*.fitv)|*.fitv"
614            "SANSView file (*.svs)|*.svs"]
[61cada5]615    ## List of allowed extensions
[b35d3d1]616    ext=['.fitv', '.FITV', '.svs', 'SVS']   
[61cada5]617   
618    def __init__(self, call_back=None, cansas=True):
[df7ed14]619        CansasReader.__init__(self)
[61cada5]620        """
[5062bbf]621        Initialize the call-back method to be called
622        after we load a file
623       
624        :param call_back: call-back method
625        :param cansas:  True = files will be written/read in CanSAS format
626                        False = write CanSAS format
[61cada5]627           
628        """
629        ## Call back method to be executed after a file is read
630        self.call_back = call_back
631        ## CanSAS format flag
632        self.cansas = cansas
[75fbd17]633        self.state = None
634    def get_state(self):
635        return self.state
[61cada5]636       
637    def read(self, path):
638        """
[5062bbf]639        Load a new P(r) inversion state from file
640       
641        :param path: file path
642       
[61cada5]643        """
[e9b12eaf]644        if self.cansas == True:
[61cada5]645            return self._read_cansas(path)
[e9b12eaf]646     
647    def _data2d_to_xml_doc(self, datainfo):
[61cada5]648        """
[5062bbf]649        Create an XML document to contain the content of a Data2D
650       
651        :param datainfo: Data2D object
652       
[61cada5]653        """
654        if not issubclass(datainfo.__class__, Data2D):
655            raise RuntimeError, "The cansas writer expects a Data2D instance"
656       
657        doc = xml.dom.minidom.Document()
658        main_node = doc.createElement("SASroot")
659        main_node.setAttribute("version", self.version)
[df7ed14]660        main_node.setAttribute("xmlns", "cansas1d/%s" % self.version)
661        main_node.setAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance")
662        main_node.setAttribute("xsi:schemaLocation", "cansas1d/%s http://svn.smallangles.net/svn/canSAS/1dwg/trunk/cansas1d.xsd" % self.version)
663       
[61cada5]664        doc.appendChild(main_node)
665       
666        entry_node = doc.createElement("SASentry")
667        main_node.appendChild(entry_node)
[df7ed14]668       
[61cada5]669        write_node(doc, entry_node, "Title", datainfo.title)
[df7ed14]670        if datainfo is not None:
671            write_node(doc, entry_node, "data_class", datainfo.__class__.__name__)
[61cada5]672        for item in datainfo.run:
673            runname = {}
674            if datainfo.run_name.has_key(item) and len(str(datainfo.run_name[item]))>1:
675                runname = {'name': datainfo.run_name[item] }
676            write_node(doc, entry_node, "Run", item, runname)
677        # Data info
[df7ed14]678        new_node = doc.createElement("SASdata")
679        entry_node.appendChild(new_node)
[e9b12eaf]680        for item in list_of_data_2d_attr:
681            element = doc.createElement(item[0])
682            exec "element.setAttribute(item[0], str(datainfo.%s))"%(item[1])
[df7ed14]683            new_node.appendChild(element)
684           
[e9b12eaf]685        for item in list_of_data2d_values:
[df7ed14]686            root_node = doc.createElement(item[0])
687            new_node.appendChild(root_node)
688           
[35b556d]689            exec "temp_list = datainfo.%s"%item[1]
[df7ed14]690
[35b556d]691            if temp_list is None or len(temp_list)== 0:
[df7ed14]692                element = doc.createElement(item[0])
[35b556d]693                exec "element.appendChild(doc.createTextNode(str(%s)))"%temp_list
[df7ed14]694                root_node.appendChild(element)
[35b556d]695            else:
696                for value in temp_list:
[df7ed14]697                    element = doc.createElement(item[0])
698                    exec "element.setAttribute(item[0], str(%s))"%value
699                    root_node.appendChild(element)
700       
[61cada5]701        # Sample info
702        sample = doc.createElement("SASsample")
703        if datainfo.sample.name is not None:
704            sample.setAttribute("name", str(datainfo.sample.name))
705        entry_node.appendChild(sample)
706        write_node(doc, sample, "ID", str(datainfo.sample.ID))
707        write_node(doc, sample, "thickness", datainfo.sample.thickness, {"unit":datainfo.sample.thickness_unit})
708        write_node(doc, sample, "transmission", datainfo.sample.transmission)
709        write_node(doc, sample, "temperature", datainfo.sample.temperature, {"unit":datainfo.sample.temperature_unit})
710       
711        for item in datainfo.sample.details:
712            write_node(doc, sample, "details", item)
713       
714        pos = doc.createElement("position")
715        written = write_node(doc, pos, "x", datainfo.sample.position.x, {"unit":datainfo.sample.position_unit})
716        written = written | write_node(doc, pos, "y", datainfo.sample.position.y, {"unit":datainfo.sample.position_unit})
717        written = written | write_node(doc, pos, "z", datainfo.sample.position.z, {"unit":datainfo.sample.position_unit})
718        if written == True:
719            sample.appendChild(pos)
720       
721        ori = doc.createElement("orientation")
722        written = write_node(doc, ori, "roll",  datainfo.sample.orientation.x, {"unit":datainfo.sample.orientation_unit})
723        written = written | write_node(doc, ori, "pitch", datainfo.sample.orientation.y, {"unit":datainfo.sample.orientation_unit})
724        written = written | write_node(doc, ori, "yaw",   datainfo.sample.orientation.z, {"unit":datainfo.sample.orientation_unit})
725        if written == True:
726            sample.appendChild(ori)
727       
728        # Instrument info
729        instr = doc.createElement("SASinstrument")
730        entry_node.appendChild(instr)
731       
732        write_node(doc, instr, "name", datainfo.instrument)
733       
734        #   Source
735        source = doc.createElement("SASsource")
736        if datainfo.source.name is not None:
737            source.setAttribute("name", str(datainfo.source.name))
738        instr.appendChild(source)
739       
740        write_node(doc, source, "radiation", datainfo.source.radiation)
741        write_node(doc, source, "beam_shape", datainfo.source.beam_shape)
742        size = doc.createElement("beam_size")
743        if datainfo.source.beam_size_name is not None:
744            size.setAttribute("name", str(datainfo.source.beam_size_name))
745        written = write_node(doc, size, "x", datainfo.source.beam_size.x, {"unit":datainfo.source.beam_size_unit})
746        written = written | write_node(doc, size, "y", datainfo.source.beam_size.y, {"unit":datainfo.source.beam_size_unit})
747        written = written | write_node(doc, size, "z", datainfo.source.beam_size.z, {"unit":datainfo.source.beam_size_unit})
748        if written == True:
749            source.appendChild(size)
750           
751        write_node(doc, source, "wavelength", datainfo.source.wavelength, {"unit":datainfo.source.wavelength_unit})
752        write_node(doc, source, "wavelength_min", datainfo.source.wavelength_min, {"unit":datainfo.source.wavelength_min_unit})
753        write_node(doc, source, "wavelength_max", datainfo.source.wavelength_max, {"unit":datainfo.source.wavelength_max_unit})
754        write_node(doc, source, "wavelength_spread", datainfo.source.wavelength_spread, {"unit":datainfo.source.wavelength_spread_unit})
755       
756        #   Collimation
757        for item in datainfo.collimation:
758            coll = doc.createElement("SAScollimation")
759            if item.name is not None:
760                coll.setAttribute("name", str(item.name))
761            instr.appendChild(coll)
762           
763            write_node(doc, coll, "length", item.length, {"unit":item.length_unit})
764           
765            for apert in item.aperture:
766                ap = doc.createElement("aperture")
767                if apert.name is not None:
768                    ap.setAttribute("name", str(apert.name))
769                if apert.type is not None:
770                    ap.setAttribute("type", str(apert.type))
771                coll.appendChild(ap)
772               
773                write_node(doc, ap, "distance", apert.distance, {"unit":apert.distance_unit})
774               
775                size = doc.createElement("size")
776                if apert.size_name is not None:
777                    size.setAttribute("name", str(apert.size_name))
778                written = write_node(doc, size, "x", apert.size.x, {"unit":apert.size_unit})
779                written = written | write_node(doc, size, "y", apert.size.y, {"unit":apert.size_unit})
780                written = written | write_node(doc, size, "z", apert.size.z, {"unit":apert.size_unit})
781                if written == True:
782                    ap.appendChild(size)
783
784        #   Detectors
785        for item in datainfo.detector:
786            det = doc.createElement("SASdetector")
787            written = write_node(doc, det, "name", item.name)
788            written = written | write_node(doc, det, "SDD", item.distance, {"unit":item.distance_unit})
789            written = written | write_node(doc, det, "slit_length", item.slit_length, {"unit":item.slit_length_unit})
790            if written == True:
791                instr.appendChild(det)
792           
793            off = doc.createElement("offset")
794            written = write_node(doc, off, "x", item.offset.x, {"unit":item.offset_unit})
795            written = written | write_node(doc, off, "y", item.offset.y, {"unit":item.offset_unit})
796            written = written | write_node(doc, off, "z", item.offset.z, {"unit":item.offset_unit})
797            if written == True:
798                det.appendChild(off)
799           
800            center = doc.createElement("beam_center")
801            written = write_node(doc, center, "x", item.beam_center.x, {"unit":item.beam_center_unit})
802            written = written | write_node(doc, center, "y", item.beam_center.y, {"unit":item.beam_center_unit})
803            written = written | write_node(doc, center, "z", item.beam_center.z, {"unit":item.beam_center_unit})
804            if written == True:
805                det.appendChild(center)
806               
807            pix = doc.createElement("pixel_size")
808            written = write_node(doc, pix, "x", item.pixel_size.x, {"unit":item.pixel_size_unit})
809            written = written | write_node(doc, pix, "y", item.pixel_size.y, {"unit":item.pixel_size_unit})
810            written = written | write_node(doc, pix, "z", item.pixel_size.z, {"unit":item.pixel_size_unit})
811            if written == True:
812                det.appendChild(pix)
813               
814            ori = doc.createElement("orientation")
815            written = write_node(doc, ori, "roll",  item.orientation.x, {"unit":item.orientation_unit})
816            written = written | write_node(doc, ori, "pitch", item.orientation.y, {"unit":item.orientation_unit})
817            written = written | write_node(doc, ori, "yaw",   item.orientation.z, {"unit":item.orientation_unit})
818            if written == True:
819                det.appendChild(ori)
820               
821        # Processes info
822        for item in datainfo.process:
823            node = doc.createElement("SASprocess")
824            entry_node.appendChild(node)
825
826            write_node(doc, node, "name", item.name)
827            write_node(doc, node, "date", item.date)
828            write_node(doc, node, "description", item.description)
829            for term in item.term:
830                value = term['value']
831                del term['value']
832                write_node(doc, node, "term", value, term)
833            for note in item.notes:
834                write_node(doc, node, "SASprocessnote", note)
835        # Return the document, and the SASentry node associated with
836        # the data we just wrote
837        return doc, entry_node
[e9b12eaf]838   
[61cada5]839    def _parse_state(self, entry):
840        """
[5062bbf]841        Read a fit result from an XML node
842       
843        :param entry: XML node to read from
844       
845        :return: PageState object
[61cada5]846        """
847        # Create an empty state
[b35d3d1]848        state = None   
[61cada5]849        # Locate the P(r) node
850        try:
851            nodes = entry.xpath('ns:%s' % FITTING_NODE_NAME, namespaces={'ns': CANSAS_NS})
[b35d3d1]852            if nodes !=[]:
853                # Create an empty state
854                state =  PageState()
855                state.fromXML(node=nodes[0])
[61cada5]856        except:
857            logging.info("XML document does not contain fitting information.\n %s" % sys.exc_value)
858           
859        return state
860   
[0b12abb5]861   
[df7ed14]862                   
863    def _parse_entry(self, dom):
[e9b12eaf]864        """
[5062bbf]865        Parse a SASentry
866       
867        :param node: SASentry node
868       
[df7ed14]869        :return: Data1D/Data2D object
[5062bbf]870       
[e9b12eaf]871        """
[df7ed14]872        node = dom.xpath('ns:data_class', namespaces={'ns': CANSAS_NS})
873        if not node or node[0].text.lstrip().rstrip() != "Data2D":
874            return CansasReader._parse_entry(self, dom)
875       
876        #Parse 2D
[e9b12eaf]877        data_info = Data2D()
878       
879        # Look up title     
880        self._store_content('ns:Title', dom, 'title', data_info)
881       
882        # Look up run number   
883        nodes = dom.xpath('ns:Run', namespaces={'ns': CANSAS_NS})
884        for item in nodes:   
885            if item.text is not None:
886                value = item.text.strip()
887                if len(value) > 0:
888                    data_info.run.append(value)
889                    if item.get('name') is not None:
890                        data_info.run_name[value] = item.get('name')
891                           
892        # Look up instrument name             
893        self._store_content('ns:SASinstrument/ns:name', dom, 'instrument', data_info)
894
895        # Notes
896        note_list = dom.xpath('ns:SASnote', namespaces={'ns': CANSAS_NS})
897        for note in note_list:
898            try:
899                if note.text is not None:
900                    note_value = note.text.strip()
901                    if len(note_value) > 0:
902                        data_info.notes.append(note_value)
903            except:
904                err_mess = "cansas_reader.read: error processing entry notes\n  %s" % sys.exc_value
905                self.errors.append(err_mess)
906                logging.error(err_mess)
907       
908        # Sample info ###################
909        entry = get_content('ns:SASsample', dom)
910        if entry is not None:
911            data_info.sample.name = entry.get('name')
912           
913        self._store_content('ns:SASsample/ns:ID', 
914                     dom, 'ID', data_info.sample)                   
915        self._store_float('ns:SASsample/ns:thickness', 
916                     dom, 'thickness', data_info.sample)
917        self._store_float('ns:SASsample/ns:transmission', 
918                     dom, 'transmission', data_info.sample)
919        self._store_float('ns:SASsample/ns:temperature', 
920                     dom, 'temperature', data_info.sample)
921       
922        nodes = dom.xpath('ns:SASsample/ns:details', namespaces={'ns': CANSAS_NS})
923        for item in nodes:
924            try:
925                if item.text is not None:
926                    detail_value = item.text.strip()
927                    if len(detail_value) > 0:
928                        data_info.sample.details.append(detail_value)
929            except:
930                err_mess = "cansas_reader.read: error processing sample details\n  %s" % sys.exc_value
931                self.errors.append(err_mess)
932                logging.error(err_mess)
933       
934        # Position (as a vector)
935        self._store_float('ns:SASsample/ns:position/ns:x', 
936                     dom, 'position.x', data_info.sample)         
937        self._store_float('ns:SASsample/ns:position/ns:y', 
938                     dom, 'position.y', data_info.sample)         
939        self._store_float('ns:SASsample/ns:position/ns:z', 
940                     dom, 'position.z', data_info.sample)         
941       
942        # Orientation (as a vector)
943        self._store_float('ns:SASsample/ns:orientation/ns:roll', 
944                     dom, 'orientation.x', data_info.sample)         
945        self._store_float('ns:SASsample/ns:orientation/ns:pitch', 
946                     dom, 'orientation.y', data_info.sample)         
947        self._store_float('ns:SASsample/ns:orientation/ns:yaw', 
948                     dom, 'orientation.z', data_info.sample)         
949       
950        # Source info ###################
951        entry = get_content('ns:SASinstrument/ns:SASsource', dom)
952        if entry is not None:
953            data_info.source.name = entry.get('name')
954       
955        self._store_content('ns:SASinstrument/ns:SASsource/ns:radiation', 
956                     dom, 'radiation', data_info.source)                   
957        self._store_content('ns:SASinstrument/ns:SASsource/ns:beam_shape', 
958                     dom, 'beam_shape', data_info.source)                   
959        self._store_float('ns:SASinstrument/ns:SASsource/ns:wavelength', 
960                     dom, 'wavelength', data_info.source)         
961        self._store_float('ns:SASinstrument/ns:SASsource/ns:wavelength_min', 
962                     dom, 'wavelength_min', data_info.source)         
963        self._store_float('ns:SASinstrument/ns:SASsource/ns:wavelength_max', 
964                     dom, 'wavelength_max', data_info.source)         
965        self._store_float('ns:SASinstrument/ns:SASsource/ns:wavelength_spread', 
966                     dom, 'wavelength_spread', data_info.source)   
967       
968        # Beam size (as a vector)   
969        entry = get_content('ns:SASinstrument/ns:SASsource/ns:beam_size', dom)
970        if entry is not None:
971            data_info.source.beam_size_name = entry.get('name')
972           
973        self._store_float('ns:SASinstrument/ns:SASsource/ns:beam_size/ns:x', 
974                     dom, 'beam_size.x', data_info.source)   
975        self._store_float('ns:SASinstrument/ns:SASsource/ns:beam_size/ns:y', 
976                     dom, 'beam_size.y', data_info.source)   
977        self._store_float('ns:SASinstrument/ns:SASsource/ns:beam_size/ns:z', 
978                     dom, 'beam_size.z', data_info.source)   
979       
980        # Collimation info ###################
981        nodes = dom.xpath('ns:SASinstrument/ns:SAScollimation', namespaces={'ns': CANSAS_NS})
982        for item in nodes:
983            collim = Collimation()
984            if item.get('name') is not None:
985                collim.name = item.get('name')
986            self._store_float('ns:length', item, 'length', collim) 
987           
988            # Look for apertures
989            apert_list = item.xpath('ns:aperture', namespaces={'ns': CANSAS_NS})
990            for apert in apert_list:
991                aperture =  Aperture()
992               
993                # Get the name and type of the aperture
994                aperture.name = apert.get('name')
995                aperture.type = apert.get('type')
996                   
997                self._store_float('ns:distance', apert, 'distance', aperture)   
998               
999                entry = get_content('ns:size', apert)
1000                if entry is not None:
1001                    aperture.size_name = entry.get('name')
1002               
1003                self._store_float('ns:size/ns:x', apert, 'size.x', aperture)   
1004                self._store_float('ns:size/ns:y', apert, 'size.y', aperture)   
1005                self._store_float('ns:size/ns:z', apert, 'size.z', aperture)
1006               
1007                collim.aperture.append(aperture)
1008               
1009            data_info.collimation.append(collim)
1010       
1011        # Detector info ######################
1012        nodes = dom.xpath('ns:SASinstrument/ns:SASdetector', namespaces={'ns': CANSAS_NS})
1013        for item in nodes:
1014           
1015            detector = Detector()
1016           
1017            self._store_content('ns:name', item, 'name', detector)
1018            self._store_float('ns:SDD', item, 'distance', detector)   
1019           
1020            # Detector offset (as a vector)
1021            self._store_float('ns:offset/ns:x', item, 'offset.x', detector)   
1022            self._store_float('ns:offset/ns:y', item, 'offset.y', detector)   
1023            self._store_float('ns:offset/ns:z', item, 'offset.z', detector)   
1024           
1025            # Detector orientation (as a vector)
1026            self._store_float('ns:orientation/ns:roll',  item, 'orientation.x', detector)   
1027            self._store_float('ns:orientation/ns:pitch', item, 'orientation.y', detector)   
1028            self._store_float('ns:orientation/ns:yaw',   item, 'orientation.z', detector)   
1029           
1030            # Beam center (as a vector)
1031            self._store_float('ns:beam_center/ns:x', item, 'beam_center.x', detector)   
1032            self._store_float('ns:beam_center/ns:y', item, 'beam_center.y', detector)   
1033            self._store_float('ns:beam_center/ns:z', item, 'beam_center.z', detector)   
1034           
1035            # Pixel size (as a vector)
1036            self._store_float('ns:pixel_size/ns:x', item, 'pixel_size.x', detector)   
1037            self._store_float('ns:pixel_size/ns:y', item, 'pixel_size.y', detector)   
1038            self._store_float('ns:pixel_size/ns:z', item, 'pixel_size.z', detector)   
1039           
1040            self._store_float('ns:slit_length', item, 'slit_length', detector)
1041           
1042            data_info.detector.append(detector)   
1043
1044        # Processes info ######################
1045        nodes = dom.xpath('ns:SASprocess', namespaces={'ns': CANSAS_NS})
1046        for item in nodes:
1047            process = Process()
1048            self._store_content('ns:name', item, 'name', process)
1049            self._store_content('ns:date', item, 'date', process)
1050            self._store_content('ns:description', item, 'description', process)
1051           
1052            term_list = item.xpath('ns:term', namespaces={'ns': CANSAS_NS})
1053            for term in term_list:
1054                try:
1055                    term_attr = {}
1056                    for attr in term.keys():
1057                        term_attr[attr] = term.get(attr).strip()
1058                    if term.text is not None:
1059                        term_attr['value'] = term.text.strip()
1060                        process.term.append(term_attr)
1061                except:
1062                    err_mess = "cansas_reader.read: error processing process term\n  %s" % sys.exc_value
1063                    self.errors.append(err_mess)
1064                    logging.error(err_mess)
1065           
1066            note_list = item.xpath('ns:SASprocessnote', namespaces={'ns': CANSAS_NS})
1067            for note in note_list:
1068                if note.text is not None:
1069                    process.notes.append(note.text.strip())
1070           
1071            data_info.process.append(process)
1072           
1073           
1074        # Data info ######################
1075        nodes = dom.xpath('ns:SASdata', namespaces={'ns': CANSAS_NS})
1076        if len(nodes)>1:
1077            raise RuntimeError, "CanSAS reader is not compatible with multiple SASdata entries"
[df7ed14]1078       
1079        for entry in nodes:
1080            for item in list_of_data_2d_attr:
1081                #get node
1082                node = get_content('ns:%s'%item[0], entry)
[0b12abb5]1083                exec "data_info.%s = parse_entry_helper(node, item)"%(item[1])
[e9b12eaf]1084                   
[df7ed14]1085            for item in list_of_data2d_values:
1086                field = get_content('ns:%s'%item[0], entry)
1087                list = []
1088                if field is not None:
[0b12abb5]1089                    list = [parse_entry_helper(node, item) for node in field]
[df7ed14]1090                exec "data_info.%s = numpy.array(list)"%item[0]
[e9b12eaf]1091       
1092        return data_info
1093
[61cada5]1094    def _read_cansas(self, path):
1095        """
[5062bbf]1096        Load data and P(r) information from a CanSAS XML file.
1097       
1098        :param path: file path
1099       
1100        :return: Data1D object if a single SASentry was found,
1101                    or a list of Data1D objects if multiple entries were found,
1102                    or None of nothing was found
1103                   
1104        :raise RuntimeError: when the file can't be opened
1105        :raise ValueError: when the length of the data vectors are inconsistent
1106       
[61cada5]1107        """
1108        output = []
[b63dc6e]1109        basename  = os.path.basename(path)
1110        root, extension = os.path.splitext(basename)
1111        ext = extension.lower()
[61cada5]1112        try:
1113            if os.path.isfile(path):
[b63dc6e]1114               
[61cada5]1115                #TODO: eventually remove the check for .xml once
1116                # the P(r) writer/reader is truly complete.
[b63dc6e]1117                if  ext in self.ext or \
1118                    ext == '.xml':
[61cada5]1119                   
1120                    tree = etree.parse(path, parser=etree.ETCompatXMLParser())
1121                    # Check the format version number
1122                    # Specifying the namespace will take care of the file format version
1123                    root = tree.getroot()
[df7ed14]1124                    entry_list = root.xpath('ns:SASentry', namespaces={'ns': CANSAS_NS})
[b35d3d1]1125                    for entry in entry_list:   
[e9b12eaf]1126                        try:
1127                            sas_entry = self._parse_entry(entry)
1128                        except:
[df7ed14]1129                            raise
[61cada5]1130                        fitstate = self._parse_state(entry)
[b35d3d1]1131                       
1132                        #state could be None when .svs file is loaded
1133                        #in this case, skip appending to output
1134                        if fitstate != None:
1135                            sas_entry.meta_data['fitstate'] = fitstate
1136                            sas_entry.filename = fitstate.file
1137                            output.append(sas_entry)
[61cada5]1138            else:
[b63dc6e]1139                self.call_back(format=ext)
[61cada5]1140                raise RuntimeError, "%s is not a file" % path
[b35d3d1]1141
[61cada5]1142            # Return output consistent with the loader's api
1143            if len(output)==0:
[b63dc6e]1144                self.call_back(state=None, datainfo=None,format=ext)
[61cada5]1145                return None
1146            else:
[b35d3d1]1147                for ind in range(len(output)):
1148                    # Call back to post the new state
1149                    state = output[ind].meta_data['fitstate']
1150                    t = time.localtime(state.timestamp)
1151                    time_str = time.strftime("%b %d %H:%M", t)
1152                    # Check that no time stamp is already appended
1153                    max_char = state.file.find("[")
1154                    if max_char < 0:
1155                        max_char = len(state.file)
[ef16f59]1156                    original_fname = state.file[0:max_char]
1157                    state.file = original_fname +' [' + time_str + ']'
[b35d3d1]1158                   
1159                       
1160                    if state is not None and state.is_data is not None:
1161                        exec 'output[%d].is_data = state.is_data'% ind
1162                     
1163                    output[ind].filename = state.file
1164                    state.data = output[ind]
1165                    state.data.name = output[ind].filename #state.data_name
1166                    state.data.id = state.data_id
1167                    if state.is_data is not None:
1168                        state.data.is_data = state.is_data
[ef16f59]1169                    if output[ind].run_name is not None and len(output[ind].run_name) != 0 :
1170                        name = output[ind].run_name
1171                    else: 
1172                        name=original_fname
1173                    state.data.group_id = name
1174                    #store state in fitting
[90a7bbd]1175                    self.call_back(state=state, datainfo=output[ind],format=ext)
[75fbd17]1176                    self.state= state
[ef16f59]1177                return output
[b35d3d1]1178             
[61cada5]1179        except:
[75fbd17]1180            #self.call_back(format=ext)
1181            self.state= state
[61cada5]1182            raise
1183           
1184    def write(self, filename, datainfo=None, fitstate=None):
1185        """
[b35d3d1]1186        Write the content of a Data1D as a CanSAS XML file only for standalone
[5062bbf]1187       
1188        :param filename: name of the file to write
1189        :param datainfo: Data1D object
1190        :param fitstate: PageState object
1191       
[61cada5]1192        """
1193        # Sanity check
1194        if self.cansas == True:
1195           
1196            # Add fitting information to the XML document
[ef16f59]1197            doc = self.write_toXML(datainfo, fitstate)
[61cada5]1198            # Write the XML document
1199            fd = open(filename, 'w')
1200            fd.write(doc.toprettyxml())
1201            fd.close()
1202        else:
1203            fitstate.toXML(file=filename)
1204       
[b35d3d1]1205    def write_toXML(self, datainfo=None, state=None):
1206        """
1207        Write toXML, a helper for write() , could be used by guimanager._on_save()
1208       
1209        : return: xml doc
1210        """
[3c44c66]1211
[b35d3d1]1212        if state.data is None:
1213            data = DataLoader.data_info.Data1D(x=[], y=[]) 
1214        else: 
1215            #make sure title and data run is filled up.
[028a0e8]1216            if state.data.title == None or state.data.title=='': state.data.title = state.data.name
1217            if state.data.run_name == None or state.data.run_name=={}: 
1218                state.data.run = [str(state.data.name)]
1219                state.data.run_name[0] = state.data.name
[b35d3d1]1220   
1221            if issubclass(state.data.__class__, DataLoader.data_info.Data1D):
[028a0e8]1222
[b35d3d1]1223                data = state.data
1224                doc, sasentry = self._to_xml_doc(data)
1225            else:
1226                data = state.data
1227                doc, sasentry = self._data2d_to_xml_doc(data)
1228           
1229
1230        if state is not None:
1231            state.toXML(doc=doc, file=data.name, entry_node=sasentry)
1232           
1233        return doc
[5062bbf]1234 
[3c44c66]1235if __name__ == "__main__":
1236    state = PageState(parent=None)
1237    #state.toXML()
1238    """
[5062bbf]1239   
[3c44c66]1240    file = open("test_state", "w")
1241    pickle.dump(state, file)
1242    print pickle.dumps(state)
1243    state.data_name = "hello---->"
1244    pickle.dump(state, file)
1245    file = open("test_state", "r")
1246    new_state= pickle.load(file)
1247    print "new state", new_state
1248    new_state= pickle.load(file)
1249    print "new state", new_state
1250    #print "state", state
1251    """
1252    import bsddb
1253    import pickle
1254    db= bsddb.btopen('file_state.db', 'c')
1255    val = (pickle.dumps(state), "hello", "hi")
1256    db['state1']= pickle.dumps(val)
1257    print pickle.loads(db['state1'])
1258    state.data_name = "hello---->22"
1259    db['state2']= pickle.dumps(state)
1260    state.data_name = "hello---->2"
1261    db['state3']= pickle.dumps(state)
1262    del db['state3']
1263    state.data_name = "hello---->3"
1264    db['state4']= pickle.dumps(state)
1265    new_state = pickle.loads(db['state1'])
1266    #print db.last()
1267    db.set_location('state2')
1268    state.data_name = "hello---->5"
1269    db['aastate5']= pickle.dumps(state)
1270    db.keys().sort()
1271    print pickle.loads(db['state2'])
1272 
1273    db.close()
Note: See TracBrowser for help on using the repository browser.