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

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

Better pep8 in sesans_reader

  • Property mode set to 100644
File size: 6.6 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(
53                    "{} has an unrecognized file extension".format(path))
54        else:
55            raise RuntimeError("{} is not a file".format(path))
56        with open(path, 'r') as input_f:
57            line = input_f.readline()
58            params = {}
59            while not line.startswith("BEGIN_DATA"):
60                terms = line.split()
61                if len(terms) >= 2:
62                    params[terms[0]] = " ".join(terms[1:])
63                line = input_f.readline()
64            self.params = params
65
66            if "FileFormatVersion" not in self.params:
67                raise RuntimeError("SES file missing FileFormatVersion")
68            if float(self.params["FileFormatVersion"]) >= 2.0:
69                raise RuntimeError("SASView only supports SES version 1")
70
71            if "SpinEchoLength_unit" not in self.params:
72                raise RuntimeError("SpinEchoLength has no units")
73            if "Wavelength_unit" not in self.params:
74                raise RuntimeError("Wavelength has no units")
75            if params["SpinEchoLength_unit"] != params["Wavelength_unit"]:
76                raise RuntimeError("The spin echo data has rudely used "
77                                   "different units for the spin echo length "
78                                   "and the wavelength.  While sasview could "
79                                   "handle this instance, it is a violation "
80                                   "of the file format and will not be "
81                                   "handled by other software.")
82
83            headers = input_f.readline().split()
84
85            self._insist_header(headers, "SpinEchoLength")
86            self._insist_header(headers, "Depolarisation")
87            self._insist_header(headers, "Depolarisation_error")
88            self._insist_header(headers, "Wavelength")
89
90            data = np.loadtxt(input_f)
91
92            if data.shape[1] != len(headers):
93                raise RuntimeError(
94                    "File has {} headers, but {} columns".format(
95                        len(headers),
96                        data.shape[1]))
97
98            if not data.size:
99                raise RuntimeError("{} is empty".format(path))
100            x = data[:, headers.index("SpinEchoLength")]
101            if "SpinEchoLength_error" in headers:
102                dx = data[:, headers.index("SpinEchoLength_error")]
103            else:
104                dx = x * 0.05
105            lam = data[:, headers.index("Wavelength")]
106            if "Wavelength_error" in headers:
107                dlam = data[:, headers.index("Wavelength_error")]
108            else:
109                dlam = lam * 0.05
110            y = data[:, headers.index("Depolarisation")]
111            dy = data[:, headers.index("Depolarisation_error")]
112
113            lam_unit = self._unit_fetch("Wavelength")
114            x, x_unit = self._unit_conversion(x, "A",
115                                              self._unit_fetch(
116                                                  "SpinEchoLength"))
117            dx, dx_unit = self._unit_conversion(
118                dx, lam_unit,
119                self._unit_fetch("SpinEchoLength"))
120            dlam, dlam_unit = self._unit_conversion(
121                dlam, lam_unit,
122                self._unit_fetch("Wavelength"))
123            y_unit = self._unit_fetch("Depolarisation")
124
125            output = Data1D(x=x, y=y, lam=lam, dy=dy, dx=dx, dlam=dlam,
126                            isSesans=True)
127
128            output.y_unit = y_unit
129            output.x_unit = x_unit
130            output.source.wavelength_unit = lam_unit
131            output.source.wavelength = lam
132            self.filename = output.filename = basename
133            output.xaxis(r"\rm{z}", x_unit)
134            # Adjust label to ln P/(lam^2 t), remove lam column refs
135            output.yaxis(r"\rm{ln(P)/(t \lambda^2)}", y_unit)
136            # Store loading process information
137            output.meta_data['loader'] = self.type_name
138            output.sample.name = params["Sample"]
139            output.sample.ID = params["DataFileTitle"]
140            output.sample.thickness = self._unit_conversion(
141                float(params["Thickness"]), "cm",
142                self._unit_fetch("Thickness"))[0]
143
144            output.sample.zacceptance = (
145                float(params["Theta_zmax"]),
146                self._unit_fetch("Theta_zmax"))
147
148            output.sample.yacceptance = (
149                float(params["Theta_ymax"]),
150                self._unit_fetch("Theta_ymax"))
151            return output
152
153    @staticmethod
154    def _insist_header(headers, name):
155        if name not in headers:
156            raise RuntimeError(
157                "Missing {} column in spin echo data".format(name))
158
159    @staticmethod
160    def _unit_conversion(value, value_unit, default_unit):
161        """
162        Performs unit conversion on a measurement.
163
164        :param value: The magnitude of the measurement
165        :param value_unit: a string containing the final desired unit
166        :param default_unit: string with the units of the original measurement
167        :return: The magnitude of the measurement in the new units
168        """
169        # (float, string, string) -> float
170        if has_converter and value_unit != default_unit:
171            data_conv_q = Converter(default_unit)
172            value = data_conv_q(value, units=value_unit)
173            new_unit = default_unit
174        else:
175            new_unit = value_unit
176        return value, new_unit
177
178    def _unit_fetch(self, unit):
179        return self.params[unit+"_unit"]
Note: See TracBrowser for help on using the repository browser.