source: sasview/DataLoader/readers/cansas_reader.py @ c35e8492

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 c35e8492 was d3966c2, checked in by Jae Cho <jhjcho@…>, 16 years ago

made it more flexible

  • Property mode set to 100644
File size: 35.1 KB
Line 
1"""
2This software was developed by the University of Tennessee as part of the
3Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
4project funded by the US National Science Foundation.
5
6See the license text in license.txt
7
8copyright 2008, University of Tennessee
9"""
10# Known issue: reader not compatible with multiple SASdata entries
11# within a single SASentry. Will raise a runtime error.
12
13#TODO: check that all vectors are written only if they have at least one non-empty value
14#TODO: Writing only allows one SASentry per file. Would be best to allow multiple entries.
15#TODO: Store error list
16#TODO: Allow for additional meta data for each section
17#TODO: Notes need to be implemented. They can be any XML structure in version 1.0
18#      Process notes have the same problem.
19#TODO: Unit conversion is not complete (temperature units are missing)
20
21
22import logging
23import numpy
24import os, sys
25from DataLoader.data_info import Data1D, Collimation, Detector, Process, Aperture
26from xml import xpath
27import xml.dom.minidom 
28
29
30has_converter = True
31try:
32    from data_util.nxsunit import Converter
33except:
34    has_converter = False
35
36def write_node(doc, parent, name, value, attr={}):
37    """
38        @param doc: document DOM
39        @param parent: parent node
40        @param name: tag of the element
41        @param value: value of the child text node
42        @param attr: attribute dictionary
43        @return: True if something was appended, otherwise False
44    """
45    if value is not None:
46        node = doc.createElement(name)
47        node.appendChild(doc.createTextNode(str(value)))
48        for item in attr:
49            node.setAttribute(item, attr[item])
50        parent.appendChild(node)
51        return True
52    return False
53
54def get_node_text(node):
55    """
56        Get the text context of a node
57       
58        @param node: node to read from
59        @return: content, attribute list
60    """
61    content = None
62    attr    = {}
63    for item in node.childNodes:
64        if item.nodeName.find('text')>=0 \
65            and len(item.nodeValue.strip())>0:
66            content = item.nodeValue.strip()
67            break
68       
69    if node.hasAttributes():
70        for i in range(node.attributes.length):
71            attr[node.attributes.item(i).nodeName] \
72                = node.attributes.item(i).nodeValue
73
74    return content, attr
75
76def get_content(location, node):
77    """
78        Get the first instance of the content of a xpath location
79       
80        @param location: xpath location
81        @param node: node to start at
82    """
83    value = None
84    attr  = {}
85    nodes = xpath.Evaluate(location, node)
86    if len(nodes)>0:
87        try:
88            # Skip comments and empty lines
89            for item in nodes[0].childNodes:
90                if item.nodeName.find('text')>=0 \
91                    and len(item.nodeValue.strip())>0:
92                    value = item.nodeValue.strip()
93                    break
94               
95            if nodes[0].hasAttributes():
96                for i in range(nodes[0].attributes.length):
97                    attr[nodes[0].attributes.item(i).nodeName] \
98                        = nodes[0].attributes.item(i).nodeValue
99        except:
100            # problem reading the node. Skip it and return that
101            # nothing was found
102            logging.error("cansas_reader.get_content: %s\n  %s" % (location, sys.exc_value))
103       
104    return value, attr
105
106def get_float(location, node):
107    """
108        Get the content of a node as a float
109       
110        @param location: xpath location
111        @param node: node to start at
112    """
113    value = None
114    attr = {}
115    content, attr = get_content(location, node)
116    if content is not None:
117        try:
118            value = float(content)   
119        except:
120            # Could not pass, skip and return None
121            logging.error("cansas_reader.get_float: could not convert '%s' to float" % content)
122       
123    return value, attr
124
125def _store_float(location, node, variable, storage):
126    """
127        Get the content of a xpath location and store
128        the result. Check that the units are compatible
129        with the destination. The value is expected to
130        be a float.
131       
132        The xpath location might or might not exist.
133        If it does not exist, nothing is done
134       
135        @param location: xpath location to fetch
136        @param node: node to read the data from
137        @param variable: name of the data member to store it in [string]
138        @param storage: data object that has the 'variable' data member
139       
140        @raise ValueError: raised when the units are not recognized
141    """
142    value, attr = get_float(location, node)
143    if value is not None:
144        # If the entry has units, check to see that they are
145        # compatible with what we currently have in the data object
146        if attr.has_key('unit'):
147            toks = variable.split('.')
148            exec "local_unit = storage.%s_unit" % toks[0]
149            if attr['unit'].lower()!=local_unit.lower():
150                if has_converter==True:
151                    try:
152                        conv = Converter(attr['unit'])
153                        exec "storage.%s = %g" % (variable, conv(value, units=local_unit))
154                    except:
155                        #Below three lines were added for the unit = 1/A. local unit is defined in 'mm'. Need to check!!!
156                        if variable == 'slit_length' and attr['unit'] !=local_unit:
157                            pass
158                        else:
159                            raise ValueError, "CanSAS reader: could not convert %s unit [%s]; expecting [%s]\n  %s" \
160                            % (variable, attr['unit'], local_unit, sys.exc_value)
161                else:
162                    raise ValueError, "CanSAS reader: unrecognized %s unit [%s]; expecting [%s]" \
163                        % (variable, attr['unit'], local_unit)
164            else:
165                exec "storage.%s = value" % variable
166        else:
167            exec "storage.%s = value" % variable
168           
169
170def _store_content(location, node, variable, storage):
171    """
172        Get the content of a xpath location and store
173        the result. The value is treated as a string.
174       
175        The xpath location might or might not exist.
176        If it does not exist, nothing is done
177       
178        @param location: xpath location to fetch
179        @param node: node to read the data from
180        @param variable: name of the data member to store it in [string]
181        @param storage: data object that has the 'variable' data member
182    """
183    value, attr = get_content(location, node)
184    if value is not None:
185        exec "storage.%s = value" % variable
186
187
188class Reader:
189    """
190        Class to load cansas 1D XML files
191       
192        Dependencies:
193            The CanSas reader requires PyXML 0.8.4 or later.
194    """
195    ## CanSAS version
196    version = '1.0'
197    ## File type
198    type = ["CanSAS 1D files (*.xml)|*.xml"]
199    ## List of allowed extensions
200    ext=['.xml', '.XML'] 
201   
202    def read(self, path):
203        """
204            Load data file
205           
206            @param path: file path
207            @return: Data1D object if a single SASentry was found,
208                        or a list of Data1D objects if multiple entries were found,
209                        or None of nothing was found
210            @raise RuntimeError: when the file can't be opened
211            @raise ValueError: when the length of the data vectors are inconsistent
212        """
213        from xml.dom.minidom import parse
214       
215        output = []
216       
217        if os.path.isfile(path):
218            basename  = os.path.basename(path)
219            root, extension = os.path.splitext(basename)
220            if extension.lower() in self.ext:
221               
222                dom = parse(path)
223               
224                # Check the format version number
225                nodes = xpath.Evaluate('SASroot', dom)
226                if nodes[0].hasAttributes():
227                    for i in range(nodes[0].attributes.length):
228                        if nodes[0].attributes.item(i).nodeName=='version':
229                            if nodes[0].attributes.item(i).nodeValue != self.version:
230                                raise ValueError, "cansas_reader: unrecognized version number %s" % \
231                                    nodes[0].attributes.item(i).nodeValue
232               
233                entry_list = xpath.Evaluate('SASroot/SASentry', dom)
234                for entry in entry_list:
235                    sas_entry = self._parse_entry(entry)
236                    sas_entry.filename = basename
237                    output.append(sas_entry)
238               
239        else:
240            raise RuntimeError, "%s is not a file" % path
241       
242        # Return output consistent with the loader's api
243        if len(output)==0:
244            return None
245        elif len(output)==1:
246            return output[0]
247        else:
248            return output               
249               
250    def _parse_entry(self, dom):
251        """
252            Parse a SASentry
253           
254            @param node: SASentry node
255            @return: Data1D object
256        """
257        x = numpy.zeros(0)
258        y = numpy.zeros(0)
259       
260        data_info = Data1D(x, y)
261       
262        # Look up title
263        _store_content('Title', dom, 'title', data_info)
264        # Look up run number   
265        nodes = xpath.Evaluate('Run', dom)
266        for item in nodes:   
267            value, attr = get_node_text(item)
268            if value is not None:
269                data_info.run.append(value)
270                if attr.has_key('name'):
271                    data_info.run_name[value] = attr['name']         
272                           
273        # Look up instrument name             
274        _store_content('SASinstrument/name', dom, 'instrument', data_info)
275        #value, attr = get_content('SASinstrument', dom)
276        #if attr.has_key('name'):
277        #    data_info.instrument = attr['name']
278
279        note_list = xpath.Evaluate('SASnote', dom)
280        for note in note_list:
281            try:
282                note_value, note_attr = get_node_text(note)
283                if note_value is not None:
284                    data_info.notes.append(note_value)
285            except:
286                logging.error("cansas_reader.read: error processing entry notes\n  %s" % sys.exc_value)
287
288       
289        # Sample info ###################
290        value, attr = get_content('SASsample', dom)
291        if attr.has_key('name'):
292            data_info.sample.name = attr['name']
293           
294        _store_content('SASsample/ID', 
295                     dom, 'ID', data_info.sample)                   
296        _store_float('SASsample/thickness', 
297                     dom, 'thickness', data_info.sample)
298        _store_float('SASsample/transmission', 
299                     dom, 'transmission', data_info.sample)
300        _store_float('SASsample/temperature', 
301                     dom, 'temperature', data_info.sample)
302        nodes = xpath.Evaluate('SASsample/details', dom)
303        for item in nodes:
304            try:
305                detail_value, detail_attr = get_node_text(item)
306                if detail_value is not None:
307                    data_info.sample.details.append(detail_value)
308            except:
309                logging.error("cansas_reader.read: error processing sample details\n  %s" % sys.exc_value)
310       
311        # Position (as a vector)
312        _store_float('SASsample/position/x', 
313                     dom, 'position.x', data_info.sample)         
314        _store_float('SASsample/position/y', 
315                     dom, 'position.y', data_info.sample)         
316        _store_float('SASsample/position/z', 
317                     dom, 'position.z', data_info.sample)         
318       
319        # Orientation (as a vector)
320        _store_float('SASsample/orientation/roll', 
321                     dom, 'orientation.x', data_info.sample)         
322        _store_float('SASsample/orientation/pitch', 
323                     dom, 'orientation.y', data_info.sample)         
324        _store_float('SASsample/orientation/yaw', 
325                     dom, 'orientation.z', data_info.sample)         
326       
327        # Source info ###################
328        value, attr = get_content('SASinstrument/SASsource', dom)
329        if attr.has_key('name'):
330            data_info.source.name = attr['name']
331       
332        _store_content('SASinstrument/SASsource/radiation', 
333                     dom, 'radiation', data_info.source)                   
334        _store_content('SASinstrument/SASsource/beam_shape', 
335                     dom, 'beam_shape', data_info.source)                   
336        _store_float('SASinstrument/SASsource/wavelength', 
337                     dom, 'wavelength', data_info.source)         
338        _store_float('SASinstrument/SASsource/wavelength_min', 
339                     dom, 'wavelength_min', data_info.source)         
340        _store_float('SASinstrument/SASsource/wavelength_max', 
341                     dom, 'wavelength_max', data_info.source)         
342        _store_float('SASinstrument/SASsource/wavelength_spread', 
343                     dom, 'wavelength_spread', data_info.source)   
344       
345        # Beam size (as a vector)   
346        value, attr = get_content('SASinstrument/SASsource/beam_size', dom)
347        if attr.has_key('name'):
348            data_info.source.beam_size_name = attr['name']
349           
350        _store_float('SASinstrument/SASsource/beam_size/x', 
351                     dom, 'beam_size.x', data_info.source)   
352        _store_float('SASinstrument/SASsource/beam_size/y', 
353                     dom, 'beam_size.y', data_info.source)   
354        _store_float('SASinstrument/SASsource/beam_size/z', 
355                     dom, 'beam_size.z', data_info.source)   
356       
357        # Collimation info ###################
358        nodes = xpath.Evaluate('SASinstrument/SAScollimation', dom)
359        for item in nodes:
360            collim = Collimation()
361            value, attr = get_node_text(item)
362            if attr.has_key('name'):
363                collim.name = attr['name']
364            _store_float('length', item, 'length', collim) 
365           
366            # Look for apertures
367            apert_list = xpath.Evaluate('aperture', item)
368            for apert in apert_list:
369                aperture =  Aperture()
370               
371                # Get the name and type of the aperture
372                ap_value, ap_attr = get_node_text(apert)
373                if ap_attr.has_key('name'):
374                    aperture.name = ap_attr['name']
375                if ap_attr.has_key('type'):
376                    aperture.type = ap_attr['type']
377                   
378                _store_float('distance', apert, 'distance', aperture)   
379               
380                value, attr = get_content('size', apert)
381                if attr.has_key('name'):
382                    aperture.size_name = attr['name']
383               
384                _store_float('size/x', apert, 'size.x', aperture)   
385                _store_float('size/y', apert, 'size.y', aperture)   
386                _store_float('size/z', apert, 'size.z', aperture)
387               
388                collim.aperture.append(aperture)
389               
390            data_info.collimation.append(collim)
391       
392        # Detector info ######################
393        nodes = xpath.Evaluate('SASinstrument/SASdetector', dom)
394        for item in nodes:
395           
396            detector = Detector()
397           
398            _store_content('name', item, 'name', detector)
399            _store_float('SDD', item, 'distance', detector)   
400           
401            # Detector offset (as a vector)
402            _store_float('offset/x', item, 'offset.x', detector)   
403            _store_float('offset/y', item, 'offset.y', detector)   
404            _store_float('offset/z', item, 'offset.z', detector)   
405           
406            # Detector orientation (as a vector)
407            _store_float('orientation/roll',  item, 'orientation.x', detector)   
408            _store_float('orientation/pitch', item, 'orientation.y', detector)   
409            _store_float('orientation/yaw',   item, 'orientation.z', detector)   
410           
411            # Beam center (as a vector)
412            _store_float('beam_center/x', item, 'beam_center.x', detector)   
413            _store_float('beam_center/y', item, 'beam_center.y', detector)   
414            _store_float('beam_center/z', item, 'beam_center.z', detector)   
415           
416            # Pixel size (as a vector)
417            _store_float('pixel_size/x', item, 'pixel_size.x', detector)   
418            _store_float('pixel_size/y', item, 'pixel_size.y', detector)   
419            _store_float('pixel_size/z', item, 'pixel_size.z', detector)   
420           
421            _store_float('slit_length', item, 'slit_length', detector)
422           
423            data_info.detector.append(detector)   
424
425        # Processes info ######################
426        nodes = xpath.Evaluate('SASprocess', dom)
427        for item in nodes:
428            process = Process()
429            _store_content('name', item, 'name', process)
430            _store_content('date', item, 'date', process)
431            _store_content('description', item, 'description', process)
432           
433            term_list = xpath.Evaluate('term', item)
434            for term in term_list:
435                try:
436                    term_value, term_attr = get_node_text(term)
437                    term_attr['value'] = term_value
438                    if term_value is not None:
439                        process.term.append(term_attr)
440                except:
441                    logging.error("cansas_reader.read: error processing process term\n  %s" % sys.exc_value)
442           
443            note_list = xpath.Evaluate('SASprocessnote', item)
444            for note in note_list:
445                try:
446                    note_value, note_attr = get_node_text(note)
447                    if note_value is not None:
448                        process.notes.append(note_value)
449                except:
450                    logging.error("cansas_reader.read: error processing process notes\n  %s" % sys.exc_value)
451           
452           
453            data_info.process.append(process)
454           
455           
456        # Data info ######################
457        nodes = xpath.Evaluate('SASdata', dom)
458        if len(nodes)>1:
459            raise RuntimeError, "CanSAS reader is not compatible with multiple SASdata entries"
460       
461        nodes = xpath.Evaluate('SASdata/Idata', dom)
462        x  = numpy.zeros(0)
463        y  = numpy.zeros(0)
464        dx = numpy.zeros(0)
465        dy = numpy.zeros(0)
466        dxw = numpy.zeros(0)
467        dxl = numpy.zeros(0)
468       
469        for item in nodes:
470            _x, attr = get_float('Q', item)
471            _dx, attr_d = get_float('Qdev', item)
472            _dxl, attr_l = get_float('dQl', item)
473            _dxw, attr_w = get_float('dQw', item)
474            if _dx == None:
475                _dx = 0.0
476            if _dxl == None:
477                _dxl = 0.0
478            if _dxw == None:
479                _dxw = 0.0
480               
481            if attr.has_key('unit') and attr['unit'].lower() != data_info.x_unit.lower():
482                if has_converter==True:
483                    try:
484                        data_conv_q = Converter(attr['unit'])
485                        _x = data_conv_q(_x, units=data_info.x_unit)
486                    except:
487                        raise ValueError, "CanSAS reader: could not convert Q unit [%s]; expecting [%s]\n  %s" \
488                        % (attr['unit'], data_info.x_unit, sys.exc_value)
489                else:
490                    raise ValueError, "CanSAS reader: unrecognized Q unit [%s]; expecting [%s]" \
491                        % (attr['unit'], data_info.x_unit)
492            # Error in Q
493            if attr_d.has_key('unit') and attr_d['unit'].lower() != data_info.x_unit.lower():
494                if has_converter==True:
495                    try:
496                        data_conv_q = Converter(attr_d['unit'])
497                        _dx = data_conv_q(_dx, units=data_info.x_unit)
498                    except:
499                        raise ValueError, "CanSAS reader: could not convert dQ unit [%s]; expecting [%s]\n  %s" \
500                        % (attr['unit'], data_info.x_unit, sys.exc_value)
501                else:
502                    raise ValueError, "CanSAS reader: unrecognized dQ unit [%s]; expecting [%s]" \
503                        % (attr['unit'], data_info.x_unit)
504            # Slit length
505            if attr_l.has_key('unit') and attr_l['unit'].lower() != data_info.x_unit.lower():
506                if has_converter==True:
507                    try:
508                        data_conv_q = Converter(attr_l['unit'])
509                        _dxl = data_conv_q(_dxl, units=data_info.x_unit)
510                    except:
511                        raise ValueError, "CanSAS reader: could not convert dQl unit [%s]; expecting [%s]\n  %s" \
512                        % (attr['unit'], data_info.x_unit, sys.exc_value)
513                else:
514                    raise ValueError, "CanSAS reader: unrecognized dQl unit [%s]; expecting [%s]" \
515                        % (attr['unit'], data_info.x_unit)
516            # Slit width
517            if attr_w.has_key('unit') and attr_w['unit'].lower() != data_info.x_unit.lower():
518                if has_converter==True:
519                    try:
520                        data_conv_q = Converter(attr_w['unit'])
521                        _dxw = data_conv_q(_dxw, units=data_info.x_unit)
522                    except:
523                        raise ValueError, "CanSAS reader: could not convert dQw unit [%s]; expecting [%s]\n  %s" \
524                        % (attr['unit'], data_info.x_unit, sys.exc_value)
525                else:
526                    raise ValueError, "CanSAS reader: unrecognized dQw unit [%s]; expecting [%s]" \
527                        % (attr['unit'], data_info.x_unit)
528                   
529            _y, attr = get_float('I', item)
530            _dy, attr_d = get_float('Idev', item)
531            if _dy == None:
532                _dy = 0.0
533            if attr.has_key('unit') and attr['unit'].lower() != data_info.y_unit.lower():
534                if has_converter==True:
535                    try:
536                        data_conv_i = Converter(attr['unit'])
537                        _y = data_conv_i(_y, units=data_info.y_unit)
538                    except:
539                        raise ValueError, "CanSAS reader: could not convert I(q) unit [%s]; expecting [%s]\n  %s" \
540                        % (attr['unit'], data_info.y_unit, sys.exc_value)
541                else:
542                    raise ValueError, "CanSAS reader: unrecognized I(q) unit [%s]; expecting [%s]" \
543                        % (attr['unit'], data_info.y_unit)
544            if attr_d.has_key('unit') and attr_d['unit'].lower() != data_info.y_unit.lower():
545                if has_converter==True:
546                    try:
547                        data_conv_i = Converter(attr_d['unit'])
548                        _dy = data_conv_i(_dy, units=data_info.y_unit)
549                    except:
550                        raise ValueError, "CanSAS reader: could not convert dI(q) unit [%s]; expecting [%s]\n  %s" \
551                        % (attr_d['unit'], data_info.y_unit, sys.exc_value)
552                else:
553                    raise ValueError, "CanSAS reader: unrecognized dI(q) unit [%s]; expecting [%s]" \
554                        % (attr_d['unit'], data_info.y_unit)
555               
556            if _x is not None and _y is not None:
557                x  = numpy.append(x, _x)
558                y  = numpy.append(y, _y)
559                dx = numpy.append(dx, _dx)
560                dy = numpy.append(dy, _dy)
561                dxl = numpy.append(dxl, _dxl)
562                dxw = numpy.append(dxw, _dxw)
563               
564           
565        data_info.x = x
566        data_info.y = y
567        data_info.dx = dx
568        data_info.dy = dy
569        data_info.dxl = dxl
570        data_info.dxw = dxw
571       
572        data_conv_q = None
573        data_conv_i = None
574       
575        if has_converter == True and data_info.x_unit != '1/A':
576            data_conv_q = Converter('1/A')
577            # Test it
578            data_conv_q(1.0, output.Q_unit)
579           
580        if has_converter == True and data_info.y_unit != '1/cm':
581            data_conv_i = Converter('1/cm')
582            # Test it
583            data_conv_i(1.0, output.I_unit)                   
584               
585        if data_conv_q is not None:
586            data_info.xaxis("\\rm{Q}", data_info.x_unit)
587        else:
588            data_info.xaxis("\\rm{Q}", 'A^{-1}')
589        if data_conv_i is not None:
590            data_info.yaxis("\\{I(Q)}", data_info.y_unit)
591        else:
592            data_info.yaxis("\\rm{I(Q)}","cm^{-1}")
593       
594        return data_info
595
596    def write(self, filename, datainfo):
597        """
598            Write the content of a Data1D as a CanSAS XML file
599           
600            @param filename: name of the file to write
601            @param datainfo: Data1D object
602        """
603       
604        if not datainfo.__class__ == Data1D: 
605            raise RuntimeError, "The cansas writer expects a Data1D instance"
606       
607        doc = xml.dom.minidom.Document()
608        main_node = doc.createElement("SASroot")
609        main_node.setAttribute("version", self.version)
610        main_node.setAttribute("xmlns", "cansas1d/%s" % self.version)
611        main_node.setAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance")
612        main_node.setAttribute("xsi:schemaLocation", "cansas1d/%s http://svn.smallangles.net/svn/canSAS/1dwg/trunk/cansas1d.xsd" % self.version)
613       
614        doc.appendChild(main_node)
615       
616        entry_node = doc.createElement("SASentry")
617        main_node.appendChild(entry_node)
618       
619        write_node(doc, entry_node, "Title", datainfo.title)
620       
621        for item in datainfo.run:
622            runname = {}
623            if datainfo.run_name.has_key(item) and len(str(datainfo.run_name[item]))>1:
624                runname = {'name': datainfo.run_name[item] }
625            write_node(doc, entry_node, "Run", item, runname)
626       
627        # Data info
628        node = doc.createElement("SASdata")
629        entry_node.appendChild(node)
630       
631        for i in range(len(datainfo.x)):
632            pt = doc.createElement("Idata")
633            node.appendChild(pt)
634            write_node(doc, pt, "Q", datainfo.x[i], {'unit':datainfo.x_unit})
635            if len(datainfo.y)>=i:
636                write_node(doc, pt, "I", datainfo.y[i], {'unit':datainfo.y_unit})
637            if datainfo.dx !=None and len(datainfo.dx)>=i:
638                write_node(doc, pt, "Qdev", datainfo.dx[i], {'unit':datainfo.x_unit})
639            if datainfo.dx !=None and len(datainfo.dy)>=i:
640                write_node(doc, pt, "Idev", datainfo.dy[i], {'unit':datainfo.y_unit})
641
642       
643        # Sample info
644        sample = doc.createElement("SASsample")
645        if datainfo.sample.name is not None:
646            sample.setAttribute("name", str(datainfo.sample.name))
647        entry_node.appendChild(sample)
648        write_node(doc, sample, "ID", str(datainfo.sample.ID))
649        write_node(doc, sample, "thickness", datainfo.sample.thickness, {"unit":datainfo.sample.thickness_unit})
650        write_node(doc, sample, "transmission", datainfo.sample.transmission)
651        write_node(doc, sample, "temperature", datainfo.sample.temperature, {"unit":datainfo.sample.temperature_unit})
652       
653        for item in datainfo.sample.details:
654            write_node(doc, sample, "details", item)
655       
656        pos = doc.createElement("position")
657        written = write_node(doc, pos, "x", datainfo.sample.position.x, {"unit":datainfo.sample.position_unit})
658        written = written | write_node(doc, pos, "y", datainfo.sample.position.y, {"unit":datainfo.sample.position_unit})
659        written = written | write_node(doc, pos, "z", datainfo.sample.position.z, {"unit":datainfo.sample.position_unit})
660        if written == True:
661            sample.appendChild(pos)
662       
663        ori = doc.createElement("orientation")
664        written = write_node(doc, ori, "roll",  datainfo.sample.orientation.x, {"unit":datainfo.sample.orientation_unit})
665        written = written | write_node(doc, ori, "pitch", datainfo.sample.orientation.y, {"unit":datainfo.sample.orientation_unit})
666        written = written | write_node(doc, ori, "yaw",   datainfo.sample.orientation.z, {"unit":datainfo.sample.orientation_unit})
667        if written == True:
668            sample.appendChild(ori)
669       
670        # Instrument info
671        instr = doc.createElement("SASinstrument")
672        entry_node.appendChild(instr)
673       
674        write_node(doc, instr, "name", datainfo.instrument)
675       
676        #   Source
677        source = doc.createElement("SASsource")
678        if datainfo.source.name is not None:
679            source.setAttribute("name", str(datainfo.source.name))
680        instr.appendChild(source)
681       
682        write_node(doc, source, "radiation", datainfo.source.radiation)
683        write_node(doc, source, "beam_shape", datainfo.source.beam_shape)
684        size = doc.createElement("beam_size")
685        if datainfo.source.beam_size_name is not None:
686            size.setAttribute("name", str(datainfo.source.beam_size_name))
687        written = write_node(doc, size, "x", datainfo.source.beam_size.x, {"unit":datainfo.source.beam_size_unit})
688        written = written | write_node(doc, size, "y", datainfo.source.beam_size.y, {"unit":datainfo.source.beam_size_unit})
689        written = written | write_node(doc, size, "z", datainfo.source.beam_size.z, {"unit":datainfo.source.beam_size_unit})
690        if written == True:
691            source.appendChild(size)
692           
693        write_node(doc, source, "wavelength", datainfo.source.wavelength, {"unit":datainfo.source.wavelength_unit})
694        write_node(doc, source, "wavelength_min", datainfo.source.wavelength_min, {"unit":datainfo.source.wavelength_min_unit})
695        write_node(doc, source, "wavelength_max", datainfo.source.wavelength_max, {"unit":datainfo.source.wavelength_max_unit})
696        write_node(doc, source, "wavelength_spread", datainfo.source.wavelength_spread, {"unit":datainfo.source.wavelength_spread_unit})
697       
698        #   Collimation
699        for item in datainfo.collimation:
700            coll = doc.createElement("SAScollimation")
701            if item.name is not None:
702                coll.setAttribute("name", str(item.name))
703            instr.appendChild(coll)
704           
705            write_node(doc, coll, "length", item.length, {"unit":item.length_unit})
706           
707            for apert in item.aperture:
708                ap = doc.createElement("aperture")
709                if apert.name is not None:
710                    ap.setAttribute("name", str(apert.name))
711                if apert.type is not None:
712                    ap.setAttribute("type", str(apert.type))
713                coll.appendChild(ap)
714               
715                write_node(doc, ap, "distance", apert.distance, {"unit":apert.distance_unit})
716               
717                size = doc.createElement("size")
718                if apert.size_name is not None:
719                    size.setAttribute("name", str(apert.size_name))
720                written = write_node(doc, size, "x", apert.size.x, {"unit":apert.size_unit})
721                written = written | write_node(doc, size, "y", apert.size.y, {"unit":apert.size_unit})
722                written = written | write_node(doc, size, "z", apert.size.z, {"unit":apert.size_unit})
723                if written == True:
724                    ap.appendChild(size)
725
726        #   Detectors
727        for item in datainfo.detector:
728            det = doc.createElement("SASdetector")
729            written = write_node(doc, det, "name", item.name)
730            written = written | write_node(doc, det, "SDD", item.distance, {"unit":item.distance_unit})
731            written = written | write_node(doc, det, "slit_length", item.slit_length, {"unit":item.slit_length_unit})
732            if written == True:
733                instr.appendChild(det)
734           
735            off = doc.createElement("offset")
736            written = write_node(doc, off, "x", item.offset.x, {"unit":item.offset_unit})
737            written = written | write_node(doc, off, "y", item.offset.y, {"unit":item.offset_unit})
738            written = written | write_node(doc, off, "z", item.offset.z, {"unit":item.offset_unit})
739            if written == True:
740                det.appendChild(off)
741           
742            center = doc.createElement("beam_center")
743            written = write_node(doc, center, "x", item.beam_center.x, {"unit":item.beam_center_unit})
744            written = written | write_node(doc, center, "y", item.beam_center.y, {"unit":item.beam_center_unit})
745            written = written | write_node(doc, center, "z", item.beam_center.z, {"unit":item.beam_center_unit})
746            if written == True:
747                det.appendChild(center)
748               
749            pix = doc.createElement("pixel_size")
750            written = write_node(doc, pix, "x", item.pixel_size.x, {"unit":item.pixel_size_unit})
751            written = written | write_node(doc, pix, "y", item.pixel_size.y, {"unit":item.pixel_size_unit})
752            written = written | write_node(doc, pix, "z", item.pixel_size.z, {"unit":item.pixel_size_unit})
753            if written == True:
754                det.appendChild(pix)
755               
756            ori = doc.createElement("orientation")
757            written = write_node(doc, ori, "roll",  item.orientation.x, {"unit":item.orientation_unit})
758            written = written | write_node(doc, ori, "pitch", item.orientation.y, {"unit":item.orientation_unit})
759            written = written | write_node(doc, ori, "yaw",   item.orientation.z, {"unit":item.orientation_unit})
760            if written == True:
761                det.appendChild(ori)
762               
763       
764        # Processes info
765        for item in datainfo.process:
766            node = doc.createElement("SASprocess")
767            entry_node.appendChild(node)
768
769            write_node(doc, node, "name", item.name)
770            write_node(doc, node, "date", item.date)
771            write_node(doc, node, "description", item.description)
772            for term in item.term:
773                value = term['value']
774                del term['value']
775                write_node(doc, node, "term", value, term)
776            for note in item.notes:
777                write_node(doc, node, "SASprocessnote", note)
778           
779       
780        # Write the file
781        fd = open(filename, 'w')
782        fd.write(doc.toprettyxml())
783        fd.close()
784       
785       
786if __name__ == "__main__": 
787    logging.basicConfig(level=logging.ERROR,
788                        format='%(asctime)s %(levelname)s %(message)s',
789                        filename='cansas_reader.log',
790                        filemode='w')
791    reader = Reader()
792    print reader.read("../test/cansas1d.xml")
793   
794   
795                       
Note: See TracBrowser for help on using the repository browser.