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