Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions easyDiffractionApp/Gui/Components/AnalysisFitables.qml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import Gui.Globals 1.0 as ExGlobals
EaComponents.TableView {
id: table

enabled: ExGlobals.Constants.proxy.isFitFinished

maxRowCountShow: 8
defaultInfoText: qsTr("No Parameters Found")

Expand Down
44 changes: 44 additions & 0 deletions easyDiffractionApp/Gui/Components/ResultsDialog.qml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import QtQuick 2.13
import QtQuick.Controls 2.13

import easyAppGui.Globals 1.0 as EaGlobals
import easyAppGui.Style 1.0 as EaStyle
import easyAppGui.Elements 1.0 as EaElements

import Gui.Globals 1.0 as ExGlobals

EaElements.Dialog {
property bool gotResults: typeof ExGlobals.Constants.proxy.fitResults.success !== 'undefined' &&
ExGlobals.Constants.proxy.isFitFinished

title: qsTr("Refinement Results")

parent: Overlay.overlay

x: (parent.width - width) * 0.5
y: (parent.height - height) * 0.5

modal: true
standardButtons: Dialog.Ok

Column {
EaElements.Label {
text: gotResults
? `Success: ${ExGlobals.Constants.proxy.fitResults.success}`
: ""
}

EaElements.Label {
text: gotResults
? `Num. refined parameters: ${ExGlobals.Constants.proxy.fitResults.nvarys}`
: ""
}

EaElements.Label {
text: gotResults
? `Goodness-of-fit (reduced \u03c7\u00b2): ${ExGlobals.Constants.proxy.fitResults.redchi2.toFixed(2)}`
: ""
}
}
}

4 changes: 4 additions & 0 deletions easyDiffractionApp/Gui/Components/qmldir
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,7 @@ ExperimentBackground 1.0 ExperimentBackground.qml

AnalysisFitables 1.0 AnalysisFitables.qml
AnalysisConstraints 1.0 AnalysisConstraints.qml

# Separate components

ResultsDialog 1.0 ResultsDialog.qml
1 change: 1 addition & 0 deletions easyDiffractionApp/Gui/Logic/PyQmlProxy.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

40 changes: 9 additions & 31 deletions easyDiffractionApp/Gui/Pages/Analysis/SideBarBasic.qml
Original file line number Diff line number Diff line change
Expand Up @@ -173,46 +173,24 @@ EaComponents.SideBarColumn {
validator: sliderFromLabel.validator
maximumLength: sliderFromLabel.maximumLength
text: slider.to.toFixed(4)
onEditingFinished: {}
}
}

// Start fitting button
EaElements.SideBarButton {
enabled: ExGlobals.Constants.proxy.experimentLoaded
fontIcon: "play-circle"
text: qsTr("Start fitting")

id: fitButton
wide: true

onClicked: {
//print("Start fitting button clicked")
ExGlobals.Constants.proxy.fit()
refinementResultsDialog.open()
}
enabled: ExGlobals.Constants.proxy.experimentLoaded
fontIcon: ExGlobals.Constants.proxy.isFitFinished ? "play-circle" : "pause-circle"
text: ExGlobals.Constants.proxy.isFitFinished ? qsTr("Start fitting") : qsTr("Stop fitting")
onClicked: ExGlobals.Constants.proxy.fit()
}
}

// Info dialog (after refinement)

EaElements.Dialog {
id: refinementResultsDialog

parent: Overlay.overlay

x: (parent.width - width) * 0.5
y: (parent.height - height) * 0.5

modal: true
standardButtons: Dialog.Ok

title: qsTr("Refinement Results")

Column {
EaElements.Label { text: typeof ExGlobals.Constants.proxy.fitResults !== 'undefined' ? `Success: ${ExGlobals.Constants.proxy.fitResults.success}` : "" }
EaElements.Label { text: typeof ExGlobals.Constants.proxy.fitResults !== 'undefined' ? `Num. refined parameters: ${ExGlobals.Constants.proxy.fitResults.nvarys}` : "" }
EaElements.Label { text: typeof ExGlobals.Constants.proxy.fitResults !== 'undefined' && typeof ExGlobals.Constants.proxy.fitResults.redchi2 !== 'undefined' ? `Goodness-of-fit (reduced \u03c7\u00b2): ${ExGlobals.Constants.proxy.fitResults.redchi2.toFixed(2)}` : "" }
}
// Init results dialog
ExComponents.ResultsDialog {
visible: typeof ExGlobals.Constants.proxy.fitResults.success !== 'undefined' &&
ExGlobals.Constants.proxy.isFitFinished
}

// Logic
Expand Down
1 change: 1 addition & 0 deletions easyDiffractionApp/Gui/Pages/Experiment/SideBarBasic.qml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ EaComponents.SideBarColumn {
EaElements.GroupBox {
title: qsTr("Experimental data")
collapsible: false
enabled: ExGlobals.Constants.proxy.isFitFinished

ExComponents.ExperimentDataExplorer {}

Expand Down
1 change: 1 addition & 0 deletions easyDiffractionApp/Gui/Pages/Sample/SideBarBasic.qml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ EaComponents.SideBarColumn {
EaElements.GroupBox {
title: qsTr("Structural phases")
collapsible: false
enabled: ExGlobals.Constants.proxy.isFitFinished

ExComponents.SamplePhasesExplorer {}

Expand Down
28 changes: 28 additions & 0 deletions easyDiffractionApp/Logic/Fitter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
from PySide2.QtCore import Signal, QThread


class Fitter(QThread):
"""
Simple wrapper for calling a function in separate thread
"""
failed = Signal(str)
finished = Signal(dict)

def __init__(self, obj, method_name, *args, **kwargs):
QThread.__init__(self, None)
self._obj = obj
self.method_name = method_name
self.args = args
self.kwargs = kwargs

def run(self):
res = {}
if hasattr(self._obj, self.method_name):
func = getattr(self._obj, self.method_name)
try:
res = func(*self.args, **self.kwargs)
except Exception as ex:
self.failed.emit(str(ex))
return str(ex)
self.finished.emit(res)
return res
43 changes: 37 additions & 6 deletions easyDiffractionApp/Logic/PyQmlProxy.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,10 @@

from easyCore.Symmetry.tools import SpacegroupInfo
from easyCore.Fitting.Fitting import Fitter
from easyCore.Fitting.Constraints import ObjConstraint, NumericConstraint
from easyCore.Utils.classTools import generatePath

from easyDiffractionLib.sample import Sample
from easyDiffractionLib import Phases, Phase, Lattice, Site, Atoms, SpaceGroup
from easyDiffractionLib import Phases, Phase, Lattice, Site, SpaceGroup
from easyDiffractionLib.interface import InterfaceFactory
from easyDiffractionLib.Elements.Experiments.Experiment import Pars1D
from easyDiffractionLib.Elements.Experiments.Pattern import Pattern1D
Expand All @@ -39,6 +38,7 @@
from easyDiffractionApp.Logic.Proxies.MatplotlibBackend import MatplotlibBridge
from easyDiffractionApp.Logic.Proxies.QtChartsBackend import QtChartsBridge
from easyDiffractionApp.Logic.Proxies.BokehBackend import BokehBridge
from easyDiffractionApp.Logic.Fitter import Fitter as ThreadedFitter

from easyDiffractionApp.Logic.ScreenRecorder import ScreenRecorder

Expand Down Expand Up @@ -107,7 +107,7 @@ class PyQmlProxy(QObject):

# Status info
statusInfoChanged = Signal()

# Misc
dummySignal = Signal()

Expand Down Expand Up @@ -234,6 +234,10 @@ def __init__(self, parent=None):
self.currentMinimizerChanged.connect(self.statusInfoChanged)
self.currentMinimizerMethodChanged.connect(self.statusInfoChanged)

# Multithreading
self._fitter_thread = None
self._fit_finished = True

# Screen recorder
self._screen_recorder = ScreenRecorder()

Expand Down Expand Up @@ -1265,22 +1269,41 @@ def _onCurrentCalculatorChanged(self):

@Slot()
def fit(self):
self.isFitFinished = False
exp_data = self._data.experiments[0]

x = exp_data.x
y = exp_data.y
weights = 1 / exp_data.e
method = self._current_minimizer_method_name

res = self.fitter.fit(x, y, weights=weights, method=method)
args = (x, y)
kwargs = {"weights": weights, "method": method}
self._fitter_thread = ThreadedFitter(self.fitter, 'fit', *args, **kwargs)
self._fitter_thread.finished.connect(self._setFitResults)
self._fitter_thread.failed.connect(self._setFitResultsFailed)
self._fitter_thread.start()

self._setFitResults(res)
self.fitFinished.emit()
# self._setFitResults(res)
# self.fitFinished.emit()

@Property('QVariant', notify=fitResultsChanged)
def fitResults(self):
return self._fit_results

@Property(bool, notify=fitFinished)
def isFitFinished(self):
print('+ isfitFinished called')
return self._fit_finished

@isFitFinished.setter
def isFitFinished(self, fit_finished: bool):
print('+ isFitFinished.setter called', fit_finished)
if self._fit_finished == fit_finished:
return
self._fit_finished = fit_finished
self.fitFinished.emit()

def _defaultFitResults(self):
return {
"success": None,
Expand All @@ -1297,6 +1320,14 @@ def _setFitResults(self, res):
"redchi2": float(res.reduced_chi)
}
self.fitResultsChanged.emit()
self.isFitFinished = True
self.fitFinished.emit()

def _setFitResultsFailed(self, res):
print("FIT FAILED")
print(str(res))
self.isFitFinished = True
self.fitFinished.emit()

def _onFitFinished(self):
print("***** _onFitFinished")
Expand Down
1 change: 0 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ vtk = '^8.1.2'
pyobjc-core = { version = '^7.1', platform = 'darwin' }
pyobjc-framework-cocoa = { version = '^7.1', platform = 'darwin' }
# easyScience
#easyCore = { git = 'https://github.com/easyScience/easyCore.git', rev = 'xarray' }
easyDiffractionLib = { git = 'https://github.com/easyScience/easyDiffractionLib.git', rev = 'develop' }
easyAppLogic = { git = 'https://github.com/easyScience/easyAppLogic.git', rev = 'develop' }
easyAppGui = { git = 'https://github.com/easyScience/easyAppGui.git', rev = 'develop' }
Expand Down