source: sasview/src/sas/sascalc/dataloader/readers/anton_paar_saxs_reader.py @ a16cbb0

Last change on this file since a16cbb0 was a5bd87a, checked in by Paul Kienzle <pkienzle@…>, 7 years ago

use decoded stream for anton-paar saxs reader

  • Property mode set to 100644
File size: 7.2 KB
Line 
1"""
2    CanSAS 2D data reader for reading HDF5 formatted CanSAS files.
3"""
4
5import numpy as np
6import re
7import os
8import sys
9
10from sas.sascalc.dataloader.readers.xml_reader import XMLreader
11from sas.sascalc.dataloader.data_info import plottable_1D, Data1D, DataInfo, Sample, Source
12from sas.sascalc.dataloader.data_info import Process, Aperture, Collimation, TransmissionSpectrum, Detector
13from sas.sascalc.dataloader.loader_exceptions import FileContentsException, DataReaderException
14
15class Reader(XMLreader):
16    """
17    A class for reading in Anton Paar .pdh files
18    """
19
20    ## Logged warnings or messages
21    logging = None
22    ## List of errors for the current data set
23    errors = None
24    ## Raw file contents to be processed
25    raw_data = None
26    ## For recursion and saving purposes, remember parent objects
27    parent_list = None
28    ## Data type name
29    type_name = "Anton Paar SAXSess"
30    ## Wildcards
31    type = ["Anton Paar SAXSess Files (*.pdh)|*.pdh"]
32    ## List of allowed extensions
33    ext = ['.pdh', '.PDH']
34    ## Flag to bypass extension check
35    allow_all = False
36
37    def reset_state(self):
38        self.current_dataset = plottable_1D(np.empty(0), np.empty(0), np.empty(0), np.empty(0))
39        self.current_datainfo = DataInfo()
40        self.datasets = []
41        self.raw_data = None
42        self.errors = set()
43        self.logging = []
44        self.output = []
45        self.detector = Detector()
46        self.collimation = Collimation()
47        self.aperture = Aperture()
48        self.process = Process()
49        self.source = Source()
50        self.sample = Sample()
51        self.trans_spectrum = TransmissionSpectrum()
52        self.upper = 5
53        self.lower = 5
54
55    def get_file_contents(self):
56        """
57            This is the general read method that all SasView data_loaders must have.
58
59            :param filename: A path for an XML formatted Anton Paar SAXSess data file.
60            :return: List of Data1D objects or a list of errors.
61            """
62
63        ## Reinitialize the class when loading a new data file to reset all class variables
64        self.reset_state()
65        buff = self.readall()
66        self.raw_data = buff.splitlines()
67        self.read_data()
68
69    def read_data(self):
70        correctly_loaded = True
71        error_message = ""
72
73        q_unit = "1/nm"
74        i_unit = "1/um^2"
75        try:
76            self.current_datainfo.title = self.raw_data[0]
77            self.current_datainfo.meta_data["Keywords"] = self.raw_data[1]
78            line3 = self.raw_data[2].split()
79            line4 = self.raw_data[3].split()
80            line5 = self.raw_data[4].split()
81            self.data_points = int(line3[0])
82            self.lower = 5
83            self.upper = self.lower + self.data_points
84            self.source.radiation = 'x-ray'
85            normal = float(line4[3])
86            self.current_datainfo.source.radiation = "x-ray"
87            self.current_datainfo.source.name = "Anton Paar SAXSess Instrument"
88            self.current_datainfo.source.wavelength = float(line4[4])
89            xvals = []
90            yvals = []
91            dyvals = []
92            for i in range(self.lower, self.upper):
93                index = i - self.lower
94                data = self.raw_data[i].split()
95                xvals.insert(index, normal * float(data[0]))
96                yvals.insert(index, normal * float(data[1]))
97                dyvals.insert(index, normal * float(data[2]))
98        except Exception as e:
99            error_message = "Couldn't load {}.\n".format(self.f_open.name)
100            error_message += e.message
101            raise FileContentsException(error_message)
102        self.current_dataset.x = np.append(self.current_dataset.x, xvals)
103        self.current_dataset.y = np.append(self.current_dataset.y, yvals)
104        self.current_dataset.dy = np.append(self.current_dataset.dy, dyvals)
105        if self.data_points != self.current_dataset.x.size:
106            error_message += "Not all data points could be loaded.\n"
107            correctly_loaded = False
108        if self.current_dataset.x.size != self.current_dataset.y.size:
109            error_message += "The x and y data sets are not the same size.\n"
110            correctly_loaded = False
111        if self.current_dataset.y.size != self.current_dataset.dy.size:
112            error_message += "The y and dy datasets are not the same size.\n"
113            correctly_loaded = False
114
115        self.current_dataset.xaxis("Q", q_unit)
116        self.current_dataset.yaxis("Intensity", i_unit)
117        xml_intermediate = self.raw_data[self.upper:]
118        xml = ''.join(xml_intermediate)
119        try:
120            self.set_xml_string(xml)
121            dom = self.xmlroot.xpath('/fileinfo')
122            self._parse_child(dom)
123        except Exception as e:
124            # Data loaded but XML metadata has an error
125            error_message += "Data points have been loaded but there was an "
126            error_message += "error reading XML metadata: " + e.message
127            correctly_loaded = False
128        self.send_to_output()
129        if not correctly_loaded:
130            raise DataReaderException(error_message)
131
132    def _parse_child(self, dom, parent=''):
133        """
134        Recursive method for stepping through the embedded XML
135        :param dom: XML node with or without children
136        """
137        for node in dom:
138            tagname = node.tag
139            value = node.text
140            attr = node.attrib
141            key = attr.get("key", '')
142            if len(node.getchildren()) > 1:
143                self._parse_child(node, key)
144                if key == "SampleDetector":
145                    self.current_datainfo.detector.append(self.detector)
146                    self.detector = Detector()
147            else:
148                if key == "value":
149                    if parent == "Wavelength":
150                        self.current_datainfo.source.wavelength = value
151                    elif parent == "SampleDetector":
152                        self.detector.distance = value
153                    elif parent == "Temperature":
154                        self.current_datainfo.sample.temperature = value
155                    elif parent == "CounterSlitLength":
156                        self.detector.slit_length = value
157                elif key == "unit":
158                    value = value.replace("_", "")
159                    if parent == "Wavelength":
160                        self.current_datainfo.source.wavelength_unit = value
161                    elif parent == "SampleDetector":
162                        self.detector.distance_unit = value
163                    elif parent == "X":
164                        self.current_dataset.xaxis(self.current_dataset._xaxis, value)
165                    elif parent == "Y":
166                        self.current_dataset.yaxis(self.current_dataset._yaxis, value)
167                    elif parent == "Temperature":
168                        self.current_datainfo.sample.temperature_unit = value
169                    elif parent == "CounterSlitLength":
170                        self.detector.slit_length_unit = value
171                elif key == "quantity":
172                    if parent == "X":
173                        self.current_dataset.xaxis(value, self.current_dataset._xunit)
174                    elif parent == "Y":
175                        self.current_dataset.yaxis(value, self.current_dataset._yunit)
Note: See TracBrowser for help on using the repository browser.