Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
62118a8
Initial implementation of occupancy by intensity. Requires ptm_stoich…
pcruzparri Feb 16, 2025
38840d8
Updating the ProteinGroup.ModInfo writing
pcruzparri Feb 23, 2025
7873281
Saving latest work. Still need to rebase onto master and address bug …
pcruzparri Aug 5, 2025
82472e1
temp save
pcruzparri Sep 23, 2025
c4d2c7e
fixing protein sequence issue. Also added a condition to check if var…
pcruzparri Sep 30, 2025
92b45a1
.
pcruzparri Sep 30, 2025
0d15de5
fixing changes during rebasing to reflect master code again.
pcruzparri Sep 30, 2025
8de1426
fixes to tests and occupancy to pass said tests. need to do a final t…
pcruzparri Oct 1, 2025
bd8a7d4
Fixes to code for remaining tests. TestModificationInfoListProteinGro…
pcruzparri Oct 2, 2025
40b17f0
update + master merging fixes
pcruzparri Nov 6, 2025
09661cd
cleaned output
pcruzparri Nov 7, 2025
0150f1f
Cleaning up mod info outputs
pcruzparri Nov 21, 2025
2fbe1ac
final fix so mods with 0 intensity do not get written.
pcruzparri Dec 10, 2025
d521c0a
made filter by common variable and common fixed boolean. Need to link…
pcruzparri Dec 10, 2025
928fdff
merge master into ptm_stoich
pcruzparri Jan 19, 2026
531dfa2
Merge branch 'master' into ptm_stoich
pcruzparri Jan 19, 2026
b685976
merge master into ptm_stoich
pcruzparri Mar 12, 2026
6b87cf0
merging
pcruzparri Mar 12, 2026
f7938d8
temp: integrating ScanMetadata
pcruzparri Mar 23, 2026
5a7ea4b
Merge branch 'ptm_stoich' of https://github.com/pcruzparri/metamorphe…
pcruzparri Mar 23, 2026
c759f00
git commit fixing mzlib/mm modification change causing integration is…
pcruzparri Mar 23, 2026
47356e6
time stamping updates to proteingroup implementing biopolymergroup.
pcruzparri Mar 23, 2026
127aa3c
Merge branch 'ptm_stoich' of https://github.com/pcruzparri/MetaMorphe…
pcruzparri Mar 23, 2026
86f525b
working with vignette data and spectralmatchandbiopolymergrouprefacto…
pcruzparri Mar 25, 2026
0c39b46
cleaning up mod pipeline plus minor qol recommendations from copilot.
pcruzparri Mar 25, 2026
10cea57
integrate mzlib stoich update
pcruzparri Apr 8, 2026
3fc7a49
merging master
pcruzparri Apr 8, 2026
bb54e1b
fixing tests to expect the new column outputs
pcruzparri Apr 13, 2026
0659dc0
Merge branch 'master' into ptm_stoich
pcruzparri Apr 14, 2026
acef537
Merge branch 'master' into ptm_stoich
pcruzparri Apr 19, 2026
312affc
Test fixes and consistent column generation enforcement
pcruzparri Apr 20, 2026
4a5ee4c
Merge branch 'master' into ptm_stoich
pcruzparri Apr 26, 2026
abcbc8a
fix merge conflicts
pcruzparri May 11, 2026
e795694
Merge branch 'master' into ptm_stoich
pcruzparri May 12, 2026
0920624
cleaning
pcruzparri May 14, 2026
c19eaeb
fixing changes to intended perviously behavior (early returns on quan…
pcruzparri May 15, 2026
f634089
more tests
pcruzparri May 15, 2026
b12dd35
Minor update to thread safe observable collection meant to facilitate…
pcruzparri May 15, 2026
a505f62
reduce diff lines
pcruzparri May 17, 2026
06a184f
Merge branch 'master' into ptm_stoich
pcruzparri May 26, 2026
de8d5c4
Remove default throw in DeconHostViewModel switch
pcruzparri May 26, 2026
71ba649
Fix SILAC copy constructor dropping IsobaricMassTagReporterIonIntensi…
pcruzparri May 26, 2026
0d9dc72
Merge branch 'master' into ptm_stoich
pcruzparri May 26, 2026
e994d03
accidentally removed used modules
pcruzparri May 28, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions MetaMorpheus/EngineLayer/GlobalVariables.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
global using obo = Omics.Modifications.IO.obo;

Check warning on line 1 in MetaMorpheus/EngineLayer/GlobalVariables.cs

View workflow job for this annotation

GitHub Actions / macos-latest

The type name 'obo' only contains lower-cased ascii characters. Such names may become reserved for the language.

Check warning on line 1 in MetaMorpheus/EngineLayer/GlobalVariables.cs

View workflow job for this annotation

GitHub Actions / ubuntu-latest

The type name 'obo' only contains lower-cased ascii characters. Such names may become reserved for the language.

Check warning on line 1 in MetaMorpheus/EngineLayer/GlobalVariables.cs

View workflow job for this annotation

GitHub Actions / Search with Built

The type name 'obo' only contains lower-cased ascii characters. Such names may become reserved for the language.

Check warning on line 1 in MetaMorpheus/EngineLayer/GlobalVariables.cs

View workflow job for this annotation

GitHub Actions / windows-latest

The type name 'obo' only contains lower-cased ascii characters. Such names may become reserved for the language.

Check warning on line 1 in MetaMorpheus/EngineLayer/GlobalVariables.cs

View workflow job for this annotation

GitHub Actions / Create Installer Artifact

The type name 'obo' only contains lower-cased ascii characters. Such names may become reserved for the language.

Check warning on line 1 in MetaMorpheus/EngineLayer/GlobalVariables.cs

View workflow job for this annotation

GitHub Actions / Create Installer Artifact

The type name 'obo' only contains lower-cased ascii characters. Such names may become reserved for the language.

Check warning on line 1 in MetaMorpheus/EngineLayer/GlobalVariables.cs

View workflow job for this annotation

GitHub Actions / Validate Installer Contents

The type name 'obo' only contains lower-cased ascii characters. Such names may become reserved for the language.

Check warning on line 1 in MetaMorpheus/EngineLayer/GlobalVariables.cs

View workflow job for this annotation

GitHub Actions / Test on Windows

The type name 'obo' only contains lower-cased ascii characters. Such names may become reserved for the language.
using Chemistry;
using Easy.Common.Extensions;
using EngineLayer.GlycoSearch;
Expand All @@ -19,6 +19,7 @@
using Transcriptomics.Digestion;
using UsefulProteomicsDatabases;
using System.Security.Cryptography;
using Omics.Modifications.IO;

Check warning on line 22 in MetaMorpheus/EngineLayer/GlobalVariables.cs

View workflow job for this annotation

GitHub Actions / macos-latest

The using directive for 'Omics.Modifications.IO' appeared previously in this namespace

Check warning on line 22 in MetaMorpheus/EngineLayer/GlobalVariables.cs

View workflow job for this annotation

GitHub Actions / ubuntu-latest

The using directive for 'Omics.Modifications.IO' appeared previously in this namespace

Check warning on line 22 in MetaMorpheus/EngineLayer/GlobalVariables.cs

View workflow job for this annotation

GitHub Actions / Search with Built

The using directive for 'Omics.Modifications.IO' appeared previously in this namespace

Check warning on line 22 in MetaMorpheus/EngineLayer/GlobalVariables.cs

View workflow job for this annotation

GitHub Actions / windows-latest

The using directive for 'Omics.Modifications.IO' appeared previously in this namespace

Check warning on line 22 in MetaMorpheus/EngineLayer/GlobalVariables.cs

View workflow job for this annotation

GitHub Actions / Create Installer Artifact

The using directive for 'Omics.Modifications.IO' appeared previously in this namespace

Check warning on line 22 in MetaMorpheus/EngineLayer/GlobalVariables.cs

View workflow job for this annotation

GitHub Actions / Create Installer Artifact

The using directive for 'Omics.Modifications.IO' appeared previously in this namespace

Check warning on line 22 in MetaMorpheus/EngineLayer/GlobalVariables.cs

View workflow job for this annotation

GitHub Actions / Validate Installer Contents

The using directive for 'Omics.Modifications.IO' appeared previously in this namespace

Check warning on line 22 in MetaMorpheus/EngineLayer/GlobalVariables.cs

View workflow job for this annotation

GitHub Actions / Test on Windows

The using directive for 'Omics.Modifications.IO' appeared previously in this namespace

namespace EngineLayer
{
Expand Down
25 changes: 25 additions & 0 deletions MetaMorpheus/EngineLayer/Ms2ScanWithSpecificMass.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,23 @@

TheScan = mzLibScan;

// Build the lightweight metadata snapshot
ScanMetadata = new ScanMetadata(
OneBasedScanNumber: mzLibScan.OneBasedScanNumber,
OneBasedPrecursorScanNumber: mzLibScan.OneBasedPrecursorScanNumber,
RetentionTime: mzLibScan.RetentionTime,
NumPeaks: mzLibScan.MassSpectrum.Size,
TotalIonCurrent: mzLibScan.TotalIonCurrent,
NativeId: mzLibScan.NativeId,
FullFilePath: fullFilePath,
PrecursorCharge: precursorCharge,
PrecursorMonoisotopicPeakMz: precursorMonoisotopicPeakMz,
PrecursorMass: PrecursorMass,
PrecursorIntensity: PrecursorIntensity,
PrecursorEnvelopePeakCount: PrecursorEnvelopePeakCount,
PrecursorFractionalIntensity: PrecursorFractionalIntensity,
OneOverK0: mzLibScan is TimsDataScan tims ? tims.OneOverK0 : null);

if (commonParam.DissociationType != DissociationType.LowCID)
{
ExperimentalFragments = neutralExperimentalFragments ?? GetNeutralExperimentalFragments(mzLibScan, commonParam);
Expand All @@ -41,6 +58,14 @@
}

public MsDataScan TheScan { get; }

/// <summary>
/// Lightweight, immutable snapshot of scan and precursor metadata.
/// Designed to be passed to SpectralMatch so the heavyweight scan objects
/// can be released from memory after scoring.
/// </summary>
public ScanMetadata ScanMetadata { get; }

public double PrecursorMonoisotopicPeakMz { get; }
public double PrecursorMass { get; }
public int PrecursorCharge { get; }
Expand All @@ -67,7 +92,7 @@
/// An array containing the intensities of the reporter ions for isobaric mass tags.
/// If multiplex quantification wasn't performed, this will be null
/// </summary>
public double[]? IsobaricMassTagReporterIonIntensities { get; private set; }

Check warning on line 95 in MetaMorpheus/EngineLayer/Ms2ScanWithSpecificMass.cs

View workflow job for this annotation

GitHub Actions / macos-latest

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 95 in MetaMorpheus/EngineLayer/Ms2ScanWithSpecificMass.cs

View workflow job for this annotation

GitHub Actions / ubuntu-latest

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 95 in MetaMorpheus/EngineLayer/Ms2ScanWithSpecificMass.cs

View workflow job for this annotation

GitHub Actions / Search with Built

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 95 in MetaMorpheus/EngineLayer/Ms2ScanWithSpecificMass.cs

View workflow job for this annotation

GitHub Actions / windows-latest

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 95 in MetaMorpheus/EngineLayer/Ms2ScanWithSpecificMass.cs

View workflow job for this annotation

GitHub Actions / Create Installer Artifact

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 95 in MetaMorpheus/EngineLayer/Ms2ScanWithSpecificMass.cs

View workflow job for this annotation

GitHub Actions / Create Installer Artifact

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 95 in MetaMorpheus/EngineLayer/Ms2ScanWithSpecificMass.cs

View workflow job for this annotation

GitHub Actions / Validate Installer Contents

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 95 in MetaMorpheus/EngineLayer/Ms2ScanWithSpecificMass.cs

View workflow job for this annotation

GitHub Actions / Test on Windows

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

public static IsotopicEnvelope[] GetNeutralExperimentalFragments(MsDataScan scan, CommonParameters commonParam)
{
Expand Down
478 changes: 193 additions & 285 deletions MetaMorpheus/EngineLayer/ProteinParsimony/ProteinGroup.cs

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -165,8 +165,8 @@ private List<ProteinGroup> DoProteinFdr(List<ProteinGroup> proteinGroups)
}

pg.BestPeptideScore = pg.AllPsmsBelowOnePercentFDR.Max(psm => psm.Score);
pg.BestPeptideQValue = pg.AllPsmsBelowOnePercentFDR.Min(psm => psm.FdrInfo.QValueNotch);
pg.BestPeptidePEP = pg.AllPsmsBelowOnePercentFDR.Min(psm => psm.FdrInfo.PEP);
pg.BestPeptideQValue = pg.AllPsmsBelowOnePercentFDR.OfType<SpectralMatch>().Min(psm => psm.FdrInfo.QValueNotch);
pg.BestPeptidePEP = pg.AllPsmsBelowOnePercentFDR.OfType<SpectralMatch>().Min(psm => psm.FdrInfo.PEP);
}

// pick the best for each paired accession based on filter type
Expand Down
12 changes: 9 additions & 3 deletions MetaMorpheus/EngineLayer/Silac/SilacConversions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
using Omics.Modifications;
using Omics.Digestion;
using EngineLayer.SpectrumMatch;
using Easy.Common.Extensions;
using MzLibUtil;
using MassSpectrometry;

namespace EngineLayer
Expand Down Expand Up @@ -453,26 +455,30 @@ public static void SilacConversionsPostQuantification(List<SilacLabel> allSilacL
flashLfqResults.CalculateProteinResultsMedianPolish(true);

//update proteingroups to have all files for quantification
// Modification occupancy is now computed by BioPolymerGroup.PopulateSampleGroupResults()
if (proteinGroups != null)
{
List<SpectraFileInfo> allInfo = originalToLabeledFileInfoDictionary.SelectMany(x => x.Value).ToList();
foreach (ProteinGroup proteinGroup in proteinGroups)
{
proteinGroup.FilesForQuantification = allInfo;
proteinGroup.IntensitiesByFile = new Dictionary<SpectraFileInfo, double>();

// Build the dictionary locally, then assign in one shot.
// The IntensitiesByFile getter returns a copy, so .Add() on it would be lost.
var intensities = new Dictionary<SpectraFileInfo, double>();
foreach (var spectraFile in allInfo)
{
if (flashLfqResults.ProteinGroups.TryGetValue(proteinGroup.ProteinGroupName, out var flashLfqProteinGroup))
{
proteinGroup.IntensitiesByFile.Add(spectraFile, flashLfqProteinGroup.GetIntensity(spectraFile));
intensities.Add(spectraFile, flashLfqProteinGroup.GetIntensity(spectraFile));
}
else
{
//needed for decoys/contaminants/proteins that aren't quantified
proteinGroup.IntensitiesByFile.Add(spectraFile, 0);
intensities.Add(spectraFile, 0);
}
}
proteinGroup.IntensitiesByFile = intensities;
}
}

Expand Down
132 changes: 82 additions & 50 deletions MetaMorpheus/EngineLayer/SpectralMatch.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,49 +7,29 @@
using System.Collections.Generic;
using System.Linq;
using Omics;
using Omics.SpectralMatch;
using System;
using Omics.Digestion;
using EngineLayer.CrosslinkSearch;
using EngineLayer.SpectrumMatch;

namespace EngineLayer
{
public abstract class SpectralMatch : IComparable<SpectralMatch>
public abstract class SpectralMatch : ISpectralMatch, IComparable<SpectralMatch>
{
public const double ToleranceForScoreDifferentiation = 1e-9;

protected SpectralMatch(IBioPolymerWithSetMods peptide, int notch, double score, int scanIndex, Ms2ScanWithSpecificMass scan, CommonParameters commonParameters, List<MatchedFragmentIon> matchedFragmentIons)
{
_BestMatchingBioPolymersWithSetMods = new List<SpectralMatchHypothesis>();
ScanIndex = scanIndex;
FullFilePath = scan.FullFilePath;
ScanNumber = scan.OneBasedScanNumber;
PrecursorScanNumber = scan.OneBasedPrecursorScanNumber;
ScanRetentionTime = scan.RetentionTime;
ScanExperimentalPeaks = scan.NumPeaks;
PrecursorScanIntensity = scan.PrecursorIntensity;
TotalIonCurrent = scan.TotalIonCurrent;
ScanPrecursorCharge = scan.PrecursorCharge;
ScanPrecursorMonoisotopicPeakMz = scan.PrecursorMonoisotopicPeakMz;
ScanPrecursorMass = scan.PrecursorMass;
PrecursorScanEnvelopePeakCount = scan.PrecursorEnvelopePeakCount;
PrecursorFractionalIntensity = scan.PrecursorFractionalIntensity;
ScanMetadata = scan.ScanMetadata;
PrecursorScanDeconvolutionScore = scan.PrecursorDeconvolutionScore;
DigestionParams = commonParameters.DigestionParams;
NativeId = scan.NativeId;
RunnerUpScore = commonParameters.ScoreCutoff;
SpectralAngle = -1;
IsobaricMassTagReporterIonIntensities = scan.IsobaricMassTagReporterIonIntensities;

if (scan.TheScan is TimsDataScan timsScan)
{
ScanOneOverK0 = timsScan.OneOverK0;
}
else
{
ScanOneOverK0 = null; // this is only used for ion mobility data, so it can be null
}

AddOrReplace(peptide, score, notch, true, matchedFragmentIons);
}

Expand All @@ -69,25 +49,80 @@
public int PsmCount { get; internal set; }
public Dictionary<string, int> ModsIdentified { get; private set; } // these should never be null under normal circumstances
public List<double> LocalizedScores { get; internal set; }
public int ScanNumber { get; }
public int? PrecursorScanNumber { get; }
public double ScanRetentionTime { get; }
public int ScanExperimentalPeaks { get; }
public double TotalIonCurrent { get; }
public int ScanPrecursorCharge { get; }
public double ScanPrecursorMonoisotopicPeakMz { get; }
public double PrecursorScanIntensity { get; }
public int PrecursorScanEnvelopePeakCount { get; }
public double PrecursorFractionalIntensity { get; }

#region Scan metadata — delegated to ScanMetadata record

/// <summary>
/// Lightweight, immutable snapshot of scan and precursor metadata.
/// Replaces the individual scan-derived fields that were previously unpacked
/// from Ms2ScanWithSpecificMass during construction.
/// </summary>
public ScanMetadata ScanMetadata { get; }

// Pass-through properties for backwards compatibility.
// Callers can be migrated to ScanMetadata.* over time.
public int ScanNumber => ScanMetadata.OneBasedScanNumber;
public int? PrecursorScanNumber => ScanMetadata.OneBasedPrecursorScanNumber;
public double ScanRetentionTime => ScanMetadata.RetentionTime;
public int ScanExperimentalPeaks => ScanMetadata.NumPeaks;
public double TotalIonCurrent => ScanMetadata.TotalIonCurrent;
public int ScanPrecursorCharge => ScanMetadata.PrecursorCharge;
public double ScanPrecursorMonoisotopicPeakMz => ScanMetadata.PrecursorMonoisotopicPeakMz;
public double PrecursorScanIntensity => ScanMetadata.PrecursorIntensity;
public int PrecursorScanEnvelopePeakCount => ScanMetadata.PrecursorEnvelopePeakCount;
public double PrecursorFractionalIntensity => ScanMetadata.PrecursorFractionalIntensity;
public double ScanPrecursorMass => ScanMetadata.PrecursorMass;
public double? ScanOneOverK0 => ScanMetadata.OneOverK0;
public string FullFilePath => ScanMetadata.FullFilePath;
public string NativeId => ScanMetadata.NativeId;

/// <summary>
/// Method-agnostic envelope-quality score in [0, 1] from mzLib's DeconvolutionScorer for
/// the precursor envelope of this PSM. 0 indicates no envelope was computed or the
/// envelope is maximally bad; higher = better-shaped Averagine match.
/// </summary>
public double PrecursorScanDeconvolutionScore { get; }
public double ScanPrecursorMass { get; }
public double? ScanOneOverK0 { get; set; } // this is only used for ion mobility data, so it can be null
public string FullFilePath { get; private set; }

#endregion

#region ISpectralMatch explicit interface implementations

/// <summary>Maps to <see cref="ScanNumber"/> for ISpectralMatch compatibility.</summary>
int ISpectralMatch.OneBasedScanNumber => ScanNumber;

/// <summary>
/// Consolidates quantification intensities for ISpectralMatch compatibility.
/// Returns ReporterIonIntensities if available (isobaric), a singleton array of
/// PrecursorScanIntensity for LFQ, or null if neither is populated.
/// </summary>
double[]? ISpectralMatch.Intensities =>

Check warning on line 98 in MetaMorpheus/EngineLayer/SpectralMatch.cs

View workflow job for this annotation

GitHub Actions / macos-latest

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 98 in MetaMorpheus/EngineLayer/SpectralMatch.cs

View workflow job for this annotation

GitHub Actions / ubuntu-latest

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 98 in MetaMorpheus/EngineLayer/SpectralMatch.cs

View workflow job for this annotation

GitHub Actions / Search with Built

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 98 in MetaMorpheus/EngineLayer/SpectralMatch.cs

View workflow job for this annotation

GitHub Actions / windows-latest

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 98 in MetaMorpheus/EngineLayer/SpectralMatch.cs

View workflow job for this annotation

GitHub Actions / Create Installer Artifact

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 98 in MetaMorpheus/EngineLayer/SpectralMatch.cs

View workflow job for this annotation

GitHub Actions / Create Installer Artifact

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 98 in MetaMorpheus/EngineLayer/SpectralMatch.cs

View workflow job for this annotation

GitHub Actions / Validate Installer Contents

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 98 in MetaMorpheus/EngineLayer/SpectralMatch.cs

View workflow job for this annotation

GitHub Actions / Test on Windows

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.
IsobaricMassTagReporterIonIntensities ??
(PrecursorScanIntensity > 0 ? new[] { PrecursorScanIntensity } : null);

/// <summary>
/// Returns the identified biopolymers (peptides/proteoforms) for ISpectralMatch compatibility.
/// Unwraps SpectralMatchHypothesis to the underlying IBioPolymerWithSetMods.
/// </summary>
public IEnumerable<IBioPolymerWithSetMods> GetIdentifiedBioPolymersWithSetMods() =>
BestMatchingBioPolymersWithSetMods.Select(h => h.SpecificBioPolymer);

public int CompareTo(ISpectralMatch? other)

Check warning on line 109 in MetaMorpheus/EngineLayer/SpectralMatch.cs

View workflow job for this annotation

GitHub Actions / macos-latest

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 109 in MetaMorpheus/EngineLayer/SpectralMatch.cs

View workflow job for this annotation

GitHub Actions / ubuntu-latest

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 109 in MetaMorpheus/EngineLayer/SpectralMatch.cs

View workflow job for this annotation

GitHub Actions / Search with Built

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 109 in MetaMorpheus/EngineLayer/SpectralMatch.cs

View workflow job for this annotation

GitHub Actions / windows-latest

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 109 in MetaMorpheus/EngineLayer/SpectralMatch.cs

View workflow job for this annotation

GitHub Actions / Create Installer Artifact

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 109 in MetaMorpheus/EngineLayer/SpectralMatch.cs

View workflow job for this annotation

GitHub Actions / Create Installer Artifact

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 109 in MetaMorpheus/EngineLayer/SpectralMatch.cs

View workflow job for this annotation

GitHub Actions / Validate Installer Contents

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 109 in MetaMorpheus/EngineLayer/SpectralMatch.cs

View workflow job for this annotation

GitHub Actions / Test on Windows

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.
{
if (other is null) return 1;
if (other is SpectralMatch mm) return CompareTo(mm);
// Fallback: compare by score descending
return Score.CompareTo(other.Score);
}

public bool Equals(ISpectralMatch? other)

Check warning on line 117 in MetaMorpheus/EngineLayer/SpectralMatch.cs

View workflow job for this annotation

GitHub Actions / macos-latest

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 117 in MetaMorpheus/EngineLayer/SpectralMatch.cs

View workflow job for this annotation

GitHub Actions / ubuntu-latest

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 117 in MetaMorpheus/EngineLayer/SpectralMatch.cs

View workflow job for this annotation

GitHub Actions / Search with Built

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 117 in MetaMorpheus/EngineLayer/SpectralMatch.cs

View workflow job for this annotation

GitHub Actions / windows-latest

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 117 in MetaMorpheus/EngineLayer/SpectralMatch.cs

View workflow job for this annotation

GitHub Actions / Create Installer Artifact

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 117 in MetaMorpheus/EngineLayer/SpectralMatch.cs

View workflow job for this annotation

GitHub Actions / Create Installer Artifact

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 117 in MetaMorpheus/EngineLayer/SpectralMatch.cs

View workflow job for this annotation

GitHub Actions / Validate Installer Contents

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 117 in MetaMorpheus/EngineLayer/SpectralMatch.cs

View workflow job for this annotation

GitHub Actions / Test on Windows

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.
{
if (other is null) return false;
return FullFilePath == other.FullFilePath
&& ScanNumber == other.OneBasedScanNumber
&& FullSequence == other.FullSequence;
}

#endregion
/// <summary>
/// Refers to the index of the Ms2ScanWithSpecificMass in an array of Ms2ScansWithSpecificMass that is sorted by precursor mass
/// </summary>
Expand All @@ -110,7 +145,6 @@

public double Score { get; private set; }
public double SpectralAngle { get; set; }
public string NativeId; // this is a property of the scan. used for mzID writing

public double DeltaScore { get { return (Score - RunnerUpScore); } }

Expand Down Expand Up @@ -165,10 +199,11 @@
protected List<SpectralMatchHypothesis> _BestMatchingBioPolymersWithSetMods;

/// <summary>
/// An array containing the intensities of the reporter ions for isobaric mass tags.
/// If multiplex quantification wasn't performed, this will be null
/// An array containing the intensities of the reporter ions for isobaric mass tags (TMT, iTRAQ, diLeu, etc.).
/// Null if multiplex quantification wasn't performed.
/// Array order matches the reporter ion order defined by the mass tag modification.
/// </summary>
public double[]? IsobaricMassTagReporterIonIntensities { get; private set; }

Check warning on line 206 in MetaMorpheus/EngineLayer/SpectralMatch.cs

View workflow job for this annotation

GitHub Actions / macos-latest

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 206 in MetaMorpheus/EngineLayer/SpectralMatch.cs

View workflow job for this annotation

GitHub Actions / ubuntu-latest

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 206 in MetaMorpheus/EngineLayer/SpectralMatch.cs

View workflow job for this annotation

GitHub Actions / Search with Built

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 206 in MetaMorpheus/EngineLayer/SpectralMatch.cs

View workflow job for this annotation

GitHub Actions / windows-latest

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 206 in MetaMorpheus/EngineLayer/SpectralMatch.cs

View workflow job for this annotation

GitHub Actions / Create Installer Artifact

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 206 in MetaMorpheus/EngineLayer/SpectralMatch.cs

View workflow job for this annotation

GitHub Actions / Create Installer Artifact

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 206 in MetaMorpheus/EngineLayer/SpectralMatch.cs

View workflow job for this annotation

GitHub Actions / Validate Installer Contents

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 206 in MetaMorpheus/EngineLayer/SpectralMatch.cs

View workflow job for this annotation

GitHub Actions / Test on Windows

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

public IEnumerable<SpectralMatchHypothesis> BestMatchingBioPolymersWithSetMods
{
Expand Down Expand Up @@ -388,6 +423,12 @@
BaseSequence = PsmTsvWriter.Resolve(bestMatchingPeptides.Select(b => b.SpecificBioPolymer.BaseSequence)).ResolvedValue;
FullSequence = PsmTsvWriter.Resolve(bestMatchingPeptides.Select(b => b.SpecificBioPolymer.FullSequence)).ResolvedValue;

// Scan metadata is an immutable record — safe to share the reference
ScanMetadata = psm.ScanMetadata;
ScanIndex = psm.ScanIndex;
PrecursorScanDeconvolutionScore = psm.PrecursorScanDeconvolutionScore;
IsobaricMassTagReporterIonIntensities = psm.IsobaricMassTagReporterIonIntensities;

ModsChemicalFormula = psm.ModsChemicalFormula;
Notch = psm.Notch;
BioPolymerWithSetModsLength = psm.BioPolymerWithSetModsLength;
Expand All @@ -401,17 +442,8 @@
PsmCount = psm.PsmCount;
ModsIdentified = psm.ModsIdentified;
LocalizedScores = psm.LocalizedScores;
ScanNumber = psm.ScanNumber;
PrecursorScanNumber = psm.PrecursorScanNumber;
ScanRetentionTime = psm.ScanRetentionTime;
ScanExperimentalPeaks = psm.ScanExperimentalPeaks;
TotalIonCurrent = psm.TotalIonCurrent;
ScanPrecursorCharge = psm.ScanPrecursorCharge;
ScanPrecursorMonoisotopicPeakMz = psm.ScanPrecursorMonoisotopicPeakMz;
ScanPrecursorMass = psm.ScanPrecursorMass;
FullFilePath = psm.FullFilePath;
ScanIndex = psm.ScanIndex;
FdrInfo = psm.FdrInfo;
PeptideFdrInfo = psm.PeptideFdrInfo;
Score = psm.Score;
RunnerUpScore = psm.RunnerUpScore;
IsDecoy = psm.IsDecoy;
Expand Down Expand Up @@ -612,4 +644,4 @@
}

}
}
}
2 changes: 1 addition & 1 deletion MetaMorpheus/EngineLayer/Util/IsobaricMassTag.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
/// This class contains information about the Isobaric Mass Tag (e.g., TMT), including the theoretical m/z values of the reporter ions
/// as well as methods designed to retrieve the intensities of those reporter ions from a given MzSpectrum.
/// It does not store any intensity information itself. Intensity information is associated with each Ms2ScanWithSpecificMass object or SpectralMatch,
/// in the IsobaricMassTagReporterIonIntensities property.
/// in the IsobaricMassTagReporterIonIntensities property (Ms2ScanWithSpecificMass) or ReporterIonIntensities property (SpectralMatch).
/// </summary>
public class IsobaricMassTag
{
Expand Down Expand Up @@ -103,7 +103,7 @@
/// Takes in a spectrum, searches for the reporter ions within the specified ppm tolerance,
/// and returns their intensities. If a reporter ion is not found, its intensity will be zero.
/// </summary>
public double[]? GetReporterIonIntensities(MzSpectrum spectrum)

Check warning on line 106 in MetaMorpheus/EngineLayer/Util/IsobaricMassTag.cs

View workflow job for this annotation

GitHub Actions / macos-latest

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 106 in MetaMorpheus/EngineLayer/Util/IsobaricMassTag.cs

View workflow job for this annotation

GitHub Actions / ubuntu-latest

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 106 in MetaMorpheus/EngineLayer/Util/IsobaricMassTag.cs

View workflow job for this annotation

GitHub Actions / Search with Built

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 106 in MetaMorpheus/EngineLayer/Util/IsobaricMassTag.cs

View workflow job for this annotation

GitHub Actions / windows-latest

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 106 in MetaMorpheus/EngineLayer/Util/IsobaricMassTag.cs

View workflow job for this annotation

GitHub Actions / Create Installer Artifact

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 106 in MetaMorpheus/EngineLayer/Util/IsobaricMassTag.cs

View workflow job for this annotation

GitHub Actions / Create Installer Artifact

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 106 in MetaMorpheus/EngineLayer/Util/IsobaricMassTag.cs

View workflow job for this annotation

GitHub Actions / Validate Installer Contents

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 106 in MetaMorpheus/EngineLayer/Util/IsobaricMassTag.cs

View workflow job for this annotation

GitHub Actions / Test on Windows

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.
{
if (spectrum == null || spectrum.Size < 1) return null;
double[] reporterIonIntensities = new double[ReporterIonMzs.Length];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System.Windows;
using Easy.Common.Extensions;
using EngineLayer;
using GuiFunctions.Util;
using iText.StyledXmlParser.Jsoup;
using MassSpectrometry;
using MzLibUtil;
Expand All @@ -26,12 +27,13 @@ public class FragmentationReanalysisViewModel : BaseViewModel
{
private readonly bool _isProtein;
private static readonly object _fragmentationLock = new();
private static readonly object _productsLock = new();

public FragmentationReanalysisViewModel(bool isProtein = true)
{
_isProtein = isProtein;
ProductIonMassTolerance = 20;
PossibleProducts = [.. GetPossibleProducts()];
PossibleProducts = new ThreadSafeObservableCollection<FragmentViewModel>(GetPossibleProducts());

IEnumerable<DissociationType> values;
CommonParameters common;
Expand Down Expand Up @@ -77,15 +79,13 @@ public void LoadFragmentationParameters(CommonParameters common, SearchParameter
FragmentationParamsViewModel = new(common, search);
}

private ObservableCollection<FragmentViewModel> _possibleProducts;
public ObservableCollection<FragmentViewModel> PossibleProducts
private ThreadSafeObservableCollection<FragmentViewModel> _possibleProducts;
public ThreadSafeObservableCollection<FragmentViewModel> PossibleProducts
{
get => _possibleProducts;
set { _possibleProducts = value; OnPropertyChanged(nameof(PossibleProducts)); }
}

private IEnumerable<ProductType> _productsToUse => PossibleProducts.Where(p => p.Use).Select(p => p.ProductType);

private bool _persist;
public bool Persist
{
Expand Down Expand Up @@ -249,7 +249,7 @@ public List<MatchedFragmentIon> MatchIonsWithNewTypes(MsDataScan ms2Scan, Spectr
List<Product> internalProducts = new List<Product>();

// Snapshot products before acquiring lock to avoid enumerating collection while it may be modified by UI thread
var productsSnapshot = _productsToUse.ToList();
var productsSnapshot = GetProductsSnapshot();
// Lock to ensure thread-safe mutation of static DissociationTypeCollection dictionary
lock (_fragmentationLock)
{
Expand Down Expand Up @@ -298,6 +298,14 @@ public List<MatchedFragmentIon> MatchIonsWithNewTypes(MsDataScan ms2Scan, Spectr
.ToList();
}

private List<ProductType> GetProductsSnapshot()
{
lock (_productsLock)
{
return PossibleProducts.Where(p => p.Use).Select(p => p.ProductType).ToList();
}
}

public static readonly IEqualityComparer<MatchedFragmentIon> MatchedFragmentIonComparer = new MatchedFragmentIonEqualityComparer();

public class MatchedFragmentIonEqualityComparer : IEqualityComparer<MatchedFragmentIon>
Expand Down
Loading
Loading