source: sasview/sansview/perspectives/fitting/pagestate.py @ 61cada5

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 61cada5 was 61cada5, checked in by Gervaise Alina <gervyh@…>, 14 years ago

working on save state of fit page

  • Property mode set to 100644
File size: 32.9 KB
Line 
1import time, os, sys
2import logging
3import DataLoader
4from xml.dom.minidom import parse
5from lxml import etree
6
7
8import copy
9
10from DataLoader.readers.cansas_reader import Reader as CansasReader
11from DataLoader.readers.cansas_reader import get_content
12
13FITTING_NODE_NAME = 'fitting_plug_in'
14CANSAS_NS = "cansas1d/1.0"
15
16list_of_state_attributes = [["is_data", "is_data", "bool"],
17                      ["group_id", "data_group_id", "string"],
18                      ["data_name", "data_name", "string"],
19                      ["data_id", "data_id", "string"],
20                      ["name", "name", "string"],
21                      ["data_name", "data_name", "string"],
22                      ["qmin", "qmin", "float"],
23                      ["qmax", "qmax", "float"],
24                      ["npts", "npts", "float"],
25                      ["shape_rbutton", "shape_rbutton", "bool"],
26                      ["shape_indep_rbutton", "shape_indep_rbutton", "bool"],
27                      ["plugin_rbutton", "plugin_rbutton","bool"],
28                      ["struct_rbutton", "struct_rbutton", "bool"],
29                      ["formfactorcombobox", "formfactorcombobox", "bool"],
30                      ["structurecombobox", "structurecombobox", "bool"],
31                      ["disp_box", "disp_box"]]
32list_of_state_parameters = [["parameters", "parameters"] ,                     
33                            ["orientation_parameters", "orientation_params"],
34                            ["dispersity_parameters", "orientation_params_disp"],
35                            ["fixed_param", "fixed_param"],                     
36                            ["fittable_param","fittable_param"]]
37
38class PageState(object):
39    """
40        Contains information to reconstruct a page of the fitpanel
41    """
42    def __init__(self, parent=None, model=None, data=None):
43       
44        """
45            Initialize the current state
46        """
47        self.file = None
48        #TODO: remove this once the inheritence is cleaned up
49        ## Data member to store the dispersion object created
50        self._disp_obj_dict = {}
51        #------------------------
52        #Data used for fitting
53        self.data = data
54        #save additional information on data that dataloader.reader does not read
55        self.is_data = None
56        self.data_name = ""
57       
58        if self.data is not None:
59            self.data_name = self.data.name
60        self.data_id = None
61        if self.data is not None and hasattr(self.data, "id"):
62            self.data_id = self.data.id
63        self.data_group_id = None
64        if self.data is not None and hasattr(self.data, "group_id"):
65            self.data_group_id = self.data.group_id
66        #-------------------------
67        ## reset True change the state of exsiting button
68        self.reset = False
69       
70        #engine type
71        self.engine_type = None
72        # flag to allow data2D plot
73        self.enable2D = False
74        # model on which the fit would be performed
75        self.model = model
76       
77        #fit page manager
78        self.manager = None
79        #Store the parent of this panel parent
80        # For this application fitpanel is the parent
81        self.parent  = parent
82        # Event_owner is the owner of model event
83        self.event_owner = None
84        ##page name
85        self.page_name = ""
86        # Contains link between  model ,all its parameters, and panel organization
87        self.parameters = []
88        # Contains list of parameters that cannot be fitted and reference to
89        #panel objects
90        self.fixed_param = []
91        # Contains list of parameters with dispersity and reference to
92        #panel objects
93        self.fittable_param = []
94        ## orientation parameters
95        self.orientation_params = []
96        ## orientation parmaters for gaussian dispersity
97        self.orientation_params_disp = []
98        ## smearer info
99        self.smearer = None
100        self.smear_type = None
101        self.dq_l = None
102        self.dq_r = None
103
104        #list of dispersion paramaters
105        self.disp_list =[]
106        if self.model is not None:
107            self.disp_list = self.model.getDispParamList()
108        self._disp_obj_dict = {}
109        self.disp_cb_dict = {}
110        self.values = []
111        self.weights = []
112                   
113        #contains link between a model and selected parameters to fit
114        self.param_toFit = []
115        ##dictionary of model type and model class
116        self.model_list_box = None
117        ## save the state of the context menu
118        self.saved_states = {}
119        ## save selection of combobox
120        self.formfactorcombobox = None
121        self.structurecombobox  = None
122        ## radio box to select type of model
123        self.shape_rbutton = False
124        self.shape_indep_rbutton = False
125        self.struct_rbutton = False
126        self.plugin_rbutton = False
127        ## the indice of the current selection
128        self.disp_box = 0
129        ## Qrange
130        ## Q range
131        self.qmin = 0.001
132        self.qmax = 0.1
133        self.npts = None
134        self.name = ""
135        ## enable smearering state
136        self.enable_smearer = False
137        self.disable_smearer = True
138        self.pinhole_smearer = False
139        self.slit_smearer   = False
140        ## disperity selection
141        self.enable_disp = False
142        self.disable_disp = True
143        ## plot 2D data
144        self.enable2D = False
145        ## state of selected all check button
146        self.cb1 = False
147        ## store value of chisqr
148        self.tcChi = None
149   
150    def clone(self):
151        """
152            Create a new copy of the current object
153        """
154        model = None
155        if self.model is not None:
156            model = self.model.clone()
157       
158        obj = PageState(self.parent, model=model)
159        obj.file = copy.deepcopy(self.file)
160        obj.data = copy.deepcopy(self.data)
161        if self.data is not None:
162            self.data_name = self.data.name
163        obj.data_name = self.data_name
164        obj.is_data = self.is_data
165        obj.model_list_box = copy.deepcopy(self.model_list_box)
166        obj.engine_type = copy.deepcopy(self.engine_type)
167       
168        obj.formfactorcombobox = self.formfactorcombobox
169        obj.structurecombobox  = self.structurecombobox 
170       
171        obj.shape_rbutton = self.shape_rbutton
172        obj.shape_indep_rbutton = self.shape_indep_rbutton
173        obj.struct_rbutton = self.struct_rbutton
174        obj.plugin_rbutton = self.plugin_rbutton
175       
176        obj.manager = self.manager
177        obj.event_owner = self.event_owner
178        obj.disp_list = copy.deepcopy(self.disp_list)
179       
180        obj.enable2D = copy.deepcopy(self.enable2D)
181        obj.parameters = copy.deepcopy(self.parameters)
182        obj.fixed_param = copy.deepcopy(self.fixed_param)
183        obj.fittable_param = copy.deepcopy(self.fittable_param)
184        obj.orientation_params =  copy.deepcopy(self.orientation_params)
185        obj.orientation_params_disp =  copy.deepcopy(self.orientation_params_disp)
186        obj.enable_disp = copy.deepcopy(self.enable_disp)
187        obj.disable_disp = copy.deepcopy(self.disable_disp)
188        obj.tcChi = self.tcChi
189 
190        if len(self._disp_obj_dict)>0:
191            for k , v in self._disp_obj_dict.iteritems():
192                obj._disp_obj_dict[k]= v
193        if len(self.disp_cb_dict)>0:
194            for k , v in self.disp_cb_dict.iteritems():
195                obj.disp_cb_dict[k]= v
196               
197        obj.values = copy.deepcopy(self.values)
198        obj.weights = copy.deepcopy(self.weights)
199        obj.enable_smearer = copy.deepcopy(self.enable_smearer)
200        obj.disable_smearer = copy.deepcopy(self.disable_smearer)
201        obj.pinhole_smearer = copy.deepcopy(self.pinhole_smearer)
202        obj.slit_smearer = copy.deepcopy(self.slit_smearer)
203        obj.smear_type = copy.deepcopy(self.smear_type)
204        obj.dq_l = copy.deepcopy(self.dq_l)
205        obj.dq_r = copy.deepcopy(self.dq_r)
206
207        obj.disp_box = copy.deepcopy(self.disp_box)
208        obj.qmin = copy.deepcopy(self.qmin)
209        obj.qmax = copy.deepcopy(self.qmax)
210        obj.npts = copy.deepcopy(self.npts )
211        obj.cb1 = copy.deepcopy(self.cb1)
212        obj.smearer = copy.deepcopy(self.smearer)
213       
214        for name, state in self.saved_states.iteritems():
215            copy_name = copy.deepcopy(name)
216            copy_state = state.clone()
217            obj.saved_states[copy_name]= copy_state
218        return obj
219   
220    def _repr_helper(self, list, rep):
221        """
222        """
223        for item in list:
224            rep += "parameter name: %s \n"%str(item[1])
225            rep += "value: %s\n"%str(item[2])
226            rep += "selected: %s\n"%str(item[0])
227            rep += "error displayed : %s \n"%str(item[4][0])
228            rep += "error value:%s \n"%str(item[4][1])
229            rep += "minimum displayed : %s \n"%str(item[5][0])
230            rep += "minimum value : %s \n"%str(item[5][1])
231            rep += "maximum displayed : %s \n"%str(item[6][0])
232            rep += "maximum value : %s \n"%str(item[6][1])
233            rep += "parameter unit: %s\n\n"%str(item[7])
234        return rep
235   
236    def __repr__(self):
237        """ output string for printing"""
238        rep = "\n\nState name: %s\n"%self.name
239        rep += "\n\nState form factor combobox selection: %s\n"%self.formfactorcombobox
240        rep += "\n\nState structure factor combobox selection: %s\n"%self.structurecombobox
241        rep += "\n\n is data : %s\n"%self.is_data
242        rep += "\n\n data's name : %s\n"%self.data_name
243        rep += "\n\n data's id : %s\n"%self.data_id
244        rep += "\n\n model type (form factor) selected: %s\n"%self.shape_rbutton
245        rep += "\n\n model type (shape independent) selected: %s\n "%self.shape_indep_rbutton
246        rep += "\n\n model type (structure factor) selected: %s\n"%self.struct_rbutton
247        rep += "\n\n model type (plug-in ) selected: %s\n"%self.plugin_rbutton
248        #rep +="data : %s\n"% str(self.data)
249        #rep += "Plotting Range: min: %s, max: %s, steps: %s\n"%(str(self.qmin),
250        #                                        str(self.qmax),str(self.npts))
251        #rep +="model  : %s\n\n"% str(self.model)
252        #rep +="number parameters(self.parameters): %s\n"%len(self.parameters)
253        #rep += self._repr_helper( list=self.parameters, rep=rep)
254        #rep +="number orientation parameters"
255        #rep +="(self.orientation_params): %s\n"%len(self.orientation_params)
256        #rep += self._repr_helper( list=self.orientation_params, rep=rep)
257        #rep +="number dispersity parameters"
258        #rep +="(self.orientation_params_disp): %s\n"%len(self.orientation_params_disp)
259        #rep += self._repr_helper( list=self.orientation_params_disp, rep=rep)
260       
261        return rep
262   
263    def _toXML_helper(self, list, element, newdoc):
264        """
265        """
266        for item in list:
267            sub_element = newdoc.createElement('parameter')
268            sub_element.setAttribute('name', str(item[1]))
269            sub_element.setAttribute('value', str(item[2]))
270            sub_element.setAttribute('selected_to_fit', str(item[0]))
271            sub_element.setAttribute('error_displayed', str(item[4][0]))
272            sub_element.setAttribute('error_value', str(item[4][1]))
273            sub_element.setAttribute('minimum_displayed', str(item[5][0]))
274            sub_element.setAttribute('minimum_value', str(item[5][1]))
275            sub_element.setAttribute('maximum_displayed', str(item[6][0]))
276            sub_element.setAttribute('maximum_value', str(item[6][1]))
277            sub_element.setAttribute('unit', str(item[7]))
278            element.appendChild(sub_element)
279       
280           
281    def toXML(self, file="fitting_state.fitv", doc=None, entry_node=None):
282        """
283            Writes the state of the InversionControl panel to file, as XML.
284           
285            Compatible with standalone writing, or appending to an
286            already existing XML document. In that case, the XML document
287            is required. An optional entry node in the XML document may also be given.
288           
289            @param file: file to write to
290            @param doc: XML document object [optional]
291            @param entry_node: XML node within the XML document at which we will append the data [optional]
292        """
293        from xml.dom.minidom import getDOMImplementation
294
295        # Check whether we have to write a standalone XML file
296        if doc is None:
297            impl = getDOMImplementation()
298            doc_type = impl.createDocumentType(FITTING_NODE_NAME, "1.0", "1.0")     
299            newdoc = impl.createDocument(None, FITTING_NODE_NAME, doc_type)
300            top_element = newdoc.documentElement
301        else:
302            # We are appending to an existing document
303            newdoc = doc
304            top_element = newdoc.createElement(FITTING_NODE_NAME)
305            if entry_node is None:
306                newdoc.documentElement.appendChild(top_element)
307            else:
308                entry_node.appendChild(top_element)
309           
310        attr = newdoc.createAttribute("version")
311        attr.nodeValue = '1.0'
312        top_element.setAttributeNode(attr)
313       
314        # File name
315        element = newdoc.createElement("filename")
316        if self.file is not None:
317            element.appendChild(newdoc.createTextNode(str(self.file)))
318        else:
319            element.appendChild(newdoc.createTextNode(str(file)))
320        top_element.appendChild(element)
321   
322        # Inputs
323        inputs = newdoc.createElement("Attributes")
324        top_element.appendChild(inputs)
325       
326        element = newdoc.createElement('data_attributes')
327        if self.data is not None and hasattr(self.data, "group_id"):
328            self.data_group_id = self.data.group_id
329        if self.data is not None and hasattr(self.data, "is_data"):
330            self.is_data = self.data.is_data
331        if self.data is not None:
332            self.data_name = self.data.name
333        if self.data is not None and hasattr(self.data, "id"):
334            self.data_id = self.data.id
335       
336        for item in list_of_state_attributes:
337            exec "element.setAttribute(item[0], str(self.%s))"%(item[1])
338        inputs.appendChild(element)   
339       
340        for item in list_of_state_parameters:
341            element = newdoc.createElement(item[0])
342            exec "self._toXML_helper(list=self.%s, element=element, newdoc=newdoc)"%item[1]                       
343            inputs.appendChild(element)
344       
345        # Save the file
346        if doc is None:
347            fd = open(file, 'w')
348            fd.write(newdoc.toprettyxml())
349            fd.close()
350            return None
351        else:
352            return newdoc.toprettyxml()
353       
354    def _fromXML_helper(self, node, list):
355        """
356        """
357        for item in node:
358            name = item.get('name')
359            value = item.get('value')
360            selected_to_fit = item.get('selected_to_fit')
361            error_displayed = item.get('error_displayed')
362            error_value = item.get('error_value')
363            minimum_displayed = item.get('minimum_displayed')
364            minimum_value = item.get('minimum_value')
365            maximum_displayed = item.get('maximum_displayed')
366            maximum_value = item.get('maximum_value')
367            unit = item.get('unit')
368            list.append([selected_to_fit, name, value, "+/-",[error_displayed, error_value],
369                         [minimum_displayed,minimum_value],[maximum_displayed,maximum_value], unit])
370       
371    def fromXML(self, file=None, node=None):
372        """
373            Load fitting state from a file
374           
375            @param file: .fitv file
376            @param node: node of a XML document to read from
377        """
378     
379        if file is not None:
380            raise RuntimeError, "PageState no longer supports non-CanSAS format for fitting files"
381           
382        if node.get('version')\
383            and node.get('version') == '1.0':
384           
385            # Get file name
386            entry = get_content('ns:filename', node)
387            if entry is not None:
388                self.file = entry.text.strip()
389       
390            # Parse fitting attributes
391            entry = get_content('ns:Attributes', node)
392            if entry is not None:
393                for item in list_of_state_attributes:
394                    field = get_content('ns:%s'%item[0], entry)
395                    if field is not None:
396                        if item[2] == "string":
397                            exec "self.%s= str(field.text)"%item[1]
398                        elif item[2] == "bool":
399                            try:
400                                exec "self.%s= field.get(str(%s))"%(item[1], item[0])
401                            except:
402                                exec "self.%s = None"%item[1]
403                        else:
404                            try:
405                                exec "self.%s = float(field.get(%s))"%(item[1], item[0])
406                            except:
407                                exec "self.%s = None"%item[1]
408               
409                for item in list_of_state_parameters:
410                    field = get_content("ns:%s"%item[0], entry)
411                    self._fromXML_helper(node=field, list=self.parameters)
412               
413
414class Reader(CansasReader):
415    """
416        Class to load a .fitv fitting file
417    """
418    ## File type
419    type_name = "Fitting"
420   
421    ## Wildcards
422    type = ["Fitting files (*.fitv)|*.fitv"]
423    ## List of allowed extensions
424    ext=['.fitv', '.FITV'] 
425   
426    def __init__(self, call_back=None, cansas=True):
427        """
428            Initialize the call-back method to be called
429            after we load a file
430            @param call_back: call-back method
431            @param cansas:  True = files will be written/read in CanSAS format
432                            False = write CanSAS format
433           
434        """
435        ## Call back method to be executed after a file is read
436        self.call_back = call_back
437        ## CanSAS format flag
438        self.cansas = cansas
439       
440    def read(self, path):
441        """
442            Load a new P(r) inversion state from file
443           
444            @param path: file path
445            @return: None
446        """
447        if self.cansas==True:
448            return self._read_cansas(path)
449        else:
450            return self._read_standalone(path)
451       
452    def _data2d_to_xml_doc(self):
453        """
454            Create an XML document to contain the content of a Data2D
455           
456            @param datainfo: Data2D object
457        """
458        if not issubclass(datainfo.__class__, Data2D):
459            raise RuntimeError, "The cansas writer expects a Data2D instance"
460       
461        doc = xml.dom.minidom.Document()
462        main_node = doc.createElement("SASroot")
463        main_node.setAttribute("version", self.version)
464     
465        doc.appendChild(main_node)
466       
467        entry_node = doc.createElement("SASentry")
468        main_node.appendChild(entry_node)
469       
470        write_node(doc, entry_node, "Title", datainfo.title)
471       
472        for item in datainfo.run:
473            runname = {}
474            if datainfo.run_name.has_key(item) and len(str(datainfo.run_name[item]))>1:
475                runname = {'name': datainfo.run_name[item] }
476            write_node(doc, entry_node, "Run", item, runname)
477       
478        # Data info
479        node = doc.createElement("SASdata")
480        entry_node.appendChild(node)
481       
482        for i in range(len(datainfo.x)):
483            pt = doc.createElement("Idata")
484            node.appendChild(pt)
485            write_node(doc, pt, "Q", datainfo.x[i], {'unit':datainfo.x_unit})
486            if len(datainfo.y)>=i:
487                write_node(doc, pt, "I", datainfo.y[i], {'unit':datainfo.y_unit})
488            if datainfo.dx !=None and len(datainfo.dx)>=i:
489                write_node(doc, pt, "Qdev", datainfo.dx[i], {'unit':datainfo.x_unit})
490            if datainfo.dy !=None and len(datainfo.dy)>=i:
491                write_node(doc, pt, "Idev", datainfo.dy[i], {'unit':datainfo.y_unit})
492
493       
494        # Sample info
495        sample = doc.createElement("SASsample")
496        if datainfo.sample.name is not None:
497            sample.setAttribute("name", str(datainfo.sample.name))
498        entry_node.appendChild(sample)
499        write_node(doc, sample, "ID", str(datainfo.sample.ID))
500        write_node(doc, sample, "thickness", datainfo.sample.thickness, {"unit":datainfo.sample.thickness_unit})
501        write_node(doc, sample, "transmission", datainfo.sample.transmission)
502        write_node(doc, sample, "temperature", datainfo.sample.temperature, {"unit":datainfo.sample.temperature_unit})
503       
504        for item in datainfo.sample.details:
505            write_node(doc, sample, "details", item)
506       
507        pos = doc.createElement("position")
508        written = write_node(doc, pos, "x", datainfo.sample.position.x, {"unit":datainfo.sample.position_unit})
509        written = written | write_node(doc, pos, "y", datainfo.sample.position.y, {"unit":datainfo.sample.position_unit})
510        written = written | write_node(doc, pos, "z", datainfo.sample.position.z, {"unit":datainfo.sample.position_unit})
511        if written == True:
512            sample.appendChild(pos)
513       
514        ori = doc.createElement("orientation")
515        written = write_node(doc, ori, "roll",  datainfo.sample.orientation.x, {"unit":datainfo.sample.orientation_unit})
516        written = written | write_node(doc, ori, "pitch", datainfo.sample.orientation.y, {"unit":datainfo.sample.orientation_unit})
517        written = written | write_node(doc, ori, "yaw",   datainfo.sample.orientation.z, {"unit":datainfo.sample.orientation_unit})
518        if written == True:
519            sample.appendChild(ori)
520       
521        # Instrument info
522        instr = doc.createElement("SASinstrument")
523        entry_node.appendChild(instr)
524       
525        write_node(doc, instr, "name", datainfo.instrument)
526       
527        #   Source
528        source = doc.createElement("SASsource")
529        if datainfo.source.name is not None:
530            source.setAttribute("name", str(datainfo.source.name))
531        instr.appendChild(source)
532       
533        write_node(doc, source, "radiation", datainfo.source.radiation)
534        write_node(doc, source, "beam_shape", datainfo.source.beam_shape)
535        size = doc.createElement("beam_size")
536        if datainfo.source.beam_size_name is not None:
537            size.setAttribute("name", str(datainfo.source.beam_size_name))
538        written = write_node(doc, size, "x", datainfo.source.beam_size.x, {"unit":datainfo.source.beam_size_unit})
539        written = written | write_node(doc, size, "y", datainfo.source.beam_size.y, {"unit":datainfo.source.beam_size_unit})
540        written = written | write_node(doc, size, "z", datainfo.source.beam_size.z, {"unit":datainfo.source.beam_size_unit})
541        if written == True:
542            source.appendChild(size)
543           
544        write_node(doc, source, "wavelength", datainfo.source.wavelength, {"unit":datainfo.source.wavelength_unit})
545        write_node(doc, source, "wavelength_min", datainfo.source.wavelength_min, {"unit":datainfo.source.wavelength_min_unit})
546        write_node(doc, source, "wavelength_max", datainfo.source.wavelength_max, {"unit":datainfo.source.wavelength_max_unit})
547        write_node(doc, source, "wavelength_spread", datainfo.source.wavelength_spread, {"unit":datainfo.source.wavelength_spread_unit})
548       
549        #   Collimation
550        for item in datainfo.collimation:
551            coll = doc.createElement("SAScollimation")
552            if item.name is not None:
553                coll.setAttribute("name", str(item.name))
554            instr.appendChild(coll)
555           
556            write_node(doc, coll, "length", item.length, {"unit":item.length_unit})
557           
558            for apert in item.aperture:
559                ap = doc.createElement("aperture")
560                if apert.name is not None:
561                    ap.setAttribute("name", str(apert.name))
562                if apert.type is not None:
563                    ap.setAttribute("type", str(apert.type))
564                coll.appendChild(ap)
565               
566                write_node(doc, ap, "distance", apert.distance, {"unit":apert.distance_unit})
567               
568                size = doc.createElement("size")
569                if apert.size_name is not None:
570                    size.setAttribute("name", str(apert.size_name))
571                written = write_node(doc, size, "x", apert.size.x, {"unit":apert.size_unit})
572                written = written | write_node(doc, size, "y", apert.size.y, {"unit":apert.size_unit})
573                written = written | write_node(doc, size, "z", apert.size.z, {"unit":apert.size_unit})
574                if written == True:
575                    ap.appendChild(size)
576
577        #   Detectors
578        for item in datainfo.detector:
579            det = doc.createElement("SASdetector")
580            written = write_node(doc, det, "name", item.name)
581            written = written | write_node(doc, det, "SDD", item.distance, {"unit":item.distance_unit})
582            written = written | write_node(doc, det, "slit_length", item.slit_length, {"unit":item.slit_length_unit})
583            if written == True:
584                instr.appendChild(det)
585           
586            off = doc.createElement("offset")
587            written = write_node(doc, off, "x", item.offset.x, {"unit":item.offset_unit})
588            written = written | write_node(doc, off, "y", item.offset.y, {"unit":item.offset_unit})
589            written = written | write_node(doc, off, "z", item.offset.z, {"unit":item.offset_unit})
590            if written == True:
591                det.appendChild(off)
592           
593            center = doc.createElement("beam_center")
594            written = write_node(doc, center, "x", item.beam_center.x, {"unit":item.beam_center_unit})
595            written = written | write_node(doc, center, "y", item.beam_center.y, {"unit":item.beam_center_unit})
596            written = written | write_node(doc, center, "z", item.beam_center.z, {"unit":item.beam_center_unit})
597            if written == True:
598                det.appendChild(center)
599               
600            pix = doc.createElement("pixel_size")
601            written = write_node(doc, pix, "x", item.pixel_size.x, {"unit":item.pixel_size_unit})
602            written = written | write_node(doc, pix, "y", item.pixel_size.y, {"unit":item.pixel_size_unit})
603            written = written | write_node(doc, pix, "z", item.pixel_size.z, {"unit":item.pixel_size_unit})
604            if written == True:
605                det.appendChild(pix)
606               
607            ori = doc.createElement("orientation")
608            written = write_node(doc, ori, "roll",  item.orientation.x, {"unit":item.orientation_unit})
609            written = written | write_node(doc, ori, "pitch", item.orientation.y, {"unit":item.orientation_unit})
610            written = written | write_node(doc, ori, "yaw",   item.orientation.z, {"unit":item.orientation_unit})
611            if written == True:
612                det.appendChild(ori)
613               
614       
615        # Processes info
616        for item in datainfo.process:
617            node = doc.createElement("SASprocess")
618            entry_node.appendChild(node)
619
620            write_node(doc, node, "name", item.name)
621            write_node(doc, node, "date", item.date)
622            write_node(doc, node, "description", item.description)
623            for term in item.term:
624                value = term['value']
625                del term['value']
626                write_node(doc, node, "term", value, term)
627            for note in item.notes:
628                write_node(doc, node, "SASprocessnote", note)
629       
630        # Return the document, and the SASentry node associated with
631        # the data we just wrote
632        return doc, entry_node
633   
634    def _read_standalone(self, path):
635        """
636            Load a new P(r) inversion state from file.
637            The P(r) node is assumed to be the top element.
638           
639            @param path: file path
640            @return: None
641        """
642        # Read the new state from file
643        state = PageState()
644        state.fromXML(file=path)
645        # Call back to post the new state
646        self.call_back(state)
647        return None
648   
649    def _parse_state(self, entry):
650        """
651            Read a fit result from an XML node
652            @param entry: XML node to read from
653            @return: PageState object
654        """
655        # Create an empty state
656        state = PageState()
657        # Locate the P(r) node
658        try:
659            nodes = entry.xpath('ns:%s' % FITTING_NODE_NAME, namespaces={'ns': CANSAS_NS})
660            state.fromXML(node=nodes[0])
661        except:
662            logging.info("XML document does not contain fitting information.\n %s" % sys.exc_value)
663           
664        return state
665   
666    def _read_cansas(self, path):
667        """
668            Load data and P(r) information from a CanSAS XML file.
669           
670            @param path: file path
671            @return: Data1D object if a single SASentry was found,
672                        or a list of Data1D objects if multiple entries were found,
673                        or None of nothing was found
674            @raise RuntimeError: when the file can't be opened
675            @raise ValueError: when the length of the data vectors are inconsistent
676        """
677        output = []
678        try:
679            if os.path.isfile(path):
680                basename  = os.path.basename(path)
681                root, extension = os.path.splitext(basename)
682                #TODO: eventually remove the check for .xml once
683                # the P(r) writer/reader is truly complete.
684                if  extension.lower() in self.ext or \
685                    extension.lower() == '.xml':
686                   
687                    tree = etree.parse(path, parser=etree.ETCompatXMLParser())
688                    # Check the format version number
689                    # Specifying the namespace will take care of the file format version
690                    root = tree.getroot()
691                    entry_list = root.xpath('/ns:SASroot/ns:SASentry', namespaces={'ns': CANSAS_NS})
692                    for entry in entry_list:
693                        sas_entry = self._parse_entry(entry)
694                        fitstate = self._parse_state(entry)
695                        sas_entry.meta_data['fitstate'] = fitstate
696                        sas_entry.filename = fitstate.file
697                        output.append(sas_entry)
698                   
699            else:
700                raise RuntimeError, "%s is not a file" % path
701           
702            # Return output consistent with the loader's api
703            if len(output)==0:
704                return None
705            elif len(output)==1:
706                # Call back to post the new state
707                state = output[0].meta_data['fitstate']
708                if state is not None and state.is_data is not None:
709                    exec 'output[0].is_data = state.is_data' 
710                 
711                output[0].filename = state.data_name
712                state.data = output[0]
713                state.data.name = state.data_name
714                state.data.id = state.data_id
715                state.data.group_id = state.data_group_id
716                self.call_back(state=state, datainfo=output[0])
717                return output[0]
718            else:
719                return output               
720        except:
721            raise
722           
723    def write(self, filename, datainfo=None, fitstate=None):
724        """
725            Write the content of a Data1D as a CanSAS XML file
726           
727            @param filename: name of the file to write
728            @param datainfo: Data1D object
729            @param fitstate: PageState object
730        """
731        # Sanity check
732        if self.cansas == True:
733           
734            # Add fitting information to the XML document
735            if fitstate is not None:
736                if fitstate.data is None:
737                    data = DataLoader.data_info.Data1D(x=[], y=[])   
738                elif issubclass(fitstate.data.__class__, DataLoader.data_info.Data1D):
739                    data = fitstate.data
740                    doc, sasentry = self._to_xml_doc(data)
741                else:
742                    data = fitstate.data
743                    doc, sasentry = self._data2d_to_xml_doc(data)
744                fitstate.toXML(doc=doc, entry_node=sasentry)
745            # Write the XML document
746            fd = open(filename, 'w')
747            fd.write(doc.toprettyxml())
748            fd.close()
749        else:
750            fitstate.toXML(file=filename)
751       
752       
753if __name__ == "__main__":
754    state = PageState(parent=None)
755    state.toXML()
756 
Note: See TracBrowser for help on using the repository browser.