From 5d771cddb4dcddfec667e95f99d8428aa7223d80 Mon Sep 17 00:00:00 2001 From: Andreas Pedersen Date: Thu, 24 Oct 2024 13:44:02 +0200 Subject: [PATCH 01/43] skeleton for analysis --- .../Gui/ApplicationWindow.qml | 12 +- .../Gui/Pages/Analysis/Layout.qml | 68 +++ .../Analysis/MainContent/AnalysisView.qml | 570 ++++++++++++++++++ .../Gui/Pages/Analysis/SideBarAdvanced.qml | 34 ++ .../Analysis/SideBarAdvanced/Calculator.qml | 21 + .../Analysis/SideBarAdvanced/Minimizer.qml | 73 +++ .../Analysis/SideBarAdvanced/ParamNames.qml | 89 +++ .../Gui/Pages/Analysis/SideBarBasic.qml | 38 ++ .../Analysis/SideBarBasic/Experiments.qml | 119 ++++ .../Analysis/SideBarBasic/FitStatusDialog.qml | 52 ++ .../Pages/Analysis/SideBarBasic/Fittables.qml | 468 ++++++++++++++ .../Pages/Analysis/SideBarBasic/Fitting.qml | 36 ++ .../Gui/Pages/Analysis/SideBarText.qml | 27 + .../Gui/Pages/Experiment/Layout.qml | 2 +- 14 files changed, 1601 insertions(+), 8 deletions(-) create mode 100644 src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Layout.qml create mode 100644 src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/MainContent/AnalysisView.qml create mode 100644 src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/SideBarAdvanced.qml create mode 100644 src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/SideBarAdvanced/Calculator.qml create mode 100644 src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/SideBarAdvanced/Minimizer.qml create mode 100644 src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/SideBarAdvanced/ParamNames.qml create mode 100644 src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/SideBarBasic.qml create mode 100644 src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/SideBarBasic/Experiments.qml create mode 100644 src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/SideBarBasic/FitStatusDialog.qml create mode 100644 src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/SideBarBasic/Fittables.qml create mode 100644 src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/SideBarBasic/Fitting.qml create mode 100644 src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/SideBarText.qml diff --git a/src_qt6/EasyReflectometryApp/Gui/ApplicationWindow.qml b/src_qt6/EasyReflectometryApp/Gui/ApplicationWindow.qml index da90aea5..e9992552 100644 --- a/src_qt6/EasyReflectometryApp/Gui/ApplicationWindow.qml +++ b/src_qt6/EasyReflectometryApp/Gui/ApplicationWindow.qml @@ -104,26 +104,24 @@ EaComponents.ApplicationWindow { // Experiment tab EaElements.AppBarTabButton { id: experimentTabButton - enabled: false + enabled: true fontIcon: "microscope" text: qsTr("Experiment") ToolTip.text: qsTr("Experimental settings and data page") Component.onCompleted:Globals.References.applicationWindow.appBarCentralTabs.experimentButton = experimentTabButton }, -/* + // Analysis tab EaElements.AppBarTabButton { id: analysisTabButton - enabled: false //ExGlobals.Variables.samplePageEnabled && - //(ExGlobals.Constants.proxy.data.experimentSkipped || - // ExGlobals.Constants.proxy.data.experimentLoaded) + enabled: true fontIcon: "calculator" text: qsTr("Analysis") ToolTip.text: qsTr("Simulation and fitting page") Component.onCompleted: Globals.References.applicationWindow.appBarCentralTabs.analysisButton = analysisTabButton }, -*/ + // Summary page EaElements.AppBarTabButton { id: summaryButton @@ -148,7 +146,7 @@ EaComponents.ApplicationWindow { Loader { source: 'Pages/Project/Layout.qml' }, Loader { source: 'Pages/Sample/Layout.qml' }, Loader { source: 'Pages/Experiment/Layout.qml' }, -// Loader { source: 'Pages/Analysis/Layout.qml' }, + Loader { source: 'Pages/Analysis/Layout.qml' }, Loader { source: 'Pages/Report/Layout.qml' } ] diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Layout.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Layout.qml new file mode 100644 index 00000000..58736532 --- /dev/null +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Layout.qml @@ -0,0 +1,68 @@ +import QtQuick +import QtQuick.Controls +//import QtQuick.XmlListModel 2.15 + +import EasyApp.Gui.Style as EaStyle +import EasyApp.Gui.Globals as EaGlobals +import EasyApp.Gui.Elements as EaElements +import EasyApp.Gui.Components as EaComponents + +import Gui.Globals as Globals +//import Gui.Components as Components + + +EaComponents.ContentPage { + defaultInfo: Globals.Proxies.main.model.defined && + Globals.Proxies.main.experiment.defined ? + "" : + qsTr("No analysis done") + + mainView: EaComponents.MainContent { +/* tabs: [ + EaElements.TabButton { + text: Globals.Proxies.experimentMainParam('_sample', 'type').value === 'pd' ? + qsTr("Fitting") : + qsTr("I vs. sinθ/λ") + }, + EaElements.TabButton { text: qsTr("Imeas vs. Icalc") } + ] +*/ + items: [ + Loader { + source: `MainContent/AnalysisView.qml` + onStatusChanged: if (status === Loader.Ready) console.debug(`${source} loaded`) + } +// Loader { +// source: `MainContent/ScChartTab.qml` +// onStatusChanged: if (status === Loader.Ready) console.debug(`${source} loaded`) +// } + ] + } + + sideBar: EaComponents.SideBar { +/* tabs: [ + EaElements.TabButton { text: qsTr("Basic controls") }, + EaElements.TabButton { text: qsTr("Extra controls"); enabled: Globals.Proxies.main.analysis.defined }, + EaElements.TabButton { text: qsTr("Text mode"); enabled: false } + ] + + items: [ + Loader { source: 'SideBarBasic.qml' }, + Loader { source: 'SideBarAdvanced.qml' }, + Loader { source: 'SideBarText.qml' } + ] +*/ +// continueButton.enabled: Globals.Proxies.main.summary.isCreated + + continueButton.onClicked: { + console.debug(`Clicking '${continueButton.text}' button: ${this}`) + Globals.Vars.summaryPageEnabled = true + Globals.Refs.app.appbar.summaryButton.toggle() + } + + Component.onCompleted: Globals.Refs.app.analysisPage.continueButton = continueButton + } + + Component.onCompleted: console.debug(`Analysis page loaded: ${this}`) + Component.onDestruction: console.debug(`Analysis page destroyed: ${this}`) +} diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/MainContent/AnalysisView.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/MainContent/AnalysisView.qml new file mode 100644 index 00000000..42a45bd3 --- /dev/null +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/MainContent/AnalysisView.qml @@ -0,0 +1,570 @@ +// SPDX-FileCopyrightText: 2023 EasyDiffraction contributors +// SPDX-License-Identifier: BSD-3-Clause +// © 2023 Contributors to the EasyDiffraction project + +import QtQuick +import QtQuick.Controls +import QtCharts + +import EasyApp.Gui.Style as EaStyle +import EasyApp.Gui.Globals as EaGlobals +import EasyApp.Gui.Elements as EaElements +import EasyApp.Gui.Charts as EaCharts + +import Gui.Globals as Globals + + +Column { + id: container + + property alias measSerie: measSerie + property alias bkgSerie: bkgSerie + property alias calcSerie: calcSerie + property alias residSerie: residSerie + + property var phaseNames: { + if (typeof Globals.Proxies.main.experiment.dataBlocksNoMeas[ + Globals.Proxies.main.experiment.currentIndex].loops._pd_phase_block !== 'undefined') { + return Globals.Proxies.main.experiment.dataBlocksNoMeas[ + Globals.Proxies.main.experiment.currentIndex].loops._pd_phase_block.map( + phase => phase.id.value) + } else if (typeof Globals.Proxies.main.experiment.dataBlocksNoMeas[ + Globals.Proxies.main.experiment.currentIndex].loops._exptl_crystal !== 'undefined') { + return Globals.Proxies.main.experiment.dataBlocksNoMeas[ + Globals.Proxies.main.experiment.currentIndex].loops._exptl_crystal.map( + phase => phase.id.value) + } else { + //console.error('No phase names found') + return [] + } + } + + property string calcSerieColor: EaStyle.Colors.chartForegrounds[0] + + property int extraMargin: -12 + property real residualToMainChartHeightRatio: 0.3 + property real mainChartHeightCoeff: 1 - residualToMainChartHeightRatio + + property bool useOpenGL: Globals.Proxies.main.fitting.isFittingNow ? + true : + EaGlobals.Vars.useOpenGL //Globals.Proxies.main.plotting.useWebGL1d + + Column { + width: parent.width + height: parent.height - 3 * EaStyle.Sizes.fontPixelSize + 2 + + /////////////////////////////////////////// + // Main chart container: Imeas, Icalc, Ibkg + /////////////////////////////////////////// + + Item { + width: parent.width + height: parent.height * mainChartHeightCoeff - + braggChart.parent.height * 0.5 + + EaCharts.QtCharts1dBase { + id: mainChart + + property var experimentDataBlocksNoMeas: Globals.Proxies.main.experiment.dataBlocksNoMeas + onExperimentDataBlocksNoMeasChanged: { + if (Globals.Proxies.experimentMainParam('_sample', 'type').value === 'pd') { + if (Globals.Proxies.experimentMainParam('_diffrn_radiation', 'type').value === 'cwl') { + axisX.title = '2θ (degree)' + } else if (Globals.Proxies.experimentMainParam('_diffrn_radiation', 'type').value === 'tof') { + axisX.title = 'TOF (µs)' + } else { + axisX.title = '' + } + } else if (Globals.Proxies.experimentMainParam('_sample', 'type').value === 'sg') { + axisX.title = 'sinθ/λ (Å⁻¹)' + } else { + axisX.title = '' + } + } + + anchors.topMargin: EaStyle.Sizes.toolButtonHeight - EaStyle.Sizes.fontPixelSize - 1 + anchors.bottomMargin: -12 - EaStyle.Sizes.fontPixelSize + + useOpenGL: container.useOpenGL + + axisX.titleVisible: false + axisX.labelsVisible: false + axisX.min: Globals.Proxies.rangeValue('xMin') + axisX.max: Globals.Proxies.rangeValue('xMax') + axisX.minAfterReset: Globals.Proxies.rangeValue('xMin') + axisX.maxAfterReset: Globals.Proxies.rangeValue('xMax') + axisX.onRangeChanged: alignAllCharts() + + axisY.title: Globals.Proxies.experimentMainParam('_sample', 'type').value === 'pd' ? + "Imeas, Icalc, Ibkg" : + "Imeas, Icalc" + axisY.min: Globals.Proxies.rangeValue('yMin') + axisY.max: Globals.Proxies.rangeValue('yMax') + axisY.minAfterReset: Globals.Proxies.rangeValue('yMin') + axisY.maxAfterReset: Globals.Proxies.rangeValue('yMax') + axisY.onRangeChanged: adjustResidualChartRangeY() + + backgroundColor: "transparent" + plotAreaColor: "transparent" + + // Measured points + /* + ScatterSeries { + id: measSerie + + axisX: mainChart.axisX + axisY: mainChart.axisY + + useOpenGL: mainChart.useOpenGL + + markerSize: 5 + borderWidth: 1 + color: EaStyle.Colors.chartForegroundsExtra[2] + borderColor: this.color + } + */ + LineSeries { + id: measSerie + + axisX: mainChart.axisX + axisY: mainChart.axisY + + //useOpenGL: mainChart.useOpenGL + + color: EaStyle.Colors.chartForegroundsExtra[2] + width: 2 + + //style: Globals.Proxies.experimentMainParam('_sample', 'type').value === 'pd' ? + // Qt.SolidLine : + // Qt.NoPen + pointsVisible: true + + onHovered: (point, state) => showMainTooltip(mainChart, point, state) + } + + // Background curve + LineSeries { + id: bkgSerie + + axisX: mainChart.axisX + axisY: mainChart.axisY + + //useOpenGL: mainChart.useOpenGL + + color: EaStyle.Colors.chartForegrounds[1] + width: 1 + + onHovered: (point, state) => showMainTooltip(mainChart, point, state) + } + + // Calculated curve + LineSeries { + id: calcSerie + + axisX: mainChart.axisX + axisY: mainChart.axisY + + //useOpenGL: mainChart.useOpenGL + + color: calcSerieColor + width: 2 + + //style: Globals.Proxies.experimentMainParam('_sample', 'type').value === 'pd' ? + // Qt.SolidLine : + // Qt.NoPen + //pointsVisible: Globals.Proxies.experimentMainParam('_sample', 'type').value === 'pd' ? + // false : + // true + + onHovered: (point, state) => showMainTooltip(mainChart, point, state) + } + + // Tool buttons + Row { + id: toolButtons + + x: mainChart.plotArea.x + mainChart.plotArea.width - width + y: mainChart.plotArea.y - height - EaStyle.Sizes.fontPixelSize + + spacing: 0.25 * EaStyle.Sizes.fontPixelSize + + EaElements.TabButton { + checked: Globals.Vars.showLegendOnAnalysisPage + autoExclusive: false + height: EaStyle.Sizes.toolButtonHeight + width: EaStyle.Sizes.toolButtonHeight + borderColor: EaStyle.Colors.chartAxis + fontIcon: "align-left" + ToolTip.text: Globals.Vars.showLegendOnAnalysisPage ? + qsTr("Hide legend") : + qsTr("Show legend") + onClicked: Globals.Vars.showLegendOnAnalysisPage = checked + } + + EaElements.TabButton { + checked: mainChart.allowHover + autoExclusive: false + height: EaStyle.Sizes.toolButtonHeight + width: EaStyle.Sizes.toolButtonHeight + borderColor: EaStyle.Colors.chartAxis + fontIcon: "comment-alt" + ToolTip.text: qsTr("Show coordinates tooltip on hover") + onClicked: mainChart.allowHover = !mainChart.allowHover + } + + Item { height: 1; width: 0.5 * EaStyle.Sizes.fontPixelSize } // spacer + + EaElements.TabButton { + checked: !mainChart.allowZoom + autoExclusive: false + height: EaStyle.Sizes.toolButtonHeight + width: EaStyle.Sizes.toolButtonHeight + borderColor: EaStyle.Colors.chartAxis + fontIcon: "arrows-alt" + ToolTip.text: qsTr("Enable pan") + onClicked: mainChart.allowZoom = !mainChart.allowZoom + } + + EaElements.TabButton { + checked: mainChart.allowZoom + autoExclusive: false + height: EaStyle.Sizes.toolButtonHeight + width: EaStyle.Sizes.toolButtonHeight + borderColor: EaStyle.Colors.chartAxis + fontIcon: "expand" + ToolTip.text: qsTr("Enable box zoom") + onClicked: mainChart.allowZoom = !mainChart.allowZoom + } + + EaElements.TabButton { + checkable: false + height: EaStyle.Sizes.toolButtonHeight + width: EaStyle.Sizes.toolButtonHeight + borderColor: EaStyle.Colors.chartAxis + fontIcon: "backspace" + ToolTip.text: qsTr("Reset axes") + onClicked: mainChart.resetAxes() + } + + } + // Tool buttons + } + } + + ////////////////////////////////////// + // Bragg peaks chart container: Bragg + ////////////////////////////////////// + + Item { + z: -1 + width: parent.width + height: (0.5 + 1.5 * phaseNames.length) * EaStyle.Sizes.fontPixelSize + + + /////onHeightChanged: console.info(`================== ${height} - ${phaseNames.length}`) + //visible: false + + EaCharts.QtCharts1dBase { + id: braggChart + + anchors.topMargin: -12 - EaStyle.Sizes.fontPixelSize * 1.5 + anchors.bottomMargin: -12 - EaStyle.Sizes.fontPixelSize * 1.5 + + useOpenGL: container.useOpenGL + + axisX.min: mainChart.axisX.min + axisX.max: mainChart.axisX.max + axisX.titleVisible: false + axisX.labelsVisible: false + + axisY.min: -0.5 * phaseNames.length + axisY.max: 0.5 + axisY.titleVisible: false + axisY.labelsVisible: false + axisY.tickCount: 2 + + backgroundColor: "transparent" + plotAreaColor: "transparent" + + //onSeriesAdded: { console.error(series) } + + /* + ScatterSeries { + id: braggSerie + + axisX: braggChart.axisX + axisY: braggChart.axisY + + //useOpenGL: braggChart.useOpenGL + + brush: Globals.Proxies.main.plotting.verticalLine( + 1.5 * EaStyle.Sizes.fontPixelSize, + EaStyle.Colors.chartForegroundsExtra[0]) + borderWidth: 0.001 + borderColor: 'transparent' + + Component.onCompleted: console.error(this) + } + */ + } + } + + ////////////////////////////////////////// + // Residual chart container: Imeas - Icalc + ////////////////////////////////////////// + + Item { + width: parent.width + height: parent.height * residualToMainChartHeightRatio - + braggChart.parent.height * 0.5 + + EaCharts.QtCharts1dBase { + id: residualChart + + anchors.topMargin: -12 - EaStyle.Sizes.fontPixelSize + + useOpenGL: container.useOpenGL + + axisX.min: mainChart.axisX.min + axisX.max: mainChart.axisX.max + axisX.titleVisible: false + axisX.labelsVisible: false + + axisY.min: Globals.Proxies.main.plotting.chartRanges.yMin + axisY.max: Globals.Proxies.main.plotting.chartRanges.yMax + axisY.tickType: ValueAxis.TicksFixed + axisY.tickCount: 3 + axisY.title: 'Imeas - Icalc' + + backgroundColor: "transparent" + plotAreaColor: "transparent" + + LineSeries { + id: residSerie + + axisX: residualChart.axisX + axisY: residualChart.axisY + + //useOpenGL: residualChart.useOpenGL + + color: EaStyle.Colors.chartForegrounds[2] + + onHovered: (point, state) => showMainTooltip(residualChart, point, state) + } + } + } + } + + ///////////////////////// + // X-axis chart container + ///////////////////////// + + Item { + z: -1 + width: parent.width + height: container.height + parent: container.parent + + EaCharts.QtCharts1dBase { + id: xAxisChart + + axisX.title: mainChart.axisX.title + axisX.min: mainChart.axisX.min + axisX.max: mainChart.axisX.max + axisX.lineVisible: false + axisX.gridVisible: false + + axisY.titleVisible: false + axisY.labelsVisible: false + axisY.visible: false + + LineSeries { + axisX: xAxisChart.axisX + axisY: xAxisChart.axisY + + Component.onCompleted: initialChartsSetupTimer.start() + + Timer { + id: initialChartsSetupTimer + interval: 50 + onTriggered: { + alignAllCharts() + adjustResidualChartRangeY() + } + } + } + } + } + + ///////// + // Legend + ///////// + + Rectangle { + visible: Globals.Vars.showLegendOnAnalysisPage + parent: container.parent + + x: mainChart.plotArea.x + mainChart.plotArea.width - width - 12 - EaStyle.Sizes.fontPixelSize + y: mainChart.plotArea.y - 12 + EaStyle.Sizes.fontPixelSize + mainChart.anchors.topMargin + EaStyle.Sizes.fontPixelSize - 1 + width: childrenRect.width + height: childrenRect.height + + color: EaStyle.Colors.mainContentBackgroundHalfTransparent + border.color: EaStyle.Colors.chartGridLine + + Column { + id: legendColumn + + leftPadding: EaStyle.Sizes.fontPixelSize + rightPadding: EaStyle.Sizes.fontPixelSize + topPadding: EaStyle.Sizes.fontPixelSize * 0.5 + bottomPadding: EaStyle.Sizes.fontPixelSize * 0.5 + + EaElements.Label { + text: '━ Measured (Imeas)' + color: measSerie.color + } + EaElements.Label { + text: Globals.Proxies.experimentMainParam('_sample', 'type').value === 'pd' ? + '━ Total calculated (Icalc)' : + '━ Calculated (Icalc)' + color: calcSerie.color + } + EaElements.Label { + visible: Globals.Proxies.experimentMainParam('_sample', 'type').value === 'pd' + text: '─ Background (Ibkg)' + color: bkgSerie.color + } + EaElements.Label { + text: '━ Residual (Imeas - Icalc)' + color: residSerie.color + } + /* + EaElements.Label { + text: '│ Ibragg (Bragg peaks)' + color: EaStyle.Colors.chartForegroundsExtra[0] //braggSerie.color + } + */ + } + } + + /////////// + // ToolTips + /////////// + + EaElements.ToolTip { + id: dataToolTip + + arrowLength: 0 + textFormat: Text.RichText + } + + // Save references to chart series to be accessible from Python for updating data + Component.onCompleted: { + Globals.Refs.app.analysisPage.plotView = this + Globals.Proxies.main.plotting.setQtChartsSerieRef('analysisPage', + 'measSerie', + this.measSerie) + Globals.Proxies.main.plotting.setQtChartsSerieRef('analysisPage', + 'bkgSerie', + this.bkgSerie) + Globals.Proxies.main.plotting.setQtChartsSerieRef('analysisPage', + 'totalCalcSerie', + this.calcSerie) + Globals.Proxies.main.plotting.setQtChartsSerieRef('analysisPage', + 'residSerie', + this.residSerie) + //Globals.Proxies.main.plotting.setQtChartsSerieRef('analysisPage', + // 'braggSerie', + // this.braggSerie) + createBraggSeries() + + Globals.Proxies.main.analysis.defined = true + } + + // Logic + + function residualChartMeanY() { + return 0 + } + + function residualChartHalfRangeY() { + if (mainChart.plotArea.height === 0) { + return 0.5 + } + + const mainChartRangeY = mainChart.axisY.max - mainChart.axisY.min + const residualToMainChartHeightRatio = residualChart.plotArea.height / mainChart.plotArea.height + const residualChartRangeY = mainChartRangeY * residualToMainChartHeightRatio + return 0.5 * residualChartRangeY + } + + function adjustResidualChartRangeY() { + residualChart.axisY.min = residualChartMeanY() - residualChartHalfRangeY() + residualChart.axisY.max = residualChartMeanY() + residualChartHalfRangeY() + console.debug('Residual chart Y-range has been adjusted') + } + + function alignAllCharts() { + xAxisChart.plotArea.width -= mainChart.plotArea.x - xAxisChart.plotArea.x + xAxisChart.plotArea.x = mainChart.plotArea.x + residualChart.plotArea.width = xAxisChart.plotArea.width + residualChart.plotArea.x = mainChart.plotArea.x + braggChart.plotArea.width = xAxisChart.plotArea.width + braggChart.plotArea.x = mainChart.plotArea.x + mainChart.plotArea.width = xAxisChart.plotArea.width + console.debug('All charts have been aligned') + } + + function showMainTooltip(chart, point, state) { + if (!mainChart.allowHover) { + return + } + const pos = chart.mapToPosition(Qt.point(point.x, point.y)) + dataToolTip.x = pos.x + dataToolTip.y = pos.y + dataToolTip.text = `

x: ${point.x.toFixed(2)}y: ${point.y.toFixed(2)}

` + dataToolTip.parent = chart + dataToolTip.visible = state + } + + function createBraggSeries() { + for (const phaseIdx in phaseNames) { + const phaseName = phaseNames[phaseIdx] + const serie = braggChart.createSeries(ChartView.SeriesTypeScatter, + phaseName, + braggChart.axisX, + braggChart.axisY) + const markerSize = //serie.useOpenGL ? + //5 : // don't work here... :( + 1.5 * EaStyle.Sizes.fontPixelSize + serie.useOpenGL = braggChart.useOpenGL + //serie.useOpenGL = Globals.Proxies.main.fitting.isFittingNow + serie.brush = Globals.Proxies.main.plotting.verticalLine( + markerSize, + EaStyle.Colors.models[phaseIdx]) + serie.borderWidth = 0.001 + serie.borderColor = 'transparent' + //serie.markerShape = ScatterSeries.MarkerShapeRectangle + serie.markerSize = serie.useOpenGL ? + 0 : + markerSize + + Globals.Proxies.main.plotting.setQtChartsSerieRef('analysisPage', + 'braggSeries', + serie) + + const legendItem = Qt.createQmlObject('import EasyApp.Gui.Elements as EaElements; EaElements.Label {}', legendColumn) + const textFont = `'${EaStyle.Fonts.fontFamily}'` + const iconFont = `'${EaStyle.Fonts.iconsFamily}'` + const textColor = `'${EaStyle.Colors.models[phaseIdx]}'` + const iconColor = `'${EaStyle.Colors.models[phaseIdx]}'` + const textHtmlStart = `│  Bragg peaks` + const iconHtml = `layer-group` + const textHtmlEnd = `${phaseName}` + legendItem.text = `${textHtmlStart} ${iconHtml} ${textHtmlEnd}` + legendItem.textFormat = Text.RichText + } + } + +} diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/SideBarAdvanced.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/SideBarAdvanced.qml new file mode 100644 index 00000000..ab8dbbc4 --- /dev/null +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/SideBarAdvanced.qml @@ -0,0 +1,34 @@ +// SPDX-FileCopyrightText: 2023 EasyDiffraction contributors +// SPDX-License-Identifier: BSD-3-Clause +// © 2023 Contributors to the EasyDiffraction project + +import QtQuick + +import EasyApp.Gui.Elements as EaElements +import EasyApp.Gui.Components as EaComponents + + +EaComponents.SideBarColumn { + + EaElements.GroupBox { + title: qsTr("Parameter names") + icon: "paint-brush" + collapsed: false + + Loader { source: 'SideBarAdvanced/ParamNames.qml' } + } + + EaElements.GroupBox { + title: qsTr("Calculation engine") + icon: 'calculator' + + Loader { source: 'SideBarAdvanced/Calculator.qml' } + } + + EaElements.GroupBox { + title: qsTr("Minimization engine") + icon: 'level-down-alt' + + Loader { source: 'SideBarAdvanced/Minimizer.qml' } + } +} diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/SideBarAdvanced/Calculator.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/SideBarAdvanced/Calculator.qml new file mode 100644 index 00000000..0cb709d0 --- /dev/null +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/SideBarAdvanced/Calculator.qml @@ -0,0 +1,21 @@ +// SPDX-FileCopyrightText: 2023 EasyDiffraction contributors +// SPDX-License-Identifier: BSD-3-Clause +// © 2023 Contributors to the EasyDiffraction project + +import QtQuick +import QtQuick.Controls + +import EasyApp.Gui.Style as EaStyle +import EasyApp.Gui.Elements as EaElements + +import Gui.Globals as Globals + + +EaElements.GroupRow { + + EaElements.ComboBox { + width: EaStyle.Sizes.sideBarContentWidth + model: ['CrysPy'] + } + +} diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/SideBarAdvanced/Minimizer.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/SideBarAdvanced/Minimizer.qml new file mode 100644 index 00000000..3578b18c --- /dev/null +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/SideBarAdvanced/Minimizer.qml @@ -0,0 +1,73 @@ +// SPDX-FileCopyrightText: 2023 EasyDiffraction contributors +// SPDX-License-Identifier: BSD-3-Clause +// © 2023 Contributors to the EasyDiffraction project + +import QtQuick +import QtQuick.Controls + +import EasyApp.Gui.Style as EaStyle +import EasyApp.Gui.Elements as EaElements + +import Gui.Globals as Globals + + +EaElements.GroupRow { + property real columnWidth: (EaStyle.Sizes.sideBarContentWidth - EaStyle.Sizes.fontPixelSize) / 4 + + EaElements.ComboBox { + width: columnWidth + topInset: minimizerLabel.height + topPadding: topInset + padding + model: ['Lmfit'] + EaElements.Label { + id: minimizerLabel + text: qsTr("Minimizer") + color: EaStyle.Colors.themeForegroundMinor + } + } + + EaElements.TextField { + width: columnWidth + topInset: methodLabel.height + topPadding: topInset + padding + horizontalAlignment: TextInput.AlignLeft + onAccepted: focus = false + text: Globals.Proxies.main.fitting.minimizerMethod + onTextEdited: Globals.Proxies.main.fitting.minimizerMethod = text + EaElements.Label { + id: methodLabel + text: qsTr("Method") + color: EaStyle.Colors.themeForegroundMinor + } + } + + EaElements.TextField { + width: columnWidth + topInset: toleranceLabel.height + topPadding: topInset + padding + horizontalAlignment: TextInput.AlignLeft + onAccepted: focus = false + text: Globals.Proxies.main.fitting.minimizerTol + onTextEdited: Globals.Proxies.main.fitting.minimizerTol = text + EaElements.Label { + id: toleranceLabel + text: qsTr("Tolerance") + color: EaStyle.Colors.themeForegroundMinor + } + } + + EaElements.TextField { + width: columnWidth + topInset: maxIterLabel.height + topPadding: topInset + padding + horizontalAlignment: TextInput.AlignLeft + onAccepted: focus = false + text: Globals.Proxies.main.fitting.minimizerMaxIter + onTextEdited: Globals.Proxies.main.fitting.minimizerMaxIter = text + EaElements.Label { + id: maxIterLabel + text: qsTr("Max iterations") + color: EaStyle.Colors.themeForegroundMinor + } + } +} diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/SideBarAdvanced/ParamNames.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/SideBarAdvanced/ParamNames.qml new file mode 100644 index 00000000..e792add2 --- /dev/null +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/SideBarAdvanced/ParamNames.qml @@ -0,0 +1,89 @@ +// SPDX-FileCopyrightText: 2023 EasyDiffraction contributors +// SPDX-License-Identifier: BSD-3-Clause +// © 2023 Contributors to the EasyDiffraction project + +import QtQuick +import QtQuick.Controls + +import EasyApp.Gui.Globals as EaGlobals +import EasyApp.Gui.Style as EaStyle +import EasyApp.Gui.Elements as EaElements +import EasyApp.Gui.Components as EaComponents + +import Gui.Globals as Globals + + +EaComponents.TableView { + id: tableView + + readonly property var param: { + "blockType": "model", + "blockIcon": "layer-group", + "blockIdx": 0, + "blockName": "co2sio4", + "categoryIcon": "atom", + "category": "_atom_site", + "prettyCategory": "atom", + "rowIndex": 2, + "rowName": "Si", + "icon": "map-marker-alt", + "name": "_fract_x", + "prettyName": "fract x", + "shortPrettyName": "x" } + + showHeader: false + tallRows: true + maxRowCountShow: model.length + + /* + model: [ + { value: EaGlobals.Vars.ShortestWithIconsAndPrettyLabels, + text: qsTr('Shortest iconified name with pretty labels') }, + { value: EaGlobals.Vars.ReducedWithIconsAndPrettyLabels, + text: qsTr('Shorter iconified name with pretty labels') }, + { value: EaGlobals.Vars.FullWithIconsAndPrettyLabels, + text: qsTr('Full iconified name with pretty labels') }, + { value: EaGlobals.Vars.FullWithPrettyLabels, + text: qsTr('Full plain text name with pretty labels') }, + { value: EaGlobals.Vars.FullWithLabels, + text: qsTr('Full plain text name with labels') }, + { value: EaGlobals.Vars.FullWithIndices, + text: qsTr('Full plain text name with indices') } + ] + */ + + model: [ + { value: EaGlobals.Vars.ShortestWithIconsAndPrettyLabels, + text: qsTr('Iconified name with pretty labels') }, + { value: EaGlobals.Vars.PlainShortWithLabels, + text: qsTr('Short plain text name with labels') }, + { value: EaGlobals.Vars.PlainFullWithLabels, + text: qsTr('Full plain text name with labels') } + ] + + header: EaComponents.TableViewHeader { + + EaComponents.TableViewLabel { + width: EaStyle.Sizes.fontPixelSize * 2.5 + } + + EaComponents.TableViewLabel { + flexibleWidth: true + } + } + + delegate: EaComponents.TableViewDelegate { + mouseArea.onPressed: EaGlobals.Vars.paramNameFormat = currentIndex + + EaElements.RadioButton { + checked: index === EaGlobals.Vars.paramNameFormat + anchors.verticalCenter: parent.verticalCenter + } + + EaComponents.TableViewTwoRowsAdvancedLabel { + text: tableView.model[index].text + minorText: Globals.Proxies.paramName(param, tableView.model[index].value) + } + } + +} diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/SideBarBasic.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/SideBarBasic.qml new file mode 100644 index 00000000..3921548c --- /dev/null +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/SideBarBasic.qml @@ -0,0 +1,38 @@ +// SPDX-FileCopyrightText: 2023 EasyDiffraction contributors +// SPDX-License-Identifier: BSD-3-Clause +// © 2023 Contributors to the EasyDiffraction project + +import QtQuick + +import EasyApp.Gui.Style 1.0 as EaStyle +import EasyApp.Gui.Elements as EaElements +import EasyApp.Gui.Components as EaComponents + +import Gui.Globals as Globals + + +EaComponents.SideBarColumn { + + EaElements.GroupBox { + collapsible: false + last: true + + Loader { source: 'SideBarBasic/Experiments.qml' } + } + + EaElements.GroupBox { + //title: qsTr("Parameters") + collapsible: false + last: true + + Loader { source: 'SideBarBasic/Fittables.qml' } + } + + EaElements.GroupBox { + //title: qsTr("Fitting") + collapsible: false + + Loader { source: 'SideBarBasic/Fitting.qml' } + } + +} diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/SideBarBasic/Experiments.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/SideBarBasic/Experiments.qml new file mode 100644 index 00000000..991a74eb --- /dev/null +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/SideBarBasic/Experiments.qml @@ -0,0 +1,119 @@ +// SPDX-FileCopyrightText: 2023 EasyDiffraction contributors +// SPDX-License-Identifier: BSD-3-Clause +// © 2023 Contributors to the EasyDiffraction project + +import QtQuick +import QtQuick.Controls +import QtQuick.Dialogs + +import EasyApp.Gui.Globals as EaGlobals +import EasyApp.Gui.Style as EaStyle +import EasyApp.Gui.Elements as EaElements +import EasyApp.Gui.Components as EaComponents +import EasyApp.Gui.Logic as EaLogic + +import Gui.Globals as Globals + + +EaElements.ComboBox { + id: comboBox + + topInset: 0 + bottomInset: 0 + + width: EaStyle.Sizes.sideBarContentWidth + anchors.bottomMargin: EaStyle.Sizes.fontPixelSize + + textRole: "name" + + model: Globals.Proxies.main.experiment.dataBlocksNoMeas + currentIndex: Globals.Proxies.main.experiment.currentIndex + + onActivated: Globals.Proxies.main.experiment.currentIndex = currentIndex + + // ComboBox delegate (popup rows) + delegate: ItemDelegate { + id: itemDelegate + + width: parent.width + height: EaStyle.Sizes.tableRowHeight + + highlighted: comboBox.highlightedIndex === index + + // ComboBox delegate (popup rows) contentItem + contentItem: Item { + width: parent.width + height: parent.height + + Row { + height: parent.height + spacing: EaStyle.Sizes.tableColumnSpacing + + EaComponents.TableViewLabel { + text: index + 1 + color: EaStyle.Colors.themeForegroundMinor + } + + EaComponents.TableViewButton { + anchors.verticalCenter: parent.verticalCenter + fontIcon: "microscope" + ToolTip.text: qsTr("Measured pattern color") + backgroundColor: "transparent" + borderColor: "transparent" + iconColor: EaStyle.Colors.chartForegroundsExtra[2] + } + + EaComponents.TableViewParameter { + enabled: false + text: comboBox.model[index].name.value + } + } + } + // ComboBox delegate (popup rows) contentItem + + // ComboBox delegate (popup rows) background + background: Rectangle { + color: itemDelegate.highlighted ? + EaStyle.Colors.tableHighlight : + index % 2 ? + EaStyle.Colors.themeBackgroundHovered2 : + EaStyle.Colors.themeBackgroundHovered1 + } + // ComboBox delegate (popup rows) background + + } + // ComboBox delegate (popup rows) + + // ComboBox (selected item) contentItem + contentItem: Item { + width: parent.width + height: parent.height + + Row { + height: parent.height + spacing: EaStyle.Sizes.tableColumnSpacing + + EaComponents.TableViewLabel { + text: currentIndex + 1 + color: EaStyle.Colors.themeForegroundMinor + } + + EaComponents.TableViewButton { + anchors.verticalCenter: parent.verticalCenter + fontIcon: "microscope" + ToolTip.text: qsTr("Measured pattern color") + backgroundColor: "transparent" + borderColor: "transparent" + iconColor: EaStyle.Colors.chartForegroundsExtra[2] + } + + EaComponents.TableViewParameter { + enabled: false + text: typeof comboBox.model[currentIndex] !== 'undefined' ? + comboBox.model[currentIndex].name.value : + '' + } + } + } + // ComboBox (selected item) contentItem +} diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/SideBarBasic/FitStatusDialog.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/SideBarBasic/FitStatusDialog.qml new file mode 100644 index 00000000..62d4707b --- /dev/null +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/SideBarBasic/FitStatusDialog.qml @@ -0,0 +1,52 @@ +// SPDX-FileCopyrightText: 2023 EasyDiffraction contributors +// SPDX-License-Identifier: BSD-3-Clause +// © 2023 Contributors to the EasyDiffraction project + +import QtQuick +import QtQuick.Controls + +import EasyApp.Gui.Globals as EaGlobals +import EasyApp.Gui.Style as EaStyle +import EasyApp.Gui.Elements as EaElements + +import Gui.Globals as Globals + + +EaElements.Dialog { + id: dialog + + visible: Globals.Proxies.main.status.fitStatus + title: qsTr("Fit status") + standardButtons: Dialog.Ok + + Component.onCompleted: Globals.Refs.app.analysisPage.fitStatusDialogOkButton = okButtonRef() + + EaElements.Label { + text: { + if (Globals.Proxies.main.status.fitStatus === 'Success') { + return 'Optimization finished successfully.' + } else if (Globals.Proxies.main.status.fitStatus === 'Failure') { + return 'Optimization failed.' + } else if (Globals.Proxies.main.status.fitStatus === 'Aborted') { + return 'Optimization aborted.' + } else if (Globals.Proxies.main.status.fitStatus === 'No free params') { + return 'Nothing to vary. Allow some parameters to be free.' + } else { + return '' + } + } + } + + // Logic + + function okButtonRef() { + const buttons = dialog.footer.contentModel.children + for (let i in buttons) { + const button = buttons[i] + if (button.text === 'OK') { + return button + } + } + return null + } +} diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/SideBarBasic/Fittables.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/SideBarBasic/Fittables.qml new file mode 100644 index 00000000..05ec6724 --- /dev/null +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/SideBarBasic/Fittables.qml @@ -0,0 +1,468 @@ +// SPDX-FileCopyrightText: 2023 EasyDiffraction contributors +// SPDX-License-Identifier: BSD-3-Clause +// © 2023 Contributors to the EasyDiffraction project + +import QtQuick +import QtQuick.Controls +import QtCharts + +import EasyApp.Gui.Logic as EaLogic +import EasyApp.Gui.Globals as EaGlobals +import EasyApp.Gui.Style as EaStyle +import EasyApp.Gui.Elements as EaElements +import EasyApp.Gui.Components as EaComponents + +import Gui.Globals as Globals + + +Column { + property int selectedParamIndex: -1 + onSelectedParamIndexChanged: { + updateSliderLimits() + updateSliderValue() + } + + property string selectedColor: EaStyle.Colors.themeForegroundHovered + + spacing: EaStyle.Sizes.fontPixelSize + + // Filter parameters widget + Row { + spacing: EaStyle.Sizes.fontPixelSize * 0.5 + + // Filter criteria + EaElements.TextField { + id: filterCriteriaField + + width: (EaStyle.Sizes.sideBarContentWidth - EaStyle.Sizes.fontPixelSize) / 3 + + placeholderText: qsTr("Filter criteria") + + onTextChanged: { + nameFilterSelector.currentIndex = nameFilterSelector.indexOfValue(text) + Globals.Proxies.main.fittables.nameFilterCriteria = text + } + } + // Filter criteria + + // Filter by name + EaElements.ComboBox { + id: nameFilterSelector + + topInset: 0 + bottomInset: 0 + + width: (EaStyle.Sizes.sideBarContentWidth - EaStyle.Sizes.fontPixelSize) / 3 + + valueRole: "value" + textRole: "text" + + displayText: currentIndex === -1 ? + qsTr("Filter by name") : + currentText.replace(' ◦ ', '') + + model: [ + { value: "", text: `All names (${Globals.Proxies.main.fittables.modelParamsCount + Globals.Proxies.main.fittables.experimentParamsCount})` }, + { value: "model", text: `layer-group Model (${Globals.Proxies.main.fittables.modelParamsCount})` }, + { value: "cell", text: `cube Unit cell` }, + { value: "atom_site", text: `atom Atom sites` }, + { value: "fract", text: `map-marker-alt Atomic coordinates` }, + { value: "occupancy", text: `fill Atomic occupancies` }, + { value: "B_iso", text: `arrows-alt Atomic displacement` }, + { value: "experiment", text: `microscope Experiment (${Globals.Proxies.main.fittables.experimentParamsCount})` }, + { value: "resolution", text: `shapes Peak shape` }, + { value: "asymmetry", text: `balance-scale-left Peak asymmetry` }, + { value: "background", text: `wave-square Background` } + ] + + onActivated: filterCriteriaField.text = currentValue + } + // Filter by name + + // Filter by variability + EaElements.ComboBox { + id: variabilityFilterSelector + + property int lastIndex: -1 + + topInset: 0 + bottomInset: 0 + + width: (EaStyle.Sizes.sideBarContentWidth - EaStyle.Sizes.fontPixelSize) / 3 + + displayText: currentIndex === -1 ? qsTr("Filter by variability") : currentText + + valueRole: "value" + textRole: "text" + + model: [ + { value: 'all', text: `All parameters (${Globals.Proxies.main.fittables.freeParamsCount + + Globals.Proxies.main.fittables.fixedParamsCount})` }, + { value: 'free', text: `Free parameters (${Globals.Proxies.main.fittables.freeParamsCount})` }, + { value: 'fixed', text: `Fixed parameters (${Globals.Proxies.main.fittables.fixedParamsCount})` } + ] + onModelChanged: currentIndex = lastIndex + + onActivated: { + lastIndex = currentIndex + Globals.Proxies.main.fittables.variabilityFilterCriteria = currentValue + } + } + // Filter by variability + + } + // Filter parameters widget + + // Table + EaComponents.TableView { + id: tableView + + property var currentValueTextInput: null + + defaultInfoText: qsTr("No parameters found") + + maxRowCountShow: 7 + + Math.trunc((applicationWindow.height - EaStyle.Sizes.appWindowMinimumHeight) / + EaStyle.Sizes.tableRowHeight) + // Table model + // We only use the length of the model object defined in backend logic and + // directly access that model in every row using the TableView index property. + model: Globals.Proxies.main_fittables_data.length + // Table model + + Component.onCompleted: selectedParamIndex = 0 + + // Header row + header: EaComponents.TableViewHeader { + EaComponents.TableViewLabel { + width: EaStyle.Sizes.fontPixelSize * 2.5 + //text: qsTr("No.") + } + + EaComponents.TableViewLabel { + flexibleWidth: true + horizontalAlignment: Text.AlignLeft + color: EaStyle.Colors.themeForegroundMinor + text: qsTr("name") + } + + EaComponents.TableViewLabel { + id: valueLabel + width: EaStyle.Sizes.fontPixelSize * 4.5 + horizontalAlignment: Text.AlignRight + color: EaStyle.Colors.themeForegroundMinor + text: qsTr("value") + } + + EaComponents.TableViewLabel { + width: EaStyle.Sizes.fontPixelSize * 2.0 + horizontalAlignment: Text.AlignLeft + //text: qsTr("units") + } + + EaComponents.TableViewLabel { + width: valueLabel.width + horizontalAlignment: Text.AlignRight + color: EaStyle.Colors.themeForegroundMinor + text: qsTr("error") + } + + EaComponents.TableViewLabel { + width: valueLabel.width + horizontalAlignment: Text.AlignRight + color: EaStyle.Colors.themeForegroundMinor + text: qsTr("min") + } + + EaComponents.TableViewLabel { + width: valueLabel.width + horizontalAlignment: Text.AlignRight + color: EaStyle.Colors.themeForegroundMinor + text: qsTr("max") + } + + EaComponents.TableViewLabel { + width: EaStyle.Sizes.fontPixelSize * 3.0 + color: EaStyle.Colors.themeForegroundMinor + text: qsTr("vary") + } + } + // Header row + + // Table content row + delegate: EaComponents.TableViewDelegate { + enabled: !Globals.Proxies.main.fitting.isFittingNow + + property bool isCurrentItem: ListView.isCurrentItem + property var item: Globals.Proxies.main_fittables_data[index] + + mouseArea.onPressed: selectedParamIndex = tableView.currentIndex + + onIsCurrentItemChanged: { + if (tableView.currentValueTextInput != valueColumn) { + tableView.currentValueTextInput = valueColumn + } + } + + EaComponents.TableViewLabel { + text: index + 1 + color: EaStyle.Colors.themeForegroundMinor + } + + EaComponents.TableViewLabel { + width: EaStyle.Sizes.fontPixelSize * 5 + text: Globals.Proxies.paramName(item, EaGlobals.Vars.paramNameFormat) + textFormat: EaGlobals.Vars.paramNameFormat === EaGlobals.Vars.PlainShortWithLabels || + EaGlobals.Vars.paramNameFormat === EaGlobals.Vars.PlainFullWithLabels ? + Text.PlainText : + Text.RichText + //clip: true + elide: Text.ElideMiddle // NEED FIX: Doesn't work with textFormat: Text.RichText + ToolTip.text: textFormat === Text.PlainText ? text : '' + } + + EaComponents.TableViewParameter { + id: valueColumn + selected: //index === tableView.currentIndex || + index === selectedParamIndex + fit: item.fit + text: item.error === 0 ? + EaLogic.Utils.toDefaultPrecision(item.value) : + Globals.Proxies.main.backendHelpers.toStdDevSmalestPrecision(item.value, item.error).value + onEditingFinished: { + focus = false + console.debug('') + console.debug("*** Editing (manual) 'value' field of fittable on Analysis page ***") + Globals.Proxies.main.fittables.editSilently(item.blockType, + item.blockIdx, + item.category, + item.rowIndex ?? -1, + item.name, + 'value', + text) + updateSliderLimits() + slider.value = Globals.Proxies.main_fittables_data[selectedParamIndex].value + + } + } + + EaComponents.TableViewLabel { + text: item.units + color: EaStyle.Colors.themeForegroundMinor + } + + EaComponents.TableViewLabel { + elide: Text.ElideNone + text: item.error === 0 ? + '' : + Globals.Proxies.main.backendHelpers.toStdDevSmalestPrecision(item.value, item.error).std_dev + } + + EaComponents.TableViewParameter { + minored: true + text: EaLogic.Utils.toDefaultPrecision(item.min).replace('Infinity', 'inf') + onEditingFinished: { + focus = false + console.debug('') + console.debug("*** Editing 'min' field of fittable on Analysis page ***") + const value = (text === '' ? '-inf' : text) + Globals.Proxies.main.fittables.editSilently(item.blockType, + item.blockIdx, + item.category, + item.rowIndex ?? -1, + item.name, + 'min', + value) + } + } + + EaComponents.TableViewParameter { + minored: true + text: EaLogic.Utils.toDefaultPrecision(item.max).replace('Infinity', 'inf') + onEditingFinished: { + focus = false + console.debug('') + console.debug("*** Editing 'max' field of fittable on Analysis page ***") + const value = (text === '' ? 'inf' : text) + Globals.Proxies.main.fittables.editSilently(item.blockType, + item.blockIdx, + item.category, + item.rowIndex ?? -1, + item.name, + 'max', + value) + } + } + + EaComponents.TableViewCheckBox { + id: fitColumn + enabled: Globals.Proxies.main.experiment.defined + checked: item.fit + onToggled: { + console.debug('') + console.debug("*** Editing 'fit' field of fittable on Analysis page ***") + Globals.Proxies.main.fittables.editSilently(item.blockType, + item.blockIdx, + item.category, + item.rowIndex ?? -1, + item.name, + 'fit', + checked) + } + } + } + // Table content row + } + // Table + + // Parameter change slider + Row { + visible: Globals.Proxies.main_fittables_data.length + + spacing: EaStyle.Sizes.fontPixelSize + + EaElements.TextField { + readOnly: true + width: EaStyle.Sizes.fontPixelSize * 6 + //text: EaLogic.Utils.toDefaultPrecision(slider.from) + //text: EaLogic.Utils.toErrSinglePrecision(slider.from, Globals.Proxies.main_fittables_data[selectedParamIndex].error) + text: { + const value = Globals.Proxies.main_fittables_data[selectedParamIndex].value + const error = Globals.Proxies.main_fittables_data[selectedParamIndex].error + //return EaLogic.Utils.toErrSinglePrecision(value, error).length <= 8 ? + // EaLogic.Utils.toErrSinglePrecision(slider.from, error) : + // EaLogic.Utils.toDefaultPrecision(slider.from) + return error === 0 ? + EaLogic.Utils.toDefaultPrecision(slider.from) : + Globals.Proxies.main.backendHelpers.toStdDevSmalestPrecision(slider.from, error).value + } + } + + EaElements.Slider { + id: slider + + enabled: !Globals.Proxies.main.fitting.isFittingNow + width: tableView.width - EaStyle.Sizes.fontPixelSize * 14 + + stepSize: (to - from) / 20 + snapMode: Slider.SnapAlways + + toolTipText: { + const value = Globals.Proxies.main_fittables_data[selectedParamIndex].value + const error = Globals.Proxies.main_fittables_data[selectedParamIndex].error + //return EaLogic.Utils.toErrSinglePrecision(value, error).length <= 8 ? + // EaLogic.Utils.toErrSinglePrecision(value, error) : + // EaLogic.Utils.toDefaultPrecision(value) + return error === 0 ? + EaLogic.Utils.toDefaultPrecision(value) : + Globals.Proxies.main.backendHelpers.toStdDevSmalestPrecision(value, error).value + } + + onMoved: { + console.debug('') + console.debug("*** Editing (slider) 'value' field of fittable on Analysis page ***") + const item = Globals.Proxies.main_fittables_data[selectedParamIndex] + Globals.Proxies.main.fittables.editSilently(item.blockType, + item.blockIdx, + item.category, + item.rowIndex ?? -1, + item.name, + 'value', + value.toString()) + } + + onPressedChanged: { + if (!pressed) { + updateSliderLimits() + } + } + } + + EaElements.TextField { + readOnly: true + width: EaStyle.Sizes.fontPixelSize * 6 + //text: EaLogic.Utils.toDefaultPrecision(slider.to) + //text: EaLogic.Utils.toErrSinglePrecision(slider.to, Globals.Proxies.main_fittables_data[selectedParamIndex].error) + text: { + const value = Globals.Proxies.main_fittables_data[selectedParamIndex].value + const error = Globals.Proxies.main_fittables_data[selectedParamIndex].error + //return EaLogic.Utils.toErrSinglePrecision(value, error).length <= 8 ? + // EaLogic.Utils.toErrSinglePrecision(slider.to, error) : + // EaLogic.Utils.toDefaultPrecision(slider.to) + return error === 0 ? + EaLogic.Utils.toDefaultPrecision(slider.to) : + Globals.Proxies.main.backendHelpers.toStdDevSmalestPrecision(slider.to, error).value + } + } + + } + // Slider + + // Move delay timer + + /* + Timer { + id: moveDelayTimer + interval: 0 //50 + onTriggered: { + if (tableView.currentValueTextInput.text !== slider.value.toFixed(4)) { + //enableOpenGL() + tableView.currentValueTextInput.text = slider.value.toFixed(4) + tableView.currentValueTextInput.editingFinished() + //disableOpenGL() + } + } + } + */ + + // Use OpenGL on slider move only + + Timer { + id: disableOpenGLTimer + interval: 1500 + onTriggered: disableOpenGLFromTimer() + } + + // Logic + + function updateSliderValue() { + const value = Globals.Proxies.main_fittables_data[selectedParamIndex].value + slider.value = EaLogic.Utils.toDefaultPrecision(value) + } + + function updateSliderLimits() { + const from = Globals.Proxies.main_fittables_data[selectedParamIndex].from + const to = Globals.Proxies.main_fittables_data[selectedParamIndex].to + slider.from = EaLogic.Utils.toDefaultPrecision(from) + slider.to = EaLogic.Utils.toDefaultPrecision(to) + } + + function enableOpenGL() { + if (Globals.Proxies.main.plotting.currentLib1d === 'QtCharts') { + Globals.Refs.app.experimentPage.plotView.useOpenGL = true + //Globals.Refs.app.modelPage.plotView.useOpenGL = true + Globals.Refs.app.analysisPage.plotView.useAnimation = false + Globals.Refs.app.analysisPage.plotView.useOpenGL = true + } + } + + function disableOpenGL() { + if (Globals.Proxies.main.plotting.currentLib1d === 'QtCharts') { + ////Globals.Proxies.main.plotting.chartRefs.QtCharts.analysisPage.totalCalcSerie.pointsReplaced() + disableOpenGLTimer.restart() + } + } + + function disableOpenGLFromTimer() { + Globals.Refs.app.experimentPage.plotView.useOpenGL = false + //Globals.Refs.app.modelPage.plotView.useOpenGL = false + ////Globals.Proxies.main.plotting.chartRefs.QtCharts.analysisPage.totalCalcSerie.pointsReplaced() + ///console.error(Globals.Proxies.main.plotting.chartRefs.QtCharts.analysisPage.totalCalcSerie) + Globals.Refs.app.analysisPage.plotView.useAnimation = true + Globals.Refs.app.analysisPage.plotView.useOpenGL = false + } + + + + +} diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/SideBarBasic/Fitting.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/SideBarBasic/Fitting.qml new file mode 100644 index 00000000..665c2e6d --- /dev/null +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/SideBarBasic/Fitting.qml @@ -0,0 +1,36 @@ +// SPDX-FileCopyrightText: 2023 EasyDiffraction contributors +// SPDX-License-Identifier: BSD-3-Clause +// © 2023 Contributors to the EasyDiffraction project + +import QtQuick +import QtQuick.Controls + +import EasyApp.Gui.Globals as EaGlobals +import EasyApp.Gui.Style as EaStyle +import EasyApp.Gui.Elements as EaElements +import EasyApp.Gui.Components as EaComponents + +import Gui.Globals as Globals + + +Column { + spacing: EaStyle.Sizes.fontPixelSize + + EaElements.SideBarButton { + enabled: Globals.Proxies.main.experiment.defined + wide: true + + fontIcon: Globals.Proxies.main.fitting.isFittingNow ? 'stop-circle' : 'play-circle' + text: Globals.Proxies.main.fitting.isFittingNow ? qsTr('Cancel fitting') : qsTr('Start fitting') + + onClicked: { + console.debug(`Clicking '${text}' button: ${this}`) + Globals.Proxies.main.fitting.startStop() + } + + Component.onCompleted: Globals.Refs.app.analysisPage.startFittingButton = this + + Loader { source: "FitStatusDialog.qml" } + } + +} diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/SideBarText.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/SideBarText.qml new file mode 100644 index 00000000..fdc19bf6 --- /dev/null +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/SideBarText.qml @@ -0,0 +1,27 @@ +// SPDX-FileCopyrightText: 2023 EasyDiffraction contributors +// SPDX-License-Identifier: BSD-3-Clause +// © 2023 Contributors to the EasyDiffraction project + +import QtQuick +import QtQuick.Controls + +import EasyApp.Gui.Style as EaStyle +import EasyApp.Gui.Elements as EaElements +import EasyApp.Gui.Components as EaComponents + +import Gui.Globals as Globals + + +ScrollView { + anchors.fill: parent + + EaElements.TextArea { + text: Globals.Proxies.main.fittables.dataJson + + //textFormat: TextEdit.RichText + font.family: EaStyle.Fonts.monoFontFamily + backgroundOpacity: 0 + readOnly: true + } +} + diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Experiment/Layout.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Experiment/Layout.qml index 67aed043..f56ede8a 100644 --- a/src_qt6/EasyReflectometryApp/Gui/Pages/Experiment/Layout.qml +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Experiment/Layout.qml @@ -35,7 +35,7 @@ EaComponents.ContentPage { continueButton.onClicked: { console.debug(`Clicking '${continueButton.text}' button ::: ${this}`) Globals.References.applicationWindow.appBarCentralTabs.analysisButton.enabled = true - Globals.References.applicationWindow.appBarCentralTabs.anslysisButton.toggle() + Globals.References.applicationWindow.appBarCentralTabs.analysisButton.toggle() } } From 6844a12c547837972926fa33280753a309ca3fb4 Mon Sep 17 00:00:00 2001 From: Andreas Pedersen Date: Thu, 24 Oct 2024 14:04:31 +0200 Subject: [PATCH 02/43] report to summary --- .../EasyReflectometryApp/Gui/ApplicationWindow.qml | 6 +----- .../Gui/Pages/Analysis/Layout.qml | 14 +++++++------- .../Gui/Pages/{Report => Summary}/Layout.qml | 0 .../{Report => Summary}/MainContent/Summary.qml | 0 .../Sidebar/Basic/Groups/Export.qml | 0 .../{Report => Summary}/Sidebar/Basic/Layout.qml | 0 .../Sidebar/Extra/Groups/Empty.qml | 0 .../{Report => Summary}/Sidebar/Extra/Layout.qml | 0 8 files changed, 8 insertions(+), 12 deletions(-) rename src_qt6/EasyReflectometryApp/Gui/Pages/{Report => Summary}/Layout.qml (100%) rename src_qt6/EasyReflectometryApp/Gui/Pages/{Report => Summary}/MainContent/Summary.qml (100%) rename src_qt6/EasyReflectometryApp/Gui/Pages/{Report => Summary}/Sidebar/Basic/Groups/Export.qml (100%) rename src_qt6/EasyReflectometryApp/Gui/Pages/{Report => Summary}/Sidebar/Basic/Layout.qml (100%) rename src_qt6/EasyReflectometryApp/Gui/Pages/{Report => Summary}/Sidebar/Extra/Groups/Empty.qml (100%) rename src_qt6/EasyReflectometryApp/Gui/Pages/{Report => Summary}/Sidebar/Extra/Layout.qml (100%) diff --git a/src_qt6/EasyReflectometryApp/Gui/ApplicationWindow.qml b/src_qt6/EasyReflectometryApp/Gui/ApplicationWindow.qml index e9992552..dc5e074e 100644 --- a/src_qt6/EasyReflectometryApp/Gui/ApplicationWindow.qml +++ b/src_qt6/EasyReflectometryApp/Gui/ApplicationWindow.qml @@ -73,7 +73,6 @@ EaComponents.ApplicationWindow { Globals.References.applicationWindow.appBarCentralTabs.homeButton = homeButton } }, - // Home page // Project page EaElements.AppBarTabButton { @@ -86,7 +85,6 @@ EaComponents.ApplicationWindow { Globals.References.applicationWindow.appBarCentralTabs.projectButton = projectButton } }, - // Project page // Sample page EaElements.AppBarTabButton { @@ -99,7 +97,6 @@ EaComponents.ApplicationWindow { Globals.References.applicationWindow.appBarCentralTabs.sampleButton = sampleButton } }, - // Sample page // Experiment tab EaElements.AppBarTabButton { @@ -133,7 +130,6 @@ EaComponents.ApplicationWindow { Globals.References.applicationWindow.appBarCentralTabs.summaryButton = summaryButton } } - // Summary page ] ////////////////////////////////// @@ -147,7 +143,7 @@ EaComponents.ApplicationWindow { Loader { source: 'Pages/Sample/Layout.qml' }, Loader { source: 'Pages/Experiment/Layout.qml' }, Loader { source: 'Pages/Analysis/Layout.qml' }, - Loader { source: 'Pages/Report/Layout.qml' } + Loader { source: 'Pages/Summary/Layout.qml' } ] ///////////// diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Layout.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Layout.qml index 58736532..40ac8e38 100644 --- a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Layout.qml +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Layout.qml @@ -12,10 +12,10 @@ import Gui.Globals as Globals EaComponents.ContentPage { - defaultInfo: Globals.Proxies.main.model.defined && - Globals.Proxies.main.experiment.defined ? - "" : - qsTr("No analysis done") +// defaultInfo: Globals.Proxies.main.model.defined && +// Globals.Proxies.main.experiment.defined ? +// "" : +// qsTr("No analysis done") mainView: EaComponents.MainContent { /* tabs: [ @@ -56,11 +56,11 @@ EaComponents.ContentPage { continueButton.onClicked: { console.debug(`Clicking '${continueButton.text}' button: ${this}`) - Globals.Vars.summaryPageEnabled = true - Globals.Refs.app.appbar.summaryButton.toggle() + Globals.References.applicationWindow.appBarCentralTabs.summaryButton.enabled = true + Globals.References.applicationWindow.appBarCentralTabs.summaryButton.toggle() } - Component.onCompleted: Globals.Refs.app.analysisPage.continueButton = continueButton +// Component.onCompleted: Globals.Refs.app.analysisPage.continueButton = continueButton } Component.onCompleted: console.debug(`Analysis page loaded: ${this}`) diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Report/Layout.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Summary/Layout.qml similarity index 100% rename from src_qt6/EasyReflectometryApp/Gui/Pages/Report/Layout.qml rename to src_qt6/EasyReflectometryApp/Gui/Pages/Summary/Layout.qml diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Report/MainContent/Summary.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Summary/MainContent/Summary.qml similarity index 100% rename from src_qt6/EasyReflectometryApp/Gui/Pages/Report/MainContent/Summary.qml rename to src_qt6/EasyReflectometryApp/Gui/Pages/Summary/MainContent/Summary.qml diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Report/Sidebar/Basic/Groups/Export.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Summary/Sidebar/Basic/Groups/Export.qml similarity index 100% rename from src_qt6/EasyReflectometryApp/Gui/Pages/Report/Sidebar/Basic/Groups/Export.qml rename to src_qt6/EasyReflectometryApp/Gui/Pages/Summary/Sidebar/Basic/Groups/Export.qml diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Report/Sidebar/Basic/Layout.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Summary/Sidebar/Basic/Layout.qml similarity index 100% rename from src_qt6/EasyReflectometryApp/Gui/Pages/Report/Sidebar/Basic/Layout.qml rename to src_qt6/EasyReflectometryApp/Gui/Pages/Summary/Sidebar/Basic/Layout.qml diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Report/Sidebar/Extra/Groups/Empty.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Summary/Sidebar/Extra/Groups/Empty.qml similarity index 100% rename from src_qt6/EasyReflectometryApp/Gui/Pages/Report/Sidebar/Extra/Groups/Empty.qml rename to src_qt6/EasyReflectometryApp/Gui/Pages/Summary/Sidebar/Extra/Groups/Empty.qml diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Report/Sidebar/Extra/Layout.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Summary/Sidebar/Extra/Layout.qml similarity index 100% rename from src_qt6/EasyReflectometryApp/Gui/Pages/Report/Sidebar/Extra/Layout.qml rename to src_qt6/EasyReflectometryApp/Gui/Pages/Summary/Sidebar/Extra/Layout.qml From 48e39b410ee25e31b250758205c26d5840895ca4 Mon Sep 17 00:00:00 2001 From: Andreas Pedersen Date: Thu, 24 Oct 2024 14:30:03 +0200 Subject: [PATCH 03/43] moving files --- .../Gui/Pages/Analysis/Layout.qml | 12 ++++----- .../Gui/Pages/Analysis/SideBarText.qml | 27 ------------------- .../Advanced}/Calculator.qml | 0 .../Advanced/Layout.qml} | 0 .../Advanced}/Minimizer.qml | 0 .../Advanced}/ParamNames.qml | 0 .../Basic}/Experiments.qml | 0 .../Basic}/FitStatusDialog.qml | 0 .../Basic}/Fittables.qml | 0 .../Basic}/Fitting.qml | 0 .../Basic/Layout.qml} | 6 ++--- 11 files changed, 8 insertions(+), 37 deletions(-) delete mode 100644 src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/SideBarText.qml rename src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/{SideBarAdvanced => Sidebar/Advanced}/Calculator.qml (100%) rename src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/{SideBarAdvanced.qml => Sidebar/Advanced/Layout.qml} (100%) rename src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/{SideBarAdvanced => Sidebar/Advanced}/Minimizer.qml (100%) rename src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/{SideBarAdvanced => Sidebar/Advanced}/ParamNames.qml (100%) rename src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/{SideBarBasic => Sidebar/Basic}/Experiments.qml (100%) rename src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/{SideBarBasic => Sidebar/Basic}/FitStatusDialog.qml (100%) rename src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/{SideBarBasic => Sidebar/Basic}/Fittables.qml (100%) rename src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/{SideBarBasic => Sidebar/Basic}/Fitting.qml (100%) rename src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/{SideBarBasic.qml => Sidebar/Basic/Layout.qml} (81%) diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Layout.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Layout.qml index 40ac8e38..e1adec3e 100644 --- a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Layout.qml +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Layout.qml @@ -40,18 +40,16 @@ EaComponents.ContentPage { } sideBar: EaComponents.SideBar { -/* tabs: [ + tabs: [ EaElements.TabButton { text: qsTr("Basic controls") }, - EaElements.TabButton { text: qsTr("Extra controls"); enabled: Globals.Proxies.main.analysis.defined }, - EaElements.TabButton { text: qsTr("Text mode"); enabled: false } + EaElements.TabButton { text: qsTr("Extra controls") } //; enabled: Globals.Proxies.main.analysis.defined } ] items: [ - Loader { source: 'SideBarBasic.qml' }, - Loader { source: 'SideBarAdvanced.qml' }, - Loader { source: 'SideBarText.qml' } + Loader { source: 'Sidebar/Basic/Layout.qml' }, + Loader { source: 'Sidebar/Advanced/Layout.qml' } ] -*/ + // continueButton.enabled: Globals.Proxies.main.summary.isCreated continueButton.onClicked: { diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/SideBarText.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/SideBarText.qml deleted file mode 100644 index fdc19bf6..00000000 --- a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/SideBarText.qml +++ /dev/null @@ -1,27 +0,0 @@ -// SPDX-FileCopyrightText: 2023 EasyDiffraction contributors -// SPDX-License-Identifier: BSD-3-Clause -// © 2023 Contributors to the EasyDiffraction project - -import QtQuick -import QtQuick.Controls - -import EasyApp.Gui.Style as EaStyle -import EasyApp.Gui.Elements as EaElements -import EasyApp.Gui.Components as EaComponents - -import Gui.Globals as Globals - - -ScrollView { - anchors.fill: parent - - EaElements.TextArea { - text: Globals.Proxies.main.fittables.dataJson - - //textFormat: TextEdit.RichText - font.family: EaStyle.Fonts.monoFontFamily - backgroundOpacity: 0 - readOnly: true - } -} - diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/SideBarAdvanced/Calculator.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Advanced/Calculator.qml similarity index 100% rename from src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/SideBarAdvanced/Calculator.qml rename to src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Advanced/Calculator.qml diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/SideBarAdvanced.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Advanced/Layout.qml similarity index 100% rename from src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/SideBarAdvanced.qml rename to src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Advanced/Layout.qml diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/SideBarAdvanced/Minimizer.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Advanced/Minimizer.qml similarity index 100% rename from src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/SideBarAdvanced/Minimizer.qml rename to src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Advanced/Minimizer.qml diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/SideBarAdvanced/ParamNames.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Advanced/ParamNames.qml similarity index 100% rename from src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/SideBarAdvanced/ParamNames.qml rename to src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Advanced/ParamNames.qml diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/SideBarBasic/Experiments.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Experiments.qml similarity index 100% rename from src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/SideBarBasic/Experiments.qml rename to src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Experiments.qml diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/SideBarBasic/FitStatusDialog.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/FitStatusDialog.qml similarity index 100% rename from src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/SideBarBasic/FitStatusDialog.qml rename to src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/FitStatusDialog.qml diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/SideBarBasic/Fittables.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Fittables.qml similarity index 100% rename from src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/SideBarBasic/Fittables.qml rename to src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Fittables.qml diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/SideBarBasic/Fitting.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Fitting.qml similarity index 100% rename from src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/SideBarBasic/Fitting.qml rename to src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Fitting.qml diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/SideBarBasic.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Layout.qml similarity index 81% rename from src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/SideBarBasic.qml rename to src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Layout.qml index 3921548c..4ae28393 100644 --- a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/SideBarBasic.qml +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Layout.qml @@ -17,7 +17,7 @@ EaComponents.SideBarColumn { collapsible: false last: true - Loader { source: 'SideBarBasic/Experiments.qml' } + Loader { source: 'Experiments.qml' } } EaElements.GroupBox { @@ -25,14 +25,14 @@ EaComponents.SideBarColumn { collapsible: false last: true - Loader { source: 'SideBarBasic/Fittables.qml' } + Loader { source: 'Fittables.qml' } } EaElements.GroupBox { //title: qsTr("Fitting") collapsible: false - Loader { source: 'SideBarBasic/Fitting.qml' } + Loader { source: 'Fitting.qml' } } } From 115dc17cc3ce0c47e3d89b4b7066694411d23153 Mon Sep 17 00:00:00 2001 From: Andreas Pedersen Date: Thu, 24 Oct 2024 14:45:41 +0200 Subject: [PATCH 04/43] more file moving --- .../Advanced/{ => Groups}/Calculator.qml | 15 +- .../Sidebar/Advanced/Groups/Minimizer.qml | 77 +++ .../Sidebar/Advanced/Groups/ParamNames.qml | 93 ++++ .../Analysis/Sidebar/Advanced/Layout.qml | 13 +- .../Analysis/Sidebar/Advanced/Minimizer.qml | 73 --- .../Analysis/Sidebar/Advanced/ParamNames.qml | 89 ---- .../Analysis/Sidebar/Basic/Experiments.qml | 119 ----- .../Analysis/Sidebar/Basic/Fittables.qml | 468 ----------------- .../Pages/Analysis/Sidebar/Basic/Fitting.qml | 36 -- .../Sidebar/Basic/Groups/Experiments.qml | 124 +++++ .../Sidebar/Basic/Groups/Fittables.qml | 469 ++++++++++++++++++ .../Analysis/Sidebar/Basic/Groups/Fitting.qml | 40 ++ .../Pages/Analysis/Sidebar/Basic/Layout.qml | 25 +- .../Basic/{ => Popups}/FitStatusDialog.qml | 0 14 files changed, 840 insertions(+), 801 deletions(-) rename src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Advanced/{ => Groups}/Calculator.qml (62%) create mode 100644 src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Advanced/Groups/Minimizer.qml create mode 100644 src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Advanced/Groups/ParamNames.qml delete mode 100644 src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Advanced/Minimizer.qml delete mode 100644 src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Advanced/ParamNames.qml delete mode 100644 src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Experiments.qml delete mode 100644 src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Fittables.qml delete mode 100644 src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Fitting.qml create mode 100644 src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Groups/Experiments.qml create mode 100644 src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Groups/Fittables.qml create mode 100644 src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Groups/Fitting.qml rename src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/{ => Popups}/FitStatusDialog.qml (100%) diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Advanced/Calculator.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Advanced/Groups/Calculator.qml similarity index 62% rename from src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Advanced/Calculator.qml rename to src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Advanced/Groups/Calculator.qml index 0cb709d0..f28125d3 100644 --- a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Advanced/Calculator.qml +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Advanced/Groups/Calculator.qml @@ -10,12 +10,15 @@ import EasyApp.Gui.Elements as EaElements import Gui.Globals as Globals +EaElements.GroupBox { + title: qsTr("Calculation engine") + icon: 'calculator' + EaElements.GroupRow { -EaElements.GroupRow { + EaElements.ComboBox { + width: EaStyle.Sizes.sideBarContentWidth + model: ['CrysPy'] + } - EaElements.ComboBox { - width: EaStyle.Sizes.sideBarContentWidth - model: ['CrysPy'] } - -} +} \ No newline at end of file diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Advanced/Groups/Minimizer.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Advanced/Groups/Minimizer.qml new file mode 100644 index 00000000..af525890 --- /dev/null +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Advanced/Groups/Minimizer.qml @@ -0,0 +1,77 @@ +// SPDX-FileCopyrightText: 2023 EasyDiffraction contributors +// SPDX-License-Identifier: BSD-3-Clause +// © 2023 Contributors to the EasyDiffraction project + +import QtQuick +import QtQuick.Controls + +import EasyApp.Gui.Style as EaStyle +import EasyApp.Gui.Elements as EaElements + +import Gui.Globals as Globals + +EaElements.GroupBox { + title: qsTr("Minimization engine") + icon: 'level-down-alt' + + EaElements.GroupRow { + property real columnWidth: (EaStyle.Sizes.sideBarContentWidth - EaStyle.Sizes.fontPixelSize) / 4 + + EaElements.ComboBox { + width: columnWidth + topInset: minimizerLabel.height + topPadding: topInset + padding + model: ['Lmfit'] + EaElements.Label { + id: minimizerLabel + text: qsTr("Minimizer") + color: EaStyle.Colors.themeForegroundMinor + } + } + + EaElements.TextField { + width: columnWidth + topInset: methodLabel.height + topPadding: topInset + padding + horizontalAlignment: TextInput.AlignLeft + onAccepted: focus = false + text: Globals.Proxies.main.fitting.minimizerMethod + onTextEdited: Globals.Proxies.main.fitting.minimizerMethod = text + EaElements.Label { + id: methodLabel + text: qsTr("Method") + color: EaStyle.Colors.themeForegroundMinor + } + } + + EaElements.TextField { + width: columnWidth + topInset: toleranceLabel.height + topPadding: topInset + padding + horizontalAlignment: TextInput.AlignLeft + onAccepted: focus = false + text: Globals.Proxies.main.fitting.minimizerTol + onTextEdited: Globals.Proxies.main.fitting.minimizerTol = text + EaElements.Label { + id: toleranceLabel + text: qsTr("Tolerance") + color: EaStyle.Colors.themeForegroundMinor + } + } + + EaElements.TextField { + width: columnWidth + topInset: maxIterLabel.height + topPadding: topInset + padding + horizontalAlignment: TextInput.AlignLeft + onAccepted: focus = false + text: Globals.Proxies.main.fitting.minimizerMaxIter + onTextEdited: Globals.Proxies.main.fitting.minimizerMaxIter = text + EaElements.Label { + id: maxIterLabel + text: qsTr("Max iterations") + color: EaStyle.Colors.themeForegroundMinor + } + } + } +} \ No newline at end of file diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Advanced/Groups/ParamNames.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Advanced/Groups/ParamNames.qml new file mode 100644 index 00000000..26a7f95d --- /dev/null +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Advanced/Groups/ParamNames.qml @@ -0,0 +1,93 @@ +// SPDX-FileCopyrightText: 2023 EasyDiffraction contributors +// SPDX-License-Identifier: BSD-3-Clause +// © 2023 Contributors to the EasyDiffraction project + +import QtQuick +import QtQuick.Controls + +import EasyApp.Gui.Globals as EaGlobals +import EasyApp.Gui.Style as EaStyle +import EasyApp.Gui.Elements as EaElements +import EasyApp.Gui.Components as EaComponents + +import Gui.Globals as Globals + +EaElements.GroupBox { + title: qsTr("Parameter names") + icon: "paint-brush" + collapsed: false + EaComponents.TableView { + id: tableView + + readonly property var param: { + "blockType": "model", + "blockIcon": "layer-group", + "blockIdx": 0, + "blockName": "co2sio4", + "categoryIcon": "atom", + "category": "_atom_site", + "prettyCategory": "atom", + "rowIndex": 2, + "rowName": "Si", + "icon": "map-marker-alt", + "name": "_fract_x", + "prettyName": "fract x", + "shortPrettyName": "x" } + + showHeader: false + tallRows: true + maxRowCountShow: model.length + + /* + model: [ + { value: EaGlobals.Vars.ShortestWithIconsAndPrettyLabels, + text: qsTr('Shortest iconified name with pretty labels') }, + { value: EaGlobals.Vars.ReducedWithIconsAndPrettyLabels, + text: qsTr('Shorter iconified name with pretty labels') }, + { value: EaGlobals.Vars.FullWithIconsAndPrettyLabels, + text: qsTr('Full iconified name with pretty labels') }, + { value: EaGlobals.Vars.FullWithPrettyLabels, + text: qsTr('Full plain text name with pretty labels') }, + { value: EaGlobals.Vars.FullWithLabels, + text: qsTr('Full plain text name with labels') }, + { value: EaGlobals.Vars.FullWithIndices, + text: qsTr('Full plain text name with indices') } + ] + */ + + model: [ + { value: EaGlobals.Vars.ShortestWithIconsAndPrettyLabels, + text: qsTr('Iconified name with pretty labels') }, + { value: EaGlobals.Vars.PlainShortWithLabels, + text: qsTr('Short plain text name with labels') }, + { value: EaGlobals.Vars.PlainFullWithLabels, + text: qsTr('Full plain text name with labels') } + ] + + header: EaComponents.TableViewHeader { + + EaComponents.TableViewLabel { + width: EaStyle.Sizes.fontPixelSize * 2.5 + } + + EaComponents.TableViewLabel { + flexibleWidth: true + } + } + + delegate: EaComponents.TableViewDelegate { + mouseArea.onPressed: EaGlobals.Vars.paramNameFormat = currentIndex + + EaElements.RadioButton { + checked: index === EaGlobals.Vars.paramNameFormat + anchors.verticalCenter: parent.verticalCenter + } + + EaComponents.TableViewTwoRowsAdvancedLabel { + text: tableView.model[index].text + minorText: Globals.Proxies.paramName(param, tableView.model[index].value) + } + } + + } +} \ No newline at end of file diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Advanced/Layout.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Advanced/Layout.qml index ab8dbbc4..69439e64 100644 --- a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Advanced/Layout.qml +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Advanced/Layout.qml @@ -7,9 +7,13 @@ import QtQuick import EasyApp.Gui.Elements as EaElements import EasyApp.Gui.Components as EaComponents +import "./Groups" as Groups + EaComponents.SideBarColumn { + Groups.ParamNames {} +/* EaElements.GroupBox { title: qsTr("Parameter names") icon: "paint-brush" @@ -17,18 +21,23 @@ EaComponents.SideBarColumn { Loader { source: 'SideBarAdvanced/ParamNames.qml' } } - +*/ + Groups.Calculator {} +/* EaElements.GroupBox { title: qsTr("Calculation engine") icon: 'calculator' Loader { source: 'SideBarAdvanced/Calculator.qml' } } - +*/ + Groups.Minimizer {} +/* EaElements.GroupBox { title: qsTr("Minimization engine") icon: 'level-down-alt' Loader { source: 'SideBarAdvanced/Minimizer.qml' } } + */ } diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Advanced/Minimizer.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Advanced/Minimizer.qml deleted file mode 100644 index 3578b18c..00000000 --- a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Advanced/Minimizer.qml +++ /dev/null @@ -1,73 +0,0 @@ -// SPDX-FileCopyrightText: 2023 EasyDiffraction contributors -// SPDX-License-Identifier: BSD-3-Clause -// © 2023 Contributors to the EasyDiffraction project - -import QtQuick -import QtQuick.Controls - -import EasyApp.Gui.Style as EaStyle -import EasyApp.Gui.Elements as EaElements - -import Gui.Globals as Globals - - -EaElements.GroupRow { - property real columnWidth: (EaStyle.Sizes.sideBarContentWidth - EaStyle.Sizes.fontPixelSize) / 4 - - EaElements.ComboBox { - width: columnWidth - topInset: minimizerLabel.height - topPadding: topInset + padding - model: ['Lmfit'] - EaElements.Label { - id: minimizerLabel - text: qsTr("Minimizer") - color: EaStyle.Colors.themeForegroundMinor - } - } - - EaElements.TextField { - width: columnWidth - topInset: methodLabel.height - topPadding: topInset + padding - horizontalAlignment: TextInput.AlignLeft - onAccepted: focus = false - text: Globals.Proxies.main.fitting.minimizerMethod - onTextEdited: Globals.Proxies.main.fitting.minimizerMethod = text - EaElements.Label { - id: methodLabel - text: qsTr("Method") - color: EaStyle.Colors.themeForegroundMinor - } - } - - EaElements.TextField { - width: columnWidth - topInset: toleranceLabel.height - topPadding: topInset + padding - horizontalAlignment: TextInput.AlignLeft - onAccepted: focus = false - text: Globals.Proxies.main.fitting.minimizerTol - onTextEdited: Globals.Proxies.main.fitting.minimizerTol = text - EaElements.Label { - id: toleranceLabel - text: qsTr("Tolerance") - color: EaStyle.Colors.themeForegroundMinor - } - } - - EaElements.TextField { - width: columnWidth - topInset: maxIterLabel.height - topPadding: topInset + padding - horizontalAlignment: TextInput.AlignLeft - onAccepted: focus = false - text: Globals.Proxies.main.fitting.minimizerMaxIter - onTextEdited: Globals.Proxies.main.fitting.minimizerMaxIter = text - EaElements.Label { - id: maxIterLabel - text: qsTr("Max iterations") - color: EaStyle.Colors.themeForegroundMinor - } - } -} diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Advanced/ParamNames.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Advanced/ParamNames.qml deleted file mode 100644 index e792add2..00000000 --- a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Advanced/ParamNames.qml +++ /dev/null @@ -1,89 +0,0 @@ -// SPDX-FileCopyrightText: 2023 EasyDiffraction contributors -// SPDX-License-Identifier: BSD-3-Clause -// © 2023 Contributors to the EasyDiffraction project - -import QtQuick -import QtQuick.Controls - -import EasyApp.Gui.Globals as EaGlobals -import EasyApp.Gui.Style as EaStyle -import EasyApp.Gui.Elements as EaElements -import EasyApp.Gui.Components as EaComponents - -import Gui.Globals as Globals - - -EaComponents.TableView { - id: tableView - - readonly property var param: { - "blockType": "model", - "blockIcon": "layer-group", - "blockIdx": 0, - "blockName": "co2sio4", - "categoryIcon": "atom", - "category": "_atom_site", - "prettyCategory": "atom", - "rowIndex": 2, - "rowName": "Si", - "icon": "map-marker-alt", - "name": "_fract_x", - "prettyName": "fract x", - "shortPrettyName": "x" } - - showHeader: false - tallRows: true - maxRowCountShow: model.length - - /* - model: [ - { value: EaGlobals.Vars.ShortestWithIconsAndPrettyLabels, - text: qsTr('Shortest iconified name with pretty labels') }, - { value: EaGlobals.Vars.ReducedWithIconsAndPrettyLabels, - text: qsTr('Shorter iconified name with pretty labels') }, - { value: EaGlobals.Vars.FullWithIconsAndPrettyLabels, - text: qsTr('Full iconified name with pretty labels') }, - { value: EaGlobals.Vars.FullWithPrettyLabels, - text: qsTr('Full plain text name with pretty labels') }, - { value: EaGlobals.Vars.FullWithLabels, - text: qsTr('Full plain text name with labels') }, - { value: EaGlobals.Vars.FullWithIndices, - text: qsTr('Full plain text name with indices') } - ] - */ - - model: [ - { value: EaGlobals.Vars.ShortestWithIconsAndPrettyLabels, - text: qsTr('Iconified name with pretty labels') }, - { value: EaGlobals.Vars.PlainShortWithLabels, - text: qsTr('Short plain text name with labels') }, - { value: EaGlobals.Vars.PlainFullWithLabels, - text: qsTr('Full plain text name with labels') } - ] - - header: EaComponents.TableViewHeader { - - EaComponents.TableViewLabel { - width: EaStyle.Sizes.fontPixelSize * 2.5 - } - - EaComponents.TableViewLabel { - flexibleWidth: true - } - } - - delegate: EaComponents.TableViewDelegate { - mouseArea.onPressed: EaGlobals.Vars.paramNameFormat = currentIndex - - EaElements.RadioButton { - checked: index === EaGlobals.Vars.paramNameFormat - anchors.verticalCenter: parent.verticalCenter - } - - EaComponents.TableViewTwoRowsAdvancedLabel { - text: tableView.model[index].text - minorText: Globals.Proxies.paramName(param, tableView.model[index].value) - } - } - -} diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Experiments.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Experiments.qml deleted file mode 100644 index 991a74eb..00000000 --- a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Experiments.qml +++ /dev/null @@ -1,119 +0,0 @@ -// SPDX-FileCopyrightText: 2023 EasyDiffraction contributors -// SPDX-License-Identifier: BSD-3-Clause -// © 2023 Contributors to the EasyDiffraction project - -import QtQuick -import QtQuick.Controls -import QtQuick.Dialogs - -import EasyApp.Gui.Globals as EaGlobals -import EasyApp.Gui.Style as EaStyle -import EasyApp.Gui.Elements as EaElements -import EasyApp.Gui.Components as EaComponents -import EasyApp.Gui.Logic as EaLogic - -import Gui.Globals as Globals - - -EaElements.ComboBox { - id: comboBox - - topInset: 0 - bottomInset: 0 - - width: EaStyle.Sizes.sideBarContentWidth - anchors.bottomMargin: EaStyle.Sizes.fontPixelSize - - textRole: "name" - - model: Globals.Proxies.main.experiment.dataBlocksNoMeas - currentIndex: Globals.Proxies.main.experiment.currentIndex - - onActivated: Globals.Proxies.main.experiment.currentIndex = currentIndex - - // ComboBox delegate (popup rows) - delegate: ItemDelegate { - id: itemDelegate - - width: parent.width - height: EaStyle.Sizes.tableRowHeight - - highlighted: comboBox.highlightedIndex === index - - // ComboBox delegate (popup rows) contentItem - contentItem: Item { - width: parent.width - height: parent.height - - Row { - height: parent.height - spacing: EaStyle.Sizes.tableColumnSpacing - - EaComponents.TableViewLabel { - text: index + 1 - color: EaStyle.Colors.themeForegroundMinor - } - - EaComponents.TableViewButton { - anchors.verticalCenter: parent.verticalCenter - fontIcon: "microscope" - ToolTip.text: qsTr("Measured pattern color") - backgroundColor: "transparent" - borderColor: "transparent" - iconColor: EaStyle.Colors.chartForegroundsExtra[2] - } - - EaComponents.TableViewParameter { - enabled: false - text: comboBox.model[index].name.value - } - } - } - // ComboBox delegate (popup rows) contentItem - - // ComboBox delegate (popup rows) background - background: Rectangle { - color: itemDelegate.highlighted ? - EaStyle.Colors.tableHighlight : - index % 2 ? - EaStyle.Colors.themeBackgroundHovered2 : - EaStyle.Colors.themeBackgroundHovered1 - } - // ComboBox delegate (popup rows) background - - } - // ComboBox delegate (popup rows) - - // ComboBox (selected item) contentItem - contentItem: Item { - width: parent.width - height: parent.height - - Row { - height: parent.height - spacing: EaStyle.Sizes.tableColumnSpacing - - EaComponents.TableViewLabel { - text: currentIndex + 1 - color: EaStyle.Colors.themeForegroundMinor - } - - EaComponents.TableViewButton { - anchors.verticalCenter: parent.verticalCenter - fontIcon: "microscope" - ToolTip.text: qsTr("Measured pattern color") - backgroundColor: "transparent" - borderColor: "transparent" - iconColor: EaStyle.Colors.chartForegroundsExtra[2] - } - - EaComponents.TableViewParameter { - enabled: false - text: typeof comboBox.model[currentIndex] !== 'undefined' ? - comboBox.model[currentIndex].name.value : - '' - } - } - } - // ComboBox (selected item) contentItem -} diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Fittables.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Fittables.qml deleted file mode 100644 index 05ec6724..00000000 --- a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Fittables.qml +++ /dev/null @@ -1,468 +0,0 @@ -// SPDX-FileCopyrightText: 2023 EasyDiffraction contributors -// SPDX-License-Identifier: BSD-3-Clause -// © 2023 Contributors to the EasyDiffraction project - -import QtQuick -import QtQuick.Controls -import QtCharts - -import EasyApp.Gui.Logic as EaLogic -import EasyApp.Gui.Globals as EaGlobals -import EasyApp.Gui.Style as EaStyle -import EasyApp.Gui.Elements as EaElements -import EasyApp.Gui.Components as EaComponents - -import Gui.Globals as Globals - - -Column { - property int selectedParamIndex: -1 - onSelectedParamIndexChanged: { - updateSliderLimits() - updateSliderValue() - } - - property string selectedColor: EaStyle.Colors.themeForegroundHovered - - spacing: EaStyle.Sizes.fontPixelSize - - // Filter parameters widget - Row { - spacing: EaStyle.Sizes.fontPixelSize * 0.5 - - // Filter criteria - EaElements.TextField { - id: filterCriteriaField - - width: (EaStyle.Sizes.sideBarContentWidth - EaStyle.Sizes.fontPixelSize) / 3 - - placeholderText: qsTr("Filter criteria") - - onTextChanged: { - nameFilterSelector.currentIndex = nameFilterSelector.indexOfValue(text) - Globals.Proxies.main.fittables.nameFilterCriteria = text - } - } - // Filter criteria - - // Filter by name - EaElements.ComboBox { - id: nameFilterSelector - - topInset: 0 - bottomInset: 0 - - width: (EaStyle.Sizes.sideBarContentWidth - EaStyle.Sizes.fontPixelSize) / 3 - - valueRole: "value" - textRole: "text" - - displayText: currentIndex === -1 ? - qsTr("Filter by name") : - currentText.replace(' ◦ ', '') - - model: [ - { value: "", text: `All names (${Globals.Proxies.main.fittables.modelParamsCount + Globals.Proxies.main.fittables.experimentParamsCount})` }, - { value: "model", text: `layer-group Model (${Globals.Proxies.main.fittables.modelParamsCount})` }, - { value: "cell", text: `cube Unit cell` }, - { value: "atom_site", text: `atom Atom sites` }, - { value: "fract", text: `map-marker-alt Atomic coordinates` }, - { value: "occupancy", text: `fill Atomic occupancies` }, - { value: "B_iso", text: `arrows-alt Atomic displacement` }, - { value: "experiment", text: `microscope Experiment (${Globals.Proxies.main.fittables.experimentParamsCount})` }, - { value: "resolution", text: `shapes Peak shape` }, - { value: "asymmetry", text: `balance-scale-left Peak asymmetry` }, - { value: "background", text: `wave-square Background` } - ] - - onActivated: filterCriteriaField.text = currentValue - } - // Filter by name - - // Filter by variability - EaElements.ComboBox { - id: variabilityFilterSelector - - property int lastIndex: -1 - - topInset: 0 - bottomInset: 0 - - width: (EaStyle.Sizes.sideBarContentWidth - EaStyle.Sizes.fontPixelSize) / 3 - - displayText: currentIndex === -1 ? qsTr("Filter by variability") : currentText - - valueRole: "value" - textRole: "text" - - model: [ - { value: 'all', text: `All parameters (${Globals.Proxies.main.fittables.freeParamsCount + - Globals.Proxies.main.fittables.fixedParamsCount})` }, - { value: 'free', text: `Free parameters (${Globals.Proxies.main.fittables.freeParamsCount})` }, - { value: 'fixed', text: `Fixed parameters (${Globals.Proxies.main.fittables.fixedParamsCount})` } - ] - onModelChanged: currentIndex = lastIndex - - onActivated: { - lastIndex = currentIndex - Globals.Proxies.main.fittables.variabilityFilterCriteria = currentValue - } - } - // Filter by variability - - } - // Filter parameters widget - - // Table - EaComponents.TableView { - id: tableView - - property var currentValueTextInput: null - - defaultInfoText: qsTr("No parameters found") - - maxRowCountShow: 7 + - Math.trunc((applicationWindow.height - EaStyle.Sizes.appWindowMinimumHeight) / - EaStyle.Sizes.tableRowHeight) - // Table model - // We only use the length of the model object defined in backend logic and - // directly access that model in every row using the TableView index property. - model: Globals.Proxies.main_fittables_data.length - // Table model - - Component.onCompleted: selectedParamIndex = 0 - - // Header row - header: EaComponents.TableViewHeader { - EaComponents.TableViewLabel { - width: EaStyle.Sizes.fontPixelSize * 2.5 - //text: qsTr("No.") - } - - EaComponents.TableViewLabel { - flexibleWidth: true - horizontalAlignment: Text.AlignLeft - color: EaStyle.Colors.themeForegroundMinor - text: qsTr("name") - } - - EaComponents.TableViewLabel { - id: valueLabel - width: EaStyle.Sizes.fontPixelSize * 4.5 - horizontalAlignment: Text.AlignRight - color: EaStyle.Colors.themeForegroundMinor - text: qsTr("value") - } - - EaComponents.TableViewLabel { - width: EaStyle.Sizes.fontPixelSize * 2.0 - horizontalAlignment: Text.AlignLeft - //text: qsTr("units") - } - - EaComponents.TableViewLabel { - width: valueLabel.width - horizontalAlignment: Text.AlignRight - color: EaStyle.Colors.themeForegroundMinor - text: qsTr("error") - } - - EaComponents.TableViewLabel { - width: valueLabel.width - horizontalAlignment: Text.AlignRight - color: EaStyle.Colors.themeForegroundMinor - text: qsTr("min") - } - - EaComponents.TableViewLabel { - width: valueLabel.width - horizontalAlignment: Text.AlignRight - color: EaStyle.Colors.themeForegroundMinor - text: qsTr("max") - } - - EaComponents.TableViewLabel { - width: EaStyle.Sizes.fontPixelSize * 3.0 - color: EaStyle.Colors.themeForegroundMinor - text: qsTr("vary") - } - } - // Header row - - // Table content row - delegate: EaComponents.TableViewDelegate { - enabled: !Globals.Proxies.main.fitting.isFittingNow - - property bool isCurrentItem: ListView.isCurrentItem - property var item: Globals.Proxies.main_fittables_data[index] - - mouseArea.onPressed: selectedParamIndex = tableView.currentIndex - - onIsCurrentItemChanged: { - if (tableView.currentValueTextInput != valueColumn) { - tableView.currentValueTextInput = valueColumn - } - } - - EaComponents.TableViewLabel { - text: index + 1 - color: EaStyle.Colors.themeForegroundMinor - } - - EaComponents.TableViewLabel { - width: EaStyle.Sizes.fontPixelSize * 5 - text: Globals.Proxies.paramName(item, EaGlobals.Vars.paramNameFormat) - textFormat: EaGlobals.Vars.paramNameFormat === EaGlobals.Vars.PlainShortWithLabels || - EaGlobals.Vars.paramNameFormat === EaGlobals.Vars.PlainFullWithLabels ? - Text.PlainText : - Text.RichText - //clip: true - elide: Text.ElideMiddle // NEED FIX: Doesn't work with textFormat: Text.RichText - ToolTip.text: textFormat === Text.PlainText ? text : '' - } - - EaComponents.TableViewParameter { - id: valueColumn - selected: //index === tableView.currentIndex || - index === selectedParamIndex - fit: item.fit - text: item.error === 0 ? - EaLogic.Utils.toDefaultPrecision(item.value) : - Globals.Proxies.main.backendHelpers.toStdDevSmalestPrecision(item.value, item.error).value - onEditingFinished: { - focus = false - console.debug('') - console.debug("*** Editing (manual) 'value' field of fittable on Analysis page ***") - Globals.Proxies.main.fittables.editSilently(item.blockType, - item.blockIdx, - item.category, - item.rowIndex ?? -1, - item.name, - 'value', - text) - updateSliderLimits() - slider.value = Globals.Proxies.main_fittables_data[selectedParamIndex].value - - } - } - - EaComponents.TableViewLabel { - text: item.units - color: EaStyle.Colors.themeForegroundMinor - } - - EaComponents.TableViewLabel { - elide: Text.ElideNone - text: item.error === 0 ? - '' : - Globals.Proxies.main.backendHelpers.toStdDevSmalestPrecision(item.value, item.error).std_dev - } - - EaComponents.TableViewParameter { - minored: true - text: EaLogic.Utils.toDefaultPrecision(item.min).replace('Infinity', 'inf') - onEditingFinished: { - focus = false - console.debug('') - console.debug("*** Editing 'min' field of fittable on Analysis page ***") - const value = (text === '' ? '-inf' : text) - Globals.Proxies.main.fittables.editSilently(item.blockType, - item.blockIdx, - item.category, - item.rowIndex ?? -1, - item.name, - 'min', - value) - } - } - - EaComponents.TableViewParameter { - minored: true - text: EaLogic.Utils.toDefaultPrecision(item.max).replace('Infinity', 'inf') - onEditingFinished: { - focus = false - console.debug('') - console.debug("*** Editing 'max' field of fittable on Analysis page ***") - const value = (text === '' ? 'inf' : text) - Globals.Proxies.main.fittables.editSilently(item.blockType, - item.blockIdx, - item.category, - item.rowIndex ?? -1, - item.name, - 'max', - value) - } - } - - EaComponents.TableViewCheckBox { - id: fitColumn - enabled: Globals.Proxies.main.experiment.defined - checked: item.fit - onToggled: { - console.debug('') - console.debug("*** Editing 'fit' field of fittable on Analysis page ***") - Globals.Proxies.main.fittables.editSilently(item.blockType, - item.blockIdx, - item.category, - item.rowIndex ?? -1, - item.name, - 'fit', - checked) - } - } - } - // Table content row - } - // Table - - // Parameter change slider - Row { - visible: Globals.Proxies.main_fittables_data.length - - spacing: EaStyle.Sizes.fontPixelSize - - EaElements.TextField { - readOnly: true - width: EaStyle.Sizes.fontPixelSize * 6 - //text: EaLogic.Utils.toDefaultPrecision(slider.from) - //text: EaLogic.Utils.toErrSinglePrecision(slider.from, Globals.Proxies.main_fittables_data[selectedParamIndex].error) - text: { - const value = Globals.Proxies.main_fittables_data[selectedParamIndex].value - const error = Globals.Proxies.main_fittables_data[selectedParamIndex].error - //return EaLogic.Utils.toErrSinglePrecision(value, error).length <= 8 ? - // EaLogic.Utils.toErrSinglePrecision(slider.from, error) : - // EaLogic.Utils.toDefaultPrecision(slider.from) - return error === 0 ? - EaLogic.Utils.toDefaultPrecision(slider.from) : - Globals.Proxies.main.backendHelpers.toStdDevSmalestPrecision(slider.from, error).value - } - } - - EaElements.Slider { - id: slider - - enabled: !Globals.Proxies.main.fitting.isFittingNow - width: tableView.width - EaStyle.Sizes.fontPixelSize * 14 - - stepSize: (to - from) / 20 - snapMode: Slider.SnapAlways - - toolTipText: { - const value = Globals.Proxies.main_fittables_data[selectedParamIndex].value - const error = Globals.Proxies.main_fittables_data[selectedParamIndex].error - //return EaLogic.Utils.toErrSinglePrecision(value, error).length <= 8 ? - // EaLogic.Utils.toErrSinglePrecision(value, error) : - // EaLogic.Utils.toDefaultPrecision(value) - return error === 0 ? - EaLogic.Utils.toDefaultPrecision(value) : - Globals.Proxies.main.backendHelpers.toStdDevSmalestPrecision(value, error).value - } - - onMoved: { - console.debug('') - console.debug("*** Editing (slider) 'value' field of fittable on Analysis page ***") - const item = Globals.Proxies.main_fittables_data[selectedParamIndex] - Globals.Proxies.main.fittables.editSilently(item.blockType, - item.blockIdx, - item.category, - item.rowIndex ?? -1, - item.name, - 'value', - value.toString()) - } - - onPressedChanged: { - if (!pressed) { - updateSliderLimits() - } - } - } - - EaElements.TextField { - readOnly: true - width: EaStyle.Sizes.fontPixelSize * 6 - //text: EaLogic.Utils.toDefaultPrecision(slider.to) - //text: EaLogic.Utils.toErrSinglePrecision(slider.to, Globals.Proxies.main_fittables_data[selectedParamIndex].error) - text: { - const value = Globals.Proxies.main_fittables_data[selectedParamIndex].value - const error = Globals.Proxies.main_fittables_data[selectedParamIndex].error - //return EaLogic.Utils.toErrSinglePrecision(value, error).length <= 8 ? - // EaLogic.Utils.toErrSinglePrecision(slider.to, error) : - // EaLogic.Utils.toDefaultPrecision(slider.to) - return error === 0 ? - EaLogic.Utils.toDefaultPrecision(slider.to) : - Globals.Proxies.main.backendHelpers.toStdDevSmalestPrecision(slider.to, error).value - } - } - - } - // Slider - - // Move delay timer - - /* - Timer { - id: moveDelayTimer - interval: 0 //50 - onTriggered: { - if (tableView.currentValueTextInput.text !== slider.value.toFixed(4)) { - //enableOpenGL() - tableView.currentValueTextInput.text = slider.value.toFixed(4) - tableView.currentValueTextInput.editingFinished() - //disableOpenGL() - } - } - } - */ - - // Use OpenGL on slider move only - - Timer { - id: disableOpenGLTimer - interval: 1500 - onTriggered: disableOpenGLFromTimer() - } - - // Logic - - function updateSliderValue() { - const value = Globals.Proxies.main_fittables_data[selectedParamIndex].value - slider.value = EaLogic.Utils.toDefaultPrecision(value) - } - - function updateSliderLimits() { - const from = Globals.Proxies.main_fittables_data[selectedParamIndex].from - const to = Globals.Proxies.main_fittables_data[selectedParamIndex].to - slider.from = EaLogic.Utils.toDefaultPrecision(from) - slider.to = EaLogic.Utils.toDefaultPrecision(to) - } - - function enableOpenGL() { - if (Globals.Proxies.main.plotting.currentLib1d === 'QtCharts') { - Globals.Refs.app.experimentPage.plotView.useOpenGL = true - //Globals.Refs.app.modelPage.plotView.useOpenGL = true - Globals.Refs.app.analysisPage.plotView.useAnimation = false - Globals.Refs.app.analysisPage.plotView.useOpenGL = true - } - } - - function disableOpenGL() { - if (Globals.Proxies.main.plotting.currentLib1d === 'QtCharts') { - ////Globals.Proxies.main.plotting.chartRefs.QtCharts.analysisPage.totalCalcSerie.pointsReplaced() - disableOpenGLTimer.restart() - } - } - - function disableOpenGLFromTimer() { - Globals.Refs.app.experimentPage.plotView.useOpenGL = false - //Globals.Refs.app.modelPage.plotView.useOpenGL = false - ////Globals.Proxies.main.plotting.chartRefs.QtCharts.analysisPage.totalCalcSerie.pointsReplaced() - ///console.error(Globals.Proxies.main.plotting.chartRefs.QtCharts.analysisPage.totalCalcSerie) - Globals.Refs.app.analysisPage.plotView.useAnimation = true - Globals.Refs.app.analysisPage.plotView.useOpenGL = false - } - - - - -} diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Fitting.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Fitting.qml deleted file mode 100644 index 665c2e6d..00000000 --- a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Fitting.qml +++ /dev/null @@ -1,36 +0,0 @@ -// SPDX-FileCopyrightText: 2023 EasyDiffraction contributors -// SPDX-License-Identifier: BSD-3-Clause -// © 2023 Contributors to the EasyDiffraction project - -import QtQuick -import QtQuick.Controls - -import EasyApp.Gui.Globals as EaGlobals -import EasyApp.Gui.Style as EaStyle -import EasyApp.Gui.Elements as EaElements -import EasyApp.Gui.Components as EaComponents - -import Gui.Globals as Globals - - -Column { - spacing: EaStyle.Sizes.fontPixelSize - - EaElements.SideBarButton { - enabled: Globals.Proxies.main.experiment.defined - wide: true - - fontIcon: Globals.Proxies.main.fitting.isFittingNow ? 'stop-circle' : 'play-circle' - text: Globals.Proxies.main.fitting.isFittingNow ? qsTr('Cancel fitting') : qsTr('Start fitting') - - onClicked: { - console.debug(`Clicking '${text}' button: ${this}`) - Globals.Proxies.main.fitting.startStop() - } - - Component.onCompleted: Globals.Refs.app.analysisPage.startFittingButton = this - - Loader { source: "FitStatusDialog.qml" } - } - -} diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Groups/Experiments.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Groups/Experiments.qml new file mode 100644 index 00000000..72bc30b7 --- /dev/null +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Groups/Experiments.qml @@ -0,0 +1,124 @@ +// SPDX-FileCopyrightText: 2023 EasyDiffraction contributors +// SPDX-License-Identifier: BSD-3-Clause +// © 2023 Contributors to the EasyDiffraction project + +import QtQuick +import QtQuick.Controls +import QtQuick.Dialogs + +import EasyApp.Gui.Globals as EaGlobals +import EasyApp.Gui.Style as EaStyle +import EasyApp.Gui.Elements as EaElements +import EasyApp.Gui.Components as EaComponents +import EasyApp.Gui.Logic as EaLogic + +import Gui.Globals as Globals + + +EaElements.GroupBox { + collapsible: false + last: true + + EaElements.ComboBox { + id: comboBox + + topInset: 0 + bottomInset: 0 + + width: EaStyle.Sizes.sideBarContentWidth + anchors.bottomMargin: EaStyle.Sizes.fontPixelSize + + textRole: "name" + + model: Globals.Proxies.main.experiment.dataBlocksNoMeas + currentIndex: Globals.Proxies.main.experiment.currentIndex + + onActivated: Globals.Proxies.main.experiment.currentIndex = currentIndex + + // ComboBox delegate (popup rows) + delegate: ItemDelegate { + id: itemDelegate + + width: parent.width + height: EaStyle.Sizes.tableRowHeight + + highlighted: comboBox.highlightedIndex === index + + // ComboBox delegate (popup rows) contentItem + contentItem: Item { + width: parent.width + height: parent.height + + Row { + height: parent.height + spacing: EaStyle.Sizes.tableColumnSpacing + + EaComponents.TableViewLabel { + text: index + 1 + color: EaStyle.Colors.themeForegroundMinor + } + + EaComponents.TableViewButton { + anchors.verticalCenter: parent.verticalCenter + fontIcon: "microscope" + ToolTip.text: qsTr("Measured pattern color") + backgroundColor: "transparent" + borderColor: "transparent" + iconColor: EaStyle.Colors.chartForegroundsExtra[2] + } + + EaComponents.TableViewParameter { + enabled: false + text: comboBox.model[index].name.value + } + } + } + // ComboBox delegate (popup rows) contentItem + + // ComboBox delegate (popup rows) background + background: Rectangle { + color: itemDelegate.highlighted ? + EaStyle.Colors.tableHighlight : + index % 2 ? + EaStyle.Colors.themeBackgroundHovered2 : + EaStyle.Colors.themeBackgroundHovered1 + } + // ComboBox delegate (popup rows) background + + } + // ComboBox delegate (popup rows) + + // ComboBox (selected item) contentItem + contentItem: Item { + width: parent.width + height: parent.height + + Row { + height: parent.height + spacing: EaStyle.Sizes.tableColumnSpacing + + EaComponents.TableViewLabel { + text: currentIndex + 1 + color: EaStyle.Colors.themeForegroundMinor + } + + EaComponents.TableViewButton { + anchors.verticalCenter: parent.verticalCenter + fontIcon: "microscope" + ToolTip.text: qsTr("Measured pattern color") + backgroundColor: "transparent" + borderColor: "transparent" + iconColor: EaStyle.Colors.chartForegroundsExtra[2] + } + + EaComponents.TableViewParameter { + enabled: false + text: typeof comboBox.model[currentIndex] !== 'undefined' ? + comboBox.model[currentIndex].name.value : + '' + } + } + } + // ComboBox (selected item) contentItem + } +} \ No newline at end of file diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Groups/Fittables.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Groups/Fittables.qml new file mode 100644 index 00000000..6a6363d9 --- /dev/null +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Groups/Fittables.qml @@ -0,0 +1,469 @@ +// SPDX-FileCopyrightText: 2023 EasyDiffraction contributors +// SPDX-License-Identifier: BSD-3-Clause +// © 2023 Contributors to the EasyDiffraction project + +import QtQuick +import QtQuick.Controls +import QtCharts + +import EasyApp.Gui.Logic as EaLogic +import EasyApp.Gui.Globals as EaGlobals +import EasyApp.Gui.Style as EaStyle +import EasyApp.Gui.Elements as EaElements +import EasyApp.Gui.Components as EaComponents + +import Gui.Globals as Globals + +EaElements.GroupBox { + //title: qsTr("Parameters") + collapsible: false + last: true + + Column { + property int selectedParamIndex: -1 + onSelectedParamIndexChanged: { + updateSliderLimits() + updateSliderValue() + } + + property string selectedColor: EaStyle.Colors.themeForegroundHovered + + spacing: EaStyle.Sizes.fontPixelSize + + // Filter parameters widget + Row { + spacing: EaStyle.Sizes.fontPixelSize * 0.5 + + // Filter criteria + EaElements.TextField { + id: filterCriteriaField + + width: (EaStyle.Sizes.sideBarContentWidth - EaStyle.Sizes.fontPixelSize) / 3 + + placeholderText: qsTr("Filter criteria") + + onTextChanged: { + nameFilterSelector.currentIndex = nameFilterSelector.indexOfValue(text) + Globals.Proxies.main.fittables.nameFilterCriteria = text + } + } + // Filter criteria + + // Filter by name + EaElements.ComboBox { + id: nameFilterSelector + + topInset: 0 + bottomInset: 0 + + width: (EaStyle.Sizes.sideBarContentWidth - EaStyle.Sizes.fontPixelSize) / 3 + + valueRole: "value" + textRole: "text" + + displayText: currentIndex === -1 ? + qsTr("Filter by name") : + currentText.replace(' ◦ ', '') + + model: [ + { value: "", text: `All names (${Globals.Proxies.main.fittables.modelParamsCount + Globals.Proxies.main.fittables.experimentParamsCount})` }, + { value: "model", text: `layer-group Model (${Globals.Proxies.main.fittables.modelParamsCount})` }, + { value: "cell", text: `cube Unit cell` }, + { value: "atom_site", text: `atom Atom sites` }, + { value: "fract", text: `map-marker-alt Atomic coordinates` }, + { value: "occupancy", text: `fill Atomic occupancies` }, + { value: "B_iso", text: `arrows-alt Atomic displacement` }, + { value: "experiment", text: `microscope Experiment (${Globals.Proxies.main.fittables.experimentParamsCount})` }, + { value: "resolution", text: `shapes Peak shape` }, + { value: "asymmetry", text: `balance-scale-left Peak asymmetry` }, + { value: "background", text: `wave-square Background` } + ] + + onActivated: filterCriteriaField.text = currentValue + } + // Filter by name + + // Filter by variability + EaElements.ComboBox { + id: variabilityFilterSelector + + property int lastIndex: -1 + + topInset: 0 + bottomInset: 0 + + width: (EaStyle.Sizes.sideBarContentWidth - EaStyle.Sizes.fontPixelSize) / 3 + + displayText: currentIndex === -1 ? qsTr("Filter by variability") : currentText + + valueRole: "value" + textRole: "text" + + model: [ + { value: 'all', text: `All parameters (${Globals.Proxies.main.fittables.freeParamsCount + + Globals.Proxies.main.fittables.fixedParamsCount})` }, + { value: 'free', text: `Free parameters (${Globals.Proxies.main.fittables.freeParamsCount})` }, + { value: 'fixed', text: `Fixed parameters (${Globals.Proxies.main.fittables.fixedParamsCount})` } + ] + onModelChanged: currentIndex = lastIndex + + onActivated: { + lastIndex = currentIndex + Globals.Proxies.main.fittables.variabilityFilterCriteria = currentValue + } + } + // Filter by variability + + } + // Filter parameters widget + + // Table + EaComponents.TableView { + id: tableView + + property var currentValueTextInput: null + + defaultInfoText: qsTr("No parameters found") + + maxRowCountShow: 7 + + Math.trunc((applicationWindow.height - EaStyle.Sizes.appWindowMinimumHeight) / + EaStyle.Sizes.tableRowHeight) + // Table model + // We only use the length of the model object defined in backend logic and + // directly access that model in every row using the TableView index property. + model: Globals.Proxies.main_fittables_data.length + // Table model + + Component.onCompleted: selectedParamIndex = 0 + + // Header row + header: EaComponents.TableViewHeader { + EaComponents.TableViewLabel { + width: EaStyle.Sizes.fontPixelSize * 2.5 + //text: qsTr("No.") + } + + EaComponents.TableViewLabel { + flexibleWidth: true + horizontalAlignment: Text.AlignLeft + color: EaStyle.Colors.themeForegroundMinor + text: qsTr("name") + } + + EaComponents.TableViewLabel { + id: valueLabel + width: EaStyle.Sizes.fontPixelSize * 4.5 + horizontalAlignment: Text.AlignRight + color: EaStyle.Colors.themeForegroundMinor + text: qsTr("value") + } + + EaComponents.TableViewLabel { + width: EaStyle.Sizes.fontPixelSize * 2.0 + horizontalAlignment: Text.AlignLeft + //text: qsTr("units") + } + + EaComponents.TableViewLabel { + width: valueLabel.width + horizontalAlignment: Text.AlignRight + color: EaStyle.Colors.themeForegroundMinor + text: qsTr("error") + } + + EaComponents.TableViewLabel { + width: valueLabel.width + horizontalAlignment: Text.AlignRight + color: EaStyle.Colors.themeForegroundMinor + text: qsTr("min") + } + + EaComponents.TableViewLabel { + width: valueLabel.width + horizontalAlignment: Text.AlignRight + color: EaStyle.Colors.themeForegroundMinor + text: qsTr("max") + } + + EaComponents.TableViewLabel { + width: EaStyle.Sizes.fontPixelSize * 3.0 + color: EaStyle.Colors.themeForegroundMinor + text: qsTr("vary") + } + } + // Header row + + // Table content row + delegate: EaComponents.TableViewDelegate { + enabled: !Globals.Proxies.main.fitting.isFittingNow + + property bool isCurrentItem: ListView.isCurrentItem + property var item: Globals.Proxies.main_fittables_data[index] + + mouseArea.onPressed: selectedParamIndex = tableView.currentIndex + + onIsCurrentItemChanged: { + if (tableView.currentValueTextInput != valueColumn) { + tableView.currentValueTextInput = valueColumn + } + } + + EaComponents.TableViewLabel { + text: index + 1 + color: EaStyle.Colors.themeForegroundMinor + } + + EaComponents.TableViewLabel { + width: EaStyle.Sizes.fontPixelSize * 5 + text: Globals.Proxies.paramName(item, EaGlobals.Vars.paramNameFormat) + textFormat: EaGlobals.Vars.paramNameFormat === EaGlobals.Vars.PlainShortWithLabels || + EaGlobals.Vars.paramNameFormat === EaGlobals.Vars.PlainFullWithLabels ? + Text.PlainText : + Text.RichText + //clip: true + elide: Text.ElideMiddle // NEED FIX: Doesn't work with textFormat: Text.RichText + ToolTip.text: textFormat === Text.PlainText ? text : '' + } + + EaComponents.TableViewParameter { + id: valueColumn + selected: //index === tableView.currentIndex || + index === selectedParamIndex + fit: item.fit + text: item.error === 0 ? + EaLogic.Utils.toDefaultPrecision(item.value) : + Globals.Proxies.main.backendHelpers.toStdDevSmalestPrecision(item.value, item.error).value + onEditingFinished: { + focus = false + console.debug('') + console.debug("*** Editing (manual) 'value' field of fittable on Analysis page ***") + Globals.Proxies.main.fittables.editSilently(item.blockType, + item.blockIdx, + item.category, + item.rowIndex ?? -1, + item.name, + 'value', + text) + updateSliderLimits() + slider.value = Globals.Proxies.main_fittables_data[selectedParamIndex].value + + } + } + + EaComponents.TableViewLabel { + text: item.units + color: EaStyle.Colors.themeForegroundMinor + } + + EaComponents.TableViewLabel { + elide: Text.ElideNone + text: item.error === 0 ? + '' : + Globals.Proxies.main.backendHelpers.toStdDevSmalestPrecision(item.value, item.error).std_dev + } + + EaComponents.TableViewParameter { + minored: true + text: EaLogic.Utils.toDefaultPrecision(item.min).replace('Infinity', 'inf') + onEditingFinished: { + focus = false + console.debug('') + console.debug("*** Editing 'min' field of fittable on Analysis page ***") + const value = (text === '' ? '-inf' : text) + Globals.Proxies.main.fittables.editSilently(item.blockType, + item.blockIdx, + item.category, + item.rowIndex ?? -1, + item.name, + 'min', + value) + } + } + + EaComponents.TableViewParameter { + minored: true + text: EaLogic.Utils.toDefaultPrecision(item.max).replace('Infinity', 'inf') + onEditingFinished: { + focus = false + console.debug('') + console.debug("*** Editing 'max' field of fittable on Analysis page ***") + const value = (text === '' ? 'inf' : text) + Globals.Proxies.main.fittables.editSilently(item.blockType, + item.blockIdx, + item.category, + item.rowIndex ?? -1, + item.name, + 'max', + value) + } + } + + EaComponents.TableViewCheckBox { + id: fitColumn + enabled: Globals.Proxies.main.experiment.defined + checked: item.fit + onToggled: { + console.debug('') + console.debug("*** Editing 'fit' field of fittable on Analysis page ***") + Globals.Proxies.main.fittables.editSilently(item.blockType, + item.blockIdx, + item.category, + item.rowIndex ?? -1, + item.name, + 'fit', + checked) + } + } + } + // Table content row + } + // Table + + // Parameter change slider + Row { + visible: Globals.Proxies.main_fittables_data.length + + spacing: EaStyle.Sizes.fontPixelSize + + EaElements.TextField { + readOnly: true + width: EaStyle.Sizes.fontPixelSize * 6 + //text: EaLogic.Utils.toDefaultPrecision(slider.from) + //text: EaLogic.Utils.toErrSinglePrecision(slider.from, Globals.Proxies.main_fittables_data[selectedParamIndex].error) + text: { + const value = Globals.Proxies.main_fittables_data[selectedParamIndex].value + const error = Globals.Proxies.main_fittables_data[selectedParamIndex].error + //return EaLogic.Utils.toErrSinglePrecision(value, error).length <= 8 ? + // EaLogic.Utils.toErrSinglePrecision(slider.from, error) : + // EaLogic.Utils.toDefaultPrecision(slider.from) + return error === 0 ? + EaLogic.Utils.toDefaultPrecision(slider.from) : + Globals.Proxies.main.backendHelpers.toStdDevSmalestPrecision(slider.from, error).value + } + } + + EaElements.Slider { + id: slider + + enabled: !Globals.Proxies.main.fitting.isFittingNow + width: tableView.width - EaStyle.Sizes.fontPixelSize * 14 + + stepSize: (to - from) / 20 + snapMode: Slider.SnapAlways + + toolTipText: { + const value = Globals.Proxies.main_fittables_data[selectedParamIndex].value + const error = Globals.Proxies.main_fittables_data[selectedParamIndex].error + //return EaLogic.Utils.toErrSinglePrecision(value, error).length <= 8 ? + // EaLogic.Utils.toErrSinglePrecision(value, error) : + // EaLogic.Utils.toDefaultPrecision(value) + return error === 0 ? + EaLogic.Utils.toDefaultPrecision(value) : + Globals.Proxies.main.backendHelpers.toStdDevSmalestPrecision(value, error).value + } + + onMoved: { + console.debug('') + console.debug("*** Editing (slider) 'value' field of fittable on Analysis page ***") + const item = Globals.Proxies.main_fittables_data[selectedParamIndex] + Globals.Proxies.main.fittables.editSilently(item.blockType, + item.blockIdx, + item.category, + item.rowIndex ?? -1, + item.name, + 'value', + value.toString()) + } + + onPressedChanged: { + if (!pressed) { + updateSliderLimits() + } + } + } + + EaElements.TextField { + readOnly: true + width: EaStyle.Sizes.fontPixelSize * 6 + //text: EaLogic.Utils.toDefaultPrecision(slider.to) + //text: EaLogic.Utils.toErrSinglePrecision(slider.to, Globals.Proxies.main_fittables_data[selectedParamIndex].error) + text: { + const value = Globals.Proxies.main_fittables_data[selectedParamIndex].value + const error = Globals.Proxies.main_fittables_data[selectedParamIndex].error + //return EaLogic.Utils.toErrSinglePrecision(value, error).length <= 8 ? + // EaLogic.Utils.toErrSinglePrecision(slider.to, error) : + // EaLogic.Utils.toDefaultPrecision(slider.to) + return error === 0 ? + EaLogic.Utils.toDefaultPrecision(slider.to) : + Globals.Proxies.main.backendHelpers.toStdDevSmalestPrecision(slider.to, error).value + } + } + + } + // Slider + + // Move delay timer + + /* + Timer { + id: moveDelayTimer + interval: 0 //50 + onTriggered: { + if (tableView.currentValueTextInput.text !== slider.value.toFixed(4)) { + //enableOpenGL() + tableView.currentValueTextInput.text = slider.value.toFixed(4) + tableView.currentValueTextInput.editingFinished() + //disableOpenGL() + } + } + } + */ + + // Use OpenGL on slider move only + + Timer { + id: disableOpenGLTimer + interval: 1500 + onTriggered: disableOpenGLFromTimer() + } + + // Logic + + function updateSliderValue() { + const value = Globals.Proxies.main_fittables_data[selectedParamIndex].value + slider.value = EaLogic.Utils.toDefaultPrecision(value) + } + + function updateSliderLimits() { + const from = Globals.Proxies.main_fittables_data[selectedParamIndex].from + const to = Globals.Proxies.main_fittables_data[selectedParamIndex].to + slider.from = EaLogic.Utils.toDefaultPrecision(from) + slider.to = EaLogic.Utils.toDefaultPrecision(to) + } + + function enableOpenGL() { + if (Globals.Proxies.main.plotting.currentLib1d === 'QtCharts') { + Globals.Refs.app.experimentPage.plotView.useOpenGL = true + //Globals.Refs.app.modelPage.plotView.useOpenGL = true + Globals.Refs.app.analysisPage.plotView.useAnimation = false + Globals.Refs.app.analysisPage.plotView.useOpenGL = true + } + } + + function disableOpenGL() { + if (Globals.Proxies.main.plotting.currentLib1d === 'QtCharts') { + ////Globals.Proxies.main.plotting.chartRefs.QtCharts.analysisPage.totalCalcSerie.pointsReplaced() + disableOpenGLTimer.restart() + } + } + + function disableOpenGLFromTimer() { + Globals.Refs.app.experimentPage.plotView.useOpenGL = false + //Globals.Refs.app.modelPage.plotView.useOpenGL = false + ////Globals.Proxies.main.plotting.chartRefs.QtCharts.analysisPage.totalCalcSerie.pointsReplaced() + ///console.error(Globals.Proxies.main.plotting.chartRefs.QtCharts.analysisPage.totalCalcSerie) + Globals.Refs.app.analysisPage.plotView.useAnimation = true + Globals.Refs.app.analysisPage.plotView.useOpenGL = false + } + } +} \ No newline at end of file diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Groups/Fitting.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Groups/Fitting.qml new file mode 100644 index 00000000..81ee238f --- /dev/null +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Groups/Fitting.qml @@ -0,0 +1,40 @@ +// SPDX-FileCopyrightText: 2023 EasyDiffraction contributors +// SPDX-License-Identifier: BSD-3-Clause +// © 2023 Contributors to the EasyDiffraction project + +import QtQuick +import QtQuick.Controls + +import EasyApp.Gui.Globals as EaGlobals +import EasyApp.Gui.Style as EaStyle +import EasyApp.Gui.Elements as EaElements +import EasyApp.Gui.Components as EaComponents + +import Gui.Globals as Globals + +EaElements.GroupBox { + //title: qsTr("Fitting") + collapsible: false + + Column { + spacing: EaStyle.Sizes.fontPixelSize + + EaElements.SideBarButton { + enabled: Globals.Proxies.main.experiment.defined + wide: true + + fontIcon: Globals.Proxies.main.fitting.isFittingNow ? 'stop-circle' : 'play-circle' + text: Globals.Proxies.main.fitting.isFittingNow ? qsTr('Cancel fitting') : qsTr('Start fitting') + + onClicked: { + console.debug(`Clicking '${text}' button: ${this}`) + Globals.Proxies.main.fitting.startStop() + } + + Component.onCompleted: Globals.Refs.app.analysisPage.startFittingButton = this + + Loader { source: "../Popups/FitStatusDialog.qml" } + } + + } +} diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Layout.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Layout.qml index 4ae28393..81b534cf 100644 --- a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Layout.qml +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Layout.qml @@ -8,31 +8,40 @@ import EasyApp.Gui.Style 1.0 as EaStyle import EasyApp.Gui.Elements as EaElements import EasyApp.Gui.Components as EaComponents +import "./Groups" as Groups import Gui.Globals as Globals EaComponents.SideBarColumn { - EaElements.GroupBox { - collapsible: false - last: true + Groups.Experiments{} +// enabled: Globals.BackendWrapper.analysisIsFitFinished +// } - Loader { source: 'Experiments.qml' } - } +// EaElements.GroupBox { +// collapsible: false +// last: true +// +// Loader { source: 'Experiments.qml' } +// } - EaElements.GroupBox { + Groups.Fittables{} + +/* EaElements.GroupBox { //title: qsTr("Parameters") collapsible: false last: true Loader { source: 'Fittables.qml' } } +*/ + Groups.Fitting{} - EaElements.GroupBox { +/* EaElements.GroupBox { //title: qsTr("Fitting") collapsible: false Loader { source: 'Fitting.qml' } } - +*/ } diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/FitStatusDialog.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Popups/FitStatusDialog.qml similarity index 100% rename from src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/FitStatusDialog.qml rename to src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Popups/FitStatusDialog.qml From 4a2924b9a322af7280c2e02170f343bd0c77a819 Mon Sep 17 00:00:00 2001 From: Andreas Pedersen Date: Fri, 25 Oct 2024 07:18:52 +0200 Subject: [PATCH 05/43] most of advanced pane is hooked up to backend --- .../Backends/Mock/Analysis.qml | 23 ++++++ .../Gui/Globals/BackendWrapper.qml | 11 +++ .../Sidebar/Advanced/Groups/Calculator.qml | 4 +- .../Sidebar/Advanced/Groups/Minimizer.qml | 79 +++++++++++-------- .../Sidebar/Basic/Groups/Experiments.qml | 14 ++-- 5 files changed, 88 insertions(+), 43 deletions(-) diff --git a/src_qt6/EasyReflectometryApp/Backends/Mock/Analysis.qml b/src_qt6/EasyReflectometryApp/Backends/Mock/Analysis.qml index 1d24afd4..9450dd29 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Mock/Analysis.qml +++ b/src_qt6/EasyReflectometryApp/Backends/Mock/Analysis.qml @@ -5,5 +5,28 @@ import QtQuick QtObject { readonly property bool isFitFinished: true + readonly property var minimizersAvailable: ['minimizer_1', 'minimizer_2', 'minimizer_3'] + readonly property var calculatorsAvailable: ['calculator_1', 'calculator_2', 'calculator_3'] + readonly property var experimentsAvailable: ['experiment_1', 'experiment_2', 'experiment_3'] + readonly property int experimentsCurrentIndex: 0 + + readonly property string minimizerCurrent: 'minimizer_1' + readonly property double minimizerTolerance: 1.0 + readonly property int minimizerMaxIterations: 2 + + // Setters + function setExperimentsCurrentIndex(value) { + console.debug(`setExperimentCurrentIndex ${value}`) + } + + function setMinimizerCurrent(value) { + console.debug(`setMinimizer ${value}`) + } + function setMinimizerTolerance(value) { + console.debug(`setMinimizerTolerance ${value}`) + } + function setMinimizerMaxIterations(value) { + console.debug(`setMinimizerMaxIterations ${value}`) + } } diff --git a/src_qt6/EasyReflectometryApp/Gui/Globals/BackendWrapper.qml b/src_qt6/EasyReflectometryApp/Gui/Globals/BackendWrapper.qml index 298e7f10..14475298 100644 --- a/src_qt6/EasyReflectometryApp/Gui/Globals/BackendWrapper.qml +++ b/src_qt6/EasyReflectometryApp/Gui/Globals/BackendWrapper.qml @@ -171,6 +171,17 @@ QtObject { // Analysis page /////////////// readonly property bool analysisIsFitFinished: activeBackend.analysis.isFitFinished + readonly property var analysisMinimizersAvailable: activeBackend.analysis.minimizersAvailable + readonly property var analysisCalculatorsAvailable: activeBackend.analysis.calculatorsAvailable + + readonly property string analysisMinimizerCurrent: activeBackend.analysis.minimizerCurrent + function analysisSetMinimizerCurrent(value) { activeBackend.analysis.setMinimizerCurrent(value) } + readonly property double analysisMinimizerTolerance: activeBackend.analysis.minimizerTolerance + function analysisSetMinimizerTolerance(value) { activeBackend.analysis.setMinimizerTolerance(value) } + readonly property int analysisMinimizerMaxIterations: activeBackend.analysis.mminimizerMaxIterations + function analysisSetMinimizerMaxIterations(value) { activeBackend.analysis.setMinimizerMaxIterations(value) } + readonly property int analysisExperimentsCurrentIndex: activeBackend.analysis.experimentsCurrentIndex + function anslysisSetExperimentsCurrentIndex(value) { activeBackend.analysis.setExperimentsCurrentIndex(value) } /////////////// diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Advanced/Groups/Calculator.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Advanced/Groups/Calculator.qml index f28125d3..ab9629a2 100644 --- a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Advanced/Groups/Calculator.qml +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Advanced/Groups/Calculator.qml @@ -17,8 +17,8 @@ EaElements.GroupBox { EaElements.ComboBox { width: EaStyle.Sizes.sideBarContentWidth - model: ['CrysPy'] + model: Globals.BackendWrapper.analysisCalculatorsAvailable } } -} \ No newline at end of file +} diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Advanced/Groups/Minimizer.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Advanced/Groups/Minimizer.qml index af525890..c87aa287 100644 --- a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Advanced/Groups/Minimizer.qml +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Advanced/Groups/Minimizer.qml @@ -11,47 +11,56 @@ import EasyApp.Gui.Elements as EaElements import Gui.Globals as Globals EaElements.GroupBox { - title: qsTr("Minimization engine") + title: qsTr("Minimization method") icon: 'level-down-alt' - EaElements.GroupRow { - property real columnWidth: (EaStyle.Sizes.sideBarContentWidth - EaStyle.Sizes.fontPixelSize) / 4 + EaElements.GroupRow{ +// property real columnWidth: (EaStyle.Sizes.sideBarContentWidth - EaStyle.Sizes.fontPixelSize) / 4 - EaElements.ComboBox { - width: columnWidth - topInset: minimizerLabel.height - topPadding: topInset + padding - model: ['Lmfit'] - EaElements.Label { - id: minimizerLabel - text: qsTr("Minimizer") - color: EaStyle.Colors.themeForegroundMinor +// Row{ + EaElements.ComboBox { + width: (EaStyle.Sizes.sideBarContentWidth - EaStyle.Sizes.fontPixelSize) / 4 + topInset: minimizerLabel.height + topPadding: topInset + padding + model: Globals.BackendWrapper.analysisMinimizersAvailable + //model: ['Lmfit'] + EaElements.Label { + id: minimizerLabel + text: qsTr("Minimizer") + color: EaStyle.Colors.themeForegroundMinor + } } - } +// } +/* Row{ + // spacing: EaStyle.Sizes.fontPixelSize - EaElements.TextField { - width: columnWidth - topInset: methodLabel.height - topPadding: topInset + padding - horizontalAlignment: TextInput.AlignLeft - onAccepted: focus = false - text: Globals.Proxies.main.fitting.minimizerMethod - onTextEdited: Globals.Proxies.main.fitting.minimizerMethod = text - EaElements.Label { - id: methodLabel - text: qsTr("Method") - color: EaStyle.Colors.themeForegroundMinor + EaElements.TextField { + width: (EaStyle.Sizes.sideBarContentWidth - EaStyle.Sizes.fontPixelSize) / 4 + topInset: methodLabel.height + topPadding: topInset + padding + horizontalAlignment: TextInput.AlignLeft + onAccepted: focus = false + //text: Globals.Proxies.main.fitting.minimizerMethod + //onTextEdited: Globals.Proxies.main.fitting.minimizerMethod = text + text: Globals.BackendWrapper.analysisMinimizerCurrent + onTextEdited: Globals.BackendWrapper.analysisSetMinimizer(text) + EaElements.Label { + id: methodLabel + text: qsTr("Method") + color: EaStyle.Colors.themeForegroundMinor + } } - } - + }*/ EaElements.TextField { - width: columnWidth + width: (EaStyle.Sizes.sideBarContentWidth - EaStyle.Sizes.fontPixelSize) / 4 topInset: toleranceLabel.height topPadding: topInset + padding horizontalAlignment: TextInput.AlignLeft onAccepted: focus = false - text: Globals.Proxies.main.fitting.minimizerTol - onTextEdited: Globals.Proxies.main.fitting.minimizerTol = text + //text: Globals.Proxies.main.fitting.minimizerTol + //onTextEdited: Globals.Proxies.main.fitting.minimizerTol = text + text: Globals.BackendWrapper.analysisMinimizerTolerance.toFixed(3) + onTextEdited: Globals.BackendWrapper.analysisMinimizerSetTolerance(text) EaElements.Label { id: toleranceLabel text: qsTr("Tolerance") @@ -60,13 +69,15 @@ EaElements.GroupBox { } EaElements.TextField { - width: columnWidth + width: (EaStyle.Sizes.sideBarContentWidth - EaStyle.Sizes.fontPixelSize) / 4 topInset: maxIterLabel.height topPadding: topInset + padding horizontalAlignment: TextInput.AlignLeft onAccepted: focus = false - text: Globals.Proxies.main.fitting.minimizerMaxIter - onTextEdited: Globals.Proxies.main.fitting.minimizerMaxIter = text + //text: Globals.Proxies.main.fitting.minimizerMaxIter + //onTextEdited: Globals.Proxies.main.fitting.minimizerMaxIter = text + text: Globals.BackendWrapper.analysisMinimizerMaxIterations + onTextEdited: Globals.Proxies.main.fittingMinimizerMaxIterations(text) EaElements.Label { id: maxIterLabel text: qsTr("Max iterations") @@ -74,4 +85,4 @@ EaElements.GroupBox { } } } -} \ No newline at end of file +} diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Groups/Experiments.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Groups/Experiments.qml index 72bc30b7..5c97420b 100644 --- a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Groups/Experiments.qml +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Groups/Experiments.qml @@ -30,10 +30,10 @@ EaElements.GroupBox { textRole: "name" - model: Globals.Proxies.main.experiment.dataBlocksNoMeas - currentIndex: Globals.Proxies.main.experiment.currentIndex + model: Globals.BackendWrapper.analysisExperimentsAvailable.length + currentIndex: Globals.BackendWrapper.analysisExperimentsCurrentIndex - onActivated: Globals.Proxies.main.experiment.currentIndex = currentIndex + onActivated: Globals.BackendWrapper.analysisExperimentsSetCurrentIndex(currentIndex) // ComboBox delegate (popup rows) delegate: ItemDelegate { @@ -98,7 +98,7 @@ EaElements.GroupBox { spacing: EaStyle.Sizes.tableColumnSpacing EaComponents.TableViewLabel { - text: currentIndex + 1 + text: comboBox.currentIndex + 1 color: EaStyle.Colors.themeForegroundMinor } @@ -113,12 +113,12 @@ EaElements.GroupBox { EaComponents.TableViewParameter { enabled: false - text: typeof comboBox.model[currentIndex] !== 'undefined' ? - comboBox.model[currentIndex].name.value : + text: typeof comboBox.model[comboBox.currentIndex] !== 'undefined' ? + comboBox.model[comboBox.currentIndex].name.value : '' } } } // ComboBox (selected item) contentItem } -} \ No newline at end of file +} From a057d976e703fcc13d5660db20b4d26d29de9865 Mon Sep 17 00:00:00 2001 From: Andreas Pedersen Date: Fri, 25 Oct 2024 13:52:30 +0200 Subject: [PATCH 06/43] calculated and measured show up on analysis --- .../Backends/Mock/Analysis.qml | 1 + .../Backends/Mock/Plotting.qml | 12 +- .../Backends/Py/plotting_1d.py | 116 +++- .../Backends/Py/py_backend.py | 2 + .../Gui/Globals/BackendWrapper.qml | 9 +- .../Gui/Globals/References.qml | 13 + .../Analysis/MainContent/AnalysisView.qml | 649 ++++-------------- .../MainContent/diffraction_AnalysisView.qml | 570 +++++++++++++++ .../Analysis/Sidebar/Basic/Groups/Fitting.qml | 4 +- .../Sidebar/Basic/Popups/FitStatusDialog.qml | 12 +- 10 files changed, 830 insertions(+), 558 deletions(-) create mode 100644 src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/MainContent/diffraction_AnalysisView.qml diff --git a/src_qt6/EasyReflectometryApp/Backends/Mock/Analysis.qml b/src_qt6/EasyReflectometryApp/Backends/Mock/Analysis.qml index 9450dd29..6f7e1d16 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Mock/Analysis.qml +++ b/src_qt6/EasyReflectometryApp/Backends/Mock/Analysis.qml @@ -10,6 +10,7 @@ QtObject { readonly property var experimentsAvailable: ['experiment_1', 'experiment_2', 'experiment_3'] readonly property int experimentsCurrentIndex: 0 + readonly property var minimizerStatus: 'Success' readonly property string minimizerCurrent: 'minimizer_1' readonly property double minimizerTolerance: 1.0 diff --git a/src_qt6/EasyReflectometryApp/Backends/Mock/Plotting.qml b/src_qt6/EasyReflectometryApp/Backends/Mock/Plotting.qml index cb1f2ce5..2a64db20 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Mock/Plotting.qml +++ b/src_qt6/EasyReflectometryApp/Backends/Mock/Plotting.qml @@ -12,10 +12,14 @@ QtObject { property double sldMaxX: 2. property double sldMinY: -20. property double sldMaxY: 20. - property double experimentMinX: -2. - property double experimentMaxX: 2. - property double experimentMinY: -20. - property double experimentMaxY: 20. + property double experimentMinX: -3. + property double experimentMaxX: 3. + property double experimentMinY: -30. + property double experimentMaxY: 30. + property double analysisMinX: -4. + property double analysisMaxX: 4. + property double analysisMinY: -40. + property double analysisMaxY: 40. function setQtChartsSerieRef(value1, value2, value3) { console.debug(`setQtChartsSerieRef ${value1}, ${value2}, ${value3}`) diff --git a/src_qt6/EasyReflectometryApp/Backends/Py/plotting_1d.py b/src_qt6/EasyReflectometryApp/Backends/Py/plotting_1d.py index 2c232c51..c6eeb4a0 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Py/plotting_1d.py +++ b/src_qt6/EasyReflectometryApp/Backends/Py/plotting_1d.py @@ -40,6 +40,10 @@ def __init__(self, project_lib: ProjectLib, parent=None): 'errorUpperSerie': None, 'errorLowerSerie': None, }, + 'analysisPage': { + 'calculatedSerie': None, + 'measuredSerie': None, + }, } } @@ -76,8 +80,8 @@ def experiment_data(self) -> DataSet1D: name='Experiment Data empty', x=np.empty(0), y=np.empty(0), - ey=np.empty(0), - ex=np.empty(0), + ye=np.empty(0), + xe=np.empty(0), ) return data @@ -115,23 +119,57 @@ def sldMaxY(self): def sldMinY(self): return self.sld_data.y.min() - # Experiment - @Property(float, notify=experimentChartRangesChanged) - def experimentMaxX(self): - return self.experiment_data.x.max() - - @Property(float, notify=experimentChartRangesChanged) - def experimentMinX(self): - return self.experiment_data.x.min() + # # Experiment + # @Property(float, notify=experimentChartRangesChanged) + # def experimentMaxX(self): + # if len(self.experiment_data.x) == 0: + # return None + # return self.experiment_data.x.max() + + # @Property(float, notify=experimentChartRangesChanged) + # def experimentMinX(self): + # if len(self.experiment_data.x) == 0: + # return None + # return self.experiment_data.x.min() - @Property(float, notify=experimentChartRangesChanged) - def experimentMaxY(self): - return np.log10(self.experiment_data.y.max()) - - @Property(float, notify=experimentChartRangesChanged) - def experimentMinY(self): - return np.log10(self.experiment_data.y.min()) - + # @Property(float, notify=experimentChartRangesChanged) + # def experimentMaxY(self): + # if len(self.experiment_data.y) == 0: + # return None + # return np.log10(self.experiment_data.y.max()) + + # @Property(float, notify=experimentChartRangesChanged) + # def experimentMinY(self): + # if len(self.experiment_data.y) == 0: + # return None + # return np.log10(self.experiment_data.y.min()) + + # # Analysis + # @Property(float, notify=sampleChartRangesChanged) + # def analysisMaxX(self): + # if self.experimentMaxX is None: + # return self.sampleMaxX + # return max(self.sampleMaxX, self.experimentMaxX) + + # @Property(float, notify=sampleChartRangesChanged) + # def analysisMinX(self): + # if self.experimentMinX is None: + # return self.sampleMinX + # return min(self.sampleMinX, self.experimentMinX) + + # @Property(float, notify=sampleChartRangesChanged) + # def analysisMaxY(self): + # if self.experimentMaxY is None: + # return self.sampleMaxY + # return max(self.sampleMaxY, self.experimentMaxY) + + # @Property(float, notify=sampleChartRangesChanged) + # def analysisMinY(self): + # if self.experimentMinY is None: + # return self.sampleMinY + # return min(self.sampleMinY, self.experimentMinY) + + # Other @Property(str, notify=currentLib1dChanged) def currentLib1d(self): return self._currentLib1d @@ -174,18 +212,13 @@ def refreshSamplePage(self): def refreshExperimentPage(self): self.drawMeasuredOnExperimentChart() + def refreshAnalysisPage(self): + self.drawCalculatedAndMeasuredOnAnalysisChart() + def drawCalculatedOnSampleChart(self): if PLOT_BACKEND == 'QtCharts': self.qtchartsReplaceCalculatedOnSampleChartAndRedraw() - def drawCalculatedOnSldChart(self): - if PLOT_BACKEND == 'QtCharts': - self.qtchartsReplaceCalculatedOnSldChartAndRedraw() - - def drawMeasuredOnExperimentChart(self): - if PLOT_BACKEND == 'QtCharts': - self.qtchartsReplaceMeasuredOnExperimentChartAndRedraw() - def qtchartsReplaceCalculatedOnSampleChartAndRedraw(self): series = self._chartRefs['QtCharts']['samplePage']['sampleSerie'] series.clear() @@ -195,6 +228,10 @@ def qtchartsReplaceCalculatedOnSampleChartAndRedraw(self): nr_points = nr_points + 1 console.debug(IO.formatMsg('sub', 'Calc curve', f'{nr_points} points', 'on sample page', 'replaced')) + def drawCalculatedOnSldChart(self): + if PLOT_BACKEND == 'QtCharts': + self.qtchartsReplaceCalculatedOnSldChartAndRedraw() + def qtchartsReplaceCalculatedOnSldChartAndRedraw(self): series = self._chartRefs['QtCharts']['samplePage']['sldSerie'] series.clear() @@ -204,6 +241,10 @@ def qtchartsReplaceCalculatedOnSldChartAndRedraw(self): nr_points = nr_points + 1 console.debug(IO.formatMsg('sub', 'Sld curve', f'{nr_points} points', 'on sample page', 'replaced')) + def drawMeasuredOnExperimentChart(self): + if PLOT_BACKEND == 'QtCharts': + self.qtchartsReplaceMeasuredOnExperimentChartAndRedraw() + def qtchartsReplaceMeasuredOnExperimentChartAndRedraw(self): series_measured = self._chartRefs['QtCharts']['experimentPage']['measuredSerie'] series_measured.clear() @@ -219,4 +260,25 @@ def qtchartsReplaceMeasuredOnExperimentChartAndRedraw(self): series_error_lower.append(point[0], np.log10(point[1] - np.sqrt(point[2]))) nr_points = nr_points + 1 - console.debug(IO.formatMsg('sub', 'Measurede curve', f'{nr_points} points', 'on experiment page', 'replaced')) \ No newline at end of file + console.debug(IO.formatMsg('sub', 'Measurede curve', f'{nr_points} points', 'on experiment page', 'replaced')) + + def drawCalculatedAndMeasuredOnAnalysisChart(self): + if PLOT_BACKEND == 'QtCharts': + self.qtchartsReplaceCalculatedAndMeasuredOnAnalysisChartAndRedraw() + + def qtchartsReplaceCalculatedAndMeasuredOnAnalysisChartAndRedraw(self): + series_measured = self._chartRefs['QtCharts']['analysisPage']['measuredSerie'] + series_measured.clear() + series_calculated = self._chartRefs['QtCharts']['analysisPage']['calculatedSerie'] + series_calculated.clear() + nr_points = 0 + for point in self.experiment_data.data_points(): + if point[0] < self._project_lib.q_max and self._project_lib.q_min < point[0]: + series_measured.append(point[0], np.log10(point[1])) + nr_points = nr_points + 1 + console.debug(IO.formatMsg('sub', 'Measurede curve', f'{nr_points} points', 'on analysis page', 'replaced')) + + for point in self.sample_data.data_points(): + series_calculated.append(point[0], np.log10(point[1])) + nr_points = nr_points + 1 + console.debug(IO.formatMsg('sub', 'Calculated curve', f'{nr_points} points', 'on analysis page', 'replaced')) diff --git a/src_qt6/EasyReflectometryApp/Backends/Py/py_backend.py b/src_qt6/EasyReflectometryApp/Backends/Py/py_backend.py index c2724b4d..4a27b464 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Py/py_backend.py +++ b/src_qt6/EasyReflectometryApp/Backends/Py/py_backend.py @@ -109,8 +109,10 @@ def _relay_sample_page_sample_changed(self): self._plotting.sldChartRangesChanged.emit() self._plotting.sampleChartRangesChanged.emit() self._plotting.refreshSamplePage() + self._plotting.refreshAnalysisPage() def _relay_experiment_page_experiment_changed(self): self._plotting.refreshExperimentPage() + self._plotting.refreshAnalysisPage() self._status.experimentsCountChanged.emit() self._sample.sampleChanged.emit() diff --git a/src_qt6/EasyReflectometryApp/Gui/Globals/BackendWrapper.qml b/src_qt6/EasyReflectometryApp/Gui/Globals/BackendWrapper.qml index 14475298..d1e5cb10 100644 --- a/src_qt6/EasyReflectometryApp/Gui/Globals/BackendWrapper.qml +++ b/src_qt6/EasyReflectometryApp/Gui/Globals/BackendWrapper.qml @@ -174,11 +174,13 @@ QtObject { readonly property var analysisMinimizersAvailable: activeBackend.analysis.minimizersAvailable readonly property var analysisCalculatorsAvailable: activeBackend.analysis.calculatorsAvailable + readonly property string analysisMinimizerStatus: activeBackend.analysis.minimizerStatus + readonly property string analysisMinimizerCurrent: activeBackend.analysis.minimizerCurrent function analysisSetMinimizerCurrent(value) { activeBackend.analysis.setMinimizerCurrent(value) } readonly property double analysisMinimizerTolerance: activeBackend.analysis.minimizerTolerance function analysisSetMinimizerTolerance(value) { activeBackend.analysis.setMinimizerTolerance(value) } - readonly property int analysisMinimizerMaxIterations: activeBackend.analysis.mminimizerMaxIterations + readonly property int analysisMinimizerMaxIterations: activeBackend.analysis.minimizerMaxIterations function analysisSetMinimizerMaxIterations(value) { activeBackend.analysis.setMinimizerMaxIterations(value) } readonly property int analysisExperimentsCurrentIndex: activeBackend.analysis.experimentsCurrentIndex function anslysisSetExperimentsCurrentIndex(value) { activeBackend.analysis.setExperimentsCurrentIndex(value) } @@ -208,5 +210,10 @@ QtObject { readonly property var plottingExperimentMinY: activeBackend.plotting.sampleMinY readonly property var plottingExperimentMaxY: activeBackend.plotting.sampleMaxY + readonly property var plottingAnalysisMinX: activeBackend.plotting.sampleMinX + readonly property var plottingAnalysisMaxX: activeBackend.plotting.sampleMaxX + readonly property var plottingAnalysisMinY: activeBackend.plotting.sampleMinY + readonly property var plottingAnalysisMaxY: activeBackend.plotting.sampleMaxY + function plottingSetQtChartsSerieRef(value1, value2, value3) { activeBackend.plotting.setQtChartsSerieRef(value1, value2, value3) } } diff --git a/src_qt6/EasyReflectometryApp/Gui/Globals/References.qml b/src_qt6/EasyReflectometryApp/Gui/Globals/References.qml index b9ba22eb..0004e1af 100644 --- a/src_qt6/EasyReflectometryApp/Gui/Globals/References.qml +++ b/src_qt6/EasyReflectometryApp/Gui/Globals/References.qml @@ -50,6 +50,19 @@ QtObject { } } } + }, + 'analysis': { + 'mainContent': { + 'analysisView': null, + }, + 'sidebar': { + 'basic': { + 'popups': { + 'startFittingButton': null, + 'fitStatusDialogOkButton': null + } + } + } } } diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/MainContent/AnalysisView.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/MainContent/AnalysisView.qml index 42a45bd3..db10ca5b 100644 --- a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/MainContent/AnalysisView.qml +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/MainContent/AnalysisView.qml @@ -14,557 +14,170 @@ import EasyApp.Gui.Charts as EaCharts import Gui.Globals as Globals -Column { +Rectangle { id: container - property alias measSerie: measSerie - property alias bkgSerie: bkgSerie - property alias calcSerie: calcSerie - property alias residSerie: residSerie - - property var phaseNames: { - if (typeof Globals.Proxies.main.experiment.dataBlocksNoMeas[ - Globals.Proxies.main.experiment.currentIndex].loops._pd_phase_block !== 'undefined') { - return Globals.Proxies.main.experiment.dataBlocksNoMeas[ - Globals.Proxies.main.experiment.currentIndex].loops._pd_phase_block.map( - phase => phase.id.value) - } else if (typeof Globals.Proxies.main.experiment.dataBlocksNoMeas[ - Globals.Proxies.main.experiment.currentIndex].loops._exptl_crystal !== 'undefined') { - return Globals.Proxies.main.experiment.dataBlocksNoMeas[ - Globals.Proxies.main.experiment.currentIndex].loops._exptl_crystal.map( - phase => phase.id.value) - } else { - //console.error('No phase names found') - return [] - } - } - - property string calcSerieColor: EaStyle.Colors.chartForegrounds[0] - - property int extraMargin: -12 - property real residualToMainChartHeightRatio: 0.3 - property real mainChartHeightCoeff: 1 - residualToMainChartHeightRatio - - property bool useOpenGL: Globals.Proxies.main.fitting.isFittingNow ? - true : - EaGlobals.Vars.useOpenGL //Globals.Proxies.main.plotting.useWebGL1d - - Column { - width: parent.width - height: parent.height - 3 * EaStyle.Sizes.fontPixelSize + 2 - - /////////////////////////////////////////// - // Main chart container: Imeas, Icalc, Ibkg - /////////////////////////////////////////// - - Item { - width: parent.width - height: parent.height * mainChartHeightCoeff - - braggChart.parent.height * 0.5 - - EaCharts.QtCharts1dBase { - id: mainChart - - property var experimentDataBlocksNoMeas: Globals.Proxies.main.experiment.dataBlocksNoMeas - onExperimentDataBlocksNoMeasChanged: { - if (Globals.Proxies.experimentMainParam('_sample', 'type').value === 'pd') { - if (Globals.Proxies.experimentMainParam('_diffrn_radiation', 'type').value === 'cwl') { - axisX.title = '2θ (degree)' - } else if (Globals.Proxies.experimentMainParam('_diffrn_radiation', 'type').value === 'tof') { - axisX.title = 'TOF (µs)' - } else { - axisX.title = '' - } - } else if (Globals.Proxies.experimentMainParam('_sample', 'type').value === 'sg') { - axisX.title = 'sinθ/λ (Å⁻¹)' - } else { - axisX.title = '' - } - } - - anchors.topMargin: EaStyle.Sizes.toolButtonHeight - EaStyle.Sizes.fontPixelSize - 1 - anchors.bottomMargin: -12 - EaStyle.Sizes.fontPixelSize - - useOpenGL: container.useOpenGL - - axisX.titleVisible: false - axisX.labelsVisible: false - axisX.min: Globals.Proxies.rangeValue('xMin') - axisX.max: Globals.Proxies.rangeValue('xMax') - axisX.minAfterReset: Globals.Proxies.rangeValue('xMin') - axisX.maxAfterReset: Globals.Proxies.rangeValue('xMax') - axisX.onRangeChanged: alignAllCharts() - - axisY.title: Globals.Proxies.experimentMainParam('_sample', 'type').value === 'pd' ? - "Imeas, Icalc, Ibkg" : - "Imeas, Icalc" - axisY.min: Globals.Proxies.rangeValue('yMin') - axisY.max: Globals.Proxies.rangeValue('yMax') - axisY.minAfterReset: Globals.Proxies.rangeValue('yMin') - axisY.maxAfterReset: Globals.Proxies.rangeValue('yMax') - axisY.onRangeChanged: adjustResidualChartRangeY() - - backgroundColor: "transparent" - plotAreaColor: "transparent" - - // Measured points - /* - ScatterSeries { - id: measSerie - - axisX: mainChart.axisX - axisY: mainChart.axisY - - useOpenGL: mainChart.useOpenGL - - markerSize: 5 - borderWidth: 1 - color: EaStyle.Colors.chartForegroundsExtra[2] - borderColor: this.color - } - */ - LineSeries { - id: measSerie - - axisX: mainChart.axisX - axisY: mainChart.axisY - - //useOpenGL: mainChart.useOpenGL - - color: EaStyle.Colors.chartForegroundsExtra[2] - width: 2 - - //style: Globals.Proxies.experimentMainParam('_sample', 'type').value === 'pd' ? - // Qt.SolidLine : - // Qt.NoPen - pointsVisible: true - - onHovered: (point, state) => showMainTooltip(mainChart, point, state) - } - - // Background curve - LineSeries { - id: bkgSerie - - axisX: mainChart.axisX - axisY: mainChart.axisY - - //useOpenGL: mainChart.useOpenGL - - color: EaStyle.Colors.chartForegrounds[1] - width: 1 - - onHovered: (point, state) => showMainTooltip(mainChart, point, state) - } - - // Calculated curve - LineSeries { - id: calcSerie - - axisX: mainChart.axisX - axisY: mainChart.axisY - - //useOpenGL: mainChart.useOpenGL - - color: calcSerieColor - width: 2 - - //style: Globals.Proxies.experimentMainParam('_sample', 'type').value === 'pd' ? - // Qt.SolidLine : - // Qt.NoPen - //pointsVisible: Globals.Proxies.experimentMainParam('_sample', 'type').value === 'pd' ? - // false : - // true - - onHovered: (point, state) => showMainTooltip(mainChart, point, state) - } - - // Tool buttons - Row { - id: toolButtons - - x: mainChart.plotArea.x + mainChart.plotArea.width - width - y: mainChart.plotArea.y - height - EaStyle.Sizes.fontPixelSize - - spacing: 0.25 * EaStyle.Sizes.fontPixelSize - - EaElements.TabButton { - checked: Globals.Vars.showLegendOnAnalysisPage - autoExclusive: false - height: EaStyle.Sizes.toolButtonHeight - width: EaStyle.Sizes.toolButtonHeight - borderColor: EaStyle.Colors.chartAxis - fontIcon: "align-left" - ToolTip.text: Globals.Vars.showLegendOnAnalysisPage ? - qsTr("Hide legend") : - qsTr("Show legend") - onClicked: Globals.Vars.showLegendOnAnalysisPage = checked - } - - EaElements.TabButton { - checked: mainChart.allowHover - autoExclusive: false - height: EaStyle.Sizes.toolButtonHeight - width: EaStyle.Sizes.toolButtonHeight - borderColor: EaStyle.Colors.chartAxis - fontIcon: "comment-alt" - ToolTip.text: qsTr("Show coordinates tooltip on hover") - onClicked: mainChart.allowHover = !mainChart.allowHover - } - - Item { height: 1; width: 0.5 * EaStyle.Sizes.fontPixelSize } // spacer - - EaElements.TabButton { - checked: !mainChart.allowZoom - autoExclusive: false - height: EaStyle.Sizes.toolButtonHeight - width: EaStyle.Sizes.toolButtonHeight - borderColor: EaStyle.Colors.chartAxis - fontIcon: "arrows-alt" - ToolTip.text: qsTr("Enable pan") - onClicked: mainChart.allowZoom = !mainChart.allowZoom - } - - EaElements.TabButton { - checked: mainChart.allowZoom - autoExclusive: false - height: EaStyle.Sizes.toolButtonHeight - width: EaStyle.Sizes.toolButtonHeight - borderColor: EaStyle.Colors.chartAxis - fontIcon: "expand" - ToolTip.text: qsTr("Enable box zoom") - onClicked: mainChart.allowZoom = !mainChart.allowZoom - } - - EaElements.TabButton { - checkable: false - height: EaStyle.Sizes.toolButtonHeight - width: EaStyle.Sizes.toolButtonHeight - borderColor: EaStyle.Colors.chartAxis - fontIcon: "backspace" - ToolTip.text: qsTr("Reset axes") - onClicked: mainChart.resetAxes() - } - - } - // Tool buttons + color: EaStyle.Colors.chartBackground + EaCharts.QtCharts1dMeasVsCalc { + id: chartView + + property alias calculated: chartView.calcSerie + property alias measured: chartView.measSerie +// property alias errorLower: chartView.bkgSerie + bkgSerie.color: measSerie.color + measSerie.width: 1 + bkgSerie.width: 1 + + anchors.topMargin: EaStyle.Sizes.toolButtonHeight - EaStyle.Sizes.fontPixelSize - 1 + + useOpenGL: EaGlobals.Vars.useOpenGL + + property double xRange: Globals.BackendWrapper.plottingAnalysisMaxX - Globals.BackendWrapper.plottingAnalysisMinX + axisX.title: "q (Å⁻¹)" + axisX.min: Globals.BackendWrapper.plottingAnalysisMinX - xRange * 0.01 + axisX.max: Globals.BackendWrapper.plottingAnalysisMaxX + xRange * 0.01 + axisX.minAfterReset: Globals.BackendWrapper.plottingAnalysisMinX - xRange * 0.01 + axisX.maxAfterReset: Globals.BackendWrapper.plottingAnalysisMaxX + xRange * 0.01 + + property double yRange: Globals.BackendWrapper.plottingAnalysisMaxY - Globals.BackendWrapper.plottingAnalysisMinY + axisY.title: "Log10 R(q)" + axisY.min: Globals.BackendWrapper.plottingAnalysisMinY - yRange * 0.01 + axisY.max: Globals.BackendWrapper.plottingAnalysisMaxY + yRange * 0.01 + axisY.minAfterReset: Globals.BackendWrapper.plottingAnalysisMinY - yRange * 0.01 + axisY.maxAfterReset: Globals.BackendWrapper.plottingAnalysisMaxY + yRange * 0.01 + + calcSerie.onHovered: (point, state) => showMainTooltip(chartView, point, state) + + // Tool buttons + Row { + id: toolButtons + + x: chartView.plotArea.x + chartView.plotArea.width - width + y: chartView.plotArea.y - height - EaStyle.Sizes.fontPixelSize + + spacing: 0.25 * EaStyle.Sizes.fontPixelSize + + EaElements.TabButton { + checked: Globals.Variables.showLegendOnAnalysisPage + autoExclusive: false + height: EaStyle.Sizes.toolButtonHeight + width: EaStyle.Sizes.toolButtonHeight + borderColor: EaStyle.Colors.chartAxis + fontIcon: "align-left" + ToolTip.text: Globals.Variables.showLegendOnAnalysisPage ? + qsTr("Hide legend") : + qsTr("Show legend") + onClicked: Globals.Variables.showLegendOnAnalysisPage = checked } - } - - ////////////////////////////////////// - // Bragg peaks chart container: Bragg - ////////////////////////////////////// - - Item { - z: -1 - width: parent.width - height: (0.5 + 1.5 * phaseNames.length) * EaStyle.Sizes.fontPixelSize - - - /////onHeightChanged: console.info(`================== ${height} - ${phaseNames.length}`) - //visible: false - - EaCharts.QtCharts1dBase { - id: braggChart - - anchors.topMargin: -12 - EaStyle.Sizes.fontPixelSize * 1.5 - anchors.bottomMargin: -12 - EaStyle.Sizes.fontPixelSize * 1.5 - - useOpenGL: container.useOpenGL - - axisX.min: mainChart.axisX.min - axisX.max: mainChart.axisX.max - axisX.titleVisible: false - axisX.labelsVisible: false - - axisY.min: -0.5 * phaseNames.length - axisY.max: 0.5 - axisY.titleVisible: false - axisY.labelsVisible: false - axisY.tickCount: 2 - backgroundColor: "transparent" - plotAreaColor: "transparent" - - //onSeriesAdded: { console.error(series) } - - /* - ScatterSeries { - id: braggSerie - - axisX: braggChart.axisX - axisY: braggChart.axisY - - //useOpenGL: braggChart.useOpenGL - - brush: Globals.Proxies.main.plotting.verticalLine( - 1.5 * EaStyle.Sizes.fontPixelSize, - EaStyle.Colors.chartForegroundsExtra[0]) - borderWidth: 0.001 - borderColor: 'transparent' - - Component.onCompleted: console.error(this) - } - */ + EaElements.TabButton { + checked: chartView.allowHover + autoExclusive: false + height: EaStyle.Sizes.toolButtonHeight + width: EaStyle.Sizes.toolButtonHeight + borderColor: EaStyle.Colors.chartAxis + fontIcon: "comment-alt" + ToolTip.text: qsTr("Show coordinates tooltip on hover") + onClicked: chartView.allowHover = !chartView.allowHover } - } - - ////////////////////////////////////////// - // Residual chart container: Imeas - Icalc - ////////////////////////////////////////// - - Item { - width: parent.width - height: parent.height * residualToMainChartHeightRatio - - braggChart.parent.height * 0.5 - - EaCharts.QtCharts1dBase { - id: residualChart - - anchors.topMargin: -12 - EaStyle.Sizes.fontPixelSize - - useOpenGL: container.useOpenGL - - axisX.min: mainChart.axisX.min - axisX.max: mainChart.axisX.max - axisX.titleVisible: false - axisX.labelsVisible: false - - axisY.min: Globals.Proxies.main.plotting.chartRanges.yMin - axisY.max: Globals.Proxies.main.plotting.chartRanges.yMax - axisY.tickType: ValueAxis.TicksFixed - axisY.tickCount: 3 - axisY.title: 'Imeas - Icalc' - - backgroundColor: "transparent" - plotAreaColor: "transparent" - LineSeries { - id: residSerie - - axisX: residualChart.axisX - axisY: residualChart.axisY - - //useOpenGL: residualChart.useOpenGL - - color: EaStyle.Colors.chartForegrounds[2] - - onHovered: (point, state) => showMainTooltip(residualChart, point, state) - } + Item { height: 1; width: 0.5 * EaStyle.Sizes.fontPixelSize } // spacer + + EaElements.TabButton { + checked: !chartView.allowZoom + autoExclusive: false + height: EaStyle.Sizes.toolButtonHeight + width: EaStyle.Sizes.toolButtonHeight + borderColor: EaStyle.Colors.chartAxis + fontIcon: "arrows-alt" + ToolTip.text: qsTr("Enable pan") + onClicked: chartView.allowZoom = !chartView.allowZoom } - } - } - ///////////////////////// - // X-axis chart container - ///////////////////////// + EaElements.TabButton { + checked: chartView.allowZoom + autoExclusive: false + height: EaStyle.Sizes.toolButtonHeight + width: EaStyle.Sizes.toolButtonHeight + borderColor: EaStyle.Colors.chartAxis + fontIcon: "expand" + ToolTip.text: qsTr("Enable box zoom") + onClicked: chartView.allowZoom = !chartView.allowZoom + } - Item { - z: -1 - width: parent.width - height: container.height - parent: container.parent + EaElements.TabButton { + checkable: false + height: EaStyle.Sizes.toolButtonHeight + width: EaStyle.Sizes.toolButtonHeight + borderColor: EaStyle.Colors.chartAxis + fontIcon: "backspace" + ToolTip.text: qsTr("Reset axes") + onClicked: chartView.resetAxes() + } - EaCharts.QtCharts1dBase { - id: xAxisChart + } + // Tool buttons - axisX.title: mainChart.axisX.title - axisX.min: mainChart.axisX.min - axisX.max: mainChart.axisX.max - axisX.lineVisible: false - axisX.gridVisible: false + // Legend + Rectangle { + visible: Globals.Variables.showLegendOnAnalysisPage - axisY.titleVisible: false - axisY.labelsVisible: false - axisY.visible: false + x: chartView.plotArea.x + chartView.plotArea.width - width - EaStyle.Sizes.fontPixelSize + y: chartView.plotArea.y + EaStyle.Sizes.fontPixelSize + width: childrenRect.width + height: childrenRect.height - LineSeries { - axisX: xAxisChart.axisX - axisY: xAxisChart.axisY + color: EaStyle.Colors.mainContentBackgroundHalfTransparent + border.color: EaStyle.Colors.chartGridLine - Component.onCompleted: initialChartsSetupTimer.start() + Column { + leftPadding: EaStyle.Sizes.fontPixelSize + rightPadding: EaStyle.Sizes.fontPixelSize + topPadding: EaStyle.Sizes.fontPixelSize * 0.5 + bottomPadding: EaStyle.Sizes.fontPixelSize * 0.5 - Timer { - id: initialChartsSetupTimer - interval: 50 - onTriggered: { - alignAllCharts() - adjustResidualChartRangeY() - } + EaElements.Label { + text: '━ I (Measured)' + color: chartView.measSerie.color + } + EaElements.Label { + text: '━ (calculated)' + color: chartView.calcSerie.color } } } - } - - ///////// - // Legend - ///////// - - Rectangle { - visible: Globals.Vars.showLegendOnAnalysisPage - parent: container.parent - - x: mainChart.plotArea.x + mainChart.plotArea.width - width - 12 - EaStyle.Sizes.fontPixelSize - y: mainChart.plotArea.y - 12 + EaStyle.Sizes.fontPixelSize + mainChart.anchors.topMargin + EaStyle.Sizes.fontPixelSize - 1 - width: childrenRect.width - height: childrenRect.height + // Legend - color: EaStyle.Colors.mainContentBackgroundHalfTransparent - border.color: EaStyle.Colors.chartGridLine + EaElements.ToolTip { + id: dataToolTip - Column { - id: legendColumn - - leftPadding: EaStyle.Sizes.fontPixelSize - rightPadding: EaStyle.Sizes.fontPixelSize - topPadding: EaStyle.Sizes.fontPixelSize * 0.5 - bottomPadding: EaStyle.Sizes.fontPixelSize * 0.5 - - EaElements.Label { - text: '━ Measured (Imeas)' - color: measSerie.color - } - EaElements.Label { - text: Globals.Proxies.experimentMainParam('_sample', 'type').value === 'pd' ? - '━ Total calculated (Icalc)' : - '━ Calculated (Icalc)' - color: calcSerie.color - } - EaElements.Label { - visible: Globals.Proxies.experimentMainParam('_sample', 'type').value === 'pd' - text: '─ Background (Ibkg)' - color: bkgSerie.color - } - EaElements.Label { - text: '━ Residual (Imeas - Icalc)' - color: residSerie.color - } - /* - EaElements.Label { - text: '│ Ibragg (Bragg peaks)' - color: EaStyle.Colors.chartForegroundsExtra[0] //braggSerie.color - } - */ + arrowLength: 0 + textFormat: Text.RichText } - } - - /////////// - // ToolTips - /////////// - - EaElements.ToolTip { - id: dataToolTip - - arrowLength: 0 - textFormat: Text.RichText - } - - // Save references to chart series to be accessible from Python for updating data - Component.onCompleted: { - Globals.Refs.app.analysisPage.plotView = this - Globals.Proxies.main.plotting.setQtChartsSerieRef('analysisPage', - 'measSerie', - this.measSerie) - Globals.Proxies.main.plotting.setQtChartsSerieRef('analysisPage', - 'bkgSerie', - this.bkgSerie) - Globals.Proxies.main.plotting.setQtChartsSerieRef('analysisPage', - 'totalCalcSerie', - this.calcSerie) - Globals.Proxies.main.plotting.setQtChartsSerieRef('analysisPage', - 'residSerie', - this.residSerie) - //Globals.Proxies.main.plotting.setQtChartsSerieRef('analysisPage', - // 'braggSerie', - // this.braggSerie) - createBraggSeries() - - Globals.Proxies.main.analysis.defined = true - } - // Logic - - function residualChartMeanY() { - return 0 - } - - function residualChartHalfRangeY() { - if (mainChart.plotArea.height === 0) { - return 0.5 + // Data is set in python backend (plotting_1d.py) + Component.onCompleted: { + Globals.References.pages.analysis.mainContent.analysisView = chartView + Globals.BackendWrapper.plottingSetQtChartsSerieRef('analysisPage', + 'measuredSerie', + measured) + Globals.BackendWrapper.plottingSetQtChartsSerieRef('analysisPage', + 'calculatedSerie', + calculated) } - - const mainChartRangeY = mainChart.axisY.max - mainChart.axisY.min - const residualToMainChartHeightRatio = residualChart.plotArea.height / mainChart.plotArea.height - const residualChartRangeY = mainChartRangeY * residualToMainChartHeightRatio - return 0.5 * residualChartRangeY - } - - function adjustResidualChartRangeY() { - residualChart.axisY.min = residualChartMeanY() - residualChartHalfRangeY() - residualChart.axisY.max = residualChartMeanY() + residualChartHalfRangeY() - console.debug('Residual chart Y-range has been adjusted') } - function alignAllCharts() { - xAxisChart.plotArea.width -= mainChart.plotArea.x - xAxisChart.plotArea.x - xAxisChart.plotArea.x = mainChart.plotArea.x - residualChart.plotArea.width = xAxisChart.plotArea.width - residualChart.plotArea.x = mainChart.plotArea.x - braggChart.plotArea.width = xAxisChart.plotArea.width - braggChart.plotArea.x = mainChart.plotArea.x - mainChart.plotArea.width = xAxisChart.plotArea.width - console.debug('All charts have been aligned') - } + // Logic function showMainTooltip(chart, point, state) { - if (!mainChart.allowHover) { + if (!chartView.allowHover) { return } const pos = chart.mapToPosition(Qt.point(point.x, point.y)) dataToolTip.x = pos.x dataToolTip.y = pos.y - dataToolTip.text = `

x: ${point.x.toFixed(2)}y: ${point.y.toFixed(2)}

` + dataToolTip.text = `

x: ${point.x.toFixed(3)}y: ${point.y.toFixed(3)}

` dataToolTip.parent = chart dataToolTip.visible = state } - - function createBraggSeries() { - for (const phaseIdx in phaseNames) { - const phaseName = phaseNames[phaseIdx] - const serie = braggChart.createSeries(ChartView.SeriesTypeScatter, - phaseName, - braggChart.axisX, - braggChart.axisY) - const markerSize = //serie.useOpenGL ? - //5 : // don't work here... :( - 1.5 * EaStyle.Sizes.fontPixelSize - serie.useOpenGL = braggChart.useOpenGL - //serie.useOpenGL = Globals.Proxies.main.fitting.isFittingNow - serie.brush = Globals.Proxies.main.plotting.verticalLine( - markerSize, - EaStyle.Colors.models[phaseIdx]) - serie.borderWidth = 0.001 - serie.borderColor = 'transparent' - //serie.markerShape = ScatterSeries.MarkerShapeRectangle - serie.markerSize = serie.useOpenGL ? - 0 : - markerSize - - Globals.Proxies.main.plotting.setQtChartsSerieRef('analysisPage', - 'braggSeries', - serie) - - const legendItem = Qt.createQmlObject('import EasyApp.Gui.Elements as EaElements; EaElements.Label {}', legendColumn) - const textFont = `'${EaStyle.Fonts.fontFamily}'` - const iconFont = `'${EaStyle.Fonts.iconsFamily}'` - const textColor = `'${EaStyle.Colors.models[phaseIdx]}'` - const iconColor = `'${EaStyle.Colors.models[phaseIdx]}'` - const textHtmlStart = `│  Bragg peaks` - const iconHtml = `layer-group` - const textHtmlEnd = `${phaseName}` - legendItem.text = `${textHtmlStart} ${iconHtml} ${textHtmlEnd}` - legendItem.textFormat = Text.RichText - } - } - } diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/MainContent/diffraction_AnalysisView.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/MainContent/diffraction_AnalysisView.qml new file mode 100644 index 00000000..42a45bd3 --- /dev/null +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/MainContent/diffraction_AnalysisView.qml @@ -0,0 +1,570 @@ +// SPDX-FileCopyrightText: 2023 EasyDiffraction contributors +// SPDX-License-Identifier: BSD-3-Clause +// © 2023 Contributors to the EasyDiffraction project + +import QtQuick +import QtQuick.Controls +import QtCharts + +import EasyApp.Gui.Style as EaStyle +import EasyApp.Gui.Globals as EaGlobals +import EasyApp.Gui.Elements as EaElements +import EasyApp.Gui.Charts as EaCharts + +import Gui.Globals as Globals + + +Column { + id: container + + property alias measSerie: measSerie + property alias bkgSerie: bkgSerie + property alias calcSerie: calcSerie + property alias residSerie: residSerie + + property var phaseNames: { + if (typeof Globals.Proxies.main.experiment.dataBlocksNoMeas[ + Globals.Proxies.main.experiment.currentIndex].loops._pd_phase_block !== 'undefined') { + return Globals.Proxies.main.experiment.dataBlocksNoMeas[ + Globals.Proxies.main.experiment.currentIndex].loops._pd_phase_block.map( + phase => phase.id.value) + } else if (typeof Globals.Proxies.main.experiment.dataBlocksNoMeas[ + Globals.Proxies.main.experiment.currentIndex].loops._exptl_crystal !== 'undefined') { + return Globals.Proxies.main.experiment.dataBlocksNoMeas[ + Globals.Proxies.main.experiment.currentIndex].loops._exptl_crystal.map( + phase => phase.id.value) + } else { + //console.error('No phase names found') + return [] + } + } + + property string calcSerieColor: EaStyle.Colors.chartForegrounds[0] + + property int extraMargin: -12 + property real residualToMainChartHeightRatio: 0.3 + property real mainChartHeightCoeff: 1 - residualToMainChartHeightRatio + + property bool useOpenGL: Globals.Proxies.main.fitting.isFittingNow ? + true : + EaGlobals.Vars.useOpenGL //Globals.Proxies.main.plotting.useWebGL1d + + Column { + width: parent.width + height: parent.height - 3 * EaStyle.Sizes.fontPixelSize + 2 + + /////////////////////////////////////////// + // Main chart container: Imeas, Icalc, Ibkg + /////////////////////////////////////////// + + Item { + width: parent.width + height: parent.height * mainChartHeightCoeff - + braggChart.parent.height * 0.5 + + EaCharts.QtCharts1dBase { + id: mainChart + + property var experimentDataBlocksNoMeas: Globals.Proxies.main.experiment.dataBlocksNoMeas + onExperimentDataBlocksNoMeasChanged: { + if (Globals.Proxies.experimentMainParam('_sample', 'type').value === 'pd') { + if (Globals.Proxies.experimentMainParam('_diffrn_radiation', 'type').value === 'cwl') { + axisX.title = '2θ (degree)' + } else if (Globals.Proxies.experimentMainParam('_diffrn_radiation', 'type').value === 'tof') { + axisX.title = 'TOF (µs)' + } else { + axisX.title = '' + } + } else if (Globals.Proxies.experimentMainParam('_sample', 'type').value === 'sg') { + axisX.title = 'sinθ/λ (Å⁻¹)' + } else { + axisX.title = '' + } + } + + anchors.topMargin: EaStyle.Sizes.toolButtonHeight - EaStyle.Sizes.fontPixelSize - 1 + anchors.bottomMargin: -12 - EaStyle.Sizes.fontPixelSize + + useOpenGL: container.useOpenGL + + axisX.titleVisible: false + axisX.labelsVisible: false + axisX.min: Globals.Proxies.rangeValue('xMin') + axisX.max: Globals.Proxies.rangeValue('xMax') + axisX.minAfterReset: Globals.Proxies.rangeValue('xMin') + axisX.maxAfterReset: Globals.Proxies.rangeValue('xMax') + axisX.onRangeChanged: alignAllCharts() + + axisY.title: Globals.Proxies.experimentMainParam('_sample', 'type').value === 'pd' ? + "Imeas, Icalc, Ibkg" : + "Imeas, Icalc" + axisY.min: Globals.Proxies.rangeValue('yMin') + axisY.max: Globals.Proxies.rangeValue('yMax') + axisY.minAfterReset: Globals.Proxies.rangeValue('yMin') + axisY.maxAfterReset: Globals.Proxies.rangeValue('yMax') + axisY.onRangeChanged: adjustResidualChartRangeY() + + backgroundColor: "transparent" + plotAreaColor: "transparent" + + // Measured points + /* + ScatterSeries { + id: measSerie + + axisX: mainChart.axisX + axisY: mainChart.axisY + + useOpenGL: mainChart.useOpenGL + + markerSize: 5 + borderWidth: 1 + color: EaStyle.Colors.chartForegroundsExtra[2] + borderColor: this.color + } + */ + LineSeries { + id: measSerie + + axisX: mainChart.axisX + axisY: mainChart.axisY + + //useOpenGL: mainChart.useOpenGL + + color: EaStyle.Colors.chartForegroundsExtra[2] + width: 2 + + //style: Globals.Proxies.experimentMainParam('_sample', 'type').value === 'pd' ? + // Qt.SolidLine : + // Qt.NoPen + pointsVisible: true + + onHovered: (point, state) => showMainTooltip(mainChart, point, state) + } + + // Background curve + LineSeries { + id: bkgSerie + + axisX: mainChart.axisX + axisY: mainChart.axisY + + //useOpenGL: mainChart.useOpenGL + + color: EaStyle.Colors.chartForegrounds[1] + width: 1 + + onHovered: (point, state) => showMainTooltip(mainChart, point, state) + } + + // Calculated curve + LineSeries { + id: calcSerie + + axisX: mainChart.axisX + axisY: mainChart.axisY + + //useOpenGL: mainChart.useOpenGL + + color: calcSerieColor + width: 2 + + //style: Globals.Proxies.experimentMainParam('_sample', 'type').value === 'pd' ? + // Qt.SolidLine : + // Qt.NoPen + //pointsVisible: Globals.Proxies.experimentMainParam('_sample', 'type').value === 'pd' ? + // false : + // true + + onHovered: (point, state) => showMainTooltip(mainChart, point, state) + } + + // Tool buttons + Row { + id: toolButtons + + x: mainChart.plotArea.x + mainChart.plotArea.width - width + y: mainChart.plotArea.y - height - EaStyle.Sizes.fontPixelSize + + spacing: 0.25 * EaStyle.Sizes.fontPixelSize + + EaElements.TabButton { + checked: Globals.Vars.showLegendOnAnalysisPage + autoExclusive: false + height: EaStyle.Sizes.toolButtonHeight + width: EaStyle.Sizes.toolButtonHeight + borderColor: EaStyle.Colors.chartAxis + fontIcon: "align-left" + ToolTip.text: Globals.Vars.showLegendOnAnalysisPage ? + qsTr("Hide legend") : + qsTr("Show legend") + onClicked: Globals.Vars.showLegendOnAnalysisPage = checked + } + + EaElements.TabButton { + checked: mainChart.allowHover + autoExclusive: false + height: EaStyle.Sizes.toolButtonHeight + width: EaStyle.Sizes.toolButtonHeight + borderColor: EaStyle.Colors.chartAxis + fontIcon: "comment-alt" + ToolTip.text: qsTr("Show coordinates tooltip on hover") + onClicked: mainChart.allowHover = !mainChart.allowHover + } + + Item { height: 1; width: 0.5 * EaStyle.Sizes.fontPixelSize } // spacer + + EaElements.TabButton { + checked: !mainChart.allowZoom + autoExclusive: false + height: EaStyle.Sizes.toolButtonHeight + width: EaStyle.Sizes.toolButtonHeight + borderColor: EaStyle.Colors.chartAxis + fontIcon: "arrows-alt" + ToolTip.text: qsTr("Enable pan") + onClicked: mainChart.allowZoom = !mainChart.allowZoom + } + + EaElements.TabButton { + checked: mainChart.allowZoom + autoExclusive: false + height: EaStyle.Sizes.toolButtonHeight + width: EaStyle.Sizes.toolButtonHeight + borderColor: EaStyle.Colors.chartAxis + fontIcon: "expand" + ToolTip.text: qsTr("Enable box zoom") + onClicked: mainChart.allowZoom = !mainChart.allowZoom + } + + EaElements.TabButton { + checkable: false + height: EaStyle.Sizes.toolButtonHeight + width: EaStyle.Sizes.toolButtonHeight + borderColor: EaStyle.Colors.chartAxis + fontIcon: "backspace" + ToolTip.text: qsTr("Reset axes") + onClicked: mainChart.resetAxes() + } + + } + // Tool buttons + } + } + + ////////////////////////////////////// + // Bragg peaks chart container: Bragg + ////////////////////////////////////// + + Item { + z: -1 + width: parent.width + height: (0.5 + 1.5 * phaseNames.length) * EaStyle.Sizes.fontPixelSize + + + /////onHeightChanged: console.info(`================== ${height} - ${phaseNames.length}`) + //visible: false + + EaCharts.QtCharts1dBase { + id: braggChart + + anchors.topMargin: -12 - EaStyle.Sizes.fontPixelSize * 1.5 + anchors.bottomMargin: -12 - EaStyle.Sizes.fontPixelSize * 1.5 + + useOpenGL: container.useOpenGL + + axisX.min: mainChart.axisX.min + axisX.max: mainChart.axisX.max + axisX.titleVisible: false + axisX.labelsVisible: false + + axisY.min: -0.5 * phaseNames.length + axisY.max: 0.5 + axisY.titleVisible: false + axisY.labelsVisible: false + axisY.tickCount: 2 + + backgroundColor: "transparent" + plotAreaColor: "transparent" + + //onSeriesAdded: { console.error(series) } + + /* + ScatterSeries { + id: braggSerie + + axisX: braggChart.axisX + axisY: braggChart.axisY + + //useOpenGL: braggChart.useOpenGL + + brush: Globals.Proxies.main.plotting.verticalLine( + 1.5 * EaStyle.Sizes.fontPixelSize, + EaStyle.Colors.chartForegroundsExtra[0]) + borderWidth: 0.001 + borderColor: 'transparent' + + Component.onCompleted: console.error(this) + } + */ + } + } + + ////////////////////////////////////////// + // Residual chart container: Imeas - Icalc + ////////////////////////////////////////// + + Item { + width: parent.width + height: parent.height * residualToMainChartHeightRatio - + braggChart.parent.height * 0.5 + + EaCharts.QtCharts1dBase { + id: residualChart + + anchors.topMargin: -12 - EaStyle.Sizes.fontPixelSize + + useOpenGL: container.useOpenGL + + axisX.min: mainChart.axisX.min + axisX.max: mainChart.axisX.max + axisX.titleVisible: false + axisX.labelsVisible: false + + axisY.min: Globals.Proxies.main.plotting.chartRanges.yMin + axisY.max: Globals.Proxies.main.plotting.chartRanges.yMax + axisY.tickType: ValueAxis.TicksFixed + axisY.tickCount: 3 + axisY.title: 'Imeas - Icalc' + + backgroundColor: "transparent" + plotAreaColor: "transparent" + + LineSeries { + id: residSerie + + axisX: residualChart.axisX + axisY: residualChart.axisY + + //useOpenGL: residualChart.useOpenGL + + color: EaStyle.Colors.chartForegrounds[2] + + onHovered: (point, state) => showMainTooltip(residualChart, point, state) + } + } + } + } + + ///////////////////////// + // X-axis chart container + ///////////////////////// + + Item { + z: -1 + width: parent.width + height: container.height + parent: container.parent + + EaCharts.QtCharts1dBase { + id: xAxisChart + + axisX.title: mainChart.axisX.title + axisX.min: mainChart.axisX.min + axisX.max: mainChart.axisX.max + axisX.lineVisible: false + axisX.gridVisible: false + + axisY.titleVisible: false + axisY.labelsVisible: false + axisY.visible: false + + LineSeries { + axisX: xAxisChart.axisX + axisY: xAxisChart.axisY + + Component.onCompleted: initialChartsSetupTimer.start() + + Timer { + id: initialChartsSetupTimer + interval: 50 + onTriggered: { + alignAllCharts() + adjustResidualChartRangeY() + } + } + } + } + } + + ///////// + // Legend + ///////// + + Rectangle { + visible: Globals.Vars.showLegendOnAnalysisPage + parent: container.parent + + x: mainChart.plotArea.x + mainChart.plotArea.width - width - 12 - EaStyle.Sizes.fontPixelSize + y: mainChart.plotArea.y - 12 + EaStyle.Sizes.fontPixelSize + mainChart.anchors.topMargin + EaStyle.Sizes.fontPixelSize - 1 + width: childrenRect.width + height: childrenRect.height + + color: EaStyle.Colors.mainContentBackgroundHalfTransparent + border.color: EaStyle.Colors.chartGridLine + + Column { + id: legendColumn + + leftPadding: EaStyle.Sizes.fontPixelSize + rightPadding: EaStyle.Sizes.fontPixelSize + topPadding: EaStyle.Sizes.fontPixelSize * 0.5 + bottomPadding: EaStyle.Sizes.fontPixelSize * 0.5 + + EaElements.Label { + text: '━ Measured (Imeas)' + color: measSerie.color + } + EaElements.Label { + text: Globals.Proxies.experimentMainParam('_sample', 'type').value === 'pd' ? + '━ Total calculated (Icalc)' : + '━ Calculated (Icalc)' + color: calcSerie.color + } + EaElements.Label { + visible: Globals.Proxies.experimentMainParam('_sample', 'type').value === 'pd' + text: '─ Background (Ibkg)' + color: bkgSerie.color + } + EaElements.Label { + text: '━ Residual (Imeas - Icalc)' + color: residSerie.color + } + /* + EaElements.Label { + text: '│ Ibragg (Bragg peaks)' + color: EaStyle.Colors.chartForegroundsExtra[0] //braggSerie.color + } + */ + } + } + + /////////// + // ToolTips + /////////// + + EaElements.ToolTip { + id: dataToolTip + + arrowLength: 0 + textFormat: Text.RichText + } + + // Save references to chart series to be accessible from Python for updating data + Component.onCompleted: { + Globals.Refs.app.analysisPage.plotView = this + Globals.Proxies.main.plotting.setQtChartsSerieRef('analysisPage', + 'measSerie', + this.measSerie) + Globals.Proxies.main.plotting.setQtChartsSerieRef('analysisPage', + 'bkgSerie', + this.bkgSerie) + Globals.Proxies.main.plotting.setQtChartsSerieRef('analysisPage', + 'totalCalcSerie', + this.calcSerie) + Globals.Proxies.main.plotting.setQtChartsSerieRef('analysisPage', + 'residSerie', + this.residSerie) + //Globals.Proxies.main.plotting.setQtChartsSerieRef('analysisPage', + // 'braggSerie', + // this.braggSerie) + createBraggSeries() + + Globals.Proxies.main.analysis.defined = true + } + + // Logic + + function residualChartMeanY() { + return 0 + } + + function residualChartHalfRangeY() { + if (mainChart.plotArea.height === 0) { + return 0.5 + } + + const mainChartRangeY = mainChart.axisY.max - mainChart.axisY.min + const residualToMainChartHeightRatio = residualChart.plotArea.height / mainChart.plotArea.height + const residualChartRangeY = mainChartRangeY * residualToMainChartHeightRatio + return 0.5 * residualChartRangeY + } + + function adjustResidualChartRangeY() { + residualChart.axisY.min = residualChartMeanY() - residualChartHalfRangeY() + residualChart.axisY.max = residualChartMeanY() + residualChartHalfRangeY() + console.debug('Residual chart Y-range has been adjusted') + } + + function alignAllCharts() { + xAxisChart.plotArea.width -= mainChart.plotArea.x - xAxisChart.plotArea.x + xAxisChart.plotArea.x = mainChart.plotArea.x + residualChart.plotArea.width = xAxisChart.plotArea.width + residualChart.plotArea.x = mainChart.plotArea.x + braggChart.plotArea.width = xAxisChart.plotArea.width + braggChart.plotArea.x = mainChart.plotArea.x + mainChart.plotArea.width = xAxisChart.plotArea.width + console.debug('All charts have been aligned') + } + + function showMainTooltip(chart, point, state) { + if (!mainChart.allowHover) { + return + } + const pos = chart.mapToPosition(Qt.point(point.x, point.y)) + dataToolTip.x = pos.x + dataToolTip.y = pos.y + dataToolTip.text = `

x: ${point.x.toFixed(2)}y: ${point.y.toFixed(2)}

` + dataToolTip.parent = chart + dataToolTip.visible = state + } + + function createBraggSeries() { + for (const phaseIdx in phaseNames) { + const phaseName = phaseNames[phaseIdx] + const serie = braggChart.createSeries(ChartView.SeriesTypeScatter, + phaseName, + braggChart.axisX, + braggChart.axisY) + const markerSize = //serie.useOpenGL ? + //5 : // don't work here... :( + 1.5 * EaStyle.Sizes.fontPixelSize + serie.useOpenGL = braggChart.useOpenGL + //serie.useOpenGL = Globals.Proxies.main.fitting.isFittingNow + serie.brush = Globals.Proxies.main.plotting.verticalLine( + markerSize, + EaStyle.Colors.models[phaseIdx]) + serie.borderWidth = 0.001 + serie.borderColor = 'transparent' + //serie.markerShape = ScatterSeries.MarkerShapeRectangle + serie.markerSize = serie.useOpenGL ? + 0 : + markerSize + + Globals.Proxies.main.plotting.setQtChartsSerieRef('analysisPage', + 'braggSeries', + serie) + + const legendItem = Qt.createQmlObject('import EasyApp.Gui.Elements as EaElements; EaElements.Label {}', legendColumn) + const textFont = `'${EaStyle.Fonts.fontFamily}'` + const iconFont = `'${EaStyle.Fonts.iconsFamily}'` + const textColor = `'${EaStyle.Colors.models[phaseIdx]}'` + const iconColor = `'${EaStyle.Colors.models[phaseIdx]}'` + const textHtmlStart = `│  Bragg peaks` + const iconHtml = `layer-group` + const textHtmlEnd = `${phaseName}` + legendItem.text = `${textHtmlStart} ${iconHtml} ${textHtmlEnd}` + legendItem.textFormat = Text.RichText + } + } + +} diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Groups/Fitting.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Groups/Fitting.qml index 81ee238f..f4e09c93 100644 --- a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Groups/Fitting.qml +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Groups/Fitting.qml @@ -31,8 +31,8 @@ EaElements.GroupBox { Globals.Proxies.main.fitting.startStop() } - Component.onCompleted: Globals.Refs.app.analysisPage.startFittingButton = this - + //Component.onCompleted: Globals.Refs.app.analysisPage.startFittingButton = this + Component.onCompleted: Globals.References.pages.analysis.sidebar.basic.popups.startFittingButton = this Loader { source: "../Popups/FitStatusDialog.qml" } } diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Popups/FitStatusDialog.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Popups/FitStatusDialog.qml index 62d4707b..89836fef 100644 --- a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Popups/FitStatusDialog.qml +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Popups/FitStatusDialog.qml @@ -15,21 +15,21 @@ import Gui.Globals as Globals EaElements.Dialog { id: dialog - visible: Globals.Proxies.main.status.fitStatus + visible: Globals.BackendWrapper.analysisMinimizerStatus title: qsTr("Fit status") standardButtons: Dialog.Ok - Component.onCompleted: Globals.Refs.app.analysisPage.fitStatusDialogOkButton = okButtonRef() + Component.onCompleted: Globals.References.pages.analysis.sidebar.basic.popups.fitStatusDialogOkButton = okButtonRef() EaElements.Label { text: { - if (Globals.Proxies.main.status.fitStatus === 'Success') { + if ( Globals.BackendWrapper.analysisMinimizerStatus === 'Success') { return 'Optimization finished successfully.' - } else if (Globals.Proxies.main.status.fitStatus === 'Failure') { + } else if (Globals.BackendWrapper.analysisMinimizerStatus === 'Failure') { return 'Optimization failed.' - } else if (Globals.Proxies.main.status.fitStatus === 'Aborted') { + } else if (Globals.BackendWrapper.analysisMinimizerStatus === 'Aborted') { return 'Optimization aborted.' - } else if (Globals.Proxies.main.status.fitStatus === 'No free params') { + } else if (Globals.BackendWrapper.analysisMinimizerStatus === 'No free params') { return 'Nothing to vary. Allow some parameters to be free.' } else { return '' From 5d35579e7f3b85caf3fdb34a4315d3f7d100d2cd Mon Sep 17 00:00:00 2001 From: Andreas Pedersen Date: Fri, 25 Oct 2024 14:15:13 +0200 Subject: [PATCH 07/43] minor corrections --- src_qt6/EasyReflectometryApp/Backends/Mock/Analysis.qml | 2 +- src_qt6/EasyReflectometryApp/Gui/Globals/BackendWrapper.qml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src_qt6/EasyReflectometryApp/Backends/Mock/Analysis.qml b/src_qt6/EasyReflectometryApp/Backends/Mock/Analysis.qml index 6f7e1d16..c5d366f9 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Mock/Analysis.qml +++ b/src_qt6/EasyReflectometryApp/Backends/Mock/Analysis.qml @@ -10,7 +10,7 @@ QtObject { readonly property var experimentsAvailable: ['experiment_1', 'experiment_2', 'experiment_3'] readonly property int experimentsCurrentIndex: 0 - readonly property var minimizerStatus: 'Success' + readonly property string minimizerStatus: none //'Success' readonly property string minimizerCurrent: 'minimizer_1' readonly property double minimizerTolerance: 1.0 diff --git a/src_qt6/EasyReflectometryApp/Gui/Globals/BackendWrapper.qml b/src_qt6/EasyReflectometryApp/Gui/Globals/BackendWrapper.qml index d1e5cb10..891846a3 100644 --- a/src_qt6/EasyReflectometryApp/Gui/Globals/BackendWrapper.qml +++ b/src_qt6/EasyReflectometryApp/Gui/Globals/BackendWrapper.qml @@ -173,6 +173,7 @@ QtObject { readonly property bool analysisIsFitFinished: activeBackend.analysis.isFitFinished readonly property var analysisMinimizersAvailable: activeBackend.analysis.minimizersAvailable readonly property var analysisCalculatorsAvailable: activeBackend.analysis.calculatorsAvailable + readonly property var analysisExperimentsAvailable: activeBackend.analysis.experimentsAvailable readonly property string analysisMinimizerStatus: activeBackend.analysis.minimizerStatus From 1e6b57cabc5aca7df4d6a127bfcb89c73de38f1a Mon Sep 17 00:00:00 2001 From: Andreas Pedersen Date: Fri, 25 Oct 2024 18:01:53 +0200 Subject: [PATCH 08/43] skeleton in python is functional --- .../Backends/Mock/Analysis.qml | 11 +-- .../Backends/Py/analysis.py | 68 +++++++++++++++++++ .../Gui/Globals/BackendWrapper.qml | 17 +++-- .../Gui/Globals/Variables.qml | 4 +- .../Sidebar/Advanced/Groups/Calculator.qml | 3 +- .../Sidebar/Advanced/Groups/Minimizer.qml | 6 +- .../Sidebar/Basic/Groups/Experiments.qml | 1 - .../Pages/Sample/MainContent/SampleView.qml | 6 +- .../Gui/Pages/Sample/MainContent/SldView.qml | 6 +- 9 files changed, 101 insertions(+), 21 deletions(-) diff --git a/src_qt6/EasyReflectometryApp/Backends/Mock/Analysis.qml b/src_qt6/EasyReflectometryApp/Backends/Mock/Analysis.qml index c5d366f9..69dbfa6f 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Mock/Analysis.qml +++ b/src_qt6/EasyReflectometryApp/Backends/Mock/Analysis.qml @@ -10,20 +10,23 @@ QtObject { readonly property var experimentsAvailable: ['experiment_1', 'experiment_2', 'experiment_3'] readonly property int experimentsCurrentIndex: 0 - readonly property string minimizerStatus: none //'Success' + readonly property string minimizerStatus: undefined //'Success' readonly property string minimizerCurrent: 'minimizer_1' readonly property double minimizerTolerance: 1.0 readonly property int minimizerMaxIterations: 2 // Setters - function setExperimentsCurrentIndex(value) { + function setCalculatorCurrentIndex(value) { + console.debug(`setCalculatorCurrentIndex ${value}`) + } + function setExperimentCurrentIndex(value) { console.debug(`setExperimentCurrentIndex ${value}`) } - - function setMinimizerCurrent(value) { + function setMinimizerCurrentIndex(value) { console.debug(`setMinimizer ${value}`) } + function setMinimizerTolerance(value) { console.debug(`setMinimizerTolerance ${value}`) } diff --git a/src_qt6/EasyReflectometryApp/Backends/Py/analysis.py b/src_qt6/EasyReflectometryApp/Backends/Py/analysis.py index ba7781a7..69a6a588 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Py/analysis.py +++ b/src_qt6/EasyReflectometryApp/Backends/Py/analysis.py @@ -3,6 +3,8 @@ from PySide6.QtCore import Slot from PySide6.QtCore import Property +from typing import List + from easyreflectometry import Project as ProjectLib #from .logic.Analysis import Analysis as AnalysisLogic @@ -21,3 +23,69 @@ def __init__(self, project_lib: ProjectLib, parent=None): def isFitFinished(self) -> bool: return True + @Property(str, notify=fitFinishedChanged) + def minimizerStatus(self) -> str: + return "Minimizer status" + + @Property('QVariantList') + def minimizersAvailable(self) -> List[str]: + return ["Minimizer 1", "Minimizer 2", "Minimizer 3"] + + @Property(str) + def minimizerCurrentIndex(self) -> int: + return 0 + + @Property('QVariantList') + def calculatorsAvailable(self) -> List[str]: + return ["Calculator 1", "Calculator 2", "Calculator 3"] + + @Property(str) + def calculatorCurrentIndex(self) -> int: + return 0 + + @Property('QVariantList') + def experimentsAvailable(self) -> List[str]: + return ["Experiment 1", "Experiment 2", "Experiment 3"] + + @Property(str) + def experimentCurrentIndex(self) -> int: + return 0 + + @Property(float) + def minimizerTolerance(self) -> float: + return 1.0 + + @Property(int) + def minimizerMaxIterations(self) -> int: + return 1000 + + # Setters + @Slot(int) + def setMinimizerCurrentIndex(self, new_value: int) -> None: + print(new_value) + #self._material_logic.index = new_value + #self.materialIndexChanged.emit(new_value) + + @Slot(int) + def setCalculatorCurrentIndex(self, new_value: int) -> None: + print(new_value) + #self._material_logic.index = new_value + #self.materialIndexChanged.emit(new_value) + + @Slot(int) + def setExperimentCurrentIndex(self, new_value: int) -> None: + print(new_value) + #self._material_logic.index = new_value + #self.materialIndexChanged.emit(new_value) + + @Slot(float) + def setMinimizerTolerance(self, new_value: float) -> None: + print(new_value) + #self._material_logic.index = new_value + #self.materialIndexChanged.emit(new_value) + + @Slot(int) + def setMinimizerMaxIterations(self, new_value: int) -> None: + print(new_value) + #self._material_logic.index = new_value + #self.materialIndexChanged.emit(new_value) \ No newline at end of file diff --git a/src_qt6/EasyReflectometryApp/Gui/Globals/BackendWrapper.qml b/src_qt6/EasyReflectometryApp/Gui/Globals/BackendWrapper.qml index 891846a3..fdb078e6 100644 --- a/src_qt6/EasyReflectometryApp/Gui/Globals/BackendWrapper.qml +++ b/src_qt6/EasyReflectometryApp/Gui/Globals/BackendWrapper.qml @@ -171,20 +171,25 @@ QtObject { // Analysis page /////////////// readonly property bool analysisIsFitFinished: activeBackend.analysis.isFitFinished + readonly property string analysisMinimizerStatus: activeBackend.analysis.minimizerStatus + readonly property var analysisMinimizersAvailable: activeBackend.analysis.minimizersAvailable + readonly property string analysisMinimizerCurrentIndex: activeBackend.analysis.minimizerCurrentIndex + function analysisSetMinimizerCurrentIndex(value) { activeBackend.analysis.setMinimizerCurrentIndex(value) } + readonly property var analysisCalculatorsAvailable: activeBackend.analysis.calculatorsAvailable - readonly property var analysisExperimentsAvailable: activeBackend.analysis.experimentsAvailable + readonly property int analysisCalculatorCurrentIndex: activeBackend.analysis.calculatorCurrentIndex + function analysisSetCalculatorCurrentIndex(value) { activeBackend.analysis.setCalculatorCurrentIndex(value) } - readonly property string analysisMinimizerStatus: activeBackend.analysis.minimizerStatus + readonly property var analysisExperimentsAvailable: activeBackend.analysis.experimentsAvailable + readonly property int analysisExperimentsCurrentIndex: activeBackend.analysis.experimentsCurrentIndex + function analysisSetExperimentsCurrentIndex(value) { activeBackend.analysis.setExperimentsCurrentIndex(value) } - readonly property string analysisMinimizerCurrent: activeBackend.analysis.minimizerCurrent - function analysisSetMinimizerCurrent(value) { activeBackend.analysis.setMinimizerCurrent(value) } readonly property double analysisMinimizerTolerance: activeBackend.analysis.minimizerTolerance function analysisSetMinimizerTolerance(value) { activeBackend.analysis.setMinimizerTolerance(value) } readonly property int analysisMinimizerMaxIterations: activeBackend.analysis.minimizerMaxIterations function analysisSetMinimizerMaxIterations(value) { activeBackend.analysis.setMinimizerMaxIterations(value) } - readonly property int analysisExperimentsCurrentIndex: activeBackend.analysis.experimentsCurrentIndex - function anslysisSetExperimentsCurrentIndex(value) { activeBackend.analysis.setExperimentsCurrentIndex(value) } + /////////////// diff --git a/src_qt6/EasyReflectometryApp/Gui/Globals/Variables.qml b/src_qt6/EasyReflectometryApp/Gui/Globals/Variables.qml index 039a2226..d269b1d4 100644 --- a/src_qt6/EasyReflectometryApp/Gui/Globals/Variables.qml +++ b/src_qt6/EasyReflectometryApp/Gui/Globals/Variables.qml @@ -8,5 +8,7 @@ import QtQuick // whose id is stored here can be accessed from any other qml file. QtObject { + property bool showLegendOnSamplePage: false property bool showLegendOnExperimentPage: false -} \ No newline at end of file + property bool showLegendOnAnalysisPage: false +} diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Advanced/Groups/Calculator.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Advanced/Groups/Calculator.qml index ab9629a2..8200ed16 100644 --- a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Advanced/Groups/Calculator.qml +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Advanced/Groups/Calculator.qml @@ -18,7 +18,8 @@ EaElements.GroupBox { EaElements.ComboBox { width: EaStyle.Sizes.sideBarContentWidth model: Globals.BackendWrapper.analysisCalculatorsAvailable + currentIndex: Globals.BackendWrapper.analysisCalculatorCurrentIndex + onCurrentIndexChanged: Globals.BackendWrapper.analysisSetCalculatorCurrentIndex(currentIndex) } - } } diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Advanced/Groups/Minimizer.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Advanced/Groups/Minimizer.qml index c87aa287..2b003ce1 100644 --- a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Advanced/Groups/Minimizer.qml +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Advanced/Groups/Minimizer.qml @@ -29,6 +29,8 @@ EaElements.GroupBox { text: qsTr("Minimizer") color: EaStyle.Colors.themeForegroundMinor } + currentIndex: Globals.BackendWrapper.analysisMinimizerCurrentIndex + onCurrentIndexChanged: Globals.BackendWrapper.analysisSetMinimizerCurrentIndex(currentIndex) } // } /* Row{ @@ -60,7 +62,7 @@ EaElements.GroupBox { //text: Globals.Proxies.main.fitting.minimizerTol //onTextEdited: Globals.Proxies.main.fitting.minimizerTol = text text: Globals.BackendWrapper.analysisMinimizerTolerance.toFixed(3) - onTextEdited: Globals.BackendWrapper.analysisMinimizerSetTolerance(text) + onTextEdited: Globals.BackendWrapper.analysisSetMinimizerTolerance(text) EaElements.Label { id: toleranceLabel text: qsTr("Tolerance") @@ -77,7 +79,7 @@ EaElements.GroupBox { //text: Globals.Proxies.main.fitting.minimizerMaxIter //onTextEdited: Globals.Proxies.main.fitting.minimizerMaxIter = text text: Globals.BackendWrapper.analysisMinimizerMaxIterations - onTextEdited: Globals.Proxies.main.fittingMinimizerMaxIterations(text) + onTextEdited: Globals.BackendWrapper.analysisSetMinimizerMaxIterations(text) EaElements.Label { id: maxIterLabel text: qsTr("Max iterations") diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Groups/Experiments.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Groups/Experiments.qml index 5c97420b..649cf3c2 100644 --- a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Groups/Experiments.qml +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Groups/Experiments.qml @@ -32,7 +32,6 @@ EaElements.GroupBox { model: Globals.BackendWrapper.analysisExperimentsAvailable.length currentIndex: Globals.BackendWrapper.analysisExperimentsCurrentIndex - onActivated: Globals.BackendWrapper.analysisExperimentsSetCurrentIndex(currentIndex) // ComboBox delegate (popup rows) diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/MainContent/SampleView.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/MainContent/SampleView.qml index 855fe0e3..c875a03b 100644 --- a/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/MainContent/SampleView.qml +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/MainContent/SampleView.qml @@ -52,16 +52,16 @@ Rectangle { spacing: 0.25 * EaStyle.Sizes.fontPixelSize EaElements.TabButton { - checked: Globals.Variables.showLegendOnExperimentPage + checked: Globals.Variables.showLegendOnSamplePage autoExclusive: false height: EaStyle.Sizes.toolButtonHeight width: EaStyle.Sizes.toolButtonHeight borderColor: EaStyle.Colors.chartAxis fontIcon: "align-left" - ToolTip.text: Globals.Variables.showLegendOnExperimentPage ? + ToolTip.text: Globals.Variables.showLegendOnSamplePage ? qsTr("Hide legend") : qsTr("Show legend") - onClicked: Globals.Variables.showLegendOnExperimentPage = checked + onClicked: Globals.Variables.showLegendOnSamplePage = checked } EaElements.TabButton { diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/MainContent/SldView.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/MainContent/SldView.qml index 84a764a8..41587e74 100644 --- a/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/MainContent/SldView.qml +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/MainContent/SldView.qml @@ -52,16 +52,16 @@ Rectangle { spacing: 0.25 * EaStyle.Sizes.fontPixelSize EaElements.TabButton { - checked: Globals.Variables.showLegendOnExperimentPage + checked: Globals.Variables.showLegendOnSamplePage autoExclusive: false height: EaStyle.Sizes.toolButtonHeight width: EaStyle.Sizes.toolButtonHeight borderColor: EaStyle.Colors.chartAxis fontIcon: "align-left" - ToolTip.text: Globals.Variables.showLegendOnExperimentPage ? + ToolTip.text: Globals.Variables.showLegendOnSamplePage ? qsTr("Hide legend") : qsTr("Show legend") - onClicked: Globals.Variables.showLegendOnExperimentPage = checked + onClicked: Globals.Variables.showLegendOnSamplePage = checked } EaElements.TabButton { From 41d684158b2721efff70d5b7ce94fdd978c3ae68 Mon Sep 17 00:00:00 2001 From: Andreas Pedersen Date: Fri, 25 Oct 2024 18:36:55 +0200 Subject: [PATCH 09/43] more analysis gui --- .../Backends/Mock/Analysis.qml | 7 + .../Gui/Globals/BackendWrapper.qml | 15 ++- .../Sidebar/Advanced/Groups/ParamNames.qml | 124 +++++++++--------- .../Analysis/Sidebar/Advanced/Layout.qml | 29 +--- .../Sidebar/Basic/Groups/Experiments.qml | 6 +- .../Analysis/Sidebar/Basic/Groups/Fitting.qml | 13 +- 6 files changed, 90 insertions(+), 104 deletions(-) diff --git a/src_qt6/EasyReflectometryApp/Backends/Mock/Analysis.qml b/src_qt6/EasyReflectometryApp/Backends/Mock/Analysis.qml index 69dbfa6f..07c28073 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Mock/Analysis.qml +++ b/src_qt6/EasyReflectometryApp/Backends/Mock/Analysis.qml @@ -16,6 +16,8 @@ QtObject { readonly property double minimizerTolerance: 1.0 readonly property int minimizerMaxIterations: 2 + readonly property bool isFitting: false + // Setters function setCalculatorCurrentIndex(value) { console.debug(`setCalculatorCurrentIndex ${value}`) @@ -33,4 +35,9 @@ QtObject { function setMinimizerMaxIterations(value) { console.debug(`setMinimizerMaxIterations ${value}`) } + + //Actions + function fittingStartStop() { + console.debug('fittingStartStop') + } } diff --git a/src_qt6/EasyReflectometryApp/Gui/Globals/BackendWrapper.qml b/src_qt6/EasyReflectometryApp/Gui/Globals/BackendWrapper.qml index fdb078e6..9dbaa273 100644 --- a/src_qt6/EasyReflectometryApp/Gui/Globals/BackendWrapper.qml +++ b/src_qt6/EasyReflectometryApp/Gui/Globals/BackendWrapper.qml @@ -173,24 +173,25 @@ QtObject { readonly property bool analysisIsFitFinished: activeBackend.analysis.isFitFinished readonly property string analysisMinimizerStatus: activeBackend.analysis.minimizerStatus - readonly property var analysisMinimizersAvailable: activeBackend.analysis.minimizersAvailable - readonly property string analysisMinimizerCurrentIndex: activeBackend.analysis.minimizerCurrentIndex - function analysisSetMinimizerCurrentIndex(value) { activeBackend.analysis.setMinimizerCurrentIndex(value) } + readonly property var analysisExperimentsAvailable: activeBackend.analysis.experimentsAvailable + readonly property int analysisExperimentsCurrentIndex: activeBackend.analysis.experimentsCurrentIndex + function analysisSetExperimentsCurrentIndex(value) { activeBackend.analysis.setExperimentCurrentIndex(value) } readonly property var analysisCalculatorsAvailable: activeBackend.analysis.calculatorsAvailable readonly property int analysisCalculatorCurrentIndex: activeBackend.analysis.calculatorCurrentIndex function analysisSetCalculatorCurrentIndex(value) { activeBackend.analysis.setCalculatorCurrentIndex(value) } - readonly property var analysisExperimentsAvailable: activeBackend.analysis.experimentsAvailable - readonly property int analysisExperimentsCurrentIndex: activeBackend.analysis.experimentsCurrentIndex - function analysisSetExperimentsCurrentIndex(value) { activeBackend.analysis.setExperimentsCurrentIndex(value) } + readonly property var analysisMinimizersAvailable: activeBackend.analysis.minimizersAvailable + readonly property string analysisMinimizerCurrentIndex: activeBackend.analysis.minimizerCurrentIndex + function analysisSetMinimizerCurrentIndex(value) { activeBackend.analysis.setMinimizerCurrentIndex(value) } readonly property double analysisMinimizerTolerance: activeBackend.analysis.minimizerTolerance function analysisSetMinimizerTolerance(value) { activeBackend.analysis.setMinimizerTolerance(value) } readonly property int analysisMinimizerMaxIterations: activeBackend.analysis.minimizerMaxIterations function analysisSetMinimizerMaxIterations(value) { activeBackend.analysis.setMinimizerMaxIterations(value) } - + readonly property bool analysisFittingRunning: activeBackend.analysis.fittingRunning + function analysisFittingStartStop() { activeBackend.analysis.fittingStartStop() } /////////////// // Summary page diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Advanced/Groups/ParamNames.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Advanced/Groups/ParamNames.qml index 26a7f95d..5d148b89 100644 --- a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Advanced/Groups/ParamNames.qml +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Advanced/Groups/ParamNames.qml @@ -16,78 +16,80 @@ EaElements.GroupBox { title: qsTr("Parameter names") icon: "paint-brush" collapsed: false - EaComponents.TableView { - id: tableView + EaElements.GroupRow{ - readonly property var param: { - "blockType": "model", - "blockIcon": "layer-group", - "blockIdx": 0, - "blockName": "co2sio4", - "categoryIcon": "atom", - "category": "_atom_site", - "prettyCategory": "atom", - "rowIndex": 2, - "rowName": "Si", - "icon": "map-marker-alt", - "name": "_fract_x", - "prettyName": "fract x", - "shortPrettyName": "x" } + EaComponents.TableView { + id: tableView - showHeader: false - tallRows: true - maxRowCountShow: model.length + readonly property var param: { + "blockType": "model", + "blockIcon": "layer-group", + "blockIdx": 0, + "blockName": "co2sio4", + "categoryIcon": "atom", + "category": "_atom_site", + "prettyCategory": "atom", + "rowIndex": 2, + "rowName": "Si", + "icon": "map-marker-alt", + "name": "_fract_x", + "prettyName": "fract x", + "shortPrettyName": "x" } - /* - model: [ - { value: EaGlobals.Vars.ShortestWithIconsAndPrettyLabels, - text: qsTr('Shortest iconified name with pretty labels') }, - { value: EaGlobals.Vars.ReducedWithIconsAndPrettyLabels, - text: qsTr('Shorter iconified name with pretty labels') }, - { value: EaGlobals.Vars.FullWithIconsAndPrettyLabels, - text: qsTr('Full iconified name with pretty labels') }, - { value: EaGlobals.Vars.FullWithPrettyLabels, - text: qsTr('Full plain text name with pretty labels') }, - { value: EaGlobals.Vars.FullWithLabels, - text: qsTr('Full plain text name with labels') }, - { value: EaGlobals.Vars.FullWithIndices, - text: qsTr('Full plain text name with indices') } - ] - */ + showHeader: false + tallRows: true + maxRowCountShow: model.length - model: [ - { value: EaGlobals.Vars.ShortestWithIconsAndPrettyLabels, - text: qsTr('Iconified name with pretty labels') }, - { value: EaGlobals.Vars.PlainShortWithLabels, - text: qsTr('Short plain text name with labels') }, - { value: EaGlobals.Vars.PlainFullWithLabels, - text: qsTr('Full plain text name with labels') } - ] + /* + model: [ + { value: EaGlobals.Vars.ShortestWithIconsAndPrettyLabels, + text: qsTr('Shortest iconified name with pretty labels') }, + { value: EaGlobals.Vars.ReducedWithIconsAndPrettyLabels, + text: qsTr('Shorter iconified name with pretty labels') }, + { value: EaGlobals.Vars.FullWithIconsAndPrettyLabels, + text: qsTr('Full iconified name with pretty labels') }, + { value: EaGlobals.Vars.FullWithPrettyLabels, + text: qsTr('Full plain text name with pretty labels') }, + { value: EaGlobals.Vars.FullWithLabels, + text: qsTr('Full plain text name with labels') }, + { value: EaGlobals.Vars.FullWithIndices, + text: qsTr('Full plain text name with indices') } + ] + */ - header: EaComponents.TableViewHeader { + model: [ + { value: EaGlobals.Vars.ShortestWithIconsAndPrettyLabels, + text: qsTr('Iconified name with pretty labels') }, + { value: EaGlobals.Vars.PlainShortWithLabels, + text: qsTr('Short plain text name with labels') }, + { value: EaGlobals.Vars.PlainFullWithLabels, + text: qsTr('Full plain text name with labels') } + ] - EaComponents.TableViewLabel { - width: EaStyle.Sizes.fontPixelSize * 2.5 - } + header: EaComponents.TableViewHeader { + + EaComponents.TableViewLabel { + width: EaStyle.Sizes.fontPixelSize * 2.5 + } - EaComponents.TableViewLabel { - flexibleWidth: true + EaComponents.TableViewLabel { + flexibleWidth: true + } } - } - delegate: EaComponents.TableViewDelegate { - mouseArea.onPressed: EaGlobals.Vars.paramNameFormat = currentIndex + delegate: EaComponents.TableViewDelegate { + mouseArea.onPressed: EaGlobals.Vars.paramNameFormat = currentIndex - EaElements.RadioButton { - checked: index === EaGlobals.Vars.paramNameFormat - anchors.verticalCenter: parent.verticalCenter - } + EaElements.RadioButton { + checked: index === EaGlobals.Vars.paramNameFormat + anchors.verticalCenter: parent.verticalCenter + } - EaComponents.TableViewTwoRowsAdvancedLabel { - text: tableView.model[index].text - minorText: Globals.Proxies.paramName(param, tableView.model[index].value) + EaComponents.TableViewTwoRowsAdvancedLabel { + text: tableView.model[index].text + minorText: Globals.Proxies.paramName(param, tableView.model[index].value) + } } } - } -} \ No newline at end of file +} diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Advanced/Layout.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Advanced/Layout.qml index 69439e64..1168f404 100644 --- a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Advanced/Layout.qml +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Advanced/Layout.qml @@ -12,32 +12,9 @@ import "./Groups" as Groups EaComponents.SideBarColumn { - Groups.ParamNames {} -/* - EaElements.GroupBox { - title: qsTr("Parameter names") - icon: "paint-brush" - collapsed: false - - Loader { source: 'SideBarAdvanced/ParamNames.qml' } - } -*/ +// Groups.ParamNames {} + Groups.Calculator {} -/* - EaElements.GroupBox { - title: qsTr("Calculation engine") - icon: 'calculator' - - Loader { source: 'SideBarAdvanced/Calculator.qml' } - } -*/ + Groups.Minimizer {} -/* - EaElements.GroupBox { - title: qsTr("Minimization engine") - icon: 'level-down-alt' - - Loader { source: 'SideBarAdvanced/Minimizer.qml' } - } - */ } diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Groups/Experiments.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Groups/Experiments.qml index 649cf3c2..0195cd68 100644 --- a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Groups/Experiments.qml +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Groups/Experiments.qml @@ -32,7 +32,7 @@ EaElements.GroupBox { model: Globals.BackendWrapper.analysisExperimentsAvailable.length currentIndex: Globals.BackendWrapper.analysisExperimentsCurrentIndex - onActivated: Globals.BackendWrapper.analysisExperimentsSetCurrentIndex(currentIndex) + onActivated: Globals.BackendWrapper.analysisSetExperimentsCurrentIndex(currentIndex) // ComboBox delegate (popup rows) delegate: ItemDelegate { @@ -68,7 +68,9 @@ EaElements.GroupBox { EaComponents.TableViewParameter { enabled: false - text: comboBox.model[index].name.value + //text: comboBox.model[index]//.name.value + text: Globals.BackendWrapper.analysisExperimentsAvailable[index] + } } } diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Groups/Fitting.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Groups/Fitting.qml index f4e09c93..4b9d8c54 100644 --- a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Groups/Fitting.qml +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Groups/Fitting.qml @@ -5,15 +5,14 @@ import QtQuick import QtQuick.Controls -import EasyApp.Gui.Globals as EaGlobals +//import EasyApp.Gui.Globals as EaGlobals import EasyApp.Gui.Style as EaStyle import EasyApp.Gui.Elements as EaElements -import EasyApp.Gui.Components as EaComponents +//import EasyApp.Gui.Components as EaComponents import Gui.Globals as Globals EaElements.GroupBox { - //title: qsTr("Fitting") collapsible: false Column { @@ -22,16 +21,14 @@ EaElements.GroupBox { EaElements.SideBarButton { enabled: Globals.Proxies.main.experiment.defined wide: true - - fontIcon: Globals.Proxies.main.fitting.isFittingNow ? 'stop-circle' : 'play-circle' - text: Globals.Proxies.main.fitting.isFittingNow ? qsTr('Cancel fitting') : qsTr('Start fitting') + fontIcon: Globals.BackendWrapper.analysisFittingRunning ? 'stop-circle' : 'play-circle' + text: Globals.BackendWrapper.analysisFittingRunning ? qsTr('Cancel fitting') : qsTr('Start fitting') onClicked: { console.debug(`Clicking '${text}' button: ${this}`) - Globals.Proxies.main.fitting.startStop() + Globals.BackendWrapper.analysisFittingStartStop() } - //Component.onCompleted: Globals.Refs.app.analysisPage.startFittingButton = this Component.onCompleted: Globals.References.pages.analysis.sidebar.basic.popups.startFittingButton = this Loader { source: "../Popups/FitStatusDialog.qml" } } From f292ee4bb7b1a2694c2cca222dc7319756d4309c Mon Sep 17 00:00:00 2001 From: Andreas Pedersen Date: Mon, 28 Oct 2024 06:14:24 +0100 Subject: [PATCH 10/43] fitables are still missing --- .../EasyReflectometryApp/Backends/Mock/Analysis.qml | 10 ++++++---- src_qt6/EasyReflectometryApp/Backends/Py/analysis.py | 6 +++--- .../Gui/Globals/BackendWrapper.qml | 4 ++-- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src_qt6/EasyReflectometryApp/Backends/Mock/Analysis.qml b/src_qt6/EasyReflectometryApp/Backends/Mock/Analysis.qml index 07c28073..fb8bd664 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Mock/Analysis.qml +++ b/src_qt6/EasyReflectometryApp/Backends/Mock/Analysis.qml @@ -6,17 +6,19 @@ QtObject { readonly property bool isFitFinished: true readonly property var minimizersAvailable: ['minimizer_1', 'minimizer_2', 'minimizer_3'] + readonly property int minimizerCurrentIndex: 0 + readonly property var calculatorsAvailable: ['calculator_1', 'calculator_2', 'calculator_3'] + readonly property int calculatorCurrentIndex: 1 + readonly property var experimentsAvailable: ['experiment_1', 'experiment_2', 'experiment_3'] + readonly property int experimentCurrentIndex: 2 - readonly property int experimentsCurrentIndex: 0 readonly property string minimizerStatus: undefined //'Success' - - readonly property string minimizerCurrent: 'minimizer_1' readonly property double minimizerTolerance: 1.0 readonly property int minimizerMaxIterations: 2 - readonly property bool isFitting: false + readonly property bool fittingRunning: false // Setters function setCalculatorCurrentIndex(value) { diff --git a/src_qt6/EasyReflectometryApp/Backends/Py/analysis.py b/src_qt6/EasyReflectometryApp/Backends/Py/analysis.py index 69a6a588..5565dcdb 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Py/analysis.py +++ b/src_qt6/EasyReflectometryApp/Backends/Py/analysis.py @@ -31,7 +31,7 @@ def minimizerStatus(self) -> str: def minimizersAvailable(self) -> List[str]: return ["Minimizer 1", "Minimizer 2", "Minimizer 3"] - @Property(str) + @Property(int) def minimizerCurrentIndex(self) -> int: return 0 @@ -39,7 +39,7 @@ def minimizerCurrentIndex(self) -> int: def calculatorsAvailable(self) -> List[str]: return ["Calculator 1", "Calculator 2", "Calculator 3"] - @Property(str) + @Property(int) def calculatorCurrentIndex(self) -> int: return 0 @@ -47,7 +47,7 @@ def calculatorCurrentIndex(self) -> int: def experimentsAvailable(self) -> List[str]: return ["Experiment 1", "Experiment 2", "Experiment 3"] - @Property(str) + @Property(int) def experimentCurrentIndex(self) -> int: return 0 diff --git a/src_qt6/EasyReflectometryApp/Gui/Globals/BackendWrapper.qml b/src_qt6/EasyReflectometryApp/Gui/Globals/BackendWrapper.qml index 9dbaa273..3e01f4b6 100644 --- a/src_qt6/EasyReflectometryApp/Gui/Globals/BackendWrapper.qml +++ b/src_qt6/EasyReflectometryApp/Gui/Globals/BackendWrapper.qml @@ -174,7 +174,7 @@ QtObject { readonly property string analysisMinimizerStatus: activeBackend.analysis.minimizerStatus readonly property var analysisExperimentsAvailable: activeBackend.analysis.experimentsAvailable - readonly property int analysisExperimentsCurrentIndex: activeBackend.analysis.experimentsCurrentIndex + readonly property int analysisExperimentsCurrentIndex: activeBackend.analysis.experimentCurrentIndex function analysisSetExperimentsCurrentIndex(value) { activeBackend.analysis.setExperimentCurrentIndex(value) } readonly property var analysisCalculatorsAvailable: activeBackend.analysis.calculatorsAvailable @@ -182,7 +182,7 @@ QtObject { function analysisSetCalculatorCurrentIndex(value) { activeBackend.analysis.setCalculatorCurrentIndex(value) } readonly property var analysisMinimizersAvailable: activeBackend.analysis.minimizersAvailable - readonly property string analysisMinimizerCurrentIndex: activeBackend.analysis.minimizerCurrentIndex + readonly property int analysisMinimizerCurrentIndex: activeBackend.analysis.minimizerCurrentIndex function analysisSetMinimizerCurrentIndex(value) { activeBackend.analysis.setMinimizerCurrentIndex(value) } readonly property double analysisMinimizerTolerance: activeBackend.analysis.minimizerTolerance From e224045c3911cf9d102986b93d69e1b76485318c Mon Sep 17 00:00:00 2001 From: Andreas Pedersen Date: Mon, 28 Oct 2024 11:54:13 +0100 Subject: [PATCH 11/43] most parts of analysis GUI seems to work towards mock backend --- .../Backends/Mock/Analysis.qml | 66 ++++- .../Backends/Mock/Sample.qml | 2 +- .../Gui/Globals/BackendWrapper.qml | 22 +- .../Sidebar/Basic/Groups/Fittables.qml | 242 ++++++++++-------- .../Analysis/Sidebar/Basic/Groups/Fitting.qml | 4 +- 5 files changed, 219 insertions(+), 117 deletions(-) diff --git a/src_qt6/EasyReflectometryApp/Backends/Mock/Analysis.qml b/src_qt6/EasyReflectometryApp/Backends/Mock/Analysis.qml index fb8bd664..757948c8 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Mock/Analysis.qml +++ b/src_qt6/EasyReflectometryApp/Backends/Mock/Analysis.qml @@ -3,8 +3,6 @@ pragma Singleton import QtQuick QtObject { - - readonly property bool isFitFinished: true readonly property var minimizersAvailable: ['minimizer_1', 'minimizer_2', 'minimizer_3'] readonly property int minimizerCurrentIndex: 0 @@ -14,13 +12,74 @@ QtObject { readonly property var experimentsAvailable: ['experiment_1', 'experiment_2', 'experiment_3'] readonly property int experimentCurrentIndex: 2 - readonly property string minimizerStatus: undefined //'Success' + // Minimizer + readonly property string minimizerStatus: ''//undefined //'Success' readonly property double minimizerTolerance: 1.0 readonly property int minimizerMaxIterations: 2 + // Fitting + readonly property bool isFitFinished: true readonly property bool fittingRunning: false + // Parameters + property int currentParameterIndex: 0 + readonly property int modelParametersCount: 10 + readonly property int experimentParametersCount: 20 + readonly property int freeParametersCount: 100 + readonly property int fixedParametersCount: 200 + readonly property var fitableParameters: [ + { + 'name': 'name 1', + 'value': 1.0, + 'error': -1.23456, + 'max': 100.0, + 'min': -100.0, + 'units': 'u1', + 'fit': true, + 'from': -10.0, + 'to': 10.0, + }, + { + 'name': 'name 2', + 'value': 2.0, + 'error': -2.34567, + 'max': 200.0, + 'min': -200.0, + 'units': 'u2', + 'fit': false, + 'from': -20.0, + 'to': 20.0, + }, + { + 'name': 'name 3', + 'value': 3.0, + 'error': -3.45678, + 'max': 300.0, + 'min': -300.0, + 'units': 'u3', + 'fit': true, + 'from': -30.0, + 'to': 30.0, + }, + ] + function setCurrentParameterMin(value) { + console.debug(`setCurrentParameterMin ${value}`) + } + function setCurrentParameterMax(value) { + console.debug(`setCurrentParameterMax ${value}`) + } + function setCurrentParameterValue(value) { + console.debug(`setCurrentParameterValue ${value}`) + } + function setCurrentParameterFit(value) { + console.debug(`setCurrentParameterFit ${value}`) + } + // Setters + function setCurrentParameterIndex(value) { + currentParameterIndex = value + console.debug(`setCurrentParameterIndex ${value}`) + } function setCalculatorCurrentIndex(value) { console.debug(`setCalculatorCurrentIndex ${value}`) } @@ -30,7 +89,6 @@ QtObject { function setMinimizerCurrentIndex(value) { console.debug(`setMinimizer ${value}`) } - function setMinimizerTolerance(value) { console.debug(`setMinimizerTolerance ${value}`) } diff --git a/src_qt6/EasyReflectometryApp/Backends/Mock/Sample.qml b/src_qt6/EasyReflectometryApp/Backends/Mock/Sample.qml index 34994d7a..a0d303c8 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Mock/Sample.qml +++ b/src_qt6/EasyReflectometryApp/Backends/Mock/Sample.qml @@ -4,7 +4,7 @@ import QtQuick QtObject { // MATERIALS - property int currentMaterialIndex: -1 + readonly property int currentMaterialIndex: -1 // Getters readonly property var materials: [ diff --git a/src_qt6/EasyReflectometryApp/Gui/Globals/BackendWrapper.qml b/src_qt6/EasyReflectometryApp/Gui/Globals/BackendWrapper.qml index 3e01f4b6..ef44a02e 100644 --- a/src_qt6/EasyReflectometryApp/Gui/Globals/BackendWrapper.qml +++ b/src_qt6/EasyReflectometryApp/Gui/Globals/BackendWrapper.qml @@ -170,9 +170,6 @@ QtObject { /////////////// // Analysis page /////////////// - readonly property bool analysisIsFitFinished: activeBackend.analysis.isFitFinished - readonly property string analysisMinimizerStatus: activeBackend.analysis.minimizerStatus - readonly property var analysisExperimentsAvailable: activeBackend.analysis.experimentsAvailable readonly property int analysisExperimentsCurrentIndex: activeBackend.analysis.experimentCurrentIndex function analysisSetExperimentsCurrentIndex(value) { activeBackend.analysis.setExperimentCurrentIndex(value) } @@ -185,14 +182,33 @@ QtObject { readonly property int analysisMinimizerCurrentIndex: activeBackend.analysis.minimizerCurrentIndex function analysisSetMinimizerCurrentIndex(value) { activeBackend.analysis.setMinimizerCurrentIndex(value) } + // Minimizer + readonly property string analysisMinimizerStatus: activeBackend.analysis.minimizerStatus readonly property double analysisMinimizerTolerance: activeBackend.analysis.minimizerTolerance function analysisSetMinimizerTolerance(value) { activeBackend.analysis.setMinimizerTolerance(value) } readonly property int analysisMinimizerMaxIterations: activeBackend.analysis.minimizerMaxIterations function analysisSetMinimizerMaxIterations(value) { activeBackend.analysis.setMinimizerMaxIterations(value) } + // Fitting readonly property bool analysisFittingRunning: activeBackend.analysis.fittingRunning + readonly property bool analysisIsFitFinished: activeBackend.analysis.isFitFinished function analysisFittingStartStop() { activeBackend.analysis.fittingStartStop() } + // Parameters + readonly property int analysisFreeParametersCount: activeBackend.analysis.freeParametersCount + readonly property int analysisFixedParametersCount: activeBackend.analysis.fixedParametersCount + readonly property int analysisModelParametersCount: activeBackend.analysis.modelParametersCount + readonly property int analysisExperimentParametersCount: activeBackend.analysis.experimentParametersCount + readonly property var analysisFitableParameters: activeBackend.analysis.fitableParameters + readonly property int analysisCurrentParameterIndex: activeBackend.analysis.currentParameterIndex + function analysisSetCurrentParameterIndex(value) { activeBackend.analysis.setCurrentParameterIndex(value) } + + function analysisSetCurrentParameterMin(value) { activeBackend.analysis.setCurrentParameterMin(value) } + function analysisSetCurrentParameterMax(value) { activeBackend.analysis.setCurrentParameterMax(value) } + function analysisSetCurrentParameterValue(value) { activeBackend.analysis.setCurrentParameterValue(value) } + function analysisSetCurrentParameterFit(value) { activeBackend.analysis.setCurrentParameterFit(value) } + + /////////////// // Summary page /////////////// diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Groups/Fittables.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Groups/Fittables.qml index 6a6363d9..ec052791 100644 --- a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Groups/Fittables.qml +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Groups/Fittables.qml @@ -20,7 +20,8 @@ EaElements.GroupBox { last: true Column { - property int selectedParamIndex: -1 + id: fittables + property int selectedParamIndex: Globals.BackendWrapper.analysisCurrentParameterIndex onSelectedParamIndexChanged: { updateSliderLimits() updateSliderValue() @@ -66,14 +67,14 @@ EaElements.GroupBox { currentText.replace(' ◦ ', '') model: [ - { value: "", text: `All names (${Globals.Proxies.main.fittables.modelParamsCount + Globals.Proxies.main.fittables.experimentParamsCount})` }, - { value: "model", text: `layer-group Model (${Globals.Proxies.main.fittables.modelParamsCount})` }, + { value: "", text: `All names (${Globals.BackendWrapper.analysisModelParametersCount + Globals.BackendWrapper.analysisExperimentParametersCount})` }, + { value: "model", text: `layer-group Model (${Globals.BackendWrapper.analysisModelParametersCount})` }, { value: "cell", text: `cube Unit cell` }, { value: "atom_site", text: `atom Atom sites` }, { value: "fract", text: `map-marker-alt Atomic coordinates` }, { value: "occupancy", text: `fill Atomic occupancies` }, { value: "B_iso", text: `arrows-alt Atomic displacement` }, - { value: "experiment", text: `microscope Experiment (${Globals.Proxies.main.fittables.experimentParamsCount})` }, + { value: "experiment", text: `microscope Experiment (${Globals.BackendWrapper.analysisExperimentParametersCount})` }, { value: "resolution", text: `shapes Peak shape` }, { value: "asymmetry", text: `balance-scale-left Peak asymmetry` }, { value: "background", text: `wave-square Background` } @@ -100,10 +101,10 @@ EaElements.GroupBox { textRole: "text" model: [ - { value: 'all', text: `All parameters (${Globals.Proxies.main.fittables.freeParamsCount + - Globals.Proxies.main.fittables.fixedParamsCount})` }, - { value: 'free', text: `Free parameters (${Globals.Proxies.main.fittables.freeParamsCount})` }, - { value: 'fixed', text: `Fixed parameters (${Globals.Proxies.main.fittables.fixedParamsCount})` } + { value: 'all', text: `All parameters (${Globals.BackendWrapper.analysisFreeParamsCount + + Globals.BackendWrapper.analysisFixedParamsCount})` }, + { value: 'free', text: `Free parameters (${Globals.BackendWrapper.analysisFreeParamsCount})` }, + { value: 'fixed', text: `Fixed parameters (${Globals.BackendWrapper.analysisFixedParamsCount})` } ] onModelChanged: currentIndex = lastIndex @@ -121,7 +122,7 @@ EaElements.GroupBox { EaComponents.TableView { id: tableView - property var currentValueTextInput: null +// property var currentValueTextInput: null defaultInfoText: qsTr("No parameters found") @@ -131,10 +132,14 @@ EaElements.GroupBox { // Table model // We only use the length of the model object defined in backend logic and // directly access that model in every row using the TableView index property. - model: Globals.Proxies.main_fittables_data.length + model: Globals.BackendWrapper.analysisFitableParameters.length //Globals.Proxies.main_fittables_data.length // Table model - Component.onCompleted: selectedParamIndex = 0 + Component.onCompleted: { + Globals.BackendWrapper.analysisSetCurrentParameterIndex(0)// fittables.selectedParamIndex = 0 + updateSliderLimits() + updateSliderValue() + } // Header row header: EaComponents.TableViewHeader { @@ -195,19 +200,30 @@ EaElements.GroupBox { // Table content row delegate: EaComponents.TableViewDelegate { - enabled: !Globals.Proxies.main.fitting.isFittingNow - - property bool isCurrentItem: ListView.isCurrentItem - property var item: Globals.Proxies.main_fittables_data[index] + enabled: !Globals.BackendWrapper.analysisFittingRunning - mouseArea.onPressed: selectedParamIndex = tableView.currentIndex +// property bool isCurrentItem: ListView.isCurrentItem +// property var item: Globals.BackendWrapper.analysisFitableParameters[index] - onIsCurrentItemChanged: { - if (tableView.currentValueTextInput != valueColumn) { - tableView.currentValueTextInput = valueColumn + mouseArea.onPressed: { + if (Globals.BackendWrapper.analysisCurrentParameterIndex !== index) { + Globals.BackendWrapper.analysisSetCurrentParameterIndex(index) + updateSliderLimits() + updateSliderValue() } } +// Globals.BackendWrapper.analysisSetCurrentParameterIndex(index)// fittables.selectedParamIndex = tableView.currentIndex +/* onIsCurrentItemChanged: { +// if (tableView.currentValueTextInput != valueColumn) { + // tableView.currentValueTextInput = valueColumn + if (Globals.BackendWrapper.analysisCurrentParameterIndex !== index) { +// Globals.BackendWrapper.analysisSetCurrentParameterIndex(index) + updateSliderLimits() + updateSliderValue() + } + } +*/ EaComponents.TableViewLabel { text: index + 1 color: EaStyle.Colors.themeForegroundMinor @@ -215,7 +231,7 @@ EaElements.GroupBox { EaComponents.TableViewLabel { width: EaStyle.Sizes.fontPixelSize * 5 - text: Globals.Proxies.paramName(item, EaGlobals.Vars.paramNameFormat) + text: Globals.BackendWrapper.analysisFitableParameters[index].name //Globals.Proxies.paramName(item, EaGlobals.Vars.paramNameFormat) textFormat: EaGlobals.Vars.paramNameFormat === EaGlobals.Vars.PlainShortWithLabels || EaGlobals.Vars.paramNameFormat === EaGlobals.Vars.PlainFullWithLabels ? Text.PlainText : @@ -228,91 +244,99 @@ EaElements.GroupBox { EaComponents.TableViewParameter { id: valueColumn selected: //index === tableView.currentIndex || - index === selectedParamIndex - fit: item.fit - text: item.error === 0 ? - EaLogic.Utils.toDefaultPrecision(item.value) : - Globals.Proxies.main.backendHelpers.toStdDevSmalestPrecision(item.value, item.error).value + index === Globals.BackendWrapper.analysisCurrentParameterIndex //fittables.selectedParamIndex + fit: Globals.BackendWrapper.analysisFitableParameters[index].fit + text: EaLogic.Utils.toDefaultPrecision(Globals.BackendWrapper.analysisFitableParameters[index].value) +// Globals.BackendWrapper.analysisFitableParameters[index].error === 0 ? +// EaLogic.Utils.toDefaultPrecision(Globals.BackendWrapper.analysisFitableParameters[index].value) : +// 1000 //Globals.Proxies.main.backendHelpers.toStdDevSmalestPrecision(item.value, item.error).value onEditingFinished: { focus = false - console.debug('') +// console.debug('') console.debug("*** Editing (manual) 'value' field of fittable on Analysis page ***") - Globals.Proxies.main.fittables.editSilently(item.blockType, + Globals.BackendWrapper.analysisSetCurrentParameterValue(text) + + /* Globals.Proxies.main.fittables.editSilently(item.blockType, item.blockIdx, item.category, item.rowIndex ?? -1, item.name, 'value', text) + */ + updateSliderValue() updateSliderLimits() - slider.value = Globals.Proxies.main_fittables_data[selectedParamIndex].value +// slider.value = Globals.BackendWrapper.analysisFitableParameters[index].value //[Globals.BackendWrapper.analysisCurrentParameterIndex].value //fittables.selectedParamIndex].value } } EaComponents.TableViewLabel { - text: item.units + text: Globals.BackendWrapper.analysisFitableParameters[index].units color: EaStyle.Colors.themeForegroundMinor } EaComponents.TableViewLabel { elide: Text.ElideNone - text: item.error === 0 ? - '' : - Globals.Proxies.main.backendHelpers.toStdDevSmalestPrecision(item.value, item.error).std_dev + text: Globals.BackendWrapper.analysisFitableParameters[index].value//Globals.BackendWrapper.analysisFitableParameters[index].error === 0 ? +// '' : +// 1000 //Globals.Proxies.main.backendHelpers.toStdDevSmalestPrecision(item.value, item.error).std_dev } EaComponents.TableViewParameter { minored: true - text: EaLogic.Utils.toDefaultPrecision(item.min).replace('Infinity', 'inf') + text: EaLogic.Utils.toDefaultPrecision(Globals.BackendWrapper.analysisFitableParameters[index].min).replace('Infinity', 'inf') onEditingFinished: { focus = false - console.debug('') +// console.debug('') console.debug("*** Editing 'min' field of fittable on Analysis page ***") const value = (text === '' ? '-inf' : text) - Globals.Proxies.main.fittables.editSilently(item.blockType, + Globals.BackendWrapper.analysisSetCurrentParameterMin(text) + /* Globals.Proxies.main.fittables.editSilently(item.blockType, item.blockIdx, item.category, item.rowIndex ?? -1, item.name, 'min', value) - } + */ } } EaComponents.TableViewParameter { minored: true - text: EaLogic.Utils.toDefaultPrecision(item.max).replace('Infinity', 'inf') + text: EaLogic.Utils.toDefaultPrecision(Globals.BackendWrapper.analysisFitableParameters[index].max).replace('Infinity', 'inf') onEditingFinished: { focus = false - console.debug('') +// console.debug('') console.debug("*** Editing 'max' field of fittable on Analysis page ***") const value = (text === '' ? 'inf' : text) - Globals.Proxies.main.fittables.editSilently(item.blockType, + Globals.BackendWrapper.analysisSetCurrentParameterMax(value) + /* Globals.Proxies.main.fittables.editSilently(item.blockType, item.blockIdx, item.category, item.rowIndex ?? -1, item.name, 'max', value) - } + */ } } EaComponents.TableViewCheckBox { id: fitColumn - enabled: Globals.Proxies.main.experiment.defined - checked: item.fit + enabled: Globals.BackendWrapper.analysisExperimentsAvailable.length// Globals.Proxies.main.experiment.defined + checked: Globals.BackendWrapper.analysisFitableParameters[index].fit onToggled: { - console.debug('') +// console.debug('') console.debug("*** Editing 'fit' field of fittable on Analysis page ***") - Globals.Proxies.main.fittables.editSilently(item.blockType, + Globals.BackendWrapper.analysisSetCurrentParameterFit(checkState) + /* Globals.Proxies.main.fittables.editSilently(item.blockType, item.blockIdx, item.category, item.rowIndex ?? -1, item.name, 'fit', checked) - } + */ } } } // Table content row @@ -321,7 +345,7 @@ EaElements.GroupBox { // Parameter change slider Row { - visible: Globals.Proxies.main_fittables_data.length + visible: Globals.BackendWrapper.analysisFitableParameters.length //Globals.Proxies.main_fittables_data.length spacing: EaStyle.Sizes.fontPixelSize @@ -331,49 +355,53 @@ EaElements.GroupBox { //text: EaLogic.Utils.toDefaultPrecision(slider.from) //text: EaLogic.Utils.toErrSinglePrecision(slider.from, Globals.Proxies.main_fittables_data[selectedParamIndex].error) text: { - const value = Globals.Proxies.main_fittables_data[selectedParamIndex].value - const error = Globals.Proxies.main_fittables_data[selectedParamIndex].error + const value = Globals.BackendWrapper.analysisFitableParameters[Globals.BackendWrapper.analysisCurrentParameterIndex].value //[fittables.selectedParamIndex].value // Globals.Proxies.main_fittables_data[selectedParamIndex].value + const error = Globals.BackendWrapper.analysisFitableParameters[Globals.BackendWrapper.analysisCurrentParameterIndex].error //[fittables.selectedParamIndex].error // Globals.Proxies.main_fittables_data[selectedParamIndex].error //return EaLogic.Utils.toErrSinglePrecision(value, error).length <= 8 ? // EaLogic.Utils.toErrSinglePrecision(slider.from, error) : // EaLogic.Utils.toDefaultPrecision(slider.from) - return error === 0 ? + return EaLogic.Utils.toDefaultPrecision(slider.from) + +/* return error === 0 ? EaLogic.Utils.toDefaultPrecision(slider.from) : - Globals.Proxies.main.backendHelpers.toStdDevSmalestPrecision(slider.from, error).value - } + 1000 //Globals.Proxies.main.backendHelpers.toStdDevSmalestPrecision(slider.from, error).value +*/ } } EaElements.Slider { id: slider - enabled: !Globals.Proxies.main.fitting.isFittingNow + enabled: !Globals.BackendWrapper.analysisFittingRunning width: tableView.width - EaStyle.Sizes.fontPixelSize * 14 stepSize: (to - from) / 20 snapMode: Slider.SnapAlways toolTipText: { - const value = Globals.Proxies.main_fittables_data[selectedParamIndex].value - const error = Globals.Proxies.main_fittables_data[selectedParamIndex].error + //const value = Globals.BackendWrapper.analysisFitableParameters[Globals.BackendWrapper.analysisCurrentParameterIndex].value //[fittables.selectedParamIndex].value //Globals.Proxies.main_fittables_data[selectedParamIndex].value + //const error = Globals.BackendWrapper.analysisFitableParameters[Globals.BackendWrapper.analysisCurrentParameterIndex].error //[fittables.selectedParamIndex].error //Globals.Proxies.main_fittables_data[selectedParamIndex].error //return EaLogic.Utils.toErrSinglePrecision(value, error).length <= 8 ? // EaLogic.Utils.toErrSinglePrecision(value, error) : // EaLogic.Utils.toDefaultPrecision(value) - return error === 0 ? + return EaLogic.Utils.toDefaultPrecision(value) +/* return error === 0 ? EaLogic.Utils.toDefaultPrecision(value) : - Globals.Proxies.main.backendHelpers.toStdDevSmalestPrecision(value, error).value - } + 1000 //Globals.Proxies.main.backendHelpers.toStdDevSmalestPrecision(value, error).value +*/ } onMoved: { - console.debug('') +// console.debug('') console.debug("*** Editing (slider) 'value' field of fittable on Analysis page ***") - const item = Globals.Proxies.main_fittables_data[selectedParamIndex] - Globals.Proxies.main.fittables.editSilently(item.blockType, + //const item = Globals.BackendWrapper.analysisFitableParameters[Globals.BackendWrapper.analysisCurrentParameterIndex] //[fittables.selectedParamIndex] //Globals.Proxies.main_fittables_data[selectedParamIndex] + Globals.BackendWrapper.analysisSetCurrentParameterValue(value) + /* Globals.Proxies.main.fittables.editSilently(item.blockType, item.blockIdx, item.category, item.rowIndex ?? -1, item.name, 'value', value.toString()) - } + */ } onPressedChanged: { if (!pressed) { @@ -388,15 +416,16 @@ EaElements.GroupBox { //text: EaLogic.Utils.toDefaultPrecision(slider.to) //text: EaLogic.Utils.toErrSinglePrecision(slider.to, Globals.Proxies.main_fittables_data[selectedParamIndex].error) text: { - const value = Globals.Proxies.main_fittables_data[selectedParamIndex].value - const error = Globals.Proxies.main_fittables_data[selectedParamIndex].error + //const value = Globals.BackendWrapper.analysisFitableParameters[Globals.BackendWrapper.analysisCurrentParameterIndex].value //[fittables.selectedParamIndex].value //Globals.Proxies.main_fittables_data[selectedParamIndex].value + //const error = Globals.BackendWrapper.analysisFitableParameters[Globals.BackendWrapper.analysisCurrentParameterIndex].error //[fittables.selectedParamIndex].error //Globals.Proxies.main_fittables_data[selectedParamIndex].error //return EaLogic.Utils.toErrSinglePrecision(value, error).length <= 8 ? // EaLogic.Utils.toErrSinglePrecision(slider.to, error) : // EaLogic.Utils.toDefaultPrecision(slider.to) - return error === 0 ? + return EaLogic.Utils.toDefaultPrecision(slider.to) +/* return error === 0 ? EaLogic.Utils.toDefaultPrecision(slider.to) : - Globals.Proxies.main.backendHelpers.toStdDevSmalestPrecision(slider.to, error).value - } + 1000 //Globals.Proxies.main.backendHelpers.toStdDevSmalestPrecision(slider.to, error).value +*/ } } } @@ -418,52 +447,53 @@ EaElements.GroupBox { } } */ + } + // Use OpenGL on slider move only - // Use OpenGL on slider move only - - Timer { - id: disableOpenGLTimer - interval: 1500 - onTriggered: disableOpenGLFromTimer() - } - - // Logic - - function updateSliderValue() { - const value = Globals.Proxies.main_fittables_data[selectedParamIndex].value - slider.value = EaLogic.Utils.toDefaultPrecision(value) - } +/* Timer { + id: disableOpenGLTimer + interval: 1500 + onTriggered: disableOpenGLFromTimer() + } +*/ + // Logic - function updateSliderLimits() { - const from = Globals.Proxies.main_fittables_data[selectedParamIndex].from - const to = Globals.Proxies.main_fittables_data[selectedParamIndex].to - slider.from = EaLogic.Utils.toDefaultPrecision(from) - slider.to = EaLogic.Utils.toDefaultPrecision(to) - } + function updateSliderValue() { + const value = Globals.BackendWrapper.analysisFitableParameters[Globals.BackendWrapper.analysisCurrentParameterIndex].value //[fittables.selectedParamIndex].value// Globals.Proxies.main_fittables_data[selectedParamIndex].value + slider.value = EaLogic.Utils.toDefaultPrecision(value) +// Globals.BackendWrapper.analysisSetCurrentParameterValue(EaLogic.Utils.toDefaultPrecision(value)) + } - function enableOpenGL() { - if (Globals.Proxies.main.plotting.currentLib1d === 'QtCharts') { - Globals.Refs.app.experimentPage.plotView.useOpenGL = true - //Globals.Refs.app.modelPage.plotView.useOpenGL = true - Globals.Refs.app.analysisPage.plotView.useAnimation = false - Globals.Refs.app.analysisPage.plotView.useOpenGL = true - } - } + function updateSliderLimits() { + const from = Globals.BackendWrapper.analysisFitableParameters[Globals.BackendWrapper.analysisCurrentParameterIndex].from //[fittables.selectedParamIndex].from //Globals.Proxies.main_fittables_data[selectedParamIndex].from + const to = Globals.BackendWrapper.analysisFitableParameters[Globals.BackendWrapper.analysisCurrentParameterIndex].to //[fittables.selectedParamIndex].to //Globals.Proxies.main_fittables_data[selectedParamIndex].to + slider.from = EaLogic.Utils.toDefaultPrecision(from) + slider.to = EaLogic.Utils.toDefaultPrecision(to) + } - function disableOpenGL() { - if (Globals.Proxies.main.plotting.currentLib1d === 'QtCharts') { - ////Globals.Proxies.main.plotting.chartRefs.QtCharts.analysisPage.totalCalcSerie.pointsReplaced() - disableOpenGLTimer.restart() - } +/* function enableOpenGL() { + if (Globals.Proxies.main.plotting.currentLib1d === 'QtCharts') { + Globals.Refs.app.experimentPage.plotView.useOpenGL = true + //Globals.Refs.app.modelPage.plotView.useOpenGL = true + Globals.Refs.app.analysisPage.plotView.useAnimation = false + Globals.Refs.app.analysisPage.plotView.useOpenGL = true } + } - function disableOpenGLFromTimer() { - Globals.Refs.app.experimentPage.plotView.useOpenGL = false - //Globals.Refs.app.modelPage.plotView.useOpenGL = false + function disableOpenGL() { + if (Globals.Proxies.main.plotting.currentLib1d === 'QtCharts') { ////Globals.Proxies.main.plotting.chartRefs.QtCharts.analysisPage.totalCalcSerie.pointsReplaced() - ///console.error(Globals.Proxies.main.plotting.chartRefs.QtCharts.analysisPage.totalCalcSerie) - Globals.Refs.app.analysisPage.plotView.useAnimation = true - Globals.Refs.app.analysisPage.plotView.useOpenGL = false + disableOpenGLTimer.restart() } } -} \ No newline at end of file + + function disableOpenGLFromTimer() { + Globals.Refs.app.experimentPage.plotView.useOpenGL = false + //Globals.Refs.app.modelPage.plotView.useOpenGL = false + ////Globals.Proxies.main.plotting.chartRefs.QtCharts.analysisPage.totalCalcSerie.pointsReplaced() + ///console.error(Globals.Proxies.main.plotting.chartRefs.QtCharts.analysisPage.totalCalcSerie) + Globals.Refs.app.analysisPage.plotView.useAnimation = true + Globals.Refs.app.analysisPage.plotView.useOpenGL = false + }*/ +} + diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Groups/Fitting.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Groups/Fitting.qml index 4b9d8c54..de19eb4c 100644 --- a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Groups/Fitting.qml +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Groups/Fitting.qml @@ -5,10 +5,8 @@ import QtQuick import QtQuick.Controls -//import EasyApp.Gui.Globals as EaGlobals import EasyApp.Gui.Style as EaStyle import EasyApp.Gui.Elements as EaElements -//import EasyApp.Gui.Components as EaComponents import Gui.Globals as Globals @@ -19,7 +17,7 @@ EaElements.GroupBox { spacing: EaStyle.Sizes.fontPixelSize EaElements.SideBarButton { - enabled: Globals.Proxies.main.experiment.defined + enabled: Globals.BackendWrapper.analysisExperimentsAvailable.length //typeof Globals.BackendWrapper.analysisExperimentsAvailable !== 'undefined'//Globals.Proxies.main.experiment.defined wide: true fontIcon: Globals.BackendWrapper.analysisFittingRunning ? 'stop-circle' : 'play-circle' text: Globals.BackendWrapper.analysisFittingRunning ? qsTr('Cancel fitting') : qsTr('Start fitting') From bdea39988bc2308e4c6d82dfef55d5d0515ad967 Mon Sep 17 00:00:00 2001 From: Andreas Pedersen Date: Mon, 28 Oct 2024 13:30:51 +0100 Subject: [PATCH 12/43] mouseArea and usage of index rathet than currentIndex --- .../Gui/Globals/BackendWrapper.qml | 14 ++++++++------ .../Sidebar/Basic/Groups/Assemblies/MultiLayer.qml | 10 ++++++---- .../Basic/Groups/Assemblies/SurfactantLayer.qml | 9 +++++---- .../Sample/Sidebar/Basic/Groups/MaterialEditor.qml | 11 +++++++---- .../Sample/Sidebar/Basic/Groups/ModelEditor.qml | 13 +++++++------ .../Sample/Sidebar/Basic/Groups/ModelSelector.qml | 14 +++++++------- 6 files changed, 40 insertions(+), 31 deletions(-) diff --git a/src_qt6/EasyReflectometryApp/Gui/Globals/BackendWrapper.qml b/src_qt6/EasyReflectometryApp/Gui/Globals/BackendWrapper.qml index ef44a02e..34c64cbb 100644 --- a/src_qt6/EasyReflectometryApp/Gui/Globals/BackendWrapper.qml +++ b/src_qt6/EasyReflectometryApp/Gui/Globals/BackendWrapper.qml @@ -195,19 +195,21 @@ QtObject { function analysisFittingStartStop() { activeBackend.analysis.fittingStartStop() } // Parameters - readonly property int analysisFreeParametersCount: activeBackend.analysis.freeParametersCount - readonly property int analysisFixedParametersCount: activeBackend.analysis.fixedParametersCount - readonly property int analysisModelParametersCount: activeBackend.analysis.modelParametersCount - readonly property int analysisExperimentParametersCount: activeBackend.analysis.experimentParametersCount - readonly property var analysisFitableParameters: activeBackend.analysis.fitableParameters readonly property int analysisCurrentParameterIndex: activeBackend.analysis.currentParameterIndex function analysisSetCurrentParameterIndex(value) { activeBackend.analysis.setCurrentParameterIndex(value) } + readonly property var analysisFitableParameters: activeBackend.analysis.fitableParameters + function analysisSetCurrentParameterValue(value) { activeBackend.analysis.setCurrentParameterValue(value) } function analysisSetCurrentParameterMin(value) { activeBackend.analysis.setCurrentParameterMin(value) } function analysisSetCurrentParameterMax(value) { activeBackend.analysis.setCurrentParameterMax(value) } - function analysisSetCurrentParameterValue(value) { activeBackend.analysis.setCurrentParameterValue(value) } function analysisSetCurrentParameterFit(value) { activeBackend.analysis.setCurrentParameterFit(value) } + readonly property int analysisFreeParametersCount: activeBackend.analysis.freeParametersCount + readonly property int analysisFixedParametersCount: activeBackend.analysis.fixedParametersCount + readonly property int analysisModelParametersCount: activeBackend.analysis.modelParametersCount + readonly property int analysisExperimentParametersCount: activeBackend.analysis.experimentParametersCount + + /////////////// // Summary page diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/Sidebar/Basic/Groups/Assemblies/MultiLayer.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/Sidebar/Basic/Groups/Assemblies/MultiLayer.qml index e4d81e2a..e89663f0 100644 --- a/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/Sidebar/Basic/Groups/Assemblies/MultiLayer.qml +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/Sidebar/Basic/Groups/Assemblies/MultiLayer.qml @@ -61,7 +61,7 @@ EaElements.GroupColumn { horizontalAlignment: Text.AlignLeft model: Globals.BackendWrapper.sampleMaterialNames onActivated: { - Globals.BackendWrapper.sampleSetCurrentLayerMaterial(currentIndex) + Globals.BackendWrapper.sampleSetCurrentLayerMaterial(index) } onModelChanged: { currentIndex = indexOfValue(Globals.BackendWrapper.sampleLayers[index].material) @@ -94,10 +94,12 @@ EaElements.GroupColumn { enabled: layersView !== null && layersView.model > 1 onClicked: Globals.BackendWrapper.sampleRemoveLayer(index) } - } - onCurrentIndexChanged: { - Globals.BackendWrapper.sampleSetCurrentLayerIndex(layersView.currentIndex) + mouseArea.onPressed: { + if (Globals.BackendWrapper.sampleCurrentLayerIndex !== index) { + Globals.BackendWrapper.sampleSetCurrentLayerIndex(index) + } + } } } // Control buttons below table diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/Sidebar/Basic/Groups/Assemblies/SurfactantLayer.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/Sidebar/Basic/Groups/Assemblies/SurfactantLayer.qml index b1b66bc4..dd33ea8d 100644 --- a/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/Sidebar/Basic/Groups/Assemblies/SurfactantLayer.qml +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/Sidebar/Basic/Groups/Assemblies/SurfactantLayer.qml @@ -107,10 +107,11 @@ EaElements.GroupColumn { currentIndex = indexOfValue(Globals.BackendWrapper.sampleLayers[index].solvent) } } - } - - onCurrentIndexChanged: { - Globals.BackendWrapper.sampleSetCurrentLayerIndex(surfactantView.currentIndex) + mouseArea.onPressed: { + if (Globals.BackendWrapper.samplCurrentLayerIndex !== index) { + Globals.BackendWrapper.sampleSetCurrentLayerIndex(index) + } + } } } Row { diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/Sidebar/Basic/Groups/MaterialEditor.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/Sidebar/Basic/Groups/MaterialEditor.qml index c3e538b2..3c88860e 100644 --- a/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/Sidebar/Basic/Groups/MaterialEditor.qml +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/Sidebar/Basic/Groups/MaterialEditor.qml @@ -80,11 +80,14 @@ EaElements.GroupBox { enabled: materialsView !== null && materialsView.model > 1 fontIcon: "minus-circle" ToolTip.text: qsTr("Remove this material") - onClicked: Globals.BackendWrapper.sampleRemoveMaterial(materialsView.currentIndex) + onClicked: Globals.BackendWrapper.sampleRemoveMaterial(index) + } + + mouseArea.onPressed: { + if (Globals.BackendWrapper.sampleCurrentMaterialIndex !== index) { + Globals.BackendWrapper.sampleSetCurrentMaterialIndex(index) + } } - } - onCurrentIndexChanged: { - Globals.BackendWrapper.sampleSetCurrentMaterialIndex(materialsView.currentIndex) } } diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/Sidebar/Basic/Groups/ModelEditor.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/Sidebar/Basic/Groups/ModelEditor.qml index 7fe4f57a..9cef4b09 100644 --- a/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/Sidebar/Basic/Groups/ModelEditor.qml +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/Sidebar/Basic/Groups/ModelEditor.qml @@ -79,16 +79,17 @@ EaElements.GroupBox { fontIcon: "minus-circle" ToolTip.text: qsTr("Remove this assembly") enabled: assembliesView.model > 1 - onClicked: Globals.BackendWrapper.sampleRemoveAssembly(assembliesView.currentIndex) + onClicked: Globals.BackendWrapper.sampleRemoveAssembly(index) } - } + mouseArea.onPressed: { + if (Globals.BackendWrapper.sampleCurrentAssembyIndex !== index) { + Globals.BackendWrapper.sampleSetCurrentAssemblyIndex(index) + } + } - onCurrentIndexChanged: { - Globals.BackendWrapper.sampleSetCurrentAssemblyIndex(assembliesView.currentIndex) } - - onModelChanged: currentIndex = 0 + onModelChanged: Globals.BackendWrapper.sampleSetCurrentAssemblyIndex(0) } // Control buttons below table diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/Sidebar/Basic/Groups/ModelSelector.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/Sidebar/Basic/Groups/ModelSelector.qml index fe0f0e43..fa59e534 100644 --- a/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/Sidebar/Basic/Groups/ModelSelector.qml +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/Sidebar/Basic/Groups/ModelSelector.qml @@ -62,16 +62,16 @@ EaElements.GroupBox { enabled: (modelView.model > 1) ? true : false//When item is selected ToolTip.text: qsTr("Remove this model") onClicked: { - Globals.BackendWrapper.sampleRemoveModel(modelView.currentIndex) + Globals.BackendWrapper.sampleRemoveModel(index) } } - } - onCurrentIndexChanged: { - Globals.BackendWrapper.sampleSetCurrentModelIndex(modelView.currentIndex) - // NEED TO CONNECT THIS - // In ModelEditor assembliesView.currentIndex = 0 - // In MultiLayer layersView.currentIndex = 0 + mouseArea.onPressed: { + if (Globals.BackendWrapper.sampleCurrentModelIndex !== index) { + Globals.BackendWrapper.sampleSetCurrentAssemblyIndex(0) + Globals.BackendWrapper.sampleSetCurrentALayerIndex(0) + } + } } } From d0b7488c9e0b24d5513018ae18022c5c6a5467a3 Mon Sep 17 00:00:00 2001 From: Andreas Pedersen Date: Mon, 28 Oct 2024 13:31:12 +0100 Subject: [PATCH 13/43] towards only updating when changes are applied --- .../Backends/Py/logic/assemblies.py | 35 ++++++--- .../Backends/Py/logic/layers.py | 71 ++++++++++++------- .../Backends/Py/logic/material.py | 23 ++++-- .../Backends/Py/logic/models.py | 34 ++++++--- .../Backends/Py/sample.py | 68 +++++++++--------- 5 files changed, 144 insertions(+), 87 deletions(-) diff --git a/src_qt6/EasyReflectometryApp/Backends/Py/logic/assemblies.py b/src_qt6/EasyReflectometryApp/Backends/Py/logic/assemblies.py index ce0376e9..083ee025 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Py/logic/assemblies.py +++ b/src_qt6/EasyReflectometryApp/Backends/Py/logic/assemblies.py @@ -63,11 +63,14 @@ def move_selected_down(self) -> None: self._assembly_index = self._assembly_index + 1 def set_name_at_current_index(self, new_value: str) -> None: - self._assemblies[self._assembly_index].name = new_value + if self._assemblies[self._assembly_index].name != new_value: + self._assemblies[self._assembly_index].name = new_value + return True + return False - def set_type_at_current_index(self, new_value: str) -> None: + def set_type_at_current_index(self, new_value: str) -> bool: if new_value == self._assemblies[self._assembly_index].type: - return + return False if new_value == 'Multi-layer': if 'Si' not in [material.name for material in self._project_lib._materials]: @@ -96,6 +99,7 @@ def set_type_at_current_index(self, new_value: str) -> None: self._assemblies[self._assembly_index] = new_assembly self._project_lib._models[self._model_index].sample._disable_changes_to_outermost_layers() + return True # Only for repeating multilayer @property @@ -104,18 +108,27 @@ def repetitions_at_current_index(self) -> str: return str(int(self._assemblies[self._assembly_index].repetitions.value)) return '1' - def set_repeated_layer_reptitions(self, new_value: int) -> None: + def set_repeated_layer_reptitions(self, new_value: int) -> bool: if isinstance(self._assemblies[self._assembly_index], RepeatingMultilayer): - self._assemblies[self._assembly_index].repetitions.value = new_value - + if new_value != self._assemblies[self._assembly_index].repetitions.value: + self._assemblies[self._assembly_index].repetitions.value = new_value + return True + return False + # # Only for surfactant layer - def set_constrain_apm(self, new_value: str) -> None: + def set_constrain_apm(self, new_value: str) -> bool: if isinstance(self._assemblies[self._assembly_index], SurfactantLayer): - self._assemblies[self._assembly_index].constrain_area_per_molecule = new_value - - def set_conformal_roughness(self, new_value: str) -> None: + if self._assemblies[self._assembly_index].constrain_area_per_molecule != new_value: + self._assemblies[self._assembly_index].constrain_area_per_molecule = new_value + return True + return False + + def set_conformal_roughness(self, new_value: str) -> bool: if isinstance(self._assemblies[self._assembly_index], SurfactantLayer): - self._assemblies[self._assembly_index].conformal_roughness = new_value + if self._assemblies[self._assembly_index].conformal_roughness != new_value: + self._assemblies[self._assembly_index].conformal_roughness = new_value + return True + return False def _from_assemblies_collection_to_list_of_dicts(assemblies_collection: Sample) -> list[dict[str, str]]: diff --git a/src_qt6/EasyReflectometryApp/Backends/Py/logic/layers.py b/src_qt6/EasyReflectometryApp/Backends/Py/logic/layers.py index fa287c26..d882b1b2 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Py/logic/layers.py +++ b/src_qt6/EasyReflectometryApp/Backends/Py/logic/layers.py @@ -67,30 +67,53 @@ def move_selected_down(self) -> None: self._layers.move_down(self._layer_index) self._layer_index = self._layer_index + 1 - def set_name_at_current_index(self, new_value: str) -> None: - self._layers[self._layer_index].name = new_value - - def set_thickness_at_current_index(self, new_value: float) -> None: - self._layers[self._layer_index].thickness.value = new_value - - def set_roughness_at_current_index(self, new_value: float) -> None: - self._layers[self._layer_index].roughness.value = new_value - - def set_material_at_current_index(self, new_value: int) -> None: - self._layers[self._layer_index].material = self._project_lib._materials[new_value] - - def set_solvent_at_current_index(self, new_value: int) -> None: - self._layers[self._layer_index].solvent = self._project_lib._materials[new_value] - - def set_apm_at_current_index(self, new_value: float) -> None: - self._layers[self._layer_index].area_per_molecule = new_value - - def set_solvation_at_current_index(self, new_value: float) -> None: - self._layers[self._layer_index].solvent_fraction = new_value - - def set_formula(self, new_value: str) -> None: - self._layers[self._layer_index].molecular_formula = new_value - + def set_name_at_current_index(self, new_value: str) -> bool: + if self._layers[self._layer_index].name != new_value: + self._layers[self._layer_index].name = new_value + return True + return False + + def set_thickness_at_current_index(self, new_value: float) -> bool: + if self._layers[self._layer_index].thickness.value != new_value: + self._layers[self._layer_index].thickness.value = new_value + return True + return False + + def set_roughness_at_current_index(self, new_value: float) -> bool: + if self._layers[self._layer_index].roughness.value != new_value: + self._layers[self._layer_index].roughness.value = new_value + return True + return False + + def set_material_at_current_index(self, new_value: int) -> bool: + if self._layers[self._layer_index].material != self._project_lib._materials[new_value]: + self._layers[self._layer_index].material = self._project_lib._materials[new_value] + return True + return False + + def set_solvent_at_current_index(self, new_value: int) -> bool: + if self._layers[self._layer_index].solvent != self._project_lib._materials[new_value]: + self._layers[self._layer_index].solvent = self._project_lib._materials[new_value] + return True + return False + + def set_apm_at_current_index(self, new_value: float) -> bool: + if self._layers[self._layer_index].area_per_molecule != new_value: + self._layers[self._layer_index].area_per_molecule = new_value + return True + return False + + def set_solvation_at_current_index(self, new_value: float) -> bool: + if self._layers[self._layer_index].solvent_fraction != new_value: + self._layers[self._layer_index].solvent_fraction = new_value + return True + return False + + def set_formula(self, new_value: str) -> bool: + if self._layers[self._layer_index].molecular_formula != new_value: + self._layers[self._layer_index].molecular_formula = new_value + return True + return False def _from_layers_collection_to_list_of_dicts(layers_collection: LayerCollection) -> list[dict[str, str]]: layers_list = [] diff --git a/src_qt6/EasyReflectometryApp/Backends/Py/logic/material.py b/src_qt6/EasyReflectometryApp/Backends/Py/logic/material.py index 81b126d7..0c3d7966 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Py/logic/material.py +++ b/src_qt6/EasyReflectometryApp/Backends/Py/logic/material.py @@ -49,15 +49,24 @@ def move_selected_down(self) -> None: self._materials.move_down(self._material_index) self._material_index = self._material_index + 1 - def set_name_at_current_index(self, new_value: str) -> None: - self._materials[self._material_index].name = new_value + def set_name_at_current_index(self, new_value: str) -> bool: + if self._materials[self._material_index].name != new_value: + self._materials[self._material_index].name = new_value + return True + return False - def set_sld_at_current_index(self, new_value: float) -> None: - self._materials[self._material_index].sld.value = new_value - - def set_isld_at_current_index(self, new_value: float) -> None: - self._materials[self._material_index].isld.value = new_value + def set_sld_at_current_index(self, new_value: float) -> bool: + if self._materials[self._material_index].sld.value != new_value: + self._materials[self._material_index].sld.value = new_value + return True + return False + def set_isld_at_current_index(self, new_value: float) -> bool: + if self._materials[self._material_index].isld.value != new_value: + self._materials[self._material_index].isld.value = new_value + return True + return False + def _from_materials_collection_to_list_of_dicts(materials_collection: MaterialCollection) -> list[dict[str, str]]: materials_list = [] for material in materials_collection: diff --git a/src_qt6/EasyReflectometryApp/Backends/Py/logic/models.py b/src_qt6/EasyReflectometryApp/Backends/Py/logic/models.py index 5b20303e..33bb42f1 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Py/logic/models.py +++ b/src_qt6/EasyReflectometryApp/Backends/Py/logic/models.py @@ -46,18 +46,30 @@ def models(self) -> list[dict[str, str]]: def models_names(self) -> list[str]: return [element['label'] for element in self.models] - def set_name_at_current_index(self, new_value: str) -> None: - self._models[self._model_index].name = new_value - - def set_scaling_at_current_index(self, new_value: str) -> None: - self._models[self._model_index].scale.value = new_value - - def set_background_at_current_index(self, new_value: str) -> None: - self._models[self._model_index].background.value = new_value - - def set_resolution_at_current_index(self, new_value: str) -> None: + def set_name_at_current_index(self, new_value: str) -> bool: + if self._models[self._model_index].name != new_value: + self._models[self._model_index].name = new_value + return True + return False + + def set_scaling_at_current_index(self, new_value: str) -> bool: + if self._models[self._model_index].scale.value != new_value: + self._models[self._model_index].scale.value = new_value + return True + return False + + def set_background_at_current_index(self, new_value: str) -> bool: + if self._models[self._model_index].background.value != new_value: + self._models[self._model_index].background.value = new_value + return True + return False + + def set_resolution_at_current_index(self, new_value: str) -> bool: if isinstance(self._models[self._model_index].resolution_function, PercentageFhwm): - self._models[self._model_index].resolution_function.constant = float(new_value) + if self._models[self._model_index].resolution_function.constant != float(new_value): + self._models[self._model_index].resolution_function.constant = float(new_value) + return True + return False def remove_at_index(self, value: str) -> None: self._models.pop(int(value)) diff --git a/src_qt6/EasyReflectometryApp/Backends/Py/sample.py b/src_qt6/EasyReflectometryApp/Backends/Py/sample.py index 7709d9f8..b8489e18 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Py/sample.py +++ b/src_qt6/EasyReflectometryApp/Backends/Py/sample.py @@ -85,18 +85,18 @@ def setCurrentMaterialIndex(self, new_value: int) -> None: @Slot(str) def setCurrentMaterialName(self, new_value: str) -> None: - self._material_logic.set_name_at_current_index(new_value) - self.materialsChanged.emit() + if self._material_logic.set_name_at_current_index(new_value): + self.materialsChanged.emit() @Slot(float) def setCurrentMaterialSld(self, new_value: float) -> None: - self._material_logic.set_sld_at_current_index(new_value) - self.materialsChanged.emit() + if self._material_logic.set_sld_at_current_index(new_value): + self.materialsChanged.emit() @Slot(float) def setCurrentMaterialISld(self, new_value: float) -> None: - self._material_logic.set_isld_at_current_index(new_value) - self.materialsChanged.emit() + if self._material_logic.set_isld_at_current_index(new_value): + self.materialsChanged.emit() # Actions @Slot(str) @@ -150,8 +150,8 @@ def setCurrentModelIndex(self, new_value: int) -> None: @Slot(str) def setCurrentModelName(self, value: str) -> None: - self._models_logic.set_name_at_current_index(value) - self.modelsTableChanged.emit() + if self._models_logic.set_name_at_current_index(value): + self.modelsTableChanged.emit() # Actions @Slot(str) @@ -209,13 +209,13 @@ def setCurrentAssemblyIndex(self, new_value: int) -> None: @Slot(str) def setCurrentAssemblyName(self, new_value: str) -> None: - self._assemblies_logic.set_name_at_current_index(new_value) - self.assembliesTableChanged.emit() + if self._assemblies_logic.set_name_at_current_index(new_value): + self.assembliesTableChanged.emit() @Slot(str) def setCurrentAssemblyType(self, new_value: str) -> None: - self._assemblies_logic.set_type_at_current_index(new_value) - self.assembliesTableChanged.emit() + if self._assemblies_logic.set_type_at_current_index(new_value): + self.assembliesTableChanged.emit() # Assembly specific @Property(str, notify=assembliesChange) @@ -224,18 +224,18 @@ def currentAssemblyRepeatedLayerReptitions(self) -> str: @Slot(int) def setCurrentAssemblyRepeatedLayerReptitions(self, new_value: int) -> None: - self._assemblies_logic.set_repeated_layer_reptitions(new_value) - self.assembliesTableChanged.emit() + if self._assemblies_logic.set_repeated_layer_reptitions(new_value): + self.assembliesTableChanged.emit() @Slot(bool) def setCurrentAssemblyConstrainAPM(self, new_value: bool) -> None: - self._assemblies_logic.set_constrain_apm(new_value) - self.assembliesTableChanged.emit() + if self._assemblies_logic.set_constrain_apm(new_value): + self.assembliesTableChanged.emit() @Slot(bool) def setCurrentAssemblyConformalRoughness(self, new_value: bool) -> None: - self._assemblies_logic.set_conformal_roughness(new_value) - self.assembliesTableChanged.emit() + if self._assemblies_logic.set_conformal_roughness(new_value): + self.assembliesTableChanged.emit() # Actions @Slot(str) @@ -288,43 +288,43 @@ def setCurrentLayerIndex(self, new_value: int) -> None: @Slot(str) def setCurrentLayerName(self, new_value: str) -> None: - self._layers_logic.set_name_at_current_index(new_value) - self.layersTableChanged.emit() + if self._layers_logic.set_name_at_current_index(new_value): + self.layersTableChanged.emit() @Slot(int) def setCurrentLayerMaterial(self, new_value: int) -> None: - self._layers_logic.set_material_at_current_index(new_value) - self.layersTableChanged.emit() + if self._layers_logic.set_material_at_current_index(new_value): + self.layersTableChanged.emit() @Slot(int) def setCurrentLayerSolvent(self, new_value: int) -> None: - self._layers_logic.set_solvent_at_current_index(new_value) - self.layersTableChanged.emit() + if self._layers_logic.set_solvent_at_current_index(new_value): + self.layersTableChanged.emit() @Slot(float) def setCurrentLayerThickness(self, new_value: float) -> None: - self._layers_logic.set_thickness_at_current_index(new_value) - self.layersTableChanged.emit() + if self._layers_logic.set_thickness_at_current_index(new_value): + self.layersTableChanged.emit() @Slot(float) def setCurrentLayerRoughness(self, new_value: float) -> None: - self._layers_logic.set_roughness_at_current_index(new_value) - self.layersTableChanged.emit() + if self._layers_logic.set_roughness_at_current_index(new_value): + self.layersTableChanged.emit() @Slot(str) def setCurrentLayerFormula(self, new_value: str) -> None: - self._layers_logic.set_formula(new_value) - self.layersTableChanged.emit() + if self._layers_logic.set_formula(new_value): + self.layersTableChanged.emit() @Slot(float) def setCurrentLayerAPM(self, new_value: float) -> None: - self._layers_logic.set_apm_at_current_index(new_value) - self.layersTableChanged.emit() + if self._layers_logic.set_apm_at_current_index(new_value): + self.layersTableChanged.emit() @Slot(float) def setCurrentLayerSolvation(self, new_value: float) -> None: - self._layers_logic.set_solvation_at_current_index(new_value) - self.layersTableChanged.emit() + if self._layers_logic.set_solvation_at_current_index(new_value): + self.layersTableChanged.emit() # Actions @Slot(str) From a70095043a0c972e2d3429c34f0c6f3423fa2c4c Mon Sep 17 00:00:00 2001 From: Andreas Pedersen Date: Mon, 28 Oct 2024 14:06:15 +0100 Subject: [PATCH 14/43] python skeleton for analysis --- .../Backends/Py/analysis.py | 163 ++++++++++++++---- .../Gui/Globals/BackendWrapper.qml | 18 +- 2 files changed, 138 insertions(+), 43 deletions(-) diff --git a/src_qt6/EasyReflectometryApp/Backends/Py/analysis.py b/src_qt6/EasyReflectometryApp/Backends/Py/analysis.py index 5565dcdb..b1c556d4 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Py/analysis.py +++ b/src_qt6/EasyReflectometryApp/Backends/Py/analysis.py @@ -10,82 +10,179 @@ class Analysis(QObject): + minimizerChanged = Signal() + calculatorChanged = Signal() + experimentsChanged = Signal() + parametersChanged = Signal() fitFinishedChanged = Signal() - def __init__(self, project_lib: ProjectLib, parent=None): super().__init__(parent) # self._logic = AnalysisLogic(project_lib) - - # Setters and getters - - @Property(bool, notify=fitFinishedChanged) - def isFitFinished(self) -> bool: - return True - - @Property(str, notify=fitFinishedChanged) - def minimizerStatus(self) -> str: - return "Minimizer status" - @Property('QVariantList') + @Property('QVariantList', notify=minimizerChanged) def minimizersAvailable(self) -> List[str]: return ["Minimizer 1", "Minimizer 2", "Minimizer 3"] - - @Property(int) + @Property(int, notify=minimizerChanged) def minimizerCurrentIndex(self) -> int: return 0 + @Slot(int) + def setMinimizerCurrentIndex(self, new_value: int) -> None: + print(new_value) + #self._material_logic.index = new_value + #self.materialIndexChanged.emit(new_value) - @Property('QVariantList') + @Property('QVariantList', notify=calculatorChanged) def calculatorsAvailable(self) -> List[str]: return ["Calculator 1", "Calculator 2", "Calculator 3"] - - @Property(int) + @Property(int, notify=calculatorChanged) def calculatorCurrentIndex(self) -> int: return 0 + @Slot(int) + def setCalculatorCurrentIndex(self, new_value: int) -> None: + print(new_value) + #self._material_logic.index = new_value + #self.materialIndexChanged.emit(new_value) - @Property('QVariantList') + @Property('QVariantList', notify=experimentsChanged) def experimentsAvailable(self) -> List[str]: return ["Experiment 1", "Experiment 2", "Experiment 3"] - - @Property(int) + @Property(int, notify=experimentsChanged) def experimentCurrentIndex(self) -> int: return 0 + @Slot(int) + def setExperimentCurrentIndex(self, new_value: int) -> None: + print(new_value) + #self._material_logic.index = new_value + #self.materialIndexChanged.emit(new_value) - @Property(float) + @Property('QVariantList', notify=parametersChanged) + def fitableParameters(self) -> List[str]: + return [ + { + 'name': 'name 1', + 'value': 1.0, + 'error': -1.23456, + 'max': 100.0, + 'min': -100.0, + 'units': 'u1', + 'fit': True, + 'from': -10.0, + 'to': 10.0, + }, + { + 'name': 'name 2', + 'value': 2.0, + 'error': -2.34567, + 'max': 200.0, + 'min': -200.0, + 'units': 'u2', + 'fit': False, + 'from': -20.0, + 'to': 20.0, + }, + { + 'name': 'name 3', + 'value': 3.0, + 'error': -3.45678, + 'max': 300.0, + 'min': -300.0, + 'units': 'u3', + 'fit': True, + 'from': -30.0, + 'to': 30.0, + }, + ] + @Property(int, notify=parametersChanged) + def currentParameterIndex(self) -> int: + return 0 + @Slot(int) + def setCurrentParameterIndex(self, new_value: int) -> None: + print(new_value) + #self._material_logic.index = new_value + #self.materialIndexChanged.emit(new_value) + + ## Minimizer + @Property(str, notify=fitFinishedChanged) + def minimizerStatus(self) -> str: + return "" + + @Property(float, notify=minimizerChanged) def minimizerTolerance(self) -> float: return 1.0 - @Property(int) + @Property(int, notify=minimizerChanged) def minimizerMaxIterations(self) -> int: return 1000 + + @Slot(float) + def setMinimizerTolerance(self, new_value: float) -> None: + print(new_value) + self.minimizerChanged.emit() + #self._material_logic.index = new_value + #self.materialIndexChanged.emit(new_value) - # Setters @Slot(int) - def setMinimizerCurrentIndex(self, new_value: int) -> None: + def setMinimizerMaxIterations(self, new_value: int) -> None: print(new_value) - #self._material_logic.index = new_value + self.minimizerChanged.emit() + #self._material_logic.index = new_value #self.materialIndexChanged.emit(new_value) - @Slot(int) - def setCalculatorCurrentIndex(self, new_value: int) -> None: + ## Fitting + @Property(bool, notify=fitFinishedChanged) + def fittingRunning(self) -> bool: + return False + + @Property(bool, notify=fitFinishedChanged) + def isFitFinished(self) -> bool: + return True + + @Slot(None) + def fittingStartStop(self) -> None: + print('fittingStartStop') + + ## Parameters + @Property(int, notify=parametersChanged) + def freeParametersCount(self) -> int: + return 1 + + @Property(int, notify=parametersChanged) + def fixedParametersCount(self) -> int: + return 2 + + @Property(int, notify=parametersChanged) + def modelParametersCount(self) -> int: + return 3 + + @Property(int, notify=parametersChanged) + def experimentParametersCount(self) -> int: + return 3 + + @Slot(float) + def setCurrentParameterValue(self, new_value: float) -> None: print(new_value) + self.parametersChanged.emit() #self._material_logic.index = new_value #self.materialIndexChanged.emit(new_value) - @Slot(int) - def setExperimentCurrentIndex(self, new_value: int) -> None: + @Slot(float) + def setCurrentParameterMin(self, new_value: float) -> None: print(new_value) + self.parametersChanged.emit() #self._material_logic.index = new_value #self.materialIndexChanged.emit(new_value) @Slot(float) - def setMinimizerTolerance(self, new_value: float) -> None: + def setCurrentParameterMax(self, new_value: float) -> None: print(new_value) + self.parametersChanged.emit() #self._material_logic.index = new_value #self.materialIndexChanged.emit(new_value) - - @Slot(int) - def setMinimizerMaxIterations(self, new_value: int) -> None: + + @Slot(bool) + def setCurrentParameterFit(self, new_value: bool) -> None: print(new_value) + self.parametersChanged.emit() #self._material_logic.index = new_value #self.materialIndexChanged.emit(new_value) \ No newline at end of file diff --git a/src_qt6/EasyReflectometryApp/Gui/Globals/BackendWrapper.qml b/src_qt6/EasyReflectometryApp/Gui/Globals/BackendWrapper.qml index 34c64cbb..7cd7948c 100644 --- a/src_qt6/EasyReflectometryApp/Gui/Globals/BackendWrapper.qml +++ b/src_qt6/EasyReflectometryApp/Gui/Globals/BackendWrapper.qml @@ -182,6 +182,10 @@ QtObject { readonly property int analysisMinimizerCurrentIndex: activeBackend.analysis.minimizerCurrentIndex function analysisSetMinimizerCurrentIndex(value) { activeBackend.analysis.setMinimizerCurrentIndex(value) } + readonly property var analysisFitableParameters: activeBackend.analysis.fitableParameters + readonly property int analysisCurrentParameterIndex: activeBackend.analysis.currentParameterIndex + function analysisSetCurrentParameterIndex(value) { activeBackend.analysis.setCurrentParameterIndex(value) } + // Minimizer readonly property string analysisMinimizerStatus: activeBackend.analysis.minimizerStatus readonly property double analysisMinimizerTolerance: activeBackend.analysis.minimizerTolerance @@ -195,21 +199,15 @@ QtObject { function analysisFittingStartStop() { activeBackend.analysis.fittingStartStop() } // Parameters - readonly property int analysisCurrentParameterIndex: activeBackend.analysis.currentParameterIndex - function analysisSetCurrentParameterIndex(value) { activeBackend.analysis.setCurrentParameterIndex(value) } - - readonly property var analysisFitableParameters: activeBackend.analysis.fitableParameters - function analysisSetCurrentParameterValue(value) { activeBackend.analysis.setCurrentParameterValue(value) } - function analysisSetCurrentParameterMin(value) { activeBackend.analysis.setCurrentParameterMin(value) } - function analysisSetCurrentParameterMax(value) { activeBackend.analysis.setCurrentParameterMax(value) } - function analysisSetCurrentParameterFit(value) { activeBackend.analysis.setCurrentParameterFit(value) } - readonly property int analysisFreeParametersCount: activeBackend.analysis.freeParametersCount readonly property int analysisFixedParametersCount: activeBackend.analysis.fixedParametersCount readonly property int analysisModelParametersCount: activeBackend.analysis.modelParametersCount readonly property int analysisExperimentParametersCount: activeBackend.analysis.experimentParametersCount - + function analysisSetCurrentParameterValue(value) { activeBackend.analysis.setCurrentParameterValue(value) } + function analysisSetCurrentParameterMin(value) { activeBackend.analysis.setCurrentParameterMin(value) } + function analysisSetCurrentParameterMax(value) { activeBackend.analysis.setCurrentParameterMax(value) } + function analysisSetCurrentParameterFit(value) { activeBackend.analysis.setCurrentParameterFit(value) } /////////////// // Summary page From 8a90681e1ad8db3ef5e33c7e0d98a8d011b6ba67 Mon Sep 17 00:00:00 2001 From: Andreas Pedersen Date: Mon, 28 Oct 2024 14:51:07 +0100 Subject: [PATCH 15/43] more skeleton work --- .../Backends/Py/analysis.py | 80 +++++-------------- .../Backends/Py/logic/calculators.py | 17 ++++ .../Backends/Py/logic/experiments.py | 23 ++++++ .../Backends/Py/logic/fitting.py | 17 ++++ .../Backends/Py/logic/parameters.py | 50 ++++++++++++ 5 files changed, 129 insertions(+), 58 deletions(-) create mode 100644 src_qt6/EasyReflectometryApp/Backends/Py/logic/calculators.py create mode 100644 src_qt6/EasyReflectometryApp/Backends/Py/logic/experiments.py create mode 100644 src_qt6/EasyReflectometryApp/Backends/Py/logic/fitting.py create mode 100644 src_qt6/EasyReflectometryApp/Backends/Py/logic/parameters.py diff --git a/src_qt6/EasyReflectometryApp/Backends/Py/analysis.py b/src_qt6/EasyReflectometryApp/Backends/Py/analysis.py index b1c556d4..279229a8 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Py/analysis.py +++ b/src_qt6/EasyReflectometryApp/Backends/Py/analysis.py @@ -6,7 +6,10 @@ from typing import List from easyreflectometry import Project as ProjectLib -#from .logic.Analysis import Analysis as AnalysisLogic +from .logic.parameters import Parameters as ParametersLogic +from .logic.fitting import Fitting as FittingLogic +from .logic.calculators import Calculators as CalculatorsLogic +from .logic.experiments import Experiments as ExperimentLogic class Analysis(QObject): @@ -18,89 +21,50 @@ class Analysis(QObject): def __init__(self, project_lib: ProjectLib, parent=None): super().__init__(parent) -# self._logic = AnalysisLogic(project_lib) - + self._paramters_logic = ParametersLogic(project_lib) + self._fitting_logic = FittingLogic(project_lib) + self._calculators_logic = CalculatorsLogic(project_lib) + self._experiments_logic = ExperimentLogic(project_lib) + @Property('QVariantList', notify=minimizerChanged) def minimizersAvailable(self) -> List[str]: - return ["Minimizer 1", "Minimizer 2", "Minimizer 3"] + return self._fitting_logic.available() @Property(int, notify=minimizerChanged) def minimizerCurrentIndex(self) -> int: - return 0 + return self._fitting_logic.current_index() @Slot(int) def setMinimizerCurrentIndex(self, new_value: int) -> None: - print(new_value) - #self._material_logic.index = new_value - #self.materialIndexChanged.emit(new_value) + self._fitting_logic.set_current_index(new_value) @Property('QVariantList', notify=calculatorChanged) def calculatorsAvailable(self) -> List[str]: - return ["Calculator 1", "Calculator 2", "Calculator 3"] + return self._calculators_logic.available() @Property(int, notify=calculatorChanged) def calculatorCurrentIndex(self) -> int: - return 0 + return self._calculators_logic.current_index() @Slot(int) def setCalculatorCurrentIndex(self, new_value: int) -> None: - print(new_value) - #self._material_logic.index = new_value - #self.materialIndexChanged.emit(new_value) + self._calculators_logic.set_current_index(new_value) @Property('QVariantList', notify=experimentsChanged) def experimentsAvailable(self) -> List[str]: - return ["Experiment 1", "Experiment 2", "Experiment 3"] + return self._experiments_logic.available() @Property(int, notify=experimentsChanged) def experimentCurrentIndex(self) -> int: - return 0 + return self._experiments_logic.current_index() @Slot(int) def setExperimentCurrentIndex(self, new_value: int) -> None: - print(new_value) - #self._material_logic.index = new_value - #self.materialIndexChanged.emit(new_value) + self._experiments_logic.set_current_index(new_value) @Property('QVariantList', notify=parametersChanged) - def fitableParameters(self) -> List[str]: - return [ - { - 'name': 'name 1', - 'value': 1.0, - 'error': -1.23456, - 'max': 100.0, - 'min': -100.0, - 'units': 'u1', - 'fit': True, - 'from': -10.0, - 'to': 10.0, - }, - { - 'name': 'name 2', - 'value': 2.0, - 'error': -2.34567, - 'max': 200.0, - 'min': -200.0, - 'units': 'u2', - 'fit': False, - 'from': -20.0, - 'to': 20.0, - }, - { - 'name': 'name 3', - 'value': 3.0, - 'error': -3.45678, - 'max': 300.0, - 'min': -300.0, - 'units': 'u3', - 'fit': True, - 'from': -30.0, - 'to': 30.0, - }, - ] + def fitableParameters(self) -> List[dict[str]]: + return self._paramters_logic.fitable() @Property(int, notify=parametersChanged) def currentParameterIndex(self) -> int: - return 0 + return self._paramters_logic.current_index() @Slot(int) def setCurrentParameterIndex(self, new_value: int) -> None: - print(new_value) - #self._material_logic.index = new_value - #self.materialIndexChanged.emit(new_value) + self._paramters_logic.set_current_index(new_value) ## Minimizer @Property(str, notify=fitFinishedChanged) diff --git a/src_qt6/EasyReflectometryApp/Backends/Py/logic/calculators.py b/src_qt6/EasyReflectometryApp/Backends/Py/logic/calculators.py new file mode 100644 index 00000000..52dc0203 --- /dev/null +++ b/src_qt6/EasyReflectometryApp/Backends/Py/logic/calculators.py @@ -0,0 +1,17 @@ +from easyreflectometry import Project as ProjectLib + + +class Calculators: + def __init__(self, project_lib: ProjectLib): + self._project_lib = project_lib + + def available(self) -> list[str]: + return ["Calculator 1", "Calculator 2", "Calculator 3"] + + def current_index(self) -> int: + return 0 + + def set_current_index(self, new_value: int) -> None: + print(new_value) + #self._material_logic.index = new_value + #self.materialIndexChanged.emit(new_value) diff --git a/src_qt6/EasyReflectometryApp/Backends/Py/logic/experiments.py b/src_qt6/EasyReflectometryApp/Backends/Py/logic/experiments.py new file mode 100644 index 00000000..e7cbcd87 --- /dev/null +++ b/src_qt6/EasyReflectometryApp/Backends/Py/logic/experiments.py @@ -0,0 +1,23 @@ +from easyreflectometry import Project as ProjectLib + + +class Experiments: + def __init__(self, project_lib: ProjectLib): + self._project_lib = project_lib + + def available(self) -> list[str]: + experimental_data = False + try: + self._project_lib.experimental_data_for_model_at_index() + experimental_data = True + except IndexError: + pass + return experimental_data + + def current_index(self) -> int: + return 0 + + def set_current_index(self, new_value: int) -> None: + print(new_value) + #self._material_logic.index = new_value + #self.materialIndexChanged.emit(new_value) diff --git a/src_qt6/EasyReflectometryApp/Backends/Py/logic/fitting.py b/src_qt6/EasyReflectometryApp/Backends/Py/logic/fitting.py new file mode 100644 index 00000000..b8862bda --- /dev/null +++ b/src_qt6/EasyReflectometryApp/Backends/Py/logic/fitting.py @@ -0,0 +1,17 @@ +from easyreflectometry import Project as ProjectLib + + +class Fitting: + def __init__(self, project_lib: ProjectLib): + self._project_lib = project_lib + + def available(self) -> list[str]: + return ["Minimizer 1", "Minimizer 2", "Minimizer 3"] + + def current_index(self) -> int: + return 0 + + def set_current_index(self, new_value: int) -> None: + print(new_value) + #self._material_logic.index = new_value + #self.materialIndexChanged.emit(new_value) diff --git a/src_qt6/EasyReflectometryApp/Backends/Py/logic/parameters.py b/src_qt6/EasyReflectometryApp/Backends/Py/logic/parameters.py new file mode 100644 index 00000000..40f801c7 --- /dev/null +++ b/src_qt6/EasyReflectometryApp/Backends/Py/logic/parameters.py @@ -0,0 +1,50 @@ +from easyreflectometry import Project as ProjectLib +from typing import List + + +class Parameters: + def __init__(self, project_lib: ProjectLib): + self._project_lib = project_lib + + def fitable(self) -> List[str]: + return [ + { + 'name': 'name 1', + 'value': 1.0, + 'error': -1.23456, + 'max': 100.0, + 'min': -100.0, + 'units': 'u1', + 'fit': True, + 'from': -10.0, + 'to': 10.0, + }, + { + 'name': 'name 2', + 'value': 2.0, + 'error': -2.34567, + 'max': 200.0, + 'min': -200.0, + 'units': 'u2', + 'fit': False, + 'from': -20.0, + 'to': 20.0, + }, + { + 'name': 'name 3', + 'value': 3.0, + 'error': -3.45678, + 'max': 300.0, + 'min': -300.0, + 'units': 'u3', + 'fit': True, + 'from': -30.0, + 'to': 30.0, + }, + ] + + def current_index(self) -> int: + return 0 + + def set_current_index(self, new_value: int) -> None: + print(new_value) \ No newline at end of file From aaf3cfc9e2b2c3b4942f02917a6272935437ec17 Mon Sep 17 00:00:00 2001 From: Andreas Pedersen Date: Thu, 31 Oct 2024 11:19:00 +0100 Subject: [PATCH 16/43] minimizer seeems functional --- .../Backends/Py/analysis.py | 53 ++++++++------- .../Backends/Py/logic/experiments.py | 7 +- .../Backends/Py/logic/fitting.py | 68 ++++++++++++++++--- .../Backends/Py/logic/status.py | 4 +- .../Backends/Py/py_backend.py | 12 +++- .../Gui/Globals/BackendWrapper.qml | 4 +- .../Sidebar/Advanced/Groups/Minimizer.qml | 47 ++++--------- src_qt6/pyproject.toml | 4 +- 8 files changed, 119 insertions(+), 80 deletions(-) diff --git a/src_qt6/EasyReflectometryApp/Backends/Py/analysis.py b/src_qt6/EasyReflectometryApp/Backends/Py/analysis.py index 279229a8..b7743484 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Py/analysis.py +++ b/src_qt6/EasyReflectometryApp/Backends/Py/analysis.py @@ -4,6 +4,7 @@ from PySide6.QtCore import Property from typing import List +from typing import Optional from easyreflectometry import Project as ProjectLib from .logic.parameters import Parameters as ParametersLogic @@ -28,13 +29,14 @@ def __init__(self, project_lib: ProjectLib, parent=None): @Property('QVariantList', notify=minimizerChanged) def minimizersAvailable(self) -> List[str]: - return self._fitting_logic.available() + return self._fitting_logic.minimizers_available() @Property(int, notify=minimizerChanged) def minimizerCurrentIndex(self) -> int: - return self._fitting_logic.current_index() + return self._fitting_logic.minimizer_current_index() @Slot(int) def setMinimizerCurrentIndex(self, new_value: int) -> None: - self._fitting_logic.set_current_index(new_value) + if self._fitting_logic.set_minimizer_current_index(new_value): + self.minimizerChanged.emit() @Property('QVariantList', notify=calculatorChanged) def calculatorsAvailable(self) -> List[str]: @@ -66,46 +68,45 @@ def currentParameterIndex(self) -> int: def setCurrentParameterIndex(self, new_value: int) -> None: self._paramters_logic.set_current_index(new_value) - ## Minimizer + ######################## + ## Fitting and Minimizer @Property(str, notify=fitFinishedChanged) def minimizerStatus(self) -> str: - return "" + return self._fitting_logic.status - @Property(float, notify=minimizerChanged) - def minimizerTolerance(self) -> float: - return 1.0 + @Property('QVariant', notify=minimizerChanged) + def minimizerTolerance(self) -> Optional[float]: + return self._fitting_logic.tolerance - @Property(int, notify=minimizerChanged) - def minimizerMaxIterations(self) -> int: - return 1000 + @Property('QVariant', notify=minimizerChanged) + def minimizerMaxIterations(self) -> Optional[int]: + return self._fitting_logic.max_iterations + + @Property(bool, notify=fitFinishedChanged) + def fittingRunning(self) -> bool: + return self._fitting_logic.running + + @Property(bool, notify=fitFinishedChanged) + def isFitFinished(self) -> bool: + return self._fitting_logic.fit_finished @Slot(float) def setMinimizerTolerance(self, new_value: float) -> None: - print(new_value) - self.minimizerChanged.emit() - #self._material_logic.index = new_value - #self.materialIndexChanged.emit(new_value) + if self._fitting_logic.set_tolerance(new_value): + self.minimizerChanged.emit() @Slot(int) def setMinimizerMaxIterations(self, new_value: int) -> None: - print(new_value) - self.minimizerChanged.emit() + if self._fitting_logic.set_max_iterations(new_value): + self.minimizerChanged.emit() #self._material_logic.index = new_value #self.materialIndexChanged.emit(new_value) - - ## Fitting - @Property(bool, notify=fitFinishedChanged) - def fittingRunning(self) -> bool: - return False - - @Property(bool, notify=fitFinishedChanged) - def isFitFinished(self) -> bool: - return True @Slot(None) def fittingStartStop(self) -> None: print('fittingStartStop') + ############# ## Parameters @Property(int, notify=parametersChanged) def freeParametersCount(self) -> int: diff --git a/src_qt6/EasyReflectometryApp/Backends/Py/logic/experiments.py b/src_qt6/EasyReflectometryApp/Backends/Py/logic/experiments.py index e7cbcd87..767b32a1 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Py/logic/experiments.py +++ b/src_qt6/EasyReflectometryApp/Backends/Py/logic/experiments.py @@ -6,13 +6,12 @@ def __init__(self, project_lib: ProjectLib): self._project_lib = project_lib def available(self) -> list[str]: - experimental_data = False + experiments_name = [] try: - self._project_lib.experimental_data_for_model_at_index() - experimental_data = True + experiments_name.append(self._project_lib.experimental_data_for_model_at_index()) except IndexError: pass - return experimental_data + return experiments_name def current_index(self) -> int: return 0 diff --git a/src_qt6/EasyReflectometryApp/Backends/Py/logic/fitting.py b/src_qt6/EasyReflectometryApp/Backends/Py/logic/fitting.py index b8862bda..ca60631d 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Py/logic/fitting.py +++ b/src_qt6/EasyReflectometryApp/Backends/Py/logic/fitting.py @@ -1,17 +1,69 @@ +from easyscience import AvailableMinimizers from easyreflectometry import Project as ProjectLib class Fitting: def __init__(self, project_lib: ProjectLib): self._project_lib = project_lib + self._minimizer_current_index = 0 + self._list_available_minimizers = list(AvailableMinimizers) + try: + self._list_available_minimizers.remove(AvailableMinimizers.LMFit) + except ValueError: + pass + try: + self._list_available_minimizers.remove(AvailableMinimizers.Bumps) + except ValueError: + pass + try: + self._list_available_minimizers.remove(AvailableMinimizers.DFO) + except ValueError: + pass - def available(self) -> list[str]: - return ["Minimizer 1", "Minimizer 2", "Minimizer 3"] + def minimizers_available(self) -> list[str]: + return [minimizer.name for minimizer in self._list_available_minimizers] - def current_index(self) -> int: - return 0 + def minimizer_current_index(self) -> int: + return self._minimizer_current_index - def set_current_index(self, new_value: int) -> None: - print(new_value) - #self._material_logic.index = new_value - #self.materialIndexChanged.emit(new_value) + def set_minimizer_current_index(self, new_value: int) -> None: + if new_value != self._minimizer_current_index: + self._minimizer_current_index = new_value + enum_new_minimizer = self._list_available_minimizers[new_value] + self._project_lib._fitter.switch_minimizer(enum_new_minimizer) + return True + return False + + @property + def status(self) -> str: + return '' #self._project_lib.status + + @property + def tolerance(self) -> float: + return self._project_lib._fitter.easy_science_multi_fitter.tolerance + + @property + def max_iterations(self) -> int: + return self._project_lib._fitter.easy_science_multi_fitter.max_evaluations + + @property + def running(self) -> bool: + return False + + @property + def fit_finished(self) -> bool: + return True + + def set_tolerance(self, new_value: float) -> bool: + if new_value != self._project_lib._fitter.easy_science_multi_fitter.tolerance: + self._project_lib._fitter.easy_science_multi_fitter.tolerance = new_value + print(new_value) + return True + return False + + def set_max_iterations(self, new_value: float) -> bool: + if new_value != self._project_lib._fitter.easy_science_multi_fitter.max_evaluations: + self._project_lib._fitter.easy_science_multi_fitter.max_evaluations = new_value + print(new_value) + return True + return False \ No newline at end of file diff --git a/src_qt6/EasyReflectometryApp/Backends/Py/logic/status.py b/src_qt6/EasyReflectometryApp/Backends/Py/logic/status.py index d061eefa..f7a54fd5 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Py/logic/status.py +++ b/src_qt6/EasyReflectometryApp/Backends/Py/logic/status.py @@ -11,11 +11,11 @@ def project(self): @property def minimizer(self): - return self._project_lib._minimizer.name + return self._project_lib._fitter.easy_science_multi_fitter.minimizer.name @property def calculator(self): - return self._project_lib._calculator().name + return self._project_lib.calculator @property def experiments_count(self): diff --git a/src_qt6/EasyReflectometryApp/Backends/Py/py_backend.py b/src_qt6/EasyReflectometryApp/Backends/Py/py_backend.py index 4a27b464..1a94e4f6 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Py/py_backend.py +++ b/src_qt6/EasyReflectometryApp/Backends/Py/py_backend.py @@ -80,7 +80,8 @@ def logger(self): def _connect_backend_parts(self) -> None: self._connect_project_page() self._connect_sample_page() - self._connect_example_page() + self._connect_experiment_page() + self._connect_analysis_page() ######### Project def _connect_project_page(self) -> None: @@ -91,9 +92,12 @@ def _connect_sample_page(self) -> None: self._sample.modelsIndexChanged.connect(self._relay_sample_page_models_index) self._sample.sampleChanged.connect(self._relay_sample_page_sample_changed) - def _connect_example_page(self) -> None: + def _connect_experiment_page(self) -> None: self._experiment.experimentChanged.connect(self._relay_experiment_page_experiment_changed) + def _connect_analysis_page(self) -> None: + self._analysis.minimizerChanged.connect(self._relay_analysis_page_minimizer_changed) + def _relay_project_page_name(self): self._status.projectChanged.emit() self._report.asHtmlChanged.emit() @@ -116,3 +120,7 @@ def _relay_experiment_page_experiment_changed(self): self._plotting.refreshAnalysisPage() self._status.experimentsCountChanged.emit() self._sample.sampleChanged.emit() + self._analysis.experimentsChanged.emit() + + def _relay_analysis_page_minimizer_changed(self): + self._status.minimizerChanged.emit() diff --git a/src_qt6/EasyReflectometryApp/Gui/Globals/BackendWrapper.qml b/src_qt6/EasyReflectometryApp/Gui/Globals/BackendWrapper.qml index 7cd7948c..b7c11e3b 100644 --- a/src_qt6/EasyReflectometryApp/Gui/Globals/BackendWrapper.qml +++ b/src_qt6/EasyReflectometryApp/Gui/Globals/BackendWrapper.qml @@ -188,9 +188,9 @@ QtObject { // Minimizer readonly property string analysisMinimizerStatus: activeBackend.analysis.minimizerStatus - readonly property double analysisMinimizerTolerance: activeBackend.analysis.minimizerTolerance + readonly property var analysisMinimizerTolerance: activeBackend.analysis.minimizerTolerance function analysisSetMinimizerTolerance(value) { activeBackend.analysis.setMinimizerTolerance(value) } - readonly property int analysisMinimizerMaxIterations: activeBackend.analysis.minimizerMaxIterations + readonly property var analysisMinimizerMaxIterations: activeBackend.analysis.minimizerMaxIterations function analysisSetMinimizerMaxIterations(value) { activeBackend.analysis.setMinimizerMaxIterations(value) } // Fitting diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Advanced/Groups/Minimizer.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Advanced/Groups/Minimizer.qml index 2b003ce1..7e893b6d 100644 --- a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Advanced/Groups/Minimizer.qml +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Advanced/Groups/Minimizer.qml @@ -15,11 +15,8 @@ EaElements.GroupBox { icon: 'level-down-alt' EaElements.GroupRow{ -// property real columnWidth: (EaStyle.Sizes.sideBarContentWidth - EaStyle.Sizes.fontPixelSize) / 4 - -// Row{ EaElements.ComboBox { - width: (EaStyle.Sizes.sideBarContentWidth - EaStyle.Sizes.fontPixelSize) / 4 + width: (EaStyle.Sizes.sideBarContentWidth - EaStyle.Sizes.fontPixelSize) / 2 topInset: minimizerLabel.height topPadding: topInset + padding model: Globals.BackendWrapper.analysisMinimizersAvailable @@ -32,37 +29,17 @@ EaElements.GroupBox { currentIndex: Globals.BackendWrapper.analysisMinimizerCurrentIndex onCurrentIndexChanged: Globals.BackendWrapper.analysisSetMinimizerCurrentIndex(currentIndex) } -// } -/* Row{ - // spacing: EaStyle.Sizes.fontPixelSize - EaElements.TextField { - width: (EaStyle.Sizes.sideBarContentWidth - EaStyle.Sizes.fontPixelSize) / 4 - topInset: methodLabel.height - topPadding: topInset + padding - horizontalAlignment: TextInput.AlignLeft - onAccepted: focus = false - //text: Globals.Proxies.main.fitting.minimizerMethod - //onTextEdited: Globals.Proxies.main.fitting.minimizerMethod = text - text: Globals.BackendWrapper.analysisMinimizerCurrent - onTextEdited: Globals.BackendWrapper.analysisSetMinimizer(text) - EaElements.Label { - id: methodLabel - text: qsTr("Method") - color: EaStyle.Colors.themeForegroundMinor - } - } - }*/ EaElements.TextField { width: (EaStyle.Sizes.sideBarContentWidth - EaStyle.Sizes.fontPixelSize) / 4 topInset: toleranceLabel.height topPadding: topInset + padding horizontalAlignment: TextInput.AlignLeft - onAccepted: focus = false - //text: Globals.Proxies.main.fitting.minimizerTol - //onTextEdited: Globals.Proxies.main.fitting.minimizerTol = text - text: Globals.BackendWrapper.analysisMinimizerTolerance.toFixed(3) - onTextEdited: Globals.BackendWrapper.analysisSetMinimizerTolerance(text) + onAccepted: { + onAccepted: Globals.BackendWrapper.analysisSetMinimizerTolerance(text) + focus = false + } + text: Globals.BackendWrapper.analysisMinimizerTolerance === undefined ? 'Defaults' : Number(Globals.BackendWrapper.analysisMinimizerTolerance).toFixed(3) EaElements.Label { id: toleranceLabel text: qsTr("Tolerance") @@ -75,14 +52,14 @@ EaElements.GroupBox { topInset: maxIterLabel.height topPadding: topInset + padding horizontalAlignment: TextInput.AlignLeft - onAccepted: focus = false - //text: Globals.Proxies.main.fitting.minimizerMaxIter - //onTextEdited: Globals.Proxies.main.fitting.minimizerMaxIter = text - text: Globals.BackendWrapper.analysisMinimizerMaxIterations - onTextEdited: Globals.BackendWrapper.analysisSetMinimizerMaxIterations(text) + onAccepted: { + Globals.BackendWrapper.analysisSetMinimizerMaxIterations(text) + focus = false + } + text: Globals.BackendWrapper.analysisMinimizerMaxIterations === undefined ? 'Defaults' : Number(Globals.BackendWrapper.analysisMinimizerMaxIterations) EaElements.Label { id: maxIterLabel - text: qsTr("Max iterations") + text: qsTr("Max evaluations") color: EaStyle.Colors.themeForegroundMinor } } diff --git a/src_qt6/pyproject.toml b/src_qt6/pyproject.toml index f6bcb5e5..c0e17f84 100644 --- a/src_qt6/pyproject.toml +++ b/src_qt6/pyproject.toml @@ -30,10 +30,12 @@ classifiers = [ requires-python = '>=3.11' dependencies = [ 'EasyApp @ git+https://github.com/EasyScience/EasyApp.git@develop', - 'easyreflectometry @ git+https://github.com/EasyScience/EasyReflectometryLib.git@197-add-experiment-data-to-project-in-order-for-this-to-be-exposed-to-the-app', + 'easyreflectometry @ git+https://github.com/EasyScience/EasyReflectometryLib.git@199-make-fitter-a-part-of-project', 'PySide6==6.6', 'toml', ] +# pip install easyscience@git+https://github.com/EasyScience/EasyScience.git@81-to-increase-usability-of-minimizer-it-should-be-possible-to-set-the-tolerance-and-the-max-number-of-iteration + [project.urls] homepage = 'https://easyreflectometry.org' From a3408f62b60005aeb0ea5b0b06c36a7aa3d0d120 Mon Sep 17 00:00:00 2001 From: Andreas Pedersen Date: Thu, 31 Oct 2024 12:20:54 +0100 Subject: [PATCH 17/43] code cleaning calculators functional --- .../Backends/Py/analysis.py | 93 ++++++++++--------- .../Backends/Py/logic/calculators.py | 16 +++- .../Backends/Py/logic/fitting.py | 52 +---------- .../Backends/Py/logic/minimizers.py | 57 ++++++++++++ .../Backends/Py/py_backend.py | 10 +- .../Backends/Py/status.py | 24 ++--- .../Sidebar/Advanced/Groups/Minimizer.qml | 1 - 7 files changed, 133 insertions(+), 120 deletions(-) create mode 100644 src_qt6/EasyReflectometryApp/Backends/Py/logic/minimizers.py diff --git a/src_qt6/EasyReflectometryApp/Backends/Py/analysis.py b/src_qt6/EasyReflectometryApp/Backends/Py/analysis.py index b7743484..5070916d 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Py/analysis.py +++ b/src_qt6/EasyReflectometryApp/Backends/Py/analysis.py @@ -11,6 +11,7 @@ from .logic.fitting import Fitting as FittingLogic from .logic.calculators import Calculators as CalculatorsLogic from .logic.experiments import Experiments as ExperimentLogic +from .logic.minimizers import Minimizers as MinimizersLogic class Analysis(QObject): @@ -26,18 +27,28 @@ def __init__(self, project_lib: ProjectLib, parent=None): self._fitting_logic = FittingLogic(project_lib) self._calculators_logic = CalculatorsLogic(project_lib) self._experiments_logic = ExperimentLogic(project_lib) + self._minimizers_logic = MinimizersLogic(project_lib) - @Property('QVariantList', notify=minimizerChanged) - def minimizersAvailable(self) -> List[str]: - return self._fitting_logic.minimizers_available() - @Property(int, notify=minimizerChanged) - def minimizerCurrentIndex(self) -> int: - return self._fitting_logic.minimizer_current_index() - @Slot(int) - def setMinimizerCurrentIndex(self, new_value: int) -> None: - if self._fitting_logic.set_minimizer_current_index(new_value): - self.minimizerChanged.emit() + ######################## + ## Fitting + @Property(str, notify=fitFinishedChanged) + def fittingStatus(self) -> str: + return self._fitting_logic.status + + @Slot(None) + def fittingStartStop(self) -> None: + print('fittingStartStop') + @Property(bool, notify=fitFinishedChanged) + def fittingRunning(self) -> bool: + return self._fitting_logic.running + + @Property(bool, notify=fitFinishedChanged) + def isFitFinished(self) -> bool: + return self._fitting_logic.fit_finished + + ######################## + ## Calculators @Property('QVariantList', notify=calculatorChanged) def calculatorsAvailable(self) -> List[str]: return self._calculators_logic.available() @@ -46,8 +57,11 @@ def calculatorCurrentIndex(self) -> int: return self._calculators_logic.current_index() @Slot(int) def setCalculatorCurrentIndex(self, new_value: int) -> None: - self._calculators_logic.set_current_index(new_value) + if self._calculators_logic.set_current_index(new_value): + self.calculatorChanged.emit() + ######################## + ## Experiments @Property('QVariantList', notify=experimentsChanged) def experimentsAvailable(self) -> List[str]: return self._experiments_logic.available() @@ -58,56 +72,49 @@ def experimentCurrentIndex(self) -> int: def setExperimentCurrentIndex(self, new_value: int) -> None: self._experiments_logic.set_current_index(new_value) - @Property('QVariantList', notify=parametersChanged) - def fitableParameters(self) -> List[dict[str]]: - return self._paramters_logic.fitable() - @Property(int, notify=parametersChanged) - def currentParameterIndex(self) -> int: - return self._paramters_logic.current_index() + ######################## + ## Minimizers + @Property('QVariantList', notify=minimizerChanged) + def minimizersAvailable(self) -> List[str]: + return self._minimizers_logic.minimizers_available() + @Property(int, notify=minimizerChanged) + def minimizerCurrentIndex(self) -> int: + return self._minimizers_logic.minimizer_current_index() @Slot(int) - def setCurrentParameterIndex(self, new_value: int) -> None: - self._paramters_logic.set_current_index(new_value) + def setMinimizerCurrentIndex(self, new_value: int) -> None: + if self._minimizers_logic.set_minimizer_current_index(new_value): + self.minimizerChanged.emit() - ######################## - ## Fitting and Minimizer - @Property(str, notify=fitFinishedChanged) - def minimizerStatus(self) -> str: - return self._fitting_logic.status - @Property('QVariant', notify=minimizerChanged) def minimizerTolerance(self) -> Optional[float]: - return self._fitting_logic.tolerance + return self._minimizers_logic.tolerance @Property('QVariant', notify=minimizerChanged) def minimizerMaxIterations(self) -> Optional[int]: - return self._fitting_logic.max_iterations - - @Property(bool, notify=fitFinishedChanged) - def fittingRunning(self) -> bool: - return self._fitting_logic.running + return self._minimizers_logic.max_iterations - @Property(bool, notify=fitFinishedChanged) - def isFitFinished(self) -> bool: - return self._fitting_logic.fit_finished - @Slot(float) def setMinimizerTolerance(self, new_value: float) -> None: - if self._fitting_logic.set_tolerance(new_value): + if self._minimizers_logic.set_tolerance(new_value): self.minimizerChanged.emit() @Slot(int) def setMinimizerMaxIterations(self, new_value: int) -> None: - if self._fitting_logic.set_max_iterations(new_value): + if self._minimizers_logic.set_max_iterations(new_value): self.minimizerChanged.emit() - #self._material_logic.index = new_value - #self.materialIndexChanged.emit(new_value) - - @Slot(None) - def fittingStartStop(self) -> None: - print('fittingStartStop') ############# ## Parameters + @Property('QVariantList', notify=parametersChanged) + def fitableParameters(self) -> List[dict[str]]: + return self._paramters_logic.fitable() + @Property(int, notify=parametersChanged) + def currentParameterIndex(self) -> int: + return self._paramters_logic.current_index() + @Slot(int) + def setCurrentParameterIndex(self, new_value: int) -> None: + self._paramters_logic.set_current_index(new_value) + @Property(int, notify=parametersChanged) def freeParametersCount(self) -> int: return 1 diff --git a/src_qt6/EasyReflectometryApp/Backends/Py/logic/calculators.py b/src_qt6/EasyReflectometryApp/Backends/Py/logic/calculators.py index 52dc0203..844fcdc3 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Py/logic/calculators.py +++ b/src_qt6/EasyReflectometryApp/Backends/Py/logic/calculators.py @@ -4,14 +4,20 @@ class Calculators: def __init__(self, project_lib: ProjectLib): self._project_lib = project_lib + self._list_available_calculators = self._project_lib._calculator.available_interfaces + self._current_index = 0 def available(self) -> list[str]: - return ["Calculator 1", "Calculator 2", "Calculator 3"] + return self._list_available_calculators def current_index(self) -> int: - return 0 + return self._current_index def set_current_index(self, new_value: int) -> None: - print(new_value) - #self._material_logic.index = new_value - #self.materialIndexChanged.emit(new_value) + if new_value != self._current_index: + self._current_index = new_value + new_calculator = self._list_available_calculators[new_value] + self._project_lib._calculator.switch(new_calculator) + return True + return False + diff --git a/src_qt6/EasyReflectometryApp/Backends/Py/logic/fitting.py b/src_qt6/EasyReflectometryApp/Backends/Py/logic/fitting.py index ca60631d..ee633975 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Py/logic/fitting.py +++ b/src_qt6/EasyReflectometryApp/Backends/Py/logic/fitting.py @@ -1,51 +1,15 @@ -from easyscience import AvailableMinimizers +# from easyscience import AvailableMinimizers from easyreflectometry import Project as ProjectLib class Fitting: def __init__(self, project_lib: ProjectLib): self._project_lib = project_lib - self._minimizer_current_index = 0 - self._list_available_minimizers = list(AvailableMinimizers) - try: - self._list_available_minimizers.remove(AvailableMinimizers.LMFit) - except ValueError: - pass - try: - self._list_available_minimizers.remove(AvailableMinimizers.Bumps) - except ValueError: - pass - try: - self._list_available_minimizers.remove(AvailableMinimizers.DFO) - except ValueError: - pass - - def minimizers_available(self) -> list[str]: - return [minimizer.name for minimizer in self._list_available_minimizers] - - def minimizer_current_index(self) -> int: - return self._minimizer_current_index - - def set_minimizer_current_index(self, new_value: int) -> None: - if new_value != self._minimizer_current_index: - self._minimizer_current_index = new_value - enum_new_minimizer = self._list_available_minimizers[new_value] - self._project_lib._fitter.switch_minimizer(enum_new_minimizer) - return True - return False @property def status(self) -> str: return '' #self._project_lib.status - @property - def tolerance(self) -> float: - return self._project_lib._fitter.easy_science_multi_fitter.tolerance - - @property - def max_iterations(self) -> int: - return self._project_lib._fitter.easy_science_multi_fitter.max_evaluations - @property def running(self) -> bool: return False @@ -53,17 +17,3 @@ def running(self) -> bool: @property def fit_finished(self) -> bool: return True - - def set_tolerance(self, new_value: float) -> bool: - if new_value != self._project_lib._fitter.easy_science_multi_fitter.tolerance: - self._project_lib._fitter.easy_science_multi_fitter.tolerance = new_value - print(new_value) - return True - return False - - def set_max_iterations(self, new_value: float) -> bool: - if new_value != self._project_lib._fitter.easy_science_multi_fitter.max_evaluations: - self._project_lib._fitter.easy_science_multi_fitter.max_evaluations = new_value - print(new_value) - return True - return False \ No newline at end of file diff --git a/src_qt6/EasyReflectometryApp/Backends/Py/logic/minimizers.py b/src_qt6/EasyReflectometryApp/Backends/Py/logic/minimizers.py new file mode 100644 index 00000000..25ce0d6b --- /dev/null +++ b/src_qt6/EasyReflectometryApp/Backends/Py/logic/minimizers.py @@ -0,0 +1,57 @@ +from easyscience import AvailableMinimizers +from easyreflectometry import Project as ProjectLib + + +class Minimizers: + def __init__(self, project_lib: ProjectLib): + self._project_lib = project_lib + self._minimizer_current_index = 0 + self._list_available_minimizers = list(AvailableMinimizers) + try: + self._list_available_minimizers.remove(AvailableMinimizers.LMFit) + except ValueError: + pass + try: + self._list_available_minimizers.remove(AvailableMinimizers.Bumps) + except ValueError: + pass + try: + self._list_available_minimizers.remove(AvailableMinimizers.DFO) + except ValueError: + pass + + def minimizers_available(self) -> list[str]: + return [minimizer.name for minimizer in self._list_available_minimizers] + + def minimizer_current_index(self) -> int: + return self._minimizer_current_index + + def set_minimizer_current_index(self, new_value: int) -> None: + if new_value != self._minimizer_current_index: + self._minimizer_current_index = new_value + enum_new_minimizer = self._list_available_minimizers[new_value] + self._project_lib._fitter.switch_minimizer(enum_new_minimizer) + return True + return False + + @property + def tolerance(self) -> float: + return self._project_lib._fitter.easy_science_multi_fitter.tolerance + + @property + def max_iterations(self) -> int: + return self._project_lib._fitter.easy_science_multi_fitter.max_evaluations + + def set_tolerance(self, new_value: float) -> bool: + if new_value != self._project_lib._fitter.easy_science_multi_fitter.tolerance: + self._project_lib._fitter.easy_science_multi_fitter.tolerance = new_value + print(new_value) + return True + return False + + def set_max_iterations(self, new_value: float) -> bool: + if new_value != self._project_lib._fitter.easy_science_multi_fitter.max_evaluations: + self._project_lib._fitter.easy_science_multi_fitter.max_evaluations = new_value + print(new_value) + return True + return False \ No newline at end of file diff --git a/src_qt6/EasyReflectometryApp/Backends/Py/py_backend.py b/src_qt6/EasyReflectometryApp/Backends/Py/py_backend.py index 1a94e4f6..b5297884 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Py/py_backend.py +++ b/src_qt6/EasyReflectometryApp/Backends/Py/py_backend.py @@ -97,9 +97,10 @@ def _connect_experiment_page(self) -> None: def _connect_analysis_page(self) -> None: self._analysis.minimizerChanged.connect(self._relay_analysis_page_minimizer_changed) + self._analysis.calculatorChanged.connect(self._relay_analysis_page_calculator_changed) def _relay_project_page_name(self): - self._status.projectChanged.emit() + self._status.statusChanged.emit() self._report.asHtmlChanged.emit() def _relay_project_page_created(self): @@ -118,9 +119,12 @@ def _relay_sample_page_sample_changed(self): def _relay_experiment_page_experiment_changed(self): self._plotting.refreshExperimentPage() self._plotting.refreshAnalysisPage() - self._status.experimentsCountChanged.emit() + self._status.statusChanged.emit() self._sample.sampleChanged.emit() self._analysis.experimentsChanged.emit() def _relay_analysis_page_minimizer_changed(self): - self._status.minimizerChanged.emit() + self._status.statusChanged.emit() + + def _relay_analysis_page_calculator_changed(self): + self._status.statusChanged.emit() \ No newline at end of file diff --git a/src_qt6/EasyReflectometryApp/Backends/Py/status.py b/src_qt6/EasyReflectometryApp/Backends/Py/status.py index 33ee2d4e..eca1db7a 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Py/status.py +++ b/src_qt6/EasyReflectometryApp/Backends/Py/status.py @@ -10,42 +10,32 @@ from .logic.status import Status as StatusLogic class Status(QObject): - projectChanged = Signal() - phaseCountChanged = Signal() - experimentsCountChanged = Signal() - calculatorChanged = Signal() - minimizerChanged = Signal() - variablesChanged = Signal() + statusChanged = Signal() def __init__(self, project_lib: ProjectLib, parent=None): super().__init__(parent) self._logic = StatusLogic(project_lib) - @Property(str, notify=projectChanged) + @Property(str, notify=statusChanged) def project(self): return self._logic.project - - def setProject(self, new_value: str): - if self._logic.project != new_value: - self._logic.project = new_value - self.projectChanged.emit() - @Property(str, notify=experimentsCountChanged) + @Property(str, notify=statusChanged) def experimentsCount(self): return self._logic.experiments_count - @Property(str, notify=calculatorChanged) + @Property(str, notify=statusChanged) def calculator(self): return self._logic.calculator - @Property(str, notify=minimizerChanged) + @Property(str, notify=statusChanged) def minimizer(self): return self._logic.minimizer - @Property(str, notify=variablesChanged) + @Property(str, notify=statusChanged) def variables(self): return self._logic.variables - @Property(str, notify=phaseCountChanged) + @Property(str, notify=statusChanged) def phaseCount(self): return None \ No newline at end of file diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Advanced/Groups/Minimizer.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Advanced/Groups/Minimizer.qml index 7e893b6d..4f26a385 100644 --- a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Advanced/Groups/Minimizer.qml +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Advanced/Groups/Minimizer.qml @@ -20,7 +20,6 @@ EaElements.GroupBox { topInset: minimizerLabel.height topPadding: topInset + padding model: Globals.BackendWrapper.analysisMinimizersAvailable - //model: ['Lmfit'] EaElements.Label { id: minimizerLabel text: qsTr("Minimizer") From fc084b099a4ddc88156a71946ddae6548ee6a385 Mon Sep 17 00:00:00 2001 From: Andreas Pedersen Date: Fri, 1 Nov 2024 10:44:20 +0100 Subject: [PATCH 18/43] parameter table on analysis seems to work --- .../Backends/Mock/Analysis.qml | 2 +- .../Backends/Py/analysis.py | 33 ++--- .../Backends/Py/logic/experiments.py | 15 ++- .../Backends/Py/logic/parameters.py | 122 ++++++++++++------ .../Backends/Py/logic/status.py | 4 - .../Backends/Py/py_backend.py | 11 +- .../Backends/Py/status.py | 14 +- .../Gui/Globals/BackendWrapper.qml | 2 +- .../Sidebar/Basic/Groups/Fittables.qml | 21 ++- .../Analysis/Sidebar/Basic/Groups/Fitting.qml | 2 +- .../Sidebar/Basic/Popups/FitStatusDialog.qml | 10 +- 11 files changed, 144 insertions(+), 92 deletions(-) diff --git a/src_qt6/EasyReflectometryApp/Backends/Mock/Analysis.qml b/src_qt6/EasyReflectometryApp/Backends/Mock/Analysis.qml index 757948c8..74a6c1f1 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Mock/Analysis.qml +++ b/src_qt6/EasyReflectometryApp/Backends/Mock/Analysis.qml @@ -13,11 +13,11 @@ QtObject { readonly property int experimentCurrentIndex: 2 // Minimizer - readonly property string minimizerStatus: ''//undefined //'Success' readonly property double minimizerTolerance: 1.0 readonly property int minimizerMaxIterations: 2 // Fitting + readonly property string fittinStatus: ''//undefined //'Success' readonly property bool isFitFinished: true readonly property bool fittingRunning: false diff --git a/src_qt6/EasyReflectometryApp/Backends/Py/analysis.py b/src_qt6/EasyReflectometryApp/Backends/Py/analysis.py index 5070916d..1ba31e16 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Py/analysis.py +++ b/src_qt6/EasyReflectometryApp/Backends/Py/analysis.py @@ -107,21 +107,22 @@ def setMinimizerMaxIterations(self, new_value: int) -> None: ## Parameters @Property('QVariantList', notify=parametersChanged) def fitableParameters(self) -> List[dict[str]]: - return self._paramters_logic.fitable() + return self._paramters_logic.list_of_dicts() @Property(int, notify=parametersChanged) def currentParameterIndex(self) -> int: return self._paramters_logic.current_index() @Slot(int) def setCurrentParameterIndex(self, new_value: int) -> None: - self._paramters_logic.set_current_index(new_value) + if self._paramters_logic.set_current_index(new_value): + self.parametersChanged.emit() @Property(int, notify=parametersChanged) def freeParametersCount(self) -> int: - return 1 + return self._paramters_logic.count_free_parameters() @Property(int, notify=parametersChanged) def fixedParametersCount(self) -> int: - return 2 + return self._paramters_logic.count_fixed_parameters() @Property(int, notify=parametersChanged) def modelParametersCount(self) -> int: @@ -133,28 +134,20 @@ def experimentParametersCount(self) -> int: @Slot(float) def setCurrentParameterValue(self, new_value: float) -> None: - print(new_value) - self.parametersChanged.emit() - #self._material_logic.index = new_value - #self.materialIndexChanged.emit(new_value) + if self._paramters_logic.set_current_parameter_value(new_value): + self.parametersChanged.emit() @Slot(float) def setCurrentParameterMin(self, new_value: float) -> None: - print(new_value) - self.parametersChanged.emit() - #self._material_logic.index = new_value - #self.materialIndexChanged.emit(new_value) + if self._paramters_logic.set_current_parameter_min(new_value): + self.parametersChanged.emit() @Slot(float) def setCurrentParameterMax(self, new_value: float) -> None: - print(new_value) - self.parametersChanged.emit() - #self._material_logic.index = new_value - #self.materialIndexChanged.emit(new_value) + if self._paramters_logic.set_current_parameter_max(new_value): + self.parametersChanged.emit() @Slot(bool) def setCurrentParameterFit(self, new_value: bool) -> None: - print(new_value) - self.parametersChanged.emit() - #self._material_logic.index = new_value - #self.materialIndexChanged.emit(new_value) \ No newline at end of file + if self._paramters_logic.set_current_parameter_fit(new_value): + self.parametersChanged.emit() \ No newline at end of file diff --git a/src_qt6/EasyReflectometryApp/Backends/Py/logic/experiments.py b/src_qt6/EasyReflectometryApp/Backends/Py/logic/experiments.py index 767b32a1..47ee1078 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Py/logic/experiments.py +++ b/src_qt6/EasyReflectometryApp/Backends/Py/logic/experiments.py @@ -1,22 +1,25 @@ from easyreflectometry import Project as ProjectLib -class Experiments: +class Experiments: def __init__(self, project_lib: ProjectLib): self._project_lib = project_lib + self._current_index = 0 def available(self) -> list[str]: experiments_name = [] try: - experiments_name.append(self._project_lib.experimental_data_for_model_at_index()) + experiments_name.append(self._project_lib.experimental_data_for_model_at_index().name) except IndexError: pass return experiments_name def current_index(self) -> int: - return 0 + return self._current_index def set_current_index(self, new_value: int) -> None: - print(new_value) - #self._material_logic.index = new_value - #self.materialIndexChanged.emit(new_value) + if new_value != self._current_index: + new_value = self._current_index + print(new_value) + return True + return False diff --git a/src_qt6/EasyReflectometryApp/Backends/Py/logic/parameters.py b/src_qt6/EasyReflectometryApp/Backends/Py/logic/parameters.py index 40f801c7..0d7fe121 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Py/logic/parameters.py +++ b/src_qt6/EasyReflectometryApp/Backends/Py/logic/parameters.py @@ -1,3 +1,4 @@ +from easyscience.Objects.new_variable import Parameter from easyreflectometry import Project as ProjectLib from typing import List @@ -5,46 +6,89 @@ class Parameters: def __init__(self, project_lib: ProjectLib): self._project_lib = project_lib - - def fitable(self) -> List[str]: - return [ - { - 'name': 'name 1', - 'value': 1.0, - 'error': -1.23456, - 'max': 100.0, - 'min': -100.0, - 'units': 'u1', - 'fit': True, - 'from': -10.0, - 'to': 10.0, - }, - { - 'name': 'name 2', - 'value': 2.0, - 'error': -2.34567, - 'max': 200.0, - 'min': -200.0, - 'units': 'u2', - 'fit': False, - 'from': -20.0, - 'to': 20.0, - }, - { - 'name': 'name 3', - 'value': 3.0, - 'error': -3.45678, - 'max': 300.0, - 'min': -300.0, - 'units': 'u3', - 'fit': True, - 'from': -30.0, - 'to': 30.0, - }, - ] + self._current_index = 0 + + @property + def as_status_string(self) -> str: + return f"{self.count_free_parameters() + self.count_fixed_parameters()} ({self.count_free_parameters()} free, {self.count_fixed_parameters()} fixed)" + + def list_of_dicts(self) -> List[str]: + return _from_parameters_to_list_of_dicts(self._project_lib.parameters) def current_index(self) -> int: - return 0 + return self._current_index def set_current_index(self, new_value: int) -> None: - print(new_value) \ No newline at end of file + if new_value != self._current_index: + self._current_index = new_value + return True + return False + + def count_free_parameters(self) -> int: + count = 0 + parameters = self._project_lib.parameters + for parameter in parameters: + if parameter.free: + count = count + 1 + return count + + def count_fixed_parameters(self) -> int: + count = 0 + parameters = self._project_lib.parameters + for parameter in parameters: + if not parameter.free: + count = count + 1 + return count + + def set_current_parameter_value(self, new_value: str) -> bool: + parameters = self._project_lib.parameters + if float(new_value) != parameters[self._current_index].value: + try: + parameters[self._current_index].value = float(new_value) + except ValueError: + pass + return True + return False + + def set_current_parameter_min(self, new_value: str) -> bool: + parameters = self._project_lib.parameters + if float(new_value) != parameters[self._current_index].min: + try: + parameters[self._current_index].min = float(new_value) + except ValueError: + pass + return True + return False + + def set_current_parameter_max(self, new_value: str) -> bool: + parameters = self._project_lib.parameters + if float(new_value) != parameters[self._current_index].max: + try: + parameters[self._current_index].max = float(new_value) + except ValueError: + pass + return True + return False + + def set_current_parameter_fit(self, new_value: str) -> bool: + parameters = self._project_lib.parameters + if bool(new_value) != parameters[self._current_index].free: + parameters[self._current_index].free = bool(new_value) + return True + return False + +def _from_parameters_to_list_of_dicts(parameters: List[Parameter]) -> list[dict[str, str]]: + parameter_list = [] + for parameter in parameters: + parameter_list.append( + { + 'name': parameter.name, + 'value': float(parameter.value), + 'error': float(parameter.variance), + 'max': float(parameter.max), + 'min': float(parameter.min), + 'units': parameter.unit, + 'fit': parameter.free + } + ) + return parameter_list \ No newline at end of file diff --git a/src_qt6/EasyReflectometryApp/Backends/Py/logic/status.py b/src_qt6/EasyReflectometryApp/Backends/Py/logic/status.py index f7a54fd5..c1ec1733 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Py/logic/status.py +++ b/src_qt6/EasyReflectometryApp/Backends/Py/logic/status.py @@ -3,7 +3,6 @@ class Status: def __init__(self, project_lib: ProjectLib): self._project_lib = project_lib - self._variables = '31 (3 free, 28 fixed)' @property def project(self): @@ -21,6 +20,3 @@ def calculator(self): def experiments_count(self): return str(len(self._project_lib._experiments.keys())) - @property - def variables(self): - return self._variables diff --git a/src_qt6/EasyReflectometryApp/Backends/Py/py_backend.py b/src_qt6/EasyReflectometryApp/Backends/Py/py_backend.py index b5297884..4f0c0fc1 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Py/py_backend.py +++ b/src_qt6/EasyReflectometryApp/Backends/Py/py_backend.py @@ -98,6 +98,7 @@ def _connect_experiment_page(self) -> None: def _connect_analysis_page(self) -> None: self._analysis.minimizerChanged.connect(self._relay_analysis_page_minimizer_changed) self._analysis.calculatorChanged.connect(self._relay_analysis_page_calculator_changed) + self._analysis.parametersChanged.connect(self._relay_analysis_page_parameters_changed) def _relay_project_page_name(self): self._status.statusChanged.emit() @@ -117,14 +118,18 @@ def _relay_sample_page_sample_changed(self): self._plotting.refreshAnalysisPage() def _relay_experiment_page_experiment_changed(self): - self._plotting.refreshExperimentPage() - self._plotting.refreshAnalysisPage() self._status.statusChanged.emit() self._sample.sampleChanged.emit() self._analysis.experimentsChanged.emit() + self._plotting.refreshExperimentPage() + self._plotting.refreshAnalysisPage() def _relay_analysis_page_minimizer_changed(self): self._status.statusChanged.emit() def _relay_analysis_page_calculator_changed(self): - self._status.statusChanged.emit() \ No newline at end of file + self._status.statusChanged.emit() + + def _relay_analysis_page_parameters_changed(self): + self._plotting.refreshSamplePage() + self._plotting.refreshAnalysisPage() \ No newline at end of file diff --git a/src_qt6/EasyReflectometryApp/Backends/Py/status.py b/src_qt6/EasyReflectometryApp/Backends/Py/status.py index eca1db7a..21f38118 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Py/status.py +++ b/src_qt6/EasyReflectometryApp/Backends/Py/status.py @@ -8,33 +8,35 @@ from easyreflectometry import Project as ProjectLib from .logic.status import Status as StatusLogic +from .logic.parameters import Parameters as ParametersLogic class Status(QObject): statusChanged = Signal() def __init__(self, project_lib: ProjectLib, parent=None): super().__init__(parent) - self._logic = StatusLogic(project_lib) + self._status_logic = StatusLogic(project_lib) + self._parameters_logic = ParametersLogic(project_lib) @Property(str, notify=statusChanged) def project(self): - return self._logic.project + return self._status_logic.project @Property(str, notify=statusChanged) def experimentsCount(self): - return self._logic.experiments_count + return self._status_logic.experiments_count @Property(str, notify=statusChanged) def calculator(self): - return self._logic.calculator + return self._status_logic.calculator @Property(str, notify=statusChanged) def minimizer(self): - return self._logic.minimizer + return self._status_logic.minimizer @Property(str, notify=statusChanged) def variables(self): - return self._logic.variables + return self._parameters_logic.as_status_string @Property(str, notify=statusChanged) def phaseCount(self): diff --git a/src_qt6/EasyReflectometryApp/Gui/Globals/BackendWrapper.qml b/src_qt6/EasyReflectometryApp/Gui/Globals/BackendWrapper.qml index b7c11e3b..b61f4815 100644 --- a/src_qt6/EasyReflectometryApp/Gui/Globals/BackendWrapper.qml +++ b/src_qt6/EasyReflectometryApp/Gui/Globals/BackendWrapper.qml @@ -187,13 +187,13 @@ QtObject { function analysisSetCurrentParameterIndex(value) { activeBackend.analysis.setCurrentParameterIndex(value) } // Minimizer - readonly property string analysisMinimizerStatus: activeBackend.analysis.minimizerStatus readonly property var analysisMinimizerTolerance: activeBackend.analysis.minimizerTolerance function analysisSetMinimizerTolerance(value) { activeBackend.analysis.setMinimizerTolerance(value) } readonly property var analysisMinimizerMaxIterations: activeBackend.analysis.minimizerMaxIterations function analysisSetMinimizerMaxIterations(value) { activeBackend.analysis.setMinimizerMaxIterations(value) } // Fitting + readonly property string analysisFittingStatus: activeBackend.analysis.fittingStatus readonly property bool analysisFittingRunning: activeBackend.analysis.fittingRunning readonly property bool analysisIsFitFinished: activeBackend.analysis.isFitFinished function analysisFittingStartStop() { activeBackend.analysis.fittingStartStop() } diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Groups/Fittables.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Groups/Fittables.qml index ec052791..623e44c4 100644 --- a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Groups/Fittables.qml +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Groups/Fittables.qml @@ -30,7 +30,7 @@ EaElements.GroupBox { property string selectedColor: EaStyle.Colors.themeForegroundHovered spacing: EaStyle.Sizes.fontPixelSize - +/* // Filter parameters widget Row { spacing: EaStyle.Sizes.fontPixelSize * 0.5 @@ -117,7 +117,7 @@ EaElements.GroupBox { } // Filter parameters widget - +*/ // Table EaComponents.TableView { id: tableView @@ -278,7 +278,7 @@ EaElements.GroupBox { EaComponents.TableViewLabel { elide: Text.ElideNone - text: Globals.BackendWrapper.analysisFitableParameters[index].value//Globals.BackendWrapper.analysisFitableParameters[index].error === 0 ? + text: Globals.BackendWrapper.analysisFitableParameters[index].error//Globals.BackendWrapper.analysisFitableParameters[index].error === 0 ? // '' : // 1000 //Globals.Proxies.main.backendHelpers.toStdDevSmalestPrecision(item.value, item.error).std_dev } @@ -459,14 +459,23 @@ EaElements.GroupBox { // Logic function updateSliderValue() { - const value = Globals.BackendWrapper.analysisFitableParameters[Globals.BackendWrapper.analysisCurrentParameterIndex].value //[fittables.selectedParamIndex].value// Globals.Proxies.main_fittables_data[selectedParamIndex].value + const value = Globals.BackendWrapper.analysisFitableParameters[Globals.BackendWrapper.analysisCurrentParameterIndex].value slider.value = EaLogic.Utils.toDefaultPrecision(value) // Globals.BackendWrapper.analysisSetCurrentParameterValue(EaLogic.Utils.toDefaultPrecision(value)) } function updateSliderLimits() { - const from = Globals.BackendWrapper.analysisFitableParameters[Globals.BackendWrapper.analysisCurrentParameterIndex].from //[fittables.selectedParamIndex].from //Globals.Proxies.main_fittables_data[selectedParamIndex].from - const to = Globals.BackendWrapper.analysisFitableParameters[Globals.BackendWrapper.analysisCurrentParameterIndex].to //[fittables.selectedParamIndex].to //Globals.Proxies.main_fittables_data[selectedParamIndex].to + var from = Globals.BackendWrapper.analysisFitableParameters[Globals.BackendWrapper.analysisCurrentParameterIndex].value * 0.9 + var to = Globals.BackendWrapper.analysisFitableParameters[Globals.BackendWrapper.analysisCurrentParameterIndex].value * 1.1 + if (from === 0 && to === 0) { + to = 0.1 + } + if (Globals.BackendWrapper.analysisFitableParameters[Globals.BackendWrapper.analysisCurrentParameterIndex].max < to) { + to = Globals.BackendWrapper.analysisFitableParameters[Globals.BackendWrapper.analysisCurrentParameterIndex].max + } + if (Globals.BackendWrapper.analysisFitableParameters[Globals.BackendWrapper.analysisCurrentParameterIndex].min > from) { + from = Globals.BackendWrapper.analysisFitableParameters[Globals.BackendWrapper.analysisCurrentParameterIndex].min + } slider.from = EaLogic.Utils.toDefaultPrecision(from) slider.to = EaLogic.Utils.toDefaultPrecision(to) } diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Groups/Fitting.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Groups/Fitting.qml index de19eb4c..a7f72830 100644 --- a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Groups/Fitting.qml +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Groups/Fitting.qml @@ -17,7 +17,7 @@ EaElements.GroupBox { spacing: EaStyle.Sizes.fontPixelSize EaElements.SideBarButton { - enabled: Globals.BackendWrapper.analysisExperimentsAvailable.length //typeof Globals.BackendWrapper.analysisExperimentsAvailable !== 'undefined'//Globals.Proxies.main.experiment.defined + enabled: Globals.BackendWrapper.analysisExperimentsAvailable.length wide: true fontIcon: Globals.BackendWrapper.analysisFittingRunning ? 'stop-circle' : 'play-circle' text: Globals.BackendWrapper.analysisFittingRunning ? qsTr('Cancel fitting') : qsTr('Start fitting') diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Popups/FitStatusDialog.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Popups/FitStatusDialog.qml index 89836fef..d294c6b6 100644 --- a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Popups/FitStatusDialog.qml +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Popups/FitStatusDialog.qml @@ -15,7 +15,7 @@ import Gui.Globals as Globals EaElements.Dialog { id: dialog - visible: Globals.BackendWrapper.analysisMinimizerStatus + visible: Globals.BackendWrapper.analysisFittingStatus title: qsTr("Fit status") standardButtons: Dialog.Ok @@ -23,13 +23,13 @@ EaElements.Dialog { EaElements.Label { text: { - if ( Globals.BackendWrapper.analysisMinimizerStatus === 'Success') { + if ( Globals.BackendWrapper.analysisFittingStatus === 'Success') { return 'Optimization finished successfully.' - } else if (Globals.BackendWrapper.analysisMinimizerStatus === 'Failure') { + } else if (Globals.BackendWrapper.analysisFittingStatus === 'Failure') { return 'Optimization failed.' - } else if (Globals.BackendWrapper.analysisMinimizerStatus === 'Aborted') { + } else if (Globals.BackendWrapper.analysisFittingStatus === 'Aborted') { return 'Optimization aborted.' - } else if (Globals.BackendWrapper.analysisMinimizerStatus === 'No free params') { + } else if (Globals.BackendWrapper.analysisFittingStatus === 'No free params') { return 'Nothing to vary. Allow some parameters to be free.' } else { return '' From 2476ea5f03c28ff2c70b3cc1e95fd0bccaa7ec73 Mon Sep 17 00:00:00 2001 From: Andreas Pedersen Date: Fri, 1 Nov 2024 14:08:31 +0100 Subject: [PATCH 19/43] fitting table and fitting function running --- .../Backends/Py/analysis.py | 18 +++++++------ .../Backends/Py/logic/fitting.py | 26 ++++++++++++++++--- .../Backends/Py/py_backend.py | 8 +++++- .../Sidebar/Basic/Groups/Fittables.qml | 2 +- 4 files changed, 41 insertions(+), 13 deletions(-) diff --git a/src_qt6/EasyReflectometryApp/Backends/Py/analysis.py b/src_qt6/EasyReflectometryApp/Backends/Py/analysis.py index 1ba31e16..892e1d46 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Py/analysis.py +++ b/src_qt6/EasyReflectometryApp/Backends/Py/analysis.py @@ -19,7 +19,7 @@ class Analysis(QObject): calculatorChanged = Signal() experimentsChanged = Signal() parametersChanged = Signal() - fitFinishedChanged = Signal() + fittingChanged = Signal() def __init__(self, project_lib: ProjectLib, parent=None): super().__init__(parent) @@ -31,22 +31,24 @@ def __init__(self, project_lib: ProjectLib, parent=None): ######################## ## Fitting - @Property(str, notify=fitFinishedChanged) + @Property(str, notify=fittingChanged) def fittingStatus(self) -> str: return self._fitting_logic.status - @Slot(None) - def fittingStartStop(self) -> None: - print('fittingStartStop') - - @Property(bool, notify=fitFinishedChanged) + @Property(bool, notify=fittingChanged) def fittingRunning(self) -> bool: return self._fitting_logic.running - @Property(bool, notify=fitFinishedChanged) + @Property(bool, notify=fittingChanged) def isFitFinished(self) -> bool: return self._fitting_logic.fit_finished + @Slot(None) + def fittingStartStop(self) -> None: + self._fitting_logic.start_stop() + self.fittingChanged.emit() + self.parametersChanged.emit() + ######################## ## Calculators @Property('QVariantList', notify=calculatorChanged) diff --git a/src_qt6/EasyReflectometryApp/Backends/Py/logic/fitting.py b/src_qt6/EasyReflectometryApp/Backends/Py/logic/fitting.py index ee633975..ebea015f 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Py/logic/fitting.py +++ b/src_qt6/EasyReflectometryApp/Backends/Py/logic/fitting.py @@ -1,19 +1,39 @@ # from easyscience import AvailableMinimizers from easyreflectometry import Project as ProjectLib +from easyscience.fitting import FitResults class Fitting: def __init__(self, project_lib: ProjectLib): self._project_lib = project_lib + self._running = False + self._finished = True + self._result: FitResults = None @property def status(self) -> str: - return '' #self._project_lib.status + if self._result is None: + return False + else: + return self._result.success @property def running(self) -> bool: - return False + return self._running @property def fit_finished(self) -> bool: - return True + return self._finished + + def start_stop(self) -> None: + if self._running: + # Stop running the fitting + self._running = False + else: + # Start running the fitting + self._running = True + self._finished = False + exp_data = self._project_lib.experimental_data_for_model_at_index(0) + self._result = self._project_lib._fitter.fit_single_data_set_1d(exp_data) + self._running = False + self._finished = True diff --git a/src_qt6/EasyReflectometryApp/Backends/Py/py_backend.py b/src_qt6/EasyReflectometryApp/Backends/Py/py_backend.py index 4f0c0fc1..e150e57a 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Py/py_backend.py +++ b/src_qt6/EasyReflectometryApp/Backends/Py/py_backend.py @@ -83,7 +83,7 @@ def _connect_backend_parts(self) -> None: self._connect_experiment_page() self._connect_analysis_page() - ######### Project + ######### Forming connections between the backend parts def _connect_project_page(self) -> None: self._project.nameChanged.connect(self._relay_project_page_name) self._project.createdChanged.connect(self._relay_project_page_created) @@ -99,6 +99,7 @@ def _connect_analysis_page(self) -> None: self._analysis.minimizerChanged.connect(self._relay_analysis_page_minimizer_changed) self._analysis.calculatorChanged.connect(self._relay_analysis_page_calculator_changed) self._analysis.parametersChanged.connect(self._relay_analysis_page_parameters_changed) + self._analysis.fittingChanged.connect(self._relay_analysis_page_fitting_changed) def _relay_project_page_name(self): self._status.statusChanged.emit() @@ -114,6 +115,7 @@ def _relay_sample_page_models_index(self, index: int): def _relay_sample_page_sample_changed(self): self._plotting.sldChartRangesChanged.emit() self._plotting.sampleChartRangesChanged.emit() + self._analysis.parametersChanged.emit() self._plotting.refreshSamplePage() self._plotting.refreshAnalysisPage() @@ -131,5 +133,9 @@ def _relay_analysis_page_calculator_changed(self): self._status.statusChanged.emit() def _relay_analysis_page_parameters_changed(self): + self._plotting.refreshSamplePage() + self._plotting.refreshAnalysisPage() + + def _relay_analysis_page_fitting_changed(self): self._plotting.refreshSamplePage() self._plotting.refreshAnalysisPage() \ No newline at end of file diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Groups/Fittables.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Groups/Fittables.qml index 623e44c4..a811004d 100644 --- a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Groups/Fittables.qml +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Groups/Fittables.qml @@ -278,7 +278,7 @@ EaElements.GroupBox { EaComponents.TableViewLabel { elide: Text.ElideNone - text: Globals.BackendWrapper.analysisFitableParameters[index].error//Globals.BackendWrapper.analysisFitableParameters[index].error === 0 ? + text: Number(Globals.BackendWrapper.analysisFitableParameters[index].error).toExponential(2)//Globals.BackendWrapper.analysisFitableParameters[index].error === 0 ? // '' : // 1000 //Globals.Proxies.main.backendHelpers.toStdDevSmalestPrecision(item.value, item.error).std_dev } From 729fa52f55db914fa4ee2479de35320a97cd73c0 Mon Sep 17 00:00:00 2001 From: Andreas Pedersen Date: Mon, 4 Nov 2024 15:41:16 +0100 Subject: [PATCH 20/43] sample behaves better --- .../Backends/Mock/Analysis.qml | 2 +- .../Backends/Py/logic/assemblies.py | 78 ++++----- .../Backends/Py/logic/layers.py | 87 +++++----- .../Backends/Py/logic/material.py | 34 ++-- .../Backends/Py/logic/models.py | 49 +++--- .../Backends/Py/py_backend.py | 22 +-- .../Backends/Py/sample.py | 153 ++++++++++++------ .../Gui/Globals/BackendWrapper.qml | 4 + .../Basic/Groups/Assemblies/MultiLayer.qml | 8 +- .../Sidebar/Basic/Groups/MaterialEditor.qml | 6 +- .../Sidebar/Basic/Groups/ModelEditor.qml | 10 +- .../Sidebar/Basic/Groups/ModelSelector.qml | 5 +- 12 files changed, 270 insertions(+), 188 deletions(-) diff --git a/src_qt6/EasyReflectometryApp/Backends/Mock/Analysis.qml b/src_qt6/EasyReflectometryApp/Backends/Mock/Analysis.qml index 74a6c1f1..e368da97 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Mock/Analysis.qml +++ b/src_qt6/EasyReflectometryApp/Backends/Mock/Analysis.qml @@ -17,7 +17,7 @@ QtObject { readonly property int minimizerMaxIterations: 2 // Fitting - readonly property string fittinStatus: ''//undefined //'Success' + readonly property string fittingStatus: ''//undefined //'Success' readonly property bool isFitFinished: true readonly property bool fittingRunning: false diff --git a/src_qt6/EasyReflectometryApp/Backends/Py/logic/assemblies.py b/src_qt6/EasyReflectometryApp/Backends/Py/logic/assemblies.py index 083ee025..2b0d3531 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Py/logic/assemblies.py +++ b/src_qt6/EasyReflectometryApp/Backends/Py/logic/assemblies.py @@ -10,30 +10,36 @@ class Assemblies: def __init__(self, project_lib: ProjectLib): self._project_lib = project_lib - self._model_index = 0 - self._assembly_index = 0 - self._assemblies: Sample = project_lib._models[self._model_index].sample # Sample is a collection of assemblies +# self.update_assemblies() +# self._model_index = 0 +# self._assembly_index = 0 +# self._assemblies: Sample = project_lib._models[self._project_lib.current_model_index].sample # Sample is a collection of assemblies - def set_model_index(self, new_value: int) -> None: - self._model_index = new_value - self._assembly_index = 0 - self._assemblies = self._project_lib._models[self._model_index].sample + @property + def _assemblies(self) -> Sample: + return self._project_lib._models[self._project_lib.current_model_index].sample # Sample is a collection of assemblies + +# def set_model_index(self, new_value: int) -> None: +# self._model_index = new_value +# self._assembly_index = 0 +# self._assemblies = self._project_lib._models[self._model_index].sample @property def index(self) -> int: - return self._assembly_index + return self._project_lib.current_assembly_index #_assembly_index @index.setter def index(self, new_value: Union[int, str]) -> None: - self._assembly_index = int(new_value) + self._project_lib.current_assembly_index = int(new_value) +# self.update_assemblies() @property def name_at_current_index(self) -> str: - return self._assemblies[self._assembly_index].name + return self._assemblies[self.index].name @property def type_at_current_index(self) -> str: - return self._assemblies[self._assembly_index].type + return self._assemblies[self.index].type @property def assemblies(self) -> list[dict[str, str]]: @@ -50,27 +56,27 @@ def add_new(self) -> None: self._assemblies.add_assembly() def duplicate_selected(self) -> None: - self._assemblies.duplicate_assembly(self._assembly_index) + self._assemblies.duplicate_assembly(self.index) def move_selected_up(self) -> None: - if self._assembly_index > 0: - self._assemblies.move_up(self._assembly_index) - self._assembly_index = self._assembly_index - 1 + if self.index > 0: + self._assemblies.move_up(self.index) + self.index = self.index - 1 def move_selected_down(self) -> None: - if self._assembly_index < len(self._assemblies) - 1: - self._assemblies.move_down(self._assembly_index) - self._assembly_index = self._assembly_index + 1 + if self.index < len(self._assemblies) - 1: + self._assemblies.move_down(self.index) + self.index = self.index + 1 def set_name_at_current_index(self, new_value: str) -> None: - if self._assemblies[self._assembly_index].name != new_value: - self._assemblies[self._assembly_index].name = new_value + if self._assemblies[self.index].name != new_value: + self._assemblies[self.index].name = new_value return True return False def set_type_at_current_index(self, new_value: str) -> bool: - if new_value == self._assemblies[self._assembly_index].type: - return False +# if new_value == self._assemblies[self.index].type: +# return False if new_value == 'Multi-layer': if 'Si' not in [material.name for material in self._project_lib._materials]: @@ -95,38 +101,38 @@ def set_type_at_current_index(self, new_value: str) -> bool: new_assembly.layers[0].solvent = self._project_lib._materials[index_air] new_assembly.layers[1].solvent = self._project_lib._materials[index_d2o] - new_assembly.name = self._assemblies[self._assembly_index].name + new_assembly.name = self._assemblies[self.index].name - self._assemblies[self._assembly_index] = new_assembly - self._project_lib._models[self._model_index].sample._disable_changes_to_outermost_layers() + self._assemblies[self.index] = new_assembly + self._project_lib._models[self._project_lib.current_model_index].sample._disable_changes_to_outermost_layers() return True # Only for repeating multilayer @property def repetitions_at_current_index(self) -> str: - if isinstance(self._assemblies[self._assembly_index], RepeatingMultilayer): - return str(int(self._assemblies[self._assembly_index].repetitions.value)) + if isinstance(self._assemblies[self.index], RepeatingMultilayer): + return str(int(self._assemblies[self.index].repetitions.value)) return '1' def set_repeated_layer_reptitions(self, new_value: int) -> bool: - if isinstance(self._assemblies[self._assembly_index], RepeatingMultilayer): - if new_value != self._assemblies[self._assembly_index].repetitions.value: - self._assemblies[self._assembly_index].repetitions.value = new_value + if isinstance(self._assemblies[self.index], RepeatingMultilayer): + if new_value != self._assemblies[self.index].repetitions.value: + self._assemblies[self.index].repetitions.value = new_value return True return False # # Only for surfactant layer def set_constrain_apm(self, new_value: str) -> bool: - if isinstance(self._assemblies[self._assembly_index], SurfactantLayer): - if self._assemblies[self._assembly_index].constrain_area_per_molecule != new_value: - self._assemblies[self._assembly_index].constrain_area_per_molecule = new_value + if isinstance(self._assemblies[self.index], SurfactantLayer): + if self._assemblies[self.index].constrain_area_per_molecule != new_value: + self._assemblies[self.index].constrain_area_per_molecule = new_value return True return False def set_conformal_roughness(self, new_value: str) -> bool: - if isinstance(self._assemblies[self._assembly_index], SurfactantLayer): - if self._assemblies[self._assembly_index].conformal_roughness != new_value: - self._assemblies[self._assembly_index].conformal_roughness = new_value + if isinstance(self._assemblies[self.index], SurfactantLayer): + if self._assemblies[self.index].conformal_roughness != new_value: + self._assemblies[self.index].conformal_roughness = new_value return True return False diff --git a/src_qt6/EasyReflectometryApp/Backends/Py/logic/layers.py b/src_qt6/EasyReflectometryApp/Backends/Py/logic/layers.py index d882b1b2..d4ddc4ff 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Py/logic/layers.py +++ b/src_qt6/EasyReflectometryApp/Backends/Py/logic/layers.py @@ -8,33 +8,38 @@ class Layers: def __init__(self, project_lib: ProjectLib): self._project_lib = project_lib - self._model_index = 0 - self._assembly_index = 0 - self._layer_index = 0 - self._layers: LayerCollection = self._project_lib._models[self._model_index].sample[self._assembly_index].layers - - def set_model_index(self, new_value: int) -> None: - self._model_index = new_value - self._assembly_index = 0 - self._layer_index = 0 - self._layers = self._project_lib._models[self._model_index].sample[self._assembly_index].layers - - def set_assembly_index(self, new_value: int) -> None: - self._assembly_index = new_value - self._layer_index = 0 - self._layers = self._project_lib._models[self._model_index].sample[self._assembly_index].layers +# self.update_layers() +# self._model_index = 0 +# self._assembly_index = 0 +# self._layer_index = 0 + + @property + def _layers(self) -> LayerCollection: + return self._project_lib._models[self._project_lib.current_model_index].sample[self._project_lib.current_assembly_index].layers + + # def set_model_index(self, new_value: int) -> None: + # self._model_index = new_value + # self._assembly_index = 0 + # self._layer_index = 0 + # self._layers = self._project_lib._models[self._model_index].sample[self._assembly_index].layers + + # def set_assembly_index(self, new_value: int) -> None: + # self._assembly_index = new_value + # self._layer_index = 0 + # self._layers = self._project_lib._models[self._model_index].sample[self._assembly_index].layers @property def index(self) -> int: - return self._layer_index + return self._project_lib.current_layer_index @index.setter def index(self, new_value: Union[int, str]) -> None: - self._layer_index = int(new_value) + self._project_lib.current_layer_index = int(new_value) +# self.update_layers() @property def name_at_current_index(self) -> str: - return self._layers[self._layer_index].name + return self._layers[self.index].name @property def layers(self) -> list[dict[str, str]]: @@ -55,63 +60,63 @@ def add_new(self) -> None: self._layers[-1].material = self._project_lib._materials[index_si] def duplicate_selected(self) -> None: - self._layers.duplicate_layer(self._layer_index) + self._layers.duplicate_layer(self.index) def move_selected_up(self) -> None: - if self._layer_index > 0: - self._layers.move_up(self._layer_index) - self._layer_index = self._layer_index - 1 + if self.index > 0: + self._layers.move_up(self.index) + self.index = self.index - 1 def move_selected_down(self) -> None: - if self._layer_index < len(self._layers) - 1: - self._layers.move_down(self._layer_index) - self._layer_index = self._layer_index + 1 + if self.index < len(self._layers) - 1: + self._layers.move_down(self.index) + self.index = self.index + 1 def set_name_at_current_index(self, new_value: str) -> bool: - if self._layers[self._layer_index].name != new_value: - self._layers[self._layer_index].name = new_value + if self._layers[self.index].name != new_value: + self._layers[self.index].name = new_value return True return False def set_thickness_at_current_index(self, new_value: float) -> bool: - if self._layers[self._layer_index].thickness.value != new_value: - self._layers[self._layer_index].thickness.value = new_value + if self._layers[self.index].thickness.value != new_value: + self._layers[self.index].thickness.value = new_value return True return False def set_roughness_at_current_index(self, new_value: float) -> bool: - if self._layers[self._layer_index].roughness.value != new_value: - self._layers[self._layer_index].roughness.value = new_value + if self._layers[self.index].roughness.value != new_value: + self._layers[self.index].roughness.value = new_value return True return False def set_material_at_current_index(self, new_value: int) -> bool: - if self._layers[self._layer_index].material != self._project_lib._materials[new_value]: - self._layers[self._layer_index].material = self._project_lib._materials[new_value] + if self._layers[self.index].material != self._project_lib._materials[new_value]: + self._layers[self.index].material = self._project_lib._materials[new_value] return True return False def set_solvent_at_current_index(self, new_value: int) -> bool: - if self._layers[self._layer_index].solvent != self._project_lib._materials[new_value]: - self._layers[self._layer_index].solvent = self._project_lib._materials[new_value] + if self._layers[self.index].solvent != self._project_lib._materials[new_value]: + self._layers[self.index].solvent = self._project_lib._materials[new_value] return True return False def set_apm_at_current_index(self, new_value: float) -> bool: - if self._layers[self._layer_index].area_per_molecule != new_value: - self._layers[self._layer_index].area_per_molecule = new_value + if self._layers[self.index].area_per_molecule != new_value: + self._layers[self.index].area_per_molecule = new_value return True return False def set_solvation_at_current_index(self, new_value: float) -> bool: - if self._layers[self._layer_index].solvent_fraction != new_value: - self._layers[self._layer_index].solvent_fraction = new_value + if self._layers[self.index].solvent_fraction != new_value: + self._layers[self.index].solvent_fraction = new_value return True return False def set_formula(self, new_value: str) -> bool: - if self._layers[self._layer_index].molecular_formula != new_value: - self._layers[self._layer_index].molecular_formula = new_value + if self._layers[self.index].molecular_formula != new_value: + self._layers[self.index].molecular_formula = new_value return True return False diff --git a/src_qt6/EasyReflectometryApp/Backends/Py/logic/material.py b/src_qt6/EasyReflectometryApp/Backends/Py/logic/material.py index 0c3d7966..14cc7e0f 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Py/logic/material.py +++ b/src_qt6/EasyReflectometryApp/Backends/Py/logic/material.py @@ -7,20 +7,20 @@ class Material: def __init__(self, project_lib: ProjectLib): self._project_lib = project_lib - self._material_index = 0 +# self._material_index = 0 self._materials = self._project_lib._materials @property def index(self) -> int: - return self._material_index + return self._project_lib.current_material_index @index.setter def index(self, new_value: Union[int, str]) -> None: - self._material_index = int(new_value) + self._project_lib.current_material_index = int(new_value) @property def name_at_current_index(self) -> str: - return self._materials[self._material_index].name + return self._materials[self.index].name @property def materials(self) -> list[dict[str, str]]: @@ -37,33 +37,33 @@ def add_new(self) -> None: self._materials.add_material() def duplicate_selected(self) -> None: - self._materials.duplicate_material(self._material_index) + self._materials.duplicate_material(self.index) def move_selected_up(self) -> None: - if self._material_index > 0: - self._materials.move_up(self._material_index) - self._material_index = self._material_index - 1 + if self.index > 0: + self._materials.move_up(self.index) + self.index = self.index - 1 def move_selected_down(self) -> None: - if self._material_index < len(self._materials) - 1: - self._materials.move_down(self._material_index) - self._material_index = self._material_index + 1 + if self.index < len(self._materials) - 1: + self._materials.move_down(self.index) + self.index = self.index + 1 def set_name_at_current_index(self, new_value: str) -> bool: - if self._materials[self._material_index].name != new_value: - self._materials[self._material_index].name = new_value + if self._materials[self.index].name != new_value: + self._materials[self.index].name = new_value return True return False def set_sld_at_current_index(self, new_value: float) -> bool: - if self._materials[self._material_index].sld.value != new_value: - self._materials[self._material_index].sld.value = new_value + if self._materials[self.index].sld.value != new_value: + self._materials[self.index].sld.value = new_value return True return False def set_isld_at_current_index(self, new_value: float) -> bool: - if self._materials[self._material_index].isld.value != new_value: - self._materials[self._material_index].isld.value = new_value + if self._materials[self.index].isld.value != new_value: + self._materials[self.index].isld.value = new_value return True return False diff --git a/src_qt6/EasyReflectometryApp/Backends/Py/logic/models.py b/src_qt6/EasyReflectometryApp/Backends/Py/logic/models.py index 33bb42f1..cbdb19ce 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Py/logic/models.py +++ b/src_qt6/EasyReflectometryApp/Backends/Py/logic/models.py @@ -8,33 +8,34 @@ class Models: def __init__(self, project_lib: ProjectLib): self._project_lib = project_lib - self._model_index = 0 +# self._model_index = 0 self._models = project_lib._models @property def index(self) -> int: - return self._model_index + return self._project_lib.current_model_index #self._model_index @index.setter def index(self, new_value: Union[int, str]) -> None: - self._model_index = int(new_value) + self._project_lib.current_model_index = int(new_value) # +# self._model_index = int(new_value) @property def name_at_current_index(self) -> str: - return self._models[self._model_index].name + return self._models[self.index].name @property def scaling_at_current_index(self) -> float: - return self._models[self._model_index].scale.value + return self._models[self.index].scale.value @property def background_at_current_index(self) -> float: - return self._models[self._model_index].background.value + return self._models[self.index].background.value @property def resolution_at_current_index(self) -> str: - if isinstance(self._models[self._model_index].resolution_function, PercentageFhwm): - return str(self._models[self._model_index].resolution_function.constant) + if isinstance(self._models[self.index].resolution_function, PercentageFhwm): + return str(self._models[self.index].resolution_function.constant) else: return '-' @@ -47,27 +48,27 @@ def models_names(self) -> list[str]: return [element['label'] for element in self.models] def set_name_at_current_index(self, new_value: str) -> bool: - if self._models[self._model_index].name != new_value: - self._models[self._model_index].name = new_value + if self._models[self.index].name != new_value: + self._models[self.index].name = new_value return True return False def set_scaling_at_current_index(self, new_value: str) -> bool: - if self._models[self._model_index].scale.value != new_value: - self._models[self._model_index].scale.value = new_value + if self._models[self.index].scale.value != new_value: + self._models[self.index].scale.value = new_value return True return False def set_background_at_current_index(self, new_value: str) -> bool: - if self._models[self._model_index].background.value != new_value: - self._models[self._model_index].background.value = new_value + if self._models[self.index].background.value != new_value: + self._models[self.index].background.value = new_value return True return False def set_resolution_at_current_index(self, new_value: str) -> bool: - if isinstance(self._models[self._model_index].resolution_function, PercentageFhwm): - if self._models[self._model_index].resolution_function.constant != float(new_value): - self._models[self._model_index].resolution_function.constant = float(new_value) + if isinstance(self._models[self.index].resolution_function, PercentageFhwm): + if self._models[self.index].resolution_function.constant != float(new_value): + self._models[self.index].resolution_function.constant = float(new_value) return True return False @@ -78,17 +79,17 @@ def add_new(self) -> None: self._models.add_model() def duplicate_selected_model(self) -> None: - self._models.duplicate_model(self._model_index) + self._models.duplicate_model(self.index) def move_selected_up(self) -> None: - if self._model_index > 0: - self._models.move_up(self._model_index) - self._model_index = self._model_index - 1 + if self.index > 0: + self._models.move_up(self.index) + self.index = self.index - 1 def move_selected_down(self) -> None: - if self._model_index < len(self._models) - 1: - self._models.move_down(self._model_index) - self._model_index = self._model_index + 1 + if self.index < len(self._models) - 1: + self._models.move_down(self.index) + self.index = self.index + 1 def _from_models_collection_to_list_of_dicts(models_collection: ModelCollection) -> list[dict[str, str]]: diff --git a/src_qt6/EasyReflectometryApp/Backends/Py/py_backend.py b/src_qt6/EasyReflectometryApp/Backends/Py/py_backend.py index e150e57a..e12c87e1 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Py/py_backend.py +++ b/src_qt6/EasyReflectometryApp/Backends/Py/py_backend.py @@ -91,15 +91,17 @@ def _connect_project_page(self) -> None: def _connect_sample_page(self) -> None: self._sample.modelsIndexChanged.connect(self._relay_sample_page_models_index) self._sample.sampleChanged.connect(self._relay_sample_page_sample_changed) + self._sample.refreshPlot.connect(self._refresh_plots) def _connect_experiment_page(self) -> None: self._experiment.experimentChanged.connect(self._relay_experiment_page_experiment_changed) + self._experiment.experimentChanged.connect(self._refresh_plots) def _connect_analysis_page(self) -> None: self._analysis.minimizerChanged.connect(self._relay_analysis_page_minimizer_changed) self._analysis.calculatorChanged.connect(self._relay_analysis_page_calculator_changed) - self._analysis.parametersChanged.connect(self._relay_analysis_page_parameters_changed) - self._analysis.fittingChanged.connect(self._relay_analysis_page_fitting_changed) + self._analysis.parametersChanged.connect(self._refresh_plots) + self._analysis.fittingChanged.connect(self._refresh_plots) def _relay_project_page_name(self): self._status.statusChanged.emit() @@ -116,15 +118,15 @@ def _relay_sample_page_sample_changed(self): self._plotting.sldChartRangesChanged.emit() self._plotting.sampleChartRangesChanged.emit() self._analysis.parametersChanged.emit() - self._plotting.refreshSamplePage() - self._plotting.refreshAnalysisPage() + # self._plotting.refreshSamplePage() + # self._plotting.refreshAnalysisPage() def _relay_experiment_page_experiment_changed(self): self._status.statusChanged.emit() self._sample.sampleChanged.emit() self._analysis.experimentsChanged.emit() - self._plotting.refreshExperimentPage() - self._plotting.refreshAnalysisPage() +# self._plotting.refreshExperimentPage() +# self._plotting.refreshAnalysisPage() def _relay_analysis_page_minimizer_changed(self): self._status.statusChanged.emit() @@ -132,10 +134,10 @@ def _relay_analysis_page_minimizer_changed(self): def _relay_analysis_page_calculator_changed(self): self._status.statusChanged.emit() - def _relay_analysis_page_parameters_changed(self): - self._plotting.refreshSamplePage() - self._plotting.refreshAnalysisPage() + # def _relay_analysis_page_parameters_changed(self): + # self._plotting.refreshSamplePage() + # self._plotting.refreshAnalysisPage() - def _relay_analysis_page_fitting_changed(self): + def _refresh_plots(self): self._plotting.refreshSamplePage() self._plotting.refreshAnalysisPage() \ No newline at end of file diff --git a/src_qt6/EasyReflectometryApp/Backends/Py/sample.py b/src_qt6/EasyReflectometryApp/Backends/Py/sample.py index b8489e18..dfd06119 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Py/sample.py +++ b/src_qt6/EasyReflectometryApp/Backends/Py/sample.py @@ -13,63 +13,78 @@ class Sample(QObject): sampleChanged = Signal() materialsChanged = Signal() - materialIndexChanged = Signal(int) +# materialTableChanged = Signal()#int) + materialIndexChanged = Signal()#int) modelsChange = Signal() modelsTableChanged = Signal() - modelsIndexChanged = Signal(int) + modelsIndexChanged = Signal()#int) assembliesChange = Signal() assembliesTableChanged = Signal() - assembliesIndexChanged = Signal(int) + assembliesIndexChanged = Signal()#int) layersChange = Signal() + layersIndexChanged = Signal()#int) layersTableChanged = Signal() + refreshPlot = Signal() + def __init__(self, project_lib: ProjectLib, parent=None): super().__init__(parent) + self._project_lib = project_lib self._material_logic = Material(project_lib) self._models_logic = Models(project_lib) self._assemblies_logic = Assemblies(project_lib) self._layers_logic = Layers(project_lib) self.connect_logic() - - def connect_logic(self) -> None: - self.modelsIndexChanged.connect(self._assemblies_logic.set_model_index) - self.modelsIndexChanged.connect(self._layers_logic.set_model_index) - self.assembliesIndexChanged.connect(self._layers_logic.set_assembly_index) + +# self._project_lib.current_model_index = 0 - self.modelsChange.connect(self.layersConnectChanges) - self.assembliesChange.connect(self.layersConnectChanges) + def connect_logic(self) -> None: + self.assembliesIndexChanged.connect(self.layersConnectChanges) self.layersTableChanged.connect(self.layersConnectChanges) - self.modelsChange.connect(self.assembliesConnectChanges) - self.assembliesIndexChanged.connect(self.assembliesConnectChanges) - self.assembliesTableChanged.connect(self.assembliesConnectChanges) +# self.modelsIndexChanged.connect(self._assemblies_logic.update_assemblies) + +# self.assembliesIndexChanged.connect(self._layers_logic.update_layers) +# self.modelsIndexChanged.connect(self._layers_logic.update_layers) + + # self.modelsChange.connect(self.layersConnectChanges) + # self.assembliesChange.connect(self.layersConnectChanges) + # self.layersTableChanged.connect(self.layersConnectChanges) + + # self.modelsChange.connect(self.assembliesConnectChanges) + # self.assembliesIndexChanged.connect(self.assembliesConnectChanges) + # self.assembliesTableChanged.connect(self.assembliesConnectChanges) - self.modelsIndexChanged.connect(self.modelsConnectChanges) - self.modelsTableChanged.connect(self.modelsConnectChanges) + # self.modelsIndexChanged.connect(self.modelsConnectChanges) + # self.modelsTableChanged.connect(self.modelsConnectChanges) - self.materialsChanged.connect(self.sampleConnectChanges) - self.modelsChange.connect(self.sampleConnectChanges) - self.assembliesChange.connect(self.sampleConnectChanges) - self.layersChange.connect(self.sampleConnectChanges) + # self.materialsChanged.connect(self.sampleConnectChanges) + # self.modelsChange.connect(self.sampleConnectChanges) + # self.assembliesChange.connect(self.sampleConnectChanges) + # self.layersChange.connect(self.sampleConnectChanges) # # # # Sample # # # - def sampleConnectChanges(self) -> None: - self.sampleChanged.emit() +# def sampleConnectChanges(self) -> None: +# self.sampleChanged.emit() # # # # Materials # # # - @Property('QVariantList', notify=materialsChanged) + @Property('QVariantList', notify=materialIndexChanged) def materials(self) -> list[dict[str, str]]: return self._material_logic.materials - - @Property('QVariantList', notify=materialsChanged) + + @Property(int, notify=materialIndexChanged) + def currentMaterialIndex(self) -> int: + return self._material_logic.index + + @Property('QVariantList', notify=materialIndexChanged) def materialNames(self) -> list[str]: return self._material_logic.material_names @@ -81,7 +96,7 @@ def currentMaterialName(self) -> str: @Slot(int) def setCurrentMaterialIndex(self, new_value: int) -> None: self._material_logic.index = new_value - self.materialIndexChanged.emit(new_value) + self.materialIndexChanged.emit()#self._material_logic.index) @Slot(str) def setCurrentMaterialName(self, new_value: str) -> None: @@ -92,11 +107,13 @@ def setCurrentMaterialName(self, new_value: str) -> None: def setCurrentMaterialSld(self, new_value: float) -> None: if self._material_logic.set_sld_at_current_index(new_value): self.materialsChanged.emit() + self.refreshPlot.emit() @Slot(float) def setCurrentMaterialISld(self, new_value: float) -> None: if self._material_logic.set_isld_at_current_index(new_value): self.materialsChanged.emit() + self.refreshPlot.emit() # Actions @Slot(str) @@ -107,33 +124,37 @@ def removeMaterial(self, value: str) -> None: @Slot() def addNewMaterial(self) -> None: self._material_logic.add_new() - self.materialsChanged.emit() + self.materialIndexChanged.emit() @Slot() def duplicateSelectedMaterial(self) -> None: self._material_logic.duplicate_selected() - self.materialsChanged.emit() + self.materialIndexChanged.emit() @Slot() def moveSelectedMaterialUp(self) -> None: self._material_logic.move_selected_up() - self.materialsChanged.emit() + self.materialIndexChanged.emit() @Slot() def moveSelectedMaterialDown(self) -> None: self._material_logic.move_selected_down() - self.materialsChanged.emit() + self.materialIndexChanged.emit() # # # # Models # # # - def modelsConnectChanges(self) -> None: - self.modelsChange.emit() +# def modelsConnectChanges(self) -> None: +# self.modelsChange.emit() @Property('QVariantList', notify=modelsChange) def models(self) -> list[dict[str, str]]: return self._models_logic.models + @Property(int, notify=modelsChange) + def currentModelIndex(self) -> int: + return self._models_logic.index + @Property('QVariantList', notify=modelsChange) def modelslNames(self) -> list[str]: return self._models_logic.models_names @@ -145,8 +166,10 @@ def currentModelName(self) -> str: # Setters @Slot(int) def setCurrentModelIndex(self, new_value: int) -> None: - self._models_logic.index = new_value - self.modelsIndexChanged.emit(new_value) + self._project_lib.current_model_index = new_value +# self._models_logic.index = new_value + self.modelsIndexChanged.emit()#new_value) + self.refreshPlot.emit() @Slot(str) def setCurrentModelName(self, value: str) -> None: @@ -185,27 +208,34 @@ def moveSelectedModelDown(self)-> None: def assembliesConnectChanges(self) -> None: self.assembliesChange.emit() - @Property('QVariantList', notify=assembliesChange) + @Property('QVariantList', notify=assembliesTableChanged) def assemblies(self) -> list[dict[str, str]]: return self._assemblies_logic.assemblies - @Property('QVariantList', notify=assembliesChange) + @Property(int, notify=assembliesIndexChanged) + def currentAssemblyIndex(self) -> int: + return self._assemblies_logic.index + + @Property('QVariantList', notify=assembliesTableChanged) def assembliesNames(self) -> list[str]: return self._assemblies_logic.assemblies_names - @Property(str, notify=assembliesChange) + @Property(str, notify=assembliesTableChanged) def currentAssemblyName(self) -> str: return self._assemblies_logic.name_at_current_index - @Property(str, notify=assembliesChange) + @Property(str, notify=assembliesIndexChanged) def currentAssemblyType(self) -> str: return self._assemblies_logic.type_at_current_index # Setters @Slot(int) def setCurrentAssemblyIndex(self, new_value: int) -> None: - self._assemblies_logic.index = new_value - self.assembliesIndexChanged.emit(new_value) + self._project_lib.current_assembly_index = new_value + self.layersTableChanged.emit() + self.assembliesTableChanged.emit() + self.assembliesIndexChanged.emit() + # self.refreshPlot.emit() @Slot(str) def setCurrentAssemblyName(self, new_value: str) -> None: @@ -214,8 +244,15 @@ def setCurrentAssemblyName(self, new_value: str) -> None: @Slot(str) def setCurrentAssemblyType(self, new_value: str) -> None: - if self._assemblies_logic.set_type_at_current_index(new_value): - self.assembliesTableChanged.emit() + self._assemblies_logic.set_type_at_current_index(new_value) + self.layersTableChanged.emit() + self.assembliesTableChanged.emit() + self.assembliesIndexChanged.emit() + self.refreshPlot.emit() + # if self._assemblies_logic.set_type_at_current_index(new_value): + # self.layersChange.emit() + # self.assembliesTableChanged.emit() + # self.refreshPlot.emit() # Assembly specific @Property(str, notify=assembliesChange) @@ -226,42 +263,50 @@ def currentAssemblyRepeatedLayerReptitions(self) -> str: def setCurrentAssemblyRepeatedLayerReptitions(self, new_value: int) -> None: if self._assemblies_logic.set_repeated_layer_reptitions(new_value): self.assembliesTableChanged.emit() + self.refreshPlot.emit() @Slot(bool) def setCurrentAssemblyConstrainAPM(self, new_value: bool) -> None: if self._assemblies_logic.set_constrain_apm(new_value): self.assembliesTableChanged.emit() + self.refreshPlot.emit() @Slot(bool) def setCurrentAssemblyConformalRoughness(self, new_value: bool) -> None: if self._assemblies_logic.set_conformal_roughness(new_value): self.assembliesTableChanged.emit() + self.refreshPlot.emit() # Actions @Slot(str) def removeAssembly(self, value: str) -> None: self._assemblies_logic.remove_at_index(value) self.assembliesTableChanged.emit() + self.refreshPlot.emit() @Slot() def addNewAssembly(self) -> None: self._assemblies_logic.add_new() self.assembliesTableChanged.emit() + self.refreshPlot.emit() @Slot() def duplicateSelectedAssembly(self) -> None: self._assemblies_logic.duplicate_selected() self.assembliesTableChanged.emit() + self.refreshPlot.emit() @Slot() def moveSelectedAssemblyUp(self) -> None: self._assemblies_logic.move_selected_up() self.assembliesTableChanged.emit() + self.refreshPlot.emit() @Slot() def moveSelectedAssemblyDown(self)-> None: self._assemblies_logic.move_selected_down() self.assembliesTableChanged.emit() + self.refreshPlot.emit() # # # # Layers @@ -273,18 +318,24 @@ def layersConnectChanges(self) -> None: def layers(self) -> list[dict[str, str]]: return self._layers_logic.layers - @Property('QVariantList', notify=layersChange) + @Property(int, notify=layersIndexChanged) + def currentLayerIndex(self) -> int: + return self._layers_logic.index + + @Property('QVariantList', notify=layersTableChanged) def layersNames(self) -> list[str]: return self._layers_logic.layers_names - @Property(str, notify=layersChange) + @Property(str, notify=layersTableChanged) def currentLayerName(self) -> str: return self._layers_logic.name_at_current_index # Setters @Slot(int) def setCurrentLayerIndex(self, new_value: int) -> None: - self._layers_logic.index = new_value + self._project_lib.current_layer_index = new_value + self.layersIndexChanged.emit() +# self._layers_logic.index = new_value @Slot(str) def setCurrentLayerName(self, new_value: str) -> None: @@ -295,59 +346,71 @@ def setCurrentLayerName(self, new_value: str) -> None: def setCurrentLayerMaterial(self, new_value: int) -> None: if self._layers_logic.set_material_at_current_index(new_value): self.layersTableChanged.emit() + self.refreshPlot.emit() @Slot(int) def setCurrentLayerSolvent(self, new_value: int) -> None: if self._layers_logic.set_solvent_at_current_index(new_value): self.layersTableChanged.emit() + self.refreshPlot.emit() @Slot(float) def setCurrentLayerThickness(self, new_value: float) -> None: if self._layers_logic.set_thickness_at_current_index(new_value): self.layersTableChanged.emit() + self.refreshPlot.emit() @Slot(float) def setCurrentLayerRoughness(self, new_value: float) -> None: if self._layers_logic.set_roughness_at_current_index(new_value): self.layersTableChanged.emit() + self.refreshPlot.emit() @Slot(str) def setCurrentLayerFormula(self, new_value: str) -> None: if self._layers_logic.set_formula(new_value): self.layersTableChanged.emit() + self.refreshPlot.emit() @Slot(float) def setCurrentLayerAPM(self, new_value: float) -> None: if self._layers_logic.set_apm_at_current_index(new_value): self.layersTableChanged.emit() + self.refreshPlot.emit() @Slot(float) def setCurrentLayerSolvation(self, new_value: float) -> None: if self._layers_logic.set_solvation_at_current_index(new_value): self.layersTableChanged.emit() + self.refreshPlot.emit() # Actions @Slot(str) def removeLayer(self, value: str) -> None: self._layers_logic.remove_at_index(value) self.layersTableChanged.emit() + self.refreshPlot.emit() @Slot() def addNewLayer(self) -> None: self._layers_logic.add_new() self.layersTableChanged.emit() + self.refreshPlot.emit() @Slot() def duplicateSelectedLayer(self) -> None: self._layers_logic.duplicate_selected() self.layersTableChanged.emit() + self.refreshPlot.emit() @Slot() def moveSelectedLayerUp(self) -> None: self._layers_logic.move_selected_up() self.layersTableChanged.emit() + self.refreshPlot.emit() @Slot() def moveSelectedLayerDown(self)-> None: self._layers_logic.move_selected_down() - self.layersTableChanged.emit() \ No newline at end of file + self.layersTableChanged.emit() + self.refreshPlot.emit() diff --git a/src_qt6/EasyReflectometryApp/Gui/Globals/BackendWrapper.qml b/src_qt6/EasyReflectometryApp/Gui/Globals/BackendWrapper.qml index b61f4815..53db7bf6 100644 --- a/src_qt6/EasyReflectometryApp/Gui/Globals/BackendWrapper.qml +++ b/src_qt6/EasyReflectometryApp/Gui/Globals/BackendWrapper.qml @@ -81,6 +81,7 @@ QtObject { readonly property var sampleMaterials: activeBackend.sample.materials readonly property var sampleMaterialNames: activeBackend.sample.materialNames + readonly property int sampleCurrentMaterialIndex: activeBackend.sample.currentMaterialIndex function sampleSetCurrentMaterialIndex(value) { activeBackend.sample.setCurrentMaterialIndex(value) } function sampleSetCurrentMaterialName(value) { activeBackend.sample.setCurrentMaterialName(value) } @@ -96,6 +97,7 @@ QtObject { readonly property var sampleModels: activeBackend.sample.models readonly property string sampleCurrentModelName: activeBackend.sample.currentModelName + readonly property int sampleCurrentModelIndex: activeBackend.sample.currentModelIndex function sampleSetCurrentModelIndex(value) { activeBackend.sample.setCurrentModelIndex(value) } function sampleSetCurrentModelName(value) { activeBackend.sample.setCurrentModelName(value) } @@ -110,6 +112,7 @@ QtObject { readonly property string sampleCurrentAssemblyName: activeBackend.sample.currentAssemblyName readonly property string sampleCurrentAssemblyType: activeBackend.sample.currentAssemblyType + readonly property int sampleCurrentAssemblyIndex: activeBackend.sample.currentAssemblyIndex function sampleSetCurrentAssemblyIndex(value) { activeBackend.sample.setCurrentAssemblyIndex(value) } function sampleSetCurrentAssemblyName(value) { activeBackend.sample.setCurrentAssemblyName(value) } @@ -130,6 +133,7 @@ QtObject { readonly property var sampleLayers: activeBackend.sample.layers readonly property string sampleCurrentLayerName: activeBackend.sample.currentLayerName + readonly property int sampleCurrentLayerIndex: activeBackend.sample.currentLayerIndex function sampleSetCurrentLayerIndex(value) { activeBackend.sample.setCurrentLayerIndex(value) } function sampleRemoveLayer(value) { activeBackend.sample.removeLayer(value) } diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/Sidebar/Basic/Groups/Assemblies/MultiLayer.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/Sidebar/Basic/Groups/Assemblies/MultiLayer.qml index e89663f0..213ab528 100644 --- a/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/Sidebar/Basic/Groups/Assemblies/MultiLayer.qml +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/Sidebar/Basic/Groups/Assemblies/MultiLayer.qml @@ -61,7 +61,7 @@ EaElements.GroupColumn { horizontalAlignment: Text.AlignLeft model: Globals.BackendWrapper.sampleMaterialNames onActivated: { - Globals.BackendWrapper.sampleSetCurrentLayerMaterial(index) + Globals.BackendWrapper.sampleSetCurrentLayerMaterial(currentIndex) } onModelChanged: { currentIndex = indexOfValue(Globals.BackendWrapper.sampleLayers[index].material) @@ -116,7 +116,7 @@ EaElements.GroupColumn { EaElements.SideBarButton { width: (EaStyle.Sizes.sideBarContentWidth - (2 * (EaStyle.Sizes.tableRowHeight + EaStyle.Sizes.fontPixelSize)) - EaStyle.Sizes.fontPixelSize) / 2 - enabled: (layersView.currentIndex > 0) ? true : false //when item is selected + enabled: Globals.BackendWrapper.sampleLayers.length//(layersView.currentIndex > 0) ? true : false //when item is selected fontIcon: "clone" text: qsTr("Duplicate layer") onClicked: Globals.BackendWrapper.sampleDuplicateSelectedLayer() @@ -124,7 +124,7 @@ EaElements.GroupColumn { EaElements.SideBarButton { width: EaStyle.Sizes.tableRowHeight - enabled: (layersView.currentIndex !== 0 && Globals.BackendWrapper.sampleLayers.length > 0 ) ? true : false//When item is selected + enabled: (Globals.BackendWrapper.sampleCurrentLayerIndex !== 0 && Globals.BackendWrapper.sampleLayers.length > 0 ) ? true : false//When item is selected fontIcon: "arrow-up" ToolTip.text: qsTr("Move layer up") onClicked: Globals.BackendWrapper.sampleMoveSelectedLayerUp() @@ -132,7 +132,7 @@ EaElements.GroupColumn { EaElements.SideBarButton { width: EaStyle.Sizes.tableRowHeight - enabled: (layersView.currentIndex + 1 !== Globals.BackendWrapper.sampleLayers.length && Globals.BackendWrapper.sampleLayers.length > 0 ) ? true : false + enabled: (Globals.BackendWrapper.sampleCurrentLayerIndex + 1 !== Globals.BackendWrapper.sampleLayers.length && Globals.BackendWrapper.sampleLayers.length > 0 ) ? true : false fontIcon: "arrow-down" ToolTip.text: qsTr("Move layer down") onClicked: Globals.BackendWrapper.sampleMoveSelectedLayerDown() diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/Sidebar/Basic/Groups/MaterialEditor.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/Sidebar/Basic/Groups/MaterialEditor.qml index 3c88860e..b00b3b60 100644 --- a/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/Sidebar/Basic/Groups/MaterialEditor.qml +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/Sidebar/Basic/Groups/MaterialEditor.qml @@ -104,7 +104,7 @@ EaElements.GroupBox { } EaElements.SideBarButton { - enabled: (materialsView.currentIndex > 0) ? true : false //When material is selected + enabled: Globals.BackendWrapper.sampleMaterials.length// (Globals.BackendWrapper.sampleCurrentMaterialIndex > 0) ? true : false //When material is selected width: (EaStyle.Sizes.sideBarContentWidth - (2 * (EaStyle.Sizes.tableRowHeight + EaStyle.Sizes.fontPixelSize)) - EaStyle.Sizes.fontPixelSize) / 2 fontIcon: "clone" text: qsTr("Duplicate material") @@ -112,7 +112,7 @@ EaElements.GroupBox { } EaElements.SideBarButton { - enabled: (materialsView.currentIndex !== 0 && Globals.BackendWrapper.sampleMaterials.length > 0) ? true : false//When item is selected + enabled: (Globals.BackendWrapper.sampleCurrentMaterialIndex !== 0 && Globals.BackendWrapper.sampleMaterials.length > 0) ? true : false//When item is selected width: EaStyle.Sizes.tableRowHeight fontIcon: "arrow-up" ToolTip.text: qsTr("Move material up") @@ -120,7 +120,7 @@ EaElements.GroupBox { } EaElements.SideBarButton { - enabled: (materialsView.currentIndex + 1 !== Globals.BackendWrapper.sampleMaterials.length && Globals.BackendWrapper.sampleMaterials.length > 0) ? true : false//When item is selected + enabled: (Globals.BackendWrapper.sampleCurrentMaterialIndex + 1 !== Globals.BackendWrapper.sampleMaterials.length && Globals.BackendWrapper.sampleMaterials.length > 0) ? true : false//When item is selected width: EaStyle.Sizes.tableRowHeight fontIcon: "arrow-down" ToolTip.text: qsTr("Move material down") diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/Sidebar/Basic/Groups/ModelEditor.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/Sidebar/Basic/Groups/ModelEditor.qml index 9cef4b09..06abb823 100644 --- a/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/Sidebar/Basic/Groups/ModelEditor.qml +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/Sidebar/Basic/Groups/ModelEditor.qml @@ -83,13 +83,13 @@ EaElements.GroupBox { } mouseArea.onPressed: { - if (Globals.BackendWrapper.sampleCurrentAssembyIndex !== index) { + if (Globals.BackendWrapper.sampleCurrentAssemblyIndex !== index) { Globals.BackendWrapper.sampleSetCurrentAssemblyIndex(index) } } } - onModelChanged: Globals.BackendWrapper.sampleSetCurrentAssemblyIndex(0) +// onModelChanged: Globals.BackendWrapper.sampleSetCurrentAssemblyIndex(0) } // Control buttons below table @@ -105,7 +105,7 @@ EaElements.GroupBox { } EaElements.SideBarButton { - enabled: (assembliesView.currentIndex > 0) ? true : false//When item is selected + enabled: Globals.BackendWrapper.sampleAssemblies.length //(assembliesView.currentIndex > 0) ? true : false//When item is selected width: (EaStyle.Sizes.sideBarContentWidth - (2 * (EaStyle.Sizes.tableRowHeight + EaStyle.Sizes.fontPixelSize)) - EaStyle.Sizes.fontPixelSize) / 2 fontIcon: "clone" text: qsTr("Duplicate assembly") @@ -113,7 +113,7 @@ EaElements.GroupBox { } EaElements.SideBarButton { - enabled: (assembliesView.currentIndex !== 0 && Globals.BackendWrapper.sampleAssemblies.length > 0 ) ? true : false//When item is selected + enabled: (Globals.BackendWrapper.sampleCurrentAssemblyIndex !== 0 && Globals.BackendWrapper.sampleAssemblies.length > 0 ) ? true : false//When item is selected width: EaStyle.Sizes.tableRowHeight fontIcon: "arrow-up" ToolTip.text: qsTr("Move assembly up") @@ -121,7 +121,7 @@ EaElements.GroupBox { } EaElements.SideBarButton { - enabled: (assembliesView.currentIndex + 1 !== Globals.BackendWrapper.sampleAssemblies.length && Globals.BackendWrapper.sampleAssemblies.length > 0 ) ? true : false//When item is selected + enabled: (Globals.BackendWrapper.sampleCurrentAssemblyIndex + 1 !== Globals.BackendWrapper.sampleAssemblies.length && Globals.BackendWrapper.sampleAssemblies.length > 0 ) ? true : false//When item is selected width: EaStyle.Sizes.tableRowHeight fontIcon: "arrow-down" ToolTip.text: qsTr("Move assembly down") diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/Sidebar/Basic/Groups/ModelSelector.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/Sidebar/Basic/Groups/ModelSelector.qml index fa59e534..c8e5a5c0 100644 --- a/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/Sidebar/Basic/Groups/ModelSelector.qml +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/Sidebar/Basic/Groups/ModelSelector.qml @@ -68,8 +68,9 @@ EaElements.GroupBox { mouseArea.onPressed: { if (Globals.BackendWrapper.sampleCurrentModelIndex !== index) { - Globals.BackendWrapper.sampleSetCurrentAssemblyIndex(0) - Globals.BackendWrapper.sampleSetCurrentALayerIndex(0) + Globals.BackendWrapper.sampleSetCurrentModelIndex(0) +// Globals.BackendWrapper.sampleSetCurrentAssemblyIndex(0) +// Globals.BackendWrapper.sampleSetCurrentALayerIndex(0) } } } From 4deb337b38b75c8145a70d67b1368f2f26102862 Mon Sep 17 00:00:00 2001 From: Andreas Pedersen Date: Mon, 4 Nov 2024 15:46:13 +0100 Subject: [PATCH 21/43] code cleaning --- .../Backends/Py/logic/assemblies.py | 16 ++----- .../Backends/Py/logic/layers.py | 16 ------- .../Backends/Py/logic/material.py | 1 - .../Backends/Py/logic/models.py | 6 +-- .../Backends/Py/py_backend.py | 8 ---- .../Backends/Py/sample.py | 48 ++----------------- 6 files changed, 10 insertions(+), 85 deletions(-) diff --git a/src_qt6/EasyReflectometryApp/Backends/Py/logic/assemblies.py b/src_qt6/EasyReflectometryApp/Backends/Py/logic/assemblies.py index 2b0d3531..680f1083 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Py/logic/assemblies.py +++ b/src_qt6/EasyReflectometryApp/Backends/Py/logic/assemblies.py @@ -10,28 +10,18 @@ class Assemblies: def __init__(self, project_lib: ProjectLib): self._project_lib = project_lib -# self.update_assemblies() -# self._model_index = 0 -# self._assembly_index = 0 -# self._assemblies: Sample = project_lib._models[self._project_lib.current_model_index].sample # Sample is a collection of assemblies @property def _assemblies(self) -> Sample: return self._project_lib._models[self._project_lib.current_model_index].sample # Sample is a collection of assemblies -# def set_model_index(self, new_value: int) -> None: -# self._model_index = new_value -# self._assembly_index = 0 -# self._assemblies = self._project_lib._models[self._model_index].sample - @property def index(self) -> int: - return self._project_lib.current_assembly_index #_assembly_index + return self._project_lib.current_assembly_index @index.setter def index(self, new_value: Union[int, str]) -> None: self._project_lib.current_assembly_index = int(new_value) -# self.update_assemblies() @property def name_at_current_index(self) -> str: @@ -75,8 +65,8 @@ def set_name_at_current_index(self, new_value: str) -> None: return False def set_type_at_current_index(self, new_value: str) -> bool: -# if new_value == self._assemblies[self.index].type: -# return False + if new_value == self._assemblies[self.index].type: + return False if new_value == 'Multi-layer': if 'Si' not in [material.name for material in self._project_lib._materials]: diff --git a/src_qt6/EasyReflectometryApp/Backends/Py/logic/layers.py b/src_qt6/EasyReflectometryApp/Backends/Py/logic/layers.py index d4ddc4ff..18e0231c 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Py/logic/layers.py +++ b/src_qt6/EasyReflectometryApp/Backends/Py/logic/layers.py @@ -8,26 +8,11 @@ class Layers: def __init__(self, project_lib: ProjectLib): self._project_lib = project_lib -# self.update_layers() -# self._model_index = 0 -# self._assembly_index = 0 -# self._layer_index = 0 @property def _layers(self) -> LayerCollection: return self._project_lib._models[self._project_lib.current_model_index].sample[self._project_lib.current_assembly_index].layers - # def set_model_index(self, new_value: int) -> None: - # self._model_index = new_value - # self._assembly_index = 0 - # self._layer_index = 0 - # self._layers = self._project_lib._models[self._model_index].sample[self._assembly_index].layers - - # def set_assembly_index(self, new_value: int) -> None: - # self._assembly_index = new_value - # self._layer_index = 0 - # self._layers = self._project_lib._models[self._model_index].sample[self._assembly_index].layers - @property def index(self) -> int: return self._project_lib.current_layer_index @@ -35,7 +20,6 @@ def index(self) -> int: @index.setter def index(self, new_value: Union[int, str]) -> None: self._project_lib.current_layer_index = int(new_value) -# self.update_layers() @property def name_at_current_index(self) -> str: diff --git a/src_qt6/EasyReflectometryApp/Backends/Py/logic/material.py b/src_qt6/EasyReflectometryApp/Backends/Py/logic/material.py index 14cc7e0f..2a45d893 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Py/logic/material.py +++ b/src_qt6/EasyReflectometryApp/Backends/Py/logic/material.py @@ -7,7 +7,6 @@ class Material: def __init__(self, project_lib: ProjectLib): self._project_lib = project_lib -# self._material_index = 0 self._materials = self._project_lib._materials @property diff --git a/src_qt6/EasyReflectometryApp/Backends/Py/logic/models.py b/src_qt6/EasyReflectometryApp/Backends/Py/logic/models.py index cbdb19ce..fa53fd35 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Py/logic/models.py +++ b/src_qt6/EasyReflectometryApp/Backends/Py/logic/models.py @@ -8,17 +8,15 @@ class Models: def __init__(self, project_lib: ProjectLib): self._project_lib = project_lib -# self._model_index = 0 self._models = project_lib._models @property def index(self) -> int: - return self._project_lib.current_model_index #self._model_index + return self._project_lib.current_model_index @index.setter def index(self, new_value: Union[int, str]) -> None: - self._project_lib.current_model_index = int(new_value) # -# self._model_index = int(new_value) + self._project_lib.current_model_index = int(new_value) @property def name_at_current_index(self) -> str: diff --git a/src_qt6/EasyReflectometryApp/Backends/Py/py_backend.py b/src_qt6/EasyReflectometryApp/Backends/Py/py_backend.py index e12c87e1..ea377d47 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Py/py_backend.py +++ b/src_qt6/EasyReflectometryApp/Backends/Py/py_backend.py @@ -118,15 +118,11 @@ def _relay_sample_page_sample_changed(self): self._plotting.sldChartRangesChanged.emit() self._plotting.sampleChartRangesChanged.emit() self._analysis.parametersChanged.emit() - # self._plotting.refreshSamplePage() - # self._plotting.refreshAnalysisPage() def _relay_experiment_page_experiment_changed(self): self._status.statusChanged.emit() self._sample.sampleChanged.emit() self._analysis.experimentsChanged.emit() -# self._plotting.refreshExperimentPage() -# self._plotting.refreshAnalysisPage() def _relay_analysis_page_minimizer_changed(self): self._status.statusChanged.emit() @@ -134,10 +130,6 @@ def _relay_analysis_page_minimizer_changed(self): def _relay_analysis_page_calculator_changed(self): self._status.statusChanged.emit() - # def _relay_analysis_page_parameters_changed(self): - # self._plotting.refreshSamplePage() - # self._plotting.refreshAnalysisPage() - def _refresh_plots(self): self._plotting.refreshSamplePage() self._plotting.refreshAnalysisPage() \ No newline at end of file diff --git a/src_qt6/EasyReflectometryApp/Backends/Py/sample.py b/src_qt6/EasyReflectometryApp/Backends/Py/sample.py index dfd06119..f0618f00 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Py/sample.py +++ b/src_qt6/EasyReflectometryApp/Backends/Py/sample.py @@ -13,19 +13,18 @@ class Sample(QObject): sampleChanged = Signal() materialsChanged = Signal() -# materialTableChanged = Signal()#int) - materialIndexChanged = Signal()#int) + materialIndexChanged = Signal() modelsChange = Signal() modelsTableChanged = Signal() - modelsIndexChanged = Signal()#int) + modelsIndexChanged = Signal() assembliesChange = Signal() assembliesTableChanged = Signal() - assembliesIndexChanged = Signal()#int) + assembliesIndexChanged = Signal() layersChange = Signal() - layersIndexChanged = Signal()#int) + layersIndexChanged = Signal() layersTableChanged = Signal() refreshPlot = Signal() @@ -46,33 +45,6 @@ def connect_logic(self) -> None: self.assembliesIndexChanged.connect(self.layersConnectChanges) self.layersTableChanged.connect(self.layersConnectChanges) -# self.modelsIndexChanged.connect(self._assemblies_logic.update_assemblies) - -# self.assembliesIndexChanged.connect(self._layers_logic.update_layers) -# self.modelsIndexChanged.connect(self._layers_logic.update_layers) - - # self.modelsChange.connect(self.layersConnectChanges) - # self.assembliesChange.connect(self.layersConnectChanges) - # self.layersTableChanged.connect(self.layersConnectChanges) - - # self.modelsChange.connect(self.assembliesConnectChanges) - # self.assembliesIndexChanged.connect(self.assembliesConnectChanges) - # self.assembliesTableChanged.connect(self.assembliesConnectChanges) - - # self.modelsIndexChanged.connect(self.modelsConnectChanges) - # self.modelsTableChanged.connect(self.modelsConnectChanges) - - # self.materialsChanged.connect(self.sampleConnectChanges) - # self.modelsChange.connect(self.sampleConnectChanges) - # self.assembliesChange.connect(self.sampleConnectChanges) - # self.layersChange.connect(self.sampleConnectChanges) - - # # # - # Sample - # # # -# def sampleConnectChanges(self) -> None: -# self.sampleChanged.emit() - # # # # Materials # # # @@ -144,9 +116,6 @@ def moveSelectedMaterialDown(self) -> None: # # # # Models # # # -# def modelsConnectChanges(self) -> None: -# self.modelsChange.emit() - @Property('QVariantList', notify=modelsChange) def models(self) -> list[dict[str, str]]: return self._models_logic.models @@ -167,8 +136,7 @@ def currentModelName(self) -> str: @Slot(int) def setCurrentModelIndex(self, new_value: int) -> None: self._project_lib.current_model_index = new_value -# self._models_logic.index = new_value - self.modelsIndexChanged.emit()#new_value) + self.modelsIndexChanged.emit() self.refreshPlot.emit() @Slot(str) @@ -235,7 +203,6 @@ def setCurrentAssemblyIndex(self, new_value: int) -> None: self.layersTableChanged.emit() self.assembliesTableChanged.emit() self.assembliesIndexChanged.emit() - # self.refreshPlot.emit() @Slot(str) def setCurrentAssemblyName(self, new_value: str) -> None: @@ -249,10 +216,6 @@ def setCurrentAssemblyType(self, new_value: str) -> None: self.assembliesTableChanged.emit() self.assembliesIndexChanged.emit() self.refreshPlot.emit() - # if self._assemblies_logic.set_type_at_current_index(new_value): - # self.layersChange.emit() - # self.assembliesTableChanged.emit() - # self.refreshPlot.emit() # Assembly specific @Property(str, notify=assembliesChange) @@ -335,7 +298,6 @@ def currentLayerName(self) -> str: def setCurrentLayerIndex(self, new_value: int) -> None: self._project_lib.current_layer_index = new_value self.layersIndexChanged.emit() -# self._layers_logic.index = new_value @Slot(str) def setCurrentLayerName(self, new_value: str) -> None: From f67b0582a7f6113cf79b119754e889df4819beb0 Mon Sep 17 00:00:00 2001 From: Andreas Pedersen Date: Tue, 5 Nov 2024 05:56:27 +0100 Subject: [PATCH 22/43] code cleaning --- src_qt6/EasyReflectometryApp/Backends/Py/sample.py | 2 -- .../Gui/Pages/Sample/Sidebar/Basic/Groups/ModelSelector.qml | 2 -- 2 files changed, 4 deletions(-) diff --git a/src_qt6/EasyReflectometryApp/Backends/Py/sample.py b/src_qt6/EasyReflectometryApp/Backends/Py/sample.py index f0618f00..ac450757 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Py/sample.py +++ b/src_qt6/EasyReflectometryApp/Backends/Py/sample.py @@ -39,8 +39,6 @@ def __init__(self, project_lib: ProjectLib, parent=None): self.connect_logic() -# self._project_lib.current_model_index = 0 - def connect_logic(self) -> None: self.assembliesIndexChanged.connect(self.layersConnectChanges) self.layersTableChanged.connect(self.layersConnectChanges) diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/Sidebar/Basic/Groups/ModelSelector.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/Sidebar/Basic/Groups/ModelSelector.qml index c8e5a5c0..b5cbd460 100644 --- a/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/Sidebar/Basic/Groups/ModelSelector.qml +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/Sidebar/Basic/Groups/ModelSelector.qml @@ -69,8 +69,6 @@ EaElements.GroupBox { mouseArea.onPressed: { if (Globals.BackendWrapper.sampleCurrentModelIndex !== index) { Globals.BackendWrapper.sampleSetCurrentModelIndex(0) -// Globals.BackendWrapper.sampleSetCurrentAssemblyIndex(0) -// Globals.BackendWrapper.sampleSetCurrentALayerIndex(0) } } } From e358a8dd827a5c1516c0b703c07c656d10ca57d6 Mon Sep 17 00:00:00 2001 From: Andreas Pedersen Date: Tue, 5 Nov 2024 06:51:28 +0100 Subject: [PATCH 23/43] plots for refl and sld are made on startup --- src_qt6/EasyReflectometryApp/Backends/Py/plotting_1d.py | 2 ++ src_qt6/EasyReflectometryApp/Backends/Py/sample.py | 2 +- src_qt6/EasyReflectometryApp/Gui/Globals/BackendWrapper.qml | 2 ++ .../Gui/Pages/Sample/MainContent/SampleView.qml | 1 + .../Gui/Pages/Sample/MainContent/SldView.qml | 2 +- 5 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src_qt6/EasyReflectometryApp/Backends/Py/plotting_1d.py b/src_qt6/EasyReflectometryApp/Backends/Py/plotting_1d.py index c6eeb4a0..3829d1d6 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Py/plotting_1d.py +++ b/src_qt6/EasyReflectometryApp/Backends/Py/plotting_1d.py @@ -215,6 +215,7 @@ def refreshExperimentPage(self): def refreshAnalysisPage(self): self.drawCalculatedAndMeasuredOnAnalysisChart() + @Slot() def drawCalculatedOnSampleChart(self): if PLOT_BACKEND == 'QtCharts': self.qtchartsReplaceCalculatedOnSampleChartAndRedraw() @@ -228,6 +229,7 @@ def qtchartsReplaceCalculatedOnSampleChartAndRedraw(self): nr_points = nr_points + 1 console.debug(IO.formatMsg('sub', 'Calc curve', f'{nr_points} points', 'on sample page', 'replaced')) + @Slot() def drawCalculatedOnSldChart(self): if PLOT_BACKEND == 'QtCharts': self.qtchartsReplaceCalculatedOnSldChartAndRedraw() diff --git a/src_qt6/EasyReflectometryApp/Backends/Py/sample.py b/src_qt6/EasyReflectometryApp/Backends/Py/sample.py index ac450757..99ec41c6 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Py/sample.py +++ b/src_qt6/EasyReflectometryApp/Backends/Py/sample.py @@ -66,7 +66,7 @@ def currentMaterialName(self) -> str: @Slot(int) def setCurrentMaterialIndex(self, new_value: int) -> None: self._material_logic.index = new_value - self.materialIndexChanged.emit()#self._material_logic.index) + self.materialIndexChanged.emit() @Slot(str) def setCurrentMaterialName(self, new_value: str) -> None: diff --git a/src_qt6/EasyReflectometryApp/Gui/Globals/BackendWrapper.qml b/src_qt6/EasyReflectometryApp/Gui/Globals/BackendWrapper.qml index 53db7bf6..8bd83d40 100644 --- a/src_qt6/EasyReflectometryApp/Gui/Globals/BackendWrapper.qml +++ b/src_qt6/EasyReflectometryApp/Gui/Globals/BackendWrapper.qml @@ -243,4 +243,6 @@ QtObject { readonly property var plottingAnalysisMaxY: activeBackend.plotting.sampleMaxY function plottingSetQtChartsSerieRef(value1, value2, value3) { activeBackend.plotting.setQtChartsSerieRef(value1, value2, value3) } + function plottingRefreshSample() { activeBackend.plotting.drawCalculatedOnSampleChart() } + function plottingRefreshSLD() { activeBackend.plotting.drawCalculatedOnSldChart() } } diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/MainContent/SampleView.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/MainContent/SampleView.qml index c875a03b..cce12f8d 100644 --- a/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/MainContent/SampleView.qml +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/MainContent/SampleView.qml @@ -151,6 +151,7 @@ Rectangle { Globals.BackendWrapper.plottingSetQtChartsSerieRef('samplePage', 'sampleSerie', chartView.calcSerie) + Globals.BackendWrapper.plottingRefreshSample() } } diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/MainContent/SldView.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/MainContent/SldView.qml index 41587e74..7d16f5af 100644 --- a/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/MainContent/SldView.qml +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/MainContent/SldView.qml @@ -151,8 +151,8 @@ Rectangle { Globals.BackendWrapper.plottingSetQtChartsSerieRef('samplePage', 'sldSerie', chartView.calcSerie) + Globals.BackendWrapper.plottingRefreshSLD() } - } // Logic From 26dde861383018988b8bb09d5a83cc3783096d90 Mon Sep 17 00:00:00 2001 From: Andreas Pedersen Date: Tue, 5 Nov 2024 07:01:46 +0100 Subject: [PATCH 24/43] experiements data shown --- src_qt6/EasyReflectometryApp/Backends/Py/py_backend.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src_qt6/EasyReflectometryApp/Backends/Py/py_backend.py b/src_qt6/EasyReflectometryApp/Backends/Py/py_backend.py index ea377d47..f2b028e3 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Py/py_backend.py +++ b/src_qt6/EasyReflectometryApp/Backends/Py/py_backend.py @@ -132,4 +132,5 @@ def _relay_analysis_page_calculator_changed(self): def _refresh_plots(self): self._plotting.refreshSamplePage() + self._plotting.refreshExperimentPage() self._plotting.refreshAnalysisPage() \ No newline at end of file From 42e76719980a12815ba3482582c3ac95d56775dc Mon Sep 17 00:00:00 2001 From: Andreas Pedersen Date: Wed, 6 Nov 2024 14:12:26 +0100 Subject: [PATCH 25/43] more responsive, status bar and analysis is updated --- .../Backends/Py/analysis.py | 24 ++-- .../Backends/Py/logic/parameters.py | 3 +- .../Backends/Py/py_backend.py | 27 ++-- .../Backends/Py/sample.py | 120 +++++++++++------- 4 files changed, 101 insertions(+), 73 deletions(-) diff --git a/src_qt6/EasyReflectometryApp/Backends/Py/analysis.py b/src_qt6/EasyReflectometryApp/Backends/Py/analysis.py index 892e1d46..cfb85f7e 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Py/analysis.py +++ b/src_qt6/EasyReflectometryApp/Backends/Py/analysis.py @@ -19,6 +19,7 @@ class Analysis(QObject): calculatorChanged = Signal() experimentsChanged = Signal() parametersChanged = Signal() + parametersIndexChanged = Signal() fittingChanged = Signal() def __init__(self, project_lib: ProjectLib, parent=None): @@ -28,6 +29,7 @@ def __init__(self, project_lib: ProjectLib, parent=None): self._calculators_logic = CalculatorsLogic(project_lib) self._experiments_logic = ExperimentLogic(project_lib) self._minimizers_logic = MinimizersLogic(project_lib) + self._chached_paramters = None ######################## ## Fitting @@ -47,7 +49,7 @@ def isFitFinished(self) -> bool: def fittingStartStop(self) -> None: self._fitting_logic.start_stop() self.fittingChanged.emit() - self.parametersChanged.emit() + self._clearCacheAndEmitParametersChanged() ######################## ## Calculators @@ -109,14 +111,16 @@ def setMinimizerMaxIterations(self, new_value: int) -> None: ## Parameters @Property('QVariantList', notify=parametersChanged) def fitableParameters(self) -> List[dict[str]]: - return self._paramters_logic.list_of_dicts() - @Property(int, notify=parametersChanged) + if self._chached_paramters is None: + self._chached_paramters = self._paramters_logic.parameters + return self._chached_paramters + @Property(int, notify=parametersIndexChanged) def currentParameterIndex(self) -> int: return self._paramters_logic.current_index() @Slot(int) def setCurrentParameterIndex(self, new_value: int) -> None: if self._paramters_logic.set_current_index(new_value): - self.parametersChanged.emit() + self.parametersIndexChanged.emit() @Property(int, notify=parametersChanged) def freeParametersCount(self) -> int: @@ -137,19 +141,23 @@ def experimentParametersCount(self) -> int: @Slot(float) def setCurrentParameterValue(self, new_value: float) -> None: if self._paramters_logic.set_current_parameter_value(new_value): - self.parametersChanged.emit() + self._clearCacheAndEmitParametersChanged() @Slot(float) def setCurrentParameterMin(self, new_value: float) -> None: if self._paramters_logic.set_current_parameter_min(new_value): - self.parametersChanged.emit() + self._clearCacheAndEmitParametersChanged() @Slot(float) def setCurrentParameterMax(self, new_value: float) -> None: if self._paramters_logic.set_current_parameter_max(new_value): - self.parametersChanged.emit() + self._clearCacheAndEmitParametersChanged() @Slot(bool) def setCurrentParameterFit(self, new_value: bool) -> None: if self._paramters_logic.set_current_parameter_fit(new_value): - self.parametersChanged.emit() \ No newline at end of file + self._clearCacheAndEmitParametersChanged() + + def _clearCacheAndEmitParametersChanged(self): + self._chached_paramters = None + self.parametersChanged.emit() \ No newline at end of file diff --git a/src_qt6/EasyReflectometryApp/Backends/Py/logic/parameters.py b/src_qt6/EasyReflectometryApp/Backends/Py/logic/parameters.py index 0d7fe121..eacadb54 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Py/logic/parameters.py +++ b/src_qt6/EasyReflectometryApp/Backends/Py/logic/parameters.py @@ -12,7 +12,8 @@ def __init__(self, project_lib: ProjectLib): def as_status_string(self) -> str: return f"{self.count_free_parameters() + self.count_fixed_parameters()} ({self.count_free_parameters()} free, {self.count_fixed_parameters()} fixed)" - def list_of_dicts(self) -> List[str]: + @property + def parameters(self) -> List[str]: return _from_parameters_to_list_of_dicts(self._project_lib.parameters) def current_index(self) -> int: diff --git a/src_qt6/EasyReflectometryApp/Backends/Py/py_backend.py b/src_qt6/EasyReflectometryApp/Backends/Py/py_backend.py index f2b028e3..f82becfc 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Py/py_backend.py +++ b/src_qt6/EasyReflectometryApp/Backends/Py/py_backend.py @@ -89,17 +89,17 @@ def _connect_project_page(self) -> None: self._project.createdChanged.connect(self._relay_project_page_created) def _connect_sample_page(self) -> None: - self._sample.modelsIndexChanged.connect(self._relay_sample_page_models_index) - self._sample.sampleChanged.connect(self._relay_sample_page_sample_changed) - self._sample.refreshPlot.connect(self._refresh_plots) + self._sample.externalSampleChanged.connect(self._relay_sample_page_sample_changed) + self._sample.externalRefreshPlot.connect(self._refresh_plots) def _connect_experiment_page(self) -> None: self._experiment.experimentChanged.connect(self._relay_experiment_page_experiment_changed) self._experiment.experimentChanged.connect(self._refresh_plots) def _connect_analysis_page(self) -> None: - self._analysis.minimizerChanged.connect(self._relay_analysis_page_minimizer_changed) - self._analysis.calculatorChanged.connect(self._relay_analysis_page_calculator_changed) + self._analysis.minimizerChanged.connect(self._relay_analysis_page) + self._analysis.calculatorChanged.connect(self._relay_analysis_page) + self._analysis.parametersChanged.connect(self._relay_analysis_page) self._analysis.parametersChanged.connect(self._refresh_plots) self._analysis.fittingChanged.connect(self._refresh_plots) @@ -110,27 +110,18 @@ def _relay_project_page_name(self): def _relay_project_page_created(self): self._report.createdChanged.emit() - def _relay_sample_page_models_index(self, index: int): - self._plotting.setModelIndex(index) - self._experiment.setModelIndex(index) - def _relay_sample_page_sample_changed(self): - self._plotting.sldChartRangesChanged.emit() - self._plotting.sampleChartRangesChanged.emit() - self._analysis.parametersChanged.emit() + self._analysis._clearCacheAndEmitParametersChanged() + self._status.statusChanged.emit() def _relay_experiment_page_experiment_changed(self): self._status.statusChanged.emit() - self._sample.sampleChanged.emit() self._analysis.experimentsChanged.emit() - def _relay_analysis_page_minimizer_changed(self): - self._status.statusChanged.emit() - - def _relay_analysis_page_calculator_changed(self): + def _relay_analysis_page(self): self._status.statusChanged.emit() def _refresh_plots(self): self._plotting.refreshSamplePage() self._plotting.refreshExperimentPage() - self._plotting.refreshAnalysisPage() \ No newline at end of file + self._plotting.refreshAnalysisPage() diff --git a/src_qt6/EasyReflectometryApp/Backends/Py/sample.py b/src_qt6/EasyReflectometryApp/Backends/Py/sample.py index 99ec41c6..d598a233 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Py/sample.py +++ b/src_qt6/EasyReflectometryApp/Backends/Py/sample.py @@ -10,8 +10,6 @@ from .logic.layers import Layers class Sample(QObject): - sampleChanged = Signal() - materialsChanged = Signal() materialIndexChanged = Signal() @@ -27,7 +25,8 @@ class Sample(QObject): layersIndexChanged = Signal() layersTableChanged = Signal() - refreshPlot = Signal() + externalRefreshPlot = Signal() + externalSampleChanged = Signal() def __init__(self, project_lib: ProjectLib, parent=None): super().__init__(parent) @@ -37,6 +36,8 @@ def __init__(self, project_lib: ProjectLib, parent=None): self._assemblies_logic = Assemblies(project_lib) self._layers_logic = Layers(project_lib) + self._chached_layers = None + self.connect_logic() def connect_logic(self) -> None: @@ -77,29 +78,34 @@ def setCurrentMaterialName(self, new_value: str) -> None: def setCurrentMaterialSld(self, new_value: float) -> None: if self._material_logic.set_sld_at_current_index(new_value): self.materialsChanged.emit() - self.refreshPlot.emit() + self.externalRefreshPlot.emit() + self.externalSampleChanged.emit() @Slot(float) def setCurrentMaterialISld(self, new_value: float) -> None: if self._material_logic.set_isld_at_current_index(new_value): self.materialsChanged.emit() - self.refreshPlot.emit() + self.externalRefreshPlot.emit() + self.externalSampleChanged.emit() # Actions @Slot(str) def removeMaterial(self, value: str) -> None: self._material_logic.remove_at_index(value) self.materialsChanged.emit() + self.externalSampleChanged.emit() @Slot() def addNewMaterial(self) -> None: self._material_logic.add_new() self.materialIndexChanged.emit() + self.externalSampleChanged.emit() @Slot() def duplicateSelectedMaterial(self) -> None: self._material_logic.duplicate_selected() self.materialIndexChanged.emit() + self.externalSampleChanged.emit() @Slot() def moveSelectedMaterialUp(self) -> None: @@ -135,7 +141,7 @@ def currentModelName(self) -> str: def setCurrentModelIndex(self, new_value: int) -> None: self._project_lib.current_model_index = new_value self.modelsIndexChanged.emit() - self.refreshPlot.emit() + self.externalRefreshPlot.emit() @Slot(str) def setCurrentModelName(self, value: str) -> None: @@ -198,7 +204,7 @@ def currentAssemblyType(self) -> str: @Slot(int) def setCurrentAssemblyIndex(self, new_value: int) -> None: self._project_lib.current_assembly_index = new_value - self.layersTableChanged.emit() + self._clearCacheAndEmitLayersChanged() #self.layersTableChanged.emit() self.assembliesTableChanged.emit() self.assembliesIndexChanged.emit() @@ -210,10 +216,11 @@ def setCurrentAssemblyName(self, new_value: str) -> None: @Slot(str) def setCurrentAssemblyType(self, new_value: str) -> None: self._assemblies_logic.set_type_at_current_index(new_value) - self.layersTableChanged.emit() + self._clearCacheAndEmitLayersChanged() #self.layersTableChanged.emit() self.assembliesTableChanged.emit() self.assembliesIndexChanged.emit() - self.refreshPlot.emit() + self.externalRefreshPlot.emit() + self.externalSampleChanged.emit() # Assembly specific @Property(str, notify=assembliesChange) @@ -224,70 +231,77 @@ def currentAssemblyRepeatedLayerReptitions(self) -> str: def setCurrentAssemblyRepeatedLayerReptitions(self, new_value: int) -> None: if self._assemblies_logic.set_repeated_layer_reptitions(new_value): self.assembliesTableChanged.emit() - self.refreshPlot.emit() + self.externalRefreshPlot.emit() @Slot(bool) def setCurrentAssemblyConstrainAPM(self, new_value: bool) -> None: if self._assemblies_logic.set_constrain_apm(new_value): self.assembliesTableChanged.emit() - self.refreshPlot.emit() + self.externalRefreshPlot.emit() + self.externalSampleChanged.emit() @Slot(bool) def setCurrentAssemblyConformalRoughness(self, new_value: bool) -> None: if self._assemblies_logic.set_conformal_roughness(new_value): self.assembliesTableChanged.emit() - self.refreshPlot.emit() + self.externalRefreshPlot.emit() + self.externalSampleChanged.emit() # Actions @Slot(str) def removeAssembly(self, value: str) -> None: self._assemblies_logic.remove_at_index(value) self.assembliesTableChanged.emit() - self.refreshPlot.emit() + self.externalRefreshPlot.emit() + self.externalSampleChanged.emit() @Slot() def addNewAssembly(self) -> None: self._assemblies_logic.add_new() self.assembliesTableChanged.emit() - self.refreshPlot.emit() + self.externalRefreshPlot.emit() + self.externalSampleChanged.emit() @Slot() def duplicateSelectedAssembly(self) -> None: self._assemblies_logic.duplicate_selected() self.assembliesTableChanged.emit() - self.refreshPlot.emit() + self.externalRefreshPlot.emit() + self.externalSampleChanged.emit() @Slot() def moveSelectedAssemblyUp(self) -> None: self._assemblies_logic.move_selected_up() self.assembliesTableChanged.emit() - self.refreshPlot.emit() + self.externalRefreshPlot.emit() @Slot() def moveSelectedAssemblyDown(self)-> None: self._assemblies_logic.move_selected_down() self.assembliesTableChanged.emit() - self.refreshPlot.emit() + self.externalRefreshPlot.emit() # # # # Layers # # # def layersConnectChanges(self) -> None: - self.layersChange.emit() + self._clearCacheAndEmitLayersChanged() @Property('QVariantList', notify=layersChange) def layers(self) -> list[dict[str, str]]: - return self._layers_logic.layers + if self._chached_layers is None: + self._chached_layers = self._layers_logic.layers + return self._chached_layers @Property(int, notify=layersIndexChanged) def currentLayerIndex(self) -> int: return self._layers_logic.index - @Property('QVariantList', notify=layersTableChanged) + @Property('QVariantList', notify=layersChange) def layersNames(self) -> list[str]: return self._layers_logic.layers_names - @Property(str, notify=layersTableChanged) + @Property(str, notify=layersChange) def currentLayerName(self) -> str: return self._layers_logic.name_at_current_index @@ -300,77 +314,91 @@ def setCurrentLayerIndex(self, new_value: int) -> None: @Slot(str) def setCurrentLayerName(self, new_value: str) -> None: if self._layers_logic.set_name_at_current_index(new_value): - self.layersTableChanged.emit() + self._clearCacheAndEmitLayersChanged() @Slot(int) def setCurrentLayerMaterial(self, new_value: int) -> None: if self._layers_logic.set_material_at_current_index(new_value): - self.layersTableChanged.emit() - self.refreshPlot.emit() + self._clearCacheAndEmitLayersChanged() + self.externalRefreshPlot.emit() + self.externalSampleChanged.emit() @Slot(int) def setCurrentLayerSolvent(self, new_value: int) -> None: if self._layers_logic.set_solvent_at_current_index(new_value): - self.layersTableChanged.emit() - self.refreshPlot.emit() + self._clearCacheAndEmitLayersChanged() + self.externalRefreshPlot.emit() + self.externalSampleChanged.emit() @Slot(float) def setCurrentLayerThickness(self, new_value: float) -> None: if self._layers_logic.set_thickness_at_current_index(new_value): - self.layersTableChanged.emit() - self.refreshPlot.emit() + self._clearCacheAndEmitLayersChanged() + self.externalRefreshPlot.emit() + self.externalSampleChanged.emit() @Slot(float) def setCurrentLayerRoughness(self, new_value: float) -> None: if self._layers_logic.set_roughness_at_current_index(new_value): - self.layersTableChanged.emit() - self.refreshPlot.emit() + self._clearCacheAndEmitLayersChanged() + self.externalRefreshPlot.emit() + self.externalSampleChanged.emit() @Slot(str) def setCurrentLayerFormula(self, new_value: str) -> None: if self._layers_logic.set_formula(new_value): - self.layersTableChanged.emit() - self.refreshPlot.emit() + self._clearCacheAndEmitLayersChanged() + self.externalRefreshPlot.emit() + self.externalSampleChanged.emit() @Slot(float) def setCurrentLayerAPM(self, new_value: float) -> None: if self._layers_logic.set_apm_at_current_index(new_value): - self.layersTableChanged.emit() - self.refreshPlot.emit() + self._clearCacheAndEmitLayersChanged() + self.externalRefreshPlot.emit() + self.externalSampleChanged.emit() @Slot(float) def setCurrentLayerSolvation(self, new_value: float) -> None: if self._layers_logic.set_solvation_at_current_index(new_value): - self.layersTableChanged.emit() - self.refreshPlot.emit() + self._clearCacheAndEmitLayersChanged() + self.externalRefreshPlot.emit() + self.externalSampleChanged.emit() # Actions @Slot(str) def removeLayer(self, value: str) -> None: self._layers_logic.remove_at_index(value) - self.layersTableChanged.emit() - self.refreshPlot.emit() + self._clearCacheAndEmitLayersChanged() + self.externalRefreshPlot.emit() + self.externalSampleChanged.emit() @Slot() def addNewLayer(self) -> None: self._layers_logic.add_new() - self.layersTableChanged.emit() - self.refreshPlot.emit() + self._clearCacheAndEmitLayersChanged() + self.externalRefreshPlot.emit() + self.externalSampleChanged.emit() @Slot() def duplicateSelectedLayer(self) -> None: self._layers_logic.duplicate_selected() - self.layersTableChanged.emit() - self.refreshPlot.emit() + self._clearCacheAndEmitLayersChanged() + self.externalRefreshPlot.emit() + self.externalSampleChanged.emit() @Slot() def moveSelectedLayerUp(self) -> None: self._layers_logic.move_selected_up() - self.layersTableChanged.emit() - self.refreshPlot.emit() + self._clearCacheAndEmitLayersChanged() + self.externalRefreshPlot.emit() @Slot() def moveSelectedLayerDown(self)-> None: self._layers_logic.move_selected_down() - self.layersTableChanged.emit() - self.refreshPlot.emit() + self._clearCacheAndEmitLayersChanged() + self.externalRefreshPlot.emit() + + def _clearCacheAndEmitLayersChanged(self): + self._chached_layers = None + self.layersChange.emit() \ No newline at end of file From 07f013ef208c26dc324953a6c0a581d01fe3e919 Mon Sep 17 00:00:00 2001 From: Andreas Pedersen Date: Wed, 6 Nov 2024 14:58:28 +0100 Subject: [PATCH 26/43] fittable with better names --- .../Backends/Py/logic/parameters.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src_qt6/EasyReflectometryApp/Backends/Py/logic/parameters.py b/src_qt6/EasyReflectometryApp/Backends/Py/logic/parameters.py index eacadb54..e875f213 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Py/logic/parameters.py +++ b/src_qt6/EasyReflectometryApp/Backends/Py/logic/parameters.py @@ -1,4 +1,6 @@ from easyscience.Objects.new_variable import Parameter +from easyscience import global_object + from easyreflectometry import Project as ProjectLib from typing import List @@ -14,7 +16,7 @@ def as_status_string(self) -> str: @property def parameters(self) -> List[str]: - return _from_parameters_to_list_of_dicts(self._project_lib.parameters) + return _from_parameters_to_list_of_dicts(self._project_lib.parameters, self._project_lib._models[self._project_lib.current_model_index].unique_name) def current_index(self) -> int: return self._current_index @@ -78,12 +80,14 @@ def set_current_parameter_fit(self, new_value: str) -> bool: return True return False -def _from_parameters_to_list_of_dicts(parameters: List[Parameter]) -> list[dict[str, str]]: +def _from_parameters_to_list_of_dicts(parameters: List[Parameter], model_unique_name: str) -> list[dict[str, str]]: parameter_list = [] for parameter in parameters: + path = global_object.map.find_path(model_unique_name, parameter.unique_name) + name = f"{global_object.map.get_item_by_key(path[-2]).name} {global_object.map.get_item_by_key(path[-1]).name}" parameter_list.append( { - 'name': parameter.name, + 'name': name, 'value': float(parameter.value), 'error': float(parameter.variance), 'max': float(parameter.max), From e4de68bd9675bf4d463bdc40c479c4cbe42ee86f Mon Sep 17 00:00:00 2001 From: Andreas Pedersen Date: Wed, 6 Nov 2024 15:58:23 +0100 Subject: [PATCH 27/43] reset button is active after sample page --- src_qt6/EasyReflectometryApp/Backends/Mock/Plotting.qml | 9 +++++++++ src_qt6/EasyReflectometryApp/Gui/ApplicationWindow.qml | 7 ++++--- src_qt6/EasyReflectometryApp/Gui/Globals/References.qml | 2 ++ src_qt6/EasyReflectometryApp/Gui/Pages/Sample/Layout.qml | 1 + 4 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src_qt6/EasyReflectometryApp/Backends/Mock/Plotting.qml b/src_qt6/EasyReflectometryApp/Backends/Mock/Plotting.qml index 2a64db20..9317594a 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Mock/Plotting.qml +++ b/src_qt6/EasyReflectometryApp/Backends/Mock/Plotting.qml @@ -24,4 +24,13 @@ QtObject { function setQtChartsSerieRef(value1, value2, value3) { console.debug(`setQtChartsSerieRef ${value1}, ${value2}, ${value3}`) } + + function drawCalculatedOnSampleChart(){ + console.debug(`drawCalculatedOnSampleChart`) + } + + function drawCalculatedOnSldChart(){ + console.debug(`drawCalculatedOnSldChart`) + } + } diff --git a/src_qt6/EasyReflectometryApp/Gui/ApplicationWindow.qml b/src_qt6/EasyReflectometryApp/Gui/ApplicationWindow.qml index dc5e074e..4befd413 100644 --- a/src_qt6/EasyReflectometryApp/Gui/ApplicationWindow.qml +++ b/src_qt6/EasyReflectometryApp/Gui/ApplicationWindow.qml @@ -26,10 +26,11 @@ EaComponents.ApplicationWindow { }, EaElements.ToolButton { - enabled: Globals.BackendWrapper.projectCreated + enabled: Globals.References.resetActive fontIcon: "backspace" ToolTip.text: qsTr("Reset to initial state without project, models and data") onClicked: { + Globals.References.resetActive = false Globals.BackendWrapper.projectReset() Globals.References.applicationWindow.appBarCentralTabs.projectButton.toggle() if (Globals.References.applicationWindow.appBarCentralTabs.sampleButton !== null) { @@ -101,7 +102,7 @@ EaComponents.ApplicationWindow { // Experiment tab EaElements.AppBarTabButton { id: experimentTabButton - enabled: true + enabled: false fontIcon: "microscope" text: qsTr("Experiment") ToolTip.text: qsTr("Experimental settings and data page") @@ -112,7 +113,7 @@ EaComponents.ApplicationWindow { // Analysis tab EaElements.AppBarTabButton { id: analysisTabButton - enabled: true + enabled: false fontIcon: "calculator" text: qsTr("Analysis") ToolTip.text: qsTr("Simulation and fitting page") diff --git a/src_qt6/EasyReflectometryApp/Gui/Globals/References.qml b/src_qt6/EasyReflectometryApp/Gui/Globals/References.qml index 0004e1af..c754d3ec 100644 --- a/src_qt6/EasyReflectometryApp/Gui/Globals/References.qml +++ b/src_qt6/EasyReflectometryApp/Gui/Globals/References.qml @@ -9,6 +9,8 @@ import QtQuick QtObject { + property bool resetActive: false + // Populated in ApplicationWindows.qml readonly property var applicationWindow: { 'appBarCentralTabs': { diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/Layout.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/Layout.qml index d9aaae3e..e5712565 100644 --- a/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/Layout.qml +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/Layout.qml @@ -43,6 +43,7 @@ EaComponents.ContentPage { continueButton.text: qsTr('Continue') continueButton.onClicked: { console.debug(`Clicking '${continueButton.text}' button ::: ${this}`) + Globals.References.resetActive = true Globals.References.applicationWindow.appBarCentralTabs.experimentButton.enabled = true Globals.References.applicationWindow.appBarCentralTabs.experimentButton.toggle() } From 5f08d7e6bb6a82c24cdfbde9804dcddc8891608f Mon Sep 17 00:00:00 2001 From: Andreas Pedersen Date: Thu, 7 Nov 2024 06:42:14 +0100 Subject: [PATCH 28/43] code cleaning an external signals --- .../Backends/Py/analysis.py | 9 + .../Backends/Py/py_backend.py | 10 +- .../Gui/Globals/References.qml | 5 - .../Sidebar/Basic/Groups/Fittables.qml | 200 +++--------------- 4 files changed, 40 insertions(+), 184 deletions(-) diff --git a/src_qt6/EasyReflectometryApp/Backends/Py/analysis.py b/src_qt6/EasyReflectometryApp/Backends/Py/analysis.py index cfb85f7e..2ea01b4e 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Py/analysis.py +++ b/src_qt6/EasyReflectometryApp/Backends/Py/analysis.py @@ -22,6 +22,11 @@ class Analysis(QObject): parametersIndexChanged = Signal() fittingChanged = Signal() + externalMinimizerChanged = Signal() + externalParametersChanged = Signal() + externalCalculatorChanged = Signal() + externalFittingChanged = Signal() + def __init__(self, project_lib: ProjectLib, parent=None): super().__init__(parent) self._paramters_logic = ParametersLogic(project_lib) @@ -50,6 +55,7 @@ def fittingStartStop(self) -> None: self._fitting_logic.start_stop() self.fittingChanged.emit() self._clearCacheAndEmitParametersChanged() + self.externalFittingChanged.emit() ######################## ## Calculators @@ -63,6 +69,7 @@ def calculatorCurrentIndex(self) -> int: def setCalculatorCurrentIndex(self, new_value: int) -> None: if self._calculators_logic.set_current_index(new_value): self.calculatorChanged.emit() + self.externalCalculatorChanged.emit() ######################## ## Experiments @@ -88,6 +95,7 @@ def minimizerCurrentIndex(self) -> int: def setMinimizerCurrentIndex(self, new_value: int) -> None: if self._minimizers_logic.set_minimizer_current_index(new_value): self.minimizerChanged.emit() + self.externalMinimizerChanged.emit() @Property('QVariant', notify=minimizerChanged) def minimizerTolerance(self) -> Optional[float]: @@ -142,6 +150,7 @@ def experimentParametersCount(self) -> int: def setCurrentParameterValue(self, new_value: float) -> None: if self._paramters_logic.set_current_parameter_value(new_value): self._clearCacheAndEmitParametersChanged() + self.externalParametersChanged.emit() @Slot(float) def setCurrentParameterMin(self, new_value: float) -> None: diff --git a/src_qt6/EasyReflectometryApp/Backends/Py/py_backend.py b/src_qt6/EasyReflectometryApp/Backends/Py/py_backend.py index f82becfc..235d0bb0 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Py/py_backend.py +++ b/src_qt6/EasyReflectometryApp/Backends/Py/py_backend.py @@ -97,11 +97,11 @@ def _connect_experiment_page(self) -> None: self._experiment.experimentChanged.connect(self._refresh_plots) def _connect_analysis_page(self) -> None: - self._analysis.minimizerChanged.connect(self._relay_analysis_page) - self._analysis.calculatorChanged.connect(self._relay_analysis_page) - self._analysis.parametersChanged.connect(self._relay_analysis_page) - self._analysis.parametersChanged.connect(self._refresh_plots) - self._analysis.fittingChanged.connect(self._refresh_plots) + self._analysis.externalMinimizerChanged.connect(self._relay_analysis_page) + self._analysis.externalCalculatorChanged.connect(self._relay_analysis_page) + self._analysis.externalParametersChanged.connect(self._relay_analysis_page) + self._analysis.externalParametersChanged.connect(self._refresh_plots) + self._analysis.externalFittingChanged.connect(self._refresh_plots) def _relay_project_page_name(self): self._status.statusChanged.emit() diff --git a/src_qt6/EasyReflectometryApp/Gui/Globals/References.qml b/src_qt6/EasyReflectometryApp/Gui/Globals/References.qml index c754d3ec..1133778a 100644 --- a/src_qt6/EasyReflectometryApp/Gui/Globals/References.qml +++ b/src_qt6/EasyReflectometryApp/Gui/Globals/References.qml @@ -67,9 +67,4 @@ QtObject { } } } - -// // Populated in plotting/... -// readonly property var plotting: { -// 'graph1d': null, -// } } diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Groups/Fittables.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Groups/Fittables.qml index a811004d..88606f81 100644 --- a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Groups/Fittables.qml +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Groups/Fittables.qml @@ -121,9 +121,6 @@ EaElements.GroupBox { // Table EaComponents.TableView { id: tableView - -// property var currentValueTextInput: null - defaultInfoText: qsTr("No parameters found") maxRowCountShow: 7 + @@ -202,9 +199,6 @@ EaElements.GroupBox { delegate: EaComponents.TableViewDelegate { enabled: !Globals.BackendWrapper.analysisFittingRunning -// property bool isCurrentItem: ListView.isCurrentItem -// property var item: Globals.BackendWrapper.analysisFitableParameters[index] - mouseArea.onPressed: { if (Globals.BackendWrapper.analysisCurrentParameterIndex !== index) { Globals.BackendWrapper.analysisSetCurrentParameterIndex(index) @@ -212,18 +206,7 @@ EaElements.GroupBox { updateSliderValue() } } -// Globals.BackendWrapper.analysisSetCurrentParameterIndex(index)// fittables.selectedParamIndex = tableView.currentIndex -/* onIsCurrentItemChanged: { -// if (tableView.currentValueTextInput != valueColumn) { - // tableView.currentValueTextInput = valueColumn - if (Globals.BackendWrapper.analysisCurrentParameterIndex !== index) { -// Globals.BackendWrapper.analysisSetCurrentParameterIndex(index) - updateSliderLimits() - updateSliderValue() - } - } -*/ EaComponents.TableViewLabel { text: index + 1 color: EaStyle.Colors.themeForegroundMinor @@ -231,43 +214,26 @@ EaElements.GroupBox { EaComponents.TableViewLabel { width: EaStyle.Sizes.fontPixelSize * 5 - text: Globals.BackendWrapper.analysisFitableParameters[index].name //Globals.Proxies.paramName(item, EaGlobals.Vars.paramNameFormat) - textFormat: EaGlobals.Vars.paramNameFormat === EaGlobals.Vars.PlainShortWithLabels || - EaGlobals.Vars.paramNameFormat === EaGlobals.Vars.PlainFullWithLabels ? - Text.PlainText : - Text.RichText - //clip: true - elide: Text.ElideMiddle // NEED FIX: Doesn't work with textFormat: Text.RichText + text: Globals.BackendWrapper.analysisFitableParameters[index].name +// textFormat: EaGlobals.Vars.paramNameFormat === EaGlobals.Vars.PlainShortWithLabels || +// EaGlobals.Vars.paramNameFormat === EaGlobals.Vars.PlainFullWithLabels ? +// Text.PlainText : +// Text.RichText +// elide: Text.ElideMiddle // NEED FIX: Doesn't work with textFormat: Text.RichText ToolTip.text: textFormat === Text.PlainText ? text : '' } EaComponents.TableViewParameter { id: valueColumn - selected: //index === tableView.currentIndex || - index === Globals.BackendWrapper.analysisCurrentParameterIndex //fittables.selectedParamIndex - fit: Globals.BackendWrapper.analysisFitableParameters[index].fit + selected: index === Globals.BackendWrapper.analysisCurrentParameterIndex +// fit: Globals.BackendWrapper.analysisFitableParameters[index].fit text: EaLogic.Utils.toDefaultPrecision(Globals.BackendWrapper.analysisFitableParameters[index].value) -// Globals.BackendWrapper.analysisFitableParameters[index].error === 0 ? -// EaLogic.Utils.toDefaultPrecision(Globals.BackendWrapper.analysisFitableParameters[index].value) : -// 1000 //Globals.Proxies.main.backendHelpers.toStdDevSmalestPrecision(item.value, item.error).value onEditingFinished: { focus = false -// console.debug('') console.debug("*** Editing (manual) 'value' field of fittable on Analysis page ***") Globals.BackendWrapper.analysisSetCurrentParameterValue(text) - - /* Globals.Proxies.main.fittables.editSilently(item.blockType, - item.blockIdx, - item.category, - item.rowIndex ?? -1, - item.name, - 'value', - text) - */ updateSliderValue() updateSliderLimits() -// slider.value = Globals.BackendWrapper.analysisFitableParameters[index].value //[Globals.BackendWrapper.analysisCurrentParameterIndex].value //fittables.selectedParamIndex].value - } } @@ -277,10 +243,9 @@ EaElements.GroupBox { } EaComponents.TableViewLabel { - elide: Text.ElideNone - text: Number(Globals.BackendWrapper.analysisFitableParameters[index].error).toExponential(2)//Globals.BackendWrapper.analysisFitableParameters[index].error === 0 ? -// '' : -// 1000 //Globals.Proxies.main.backendHelpers.toStdDevSmalestPrecision(item.value, item.error).std_dev +// elide: Text.ElideNone + text: EaLogic.Utils.toDefaultPrecision(Globals.BackendWrapper.analysisFitableParameters[index].error) + //text: Number(Globals.BackendWrapper.analysisFitableParameters[index].error).toExponential(2) } EaComponents.TableViewParameter { @@ -288,18 +253,10 @@ EaElements.GroupBox { text: EaLogic.Utils.toDefaultPrecision(Globals.BackendWrapper.analysisFitableParameters[index].min).replace('Infinity', 'inf') onEditingFinished: { focus = false -// console.debug('') console.debug("*** Editing 'min' field of fittable on Analysis page ***") const value = (text === '' ? '-inf' : text) Globals.BackendWrapper.analysisSetCurrentParameterMin(text) - /* Globals.Proxies.main.fittables.editSilently(item.blockType, - item.blockIdx, - item.category, - item.rowIndex ?? -1, - item.name, - 'min', - value) - */ } + } } EaComponents.TableViewParameter { @@ -307,36 +264,20 @@ EaElements.GroupBox { text: EaLogic.Utils.toDefaultPrecision(Globals.BackendWrapper.analysisFitableParameters[index].max).replace('Infinity', 'inf') onEditingFinished: { focus = false -// console.debug('') console.debug("*** Editing 'max' field of fittable on Analysis page ***") const value = (text === '' ? 'inf' : text) Globals.BackendWrapper.analysisSetCurrentParameterMax(value) - /* Globals.Proxies.main.fittables.editSilently(item.blockType, - item.blockIdx, - item.category, - item.rowIndex ?? -1, - item.name, - 'max', - value) - */ } + } } EaComponents.TableViewCheckBox { id: fitColumn - enabled: Globals.BackendWrapper.analysisExperimentsAvailable.length// Globals.Proxies.main.experiment.defined + enabled: Globals.BackendWrapper.analysisExperimentsAvailable.length checked: Globals.BackendWrapper.analysisFitableParameters[index].fit onToggled: { -// console.debug('') console.debug("*** Editing 'fit' field of fittable on Analysis page ***") Globals.BackendWrapper.analysisSetCurrentParameterFit(checkState) - /* Globals.Proxies.main.fittables.editSilently(item.blockType, - item.blockIdx, - item.category, - item.rowIndex ?? -1, - item.name, - 'fit', - checked) - */ } + } } } // Table content row @@ -345,27 +286,18 @@ EaElements.GroupBox { // Parameter change slider Row { - visible: Globals.BackendWrapper.analysisFitableParameters.length //Globals.Proxies.main_fittables_data.length + visible: Globals.BackendWrapper.analysisFitableParameters.length spacing: EaStyle.Sizes.fontPixelSize EaElements.TextField { readOnly: true width: EaStyle.Sizes.fontPixelSize * 6 - //text: EaLogic.Utils.toDefaultPrecision(slider.from) - //text: EaLogic.Utils.toErrSinglePrecision(slider.from, Globals.Proxies.main_fittables_data[selectedParamIndex].error) text: { - const value = Globals.BackendWrapper.analysisFitableParameters[Globals.BackendWrapper.analysisCurrentParameterIndex].value //[fittables.selectedParamIndex].value // Globals.Proxies.main_fittables_data[selectedParamIndex].value - const error = Globals.BackendWrapper.analysisFitableParameters[Globals.BackendWrapper.analysisCurrentParameterIndex].error //[fittables.selectedParamIndex].error // Globals.Proxies.main_fittables_data[selectedParamIndex].error - //return EaLogic.Utils.toErrSinglePrecision(value, error).length <= 8 ? - // EaLogic.Utils.toErrSinglePrecision(slider.from, error) : - // EaLogic.Utils.toDefaultPrecision(slider.from) + const value = Globals.BackendWrapper.analysisFitableParameters[Globals.BackendWrapper.analysisCurrentParameterIndex].value + const error = Globals.BackendWrapper.analysisFitableParameters[Globals.BackendWrapper.analysisCurrentParameterIndex].error return EaLogic.Utils.toDefaultPrecision(slider.from) - -/* return error === 0 ? - EaLogic.Utils.toDefaultPrecision(slider.from) : - 1000 //Globals.Proxies.main.backendHelpers.toStdDevSmalestPrecision(slider.from, error).value -*/ } + } } EaElements.Slider { @@ -378,33 +310,16 @@ EaElements.GroupBox { snapMode: Slider.SnapAlways toolTipText: { - //const value = Globals.BackendWrapper.analysisFitableParameters[Globals.BackendWrapper.analysisCurrentParameterIndex].value //[fittables.selectedParamIndex].value //Globals.Proxies.main_fittables_data[selectedParamIndex].value - //const error = Globals.BackendWrapper.analysisFitableParameters[Globals.BackendWrapper.analysisCurrentParameterIndex].error //[fittables.selectedParamIndex].error //Globals.Proxies.main_fittables_data[selectedParamIndex].error - //return EaLogic.Utils.toErrSinglePrecision(value, error).length <= 8 ? - // EaLogic.Utils.toErrSinglePrecision(value, error) : - // EaLogic.Utils.toDefaultPrecision(value) return EaLogic.Utils.toDefaultPrecision(value) -/* return error === 0 ? - EaLogic.Utils.toDefaultPrecision(value) : - 1000 //Globals.Proxies.main.backendHelpers.toStdDevSmalestPrecision(value, error).value -*/ } - - onMoved: { -// console.debug('') - console.debug("*** Editing (slider) 'value' field of fittable on Analysis page ***") - //const item = Globals.BackendWrapper.analysisFitableParameters[Globals.BackendWrapper.analysisCurrentParameterIndex] //[fittables.selectedParamIndex] //Globals.Proxies.main_fittables_data[selectedParamIndex] - Globals.BackendWrapper.analysisSetCurrentParameterValue(value) - /* Globals.Proxies.main.fittables.editSilently(item.blockType, - item.blockIdx, - item.category, - item.rowIndex ?? -1, - item.name, - 'value', - value.toString()) - */ } - + } +// onMoved: { +// console.debug("*** Editing (slider) 'value' field of fittable on Analysis page ***") +// Globals.BackendWrapper.analysisSetCurrentParameterValue(value) +// } onPressedChanged: { if (!pressed) { + console.debug("*** Editing (slider) 'value' field of fittable on Analysis page ***") + Globals.BackendWrapper.analysisSetCurrentParameterValue(value) updateSliderLimits() } } @@ -413,55 +328,17 @@ EaElements.GroupBox { EaElements.TextField { readOnly: true width: EaStyle.Sizes.fontPixelSize * 6 - //text: EaLogic.Utils.toDefaultPrecision(slider.to) - //text: EaLogic.Utils.toErrSinglePrecision(slider.to, Globals.Proxies.main_fittables_data[selectedParamIndex].error) text: { - //const value = Globals.BackendWrapper.analysisFitableParameters[Globals.BackendWrapper.analysisCurrentParameterIndex].value //[fittables.selectedParamIndex].value //Globals.Proxies.main_fittables_data[selectedParamIndex].value - //const error = Globals.BackendWrapper.analysisFitableParameters[Globals.BackendWrapper.analysisCurrentParameterIndex].error //[fittables.selectedParamIndex].error //Globals.Proxies.main_fittables_data[selectedParamIndex].error - //return EaLogic.Utils.toErrSinglePrecision(value, error).length <= 8 ? - // EaLogic.Utils.toErrSinglePrecision(slider.to, error) : - // EaLogic.Utils.toDefaultPrecision(slider.to) return EaLogic.Utils.toDefaultPrecision(slider.to) -/* return error === 0 ? - EaLogic.Utils.toDefaultPrecision(slider.to) : - 1000 //Globals.Proxies.main.backendHelpers.toStdDevSmalestPrecision(slider.to, error).value -*/ } - } - - } - // Slider - - // Move delay timer - - /* - Timer { - id: moveDelayTimer - interval: 0 //50 - onTriggered: { - if (tableView.currentValueTextInput.text !== slider.value.toFixed(4)) { - //enableOpenGL() - tableView.currentValueTextInput.text = slider.value.toFixed(4) - tableView.currentValueTextInput.editingFinished() - //disableOpenGL() } } } - */ - } - // Use OpenGL on slider move only - -/* Timer { - id: disableOpenGLTimer - interval: 1500 - onTriggered: disableOpenGLFromTimer() } -*/ // Logic function updateSliderValue() { const value = Globals.BackendWrapper.analysisFitableParameters[Globals.BackendWrapper.analysisCurrentParameterIndex].value slider.value = EaLogic.Utils.toDefaultPrecision(value) -// Globals.BackendWrapper.analysisSetCurrentParameterValue(EaLogic.Utils.toDefaultPrecision(value)) } function updateSliderLimits() { @@ -479,30 +356,5 @@ EaElements.GroupBox { slider.from = EaLogic.Utils.toDefaultPrecision(from) slider.to = EaLogic.Utils.toDefaultPrecision(to) } - -/* function enableOpenGL() { - if (Globals.Proxies.main.plotting.currentLib1d === 'QtCharts') { - Globals.Refs.app.experimentPage.plotView.useOpenGL = true - //Globals.Refs.app.modelPage.plotView.useOpenGL = true - Globals.Refs.app.analysisPage.plotView.useAnimation = false - Globals.Refs.app.analysisPage.plotView.useOpenGL = true - } - } - - function disableOpenGL() { - if (Globals.Proxies.main.plotting.currentLib1d === 'QtCharts') { - ////Globals.Proxies.main.plotting.chartRefs.QtCharts.analysisPage.totalCalcSerie.pointsReplaced() - disableOpenGLTimer.restart() - } - } - - function disableOpenGLFromTimer() { - Globals.Refs.app.experimentPage.plotView.useOpenGL = false - //Globals.Refs.app.modelPage.plotView.useOpenGL = false - ////Globals.Proxies.main.plotting.chartRefs.QtCharts.analysisPage.totalCalcSerie.pointsReplaced() - ///console.error(Globals.Proxies.main.plotting.chartRefs.QtCharts.analysisPage.totalCalcSerie) - Globals.Refs.app.analysisPage.plotView.useAnimation = true - Globals.Refs.app.analysisPage.plotView.useOpenGL = false - }*/ } From 0bddccc93cc7fe34524ecc9a6870720903cb994c Mon Sep 17 00:00:00 2001 From: Andreas Pedersen Date: Thu, 7 Nov 2024 09:53:22 +0100 Subject: [PATCH 29/43] code cleaning and better signalling --- .../Backends/Py/experiment.py | 24 +++--- .../Backends/Py/logic/project.py | 17 ++++- .../Backends/Py/plotting_1d.py | 75 +------------------ .../Backends/Py/project.py | 9 +++ .../Backends/Py/py_backend.py | 7 +- .../Sidebar/Basic/Groups/ExperimentalData.qml | 8 +- .../Basic/Groups/InstrumentParameters.qml | 2 +- .../Sidebar/Basic/Groups/QRange.qml | 5 +- .../Pages/Experiment/Sidebar/Basic/Layout.qml | 6 +- .../Gui/Pages/Project/Layout.qml | 4 +- 10 files changed, 46 insertions(+), 111 deletions(-) diff --git a/src_qt6/EasyReflectometryApp/Backends/Py/experiment.py b/src_qt6/EasyReflectometryApp/Backends/Py/experiment.py index bba6372b..e77a564a 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Py/experiment.py +++ b/src_qt6/EasyReflectometryApp/Backends/Py/experiment.py @@ -53,33 +53,33 @@ def setModelIndex(self, value: int) -> None: @Slot(float) def setScaling(self, new_value: float) -> None: - self._model_logic.set_scaling_at_current_index(new_value) - self.experimentChanged.emit() + if self._model_logic.set_scaling_at_current_index(new_value): + self.experimentChanged.emit() @Slot(float) def setBackground(self, new_value: float) -> None: - self._model_logic.set_background_at_current_index(new_value) - self.experimentChanged.emit() + if self._model_logic.set_background_at_current_index(new_value): + self.experimentChanged.emit() @Slot(float) def setResolution(self, new_value: float) -> None: - self._model_logic.set_resolution_at_current_index(new_value) - self.experimentChanged.emit() + if self._model_logic.set_resolution_at_current_index(new_value): + self.experimentChanged.emit() @Slot(float) def setQMin(self, new_value: float) -> None: - self._project_logic.set_q_min(new_value) - self.experimentChanged.emit() + if self._project_logic.set_q_min(new_value): + self.experimentChanged.emit() @Slot(float) def setQMax(self, new_value: float) -> None: - self._project_logic.set_q_max(new_value) - self.experimentChanged.emit() + if self._project_logic.set_q_max(new_value): + self.experimentChanged.emit() @Slot(int) def setQElements(self, new_value: float) -> None: - self._project_logic.set_q_resolution(new_value) - self.experimentChanged.emit() + if self._project_logic.set_q_resolution(new_value): + self.experimentChanged.emit() # Actions @Slot(str) diff --git a/src_qt6/EasyReflectometryApp/Backends/Py/logic/project.py b/src_qt6/EasyReflectometryApp/Backends/Py/logic/project.py index fb34c7e4..4656543e 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Py/logic/project.py +++ b/src_qt6/EasyReflectometryApp/Backends/Py/logic/project.py @@ -48,21 +48,30 @@ def q_min(self) -> float: return self._project_lib.q_min def set_q_min(self, new_value: str) -> None: - self._project_lib.q_min = float(new_value) + if float(new_value) != self._project_lib.q_min: + self._project_lib.q_min = float(new_value) + return True + return False @property def q_max(self) -> float: return self._project_lib.q_max def set_q_max(self, new_value: str) -> None: - self._project_lib.q_max = float(new_value) - + if float(new_value) != self._project_lib.q_max: + self._project_lib.q_max = float(new_value) + return True + return False + @property def q_resolution(self) -> int: return self._project_lib.q_resolution def set_q_resolution(self, new_value: str) -> None: - self._project_lib.q_resolution = int(new_value) + if float(new_value) != self._project_lib.q_resolution: + self._project_lib.q_resolution = int(new_value) + return True + return False @property def experimental_data_at_current_index(self) -> bool: diff --git a/src_qt6/EasyReflectometryApp/Backends/Py/plotting_1d.py b/src_qt6/EasyReflectometryApp/Backends/Py/plotting_1d.py index 3829d1d6..bb41c974 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Py/plotting_1d.py +++ b/src_qt6/EasyReflectometryApp/Backends/Py/plotting_1d.py @@ -14,8 +14,6 @@ PLOT_BACKEND = 'QtCharts' class Plotting1d(QObject): - currentLib1dChanged = Signal() - useAcceleration1dChanged = Signal() chartRefsChanged = Signal() sldChartRangesChanged = Signal() sampleChartRangesChanged = Signal() @@ -118,79 +116,8 @@ def sldMaxY(self): @Property(float, notify=sldChartRangesChanged) def sldMinY(self): return self.sld_data.y.min() - - # # Experiment - # @Property(float, notify=experimentChartRangesChanged) - # def experimentMaxX(self): - # if len(self.experiment_data.x) == 0: - # return None - # return self.experiment_data.x.max() - - # @Property(float, notify=experimentChartRangesChanged) - # def experimentMinX(self): - # if len(self.experiment_data.x) == 0: - # return None - # return self.experiment_data.x.min() - - # @Property(float, notify=experimentChartRangesChanged) - # def experimentMaxY(self): - # if len(self.experiment_data.y) == 0: - # return None - # return np.log10(self.experiment_data.y.max()) - - # @Property(float, notify=experimentChartRangesChanged) - # def experimentMinY(self): - # if len(self.experiment_data.y) == 0: - # return None - # return np.log10(self.experiment_data.y.min()) - - # # Analysis - # @Property(float, notify=sampleChartRangesChanged) - # def analysisMaxX(self): - # if self.experimentMaxX is None: - # return self.sampleMaxX - # return max(self.sampleMaxX, self.experimentMaxX) - - # @Property(float, notify=sampleChartRangesChanged) - # def analysisMinX(self): - # if self.experimentMinX is None: - # return self.sampleMinX - # return min(self.sampleMinX, self.experimentMinX) - - # @Property(float, notify=sampleChartRangesChanged) - # def analysisMaxY(self): - # if self.experimentMaxY is None: - # return self.sampleMaxY - # return max(self.sampleMaxY, self.experimentMaxY) - - # @Property(float, notify=sampleChartRangesChanged) - # def analysisMinY(self): - # if self.experimentMinY is None: - # return self.sampleMinY - # return min(self.sampleMinY, self.experimentMinY) - # Other - @Property(str, notify=currentLib1dChanged) - def currentLib1d(self): - return self._currentLib1d - - @currentLib1d.setter - def currentLib1d(self, newValue): - if self._currentLib1d == newValue: - return - self._currentLib1d = newValue - self.currentLib1dChanged.emit() - - @Property(bool, notify=useAcceleration1dChanged) - def useAcceleration1d(self): - return self._useAcceleration1d - - @useAcceleration1d.setter - def useAcceleration1d(self, newValue): - if self._useAcceleration1d == newValue: - return - self._useAcceleration1d = newValue - self.useAcceleration1dChanged.emit() + @Property('QVariant', notify=chartRefsChanged) def chartRefs(self): diff --git a/src_qt6/EasyReflectometryApp/Backends/Py/project.py b/src_qt6/EasyReflectometryApp/Backends/Py/project.py index 05ba07eb..18f12262 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Py/project.py +++ b/src_qt6/EasyReflectometryApp/Backends/Py/project.py @@ -15,6 +15,9 @@ class Project(QObject): descriptionChanged = Signal() locationChanged = Signal() + externalCreatedChanged = Signal() + externalNameChanged = Signal() + def __init__(self, project_lib: ProjectLib, parent=None): super().__init__(parent) self._logic = ProjectLogic(project_lib) @@ -44,6 +47,7 @@ def setName(self, new_value: str) -> None: if self._logic.name != new_value: self._logic.name = new_value self.nameChanged.emit() + self.externalNameChanged.emit() @Property(str, notify=descriptionChanged) def description(self) -> str: @@ -71,6 +75,7 @@ def setLocation(self, new_value: str) -> None: def create(self) -> None: self._logic.create() self.createdChanged.emit() + self.externalCreatedChanged.emit() @Slot(str) def load(self, path: str) -> None: @@ -79,6 +84,8 @@ def load(self, path: str) -> None: self.nameChanged.emit() self.descriptionChanged.emit() self.locationChanged.emit() + self.externalCreatedChanged.emit() + self.externalNameChanged.emit() @Slot() def save(self) -> None: @@ -91,3 +98,5 @@ def reset(self) -> None: self.nameChanged.emit() self.descriptionChanged.emit() self.locationChanged.emit() + self.externalCreatedChanged.emit() + self.externalNameChanged.emit() diff --git a/src_qt6/EasyReflectometryApp/Backends/Py/py_backend.py b/src_qt6/EasyReflectometryApp/Backends/Py/py_backend.py index 235d0bb0..64cfb6cc 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Py/py_backend.py +++ b/src_qt6/EasyReflectometryApp/Backends/Py/py_backend.py @@ -85,8 +85,8 @@ def _connect_backend_parts(self) -> None: ######### Forming connections between the backend parts def _connect_project_page(self) -> None: - self._project.nameChanged.connect(self._relay_project_page_name) - self._project.createdChanged.connect(self._relay_project_page_created) + self._project.externalNameChanged.connect(self._relay_project_page_name) + self._project.externalCreatedChanged.connect(self._relay_project_page_created) def _connect_sample_page(self) -> None: self._sample.externalSampleChanged.connect(self._relay_sample_page_sample_changed) @@ -122,6 +122,9 @@ def _relay_analysis_page(self): self._status.statusChanged.emit() def _refresh_plots(self): + self._plotting.sampleChartRangesChanged.emit() + self._plotting.sldChartRangesChanged.emit() + self._plotting.experimentChartRangesChanged.emit() self._plotting.refreshSamplePage() self._plotting.refreshExperimentPage() self._plotting.refreshAnalysisPage() diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Experiment/Sidebar/Basic/Groups/ExperimentalData.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Experiment/Sidebar/Basic/Groups/ExperimentalData.qml index 50b55e95..cc6ecbf5 100644 --- a/src_qt6/EasyReflectometryApp/Gui/Pages/Experiment/Sidebar/Basic/Groups/ExperimentalData.qml +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Experiment/Sidebar/Basic/Groups/ExperimentalData.qml @@ -16,7 +16,7 @@ EaElements.GroupBox { EaElements.SideBarButton { enabled: true - + wide: true fontIcon: "upload" text: qsTr("Import data from local drive") @@ -29,12 +29,6 @@ EaElements.GroupBox { source: '../Popups/OpenExperimentFile.qml' } } - - EaElements.SideBarButton { - fontIcon: "arrow-circle-right" - text: qsTr("Continue without experiment data") - Component.onCompleted: Globals.Variables.continueWithoutExperimentDataButton = this - } } Component.onCompleted: Globals.Variables.experimentalDataGroup = this diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Experiment/Sidebar/Basic/Groups/InstrumentParameters.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Experiment/Sidebar/Basic/Groups/InstrumentParameters.qml index 7913ca8b..76ba8e36 100644 --- a/src_qt6/EasyReflectometryApp/Gui/Pages/Experiment/Sidebar/Basic/Groups/InstrumentParameters.qml +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Experiment/Sidebar/Basic/Groups/InstrumentParameters.qml @@ -10,7 +10,7 @@ import Gui.Globals as Globals EaElements.GroupBox { title: qsTr("Instrumental parameters") visible: Globals.BackendWrapper.experimentExperimentalData - collapsed: true + collapsed: false Row { spacing: EaStyle.Sizes.fontPixelSize diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Experiment/Sidebar/Basic/Groups/QRange.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Experiment/Sidebar/Basic/Groups/QRange.qml index 93bbf287..a18c88c6 100644 --- a/src_qt6/EasyReflectometryApp/Gui/Pages/Experiment/Sidebar/Basic/Groups/QRange.qml +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Experiment/Sidebar/Basic/Groups/QRange.qml @@ -10,7 +10,7 @@ import Gui.Globals as Globals EaElements.GroupBox { title: qsTr("Q range of interest") - visible: Globals.BackendWrapper.experimentExperimentalData + collapsed: false Row { spacing: EaStyle.Sizes.fontPixelSize * 0.5 @@ -20,7 +20,6 @@ EaElements.GroupBox { width: labelWidth() } EaElements.Parameter { - enabled: Globals.BackendWrapper.experimentExperimentalData width: textFieldWidth() units: "Å-1" text: Globals.BackendWrapper.experimentQMin.toFixed(3) @@ -33,7 +32,6 @@ EaElements.GroupBox { width: labelWidth() } EaElements.Parameter { - enabled: Globals.BackendWrapper.experimentExperimentalData width: textFieldWidth() units: "Å-1" text: Globals.BackendWrapper.experimentQMax.toFixed(3) @@ -46,7 +44,6 @@ EaElements.GroupBox { width: labelWidth() } EaElements.Parameter { - enabled: Globals.BackendWrapper.experimentExperimentalData width: textFieldWidth() text: Globals.BackendWrapper.experimentQResolution onEditingFinished: Globals.BackendWrapper.experimentSetQElements(text) diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Experiment/Sidebar/Basic/Layout.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Experiment/Sidebar/Basic/Layout.qml index 6fef4346..ca04829d 100644 --- a/src_qt6/EasyReflectometryApp/Gui/Pages/Experiment/Sidebar/Basic/Layout.qml +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Experiment/Sidebar/Basic/Layout.qml @@ -11,12 +11,10 @@ EaComponents.SideBarColumn { Groups.ExperimentalData{ enabled: Globals.BackendWrapper.analysisIsFitFinished } - - Groups.InstrumentParameters{ + Groups.QRange{ enabled: Globals.BackendWrapper.analysisIsFitFinished } - - Groups.QRange{ + Groups.InstrumentParameters{ enabled: Globals.BackendWrapper.analysisIsFitFinished } } diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Project/Layout.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Project/Layout.qml index 21151199..e4728e03 100644 --- a/src_qt6/EasyReflectometryApp/Gui/Pages/Project/Layout.qml +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Project/Layout.qml @@ -34,9 +34,7 @@ EaComponents.ContentPage { Loader { source: 'Sidebar/Basic/Layout.qml' } ] - continueButton.text: Globals.BackendWrapper.projectCreated ? - qsTr('Continue') : - qsTr('Continue without project') + continueButton.text: qsTr('Continue') continueButton.onClicked: { console.debug(`Clicking '${continueButton.text}' button ::: ${this}`) From 5d118900dc7e3ea12bc623fed5812f248a3e23af Mon Sep 17 00:00:00 2001 From: Andreas Pedersen Date: Thu, 7 Nov 2024 10:24:48 +0100 Subject: [PATCH 30/43] code cleaning --- src_qt6/EasyReflectometryApp/Backends/Py/plotting_1d.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src_qt6/EasyReflectometryApp/Backends/Py/plotting_1d.py b/src_qt6/EasyReflectometryApp/Backends/Py/plotting_1d.py index bb41c974..a504bd1c 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Py/plotting_1d.py +++ b/src_qt6/EasyReflectometryApp/Backends/Py/plotting_1d.py @@ -117,8 +117,6 @@ def sldMaxY(self): def sldMinY(self): return self.sld_data.y.min() - - @Property('QVariant', notify=chartRefsChanged) def chartRefs(self): return self._chartRefs From eb508b33935c1081ed347af794e10117737f8a44 Mon Sep 17 00:00:00 2001 From: Andreas Pedersen Date: Thu, 7 Nov 2024 10:55:39 +0100 Subject: [PATCH 31/43] advanced tab sample skeleton --- .../Pages/Experiment/Sidebar/Basic/Layout.qml | 3 - .../Gui/Pages/Sample/Layout.qml | 8 +- .../Sidebar/Advanced/Groups/Constraints.qml | 210 ++++++++++++++++++ .../Sidebar/Advanced}/Groups/QRange.qml | 0 .../Pages/Sample/Sidebar/Advanced/Layout.qml | 22 +- .../Gui/Pages/Sample/Sidebar/Basic/Layout.qml | 20 +- 6 files changed, 230 insertions(+), 33 deletions(-) create mode 100644 src_qt6/EasyReflectometryApp/Gui/Pages/Sample/Sidebar/Advanced/Groups/Constraints.qml rename src_qt6/EasyReflectometryApp/Gui/Pages/{Experiment/Sidebar/Basic => Sample/Sidebar/Advanced}/Groups/QRange.qml (100%) diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Experiment/Sidebar/Basic/Layout.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Experiment/Sidebar/Basic/Layout.qml index ca04829d..b30d6d99 100644 --- a/src_qt6/EasyReflectometryApp/Gui/Pages/Experiment/Sidebar/Basic/Layout.qml +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Experiment/Sidebar/Basic/Layout.qml @@ -11,9 +11,6 @@ EaComponents.SideBarColumn { Groups.ExperimentalData{ enabled: Globals.BackendWrapper.analysisIsFitFinished } - Groups.QRange{ - enabled: Globals.BackendWrapper.analysisIsFitFinished - } Groups.InstrumentParameters{ enabled: Globals.BackendWrapper.analysisIsFitFinished } diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/Layout.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/Layout.qml index e5712565..5dc96c1d 100644 --- a/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/Layout.qml +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/Layout.qml @@ -30,13 +30,13 @@ EaComponents.ContentPage { sideBar: EaComponents.SideBar { tabs: [ - EaElements.TabButton { text: qsTr('Basic controls') } -// EaElements.TabButton { text: qsTr('Advanced controls') } + EaElements.TabButton { text: qsTr('Basic controls') }, + EaElements.TabButton { text: qsTr('Advanced controls') } ] items: [ - Loader { source: 'Sidebar/Basic/Layout.qml' } - // Loader { source: 'Sidebar/Advanced/Layout.qml' } + Loader { source: 'Sidebar/Basic/Layout.qml' }, + Loader { source: 'Sidebar/Advanced/Layout.qml' } ] diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/Sidebar/Advanced/Groups/Constraints.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/Sidebar/Advanced/Groups/Constraints.qml new file mode 100644 index 00000000..47f9be49 --- /dev/null +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/Sidebar/Advanced/Groups/Constraints.qml @@ -0,0 +1,210 @@ +import QtQuick 2.13 +import QtQuick.Controls 2.13 +import QtQml.XmlListModel + +import easyApp.Gui.Style as EaStyle +import easyApp.Gui.Elements as EaElements +import easyApp.Gui.Components as EaComponents +import easyApp.Gui.Logic as EaLogic + +import Gui.Globals as Globals + +EaElements.GroupBox { + title: qsTr("Sample constraints") + enabled: true + last: false + +// ExComponents.AnalysisConstraints {} + + Column { + spacing: EaStyle.Sizes.fontPixelSize * 0.5 + + // Type 1 START + // Column { + + // EaElements.Label { + // enabled: false + // text: qsTr("Type 1") + // } + + // Grid { + // columns: 4 + // columnSpacing: EaStyle.Sizes.fontPixelSize * 0.5 + // rowSpacing: EaStyle.Sizes.fontPixelSize * 0.5 + // anchors.horizontalCenter: parent.horizontalCenter + // verticalItemAlignment: Grid.AlignVCenter + + // EaElements.ComboBox { + // id: dependentPar2 + // width: 359 + // currentIndex: -1 + // displayText: currentIndex === -1 ? "Select parameter" : currentText + // // textFormat: ExGlobals.Variables.iconifiedNames ? Text.RichText : Text.PlainText + // // elide: Text.ElideMiddle + // textRole: ExGlobals.Variables.iconifiedNames ? "iconified_label" : "label" + // model: XmlListModel { + // xml: ExGlobals.Constants.proxy.parameter.parametersAsXml + // query: "/root/item" + // XmlRole { name: "label"; query: "label/string()" } + // onXmlChanged: dependentParCurrentIndex2 = dependentPar2.currentIndex + // } + // onCurrentIndexChanged: { + // if (dependentPar2.currentIndex === -1 && model.count > 0) + // dependentPar2.currentIndex = dependentParCurrentIndex2 + // } + // } + + // EaElements.ComboBox { + // id: relationalOperator2 + // width: 47 + // currentIndex: 0 + // //model: [">", "<"] + // font.family: EaStyle.Fonts.iconsFamily + // model: XmlListModel { + // xml: ">\uf531<\uf536" + // query: "/root/item" + // XmlRole { name: "icon"; query: "icon/string()" } + // } + // } + + // EaElements.TextField { + // id: value2 + // width: 65 + // horizontalAlignment: Text.AlignRight + // text: "1.0000" + // } + + // EaElements.SideBarButton { + // id: addConstraint2 + // width: 35 + // fontIcon: "plus-circle" + // ToolTip.text: qsTr("Add numeric constraint for single parameter") + // onClicked: { + // ExGlobals.Constants.proxy.fitter.addConstraint( + // dependentPar2.currentIndex, + // relationalOperator2.currentText.replace("\uf531", ">").replace("\uf536", "<"), + // value2.text, + // "", + // -1 + // ) + // } + // } + // } + // } + // Type 1 END + + // Type 2 START + Column { + + EaElements.Label { + enabled: false + text: qsTr("Parameter-Parameter Constraints") + } + + Grid { + columns: 4 + columnSpacing: EaStyle.Sizes.fontPixelSize * 0.5 + rowSpacing: EaStyle.Sizes.fontPixelSize * 0.5 + verticalItemAlignment: Grid.AlignVCenter + + EaElements.ComboBox { + id: dependentPar + width: 359 + currentIndex: -1 + displayText: currentIndex === -1 ? "Select parameter" : currentText + // textFormat: ExGlobals.Variables.iconifiedNames ? Text.RichText : Text.PlainText + // elide: Text.ElideMiddle + textRole: ExGlobals.Variables.iconifiedNames ? "iconified_label" : "label" + model: XmlListModel { +// xml: ExGlobals.Constants.proxy.parameter.parametersAsXml + query: "/data/item" +// XmlRole { name: "label"; query: "label/string()" } +// onXmlChanged: dependentParCurrentIndex = dependentPar.currentIndex + } + onCurrentIndexChanged: { + //print(currentText) + if (dependentPar.currentIndex === -1 && model.count > 0) + dependentPar.currentIndex = dependentParCurrentIndex + } + } + + EaElements.ComboBox { + id: relationalOperator + width: 47 + currentIndex: 0 + font.family: EaStyle.Fonts.iconsFamily + //model: ["=", ">", "<"] + model: XmlListModel { + // xml: "=\uf52c>\uf531<\uf536" + query: "/root/item" +// XmlRole { name: "icon"; query: "icon/string()" } + } + } + + Item { height: 1; width: 1 } + Item { height: 1; width: 1 } + + EaElements.ComboBox { + id: independentPar + width: dependentPar.width + currentIndex: -1 + displayText: currentIndex === -1 ? "Select parameter" : currentText + // textFormat: ExGlobals.Variables.iconifiedNames ? Text.RichText : Text.PlainText + // elide: Text.ElideMiddle + textRole: ExGlobals.Variables.iconifiedNames ? "iconified_label" : "label" + model: XmlListModel { +// xml: ExGlobals.Constants.proxy.parameter.parametersAsXml + query: "/data/item" +// XmlRole { name: "label"; query: "label/string()" } + // XmlRole { name: "iconified_label"; query: "iconified_label_with_index/string()" } +// onXmlChanged: independentParCurrentIndex = independentPar.currentIndex + } + onCurrentIndexChanged: { + if (independentPar.currentIndex === -1 && model.count > 0) + independentPar.currentIndex = independentParCurrentIndex + } + } + + EaElements.ComboBox { + id: arithmeticOperator + width: relationalOperator.width + currentIndex: 0 + font.family: EaStyle.Fonts.iconsFamily + //model: ["", "*", "/", "+", "-"] + //model: ["\uf00d", "\uf529", "\uf067", "\uf068"] + model: XmlListModel { +// xml: "*\uf00d/\uf529+\uf067-\uf068" + query: "/root/item" +// XmlRole { name: "icon"; query: "icon/string()" } + } + } + + EaElements.TextField { + id: value + width: 65 + horizontalAlignment: Text.AlignRight + text: "1.0000" + } + + EaElements.SideBarButton { + id: addConstraint + width: 35 + fontIcon: "plus-circle" + ToolTip.text: qsTr("Add constraint between two parameters") + onClicked: { + ExGlobals.Constants.proxy.parameter.addConstraint( + dependentPar.currentIndex, + relationalOperator.currentText.replace("\uf52c", "=").replace("\uf531", ">").replace("\uf536", "<"), + value.text, + arithmeticOperator.currentText.replace("\uf00d", "*").replace("\uf529", "/").replace("\uf067", "+").replace("\uf068", "-"), + independentPar.currentIndex + ) + } + } + } + } + // Type 2 END + + } +} + diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Experiment/Sidebar/Basic/Groups/QRange.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/Sidebar/Advanced/Groups/QRange.qml similarity index 100% rename from src_qt6/EasyReflectometryApp/Gui/Pages/Experiment/Sidebar/Basic/Groups/QRange.qml rename to src_qt6/EasyReflectometryApp/Gui/Pages/Sample/Sidebar/Advanced/Groups/QRange.qml diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/Sidebar/Advanced/Layout.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/Sidebar/Advanced/Layout.qml index 0fbbee29..5824765a 100644 --- a/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/Sidebar/Advanced/Layout.qml +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/Sidebar/Advanced/Layout.qml @@ -1,16 +1,21 @@ -import QtQuick 2.13 -import QtQuick.Controls 2.13 -import QtQML.XmlListModel 2.13 +import QtQuick 2.14 +import QtQuick.Controls 2.14 +//import QtQml.XmlListModel -import easyApp.Gui.Style 1.0 as EaStyle -import easyApp.Gui.Elements 1.0 as EaElements +//import easyApp.Gui.Style 1.0 as EaStyle import easyApp.Gui.Components 1.0 as EaComponents -import Gui.Globals 1.0 as ExGlobals -import Gui.Components 1.0 as ExComponents +import Gui.Globals as Globals +import "./Groups" as Groups EaComponents.SideBarColumn { - + Groups.QRange{ + enabled: Globals.BackendWrapper.analysisIsFitFinished + } + Groups.Constraints{ + enabled: Globals.BackendWrapper.analysisIsFitFinished + } +/* property int independentParCurrentIndex: 0 property int dependentParCurrentIndex: 0 property int dependentParCurrentIndex2: 0 @@ -271,4 +276,5 @@ EaComponents.SideBarColumn { onToggled: ExGlobals.Constants.proxy.simulation.setPlotRQ4() } } + */ } diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/Sidebar/Basic/Layout.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/Sidebar/Basic/Layout.qml index cec36979..f13c8080 100644 --- a/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/Sidebar/Basic/Layout.qml +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/Sidebar/Basic/Layout.qml @@ -1,42 +1,26 @@ import QtQuick 2.14 import QtQuick.Controls 2.14 -import QtQml.XmlListModel +//import QtQml.XmlListModel -import easyApp.Gui.Style 1.0 as EaStyle +//import easyApp.Gui.Style 1.0 as EaStyle import easyApp.Gui.Components 1.0 as EaComponents import Gui.Globals as Globals import "./Groups" as Groups - EaComponents.SideBarColumn { Groups.MaterialEditor{ enabled: Globals.BackendWrapper.analysisIsFitFinished } - Groups.ModelSelector{ enabled: Globals.BackendWrapper.analysisIsFitFinished } - Groups.ModelEditor { id: modelEditor enabled: Globals.BackendWrapper.analysisIsFitFinished } - Groups.AssemblyEditor{ id: assemblyEditor enabled: Globals.BackendWrapper.analysisIsFitFinished } - - - // Logic - - function labelWidth() { - return (EaStyle.Sizes.sideBarContentWidth - EaStyle.Sizes.fontPixelSize * 2.5 - textFieldWidth() * 3) / 3 - } - - function textFieldWidth() { - return EaStyle.Sizes.fontPixelSize * 7.0 - } - } From 947330ab35dab432ca78c5bf584753edd282aac4 Mon Sep 17 00:00:00 2001 From: Andreas Pedersen Date: Thu, 7 Nov 2024 13:57:36 +0100 Subject: [PATCH 32/43] skeleton constraints --- .../Backends/Mock/Sample.qml | 22 +++ .../Gui/Globals/BackendWrapper.qml | 6 + .../Sidebar/Advanced/Groups/Constraints.qml | 137 ++---------------- .../Sample/Sidebar/Advanced/Groups/QRange.qml | 1 - .../Gui/Pages/Sample/Sidebar/Basic/Layout.qml | 2 - 5 files changed, 44 insertions(+), 124 deletions(-) diff --git a/src_qt6/EasyReflectometryApp/Backends/Mock/Sample.qml b/src_qt6/EasyReflectometryApp/Backends/Mock/Sample.qml index a0d303c8..c6249883 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Mock/Sample.qml +++ b/src_qt6/EasyReflectometryApp/Backends/Mock/Sample.qml @@ -264,4 +264,26 @@ QtObject { function moveSelectedLayerDown() { console.debug(`moveSelectedLayerDown ${currentLayerIndex}`) } + + // Constraints + readonly property var parameterNames: [ + 'parameter 1', + 'parameter 2', + 'parameter 3' + ] + readonly property var relationOperators: [ + '=', + '<', + '>' + ] + readonly property var arithmicOperators: [ + '+', + '-', + '*', + '/' + ] + + function addConstraint(value1, value2, value3, value4, value5) { + console.debug(`addConstraint ${value1} ${value2} ${value3} ${value4} ${value5}`) + } } diff --git a/src_qt6/EasyReflectometryApp/Gui/Globals/BackendWrapper.qml b/src_qt6/EasyReflectometryApp/Gui/Globals/BackendWrapper.qml index 8bd83d40..26b86b31 100644 --- a/src_qt6/EasyReflectometryApp/Gui/Globals/BackendWrapper.qml +++ b/src_qt6/EasyReflectometryApp/Gui/Globals/BackendWrapper.qml @@ -150,6 +150,12 @@ QtObject { function sampleSetCurrentLayerAPM(value) { activeBackend.sample.setCurrentLayerAPM(value) } function sampleSetCurrentLayerSolvation(value) { activeBackend.sample.setCurrentLayerSolvation(value) } + // Constraints + readonly property var sampleParameterNames: activeBackend.sample.parameterNames + readonly property var sampleRelationOperators: activeBackend.sample.relationOperators + readonly property var sampleArithmicOperators: activeBackend.sample.arithmicOperators + + function sampleAddConstraint(value1, value2, value3, value4, value5) { activeBackend.sample.addConstraint(value1, value2, value3, value4, value5) } ////////////////// // Experiment page diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/Sidebar/Advanced/Groups/Constraints.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/Sidebar/Advanced/Groups/Constraints.qml index 47f9be49..b3a55096 100644 --- a/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/Sidebar/Advanced/Groups/Constraints.qml +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/Sidebar/Advanced/Groups/Constraints.qml @@ -14,86 +14,11 @@ EaElements.GroupBox { enabled: true last: false -// ExComponents.AnalysisConstraints {} +// property int independentParCurrentIndex: 0 +// property int dependentParCurrentIndex: 0 Column { spacing: EaStyle.Sizes.fontPixelSize * 0.5 - - // Type 1 START - // Column { - - // EaElements.Label { - // enabled: false - // text: qsTr("Type 1") - // } - - // Grid { - // columns: 4 - // columnSpacing: EaStyle.Sizes.fontPixelSize * 0.5 - // rowSpacing: EaStyle.Sizes.fontPixelSize * 0.5 - // anchors.horizontalCenter: parent.horizontalCenter - // verticalItemAlignment: Grid.AlignVCenter - - // EaElements.ComboBox { - // id: dependentPar2 - // width: 359 - // currentIndex: -1 - // displayText: currentIndex === -1 ? "Select parameter" : currentText - // // textFormat: ExGlobals.Variables.iconifiedNames ? Text.RichText : Text.PlainText - // // elide: Text.ElideMiddle - // textRole: ExGlobals.Variables.iconifiedNames ? "iconified_label" : "label" - // model: XmlListModel { - // xml: ExGlobals.Constants.proxy.parameter.parametersAsXml - // query: "/root/item" - // XmlRole { name: "label"; query: "label/string()" } - // onXmlChanged: dependentParCurrentIndex2 = dependentPar2.currentIndex - // } - // onCurrentIndexChanged: { - // if (dependentPar2.currentIndex === -1 && model.count > 0) - // dependentPar2.currentIndex = dependentParCurrentIndex2 - // } - // } - - // EaElements.ComboBox { - // id: relationalOperator2 - // width: 47 - // currentIndex: 0 - // //model: [">", "<"] - // font.family: EaStyle.Fonts.iconsFamily - // model: XmlListModel { - // xml: ">\uf531<\uf536" - // query: "/root/item" - // XmlRole { name: "icon"; query: "icon/string()" } - // } - // } - - // EaElements.TextField { - // id: value2 - // width: 65 - // horizontalAlignment: Text.AlignRight - // text: "1.0000" - // } - - // EaElements.SideBarButton { - // id: addConstraint2 - // width: 35 - // fontIcon: "plus-circle" - // ToolTip.text: qsTr("Add numeric constraint for single parameter") - // onClicked: { - // ExGlobals.Constants.proxy.fitter.addConstraint( - // dependentPar2.currentIndex, - // relationalOperator2.currentText.replace("\uf531", ">").replace("\uf536", "<"), - // value2.text, - // "", - // -1 - // ) - // } - // } - // } - // } - // Type 1 END - - // Type 2 START Column { EaElements.Label { @@ -112,20 +37,11 @@ EaElements.GroupBox { width: 359 currentIndex: -1 displayText: currentIndex === -1 ? "Select parameter" : currentText - // textFormat: ExGlobals.Variables.iconifiedNames ? Text.RichText : Text.PlainText - // elide: Text.ElideMiddle - textRole: ExGlobals.Variables.iconifiedNames ? "iconified_label" : "label" - model: XmlListModel { -// xml: ExGlobals.Constants.proxy.parameter.parametersAsXml - query: "/data/item" -// XmlRole { name: "label"; query: "label/string()" } -// onXmlChanged: dependentParCurrentIndex = dependentPar.currentIndex - } - onCurrentIndexChanged: { - //print(currentText) - if (dependentPar.currentIndex === -1 && model.count > 0) - dependentPar.currentIndex = dependentParCurrentIndex - } + model: Globals.BackendWrapper.sampleParameterNames + // onCurrentIndexChanged: { + // if (dependentPar.currentIndex === -1 && model.count > 0) + // dependentPar.currentIndex = dependentParCurrentIndex + // } } EaElements.ComboBox { @@ -133,12 +49,7 @@ EaElements.GroupBox { width: 47 currentIndex: 0 font.family: EaStyle.Fonts.iconsFamily - //model: ["=", ">", "<"] - model: XmlListModel { - // xml: "=\uf52c>\uf531<\uf536" - query: "/root/item" -// XmlRole { name: "icon"; query: "icon/string()" } - } + model: Globals.BackendWrapper.sampleRelationOperators } Item { height: 1; width: 1 } @@ -149,20 +60,11 @@ EaElements.GroupBox { width: dependentPar.width currentIndex: -1 displayText: currentIndex === -1 ? "Select parameter" : currentText - // textFormat: ExGlobals.Variables.iconifiedNames ? Text.RichText : Text.PlainText - // elide: Text.ElideMiddle - textRole: ExGlobals.Variables.iconifiedNames ? "iconified_label" : "label" - model: XmlListModel { -// xml: ExGlobals.Constants.proxy.parameter.parametersAsXml - query: "/data/item" -// XmlRole { name: "label"; query: "label/string()" } - // XmlRole { name: "iconified_label"; query: "iconified_label_with_index/string()" } -// onXmlChanged: independentParCurrentIndex = independentPar.currentIndex - } - onCurrentIndexChanged: { - if (independentPar.currentIndex === -1 && model.count > 0) - independentPar.currentIndex = independentParCurrentIndex - } + model: Globals.BackendWrapper.sampleParameterNames +// onCurrentIndexChanged: { +// if (independentPar.currentIndex === -1 && model.count > 0) +// independentPar.currentIndex = independentParCurrentIndex +// } } EaElements.ComboBox { @@ -170,13 +72,7 @@ EaElements.GroupBox { width: relationalOperator.width currentIndex: 0 font.family: EaStyle.Fonts.iconsFamily - //model: ["", "*", "/", "+", "-"] - //model: ["\uf00d", "\uf529", "\uf067", "\uf068"] - model: XmlListModel { -// xml: "*\uf00d/\uf529+\uf067-\uf068" - query: "/root/item" -// XmlRole { name: "icon"; query: "icon/string()" } - } + model: Globals.BackendWrapper.sampleArithmicOperators } EaElements.TextField { @@ -188,11 +84,12 @@ EaElements.GroupBox { EaElements.SideBarButton { id: addConstraint + enabled: ( dependentPar.currentIndex !== -1 && independentPar.currentIndex !== -1 && independentPar.currentIndex !== dependentPar.currentIndex ) width: 35 fontIcon: "plus-circle" ToolTip.text: qsTr("Add constraint between two parameters") onClicked: { - ExGlobals.Constants.proxy.parameter.addConstraint( + Globals.BackendWrapper.sampleAddConstraint( dependentPar.currentIndex, relationalOperator.currentText.replace("\uf52c", "=").replace("\uf531", ">").replace("\uf536", "<"), value.text, @@ -203,8 +100,6 @@ EaElements.GroupBox { } } } - // Type 2 END - } } diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/Sidebar/Advanced/Groups/QRange.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/Sidebar/Advanced/Groups/QRange.qml index a18c88c6..cf0da881 100644 --- a/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/Sidebar/Advanced/Groups/QRange.qml +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/Sidebar/Advanced/Groups/QRange.qml @@ -4,7 +4,6 @@ import QtQuick.Controls 2.13 import easyApp.Gui.Style as EaStyle import easyApp.Gui.Elements as EaElements import easyApp.Gui.Components as EaComponents -import easyApp.Gui.Logic as EaLogic import Gui.Globals as Globals diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/Sidebar/Basic/Layout.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/Sidebar/Basic/Layout.qml index f13c8080..b1ba3525 100644 --- a/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/Sidebar/Basic/Layout.qml +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/Sidebar/Basic/Layout.qml @@ -1,8 +1,6 @@ import QtQuick 2.14 import QtQuick.Controls 2.14 -//import QtQml.XmlListModel -//import easyApp.Gui.Style 1.0 as EaStyle import easyApp.Gui.Components 1.0 as EaComponents import Gui.Globals as Globals From 48384e80b050d05238bd3cc7ce110f2be18dfca2 Mon Sep 17 00:00:00 2001 From: Andreas Pedersen Date: Thu, 7 Nov 2024 15:30:36 +0100 Subject: [PATCH 33/43] Q range to sample logic --- .../Backends/Mock/Experiment.qml | 14 ---- .../Backends/Mock/Sample.qml | 16 +++++ .../Backends/Py/experiment.py | 50 ++++++-------- .../Backends/Py/logic/models.py | 8 +-- .../Backends/Py/py_backend.py | 4 +- .../Backends/Py/sample.py | 65 ++++++++++++++++--- .../Gui/Globals/BackendWrapper.qml | 14 ++-- .../Sample/Sidebar/Advanced/Groups/QRange.qml | 12 ++-- 8 files changed, 112 insertions(+), 71 deletions(-) diff --git a/src_qt6/EasyReflectometryApp/Backends/Mock/Experiment.qml b/src_qt6/EasyReflectometryApp/Backends/Mock/Experiment.qml index 9fd8382e..6bdbb428 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Mock/Experiment.qml +++ b/src_qt6/EasyReflectometryApp/Backends/Mock/Experiment.qml @@ -8,10 +8,6 @@ QtObject { property double background: 2. property string resolution: '3.00' - property double q_min: 4. - property double q_max: 5. - property int q_resolution: 6 - // Setters function setScaling(value) { console.debug(`setScaling ${value}`) @@ -23,16 +19,6 @@ QtObject { console.debug(`setResolution ${value}`) } - function setQMin(value) { - console.debug(`setQMin ${value}`) - } - function setQMax(value) { - console.debug(`setQMax ${value}`) - } - function setQElements(value) { - console.debug(`setQElements ${value}`) - } - function load(path) { console.debug(`Loading experiment from ${path}`) } diff --git a/src_qt6/EasyReflectometryApp/Backends/Mock/Sample.qml b/src_qt6/EasyReflectometryApp/Backends/Mock/Sample.qml index c6249883..8a3e55ff 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Mock/Sample.qml +++ b/src_qt6/EasyReflectometryApp/Backends/Mock/Sample.qml @@ -286,4 +286,20 @@ QtObject { function addConstraint(value1, value2, value3, value4, value5) { console.debug(`addConstraint ${value1} ${value2} ${value3} ${value4} ${value5}`) } + + // Q Range + property double q_min: 4. + property double q_max: 5. + property int q_resolution: 6 + + // Setters + function setQMin(value) { + console.debug(`setQMin ${value}`) + } + function setQMax(value) { + console.debug(`setQMax ${value}`) + } + function setQElements(value) { + console.debug(`setQElements ${value}`) + } } diff --git a/src_qt6/EasyReflectometryApp/Backends/Py/experiment.py b/src_qt6/EasyReflectometryApp/Backends/Py/experiment.py index e77a564a..2bda1ed2 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Py/experiment.py +++ b/src_qt6/EasyReflectometryApp/Backends/Py/experiment.py @@ -30,18 +30,6 @@ def background(self) -> float: def resolution(self) -> str: return self._model_logic.resolution_at_current_index - @Property(float, notify=experimentChanged) - def q_min(self) -> float: - return self._project_logic.q_min - - @Property(float, notify=experimentChanged) - def q_max(self) -> float: - return self._project_logic.q_max - - @Property(int, notify=experimentChanged) - def q_resolution(self) -> int: - return self._project_logic.q_resolution - @Property(bool, notify=experimentChanged) def experimentalData(self) -> bool: return self._project_logic.experimental_data_at_current_index @@ -61,25 +49,25 @@ def setBackground(self, new_value: float) -> None: if self._model_logic.set_background_at_current_index(new_value): self.experimentChanged.emit() - @Slot(float) - def setResolution(self, new_value: float) -> None: - if self._model_logic.set_resolution_at_current_index(new_value): - self.experimentChanged.emit() - - @Slot(float) - def setQMin(self, new_value: float) -> None: - if self._project_logic.set_q_min(new_value): - self.experimentChanged.emit() - - @Slot(float) - def setQMax(self, new_value: float) -> None: - if self._project_logic.set_q_max(new_value): - self.experimentChanged.emit() - - @Slot(int) - def setQElements(self, new_value: float) -> None: - if self._project_logic.set_q_resolution(new_value): - self.experimentChanged.emit() + # @Slot(float) + # def setResolution(self, new_value: float) -> None: + # if self._model_logic.set_resolution_at_current_index(new_value): + # self.experimentChanged.emit() + + # @Slot(float) + # def setQMin(self, new_value: float) -> None: + # if self._project_logic.set_q_min(new_value): + # self.experimentChanged.emit() + + # @Slot(float) + # def setQMax(self, new_value: float) -> None: + # if self._project_logic.set_q_max(new_value): + # self.experimentChanged.emit() + + # @Slot(int) + # def setQElements(self, new_value: float) -> None: + # if self._project_logic.set_q_resolution(new_value): + # self.experimentChanged.emit() # Actions @Slot(str) diff --git a/src_qt6/EasyReflectometryApp/Backends/Py/logic/models.py b/src_qt6/EasyReflectometryApp/Backends/Py/logic/models.py index fa53fd35..1d6063ac 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Py/logic/models.py +++ b/src_qt6/EasyReflectometryApp/Backends/Py/logic/models.py @@ -52,14 +52,14 @@ def set_name_at_current_index(self, new_value: str) -> bool: return False def set_scaling_at_current_index(self, new_value: str) -> bool: - if self._models[self.index].scale.value != new_value: - self._models[self.index].scale.value = new_value + if self._models[self.index].scale.value != float(new_value): + self._models[self.index].scale.value = float(new_value) return True return False def set_background_at_current_index(self, new_value: str) -> bool: - if self._models[self.index].background.value != new_value: - self._models[self.index].background.value = new_value + if self._models[self.index].background.value != float(new_value): + self._models[self.index].background.value = float(new_value) return True return False diff --git a/src_qt6/EasyReflectometryApp/Backends/Py/py_backend.py b/src_qt6/EasyReflectometryApp/Backends/Py/py_backend.py index 64cfb6cc..8133edd4 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Py/py_backend.py +++ b/src_qt6/EasyReflectometryApp/Backends/Py/py_backend.py @@ -115,11 +115,13 @@ def _relay_sample_page_sample_changed(self): self._status.statusChanged.emit() def _relay_experiment_page_experiment_changed(self): - self._status.statusChanged.emit() + self._analysis._clearCacheAndEmitParametersChanged() self._analysis.experimentsChanged.emit() + self._status.statusChanged.emit() def _relay_analysis_page(self): self._status.statusChanged.emit() + self._experiment.experimentChanged.emit() def _refresh_plots(self): self._plotting.sampleChartRangesChanged.emit() diff --git a/src_qt6/EasyReflectometryApp/Backends/Py/sample.py b/src_qt6/EasyReflectometryApp/Backends/Py/sample.py index d598a233..df8240c1 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Py/sample.py +++ b/src_qt6/EasyReflectometryApp/Backends/Py/sample.py @@ -4,10 +4,11 @@ from PySide6.QtCore import Property from easyreflectometry import Project as ProjectLib -from .logic.material import Material -from .logic.models import Models -from .logic.assemblies import Assemblies -from .logic.layers import Layers +from .logic.material import Material as MaterialLogic +from .logic.assemblies import Assemblies as AssembliesLogic +from .logic.layers import Layers as LayersLogic +from .logic.models import Models as ModelsLogic +from .logic.project import Project as ProjectLogic class Sample(QObject): materialsChanged = Signal() @@ -25,16 +26,19 @@ class Sample(QObject): layersIndexChanged = Signal() layersTableChanged = Signal() + qRangeChanged = Signal() + externalRefreshPlot = Signal() externalSampleChanged = Signal() def __init__(self, project_lib: ProjectLib, parent=None): super().__init__(parent) self._project_lib = project_lib - self._material_logic = Material(project_lib) - self._models_logic = Models(project_lib) - self._assemblies_logic = Assemblies(project_lib) - self._layers_logic = Layers(project_lib) + self._material_logic = MaterialLogic(project_lib) + self._models_logic = ModelsLogic(project_lib) + self._assemblies_logic = AssembliesLogic(project_lib) + self._layers_logic = LayersLogic(project_lib) + self._project_logic = ProjectLogic(project_lib) self._chached_layers = None @@ -401,4 +405,47 @@ def moveSelectedLayerDown(self)-> None: def _clearCacheAndEmitLayersChanged(self): self._chached_layers = None - self.layersChange.emit() \ No newline at end of file + self.layersChange.emit() + + # # # + # Q Range + # # # + + @Property(float, notify=qRangeChanged) + def q_min(self) -> float: + return self._project_logic.q_min + + @Property(float, notify=qRangeChanged) + def q_max(self) -> float: + return self._project_logic.q_max + + @Property(int, notify=qRangeChanged) + def q_resolution(self) -> int: + return self._project_logic.q_resolution + + @Property(bool, notify=qRangeChanged) + def experimentalData(self) -> bool: + return self._project_logic.experimental_data_at_current_index + + # Setters + @Slot(int) + def setModelIndex(self, value: int) -> None: + self._models_logic.index = value + + @Slot(float) + def setQMin(self, new_value: float) -> None: + if self._project_logic.set_q_min(new_value): + self.qRangeChanged.emit() + self.externalRefreshPlot.emit() + + @Slot(float) + def setQMax(self, new_value: float) -> None: + if self._project_logic.set_q_max(new_value): + self.qRangeChanged.emit() + self.externalRefreshPlot.emit() + + @Slot(int) + def setQElements(self, new_value: float) -> None: + if self._project_logic.set_q_resolution(new_value): + self.qRangeChanged.emit() + self.externalRefreshPlot.emit() diff --git a/src_qt6/EasyReflectometryApp/Gui/Globals/BackendWrapper.qml b/src_qt6/EasyReflectometryApp/Gui/Globals/BackendWrapper.qml index 26b86b31..35bdac2c 100644 --- a/src_qt6/EasyReflectometryApp/Gui/Globals/BackendWrapper.qml +++ b/src_qt6/EasyReflectometryApp/Gui/Globals/BackendWrapper.qml @@ -157,6 +157,14 @@ QtObject { function sampleAddConstraint(value1, value2, value3, value4, value5) { activeBackend.sample.addConstraint(value1, value2, value3, value4, value5) } + // Q range + readonly property var sampleQMin: activeBackend.sample.q_min + function sampleSetQMin(value) { activeBackend.sample.setQMin(value) } + readonly property var sampleQMax: activeBackend.sample.q_max + function sampleSetQMax(value) { activeBackend.sample.setQMax(value) } + readonly property var sampleQResolution: activeBackend.sample.q_resolution + function sampleSetQElements(value) { activeBackend.sample.setQElements(value) } + ////////////////// // Experiment page ////////////////// @@ -168,12 +176,6 @@ QtObject { function experimentSetBackground(value) { activeBackend.experiment.setBackground(value) } readonly property var experimentResolution: activeBackend.experiment.resolution function experimentSetResolution(value) { activeBackend.experiment.setResolution(value) } - readonly property var experimentQMin: activeBackend.experiment.q_min - function experimentSetQMin(value) { activeBackend.experiment.setQMin(value) } - readonly property var experimentQMax: activeBackend.experiment.q_max - function experimentSetQMax(value) { activeBackend.experiment.setQMax(value) } - readonly property var experimentQResolution: activeBackend.experiment.q_resolution - function experimentSetQElements(value) { activeBackend.experiment.setQElements(value) } function experimentLoad(value) { activeBackend.experiment.load(value) } diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/Sidebar/Advanced/Groups/QRange.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/Sidebar/Advanced/Groups/QRange.qml index cf0da881..0aede6fe 100644 --- a/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/Sidebar/Advanced/Groups/QRange.qml +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/Sidebar/Advanced/Groups/QRange.qml @@ -21,8 +21,8 @@ EaElements.GroupBox { EaElements.Parameter { width: textFieldWidth() units: "Å-1" - text: Globals.BackendWrapper.experimentQMin.toFixed(3) - onEditingFinished: Globals.BackendWrapper.experimentSetQMin(text) + text: Globals.BackendWrapper.sampleQMin.toFixed(3) + onEditingFinished: Globals.BackendWrapper.sampleSetQMin(text) } EaComponents.TableViewLabel{ @@ -33,8 +33,8 @@ EaElements.GroupBox { EaElements.Parameter { width: textFieldWidth() units: "Å-1" - text: Globals.BackendWrapper.experimentQMax.toFixed(3) - onEditingFinished: Globals.BackendWrapper.experimentSetQMax(text) + text: Globals.BackendWrapper.sampleQMax.toFixed(3) + onEditingFinished: Globals.BackendWrapper.sampleSetQMax(text) } EaComponents.TableViewLabel{ @@ -44,8 +44,8 @@ EaElements.GroupBox { } EaElements.Parameter { width: textFieldWidth() - text: Globals.BackendWrapper.experimentQResolution - onEditingFinished: Globals.BackendWrapper.experimentSetQElements(text) + text: Globals.BackendWrapper.sampleQResolution + onEditingFinished: Globals.BackendWrapper.sampleSetQElements(text) } } From bdf009ceb34ef6dd773647e8702e269842c4c04c Mon Sep 17 00:00:00 2001 From: Andreas Pedersen Date: Thu, 7 Nov 2024 15:32:37 +0100 Subject: [PATCH 34/43] code cleaning --- .../Gui/Pages/Analysis/Sidebar/Basic/Groups/Fittables.qml | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Groups/Fittables.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Groups/Fittables.qml index 88606f81..6ca4d3ef 100644 --- a/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Groups/Fittables.qml +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Groups/Fittables.qml @@ -215,18 +215,12 @@ EaElements.GroupBox { EaComponents.TableViewLabel { width: EaStyle.Sizes.fontPixelSize * 5 text: Globals.BackendWrapper.analysisFitableParameters[index].name -// textFormat: EaGlobals.Vars.paramNameFormat === EaGlobals.Vars.PlainShortWithLabels || -// EaGlobals.Vars.paramNameFormat === EaGlobals.Vars.PlainFullWithLabels ? -// Text.PlainText : -// Text.RichText -// elide: Text.ElideMiddle // NEED FIX: Doesn't work with textFormat: Text.RichText ToolTip.text: textFormat === Text.PlainText ? text : '' } EaComponents.TableViewParameter { id: valueColumn selected: index === Globals.BackendWrapper.analysisCurrentParameterIndex -// fit: Globals.BackendWrapper.analysisFitableParameters[index].fit text: EaLogic.Utils.toDefaultPrecision(Globals.BackendWrapper.analysisFitableParameters[index].value) onEditingFinished: { focus = false @@ -243,9 +237,7 @@ EaElements.GroupBox { } EaComponents.TableViewLabel { -// elide: Text.ElideNone text: EaLogic.Utils.toDefaultPrecision(Globals.BackendWrapper.analysisFitableParameters[index].error) - //text: Number(Globals.BackendWrapper.analysisFitableParameters[index].error).toExponential(2) } EaComponents.TableViewParameter { From 86a173bab5af6f0bd9092596e9e0c2c6e8bfc6d8 Mon Sep 17 00:00:00 2001 From: Andreas Pedersen Date: Fri, 8 Nov 2024 10:41:41 +0100 Subject: [PATCH 35/43] constraints seem to work --- .../Backends/Mock/Sample.qml | 13 +---- .../Backends/Py/logic/parameters.py | 42 +++++++++++++++ .../Backends/Py/sample.py | 30 ++++++++++- .../Sidebar/Advanced/Groups/Constraints.qml | 52 +++++++++++-------- 4 files changed, 103 insertions(+), 34 deletions(-) diff --git a/src_qt6/EasyReflectometryApp/Backends/Mock/Sample.qml b/src_qt6/EasyReflectometryApp/Backends/Mock/Sample.qml index 8a3e55ff..8f280388 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Mock/Sample.qml +++ b/src_qt6/EasyReflectometryApp/Backends/Mock/Sample.qml @@ -271,17 +271,8 @@ QtObject { 'parameter 2', 'parameter 3' ] - readonly property var relationOperators: [ - '=', - '<', - '>' - ] - readonly property var arithmicOperators: [ - '+', - '-', - '*', - '/' - ] + readonly property var relationOperators: ['=', '<', '>'] + readonly property var arithmicOperators: ['', '*', '/', '+', '-'] function addConstraint(value1, value2, value3, value4, value5) { console.debug(`addConstraint ${value1} ${value2} ${value3} ${value4} ${value5}`) diff --git a/src_qt6/EasyReflectometryApp/Backends/Py/logic/parameters.py b/src_qt6/EasyReflectometryApp/Backends/Py/logic/parameters.py index e875f213..14495e4c 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Py/logic/parameters.py +++ b/src_qt6/EasyReflectometryApp/Backends/Py/logic/parameters.py @@ -1,5 +1,7 @@ from easyscience.Objects.new_variable import Parameter from easyscience import global_object +from easyscience.Constraints import ObjConstraint +from easyscience.Constraints import NumericConstraint from easyreflectometry import Project as ProjectLib from typing import List @@ -80,6 +82,46 @@ def set_current_parameter_fit(self, new_value: str) -> bool: return True return False + ### Constraints + def constraint_relations(self) -> List[str]: + return [ '=', '<', '>' ] + + def constraint_arithmetic(self) -> List[str]: + return [ '', '*', '/', '+', '-'] + + def add_constraint( + self, + dependent_idx: int, + relational_operator: str, + value: float, + arithmetic_operator: str, + independent_idx: int + ) -> None: + + independent = self._project_lib.parameters[independent_idx] + dependent = self._project_lib.parameters[dependent_idx] + + if arithmetic_operator != "" and independent_idx > -1: + constaint = ObjConstraint( + dependent_obj=dependent, + operator=str(float(value)) + arithmetic_operator, + independent_obj=independent + ) + elif arithmetic_operator == "" and independent_idx == -1: + constaint = NumericConstraint( + dependent_obj=dependent, + operator=relational_operator.replace("=", "=="), + value=float(value) + ) + else: + print("Failed to add constraint: Unsupported type") + return + # print(c) + independent.user_constraints[dependent.name] = constaint + constaint() + + print(f"{dependent_idx}, {relational_operator}, {value}, {arithmetic_operator}, {independent_idx}") + def _from_parameters_to_list_of_dicts(parameters: List[Parameter], model_unique_name: str) -> list[dict[str, str]]: parameter_list = [] for parameter in parameters: diff --git a/src_qt6/EasyReflectometryApp/Backends/Py/sample.py b/src_qt6/EasyReflectometryApp/Backends/Py/sample.py index df8240c1..23af8226 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Py/sample.py +++ b/src_qt6/EasyReflectometryApp/Backends/Py/sample.py @@ -9,6 +9,7 @@ from .logic.layers import Layers as LayersLogic from .logic.models import Models as ModelsLogic from .logic.project import Project as ProjectLogic +from .logic.parameters import Parameters as ParametersLogic class Sample(QObject): materialsChanged = Signal() @@ -39,6 +40,7 @@ def __init__(self, project_lib: ProjectLib, parent=None): self._assemblies_logic = AssembliesLogic(project_lib) self._layers_logic = LayersLogic(project_lib) self._project_logic = ProjectLogic(project_lib) + self._paramters_logic = ParametersLogic(project_lib) self._chached_layers = None @@ -406,11 +408,35 @@ def moveSelectedLayerDown(self)-> None: def _clearCacheAndEmitLayersChanged(self): self._chached_layers = None self.layersChange.emit() - + # # # - # Q Range + # Constraints # # # + @Property('QVariantList', notify=layersChange) + def parameterNames(self) -> list[dict[str, str]]: + return [parameter['name'] for parameter in self._paramters_logic.parameters] + + @Property('QVariantList', notify=layersChange) + def relationOperators(self) -> list[str]: + return self._paramters_logic.constraint_relations() + @Property('QVariantList', notify=layersChange) + def arithmicOperators(self) -> list[str]: + return self._paramters_logic.constraint_arithmetic() + + @Slot(str, str, str, str, str) + def addConstraint(self, value1: str, value2: str, value3: str, value4: str, value5: str) -> None: + self._paramters_logic.add_constraint( + dependent_idx=int(value1), + relational_operator=value2, + value=float(value3), + arithmetic_operator=value4, + independent_idx=int(value5) + ) + + # # # + # Q Range + # # # @Property(float, notify=qRangeChanged) def q_min(self) -> float: return self._project_logic.q_min diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/Sidebar/Advanced/Groups/Constraints.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/Sidebar/Advanced/Groups/Constraints.qml index b3a55096..d49ce999 100644 --- a/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/Sidebar/Advanced/Groups/Constraints.qml +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/Sidebar/Advanced/Groups/Constraints.qml @@ -14,16 +14,13 @@ EaElements.GroupBox { enabled: true last: false -// property int independentParCurrentIndex: 0 -// property int dependentParCurrentIndex: 0 - Column { spacing: EaStyle.Sizes.fontPixelSize * 0.5 Column { EaElements.Label { enabled: false - text: qsTr("Parameter-Parameter Constraints") + text: qsTr("Numeric or Parameter-Parameter constraint") } Grid { @@ -36,12 +33,13 @@ EaElements.GroupBox { id: dependentPar width: 359 currentIndex: -1 - displayText: currentIndex === -1 ? "Select parameter" : currentText + displayText: currentIndex === -1 ? "Select dependent parameter" : currentText model: Globals.BackendWrapper.sampleParameterNames - // onCurrentIndexChanged: { - // if (dependentPar.currentIndex === -1 && model.count > 0) - // dependentPar.currentIndex = dependentParCurrentIndex - // } + onCurrentIndexChanged: { + independentPar.model = Globals.BackendWrapper.sampleParameterNames + independentPar.model[currentIndex] = 'Dependent parameter' + independentPar.currentIndex = -1 + } } EaElements.ComboBox { @@ -59,12 +57,20 @@ EaElements.GroupBox { id: independentPar width: dependentPar.width currentIndex: -1 - displayText: currentIndex === -1 ? "Select parameter" : currentText + displayText: currentIndex === -1 ? "Numeric constrain or select independent parameter" : currentText model: Globals.BackendWrapper.sampleParameterNames -// onCurrentIndexChanged: { -// if (independentPar.currentIndex === -1 && model.count > 0) -// independentPar.currentIndex = independentParCurrentIndex -// } + onCurrentIndexChanged: { + dependentPar.model = Globals.BackendWrapper.sampleParameterNames + if (currentIndex === -1){ + displayText: "Numeric constrain or select independent parameter" + arithmeticOperator.model = Globals.BackendWrapper.sampleArithmicOperators.slice(0,1) // no arithmetic operators + } + else{ + arithmeticOperator.model = Globals.BackendWrapper.sampleArithmicOperators.slice(1) // allow all arithmetic operators + dependentPar.model[currentIndex] = 'Independent parameter' + //arithmeticOperator.currentIndex = 0 + } + } } EaElements.ComboBox { @@ -72,7 +78,7 @@ EaElements.GroupBox { width: relationalOperator.width currentIndex: 0 font.family: EaStyle.Fonts.iconsFamily - model: Globals.BackendWrapper.sampleArithmicOperators + model: arithmeticOperator.model = Globals.BackendWrapper.sampleArithmicOperators.slice(0,1) } EaElements.TextField { @@ -90,12 +96,16 @@ EaElements.GroupBox { ToolTip.text: qsTr("Add constraint between two parameters") onClicked: { Globals.BackendWrapper.sampleAddConstraint( - dependentPar.currentIndex, - relationalOperator.currentText.replace("\uf52c", "=").replace("\uf531", ">").replace("\uf536", "<"), - value.text, - arithmeticOperator.currentText.replace("\uf00d", "*").replace("\uf529", "/").replace("\uf067", "+").replace("\uf068", "-"), - independentPar.currentIndex - ) + dependentPar.currentIndex, + relationalOperator.currentText.replace("\uf52c", "=").replace("\uf531", ">").replace("\uf536", "<"), + value.text, + arithmeticOperator.currentText.replace("\uf00d", "*").replace("\uf529", "/").replace("\uf067", "+").replace("\uf068", "-"), + independentPar.currentIndex + ) + independentPar.currentIndex = -1 + dependentPar.currentIndex = -1 + relationalOperator.currentIndex = 0 + arithmeticOperator.currentIndex = 0 } } } From 0610bfbe85ce01721607861e13499a1489e01fc1 Mon Sep 17 00:00:00 2001 From: Andreas Pedersen Date: Sat, 9 Nov 2024 10:19:00 +0100 Subject: [PATCH 36/43] load and save project --- .../Backends/Py/experiment.py | 26 ++++--------------- .../Backends/Py/logic/project.py | 2 +- .../Backends/Py/project.py | 4 +-- .../Backends/Py/py_backend.py | 14 +++++++--- 4 files changed, 19 insertions(+), 27 deletions(-) diff --git a/src_qt6/EasyReflectometryApp/Backends/Py/experiment.py b/src_qt6/EasyReflectometryApp/Backends/Py/experiment.py index 2bda1ed2..438c2c4c 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Py/experiment.py +++ b/src_qt6/EasyReflectometryApp/Backends/Py/experiment.py @@ -12,6 +12,7 @@ class Experiment(QObject): experimentChanged = Signal() + externalExperimentChanged = Signal() def __init__(self, project_lib: ProjectLib, parent=None): super().__init__(parent) @@ -43,34 +44,17 @@ def setModelIndex(self, value: int) -> None: def setScaling(self, new_value: float) -> None: if self._model_logic.set_scaling_at_current_index(new_value): self.experimentChanged.emit() + self.externalExperimentChanged.emit() @Slot(float) def setBackground(self, new_value: float) -> None: if self._model_logic.set_background_at_current_index(new_value): self.experimentChanged.emit() - - # @Slot(float) - # def setResolution(self, new_value: float) -> None: - # if self._model_logic.set_resolution_at_current_index(new_value): - # self.experimentChanged.emit() - - # @Slot(float) - # def setQMin(self, new_value: float) -> None: - # if self._project_logic.set_q_min(new_value): - # self.experimentChanged.emit() - - # @Slot(float) - # def setQMax(self, new_value: float) -> None: - # if self._project_logic.set_q_max(new_value): - # self.experimentChanged.emit() - - # @Slot(int) - # def setQElements(self, new_value: float) -> None: - # if self._project_logic.set_q_resolution(new_value): - # self.experimentChanged.emit() + self.externalExperimentChanged.emit() # Actions @Slot(str) def load(self, path: str) -> None: self._project_logic.load_experiment(generalizePath(path)) - self.experimentChanged.emit() \ No newline at end of file + self.experimentChanged.emit() + self.externalExperimentChanged.emit() diff --git a/src_qt6/EasyReflectometryApp/Backends/Py/logic/project.py b/src_qt6/EasyReflectometryApp/Backends/Py/logic/project.py index 4656543e..08920d0f 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Py/logic/project.py +++ b/src_qt6/EasyReflectometryApp/Backends/Py/logic/project.py @@ -93,7 +93,7 @@ def create(self) -> None: self._project_lib.save_as_json() def save(self) -> None: - self._project_lib.save_as_json() + self._project_lib.save_as_json(overwrite=True) def load(self, path: str) -> None: self._project_lib.load_from_json(path) diff --git a/src_qt6/EasyReflectometryApp/Backends/Py/project.py b/src_qt6/EasyReflectometryApp/Backends/Py/project.py index 18f12262..71e1e11e 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Py/project.py +++ b/src_qt6/EasyReflectometryApp/Backends/Py/project.py @@ -17,6 +17,7 @@ class Project(QObject): externalCreatedChanged = Signal() externalNameChanged = Signal() + externalProjectLoaded = Signal() def __init__(self, project_lib: ProjectLib, parent=None): super().__init__(parent) @@ -84,8 +85,7 @@ def load(self, path: str) -> None: self.nameChanged.emit() self.descriptionChanged.emit() self.locationChanged.emit() - self.externalCreatedChanged.emit() - self.externalNameChanged.emit() + self.externalProjectLoaded.emit() @Slot() def save(self) -> None: diff --git a/src_qt6/EasyReflectometryApp/Backends/Py/py_backend.py b/src_qt6/EasyReflectometryApp/Backends/Py/py_backend.py index 8133edd4..d7c23bd0 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Py/py_backend.py +++ b/src_qt6/EasyReflectometryApp/Backends/Py/py_backend.py @@ -87,14 +87,15 @@ def _connect_backend_parts(self) -> None: def _connect_project_page(self) -> None: self._project.externalNameChanged.connect(self._relay_project_page_name) self._project.externalCreatedChanged.connect(self._relay_project_page_created) + self._project.externalProjectLoaded.connect(self._relay_project_page_projec_loaded) def _connect_sample_page(self) -> None: self._sample.externalSampleChanged.connect(self._relay_sample_page_sample_changed) self._sample.externalRefreshPlot.connect(self._refresh_plots) def _connect_experiment_page(self) -> None: - self._experiment.experimentChanged.connect(self._relay_experiment_page_experiment_changed) - self._experiment.experimentChanged.connect(self._refresh_plots) + self._experiment.externalExperimentChanged.connect(self._relay_experiment_page_experiment_changed) + self._experiment.externalExperimentChanged.connect(self._refresh_plots) def _connect_analysis_page(self) -> None: self._analysis.externalMinimizerChanged.connect(self._relay_analysis_page) @@ -110,13 +111,20 @@ def _relay_project_page_name(self): def _relay_project_page_created(self): self._report.createdChanged.emit() + def _relay_project_page_projec_loaded(self): + self._experiment.experimentChanged.emit() + self._analysis.experimentsChanged.emit() + self._analysis._clearCacheAndEmitParametersChanged() + self._status.statusChanged.emit() + self._refresh_plots() + def _relay_sample_page_sample_changed(self): self._analysis._clearCacheAndEmitParametersChanged() self._status.statusChanged.emit() def _relay_experiment_page_experiment_changed(self): - self._analysis._clearCacheAndEmitParametersChanged() self._analysis.experimentsChanged.emit() + self._analysis._clearCacheAndEmitParametersChanged() self._status.statusChanged.emit() def _relay_analysis_page(self): From 8e498b90573b170aa66809cdb02807b62e0c9ddf Mon Sep 17 00:00:00 2001 From: Andreas Pedersen Date: Mon, 11 Nov 2024 19:21:25 +0100 Subject: [PATCH 37/43] fixing loading a json --- .../Backends/Py/logic/material.py | 5 +- .../Backends/Py/logic/parameters.py | 25 +++---- .../Backends/Py/plotting_1d.py | 12 +--- .../Backends/Py/py_backend.py | 8 ++- .../Backends/Py/sample.py | 67 ++++++++++--------- .../Sidebar/Basic/Groups/ModelSelector.qml | 2 +- 6 files changed, 62 insertions(+), 57 deletions(-) diff --git a/src_qt6/EasyReflectometryApp/Backends/Py/logic/material.py b/src_qt6/EasyReflectometryApp/Backends/Py/logic/material.py index 2a45d893..81cae509 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Py/logic/material.py +++ b/src_qt6/EasyReflectometryApp/Backends/Py/logic/material.py @@ -7,7 +7,10 @@ class Material: def __init__(self, project_lib: ProjectLib): self._project_lib = project_lib - self._materials = self._project_lib._materials + + @property + def _materials(self) -> MaterialCollection: + return self._project_lib._materials @property def index(self) -> int: diff --git a/src_qt6/EasyReflectometryApp/Backends/Py/logic/parameters.py b/src_qt6/EasyReflectometryApp/Backends/Py/logic/parameters.py index 14495e4c..8801f240 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Py/logic/parameters.py +++ b/src_qt6/EasyReflectometryApp/Backends/Py/logic/parameters.py @@ -126,16 +126,17 @@ def _from_parameters_to_list_of_dicts(parameters: List[Parameter], model_unique_ parameter_list = [] for parameter in parameters: path = global_object.map.find_path(model_unique_name, parameter.unique_name) - name = f"{global_object.map.get_item_by_key(path[-2]).name} {global_object.map.get_item_by_key(path[-1]).name}" - parameter_list.append( - { - 'name': name, - 'value': float(parameter.value), - 'error': float(parameter.variance), - 'max': float(parameter.max), - 'min': float(parameter.min), - 'units': parameter.unit, - 'fit': parameter.free - } - ) + if 0 < len(path): + name = f"{global_object.map.get_item_by_key(path[-2]).name} {global_object.map.get_item_by_key(path[-1]).name}" + parameter_list.append( + { + 'name': name, + 'value': float(parameter.value), + 'error': float(parameter.variance), + 'max': float(parameter.max), + 'min': float(parameter.min), + 'units': parameter.unit, + 'fit': parameter.free + } + ) return parameter_list \ No newline at end of file diff --git a/src_qt6/EasyReflectometryApp/Backends/Py/plotting_1d.py b/src_qt6/EasyReflectometryApp/Backends/Py/plotting_1d.py index a504bd1c..afce62e5 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Py/plotting_1d.py +++ b/src_qt6/EasyReflectometryApp/Backends/Py/plotting_1d.py @@ -24,8 +24,6 @@ def __init__(self, project_lib: ProjectLib, parent=None): self._project_lib = project_lib self._proxy = parent self._currentLib1d = 'QtCharts' - self._useAcceleration1d = True - self._model_index = 0 self._chartRefs = { 'QtCharts': { @@ -48,7 +46,7 @@ def __init__(self, project_lib: ProjectLib, parent=None): @property def sample_data(self) -> DataSet1D: try: - data = self._project_lib.sample_data_for_model_at_index() + data = self._project_lib.sample_data_for_model_at_index(self._project_lib.current_model_index) except IndexError: data = DataSet1D( name='Sample Data empty', @@ -60,7 +58,7 @@ def sample_data(self) -> DataSet1D: @property def sld_data(self) -> DataSet1D: try: - data = self._project_lib.sld_data_for_model_at_index() + data = self._project_lib.sld_data_for_model_at_index(self._project_lib.current_model_index) except IndexError: data = DataSet1D( name='SLD Data empty', @@ -72,7 +70,7 @@ def sld_data(self) -> DataSet1D: @property def experiment_data(self) -> DataSet1D: try: - data = self._project_lib.experimental_data_for_model_at_index() + data = self._project_lib.experimental_data_for_model_at_index(self._project_lib.current_model_index) except IndexError: data = DataSet1D( name='Experiment Data empty', @@ -121,10 +119,6 @@ def sldMinY(self): def chartRefs(self): return self._chartRefs - @Slot(int) - def setModelIndex(self, value: int) -> None: - self._model_index = value - @Slot(str, str, 'QVariant') def setQtChartsSerieRef(self, page:str, serie:str, ref: QObject): self._chartRefs['QtCharts'][page][serie] = ref diff --git a/src_qt6/EasyReflectometryApp/Backends/Py/py_backend.py b/src_qt6/EasyReflectometryApp/Backends/Py/py_backend.py index d7c23bd0..714d7ad9 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Py/py_backend.py +++ b/src_qt6/EasyReflectometryApp/Backends/Py/py_backend.py @@ -87,7 +87,7 @@ def _connect_backend_parts(self) -> None: def _connect_project_page(self) -> None: self._project.externalNameChanged.connect(self._relay_project_page_name) self._project.externalCreatedChanged.connect(self._relay_project_page_created) - self._project.externalProjectLoaded.connect(self._relay_project_page_projec_loaded) + self._project.externalProjectLoaded.connect(self._relay_project_page_project_loaded) def _connect_sample_page(self) -> None: self._sample.externalSampleChanged.connect(self._relay_sample_page_sample_changed) @@ -111,7 +111,11 @@ def _relay_project_page_name(self): def _relay_project_page_created(self): self._report.createdChanged.emit() - def _relay_project_page_projec_loaded(self): + def _relay_project_page_project_loaded(self): + self._sample.materialsTableChanged.emit() + self._sample.modelsTableChanged.emit() + self._sample.assembliesTableChanged.emit() + self._sample._clearCacheAndEmitLayersChanged() self._experiment.experimentChanged.emit() self._analysis.experimentsChanged.emit() self._analysis._clearCacheAndEmitParametersChanged() diff --git a/src_qt6/EasyReflectometryApp/Backends/Py/sample.py b/src_qt6/EasyReflectometryApp/Backends/Py/sample.py index 23af8226..0a84f4c1 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Py/sample.py +++ b/src_qt6/EasyReflectometryApp/Backends/Py/sample.py @@ -12,20 +12,21 @@ from .logic.parameters import Parameters as ParametersLogic class Sample(QObject): - materialsChanged = Signal() - materialIndexChanged = Signal() + #materialsChanged = Signal() + materialsTableChanged = Signal() + materialsIndexChanged = Signal() - modelsChange = Signal() + #modelsChange = Signal() modelsTableChanged = Signal() modelsIndexChanged = Signal() - assembliesChange = Signal() +# assembliesChange = Signal() assembliesTableChanged = Signal() assembliesIndexChanged = Signal() layersChange = Signal() layersIndexChanged = Signal() - layersTableChanged = Signal() +# layersTableChanged = Signal() qRangeChanged = Signal() @@ -40,7 +41,7 @@ def __init__(self, project_lib: ProjectLib, parent=None): self._assemblies_logic = AssembliesLogic(project_lib) self._layers_logic = LayersLogic(project_lib) self._project_logic = ProjectLogic(project_lib) - self._paramters_logic = ParametersLogic(project_lib) + self._parameters_logic = ParametersLogic(project_lib) self._chached_layers = None @@ -48,24 +49,24 @@ def __init__(self, project_lib: ProjectLib, parent=None): def connect_logic(self) -> None: self.assembliesIndexChanged.connect(self.layersConnectChanges) - self.layersTableChanged.connect(self.layersConnectChanges) +# self.layersTableChanged.connect(self.layersConnectChanges) # # # # Materials # # # - @Property('QVariantList', notify=materialIndexChanged) + @Property('QVariantList', notify=materialsTableChanged) def materials(self) -> list[dict[str, str]]: return self._material_logic.materials - @Property(int, notify=materialIndexChanged) + @Property(int, notify=materialsIndexChanged) def currentMaterialIndex(self) -> int: return self._material_logic.index - @Property('QVariantList', notify=materialIndexChanged) + @Property('QVariantList', notify=materialsTableChanged) def materialNames(self) -> list[str]: return self._material_logic.material_names - @Property(str, notify=materialIndexChanged) + @Property(str, notify=materialsIndexChanged) def currentMaterialName(self) -> str: return self._material_logic.name_at_current_index @@ -73,24 +74,24 @@ def currentMaterialName(self) -> str: @Slot(int) def setCurrentMaterialIndex(self, new_value: int) -> None: self._material_logic.index = new_value - self.materialIndexChanged.emit() + self.materialsIndexChanged.emit() @Slot(str) def setCurrentMaterialName(self, new_value: str) -> None: if self._material_logic.set_name_at_current_index(new_value): - self.materialsChanged.emit() + self.materialsTableChanged.emit() @Slot(float) def setCurrentMaterialSld(self, new_value: float) -> None: if self._material_logic.set_sld_at_current_index(new_value): - self.materialsChanged.emit() + self.materialsTableChanged.emit() self.externalRefreshPlot.emit() self.externalSampleChanged.emit() @Slot(float) def setCurrentMaterialISld(self, new_value: float) -> None: if self._material_logic.set_isld_at_current_index(new_value): - self.materialsChanged.emit() + self.materialsTableChanged.emit() self.externalRefreshPlot.emit() self.externalSampleChanged.emit() @@ -98,43 +99,43 @@ def setCurrentMaterialISld(self, new_value: float) -> None: @Slot(str) def removeMaterial(self, value: str) -> None: self._material_logic.remove_at_index(value) - self.materialsChanged.emit() + self.materialsTableChanged.emit() self.externalSampleChanged.emit() @Slot() def addNewMaterial(self) -> None: self._material_logic.add_new() - self.materialIndexChanged.emit() + self.materialsTableChanged.emit() self.externalSampleChanged.emit() @Slot() def duplicateSelectedMaterial(self) -> None: self._material_logic.duplicate_selected() - self.materialIndexChanged.emit() + self.materialsTableChanged.emit() self.externalSampleChanged.emit() @Slot() def moveSelectedMaterialUp(self) -> None: self._material_logic.move_selected_up() - self.materialIndexChanged.emit() + self.materialsTableChanged.emit() @Slot() def moveSelectedMaterialDown(self) -> None: self._material_logic.move_selected_down() - self.materialIndexChanged.emit() + self.materialsTableChanged.emit() # # # # Models # # # - @Property('QVariantList', notify=modelsChange) + @Property('QVariantList', notify=modelsTableChanged) def models(self) -> list[dict[str, str]]: return self._models_logic.models - @Property(int, notify=modelsChange) + @Property(int, notify=modelsIndexChanged) def currentModelIndex(self) -> int: return self._models_logic.index - @Property('QVariantList', notify=modelsChange) + @Property('QVariantList', notify=modelsTableChanged) def modelslNames(self) -> list[str]: return self._models_logic.models_names @@ -147,6 +148,8 @@ def currentModelName(self) -> str: def setCurrentModelIndex(self, new_value: int) -> None: self._project_lib.current_model_index = new_value self.modelsIndexChanged.emit() + self.assembliesTableChanged.emit() + self._clearCacheAndEmitLayersChanged() self.externalRefreshPlot.emit() @Slot(str) @@ -183,8 +186,8 @@ def moveSelectedModelDown(self)-> None: # # # # Assemblies # # # - def assembliesConnectChanges(self) -> None: - self.assembliesChange.emit() +# def assembliesConnectChanges(self) -> None: +# self.assembliesChange.emit() @Property('QVariantList', notify=assembliesTableChanged) def assemblies(self) -> list[dict[str, str]]: @@ -210,7 +213,7 @@ def currentAssemblyType(self) -> str: @Slot(int) def setCurrentAssemblyIndex(self, new_value: int) -> None: self._project_lib.current_assembly_index = new_value - self._clearCacheAndEmitLayersChanged() #self.layersTableChanged.emit() + self._clearCacheAndEmitLayersChanged() self.assembliesTableChanged.emit() self.assembliesIndexChanged.emit() @@ -222,14 +225,14 @@ def setCurrentAssemblyName(self, new_value: str) -> None: @Slot(str) def setCurrentAssemblyType(self, new_value: str) -> None: self._assemblies_logic.set_type_at_current_index(new_value) - self._clearCacheAndEmitLayersChanged() #self.layersTableChanged.emit() + self._clearCacheAndEmitLayersChanged() self.assembliesTableChanged.emit() self.assembliesIndexChanged.emit() self.externalRefreshPlot.emit() self.externalSampleChanged.emit() # Assembly specific - @Property(str, notify=assembliesChange) + @Property(str, notify=assembliesTableChanged) def currentAssemblyRepeatedLayerReptitions(self) -> str: return self._assemblies_logic.repetitions_at_current_index @@ -414,19 +417,19 @@ def _clearCacheAndEmitLayersChanged(self): # # # @Property('QVariantList', notify=layersChange) def parameterNames(self) -> list[dict[str, str]]: - return [parameter['name'] for parameter in self._paramters_logic.parameters] + return [parameter['name'] for parameter in self._parameters_logic.parameters] @Property('QVariantList', notify=layersChange) def relationOperators(self) -> list[str]: - return self._paramters_logic.constraint_relations() + return self._parameters_logic.constraint_relations() @Property('QVariantList', notify=layersChange) def arithmicOperators(self) -> list[str]: - return self._paramters_logic.constraint_arithmetic() + return self._parameters_logic.constraint_arithmetic() @Slot(str, str, str, str, str) def addConstraint(self, value1: str, value2: str, value3: str, value4: str, value5: str) -> None: - self._paramters_logic.add_constraint( + self._parameters_logic.add_constraint( dependent_idx=int(value1), relational_operator=value2, value=float(value3), diff --git a/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/Sidebar/Basic/Groups/ModelSelector.qml b/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/Sidebar/Basic/Groups/ModelSelector.qml index b5cbd460..490e1774 100644 --- a/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/Sidebar/Basic/Groups/ModelSelector.qml +++ b/src_qt6/EasyReflectometryApp/Gui/Pages/Sample/Sidebar/Basic/Groups/ModelSelector.qml @@ -68,7 +68,7 @@ EaElements.GroupBox { mouseArea.onPressed: { if (Globals.BackendWrapper.sampleCurrentModelIndex !== index) { - Globals.BackendWrapper.sampleSetCurrentModelIndex(0) + Globals.BackendWrapper.sampleSetCurrentModelIndex(index) } } } From 71fc306fb55c7203d12c7f182bb9bc94603002d4 Mon Sep 17 00:00:00 2001 From: Andreas Pedersen Date: Mon, 11 Nov 2024 20:24:40 +0100 Subject: [PATCH 38/43] add model --- src_qt6/EasyReflectometryApp/Backends/Py/logic/models.py | 5 +++++ src_qt6/EasyReflectometryApp/Backends/Py/logic/project.py | 4 ++-- src_qt6/EasyReflectometryApp/Backends/Py/sample.py | 1 + 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src_qt6/EasyReflectometryApp/Backends/Py/logic/models.py b/src_qt6/EasyReflectometryApp/Backends/Py/logic/models.py index 1d6063ac..1a0714c8 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Py/logic/models.py +++ b/src_qt6/EasyReflectometryApp/Backends/Py/logic/models.py @@ -75,6 +75,11 @@ def remove_at_index(self, value: str) -> None: def add_new(self) -> None: self._models.add_model() + if 'Si' not in [material.name for material in self._project_lib._materials]: + self._project_lib._materials.add_material('Si', 2.07, 0.0) + index_si = [material.name for material in self._project_lib._materials].index('Si') + self._models[-1].sample.data[1].layers.data[0].material = self._project_lib._materials[index_si] +# self._project_lib.current_model_index = len(self._models) - 1 def duplicate_selected_model(self) -> None: self._models.duplicate_model(self.index) diff --git a/src_qt6/EasyReflectometryApp/Backends/Py/logic/project.py b/src_qt6/EasyReflectometryApp/Backends/Py/logic/project.py index 08920d0f..ed096cf9 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Py/logic/project.py +++ b/src_qt6/EasyReflectometryApp/Backends/Py/logic/project.py @@ -77,7 +77,7 @@ def set_q_resolution(self, new_value: str) -> None: def experimental_data_at_current_index(self) -> bool: experimental_data = False try: - self._project_lib.experimental_data_for_model_at_index() + self._project_lib.experimental_data_for_model_at_index(self._project_lib._current_model_index) experimental_data = True except IndexError: pass @@ -99,7 +99,7 @@ def load(self, path: str) -> None: self._project_lib.load_from_json(path) def load_experiment(self, path: str) -> None: - self._project_lib.load_experiment_for_model_at_index(path) + self._project_lib.load_experiment_for_model_at_index(path, self._project_lib._current_model_index) def reset(self) -> None: self._project_lib.reset() diff --git a/src_qt6/EasyReflectometryApp/Backends/Py/sample.py b/src_qt6/EasyReflectometryApp/Backends/Py/sample.py index 0a84f4c1..7fb9fef0 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Py/sample.py +++ b/src_qt6/EasyReflectometryApp/Backends/Py/sample.py @@ -167,6 +167,7 @@ def removeModel(self, value: str) -> None: def addNewModel(self) -> None: self._models_logic.add_new() self.modelsTableChanged.emit() +# self.externalRefreshPlot.emit() @Slot() def duplicateSelectedModel(self) -> None: From 7ecf7a41fb35c6807276ca4eb224eea8b8f2fee1 Mon Sep 17 00:00:00 2001 From: Andreas Pedersen Date: Wed, 13 Nov 2024 08:57:18 +0100 Subject: [PATCH 39/43] code cleaning --- .../Backends/Py/logic/assemblies.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src_qt6/EasyReflectometryApp/Backends/Py/logic/assemblies.py b/src_qt6/EasyReflectometryApp/Backends/Py/logic/assemblies.py index 680f1083..c6aa3dce 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Py/logic/assemblies.py +++ b/src_qt6/EasyReflectometryApp/Backends/Py/logic/assemblies.py @@ -44,6 +44,8 @@ def remove_at_index(self, value: str) -> None: def add_new(self) -> None: self._assemblies.add_assembly() + index_si = self._get_index_si() + self._assemblies[-1].layers[0].material = self._project_lib._materials[index_si] def duplicate_selected(self) -> None: self._assemblies.duplicate_assembly(self.index) @@ -69,15 +71,11 @@ def set_type_at_current_index(self, new_value: str) -> bool: return False if new_value == 'Multi-layer': - if 'Si' not in [material.name for material in self._project_lib._materials]: - self._project_lib._materials.add_material('Si', 2.07, 0.0) - index_si = [material.name for material in self._project_lib._materials].index('Si') + index_si = self._get_index_si() new_assembly = Multilayer() new_assembly.layers[0].material = self._project_lib._materials[index_si] elif new_value == 'Repeating Multi-layer': - if 'Si' not in [material.name for material in self._project_lib._materials]: - self._project_lib._materials.add_material('Si', 2.07, 0.0) - index_si = [material.name for material in self._project_lib._materials].index('Si') + index_si = self._get_index_si() new_assembly = RepeatingMultilayer() new_assembly.layers[0].material = self._project_lib._materials[index_si] elif new_value == 'Surfactant Layer': @@ -125,6 +123,11 @@ def set_conformal_roughness(self, new_value: str) -> bool: self._assemblies[self.index].conformal_roughness = new_value return True return False + + def _get_index_si(self) -> int: + if 'Si' not in [material.name for material in self._project_lib._materials]: + self._project_lib._materials.add_material('Si', 2.07, 0.0) + return [material.name for material in self._project_lib._materials].index('Si') def _from_assemblies_collection_to_list_of_dicts(assemblies_collection: Sample) -> list[dict[str, str]]: From c20c80048bab235cc9592ed60ed1feccab53d03a Mon Sep 17 00:00:00 2001 From: Andreas Pedersen Date: Wed, 13 Nov 2024 13:40:19 +0100 Subject: [PATCH 40/43] new add model and cleaning --- .../Backends/Py/logic/assemblies.py | 21 ++++------------ .../Backends/Py/logic/models.py | 24 +++++++++++++++---- .../Backends/Py/sample.py | 10 +------- 3 files changed, 25 insertions(+), 30 deletions(-) diff --git a/src_qt6/EasyReflectometryApp/Backends/Py/logic/assemblies.py b/src_qt6/EasyReflectometryApp/Backends/Py/logic/assemblies.py index c6aa3dce..ca7fa5c7 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Py/logic/assemblies.py +++ b/src_qt6/EasyReflectometryApp/Backends/Py/logic/assemblies.py @@ -44,7 +44,7 @@ def remove_at_index(self, value: str) -> None: def add_new(self) -> None: self._assemblies.add_assembly() - index_si = self._get_index_si() + index_si = self._project_lib.get_index_si() self._assemblies[-1].layers[0].material = self._project_lib._materials[index_si] def duplicate_selected(self) -> None: @@ -71,20 +71,14 @@ def set_type_at_current_index(self, new_value: str) -> bool: return False if new_value == 'Multi-layer': - index_si = self._get_index_si() new_assembly = Multilayer() - new_assembly.layers[0].material = self._project_lib._materials[index_si] + new_assembly.layers[0].material = self._assemblies[self.index].layers.data[0].material elif new_value == 'Repeating Multi-layer': - index_si = self._get_index_si() new_assembly = RepeatingMultilayer() - new_assembly.layers[0].material = self._project_lib._materials[index_si] + new_assembly.layers[0].material = self._assemblies[self.index].layers.data[0].material elif new_value == 'Surfactant Layer': - if 'Air' not in [material.name for material in self._project_lib._materials]: - self._project_lib._materials.add_material('Air', 0.0, 0.0) - if 'D2O' not in [material.name for material in self._project_lib._materials]: - self._project_lib._materials.add_material('D2O', 6.36, 0.0) - index_air = [material.name for material in self._project_lib._materials].index('Air') - index_d2o = [material.name for material in self._project_lib._materials].index('D2O') + index_air = self._project_lib.get_index_air() + index_d2o = self._project_lib.get_index_d2o() new_assembly = SurfactantLayer() new_assembly.layers[0].solvent = self._project_lib._materials[index_air] new_assembly.layers[1].solvent = self._project_lib._materials[index_d2o] @@ -123,11 +117,6 @@ def set_conformal_roughness(self, new_value: str) -> bool: self._assemblies[self.index].conformal_roughness = new_value return True return False - - def _get_index_si(self) -> int: - if 'Si' not in [material.name for material in self._project_lib._materials]: - self._project_lib._materials.add_material('Si', 2.07, 0.0) - return [material.name for material in self._project_lib._materials].index('Si') def _from_assemblies_collection_to_list_of_dicts(assemblies_collection: Sample) -> list[dict[str, str]]: diff --git a/src_qt6/EasyReflectometryApp/Backends/Py/logic/models.py b/src_qt6/EasyReflectometryApp/Backends/Py/logic/models.py index 1a0714c8..4eb22c3f 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Py/logic/models.py +++ b/src_qt6/EasyReflectometryApp/Backends/Py/logic/models.py @@ -75,11 +75,25 @@ def remove_at_index(self, value: str) -> None: def add_new(self) -> None: self._models.add_model() - if 'Si' not in [material.name for material in self._project_lib._materials]: - self._project_lib._materials.add_material('Si', 2.07, 0.0) - index_si = [material.name for material in self._project_lib._materials].index('Si') - self._models[-1].sample.data[1].layers.data[0].material = self._project_lib._materials[index_si] -# self._project_lib.current_model_index = len(self._models) - 1 + self._models[-1].sample.add_assembly() + self._models[-1].sample._enable_changes_to_outermost_layers() + + self._models[-1].sample.data[0].layers.data[0].material = self._project_lib._materials[self._project_lib.get_index_air()] + self._models[-1].sample.data[0].layers.data[0].thickness = 0.0 + self._models[-1].sample.data[0].layers.data[0].roughness = 0.0 + self._models[-1].sample.data[0].name = 'Superphase' + + self._models[-1].sample.data[1].layers.data[0].material = self._project_lib._materials[self._project_lib.get_index_sio2()] + self._models[-1].sample.data[1].layers.data[0].thickness = 20.0 + self._models[-1].sample.data[1].layers.data[0].roughness = 3.0 + self._models[-1].sample.data[1].name = 'SiO2' + + self._models[-1].sample.data[2].layers.data[0].material = self._project_lib._materials[self._project_lib.get_index_si()] + self._models[-1].sample.data[2].name = 'Substrate' + self._models[-1].sample.data[2].layers.data[0].thickness = 0.0 + self._models[-1].sample.data[2].layers.data[0].roughness = 1.2 + + self._models[-1].sample._disable_changes_to_outermost_layers() def duplicate_selected_model(self) -> None: self._models.duplicate_model(self.index) diff --git a/src_qt6/EasyReflectometryApp/Backends/Py/sample.py b/src_qt6/EasyReflectometryApp/Backends/Py/sample.py index 7fb9fef0..a1e108d9 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Py/sample.py +++ b/src_qt6/EasyReflectometryApp/Backends/Py/sample.py @@ -12,21 +12,17 @@ from .logic.parameters import Parameters as ParametersLogic class Sample(QObject): - #materialsChanged = Signal() materialsTableChanged = Signal() materialsIndexChanged = Signal() - #modelsChange = Signal() modelsTableChanged = Signal() modelsIndexChanged = Signal() -# assembliesChange = Signal() assembliesTableChanged = Signal() assembliesIndexChanged = Signal() layersChange = Signal() layersIndexChanged = Signal() -# layersTableChanged = Signal() qRangeChanged = Signal() @@ -49,7 +45,6 @@ def __init__(self, project_lib: ProjectLib, parent=None): def connect_logic(self) -> None: self.assembliesIndexChanged.connect(self.layersConnectChanges) -# self.layersTableChanged.connect(self.layersConnectChanges) # # # # Materials @@ -167,7 +162,7 @@ def removeModel(self, value: str) -> None: def addNewModel(self) -> None: self._models_logic.add_new() self.modelsTableChanged.emit() -# self.externalRefreshPlot.emit() + self.materialsTableChanged.emit() @Slot() def duplicateSelectedModel(self) -> None: @@ -187,9 +182,6 @@ def moveSelectedModelDown(self)-> None: # # # # Assemblies # # # -# def assembliesConnectChanges(self) -> None: -# self.assembliesChange.emit() - @Property('QVariantList', notify=assembliesTableChanged) def assemblies(self) -> list[dict[str, str]]: return self._assemblies_logic.assemblies From c1d47722270cb1c6391d562b0caf93c06a442d42 Mon Sep 17 00:00:00 2001 From: Andreas Pedersen Date: Fri, 15 Nov 2024 13:39:41 +0100 Subject: [PATCH 41/43] get name for minimizer --- src_qt6/EasyReflectometryApp/Backends/Py/logic/status.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src_qt6/EasyReflectometryApp/Backends/Py/logic/status.py b/src_qt6/EasyReflectometryApp/Backends/Py/logic/status.py index c1ec1733..5075d0d4 100644 --- a/src_qt6/EasyReflectometryApp/Backends/Py/logic/status.py +++ b/src_qt6/EasyReflectometryApp/Backends/Py/logic/status.py @@ -10,7 +10,7 @@ def project(self): @property def minimizer(self): - return self._project_lib._fitter.easy_science_multi_fitter.minimizer.name + return self._project_lib.minimizer.name @property def calculator(self): From 8535a406bdfb2154b748a813dd5e674d520ab632 Mon Sep 17 00:00:00 2001 From: Andreas Pedersen Date: Fri, 15 Nov 2024 14:00:25 +0100 Subject: [PATCH 42/43] Fitter to MultiFitter --- EasyReflectometryApp/Logic/Proxies/Fitter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EasyReflectometryApp/Logic/Proxies/Fitter.py b/EasyReflectometryApp/Logic/Proxies/Fitter.py index 5d657089..bd4705a7 100644 --- a/EasyReflectometryApp/Logic/Proxies/Fitter.py +++ b/EasyReflectometryApp/Logic/Proxies/Fitter.py @@ -8,7 +8,7 @@ from easyscience import global_object -from easyreflectometry.fitting import Fitter as easyFitter +from easyreflectometry.fitting import MultiFitter as easyFitter class Fitter(QThread): From f6ba7efca5fff111526f353ac52739c35b1a678d Mon Sep 17 00:00:00 2001 From: Andreas Pedersen Date: Fri, 15 Nov 2024 14:15:47 +0100 Subject: [PATCH 43/43] easy_f to easy_science_multi_fitter --- EasyReflectometryApp/Logic/Proxies/Calculator.py | 2 +- EasyReflectometryApp/Logic/Proxies/Fitter.py | 2 +- EasyReflectometryApp/Logic/Proxies/Minimizer.py | 4 ++-- EasyReflectometryApp/Logic/Proxies/Parameter.py | 2 +- EasyReflectometryApp/Logic/Proxies/State.py | 4 ++-- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/EasyReflectometryApp/Logic/Proxies/Calculator.py b/EasyReflectometryApp/Logic/Proxies/Calculator.py index b3fa77a7..6ae38513 100644 --- a/EasyReflectometryApp/Logic/Proxies/Calculator.py +++ b/EasyReflectometryApp/Logic/Proxies/Calculator.py @@ -43,7 +43,7 @@ def currentCalculatorIndex(self, new_index: int): model = self.parent._data_proxy._data[self.parent._data_proxy.currentDataIndex].model model.switch_interface(new_name) - self.parent._fitter_proxy.eFitter.easy_f.initialize(self.parent._model_proxy._model, + self.parent._fitter_proxy.eFitter.easy_science_multi_fitter.initialize(self.parent._model_proxy._model, self.parent._interface.fit_func) self.calculatorChanged.emit() diff --git a/EasyReflectometryApp/Logic/Proxies/Fitter.py b/EasyReflectometryApp/Logic/Proxies/Fitter.py index bd4705a7..d15229e5 100644 --- a/EasyReflectometryApp/Logic/Proxies/Fitter.py +++ b/EasyReflectometryApp/Logic/Proxies/Fitter.py @@ -148,7 +148,7 @@ def nonthreaded_fit(self): weights = [1 / i.ye for i in exp_data] method = self.parent.minimizer._current_minimizer.method - res = self.eFitter.easy_f.fit(x, y, weights=weights, method=method) + res = self.eFitter.easy_science_multi_fitter.fit(x, y, weights=weights, method=method) self._setFitResults(res) # def threaded_fit(self): diff --git a/EasyReflectometryApp/Logic/Proxies/Minimizer.py b/EasyReflectometryApp/Logic/Proxies/Minimizer.py index ebf9ffec..2359d2e9 100644 --- a/EasyReflectometryApp/Logic/Proxies/Minimizer.py +++ b/EasyReflectometryApp/Logic/Proxies/Minimizer.py @@ -32,7 +32,7 @@ def minimizerNames(self): @Property(int, notify=currentMinimizerChanged) def currentMinimizerIndex(self): - current_name = self.parent._fitter_proxy.eFitter.easy_f.minimizer.name + current_name = self.parent._fitter_proxy.eFitter.easy_science_multi_fitter.minimizer.name return self.minimizerNames.index(current_name) @currentMinimizerIndex.setter @@ -41,7 +41,7 @@ def currentMinimizerIndex(self, new_index: int): if self.currentMinimizerIndex == new_index: return new_name = self.minimizerNames[new_index] - self.parent._fitter_proxy.eFitter.easy_f.switch_minimizer(new_name) + self.parent._fitter_proxy.eFitter.easy_science_multi_fitter.switch_minimizer(new_name) self.currentMinimizerChanged.emit() @Property(int, notify=currentMinimizerMethodChanged) diff --git a/EasyReflectometryApp/Logic/Proxies/Parameter.py b/EasyReflectometryApp/Logic/Proxies/Parameter.py index e1722a86..ad64751b 100644 --- a/EasyReflectometryApp/Logic/Proxies/Parameter.py +++ b/EasyReflectometryApp/Logic/Proxies/Parameter.py @@ -303,7 +303,7 @@ def toggleConstraintByIndex(self, index, enabled): self.parent.sampleChanged.emit() def removeAllConstraints(self): - for _ in range(len(self.eFitter.easy_f.fit_constraints())): + for _ in range(len(self.eFitter.easy_science_multi_fitter.fit_constraints())): self.removeConstraintByIndex(0) self.constraintsRemoved.emit() self.sampleChanged.emit() diff --git a/EasyReflectometryApp/Logic/Proxies/State.py b/EasyReflectometryApp/Logic/Proxies/State.py index b838fe3a..87335698 100644 --- a/EasyReflectometryApp/Logic/Proxies/State.py +++ b/EasyReflectometryApp/Logic/Proxies/State.py @@ -49,7 +49,7 @@ def statusModelAsObj(self): "calculation": self.parent._interface.current_interface_name, "minimization": - f'{self.parent._fitter_proxy.eFitter.easy_f.minimizer._method}' + f'{self.parent._fitter_proxy.eFitter.easy_science_multi_fitter.minimizer._method}' } self._status_model = obj return obj @@ -63,7 +63,7 @@ def statusModelAsXml(self): "label": "Minimization", "value": - f'{self.parent._fitter_proxy.eFitter.easy_f.minimizer._method}' + f'{self.parent._fitter_proxy.eFitter.easy_science_multi_fitter.minimizer._method}' }] xml = XMLSerializer().encode({"item":model}, data_only=True) return xml