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

Last change on this file since d620d03c was 3053a4a, checked in by GitHub <noreply@…>, 7 years ago

remove infinite loop from sesans reader (#129)

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