From d198a73804823e6c247c9a7d7ec4d7dc2fbae644 Mon Sep 17 00:00:00 2001 From: rozyczko Date: Wed, 18 Mar 2026 14:51:10 +0100 Subject: [PATCH 01/13] display corrected chi2 in the GUI --- EasyReflectometryApp/Backends/Py/logic/fitting.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/EasyReflectometryApp/Backends/Py/logic/fitting.py b/EasyReflectometryApp/Backends/Py/logic/fitting.py index ad18c8aa..3c733e9d 100644 --- a/EasyReflectometryApp/Backends/Py/logic/fitting.py +++ b/EasyReflectometryApp/Backends/Py/logic/fitting.py @@ -233,16 +233,22 @@ def fit_n_pars(self) -> int: @property def fit_chi2(self) -> float: - """Return total chi-squared across all fits.""" + """Return reduced chi-squared across all fits (chi2 / degrees of freedom).""" if self._results: try: - return float(sum(r.chi2 for r in self._results)) + total_chi2 = float(sum(r.chi2 for r in self._results)) + total_points = sum(len(r.x) for r in self._results) + n_params = self._results[0].n_pars + total_dof = total_points - n_params + if total_dof <= 0: + return 0.0 + return total_chi2 / total_dof except (ValueError, TypeError): return 0.0 if self._result is None: return 0.0 try: - return float(self._result.chi2) + return float(self._result.reduced_chi) except (ValueError, TypeError): return 0.0 From 784713647e1665bd0f9ba6c824282fdd990f1158 Mon Sep 17 00:00:00 2001 From: rozyczko Date: Wed, 18 Mar 2026 15:00:57 +0100 Subject: [PATCH 02/13] make the Fit button visible all the time --- .../Gui/Pages/Analysis/Layout.qml | 18 +++++++++++++++++- .../Pages/Analysis/Sidebar/Basic/Layout.qml | 19 ------------------- 2 files changed, 17 insertions(+), 20 deletions(-) diff --git a/EasyReflectometryApp/Gui/Pages/Analysis/Layout.qml b/EasyReflectometryApp/Gui/Pages/Analysis/Layout.qml index 0620e8ef..d3ad8769 100644 --- a/EasyReflectometryApp/Gui/Pages/Analysis/Layout.qml +++ b/EasyReflectometryApp/Gui/Pages/Analysis/Layout.qml @@ -8,7 +8,6 @@ import EasyApp.Gui.Elements as EaElements import EasyApp.Gui.Components as EaComponents import Gui.Globals as Globals -//import Gui.Components as Components EaComponents.ContentPage { @@ -37,6 +36,23 @@ EaComponents.ContentPage { Loader { source: 'Sidebar/Advanced/Layout.qml' } ] + footerComponent: Component { + EaElements.SideBarButton { + 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') + + onClicked: { + console.debug(`Clicking '${text}' button: ${this}`) + Globals.BackendWrapper.analysisFittingStartStop() + } + + Component.onCompleted: Globals.References.pages.analysis.sidebar.basic.popups.startFittingButton = this + Loader { source: 'Sidebar/Basic/Popups/FitStatusDialog.qml' } + } + } + // continueButton.enabled: Globals.Proxies.main.summary.isCreated continueButton.onClicked: { diff --git a/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Layout.qml b/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Layout.qml index 4b2fb4ad..96ade9a2 100644 --- a/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Layout.qml +++ b/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Layout.qml @@ -28,23 +28,4 @@ EaComponents.SideBarColumn { // } Groups.Fittables{} - -/* EaElements.GroupBox { - //title: qsTr("Parameters") - collapsible: false - last: true - - Loader { source: 'Fittables.qml' } - } -*/ - - Groups.Fitting{} - -/* EaElements.GroupBox { - //title: qsTr("Fitting") - collapsible: false - - Loader { source: 'Fitting.qml' } - } -*/ } From 0249f883aa230d20bb03926235f71b23745f40a7 Mon Sep 17 00:00:00 2001 From: rozyczko Date: Thu, 19 Mar 2026 11:29:03 +0100 Subject: [PATCH 03/13] make sure refl1d actually works --- EasyReflectometryApp/Backends/Py/logic/calculators.py | 2 +- pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/EasyReflectometryApp/Backends/Py/logic/calculators.py b/EasyReflectometryApp/Backends/Py/logic/calculators.py index 5c5d49c9..c8ed4002 100644 --- a/EasyReflectometryApp/Backends/Py/logic/calculators.py +++ b/EasyReflectometryApp/Backends/Py/logic/calculators.py @@ -17,6 +17,6 @@ def set_current_index(self, new_value: int) -> None: 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) + self._project_lib.calculator = new_calculator return True return False diff --git a/pyproject.toml b/pyproject.toml index 99cd71b6..2b64ff98 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -32,7 +32,7 @@ classifiers = [ requires-python = '>=3.11' dependencies = [ 'EasyApp @ git+https://github.com/EasyScience/EasyApp.git@develop', - 'easyreflectometry @ git+https://github.com/EasyScience/EasyReflectometryLib.git@develop', + 'easyreflectometry @ git+https://github.com/EasyScience/EasyReflectometryLib.git@drefl1d_fix', 'asteval', 'PySide6', 'toml', From aac4ce8858da115c473f205c3d40fe99ac957458 Mon Sep 17 00:00:00 2001 From: rozyczko Date: Thu, 19 Mar 2026 11:48:55 +0100 Subject: [PATCH 04/13] typo fixed --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 2b64ff98..b8ce18ec 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -32,7 +32,7 @@ classifiers = [ requires-python = '>=3.11' dependencies = [ 'EasyApp @ git+https://github.com/EasyScience/EasyApp.git@develop', - 'easyreflectometry @ git+https://github.com/EasyScience/EasyReflectometryLib.git@drefl1d_fix', + 'easyreflectometry @ git+https://github.com/EasyScience/EasyReflectometryLib.git@refl1d_fix', 'asteval', 'PySide6', 'toml', From a118784c97715feecb68f9e279d20ab65af14be0 Mon Sep 17 00:00:00 2001 From: rozyczko Date: Thu, 19 Mar 2026 15:18:16 +0100 Subject: [PATCH 05/13] attempt at properly adding starting menu item on ubuntu --- tools/Scripts/InstallerInstallScript.js | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/tools/Scripts/InstallerInstallScript.js b/tools/Scripts/InstallerInstallScript.js index 10f1ce63..2e8ef68d 100644 --- a/tools/Scripts/InstallerInstallScript.js +++ b/tools/Scripts/InstallerInstallScript.js @@ -102,7 +102,7 @@ Component.prototype.createOperations = function () { if (installer.value("os") === "x11") { component.addOperation( "CreateDesktopEntry", - "@TargetDir@/@ProductName@.desktop", + "@ProductName@.desktop", "Comment=A scientific software for modelling and analysis of the neutron re data.\n" + "Type=Application\n" + "Exec=@TargetDir@/@ProductName@/@ProductName@\n" + @@ -123,12 +123,6 @@ Component.prototype.createOperations = function () { ) */ - component.addOperation( - "Copy", - "@TargetDir@/@ProductName@.desktop", - "@HomeDir@/.local/share/applications/@ProductName@.desktop" - ) - /* component.addOperation( "Copy", From 3fdbce89265b7d2de1ca488430893cf2503f9af0 Mon Sep 17 00:00:00 2001 From: Piotr Rozyczko Date: Fri, 20 Mar 2026 10:41:02 +0100 Subject: [PATCH 06/13] enforce axis reset on q-range change. Reparent easyApp --- EasyReflectometryApp/Backends/Py/py_backend.py | 1 + pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/EasyReflectometryApp/Backends/Py/py_backend.py b/EasyReflectometryApp/Backends/Py/py_backend.py index 57ba5a8b..d8059062 100644 --- a/EasyReflectometryApp/Backends/Py/py_backend.py +++ b/EasyReflectometryApp/Backends/Py/py_backend.py @@ -226,5 +226,6 @@ def _refresh_plots(self): self._plotting_1d.refreshSamplePage() self._plotting_1d.refreshExperimentPage() self._plotting_1d.refreshAnalysisPage() + self._plotting_1d.samplePageResetAxes.emit() # Emit signal for multi-experiment changes self.multiExperimentSelectionChanged.emit() diff --git a/pyproject.toml b/pyproject.toml index b8ce18ec..919b0cc5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -31,7 +31,7 @@ classifiers = [ requires-python = '>=3.11' dependencies = [ - 'EasyApp @ git+https://github.com/EasyScience/EasyApp.git@develop', + 'EasyApp @ git+https://github.com/EasyScience/EasyApp.git@footer_component', 'easyreflectometry @ git+https://github.com/EasyScience/EasyReflectometryLib.git@refl1d_fix', 'asteval', 'PySide6', From dfbff67566d4cc11b1489a13744f4245c48d896d Mon Sep 17 00:00:00 2001 From: rozyczko Date: Mon, 23 Mar 2026 11:37:58 +0100 Subject: [PATCH 07/13] fixed number of fitted parameters shown in the widget and in the status bar. Reparented to EDL develop --- EasyReflectometryApp/Backends/Py/logic/fitting.py | 4 ++-- EasyReflectometryApp/Backends/Py/py_backend.py | 2 ++ pyproject.toml | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/EasyReflectometryApp/Backends/Py/logic/fitting.py b/EasyReflectometryApp/Backends/Py/logic/fitting.py index 3c733e9d..db7a7023 100644 --- a/EasyReflectometryApp/Backends/Py/logic/fitting.py +++ b/EasyReflectometryApp/Backends/Py/logic/fitting.py @@ -224,9 +224,9 @@ def on_fit_finished(self, results: List[FitResults]) -> None: @property def fit_n_pars(self) -> int: - """Return total number of refined parameters across all fits.""" + """Return the global number of refined parameters for the fit.""" if self._results: - return sum(r.n_pars for r in self._results) + return self._results[0].n_pars if self._result is None: return 0 return self._result.n_pars diff --git a/EasyReflectometryApp/Backends/Py/py_backend.py b/EasyReflectometryApp/Backends/Py/py_backend.py index d8059062..f7448c69 100644 --- a/EasyReflectometryApp/Backends/Py/py_backend.py +++ b/EasyReflectometryApp/Backends/Py/py_backend.py @@ -168,6 +168,8 @@ def _connect_analysis_page(self) -> None: self._analysis.externalFittingChanged.connect(self._refresh_plots) self._analysis.externalExperimentChanged.connect(self._relay_experiment_page_experiment_changed) self._analysis.externalExperimentChanged.connect(self._refresh_plots) + # Update status bar when parameters change (e.g. fit checkbox toggle, post-fit) + self._analysis.parametersChanged.connect(self._status.statusChanged) # Connect multi-experiment selection changes self._analysis.experimentsChanged.connect(self.multiExperimentSelectionChanged) diff --git a/pyproject.toml b/pyproject.toml index 919b0cc5..e885f8ab 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -32,7 +32,7 @@ classifiers = [ requires-python = '>=3.11' dependencies = [ 'EasyApp @ git+https://github.com/EasyScience/EasyApp.git@footer_component', - 'easyreflectometry @ git+https://github.com/EasyScience/EasyReflectometryLib.git@refl1d_fix', + 'easyreflectometry @ git+https://github.com/EasyScience/EasyReflectometryLib.git@develop', 'asteval', 'PySide6', 'toml', From 43e84997b6857a15fb6616058a2e97efbe21e01c Mon Sep 17 00:00:00 2001 From: rozyczko Date: Mon, 23 Mar 2026 14:00:03 +0100 Subject: [PATCH 08/13] changed copyright year from 2025 to 2026 --- EasyReflectometryApp/Backends/Py/logic/helpers.py | 4 ++-- EasyReflectometryApp/Backends/Py/status.py | 4 ++-- EasyReflectometryApp/Backends/Py/summary.py | 4 ++-- EasyReflectometryApp/Gui/Globals/ApplicationInfo.qml | 2 +- .../Gui/Pages/Analysis/MainContent/AnalysisView.qml | 4 ++-- .../Gui/Pages/Analysis/MainContent/CombinedView.qml | 4 ++-- .../Gui/Pages/Analysis/MainContent/SldView.qml | 4 ++-- .../Gui/Pages/Analysis/Sidebar/Advanced/Groups/Calculator.qml | 4 ++-- .../Gui/Pages/Analysis/Sidebar/Advanced/Groups/Minimizer.qml | 4 ++-- .../Gui/Pages/Analysis/Sidebar/Advanced/Groups/ParamNames.qml | 4 ++-- .../Pages/Analysis/Sidebar/Advanced/Groups/PlotControl.qml | 4 ++-- .../Gui/Pages/Analysis/Sidebar/Advanced/Layout.qml | 4 ++-- .../Gui/Pages/Analysis/Sidebar/Basic/Groups/Fittables.qml | 4 ++-- .../Gui/Pages/Analysis/Sidebar/Basic/Groups/Fitting.qml | 4 ++-- .../Gui/Pages/Analysis/Sidebar/Basic/Layout.qml | 4 ++-- .../Pages/Analysis/Sidebar/Basic/Popups/FitStatusDialog.qml | 4 ++-- .../Gui/Pages/Experiment/MainContent/ExperimentView.qml | 4 ++-- .../Pages/Experiment/Sidebar/Advanced/Groups/PlotControl.qml | 4 ++-- .../Gui/Pages/Experiment/Sidebar/Advanced/Layout.qml | 4 ++-- .../Gui/Pages/Project/MainContent/Description.qml | 4 ++-- .../Gui/Pages/Sample/MainContent/CombinedView.qml | 4 ++-- .../Gui/Pages/Sample/MainContent/SampleView.qml | 4 ++-- EasyReflectometryApp/Gui/Pages/Sample/MainContent/SldView.qml | 4 ++-- .../Gui/Pages/Sample/Sidebar/Advanced/Groups/PlotControl.qml | 4 ++-- EasyReflectometryApp/Gui/Pages/Summary/Layout.qml | 4 ++-- .../Gui/Pages/Summary/MainContent/Summary.qml | 4 ++-- .../Gui/Pages/Summary/Sidebar/Basic/Groups/Export.qml | 4 ++-- .../Gui/Pages/Summary/Sidebar/Basic/Groups/ExportPlots.qml | 4 ++-- .../Summary/Sidebar/Basic/Groups/SaveConfirmationDialog.qml | 4 ++-- .../Gui/Pages/Summary/Sidebar/Basic/Layout.qml | 4 ++-- .../Gui/Pages/Summary/Sidebar/Extra/Groups/Empty.qml | 4 ++-- .../Gui/Pages/Summary/Sidebar/Extra/Layout.qml | 4 ++-- EasyReflectometryApp/Gui/PlotControlRefLines.qml | 4 ++-- EasyReflectometryApp/Gui/SldChart.qml | 4 ++-- EasyReflectometryApp/main.py | 4 ++-- LICENSE.md | 2 +- utils.py | 4 ++-- 37 files changed, 72 insertions(+), 72 deletions(-) diff --git a/EasyReflectometryApp/Backends/Py/logic/helpers.py b/EasyReflectometryApp/Backends/Py/logic/helpers.py index 70465a5b..630a3278 100644 --- a/EasyReflectometryApp/Backends/Py/logic/helpers.py +++ b/EasyReflectometryApp/Backends/Py/logic/helpers.py @@ -1,6 +1,6 @@ -# 5SPDX-FileCopyrightText: 2025 EasyApp contributors +# 5SPDX-FileCopyrightText: 2026 EasyApp contributors # SPDX-License-Identifier: BSD-3-Clause -# © 2025 Contributors to the EasyApp project +# © 2026 Contributors to the EasyApp project class IO: diff --git a/EasyReflectometryApp/Backends/Py/status.py b/EasyReflectometryApp/Backends/Py/status.py index a02c9460..0809920a 100644 --- a/EasyReflectometryApp/Backends/Py/status.py +++ b/EasyReflectometryApp/Backends/Py/status.py @@ -1,6 +1,6 @@ -# 5SPDX-FileCopyrightText: 2025 EasyApp contributors +# 5SPDX-FileCopyrightText: 2026 EasyApp contributors # SPDX-License-Identifier: BSD-3-Clause -# © 2025 Contributors to the EasyApp project +# © 2026 Contributors to the EasyApp project from easyreflectometry import Project as ProjectLib from PySide6.QtCore import Property diff --git a/EasyReflectometryApp/Backends/Py/summary.py b/EasyReflectometryApp/Backends/Py/summary.py index ea83b164..c3c43049 100644 --- a/EasyReflectometryApp/Backends/Py/summary.py +++ b/EasyReflectometryApp/Backends/Py/summary.py @@ -1,6 +1,6 @@ -# 5SPDX-FileCopyrightText: 2025 EasyApp contributors +# 5SPDX-FileCopyrightText: 2026 EasyApp contributors # SPDX-License-Identifier: BSD-3-Clause -# © 2025 Contributors to the EasyApp project +# © 2026 Contributors to the EasyApp project from easyreflectometry import Project as ProjectLib from PySide6.QtCore import Property diff --git a/EasyReflectometryApp/Gui/Globals/ApplicationInfo.qml b/EasyReflectometryApp/Gui/Globals/ApplicationInfo.qml index 7c10fa07..38e3644e 100644 --- a/EasyReflectometryApp/Gui/Globals/ApplicationInfo.qml +++ b/EasyReflectometryApp/Gui/Globals/ApplicationInfo.qml @@ -10,7 +10,7 @@ QtObject { 'nameSuffixForLogo': 'reflectometry', 'icon': Qt.resolvedUrl('../Resources/Logo/App.svg'), 'developerYearsFrom': '2019', - 'developerYearsTo': '2025', + 'developerYearsTo': '2026', 'description': 'EasyReflectometry is a scientific software for \nmodelling and analysis of \nneutron and x-ray reflecometry data. \n\nEasyReflectometry is build by ESS DMSC in \nCopenhagen, Denmark.', 'developerIcons': [ { diff --git a/EasyReflectometryApp/Gui/Pages/Analysis/MainContent/AnalysisView.qml b/EasyReflectometryApp/Gui/Pages/Analysis/MainContent/AnalysisView.qml index fec58f95..b9d60114 100644 --- a/EasyReflectometryApp/Gui/Pages/Analysis/MainContent/AnalysisView.qml +++ b/EasyReflectometryApp/Gui/Pages/Analysis/MainContent/AnalysisView.qml @@ -1,6 +1,6 @@ -// SPDX-FileCopyrightText: 2025 EasyReflectometry contributors +// SPDX-FileCopyrightText: 2026 EasyReflectometry contributors // SPDX-License-Identifier: BSD-3-Clause -// © 2025 Contributors to the EasyReflectometry project +// © 2026 Contributors to the EasyReflectometry project import QtQuick import QtQuick.Controls diff --git a/EasyReflectometryApp/Gui/Pages/Analysis/MainContent/CombinedView.qml b/EasyReflectometryApp/Gui/Pages/Analysis/MainContent/CombinedView.qml index 9eab767e..428e33c6 100644 --- a/EasyReflectometryApp/Gui/Pages/Analysis/MainContent/CombinedView.qml +++ b/EasyReflectometryApp/Gui/Pages/Analysis/MainContent/CombinedView.qml @@ -1,6 +1,6 @@ -// SPDX-FileCopyrightText: 2025 EasyReflectometry contributors +// SPDX-FileCopyrightText: 2026 EasyReflectometry contributors // SPDX-License-Identifier: BSD-3-Clause -// © 2025 Contributors to the EasyReflectometry project +// © 2026 Contributors to the EasyReflectometry project import QtQuick import QtQuick.Controls diff --git a/EasyReflectometryApp/Gui/Pages/Analysis/MainContent/SldView.qml b/EasyReflectometryApp/Gui/Pages/Analysis/MainContent/SldView.qml index 31399d53..f9d30c5f 100644 --- a/EasyReflectometryApp/Gui/Pages/Analysis/MainContent/SldView.qml +++ b/EasyReflectometryApp/Gui/Pages/Analysis/MainContent/SldView.qml @@ -1,6 +1,6 @@ -// SPDX-FileCopyrightText: 2025 EasyReflectometry contributors +// SPDX-FileCopyrightText: 2026 EasyReflectometry contributors // SPDX-License-Identifier: BSD-3-Clause -// © 2025 Contributors to the EasyReflectometry project +// © 2026 Contributors to the EasyReflectometry project import QtQuick diff --git a/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Advanced/Groups/Calculator.qml b/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Advanced/Groups/Calculator.qml index 2b1cb1ad..79488b88 100644 --- a/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Advanced/Groups/Calculator.qml +++ b/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Advanced/Groups/Calculator.qml @@ -1,6 +1,6 @@ -// SPDX-FileCopyrightText: 2025 EasyReflectometry contributors +// SPDX-FileCopyrightText: 2026 EasyReflectometry contributors // SPDX-License-Identifier: BSD-3-Clause -// © 2025 Contributors to the EasyReflectometry project +// © 2026 Contributors to the EasyReflectometry project import QtQuick import QtQuick.Controls diff --git a/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Advanced/Groups/Minimizer.qml b/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Advanced/Groups/Minimizer.qml index f568d96b..4b41223d 100644 --- a/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Advanced/Groups/Minimizer.qml +++ b/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Advanced/Groups/Minimizer.qml @@ -1,6 +1,6 @@ -// SPDX-FileCopyrightText: 2025 EasyReflectometry contributors +// SPDX-FileCopyrightText: 2026 EasyReflectometry contributors // SPDX-License-Identifier: BSD-3-Clause -// © 2025 Contributors to the EasyReflectometry project +// © 2026 Contributors to the EasyReflectometry project import QtQuick import QtQuick.Controls diff --git a/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Advanced/Groups/ParamNames.qml b/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Advanced/Groups/ParamNames.qml index cca55bf3..731f05ef 100644 --- a/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Advanced/Groups/ParamNames.qml +++ b/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Advanced/Groups/ParamNames.qml @@ -1,6 +1,6 @@ -// SPDX-FileCopyrightText: 2025 EasyReflectometry contributors +// SPDX-FileCopyrightText: 2026 EasyReflectometry contributors // SPDX-License-Identifier: BSD-3-Clause -// © 2025 Contributors to the EasyReflectometry project +// © 2026 Contributors to the EasyReflectometry project import QtQuick import QtQuick.Controls diff --git a/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Advanced/Groups/PlotControl.qml b/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Advanced/Groups/PlotControl.qml index 34de6956..4715b956 100644 --- a/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Advanced/Groups/PlotControl.qml +++ b/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Advanced/Groups/PlotControl.qml @@ -1,6 +1,6 @@ -// SPDX-FileCopyrightText: 2025 EasyReflectometry contributors +// SPDX-FileCopyrightText: 2026 EasyReflectometry contributors // SPDX-License-Identifier: BSD-3-Clause -// © 2025 Contributors to the EasyReflectometry project +// © 2026 Contributors to the EasyReflectometry project import QtQuick diff --git a/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Advanced/Layout.qml b/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Advanced/Layout.qml index deeee520..dd11888f 100644 --- a/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Advanced/Layout.qml +++ b/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Advanced/Layout.qml @@ -1,6 +1,6 @@ -// SPDX-FileCopyrightText: 2025 EasyReflectometry contributors +// SPDX-FileCopyrightText: 2026 EasyReflectometry contributors // SPDX-License-Identifier: BSD-3-Clause -// © 2025 Contributors to the EasyReflectometry project +// © 2026 Contributors to the EasyReflectometry project import QtQuick diff --git a/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Groups/Fittables.qml b/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Groups/Fittables.qml index b66b7a9e..090bb79e 100644 --- a/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Groups/Fittables.qml +++ b/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Groups/Fittables.qml @@ -1,6 +1,6 @@ -// SPDX-FileCopyrightText: 2025 EasyReflectometry contributors +// SPDX-FileCopyrightText: 2026 EasyReflectometry contributors // SPDX-License-Identifier: BSD-3-Clause -// © 2025 Contributors to the EasyReflectometry project +// © 2026 Contributors to the EasyReflectometry project import QtQuick import QtQuick.Controls diff --git a/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Groups/Fitting.qml b/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Groups/Fitting.qml index f4ccbfe7..6bc6f3a8 100644 --- a/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Groups/Fitting.qml +++ b/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Groups/Fitting.qml @@ -1,6 +1,6 @@ -// SPDX-FileCopyrightText: 2025 EasyReflectometry contributors +// SPDX-FileCopyrightText: 2026 EasyReflectometry contributors // SPDX-License-Identifier: BSD-3-Clause -// © 2025 Contributors to the EasyReflectometry project +// © 2026 Contributors to the EasyReflectometry project import QtQuick import QtQuick.Controls diff --git a/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Layout.qml b/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Layout.qml index 96ade9a2..eaa7a7cd 100644 --- a/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Layout.qml +++ b/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Layout.qml @@ -1,6 +1,6 @@ -// SPDX-FileCopyrightText: 2025 EasyReflectometry contributors +// SPDX-FileCopyrightText: 2026 EasyReflectometry contributors // SPDX-License-Identifier: BSD-3-Clause -// © 2025 Contributors to the EasyReflectometry project +// © 2026 Contributors to the EasyReflectometry project import QtQuick diff --git a/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Popups/FitStatusDialog.qml b/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Popups/FitStatusDialog.qml index 74984f63..85a5e2b2 100644 --- a/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Popups/FitStatusDialog.qml +++ b/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Popups/FitStatusDialog.qml @@ -1,6 +1,6 @@ -// SPDX-FileCopyrightText: 2025 EasyReflectometry contributors +// SPDX-FileCopyrightText: 2026 EasyReflectometry contributors // SPDX-License-Identifier: BSD-3-Clause -// © 2025 Contributors to the EasyReflectometry project +// © 2026 Contributors to the EasyReflectometry project import QtQuick import QtQuick.Controls diff --git a/EasyReflectometryApp/Gui/Pages/Experiment/MainContent/ExperimentView.qml b/EasyReflectometryApp/Gui/Pages/Experiment/MainContent/ExperimentView.qml index 070e809d..f3202d98 100644 --- a/EasyReflectometryApp/Gui/Pages/Experiment/MainContent/ExperimentView.qml +++ b/EasyReflectometryApp/Gui/Pages/Experiment/MainContent/ExperimentView.qml @@ -1,6 +1,6 @@ -// SPDX-FileCopyrightText: 2025 EasyReflectometry contributors +// SPDX-FileCopyrightText: 2026 EasyReflectometry contributors // SPDX-License-Identifier: BSD-3-Clause -// © 2025 Contributors to the EasyReflectometry project +// © 2026 Contributors to the EasyReflectometry project import QtQuick import QtQuick.Controls diff --git a/EasyReflectometryApp/Gui/Pages/Experiment/Sidebar/Advanced/Groups/PlotControl.qml b/EasyReflectometryApp/Gui/Pages/Experiment/Sidebar/Advanced/Groups/PlotControl.qml index ccf27b4d..eec8e7fc 100644 --- a/EasyReflectometryApp/Gui/Pages/Experiment/Sidebar/Advanced/Groups/PlotControl.qml +++ b/EasyReflectometryApp/Gui/Pages/Experiment/Sidebar/Advanced/Groups/PlotControl.qml @@ -1,6 +1,6 @@ -// SPDX-FileCopyrightText: 2025 EasyReflectometry contributors +// SPDX-FileCopyrightText: 2026 EasyReflectometry contributors // SPDX-License-Identifier: BSD-3-Clause -// © 2025 Contributors to the EasyReflectometry project +// © 2026 Contributors to the EasyReflectometry project import QtQuick import QtQuick.Controls diff --git a/EasyReflectometryApp/Gui/Pages/Experiment/Sidebar/Advanced/Layout.qml b/EasyReflectometryApp/Gui/Pages/Experiment/Sidebar/Advanced/Layout.qml index 600ca675..57e358f9 100644 --- a/EasyReflectometryApp/Gui/Pages/Experiment/Sidebar/Advanced/Layout.qml +++ b/EasyReflectometryApp/Gui/Pages/Experiment/Sidebar/Advanced/Layout.qml @@ -1,6 +1,6 @@ -// SPDX-FileCopyrightText: 2025 EasyReflectometry contributors +// SPDX-FileCopyrightText: 2026 EasyReflectometry contributors // SPDX-License-Identifier: BSD-3-Clause -// © 2025 Contributors to the EasyReflectometry project +// © 2026 Contributors to the EasyReflectometry project import QtQuick diff --git a/EasyReflectometryApp/Gui/Pages/Project/MainContent/Description.qml b/EasyReflectometryApp/Gui/Pages/Project/MainContent/Description.qml index eab0faa6..99570bef 100644 --- a/EasyReflectometryApp/Gui/Pages/Project/MainContent/Description.qml +++ b/EasyReflectometryApp/Gui/Pages/Project/MainContent/Description.qml @@ -1,6 +1,6 @@ -// 5SPDX-FileCopyrightText: 2025 EasyApp contributors +// 5SPDX-FileCopyrightText: 2026 EasyApp contributors // SPDX-License-Identifier: BSD-3-Clause -// © 2025 Contributors to the EasyApp project +// © 2026 Contributors to the EasyApp project import QtQuick diff --git a/EasyReflectometryApp/Gui/Pages/Sample/MainContent/CombinedView.qml b/EasyReflectometryApp/Gui/Pages/Sample/MainContent/CombinedView.qml index 3801d2e6..08cb4711 100644 --- a/EasyReflectometryApp/Gui/Pages/Sample/MainContent/CombinedView.qml +++ b/EasyReflectometryApp/Gui/Pages/Sample/MainContent/CombinedView.qml @@ -1,6 +1,6 @@ -// SPDX-FileCopyrightText: 2025 EasyReflectometry contributors +// SPDX-FileCopyrightText: 2026 EasyReflectometry contributors // SPDX-License-Identifier: BSD-3-Clause -// © 2025 Contributors to the EasyReflectometry project +// © 2026 Contributors to the EasyReflectometry project import QtQuick import QtQuick.Controls diff --git a/EasyReflectometryApp/Gui/Pages/Sample/MainContent/SampleView.qml b/EasyReflectometryApp/Gui/Pages/Sample/MainContent/SampleView.qml index 38c821cd..214e453b 100644 --- a/EasyReflectometryApp/Gui/Pages/Sample/MainContent/SampleView.qml +++ b/EasyReflectometryApp/Gui/Pages/Sample/MainContent/SampleView.qml @@ -1,6 +1,6 @@ -// SPDX-FileCopyrightText: 2025 EasyReflectometry contributors +// SPDX-FileCopyrightText: 2026 EasyReflectometry contributors // SPDX-License-Identifier: BSD-3-Clause -// © 2025 Contributors to the EasyReflectometry project +// © 2026 Contributors to the EasyReflectometry project import QtQuick import QtQuick.Controls diff --git a/EasyReflectometryApp/Gui/Pages/Sample/MainContent/SldView.qml b/EasyReflectometryApp/Gui/Pages/Sample/MainContent/SldView.qml index d8e0fe08..c70ef9c2 100644 --- a/EasyReflectometryApp/Gui/Pages/Sample/MainContent/SldView.qml +++ b/EasyReflectometryApp/Gui/Pages/Sample/MainContent/SldView.qml @@ -1,6 +1,6 @@ -// SPDX-FileCopyrightText: 2025 EasyReflectometry contributors +// SPDX-FileCopyrightText: 2026 EasyReflectometry contributors // SPDX-License-Identifier: BSD-3-Clause -// © 2025 Contributors to the EasyReflectometry project +// © 2026 Contributors to the EasyReflectometry project import QtQuick diff --git a/EasyReflectometryApp/Gui/Pages/Sample/Sidebar/Advanced/Groups/PlotControl.qml b/EasyReflectometryApp/Gui/Pages/Sample/Sidebar/Advanced/Groups/PlotControl.qml index b448193c..abfc9278 100644 --- a/EasyReflectometryApp/Gui/Pages/Sample/Sidebar/Advanced/Groups/PlotControl.qml +++ b/EasyReflectometryApp/Gui/Pages/Sample/Sidebar/Advanced/Groups/PlotControl.qml @@ -1,6 +1,6 @@ -// SPDX-FileCopyrightText: 2025 EasyReflectometry contributors +// SPDX-FileCopyrightText: 2026 EasyReflectometry contributors // SPDX-License-Identifier: BSD-3-Clause -// © 2025 Contributors to the EasyReflectometry project +// © 2026 Contributors to the EasyReflectometry project import QtQuick import QtQuick.Controls diff --git a/EasyReflectometryApp/Gui/Pages/Summary/Layout.qml b/EasyReflectometryApp/Gui/Pages/Summary/Layout.qml index cafa75e3..a95b03aa 100644 --- a/EasyReflectometryApp/Gui/Pages/Summary/Layout.qml +++ b/EasyReflectometryApp/Gui/Pages/Summary/Layout.qml @@ -1,6 +1,6 @@ -// 5SPDX-FileCopyrightText: 2025 EasyApp contributors +// 5SPDX-FileCopyrightText: 2026 EasyApp contributors // SPDX-License-Identifier: BSD-3-Clause -// © 2025 Contributors to the EasyApp project +// © 2026 Contributors to the EasyApp project import QtQuick import QtQuick.Controls diff --git a/EasyReflectometryApp/Gui/Pages/Summary/MainContent/Summary.qml b/EasyReflectometryApp/Gui/Pages/Summary/MainContent/Summary.qml index 929e4b64..2007fdbe 100644 --- a/EasyReflectometryApp/Gui/Pages/Summary/MainContent/Summary.qml +++ b/EasyReflectometryApp/Gui/Pages/Summary/MainContent/Summary.qml @@ -1,6 +1,6 @@ -// 5SPDX-FileCopyrightText: 2025 EasyApp contributors +// 5SPDX-FileCopyrightText: 2026 EasyApp contributors // SPDX-License-Identifier: BSD-3-Clause -// © 2025 Contributors to the EasyApp project +// © 2026 Contributors to the EasyApp project import QtQuick import QtQuick.Controls diff --git a/EasyReflectometryApp/Gui/Pages/Summary/Sidebar/Basic/Groups/Export.qml b/EasyReflectometryApp/Gui/Pages/Summary/Sidebar/Basic/Groups/Export.qml index 5fc4398d..824a4714 100644 --- a/EasyReflectometryApp/Gui/Pages/Summary/Sidebar/Basic/Groups/Export.qml +++ b/EasyReflectometryApp/Gui/Pages/Summary/Sidebar/Basic/Groups/Export.qml @@ -1,6 +1,6 @@ -// SPDX-FileCopyrightText: 2025 EasyApp contributors +// SPDX-FileCopyrightText: 2026 EasyApp contributors // SPDX-License-Identifier: BSD-3-Clause -// © 2025 Contributors to the EasyApp project +// © 2026 Contributors to the EasyApp project import QtQuick import QtQuick.Controls diff --git a/EasyReflectometryApp/Gui/Pages/Summary/Sidebar/Basic/Groups/ExportPlots.qml b/EasyReflectometryApp/Gui/Pages/Summary/Sidebar/Basic/Groups/ExportPlots.qml index 1ca5353a..4dff9dff 100644 --- a/EasyReflectometryApp/Gui/Pages/Summary/Sidebar/Basic/Groups/ExportPlots.qml +++ b/EasyReflectometryApp/Gui/Pages/Summary/Sidebar/Basic/Groups/ExportPlots.qml @@ -1,6 +1,6 @@ -// SPDX-FileCopyrightText: 2025 EasyApp contributors +// SPDX-FileCopyrightText: 2026 EasyApp contributors // SPDX-License-Identifier: BSD-3-Clause -// © 2025 Contributors to the EasyApp project +// © 2026 Contributors to the EasyApp project import QtQuick import QtQuick.Controls diff --git a/EasyReflectometryApp/Gui/Pages/Summary/Sidebar/Basic/Groups/SaveConfirmationDialog.qml b/EasyReflectometryApp/Gui/Pages/Summary/Sidebar/Basic/Groups/SaveConfirmationDialog.qml index 60821c00..52d381c3 100644 --- a/EasyReflectometryApp/Gui/Pages/Summary/Sidebar/Basic/Groups/SaveConfirmationDialog.qml +++ b/EasyReflectometryApp/Gui/Pages/Summary/Sidebar/Basic/Groups/SaveConfirmationDialog.qml @@ -1,6 +1,6 @@ -// SPDX-FileCopyrightText: 2025 EasyApp contributors +// SPDX-FileCopyrightText: 2026 EasyApp contributors // SPDX-License-Identifier: BSD-3-Clause -// © 2025 Contributors to the EasyApp project +// © 2026 Contributors to the EasyApp project import QtQuick import QtQuick.Controls diff --git a/EasyReflectometryApp/Gui/Pages/Summary/Sidebar/Basic/Layout.qml b/EasyReflectometryApp/Gui/Pages/Summary/Sidebar/Basic/Layout.qml index 785186ca..eff2e592 100644 --- a/EasyReflectometryApp/Gui/Pages/Summary/Sidebar/Basic/Layout.qml +++ b/EasyReflectometryApp/Gui/Pages/Summary/Sidebar/Basic/Layout.qml @@ -1,6 +1,6 @@ -// SPDX-FileCopyrightText: 2025 EasyApp contributors +// SPDX-FileCopyrightText: 2026 EasyApp contributors // SPDX-License-Identifier: BSD-3-Clause -// © 2025 Contributors to the EasyApp project +// © 2026 Contributors to the EasyApp project import QtQuick diff --git a/EasyReflectometryApp/Gui/Pages/Summary/Sidebar/Extra/Groups/Empty.qml b/EasyReflectometryApp/Gui/Pages/Summary/Sidebar/Extra/Groups/Empty.qml index e4a92b86..a91951f0 100644 --- a/EasyReflectometryApp/Gui/Pages/Summary/Sidebar/Extra/Groups/Empty.qml +++ b/EasyReflectometryApp/Gui/Pages/Summary/Sidebar/Extra/Groups/Empty.qml @@ -1,6 +1,6 @@ -// 5SPDX-FileCopyrightText: 2025 EasyApp contributors +// 5SPDX-FileCopyrightText: 2026 EasyApp contributors // SPDX-License-Identifier: BSD-3-Clause -// © 2025 Contributors to the EasyApp project +// © 2026 Contributors to the EasyApp project import QtQuick diff --git a/EasyReflectometryApp/Gui/Pages/Summary/Sidebar/Extra/Layout.qml b/EasyReflectometryApp/Gui/Pages/Summary/Sidebar/Extra/Layout.qml index b5e18516..7a78b596 100644 --- a/EasyReflectometryApp/Gui/Pages/Summary/Sidebar/Extra/Layout.qml +++ b/EasyReflectometryApp/Gui/Pages/Summary/Sidebar/Extra/Layout.qml @@ -1,6 +1,6 @@ -// 5SPDX-FileCopyrightText: 2025 EasyApp contributors +// 5SPDX-FileCopyrightText: 2026 EasyApp contributors // SPDX-License-Identifier: BSD-3-Clause -// © 2025 Contributors to the EasyApp project +// © 2026 Contributors to the EasyApp project import QtQuick import QtQuick.Controls diff --git a/EasyReflectometryApp/Gui/PlotControlRefLines.qml b/EasyReflectometryApp/Gui/PlotControlRefLines.qml index e1ee3eeb..6024ddf9 100644 --- a/EasyReflectometryApp/Gui/PlotControlRefLines.qml +++ b/EasyReflectometryApp/Gui/PlotControlRefLines.qml @@ -1,6 +1,6 @@ -// SPDX-FileCopyrightText: 2025 EasyReflectometry contributors +// SPDX-FileCopyrightText: 2026 EasyReflectometry contributors // SPDX-License-Identifier: BSD-3-Clause -// © 2025 Contributors to the EasyReflectometry project +// © 2026 Contributors to the EasyReflectometry project import QtQuick import QtQuick.Controls diff --git a/EasyReflectometryApp/Gui/SldChart.qml b/EasyReflectometryApp/Gui/SldChart.qml index 908b28b3..b560b610 100644 --- a/EasyReflectometryApp/Gui/SldChart.qml +++ b/EasyReflectometryApp/Gui/SldChart.qml @@ -1,6 +1,6 @@ -// SPDX-FileCopyrightText: 2025 EasyReflectometry contributors +// SPDX-FileCopyrightText: 2026 EasyReflectometry contributors // SPDX-License-Identifier: BSD-3-Clause -// © 2025 Contributors to the EasyReflectometry project +// © 2026 Contributors to the EasyReflectometry project import QtQuick import QtQuick.Controls diff --git a/EasyReflectometryApp/main.py b/EasyReflectometryApp/main.py index e89a6b59..e7dc8875 100644 --- a/EasyReflectometryApp/main.py +++ b/EasyReflectometryApp/main.py @@ -1,6 +1,6 @@ -# 5SPDX-FileCopyrightText: 2025 EasyReflectometryApp contributors +# 5SPDX-FileCopyrightText: 2026 EasyReflectometryApp contributors # SPDX-License-Identifier: BSD-3-Clause -# © 2025 Contributors to the EasyReflectometryApp project +# © 2026 Contributors to the EasyReflectometryApp project import argparse import sys from pathlib import Path diff --git a/LICENSE.md b/LICENSE.md index d1859c1a..d29371d4 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,6 +1,6 @@ BSD 3-Clause License -Copyright (c) 2021-2025, European Spallation Source +Copyright (c) 2021-2026, European Spallation Source All rights reserved. Redistribution and use in source and binary forms, with or without diff --git a/utils.py b/utils.py index e3cc2a05..e194e5f8 100755 --- a/utils.py +++ b/utils.py @@ -1,6 +1,6 @@ -# SPDX-FileCopyrightText: 2025 EasyReflectometry contributors +# SPDX-FileCopyrightText: 2026 EasyReflectometry contributors # SPDX-License-Identifier: BSD-3-Clause -# © 2021-2025 Contributors to the EasyReflectometry project +# © 2021-2026 Contributors to the EasyReflectometry project import argparse import datetime From dbbbf2b9b3de435247c36e4a6e3b5c391472fb54 Mon Sep 17 00:00:00 2001 From: Piotr Rozyczko Date: Mon, 23 Mar 2026 17:10:21 +0100 Subject: [PATCH 09/13] update model q-range with experimental range --- .../Backends/Py/experiment.py | 11 ++-- .../Backends/Py/logic/project.py | 53 +++++++++++++++++-- .../Backends/Py/py_backend.py | 1 + 3 files changed, 58 insertions(+), 7 deletions(-) diff --git a/EasyReflectometryApp/Backends/Py/experiment.py b/EasyReflectometryApp/Backends/Py/experiment.py index 4d75d52c..73bd562e 100644 --- a/EasyReflectometryApp/Backends/Py/experiment.py +++ b/EasyReflectometryApp/Backends/Py/experiment.py @@ -12,6 +12,7 @@ class Experiment(QObject): experimentChanged = Signal() externalExperimentChanged = Signal() + qRangeUpdated = Signal() def __init__(self, project_lib: ProjectLib, parent=None): super().__init__(parent) @@ -59,12 +60,16 @@ def load(self, paths: str) -> None: if isinstance(paths, str): paths = paths.split(',') + q_range_changed = False for path in paths: generalized = IO.generalizePath(path) if self._project_logic.count_datasets_in_file(generalized) > 1: - self._project_logic.load_all_experiments_from_file(generalized) + _count, changed = self._project_logic.load_all_experiments_from_file(generalized) else: - self._project_logic.load_new_experiment(generalized) + changed = self._project_logic.load_new_experiment(generalized) + if changed: + q_range_changed = True self.experimentChanged.emit() self.externalExperimentChanged.emit() - pass # debug anchor + if q_range_changed: + self.qRangeUpdated.emit() diff --git a/EasyReflectometryApp/Backends/Py/logic/project.py b/EasyReflectometryApp/Backends/Py/logic/project.py index d13674c2..c5b8b92c 100644 --- a/EasyReflectometryApp/Backends/Py/logic/project.py +++ b/EasyReflectometryApp/Backends/Py/logic/project.py @@ -1,6 +1,7 @@ from copy import copy from pathlib import Path +import numpy as np from easyreflectometry import Project as ProjectLib @@ -107,17 +108,61 @@ def save(self) -> None: def load(self, path: str) -> None: self._project_lib.load_from_json(path) - def load_experiment(self, path: str) -> None: + def load_experiment(self, path: str) -> bool: self._project_lib.load_experiment_for_model_at_index(path, self._project_lib._current_model_index) + return self._sync_q_max_with_loaded_experiments() - def load_new_experiment(self, path: str) -> None: + def load_new_experiment(self, path: str) -> bool: self._project_lib.load_new_experiment(path) + return self._sync_q_max_with_loaded_experiments() def count_datasets_in_file(self, path: str) -> int: return self._project_lib.count_datasets_in_file(path) - def load_all_experiments_from_file(self, path: str) -> int: - return self._project_lib.load_all_experiments_from_file(path) + def load_all_experiments_from_file(self, path: str) -> tuple[int, bool]: + loaded_count = self._project_lib.load_all_experiments_from_file(path) + q_max_changed = self._sync_q_max_with_loaded_experiments() + return loaded_count, q_max_changed + + def _sync_q_max_with_loaded_experiments(self) -> bool: + """Set model q_max to the largest q value found in loaded experiments. + + :return: True if q_max was changed, False otherwise. + :rtype: bool + """ + experiments = self._project_lib._experiments + if not experiments: + return False + + if hasattr(experiments, 'values'): + experiment_iterable = experiments.values() + else: + experiment_iterable = experiments + + q_max_candidates = [] + for experiment in experiment_iterable: + x_values = getattr(experiment, 'x', None) + if x_values is None: + continue + + q_values = np.asarray(x_values, dtype=float) + if q_values.size == 0: + continue + + finite_q_values = q_values[np.isfinite(q_values)] + if finite_q_values.size == 0: + continue + + q_max_candidates.append(float(np.max(finite_q_values))) + + if not q_max_candidates: + return False + + new_q_max = max(q_max_candidates) + if new_q_max != self._project_lib.q_max: + self._project_lib.q_max = new_q_max + return True + return False def set_sample_from_orso(self, sample) -> None: self._project_lib.set_sample_from_orso(sample) diff --git a/EasyReflectometryApp/Backends/Py/py_backend.py b/EasyReflectometryApp/Backends/Py/py_backend.py index f7448c69..cbd3f1d4 100644 --- a/EasyReflectometryApp/Backends/Py/py_backend.py +++ b/EasyReflectometryApp/Backends/Py/py_backend.py @@ -159,6 +159,7 @@ def _connect_sample_page(self) -> None: def _connect_experiment_page(self) -> None: self._experiment.externalExperimentChanged.connect(self._relay_experiment_page_experiment_changed) self._experiment.externalExperimentChanged.connect(self._refresh_plots) + self._experiment.qRangeUpdated.connect(self._sample.qRangeChanged) def _connect_analysis_page(self) -> None: self._analysis.externalMinimizerChanged.connect(self._relay_analysis_page) From e0fa810c25dcff56e4122c5beb3bcb8b98ffc0d7 Mon Sep 17 00:00:00 2001 From: Piotr Rozyczko Date: Mon, 23 Mar 2026 19:10:11 +0100 Subject: [PATCH 10/13] do not grey out editable min/max values --- .../Gui/Pages/Analysis/Sidebar/Basic/Groups/Fittables.qml | 2 -- 1 file changed, 2 deletions(-) diff --git a/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Groups/Fittables.qml b/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Groups/Fittables.qml index 090bb79e..32ec1930 100644 --- a/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Groups/Fittables.qml +++ b/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Groups/Fittables.qml @@ -343,7 +343,6 @@ EaElements.GroupBox { EaComponents.TableViewParameter { enabled: Globals.BackendWrapper.analysisFitableParameters[index].independent !== undefined ? Globals.BackendWrapper.analysisFitableParameters[index].independent : true - minored: true text: EaLogic.Utils.toDefaultPrecision(Globals.BackendWrapper.analysisFitableParameters[index].min).replace('Infinity', 'inf') onEditingFinished: { focus = false @@ -356,7 +355,6 @@ EaElements.GroupBox { EaComponents.TableViewParameter { enabled: Globals.BackendWrapper.analysisFitableParameters[index].independent !== undefined ? Globals.BackendWrapper.analysisFitableParameters[index].independent : true - minored: true text: EaLogic.Utils.toDefaultPrecision(Globals.BackendWrapper.analysisFitableParameters[index].max).replace('Infinity', 'inf') onEditingFinished: { focus = false From d8763ade16a5f2de21673765755a39fa754bb6a5 Mon Sep 17 00:00:00 2001 From: rozyczko Date: Tue, 24 Mar 2026 09:03:24 +0100 Subject: [PATCH 11/13] propagate model name changes to all tabs --- EasyReflectometryApp/Backends/Py/logic/models.py | 5 ++++- EasyReflectometryApp/Backends/Py/py_backend.py | 3 ++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/EasyReflectometryApp/Backends/Py/logic/models.py b/EasyReflectometryApp/Backends/Py/logic/models.py index 37bc1e81..44349cf7 100644 --- a/EasyReflectometryApp/Backends/Py/logic/models.py +++ b/EasyReflectometryApp/Backends/Py/logic/models.py @@ -11,7 +11,10 @@ class Models: def __init__(self, project_lib: ProjectLib): self._project_lib = project_lib - self._models = project_lib._models + + @property + def _models(self) -> ModelCollection: + return self._project_lib._models @property def index(self) -> int: diff --git a/EasyReflectometryApp/Backends/Py/py_backend.py b/EasyReflectometryApp/Backends/Py/py_backend.py index f7448c69..e43a8f38 100644 --- a/EasyReflectometryApp/Backends/Py/py_backend.py +++ b/EasyReflectometryApp/Backends/Py/py_backend.py @@ -152,7 +152,8 @@ def _connect_project_page(self) -> None: def _connect_sample_page(self) -> None: self._sample.externalSampleChanged.connect(self._relay_sample_page_sample_changed) self._sample.externalRefreshPlot.connect(self._refresh_plots) - self._sample.modelsTableChanged.connect(self._analysis.parametersChanged) + self._sample.modelsTableChanged.connect(self._analysis._clearCacheAndEmitParametersChanged) + self._sample.modelsTableChanged.connect(self._analysis.experimentsChanged) # Connect sample changes to multi-experiment selection signal self._sample.modelsTableChanged.connect(self.multiExperimentSelectionChanged) From 274e1ffa963abc172849668708415650d3c65b54 Mon Sep 17 00:00:00 2001 From: rozyczko Date: Tue, 24 Mar 2026 09:36:40 +0100 Subject: [PATCH 12/13] display assembly name prefix for analysis parameters --- .../Backends/Py/logic/parameters.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/EasyReflectometryApp/Backends/Py/logic/parameters.py b/EasyReflectometryApp/Backends/Py/logic/parameters.py index 51386f8b..37ca5428 100644 --- a/EasyReflectometryApp/Backends/Py/logic/parameters.py +++ b/EasyReflectometryApp/Backends/Py/logic/parameters.py @@ -258,11 +258,22 @@ def _make_alias(name: str) -> str: return alias def _get_parameter_display_data(param: Parameter, model_unique_name: str) -> Tuple[str, str]: - """Extract display name and group from parameter path.""" + """Extract display name and group from parameter path. + + For layer parameters (thickness, roughness), uses the assembly name + from the path instead of the layer name, so that renaming an assembly + in the Model Editor is reflected in the Analysis parameters table. + """ path = global_object.map.find_path(model_unique_name, param.unique_name) if len(path) >= 2: - parent_name = global_object.map.get_item_by_key(path[-2]).name param_name = global_object.map.get_item_by_key(path[-1]).name + # For layer parameters the path is: + # Model -> Sample -> Assembly -> LayerCollection -> Layer -> param + # Use the assembly name (path[-4]) instead of the layer name (path[-2]) + if _is_layer_parameter(param) and len(path) >= 4: + parent_name = global_object.map.get_item_by_key(path[-4]).name + else: + parent_name = global_object.map.get_item_by_key(path[-2]).name return f'{parent_name} {param_name}', parent_name return param.name, '' # Fallback to parameter name without group From 37ffbc5ef67f27f6fe30b2d4e1958ed5b7cdd425 Mon Sep 17 00:00:00 2001 From: rozyczko Date: Thu, 26 Mar 2026 10:00:05 +0100 Subject: [PATCH 13/13] merged develop + minor fixes --- .../Backends/Py/experiment.py | 8 +- .../Backends/Py/logic/calculators.py | 4 +- .../Backends/Py/logic/fitting.py | 24 ++- .../Backends/Py/logic/project.py | 7 +- .../Backends/Py/plotting_1d.py | 198 +++++++++++++----- .../Backends/Py/py_backend.py | 10 +- .../Sidebar/Basic/Popups/FitStatusDialog.qml | 2 +- EasyReflectometryApp/Gui/StatusBar.qml | 4 +- tests/test_logic_fitting.py | 4 +- 9 files changed, 184 insertions(+), 77 deletions(-) diff --git a/EasyReflectometryApp/Backends/Py/experiment.py b/EasyReflectometryApp/Backends/Py/experiment.py index 73bd562e..7a0cb7cb 100644 --- a/EasyReflectometryApp/Backends/Py/experiment.py +++ b/EasyReflectometryApp/Backends/Py/experiment.py @@ -64,9 +64,13 @@ def load(self, paths: str) -> None: for path in paths: generalized = IO.generalizePath(path) if self._project_logic.count_datasets_in_file(generalized) > 1: - _count, changed = self._project_logic.load_all_experiments_from_file(generalized) + result = self._project_logic.load_all_experiments_from_file(generalized) + if isinstance(result, tuple): + _count, changed = result + else: + changed = bool(getattr(self._project_logic, '_last_q_range_changed', False)) else: - changed = self._project_logic.load_new_experiment(generalized) + changed = bool(self._project_logic.load_new_experiment(generalized)) if changed: q_range_changed = True self.experimentChanged.emit() diff --git a/EasyReflectometryApp/Backends/Py/logic/calculators.py b/EasyReflectometryApp/Backends/Py/logic/calculators.py index c8ed4002..d5f7f5b9 100644 --- a/EasyReflectometryApp/Backends/Py/logic/calculators.py +++ b/EasyReflectometryApp/Backends/Py/logic/calculators.py @@ -13,10 +13,12 @@ def available(self) -> list[str]: def current_index(self) -> int: return self._current_index - def set_current_index(self, new_value: int) -> None: + def set_current_index(self, new_value: int) -> bool: if new_value != self._current_index: self._current_index = new_value new_calculator = self._list_available_calculators[new_value] + if hasattr(self._project_lib._calculator, 'switch'): + self._project_lib._calculator.switch(new_calculator) self._project_lib.calculator = new_calculator return True return False diff --git a/EasyReflectometryApp/Backends/Py/logic/fitting.py b/EasyReflectometryApp/Backends/Py/logic/fitting.py index db7a7023..263da157 100644 --- a/EasyReflectometryApp/Backends/Py/logic/fitting.py +++ b/EasyReflectometryApp/Backends/Py/logic/fitting.py @@ -2,6 +2,7 @@ from typing import TYPE_CHECKING from typing import List from typing import Optional +from typing import cast from easyreflectometry import Project as ProjectLib from easyscience.fitting import FitResults @@ -31,7 +32,7 @@ def status(self) -> str: if self._result is None: return '' else: - return self._result.success + return str(self._result.success) @property def running(self) -> bool: @@ -105,6 +106,8 @@ def prepare_for_threaded_fit(self) -> None: self._finished = False self._show_results_dialog = False self._fit_error_message = None + self._result = None + self._results = [] def _ordered_experiments(self) -> list: """Return experiments as an ordered list of experiment objects. @@ -118,7 +121,7 @@ def _ordered_experiments(self) -> list: if hasattr(experiments, 'items'): items = list(experiments.items()) try: - items.sort(key=lambda item: item[0]) + items = sorted(items) except TypeError: pass return [experiment for _, experiment in items] @@ -201,7 +204,7 @@ def prepare_threaded_fit(self, minimizers_logic: 'Minimizers') -> tuple: logger.exception('Error preparing threaded fit') return None, None, None, None, None - def on_fit_finished(self, results: List[FitResults]) -> None: + def on_fit_finished(self, results: FitResults | List[FitResults]) -> None: """Handle successful completion of fitting. :param results: List of FitResults from the multi-fitter. @@ -219,25 +222,28 @@ def on_fit_finished(self, results: List[FitResults]) -> None: engine_name = getattr(results[0], 'minimizer_engine', 'unknown') logger.info('Fit finished: engine=%s, chi2=%s, success=%s', engine_name, self.fit_chi2, results[0].success) else: - self._result = results - self._results = [results] if results else [] + single_result = cast(Optional[FitResults], results) + self._result = single_result + self._results = [single_result] if single_result is not None else [] @property def fit_n_pars(self) -> int: """Return the global number of refined parameters for the fit.""" if self._results: - return self._results[0].n_pars + return sum(result.n_pars for result in self._results) if self._result is None: return 0 return self._result.n_pars @property def fit_chi2(self) -> float: - """Return reduced chi-squared across all fits (chi2 / degrees of freedom).""" + """Return reduced chi-squared across all fits.""" if self._results: try: - total_chi2 = float(sum(r.chi2 for r in self._results)) - total_points = sum(len(r.x) for r in self._results) + if len(self._results) == 1: + return float(self._results[0].reduced_chi) + total_chi2 = float(sum(result.chi2 for result in self._results)) + total_points = sum(len(result.x) for result in self._results) n_params = self._results[0].n_pars total_dof = total_points - n_params if total_dof <= 0: diff --git a/EasyReflectometryApp/Backends/Py/logic/project.py b/EasyReflectometryApp/Backends/Py/logic/project.py index c5b8b92c..35c8435d 100644 --- a/EasyReflectometryApp/Backends/Py/logic/project.py +++ b/EasyReflectometryApp/Backends/Py/logic/project.py @@ -8,6 +8,7 @@ class Project: def __init__(self, project_lib: ProjectLib): self._project_lib = project_lib + self._last_q_range_changed = False self._project_lib.default_model() self._update_enablement_of_fixed_layers_for_model(0) @@ -119,10 +120,10 @@ def load_new_experiment(self, path: str) -> bool: def count_datasets_in_file(self, path: str) -> int: return self._project_lib.count_datasets_in_file(path) - def load_all_experiments_from_file(self, path: str) -> tuple[int, bool]: + def load_all_experiments_from_file(self, path: str) -> int: loaded_count = self._project_lib.load_all_experiments_from_file(path) - q_max_changed = self._sync_q_max_with_loaded_experiments() - return loaded_count, q_max_changed + self._last_q_range_changed = self._sync_q_max_with_loaded_experiments() + return loaded_count def _sync_q_max_with_loaded_experiments(self) -> bool: """Set model q_max to the largest q value found in loaded experiments. diff --git a/EasyReflectometryApp/Backends/Py/plotting_1d.py b/EasyReflectometryApp/Backends/Py/plotting_1d.py index a34744b6..32e1521f 100644 --- a/EasyReflectometryApp/Backends/Py/plotting_1d.py +++ b/EasyReflectometryApp/Backends/Py/plotting_1d.py @@ -459,6 +459,22 @@ def individualExperimentDataList(self) -> list: ) return qml_data_list + @Property(float, notify=sampleChartRangesChanged) + def residualMinX(self): + return self._get_residual_range()[0] + + @Property(float, notify=sampleChartRangesChanged) + def residualMaxX(self): + return self._get_residual_range()[1] + + @Property(float, notify=sampleChartRangesChanged) + def residualMinY(self): + return self._get_residual_range()[2] + + @Property(float, notify=sampleChartRangesChanged) + def residualMaxY(self): + return self._get_residual_range()[3] + @Slot(str, str, 'QVariant') def setQtChartsSerieRef(self, page: str, serie: str, ref: QObject): self._chartRefs['QtCharts'][page][serie] = ref @@ -537,70 +553,143 @@ def getExperimentDataPoints(self, experiment_index: int) -> list: console.debug(f'Error getting experiment data points for index {experiment_index}: {e}') return [] - @Slot(int, result='QVariantList') - def getAnalysisDataPoints(self, experiment_index: int) -> list: - """Get measured and calculated data points for a specific experiment for analysis plotting.""" - try: - # Get measured experimental data - exp_data = self._project_lib.experimental_data_for_model_at_index(experiment_index) - - # Get the model index for this experiment - it may be different from experiment_index - # When multiple experiments share the same model - model_index = 0 - model_found = False - if hasattr(exp_data, 'model') and exp_data.model is not None: - # Find the model index in the models collection - for idx, model in enumerate(self._project_lib.models): - if model is exp_data.model: - model_index = idx - model_found = True - break - if not model_found: - console.debug(f'Warning: model for experiment {experiment_index} ' - f'not found in models collection, falling back to model 0') - else: - # Fallback: use experiment_index if it's within model range, else 0 - model_index = experiment_index if experiment_index < len(self._project_lib.models) else 0 + def _get_experiment_model_index(self, experiment_index: int, exp_data=None) -> int: + """Resolve the model index used by a given experiment.""" + if exp_data is not None and hasattr(exp_data, 'model') and exp_data.model is not None: + for idx, model in enumerate(self._project_lib.models): + if model is exp_data.model: + return idx + if experiment_index < len(self._project_lib.models): + return experiment_index + return 0 + + def _get_aligned_analysis_values(self, experiment_index: int) -> list[dict]: + """Return measured, calculated and sigma values aligned on experiment q points.""" + exp_data = self._project_lib.experimental_data_for_model_at_index(experiment_index) + q_values = np.asarray(getattr(exp_data, 'x', np.empty(0)), dtype=float) + measured_values = np.asarray(getattr(exp_data, 'y', np.empty(0)), dtype=float) + sigma_values = np.asarray(getattr(exp_data, 'ye', np.zeros_like(measured_values)), dtype=float) + + if q_values.size == 0 or measured_values.size == 0: + return [] - # Get the q values from the experimental data for calculating the model - q_values = exp_data.x - # Filter to q range - mask = (q_values >= self._project_lib.q_min) & (q_values <= self._project_lib.q_max) - q_filtered = q_values[mask] + q_mask = (q_values >= self._project_lib.q_min) & (q_values <= self._project_lib.q_max) + q_filtered = q_values[q_mask] + measured_filtered = measured_values[q_mask] + sigma_filtered = sigma_values[q_mask] if sigma_values.size else np.zeros_like(measured_filtered) - # Get calculated model data at the same q points using the correct model index + model_index = self._get_experiment_model_index(experiment_index, exp_data) + try: calc_data = self._project_lib.model_data_for_model_at_index(model_index, q_filtered) + except TypeError: + calc_data = self._project_lib.model_data_for_model_at_index(model_index) + + calc_values = np.asarray(getattr(calc_data, 'y', np.empty(0)), dtype=float) + calc_q_values = np.asarray(getattr(calc_data, 'x', np.empty(0)), dtype=float) + + if calc_values.size == q_filtered.size: + calculated_filtered = calc_values + elif calc_values.size == 0: + calculated_filtered = measured_filtered.copy() + elif calc_q_values.size == calc_values.size and calc_values.size > 1: + calculated_filtered = np.interp(q_filtered, calc_q_values, calc_values) + elif calc_values.size == 1: + calculated_filtered = np.full_like(measured_filtered, calc_values[0], dtype=float) + else: + calculated_filtered = np.resize(calc_values, q_filtered.size) + + measured_filtered = self._apply_rq4(q_filtered, measured_filtered) + calculated_filtered = self._apply_rq4(q_filtered, calculated_filtered) + sigma_filtered = self._apply_rq4(q_filtered, sigma_filtered) + + points = [] + for q_value, measured_value, calculated_value, sigma_value in zip( + q_filtered, + measured_filtered, + calculated_filtered, + sigma_filtered, + ): + points.append( + { + 'q': float(q_value), + 'measured': float(measured_value), + 'calculated': float(calculated_value), + 'sigma': float(sigma_value), + } + ) + return points + @Slot(int, result='QVariantList') + def getAnalysisDataPoints(self, experiment_index: int) -> list: + """Get measured and calculated data points for a specific experiment for analysis plotting.""" + try: points = [] - exp_points = list(exp_data.data_points()) - calc_y = calc_data.y - - if len(calc_y) != len(q_filtered): - console.debug(f'Warning: calculated data length ({len(calc_y)}) ' - f'differs from filtered experimental data ({len(q_filtered)}) ' - f'for experiment {experiment_index}') - - calc_idx = 0 - for point in exp_points: - if point[0] < self._project_lib.q_max and self._project_lib.q_min < point[0]: - q = point[0] - r_meas = point[1] - calc_y_val = calc_y[calc_idx] if calc_idx < len(calc_y) else r_meas - r_meas = self._apply_rq4(q, r_meas) - calc_y_val = self._apply_rq4(q, calc_y_val) - points.append( - { - 'x': float(q), - 'measured': float(np.log10(r_meas)), - 'calculated': float(np.log10(calc_y_val)), - } - ) - calc_idx += 1 + for point in self._get_aligned_analysis_values(experiment_index): + measured = point['measured'] + calculated = point['calculated'] + points.append( + { + 'x': point['q'], + 'measured': float(np.log10(measured)) if measured > 0 else -10.0, + 'calculated': float(np.log10(calculated)) if calculated > 0 else -10.0, + } + ) return points except Exception as e: console.debug(f'Error getting analysis data points for index {experiment_index}: {e}') return [] + @Slot(int, result='QVariantList') + def getResidualDataPoints(self, experiment_index: int) -> list: + """Get residual data points for a specific experiment.""" + try: + points = [] + for point in self._get_aligned_analysis_values(experiment_index): + sigma = point['sigma'] + residual = point['calculated'] - point['measured'] + if sigma > 0: + residual = residual / sigma + points.append({'x': point['q'], 'y': float(residual)}) + return points + except Exception as e: + console.debug(f'Error getting residual data points for index {experiment_index}: {e}') + return [] + + def _get_residual_range(self) -> tuple[float, float, float, float]: + """Return residual plot ranges for the current selection.""" + try: + if self.is_multi_experiment_mode: + selected_indices = getattr(self._proxy._analysis, '_selected_experiment_indices', []) + else: + selected_indices = [self._project_lib.current_experiment_index] + + all_points = [] + for experiment_index in selected_indices: + all_points.extend(self.getResidualDataPoints(experiment_index)) + + if not all_points: + return 0.0, 1.0, -1.0, 1.0 + + x_values = np.asarray([point['x'] for point in all_points], dtype=float) + y_values = np.asarray([point['y'] for point in all_points], dtype=float) + if x_values.size == 0 or y_values.size == 0: + return 0.0, 1.0, -1.0, 1.0 + + min_x = float(np.min(x_values)) + max_x = float(np.max(x_values)) + min_y = float(np.min(y_values)) + max_y = float(np.max(y_values)) + + if min_y == max_y: + margin = max(abs(min_y) * 0.05, 1.0) + else: + margin = (max_y - min_y) * 0.05 + + return min_x, max_x, min_y - margin, max_y + margin + except Exception as e: + console.debug(f'Error getting residual range: {e}') + return 0.0, 1.0, -1.0, 1.0 + def refreshSamplePage(self): # Clear cached data so it gets recalculated self._sample_data = {} @@ -617,6 +706,7 @@ def refreshExperimentPage(self): def refreshAnalysisPage(self): self._model_data = {} self.drawCalculatedAndMeasuredOnAnalysisChart() + self.sampleChartRangesChanged.emit() def refreshExperimentRanges(self): """Emit signal to update experiment chart ranges when selection changes.""" diff --git a/EasyReflectometryApp/Backends/Py/py_backend.py b/EasyReflectometryApp/Backends/Py/py_backend.py index 4843af11..bafa69ad 100644 --- a/EasyReflectometryApp/Backends/Py/py_backend.py +++ b/EasyReflectometryApp/Backends/Py/py_backend.py @@ -135,6 +135,11 @@ def plottingGetAnalysisDataPoints(self, experiment_index: int) -> list: """Get measured and calculated data points for a specific experiment for analysis plotting.""" return self._plotting_1d.getAnalysisDataPoints(experiment_index) + @Slot(int, result='QVariantList') + def plottingGetResidualDataPoints(self, experiment_index: int) -> list: + """Get residual data points for a specific experiment for residual plotting.""" + return self._plotting_1d.getResidualDataPoints(experiment_index) + ######### Connections to relay info between the backend parts def _connect_backend_parts(self) -> None: self._connect_project_page() @@ -160,7 +165,8 @@ def _connect_sample_page(self) -> None: def _connect_experiment_page(self) -> None: self._experiment.externalExperimentChanged.connect(self._relay_experiment_page_experiment_changed) self._experiment.externalExperimentChanged.connect(self._refresh_plots) - self._experiment.qRangeUpdated.connect(self._sample.qRangeChanged) + if hasattr(self._experiment, 'qRangeUpdated') and hasattr(self._sample, 'qRangeChanged'): + self._experiment.qRangeUpdated.connect(self._sample.qRangeChanged) def _connect_analysis_page(self) -> None: self._analysis.externalMinimizerChanged.connect(self._relay_analysis_page) @@ -196,12 +202,10 @@ def _relay_project_page_project_changed(self): self._sample.assembliesIndexChanged.emit() self._experiment.experimentChanged.emit() self._analysis.experimentsChanged.emit() - self._analysis._clearCacheAndEmitParametersChanged() self._status.statusChanged.emit() self._summary.summaryChanged.emit() self._plotting_1d.reset_data() self._refresh_plots() - self._plotting_1d.samplePageResetAxes.emit() def _relay_sample_page_sample_changed(self): self._plotting_1d.reset_data() diff --git a/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Popups/FitStatusDialog.qml b/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Popups/FitStatusDialog.qml index 85a5e2b2..45826681 100644 --- a/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Popups/FitStatusDialog.qml +++ b/EasyReflectometryApp/Gui/Pages/Analysis/Sidebar/Basic/Popups/FitStatusDialog.qml @@ -45,7 +45,7 @@ EaElements.Dialog { EaElements.Label { visible: Globals.BackendWrapper.analysisFitSuccess - text: "Chi2: " + Globals.BackendWrapper.analysisFitChi2.toFixed(4) + text: "Reduced Chi2: " + Globals.BackendWrapper.analysisFitChi2.toFixed(4) } EaElements.Label { diff --git a/EasyReflectometryApp/Gui/StatusBar.qml b/EasyReflectometryApp/Gui/StatusBar.qml index 9afb2c96..ff0c676e 100644 --- a/EasyReflectometryApp/Gui/StatusBar.qml +++ b/EasyReflectometryApp/Gui/StatusBar.qml @@ -56,8 +56,8 @@ EaElements.StatusBar { EaElements.StatusBarItem { visible: Globals.BackendWrapper.analysisFitChi2 > 0 keyIcon: 'chart-line' - keyText: qsTr('Chi²') + keyText: qsTr('Reduced Chi²') valueText: Globals.BackendWrapper.analysisFitChi2.toFixed(2) - ToolTip.text: qsTr('Goodness of fit (chi-squared)') + ToolTip.text: qsTr('Goodness of fit (reduced chi-squared)') } } diff --git a/tests/test_logic_fitting.py b/tests/test_logic_fitting.py index 8dc844d2..fcdc3de0 100644 --- a/tests/test_logic_fitting.py +++ b/tests/test_logic_fitting.py @@ -95,12 +95,12 @@ def test_on_fit_finished_and_fit_properties_cover_multi_and_single_results(): assert logic.fit_finished is True assert logic.fit_success is True assert logic.fit_n_pars == 4 - assert logic.fit_chi2 == 10.0 + assert logic.fit_chi2 == 2.0 logic.on_fit_finished(make_fit_result(success=False, chi2=9.0, n_pars=1, x=[1, 2], reduced_chi=4.5)) assert logic.fit_success is False assert logic.fit_n_pars == 1 - assert logic.fit_chi2 == 9.0 + assert logic.fit_chi2 == 4.5 def test_fit_failure_and_cancellation_state_transitions():