-
Notifications
You must be signed in to change notification settings - Fork 41
Omics: Proteomics
Nic Bollis edited this page Nov 25, 2025
·
1 revision
The Proteomics library provides protein-specific implementations of the Omics framework, enabling comprehensive protein analysis for mass spectrometry applications. It extends the base Omics interfaces with protein-specific features including enzymatic digestion, post-translational modifications (PTMs), sequence variants, and SILAC labeling support.
- Protein Class: Complete protein representation with metadata and modifications
- Peptide Generation: Advanced digestion with trypsin and other proteases
- PTM Support: Comprehensive post-translational modification handling
- Sequence Variants: SNP, indel, and splice variant support
- SILAC Labeling: Stable isotope labeling for quantitative proteomics
- Glycoproteomics: N-glycan and O-glycan peptide support
- Top-Down Proteomics: Intact protein and truncation product analysis
using Proteomics;
using Proteomics.ProteolyticDigestion;
using Omics.Modifications;
// Create a protein
var protein = new Protein(
sequence: "MAQTQVLQVAKEATPTPLPTAVPR",
accession: "P12345",
organism: "Homo sapiens",
geneNames: new List<Tuple<string, string>>
{
Tuple.Create("primary", "ALB")
}
);
// Configure digestion
var digestionParams = new DigestionParams(
protease: "trypsin",
maxMissedCleavages: 2,
minPeptideLength: 7,
maxPeptideLength: 30
);
// Digest with modifications
var carbamidomethyl = /* carbamidomethylation of C */;
var oxidation = /* oxidation of M */;
var peptides = protein.Digest(
digestionParams,
new List<Modification> { carbamidomethyl }, // Fixed mods
new List<Modification> { oxidation } // Variable mods
).ToList();
// Process peptides
foreach (var peptide in peptides)
{
Console.WriteLine($"{peptide.FullSequence}");
Console.WriteLine($" Mass: {peptide.MonoisotopicMass:F4} Da");
Console.WriteLine($" Charge states: {string.Join(", ", peptide.GetChargesToGenerate())}");
// Fragment the peptide
var products = new List<Product>();
peptide.Fragment(DissociationType.HCD, FragmentationTerminus.Both, products);
Console.WriteLine($" Fragment ions: {products.Count}");
}classDiagram
%% Core Interfaces
class IBioPolymer {
<<interface>>
+Digest(params, fixed, variable) IEnumerable~IBioPolymerWithSetMods~
}
class IBioPolymerWithSetMods {
<<interface>>
+Fragment(dissociationType, terminus, products)
}
%% Protein Implementation
class Protein {
+string BaseSequence
+string Accession
+string Organism
+List~Tuple~string,string~~ GeneNames
+IDictionary~int,List~Modification~~ OneBasedPossibleLocalizedModifications
+List~SequenceVariation~ SequenceVariations
+List~TruncationProduct~ TruncationProducts
+Digest(params, fixed, variable) IEnumerable~PeptideWithSetModifications~
}
class PeptideWithSetModifications {
+string BaseSequence
+string FullSequence
+double MonoisotopicMass
+Dictionary~int,Modification~ AllModsOneIsNterminus
+int OneBasedStartResidue
+int OneBasedEndResidue
+int MissedCleavages
+Fragment(dissociationType, terminus, products)
+GetChargesToGenerate() int[]
}
class ProteolyticPeptide {
+char PreviousResidue
+char NextResidue
+CleavageSpecificity CleavageSpecificityForFdrCategory
+GetModifiedPeptides(fixed, params, variable) IEnumerable~PeptideWithSetModifications~
}
class AminoAcidPolymer {
+ElementCount() Dictionary~string,int~
+GetChemicalFormula() ChemicalFormula
+GetIsoDistribution() IsotopicDistribution
}
class ProteinDigestion {
+Digestion(protein, topDown) IEnumerable~ProteolyticPeptide~
+SpeedySemiSpecificDigestion(protein) IEnumerable~ProteolyticPeptide~
}
class DigestionParams {
+Protease Protease
+int MaxMissedCleavages
+int MinPeptideLength
+int MaxPeptideLength
+InitiatorMethionineBehavior InitiatorMethionineBehavior
+CleavageSpecificity SearchModeType
}
%% Relationships
IBioPolymer <|.. Protein
IBioPolymerWithSetMods <|.. PeptideWithSetModifications
Protein ..> PeptideWithSetModifications : creates
Protein ..> ProteolyticPeptide : creates
ProteolyticPeptide ..> PeptideWithSetModifications : creates
PeptideWithSetModifications --|> AminoAcidPolymer
Protein ..> ProteinDigestion : uses
ProteinDigestion ..> DigestionParams : uses
The Protein class represents a complete protein with all associated metadata:
public class Protein : IBioPolymer
{
// Core Properties
public string BaseSequence { get; }
public string Accession { get; }
public string Name { get; }
public string FullName { get; }
public string Organism { get; }
public int Length => BaseSequence.Length;
public bool IsDecoy { get; }
public bool IsContaminant { get; }
// Biological Information
public List<Tuple<string, string>> GeneNames { get; }
public IDictionary<int, List<Modification>> OneBasedPossibleLocalizedModifications { get; }
public List<SequenceVariation> SequenceVariations { get; }
public List<TruncationProduct> TruncationProducts { get; }
public List<DisulfideBond> DisulfideBonds { get; }
public List<SpliceSite> SpliceSites { get; }
// Digestion
public IEnumerable<PeptideWithSetModifications> Digest(
DigestionParams digestionParams,
List<Modification> allKnownFixedModifications,
List<Modification> variableModifications);
}Constructor Options:
// Basic protein
var protein = new Protein(
sequence: "MAQTQVLQVAK",
accession: "P12345"
);
// Protein with full metadata
var proteinWithMetadata = new Protein(
sequence: "MAQTQVLQVAK",
accession: "P12345",
organism: "Homo sapiens",
geneNames: new List<Tuple<string, string>>
{
Tuple.Create("primary", "ALB"),
Tuple.Create("ORF", "albumin")
},
oneBasedModifications: new Dictionary<int, List<Modification>>
{
{ 3, new List<Modification> { acetylation } } // Acetylation at position 3
},
name: "ALB_HUMAN",
fullName: "Serum albumin",
isDecoy: false,
isContaminant: false
);Represents a peptide with specific modifications applied:
public class PeptideWithSetModifications : AminoAcidPolymer, IBioPolymerWithSetMods
{
// Sequence Information
public string BaseSequence { get; }
public string FullSequence { get; }
public int Length => BaseSequence.Length;
// Position in Parent Protein
public int OneBasedStartResidue { get; }
public int OneBasedEndResidue { get; }
public char PreviousResidue { get; }
public char NextResidue { get; }
// Digestion Information
public int MissedCleavages { get; }
public CleavageSpecificity CleavageSpecificityForFdrCategory { get; }
public IBioPolymer Parent { get; } // Parent protein
// Modifications
public Dictionary<int, Modification> AllModsOneIsNterminus { get; }
public int NumMods { get; }
public int NumFixedMods { get; }
// Mass Properties
public double MonoisotopicMass { get; }
public double MostAbundantMonoisotopicMass { get; }
// Fragmentation
public void Fragment(
DissociationType dissociationType,
FragmentationTerminus fragmentationTerminus,
List<Product> products);
// Charge State Prediction
public int[] GetChargesToGenerate();
}Key Features:
var peptide = peptides.First();
// Access sequence information
Console.WriteLine($"Sequence: {peptide.BaseSequence}");
Console.WriteLine($"Full: {peptide.FullSequence}");
Console.WriteLine($"Context: {peptide.PreviousResidue}.{peptide.BaseSequence}.{peptide.NextResidue}");
// Position in protein
Console.WriteLine($"Position: {peptide.OneBasedStartResidue}-{peptide.OneBasedEndResidue}");
// Modifications
foreach (var mod in peptide.AllModsOneIsNterminus)
{
Console.WriteLine($"Mod at {mod.Key}: {mod.Value.IdWithMotif}");
}
// Mass
Console.WriteLine($"Monoisotopic mass: {peptide.MonoisotopicMass:F4} Da");
// Charge states
var charges = peptide.GetChargesToGenerate();
Console.WriteLine($"Predicted charges: {string.Join(", ", charges)}");// Create protein
var protein = new Protein("MAQTQVLQVAKEATPTPLPTAVPR", "P12345");
// Configure digestion parameters
var digestionParams = new DigestionParams(
protease: "trypsin",
maxMissedCleavages: 2,
minPeptideLength: 7,
maxPeptideLength: 30,
initiatorMethionineBehavior: InitiatorMethionineBehavior.Variable
);
// Perform digestion
var peptides = protein.Digest(
digestionParams,
fixedModifications,
variableModifications
).ToList();
Console.WriteLine($"Generated {peptides.Count} peptides");// Define modifications
var fixedMods = new List<Modification>
{
PtmListLoader.LoadPtmFromUnimodString("Carbamidomethyl on C")
};
var variableMods = new List<Modification>
{
PtmListLoader.LoadPtmFromUnimodString("Oxidation on M"),
PtmListLoader.LoadPtmFromUnimodString("Phospho on S"),
PtmListLoader.LoadPtmFromUnimodString("Phospho on T")
};
// Digest
var peptides = protein.Digest(digestionParams, fixedMods, variableMods);
// Each peptide has specific modifications
foreach (var peptide in peptides.Take(10))
{
Console.WriteLine(peptide.FullSequence);
// Example: PEPTIDE[Common:Oxidation on M]
// Example: [Common:Phospho on S]SEQUENCE
}// Variable: Generate both with and without M
var variableParams = new DigestionParams(
protease: "trypsin",
initiatorMethionineBehavior: InitiatorMethionineBehavior.Variable
);
var variablePeptides = protein.Digest(variableParams, fixedMods, variableMods);
// Generates: MAQTQVLQVAK and AQTQVLQVAK
// Retain: Always keep M
var retainParams = new DigestionParams(
protease: "trypsin",
initiatorMethionineBehavior: InitiatorMethionineBehavior.Retain
);
var retainPeptides = protein.Digest(retainParams, fixedMods, variableMods);
// Generates: MAQTQVLQVAK only
// Cleave: Always remove M
var cleaveParams = new DigestionParams(
protease: "trypsin",
initiatorMethionineBehavior: InitiatorMethionineBehavior.Cleave
);
var cleavePeptides = protein.Digest(cleaveParams, fixedMods, variableMods);
// Generates: AQTQVLQVAK onlyHandle protein sequence variants (SNPs, indels):
// Add sequence variant
var variant = new SequenceVariation(
oneBasedBeginPosition: 10,
oneBasedEndPosition: 10,
originalSequence: "A",
variantSequence: "V",
description: "A10V missense"
);
protein.SequenceVariations.Add(variant);
// Generate variant proteins
var variantProteins = protein.GetVariantBioPolymers(
maxAllowedVariants: 4,
minAlleleDepth: 1
);
foreach (var variantProtein in variantProteins)
{
Console.WriteLine($"Accession: {variantProtein.Accession}");
Console.WriteLine($"Applied variants: {variantProtein.AppliedSequenceVariations.Count}");
// Digest variant protein
var variantPeptides = variantProtein.Digest(digestionParams, fixedMods, variableMods);
}Support for stable isotope labeling:
// Define SILAC label (heavy lysine: +8 Da)
var silacLabel = new SilacLabel(
originalAminoAcid: 'K',
aminoAcidLabel: 'a', // Represent labeled K as 'a'
labelChemicalFormula: ChemicalFormula.ParseFormula("C'6N'2"), // Heavy C and N
massDifference: 8.014199
);
// Add heavy arginine to same label
var heavyArg = new SilacLabel(
originalAminoAcid: 'R',
aminoAcidLabel: 'b', // Represent labeled R as 'b'
labelChemicalFormula: ChemicalFormula.ParseFormula("C'6N'4"),
massDifference: 10.008269
);
silacLabel.AddAdditionalSilacLabel(heavyArg);
// Digest with SILAC
var silacPeptides = protein.Digest(
digestionParams,
fixedMods,
variableMods,
silacLabels: new List<SilacLabel> { silacLabel },
turnoverLabels: null // For multiplex experiments
).ToList();
// Results include both light and heavy peptides
foreach (var peptide in silacPeptides.Where(p => p.BaseSequence.Contains('a') || p.BaseSequence.Contains('b')))
{
Console.WriteLine($"{peptide.FullSequence} (heavy)");
}Filter for glycopeptides:
// Keep only N-glycopeptides (NxS/NxT motif)
var nGlycoParams = new DigestionParams(
protease: "trypsin",
keepNGlycopeptide: true
);
var nGlycoPeptides = protein.Digest(nGlycoParams, fixedMods, variableMods);
// Keep only O-glycopeptides (contains S or T)
var oGlycoParams = new DigestionParams(
protease: "trypsin",
keepOGlycopeptide: true
);
var oGlycoPeptides = protein.Digest(oGlycoParams, fixedMods, variableMods);
// Keep both
var allGlycoParams = new DigestionParams(
protease: "trypsin",
keepNGlycopeptide: true,
keepOGlycopeptide: true
);
var allGlycoPeptides = protein.Digest(allGlycoParams, fixedMods, variableMods);Work with intact proteins and truncation products:
// Configure for top-down
var topDownParams = new DigestionParams(
protease: "top-down",
minPeptideLength: 50,
maxPeptideLength: int.MaxValue,
searchModeType: CleavageSpecificity.None
);
// Add truncation products (N- and C-terminal truncations)
protein.AddTruncations(
addFullProtein: true, // Include intact protein
addForEachOrigninalProteolysisProduct: true, // Truncate each proteolysis product
addNterminalDigestionTruncations: true,
addCterminalDigestionTruncations: true,
minProductBaseSequenceLength: 50,
lengthOfProteolysis: 5 // Up to 5 aa removed from each end
);
// Digest (returns intact and truncated forms)
var topDownPeptides = protein.Digest(
topDownParams,
fixedMods,
variableMods,
topDownTruncationSearch: true
).ToList();
Console.WriteLine($"Generated {topDownPeptides.Count} proteoforms");var peptide = peptides.First();
// Get chemical formula
var formula = peptide.GetChemicalFormula();
Console.WriteLine($"Formula: {formula.Formula}");
// Get isotopic distribution
var isotopeDistribution = peptide.GetIsotopicDistribution();
foreach (var (mass, intensity) in isotopeDistribution.Masses.Zip(isotopeDistribution.Intensities))
{
Console.WriteLine($" m/z {mass:F4}: {intensity:F2}%");
}
// Element counts
var elementCounts = peptide.ElementCount();
foreach (var (element, count) in elementCounts)
{
Console.WriteLine($"{element}: {count}");
}// Get predicted charge states based on peptide properties
var charges = peptide.GetChargesToGenerate();
Console.WriteLine($"Predicted charge states: {string.Join(", ", charges)}");
// Generate m/z values for each charge state
foreach (var charge in charges)
{
double mz = (peptide.MonoisotopicMass + charge * Constants.ProtonMass) / charge;
Console.WriteLine($" +{charge}: {mz:F4} m/z");
}// Access peptide metadata
Console.WriteLine($"Parent protein: {peptide.Parent.Accession}");
Console.WriteLine($"Start-End: {peptide.OneBasedStartResidue}-{peptide.OneBasedEndResidue}");
Console.WriteLine($"Previous: {peptide.PreviousResidue}, Next: {peptide.NextResidue}");
Console.WriteLine($"Missed cleavages: {peptide.MissedCleavages}");
Console.WriteLine($"Specificity: {peptide.CleavageSpecificityForFdrCategory}");
Console.WriteLine($"Description: {peptide.PeptideDescription}");// Load protein database
var proteins = ProteinDbLoader.LoadProteinFasta(
"uniprot_human.fasta",
generateTargets: true,
decoyType: DecoyType.Reverse,
isContaminant: false,
out var errors
);
Console.WriteLine($"Loaded {proteins.Count} proteins");
// Configure search parameters
var searchParams = new DigestionParams(
protease: "trypsin",
maxMissedCleavages: 2,
minPeptideLength: 7,
maxPeptideLength: 50,
initiatorMethionineBehavior: InitiatorMethionineBehavior.Variable,
searchModeType: CleavageSpecificity.Full
);
// Generate theoretical peptides
var theoreticalPeptides = proteins
.AsParallel()
.SelectMany(p => p.Digest(searchParams, fixedMods, variableMods))
.Where(p => p.MonoisotopicMass >= 500 && p.MonoisotopicMass <= 5000)
.Distinct()
.ToList();
Console.WriteLine($"Generated {theoreticalPeptides.Count} unique peptides");// Load experimental spectrum
var spectrum = /* load from file */;
// Get candidate peptides
var candidates = theoreticalPeptides
.Where(p => Math.Abs(p.MonoisotopicMass - spectrum.PrecursorMass) < tolerance)
.ToList();
// Score each candidate
foreach (var candidate in candidates)
{
// Generate theoretical fragments
var products = new List<Product>();
candidate.Fragment(DissociationType.HCD, FragmentationTerminus.Both, products);
// Match to experimental spectrum
int matchedIons = 0;
double totalIntensity = 0;
foreach (var product in products)
{
int closestPeakIndex = spectrum.GetClosestPeakIndex(product.NeutralMass);
if (closestPeakIndex >= 0)
{
double experimentalMz = spectrum.XArray[closestPeakIndex];
if (Math.Abs(product.NeutralMass - experimentalMz) < ionTolerance)
{
matchedIons++;
totalIntensity += spectrum.YArray[closestPeakIndex];
}
}
}
double score = matchedIons * totalIntensity;
Console.WriteLine($"{candidate.FullSequence}: {score:F2}");
}// Calculate sequence coverage
var identifiedPeptides = /* peptides identified from MS */;
var coveredResidues = new HashSet<int>();
foreach (var peptide in identifiedPeptides.Where(p => p.Parent.Accession == protein.Accession))
{
for (int i = peptide.OneBasedStartResidue; i <= peptide.OneBasedEndResidue; i++)
{
coveredResidues.Add(i);
}
}
double coverage = (double)coveredResidues.Count / protein.Length * 100;
Console.WriteLine($"Sequence coverage: {coverage:F1}%");
// Visualize coverage
var coverageArray = new bool[protein.Length];
foreach (int pos in coveredResidues)
{
coverageArray[pos - 1] = true;
}
for (int i = 0; i < protein.Length; i++)
{
Console.Write(coverageArray[i] ? protein[i] : protein[i].ToString().ToLower());
}// Label-free quantification
var peptideIntensities = new Dictionary<string, List<double>>();
foreach (var run in experimentalRuns)
{
foreach (var peptide in identifiedPeptides)
{
if (!peptideIntensities.ContainsKey(peptide.FullSequence))
{
peptideIntensities[peptide.FullSequence] = new List<double>();
}
peptideIntensities[peptide.FullSequence].Add(GetPeptideIntensity(peptide, run));
}
}
// Calculate protein abundance
var proteinAbundance = peptideIntensities
.Where(kvp => kvp.Value.Count >= 3) // Require 3+ observations
.Select(kvp => kvp.Value.Average())
.Average();
Console.WriteLine($"Protein abundance: {proteinAbundance:E2}");Proteomics
↓
Omics (IBioPolymer, IBioPolymerWithSetMods, Modifications, Digestion, Fragmentation)
↓
Chemistry (ChemicalFormula, PeriodicTable)
↓
MassSpectrometry (DissociationType)
↓
MzLibUtil (Utilities)
- MetaMorpheus: Database searching and PTM discovery
- FlashLFQ: Label-free quantification
- UsefulProteomicsDatabases: Database loading and management
// Good: Process proteins in batches for large databases
const int batchSize = 1000;
var allPeptides = new List<PeptideWithSetModifications>();
for (int i = 0; i < proteins.Count; i += batchSize)
{
var batch = proteins.Skip(i).Take(batchSize);
var batchPeptides = batch
.AsParallel()
.SelectMany(p => p.Digest(params, fixed, variable))
.ToList();
allPeptides.AddRange(batchPeptides);
// Process or save batch results
Console.WriteLine($"Processed {Math.Min(i + batchSize, proteins.Count)}/{proteins.Count} proteins");
}// Good: Load modifications from standard databases
var allMods = PtmListLoader.ReadModsFromFile("mods.txt");
var fixedMods = allMods.Where(m => m.ModificationType == "Fixed").ToList();
var variableMods = allMods.Where(m => m.ModificationType == "Variable").ToList();
// Good: Limit variable modifications to prevent explosion
var params = new DigestionParams(
maxModificationIsoforms: 1024,
maxModsForPeptides: 2 // Max 2 variable mods per peptide
);
// Avoid: Too many variable modifications
var tooManyMods = allMods.Where(m => m.ModificationType == "Variable").ToList(); // Bad// Good: Use parallel processing
var peptides = proteins
.AsParallel()
.WithDegreeOfParallelism(Environment.ProcessorCount)
.SelectMany(p => p.Digest(params, fixed, variable))
.ToList();
// Good: Filter early
var peptides = proteins
.AsParallel()
.SelectMany(p => p.Digest(params, fixed, variable))
.Where(p => p.MonoisotopicMass >= 500 && p.MonoisotopicMass <= 5000)
.ToList();
// Good: Cache results
var proteinPeptideMap = proteins
.ToDictionary(
p => p.Accession,
p => p.Digest(params, fixed, variable).ToList()
);- Omics: Base Foundation - Core omics interfaces
- Omics: Modifications - PTM system
- Omics: Digestion - Enzymatic digestion framework
- Omics: Fragmentation - MS/MS fragmentation
- File Reading: Sequence Databases - Loading protein databases
- Decoy Generation - Generating decoy proteins