Skip to content

Analysis#100

Merged
henrikjacobsenfys merged 44 commits intodevelopfrom
analysis
Feb 28, 2026
Merged

Analysis#100
henrikjacobsenfys merged 44 commits intodevelopfrom
analysis

Conversation

@henrikjacobsenfys
Copy link
Member

@henrikjacobsenfys henrikjacobsenfys commented Feb 12, 2026

This implements the analysis class, consisting of a base class, analysis1d and analysis as discussed here: easyscience/dynamics#5

Furthermore, it implements energy_offset in Convolution, as this is required.

Finally, some small refactoring and bug fixes also found their way into this PR

@henrikjacobsenfys henrikjacobsenfys added [scope] enhancement Adds/improves features (major.MINOR.patch) [priority] medium Normal/default priority labels Feb 12, 2026
@codecov
Copy link

codecov bot commented Feb 12, 2026

Codecov Report

❌ Patch coverage is 97.50958% with 13 lines in your changes missing coverage. Please review.
⚠️ Please upload report for BASE (develop@33b093b). Learn more about missing BASE report.

Files with missing lines Patch % Lines
src/easydynamics/analysis/analysis.py 93.63% 5 Missing and 5 partials ⚠️
src/easydynamics/analysis/analysis_base.py 98.19% 1 Missing and 1 partial ⚠️
src/easydynamics/analysis/analysis1d.py 99.28% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             develop     #100   +/-   ##
==========================================
  Coverage           ?   98.12%           
==========================================
  Files              ?       36           
  Lines              ?     2292           
  Branches           ?      375           
==========================================
  Hits               ?     2249           
  Misses             ?       23           
  Partials           ?       20           
Flag Coverage Δ
integration 0.00% <0.00%> (?)
unittests 98.12% <97.50%> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@henrikjacobsenfys henrikjacobsenfys marked this pull request as ready for review February 23, 2026 12:27
Copy link
Member

@rozyczko rozyczko left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Part 1. More to come

Comment on lines 5 to 6
from inspect import Parameter

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This imports inspect.Parameter (a function signature parameter descriptor) instead of easyscience.variable.Parameter. The type hints on line 72 use this incorrectly imported Parameter class for extra_parameters, which will cause type confusion and potential runtime issues.

Copy link
Member Author

@henrikjacobsenfys henrikjacobsenfys Feb 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Haha oops. I blame the tab button.

Comment on lines +339 to +340
weights = 1.0 / e
return x, y, weights
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you sure the variances are never zero? Maybe make a check here?

if np.any(e == 0):
    raise ValueError('Cannot compute weights: some variances are zero.')

Comment on lines +45 to +53
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,
)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Analysis class creates Analysis1d objects in __init__ with references to experiment, sample_model, and instrument_model.
However, when these properties are changed via setters (inherited from AnalysisBase), the Analysis1d objects in _analysis_list are not regenerated.

This means that changing experiment won't update the data used by individual Q analyses and changing sample_model won't update the components used for fitting.

you could potentially override the setters in Analysis class or add regeneration logic:

def _on_experiment_changed(self) -> None:
    super()._on_experiment_changed()
    self._regenerate_analysis_list()

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, this is really important! I'll save it for last since it requires some thinking.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I fixed it. The logic behind updating sample models etc needs an overhaul. For now, I think what I have works, and then I'll have to think about how to do it properly. The issue is to find a balance between keeping everything up to date while not overwriting any changes users have made.

Comment on lines 134 to 135
Args:
energy (float): The energy value to calculate the model for.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see any arguments in the method signature?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed docstring :)

Comment on lines 218 to 223
Args:
add_background (bool): Whether to add the background to the
model prediction when plotting individual components.

kwargs: Keyword arguments to pass to the plotting
function.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

missing plot_components arg description
missing return value type (-> None)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This has not been addressed yet

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be fixed now

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

image This is how it looks on my computer. I don't understand why it doesn't show up here

Comment on lines 267 to 268
**kwargs,
) -> None:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not -> None but plopp figure object

Comment on lines 310 to 311
ValueError: If the Q index is not valid.
"""
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's IndexError raised (line 318)

@henrikjacobsenfys
Copy link
Member Author

I'm working on fixing the docstrings for analysis.py, so don't worry too much about them :)

Copy link
Member

@rozyczko rozyczko left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This time more sinister issues found.

Also,
Current tests are OK, but some aspects are not covered:

  • Analysis lifecycle rebuild behavior after replacing experiment/sample/instrument
  • ConvolutionBase.convert_energy_unit with non-zero energy_offset
  • ConvolutionBase setter path when assigning single ModelComponent

Comment on lines 180 to 181
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This converts self.energy but not self.energy_offset.
energy_with_offset then subtracts a value in the old unit from energy in the new unit.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, fixed!

Comment on lines 189 to 191
def sample_components(self, sample_components: ComponentCollection | ModelComponent) -> None:
"""Set the sample model.
Args:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sample_components (and resolution_components) setters accept both ComponentCollection | ModelComponent but do not wrap ModelComponent into ComponentCollection.

Downstream, Convolution assumes .components exists on these attributes.

e.g.

conv.sample_components = Gaussian()
conv.convolution()
AttributeError: 'Gaussian' object has no attribute 'components'.

Same for resolution_components.

You could just mirror __init__ behavior inside setters:
if input is ModelComponent, wrap as ComponentCollection([component]).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice spot. I had encountered this problem elsewhere (hense the fix in the init), but did not realise I hadn't fixed the setters.

@henrikjacobsenfys
Copy link
Member Author

I think I fixed all the problems (and a few minor things that I found because I wanted to get high code coverage :) ) @rozyczko

@rozyczko
Copy link
Member

Analysis.plot_data_and_model still declares return value None and doesn't return the figure object, but its Analysis1d counterpart declares and returns InteractiveFigure. Is this discrepancy as expected?

@henrikjacobsenfys
Copy link
Member Author

Analysis.plot_data_and_model still declares return value None and doesn't return the figure object, but its Analysis1d counterpart declares and returns InteractiveFigure. Is this discrepancy as expected?

That's just me being silly. It now returns the figure

Copy link
Member

@rozyczko rozyczko left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good now :)

@henrikjacobsenfys henrikjacobsenfys merged commit 9eeee30 into develop Feb 28, 2026
34 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

[priority] medium Normal/default priority [scope] enhancement Adds/improves features (major.MINOR.patch)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants