Skip to content

feat(parallelsearch): per-ID PEP for transient databases#11

Open
nbollis wants to merge 2 commits into
ManySearchTaskfrom
pep-per-id
Open

feat(parallelsearch): per-ID PEP for transient databases#11
nbollis wants to merge 2 commits into
ManySearchTaskfrom
pep-per-id

Conversation

@nbollis

@nbollis nbollis commented Jun 17, 2026

Copy link
Copy Markdown
Owner

Extracts the PEP component from PR #10 (ms-analysis) into its own branch/PR so it can be reviewed and merged independently.

Summary

Trains ONE FastTree PEP model on the large, decoy-rich base (human) search and reuses it to assign a PEP + PEP_QValue to every transient database's hits. The transient databases are far too small to train their own model and are out-of-sample relative to the base search, so no cross-validation is needed for them.

New engine

  • TransientPepAnalysisEngine (sealed, EngineLayer.ParallelSearch) — TrainSingleModelAndAssignBasePep() trains one model, snapshots a PEP→PEP_QValue background curve; AssignPepFromTrainedModel() reuses the model on transient PSMs.

Integration

  • ParallelSearchTask.cs: TrainBasePepModel() called after the baseline search; PEP assignment runs in PerformPostSearchAnalysis after FDR alignment but before metric collectors.
  • IsConfidentMatch() static helper + OutputPepQValueThreshold const for testing.
  • PEPAnalysisEngine._randomSeed changed private→protected (inherited by the transient engine).

Metrics

  • BasicMetricCollector: 4 new columns — PSM/peptide counts at 1% and 5% PEP_QValue.
  • TransientDatabaseMetrics: 4 new [Optional] properties with round-trip through the Results dictionary.

Tests (19 pass)

  • PepBackgroundCurveTests (9) — curve snapshot and binary-search lookup
  • PepTransientAssignmentTests (2) — no-op on untrained, missing-FdrInfo creation
  • ConfidenceFilterTests (4) — pure confidence decision logic
  • BasicMetricCollectorTests + TransientDatabaseMetricsPepColumnsTests (4)
  • ParallelSearchEndToEndTests — integration test (note: fails on a pre-existing StatisticalTestResultFile path issue unrelated to PEP)

Build

  • Release configuration: 0 errors, 11 projects

Note

This is extracted from the larger ms-analysis PR (#10) that also includes family-aware organism detection, MSL library search, and visualization changes. Those will ship in follow-up PRs.

…odel-on-base, score-all-transients)

Extracts the PEP component from PR #10 into its own branch/PR,
so it can be reviewed and merged independently of the family-aware
organism detection and other stacked features.

Adds:
- TransientPepAnalysisEngine: sealed EngineLayer class that trains
  ONE FastTree model on the (large, decoy-rich) base search and
  reuses it to assign PEP + PEP_QValue to every transient database,
  avoiding per-database retraining.
- PepAnalysisEngine._randomSeed changed private→protected.
- ParallelSearchTask integration: TrainBasePepModel() called after
  the base search on ManySearchTask; PEP assignments in
  PerformPostSearchAnalysis before metric collectors and stats.
- BasicMetricCollector: 4 PEP-based confident count columns
  (PSM/peptide at 1% and 5% PEP_QValue).
- TransientDatabaseMetrics: 4 PEP [Optional] properties with
  full Results-dictionary round-trip.
- IsConfidentMatch static helper + OutputPepQValueThreshold const
  for testing.
- 8 test files (4 new unit, 1 modified, 3 dedicated PEP tests, 1 E2E).

Build: 0 errors. Tests: 19 PEP-specific pass, 14 existing pass.
/// is the smallest value >= <paramref name="pep"/> (lower-bound). Because PEP_QValue is monotone in PEP,
/// this is the q-value at that confidence level. Returns 2 (the FdrInfo sentinel) when no curve exists.
/// </summary>
internal static double LookupBackgroundPepQValue(double pep, double[] pepAsc, double[] qByPep)

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a way to reuse the FDRAlignment that we have in EngineLayer/ParallelSearch/FdrAlignment instead of reinventing this from scratch?

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right that score->QValue and PEP->PEP_QValue are the same operation conceptually — both sort, compute target/decoy q-values via CalculateQValue, then look up. The implementation here calls FdrAnalysisEngine.CalculateQValue(..., pepCalculation: true), which IS reusing the existing FDR engine rather than reinventing it from scratch. A shared abstraction that parameterizes sort direction and the FdrInfo field would be a good follow-up refactor (the alignment services have extra state like notch tracking that the PEP curve does not need).

Comment thread MetaMorpheus/TaskLayer/ParallelSearch/ParallelSearchTask.cs Outdated

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PEP baseline processing should be performed in the initialize method instead of the main run specific.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved. TrainBasePepModel() now runs inside Initialize() after the baseline FDR and parsimony, before the base PSM/peptide/protein files are written, so the base output files include PEP and PEP_QValue in their FdrInfo.

.ToList();
}

// PEP: assign each transient PSM/peptide a posterior error probability + PEP_QValue (mapped onto the

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should happen in PerformPostSearchAnalysis instead of the Search method

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PEP assignment block was already inside PerformPostSearchAnalysis (not in PerformSearch). The unified diff context was compressed and showed PerformSearch as the nearest enclosing function in the diff output, but the code at that location is inside PerformPostSearchAnalysis which starts at line 667. No change was needed.

}
}

private const double OutputPepQValueThreshold = 0.05;

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No new const. PEP and Q Value will operate upon the same threshold.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed OutputPepQValueThreshold and the IsConfidentMatch helper that depended on it. PEP and QValue now operate on the same threshold.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed OutputPepQValueThreshold and the IsConfidentMatch helper that depended on it. PEP and QValue now operate on the same threshold.

/// is below pepQThreshold OR its score-based QValue is at or below qThreshold. When PEP is inactive, only the
/// score-based QValue is used. A null FdrInfo is never confident.
/// </summary>
internal static bool IsConfidentMatch(FdrInfo info, bool pepActive, double pepQThreshold, double qThreshold)

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the purpose of this method? Do we need it?

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed. This was test-only scaffolding; testing can use explicit filtering instead. ConfidenceFilterTests.cs has also been removed.

…Match/OuputPepQValueThreshold, remove RT predictor field
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.

2 participants