Commit 28797618 authored by Henri Payno's avatar Henri Payno
Browse files

[orangecontrib] start removing RunnableProcess

parent f3be7257
...@@ -34,7 +34,7 @@ from est.core.types import XASObject ...@@ -34,7 +34,7 @@ from est.core.types import XASObject
from ..utils import extract_properties_from_dict from ..utils import extract_properties_from_dict
import logging import logging
from collections import namedtuple from collections import namedtuple
from ewokscore.task import Task from ewokscore.taskwithprogress import TaskWithProgress as Task
from typing import Iterable from typing import Iterable
_logger = logging.getLogger(__name__) _logger = logging.getLogger(__name__)
......
...@@ -155,10 +155,9 @@ class PyMca_normalization( ...@@ -155,10 +155,9 @@ class PyMca_normalization(
if self.inputs.normalization: if self.inputs.normalization:
self.setConfiguration(self.inputs.normalization) self.setConfiguration(self.inputs.normalization)
_xas_obj.configuration["Normalization"] = self.inputs.normalization _xas_obj.configuration["Normalization"] = self.inputs.normalization
self._advancement.reset(max_=_xas_obj.n_spectrum) self.progress = 0.0
self._advancement.startProcess()
self._pool_process(xas_obj=_xas_obj) self._pool_process(xas_obj=_xas_obj)
self._advancement.endProcess() self.progress = 100.0
if _xas_obj.normalized_energy is None: if _xas_obj.normalized_energy is None:
raise ValueError("Fail to compute normalize energy") raise ValueError("Fail to compute normalize energy")
self.register_process( self.register_process(
...@@ -176,14 +175,16 @@ class PyMca_normalization( ...@@ -176,14 +175,16 @@ class PyMca_normalization(
"""process normalization from a pool""" """process normalization from a pool"""
assert isinstance(xas_obj, XASObject) assert isinstance(xas_obj, XASObject)
if not _USE_MULTIPROCESSING_POOL: if not _USE_MULTIPROCESSING_POOL:
for spectrum in xas_obj.spectra.data.flat: for i_s, spectrum in enumerate(xas_obj.spectra.data.flat):
process_spectr_norm( process_spectr_norm(
spectrum=spectrum, spectrum=spectrum,
configuration=xas_obj.configuration, configuration=xas_obj.configuration,
callbacks=self.callbacks, callbacks=self.callbacks,
overwrite=True, overwrite=True,
) )
self.progress = i_s / len(xas_obj.spectra.data.flat) * 100.0
else: else:
# TODO: remove this mode for simplification
from multiprocessing import Manager from multiprocessing import Manager
manager = Manager() manager = Manager()
......
...@@ -31,49 +31,33 @@ __date__ = "06/07/2019" ...@@ -31,49 +31,33 @@ __date__ = "06/07/2019"
from silx.gui import qt from silx.gui import qt
from Orange.widgets import gui from Orange.widgets import gui
import logging import logging
from ewoksorange.bindings.owwidgets import OWEwoksWidgetOneThread
from est.core.types import XASObject
_logger = logging.getLogger(__file__) _logger = logging.getLogger(__file__)
class _ProcessForOrangeMixIn(object): class _ProcessForOrangeMixIn(OWEwoksWidgetOneThread):
""" def _ewoksTaskFinishedCallback(self):
Group processing and progress display in a common class for xasObject with self._ewoksTaskFinishedContext():
process. self.outputsChanged()
super()._ewoksTaskFinishedCallback()
If this process own a widget to display the xas object then this one should def handleNewSignals(self):
be named '_window' self.inputsChanged()
""" super().handleNewSignals()
def __init__(self): def inputsChanged(self):
# progress pass
self._progress = gui.ProgressBar(self, 100)
"""progress bar"""
self.__processingThread = None
"""Thread for processing"""
# progress
self._progress = gui.ProgressBar(self, 100)
def _startProcess(self): def outputsChanged(self):
if hasattr(self, "_window"): print("output variables are", self.output_variables)
self._window.setEnabled(False) # TODO: maybe we would expect a task_outputs to match the task_inputs
self._progress.widget.progressBarInit() if "xas_obj" in self.task_inputs:
print("xas_obj contains", self.task_inputs)
def _endProcess(self, xas_obj): xas_obj = self.output_variables["xas_obj"].value
if hasattr(self, "_window"): if isinstance(xas_obj, dict):
self._window.setEnabled(True) xas_obj = XASObject.from_dict(xas_obj)
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:
if hasattr(self, "_window") and hasattr(self._window, "setXASObj"): if hasattr(self, "_window") and hasattr(self._window, "setXASObj"):
self._window.setXASObj(xas_obj=xas_obj) self._window.setXASObj(xas_obj=xas_obj)
elif hasattr(self, "_window") and hasattr(self._window, "xasObjViewer"): elif hasattr(self, "_window") and hasattr(self._window, "xasObjViewer"):
...@@ -81,70 +65,3 @@ class _ProcessForOrangeMixIn(object): ...@@ -81,70 +65,3 @@ class _ProcessForOrangeMixIn(object):
self._window.xasObjViewer.setXASObj(xas_obj=xas_obj) self._window.xasObjViewer.setXASObj(xas_obj=xas_obj)
# emit signal for the plot # emit signal for the plot
self.Outputs.xas_obj.send(xas_obj) self.Outputs.xas_obj.send(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()
...@@ -94,4 +94,4 @@ class _ParameterWindowContainer(qt.QWidget): ...@@ -94,4 +94,4 @@ class _ParameterWindowContainer(qt.QWidget):
return self._mainwidget.getParameters() return self._mainwidget.getParameters()
def setParameters(self, params): def setParameters(self, params):
self._mainwidget.setParameters(params=params) self._mainwidget.setParameters(params)
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
__authors__ = ["H. Payno"] __authors__ = ["H. Payno"]
__license__ = "MIT" __license__ = "MIT"
__date__ = "06/07/2019" __date__ = "04/10/2021"
import functools import functools
...@@ -39,7 +39,6 @@ from silx.gui import qt ...@@ -39,7 +39,6 @@ from silx.gui import qt
from silx.gui.plot import LegendSelector from silx.gui.plot import LegendSelector
import est.core.process.larch.autobk import est.core.process.larch.autobk
from orangecontrib.est.process import _ProcessForOrangeMixIn from orangecontrib.est.process import _ProcessForOrangeMixIn
from orangecontrib.est.process import ProcessRunnable
from est.core.types import XASObject from est.core.types import XASObject
from est.gui.XasObjectViewer import XasObjectViewer, ViewType from est.gui.XasObjectViewer import XasObjectViewer, ViewType
from est.gui.XasObjectViewer import ( from est.gui.XasObjectViewer import (
......
...@@ -39,7 +39,6 @@ from silx.gui import qt ...@@ -39,7 +39,6 @@ from silx.gui import qt
from silx.gui.plot import LegendSelector from silx.gui.plot import LegendSelector
import est.core.process.larch.mback import est.core.process.larch.mback
from orangecontrib.est.process import _ProcessForOrangeMixIn from orangecontrib.est.process import _ProcessForOrangeMixIn
from orangecontrib.est.process import ProcessRunnable
from est.core.types import XASObject from est.core.types import XASObject
from est.gui.XasObjectViewer import XasObjectViewer, ViewType from est.gui.XasObjectViewer import XasObjectViewer, ViewType
from est.gui.larch.mback import _MBackParameters from est.gui.larch.mback import _MBackParameters
......
...@@ -39,7 +39,6 @@ from silx.gui import qt ...@@ -39,7 +39,6 @@ from silx.gui import qt
from silx.gui.plot import LegendSelector from silx.gui.plot import LegendSelector
import est.core.process.larch.mback_norm import est.core.process.larch.mback_norm
from orangecontrib.est.process import _ProcessForOrangeMixIn from orangecontrib.est.process import _ProcessForOrangeMixIn
from orangecontrib.est.process import ProcessRunnable
from est.core.types import XASObject from est.core.types import XASObject
from est.gui.XasObjectViewer import XasObjectViewer, ViewType from est.gui.XasObjectViewer import XasObjectViewer, ViewType
from est.gui.XasObjectViewer import _plot_norm, _plot_mback_mu from est.gui.XasObjectViewer import _plot_norm, _plot_mback_mu
......
...@@ -39,7 +39,6 @@ from silx.gui import qt ...@@ -39,7 +39,6 @@ from silx.gui import qt
from silx.gui.plot import LegendSelector from silx.gui.plot import LegendSelector
import est.core.process.larch.pre_edge import est.core.process.larch.pre_edge
from orangecontrib.est.process import _ProcessForOrangeMixIn from orangecontrib.est.process import _ProcessForOrangeMixIn
from orangecontrib.est.process import ProcessRunnable
from est.core.types import XASObject from est.core.types import XASObject
from est.gui.XasObjectViewer import XasObjectViewer, ViewType from est.gui.XasObjectViewer import XasObjectViewer, ViewType
from est.gui.XasObjectViewer import ( from est.gui.XasObjectViewer import (
......
...@@ -39,7 +39,6 @@ from silx.gui import qt ...@@ -39,7 +39,6 @@ from silx.gui import qt
from silx.gui.plot import LegendSelector from silx.gui.plot import LegendSelector
import est.core.process.larch.xftf import est.core.process.larch.xftf
from orangecontrib.est.process import _ProcessForOrangeMixIn from orangecontrib.est.process import _ProcessForOrangeMixIn
from orangecontrib.est.process import ProcessRunnable
from est.core.types import XASObject from est.core.types import XASObject
from est.gui.XasObjectViewer import ( from est.gui.XasObjectViewer import (
XasObjectViewer, XasObjectViewer,
......
...@@ -41,7 +41,7 @@ from PyMca5.PyMcaGui.physics.xas.XASPostEdgeParameters import XASPostEdgeParamet ...@@ -41,7 +41,7 @@ from PyMca5.PyMcaGui.physics.xas.XASPostEdgeParameters import XASPostEdgeParamet
from silx.gui import qt from silx.gui import qt
from silx.gui.plot import LegendSelector from silx.gui.plot import LegendSelector
import est.core.process.pymca.exafs import est.core.process.pymca.exafs
from orangecontrib.est.process import _ProcessForOrangeMixIn, ProcessRunnable from orangecontrib.est.process import _ProcessForOrangeMixIn
from est.gui.XasObjectViewer import XasObjectViewer, ViewType from est.gui.XasObjectViewer import XasObjectViewer, ViewType
from est.gui.XasObjectViewer import ( from est.gui.XasObjectViewer import (
_exafs_signal_plot, _exafs_signal_plot,
...@@ -117,8 +117,7 @@ class ExafsWindow(qt.QMainWindow): ...@@ -117,8 +117,7 @@ class ExafsWindow(qt.QMainWindow):
class ExafsOW( class ExafsOW(
_ProcessForOrangeMixIn, _ProcessForOrangeMixIn, ewokstaskclass=est.core.process.pymca.exafs.PyMca_exafs
OWWidget,
): ):
""" """
Widget used for signal extraction Widget used for signal extraction
...@@ -135,23 +134,22 @@ class ExafsOW( ...@@ -135,23 +134,22 @@ class ExafsOW(
want_main_area = True want_main_area = True
resizing_enabled = True resizing_enabled = True
allows_cycle = False allows_cycle = False
ewokstaskclass = est.core.process.pymca.exafs.PyMca_exafs
_larchSettings = Setting(dict()) _larchSettings = Setting(dict())
# kept for compatibility # kept for compatibility
static_input = Setting({"xas_obj": None, "exafs": None}) static_input = Setting({"xas_obj": None, "exafs": None})
"""Store the configuration of the PyMca XASClass""" """Store the configuration of the PyMca XASClass"""
#
class Inputs: # class Inputs:
xas_obj = Input("xas_obj", XASObject, default=True) # xas_obj = Input("xas_obj", XASObject, default=True)
# simple compatibility for some Orange widget and especialy the # # simple compatibility for some Orange widget and especialy the
# 'spectroscopy add-on' # # 'spectroscopy add-on'
data_table = Input("Data", Orange.data.Table) # data_table = Input("Data", Orange.data.Table)
#
class Outputs: # class Outputs:
xas_obj = Output("xas_obj", XASObject) # xas_obj = Output("xas_obj", XASObject)
# by default we want to avoid sending 'Orange.data.Table' to avoid # # by default we want to avoid sending 'Orange.data.Table' to avoid
# loosing the XASObject flow process and results. # # loosing the XASObject flow process and results.
def __init__(self): def __init__(self):
super().__init__() super().__init__()
...@@ -189,65 +187,65 @@ class ExafsOW( ...@@ -189,65 +187,65 @@ class ExafsOW(
"exafs": self._window._pymcaWindow.getParameters(), "exafs": self._window._pymcaWindow.getParameters(),
} }
@Inputs.data_table #
def processFrmDataTable(self, data_table): # @Inputs.data_table
if data_table is None: # def processFrmDataTable(self, data_table):
return # if data_table is None:
self.process(Converter.toXASObject(data_table=data_table)) # return
# self.process(Converter.toXASObject(data_table=data_table))
@Inputs.xas_obj #
def process(self, xas_obj): # @Inputs.xas_obj
if xas_obj is None: # def process(self, xas_obj):
return # if xas_obj is None:
# return
if not self._canProcess(): #
_logger.warning( # if not self._canProcess():
"There is some processing on going already, will" # _logger.warning(
"not process the new dataset" # "There is some processing on going already, will"
) # "not process the new dataset"
# )
self._latest_xas_obj = xas_obj #
self._startProcess() # self._latest_xas_obj = xas_obj
# self._startProcess()
# setup the exafs process #
process_obj = QPyMca_exafs(inputs={"xas_obj": xas_obj}) # # setup the exafs process
process_obj._advancement.sigProgress.connect(self._setProgressValue) # process_obj = QPyMca_exafs(inputs={"xas_obj": xas_obj})
process_obj.set_properties( # process_obj._advancement.sigProgress.connect(self._setProgressValue)
{"_pymcaSettings": self._window._pymcaWindow.getParameters()} # process_obj.set_properties(
) # {"_pymcaSettings": self._window._pymcaWindow.getParameters()}
# )
# update the processing thread #
thread = self.getProcessingThread() # # update the processing thread
thread.init(process_obj=process_obj, xas_obj=self._latest_xas_obj) # thread = self.getProcessingThread()
self._callback_finish = functools.partial( # thread.init(process_obj=process_obj, xas_obj=self._latest_xas_obj)
self._endProcess, self._latest_xas_obj # self._callback_finish = functools.partial(
) # self._endProcess, self._latest_xas_obj
thread.finished.connect(self._callback_finish) # )
# start processing # thread.finished.connect(self._callback_finish)
thread.start(priority=qt.QThread.LowPriority) # # start processing
# thread.start(priority=qt.QThread.LowPriority)
def _setProgressValue(self, value):
self._progress.widget.progressBarSet(value)
class QPyMca_exafs(est.core.process.pymca.exafs.PyMca_exafs): #
""" #
Normalization able to give advancement using qt.Signal and QThreadPool # class QPyMca_exafs(est.core.process.pymca.exafs.PyMca_exafs):
""" # """
# Normalization able to give advancement using qt.Signal and QThreadPool
def __init__(self, *args, **kwargs): # """
est.core.process.pymca.exafs.PyMca_exafs.__init__(self, *args, **kwargs) #
self._advancement = QProgress("normalization") # def __init__(self, *args, **kwargs):
# est.core.process.pymca.exafs.PyMca_exafs.__init__(self, *args, **kwargs)
def _pool_process(self, xas_obj): # self._advancement = QProgress("normalization")
self.pool = qt.QThreadPool() #
self.pool.setMaxThreadCount(5) # def _pool_process(self, xas_obj):
for spectrum in xas_obj.spectra: # self.pool = qt.QThreadPool()
runnable = ProcessRunnable( # self.pool.setMaxThreadCount(5)
fct=est.core.process.pymca.exafs.process_spectr_exafs, # for spectrum in xas_obj.spectra:
spectrum=spectrum, # runnable = ProcessRunnable(
configuration=xas_obj.configuration, # fct=est.core.process.pymca.exafs.process_spectr_exafs,
callback=self._advancement.increaseAdvancement, # spectrum=spectrum,
) # configuration=xas_obj.configuration,
self.pool.start(runnable) # callback=self._advancement.increaseAdvancement,
self.pool.waitForDone() # )
# self.pool.start(runnable)
# self.pool.waitForDone()
...@@ -43,7 +43,7 @@ from silx.gui import qt ...@@ -43,7 +43,7 @@ from silx.gui import qt
from silx.gui.plot import LegendSelector from silx.gui.plot import LegendSelector
import est.core.process.pymca.ft import est.core.process.pymca.ft
from orangecontrib.est.process import _ProcessForOrangeMixIn, ProcessRunnable from orangecontrib.est.process import _ProcessForOrangeMixIn
from est.core.types import XASObject from est.core.types import XASObject
from est.gui.XasObjectViewer import XasObjectViewer, ViewType from est.gui.XasObjectViewer import XasObjectViewer, ViewType
from est.gui.XasObjectViewer import _normalized_exafs, _ft_window_plot from est.gui.XasObjectViewer import _normalized_exafs, _ft_window_plot
...@@ -135,10 +135,7 @@ class FTWindow(qt.QMainWindow): ...@@ -135,10 +135,7 @@ class FTWindow(qt.QMainWindow):
) )
class FTOW( class FTOW(_ProcessForOrangeMixIn, ewokstaskclass=est.core.process.pymca.ft.PyMca_ft):
_ProcessForOrangeMixIn,
OWWidget,
):
""" """
Widget used for signal extraction Widget used for signal extraction
""" """
...@@ -154,23 +151,22 @@ class FTOW( ...@@ -154,23 +151,22 @@ class FTOW(
want_main_area = True want_main_area = True
resizing_enabled = True resizing_enabled = True
allows_cycle = False allows_cycle = False
ewokstaskclass = est.core.process.pymca.ft.PyMca_ft
_pymcaSettings = Setting(dict()) _pymcaSettings = Setting(dict())
# kept for compatibility # kept for compatibility
static_input = dict({"ft": None, "xas_obj": None}) static_input = dict({"ft": None, "xas_obj": None})
"""Store the configuration of the PyMca XASClass""" """Store the configuration of the PyMca XASClass"""
#
class Inputs: # class Inputs:
xas_obj = Input("xas_obj", XASObject, default=True) # xas_obj = Input("xas_obj", XASObject, default=True)
# simple compatibility for some Orange widget and especialy the # # simple compatibility for some Orange widget and especialy the
# 'spectroscopy add-on' # # 'spectroscopy add-on'
data_table = Input("Data", Orange.data.Table) # data_table = Input("Data", Orange.data.Table)
#
class Outputs: # class Outputs:
xas_obj = Output("xas_obj", XASObject) # xas_obj = Output("xas_obj", XASObject)
# by default we want to avoid sending 'Orange.data.Table' to avoid # # by default we want to avoid sending 'Orange.data.Table' to avoid
# loosing the XASObject flow process and results. # # loosing the XASObject flow process and results.
def __init__(self): def __init__(self):
super().__init__() super().__init__()
...@@ -179,9 +175,6 @@ class FTOW( ...@@ -179,9 +175,6 @@ class FTOW(
layout = gui.vBox(self.mainArea, "fourier transform").layout() layout = gui.vBox(self.mainArea, "fourier transform").layout()
layout.addWidget(self._window) layout.addWidget(self._window)
# progress
self._progress = gui.ProgressBar(self, 100)
# manage settings # manage settings
pymca_settings = self.static_input.get("ft", None) pymca_settings = self.static_input.get("ft", None)
if pymca_settings is None: if pymca_settings is None:
...@@ -200,43 +193,44 @@ class FTOW( ...@@ -200,43 +193,44 @@ class FTOW(
if self._latest_xas_obj: if self._latest_xas_obj:
self.process(xas_obj=self._latest_xas_obj) self.process(xas_obj=self._latest_xas_obj)
@Inputs.data_table #
def processFrmDataTable(self, data_table): # @Inputs.data_table
if data_table is None: # def processFrmDataTable(self, data_table):
return # if data_table is None:
self.process(Converter.toXASObject(data_table=data_table)) # return
# self.process(Converter.toXASObject(data_table=data_table))
@Inputs.xas_obj #
def process(self, xas_obj): # @Inputs.xas_obj
if xas_obj is None: # def process(self, xas_obj):
return # if xas_obj is None: