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

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.2.2ticket-1009ticket-1094-headlessticket-1242-2d-resolutionticket-1243ticket-1249ticket885unittest-saveload
Last change on this file since 10ab40e was a235f715, checked in by krzywon, 8 years ago

#500: Final changes to Anton Paar SAXSESS reader.

  • Property mode set to 100644
File size: 7.4 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, Sample, Source
12from sas.sascalc.dataloader.data_info import Process, Aperture, Collimation, TransmissionSpectrum, Detector
13
14
15class Reader(XMLreader):
16    """
17    A class for reading in CanSAS v2.0 data files. The existing iteration opens Mantid generated HDF5 formatted files
18    with file extension .h5/.H5. Any number of data sets may be present within the file and any dimensionality of data
19    may be used. Currently 1D and 2D SAS data sets are supported, but future implementations will include 1D and 2D
20    SESANS data. This class assumes a single data set for each sasentry.
21
22    :Dependencies:
23        The CanSAS HDF5 reader requires h5py v2.5.0 or later.
24    """
25
26    ## Logged warnings or messages
27    logging = None
28    ## List of errors for the current data set
29    errors = None
30    ## Raw file contents to be processed
31    raw_data = None
32    ## Data set being modified
33    current_dataset = None
34    ## For recursion and saving purposes, remember parent objects
35    parent_list = None
36    ## Data type name
37    type_name = "Anton Paar SAXSess"
38    ## Wildcards
39    type = ["Anton Paar SAXSess Files (*.pdh)|*.pdh"]
40    ## List of allowed extensions
41    ext = ['.pdh', '.PDH']
42    ## Flag to bypass extension check
43    allow_all = False
44    ## List of files to return
45    output = None
46
47    def reset_state(self):
48        self.current_dataset = Data1D(np.empty(0), np.empty(0),
49                                            np.empty(0), np.empty(0))
50        self.datasets = []
51        self.raw_data = None
52        self.errors = set()
53        self.logging = []
54        self.output = []
55        self.detector = Detector()
56        self.collimation = Collimation()
57        self.aperture = Aperture()
58        self.process = Process()
59        self.source = Source()
60        self.sample = Sample()
61        self.trans_spectrum = TransmissionSpectrum()
62        self.upper = 5
63        self.lower = 5
64
65    def read(self, filename):
66        """
67            This is the general read method that all SasView data_loaders must have.
68
69            :param filename: A path for an XML formatted Anton Paar SAXSess data file.
70            :return: List of Data1D objects or a list of errors.
71            """
72
73        ## Reinitialize the class when loading a new data file to reset all class variables
74        self.reset_state()
75        ## Check that the file exists
76        if os.path.isfile(filename):
77            basename = os.path.basename(filename)
78            _, extension = os.path.splitext(basename)
79            # If the file type is not allowed, return empty list
80            if extension in self.ext or self.allow_all:
81                ## Load the data file
82                input_f = open(filename, 'r')
83                buff = input_f.read()
84                self.raw_data = buff.splitlines()
85                self.read_data()
86        return self.output
87
88    def read_data(self):
89        q_unit = "1/nm"
90        i_unit = "1/um^2"
91        self.current_dataset.title = self.raw_data[0]
92        self.current_dataset.meta_data["Keywords"] = self.raw_data[1]
93        line3 = self.raw_data[2].split()
94        line4 = self.raw_data[3].split()
95        line5 = self.raw_data[4].split()
96        self.data_points = int(line3[0])
97        self.lower = 5
98        self.upper = self.lower + self.data_points
99        self.source.radiation = 'x-ray'
100        normal = float(line4[3])
101        self.current_dataset.source.radiation = "x-ray"
102        self.current_dataset.source.name = "Anton Paar SAXSess Instrument"
103        self.current_dataset.source.wavelength = float(line4[4])
104        xvals = []
105        yvals = []
106        dyvals = []
107        for i in range(self.lower, self.upper):
108            index = i - self.lower
109            data = self.raw_data[i].split()
110            xvals.insert(index, normal * float(data[0]))
111            yvals.insert(index, normal * float(data[1]))
112            dyvals.insert(index, normal * float(data[2]))
113        self.current_dataset.x = np.append(self.current_dataset.x, xvals)
114        self.current_dataset.y = np.append(self.current_dataset.y, yvals)
115        self.current_dataset.dy = np.append(self.current_dataset.dy, dyvals)
116        if self.data_points != self.current_dataset.x.size:
117            self.errors.add("Not all data was loaded properly.")
118        if self.current_dataset.dx.size != self.current_dataset.x.size:
119            dxvals = np.zeros(self.current_dataset.x.size)
120            self.current_dataset.dx = dxvals
121        if self.current_dataset.x.size != self.current_dataset.y.size:
122            self.errors.add("The x and y data sets are not the same size.")
123        if self.current_dataset.y.size != self.current_dataset.dy.size:
124            self.errors.add("The y and dy datasets are not the same size.")
125        self.current_dataset.errors = self.errors
126        self.current_dataset.xaxis("Q", q_unit)
127        self.current_dataset.yaxis("Intensity", i_unit)
128        xml_intermediate = self.raw_data[self.upper:]
129        xml = ''.join(xml_intermediate)
130        self.set_xml_string(xml)
131        dom = self.xmlroot.xpath('/fileinfo')
132        self._parse_child(dom)
133        self.output.append(self.current_dataset)
134
135    def _parse_child(self, dom, parent=''):
136        """
137        Recursive method for stepping through the embedded XML
138        :param dom: XML node with or without children
139        """
140        for node in dom:
141            tagname = node.tag
142            value = node.text
143            attr = node.attrib
144            key = attr.get("key", '')
145            if len(node.getchildren()) > 1:
146                self._parse_child(node, key)
147                if key == "SampleDetector":
148                    self.current_dataset.detector.append(self.detector)
149                    self.detector = Detector()
150            else:
151                if key == "value":
152                    if parent == "Wavelength":
153                        self.current_dataset.source.wavelength = value
154                    elif parent == "SampleDetector":
155                        self.detector.distance = value
156                    elif parent == "Temperature":
157                        self.current_dataset.sample.temperature = value
158                    elif parent == "CounterSlitLength":
159                        self.detector.slit_length = value
160                elif key == "unit":
161                    value = value.replace("_", "")
162                    if parent == "Wavelength":
163                        self.current_dataset.source.wavelength_unit = value
164                    elif parent == "SampleDetector":
165                        self.detector.distance_unit = value
166                    elif parent == "X":
167                        self.current_dataset.xaxis(self.current_dataset._xaxis, value)
168                    elif parent == "Y":
169                        self.current_dataset.yaxis(self.current_dataset._yaxis, value)
170                    elif parent == "Temperature":
171                        self.current_dataset.sample.temperature_unit = value
172                    elif parent == "CounterSlitLength":
173                        self.detector.slit_length_unit = value
174                elif key == "quantity":
175                    if parent == "X":
176                        self.current_dataset.xaxis(value, self.current_dataset._xunit)
177                    elif parent == "Y":
178                        self.current_dataset.yaxis(value, self.current_dataset._yunit)
Note: See TracBrowser for help on using the repository browser.