diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000000..5b462cccda --- /dev/null +++ b/.editorconfig @@ -0,0 +1,4 @@ +root = true + +[*] +insert_final_newline = true diff --git a/.gitignore b/.gitignore index 9f446d4ced..0a3cf251d0 100644 --- a/.gitignore +++ b/.gitignore @@ -234,4 +234,6 @@ _Pvt_Extensions # Macintosh files **/.DS_Store +/.opencode/ /AGENTS.md +/.serena diff --git a/MetaMorpheus/CMD/CMD.csproj b/MetaMorpheus/CMD/CMD.csproj index 13fa31edc9..370c3f309e 100644 --- a/MetaMorpheus/CMD/CMD.csproj +++ b/MetaMorpheus/CMD/CMD.csproj @@ -24,7 +24,7 @@ - + @@ -36,4 +36,8 @@ + + + + \ No newline at end of file diff --git a/MetaMorpheus/CMD/Properties/launchSettings.json b/MetaMorpheus/CMD/Properties/launchSettings.json new file mode 100644 index 0000000000..c92b8a2b35 --- /dev/null +++ b/MetaMorpheus/CMD/Properties/launchSettings.json @@ -0,0 +1,11 @@ +{ + "profiles": { + "CMD": { + "commandName": "Project" + }, + "WSL": { + "commandName": "WSL2", + "distributionName": "" + } + } +} \ No newline at end of file diff --git a/MetaMorpheus/EngineLayer/ClassicSearch/ClassicSearchEngine.cs b/MetaMorpheus/EngineLayer/ClassicSearch/ClassicSearchEngine.cs index a275e1e678..4c1c0af479 100644 --- a/MetaMorpheus/EngineLayer/ClassicSearch/ClassicSearchEngine.cs +++ b/MetaMorpheus/EngineLayer/ClassicSearch/ClassicSearchEngine.cs @@ -158,7 +158,7 @@ protected override MetaMorpheusEngineResults RunSpecific() // check if we've already generated theoretical fragments for this peptide+dissociation type if (peptideTheorProducts.Count == 0) { - specificBioPolymer.Fragment(dissociationType, CommonParameters.DigestionParams.FragmentationTerminus, peptideTheorProducts); + specificBioPolymer.Fragment(dissociationType, CommonParameters.DigestionParams.FragmentationTerminus, peptideTheorProducts, CommonParameters.FragmentationParameters); } // match theoretical target ions to spectrum @@ -205,7 +205,7 @@ private void DecoyScoreForSpectralLibrarySearch(ScanWithIndexAndNotchInfo scan, if (decoyTheoreticalFragments.Count == 0) { - reversedOnTheFlyDecoy.Fragment(dissociationType, CommonParameters.DigestionParams.FragmentationTerminus, decoyTheoreticalFragments); + reversedOnTheFlyDecoy.Fragment(dissociationType, CommonParameters.DigestionParams.FragmentationTerminus, decoyTheoreticalFragments, CommonParameters.FragmentationParameters); } Ms2ScanWithSpecificMass theScan = ArrayOfSortedMS2Scans[scan.ScanIndex]; var decoyMatchedIons = MatchFragmentIons(theScan, decoyTheoreticalFragments, CommonParameters, diff --git a/MetaMorpheus/EngineLayer/CommonParameters.cs b/MetaMorpheus/EngineLayer/CommonParameters.cs index f745ce5f48..139edccc1c 100644 --- a/MetaMorpheus/EngineLayer/CommonParameters.cs +++ b/MetaMorpheus/EngineLayer/CommonParameters.cs @@ -7,9 +7,9 @@ using System.Reflection; using Nett; using Omics.Digestion; -using Omics.Fragmentation.Peptide; using Transcriptomics.Digestion; using EngineLayer.DIA; +using Transcriptomics; namespace EngineLayer { @@ -47,7 +47,8 @@ public CommonParameters( bool trimMs1Peaks = false, bool trimMsMsPeaks = true, Tolerance productMassTolerance = null, - Tolerance precursorMassTolerance = null, + Tolerance precursorMassTolerance = null, + Tolerance productMassTolerance_LowRes = null, Tolerance deconvolutionMassTolerance = null, int maxThreadsToUsePerFile = -1, IDigestionParams digestionParams = null, @@ -60,7 +61,8 @@ public CommonParameters( DeconvolutionParameters precursorDeconParams = null, DeconvolutionParameters productDeconParams = null, bool useMostAbundantPrecursorIntensity = true, - DIAparameters diaParameters = null) + DIAparameters diaParameters = null, + IFragmentationParams fragmentationParams = null) { TaskDescriptor = taskDescriptor; @@ -84,6 +86,7 @@ public CommonParameters( MaxThreadsToUsePerFile = maxThreadsToUsePerFile == -1 ? Environment.ProcessorCount > 1 ? Environment.ProcessorCount - 1 : 1 : maxThreadsToUsePerFile; ProductMassTolerance = productMassTolerance ?? new PpmTolerance(20); PrecursorMassTolerance = precursorMassTolerance ?? new PpmTolerance(5); + ProductMassTolerance_LowRes = productMassTolerance_LowRes ?? ProductMassTolerance; DeconvolutionMassTolerance = deconvolutionMassTolerance ?? new PpmTolerance(4); DigestionParams = digestionParams ?? new DigestionParams(); DissociationType = dissociationType; @@ -119,11 +122,13 @@ public CommonParameters( ListOfModsFixed = listOfModsFixed ?? new List<(string, string)>(); PrecursorDeconvolutionParameters.AverageResidueModel = new OxyriboAveragine(); ProductDeconvolutionParameters.AverageResidueModel = new OxyriboAveragine(); + FragmentationParameters = fragmentationParams ?? RnaFragmentationParams.Default; } else { ListOfModsVariable = listOfModsVariable ?? new List<(string, string)> { ("Common Variable", "Oxidation on M") }; ListOfModsFixed = listOfModsFixed ?? new List<(string, string)> { ("Common Fixed", "Carbamidomethyl on C"), ("Common Fixed", "Carbamidomethyl on U") }; + FragmentationParameters = fragmentationParams ?? new FragmentationParams(); } CustomIons = digestionParams.ProductsFromDissociationType()[DissociationType.Custom]; @@ -157,8 +162,9 @@ public int DeconvolutionMaxAssumedChargeState [TomlIgnore] public Tolerance DeconvolutionMassTolerance { get; private set; } public int TotalPartitions { get; set; } public Tolerance ProductMassTolerance { get; set; } // public setter required for calibration task + public Tolerance ProductMassTolerance_LowRes { get; set; }// Wider mass tolerance for lower resolution analyzer (e.g. ion trap). For now, this is a independent parameter, will not be modified by the calibration task. public Tolerance PrecursorMassTolerance { get; set; } // public setter required for calibration task - public bool AddCompIons { get; private set; } + public bool AddCompIons { get; set; } /// /// Only peptides/PSMs with Q-Value and Q-Value Notch below this threshold are used for quantification and /// spectral library generation. If SearchParameters.WriteHighQValuePsms is set to false, only @@ -199,6 +205,7 @@ public int DeconvolutionMaxAssumedChargeState public bool UseMostAbundantPrecursorIntensity { get; set; } public DIAparameters? DIAparameters { get; set; } //only for DIA analysis involving pseudo ms2 scan generation + public IFragmentationParams FragmentationParameters { get; set; } public CommonParameters Clone() { @@ -257,6 +264,7 @@ public CommonParameters CloneWithNewTerminus(FragmentationTerminus? terminus = n TrimMsMsPeaks, ProductMassTolerance, PrecursorMassTolerance, + ProductMassTolerance_LowRes, DeconvolutionMassTolerance, MaxThreadsToUsePerFile, DigestionParams.Clone(terminus), @@ -267,7 +275,10 @@ public CommonParameters CloneWithNewTerminus(FragmentationTerminus? terminus = n MinVariantDepth, AddTruncations, PrecursorDeconvolutionParameters, - ProductDeconvolutionParameters); + ProductDeconvolutionParameters, + UseMostAbundantPrecursorIntensity, + DIAparameters, + FragmentationParameters); } public void SetCustomProductTypes() diff --git a/MetaMorpheus/EngineLayer/EngineLayer.csproj b/MetaMorpheus/EngineLayer/EngineLayer.csproj index d2f7beb085..0cc8ac4775 100644 --- a/MetaMorpheus/EngineLayer/EngineLayer.csproj +++ b/MetaMorpheus/EngineLayer/EngineLayer.csproj @@ -29,7 +29,7 @@ - + diff --git a/MetaMorpheus/EngineLayer/GlycoSearch/GlycoSearchEngine.cs b/MetaMorpheus/EngineLayer/GlycoSearch/GlycoSearchEngine.cs index 8681df4139..3648d4ffe4 100644 --- a/MetaMorpheus/EngineLayer/GlycoSearch/GlycoSearchEngine.cs +++ b/MetaMorpheus/EngineLayer/GlycoSearch/GlycoSearchEngine.cs @@ -55,7 +55,6 @@ public GlycoSearchEngine(List[] globalCsms, Ms2ScanWithSpeci this.OxoniumIonFilter = oxoniumIonFilter; this._oglycanDatabase = oglycanDatabase; this._nglycanDatabase = nglycanDatabase; - SecondFragmentIndex = secondFragmentIndex; PrecusorSearchMode = commonParameters.PrecursorMassTolerance; ProductSearchMode = new SinglePpmAroundZeroSearchMode(20); //For Oxonium ion only @@ -324,7 +323,8 @@ private GlycoSpectralMatch CreateGsm(Ms2ScanWithSpecificMass theScan, int scanIn var PeptideScore = score - DiagnosticIonScore; - var p = theScan.TheScan.MassSpectrum.Size * CommonParameters.ProductMassTolerance.GetRange(1000).Width / theScan.TheScan.MassSpectrum.Range.Width; + var parentProductTolerance = IsLowResolutionScan(theScan) ? CommonParameters.ProductMassTolerance_LowRes : CommonParameters.ProductMassTolerance; + var p = theScan.TheScan.MassSpectrum.Size * parentProductTolerance.GetRange(1000).Width / theScan.TheScan.MassSpectrum.Range.Width; int n = fragmentsForEachGlycoPeptide.Where(v => v.ProductType == ProductType.c || v.ProductType == ProductType.zDot).Count(); @@ -333,7 +333,6 @@ private GlycoSpectralMatch CreateGsm(Ms2ScanWithSpecificMass theScan, int scanIn foreach (var childScan in theScan.ChildScans) { var childFragments = GlycoPeptides.OGlyGetTheoreticalFragments(CommonParameters.MS2ChildScanDissociationType, CommonParameters.CustomIons, peptide, peptideWithMod); - var matchedChildIons = MatchFragmentIons(childScan, childFragments, CommonParameters); n += childFragments.Where(v => v.ProductType == ProductType.c || v.ProductType == ProductType.zDot).Count(); @@ -356,7 +355,8 @@ private GlycoSpectralMatch CreateGsm(Ms2ScanWithSpecificMass theScan, int scanIn //TO THINK:may think a different way to use childScore score += childScore; - p += childScan.TheScan.MassSpectrum.Size * CommonParameters.ProductMassTolerance.GetRange(1000).Width / childScan.TheScan.MassSpectrum.Range.Width; + var productTolerance = IsLowResolutionScan(childScan) ? CommonParameters.ProductMassTolerance_LowRes : CommonParameters.ProductMassTolerance; + p += childScan.TheScan.MassSpectrum.Size * productTolerance.GetRange(1000).Width / childScan.TheScan.MassSpectrum.Range.Width; } @@ -439,12 +439,16 @@ private void FindOGlycan(Ms2ScanWithSpecificMass theScan, int scanIndex, int sco SortedDictionary modPos = GlycoSpectralMatch.GetPossibleModSites(theScanBestPeptide, Motifs); //list all of the possible glycoslation site/postition var localizationScan = theScan; + var toleranceForLocalizationScan = CommonParameters.ProductMassTolerance; List products = new List(); // product list for the theoretical fragment ions //For HCD-pd-ETD or CD-pd-EThcD type of data, we generate the different rpoducts. if (theScan.ChildScans.Count > 0 && GlycoPeptides.DissociationTypeContainETD(CommonParameters.MS2ChildScanDissociationType, CommonParameters.CustomIons)) { localizationScan = theScan.ChildScans.First(); + // For the localization scan, if it is from ion trap, we will use a wider tolerance for the localization. + toleranceForLocalizationScan = localizationScan.TheScan.MzAnalyzer == MZAnalyzerType.IonTrap2D || + localizationScan.TheScan.MzAnalyzer == MZAnalyzerType.IonTrap3D ? CommonParameters.ProductMassTolerance_LowRes : CommonParameters.ProductMassTolerance; theScanBestPeptide.Fragment(DissociationType.ETD, FragmentationTerminus.Both, products); } @@ -477,7 +481,7 @@ private void FindOGlycan(Ms2ScanWithSpecificMass theScan, int scanIndex, int sco if (GraphCheck(modPos, GlycanBoxes[iDLow])) // the glycosite number should be larger than the possible glycan number. { LocalizationGraph localizationGraph = new LocalizationGraph(modPos, GlycanBoxes[iDLow], GlycanBoxes[iDLow].ChildGlycanBoxes, iDLow); - LocalizationGraph.LocalizeOGlycan(localizationGraph, localizationScan, CommonParameters.ProductMassTolerance, products); //create the localization graph with the glycan mass and the possible glycosite. + LocalizationGraph.LocalizeOGlycan(localizationGraph, localizationScan, toleranceForLocalizationScan, products); //create the localization graph with the glycan mass and the possible glycosite. double currentLocalizationScore = localizationGraph.TotalScore; if (currentLocalizationScore > bestLocalizedScore) //Try to find the best glycanBox with the highest score. diff --git a/MetaMorpheus/EngineLayer/Gptmd/GptmdEngine.cs b/MetaMorpheus/EngineLayer/Gptmd/GptmdEngine.cs index 99c1c4a423..ded6bade32 100644 --- a/MetaMorpheus/EngineLayer/Gptmd/GptmdEngine.cs +++ b/MetaMorpheus/EngineLayer/Gptmd/GptmdEngine.cs @@ -136,7 +136,7 @@ protected override MetaMorpheusEngineResults RunSpecific() var newPep = pepWithSetMods.Localize(pepSeqIndex, mod.MonoisotopicMass.Value); peptideTheorProducts.Clear(); - newPep.Fragment(dissociationType, CommonParameters.DigestionParams.FragmentationTerminus, peptideTheorProducts); + newPep.Fragment(dissociationType, CommonParameters.DigestionParams.FragmentationTerminus, peptideTheorProducts, CommonParameters.FragmentationParameters); ms2ScanWithSpecificMass ??= new Ms2ScanWithSpecificMass(scan, precursorMass, precursorCharge, fileName, CommonParameters); var matchedIons = MatchFragmentIons(ms2ScanWithSpecificMass, peptideTheorProducts, CommonParameters, matchAllCharges: false); diff --git a/MetaMorpheus/EngineLayer/Indexing/IndexingEngine.cs b/MetaMorpheus/EngineLayer/Indexing/IndexingEngine.cs index ec51eda000..daf416cb0b 100644 --- a/MetaMorpheus/EngineLayer/Indexing/IndexingEngine.cs +++ b/MetaMorpheus/EngineLayer/Indexing/IndexingEngine.cs @@ -160,7 +160,7 @@ protected override MetaMorpheusEngineResults RunSpecific() for (int peptideId = 0; peptideId < peptides.Count; peptideId++) { - peptides[peptideId].Fragment(CommonParameters.DissociationType, CommonParameters.DigestionParams.FragmentationTerminus, fragments); + peptides[peptideId].Fragment(CommonParameters.DissociationType, CommonParameters.DigestionParams.FragmentationTerminus, fragments, CommonParameters.FragmentationParameters); foreach (var theoreticalFragment in fragments) { diff --git a/MetaMorpheus/EngineLayer/Localization/LocalizationEngine.cs b/MetaMorpheus/EngineLayer/Localization/LocalizationEngine.cs index da2f989a44..9d25ba2eea 100644 --- a/MetaMorpheus/EngineLayer/Localization/LocalizationEngine.cs +++ b/MetaMorpheus/EngineLayer/Localization/LocalizationEngine.cs @@ -65,7 +65,7 @@ protected override MetaMorpheusEngineResults RunSpecific() var peptideWithLocalizedMassDiff = peptide.Localize(r, massDifference); // this is the list of theoretical products for this peptide with mass-difference on this residue - peptideWithLocalizedMassDiff.Fragment(CommonParameters.DissociationType, CommonParameters.DigestionParams.FragmentationTerminus, productsWithLocalizedMassDiff); + peptideWithLocalizedMassDiff.Fragment(CommonParameters.DissociationType, CommonParameters.DigestionParams.FragmentationTerminus, productsWithLocalizedMassDiff, CommonParameters.FragmentationParameters); var matchedIons = MatchFragmentIons(scanWithSpecificMass, productsWithLocalizedMassDiff, CommonParameters); diff --git a/MetaMorpheus/EngineLayer/MetaMorpheusEngine.cs b/MetaMorpheus/EngineLayer/MetaMorpheusEngine.cs index f8191d7fa9..71960e8c71 100644 --- a/MetaMorpheus/EngineLayer/MetaMorpheusEngine.cs +++ b/MetaMorpheus/EngineLayer/MetaMorpheusEngine.cs @@ -130,6 +130,9 @@ private static double CalculateAllChargesPeptideScore(MsDataScan thisScan, List< public static List MatchFragmentIons(Ms2ScanWithSpecificMass scan, List theoreticalProducts, CommonParameters commonParameters, bool matchAllCharges = false) { + // auto-detect low-res scans from mass analyzer metadata and use wider tolerance for ion trap child scans + bool isLowRes = IsLowResolutionScan(scan); + var productMassTolerance = isLowRes ? commonParameters.ProductMassTolerance_LowRes : commonParameters.ProductMassTolerance; if (matchAllCharges) { return MatchFragmentIonsOfAllCharges(scan, theoreticalProducts, commonParameters); @@ -153,7 +156,8 @@ public static List MatchFragmentIons(Ms2ScanWithSpecificMass double theoreticalFragmentMz = Math.Round(product.NeutralMass.ToMz(1) / 1.0005079, 0) * 1.0005079; var closestMzIndex = scan.TheScan.MassSpectrum.GetClosestPeakIndex(theoreticalFragmentMz); - if (commonParameters.ProductMassTolerance.Within(scan.TheScan.MassSpectrum.XArray[closestMzIndex], theoreticalFragmentMz)) + + if (productMassTolerance.Within(scan.TheScan.MassSpectrum.XArray[closestMzIndex], theoreticalFragmentMz)) { matchedFragmentIons.Add(new MatchedFragmentIon(product, theoreticalFragmentMz, scan.TheScan.MassSpectrum.YArray[closestMzIndex], 1)); } @@ -183,7 +187,7 @@ public static List MatchFragmentIons(Ms2ScanWithSpecificMass // is the mass error acceptable? if (closestExperimentalMass != null - && commonParameters.ProductMassTolerance.Within(closestExperimentalMass.MonoisotopicMass, product.NeutralMass) + && productMassTolerance.Within(closestExperimentalMass.MonoisotopicMass, product.NeutralMass) && Math.Abs(closestExperimentalMass.Charge) <= Math.Abs(scan.PrecursorCharge))//TODO apply this filter before picking the envelope { matchedFragmentIons.Add(new MatchedFragmentIon(product, closestExperimentalMass.MonoisotopicMass.ToMz(closestExperimentalMass.Charge), @@ -211,7 +215,7 @@ public static List MatchFragmentIons(Ms2ScanWithSpecificMass IsotopicEnvelope closestExperimentalMass = scan.GetClosestExperimentalIsotopicEnvelope(compIonMass); // is the mass error acceptable? - if (commonParameters.ProductMassTolerance.Within(closestExperimentalMass.MonoisotopicMass, compIonMass) && closestExperimentalMass.Charge <= scan.PrecursorCharge) + if (productMassTolerance.Within(closestExperimentalMass.MonoisotopicMass, compIonMass) && closestExperimentalMass.Charge <= scan.PrecursorCharge) { //found the peak, but we don't want to save that m/z because it's the complementary of the observed ion that we "added". Need to create a fake ion instead. double mz = (scan.PrecursorMass + protonMassShift - closestExperimentalMass.MonoisotopicMass).ToMz(closestExperimentalMass.Charge); @@ -230,6 +234,8 @@ public static List MatchFragmentIons(Ms2ScanWithSpecificMass //But for library generation, we need find all the matched peaks with all the different charges. private static List MatchFragmentIonsOfAllCharges(Ms2ScanWithSpecificMass scan, List theoreticalProducts, CommonParameters commonParameters) { + bool isLowRes = IsLowResolutionScan(scan); + var productMassTolerance = isLowRes ? commonParameters.ProductMassTolerance_LowRes : commonParameters.ProductMassTolerance; var matchedFragmentIons = new List(); var ions = new List(); @@ -249,8 +255,8 @@ private static List MatchFragmentIonsOfAllCharges(Ms2ScanWit } //get the range we can accept - var minMass = commonParameters.ProductMassTolerance.GetMinimumValue(product.NeutralMass); - var maxMass = commonParameters.ProductMassTolerance.GetMaximumValue(product.NeutralMass); + var minMass = productMassTolerance.GetMinimumValue(product.NeutralMass); + var maxMass = productMassTolerance.GetMaximumValue(product.NeutralMass); var closestExperimentalMassList = scan.GetClosestExperimentalIsotopicEnvelopeList(minMass, maxMass); if (closestExperimentalMassList != null) { @@ -259,7 +265,7 @@ private static List MatchFragmentIonsOfAllCharges(Ms2ScanWit String ion = $"{product.ProductType.ToString()}{ product.FragmentNumber}^{x.Charge}-{product.NeutralLoss}"; if (x != null && !ions.Contains(ion) - && commonParameters.ProductMassTolerance.Within(x.MonoisotopicMass, product.NeutralMass) + && productMassTolerance.Within(x.MonoisotopicMass, product.NeutralMass) && Math.Abs(x.Charge) <= Math.Abs(scan.PrecursorCharge))//TODO apply this filter before picking the envelope { Product temProduct = product; @@ -274,6 +280,17 @@ private static List MatchFragmentIonsOfAllCharges(Ms2ScanWit return matchedFragmentIons; } + + /// + /// Determines whether the given scan was acquired on a low-resolution mass analyzer (e.g., ion trap). + /// Used to select the appropriate product mass tolerance for fragment ion matching. + /// + internal static bool IsLowResolutionScan(Ms2ScanWithSpecificMass scan) + { + var analyzer = scan.TheScan.MzAnalyzer; + return analyzer == MZAnalyzerType.IonTrap2D || analyzer == MZAnalyzerType.IonTrap3D; + } + protected abstract MetaMorpheusEngineResults RunSpecific(); public MetaMorpheusEngineResults Run() diff --git a/MetaMorpheus/EngineLayer/ModernSearch/ModernSearchEngine.cs b/MetaMorpheus/EngineLayer/ModernSearch/ModernSearchEngine.cs index 3d1660c149..5292a56c30 100644 --- a/MetaMorpheus/EngineLayer/ModernSearch/ModernSearchEngine.cs +++ b/MetaMorpheus/EngineLayer/ModernSearch/ModernSearchEngine.cs @@ -340,7 +340,7 @@ protected SpectralMatch FineScorePeptide(int id, Ms2ScanWithSpecificMass scan, i { PeptideWithSetModifications peptide = PeptideIndex[id]; - peptide.Fragment(CommonParameters.DissociationType, FragmentationTerminus.Both, peptideTheorProducts); + peptide.Fragment(CommonParameters.DissociationType, FragmentationTerminus.Both, peptideTheorProducts, CommonParameters.FragmentationParameters); List matchedIons = MatchFragmentIons(scan, peptideTheorProducts, CommonParameters); diff --git a/MetaMorpheus/EngineLayer/Mods/RnaMods.txt b/MetaMorpheus/EngineLayer/Mods/RnaMods.txt index 03c1289752..3fe4e6c080 100644 --- a/MetaMorpheus/EngineLayer/Mods/RnaMods.txt +++ b/MetaMorpheus/EngineLayer/Mods/RnaMods.txt @@ -1,4 +1,56 @@ -################################## METALS + +--------------------------------------------------------------------------- + UniProt Knowledgebase: + Swiss-Prot Protein Knowledgebase + TrEMBL Protein Database + SIB Swiss Institute of Bioinformatics; Geneva, Switzerland + European Bioinformatics Institute (EBI); Hinxton, United Kingdom + Protein Information Resource (PIR); Washington DC, USA +--------------------------------------------------------------------------- + +Description: Controlled vocabulary of posttranslational modifications (PTM) +Name: ptmlist.txt +Release: 2018_01 of 31-Jan-2018 + +--------------------------------------------------------------------------- + + This document lists the posttranslational modifications used in the + UniProt knowledgebase (Swiss-Prot and TrEMBL). + + The definition of the posttranslational modifications usage as well as + other information is provided in the following format: + + --------- --------------------------- ------------------------------ + Line code Content Occurrence in an entry + --------- --------------------------- ------------------------------ + ID Identifier (FT description) Once; starts a PTM entry + AC Accession (PTM-xxxx) Once + FT Feature key Once + TG Target Once; two targets separated by + a dash in case of intrachain + crosslinks + PA Position of the modification Optional; once + on the amino acid + PP Position of the modification Optional; once + in the polypeptide + CF Correction formula Optional; once + MM Monoisotopic mass difference Optional; once + MA Average mass difference Optional; once + LC Cellular location Optional; once; alternatives + can be proposed + TR Taxonomic range Optional; once or more + KW Keyword Optional; once or more + DR Cross-reference to PTM Optional; once or more + databases + BM Backbone modification Optional; once; alternatives can be + proposed; if present, the + affected fragment types are + listed after the modification + // Terminator Once; ends an entry + + +___________________________________________________________________________ +################################## METALS ID Sodium TG A or C or G or U PP Anywhere. @@ -14,40 +66,77 @@ CF H-1 K1 DR Unimod; 530. // ################################## Biological -ID Methylation -TG A or C or G or U or T or Y +ID 2'-O-Methyladenosine +TG A +PP Anywhere. +MT Biological +CF C1 H2 +BL Suppressed +DR Unimod; 34. +// +ID N6-methyladenosine +TG A +PP Anywhere. +MT Biological +CF C1 H2 +BL Modified +DR Unimod; 34. +// +ID 2'-O-Methyluridine +TG U +PP Anywhere. +MT Biological +CF C1 H2 +BL Suppressed +DR Unimod; 34. +// +ID 5-Methylcytidine +TG C PP Anywhere. MT Biological CF C1 H2 +BL Modified:C1H2 DR Unimod; 34. // +ID N6,2'-O-dimethyladenosine +TG A +PP Anywhere. +MT Biological +CF C2 H4 +BL Suppressed:C1H2 +DR Unimod; 36. +// +################################## Simple Biological +ID Methylation +TG A or C or G or U or T or Y +PP Anywhere. +MT Simple Biological +CF C1 H2 +// ID Dimethylation TG A or C or G or U or T or Y PP Anywhere. -MT Biological +MT Simple Biological CF C2 H4 -DR Unimod; 34. // ID MethoxyEthoxylation TG A or C or G or U PP Anywhere. -MT Biological +MT Simple Biological CF C3 H6 O1 -DR Unimod; 34. // +################################## Base Conversion ID Deoxylnosine TG T PP Anywhere. -MT Biological +MT Base Conversion CF N-1H-1 -DR Unimod; 34. // ID Deoxylnosine TG G PP Anywhere. -MT Biological +MT Base Conversion CF N-1H-1O-1 -DR Unimod; 34. // ################################## Common Artificial ID DeoxyFluoronation @@ -55,7 +144,6 @@ TG A or C or G or U PP Anywhere. MT Common Artificial CF O-1 H-1 F1 -DR Unimod; 34. // ################################## Terminal Shifts ID Cyclic Phosphate @@ -63,34 +151,55 @@ TG X PP Oligo 3'-terminal. MT Digestion Termini CF H-2 O-1 -DR Unimod; 280. // ID Terminal Phosphorylation TG X PP Oligo 5'-terminal. MT Digestion Termini CF H1 O3 P1 -DR Unimod; 280. // ID Terminal Dephosphorylation TG X PP Oligo 5'-terminal. MT Digestion Termini CF P-1 O-3 H-1 -DR Unimod; 280. // ID Pfizer 5'-Cap TG X PP 5'-terminal. MT Standard CF C13H22N5O14P3 -DR Unimod; 280. // ################################## Backbone Shift ID Phosphorothioate TG X +FT Backbone PP Anywhere. MT Common Variable CF SO-1 -DR Unimod; 280. +BM w,x,c,d +// +ID Boranophosphate +TG X +PP Anywhere. +FT Backbone +MT Therapeutic +CF B1 H3 O-1 +BM w,x,c,d +// +ID N3'-Phosphoramidate +TG X +PP Anywhere. +FT Backbone +MT Therapeutic +CF N1 H1 O-1 # Replace 3'-O with NH +BM w,b,c,d +// +ID Methylphosphonate +TG X +PP Anywhere. +FT Backbone +MT Therapeutic +CF C1 H2 O-1 +BM w,x,c,d // \ No newline at end of file diff --git a/MetaMorpheus/EngineLayer/NonSpecificEnzymeSearch/NonSpecificEnzymeSearchEngine.cs b/MetaMorpheus/EngineLayer/NonSpecificEnzymeSearch/NonSpecificEnzymeSearchEngine.cs index 85b530b504..ed363e2ab8 100644 --- a/MetaMorpheus/EngineLayer/NonSpecificEnzymeSearch/NonSpecificEnzymeSearchEngine.cs +++ b/MetaMorpheus/EngineLayer/NonSpecificEnzymeSearch/NonSpecificEnzymeSearchEngine.cs @@ -124,13 +124,13 @@ protected override MetaMorpheusEngineResults RunSpecific() foreach (int id in idsOfPeptidesPossiblyObserved.Where(id => scoringTable[id] == maxInitialScore)) { PeptideWithSetModifications peptide = PeptideIndex[id]; - peptide.Fragment(CommonParameters.DissociationType, CommonParameters.DigestionParams.FragmentationTerminus, peptideTheorProducts); + peptide.Fragment(CommonParameters.DissociationType, CommonParameters.DigestionParams.FragmentationTerminus, peptideTheorProducts, CommonParameters.FragmentationParameters); Tuple notchAndUpdatedPeptide = Accepts(peptideTheorProducts, scan.PrecursorMass, peptide, CommonParameters.DigestionParams.FragmentationTerminus, MassDiffAcceptor, semiSpecificSearch); int notch = notchAndUpdatedPeptide.Item1; if (notch >= 0) { peptide = notchAndUpdatedPeptide.Item2; - peptide.Fragment(CommonParameters.DissociationType, FragmentationTerminus.Both, peptideTheorProducts); + peptide.Fragment(CommonParameters.DissociationType, FragmentationTerminus.Both, peptideTheorProducts, CommonParameters.FragmentationParameters); List matchedIons = MatchFragmentIons(scan, peptideTheorProducts, ModifiedParametersNoComp); double thisScore = CalculatePeptideScore(scan.TheScan, matchedIons); diff --git a/MetaMorpheus/EngineLayer/SpectralLibrarySearch/SpectralLibrarySearchFunction.cs b/MetaMorpheus/EngineLayer/SpectralLibrarySearch/SpectralLibrarySearchFunction.cs index c32832c180..a8630ae29b 100644 --- a/MetaMorpheus/EngineLayer/SpectralLibrarySearch/SpectralLibrarySearchFunction.cs +++ b/MetaMorpheus/EngineLayer/SpectralLibrarySearch/SpectralLibrarySearchFunction.cs @@ -60,7 +60,7 @@ public static void CalculateSpectralAngles(SpectralLibrary spectralLibrary, Spec else if (bestMatch.IsDecoy && spectralLibrary.TryGetSpectrum(bestMatch.SpecificBioPolymer.Description, scan.PrecursorCharge, out var targetlibrarySpectrum)) { var decoyPeptideTheorProducts = new List(); - bestMatch.SpecificBioPolymer.Fragment(commonParameters.DissociationType, commonParameters.DigestionParams.FragmentationTerminus, decoyPeptideTheorProducts); + bestMatch.SpecificBioPolymer.Fragment(commonParameters.DissociationType, commonParameters.DigestionParams.FragmentationTerminus, decoyPeptideTheorProducts, commonParameters.FragmentationParameters); var decoylibrarySpectrum = LibrarySpectrum.GetDecoyLibrarySpectrumFromTargetByReverse(targetlibrarySpectrum, decoyPeptideTheorProducts); SpectralSimilarity s = new SpectralSimilarity(scan.TheScan.MassSpectrum, decoylibrarySpectrum.Select(x => x.Mz).ToArray(), decoylibrarySpectrum.Select(x => x.Intensity).ToArray(), SpectralSimilarity.SpectrumNormalizationScheme.SquareRootSpectrumSum, diff --git a/MetaMorpheus/GUI/App.xaml b/MetaMorpheus/GUI/App.xaml index 3b560cfcf2..31a78fda89 100644 --- a/MetaMorpheus/GUI/App.xaml +++ b/MetaMorpheus/GUI/App.xaml @@ -2,6 +2,7 @@ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:MetaMorpheusGUI" + xmlns:guiFunctions="clr-namespace:GuiFunctions;assembly=GuiFunctions" StartupUri="MainWindow.xaml"> @@ -105,7 +106,21 @@ - + + + + @@ -113,5 +128,7 @@ + + \ No newline at end of file diff --git a/MetaMorpheus/GUI/GUI.csproj b/MetaMorpheus/GUI/GUI.csproj index a264ec25cb..9449ab0152 100644 --- a/MetaMorpheus/GUI/GUI.csproj +++ b/MetaMorpheus/GUI/GUI.csproj @@ -63,7 +63,7 @@ - + diff --git a/MetaMorpheus/GUI/GUI_h05aw1sq_wpftmp.csproj b/MetaMorpheus/GUI/GUI_h05aw1sq_wpftmp.csproj new file mode 100644 index 0000000000..4f03a4b587 --- /dev/null +++ b/MetaMorpheus/GUI/GUI_h05aw1sq_wpftmp.csproj @@ -0,0 +1,448 @@ + + + MetaMorpheusGUI + obj\Debug\ + obj\ + C:\Users\Nic\source\repos\MetaMorpheus\MetaMorpheus\GUI\obj\ + <_TargetAssemblyProjectName>GUI + + + + WinExe + net8.0-windows + true + false + false + false + false + false + false + MetaMorpheusGUI + MetaMorpheusGUI + Debug;Release + full + true + Icons\MMnice.ico + true + + + true + false + false + false + + + x64 + + + x64 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Always + + + Always + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/MetaMorpheus/GUI/MainWindow.xaml b/MetaMorpheus/GUI/MainWindow.xaml index f0848612ad..ebab7d7fab 100644 --- a/MetaMorpheus/GUI/MainWindow.xaml +++ b/MetaMorpheus/GUI/MainWindow.xaml @@ -154,20 +154,6 @@ - - - - - + + @@ -380,6 +380,15 @@ + + + + + Write intermediate search result files during calibration. + + + + @@ -435,7 +444,6 @@ + + + + + + + + + + + + + + + + Basic search designed for standard search spaces (tight precursor mass tolerance, strict enzyme specificity) + + Ideal for low RAM machines. + + + + + + + + + Indexed search designed for massive search spaces (wide/open precursor mass tolerance). + + This search generates an indexed database that is saved to the folder of the original database. + + Subsequent "Modern Searches" are much faster after the creation of the indexed database. + + This search has potentially high RAM requirements, requiring database partitions. + + + + + + + + + @@ -519,4 +581,4 @@ - \ No newline at end of file + diff --git a/MetaMorpheus/GUI/TaskWindows/CalibrateTaskWindow.xaml.cs b/MetaMorpheus/GUI/TaskWindows/CalibrateTaskWindow.xaml.cs index 2906a3b917..5a06d67ced 100644 --- a/MetaMorpheus/GUI/TaskWindows/CalibrateTaskWindow.xaml.cs +++ b/MetaMorpheus/GUI/TaskWindows/CalibrateTaskWindow.xaml.cs @@ -1,4 +1,4 @@ -using EngineLayer; +using EngineLayer; using GuiFunctions; using MassSpectrometry; using MzLibUtil; @@ -99,8 +99,29 @@ private void UpdateFieldsFromTask(CalibrationTask task) PrecursorMassToleranceComboBox.SelectedIndex = task.CommonParameters.PrecursorMassTolerance is AbsoluteTolerance ? 0 : 1; CustomFragmentationWindow = new CustomFragmentationWindow(task.CommonParameters.CustomIons); writeIndexMzmlCheckbox.IsChecked = task.CalibrationParameters.WriteIndexedMzml; - - //writeIntermediateFilesCheckBox.IsChecked = task.CalibrationParameters.WriteIntermediateFiles; + NumberOfDatabaseSearchesTextBox.Text = task.CommonParameters.TotalPartitions.ToString(CultureInfo.InvariantCulture); + + //// Set Search Type radio buttons + switch (task.CalibrationParameters.SearchType) + { + case SearchType.Classic: + ClassicSearchRadioButton.IsChecked = true; + ModernSearchRadioButton.IsChecked = false; + break; + case SearchType.Modern: + ClassicSearchRadioButton.IsChecked = false; + ModernSearchRadioButton.IsChecked = true; + break; + default: + MessageBox.Show( + $"SearchType '{task.CalibrationParameters.SearchType}' is not supported by the Calibration Task window.", + "Unsupported Search Type", + MessageBoxButton.OK, + MessageBoxImage.Warning); + break; + } + + writeIntermediateFilesCheckBox.IsChecked = task.CalibrationParameters.WriteIntermediateFiles; MinScoreAllowed.Text = task.CommonParameters.ScoreCutoff.ToString(CultureInfo.InvariantCulture); @@ -159,7 +180,7 @@ private void UpdateFieldsFromTask(CalibrationTask task) private void PopulateChoices() { - bool isRnaMode = GuiGlobalParamsViewModel.Instance.IsRnaMode; + bool isRnaMode = GuiGlobalParamsViewModel.Instance.IsRnaMode; List modsToUse = isRnaMode ? GlobalVariables.AllRnaModsKnown.ToList() : GlobalVariables.AllModsKnown.ToList(); foreach (string dissassociationType in GlobalVariables.AllSupportedDissociationTypes.Keys) @@ -236,7 +257,7 @@ private void SaveButton_Click(object sender, RoutedEventArgs e) if (!TaskValidator.CheckTaskSettingsValidity(PrecursorMassToleranceTextBox.Text, ProductMassToleranceTextBox.Text, MissedCleavagesTextBox.Text, MaxModificationIsoformsTextBox.Text, MinPeptideLengthTextBox.Text, MaxPeptideLengthTextBox.Text, MaxThreadsTextBox.Text, MinScoreAllowed.Text, - fieldNotUsed, fieldNotUsed, fieldNotUsed, fieldNotUsed, fieldNotUsed, fieldNotUsed, null, null, fieldNotUsed, MaxModsPerPeptideTextBox.Text, fieldNotUsed, + fieldNotUsed, fieldNotUsed, fieldNotUsed, fieldNotUsed, fieldNotUsed, fieldNotUsed, null, null, fieldNotUsed, MaxModsPerPeptideTextBox.Text, fieldNotUsed, null, null, null)) { return; @@ -332,11 +353,12 @@ private void SaveButton_Click(object sender, RoutedEventArgs e) assumeOrphanPeaksAreZ1Fragments: protease.Name != "top-down" && !isRnaMode, minVariantDepth: minVariantDepth, maxHeterozygousVariants: maxHeterozygousVariants, + totalPartitions: int.Parse(NumberOfDatabaseSearchesTextBox.Text, CultureInfo.InvariantCulture), trimMsMsPeaks: false, doPrecursorDeconvolution: doPrecursorDeconvolution, precursorDeconParams: precursorDeconvolutionParameters, productDeconParams: productDeconvolutionParameters, - useProvidedPrecursorInfo: useProvidedPrecursorInfo); + useProvidedPrecursorInfo: useProvidedPrecursorInfo); TheTask.CommonParameters = commonParamsToSave; } else //bottom-up @@ -354,6 +376,7 @@ private void SaveButton_Click(object sender, RoutedEventArgs e) assumeOrphanPeaksAreZ1Fragments: protease.Name != "top-down", minVariantDepth: minVariantDepth, maxHeterozygousVariants: maxHeterozygousVariants, + totalPartitions: int.Parse(NumberOfDatabaseSearchesTextBox.Text, CultureInfo.InvariantCulture), useProvidedPrecursorInfo: useProvidedPrecursorInfo, doPrecursorDeconvolution: doPrecursorDeconvolution, precursorDeconParams: precursorDeconvolutionParameters, @@ -362,6 +385,24 @@ private void SaveButton_Click(object sender, RoutedEventArgs e) } TheTask.CalibrationParameters.WriteIndexedMzml = writeIndexMzmlCheckbox.IsChecked.Value; + TheTask.CalibrationParameters.WriteIntermediateFiles = writeIntermediateFilesCheckBox.IsChecked.Value; + if (ModernSearchRadioButton.IsChecked == true) + { + TheTask.CalibrationParameters.SearchType = SearchType.Modern; + } + else if (ClassicSearchRadioButton.IsChecked == true) + { + TheTask.CalibrationParameters.SearchType = SearchType.Classic; + } + else + { + MessageBox.Show( + "No search type is selected. Please select Classic or Modern search.", + "No Search Type Selected", + MessageBoxButton.OK, + MessageBoxImage.Warning); + return; + } DialogResult = true; } diff --git a/MetaMorpheus/GUI/TaskWindows/GlycoSearchTaskWindow.xaml b/MetaMorpheus/GUI/TaskWindows/GlycoSearchTaskWindow.xaml index 7ff8028446..5e48599319 100644 --- a/MetaMorpheus/GUI/TaskWindows/GlycoSearchTaskWindow.xaml +++ b/MetaMorpheus/GUI/TaskWindows/GlycoSearchTaskWindow.xaml @@ -238,23 +238,41 @@ - - - + + - - + + + + + - + @@ -264,7 +264,7 @@ - + @@ -642,10 +675,7 @@ - - - - + @@ -684,36 +714,6 @@ - - - - - - - - - - - - - - @@ -1005,92 +1005,8 @@ - - - - - - - Generates experimental (not theoretical) complementary ions for each MS2. - - Useful for localization of modifications. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Search for theoretical internal fragment ions AFTER scoring. These ions are useful for localizing PTMs, but are not used during scoring. - - - - - - - - - - + + diff --git a/MetaMorpheus/GUI/TaskWindows/SearchTaskWindow.xaml.cs b/MetaMorpheus/GUI/TaskWindows/SearchTaskWindow.xaml.cs index efe82b1789..df2f2e58ea 100644 --- a/MetaMorpheus/GUI/TaskWindows/SearchTaskWindow.xaml.cs +++ b/MetaMorpheus/GUI/TaskWindows/SearchTaskWindow.xaml.cs @@ -1,8 +1,11 @@ using EngineLayer; +using GuiFunctions; using MassSpectrometry; using MzLibUtil; using Nett; +using Omics.Digestion; using Omics.Fragmentation; +using Omics.Modifications; using Proteomics.ProteolyticDigestion; using System; using System.Collections.Generic; @@ -15,11 +18,9 @@ using System.Windows.Controls; using System.Windows.Input; using TaskLayer; -using UsefulProteomicsDatabases; -using GuiFunctions; -using Omics.Digestion; -using Omics.Modifications; +using Transcriptomics; using Transcriptomics.Digestion; +using UsefulProteomicsDatabases; namespace MetaMorpheusGUI { @@ -38,6 +39,7 @@ public partial class SearchTaskWindow : Window private bool AutomaticallyAskAndOrUpdateParametersBasedOnProtease = true; private CustomFragmentationWindow CustomFragmentationWindow; private MassDifferenceAcceptorSelectionViewModel _massDifferenceAcceptorViewModel; + private FragmentationParamsViewModel _fragmentationParamsViewModel; private string _defaultMultiplexType = "TMT10"; private DeconHostViewModel DeconHostViewModel; @@ -53,7 +55,7 @@ public SearchTaskWindow(SearchTask task) { Title = "RNA Search Task"; TheTask.SearchParameters = new RnaSearchParameters(); - TheTask.CommonParameters = new CommonParameters("RnaSearchTask", digestionParams: new RnaDigestionParams("RNase T1", 3), dissociationType: DissociationType.CID, deconvolutionMaxAssumedChargeState: -20, precursorMassTolerance: new PpmTolerance(15)); + TheTask.CommonParameters = new CommonParameters("RnaSearchTask", digestionParams: new RnaDigestionParams("RNase T1", 3), dissociationType: DissociationType.CID, deconvolutionMaxAssumedChargeState: -20, precursorMassTolerance: new PpmTolerance(15), fragmentationParams: new RnaFragmentationParams()); } else { @@ -307,20 +309,14 @@ private void UpdateFieldsFromTask(SearchTask task) MissedCleavagesTextBox.Text = task.CommonParameters.DigestionParams.MaxMissedCleavages == int.MaxValue ? "" : task.CommonParameters.DigestionParams.MaxMissedCleavages.ToString(CultureInfo.InvariantCulture); MinPeptideLengthTextBox.Text = task.CommonParameters.DigestionParams.MinLength.ToString(CultureInfo.InvariantCulture); MaxPeptideLengthTextBox.Text = task.CommonParameters.DigestionParams.MaxLength == int.MaxValue ? "" : task.CommonParameters.DigestionParams.MaxLength.ToString(CultureInfo.InvariantCulture); - MaxFragmentMassTextBox.Text = task.SearchParameters.MaxFragmentSize.ToString(CultureInfo.InvariantCulture); //put after max peptide length to allow for override of auto maxModificationIsoformsTextBox.Text = task.CommonParameters.DigestionParams.MaxModificationIsoforms.ToString(CultureInfo.InvariantCulture); MaxModNumTextBox.Text = task.CommonParameters.DigestionParams.MaxMods.ToString(CultureInfo.InvariantCulture); DissociationTypeComboBox.SelectedItem = task.CommonParameters.DissociationType.ToString(); SeparationTypeComboBox.SelectedItem = task.CommonParameters.SeparationType.ToString(); - NTerminalIons.IsChecked = task.CommonParameters.DigestionParams.FragmentationTerminus == FragmentationTerminus.Both || task.CommonParameters.DigestionParams.FragmentationTerminus == FragmentationTerminus.N; - CTerminalIons.IsChecked = task.CommonParameters.DigestionParams.FragmentationTerminus == FragmentationTerminus.Both || task.CommonParameters.DigestionParams.FragmentationTerminus == FragmentationTerminus.C; - InternalIonsCheckBox.IsChecked = task.SearchParameters.MinAllowedInternalFragmentLength != 0; - MinInternalFragmentLengthTextBox.Text = task.SearchParameters.MinAllowedInternalFragmentLength.ToString(); ProductMassToleranceTextBox.Text = task.CommonParameters.ProductMassTolerance.Value.ToString(CultureInfo.InvariantCulture); ProductMassToleranceComboBox.SelectedIndex = task.CommonParameters.ProductMassTolerance is AbsoluteTolerance ? 0 : 1; PrecursorMassToleranceTextBox.Text = task.CommonParameters.PrecursorMassTolerance.Value.ToString(CultureInfo.InvariantCulture); PrecursorMassToleranceComboBox.SelectedIndex = task.CommonParameters.PrecursorMassTolerance is AbsoluteTolerance ? 0 : 1; - AddCompIonCheckBox.IsChecked = task.CommonParameters.AddCompIons; NumberOfDatabaseSearchesTextBox.Text = task.CommonParameters.TotalPartitions.ToString(CultureInfo.InvariantCulture); RemoveContaminantRadioBox.IsChecked = task.SearchParameters.TCAmbiguity == TargetContaminantAmbiguity.RemoveContaminant; RemoveTargetRadioBox.IsChecked = task.SearchParameters.TCAmbiguity == TargetContaminantAmbiguity.RemoveTarget; @@ -441,6 +437,9 @@ private void UpdateFieldsFromTask(SearchTask task) _massDifferenceAcceptorViewModel = new(task.SearchParameters.MassDiffAcceptorType, task.SearchParameters.CustomMdac, task.CommonParameters.PrecursorMassTolerance.Value); WritePrunedDBCheckBox.IsChecked = task.SearchParameters.WritePrunedDatabase; UpdateModSelectionGrid(); + + _fragmentationParamsViewModel = new FragmentationParamsViewModel(task.CommonParameters, task.SearchParameters); + FragmentationParametersControl.DataContext = _fragmentationParamsViewModel; } private void CancelButton_Click(object sender, RoutedEventArgs e) @@ -472,11 +471,11 @@ private void SaveButton_Click(object sender, RoutedEventArgs e) WindowWidthThomsonsTextBox.Text, NumberOfWindowsTextBox.Text, NumberOfDatabaseSearchesTextBox.Text, - MaxModNumTextBox.Text, - MaxFragmentMassTextBox.Text, + MaxModNumTextBox.Text, + _fragmentationParamsViewModel.MaxFragmentMassDa.ToString(), QValueThresholdTextBox.Text, - PepQValueThresholdTextBox.Text, - InternalIonsCheckBox.IsChecked.Value ? MinInternalFragmentLengthTextBox.Text : null)) + PepQValueThresholdTextBox.Text, + _fragmentationParamsViewModel.GenerateInternalIons ? _fragmentationParamsViewModel.MinInternalIonLength.ToString() : null)) { return; } @@ -560,7 +559,7 @@ private void SaveButton_Click(object sender, RoutedEventArgs e) { PrecursorMassTolerance = new PpmTolerance(double.Parse(PrecursorMassToleranceTextBox.Text, CultureInfo.InvariantCulture)); } - TheTask.SearchParameters.MaxFragmentSize = double.Parse(MaxFragmentMassTextBox.Text, CultureInfo.InvariantCulture); + TheTask.SearchParameters.MaxFragmentSize = _fragmentationParamsViewModel.MaxFragmentMassDa; var listOfModsVariable = new List<(string, string)>(); foreach (var heh in VariableModTypeForTreeViewObservableCollection) @@ -642,12 +641,13 @@ private void SaveButton_Click(object sender, RoutedEventArgs e) windowWidthThomsons: windowWidthThompsons, numberOfWindows: numberOfWindows,//maybe change this some day normalizePeaksAccrossAllWindows: normalizePeaksAccrossAllWindows,//maybe change this some day - addCompIons: AddCompIonCheckBox.IsChecked.Value, + addCompIons: _fragmentationParamsViewModel.GenerateComplementaryIons, assumeOrphanPeaksAreZ1Fragments: protease.Name != "top-down", minVariantDepth: MinVariantDepth, maxHeterozygousVariants: MaxHeterozygousVariants, precursorDeconParams: precursorDeconvolutionParameters, - productDeconParams: productDeconvolutionParameters); + productDeconParams: productDeconvolutionParameters, + fragmentationParams: _fragmentationParamsViewModel.ToFragmentationParams() ); if (ClassicSearchRadioButton.IsChecked.Value) { @@ -668,7 +668,7 @@ private void SaveButton_Click(object sender, RoutedEventArgs e) return; } - TheTask.SearchParameters.MinAllowedInternalFragmentLength = InternalIonsCheckBox.IsChecked.Value ? Convert.ToInt32(MinInternalFragmentLengthTextBox.Text) : 0; + TheTask.SearchParameters.MinAllowedInternalFragmentLength = _fragmentationParamsViewModel.GenerateInternalIons ? _fragmentationParamsViewModel.MinInternalIonLength : 0; TheTask.SearchParameters.DoParsimony = CheckBoxParsimony.IsChecked.Value; TheTask.SearchParameters.NoOneHitWonders = CheckBoxNoOneHitWonders.IsChecked.Value; TheTask.SearchParameters.DoLabelFreeQuantification = !CheckBoxNoQuant.IsChecked.Value; @@ -858,13 +858,13 @@ private void NonSpecificUsingNonSpecific(object sender, RoutedEventArgs e) if (NonSpecificSearchRadioButton.IsChecked.Value) { ProteaseComboBox.SelectedItem = ProteaseDictionary.Dictionary["non-specific"]; - AddCompIonCheckBox.IsChecked = true; + _fragmentationParamsViewModel.GenerateComplementaryIons = true; } else { - AddCompIonCheckBox.IsChecked = false; - NTerminalIons.IsChecked = true; - CTerminalIons.IsChecked = true; + _fragmentationParamsViewModel.GenerateComplementaryIons = false; + _fragmentationParamsViewModel.RightSideFragmentIons = true; + _fragmentationParamsViewModel.LeftSideFragmentIons = true; } } @@ -920,8 +920,8 @@ private void ProteaseSpecificUpdate(object sender, SelectionChangedEventArgs e) { DeconHostViewModel.SetAllPrecursorMaxChargeState(60); DeconHostViewModel.SetAllProductMaxChargeState(20); - InternalIonsCheckBox.IsChecked = true; - MinInternalFragmentLengthTextBox.Text = "10"; + _fragmentationParamsViewModel.GenerateInternalIons = true; + _fragmentationParamsViewModel.MinInternalIonLength = 10; CheckBoxNoQuant.IsChecked = true; _massDifferenceAcceptorViewModel.SelectedType = _massDifferenceAcceptorViewModel.MassDiffAcceptorTypes.First(p => p.Type == MassDiffAcceptorType.PlusOrMinusThreeMM); @@ -1012,14 +1012,14 @@ private void ProteaseSpecificUpdate(object sender, TextChangedEventArgs e) int maxLength = Convert.ToInt32(MaxPeptideLengthTextBox.Text); if (maxLength > 0 && maxLength < 100) //default is 30000; 30000/300=100 { - MaxFragmentMassTextBox.Text = (maxLength * 300).ToString(); //assume the average residue doesn't have a mass over 300 Da (largest is W @ 204, but mods exist) + _fragmentationParamsViewModel.MaxFragmentMassDa = maxLength * 300; //assume the average residue doesn't have a mass over 300 Da (largest is W @ 204, but mods exist) } } } private void SemiSpecificUpdate(object sender, RoutedEventArgs e) { - AddCompIonCheckBox.IsChecked = SemiSpecificSearchRadioButton.IsChecked.Value; + _fragmentationParamsViewModel.GenerateComplementaryIons = SemiSpecificSearchRadioButton.IsChecked.Value; if (SemiSpecificSearchRadioButton.IsChecked.Value) { MissedCleavagesTextBox.Text = "2"; @@ -1027,8 +1027,8 @@ private void SemiSpecificUpdate(object sender, RoutedEventArgs e) } else { - NTerminalIons.IsChecked = true; - CTerminalIons.IsChecked = true; + _fragmentationParamsViewModel.RightSideFragmentIons = true; + _fragmentationParamsViewModel.LeftSideFragmentIons = true; } } @@ -1171,7 +1171,7 @@ private void SnesUpdates(CleavageSpecificity searchModeType) { searchModeType = CleavageSpecificity.None; //prevents an accidental semi attempt of a non-specific protease - if (CTerminalIons.IsChecked.Value) + if (_fragmentationParamsViewModel.LeftSideFragmentIons) { Protease singleC = ProteaseDictionary.Dictionary["singleC"]; ProteaseComboBox.SelectedItem = singleC; @@ -1182,41 +1182,48 @@ private void SnesUpdates(CleavageSpecificity searchModeType) ProteaseComboBox.SelectedItem = singleN; } } - if (!AddCompIonCheckBox.IsChecked.Value) + if (!_fragmentationParamsViewModel.GenerateComplementaryIons) { MessageBox.Show("Warning: Complementary ions are strongly recommended when using this algorithm."); } //only use N or C termini, not both - if (CTerminalIons.IsChecked.Value) + if (_fragmentationParamsViewModel.LeftSideFragmentIons) { - NTerminalIons.IsChecked = false; + _fragmentationParamsViewModel.RightSideFragmentIons = false; } else { - NTerminalIons.IsChecked = true; + _fragmentationParamsViewModel.LeftSideFragmentIons = true; } } } private FragmentationTerminus GetFragmentationTerminus() { - if (NTerminalIons.IsChecked.Value && !CTerminalIons.IsChecked.Value) - { - return FragmentationTerminus.N; - } - else if (!NTerminalIons.IsChecked.Value && CTerminalIons.IsChecked.Value) - { - return FragmentationTerminus.C; - } - else if (!NTerminalIons.IsChecked.Value && !CTerminalIons.IsChecked.Value) //why would you want this - { - MessageBox.Show("Warning: No ion types were selected. MetaMorpheus will be unable to search MS/MS spectra."); - return FragmentationTerminus.None; - } - else - { - return FragmentationTerminus.Both; - } + FragmentationTerminus newTerm; + switch (_fragmentationParamsViewModel.LeftSideFragmentIons, _fragmentationParamsViewModel.RightSideFragmentIons) + { + case (true, false) when !GuiGlobalParamsViewModel.Instance.IsRnaMode: + newTerm = FragmentationTerminus.N; + break; + case (false, true) when !GuiGlobalParamsViewModel.Instance.IsRnaMode: + newTerm = FragmentationTerminus.C; + break; + case (true, false) when GuiGlobalParamsViewModel.Instance.IsRnaMode: + newTerm = FragmentationTerminus.FivePrime; + break; + case (false, true) when GuiGlobalParamsViewModel.Instance.IsRnaMode: + newTerm = FragmentationTerminus.ThreePrime; + break; + case (false, false): + MessageBox.Show("Warning: No ion types were selected. MetaMorpheus will be unable to search MS/MS spectra."); + newTerm = FragmentationTerminus.None; + break; + default: + newTerm = FragmentationTerminus.Both; + break; + } + return newTerm; } //string out is for error messages @@ -1372,16 +1379,6 @@ private void AddTruncationsCheckBox_Checked(object sender, RoutedEventArgs e) InitiatorMethionineBehaviorComboBox.SelectedIndex = (int)InitiatorMethionineBehavior.Retain; } } - - /// - /// Sets the value of the Internal Ions TextBox upon being checked - /// - /// - /// - private void InternalIonsCheckBox_Checked(object sender, RoutedEventArgs e) - { - MinInternalFragmentLengthTextBox.Text = "4"; - } } public class DataContextForSearchTaskWindow : INotifyPropertyChanged diff --git a/MetaMorpheus/GUI/Util/Converters/BoolToFontWeightConverter.cs b/MetaMorpheus/GUI/Util/Converters/BoolToFontWeightConverter.cs new file mode 100644 index 0000000000..f7f860d004 --- /dev/null +++ b/MetaMorpheus/GUI/Util/Converters/BoolToFontWeightConverter.cs @@ -0,0 +1,22 @@ +using System; +using System.Globalization; +using System.Windows; + +namespace MetaMorpheusGUI; + +public class BoolToFontWeightConverter : BaseValueConverter +{ + public override object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + if (value is bool boolValue && boolValue) + { + return FontWeights.Bold; + } + return FontWeights.Normal; + } + + public override object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } +} diff --git a/MetaMorpheus/GUI/Util/Converters/CollapseOnRnaModeConverter.cs b/MetaMorpheus/GUI/Util/Converters/CollapseOnRnaModeConverter.cs index f8a8f66250..860df3d9cb 100644 --- a/MetaMorpheus/GUI/Util/Converters/CollapseOnRnaModeConverter.cs +++ b/MetaMorpheus/GUI/Util/Converters/CollapseOnRnaModeConverter.cs @@ -18,4 +18,19 @@ public object ConvertBack(object value, Type targetType, object parameter, Cultu { throw new NotImplementedException(); } +} + +public class CollapseOnProteinModeConverter : IValueConverter +{ + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + // Collapse the element if RNA mode is enabled + return GuiGlobalParamsViewModel.Instance == null || !GuiGlobalParamsViewModel.Instance.IsRnaMode + ? System.Windows.Visibility.Collapsed + : System.Windows.Visibility.Visible; + } + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } } \ No newline at end of file diff --git a/MetaMorpheus/GUI/Util/TaskValidator.cs b/MetaMorpheus/GUI/Util/TaskValidator.cs index cb37dd7b86..c15690777c 100644 --- a/MetaMorpheus/GUI/Util/TaskValidator.cs +++ b/MetaMorpheus/GUI/Util/TaskValidator.cs @@ -35,7 +35,8 @@ public static bool CheckTaskSettingsValidity(string precursorMassTolerance, string maxFragmentMass, string qValueFilter, string pepqValueFilter, - string minInternalIonLength + string minInternalIonLength, + string productMassTolerance_LowRes = null ) { maxMissedCleavages = MaxValueConversion(maxMissedCleavages); @@ -45,6 +46,7 @@ string minInternalIonLength { (CheckPrecursorMassTolerance(precursorMassTolerance)), (CheckProductMassTolerance(productMassTolerance)), + (string.IsNullOrWhiteSpace(productMassTolerance_LowRes) || CheckProductMassTolerance_LowRes(productMassTolerance_LowRes)), (CheckMaxMissedCleavages(maxMissedCleavages)), (CheckMaxModificationIsoForms(maxModificationIsoforms)), (CheckPeptideLength(minPeptideLength, maxPeptideLength)), @@ -171,6 +173,16 @@ public static bool CheckProductMassTolerance(string text) return true; } + public static bool CheckProductMassTolerance_LowRes(string text) + { + if (!double.TryParse(text, NumberStyles.Any, CultureInfo.InvariantCulture, out double childScanMassTolerance) || childScanMassTolerance <= 0) + { + MessageBox.Show("The Low-Res product mass tolerance is invalid. \n You entered " + '"' + text + '"' + "\n Please enter a positive number."); + return false; + } + return true; + } + public static bool CheckNumberOfDatabasePartitions(string text) { if (!int.TryParse(text, out int numberOfDatabaseSearches) || numberOfDatabaseSearches <= 0) diff --git a/MetaMorpheus/GUI/Views/CustomMIonLossWindow.xaml b/MetaMorpheus/GUI/Views/CustomMIonLossWindow.xaml new file mode 100644 index 0000000000..5c01e21c5e --- /dev/null +++ b/MetaMorpheus/GUI/Views/CustomMIonLossWindow.xaml @@ -0,0 +1,144 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + * Required fields. Select at least one applicable mode. + + + + +