Skip to content

feat: the proposer and the unlisted-line check take the sum/escape peaks as explained - #56

Closed
Paullo9 wants to merge 5 commits into
mainfrom
issue-15-pileup-explained
Closed

Paullo9 wants to merge 5 commits into
mainfrom
issue-15-pileup-explained

Conversation

@Paullo9

@Paullo9 Paullo9 commented Oct 31, 2026

Copy link
Copy Markdown
Contributor

Requested by Paul · project thread

Fixes #15 (together with #53 and #55, which carry the take-off angle, thickness, dose and map sigma; this PR is the last engineering piece and is based on main, independent of them).

Diagnosis

With the sum/escape model on, the Quantify fit explains the pile-up and escape peaks, but the unlisted-line check ran the element proposer on the bare spectrum. The proposer's own free sum columns won those peaks, yet every element tested against them stayed a candidate at or above L_D, and the check names all of those.

Measured on the tools/edx-sim planted pool (eds-proposer-sim.json, seeded Poisson, listed Al Mg Si O Cu, model on):

  • 100 counts/px: the check named Ar, Ag, Pd (all at the Al+Al sum, 2.97 keV).
  • 300 counts/px: the check named Rh, Ar, In, Sn, Pd, Ag, Cd, Ru, Bi, K (the six sum peaks, 2.5 to 3.5 keV).
  • Planted Fe K-alpha with a common escape fraction and the free escape columns off: the Fe escape at 4.66 keV was named La, with Ce, Cr and Cs beside it.

Cause: the proposer did not know the quant model's sum and escape components. What would refute it: candidates that stay when those components are a fixed part of the proposer's model. None stay (below).

Change

  • SumEscapeResult.componentCounts: the fitted c S(A) + f E(A) per fitted channel (zeros when off).
  • ElementProposer.propose(..., explained:): counts the caller's model already explains, added to every identification and report fit as a fixed offset (not to the hole-region fit). nil, the default, is the old behaviour bit for bit.
  • The quantification keeps the components on its axis, and UnlistedLineChecker.propose hands them to the proposer.

What moves (model on only; model off is unchanged)

planted case before after
tools/edx-sim, 100 counts/px Ar, Ag, Pd named nothing named
tools/edx-sim, 300 counts/px Rh, Ar, In, Sn, Pd, Ag, Cd, Ru, Bi, K named nothing named
Fe escape, common fraction, free escape columns off La, Ce, Cr, Cs named nothing named
300 counts/px + K K-alpha 3000 counts (between Al+Si and Si+Si) (new case) K named first

No Python reference to cross-check: eXSpy has no sum or escape model and no automatic element identification (searched the pinned eXSpy source for pile-up, sum peak and escape: no match). Tested against planted truth only; validation: "none" stands.

Tests

  • New SumEscapeExplainedTests (red before on the cases above; the diagnosis run on unchanged main gave the before column).
  • swift test -c release --parallel --skip SpectroKitParityTests: all green (the two known issues in AxisGateTests are pre-existing).
  • Reviewed before commit: no blocking findings; the note that the reported components are the exact sum term at the final areas, not the linearised one in fit.model, is now in the doc comment.

Docs rows left for a follow-up (the files are at their size limit): the parity row for sum and Si-escape peaks (add componentCounts, propose(explained:), SumEscapeExplainedTests) and open-items item 8 (the proposer and the check now use the model's peaks).

🤖 Generated with Claude Code

…aks as explained

With the sum/escape model on, the unlisted-line check proposed on the bare spectrum and named the modelled pile-up and escape peaks as elements. SumEscapeResult.componentCounts (the fitted c S(A) + f E(A)) is now carried by the quantification and handed to ElementProposer.propose(explained:), which adds it to every fit as a fixed offset. nil (the default, and the model off) runs the proposer as before.

Planted pools (tools/edx-sim proposer_sim, model on): 100 counts/px no longer names Ar, Ag, Pd; 300 counts/px no longer names Rh, Ar, In, Sn, Pd, Ag, Cd, Ru, Bi, K; a planted Fe escape with the free escape columns off no longer names La, Ce, Cr, Cs. A planted K K-alpha between two sum peaks is still named first. Model off: unchanged.

Done: sum/escape peaks are explained counts for the proposer and the check. Next: docs rows for parity.md and open-items.md item 8.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Paullo9 and others added 4 commits October 31, 2026 16:32
The pooled quantification result gained a package field, sumEscapeCounts, in this
branch. The golden dump is a Mirror walk of the result, so each quantification in
demo-edx-tiny-dm4, eds-realistic-l-sim, eds-unlisted-sim and eds-weakline-sim
printed one more line and SpectroGoldenTests failed on line count (4 issues, the
red on test, test-floors and test-macos15).

Re-recorded with SPECTRO_GOLDEN_DIR. diff old new: 9 lines added, all
"quantification.sumEscapeCounts = nil", 0 lines removed or changed. No number moves.

Done: golden baselines match the branch; parity target green locally (83 tests).
Next: merge origin/main and push.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ined

# Conflicts:
#	Sources/SpectroEDX/Quant/PooledQuantification.swift
Main gained #59, which carries this branch's feature in a wider form: the pooled
result's sumEscapeCounts is filled from every kept sum-peak fit (explicit model,
always, and whenSignificant), and SumEscapeExplainedTests is a superset of this
branch's copy. Conflicts in PooledQuantification.swift and
SumEscapeExplainedTests.swift take main's side; the golden re-record and its
header note are already in main. After this merge the tree equals origin/main.

Done: branch up to date; it adds nothing over main.
Next: the PR can close as superseded by #59.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Paullo9 commented Oct 31, 2026

Copy link
Copy Markdown
Contributor Author

Closing as superseded by #59. After #59 merged and main was merged into this branch, the PR has no remaining diff against main: #59 already brings in the sum- and escape-peak "explained" handling, and covers more. The red CI was only SpectroGoldenTests. It printed extra = nil lines for the new result field, and no number moved.


Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Sigma on wt% and at%: thickness, dose, detector, per-pixel map

1 participant