source: sasview/src/sas/sascalc/dataloader/readers/ascii_reader.py @ 1f6d293

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.2ticket-1009ticket-1094-headlessticket-1242-2d-resolutionticket-1243ticket-1249ticket885unittest-saveload
Last change on this file since 1f6d293 was b699768, checked in by Piotr Rozyczko <piotr.rozyczko@…>, 9 years ago

Initial commit of the refactored SasCalc? module.

  • Property mode set to 100644
File size: 15.3 KB
Line 
1"""
2    ASCII 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#If you use DANSE applications to do scientific research that leads to
9#publication, we ask that you acknowledge the use of the software with the
10#following sentence:
11#This work benefited from DANSE software developed under NSF award DMR-0520547.
12#copyright 2008, University of Tennessee
13#############################################################################
14
15
16import numpy
17import os
18from sas.sascalc.dataloader.data_info import Data1D
19
20# Check whether we have a converter available
21has_converter = True
22try:
23    from sas.sascalc.data_util.nxsunit import Converter
24except:
25    has_converter = False
26_ZERO = 1e-16
27
28
29class Reader:
30    """
31    Class to load ascii files (2, 3 or 4 columns).
32    """
33    ## File type
34    type_name = "ASCII"
35   
36    ## Wildcards
37    type = ["ASCII files (*.txt)|*.txt",
38            "ASCII files (*.dat)|*.dat",
39            "ASCII files (*.abs)|*.abs",
40            "CSV files (*.csv)|*.csv"]
41    ## List of allowed extensions
42    ext = ['.txt', '.TXT', '.dat', '.DAT', '.abs', '.ABS', 'csv', 'CSV']
43   
44    ## Flag to bypass extension check
45    allow_all = True
46   
47    def read(self, path):
48        """
49        Load data file
50       
51        :param path: file path
52       
53        :return: Data1D object, or None
54       
55        :raise RuntimeError: when the file can't be opened
56        :raise ValueError: when the length of the data vectors are inconsistent
57        """
58        if os.path.isfile(path):
59            basename = os.path.basename(path)
60            _, extension = os.path.splitext(basename)
61            if self.allow_all or extension.lower() in self.ext:
62                try:
63                    # Read in binary mode since GRASP frequently has no-ascii
64                    # characters that brakes the open operation
65                    input_f = open(path,'rb')
66                except:
67                    raise  RuntimeError, "ascii_reader: cannot open %s" % path
68                buff = input_f.read()
69                lines = buff.splitlines()
70                 
71                x  = numpy.zeros(0)
72                y  = numpy.zeros(0)
73                dy = numpy.zeros(0)
74                dx = numpy.zeros(0)
75               
76                #temp. space to sort data
77                tx  = numpy.zeros(0)
78                ty  = numpy.zeros(0)
79                tdy = numpy.zeros(0)
80                tdx = numpy.zeros(0)
81               
82                output = Data1D(x, y, dy=dy, dx=dx)
83                self.filename = output.filename = basename
84           
85                data_conv_q = None
86                data_conv_i = None
87               
88                if has_converter == True and output.x_unit != '1/A':
89                    data_conv_q = Converter('1/A')
90                    # Test it
91                    data_conv_q(1.0, output.x_unit)
92                   
93                if has_converter == True and output.y_unit != '1/cm':
94                    data_conv_i = Converter('1/cm')
95                    # Test it
96                    data_conv_i(1.0, output.y_unit)
97           
98                # The first good line of data will define whether
99                # we have 2-column or 3-column ascii
100                has_error_dx = None
101                has_error_dy = None
102               
103                #Initialize counters for data lines and header lines.
104                is_data = False  # Has more than 5 lines
105                # More than "5" lines of data is considered as actual
106                # data unless that is the only data
107                mum_data_lines = 5
108                # To count # of current data candidate lines
109                i = -1
110                # To count total # of previous data candidate lines
111                i1 = -1
112                # To count # of header lines
113                j = -1
114                # Helps to count # of header lines
115                j1 = -1
116                #minimum required number of columns of data; ( <= 4).
117                lentoks = 2
118                for line in lines:
119                    # Initial try for CSV (split on ,)
120                    toks = line.split(',')
121                    # Now try SCSV (split on ;)
122                    if len(toks) < 2:
123                        toks = line.split(';')
124                    # Now go for whitespace                   
125                    if len(toks) < 2:
126                        toks = line.split()
127                    try:
128                        #Make sure that all columns are numbers.
129                        for colnum in range(len(toks)):
130                            float(toks[colnum])
131                           
132                        _x = float(toks[0])
133                        _y = float(toks[1])
134                       
135                        #Reset the header line counters
136                        if j == j1:
137                            j = 0
138                            j1 = 0
139                           
140                        if i > 1:
141                            is_data = True
142                       
143                        if data_conv_q is not None:
144                            _x = data_conv_q(_x, units=output.x_unit)
145                           
146                        if data_conv_i is not None:
147                            _y = data_conv_i(_y, units=output.y_unit)
148                       
149                        # If we have an extra token, check
150                        # whether it can be interpreted as a
151                        # third column.
152                        _dy = None
153                        if len(toks) > 2:
154                            try:
155                                _dy = float(toks[2])
156                               
157                                if data_conv_i is not None:
158                                    _dy = data_conv_i(_dy, units=output.y_unit)
159                               
160                            except:
161                                # The third column is not a float, skip it.
162                                pass
163                           
164                        # If we haven't set the 3rd column
165                        # flag, set it now.
166                        if has_error_dy == None:
167                            has_error_dy = False if _dy == None else True
168                           
169                        #Check for dx
170                        _dx = None
171                        if len(toks) > 3:
172                            try:
173                                _dx = float(toks[3])
174                               
175                                if data_conv_i is not None:
176                                    _dx = data_conv_i(_dx, units=output.x_unit)
177                               
178                            except:
179                                # The 4th column is not a float, skip it.
180                                pass
181                           
182                        # If we haven't set the 3rd column
183                        # flag, set it now.
184                        if has_error_dx == None:
185                            has_error_dx = False if _dx == None else True
186                       
187                        #After talked with PB, we decided to take care of only
188                        # 4 columns of data for now.
189                        #number of columns in the current line
190                        #To remember the # of columns in the current
191                        #line of data
192                        new_lentoks = len(toks)
193                       
194                        #If the previous columns not equal to the current,
195                        #mark the previous as non-data and reset the dependents.
196                        if lentoks != new_lentoks:
197                            if is_data == True:
198                                break
199                            else:
200                                i = -1
201                                i1 = 0
202                                j = -1
203                                j1 = -1
204                           
205                        #Delete the previously stored lines of data candidates
206                        # if is not data.
207                        if i < 0 and -1 < i1 < mum_data_lines and \
208                            is_data == False:
209                            try:
210                                x = numpy.zeros(0)
211                                y = numpy.zeros(0)
212                            except:
213                                pass
214                           
215                        x = numpy.append(x, _x)
216                        y = numpy.append(y, _y)
217                       
218                        if has_error_dy == True:
219                            #Delete the previously stored lines of
220                            # data candidates if is not data.
221                            if i < 0 and -1 < i1 < mum_data_lines and \
222                                is_data == False:
223                                try:
224                                    dy = numpy.zeros(0)
225                                except:
226                                    pass
227                            dy = numpy.append(dy, _dy)
228                           
229                        if has_error_dx == True:
230                            #Delete the previously stored lines of
231                            # data candidates if is not data.
232                            if i < 0 and -1 < i1 < mum_data_lines and \
233                                is_data == False:
234                                try:
235                                    dx = numpy.zeros(0)
236                                except:
237                                    pass
238                            dx = numpy.append(dx, _dx)
239                           
240                        #Same for temp.
241                        #Delete the previously stored lines of data candidates
242                        # if is not data.
243                        if i < 0 and -1 < i1 < mum_data_lines and\
244                            is_data == False:
245                            try:
246                                tx = numpy.zeros(0)
247                                ty = numpy.zeros(0)
248                            except:
249                                pass
250
251                        tx = numpy.append(tx, _x)
252                        ty = numpy.append(ty, _y)
253                       
254                        if has_error_dy == True:
255                            #Delete the previously stored lines of
256                            # data candidates if is not data.
257                            if i < 0 and -1 < i1 < mum_data_lines and \
258                                is_data == False:
259                                try:
260                                    tdy = numpy.zeros(0)
261                                except:
262                                    pass
263                            tdy = numpy.append(tdy, _dy)
264                        if has_error_dx == True:
265                            #Delete the previously stored lines of
266                            # data candidates if is not data.
267                            if i < 0 and -1 < i1 < mum_data_lines and \
268                                is_data == False:
269                                try:
270                                    tdx = numpy.zeros(0)
271                                except:
272                                    pass
273                            tdx = numpy.append(tdx, _dx)
274
275                        #reset i1 and flag lentoks for the next
276                        if lentoks < new_lentoks:
277                            if is_data == False:
278                                i1 = -1
279                        #To remember the # of columns on the current line
280                        # for the next line of data
281                        lentoks = len(toks)
282                       
283                        #Reset # of header lines and counts #
284                        # of data candidate lines
285                        if j == 0 and j1 == 0:
286                            i1 = i + 1
287                        i += 1
288                    except:
289                        # It is data and meet non - number, then stop reading
290                        if is_data == True:
291                            break
292                        lentoks = 2
293                        #Counting # of header lines
294                        j += 1
295                        if j == j1 + 1:
296                            j1 = j
297                        else:
298                            j = -1
299                        #Reset # of lines of data candidates
300                        i = -1
301                       
302                        # Couldn't parse this line, skip it
303                        pass
304                   
305                input_f.close()
306                # Sanity check
307                if has_error_dy == True and not len(y) == len(dy):
308                    msg = "ascii_reader: y and dy have different length"
309                    raise RuntimeError, msg
310                if has_error_dx == True and not len(x) == len(dx):
311                    msg = "ascii_reader: y and dy have different length"
312                    raise RuntimeError, msg
313                # If the data length is zero, consider this as
314                # though we were not able to read the file.
315                if len(x) == 0:
316                    raise RuntimeError, "ascii_reader: could not load file"
317               
318                #Let's re-order the data to make cal.
319                # curve look better some cases
320                ind = numpy.lexsort((ty, tx))
321                for i in ind:
322                    x[i] = tx[ind[i]]
323                    y[i] = ty[ind[i]]
324                    if has_error_dy == True:
325                        dy[i] = tdy[ind[i]]
326                    if has_error_dx == True:
327                        dx[i] = tdx[ind[i]]
328                # Zeros in dx, dy
329                if has_error_dx:
330                    dx[dx == 0] = _ZERO
331                if has_error_dy:
332                    dy[dy == 0] = _ZERO
333                #Data
334                output.x = x[x != 0]
335                output.y = y[x != 0]
336                output.dy = dy[x != 0] if has_error_dy == True\
337                    else numpy.zeros(len(output.y))
338                output.dx = dx[x != 0] if has_error_dx == True\
339                    else numpy.zeros(len(output.x))
340                               
341                if data_conv_q is not None:
342                    output.xaxis("\\rm{Q}", output.x_unit)
343                else:
344                    output.xaxis("\\rm{Q}", 'A^{-1}')
345                if data_conv_i is not None:
346                    output.yaxis("\\rm{Intensity}", output.y_unit)
347                else:
348                    output.yaxis("\\rm{Intensity}", "cm^{-1}")
349                   
350                # Store loading process information
351                output.meta_data['loader'] = self.type_name
352                if len(output.x) < 1:
353                    raise RuntimeError, "%s is empty" % path
354                return output
355           
356        else:
357            raise RuntimeError, "%s is not a file" % path
358        return None
Note: See TracBrowser for help on using the repository browser.