pre_edge.py 8.91 KB
Newer Older
payno's avatar
payno committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2017 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.
#
# ###########################################################################*/
"""wrapper to the larch mback process"""

payno's avatar
payno committed
27
from est.core.types import Spectrum, XASObject
payno's avatar
payno committed
28
from est.core.process.process import Process
29
from est.core.process.process import _NexusSpectrumDef, _NexusDatasetDef
30
31
from est.core.process.process import _input_desc
from est.core.process.process import _output_desc
32
from est.core.utils.symbol import MU_CHAR
payno's avatar
payno committed
33
34
35
36
from larch.xafs.pre_edge import pre_edge
import multiprocessing
import functools
import logging
payno's avatar
payno committed
37

payno's avatar
payno committed
38
39
40
41
42
43
44
_logger = logging.getLogger(__name__)

_DEBUG = True
if _DEBUG:
    from larch.symboltable import Group


payno's avatar
payno committed
45
46
47
48
49
50
51
52
def process_spectr_pre_edge(
    spectrum,
    configuration,
    overwrite=True,
    callbacks=None,
    output=None,
    output_dict=None,
):
payno's avatar
payno committed
53
54
    """

55
56
57
58
59
60
    :param spectrum: spectrum to process
    :type: :class:`.Spectrum`
    :param configuration: configuration of the pymca normalization
    :type: dict
    :param overwrite: False if we want to return a new Spectrum instance
    :type: bool
61
    :param callbacks: callbacks to execute.
payno's avatar
payno committed
62
63
    :param output: list to store the result, needed for pool processing
    :type: multiprocessing.manager.list
64
65
66
    :param output_dict: key is: input spectrum, value is index in the output
                        list.
    :type: dict
payno's avatar
payno committed
67
68
69
    :return: processed spectrum
    :rtype: tuple (configuration, spectrum)
    """
payno's avatar
payno committed
70
    _logger.debug("start pre_edge on spectrum (%s, %s)" % (spectrum.x, spectrum.y))
payno's avatar
payno committed
71
72
    assert isinstance(spectrum, Spectrum)
    if spectrum.energy is None or spectrum.mu is None:
payno's avatar
payno committed
73
74
75
        _logger.error(
            "Energy and or Mu is/are not specified, unable to " "compute pre edge"
        )
payno's avatar
payno committed
76
        return None, None
77
    _conf = configuration
payno's avatar
payno committed
78
79
    if "pre_edge" in _conf:
        _conf = _conf["pre_edge"]
payno's avatar
payno committed
80
    opts = {}
payno's avatar
payno committed
81
82
83
84
85
86
87
    for opt_name in (
        "z",
        "edge",
        "e0",
        "pre1",
        "pre2",
        "norm1",
88
89
90
91
        "nnorm",
        "nvict",
        "step",
        "make_flat",
payno's avatar
payno committed
92
93
94
95
96
        "norm2",
        "order",
        "leexiang",
        "tables",
        "fit_erfc",
97
        "make_flat",
payno's avatar
payno committed
98
    ):
99
100
        if opt_name in _conf:
            opts[opt_name] = _conf[opt_name]
101
102
    print("{{{{{{{{{{{{{{{{{{{{{")
    print("configuration is", configuration)
payno's avatar
payno committed
103
104
105
106
107
108

    if _DEBUG is True:
        assert isinstance(spectrum, Group)
    if overwrite:
        _spectrum = spectrum
    else:
109
        _spectrum = Spectrum().load_frm_dict(spectrum=spectrum)
110

111
    pre_edge(_spectrum, group=_spectrum, **opts)
112
113
114
    if callbacks:
        for callback in callbacks:
            callback()
payno's avatar
payno committed
115
116
117
118
119
120
121
122
123
124
125
126

    return configuration, _spectrum


def larch_pre_edge(xas_obj):
    """

    :param xas_obj: object containing the configuration and spectra to process
    :type: Union[XASObject, dict]
    :return: spectra dict
    :rtype: XASObject
    """
payno's avatar
payno committed
127
128
    mback_obj = Larch_pre_edge(inputs={"xas_obj": xas_obj})
    return mback_obj.run()
payno's avatar
payno committed
129

payno's avatar
payno committed
130

payno's avatar
payno committed
131
_USE_MULTIPROCESSING_POOL = False
payno's avatar
payno committed
132
# note: we cannot use multiprocessing pool with pypushflow for now.
payno's avatar
payno committed
133
134
135


class Larch_pre_edge(Process):
136

137
    _INPUT_NAMES = set(["xas_obj"])
138

139
    _OUTPUT_NAMES = set(["xas_obj"])
140

141
142
    def __init__(self, varinfo=None, **inputs):
        Process.__init__(self, name="pre_edge", varinfo=varinfo, **inputs)
payno's avatar
payno committed
143

144
    def set_properties(self, properties):
payno's avatar
payno committed
145
146
        if "_larchSettings" in properties:
            self._settings = properties["_larchSettings"]
payno's avatar
payno committed
147

148
149
    def run(self):
        xas_obj = self.inputs.xas_obj
150
        if xas_obj is None:
151
            raise ValueError("xas_obj should be provided")
152
153
        self._xas_obj = self.getXasObject(xas_obj=xas_obj)
        _xas_obj = self._xas_obj
payno's avatar
payno committed
154
        if self._settings:
payno's avatar
payno committed
155
            _xas_obj.configuration["pre_edge"] = self._settings
payno's avatar
payno committed
156
157
158
159
160

        self._advancement.reset(max_=_xas_obj.n_spectrum)
        self._advancement.startProcess()
        self._pool_process(xas_obj=_xas_obj)
        self._advancement.endProcess()
payno's avatar
payno committed
161
162
163
        self.register_process(
            _xas_obj,
            data_keys=(
164
165
166
                _NexusDatasetDef(
                    "flat", units="{}(E)".format(MU_CHAR), units_latex="\mu(E)"
                ),
167
168
169
170
171
172
173
                _NexusDatasetDef("dmude"),
                _NexusDatasetDef("edge_step_poly"),
                _NexusDatasetDef("norm"),
                _NexusDatasetDef("norm_area"),
                _NexusDatasetDef("post_edge"),
                _NexusDatasetDef("pre_edge_details"),
                _NexusDatasetDef("e0", "eV"),
174
175
176
                _NexusDatasetDef(
                    "Mu", units="{}(E)".format(MU_CHAR), units_latex="\mu(E)"
                ),
177
                _NexusDatasetDef("energy", "eV"),
178
179
180
                _NexusDatasetDef(
                    "mu_ref", units="{}(E)".format(MU_CHAR), units_latex="\mu(E)"
                ),
181
182
183
                _NexusDatasetDef("I0"),
                _NexusDatasetDef("I1"),
                _NexusDatasetDef("I2"),
payno's avatar
payno committed
184
            ),
185
            plots=(
payno's avatar
payno committed
186
                _NexusSpectrumDef(
payno's avatar
payno committed
187
188
189
190
                    signal="Mu",
                    axes=("energy",),
                    auxiliary_signals=None,
                    silx_style={"signal_scale_type": "linear"},
191
192
                    title="Mu",
                    title_latex="\mu",
payno's avatar
payno committed
193
194
                ),
                _NexusSpectrumDef(
payno's avatar
payno committed
195
196
197
198
199
200
201
202
203
204
205
206
207
                    signal="Mu",
                    axes=("energy",),
                    auxiliary_signals=("I0", "I1", "I2"),
                    silx_style={
                        "y_axis": ("I0", "I1", "I2"),
                        "signal_scale_type": "linear",
                    },
                ),
                _NexusSpectrumDef(
                    signal="Mu",
                    axes=("energy",),
                    auxiliary_signals=("mu_ref",),
                    silx_style={"signal_scale_type": "linear"},
208
209
                    title="Mu vs Mu ref",
                    title_latex="\mu \quad vs \quad \mu_{ref}",
payno's avatar
payno committed
210
211
212
213
214
215
                ),
                _NexusSpectrumDef(
                    signal="flat",
                    axes=("energy",),
                    auxiliary_signals=None,
                    silx_style={"signal_scale_type": "linear"},
216
217
                    title="Mu flat",
                    title_latex="\mu_{flat}",
payno's avatar
payno committed
218
                ),
payno's avatar
payno committed
219
220
            ),
        )
221
        self.outputs.xas_obj = _xas_obj.to_dict()
payno's avatar
payno committed
222
223
224
225
226
227
        return _xas_obj

    def _pool_process(self, xas_obj):
        assert isinstance(xas_obj, XASObject)
        if not _USE_MULTIPROCESSING_POOL:
            for spectrum in xas_obj.spectra:
payno's avatar
payno committed
228
229
230
231
232
233
                process_spectr_pre_edge(
                    spectrum=spectrum,
                    configuration=xas_obj.configuration,
                    callbacks=self.callbacks,
                    overwrite=True,
                )
payno's avatar
payno committed
234
235
        else:
            from multiprocessing import Manager
payno's avatar
payno committed
236

payno's avatar
payno committed
237
238
239
240
241
242
243
244
            manager = Manager()
            output_dict = {}
            res_list = manager.list()
            for i_spect, spect in enumerate(xas_obj.spectra):
                res_list.append(None)
                output_dict[spect] = i_spect

            with multiprocessing.Pool(5) as p:
payno's avatar
payno committed
245
246
247
248
249
250
251
252
                partial_ = functools.partial(
                    process_spectr_pre_edge,
                    configuration=xas_obj.configuration,
                    callbacks=self.callbacks,
                    overwrite=False,
                    output=res_list,
                    output_dict=output_dict,
                )
payno's avatar
payno committed
253
254
255
256
257
258
259
260
261
262
263
                p.map(partial_, xas_obj.spectra)

            # then update local spectrum
            for spectrum, res in zip(xas_obj.spectra, res_list):
                spectrum.update(res)

    def definition(self):
        return "pre_edge calculation"

    def program_version(self):
        import larch.version
payno's avatar
payno committed
264
265

        return larch.version.version_data()["larch"]
payno's avatar
payno committed
266

267
268
    @staticmethod
    def program_name():
payno's avatar
payno committed
269
        return "larch_pre_edge"
payno's avatar
payno committed
270

271
    __call__ = run