Commit 9913c390 authored by payno's avatar payno

Merge branch 'fix_10' into 'master'

Fix 10 - make pymca process from a thread

Closes #10

See merge request !8
parents d748b44e a32b41b1
Pipeline #12521 passed with stage
in 4 minutes and 16 seconds
# 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/07/2019"
from silx.gui import qt
from Orange.widgets import gui
import logging
_logger = logging.getLogger(__file__)
class _PyMcaProcessForOrangeMixIn(object):
"""
Group processing and progress display in a common class for pymca process
"""
def __init__(self):
# progress
self._progress = gui.ProgressBar(self, 100)
"""progress bar"""
self.__processingThread = None
"""Thread for processing"""
# progress
self._progress = gui.ProgressBar(self, 100)
def _startProcess(self):
self._window.setEnabled(False)
def _endProcess(self, xas_obj):
self._window.setEnabled(True)
if self._callback_finish:
try:
self.getProcessingThread()._process_obj._advancement.sigProgress.disconnect(self._setProgressValue)
except ... as e:
_logger.error(str(e))
self.getProcessingThread().finished.disconnect(self._callback_finish)
self._callback_finish = None
if xas_obj is None:
return
else:
self._window.xasObjViewer.setXASObj(xas_obj=xas_obj)
# emit signal for the plot
self.send("spectra", xas_obj)
def _canProcess(self):
return self.__processingThread is None or not self.__processingThread.isRunning()
def getProcessingThread(self):
if self.__processingThread is None:
self.__processingThread = ProcessQThread(parent=self)
return self.__processingThread
def _setProgressValue(self, value):
self._progress.widget.progressBarSet(value)
class ProcessRunnable(qt.QRunnable):
"""
qt Runnable for standard process.
process function should take as input(spectrum, configuration, overwrite)
:param function pointer fct: process function
:param :class:`.Spectrum`: spectrum to process
:param dict configuration: configuration of the process
:param function pointer callback: optional callback to execute at the end of
the run. Should take no parameter
"""
def __init__(self, fct, spectrum, configuration, callback=None):
qt.QRunnable.__init__(self)
self._spectrum = spectrum
self._configuration = configuration
self._callback = callback
self._function = fct
def run(self):
try:
self._configuration, self._spectrum = self._function(
spectrum=self._spectrum,
configuration=self._configuration,
overwrite=True)
except (KeyError, ValueError) as e:
_logger.error(e)
if self._callback:
self._callback()
class ProcessQThread(qt.QThread):
"""
Thread dedicated to process execution.
"""
def __init__(self, parent=None):
qt.QThread.__init__(self, parent)
def init(self, xas_obj, process_obj):
"""
Initialize the thread for processing xas_obj from proces_obj
:param :class:`.XASObject` xas_obj: object to process
:param :class:`.Process` process_obj: object to process xas_obj
"""
self._xas_obj = xas_obj
self._process_obj = process_obj
def run(self):
self._xas_obj = self._process_obj.process(self._xas_obj)
......@@ -34,9 +34,11 @@ from xas.core.process.progress import Progress
class QProgress(Progress, qt.QObject):
sigProgress = qt.Signal(int)
def __init__(self, name):
Progress.__init__(self, name)
assert name is not None
qt.QObject.__init__(self)
Progress.__init__(self, name)
def startProcess(self):
self.sigProgress.emit(0)
......
......@@ -35,9 +35,11 @@ from Orange.widgets.widget import OWWidget
from Orange.widgets.settings import Setting
from xas.core.types import XASObject, Spectrum
import xas.core.process.exafs
from ..progress import QProgress
from xas.gui.XasObjectViewer import XasObjectViewer, _CurveOperation, ViewType
from ..progress import QProgress
from orangecontrib.xas.process import _PyMcaProcessForOrangeMixIn, ProcessRunnable
from PyMca5.PyMcaGui.physics.xas.XASPostEdgeParameters import XASPostEdgeParameters
import functools
import logging
_logger = logging.getLogger(__file__)
......@@ -143,7 +145,7 @@ class ExafsWindow(qt.QMainWindow):
self.xasObjViewer._mapView.keySelectionDocker.setVisible(self.xasObjViewer.getViewType() is ViewType.map)
class ExafsOW(OWWidget):
class ExafsOW(_PyMcaProcessForOrangeMixIn, OWWidget):
"""
Widget used for signal extraction
"""
......@@ -168,17 +170,14 @@ class ExafsOW(OWWidget):
def __init__(self):
super().__init__()
self._latest_xas_obj = None
self._window = ExafsWindow()
layout = gui.vBox(self.mainArea, 'fourier transform').layout()
layout.addWidget(self._window)
self._latest_xas_obj = None
self._window.xasObjViewer._spectrumView._plot.getXAxis().setLabel("K")
self._window.xasObjViewer._spectrumView._plot.getYAxis().setLabel("Normalized Units")
# progress
self._progress = gui.ProgressBar(self, 100)
# manage settings
if self._pymcaSettings != dict():
self._window._pymcaWindow.setParameters(self._pymcaSettings)
......@@ -192,29 +191,53 @@ class ExafsOW(OWWidget):
if self._latest_xas_obj:
self.process(self._latest_xas_obj)
def _update_settings(self):
self._pymcaSettings = self._window._pymcaWindow.getParameters()
def process(self, xas_obj):
if xas_obj is None:
return
if not self._canProcess():
_logger.warning('There is some processing on going already, will'
'not process the new dataset')
self._latest_xas_obj = xas_obj.copy()
self._startProcess()
# setup the exafs process
process_obj = QPyMca_exafs()
process_obj._advancement.sigProgress.connect(self._setProgressValue)
process_obj.setProperties({'_pymcaSettings': self._window._pymcaWindow.getParameters()})
xas_obj = process_obj.process(xas_obj)
process_obj._advancement.sigProgress.disconnect(self._setProgressValue)
self._window.xasObjViewer.setXASObj(xas_obj)
# emit signal for the plot
self.send("spectra", xas_obj)
def _update_settings(self):
self._pymcaSettings = self._window._pymcaWindow.getParameters()
# update the processing thread
thread = self.getProcessingThread()
thread.init(process_obj=process_obj, xas_obj=xas_obj)
self._callback_finish = functools.partial(self._endProcess, xas_obj)
thread.finished.connect(self._callback_finish)
# start processing
thread.start(priority=qt.QThread.LowPriority)
def _setProgressValue(self, value):
self._progress.widget.progressBarSet(value)
class QPyMca_exafs(xas.core.process.exafs.PyMca_exafs):
"""
Normalization able to give advancement using qt.Signal and QThreadPool
"""
def __init__(self):
xas.core.process.exafs.PyMca_exafs.__init__(self)
self._advancement = QProgress('exafs')
self._advancement = QProgress('normalization')
def _pool_process(self, xas_obj):
self.pool = qt.QThreadPool()
self.pool.setMaxThreadCount(5)
for spectrum in xas_obj.spectra:
runnable = ProcessRunnable(fct=xas.core.process.exafs.process_spectr_exafs,
spectrum=spectrum,
configuration=xas_obj.configuration,
callback=self._advancement.increaseAdvancement)
self.pool.start(runnable)
self.pool.waitForDone()
......@@ -38,6 +38,8 @@ import xas.core.process.ft
from ..progress import QProgress
from xas.gui.XasObjectViewer import XasObjectViewer, _CurveOperation, ViewType
from PyMca5.PyMcaGui.physics.xas.XASFourierTransformParameters import XASFourierTransformParameters
from orangecontrib.xas.process import _PyMcaProcessForOrangeMixIn, ProcessRunnable
import functools
import logging
_logger = logging.getLogger(__file__)
......@@ -115,7 +117,7 @@ class FTWindow(qt.QMainWindow):
self.xasObjViewer._mapView.keySelectionDocker.setVisible(self.xasObjViewer.getViewType() is ViewType.map)
class FTOW(OWWidget):
class FTOW(_PyMcaProcessForOrangeMixIn, OWWidget):
"""
Widget used for signal extraction
"""
......@@ -140,8 +142,8 @@ class FTOW(OWWidget):
def __init__(self):
super().__init__()
self._window = FTWindow(parent=self)
self._latest_xas_obj = None
self._window = FTWindow(parent=self)
layout = gui.vBox(self.mainArea, 'fourier transform').layout()
layout.addWidget(self._window)
......@@ -164,16 +166,26 @@ class FTOW(OWWidget):
if xas_obj is None:
return
if not self._canProcess():
_logger.warning('There is some processing on going already, will'
'not process the new dataset')
self._latest_xas_obj = xas_obj.copy()
self._startProcess()
# setup the ft process
process_obj = QPyMca_ft()
process_obj._advancement.sigProgress.connect(self._setProgressValue)
process_obj.setProperties({'_pymcaSettings': self._window._pymcaWindow.getParameters()})
xas_obj = process_obj.process(xas_obj)
process_obj._advancement.sigProgress.disconnect(self._setProgressValue)
self._window.xasObjViewer.setXASObj(xas_obj)
# emit signal for the plot
self.send("spectra", xas_obj)
# update the processing thread
thread = self.getProcessingThread()
thread.init(process_obj=process_obj, xas_obj=xas_obj)
self._callback_finish = functools.partial(self._endProcess, xas_obj)
thread.finished.connect(self._callback_finish)
# start processing
thread.start(priority=qt.QThread.LowPriority)
def _update_settings(self):
self._pymcaSettings = self._window._pymcaWindow.getParameters()
......@@ -183,6 +195,20 @@ class FTOW(OWWidget):
class QPyMca_ft(xas.core.process.ft.PyMca_ft):
"""
Normalization able to give advancement using qt.Signal and QThreadPool
"""
def __init__(self):
xas.core.process.ft.PyMca_ft.__init__(self)
self._advancement = QProgress('exafs')
self._advancement = QProgress('normalization')
def _pool_process(self, xas_obj):
self.pool = qt.QThreadPool()
self.pool.setMaxThreadCount(5)
for spectrum in xas_obj.spectra:
runnable = ProcessRunnable(fct=xas.core.process.ft.process_spectr_ft,
spectrum=spectrum,
configuration=xas_obj.configuration,
callback=self._advancement.increaseAdvancement)
self.pool.start(runnable)
self.pool.waitForDone()
......@@ -36,7 +36,9 @@ from silx.gui import qt
from xas.core.types import XASObject, Spectrum
import xas.core.process.k_weight
from ..progress import QProgress
from orangecontrib.xas.process import _PyMcaProcessForOrangeMixIn, ProcessRunnable
from xas.gui.XasObjectViewer import XasObjectViewer, _CurveOperation, ViewType
import functools
import logging
_logger = logging.getLogger(__file__)
......@@ -134,7 +136,7 @@ class KWeightWindow(qt.QMainWindow):
self.xasObjViewer._mapView.keySelectionDocker.setVisible(self.xasObjViewer.getViewType() is ViewType.map)
class KWeightOW(OWWidget):
class KWeightOW(_PyMcaProcessForOrangeMixIn, OWWidget):
"""
Widget used for signal extraction
"""
......@@ -159,10 +161,10 @@ class KWeightOW(OWWidget):
def __init__(self):
super().__init__()
self._latest_xas_obj = None
layout = gui.vBox(self.mainArea, 'fourier transform').layout()
self._window = KWeightWindow(parent=self)
layout.addWidget(self._window)
self._latest_xas_obj = None
# progress
self._progress = gui.ProgressBar(self, 100)
......@@ -183,16 +185,25 @@ class KWeightOW(OWWidget):
if xas_obj is None:
return
if not self._canProcess():
_logger.warning('There is some processing on going already, will'
'not process the new dataset')
self._latest_xas_obj = xas_obj.copy()
process_obj = QPyMca_K_weight()
self._startProcess()
# setup the k weight process
process_obj = QPyMca_k_weight()
process_obj._advancement.sigProgress.connect(self._setProgressValue)
process_obj.setProperties({'_kWeightSetting': self._window._k_spin_box.value()})
xas_obj = process_obj.process(xas_obj)
process_obj._advancement.sigProgress.disconnect(self._setProgressValue)
self._window.xasObjViewer.setXASObj(xas_obj)
# emit signal for the plot
self.send("spectra", xas_obj)
# update the processing thread
thread = self.getProcessingThread()
thread.init(process_obj=process_obj, xas_obj=xas_obj)
self._callback_finish = functools.partial(self._endProcess, xas_obj)
thread.finished.connect(self._callback_finish)
# start processing
thread.start(priority=qt.QThread.LowPriority)
def _update_settings(self):
self._kWeightSetting = self._window._k_spin_box.value()
......@@ -201,7 +212,21 @@ class KWeightOW(OWWidget):
self._progress.widget.progressBarSet(value)
class QPyMca_K_weight(xas.core.process.k_weight.PyMca_k_weight):
class QPyMca_k_weight(xas.core.process.k_weight.PyMca_k_weight):
"""
Normalization able to give advancement using qt.Signal and QThreadPool
"""
def __init__(self):
xas.core.process.k_weight.PyMca_k_weight.__init__(self)
self._advancement = QProgress('k weight')
self._advancement = QProgress('normalization')
def _pool_process(self, xas_obj):
self.pool = qt.QThreadPool()
self.pool.setMaxThreadCount(5)
for spectrum in xas_obj.spectra:
runnable = ProcessRunnable(fct=xas.core.process.k_weight.process_spectr_k,
spectrum=spectrum,
configuration=xas_obj.configuration,
callback=self._advancement.increaseAdvancement)
self.pool.start(runnable)
self.pool.waitForDone()
......@@ -38,6 +38,8 @@ from ..progress import QProgress
from xas.core.types import XASObject, Spectrum
from xas.gui.XasObjectViewer import XasObjectViewer, _CurveOperation, ViewType
import xas.core.process.normalization
from orangecontrib.xas.process import _PyMcaProcessForOrangeMixIn, ProcessRunnable
import functools
import logging
_logger = logging.getLogger(__file__)
......@@ -151,7 +153,7 @@ class NormalizationWindow(qt.QMainWindow):
self.xasObjViewer._mapView.keySelectionDocker.setVisible(self.xasObjViewer.getViewType() is ViewType.map)
class NormalizationOW(OWWidget):
class NormalizationOW(_PyMcaProcessForOrangeMixIn, OWWidget):
"""
Widget used for signal extraction
"""
......@@ -176,16 +178,13 @@ class NormalizationOW(OWWidget):
"""Store the configuration of the PyMca XASClass"""
def __init__(self):
OWWidget.__init__(self)
super().__init__()
self._latest_xas_obj = None
self._window = NormalizationWindow(parent=self)
layout = gui.vBox(self.mainArea, 'fourier transform').layout()
layout.addWidget(self._window)
self._window.xasObjViewer.setWindowTitle('spectra')
# progress
self._progress = gui.ProgressBar(self, 100)
# manage settings
if self._pymcaSettings != dict():
self._window._pymcaWindow.setParameters(self._pymcaSettings)
......@@ -197,35 +196,55 @@ class NormalizationOW(OWWidget):
_sig = self._window._pymcaWindow.sigXASNormalizationParametersSignal
_sig.connect(self._updateProcess)
def _updateProcess(self):
self._update_settings()
if self._latest_xas_obj:
self.process(self._latest_xas_obj)
def _update_settings(self):
self._pymcaSettings = self._window._pymcaWindow.getParameters()
def process(self, xas_obj):
if xas_obj is None:
return
# TODO: move process to multiprocessing + add advancement progress
if not self._canProcess():
_logger.warning('There is some processing on going already, will'
'not process the new dataset')
self._latest_xas_obj = xas_obj.copy()
self._startProcess()
# setup the normalization process
process_obj = QPyMca_normalization()
process_obj._advancement.sigProgress.connect(self._setProgressValue)
process_obj.setProperties({'_pymcaSettings': self._window._pymcaWindow.getParameters()})
xas_obj = process_obj.process(xas_obj)
process_obj._advancement.sigProgress.disconnect(self._setProgressValue)
self._window.xasObjViewer.setXASObj(xas_obj=xas_obj)
# emit signal for the plot
self.send("spectra", xas_obj)
def _updateProcess(self):
self._update_settings()
if self._latest_xas_obj:
self.process(self._latest_xas_obj)
def _update_settings(self):
self._pymcaSettings = self._window._pymcaWindow.getParameters()
def _setProgressValue(self, value):
self._progress.widget.progressBarSet(value)
# update the processing thread
thread = self.getProcessingThread()
thread.init(process_obj=process_obj, xas_obj=xas_obj)
self._callback_finish = functools.partial(self._endProcess, xas_obj)
thread.finished.connect(self._callback_finish)
# start processing
thread.start(priority=qt.QThread.LowPriority)
class QPyMca_normalization(xas.core.process.normalization.PyMca_normalization):
"""
Normalization able to give advancement using qt.Signal and QThreadPool
"""
def __init__(self):
xas.core.process.normalization.PyMca_normalization.__init__(self)
self._advancement = QProgress('normalization')
def _pool_process(self, xas_obj):
self.pool = qt.QThreadPool()
self.pool.setMaxThreadCount(5)
for spectrum in xas_obj.spectra:
runnable = ProcessRunnable(fct=xas.core.process.normalization.process_spectr_norm,
spectrum=spectrum,
configuration=xas_obj.configuration,
callback=self._advancement.increaseAdvancement)
self.pool.start(runnable)
self.pool.waitForDone()
......@@ -40,6 +40,7 @@ import os
import logging
_logger = logging.getLogger(__file__)
_DEBUG = True
class XASInputOW(OWWidget):
"""
......@@ -99,6 +100,8 @@ class XASInputOW(OWWidget):
except ValueError as e:
qt.QMessageBox.warning(self, '', str(e))
else:
if _DEBUG is True and xas_obj.n_spectrum > 100:
xas_obj._setSpectra(xas_obj.spectra[0:100])
self.send("spectra", xas_obj)
def _manageSettings(self):
......
......@@ -27,43 +27,86 @@ __authors__ = ["H. Payno"]
__license__ = "MIT"
__date__ = "06/11/2019"
from xas.core.types import XASObject
from .progress import Progress
from xas.core.types import XASObject, Spectrum
from .process import Process
from PyMca5.PyMcaPhysics.xas.XASClass import XASClass
from PyMca5.PyMcaPhysics.xas.XASClass import e2k
from PyMca5.PyMcaPhysics.xas.XASClass import e2k, k2e
import multiprocessing
import functools
import numpy
import logging
_logger = logging.getLogger(__name__)
def _process_spectrum(spectrum, configuration):
"""process a single spectrum"""
def process_spectr_exafs(spectrum, configuration, overwrite=True, callback=None,
output=None, output_dict=None):
"""
:param :class:`.Spectrum` spectrum: spectrum to process
:param dict configuration: configuration of the pymca normalization
:param bool overwrite: False if we want to return a new Spectrum instance
:param function pointer callback: callback to execute.
:param output: list to store the result, needed for pool processing
:type: multiprocessing.manager.list
:param dict output_dict: key: input spectrum, value: index in the output
list.
:return: processed spectrum
:rtype: tuple (configuration, spectrum)
"""
if spectrum.energy is None or spectrum.mu is None:
_logger.error('Energy and or Mu is/are not specified, unable to '
'compute exafs')
return None, None
pymca_xas = XASClass()
pymca_xas.setSpectrum(energy=spectrum.energy,
mu=spectrum.mu)
pymca_xas.setConfiguration(configuration)
spectrum.update(pymca_xas.processSpectrum())
if configuration is not None:
pymca_xas.setConfiguration(configuration)
assert 'NormalizedBackground' in spectrum
if 'Energy' not in spectrum or 'Mu' not in spectrum:
_logger.error('Energy and or Mu is/are not specified, unable to '
'compute exafs')
if 'NormalizedBackground' not in spectrum:
_logger.warning('spectrum has not been normalized, will not process exafs')
return None, None
if 'EXAFSKValues' in spectrum and 'Mu' in spectrum:
kValues = spectrum['EXAFSKValues']
else:
if 'Mu' not in spectrum:
print('********************** computing **********************')
if 'Edge' not in spectrum:
spectrum.update(pymca_xas.processSpectrum())
e0 = spectrum['Edge']
energy = spectrum['Energy']
kValues = e2k(energy - e0)
spectrum['EXAFSKValues'] = kValues
mu = spectrum.mu
spectrum['EXAFS'] = pymca_xas.postEdge(k=kValues, mu=mu)
e0 = pymca_xas.calculateE0()
ddict = spectrum.to_dict()
ddict["Energy"] = pymca_xas._energy
ddict["Mu"] = pymca_xas._mu
cleanMu = pymca_xas._mu - ddict["NormalizedBackground"]
kValues = e2k(pymca_xas._energy - e0)
ddict.update(pymca_xas.postEdge(kValues, cleanMu))
dataSet = numpy.zeros((cleanMu.size, 2), numpy.float)
dataSet[:, 0] = kValues
dataSet[:, 1] = cleanMu
# exafs normalization
exafs = (cleanMu - ddict["PostEdgeB"]) / ddict["PostEdgeB"]
ddict["EXAFSEnergy"] = k2e(kValues)
ddict["EXAFSKValues"] = kValues
ddict["EXAFSSignal"] = cleanMu
if ddict["KWeight"]:
exafs *= pow(kValues, ddict["KWeight"])
ddict["EXAFSNormalized"] = exafs
if callback:
callback()
res_spectrum = Spectrum.from_dict(ddict=ddict)
def get_output(orignal_spec, res_spec):
if overwrite:
orignal_spec.update(res_spec)
return orignal_spec
else:
return res_spec
if output is not None:
assert output_dict is not None
output[output_dict[spectrum]] = get_output(spectrum, res_spectrum)
return configuration, spectrum
return configuration, get_output(spectrum, res_spectrum)
def pymca_exafs(xas_obj):
......@@ -78,11 +121,15 @@ def pymca_exafs(xas_obj):
return exafs_obj.process(xas_obj=xas_obj)
class PyMca_exafs(object):
_USE_MULTIPROCESSING_POOL = False
# note: we cannot use multiprocessing pool with push workflow for now.
class PyMca_exafs(Process):
"""Process spectra for exafs and get information about the processing
advancement"""
def __init__(self):
self._advancement = Progress('exafs')
Process.__init__(self, name='exafs')
self._settings = None
def setProperties(self, properties):
......@@ -90,20 +137,46 @@ class PyMca_exafs(object):
self._settings = properties['_pymcaSettings']
def process(self, xas_obj):
if isinstance(xas_obj, dict):
_xas_obj = XASObject.from_dict(xas_obj)
else:
_xas_obj = xas_obj
_xas_obj = self.getXasObject(xas_obj=xas_obj)
if self._settings:
_xas_obj.configuration['EXAFS'] = self._settings
self._advancement.reset(max_=_xas_obj.n_spectrum)
self._advancement.startProcess()
for i_spectrum, spectrum in enumerate(_xas_obj.spectra):
_xas_obj.configuration, _xas_obj.spectra[i_spectrum] = _process_spectrum(spectrum=spectrum,
configuration=_xas_obj.configuration)
self._advancement.setAdvancement(int(i_spectrum / _xas_obj.n_spectrum * 100))
self._pool_process(xas_obj=_xas_obj)
self._advancement.endProcess()
assert isinstance(_xas_obj, XASObject)
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:
assert 'NormalizedBackground' in spectrum
process_spectr_exafs(spectrum=spectrum,
configuration=xas_obj.configuration,
callback=self._advancement.increaseAdvancement,
overwrite=True)
assert 'EXAFSKValues' in spectrum
else:
from multiprocessing import Manager
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