Single kernel call for volume and intensity#3963
Conversation
There was a problem hiding this comment.
Pull request overview
This PR updates the size distribution model-matrix generation so that both per-bin intensity and volume are obtained via a single sasmodels kernel call, removing the prior duplicated/hard-coded volume math path.
Changes:
- Replaces
load_model/DirectModelusage withload_model_info+build_modelandcall_Fqingenerate_model_matrix. - Computes per-bin intensity from returned kernel outputs and stores per-bin volumes on the class for later use.
Comments suppressed due to low confidence (1)
src/sas/sascalc/size_distribution/SizeDistribution.py:193
self._volumesis initialized twice in__init__(once untyped, then again with a type annotation). This duplication is redundant and can confuse readers/type checkers; remove the earlierself._volumes = Noneassignment and keep the single typed initialization.
self.model_matrix: np.ndarray | None = None
self._volumes = None
# Advanced parameters for MaxEnt
self._iterMax: int = 5000
self._skyBackground: float = 1e-6
self._weightType: str = "dI"
self._weightFactor: float = 1.0
self._weightPercent: float = 1.0
self._weights: np.ndarray | None = np.array(data.dy)
self._bin_edges: np.ndarray = np.array([])
self._binDiff: np.ndarray = np.array([])
self._volumes: np.ndarray | None = None
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
eb993fb to
d921180
Compare
| call_pars = p.copy() | ||
| _, Fsq, _, volume, volume_ratio = call_Fq(calculator, call_pars) | ||
|
|
||
| # Compute intensity using kernel convention: combined_scale = scale / shell_volume |
There was a problem hiding this comment.
This is duplicating code from within sasmodels.kernel.Kernel.Iq. This isn't avoidable in the current implementation, but we should consider this use case when addressing sasmodels #182.
The idea is to return intermediate and derived values from the calculation back to the caller. The current hack to get P@S is that sasmodels.product sets up a kernel.results() function that returns a dictionary with keys P(Q), S(Q), volume, volume_ratio and radius_effective after calling kernel.Iq(). We could extend this to the base Kernel class in sasmodels. Then using call_kernel instead of call_Fq we can get the volume and volume ratio from calculator.results().
|
Hey @pkienzle! Thanks for your review! I have addressed your comments in my recent commit. |
|
_volumes is never used. Is this preparation for a future change? |
I somehow managed to miss one commit. The goal in the issue was to replace |
|
Don't scale volume by volume ratio. Intensity scales with the volume fraction of the material in the shell. Volume ratio is for determining the average volume enclosed by the shape when computing structure factors. Since shape is fixed as ellipsoid then volume ratio is one and you won't see a problem. Maxent on vesicles would be a problem, which you can verify by comparing to maxent on a core-shell model. With background fixed at zero and scale fixed at one you don't need to include them in the intensity calculation. It doesn't hurt, but it doesn't help either. The Outside this PR there are a number of things that could change. Linear systems don't need levenberg-marquardt. For background_fit you can use np.polyfit with deg=0|1 and w=1/σ. PEP8 recommends short snake_case rather than CamelCase for module names, so PEP8 recommends CamelCase for class names and snake_case for functions and methods, such as Shouldn't be using a builtin function like In The weight type setter in size distribution is suspect. It is calling update weights with default None for the full data, whereas the prep maxent call is using a trimmed q range for the data. Easiest if changing weight type does nothing special since the prep maxent call provides the data for weights. More generally, the size distribution controls aren't going to change during analysis, so they should be set as arguments to the constructor rather than assigned as attributes. SizeDistributionThread is accessing "private" |
|
Please fix the merge conflicts and remove the volume ratio scaling. Code style can be put in as a separate issue if you want to minimize changes for this PR. |
Description
Removes hard-coded/duplicated volume math and ensures intensities/volumes come from the model kernel.
Replaces the previous per-bin DirectModel/analytic volume approach with a kernel-based single call.
Builds the sasmodels kernel (from model info) and calls
call_Fqfor each bin to retrieve Fsq and volume. Compute intensity per bin asintensity = (scale/volume) * Fsq + backgroundand store per-bin volumes inself._volumes.Fixes #3418
How Has This Been Tested?
Tested functionality -- same as before.
Review Checklist:
Documentation
Installers
Licensing