source: sasview/sansview/perspectives/fitting/pagestate.py @ 26f3dd5

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

working on save option

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