source: sasview/src/sas/sascalc/dataloader/readers/danse_reader.py @ dcd6efd

magnetic_scattrelease-4.2.2ticket-1009ticket-1094-headlessticket-1242-2d-resolutionticket-1243ticket-1249
Last change on this file since dcd6efd was fc51d06, checked in by krzywon, 6 years ago

Fix broken unit tests and general cleanup.

  • Property mode set to 100644
File size: 7.4 KB
Line 
1"""
2    DANSE/SANS file 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#############################################################################
14import math
15import os
16import logging
17
18import numpy as np
19
20from ..data_info import plottable_2D, DataInfo, Detector
21from ..manipulations import reader2D_converter
22from ..file_reader_base_class import FileReader
23from ..loader_exceptions import FileContentsException, DataReaderException
24
25logger = logging.getLogger(__name__)
26
27# Look for unit converter
28has_converter = True
29try:
30    from sas.sascalc.data_util.nxsunit import Converter
31except:
32    has_converter = False
33
34
35class Reader(FileReader):
36    """
37    Example data manipulation
38    """
39    ## File type
40    type_name = "DANSE"
41    ## Wildcards
42    type = ["DANSE files (*.sans)|*.sans"]
43    ## Extension
44    ext  = ['.sans', '.SANS']
45
46    def get_file_contents(self):
47        self.current_datainfo = DataInfo()
48        self.current_dataset = plottable_2D()
49        self.output = []
50
51        loaded_correctly = True
52        error_message = ""
53
54        # defaults
55        # wavelength in Angstrom
56        wavelength = 10.0
57        # Distance in meter
58        distance   = 11.0
59        # Pixel number of center in x
60        center_x   = 65
61        # Pixel number of center in y
62        center_y   = 65
63        # Pixel size [mm]
64        pixel      = 5.0
65        # Size in x, in pixels
66        size_x     = 128
67        # Size in y, in pixels
68        size_y     = 128
69        # Format version
70        fversion   = 1.0
71
72        self.current_datainfo.filename = os.path.basename(self.f_open.name)
73        detector = Detector()
74        self.current_datainfo.detector.append(detector)
75
76        self.current_dataset.data = np.zeros([size_x, size_y])
77        self.current_dataset.err_data = np.zeros([size_x, size_y])
78
79        read_on = True
80        data_start_line = 1
81        while read_on:
82            line = self.nextline()
83            data_start_line += 1
84            if line.find("DATA:") >= 0:
85                read_on = False
86                break
87            toks = line.split(':')
88            try:
89                if toks[0] == "FORMATVERSION":
90                    fversion = float(toks[1])
91                elif toks[0] == "WAVELENGTH":
92                    wavelength = float(toks[1])
93                elif toks[0] == "DISTANCE":
94                    distance = float(toks[1])
95                elif toks[0] == "CENTER_X":
96                    center_x = float(toks[1])
97                elif toks[0] == "CENTER_Y":
98                    center_y = float(toks[1])
99                elif toks[0] == "PIXELSIZE":
100                    pixel = float(toks[1])
101                elif toks[0] == "SIZE_X":
102                    size_x = int(toks[1])
103                elif toks[0] == "SIZE_Y":
104                    size_y = int(toks[1])
105            except ValueError as e:
106                error_message += "Unable to parse {}. Default value used.\n".format(toks[0])
107                loaded_correctly = False
108
109        # Read the data
110        data = []
111        error = []
112        if not fversion >= 1.0:
113            msg = "danse_reader can't read this file {}".format(self.f_open.name)
114            raise FileContentsException(msg)
115
116        for line_num, data_str in enumerate(self.nextlines()):
117            toks = data_str.split()
118            try:
119                val = float(toks[0])
120                err = float(toks[1])
121                data.append(val)
122                error.append(err)
123            except ValueError as exc:
124                msg = "Unable to parse line {}: {}".format(line_num + data_start_line, data_str.strip())
125                raise FileContentsException(msg)
126
127        num_pts = size_x * size_y
128        if len(data) < num_pts:
129            msg = "Not enough data points provided. Expected {} but got {}".format(
130                size_x * size_y, len(data))
131            raise FileContentsException(msg)
132        elif len(data) > num_pts:
133            error_message += ("Too many data points provided. Expected {0} but"
134                " got {1}. Only the first {0} will be used.\n").format(num_pts, len(data))
135            loaded_correctly = False
136            data = data[:num_pts]
137            error = error[:num_pts]
138
139        # Qx and Qy vectors
140        theta = pixel / distance / 100.0
141        i_x = np.arange(size_x)
142        theta = (i_x - center_x + 1) * pixel / distance / 100.0
143        x_vals = 4.0 * np.pi / wavelength * np.sin(theta / 2.0)
144        xmin = x_vals.min()
145        xmax = x_vals.max()
146
147        i_y = np.arange(size_y)
148        theta = (i_y - center_y + 1) * pixel / distance / 100.0
149        y_vals = 4.0 * np.pi / wavelength * np.sin(theta / 2.0)
150        ymin = y_vals.min()
151        ymax = y_vals.max()
152
153        self.current_dataset.data = np.array(data, dtype=np.float64).reshape((size_y, size_x))
154        if fversion > 1.0:
155            self.current_dataset.err_data = np.array(error, dtype=np.float64).reshape((size_y, size_x))
156
157        # Store all data
158        # Store wavelength
159        if has_converter and self.current_datainfo.source.wavelength_unit != 'A':
160            conv = Converter('A')
161            wavelength = conv(wavelength,
162                              units=self.current_datainfo.source.wavelength_unit)
163        self.current_datainfo.source.wavelength = wavelength
164
165        # Store distance
166        if has_converter and detector.distance_unit != 'm':
167            conv = Converter('m')
168            distance = conv(distance, units=detector.distance_unit)
169        detector.distance = distance
170
171        # Store pixel size
172        if has_converter and detector.pixel_size_unit != 'mm':
173            conv = Converter('mm')
174            pixel = conv(pixel, units=detector.pixel_size_unit)
175        detector.pixel_size.x = pixel
176        detector.pixel_size.y = pixel
177
178        # Store beam center in distance units
179        detector.beam_center.x = center_x * pixel
180        detector.beam_center.y = center_y * pixel
181
182        self.current_dataset = self.set_default_2d_units(self.current_dataset)
183        self.current_dataset.x_bins = x_vals
184        self.current_dataset.y_bins = y_vals
185
186        # Reshape data
187        x_vals = np.tile(x_vals, (size_y, 1)).flatten()
188        y_vals = np.tile(y_vals, (size_x, 1)).T.flatten()
189        if (np.all(self.current_dataset.err_data == None)
190                or np.any(self.current_dataset.err_data <= 0)):
191            new_err_data = np.sqrt(np.abs(self.current_dataset.data))
192        else:
193            new_err_data = self.current_dataset.err_data.flatten()
194
195        self.current_dataset.err_data = new_err_data
196        self.current_dataset.qx_data = x_vals
197        self.current_dataset.qy_data = y_vals
198        self.current_dataset.q_data = np.sqrt(x_vals**2 + y_vals**2)
199        self.current_dataset.mask = np.ones(len(x_vals), dtype=bool)
200
201        # Store loading process information
202        self.current_datainfo.meta_data['loader'] = self.type_name
203
204        self.send_to_output()
205
206        if not loaded_correctly:
207            raise DataReaderException(error_message)
Note: See TracBrowser for help on using the repository browser.