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

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 cb0d17c was 7d8094b, checked in by Mathieu Doucet <doucetm@…>, 15 years ago

dataloader: allow for input to write to be child class. Modify clone_without_data to receive a Data1D (or child of Data1D) as an input.

  • Property mode set to 100644
File size: 35.5 KB
RevLine 
[8780e9a]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"""
[579ba85]10# Known issue: reader not compatible with multiple SASdata entries
11# within a single SASentry. Will raise a runtime error.
[8780e9a]12
[4c00964]13#TODO: check that all vectors are written only if they have at least one non-empty value
[579ba85]14#TODO: Writing only allows one SASentry per file. Would be best to allow multiple entries.
[8780e9a]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.
[e390933]19#TODO: Unit conversion is not complete (temperature units are missing)
[8780e9a]20
21
22import logging
23import numpy
24import os, sys
[d6513cd]25from DataLoader.data_info import Data1D, Collimation, Detector, Process, Aperture
[8780e9a]26from xml import xpath
[4c00964]27import xml.dom.minidom 
28
[8780e9a]29
[b39c817]30has_converter = True
31try:
32    from data_util.nxsunit import Converter
33except:
34    has_converter = False
35
[4c00964]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
[8780e9a]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               
[d6513cd]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
[8780e9a]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:
[b39c817]118            value = float(content)   
[8780e9a]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('.')
[e390933]148            exec "local_unit = storage.%s_unit" % toks[0]
149            if attr['unit'].lower()!=local_unit.lower():
[b39c817]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:
[d3966c2]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)
[b39c817]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           
[8780e9a]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
[28caa03]198    type_name = "CanSAS 1D"
199    ## Wildcards
[8780e9a]200    type = ["CanSAS 1D files (*.xml)|*.xml"]
201    ## List of allowed extensions
202    ext=['.xml', '.XML'] 
203   
204    def read(self, path):
205        """
206            Load data file
207           
208            @param path: file path
209            @return: Data1D object if a single SASentry was found,
210                        or a list of Data1D objects if multiple entries were found,
211                        or None of nothing was found
212            @raise RuntimeError: when the file can't be opened
213            @raise ValueError: when the length of the data vectors are inconsistent
214        """
215        from xml.dom.minidom import parse
216       
217        output = []
218       
219        if os.path.isfile(path):
220            basename  = os.path.basename(path)
221            root, extension = os.path.splitext(basename)
222            if extension.lower() in self.ext:
223               
224                dom = parse(path)
225               
226                # Check the format version number
227                nodes = xpath.Evaluate('SASroot', dom)
228                if nodes[0].hasAttributes():
229                    for i in range(nodes[0].attributes.length):
230                        if nodes[0].attributes.item(i).nodeName=='version':
231                            if nodes[0].attributes.item(i).nodeValue != self.version:
232                                raise ValueError, "cansas_reader: unrecognized version number %s" % \
233                                    nodes[0].attributes.item(i).nodeValue
234               
235                entry_list = xpath.Evaluate('SASroot/SASentry', dom)
236                for entry in entry_list:
237                    sas_entry = self._parse_entry(entry)
238                    sas_entry.filename = basename
239                    output.append(sas_entry)
240               
241        else:
242            raise RuntimeError, "%s is not a file" % path
243       
244        # Return output consistent with the loader's api
245        if len(output)==0:
246            return None
247        elif len(output)==1:
248            return output[0]
249        else:
250            return output               
251               
252    def _parse_entry(self, dom):
253        """
254            Parse a SASentry
255           
256            @param node: SASentry node
257            @return: Data1D object
258        """
259        x = numpy.zeros(0)
260        y = numpy.zeros(0)
261       
262        data_info = Data1D(x, y)
263       
264        # Look up title
265        _store_content('Title', dom, 'title', data_info)
[579ba85]266        # Look up run number   
267        nodes = xpath.Evaluate('Run', dom)
268        for item in nodes:   
269            value, attr = get_node_text(item)
270            if value is not None:
271                data_info.run.append(value)
272                if attr.has_key('name'):
273                    data_info.run_name[value] = attr['name']         
274                           
[8780e9a]275        # Look up instrument name             
[579ba85]276        _store_content('SASinstrument/name', dom, 'instrument', data_info)
277        #value, attr = get_content('SASinstrument', dom)
278        #if attr.has_key('name'):
279        #    data_info.instrument = attr['name']
[8780e9a]280
281        note_list = xpath.Evaluate('SASnote', dom)
282        for note in note_list:
283            try:
284                note_value, note_attr = get_node_text(note)
285                if note_value is not None:
286                    data_info.notes.append(note_value)
287            except:
288                logging.error("cansas_reader.read: error processing entry notes\n  %s" % sys.exc_value)
289
290       
291        # Sample info ###################
[579ba85]292        value, attr = get_content('SASsample', dom)
293        if attr.has_key('name'):
294            data_info.sample.name = attr['name']
295           
[8780e9a]296        _store_content('SASsample/ID', 
297                     dom, 'ID', data_info.sample)                   
298        _store_float('SASsample/thickness', 
299                     dom, 'thickness', data_info.sample)
300        _store_float('SASsample/transmission', 
301                     dom, 'transmission', data_info.sample)
302        _store_float('SASsample/temperature', 
303                     dom, 'temperature', data_info.sample)
304        nodes = xpath.Evaluate('SASsample/details', dom)
305        for item in nodes:
306            try:
307                detail_value, detail_attr = get_node_text(item)
308                if detail_value is not None:
309                    data_info.sample.details.append(detail_value)
310            except:
311                logging.error("cansas_reader.read: error processing sample details\n  %s" % sys.exc_value)
312       
313        # Position (as a vector)
314        _store_float('SASsample/position/x', 
315                     dom, 'position.x', data_info.sample)         
316        _store_float('SASsample/position/y', 
317                     dom, 'position.y', data_info.sample)         
318        _store_float('SASsample/position/z', 
319                     dom, 'position.z', data_info.sample)         
320       
321        # Orientation (as a vector)
322        _store_float('SASsample/orientation/roll', 
323                     dom, 'orientation.x', data_info.sample)         
324        _store_float('SASsample/orientation/pitch', 
325                     dom, 'orientation.y', data_info.sample)         
326        _store_float('SASsample/orientation/yaw', 
327                     dom, 'orientation.z', data_info.sample)         
328       
329        # Source info ###################
[4c00964]330        value, attr = get_content('SASinstrument/SASsource', dom)
331        if attr.has_key('name'):
332            data_info.source.name = attr['name']
333       
[8780e9a]334        _store_content('SASinstrument/SASsource/radiation', 
335                     dom, 'radiation', data_info.source)                   
336        _store_content('SASinstrument/SASsource/beam_shape', 
337                     dom, 'beam_shape', data_info.source)                   
338        _store_float('SASinstrument/SASsource/wavelength', 
339                     dom, 'wavelength', data_info.source)         
340        _store_float('SASinstrument/SASsource/wavelength_min', 
341                     dom, 'wavelength_min', data_info.source)         
342        _store_float('SASinstrument/SASsource/wavelength_max', 
343                     dom, 'wavelength_max', data_info.source)         
344        _store_float('SASinstrument/SASsource/wavelength_spread', 
345                     dom, 'wavelength_spread', data_info.source)   
346       
[579ba85]347        # Beam size (as a vector)   
348        value, attr = get_content('SASinstrument/SASsource/beam_size', dom)
349        if attr.has_key('name'):
350            data_info.source.beam_size_name = attr['name']
351           
[8780e9a]352        _store_float('SASinstrument/SASsource/beam_size/x', 
353                     dom, 'beam_size.x', data_info.source)   
354        _store_float('SASinstrument/SASsource/beam_size/y', 
355                     dom, 'beam_size.y', data_info.source)   
356        _store_float('SASinstrument/SASsource/beam_size/z', 
357                     dom, 'beam_size.z', data_info.source)   
358       
359        # Collimation info ###################
360        nodes = xpath.Evaluate('SASinstrument/SAScollimation', dom)
361        for item in nodes:
362            collim = Collimation()
[4c00964]363            value, attr = get_node_text(item)
364            if attr.has_key('name'):
365                collim.name = attr['name']
[8780e9a]366            _store_float('length', item, 'length', collim) 
367           
368            # Look for apertures
369            apert_list = xpath.Evaluate('aperture', item)
370            for apert in apert_list:
[d6513cd]371                aperture =  Aperture()
[4c00964]372               
373                # Get the name and type of the aperture
[579ba85]374                ap_value, ap_attr = get_node_text(apert)
[4c00964]375                if ap_attr.has_key('name'):
376                    aperture.name = ap_attr['name']
377                if ap_attr.has_key('type'):
378                    aperture.type = ap_attr['type']
379                   
[8780e9a]380                _store_float('distance', apert, 'distance', aperture)   
[579ba85]381               
382                value, attr = get_content('size', apert)
383                if attr.has_key('name'):
384                    aperture.size_name = attr['name']
385               
[8780e9a]386                _store_float('size/x', apert, 'size.x', aperture)   
387                _store_float('size/y', apert, 'size.y', aperture)   
388                _store_float('size/z', apert, 'size.z', aperture)
389               
390                collim.aperture.append(aperture)
391               
392            data_info.collimation.append(collim)
393       
394        # Detector info ######################
395        nodes = xpath.Evaluate('SASinstrument/SASdetector', dom)
396        for item in nodes:
397           
398            detector = Detector()
399           
400            _store_content('name', item, 'name', detector)
401            _store_float('SDD', item, 'distance', detector)   
402           
403            # Detector offset (as a vector)
404            _store_float('offset/x', item, 'offset.x', detector)   
405            _store_float('offset/y', item, 'offset.y', detector)   
406            _store_float('offset/z', item, 'offset.z', detector)   
407           
408            # Detector orientation (as a vector)
[579ba85]409            _store_float('orientation/roll',  item, 'orientation.x', detector)   
410            _store_float('orientation/pitch', item, 'orientation.y', detector)   
411            _store_float('orientation/yaw',   item, 'orientation.z', detector)   
[8780e9a]412           
413            # Beam center (as a vector)
414            _store_float('beam_center/x', item, 'beam_center.x', detector)   
415            _store_float('beam_center/y', item, 'beam_center.y', detector)   
416            _store_float('beam_center/z', item, 'beam_center.z', detector)   
417           
418            # Pixel size (as a vector)
419            _store_float('pixel_size/x', item, 'pixel_size.x', detector)   
420            _store_float('pixel_size/y', item, 'pixel_size.y', detector)   
421            _store_float('pixel_size/z', item, 'pixel_size.z', detector)   
422           
423            _store_float('slit_length', item, 'slit_length', detector)
424           
425            data_info.detector.append(detector)   
426
427        # Processes info ######################
428        nodes = xpath.Evaluate('SASprocess', dom)
429        for item in nodes:
430            process = Process()
431            _store_content('name', item, 'name', process)
432            _store_content('date', item, 'date', process)
433            _store_content('description', item, 'description', process)
434           
435            term_list = xpath.Evaluate('term', item)
436            for term in term_list:
437                try:
438                    term_value, term_attr = get_node_text(term)
439                    term_attr['value'] = term_value
440                    if term_value is not None:
441                        process.term.append(term_attr)
442                except:
443                    logging.error("cansas_reader.read: error processing process term\n  %s" % sys.exc_value)
444           
445            note_list = xpath.Evaluate('SASprocessnote', item)
446            for note in note_list:
447                try:
448                    note_value, note_attr = get_node_text(note)
449                    if note_value is not None:
450                        process.notes.append(note_value)
451                except:
452                    logging.error("cansas_reader.read: error processing process notes\n  %s" % sys.exc_value)
453           
454           
455            data_info.process.append(process)
456           
457           
458        # Data info ######################
[579ba85]459        nodes = xpath.Evaluate('SASdata', dom)
460        if len(nodes)>1:
461            raise RuntimeError, "CanSAS reader is not compatible with multiple SASdata entries"
462       
[8780e9a]463        nodes = xpath.Evaluate('SASdata/Idata', dom)
464        x  = numpy.zeros(0)
465        y  = numpy.zeros(0)
466        dx = numpy.zeros(0)
467        dy = numpy.zeros(0)
[d00f8ff]468        dxw = numpy.zeros(0)
469        dxl = numpy.zeros(0)
[8780e9a]470       
471        for item in nodes:
472            _x, attr = get_float('Q', item)
[e390933]473            _dx, attr_d = get_float('Qdev', item)
[d00f8ff]474            _dxl, attr_l = get_float('dQl', item)
475            _dxw, attr_w = get_float('dQw', item)
[8780e9a]476            if _dx == None:
477                _dx = 0.0
[d00f8ff]478            if _dxl == None:
479                _dxl = 0.0
480            if _dxw == None:
481                _dxw = 0.0
[8780e9a]482               
[e390933]483            if attr.has_key('unit') and attr['unit'].lower() != data_info.x_unit.lower():
484                if has_converter==True:
485                    try:
486                        data_conv_q = Converter(attr['unit'])
487                        _x = data_conv_q(_x, units=data_info.x_unit)
488                    except:
489                        raise ValueError, "CanSAS reader: could not convert Q unit [%s]; expecting [%s]\n  %s" \
490                        % (attr['unit'], data_info.x_unit, sys.exc_value)
491                else:
492                    raise ValueError, "CanSAS reader: unrecognized Q unit [%s]; expecting [%s]" \
493                        % (attr['unit'], data_info.x_unit)
[d00f8ff]494            # Error in Q
[e390933]495            if attr_d.has_key('unit') and attr_d['unit'].lower() != data_info.x_unit.lower():
496                if has_converter==True:
497                    try:
498                        data_conv_q = Converter(attr_d['unit'])
499                        _dx = data_conv_q(_dx, units=data_info.x_unit)
500                    except:
501                        raise ValueError, "CanSAS reader: could not convert dQ unit [%s]; expecting [%s]\n  %s" \
502                        % (attr['unit'], data_info.x_unit, sys.exc_value)
503                else:
504                    raise ValueError, "CanSAS reader: unrecognized dQ unit [%s]; expecting [%s]" \
505                        % (attr['unit'], data_info.x_unit)
[d00f8ff]506            # Slit length
507            if attr_l.has_key('unit') and attr_l['unit'].lower() != data_info.x_unit.lower():
508                if has_converter==True:
509                    try:
510                        data_conv_q = Converter(attr_l['unit'])
511                        _dxl = data_conv_q(_dxl, units=data_info.x_unit)
512                    except:
513                        raise ValueError, "CanSAS reader: could not convert dQl unit [%s]; expecting [%s]\n  %s" \
514                        % (attr['unit'], data_info.x_unit, sys.exc_value)
515                else:
516                    raise ValueError, "CanSAS reader: unrecognized dQl unit [%s]; expecting [%s]" \
517                        % (attr['unit'], data_info.x_unit)
518            # Slit width
519            if attr_w.has_key('unit') and attr_w['unit'].lower() != data_info.x_unit.lower():
520                if has_converter==True:
521                    try:
522                        data_conv_q = Converter(attr_w['unit'])
523                        _dxw = data_conv_q(_dxw, units=data_info.x_unit)
524                    except:
525                        raise ValueError, "CanSAS reader: could not convert dQw unit [%s]; expecting [%s]\n  %s" \
526                        % (attr['unit'], data_info.x_unit, sys.exc_value)
527                else:
528                    raise ValueError, "CanSAS reader: unrecognized dQw unit [%s]; expecting [%s]" \
529                        % (attr['unit'], data_info.x_unit)
[e390933]530                   
[8780e9a]531            _y, attr = get_float('I', item)
[e390933]532            _dy, attr_d = get_float('Idev', item)
[8780e9a]533            if _dy == None:
534                _dy = 0.0
535            if attr.has_key('unit') and attr['unit'].lower() != data_info.y_unit.lower():
[e390933]536                if has_converter==True:
537                    try:
538                        data_conv_i = Converter(attr['unit'])
539                        _y = data_conv_i(_y, units=data_info.y_unit)
540                    except:
541                        raise ValueError, "CanSAS reader: could not convert I(q) unit [%s]; expecting [%s]\n  %s" \
542                        % (attr['unit'], data_info.y_unit, sys.exc_value)
543                else:
544                    raise ValueError, "CanSAS reader: unrecognized I(q) unit [%s]; expecting [%s]" \
545                        % (attr['unit'], data_info.y_unit)
546            if attr_d.has_key('unit') and attr_d['unit'].lower() != data_info.y_unit.lower():
547                if has_converter==True:
548                    try:
549                        data_conv_i = Converter(attr_d['unit'])
550                        _dy = data_conv_i(_dy, units=data_info.y_unit)
551                    except:
552                        raise ValueError, "CanSAS reader: could not convert dI(q) unit [%s]; expecting [%s]\n  %s" \
553                        % (attr_d['unit'], data_info.y_unit, sys.exc_value)
554                else:
555                    raise ValueError, "CanSAS reader: unrecognized dI(q) unit [%s]; expecting [%s]" \
556                        % (attr_d['unit'], data_info.y_unit)
[8780e9a]557               
558            if _x is not None and _y is not None:
559                x  = numpy.append(x, _x)
[579ba85]560                y  = numpy.append(y, _y)
561                dx = numpy.append(dx, _dx)
562                dy = numpy.append(dy, _dy)
[d00f8ff]563                dxl = numpy.append(dxl, _dxl)
564                dxw = numpy.append(dxw, _dxw)
565               
[8780e9a]566           
567        data_info.x = x
568        data_info.y = y
569        data_info.dx = dx
570        data_info.dy = dy
[d00f8ff]571        data_info.dxl = dxl
572        data_info.dxw = dxw
[d6513cd]573       
574        data_conv_q = None
575        data_conv_i = None
576       
[ca10d8e]577        if has_converter == True and data_info.x_unit != '1/A':
578            data_conv_q = Converter('1/A')
[d6513cd]579            # Test it
580            data_conv_q(1.0, output.Q_unit)
581           
[ca10d8e]582        if has_converter == True and data_info.y_unit != '1/cm':
583            data_conv_i = Converter('1/cm')
[d6513cd]584            # Test it
[e390933]585            data_conv_i(1.0, output.I_unit)                   
586               
[99d1af6]587        if data_conv_q is not None:
[d6513cd]588            data_info.xaxis("\\rm{Q}", data_info.x_unit)
[99d1af6]589        else:
590            data_info.xaxis("\\rm{Q}", 'A^{-1}')
591        if data_conv_i is not None:
[0e2aa40]592            data_info.yaxis("\\rm{Intensity}", data_info.y_unit)
[99d1af6]593        else:
[0e2aa40]594            data_info.yaxis("\\rm{Intensity}","cm^{-1}")
[99d1af6]595       
[8780e9a]596        return data_info
597
[b3de3a45]598    def _to_xml_doc(self, datainfo):
[4c00964]599        """
[b3de3a45]600            Create an XML document to contain the content of a Data1D
[4c00964]601           
602            @param datainfo: Data1D object
603        """
604       
[7d8094b]605        if not issubclass(datainfo.__class__, Data1D):
[4c00964]606            raise RuntimeError, "The cansas writer expects a Data1D instance"
607       
608        doc = xml.dom.minidom.Document()
609        main_node = doc.createElement("SASroot")
[fee780b]610        main_node.setAttribute("version", self.version)
611        main_node.setAttribute("xmlns", "cansas1d/%s" % self.version)
612        main_node.setAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance")
613        main_node.setAttribute("xsi:schemaLocation", "cansas1d/%s http://svn.smallangles.net/svn/canSAS/1dwg/trunk/cansas1d.xsd" % self.version)
614       
[4c00964]615        doc.appendChild(main_node)
616       
617        entry_node = doc.createElement("SASentry")
618        main_node.appendChild(entry_node)
619       
[579ba85]620        write_node(doc, entry_node, "Title", datainfo.title)
621       
622        for item in datainfo.run:
623            runname = {}
624            if datainfo.run_name.has_key(item) and len(str(datainfo.run_name[item]))>1:
625                runname = {'name': datainfo.run_name[item] }
626            write_node(doc, entry_node, "Run", item, runname)
[4c00964]627       
628        # Data info
629        node = doc.createElement("SASdata")
630        entry_node.appendChild(node)
631       
[579ba85]632        for i in range(len(datainfo.x)):
633            pt = doc.createElement("Idata")
634            node.appendChild(pt)
635            write_node(doc, pt, "Q", datainfo.x[i], {'unit':datainfo.x_unit})
636            if len(datainfo.y)>=i:
637                write_node(doc, pt, "I", datainfo.y[i], {'unit':datainfo.y_unit})
[5b396b3]638            if datainfo.dx !=None and len(datainfo.dx)>=i:
[579ba85]639                write_node(doc, pt, "Qdev", datainfo.dx[i], {'unit':datainfo.x_unit})
[f31701c]640            if datainfo.dy !=None and len(datainfo.dy)>=i:
[579ba85]641                write_node(doc, pt, "Idev", datainfo.dy[i], {'unit':datainfo.y_unit})
642
643       
[4c00964]644        # Sample info
645        sample = doc.createElement("SASsample")
[579ba85]646        if datainfo.sample.name is not None:
647            sample.setAttribute("name", str(datainfo.sample.name))
[4c00964]648        entry_node.appendChild(sample)
[579ba85]649        write_node(doc, sample, "ID", str(datainfo.sample.ID))
[4c00964]650        write_node(doc, sample, "thickness", datainfo.sample.thickness, {"unit":datainfo.sample.thickness_unit})
651        write_node(doc, sample, "transmission", datainfo.sample.transmission)
652        write_node(doc, sample, "temperature", datainfo.sample.temperature, {"unit":datainfo.sample.temperature_unit})
653       
654        for item in datainfo.sample.details:
655            write_node(doc, sample, "details", item)
656       
657        pos = doc.createElement("position")
[579ba85]658        written = write_node(doc, pos, "x", datainfo.sample.position.x, {"unit":datainfo.sample.position_unit})
659        written = written | write_node(doc, pos, "y", datainfo.sample.position.y, {"unit":datainfo.sample.position_unit})
660        written = written | write_node(doc, pos, "z", datainfo.sample.position.z, {"unit":datainfo.sample.position_unit})
[4c00964]661        if written == True:
662            sample.appendChild(pos)
663       
664        ori = doc.createElement("orientation")
[579ba85]665        written = write_node(doc, ori, "roll",  datainfo.sample.orientation.x, {"unit":datainfo.sample.orientation_unit})
666        written = written | write_node(doc, ori, "pitch", datainfo.sample.orientation.y, {"unit":datainfo.sample.orientation_unit})
667        written = written | write_node(doc, ori, "yaw",   datainfo.sample.orientation.z, {"unit":datainfo.sample.orientation_unit})
[4c00964]668        if written == True:
669            sample.appendChild(ori)
670       
671        # Instrument info
672        instr = doc.createElement("SASinstrument")
673        entry_node.appendChild(instr)
674       
675        write_node(doc, instr, "name", datainfo.instrument)
676       
677        #   Source
678        source = doc.createElement("SASsource")
[579ba85]679        if datainfo.source.name is not None:
680            source.setAttribute("name", str(datainfo.source.name))
[4c00964]681        instr.appendChild(source)
682       
683        write_node(doc, source, "radiation", datainfo.source.radiation)
684        write_node(doc, source, "beam_shape", datainfo.source.beam_shape)
[579ba85]685        size = doc.createElement("beam_size")
686        if datainfo.source.beam_size_name is not None:
687            size.setAttribute("name", str(datainfo.source.beam_size_name))
688        written = write_node(doc, size, "x", datainfo.source.beam_size.x, {"unit":datainfo.source.beam_size_unit})
689        written = written | write_node(doc, size, "y", datainfo.source.beam_size.y, {"unit":datainfo.source.beam_size_unit})
690        written = written | write_node(doc, size, "z", datainfo.source.beam_size.z, {"unit":datainfo.source.beam_size_unit})
691        if written == True:
692            source.appendChild(size)
693           
[4c00964]694        write_node(doc, source, "wavelength", datainfo.source.wavelength, {"unit":datainfo.source.wavelength_unit})
695        write_node(doc, source, "wavelength_min", datainfo.source.wavelength_min, {"unit":datainfo.source.wavelength_min_unit})
696        write_node(doc, source, "wavelength_max", datainfo.source.wavelength_max, {"unit":datainfo.source.wavelength_max_unit})
697        write_node(doc, source, "wavelength_spread", datainfo.source.wavelength_spread, {"unit":datainfo.source.wavelength_spread_unit})
698       
699        #   Collimation
700        for item in datainfo.collimation:
701            coll = doc.createElement("SAScollimation")
[579ba85]702            if item.name is not None:
703                coll.setAttribute("name", str(item.name))
[4c00964]704            instr.appendChild(coll)
705           
706            write_node(doc, coll, "length", item.length, {"unit":item.length_unit})
707           
708            for apert in item.aperture:
[579ba85]709                ap = doc.createElement("aperture")
710                if apert.name is not None:
711                    ap.setAttribute("name", str(apert.name))
712                if apert.type is not None:
713                    ap.setAttribute("type", str(apert.type))
714                coll.appendChild(ap)
[4c00964]715               
716                write_node(doc, ap, "distance", apert.distance, {"unit":apert.distance_unit})
717               
718                size = doc.createElement("size")
[579ba85]719                if apert.size_name is not None:
720                    size.setAttribute("name", str(apert.size_name))
721                written = write_node(doc, size, "x", apert.size.x, {"unit":apert.size_unit})
722                written = written | write_node(doc, size, "y", apert.size.y, {"unit":apert.size_unit})
723                written = written | write_node(doc, size, "z", apert.size.z, {"unit":apert.size_unit})
724                if written == True:
725                    ap.appendChild(size)
[4c00964]726
727        #   Detectors
728        for item in datainfo.detector:
729            det = doc.createElement("SASdetector")
[579ba85]730            written = write_node(doc, det, "name", item.name)
731            written = written | write_node(doc, det, "SDD", item.distance, {"unit":item.distance_unit})
732            written = written | write_node(doc, det, "slit_length", item.slit_length, {"unit":item.slit_length_unit})
733            if written == True:
734                instr.appendChild(det)
[4c00964]735           
736            off = doc.createElement("offset")
[579ba85]737            written = write_node(doc, off, "x", item.offset.x, {"unit":item.offset_unit})
738            written = written | write_node(doc, off, "y", item.offset.y, {"unit":item.offset_unit})
739            written = written | write_node(doc, off, "z", item.offset.z, {"unit":item.offset_unit})
740            if written == True:
741                det.appendChild(off)
[4c00964]742           
743            center = doc.createElement("beam_center")
[579ba85]744            written = write_node(doc, center, "x", item.beam_center.x, {"unit":item.beam_center_unit})
745            written = written | write_node(doc, center, "y", item.beam_center.y, {"unit":item.beam_center_unit})
746            written = written | write_node(doc, center, "z", item.beam_center.z, {"unit":item.beam_center_unit})
747            if written == True:
748                det.appendChild(center)
749               
[4c00964]750            pix = doc.createElement("pixel_size")
[579ba85]751            written = write_node(doc, pix, "x", item.pixel_size.x, {"unit":item.pixel_size_unit})
752            written = written | write_node(doc, pix, "y", item.pixel_size.y, {"unit":item.pixel_size_unit})
753            written = written | write_node(doc, pix, "z", item.pixel_size.z, {"unit":item.pixel_size_unit})
754            if written == True:
755                det.appendChild(pix)
756               
757            ori = doc.createElement("orientation")
758            written = write_node(doc, ori, "roll",  item.orientation.x, {"unit":item.orientation_unit})
759            written = written | write_node(doc, ori, "pitch", item.orientation.y, {"unit":item.orientation_unit})
760            written = written | write_node(doc, ori, "yaw",   item.orientation.z, {"unit":item.orientation_unit})
761            if written == True:
762                det.appendChild(ori)
763               
[4c00964]764       
[579ba85]765        # Processes info
[4c00964]766        for item in datainfo.process:
767            node = doc.createElement("SASprocess")
768            entry_node.appendChild(node)
769
[579ba85]770            write_node(doc, node, "name", item.name)
771            write_node(doc, node, "date", item.date)
772            write_node(doc, node, "description", item.description)
773            for term in item.term:
774                value = term['value']
775                del term['value']
776                write_node(doc, node, "term", value, term)
777            for note in item.notes:
778                write_node(doc, node, "SASprocessnote", note)
[4c00964]779       
[b3de3a45]780        # Return the document, and the SASentry node associated with
781        # the data we just wrote
782        return doc, entry_node
783           
784    def write(self, filename, datainfo):
785        """
786            Write the content of a Data1D as a CanSAS XML file
787           
788            @param filename: name of the file to write
789            @param datainfo: Data1D object
790        """
791        # Create XML document
792        doc, sasentry = self._to_xml_doc(datainfo)
[4c00964]793        # Write the file
794        fd = open(filename, 'w')
795        fd.write(doc.toprettyxml())
796        fd.close()
797       
798       
[8780e9a]799if __name__ == "__main__": 
800    logging.basicConfig(level=logging.ERROR,
801                        format='%(asctime)s %(levelname)s %(message)s',
802                        filename='cansas_reader.log',
803                        filemode='w')
804    reader = Reader()
805    print reader.read("../test/cansas1d.xml")
806   
807   
808                       
Note: See TracBrowser for help on using the repository browser.