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

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 83ee7258 was 5a8cdbb, checked in by lewis, 7 years ago

Merge branch 'master' into ticket-876

  • Property mode set to 100644
File size: 6.7 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.file_reader_base_class import FileReader
11from sas.sascalc.dataloader.data_info import plottable_1D, DataInfo
12from sas.sascalc.dataloader.loader_exceptions import FileContentsException, DataReaderException
13
14# Check whether we have a converter available
15has_converter = True
16try:
17    from sas.sascalc.data_util.nxsunit import Converter
18except:
19    has_converter = False
20_ZERO = 1e-16
21
22class Reader(FileReader):
23    """
24    Class to load sesans files (6 columns).
25    """
26    # File type
27    type_name = "SESANS"
28
29    ## Wildcards
30    type = ["SESANS files (*.ses)|*.ses",
31            "SESANS files (*..sesans)|*.sesans"]
32    # List of allowed extensions
33    ext = ['.ses', '.SES', '.sesans', '.SESANS']
34
35    # Flag to bypass extension check
36    allow_all = True
37
38    def get_file_contents(self):
39        self.current_datainfo = DataInfo()
40        self.current_dataset = plottable_1D(np.array([]), np.array([]))
41        self.current_datainfo.isSesans = True
42        self.output = []
43
44        line = self.f_open.readline()
45        params = {}
46        while not line.startswith("BEGIN_DATA"):
47            terms = line.split()
48            if len(terms) >= 2:
49                params[terms[0]] = " ".join(terms[1:])
50            line = self.f_open.readline()
51        self.params = params
52
53        if "FileFormatVersion" not in self.params:
54            raise FileContentsException("SES file missing FileFormatVersion")
55        if float(self.params["FileFormatVersion"]) >= 2.0:
56            raise FileContentsException("SASView only supports SES version 1")
57
58        if "SpinEchoLength_unit" not in self.params:
59            raise FileContentsException("SpinEchoLength has no units")
60        if "Wavelength_unit" not in self.params:
61            raise FileContentsException("Wavelength has no units")
62        if params["SpinEchoLength_unit"] != params["Wavelength_unit"]:
63            raise FileContentsException("The spin echo data has rudely used "
64                               "different units for the spin echo length "
65                               "and the wavelength.  While sasview could "
66                               "handle this instance, it is a violation "
67                               "of the file format and will not be "
68                               "handled by other software.")
69
70        headers = self.f_open.readline().split()
71
72        self._insist_header(headers, "SpinEchoLength")
73        self._insist_header(headers, "Depolarisation")
74        self._insist_header(headers, "Depolarisation_error")
75        self._insist_header(headers, "Wavelength")
76
77            data = np.loadtxt(self.f_open)
78
79            if data.shape[1] != len(headers):
80                raise FileContentsException(
81                    "File has {} headers, but {} columns".format(
82                        len(headers),
83                        data.shape[1]))
84
85            if not data.size:
86                raise FileContentsException("{} is empty".format(path))
87            x = data[:, headers.index("SpinEchoLength")]
88            if "SpinEchoLength_error" in headers:
89                dx = data[:, headers.index("SpinEchoLength_error")]
90            else:
91                dx = x * 0.05
92            lam = data[:, headers.index("Wavelength")]
93            if "Wavelength_error" in headers:
94                dlam = data[:, headers.index("Wavelength_error")]
95            else:
96                dlam = lam * 0.05
97            y = data[:, headers.index("Depolarisation")]
98            dy = data[:, headers.index("Depolarisation_error")]
99
100            lam_unit = self._unit_fetch("Wavelength")
101            x, x_unit = self._unit_conversion(x, "A",
102                                              self._unit_fetch(
103                                                  "SpinEchoLength"))
104            dx, dx_unit = self._unit_conversion(
105                dx, lam_unit,
106                self._unit_fetch("SpinEchoLength"))
107            dlam, dlam_unit = self._unit_conversion(
108                dlam, lam_unit,
109                self._unit_fetch("Wavelength"))
110            y_unit = self._unit_fetch("Depolarisation")
111
112            self.current_dataset.x = x
113            self.current_dataset.y = y
114            self.current_dataset.lam = lam
115            self.current_dataset.dy = dy
116            self.current_dataset.dx = dx
117            self.current_dataset.dlam = dlam
118            self.current_datainfo.isSesans = True
119
120            self.current_datainfo._yunit = y_unit
121            self.current_datainfo._xunit = x_unit
122            self.current_datainfo.source.wavelength_unit = lam_unit
123            self.current_datainfo.source.wavelength = lam
124            self.current_datainfo.filename = os.basename(self.f_open.name)
125            self.current_dataset.xaxis(r"\rm{z}", x_unit)
126            # Adjust label to ln P/(lam^2 t), remove lam column refs
127            self.current_dataset.yaxis(r"\rm{ln(P)/(t \lambda^2)}", y_unit)
128            # Store loading process information
129            self.current_datainfo.meta_data['loader'] = self.type_name
130            self.current_datainfo.sample.name = params["Sample"]
131            self.current_datainfo.sample.ID = params["DataFileTitle"]
132            self.current_datainfo.sample.thickness = self._unit_conversion(
133                float(params["Thickness"]), "cm",
134                self._unit_fetch("Thickness"))[0]
135
136            self.current_datainfo.sample.zacceptance = (
137                float(params["Theta_zmax"]),
138                self._unit_fetch("Theta_zmax"))
139
140            self.current_datainfo.sample.yacceptance = (
141                float(params["Theta_ymax"]),
142                self._unit_fetch("Theta_ymax"))
143
144            self.send_to_output()
145
146    @staticmethod
147    def _insist_header(headers, name):
148        if name not in headers:
149            raise FileContentsException(
150                "Missing {} column in spin echo data".format(name))
151
152    @staticmethod
153    def _unit_conversion(value, value_unit, default_unit):
154        """
155        Performs unit conversion on a measurement.
156
157        :param value: The magnitude of the measurement
158        :param value_unit: a string containing the final desired unit
159        :param default_unit: string with the units of the original measurement
160        :return: The magnitude of the measurement in the new units
161        """
162        # (float, string, string) -> float
163        if has_converter and value_unit != default_unit:
164            data_conv_q = Converter(default_unit)
165            value = data_conv_q(value, units=value_unit)
166            new_unit = default_unit
167        else:
168            new_unit = value_unit
169        return value, new_unit
170
171    def _unit_fetch(self, unit):
172        return self.params[unit+"_unit"]
Note: See TracBrowser for help on using the repository browser.