k_weight.py 8.92 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
25
26
27
28
29
# 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.
#
# ###########################################################################*/

__authors__ = ["H. Payno"]
__license__ = "MIT"
__date__ = "06/11/2019"

30
import functools
31
import logging
32
33
import multiprocessing
from PyMca5.PyMcaPhysics.xas.XASClass import XASClass, e2k
payno's avatar
payno committed
34
35
36
from est.core.process.process import Process
from est.core.process.pymca.exafs import process_spectr_exafs
from est.core.types import XASObject, Spectrum
37
38
39
40

_logger = logging.getLogger(__name__)


payno's avatar
payno committed
41
42
43
44
45
46
47
48
def process_spectr_k(
    spectrum,
    configuration,
    overwrite=True,
    callbacks=None,
    output=None,
    output_dict=None,
):
49
50
    """

51
52
53
54
55
56
57
    :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
    :param callback: callback to execute.
58
59
    :param output: list to store the result, needed for pool processing
    :type: multiprocessing.manager.list
60
61
62
    :param output_dict: key is input spectrum, value is index in the output
                        list.
    :type: dict
63
    :return: processed spectrum
64
65
    :rtype: tuple (configuration, spectrum)
    """
payno's avatar
payno committed
66
67
68
    _logger.debug(
        "start k weight definition on spectrum (%s, %s)" % (spectrum.x, spectrum.y)
    )
69
70
71
72
    assert spectrum is not None

    pymca_xas = XASClass()
    if spectrum.energy is None or spectrum.mu is None:
payno's avatar
payno committed
73
74
75
76
        raise ValueError(
            "Energy and or Mu is/are not specified, unable to " "compute exafs"
        )
    pymca_xas.setSpectrum(energy=spectrum.energy, mu=spectrum.mu)
77
    if configuration is not None:
payno's avatar
payno committed
78
        if "KWeight" in configuration and configuration["KWeight"] is not None:
payno's avatar
payno committed
79
80
            configuration["FT"]["KWeight"] = configuration["KWeight"]
            configuration["EXAFS"]["KWeight"] = configuration["KWeight"]
81
        pymca_xas.setConfiguration(configuration)
82
83
84
85
86
87

    if overwrite:
        spectrum_ = spectrum
    else:
        spectrum_ = Spectrum.from_dict(spectrum.to_dict())

payno's avatar
payno committed
88
    # we need to update EXAFSNormalized since we are overwriting it
payno's avatar
payno committed
89
90
91
    cf, exafs_res = process_spectr_exafs(
        spectrum=spectrum_, configuration=configuration
    )
92
    if exafs_res is None:
payno's avatar
payno committed
93
        err = "Failed to process exafs."
94
        if spectrum.x is not None or spectrum.y is not None:
payno's avatar
payno committed
95
96
97
98
99
            err = (
                err
                + "Spectrum (x, y) coords: "
                + ",".join((str(spectrum.x), str(spectrum.y)))
            )
100
        raise ValueError(err)
101

payno's avatar
payno committed
102
103
    # update EXAFSNormalized
    e0 = pymca_xas.calculateE0()
payno's avatar
payno committed
104

105
    kValues = e2k(spectrum_.energy - e0)
payno's avatar
payno committed
106
107
108
109
110
111
    exafs = exafs_res["EXAFSNormalized"]
    if "KWeight" in configuration and configuration["KWeight"] is not None:
        exafs *= pow(kValues, configuration["KWeight"])
    spectrum_["EXAFSNormalized"] = exafs
    configuration_ = pymca_xas.getConfiguration()

112
113
114
    if callbacks:
        for callback in callbacks:
            callback()
115
116
117
118

    if output is not None:
        assert output_dict is not None
        output[output_dict[spectrum]] = spectrum_
payno's avatar
payno committed
119
    return configuration_, spectrum_
120
121


122
def pymca_k_weight(xas_obj):
123
    """
payno's avatar
payno committed
124
    Set weight for exafs values
125

126
    :param xas_obj: object containing the configuration and spectra to process
payno's avatar
payno committed
127
    :type: Union[:class:`.XASObject`, dict]
128
    :return: spectra dict
payno's avatar
payno committed
129
    :rtype: :class:`.XASObject`
130
    """
payno's avatar
payno committed
131
132
    k_weight_obj = PyMca_k_weight(inputs={"xas_obj": xas_obj})
    return k_weight_obj.run()
133
134


135
_USE_MULTIPROCESSING_POOL = False
payno's avatar
payno committed
136
# note: we cannot use multiprocessing pool with pypushflow for now.
137
138


139
class PyMca_k_weight(Process):
140

141
    _INPUT_NAMES = set(["xas_obj"])
142

143
    _OUTPUT_NAMES = set(["xas_obj"])
144

145
146
    def __init__(self, varinfo=None, **inputs):
        Process.__init__(self, name="k weight", varinfo=varinfo, **inputs)
147

148
    def set_properties(self, properties):
payno's avatar
payno committed
149
        if "_kWeightSetting" in properties:
150
            _properties = properties.copy()
payno's avatar
payno committed
151
152
            _properties["k_weight"] = _properties["_kWeightSetting"]
            del _properties["_kWeightSetting"]
153
            self.setConfiguration(_properties)
154
155

    def _k_weight(self):
payno's avatar
payno committed
156
157
        if "k_weight" in self._settings:
            return self._settings["k_weight"]
158
        return None
159

160
    def run(self):
161
        """
payno's avatar
payno committed
162

163
        :param xas_obj: object containing the configuration and spectra to process
payno's avatar
payno committed
164
        :type: Union[:class:`.XASObject`, dict]
165
        :return: spectra dict
payno's avatar
payno committed
166
        :rtype: :class:`.XASObject`
167
        """
168
        xas_obj = self.inputs.xas_obj
169
        if xas_obj is None:
170
            raise ValueError("xas_obj should be provided")
171
        _xas_obj = self.getXasObject(xas_obj=xas_obj)
payno's avatar
payno committed
172
        if self._k_weight() is not None:
payno's avatar
payno committed
173
            _xas_obj.configuration["SET_KWEIGHT"] = self._k_weight()
174

payno's avatar
payno committed
175
        if "SET_KWEIGHT" not in _xas_obj.configuration:
176
            _logger.warning(
payno's avatar
payno committed
177
178
179
180
                "Missing configuration to know which value we should set "
                "to k weight, will be set to 0 by default"
            )
            _xas_obj.configuration["SET_KWEIGHT"] = 0
181

payno's avatar
payno committed
182
        for key in ("FT", "EXAFS", "Normalization"):
183
184
185
            if key not in _xas_obj.configuration:
                _xas_obj.configuration[key] = {}

payno's avatar
payno committed
186
187
188
189
190
191
192
193
        _xas_obj.configuration["KWeight"] = _xas_obj.configuration["SET_KWEIGHT"]
        _xas_obj.configuration["FT"]["KWeight"] = _xas_obj.configuration["SET_KWEIGHT"]
        _xas_obj.configuration["EXAFS"]["KWeight"] = _xas_obj.configuration[
            "SET_KWEIGHT"
        ]
        _xas_obj.configuration["Normalization"]["KWeight"] = _xas_obj.configuration[
            "SET_KWEIGHT"
        ]
194

195
        self._advancement.reset(max_=_xas_obj.n_spectrum)
196
        self._advancement.startProcess()
197
        self._pool_process(xas_obj=_xas_obj)
198
        self._advancement.endProcess()
199
        self.register_process(xas_obj=_xas_obj, data_keys=tuple())
200
        self.outputs.xas_obj = _xas_obj.to_dict()
201
        return _xas_obj
202

203
204
    def _pool_process(self, xas_obj):
        """process normalization from a pool"""
205
206
        assert isinstance(xas_obj, XASObject)
        if not _USE_MULTIPROCESSING_POOL:
payno's avatar
payno committed
207
            assert "KWeight" in xas_obj.configuration
payno's avatar
payno committed
208
            for spectrum in xas_obj.spectra.data.flat:
payno's avatar
payno committed
209
210
211
212
213
214
215
                process_spectr_k(
                    spectrum=spectrum,
                    configuration=xas_obj.configuration,
                    callbacks=self.callbacks,
                    overwrite=True,
                )
                assert "KWeight" in xas_obj.configuration
216
217
        else:
            with multiprocessing.Pool(5) as p:
payno's avatar
payno committed
218
219
220
221
222
223
                partial_ = functools.partial(
                    process_spectr_k,
                    configuration=xas_obj.configuration,
                    callbacks=self.callbacks,
                    overwrite=True,
                )
224
                p.map(partial_, xas_obj.spectra)
225

226
227
228
229
230
    def definition(self):
        return "Define k weight for xas treatment"

    def program_version(self):
        import PyMca5
payno's avatar
payno committed
231

232
233
        return PyMca5.version()

234
235
    @staticmethod
    def program_name():
payno's avatar
payno committed
236
        return "pymca_k_weight"
237

238
    __call__ = run
239
240
241
242
243


if __name__ == "__main__":
    import sys
    import yaml
payno's avatar
payno committed
244

245
246
247
248
249
250
251
    xas_object_yaml_file = sys.argv[1]
    _logger.debug("Load xas object from {}".format(xas_object_yaml_file))
    with open(xas_object_yaml_file, "r") as file:
        ddict = yaml.load(file)["input_data"]
        xas_object = XASObject.from_dict(ddict)
    print("******* do k-weight ********")
    res_xas_object = pymca_k_weight(xas_obj=xas_object)
252
    res_xas_object._create_saving_pt()
253
254
255
256

    # dump resulting object
    with open(xas_object_yaml_file, "w") as file:
        yaml.dump({"input_data": res_xas_object.to_dict()}, file)
257
258
259
260

    # dump resulting object into output_normalization file
    with open("output_k_weight.yaml", "w") as file:
        yaml.dump({"input_data": res_xas_object.to_dict()}, file)