-
Notifications
You must be signed in to change notification settings - Fork 1
Sample and resolution model #69
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Conversation
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## develop #69 +/- ##
===========================================
- Coverage 97.83% 96.26% -1.58%
===========================================
Files 16 21 +5
Lines 786 1043 +257
===========================================
+ Hits 769 1004 +235
- Misses 17 39 +22
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
rozyczko
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A few serious issues highlighted in the code. I'll look at minor issues once these are addressed.
Additionally, I think that the naming and inheritance structure is confusing:
SampleModelBase → SampleModel, ResolutionModel, BackgroundModel
But ResolutionModel and BackgroundModel are not sample models - they're instrument-related
InstrumentModel inherits from NewBase (not ModelBase), creating inconsistency
Recommendation: Consider renaming:
SampleModelBase → QDependentModelBase or SpectralModelBase
Or create separate base classes for InstrumentComponentModelBase vs SampleModelBase
| from easyscience.base_classes.model_base import ModelBase | ||
| from numpy.typing import ArrayLike | ||
|
|
||
| from easydynamics.sample_model import ComponentCollection |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
package-level import imports all components and diffusion models.
This makes the base class heavy and increases the chance of circular imports.
Consider direct import from the local module (ComponentCollection) to keep the base layer minimal and avoid side effects.
| components: ModelComponent | ComponentCollection | None = None, | ||
| Q: Q_type | None = None, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Responsibility split is blurry: SampleModelBase owns ComponentCollection and Q, while SampleModel also owns diffusion models and temperature. There is duplication of evaluation logic. Consider a clearer separation where base handles only collection evaluation and subclasses inject preprocessing (like detailed balance) .
| # -------------------------------------------------------------------- | ||
|
|
||
| def __repr__(self): | ||
| return f"{self.__class__.__name__}(unique_name={self.unique_name}, unit={self.unit}), Q = {self.Q}, components = {self.components}" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Didn't you mean self._unit? There's no self.unit here. A test would catch it
| def append_component(self, component: ModelComponent): | ||
| """Append a component to the ResolutionModel. Does not allow DeltaFunction or Polynomial components, as these are not physical resolution components. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This blocks disallowed components, but append_components_from_collection() and the components setter in the base class bypass that check, allowing forbidden components to be inserted indirectly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I've fixed this. Tests will show :)
| def _validate_and_convert_Q(self, Q: Q_type) -> np.ndarray: | ||
| """ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider accepting sc.Variable for consistency
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good idea. Made a todo about moving entirely to scipp for internal use of Q. Will be a while though
| def append_component(self, component: ModelComponent) -> None: | ||
| if not isinstance(component, ModelComponent): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changing Q, adding/removing components, or altering diffusion models does not invalidate or regenerate _component_collections. This can silently return stale results. Consider lazy regeneration or a dirty-flag pattern on Q, components, and diffusion models, as mentioned by you earlier in the discussion
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yup, this will come last once the rest is polished. It's not too terrible to ask users to run generate_component_collections() before they start doing stuff..
| raise TypeError( | ||
| f"unit must be None, a string, or a scipp Unit, got {type(unit).__name__}" | ||
| ) | ||
| self._unit = unit |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing unit property - should be in the base class
| super().__init__( | ||
| display_name=display_name, | ||
| unique_name=unique_name, | ||
| ) | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SampleModelBase.__init__ never initializes self._component_collections but evaluate accesses it! This will raise AttributeError
|
It's missing a few test that I will do soon, and also the "dirty" pattern, but everything else should be there @rozyczko |
First draft of sample and resolution model. If I could get some feedback on the general outline that'd be great. There's still a lot of polishing and testing to be done, but the general idea is there. Try out the
sample_model.ipynbnotebook in examples :)