From 95d788598b1aaff20ffc7b393515d22a38aa6357 Mon Sep 17 00:00:00 2001 From: henrikjacobsenfys Date: Wed, 15 Apr 2026 15:49:30 +0200 Subject: [PATCH 1/2] Fix bug when there is only one Q index --- pixi.lock | 4 +- pyproject.toml | 3 +- src/easydynamics/analysis/analysis.py | 38 +++++++++----- .../easydynamics/analysis/test_analysis.py | 49 +++++++++++++++++++ 4 files changed, 78 insertions(+), 16 deletions(-) diff --git a/pixi.lock b/pixi.lock index efafa5aa..e423bfad 100644 --- a/pixi.lock +++ b/pixi.lock @@ -3888,8 +3888,8 @@ packages: requires_python: '>=3.5' - pypi: ./ name: easydynamics - version: 0.4.0+dev5 - sha256: ff8f55922804cdb622d0eb0aecd00105aeb30e470aa79b05bf6f92556ad8ce67 + version: 0.4.0+devdirty5 + sha256: 23d0790d25938acbe8e96780e087d1b29916963a0f6b4d04b906012d906c5cfb requires_dist: - darkdetect - easyscience diff --git a/pyproject.toml b/pyproject.toml index 17452cd7..befd67f4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -256,8 +256,7 @@ select = [ # Ignore specific rules globally ignore = [ 'COM812', # https://docs.astral.sh/ruff/rules/missing-trailing-comma/ - # The following is replaced by 'D'/[tool.ruff.lint.pydocstyle] and [tool.pydoclint] - 'DOC', # https://docs.astral.sh/ruff/rules/#pydoclint-doc + # The following is replaced by 'D'/[tool.ruff.lint.pydocstyle] and [tool.pydoclint] 'DOC', # https://docs.astral.sh/ruff/rules/#pydoclint-doc # Disable, as [tool.format_docstring] split one-line docstrings into the canonical multi-line layout 'D200', # https://docs.astral.sh/ruff/rules/unnecessary-multiline-docstring/ ] diff --git a/src/easydynamics/analysis/analysis.py b/src/easydynamics/analysis/analysis.py index bb937e34..1acdeca1 100644 --- a/src/easydynamics/analysis/analysis.py +++ b/src/easydynamics/analysis/analysis.py @@ -71,17 +71,8 @@ def __init__( self._analysis_list = [] if self.Q is not None: - for Q_index in range(len(self.Q)): - analysis = Analysis1d( - display_name=f'{self.display_name}_Q{Q_index}', - unique_name=(f'{self.unique_name}_Q{Q_index}'), - experiment=self.experiment, - sample_model=self.sample_model, - instrument_model=self.instrument_model, - extra_parameters=self._extra_parameters, - Q_index=Q_index, - ) - self._analysis_list.append(analysis) + self._create_analysis_list() + # Now we can allow updates to trigger recalculations self._call_updaters = True @@ -519,6 +510,24 @@ def _on_instrument_model_changed(self) -> None: for analysis in self.analysis_list: analysis.instrument_model = self.instrument_model + def _create_analysis_list(self) -> None: + """ + Create the list of Analysis1d objects, one for each Q index, based on the current + experiment, sample model, and instrument model. + """ + self._analysis_list = [] + for Q_index in range(len(self.Q)): + analysis = Analysis1d( + display_name=f'{self.display_name}_Q{Q_index}', + unique_name=(f'{self.unique_name}_Q{Q_index}'), + experiment=self.experiment, + sample_model=self.sample_model, + instrument_model=self.instrument_model, + extra_parameters=self._extra_parameters, + Q_index=Q_index, + ) + self._analysis_list.append(analysis) + ############# # Private methods ############# @@ -661,7 +670,12 @@ def _create_components_dataset( for analysis in self.analysis_list ] - return sc.concat(datasets, dim='Q') + ds = sc.concat(datasets, dim='Q') + + if len(datasets) == 1: + ds = ds.assign_coords(Q=self.Q) + + return ds ############# # Dunder methods diff --git a/tests/unit/easydynamics/analysis/test_analysis.py b/tests/unit/easydynamics/analysis/test_analysis.py index 25274a55..0338c9e4 100644 --- a/tests/unit/easydynamics/analysis/test_analysis.py +++ b/tests/unit/easydynamics/analysis/test_analysis.py @@ -41,6 +41,31 @@ def analysis(self): extra_parameters=None, ) + @pytest.fixture + def analysis_single_Q(self): + Q = sc.array(dims=['Q'], values=[1, 2, 3], unit='1/Angstrom') + energy = sc.array(dims=['energy'], values=[10.0, 20.0, 30.0], unit='meV') + data = sc.array( + dims=['Q', 'energy'], + values=[[1.0, 2.0, 3.0], [4.0, 5.0, 6.0], [7.0, 8.0, 9.0]], + variances=[[0.1, 0.2, 0.3], [0.4, 0.5, 0.6], [0.7, 0.8, 0.9]], + ) + + data_array = sc.DataArray(data=data, coords={'Q': Q, 'energy': energy}) + + experiment = Experiment(data=data_array) + experiment.rebin({'Q': 1}) + sample_model = SampleModel(components=Gaussian(), display_name='Gaussian') + instrument_model = InstrumentModel() + + return Analysis( + display_name='TestAnalysis', + experiment=experiment, + sample_model=sample_model, + instrument_model=instrument_model, + extra_parameters=None, + ) + def test_init(self, analysis): # WHEN THEN @@ -729,3 +754,27 @@ def test_create_components_dataset(self, analysis): assert component_name in components_dataset assert 'Q' in components_dataset[component_name].dims assert 'energy' in components_dataset[component_name].dims + assert components_dataset.sizes['Q'] == analysis.Q.sizes['Q'] + + def test_create_components_dataset_single_Q(self, analysis_single_Q): + # WHEN + + # Add another component so that there are two components + analysis_single_Q.sample_model.append_component( + Gaussian(display_name='Gaussian2', area=0.5) + ) + + # THEN + components_dataset = analysis_single_Q._create_components_dataset(add_background=True) + + # THEN EXPECT + assert isinstance(components_dataset, sc.Dataset) + component_names = [comp.display_name for comp in analysis_single_Q.sample_model.components] + for component_name in component_names: + assert component_name in components_dataset + assert 'Q' in components_dataset[component_name].dims + assert 'energy' in components_dataset[component_name].dims + + assert components_dataset.coords['Q'].dims == ('Q',) + assert components_dataset.sizes['Q'] == 1 + assert components_dataset.coords['Q'].ndim == 1 From 48c56b67787f9d2322305e739eb03d58104489e9 Mon Sep 17 00:00:00 2001 From: henrikjacobsenfys Date: Mon, 20 Apr 2026 13:16:09 +0200 Subject: [PATCH 2/2] PR comment --- pixi.lock | 4 ++-- src/easydynamics/analysis/analysis.py | 6 +----- src/easydynamics/convolution/numerical_convolution_base.py | 6 +++--- 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/pixi.lock b/pixi.lock index e423bfad..0d2efa1f 100644 --- a/pixi.lock +++ b/pixi.lock @@ -3888,8 +3888,8 @@ packages: requires_python: '>=3.5' - pypi: ./ name: easydynamics - version: 0.4.0+devdirty5 - sha256: 23d0790d25938acbe8e96780e087d1b29916963a0f6b4d04b906012d906c5cfb + version: 0.4.0+devdirty10 + sha256: 03e3e912335d4cddf2e70179da113fb35cb4cad133450b3a9e8583aaf5927e6e requires_dist: - darkdetect - easyscience diff --git a/src/easydynamics/analysis/analysis.py b/src/easydynamics/analysis/analysis.py index 92b128b4..fe238166 100644 --- a/src/easydynamics/analysis/analysis.py +++ b/src/easydynamics/analysis/analysis.py @@ -675,11 +675,7 @@ def _create_components_dataset( ] ds = sc.concat(datasets, dim='Q') - - if len(datasets) == 1: - ds = ds.assign_coords(Q=self.Q) - - return ds + return ds.assign_coords(Q=self.Q) ############# # Dunder methods diff --git a/src/easydynamics/convolution/numerical_convolution_base.py b/src/easydynamics/convolution/numerical_convolution_base.py index 818579ac..c49245c7 100644 --- a/src/easydynamics/convolution/numerical_convolution_base.py +++ b/src/easydynamics/convolution/numerical_convolution_base.py @@ -66,13 +66,13 @@ def __init__( The factor by which to extend the input data range before convolution. temperature : Parameter | Numeric | None, default=None The temperature to use for detailed balance correction. - temperature_unit : str | sc.Unit, default="K" + temperature_unit : str | sc.Unit, default='K' The unit of the temperature parameter. - unit : str | sc.Unit, default="meV" + unit : str | sc.Unit, default='meV' The unit of the energy. normalize_detailed_balance : bool, default=True Whether to normalize the detailed balance correction. - display_name : str | None, default="MyConvolution" + display_name : str | None, default='MyConvolution' Display name of the model. unique_name : str | None, default=None Unique name of the model. If None, a unique name will be generated.