Skip to content

Commit

Permalink
Merge pull request #1102 from vasole/thread
Browse files Browse the repository at this point in the history
[MacOS] [ROI Imaging] Rework threading mechanism
  • Loading branch information
vasole authored Feb 17, 2025
2 parents fbdd1f8 + 0e54070 commit 0cea462
Show file tree
Hide file tree
Showing 2 changed files with 112 additions and 59 deletions.
85 changes: 57 additions & 28 deletions src/PyMca5/PyMcaPlugins/NNMAStackPlugin.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#/*##########################################################################
# Copyright (C) 2004-2023 European Synchrotron Radiation Facility
# Copyright (C) 2004-2025 European Synchrotron Radiation Facility
#
# This file is part of the PyMca X-ray Fluorescence Toolkit developed at
# the ESRF.
Expand Down Expand Up @@ -178,23 +178,10 @@ def calculate(self):
if ret:
self._executeFunctionAndParameters()

def _executeFunctionAndParameters(self):
_logger.debug("NNMAStackPlugin _executeFunctionAndParameters")
self.widget = None
self.thread = CalculationThread.CalculationThread(\
calculation_method=self.actualCalculation)
self.configurationWidget.show()
message = "Please wait. NNMA Calculation going on."
_logger.debug("NNMAStackPlugin starting thread")
self.thread.start()
_logger.debug("NNMAStackPlugin waitingMessageDialog")
CalculationThread.waitingMessageDialog(self.thread,
message=message,
parent=self.configurationWidget)
_logger.debug("NNMAStackPlugin waitingMessageDialog passed")
self.threadFinished()

def actualCalculation(self):
def _getFunctionAndParameters(self):
"""
Get the function, vars and kw for the calculation thread
"""
_logger.debug("NNMAStackPlugin actualCalculation")
nnmaParameters = self.configurationWidget.getParameters()
self._status.setText("Calculation going on")
Expand All @@ -216,6 +203,16 @@ def actualCalculation(self):
spatial_mask = numpy.isfinite(self.getStackOriginalImage())
ddict['mask'] = spatial_mask
del nnmaParameters
return function, None, ddict

def _executeFunctionAndParameters(self):
_logger.debug("_executeFunctionAndParameters")
self.widget = None
self.configurationWidget.show()
function, dummy, ddict = self._getFunctionAndParameters()
_logger.info("NNMA function %s" % function.__name__)
_logger.info("NNMA parameters %s" % ddict)

stack = self.getStackDataObject()
if isinstance(stack, numpy.ndarray):
if stack.data.dtype not in [numpy.float64, numpy.float32]:
Expand All @@ -236,18 +233,48 @@ def actualCalculation(self):
tmpData.shape = -1
data[:, i] = tmpData
data.shape = oldShape[1:] + oldShape[0:1]
result = function(data, **ddict)
data = None
else:
result = function(stack, **ddict)
if stack.data.shape != oldShape:
stack.data.shape = oldShape
return result
data = stack
try:
if _logger.getEffectiveLevel() == logging.DEBUG:
result = function(inputStack, **ddict)
self.threadFinished(result)
else:
thread = CalculationThread.CalculationThread(\
calculation_method=function,
calculation_vars=data,
calculation_kw=ddict,
expand_vars=False,
expand_kw=True)
thread.start()
message = "Please wait. NNMA Calculation going on."
_logger.debug("NNMAStackPlugin waitingMessageDialog")
CalculationThread.waitingMessageDialog(thread,
message=message,
parent=self.configurationWidget,
modal=True,
update_callback=None,
frameless=False)
_logger.debug("NNMAStackPlugin waitingMessageDialog passed")
result = thread.getResult()
self.threadFinished(result)
except Exception:
msg = qt.QMessageBox(self)
msg.setIcon(qt.QMessageBox.Critical)
msg.setWindowTitle("Calculation error")
msg.setText("Error on NNMA calculation")
msg.setInformativeText(str(sys.exc_info()[1]))
msg.setDetailedText(traceback.format_exc())
msg.exec()
finally:
if mcaIndex == 0:
data = None
else:
if stack.data.shape != oldShape:
stack.data.shape = oldShape

def threadFinished(self):
_logger.debug("NNMAStackPlugin threadFinished")
result = self.thread.result
self.thread = None
def threadFinished(self, result):
_logger.info("threadFinished")
if type(result) == type((1,)):
#if we receive a tuple there was an error
if len(result):
Expand All @@ -258,6 +285,8 @@ def threadFinished(self):
return
self._status.setText("Ready")
curve = self.configurationWidget.getSpectrum(binned=True)


if curve not in [None, []]:
xValues = curve[0]
else:
Expand Down
86 changes: 55 additions & 31 deletions src/PyMca5/PyMcaPlugins/PCAStackPlugin.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#/*##########################################################################
# Copyright (C) 2004-2023 European Synchrotron Radiation Facility
# Copyright (C) 2004-2025 European Synchrotron Radiation Facility
#
# This file is part of the PyMca X-ray Fluorescence Toolkit developed at
# the ESRF.
Expand Down Expand Up @@ -181,25 +181,11 @@ def calculate(self):
self._kMeansWidget = None
self._executeFunctionAndParameters()

def _executeFunctionAndParameters(self):
self.widget = None
self.configurationWidget.show()
if _logger.getEffectiveLevel() == logging.DEBUG:
self.thread = CalculationThread.CalculationThread(\
calculation_method=self.actualCalculation)
self.thread.result = self.actualCalculation()
self.threadFinished()
else:
self.thread = CalculationThread.CalculationThread(\
calculation_method=self.actualCalculation)
self.thread.start()
message = "Please wait. PCA Calculation going on."
CalculationThread.waitingMessageDialog(self.thread,
message=message,
parent=self.configurationWidget)
self.threadFinished()

def actualCalculation(self):
def _getFunctionAndParameters(self):
"""
Get the function, vars and kw for the calculation thread
"""
#obtain the parameters for the calculation
pcaParameters = self.configurationWidget.getParameters()
self._status.setText("Calculation going on")
self.configurationWidget.setEnabled(False)
Expand Down Expand Up @@ -228,17 +214,21 @@ def actualCalculation(self):
spatial_mask = numpy.isfinite(self.getStackOriginalImage())
pcaParameters['mask'] = spatial_mask
pcaParameters["legacy"] = False
return function, None, pcaParameters

def _executeFunctionAndParameters(self):
_logger.debug("_executeFunctionAndParameters")
self.widget = None
self.configurationWidget.show()
function, dummy, pcaParameters = self._getFunctionAndParameters()
_logger.info("PCA function %s" % function.__name__)
_logger.info("PCA parameters %s" % pcaParameters)
if "Multiple" in self.__methodlabel:
stackList = self.getStackDataObjectList()
oldShapes = []
for stack in stackList:
oldShapes.append(stack.data.shape)
result = function(stackList, **pcaParameters)
for i in range(len(stackList)):
stackList[i].data.shape = oldShapes[i]
return result
inputStack = stackList
else:
stack = self.getStackDataObject()
if isinstance(stack, numpy.ndarray):
Expand All @@ -248,14 +238,47 @@ def actualCalculation(self):
text += " WARNING: Non floating point data."
self._status.setText(text)
oldShape = stack.data.shape
result = function(stack, **pcaParameters)
if stack.data.shape != oldShape:
stack.data.shape = oldShape
return result
inputStack = stack

def threadFinished(self):
result = self.thread.getResult()
self.thread = None
try:
if _logger.getEffectiveLevel() == logging.DEBUG:
result = function(inputStack, **pcaParameters)
self.threadFinished(result)
else:
thread = CalculationThread.CalculationThread(\
calculation_method=function,
calculation_vars=inputStack,
calculation_kw=pcaParameters,
expand_vars=False,
expand_kw=True)
thread.start()
message = "Please wait. PCA Calculation going on."
CalculationThread.waitingMessageDialog(thread,
message=message,
parent=self.configurationWidget,
modal=True,
update_callback=None,
frameless=False)
result = thread.getResult()
self.threadFinished(result)
except Exception:
msg = qt.QMessageBox(self)
msg.setIcon(qt.QMessageBox.Critical)
msg.setWindowTitle("Calculation error")
msg.setText("Error on PCA calculation")
msg.setInformativeText(str(sys.exc_info()[1]))
msg.setDetailedText(traceback.format_exc())
msg.exec()
finally:
if "Multiple" in self.__methodlabel:
for i in range(len(stackList)):
stackList[i].data.shape = oldShapes[i]
else:
if stack.data.shape != oldShape:
stack.data.shape = oldShape

def threadFinished(self, result):
_logger.info("threadFinished")
if type(result) == type((1,)):
#if we receive a tuple there was an error
if len(result):
Expand All @@ -265,6 +288,7 @@ def threadFinished(self):
raise Exception(result[1], result[2])
return
self._status.setText("Ready")

curve = self.configurationWidget.getSpectrum(binned=True)
if curve not in [None, []]:
xValues = curve[0]
Expand Down

0 comments on commit 0cea462

Please sign in to comment.