Skip to content

A numbering gap in the experimental design is quantified with a warning; only a duplicate is refused - #3

Draft
trishorts wants to merge 1 commit into
masterfrom
feat/design-gap-warning
Draft

trishorts wants to merge 1 commit into
masterfrom
feat/design-gap-warning

Conversation

@trishorts

@trishorts trishorts commented Oct 7, 2026 •

Copy link
Copy Markdown
Owner

Project of origin: QuantProject (consumed by sdrf, PXReprise, aging)

Draft, waiting on smith-chem-wisc/mzLib#1422. It stays a draft on this fork until an mzLib release carries #1422. That release's pin bump is then added here, and the PR is opened on smith-chem-wisc/FlashLFQ. Until then CI builds against the current pin, 1.0.592, where TheCommandLineQuantifiesABiorepGapAsNumberedAndSaysSo is expected to fail (see "Why this needs mzLib #1422"). Every result below is from a local package of mzLib 1.0.594 plus #1422 and #1426 (9.9.1247) unless it says 1.0.592.

What

A gap in the experimental design's numbering is now quantified with a warning instead of refused. This covers a condition's biological replicates, a biorep's fractions and a fraction's technical replicates. A duplicate (two files at one condition, biorep, fraction and techrep) is still refused.

Before, any gap stopped the run: Condition "X" sample N is missing! (also ... fraction N is missing! and ... replicate N is missing!).

Numbers are never closed up:

  • A biorep number can name a subject across conditions. Control 1–3 and treated 4–6 is a common numbering, and replicate 4 of one condition can be replicate 4 of another (matched tissue, paired designs).
  • A gap can be a lost sample or file. Closing it up hides that.

One rule, here, in MetaMorpheus and in mzLib

This is the third copy of the rule, and the last place the old one lives. It says what the others say:

mzLib #1426 (--sdrfDesign report) MetaMorpheus, trishorts/MetaMorpheus#29 (run warning) FlashLFQ, this PR (run warning)
biorep gap Condition 'FA': biological replicates 3, 4, kept as the SDRF numbers them. ... Condition "FA": biological replicates 3, 4, quantified as numbered; biological replicates 1, 2 are not in the design. ... same as MetaMorpheus
fraction gap Condition 'A' biorep 1: fractions 1, 3, kept as the SDRF numbers them. ... Condition "A" biorep 1: fractions 1, 3, quantified as numbered; fraction 2 is not in the design. ... same as MetaMorpheus
techrep gap Condition 'A' biorep 1 fraction 1: technical replicates 1, 3, kept as ... Condition "A" biorep 1 fraction 1: technical replicates 1, 3, quantified as numbered; ... same as MetaMorpheus
duplicate refused refused: Duplicates are not allowed:\nCondition "A" biorep 3 fraction 2 techrep 1 refused, same message

The MetaMorpheus and FlashLFQ warnings each end with "A missing number may be a sample or file that was lost or not searched."

FlashLfqSettings.GetWarningsInExperimentalDesign is a copy of MetaMorpheus's ExperimentalDesign.GetWarningsInExperimentalDesign, line for line. FlashLFQ does not reference MetaMorpheus, so there is no shared method to call. If the rule moves into mzLib later, both copies can be deleted.

Behaviour

in the design before now
numbers run 1..N quantified quantified (unchanged)
a gap in bioreps, fractions or techreps, or numbering not starting at 1 refused: ... is missing!, nothing quantified quantified as numbered, one warning per gap
duplicate refused: Duplicates are not allowed: Condition "A" sample 3 fraction 2 replicate 1 refused: ... Condition "A" biorep 3 fraction 2 techrep 1 (reworded to match MetaMorpheus)
blank condition, a number below 1 refused refused (unchanged)
  • FlashLfqSettings.ValidateExperimentalDesign now refuses only duplicates, after the existing blank and below-1 checks. It still throws, so both callers (the command line and the GUI's Run button) behave as before.
  • New FlashLfqSettings.GetWarningsInExperimentalDesign returns one line per gap.
  • Where the warning goes:
    • Command line: printed after the design is validated, unless --sil.
    • GUI: added to the notifications box when Run is pressed. The GUI's console output already goes to that box.
    • FlashLFQ writes no run summary file, so unlike MetaMorpheus's results.txt there is no file copy of the warning.

Fractions carry meaning, and a gap keeps it. Match-between-runs transfers only between fractions at most one apart (mzLib FlashLfqEngine.cs:832). Fractions numbered 1 and 3 therefore exchange no transfers, which is what the numbers say (read, not run).

Why this needs mzLib #1422

FlashLFQ's normalization and Bayesian step walked replicates 0..max. #1422 makes them walk the numbers that exist. Measured with the new end-to-end tests, which copy one mzML with intensities scaled ×1/×2(/×3), so normalization has a difference to remove:

case mzLib 1.0.592 (current pin) 9.9.1247 (with #1422)
biorep gap, first condition has no biorep 1 (bioreps 2, 3) normalization silently does nothing: the ×2 file stays at 2× (1262189.7, 2524379.4 for AAAHSSLK); test fails normalized as bioreps 1, 2 would be; test passes
fraction gap (fractions 1, 3 in two bioreps) normalized as fractions 1, 2 would be same
techrep gap (techreps 1, 3) normalized as techreps 1, 2 would be same

So the fraction and techrep fixtures show no dependency on #1422. They do not build the cases #1422 fixes in fraction normalization (a lost biorep across fractions), so that is not evidence the dependency is absent. #1422's description lists the other failures: Sequence contains no elements in fraction normalization, and KeyNotFoundException in the Bayesian step.

Tested

New, in Test/ExperimentalDesignGapTests.cs:

  • ABiorepGapIsAWarningNotAnError: bioreps 1, 2, 4 → no error, exactly one warning, naming 3.

  • StudyWideBiorepNumbersWarnOnlyForTheConditionThatDoesNotStartAtOne: control 1, 2 / treated 3, 4 → one warning, for treated.

  • FractionAndTechrepGapsAreWarningsNamingTheirBiorepAndFraction: exactly the two expected warnings.

  • ContiguousNumbersGiveNoWarning.

  • ADuplicateIsStillRefused: the exact message.

  • TheCommandLineQuantifies{ABiorep,AFraction,ATechrep}GapAsNumberedAndSaysSo: each runs FlashLfqExecutable.Main with --nor three times (gapped; contiguous; contiguous without normalization), then checks:

    • the warning is printed and no error;
    • the gapped and contiguous peptide tables are identical;
    • the normalized table differs from the un-normalized one, so the comparison is not trivially equal.

    An earlier draft of this test passed trivially. Its two sample files share no peptides, and --nor false turns normalization on (it is a bare switch). The fixture and the helper were changed so this third check would catch it.

Falsified: each of five mutations turned tests red, and the restored source passed again (8 passed, 0 failed):

  • master's gap-refusing loop put back: 7 red;
  • duplicate not refused: 1 red;
  • no gap warnings at all: 6 red;
  • command line prints no warning: 3 red;
  • mzLib 1.0.592 instead of #1422: 1 red (the biorep case, above).

Full Test project against 9.9.1247: 37 passed, 0 failed, 2 skipped. The whole solution, GUI included, builds.

Not covered: the GUI's notification lines have no test (Test.csproj does not reference GUI).

Not in this PR

  • The pin bump to the mzLib release carrying #1422. It is added before this PR leaves draft.
  • The GUI's grid still calls a biorep "Sample" and a techrep "Replicate". The messages now say "biorep" and "techrep", as MetaMorpheus does. Renaming the grid columns is left alone.

🤖 Generated with Claude Code

…plicate is refused

A gap in a condition's bioreps, a biorep's fractions or a fraction's techreps
was refused ("Condition "X" sample N is missing!"). It is now quantified as
numbered, and the command line and the GUI's notifications say where each gap
is, in the words MetaMorpheus uses for the same rule. A duplicate is still
refused, now worded as MetaMorpheus words it.

Needs the mzLib release carrying smith-chem-wisc/mzLib#1422: before it, biorep
normalization silently does nothing when the first condition has no biorep 1.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.

1 participant