Repository navigation
fix: MLLS composition counts a negative amount as not detected and keeps the other elements - #81
Merged
Merged
Conversation
…eps the other elements Found in an app EELS room: with C K, N K and O K picked and N absent, the unconstrained MLLS amount of N came out below zero, and composition(_: EELSMLLSResult, symbols:) refused the whole pixel, so C and O lost their at% and wt% too. An amount at or below zero now counts as 0 at% and 0 wt%, is flagged in the new EELSCompositionPixel.notDetected, and the others are normalised among themselves. This is a kit decision consistent with the non-negative model fit, which gives an absent element 0. exSpy has no EELS composition; its EDS Cliff-Lorimer passes a negative line through as a negative fraction. noComposition now means no amount is above zero. Pixels with every amount positive are bit-identical. The model-fit composition fills notDetected; its numbers do not change. Done: per-element not-detected rule for MLLS composition, red-first test. Next: the app shows not-detected elements in the footer and the table. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Contributor
Author
|
Checked on 3 real EELS spectrum images (C K, N K, O K picked; N absent) through the macTEM EELS room, with this change on top of 0.12.0. Before: every MLLS at% and wt% pixel was NaN and the table had no at% or wt%. After: 0 NaN pixels, N is 0 at% and flagged not detected at every pixel and in the table, and the MLLS intensities are unchanged. The median |MLLS − NNLS| per image is 1.4 to 4.1 at% for C and 1.6 to 4.1 at% for O (MLLS puts more in O), and 0 to 0.2 at% for N. NNLS and the other stages are bit-identical. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Requested by Paul · project thread
Found in an app EELS room on a real STEM spectrum image: with C K, N K and O K picked and N absent, the MLLS composition was empty at every pixel, for C and O as well as N.
Cause
EELSQuantification.composition(_: EELSMLLSResult, symbols:)refused the whole pixel (noComposition) when any amount was below zero. MLLS is unconstrained, so an absent element's amount scatters around zero and is negative at about half the pixels, or at all of them when another edge's tail is not fully modelled.Refuted if: the pixels without composition were not exactly those with a negative amount. Checked: in the synthetic test the odd pixels (N below zero) were
noComposition, the even ones (N above zero) were not.What the references do
EELSModel.quantifyprints the intensities, negative ones included). HyperSpy has none either.Fix (chosen rule)
An amount at or below zero is not detected: it counts as 0 at% and 0 wt%, the new per-element
EELSCompositionPixel.notDetectedflags it, and the others are normalised among themselves. Why: it matches what the NNLS model fit gives on the same picks, leaves every all-positive pixel bit-identical, and needs no detection-limit choice. A 1-sigma or 3-sigma detection limit would also move small positive amounts; that stays an app or later kit decision.noCompositionnow means no amount is above zero.notDetected == falseonly means the amount is above zero, not above a detection limit (documented). Clamping per pixel biases an average of pixel compositions upward for an absent element; the doc comment says to quantify a summed region instead.notDetected; its numbers do not change.EELSCompositionPixel, which has no public initialiser, so consumers stay source-compatible.Numbers move
Synthetic: the planted C, N and O image, 3 x 2 pixels, with N moved by linearity to +1.5 % of C on even pixels and below zero on odd pixels (per-pixel planted exponents, whole axis).
noComposition: no at%, no wt% for C, N or OnoCompositionnoCompositionnoCompositionTests
testCompositionWithNegativeAbsentElementKeepsTheOthersfailed before the fix (pixel 1noComposition).swift test -c release --parallel --skip SpectroKitParityTestsgreen (132 + 322 + 66 + 1 tests, the known issues unchanged).MLLSPinsTestsincluded.notDetectedchecks and a stale test comment fix, all done.This PR changes numbers a user sees: it waits for Paul.
🤖 Generated with Claude Code