source: sasview/DataLoader/readers/cansas_reader.py @ 8dc0b746

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 8dc0b746 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
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_name = "CanSAS 1D"
199    ## Wildcards
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)
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                           
275        # Look up instrument name             
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']
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 ###################
292        value, attr = get_content('SASsample', dom)
293        if attr.has_key('name'):
294            data_info.sample.name = attr['name']
295           
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 ###################
330        value, attr = get_content('SASinstrument/SASsource', dom)
331        if attr.has_key('name'):
332            data_info.source.name = attr['name']
333       
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       
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           
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()
363            value, attr = get_node_text(item)
364            if attr.has_key('name'):
365                collim.name = attr['name']
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:
371                aperture =  Aperture()
372               
373                # Get the name and type of the aperture
374                ap_value, ap_attr = get_node_text(apert)
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                   
380                _store_float('distance', apert, 'distance', aperture)   
381               
382                value, attr = get_content('size', apert)
383                if attr.has_key('name'):
384                    aperture.size_name = attr['name']
385               
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)
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)   
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 ######################
459        nodes = xpath.Evaluate('SASdata', dom)
460        if len(nodes)>1:
461            raise RuntimeError, "CanSAS reader is not compatible with multiple SASdata entries"
462       
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)
468        dxw = numpy.zeros(0)
469        dxl = numpy.zeros(0)
470       
471        for item in nodes:
472            _x, attr = get_float('Q', item)
473            _dx, attr_d = get_float('Qdev', item)
474            _dxl, attr_l = get_float('dQl', item)
475            _dxw, attr_w = get_float('dQw', item)
476            if _dx == None:
477                _dx = 0.0
478            if _dxl == None:
479                _dxl = 0.0
480            if _dxw == None:
481                _dxw = 0.0
482               
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)
494            # Error in Q
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)
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)
530                   
531            _y, attr = get_float('I', item)
532            _dy, attr_d = get_float('Idev', item)
533            if _dy == None:
534                _dy = 0.0
535            if attr.has_key('unit') and attr['unit'].lower() != data_info.y_unit.lower():
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)
557               
558            if _x is not None and _y is not None:
559                x  = numpy.append(x, _x)
560                y  = numpy.append(y, _y)
561                dx = numpy.append(dx, _dx)
562                dy = numpy.append(dy, _dy)
563                dxl = numpy.append(dxl, _dxl)
564                dxw = numpy.append(dxw, _dxw)
565               
566           
567        data_info.x = x
568        data_info.y = y
569        data_info.dx = dx
570        data_info.dy = dy
571        data_info.dxl = dxl
572        data_info.dxw = dxw
573       
574        data_conv_q = None
575        data_conv_i = None
576       
577        if has_converter == True and data_info.x_unit != '1/A':
578            data_conv_q = Converter('1/A')
579            # Test it
580            data_conv_q(1.0, output.Q_unit)
581           
582        if has_converter == True and data_info.y_unit != '1/cm':
583            data_conv_i = Converter('1/cm')
584            # Test it
585            data_conv_i(1.0, output.I_unit)                   
586               
587        if data_conv_q is not None:
588            data_info.xaxis("\\rm{Q}", data_info.x_unit)
589        else:
590            data_info.xaxis("\\rm{Q}", 'A^{-1}')
591        if data_conv_i is not None:
592            data_info.yaxis("\\rm{Intensity}", data_info.y_unit)
593        else:
594            data_info.yaxis("\\rm{Intensity}","cm^{-1}")
595       
596        return data_info
597
598    def _to_xml_doc(self, datainfo):
599        """
600            Create an XML document to contain the content of a Data1D
601           
602            @param datainfo: Data1D object
603        """
604       
605        if not issubclass(datainfo.__class__, Data1D):
606            raise RuntimeError, "The cansas writer expects a Data1D instance"
607       
608        doc = xml.dom.minidom.Document()
609        main_node = doc.createElement("SASroot")
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       
615        doc.appendChild(main_node)
616       
617        entry_node = doc.createElement("SASentry")
618        main_node.appendChild(entry_node)
619       
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)
627       
628        # Data info
629        node = doc.createElement("SASdata")
630        entry_node.appendChild(node)
631       
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})
638            if datainfo.dx !=None and len(datainfo.dx)>=i:
639                write_node(doc, pt, "Qdev", datainfo.dx[i], {'unit':datainfo.x_unit})
640            if datainfo.dy !=None and len(datainfo.dy)>=i:
641                write_node(doc, pt, "Idev", datainfo.dy[i], {'unit':datainfo.y_unit})
642
643       
644        # Sample info
645        sample = doc.createElement("SASsample")
646        if datainfo.sample.name is not None:
647            sample.setAttribute("name", str(datainfo.sample.name))
648        entry_node.appendChild(sample)
649        write_node(doc, sample, "ID", str(datainfo.sample.ID))
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")
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})
661        if written == True:
662            sample.appendChild(pos)
663       
664        ori = doc.createElement("orientation")
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})
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")
679        if datainfo.source.name is not None:
680            source.setAttribute("name", str(datainfo.source.name))
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)
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           
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")
702            if item.name is not None:
703                coll.setAttribute("name", str(item.name))
704            instr.appendChild(coll)
705           
706            write_node(doc, coll, "length", item.length, {"unit":item.length_unit})
707           
708            for apert in item.aperture:
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)
715               
716                write_node(doc, ap, "distance", apert.distance, {"unit":apert.distance_unit})
717               
718                size = doc.createElement("size")
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)
726
727        #   Detectors
728        for item in datainfo.detector:
729            det = doc.createElement("SASdetector")
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)
735           
736            off = doc.createElement("offset")
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)
742           
743            center = doc.createElement("beam_center")
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               
750            pix = doc.createElement("pixel_size")
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               
764       
765        # Processes info
766        for item in datainfo.process:
767            node = doc.createElement("SASprocess")
768            entry_node.appendChild(node)
769
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)
779       
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)
793        # Write the file
794        fd = open(filename, 'w')
795        fd.write(doc.toprettyxml())
796        fd.close()
797       
798       
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.