source: sasview/sansview/perspectives/fitting/pagestate.py @ 1b17a64

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 1b17a64 was 3ad91de, checked in by Gervaise Alina <gervyh@…>, 15 years ago

working on save state

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