source: sasview/src/sas/sascalc/dataloader/readers/sesans_reader.py @ cb9feea8

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 cb9feea8 was cb9feea8, checked in by Adam Washington <adam.washington@…>, 3 years ago

Pulled code out of conditional in sesans_reader.py

  • Property mode set to 100644
File size: 5.9 KB
Line 
1"""
2    SESANS reader (based on ASCII reader)
3
4    Reader for .ses or .sesans file format
5
6    Jurrian Bakker
7"""
8import numpy as np
9import os
10from sas.sascalc.dataloader.data_info import Data1D
11
12# Check whether we have a converter available
13has_converter = True
14try:
15    from sas.sascalc.data_util.nxsunit import Converter
16except:
17    has_converter = False
18_ZERO = 1e-16
19
20
21class Reader:
22    """
23    Class to load sesans files (6 columns).
24    """
25    # File type
26    type_name = "SESANS"
27
28    # Wildcards
29    type = ["SESANS files (*.ses)|*.ses",
30            "SESANS files (*..sesans)|*.sesans"]
31    # List of allowed extensions
32    ext = ['.ses', '.SES', '.sesans', '.SESANS']
33
34    # Flag to bypass extension check
35    allow_all = True
36
37    def read(self, path):
38        """
39        Load data file
40
41        :param path: file path
42
43        :return: SESANSData1D object, or None
44
45        :raise RuntimeError: when the file can't be opened
46        :raise ValueError: when the length of the data vectors are inconsistent
47        """
48        if os.path.isfile(path):
49            basename = os.path.basename(path)
50            _, extension = os.path.splitext(basename)
51            if not (self.allow_all or extension.lower() in self.ext):
52                raise RuntimeError("{} has an unrecognized file extension".format(path))
53        else:
54            raise RunetimeError("{} is not a file".format(path))
55        with open(path, 'r') as input_f:
56            # Read in binary mode since GRASP frequently has no-ascii
57            # characters that brakes the open operation
58            line = input_f.readline()
59            params = {}
60            while line.strip() != "":
61                terms = line.strip().split("\t")
62                params[terms[0].strip()] = " ".join(terms[1:]).strip()
63                line = input_f.readline()
64            headers_temp = input_f.readline().strip().split("\t")
65            headers = {}
66            for h in headers_temp:
67                temp = h.strip().split()
68                headers[h[:-1].strip()] = temp[-1][1:-1]
69            data = np.loadtxt(input_f)
70            if data.size < 1:
71                raise RuntimeError("{} is empty".format(path))
72            x = data[:, 0]
73            dx = data[:, 3]
74            lam = data[:, 4]
75            dlam = data[:, 5]
76            y = data[:, 1]
77            dy = data[:, 2]
78
79            lam_unit = self._header_fetch(headers, "wavelength")
80            if lam_unit == "AA":
81                lam_unit = "A"
82
83            x, x_unit = self._unit_conversion(
84                x, lam_unit,
85                self._fetch_unit(headers, "spin echo length"))
86            dx, dx_unit = self._unit_conversion(
87                dx, lam_unit,
88                self._fetch_unit(headers, "error SEL"))
89            dlam, dlam_unit = self._unit_conversion(
90                dlam, lam_unit,
91                self._fetch_unit(headers, "error wavelength"))
92            y_unit = r'\AA^{-2} cm^{-1}'
93
94            output = Data1D(x=x, y=y, lam=lam, dy=dy, dx=dx, dlam=dlam,
95                            isSesans=True)
96            self.filename = output.filename = basename
97            output.xaxis(r"\rm{z}", x_unit)
98            # Adjust label to ln P/(lam^2 t), remove lam column refs
99            output.yaxis(r"\rm{ln(P)/(t \lambda^2)}", y_unit)
100            # Store loading process information
101            output.meta_data['loader'] = self.type_name
102            output.sample.name = params["Sample"]
103            output.sample.ID = params["DataFileTitle"]
104
105            output.sample.zacceptance = (
106                float(self._header_fetch(params, "Q_zmax")),
107                self._fetch_unit(params, "Q_zmax"))
108
109            output.sample.yacceptance = (
110                float(self._header_fetch(params, "Q_ymax")),
111                self._fetch_unit(params, "Q_ymax"))
112            return output
113
114    @staticmethod
115    def _unit_conversion(value, value_unit, default_unit):
116        """
117        Performs unit conversion on a measurement.
118
119        :param value: The magnitude of the measurement
120        :param value_unit: a string containing the final desired unit
121        :param default_unit: a string containing the units of the original measurement
122        :return: The magnitude of the measurement in the new units
123        """
124        # (float, string, string) -> float
125        if has_converter and value_unit != default_unit:
126            data_conv_q = Converter(value_unit)
127            value = data_conv_q(value, units=default_unit)
128            new_unit = default_unit
129        else:
130            new_unit = value_unit
131        return value, new_unit
132
133    @staticmethod
134    def _header_fetch(headers, key):
135        """
136        Pull the value of a unit defined header from a dict. Example::
137
138         d = {"Length [m]": 17}
139         self._header_fetch(d, "Length") == 17
140
141        :param header: A dictionary of values
142        :param key: A string which is a prefix for one of the keys in the dict
143        :return: The value of the dictionary for the specified key
144        """
145        # (dict<string, x>, string) -> x
146        index = [k for k in headers.keys()
147                 if k.startswith(key)][0]
148        return headers[index]
149
150    @staticmethod
151    def _fetch_unit(params, key):
152        """
153        Pull the unit off of a dictionary header. Example::
154
155         d = {"Length [m]": 17}
156         self._fetch_unit(d, "Length") == "m"
157
158        :param header: A dictionary of values, where the keys are strings
159        with the units for the values appended onto the string within square
160        brackets (See the example above)
161        :param key: A string with the prefix of the dictionary key whose unit
162        is being fetched
163        :return: A string containing the unit specifed in the header
164        """
165        # (dict<string, _>, string) -> string
166        index = [k for k in params.keys()
167                 if k.startswith(key)][0]
168        unit = index.strip().split()[-1][1:-1]
169        if unit.startswith(r"\A"):
170            unit = "1/A"
171        return unit
Note: See TracBrowser for help on using the repository browser.