source: sasview/sansview/perspectives/fitting/pagestate.py @ 992199e

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 992199e was fb59ed9, checked in by Jae Cho <jhjcho@…>, 14 years ago

added new models

  • Property mode set to 100644
File size: 54.7 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
633       
634    def read(self, path):
635        """
[5062bbf]636        Load a new P(r) inversion state from file
637       
638        :param path: file path
639       
[61cada5]640        """
[e9b12eaf]641        if self.cansas == True:
[61cada5]642            return self._read_cansas(path)
[e9b12eaf]643     
644    def _data2d_to_xml_doc(self, datainfo):
[61cada5]645        """
[5062bbf]646        Create an XML document to contain the content of a Data2D
647       
648        :param datainfo: Data2D object
649       
[61cada5]650        """
651        if not issubclass(datainfo.__class__, Data2D):
652            raise RuntimeError, "The cansas writer expects a Data2D instance"
653       
654        doc = xml.dom.minidom.Document()
655        main_node = doc.createElement("SASroot")
656        main_node.setAttribute("version", self.version)
[df7ed14]657        main_node.setAttribute("xmlns", "cansas1d/%s" % self.version)
658        main_node.setAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance")
659        main_node.setAttribute("xsi:schemaLocation", "cansas1d/%s http://svn.smallangles.net/svn/canSAS/1dwg/trunk/cansas1d.xsd" % self.version)
660       
[61cada5]661        doc.appendChild(main_node)
662       
663        entry_node = doc.createElement("SASentry")
664        main_node.appendChild(entry_node)
[df7ed14]665       
[61cada5]666        write_node(doc, entry_node, "Title", datainfo.title)
[df7ed14]667        if datainfo is not None:
668            write_node(doc, entry_node, "data_class", datainfo.__class__.__name__)
[61cada5]669        for item in datainfo.run:
670            runname = {}
671            if datainfo.run_name.has_key(item) and len(str(datainfo.run_name[item]))>1:
672                runname = {'name': datainfo.run_name[item] }
673            write_node(doc, entry_node, "Run", item, runname)
674        # Data info
[df7ed14]675        new_node = doc.createElement("SASdata")
676        entry_node.appendChild(new_node)
[e9b12eaf]677        for item in list_of_data_2d_attr:
678            element = doc.createElement(item[0])
679            exec "element.setAttribute(item[0], str(datainfo.%s))"%(item[1])
[df7ed14]680            new_node.appendChild(element)
681           
[e9b12eaf]682        for item in list_of_data2d_values:
[df7ed14]683            root_node = doc.createElement(item[0])
684            new_node.appendChild(root_node)
685           
[35b556d]686            exec "temp_list = datainfo.%s"%item[1]
[df7ed14]687
[35b556d]688            if temp_list is None or len(temp_list)== 0:
[df7ed14]689                element = doc.createElement(item[0])
[35b556d]690                exec "element.appendChild(doc.createTextNode(str(%s)))"%temp_list
[df7ed14]691                root_node.appendChild(element)
[35b556d]692            else:
693                for value in temp_list:
[df7ed14]694                    element = doc.createElement(item[0])
695                    exec "element.setAttribute(item[0], str(%s))"%value
696                    root_node.appendChild(element)
697       
[61cada5]698        # Sample info
699        sample = doc.createElement("SASsample")
700        if datainfo.sample.name is not None:
701            sample.setAttribute("name", str(datainfo.sample.name))
702        entry_node.appendChild(sample)
703        write_node(doc, sample, "ID", str(datainfo.sample.ID))
704        write_node(doc, sample, "thickness", datainfo.sample.thickness, {"unit":datainfo.sample.thickness_unit})
705        write_node(doc, sample, "transmission", datainfo.sample.transmission)
706        write_node(doc, sample, "temperature", datainfo.sample.temperature, {"unit":datainfo.sample.temperature_unit})
707       
708        for item in datainfo.sample.details:
709            write_node(doc, sample, "details", item)
710       
711        pos = doc.createElement("position")
712        written = write_node(doc, pos, "x", datainfo.sample.position.x, {"unit":datainfo.sample.position_unit})
713        written = written | write_node(doc, pos, "y", datainfo.sample.position.y, {"unit":datainfo.sample.position_unit})
714        written = written | write_node(doc, pos, "z", datainfo.sample.position.z, {"unit":datainfo.sample.position_unit})
715        if written == True:
716            sample.appendChild(pos)
717       
718        ori = doc.createElement("orientation")
719        written = write_node(doc, ori, "roll",  datainfo.sample.orientation.x, {"unit":datainfo.sample.orientation_unit})
720        written = written | write_node(doc, ori, "pitch", datainfo.sample.orientation.y, {"unit":datainfo.sample.orientation_unit})
721        written = written | write_node(doc, ori, "yaw",   datainfo.sample.orientation.z, {"unit":datainfo.sample.orientation_unit})
722        if written == True:
723            sample.appendChild(ori)
724       
725        # Instrument info
726        instr = doc.createElement("SASinstrument")
727        entry_node.appendChild(instr)
728       
729        write_node(doc, instr, "name", datainfo.instrument)
730       
731        #   Source
732        source = doc.createElement("SASsource")
733        if datainfo.source.name is not None:
734            source.setAttribute("name", str(datainfo.source.name))
735        instr.appendChild(source)
736       
737        write_node(doc, source, "radiation", datainfo.source.radiation)
738        write_node(doc, source, "beam_shape", datainfo.source.beam_shape)
739        size = doc.createElement("beam_size")
740        if datainfo.source.beam_size_name is not None:
741            size.setAttribute("name", str(datainfo.source.beam_size_name))
742        written = write_node(doc, size, "x", datainfo.source.beam_size.x, {"unit":datainfo.source.beam_size_unit})
743        written = written | write_node(doc, size, "y", datainfo.source.beam_size.y, {"unit":datainfo.source.beam_size_unit})
744        written = written | write_node(doc, size, "z", datainfo.source.beam_size.z, {"unit":datainfo.source.beam_size_unit})
745        if written == True:
746            source.appendChild(size)
747           
748        write_node(doc, source, "wavelength", datainfo.source.wavelength, {"unit":datainfo.source.wavelength_unit})
749        write_node(doc, source, "wavelength_min", datainfo.source.wavelength_min, {"unit":datainfo.source.wavelength_min_unit})
750        write_node(doc, source, "wavelength_max", datainfo.source.wavelength_max, {"unit":datainfo.source.wavelength_max_unit})
751        write_node(doc, source, "wavelength_spread", datainfo.source.wavelength_spread, {"unit":datainfo.source.wavelength_spread_unit})
752       
753        #   Collimation
754        for item in datainfo.collimation:
755            coll = doc.createElement("SAScollimation")
756            if item.name is not None:
757                coll.setAttribute("name", str(item.name))
758            instr.appendChild(coll)
759           
760            write_node(doc, coll, "length", item.length, {"unit":item.length_unit})
761           
762            for apert in item.aperture:
763                ap = doc.createElement("aperture")
764                if apert.name is not None:
765                    ap.setAttribute("name", str(apert.name))
766                if apert.type is not None:
767                    ap.setAttribute("type", str(apert.type))
768                coll.appendChild(ap)
769               
770                write_node(doc, ap, "distance", apert.distance, {"unit":apert.distance_unit})
771               
772                size = doc.createElement("size")
773                if apert.size_name is not None:
774                    size.setAttribute("name", str(apert.size_name))
775                written = write_node(doc, size, "x", apert.size.x, {"unit":apert.size_unit})
776                written = written | write_node(doc, size, "y", apert.size.y, {"unit":apert.size_unit})
777                written = written | write_node(doc, size, "z", apert.size.z, {"unit":apert.size_unit})
778                if written == True:
779                    ap.appendChild(size)
780
781        #   Detectors
782        for item in datainfo.detector:
783            det = doc.createElement("SASdetector")
784            written = write_node(doc, det, "name", item.name)
785            written = written | write_node(doc, det, "SDD", item.distance, {"unit":item.distance_unit})
786            written = written | write_node(doc, det, "slit_length", item.slit_length, {"unit":item.slit_length_unit})
787            if written == True:
788                instr.appendChild(det)
789           
790            off = doc.createElement("offset")
791            written = write_node(doc, off, "x", item.offset.x, {"unit":item.offset_unit})
792            written = written | write_node(doc, off, "y", item.offset.y, {"unit":item.offset_unit})
793            written = written | write_node(doc, off, "z", item.offset.z, {"unit":item.offset_unit})
794            if written == True:
795                det.appendChild(off)
796           
797            center = doc.createElement("beam_center")
798            written = write_node(doc, center, "x", item.beam_center.x, {"unit":item.beam_center_unit})
799            written = written | write_node(doc, center, "y", item.beam_center.y, {"unit":item.beam_center_unit})
800            written = written | write_node(doc, center, "z", item.beam_center.z, {"unit":item.beam_center_unit})
801            if written == True:
802                det.appendChild(center)
803               
804            pix = doc.createElement("pixel_size")
805            written = write_node(doc, pix, "x", item.pixel_size.x, {"unit":item.pixel_size_unit})
806            written = written | write_node(doc, pix, "y", item.pixel_size.y, {"unit":item.pixel_size_unit})
807            written = written | write_node(doc, pix, "z", item.pixel_size.z, {"unit":item.pixel_size_unit})
808            if written == True:
809                det.appendChild(pix)
810               
811            ori = doc.createElement("orientation")
812            written = write_node(doc, ori, "roll",  item.orientation.x, {"unit":item.orientation_unit})
813            written = written | write_node(doc, ori, "pitch", item.orientation.y, {"unit":item.orientation_unit})
814            written = written | write_node(doc, ori, "yaw",   item.orientation.z, {"unit":item.orientation_unit})
815            if written == True:
816                det.appendChild(ori)
817               
818        # Processes info
819        for item in datainfo.process:
820            node = doc.createElement("SASprocess")
821            entry_node.appendChild(node)
822
823            write_node(doc, node, "name", item.name)
824            write_node(doc, node, "date", item.date)
825            write_node(doc, node, "description", item.description)
826            for term in item.term:
827                value = term['value']
828                del term['value']
829                write_node(doc, node, "term", value, term)
830            for note in item.notes:
831                write_node(doc, node, "SASprocessnote", note)
832        # Return the document, and the SASentry node associated with
833        # the data we just wrote
834        return doc, entry_node
[e9b12eaf]835   
[61cada5]836    def _parse_state(self, entry):
837        """
[5062bbf]838        Read a fit result from an XML node
839       
840        :param entry: XML node to read from
841       
842        :return: PageState object
[61cada5]843        """
844        # Create an empty state
[b35d3d1]845        state = None   
[61cada5]846        # Locate the P(r) node
847        try:
848            nodes = entry.xpath('ns:%s' % FITTING_NODE_NAME, namespaces={'ns': CANSAS_NS})
[b35d3d1]849            if nodes !=[]:
850                # Create an empty state
851                state =  PageState()
852                state.fromXML(node=nodes[0])
[61cada5]853        except:
854            logging.info("XML document does not contain fitting information.\n %s" % sys.exc_value)
855           
856        return state
857   
[0b12abb5]858   
[df7ed14]859                   
860    def _parse_entry(self, dom):
[e9b12eaf]861        """
[5062bbf]862        Parse a SASentry
863       
864        :param node: SASentry node
865       
[df7ed14]866        :return: Data1D/Data2D object
[5062bbf]867       
[e9b12eaf]868        """
[df7ed14]869        node = dom.xpath('ns:data_class', namespaces={'ns': CANSAS_NS})
870        if not node or node[0].text.lstrip().rstrip() != "Data2D":
871            return CansasReader._parse_entry(self, dom)
872       
873        #Parse 2D
[e9b12eaf]874        data_info = Data2D()
875       
876        # Look up title     
877        self._store_content('ns:Title', dom, 'title', data_info)
878       
879        # Look up run number   
880        nodes = dom.xpath('ns:Run', namespaces={'ns': CANSAS_NS})
881        for item in nodes:   
882            if item.text is not None:
883                value = item.text.strip()
884                if len(value) > 0:
885                    data_info.run.append(value)
886                    if item.get('name') is not None:
887                        data_info.run_name[value] = item.get('name')
888                           
889        # Look up instrument name             
890        self._store_content('ns:SASinstrument/ns:name', dom, 'instrument', data_info)
891
892        # Notes
893        note_list = dom.xpath('ns:SASnote', namespaces={'ns': CANSAS_NS})
894        for note in note_list:
895            try:
896                if note.text is not None:
897                    note_value = note.text.strip()
898                    if len(note_value) > 0:
899                        data_info.notes.append(note_value)
900            except:
901                err_mess = "cansas_reader.read: error processing entry notes\n  %s" % sys.exc_value
902                self.errors.append(err_mess)
903                logging.error(err_mess)
904       
905        # Sample info ###################
906        entry = get_content('ns:SASsample', dom)
907        if entry is not None:
908            data_info.sample.name = entry.get('name')
909           
910        self._store_content('ns:SASsample/ns:ID', 
911                     dom, 'ID', data_info.sample)                   
912        self._store_float('ns:SASsample/ns:thickness', 
913                     dom, 'thickness', data_info.sample)
914        self._store_float('ns:SASsample/ns:transmission', 
915                     dom, 'transmission', data_info.sample)
916        self._store_float('ns:SASsample/ns:temperature', 
917                     dom, 'temperature', data_info.sample)
918       
919        nodes = dom.xpath('ns:SASsample/ns:details', namespaces={'ns': CANSAS_NS})
920        for item in nodes:
921            try:
922                if item.text is not None:
923                    detail_value = item.text.strip()
924                    if len(detail_value) > 0:
925                        data_info.sample.details.append(detail_value)
926            except:
927                err_mess = "cansas_reader.read: error processing sample details\n  %s" % sys.exc_value
928                self.errors.append(err_mess)
929                logging.error(err_mess)
930       
931        # Position (as a vector)
932        self._store_float('ns:SASsample/ns:position/ns:x', 
933                     dom, 'position.x', data_info.sample)         
934        self._store_float('ns:SASsample/ns:position/ns:y', 
935                     dom, 'position.y', data_info.sample)         
936        self._store_float('ns:SASsample/ns:position/ns:z', 
937                     dom, 'position.z', data_info.sample)         
938       
939        # Orientation (as a vector)
940        self._store_float('ns:SASsample/ns:orientation/ns:roll', 
941                     dom, 'orientation.x', data_info.sample)         
942        self._store_float('ns:SASsample/ns:orientation/ns:pitch', 
943                     dom, 'orientation.y', data_info.sample)         
944        self._store_float('ns:SASsample/ns:orientation/ns:yaw', 
945                     dom, 'orientation.z', data_info.sample)         
946       
947        # Source info ###################
948        entry = get_content('ns:SASinstrument/ns:SASsource', dom)
949        if entry is not None:
950            data_info.source.name = entry.get('name')
951       
952        self._store_content('ns:SASinstrument/ns:SASsource/ns:radiation', 
953                     dom, 'radiation', data_info.source)                   
954        self._store_content('ns:SASinstrument/ns:SASsource/ns:beam_shape', 
955                     dom, 'beam_shape', data_info.source)                   
956        self._store_float('ns:SASinstrument/ns:SASsource/ns:wavelength', 
957                     dom, 'wavelength', data_info.source)         
958        self._store_float('ns:SASinstrument/ns:SASsource/ns:wavelength_min', 
959                     dom, 'wavelength_min', data_info.source)         
960        self._store_float('ns:SASinstrument/ns:SASsource/ns:wavelength_max', 
961                     dom, 'wavelength_max', data_info.source)         
962        self._store_float('ns:SASinstrument/ns:SASsource/ns:wavelength_spread', 
963                     dom, 'wavelength_spread', data_info.source)   
964       
965        # Beam size (as a vector)   
966        entry = get_content('ns:SASinstrument/ns:SASsource/ns:beam_size', dom)
967        if entry is not None:
968            data_info.source.beam_size_name = entry.get('name')
969           
970        self._store_float('ns:SASinstrument/ns:SASsource/ns:beam_size/ns:x', 
971                     dom, 'beam_size.x', data_info.source)   
972        self._store_float('ns:SASinstrument/ns:SASsource/ns:beam_size/ns:y', 
973                     dom, 'beam_size.y', data_info.source)   
974        self._store_float('ns:SASinstrument/ns:SASsource/ns:beam_size/ns:z', 
975                     dom, 'beam_size.z', data_info.source)   
976       
977        # Collimation info ###################
978        nodes = dom.xpath('ns:SASinstrument/ns:SAScollimation', namespaces={'ns': CANSAS_NS})
979        for item in nodes:
980            collim = Collimation()
981            if item.get('name') is not None:
982                collim.name = item.get('name')
983            self._store_float('ns:length', item, 'length', collim) 
984           
985            # Look for apertures
986            apert_list = item.xpath('ns:aperture', namespaces={'ns': CANSAS_NS})
987            for apert in apert_list:
988                aperture =  Aperture()
989               
990                # Get the name and type of the aperture
991                aperture.name = apert.get('name')
992                aperture.type = apert.get('type')
993                   
994                self._store_float('ns:distance', apert, 'distance', aperture)   
995               
996                entry = get_content('ns:size', apert)
997                if entry is not None:
998                    aperture.size_name = entry.get('name')
999               
1000                self._store_float('ns:size/ns:x', apert, 'size.x', aperture)   
1001                self._store_float('ns:size/ns:y', apert, 'size.y', aperture)   
1002                self._store_float('ns:size/ns:z', apert, 'size.z', aperture)
1003               
1004                collim.aperture.append(aperture)
1005               
1006            data_info.collimation.append(collim)
1007       
1008        # Detector info ######################
1009        nodes = dom.xpath('ns:SASinstrument/ns:SASdetector', namespaces={'ns': CANSAS_NS})
1010        for item in nodes:
1011           
1012            detector = Detector()
1013           
1014            self._store_content('ns:name', item, 'name', detector)
1015            self._store_float('ns:SDD', item, 'distance', detector)   
1016           
1017            # Detector offset (as a vector)
1018            self._store_float('ns:offset/ns:x', item, 'offset.x', detector)   
1019            self._store_float('ns:offset/ns:y', item, 'offset.y', detector)   
1020            self._store_float('ns:offset/ns:z', item, 'offset.z', detector)   
1021           
1022            # Detector orientation (as a vector)
1023            self._store_float('ns:orientation/ns:roll',  item, 'orientation.x', detector)   
1024            self._store_float('ns:orientation/ns:pitch', item, 'orientation.y', detector)   
1025            self._store_float('ns:orientation/ns:yaw',   item, 'orientation.z', detector)   
1026           
1027            # Beam center (as a vector)
1028            self._store_float('ns:beam_center/ns:x', item, 'beam_center.x', detector)   
1029            self._store_float('ns:beam_center/ns:y', item, 'beam_center.y', detector)   
1030            self._store_float('ns:beam_center/ns:z', item, 'beam_center.z', detector)   
1031           
1032            # Pixel size (as a vector)
1033            self._store_float('ns:pixel_size/ns:x', item, 'pixel_size.x', detector)   
1034            self._store_float('ns:pixel_size/ns:y', item, 'pixel_size.y', detector)   
1035            self._store_float('ns:pixel_size/ns:z', item, 'pixel_size.z', detector)   
1036           
1037            self._store_float('ns:slit_length', item, 'slit_length', detector)
1038           
1039            data_info.detector.append(detector)   
1040
1041        # Processes info ######################
1042        nodes = dom.xpath('ns:SASprocess', namespaces={'ns': CANSAS_NS})
1043        for item in nodes:
1044            process = Process()
1045            self._store_content('ns:name', item, 'name', process)
1046            self._store_content('ns:date', item, 'date', process)
1047            self._store_content('ns:description', item, 'description', process)
1048           
1049            term_list = item.xpath('ns:term', namespaces={'ns': CANSAS_NS})
1050            for term in term_list:
1051                try:
1052                    term_attr = {}
1053                    for attr in term.keys():
1054                        term_attr[attr] = term.get(attr).strip()
1055                    if term.text is not None:
1056                        term_attr['value'] = term.text.strip()
1057                        process.term.append(term_attr)
1058                except:
1059                    err_mess = "cansas_reader.read: error processing process term\n  %s" % sys.exc_value
1060                    self.errors.append(err_mess)
1061                    logging.error(err_mess)
1062           
1063            note_list = item.xpath('ns:SASprocessnote', namespaces={'ns': CANSAS_NS})
1064            for note in note_list:
1065                if note.text is not None:
1066                    process.notes.append(note.text.strip())
1067           
1068            data_info.process.append(process)
1069           
1070           
1071        # Data info ######################
1072        nodes = dom.xpath('ns:SASdata', namespaces={'ns': CANSAS_NS})
1073        if len(nodes)>1:
1074            raise RuntimeError, "CanSAS reader is not compatible with multiple SASdata entries"
[df7ed14]1075       
1076        for entry in nodes:
1077            for item in list_of_data_2d_attr:
1078                #get node
1079                node = get_content('ns:%s'%item[0], entry)
[0b12abb5]1080                exec "data_info.%s = parse_entry_helper(node, item)"%(item[1])
[e9b12eaf]1081                   
[df7ed14]1082            for item in list_of_data2d_values:
1083                field = get_content('ns:%s'%item[0], entry)
1084                list = []
1085                if field is not None:
[0b12abb5]1086                    list = [parse_entry_helper(node, item) for node in field]
[df7ed14]1087                exec "data_info.%s = numpy.array(list)"%item[0]
[e9b12eaf]1088       
1089        return data_info
1090
[61cada5]1091    def _read_cansas(self, path):
1092        """
[5062bbf]1093        Load data and P(r) information from a CanSAS XML file.
1094       
1095        :param path: file path
1096       
1097        :return: Data1D object if a single SASentry was found,
1098                    or a list of Data1D objects if multiple entries were found,
1099                    or None of nothing was found
1100                   
1101        :raise RuntimeError: when the file can't be opened
1102        :raise ValueError: when the length of the data vectors are inconsistent
1103       
[61cada5]1104        """
1105        output = []
[b63dc6e]1106        basename  = os.path.basename(path)
1107        root, extension = os.path.splitext(basename)
1108        ext = extension.lower()
[61cada5]1109        try:
1110            if os.path.isfile(path):
[b63dc6e]1111               
[61cada5]1112                #TODO: eventually remove the check for .xml once
1113                # the P(r) writer/reader is truly complete.
[b63dc6e]1114                if  ext in self.ext or \
1115                    ext == '.xml':
[61cada5]1116                   
1117                    tree = etree.parse(path, parser=etree.ETCompatXMLParser())
1118                    # Check the format version number
1119                    # Specifying the namespace will take care of the file format version
1120                    root = tree.getroot()
[df7ed14]1121                    entry_list = root.xpath('ns:SASentry', namespaces={'ns': CANSAS_NS})
[b35d3d1]1122                    for entry in entry_list:   
[e9b12eaf]1123                        try:
1124                            sas_entry = self._parse_entry(entry)
1125                        except:
[df7ed14]1126                            raise
[61cada5]1127                        fitstate = self._parse_state(entry)
[b35d3d1]1128                       
1129                        #state could be None when .svs file is loaded
1130                        #in this case, skip appending to output
1131                        if fitstate != None:
1132                            sas_entry.meta_data['fitstate'] = fitstate
1133                            sas_entry.filename = fitstate.file
1134                            output.append(sas_entry)
[61cada5]1135            else:
[b63dc6e]1136                self.call_back(format=ext)
[61cada5]1137                raise RuntimeError, "%s is not a file" % path
[b35d3d1]1138
[61cada5]1139            # Return output consistent with the loader's api
1140            if len(output)==0:
[b63dc6e]1141                self.call_back(state=None, datainfo=None,format=ext)
[61cada5]1142                return None
1143            else:
[b35d3d1]1144                for ind in range(len(output)):
1145                    # Call back to post the new state
1146                    state = output[ind].meta_data['fitstate']
1147                    t = time.localtime(state.timestamp)
1148                    time_str = time.strftime("%b %d %H:%M", t)
1149                    # Check that no time stamp is already appended
1150                    max_char = state.file.find("[")
1151                    if max_char < 0:
1152                        max_char = len(state.file)
[ef16f59]1153                    original_fname = state.file[0:max_char]
1154                    state.file = original_fname +' [' + time_str + ']'
[b35d3d1]1155                   
1156                       
1157                    if state is not None and state.is_data is not None:
1158                        exec 'output[%d].is_data = state.is_data'% ind
1159                     
1160                    output[ind].filename = state.file
1161                    state.data = output[ind]
1162                    state.data.name = output[ind].filename #state.data_name
1163                    state.data.id = state.data_id
1164                    if state.is_data is not None:
1165                        state.data.is_data = state.is_data
[ef16f59]1166                    if output[ind].run_name is not None and len(output[ind].run_name) != 0 :
1167                        name = output[ind].run_name
1168                    else: 
1169                        name=original_fname
1170                    state.data.group_id = name
1171                    #store state in fitting
[b63dc6e]1172                    self.call_back(state=state, datainfo=output[ind],format=ext)
[ef16f59]1173                return output
[b35d3d1]1174             
[61cada5]1175        except:
[b63dc6e]1176            self.call_back(format=ext)
[61cada5]1177            raise
1178           
1179    def write(self, filename, datainfo=None, fitstate=None):
1180        """
[b35d3d1]1181        Write the content of a Data1D as a CanSAS XML file only for standalone
[5062bbf]1182       
1183        :param filename: name of the file to write
1184        :param datainfo: Data1D object
1185        :param fitstate: PageState object
1186       
[61cada5]1187        """
1188        # Sanity check
1189        if self.cansas == True:
1190           
1191            # Add fitting information to the XML document
[ef16f59]1192            doc = self.write_toXML(datainfo, fitstate)
[61cada5]1193            # Write the XML document
1194            fd = open(filename, 'w')
1195            fd.write(doc.toprettyxml())
1196            fd.close()
1197        else:
1198            fitstate.toXML(file=filename)
1199       
[b35d3d1]1200    def write_toXML(self, datainfo=None, state=None):
1201        """
1202        Write toXML, a helper for write() , could be used by guimanager._on_save()
1203       
1204        : return: xml doc
1205        """
[3c44c66]1206
[b35d3d1]1207        if state.data is None:
1208            data = DataLoader.data_info.Data1D(x=[], y=[]) 
1209        else: 
1210            #make sure title and data run is filled up.
[028a0e8]1211            if state.data.title == None or state.data.title=='': state.data.title = state.data.name
1212            if state.data.run_name == None or state.data.run_name=={}: 
1213                state.data.run = [str(state.data.name)]
1214                state.data.run_name[0] = state.data.name
[b35d3d1]1215   
1216            if issubclass(state.data.__class__, DataLoader.data_info.Data1D):
[028a0e8]1217
[b35d3d1]1218                data = state.data
1219                doc, sasentry = self._to_xml_doc(data)
1220            else:
1221                data = state.data
1222                doc, sasentry = self._data2d_to_xml_doc(data)
1223           
1224
1225        if state is not None:
1226            state.toXML(doc=doc, file=data.name, entry_node=sasentry)
1227           
1228        return doc
[5062bbf]1229 
[3c44c66]1230if __name__ == "__main__":
1231    state = PageState(parent=None)
1232    #state.toXML()
1233    """
[5062bbf]1234   
[3c44c66]1235    file = open("test_state", "w")
1236    pickle.dump(state, file)
1237    print pickle.dumps(state)
1238    state.data_name = "hello---->"
1239    pickle.dump(state, file)
1240    file = open("test_state", "r")
1241    new_state= pickle.load(file)
1242    print "new state", new_state
1243    new_state= pickle.load(file)
1244    print "new state", new_state
1245    #print "state", state
1246    """
1247    import bsddb
1248    import pickle
1249    db= bsddb.btopen('file_state.db', 'c')
1250    val = (pickle.dumps(state), "hello", "hi")
1251    db['state1']= pickle.dumps(val)
1252    print pickle.loads(db['state1'])
1253    state.data_name = "hello---->22"
1254    db['state2']= pickle.dumps(state)
1255    state.data_name = "hello---->2"
1256    db['state3']= pickle.dumps(state)
1257    del db['state3']
1258    state.data_name = "hello---->3"
1259    db['state4']= pickle.dumps(state)
1260    new_state = pickle.loads(db['state1'])
1261    #print db.last()
1262    db.set_location('state2')
1263    state.data_name = "hello---->5"
1264    db['aastate5']= pickle.dumps(state)
1265    db.keys().sort()
1266    print pickle.loads(db['state2'])
1267 
1268    db.close()
Note: See TracBrowser for help on using the repository browser.