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

Last change on this file since a16cbb0 was e3775c6, checked in by krzywon, 7 years ago

Use startswith instead of count for line matching in ABS reader.

  • Property mode set to 100644
File size: 9.2 KB
Line 
1"""
2    IGOR 1D data reader
3"""
4#####################################################################
5# This software was developed by the University of Tennessee as part of the
6# Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
7# project funded by the US National Science Foundation.
8# See the license text in license.txt
9# copyright 2008, University of Tennessee
10######################################################################
11
12import logging
13
14import numpy as np
15
16from sas.sascalc.data_util.nxsunit import Converter
17from ..file_reader_base_class import FileReader
18from ..data_info import DataInfo, plottable_1D, Data1D, Detector
19from ..loader_exceptions import FileContentsException, DefaultReaderException
20
21logger = logging.getLogger(__name__)
22
23
24class Reader(FileReader):
25    """
26    Class to load IGOR reduced .ABS files
27    """
28    # File type
29    type_name = "IGOR 1D"
30    # Wildcards
31    type = ["IGOR 1D files (*.abs)|*.abs", "IGOR 1D USANS files (*.cor)|*.cor"]
32    # List of allowed extensions
33    ext = ['.abs', '.cor']
34
35    def get_file_contents(self):
36        """
37        Get the contents of the file
38
39        :raise RuntimeError: when the file can't be opened
40        :raise ValueError: when the length of the data vectors are inconsistent
41        """
42        buff = self.readall()
43        filepath = self.f_open.name
44        lines = buff.splitlines()
45        self.output = []
46        self.current_datainfo = DataInfo()
47        self.current_datainfo.filename = filepath
48        detector = Detector()
49        data_line = 0
50        self.reset_data_list(len(lines))
51        self.current_datainfo.detector.append(detector)
52        self.current_datainfo.filename = filepath
53
54        is_info = False
55        is_center = False
56        is_data_started = False
57
58        base_q_unit = '1/A'
59        base_i_unit = '1/cm'
60        data_conv_q = Converter(base_q_unit)
61        data_conv_i = Converter(base_i_unit)
62
63        for line in lines:
64            # Information line 1
65            if is_info:
66                is_info = False
67                line_toks = line.split()
68
69                # Wavelength in Angstrom
70                try:
71                    value = float(line_toks[1])
72                    if self.current_datainfo.source.wavelength_unit != 'A':
73                        conv = Converter('A')
74                        self.current_datainfo.source.wavelength = conv(value,
75                            units=self.current_datainfo.source.wavelength_unit)
76                    else:
77                        self.current_datainfo.source.wavelength = value
78                except KeyError:
79                    msg = "ABSReader cannot read wavelength from %s" % filepath
80                    self.current_datainfo.errors.append(msg)
81
82                # Detector distance in meters
83                try:
84                    value = float(line_toks[3])
85                    if detector.distance_unit != 'm':
86                        conv = Converter('m')
87                        detector.distance = conv(value,
88                                        units=detector.distance_unit)
89                    else:
90                        detector.distance = value
91                except Exception:
92                    msg = "ABSReader cannot read SDD from %s" % filepath
93                    self.current_datainfo.errors.append(msg)
94
95                # Transmission
96                try:
97                    self.current_datainfo.sample.transmission = \
98                        float(line_toks[4])
99                except ValueError:
100                    # Transmission isn't always in the header
101                    pass
102
103                # Sample thickness in mm
104                try:
105                    # ABS writer adds 'C' with no space to the end of the
106                    # thickness column.  Remove it if it is there before
107                    # converting the thickness.
108                    if line_toks[5][-1] not in '012345679.':
109                        value = float(line_toks[5][:-1])
110                    else:
111                        value = float(line_toks[5])
112                    if self.current_datainfo.sample.thickness_unit != 'cm':
113                        conv = Converter('cm')
114                        self.current_datainfo.sample.thickness = conv(value,
115                            units=self.current_datainfo.sample.thickness_unit)
116                    else:
117                        self.current_datainfo.sample.thickness = value
118                except ValueError:
119                    # Thickness is not a mandatory entry
120                    pass
121
122            # MON CNT  LAMBDA  DET ANG  DET DIST  TRANS  THICK  AVE   STEP
123            if line.count("LAMBDA") > 0:
124                is_info = True
125
126            # Find center info line
127            if is_center:
128                is_center = False
129                line_toks = line.split()
130                # Center in bin number
131                center_x = float(line_toks[0])
132                center_y = float(line_toks[1])
133
134                # Bin size
135                if detector.pixel_size_unit != 'mm':
136                    conv = Converter('mm')
137                    detector.pixel_size.x = conv(5.08,
138                                        units=detector.pixel_size_unit)
139                    detector.pixel_size.y = conv(5.08,
140                                        units=detector.pixel_size_unit)
141                else:
142                    detector.pixel_size.x = 5.08
143                    detector.pixel_size.y = 5.08
144
145                # Store beam center in distance units
146                # Det 640 x 640 mm
147                if detector.beam_center_unit != 'mm':
148                    conv = Converter('mm')
149                    detector.beam_center.x = conv(center_x * 5.08,
150                                     units=detector.beam_center_unit)
151                    detector.beam_center.y = conv(center_y * 5.08,
152                                     units=detector.beam_center_unit)
153                else:
154                    detector.beam_center.x = center_x * 5.08
155                    detector.beam_center.y = center_y * 5.08
156
157                # Detector type
158                try:
159                    detector.name = line_toks[7]
160                except:
161                    # Detector name is not a mandatory entry
162                    pass
163
164            # BCENT(X,Y)  A1(mm)  A2(mm)  A1A2DIST(m)  DL/L  BSTOP(mm)  DET_TYP
165            if line.count("BCENT") > 0:
166                is_center = True
167
168            # Parse the data
169            if is_data_started:
170                toks = line.split()
171
172                try:
173                    _x = float(toks[0])
174                    _y = float(toks[1])
175                    _dy = float(toks[2])
176                    _dx = float(toks[3])
177
178                    if data_conv_q is not None:
179                        _x = data_conv_q(_x, units=base_q_unit)
180                        _dx = data_conv_q(_dx, units=base_q_unit)
181
182                    if data_conv_i is not None:
183                        _y = data_conv_i(_y, units=base_i_unit)
184                        _dy = data_conv_i(_dy, units=base_i_unit)
185
186                    self.current_dataset.x[data_line] = _x
187                    self.current_dataset.y[data_line] = _y
188                    self.current_dataset.dy[data_line] = _dy
189                    if _dx > 0:
190                        self.current_dataset.dx[data_line] = _dx
191                    else:
192                        if data_line == 0:
193                            self.current_dataset.dx = None
194                            self.current_dataset.dxl = np.zeros(len(lines))
195                            self.current_dataset.dxw = np.zeros(len(lines))
196                        self.current_dataset.dxl[data_line] = abs(_dx)
197                        self.current_dataset.dxw[data_line] = 0
198                    data_line += 1
199
200                except ValueError:
201                    # Could not read this data line. If we are here
202                    # it is because we are in the data section. Just
203                    # skip it.
204                    pass
205
206            # SANS Data:
207            # The 6 columns are | Q (1/A) | I(Q) (1/cm) | std. dev.
208            # I(Q) (1/cm) | sigmaQ | meanQ | ShadowFactor|
209            # USANS Data:
210            # EMP LEVEL: <value> ; BKG LEVEL: <value>
211            if line.startswith("The 6 columns") or line.startswith("EMP LEVEL"):
212                is_data_started = True
213
214        self.remove_empty_q_values()
215
216        # Sanity check
217        if not len(self.current_dataset.y) == len(self.current_dataset.dy):
218            self.set_all_to_none()
219            msg = "abs_reader: y and dy have different length"
220            raise ValueError(msg)
221        # If the data length is zero, consider this as
222        # though we were not able to read the file.
223        if len(self.current_dataset.x) == 0:
224            self.set_all_to_none()
225            raise ValueError("ascii_reader: could not load file")
226
227        if data_conv_q is not None:
228            self.current_dataset.xaxis("\\rm{Q}", base_q_unit)
229        else:
230            self.current_dataset.xaxis("\\rm{Q}", 'A^{-1}')
231        if data_conv_i is not None:
232            self.current_dataset.yaxis("\\rm{Intensity}", base_i_unit)
233        else:
234            self.current_dataset.yaxis("\\rm{Intensity}", "cm^{-1}")
235
236        # Store loading process information
237        self.current_datainfo.meta_data['loader'] = self.type_name
238        self.send_to_output()
Note: See TracBrowser for help on using the repository browser.