io.py 7.99 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2017-2019 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
# ###########################################################################*/
25
"""simple helper functions to insure a simple link with the `io` module (and XASObject)"""
26
27
28
29
30
31

__authors__ = ["H. Payno"]
__license__ = "MIT"
__date__ = "07/16/2019"


payno's avatar
payno committed
32
33
from est.io import read_xas, write_xas, get_xasproc
from est.core.types import XASObject
34
from silx.io.url import DataUrl
35
from est.core.types import Dim
payno's avatar
PEP8    
payno committed
36
from est.units import ur
37
from typing import Union
38
from est.io.utils.information import InputInformation
39
40
41
42
43
import h5py
import logging

_logger = logging.getLogger(__name__)

Mauro Rovezzi's avatar
Mauro Rovezzi committed
44
DEFAULT_SPECTRA_PATH = "/data/NXdata/data"
45

Mauro Rovezzi's avatar
Mauro Rovezzi committed
46
DEFAULT_CHANNEL_PATH = "/data/NXdata/Channel"
47

Mauro Rovezzi's avatar
Mauro Rovezzi committed
48
DEFAULT_CONF_PATH = "/configuration"
49
50


payno's avatar
payno committed
51
52
53
54
55
56
57
def read(
    spectra_url,
    channel_url,
    dimensions=(Dim.DIM_2, Dim.DIM_1, Dim.DIM_0),
    config_url=None,
    energy_unit=ur.eV,
):
58
    """
Mauro Rovezzi's avatar
Mauro Rovezzi committed
59

60
61
62
    :param DataUrl spectra_url: data url to the spectra
    :param DataUrl channel_url: data url to the channel / energy
    :param DataUrl config_url: data url to the process configuration
63
64
    :param dimensions: way the data has been stored.
                       Usually is (X, Y, channels) of (Channels, Y, X).
65
                       If None, by default is considered to be (Z, Y, X)
66
    :type: tuple
Mauro Rovezzi's avatar
Mauro Rovezzi committed
67
    :return:
68
69
    :rtype: XASObject
    """
70
71
    dimensions_ = dimensions
    if dimensions_ is None:
72
        dimensions_ = (Dim.DIM_2, Dim.DIM_1, Dim.DIM_0)
73
    reader = XASReader()
Mauro Rovezzi's avatar
Mauro Rovezzi committed
74
    return reader.read_frm_url(
75
76
77
78
79
80
81
        InputInformation(
            spectra_url=spectra_url,
            channel_url=channel_url,
            config_url=config_url,
            dimensions=dimensions_,
            energy_unit=energy_unit,
        )
Mauro Rovezzi's avatar
Mauro Rovezzi committed
82
    )
83
84


85
86
87
def read_frm_file(
    file_path,
    energy_unit=ur.eV,
88
    dimensions: tuple = (Dim.DIM_2, Dim.DIM_1, Dim.DIM_0),
89
    columns_names: Union[None, dict] = None,
90
):
91
    """
Mauro Rovezzi's avatar
Mauro Rovezzi committed
92

93
94
95
    :param str file_path: path to the file containing the spectra. Must ba a
                          .dat file that pymca can handle or a .h5py with
                          default path
96
97
    :param tuple dimensions: dimensions of the input data. For ASCII file can
                             be (X, Y) or (Y, X)
98
99
    :param Union[None,tuple] columns: name of the column to take for .dat...
                                      files.
100
    :return XasObject created from the input
101
102
    :rtype: XASObject
    """
payno's avatar
payno committed
103
    if file_path in (None, ""):
104
        return
105
    reader = XASReader()
106
    return reader.read_from_file(
107
108
109
110
        file_path=file_path,
        energy_unit=energy_unit,
        dimensions=dimensions,
        columns_names=columns_names,
111
    )
112
113
114
115


class XASReader(object):
    """Simple reader of a xas file"""
Mauro Rovezzi's avatar
Mauro Rovezzi committed
116

117
    @staticmethod
118
119
    def read_frm_url(input_information):
        sp, en, conf = read_xas(information=input_information)
120
121
        return XASObject(spectra=sp, energy=en, configuration=conf)

122
    @staticmethod
123
124
125
    def read_from_file(
        file_path,
        energy_unit=ur.eV,
126
        dimensions=(Dim.DIM_2, Dim.DIM_1, Dim.DIM_0),
127
        columns_names=None,
128
    ):
129
130
        """

Mauro Rovezzi's avatar
Mauro Rovezzi committed
131
        :param str file_path:
132
133
        :return: `.XASObject`
        """
134
        # TODO: we should be able to avoid calling the creation of an InputInformation
payno's avatar
payno committed
135
        if file_path.endswith((".dat", ".csv")):
136
            return XASReader.read_frm_url(
137
138
139
140
141
142
143
                InputInformation(
                    spectra_url=DataUrl(file_path=file_path, scheme="PyMca"),
                    channel_url=DataUrl(file_path=file_path, scheme="PyMca"),
                    energy_unit=energy_unit,
                    dimensions=dimensions,
                    columns_names=columns_names,
                )
Mauro Rovezzi's avatar
Mauro Rovezzi committed
144
145
            )
        elif file_path.endswith(".xmu"):
146
            return XASReader.read_frm_url(
147
148
149
150
151
152
153
                InputInformation(
                    spectra_url=DataUrl(file_path=file_path, scheme="larch"),
                    channel_url=DataUrl(file_path=file_path, scheme="larch"),
                    energy_unit=energy_unit,
                    dimensions=dimensions,
                    columns_names=columns_names,
                )
Mauro Rovezzi's avatar
Mauro Rovezzi committed
154
            )
155
        elif h5py.is_hdf5(file_path):
156
            return XASReader.read_frm_url(
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
                InputInformation(
                    spectra_url=DataUrl(
                        file_path=file_path,
                        scheme="silx",
                        data_path=DEFAULT_SPECTRA_PATH,
                    ),
                    channel_url=DataUrl(
                        file_path=file_path,
                        scheme="silx",
                        data_path=DEFAULT_CHANNEL_PATH,
                    ),
                    config_url=DataUrl(
                        file_path=file_path, scheme="silx", data_path="configuration"
                    ),
                    energy_unit=energy_unit,
                    dimensions=dimensions,
                )
Mauro Rovezzi's avatar
Mauro Rovezzi committed
174
            )
175
        else:
payno's avatar
payno committed
176
177
178
            raise ValueError(
                "file type {} not managed, unable to load".format(file_path)
            )
179
180
181
182
183
184
185
186
187

    __call__ = read_from_file


class XASWriter(object):
    """
    class to write the output file. In this case we need a class in order to
    setup the output file before
    """
Mauro Rovezzi's avatar
Mauro Rovezzi committed
188

189
190
191
192
193
194
195
196
197
198
199
    def __init__(self):
        self._output_file = None

    @property
    def output_file(self):
        return self._output_file

    @output_file.setter
    def output_file(self, file_):
        self._output_file = file_

200
    def set_properties(self, properties):
Mauro Rovezzi's avatar
Mauro Rovezzi committed
201
202
        if "_output_file_setting" in properties:
            self._output_file = properties["_output_file_setting"]
203
204
205
206
207

    def dump_xas(self, xas_obj, write_process=True):
        """
        write the XASObject into a hdf5 file.

208
209
        :param xas_obj: object to be stored
        :type: Union[:class:`.XASObject`,dict]
210
        :param bool write_process: if True then store the process flow in the
211
            same file.
212
213
214
215
216
217
218
        """
        if isinstance(xas_obj, dict):
            _xas_obj = XASObject.from_dict(xas_obj)
        else:
            _xas_obj = xas_obj

        if not self._output_file:
Mauro Rovezzi's avatar
Mauro Rovezzi committed
219
            _logger.warning(
220
                "no output file defined, please give path to the output file"
Mauro Rovezzi's avatar
Mauro Rovezzi committed
221
            )
222
223
            self._output_file = input()

payno's avatar
payno committed
224
        _logger.info("dump xas obj to {}".format(self._output_file))
225
226

        # write raw data
Mauro Rovezzi's avatar
Mauro Rovezzi committed
227
228
229
230
231
232
        write_xas(
            h5_file=self._output_file,
            energy=_xas_obj.energy,
            mu=_xas_obj.absorbed_beam(),
            entry=_xas_obj.entry,
        )
233
234
235

        if write_process is True:
            if len(get_xasproc(self._output_file, entry=_xas_obj.entry)) > 0:
Mauro Rovezzi's avatar
Mauro Rovezzi committed
236
237
238
                _logger.warning(
                    "removing previous process registred. They are no " "more accurate"
                )
239
240
241
242
243
244
                _xas_obj.clean_process_flow()

            # write process flow
            _xas_obj.copy_process_flow_to(self._output_file)

    __call__ = dump_xas