Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
1d5643a
initial analysis class
henrikjacobsenfys Feb 3, 2026
5e460ce
make analysis_base
henrikjacobsenfys Feb 6, 2026
74629d8
test things in notebook
henrikjacobsenfys Feb 6, 2026
9af6322
reintroduce energy_offset in convolution. It's needed.
henrikjacobsenfys Feb 6, 2026
ba85d95
Progress on Analysis
henrikjacobsenfys Feb 6, 2026
1c77784
multiple parameters with same unique_name?????
henrikjacobsenfys Feb 8, 2026
8c37ee4
fitting and plotting for multiple Q
henrikjacobsenfys Feb 10, 2026
b477a38
analysis MWP
henrikjacobsenfys Feb 11, 2026
08cdef2
Add plotting of parameters and examples
henrikjacobsenfys Feb 12, 2026
02158a1
Update failing tests
henrikjacobsenfys Feb 12, 2026
b9d3fec
Instrument model (#94)
henrikjacobsenfys Feb 5, 2026
248773d
initial analysis class
henrikjacobsenfys Feb 3, 2026
ce9acf8
fix merge conflict
henrikjacobsenfys Feb 12, 2026
f16a7e3
Remove notebook
henrikjacobsenfys Feb 12, 2026
7a31120
Update notebook, remove unused file
henrikjacobsenfys Feb 12, 2026
10d085e
pixi run fix
henrikjacobsenfys Feb 12, 2026
4e3d1c4
add missing tests
henrikjacobsenfys Feb 12, 2026
703d824
More missing tests
henrikjacobsenfys Feb 12, 2026
e343767
test analysis_base
henrikjacobsenfys Feb 12, 2026
fb7682c
100% coverage of base
henrikjacobsenfys Feb 12, 2026
51194a5
Test analysis1d
henrikjacobsenfys Feb 16, 2026
0972807
Another test
henrikjacobsenfys Feb 16, 2026
d054345
More analysis1d tests
henrikjacobsenfys Feb 17, 2026
9c01ffc
linting
henrikjacobsenfys Feb 17, 2026
61f49bd
update component_collection among other things
henrikjacobsenfys Feb 18, 2026
5178525
Add a few more tests
henrikjacobsenfys Feb 18, 2026
ad0689b
fix failing test
henrikjacobsenfys Feb 18, 2026
1b31537
Update analyis example
henrikjacobsenfys Feb 22, 2026
9b4548c
analysis tests
henrikjacobsenfys Feb 23, 2026
21da9d3
Minor fixes and tests
henrikjacobsenfys Feb 23, 2026
5d01a44
one more test
henrikjacobsenfys Feb 23, 2026
2c16a51
more tests
henrikjacobsenfys Feb 23, 2026
60aefa2
Update docstrings for AnalysisBase
henrikjacobsenfys Feb 25, 2026
9f381a1
pixi run fix
henrikjacobsenfys Feb 25, 2026
5e46e46
pixi run fix
henrikjacobsenfys Feb 25, 2026
918d6b9
more docstring for analysis1d
henrikjacobsenfys Feb 25, 2026
c9d4770
finish analysis1d docstring
henrikjacobsenfys Feb 25, 2026
7385c9a
react to PR comments
henrikjacobsenfys Feb 25, 2026
9c48b80
Update analysis.py docstrings
henrikjacobsenfys Feb 25, 2026
f49abdb
Handle changes to experiment etc in analysis
henrikjacobsenfys Feb 25, 2026
6af16cd
fix updaters
henrikjacobsenfys Feb 25, 2026
ee21733
More tests and response to PR comments
henrikjacobsenfys Feb 27, 2026
c330bb2
More docstrings
henrikjacobsenfys Feb 27, 2026
99953fd
Merge branch 'develop' into more-docstring
henrikjacobsenfys Feb 28, 2026
899916a
fix merge conflicts properly
henrikjacobsenfys Feb 28, 2026
0c4c064
make math render properly
henrikjacobsenfys Mar 2, 2026
a697324
minor update
henrikjacobsenfys Mar 2, 2026
9a7ec4d
minor update
henrikjacobsenfys Mar 2, 2026
17f66df
update conftest
henrikjacobsenfys Mar 3, 2026
faa6815
Delete conftest content since weakref bug has been fixed
henrikjacobsenfys Mar 3, 2026
3943b4f
Merge branch 'develop' into more-docstring
henrikjacobsenfys Mar 4, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/easydynamics/analysis/analysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -374,7 +374,7 @@ def plot_parameters(

Returns:
InteractiveFigure: A Plopp InteractiveFigure containing the
plot of the parameters.
plot of the parameters.
"""

ds = self.parameters_to_dataset()
Expand Down
12 changes: 9 additions & 3 deletions src/easydynamics/convolution/convolution.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,9 +136,15 @@ def convolution(
return total

def _convolve_delta_functions(self) -> np.ndarray:
"Convolve delta function components of the sample model with"
'the resolution components.'
'No detailed balance correction is applied to delta functions.'
"""Convolve delta function components of the sample model with
the resolution components. No detailed balance correction is
applied to delta functions.

Returns:
np.ndarray
The convolved values of the delta function components
evaluated at energy.
"""
return sum(
delta.area.value
* self._resolution_components.evaluate(
Expand Down
25 changes: 12 additions & 13 deletions src/easydynamics/convolution/convolution_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,14 @@ class ConvolutionBase:
base class has no convolution functionality.

Args:
energy : np.ndarray or scipp.Variable
1D array of energy values where the convolution is evaluated.
sample_components : ComponentCollection or ModelComponent
The sample model to be convolved.
resolution_components : ComponentCollection or ModelComponent
The resolution model to convolve with.
energy_unit : str or sc.Unit, optional
The unit of the energy. Default is 'meV'.
energy : np.ndarray or scipp.Variable
1D array of energy values where the convolution is evaluated
sample_components : ComponentCollection or ModelComponent
The sample model to be convolved.
resolution_components : ComponentCollection or ModelComponent
The resolution model to convolve with.
energy_unit : str or sc.Unit, optional
The unit of the energy. Default is 'meV'.
"""

def __init__(
Expand Down Expand Up @@ -126,16 +126,15 @@ def energy(self) -> sc.Variable:
return self._energy

@energy.setter
def energy(self, energy: np.ndarray) -> None:
def energy(self, energy: np.ndarray | sc.Variable) -> None:
"""Set the energy.
Args:
energy : np.ndarray or scipp.Variable
1D array of energy values where the convolution is
evaluated.
energy (np.ndarray | scipp.Variable): 1D array of energy
values where the convolution is evaluated.

Raises:
TypeError: If energy is not a numpy ndarray or a
scipp Variable.
scipp Variable.
"""

if isinstance(energy, Numeric):
Expand Down
134 changes: 119 additions & 15 deletions src/easydynamics/experiment/experiment.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,21 @@ class Experiment(NewBase):

This is a minimal implementation that will be extended in the
future.

Args:
display_name (str): Display name of the experiment.
unique_name (str | None): Unique name of the experiment. If
None, a unique name will be generated.
data (sc.DataArray | str | None): Dataset associated with the
experiment. Can be a sc.DataArray or a filename string to
load from. If None, no data is loaded.

Attributes:
data (sc.DataArray | None): Dataset associated with the
experiment.
binned_data (sc.DataArray | None): Binned dataset associated
with the experiment. This is derived from `data` and is updated
whenever `data` is set.
"""

def __init__(
Expand Down Expand Up @@ -50,12 +65,26 @@ def __init__(

@property
def data(self) -> sc.DataArray | None:
"""Get the dataset associated with this experiment."""
"""Get the dataset associated with this experiment.

Returns:
sc.DataArray | None: The dataset associated with this
experiment, or None if no data is loaded.
"""
return self._data

@data.setter
def data(self, value: sc.DataArray) -> None:
"""Set the dataset associated with this experiment."""
"""Set the dataset associated with this experiment.

Args:
value (sc.DataArray): The new dataset to associate with this
experiment.

Raises:
TypeError: If the value is not a sc.DataArray.
ValueError: If the dataset is missing required coordinates.
"""
if not isinstance(value, sc.DataArray):
raise TypeError(f'Data must be a sc.DataArray, not {type(value).__name__}')
self._validate_coordinates(value)
Expand All @@ -66,36 +95,76 @@ def data(self, value: sc.DataArray) -> None:

@property
def binned_data(self) -> sc.DataArray | None:
"""Get the binned dataset associated with this experiment."""
"""Get the binned dataset associated with this experiment.

Returns:
sc.DataArray | None: The binned dataset associated with this
experiment, or None if no data is loaded.
"""
return self._binned_data

@binned_data.setter
def binned_data(self, value: sc.DataArray) -> None:
"""Set the binned dataset associated with this experiment."""
"""Set the binned dataset associated with this experiment. Read-
only property. Use rebin() to rebin the data instead.

Args:
value (sc.DataArray): The new binned dataset to associate
with this experiment (ignored)

Raises:
AttributeError: Always, since binned_data is read-only.
"""
raise AttributeError('binned_data is a read-only property. Use rebin() to rebin the data')

@property
def Q(self) -> sc.Variable | None:
"""Get the Q values from the dataset."""
"""Get the Q values from the dataset.

Returns:
sc.Variable | None: The Q values from the dataset, or None
if no data is loaded.
"""
if self._data is None:
return None
return self._binned_data.coords['Q']

@Q.setter
def Q(self, value: sc.Variable) -> None:
"""Set the Q values for the dataset."""
"""Set the Q values for the dataset. Q is a read-only property
derived from the data, so this setter raises an error.

Args:
value (sc.Variable): The new Q values to set (ignored)

Raises:
AttributeError: Always, since Q is read-only.
"""
raise AttributeError('Q is a read-only property derived from the data.')

@property
def energy(self) -> sc.Variable | None:
"""Get the energy values from the dataset."""
"""Get the energy values from the dataset.

Returns:
sc.Variable | None: The energy values from the dataset, or
None if no data is loaded.
"""
if self._data is None:
return None
return self._binned_data.coords['energy']

@energy.setter
def energy(self, value: sc.Variable) -> None:
"""Set the energy values for the dataset."""
"""Set the energy values for the dataset. Energy is a read-only
property derived from the data, so this setter raises an error.

Args:
value (sc.Variable): The new energy values to set (ignored)

Raises:
AttributeError: Always, since energy is read-only.
"""
raise AttributeError('energy is a read-only property derived from the data.')

###########
Expand All @@ -109,6 +178,12 @@ def load_hdf5(self, filename: str, display_name: str | None = None):
filename (str ): Path to the HDF5 file.
display_name (str | None): Optional display name for the
experiment.

Raises:
TypeError: If filename is not a string or if display_name is
not a string or None.
ValueError: If the loaded data is missing required
coordinates.
"""
if not isinstance(filename, str):
raise TypeError(f'Filename must be a string, not {type(filename).__name__}')
Expand All @@ -133,6 +208,12 @@ def save_hdf5(self, filename: str | None = None):

Args:
filename (str | None): Path to the output HDF5 file.
If None, the file will be named after the unique_name of
the experiment with a .h5 extension.

Raises:
TypeError: If filename is not a string or None.
ValueError: If there is no data to save.
"""

if filename is None:
Expand Down Expand Up @@ -160,12 +241,13 @@ def rebin(self, dimensions: dict[str, int | sc.Variable]) -> None:

Args:
dimensions (dict[str, int | sc.Variable]): A dictionary
mapping dimension names to number of bins (int) or bin edges
(sc.Variable).
mapping dimension names to number of bins (int) or bin
edges (sc.Variable).

Raises:
TypeError: If dimensions is not a dictionary or if
keys/values are of incorrect types. KeyError: If a specified
dimension is not in the dataset.
keys/values are of incorrect types.
KeyError: If a specified dimension is not in the dataset.
"""

if not isinstance(dimensions, dict):
Expand Down Expand Up @@ -208,7 +290,16 @@ def rebin(self, dimensions: dict[str, int | sc.Variable]) -> None:
###########

def plot_data(self, slicer=False, **kwargs) -> None:
"""Plot the dataset using plopp."""
"""Plot the dataset using plopp: https://scipp.github.io/plopp/

Args:
slicer (bool): If True, use plopp's slicer instead of plot.
**kwargs: Additional keyword arguments to pass to plopp.

Raises:
ValueError: If there is no data to plot.
RuntimeError: If not in a Jupyter notebook environment.
"""

if self._binned_data is None:
raise ValueError('No data to plot. Please load data first.')
Expand Down Expand Up @@ -243,6 +334,9 @@ def plot_data(self, slicer=False, **kwargs) -> None:
def _validate_coordinates(data: sc.DataArray) -> None:
"""Validate that required coordinates are present in the data.

Args:
data (sc.DataArray): The data to validate.

Raises:
ValueError: If required coordinates are missing.
"""
Expand All @@ -258,7 +352,7 @@ def _convert_to_bin_centers(self, data: sc.DataArray) -> sc.DataArray:
"""Convert the coordinates of the data to bin centers.

Args:
data (sc.DataArray): The data to check.
data (sc.DataArray): The data to convert.

Returns:
sc.DataArray: The data with coordinates at bin centers.
Expand All @@ -275,10 +369,20 @@ def _convert_to_bin_centers(self, data: sc.DataArray) -> sc.DataArray:
###########

def __repr__(self) -> str:
"""Return a string representation of the Experiment object.

Returns:
str: A string representation of the Experiment object.
"""

return f'Experiment `{self.unique_name}` with data: {self._data}'

def __copy__(self) -> 'Experiment':
"""Return a copy of the object."""
"""Return a copy of the object.

Returns:
Experiment: A copy of the Experiment object.
"""
temp = self.to_dict(skip=['unique_name'])
new_obj = self.__class__.from_dict(temp)
new_obj.data = self.data.copy() if self.data is not None else None
Expand Down
35 changes: 19 additions & 16 deletions src/easydynamics/sample_model/background_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,22 +14,25 @@ class BackgroundModel(ModelBase):
"""BackgroundModel represents a model of the background in an
experiment at various Q.

Parameters
----------
display_name : str
Display name of the model.
unique_name : str | None
Unique name of the model. If None, a unique name will be
generated.
unit : str | sc.Unit | None
Unit of the model. If None, unitless.
components : ModelComponent | ComponentCollection | None
Template components of the model. If None, no components are
added.
These components are copied into ComponentCollections for each
Q value.
Q : Q_type | None
Q values for the model. If None, Q is not set.
Args:
display_name (str): Display name of the model.
unique_name (str | None): Unique name of the model. If None, a
unique name will be generated.
unit (str | sc.Unit | None): Unit of the model. Defaults to
"meV".
components (ModelComponent | ComponentCollection | None):
Template components of the model. If None, no components
are added. These components are copied into
ComponentCollections for each Q value.
Q (Q_type | None): Q values for the model. If None, Q is not
set.

Attributes:
unit (str | sc.Unit): Unit of the model.
components (list[ModelComponent]): List of ModelComponents in
the model.
Q (np.ndarray | Numeric | list | ArrayLike | sc.Variable
| None): Q values of the model.
"""

def __init__(
Expand Down
Loading
Loading