diff --git a/MetaMorpheus/CMD/CMD.csproj b/MetaMorpheus/CMD/CMD.csproj index 927a97c0d..becf89ce6 100644 --- a/MetaMorpheus/CMD/CMD.csproj +++ b/MetaMorpheus/CMD/CMD.csproj @@ -24,7 +24,7 @@ - + diff --git a/MetaMorpheus/EngineLayer/AnalyteType.cs b/MetaMorpheus/EngineLayer/AnalyteType.cs new file mode 100644 index 000000000..8b8d754ce --- /dev/null +++ b/MetaMorpheus/EngineLayer/AnalyteType.cs @@ -0,0 +1,56 @@ +using System.Collections.Generic; + +namespace EngineLayer +{ + public enum AnalyteType + { + Peptide, + Proteoform, + Oligo + } + + /// + /// Accessor methods for specific information about certain analyte types + /// + public static class AnalyteTypeExtensions + { + private static readonly Dictionary AnalyteTypes = new() + { + { AnalyteType.Peptide, new AnalyteTypeData("PSM", "Peptide", "Protein", "psmtsv") }, + { AnalyteType.Proteoform, new AnalyteTypeData("PSM", "Proteoform", "Protein", "psmtsv") }, + { AnalyteType.Oligo, new AnalyteTypeData("OSM", "Oligo", "Transcript", "osmtsv") }, + }; + + public static string GetSpectralMatchLabel(this AnalyteType analyteType) => AnalyteTypes[analyteType].SpectralMatchLabel; + public static string GetSpectralMatchExtension(this AnalyteType analyteType) => AnalyteTypes[analyteType].SpectralMatchExtension; + public static string GetUniqueFormLabel(this AnalyteType analyteType) => AnalyteTypes[analyteType].UniqueFormLabel; + public static string GetBioPolymerLabel(this AnalyteType analyteType) => AnalyteTypes[analyteType].BioPolymerLabel; + } + + /// + /// Represents an analyte type and is used to determine the output format of the analyte type. + /// + internal class AnalyteTypeData(string spectralMatchLabel, string uniqueFormLabel, string bioPolymerLabel, string spectralMatchExtension) + { + /// + /// Gets or sets the label for spectral matches (e.g. PSM). + /// + internal string SpectralMatchLabel { get; init; } = spectralMatchLabel; + + /// + /// Extension for spectral matches (e.g. psmtsv). + /// + internal string SpectralMatchExtension { get; init; } = spectralMatchExtension; + + /// + /// Gets or sets the label for unique forms (e.g. Peptide). + /// + internal string UniqueFormLabel { get; init; } = uniqueFormLabel; + + /// + /// Gets or sets the label for grouped forms (e.g. Protein). + /// + internal string BioPolymerLabel { get; init; } = bioPolymerLabel; + } +} + diff --git a/MetaMorpheus/EngineLayer/EngineLayer.csproj b/MetaMorpheus/EngineLayer/EngineLayer.csproj index f937bdc7f..c0aa4ef10 100644 --- a/MetaMorpheus/EngineLayer/EngineLayer.csproj +++ b/MetaMorpheus/EngineLayer/EngineLayer.csproj @@ -21,7 +21,7 @@ - + diff --git a/MetaMorpheus/EngineLayer/GlobalVariables.cs b/MetaMorpheus/EngineLayer/GlobalVariables.cs index 96efe5960..51bfc06eb 100644 --- a/MetaMorpheus/EngineLayer/GlobalVariables.cs +++ b/MetaMorpheus/EngineLayer/GlobalVariables.cs @@ -34,7 +34,7 @@ public static class GlobalVariables private static char[] _InvalidAminoAcids; // this affects output labels, etc. and can be changed to "Proteoform" for top-down searches - public static string AnalyteType; + public static AnalyteType AnalyteType; public static List ErrorsReadingMods; @@ -65,7 +65,7 @@ public static void SetUpGlobalVariables() Loaders.LoadElements(); AcceptedDatabaseFormats = new List { ".fasta", ".fa", ".xml", ".msp" }; AcceptedSpectraFormats = new List { ".raw", ".mzml", ".mgf" }; - AnalyteType = "Peptide"; + AnalyteType = AnalyteType.Peptide; _InvalidAminoAcids = new char[] { 'X', 'B', 'J', 'Z', ':', '|', ';', '[', ']', '{', '}', '(', ')', '+', '-' }; ExperimentalDesignFileName = "ExperimentalDesign.tsv"; SeparationTypes = new List { { "HPLC" }, { "CZE" } }; diff --git a/MetaMorpheus/EngineLayer/NonSpecificEnzymeSearch/NonSpecificEnzymeSearchEngine.cs b/MetaMorpheus/EngineLayer/NonSpecificEnzymeSearch/NonSpecificEnzymeSearchEngine.cs index 4c23fa7d2..ff18c3c27 100644 --- a/MetaMorpheus/EngineLayer/NonSpecificEnzymeSearch/NonSpecificEnzymeSearchEngine.cs +++ b/MetaMorpheus/EngineLayer/NonSpecificEnzymeSearch/NonSpecificEnzymeSearchEngine.cs @@ -377,7 +377,7 @@ private Tuple Accepts(List fragments, updatedMods.Add(key, mod.Value); } } - if (terminalMod != null) + if (terminalMod != null && !updatedMods.Keys.Contains(startResidue - 1)) { updatedMods.Add(startResidue - 1, terminalMod); } diff --git a/MetaMorpheus/GUI/GUI.csproj b/MetaMorpheus/GUI/GUI.csproj index 0db67590d..0ac630833 100644 --- a/MetaMorpheus/GUI/GUI.csproj +++ b/MetaMorpheus/GUI/GUI.csproj @@ -55,7 +55,7 @@ - + diff --git a/MetaMorpheus/GUI/TaskWindows/GPTMDTaskWindow.xaml b/MetaMorpheus/GUI/TaskWindows/GPTMDTaskWindow.xaml index bfb5d6c8a..2341862a1 100644 --- a/MetaMorpheus/GUI/TaskWindows/GPTMDTaskWindow.xaml +++ b/MetaMorpheus/GUI/TaskWindows/GPTMDTaskWindow.xaml @@ -48,34 +48,7 @@ - - - - - - Use the charge states and precursor masses determined by the instrument controller. - - - - - - - Additionally searches for coisolated peptides, allowing for multiple peptides to be identified from a single MS2. - - - - - - - + diff --git a/MetaMorpheus/GUI/TaskWindows/GPTMDTaskWindow.xaml.cs b/MetaMorpheus/GUI/TaskWindows/GPTMDTaskWindow.xaml.cs index 4c3449f93..37d595cfa 100644 --- a/MetaMorpheus/GUI/TaskWindows/GPTMDTaskWindow.xaml.cs +++ b/MetaMorpheus/GUI/TaskWindows/GPTMDTaskWindow.xaml.cs @@ -29,6 +29,7 @@ public partial class GptmdTaskWindow : Window private readonly ObservableCollection GptmdModTypeForTreeViewObservableCollection = new ObservableCollection(); private bool AutomaticallyAskAndOrUpdateParametersBasedOnProtease = true; private CustomFragmentationWindow CustomFragmentationWindow; + private DeconHostViewModel DeconHostViewModel; public GptmdTaskWindow(GptmdTask myGPTMDtask) { @@ -39,6 +40,7 @@ public GptmdTaskWindow(GptmdTask myGPTMDtask) PopulateChoices(); UpdateFieldsFromTask(TheTask); AutomaticallyAskAndOrUpdateParametersBasedOnProtease = true; + DeisotopingControl.DataContext = DeconHostViewModel; if (myGPTMDtask == null) { @@ -62,10 +64,10 @@ private void Row_DoubleClick(object sender, MouseButtonEventArgs e) private void UpdateFieldsFromTask(GptmdTask task) { + DeconHostViewModel = new DeconHostViewModel(TheTask.CommonParameters.PrecursorDeconvolutionParameters, + TheTask.CommonParameters.ProductDeconvolutionParameters, + TheTask.CommonParameters.UseProvidedPrecursorInfo, TheTask.CommonParameters.DoPrecursorDeconvolution); ProteaseComboBox.SelectedItem = task.CommonParameters.DigestionParams.Protease; //protease needs to come first or recommended settings can overwrite the actual settings - UseProvidedPrecursor.IsChecked = task.CommonParameters.UseProvidedPrecursorInfo; - DeconvolutePrecursors.IsChecked = task.CommonParameters.DoPrecursorDeconvolution; - DeconvolutionMaxAssumedChargeStateTextBox.Text = task.CommonParameters.DeconvolutionMaxAssumedChargeState.ToString(); MissedCleavagesTextBox.Text = task.CommonParameters.DigestionParams.MaxMissedCleavages == int.MaxValue ? "" : task.CommonParameters.DigestionParams.MaxMissedCleavages.ToString(CultureInfo.InvariantCulture); MinPeptideLengthTextBox.Text = task.CommonParameters.DigestionParams.MinPeptideLength.ToString(CultureInfo.InvariantCulture); MaxPeptideLengthTextBox.Text = task.CommonParameters.DigestionParams.MaxPeptideLength == int.MaxValue ? "" : task.CommonParameters.DigestionParams.MaxPeptideLength.ToString(CultureInfo.InvariantCulture); @@ -260,8 +262,8 @@ private void ProteaseSpecificUpdate(object sender, SelectionChangedEventArgs e) case "top-down": if (UpdateGUISettings.UseTopDownRecommendedSettings()) { - UseProvidedPrecursor.IsChecked = false; - DeconvolutionMaxAssumedChargeStateTextBox.Text = "60"; + DeconHostViewModel.UseProvidedPrecursors = false; + DeconHostViewModel.PrecursorDeconvolutionParameters.MaxAssumedChargeState = 60; TrimMsMs.IsChecked = false; //uncheck all variable mods foreach (var mod in VariableModTypeForTreeViewObservableCollection) @@ -354,7 +356,7 @@ private void SaveButton_Click(object sender, RoutedEventArgs e) if (!GlobalGuiSettings.CheckTaskSettingsValidity(PrecursorMassToleranceTextBox.Text, ProductMassToleranceTextBox.Text, MissedCleavagesTextBox.Text, MaxModificationIsoformsTextBox.Text, MinPeptideLengthTextBox.Text, MaxPeptideLengthTextBox.Text, MaxThreadsTextBox.Text, MinScoreAllowed.Text, - fieldNotUsed, fieldNotUsed, DeconvolutionMaxAssumedChargeStateTextBox.Text, NumberOfPeaksToKeepPerWindowTextBox.Text, MinimumAllowedIntensityRatioToBasePeakTexBox.Text, + fieldNotUsed, fieldNotUsed, DeconHostViewModel.PrecursorDeconvolutionParameters.MaxAssumedChargeState.ToString(), NumberOfPeaksToKeepPerWindowTextBox.Text, MinimumAllowedIntensityRatioToBasePeakTexBox.Text, null, null, fieldNotUsed, fieldNotUsed, fieldNotUsed, null, null, null)) { return; @@ -441,10 +443,14 @@ private void SaveButton_Click(object sender, RoutedEventArgs e) } bool parseMaxThreadsPerFile = int.Parse(MaxThreadsTextBox.Text, CultureInfo.InvariantCulture) <= Environment.ProcessorCount && int.Parse(MaxThreadsTextBox.Text, CultureInfo.InvariantCulture) > 0; + DeconvolutionParameters precursorDeconvolutionParameters = DeconHostViewModel.PrecursorDeconvolutionParameters.Parameters; + DeconvolutionParameters productDeconvolutionParameters = DeconHostViewModel.ProductDeconvolutionParameters.Parameters; + bool useProvidedPrecursorInfo = DeconHostViewModel.UseProvidedPrecursors; + bool doPrecursorDeconvolution = DeconHostViewModel.DoPrecursorDeconvolution; + CommonParameters commonParamsToSave = new CommonParameters( - useProvidedPrecursorInfo: UseProvidedPrecursor.IsChecked.Value, - deconvolutionMaxAssumedChargeState: int.Parse(DeconvolutionMaxAssumedChargeStateTextBox.Text, CultureInfo.InvariantCulture), - doPrecursorDeconvolution: DeconvolutePrecursors.IsChecked.Value, + useProvidedPrecursorInfo: useProvidedPrecursorInfo, + doPrecursorDeconvolution: doPrecursorDeconvolution, taskDescriptor: OutputFileNameTextBox.Text != "" ? OutputFileNameTextBox.Text : "GPTMDTask", maxThreadsToUsePerFile: parseMaxThreadsPerFile ? int.Parse(MaxThreadsTextBox.Text, CultureInfo.InvariantCulture) : new CommonParameters().MaxThreadsToUsePerFile, digestionParams: new DigestionParams( @@ -468,7 +474,9 @@ private void SaveButton_Click(object sender, RoutedEventArgs e) assumeOrphanPeaksAreZ1Fragments: protease.Name != "top-down", addCompIons: AddCompIonCheckBox.IsChecked.Value, minVariantDepth: minVariantDepth, - maxHeterozygousVariants: maxHeterozygousVariants); + maxHeterozygousVariants: maxHeterozygousVariants, + precursorDeconParams: precursorDeconvolutionParameters, + productDeconParams: productDeconvolutionParameters); TheTask.GptmdParameters.ListOfModsGptmd = new List<(string, string)>(); foreach (var heh in GptmdModTypeForTreeViewObservableCollection) diff --git a/MetaMorpheus/GUI/TaskWindows/GlycoSearchTaskWindow.xaml b/MetaMorpheus/GUI/TaskWindows/GlycoSearchTaskWindow.xaml index 7be5c8b7d..5e546dc80 100644 --- a/MetaMorpheus/GUI/TaskWindows/GlycoSearchTaskWindow.xaml +++ b/MetaMorpheus/GUI/TaskWindows/GlycoSearchTaskWindow.xaml @@ -159,20 +159,7 @@ - - - - - - - - - - - - - - + diff --git a/MetaMorpheus/GUI/TaskWindows/GlycoSearchTaskWindow.xaml.cs b/MetaMorpheus/GUI/TaskWindows/GlycoSearchTaskWindow.xaml.cs index e63556f94..59034fe9c 100644 --- a/MetaMorpheus/GUI/TaskWindows/GlycoSearchTaskWindow.xaml.cs +++ b/MetaMorpheus/GUI/TaskWindows/GlycoSearchTaskWindow.xaml.cs @@ -29,6 +29,7 @@ public partial class GlycoSearchTaskWindow : Window private readonly ObservableCollection FixedModTypeForTreeViewObservableCollection = new ObservableCollection(); private readonly ObservableCollection VariableModTypeForTreeViewObservableCollection = new ObservableCollection(); private CustomFragmentationWindow CustomFragmentationWindow; + private DeconHostViewModel DeconHostViewModel; public GlycoSearchTaskWindow() : this(null) { @@ -40,6 +41,7 @@ public GlycoSearchTaskWindow(GlycoSearchTask task) PopulateChoices(); TheTask = task ?? new GlycoSearchTask(); UpdateFieldsFromTask(TheTask); + DeisotopingControl.DataContext = DeconHostViewModel; if (task == null) { @@ -159,8 +161,9 @@ private void UpdateFieldsFromTask(GlycoSearchTask task) CheckBoxDecoy.IsChecked = task._glycoSearchParameters.DecoyType != DecoyType.None; RadioButtonReverseDecoy.IsChecked = task._glycoSearchParameters.DecoyType == DecoyType.Reverse; RadioButtonSlideDecoy.IsChecked = task._glycoSearchParameters.DecoyType == DecoyType.Slide; - deconvolutePrecursors.IsChecked = task.CommonParameters.DoPrecursorDeconvolution; - useProvidedPrecursor.IsChecked = task.CommonParameters.UseProvidedPrecursorInfo; + DeconHostViewModel = new DeconHostViewModel(TheTask.CommonParameters.PrecursorDeconvolutionParameters, + TheTask.CommonParameters.ProductDeconvolutionParameters, + TheTask.CommonParameters.UseProvidedPrecursorInfo, TheTask.CommonParameters.DoPrecursorDeconvolution); missedCleavagesTextBox.Text = task.CommonParameters.DigestionParams.MaxMissedCleavages.ToString(CultureInfo.InvariantCulture); MinPeptideLengthTextBox.Text = task.CommonParameters.DigestionParams.MinPeptideLength.ToString(CultureInfo.InvariantCulture); MaxPeptideLengthTextBox.Text = task.CommonParameters.DigestionParams.MaxPeptideLength == int.MaxValue ? "" : task.CommonParameters.DigestionParams.MaxPeptideLength.ToString(CultureInfo.InvariantCulture); @@ -243,7 +246,7 @@ private void SaveButton_Click(object sender, RoutedEventArgs e) if (!GlobalGuiSettings.CheckTaskSettingsValidity(PrecusorMsTlTextBox.Text, productMassToleranceTextBox.Text, missedCleavagesTextBox.Text, maxModificationIsoformsTextBox.Text, MinPeptideLengthTextBox.Text, MaxPeptideLengthTextBox.Text, maxThreadsTextBox.Text, minScoreAllowed.Text, - fieldNotUsed, fieldNotUsed, fieldNotUsed, TopNPeaksTextBox.Text, MinRatioTextBox.Text, null, null, numberOfDatabaseSearchesTextBox.Text, TxtBoxMaxModPerPep.Text, + fieldNotUsed, fieldNotUsed, DeconHostViewModel.PrecursorDeconvolutionParameters.MaxAssumedChargeState.ToString(), TopNPeaksTextBox.Text, MinRatioTextBox.Text, null, null, numberOfDatabaseSearchesTextBox.Text, TxtBoxMaxModPerPep.Text, fieldNotUsed, null, null, null)) { return; @@ -369,12 +372,17 @@ private void SaveButton_Click(object sender, RoutedEventArgs e) listOfModsFixed.AddRange(heh.Children.Where(b => b.Use).Select(b => (b.Parent.DisplayName, b.ModName))); } + DeconvolutionParameters precursorDeconvolutionParameters = DeconHostViewModel.PrecursorDeconvolutionParameters.Parameters; + DeconvolutionParameters productDeconvolutionParameters = DeconHostViewModel.ProductDeconvolutionParameters.Parameters; + bool useProvidedPrecursorInfo = DeconHostViewModel.UseProvidedPrecursors; + bool doPrecursorDeconvolution = DeconHostViewModel.DoPrecursorDeconvolution; + CommonParameters commonParamsToSave = new CommonParameters( precursorMassTolerance: PrecursorMassTolerance, taskDescriptor: OutputFileNameTextBox.Text != "" ? OutputFileNameTextBox.Text : "GlycoSearchTask", productMassTolerance: ProductMassTolerance, - doPrecursorDeconvolution: deconvolutePrecursors.IsChecked.Value, - useProvidedPrecursorInfo: useProvidedPrecursor.IsChecked.Value, + doPrecursorDeconvolution: doPrecursorDeconvolution, + useProvidedPrecursorInfo: useProvidedPrecursorInfo, digestionParams: digestionParamsToSave, trimMs1Peaks: trimMs1.IsChecked.Value, trimMsMsPeaks: trimMsMs.IsChecked.Value, @@ -387,7 +395,9 @@ private void SaveButton_Click(object sender, RoutedEventArgs e) maxThreadsToUsePerFile: int.Parse(maxThreadsTextBox.Text, CultureInfo.InvariantCulture), listOfModsVariable: listOfModsVariable, listOfModsFixed: listOfModsFixed, - assumeOrphanPeaksAreZ1Fragments: protease.Name != "top-down"); + assumeOrphanPeaksAreZ1Fragments: protease.Name != "top-down", + precursorDeconParams: precursorDeconvolutionParameters, + productDeconParams: productDeconvolutionParameters); TheTask.CommonParameters = commonParamsToSave; diff --git a/MetaMorpheus/GUI/TaskWindows/SearchTaskWindow.xaml b/MetaMorpheus/GUI/TaskWindows/SearchTaskWindow.xaml index 98514670c..3b0914ecf 100644 --- a/MetaMorpheus/GUI/TaskWindows/SearchTaskWindow.xaml +++ b/MetaMorpheus/GUI/TaskWindows/SearchTaskWindow.xaml @@ -661,41 +661,7 @@ - - - - - - - Use the charge states and precursor masses determined by the instrument controller. - - - - - - - - - - - Additionally searches for coisolated peptides, allowing for multiple peptides to be identified from a single MS2. - - - - - - - - - + diff --git a/MetaMorpheus/GUI/TaskWindows/SearchTaskWindow.xaml.cs b/MetaMorpheus/GUI/TaskWindows/SearchTaskWindow.xaml.cs index 1767492b3..124ceebd5 100644 --- a/MetaMorpheus/GUI/TaskWindows/SearchTaskWindow.xaml.cs +++ b/MetaMorpheus/GUI/TaskWindows/SearchTaskWindow.xaml.cs @@ -39,6 +39,7 @@ public partial class SearchTaskWindow : Window private bool AutomaticallyAskAndOrUpdateParametersBasedOnProtease = true; private CustomFragmentationWindow CustomFragmentationWindow; private string _defaultMultiplexType = "TMT10"; + private DeconHostViewModel DeconHostViewModel; internal SearchTask TheTask { get; private set; } @@ -51,6 +52,7 @@ public SearchTaskWindow(SearchTask task) PopulateChoices(); UpdateFieldsFromTask(TheTask); AutomaticallyAskAndOrUpdateParametersBasedOnProtease = true; + DeisotopingControl.DataContext = DeconHostViewModel; if (task == null) { @@ -285,18 +287,19 @@ private void UpdateFieldsFromTask(SearchTask task) PrecursorMassToleranceComboBox.SelectedIndex = task.CommonParameters.PrecursorMassTolerance is AbsoluteTolerance ? 0 : 1; AddCompIonCheckBox.IsChecked = task.CommonParameters.AddCompIons; NumberOfDatabaseSearchesTextBox.Text = task.CommonParameters.TotalPartitions.ToString(CultureInfo.InvariantCulture); - DeconvolutePrecursors.IsChecked = task.CommonParameters.DoPrecursorDeconvolution; - UseProvidedPrecursor.IsChecked = task.CommonParameters.UseProvidedPrecursorInfo; RemoveContaminantRadioBox.IsChecked = task.SearchParameters.TCAmbiguity == TargetContaminantAmbiguity.RemoveContaminant; RemoveTargetRadioBox.IsChecked = task.SearchParameters.TCAmbiguity == TargetContaminantAmbiguity.RemoveTarget; RenameTCProteinsRadioBox.IsChecked = task.SearchParameters.TCAmbiguity == TargetContaminantAmbiguity.RenameProtein; AllAmbiguity.IsChecked = task.CommonParameters.ReportAllAmbiguity; - DeconvolutionMaxAssumedChargeStateTextBox.Text = task.CommonParameters.DeconvolutionMaxAssumedChargeState.ToString(); MinScoreAllowed.Text = task.CommonParameters.ScoreCutoff.ToString(CultureInfo.InvariantCulture); TrimMs1.IsChecked = task.CommonParameters.TrimMs1Peaks; TrimMsMs.IsChecked = task.CommonParameters.TrimMsMsPeaks; AddTruncationsCheckBox.IsChecked = task.CommonParameters.AddTruncations; + DeconHostViewModel = new DeconHostViewModel(TheTask.CommonParameters.PrecursorDeconvolutionParameters, + TheTask.CommonParameters.ProductDeconvolutionParameters, + TheTask.CommonParameters.UseProvidedPrecursorInfo, TheTask.CommonParameters.DoPrecursorDeconvolution); + NumberOfPeaksToKeepPerWindowTextBox.Text = task.CommonParameters.NumberOfPeaksToKeepPerWindow == int.MaxValue || !task.CommonParameters.NumberOfPeaksToKeepPerWindow.HasValue ? "" : task.CommonParameters.NumberOfPeaksToKeepPerWindow.Value.ToString(CultureInfo.InvariantCulture); MinimumAllowedIntensityRatioToBasePeakTexBox.Text = task.CommonParameters.MinimumAllowedIntensityRatioToBasePeak == double.MaxValue || !task.CommonParameters.MinimumAllowedIntensityRatioToBasePeak.HasValue ? "" : task.CommonParameters.MinimumAllowedIntensityRatioToBasePeak.Value.ToString(CultureInfo.InvariantCulture); WindowWidthThomsonsTextBox.Text = task.CommonParameters.WindowWidthThomsons == double.MaxValue || !task.CommonParameters.WindowWidthThomsons.HasValue ? "" : task.CommonParameters.WindowWidthThomsons.Value.ToString(CultureInfo.InvariantCulture); @@ -425,6 +428,7 @@ private void SaveButton_Click(object sender, RoutedEventArgs e) CleavageSpecificity searchModeType = GetSearchModeType(); //change search type to semi or non if selected SnesUpdates(searchModeType); //decide on singleN/C, make comp ion changes + // TODO: Reconcile Isodec params with Mass difference acceptor if (!GlobalGuiSettings.CheckTaskSettingsValidity( PrecursorMassToleranceTextBox.Text, ProductMassToleranceTextBox.Text, @@ -436,7 +440,7 @@ private void SaveButton_Click(object sender, RoutedEventArgs e) MinScoreAllowed.Text, PeakFindingToleranceTextBox.Text, HistogramBinWidthTextBox.Text, - DeconvolutionMaxAssumedChargeStateTextBox.Text, + DeconHostViewModel.PrecursorDeconvolutionParameters.MaxAssumedChargeState.ToString(), NumberOfPeaksToKeepPerWindowTextBox.Text, MinimumAllowedIntensityRatioToBasePeakTexBox.Text, WindowWidthThomsonsTextBox.Text, @@ -567,14 +571,19 @@ private void SaveButton_Click(object sender, RoutedEventArgs e) bool parseMaxThreadsPerFile = !MaxThreadsTextBox.Text.Equals("") && (int.Parse(MaxThreadsTextBox.Text) <= Environment.ProcessorCount && int.Parse(MaxThreadsTextBox.Text) > 0); + + DeconvolutionParameters precursorDeconvolutionParameters = DeconHostViewModel.PrecursorDeconvolutionParameters.Parameters; + DeconvolutionParameters productDeconvolutionParameters = DeconHostViewModel.ProductDeconvolutionParameters.Parameters; + bool useProvidedPrecursorInfo = DeconHostViewModel.UseProvidedPrecursors; + bool doPrecursorDeconvolution = DeconHostViewModel.DoPrecursorDeconvolution; + CommonParameters commonParamsToSave = new CommonParameters( taskDescriptor: OutputFileNameTextBox.Text != "" ? OutputFileNameTextBox.Text : "SearchTask", maxThreadsToUsePerFile: parseMaxThreadsPerFile ? int.Parse(MaxThreadsTextBox.Text, CultureInfo.InvariantCulture) : new CommonParameters().MaxThreadsToUsePerFile, reportAllAmbiguity: AllAmbiguity.IsChecked.Value, - deconvolutionMaxAssumedChargeState: int.Parse(DeconvolutionMaxAssumedChargeStateTextBox.Text, CultureInfo.InvariantCulture), totalPartitions: int.Parse(NumberOfDatabaseSearchesTextBox.Text, CultureInfo.InvariantCulture), - doPrecursorDeconvolution: DeconvolutePrecursors.IsChecked.Value, - useProvidedPrecursorInfo: UseProvidedPrecursor.IsChecked.Value, + doPrecursorDeconvolution: doPrecursorDeconvolution, + useProvidedPrecursorInfo: useProvidedPrecursorInfo, qValueThreshold: !PepQValueThresholdCheckbox.IsChecked.Value ? double.Parse(QValueThresholdTextBox.Text, CultureInfo.InvariantCulture) : 1.0, pepQValueThreshold: PepQValueThresholdCheckbox.IsChecked.Value ? double.Parse(PepQValueThresholdTextBox.Text, CultureInfo.InvariantCulture) : 1.0, scoreCutoff: double.Parse(MinScoreAllowed.Text, CultureInfo.InvariantCulture), @@ -596,7 +605,9 @@ private void SaveButton_Click(object sender, RoutedEventArgs e) addCompIons: AddCompIonCheckBox.IsChecked.Value, assumeOrphanPeaksAreZ1Fragments: protease.Name != "top-down", minVariantDepth: MinVariantDepth, - maxHeterozygousVariants: MaxHeterozygousVariants); + maxHeterozygousVariants: MaxHeterozygousVariants, + precursorDeconParams: precursorDeconvolutionParameters, + productDeconParams: productDeconvolutionParameters); if (ClassicSearchRadioButton.IsChecked.Value) { @@ -880,8 +891,8 @@ private void ProteaseSpecificUpdate(object sender, SelectionChangedEventArgs e) case "top-down": if (UpdateGUISettings.UseTopDownRecommendedSettings()) { - UseProvidedPrecursor.IsChecked = false; - DeconvolutionMaxAssumedChargeStateTextBox.Text = "60"; + DeconHostViewModel.DoPrecursorDeconvolution = true; + DeconHostViewModel.PrecursorDeconvolutionParameters.MaxAssumedChargeState = 60; TrimMsMs.IsChecked = false; CheckBoxNoQuant.IsChecked = true; MassDiffAccept3mm.IsChecked = true; diff --git a/MetaMorpheus/GUI/TaskWindows/XLSearchTaskWindow.xaml b/MetaMorpheus/GUI/TaskWindows/XLSearchTaskWindow.xaml index 81de1944f..9de85d76b 100644 --- a/MetaMorpheus/GUI/TaskWindows/XLSearchTaskWindow.xaml +++ b/MetaMorpheus/GUI/TaskWindows/XLSearchTaskWindow.xaml @@ -147,20 +147,7 @@ - - - - - - - - - - - - - - + diff --git a/MetaMorpheus/GUI/TaskWindows/XLSearchTaskWindow.xaml.cs b/MetaMorpheus/GUI/TaskWindows/XLSearchTaskWindow.xaml.cs index 42eac5f43..47c07d2cb 100644 --- a/MetaMorpheus/GUI/TaskWindows/XLSearchTaskWindow.xaml.cs +++ b/MetaMorpheus/GUI/TaskWindows/XLSearchTaskWindow.xaml.cs @@ -29,6 +29,7 @@ public partial class XLSearchTaskWindow : Window private readonly ObservableCollection FixedModTypeForTreeViewObservableCollection = new ObservableCollection(); private readonly ObservableCollection VariableModTypeForTreeViewObservableCollection = new ObservableCollection(); private CustomFragmentationWindow CustomFragmentationWindow; + private DeconHostViewModel DeconHostViewModel; public XLSearchTaskWindow(XLSearchTask task) { @@ -36,6 +37,7 @@ public XLSearchTaskWindow(XLSearchTask task) PopulateChoices(); TheTask = task ?? new XLSearchTask(); UpdateFieldsFromTask(TheTask); + DeisotopingControl.DataContext = DeconHostViewModel; if (task == null) { @@ -150,8 +152,9 @@ private void UpdateFieldsFromTask(XLSearchTask task) } checkBoxDecoy.IsChecked = task.XlSearchParameters.DecoyType != DecoyType.None; - deconvolutePrecursors.IsChecked = task.CommonParameters.DoPrecursorDeconvolution; - useProvidedPrecursor.IsChecked = task.CommonParameters.UseProvidedPrecursorInfo; + DeconHostViewModel = new DeconHostViewModel(TheTask.CommonParameters.PrecursorDeconvolutionParameters, + TheTask.CommonParameters.ProductDeconvolutionParameters, + TheTask.CommonParameters.UseProvidedPrecursorInfo, TheTask.CommonParameters.DoPrecursorDeconvolution); missedCleavagesTextBox.Text = task.CommonParameters.DigestionParams.MaxMissedCleavages.ToString(CultureInfo.InvariantCulture); MinPeptideLengthTextBox.Text = task.CommonParameters.DigestionParams.MinPeptideLength.ToString(CultureInfo.InvariantCulture); MaxPeptideLengthTextBox.Text = task.CommonParameters.DigestionParams.MaxPeptideLength == int.MaxValue ? "" : task.CommonParameters.DigestionParams.MaxPeptideLength.ToString(CultureInfo.InvariantCulture); @@ -235,7 +238,7 @@ private void SaveButton_Click(object sender, RoutedEventArgs e) if (!GlobalGuiSettings.CheckTaskSettingsValidity(XLPrecusorMsTlTextBox.Text, productMassToleranceTextBox.Text, missedCleavagesTextBox.Text, maxModificationIsoformsTextBox.Text, MinPeptideLengthTextBox.Text, MaxPeptideLengthTextBox.Text, maxThreadsTextBox.Text, minScoreAllowed.Text, - fieldNotUsed, fieldNotUsed, fieldNotUsed, TopNPeaksTextBox.Text, MinRatioTextBox.Text, null, null, numberOfDatabaseSearchesTextBox.Text, + fieldNotUsed, fieldNotUsed, DeconHostViewModel.PrecursorDeconvolutionParameters.MaxAssumedChargeState.ToString(), TopNPeaksTextBox.Text, MinRatioTextBox.Text, null, null, numberOfDatabaseSearchesTextBox.Text, fieldNotUsed, fieldNotUsed, null, null, null)) { return; @@ -317,12 +320,17 @@ private void SaveButton_Click(object sender, RoutedEventArgs e) } bool _addCompIons = ckbAddCompIon.IsChecked.Value; + DeconvolutionParameters precursorDeconvolutionParameters = DeconHostViewModel.PrecursorDeconvolutionParameters.Parameters; + DeconvolutionParameters productDeconvolutionParameters = DeconHostViewModel.ProductDeconvolutionParameters.Parameters; + bool useProvidedPrecursorInfo = DeconHostViewModel.UseProvidedPrecursors; + bool doPrecursorDeconvolution = DeconHostViewModel.DoPrecursorDeconvolution; + CommonParameters commonParamsToSave = new CommonParameters( precursorMassTolerance: PrecursorMassTolerance, taskDescriptor: OutputFileNameTextBox.Text != "" ? OutputFileNameTextBox.Text : "XLSearchTask", productMassTolerance: ProductMassTolerance, - doPrecursorDeconvolution: deconvolutePrecursors.IsChecked.Value, - useProvidedPrecursorInfo: useProvidedPrecursor.IsChecked.Value, + doPrecursorDeconvolution: doPrecursorDeconvolution, + useProvidedPrecursorInfo: useProvidedPrecursorInfo, digestionParams: digestionParamsToSave, trimMs1Peaks: trimMs1.IsChecked.Value, trimMsMsPeaks: trimMsMs.IsChecked.Value, @@ -338,7 +346,9 @@ private void SaveButton_Click(object sender, RoutedEventArgs e) totalPartitions: int.Parse(numberOfDatabaseSearchesTextBox.Text, CultureInfo.InvariantCulture), listOfModsVariable: listOfModsVariable, listOfModsFixed: listOfModsFixed, - assumeOrphanPeaksAreZ1Fragments: protease.Name != "top-down"); + assumeOrphanPeaksAreZ1Fragments: protease.Name != "top-down", + precursorDeconParams: precursorDeconvolutionParameters, + productDeconParams: productDeconvolutionParameters); TheTask.CommonParameters = commonParamsToSave; diff --git a/MetaMorpheus/GUI/Util/Converters/DeconvolutionTypeToControlConverter.cs b/MetaMorpheus/GUI/Util/Converters/DeconvolutionTypeToControlConverter.cs new file mode 100644 index 000000000..1daf97137 --- /dev/null +++ b/MetaMorpheus/GUI/Util/Converters/DeconvolutionTypeToControlConverter.cs @@ -0,0 +1,53 @@ +using System; +using System.Globalization; +using GuiFunctions; +using MassSpectrometry; + +namespace MetaMorpheusGUI +{ + /// + /// Converts a DeconvolutionType to a corresponding control. + /// + public class DeconvolutionTypeToControlConverter : BaseValueConverter + { + /// + /// Converts a DeconvolutionType to a corresponding control. + /// + /// The value to convert, expected to be of type DeconParamsViewModel. + /// The type of the target property. + /// Optional parameter to be used in the converter logic. + /// The culture to use in the converter. + /// A control corresponding to the DeconvolutionType. + /// Thrown when the value is not of type DeconParamsViewModel or the DeconvolutionType is invalid. + public override object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + // Assuming value is of an enum type DeconvolutionType + if (value is not DeconParamsViewModel viewModel) + throw new ArgumentException("Invalid value type", nameof(value)); + + switch (viewModel.DeconvolutionType) + { + case DeconvolutionType.ClassicDeconvolution: + return new ClassicDeconParamsControl() { DataContext = value as ClassicDeconParamsViewModel }; + + case DeconvolutionType.ExampleNewDeconvolutionTemplate: + default: + throw new ArgumentException("Invalid DeconvolutionType", nameof(value)); + } + } + + /// + /// Converts a value back to its source type. Not implemented. + /// + /// The value produced by the binding target. + /// The type to convert to. + /// Optional parameter to be used in the converter logic. + /// The culture to use in the converter. + /// Throws NotImplementedException. + /// Always thrown as this method is not implemented. + public override object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + } +} diff --git a/MetaMorpheus/GUI/Views/Deconvolution/ClassicDeconParamsControl.xaml b/MetaMorpheus/GUI/Views/Deconvolution/ClassicDeconParamsControl.xaml new file mode 100644 index 000000000..dcd2e62ba --- /dev/null +++ b/MetaMorpheus/GUI/Views/Deconvolution/ClassicDeconParamsControl.xaml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + diff --git a/MetaMorpheus/GUI/Views/Deconvolution/ClassicDeconParamsControl.xaml.cs b/MetaMorpheus/GUI/Views/Deconvolution/ClassicDeconParamsControl.xaml.cs new file mode 100644 index 000000000..c866b44c9 --- /dev/null +++ b/MetaMorpheus/GUI/Views/Deconvolution/ClassicDeconParamsControl.xaml.cs @@ -0,0 +1,15 @@ +using System.Windows.Controls; + +namespace MetaMorpheusGUI +{ + /// + /// Interaction logic for ClassicDeconParamsControl.xaml + /// + public partial class ClassicDeconParamsControl : UserControl + { + public ClassicDeconParamsControl() + { + InitializeComponent(); + } + } +} diff --git a/MetaMorpheus/GUI/Views/Deconvolution/HostDeconParamControl.xaml b/MetaMorpheus/GUI/Views/Deconvolution/HostDeconParamControl.xaml new file mode 100644 index 000000000..ca2a2f1fe --- /dev/null +++ b/MetaMorpheus/GUI/Views/Deconvolution/HostDeconParamControl.xaml @@ -0,0 +1,112 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Use the charge states and precursor masses determined by the instrument controller. + + + + + + + + + + + Additionally searches for coisolated peptides, allowing for multiple peptides to be identified from a single MS2. + + + + + + + + + + + The type of deconvolution to perform. + + + + + + + + + + + + + + + + diff --git a/MetaMorpheus/GUI/Views/Deconvolution/HostDeconParamControl.xaml.cs b/MetaMorpheus/GUI/Views/Deconvolution/HostDeconParamControl.xaml.cs new file mode 100644 index 000000000..3c4c7f862 --- /dev/null +++ b/MetaMorpheus/GUI/Views/Deconvolution/HostDeconParamControl.xaml.cs @@ -0,0 +1,15 @@ +using System.Windows.Controls; + +namespace MetaMorpheusGUI +{ + /// + /// Interaction logic for HostDeconParamControl.xaml + /// + public partial class HostDeconParamControl : UserControl + { + public HostDeconParamControl() + { + InitializeComponent(); + } + } +} diff --git a/MetaMorpheus/GuiFunctions/GuiFunctions.csproj b/MetaMorpheus/GuiFunctions/GuiFunctions.csproj index e18966830..3eafcfea2 100644 --- a/MetaMorpheus/GuiFunctions/GuiFunctions.csproj +++ b/MetaMorpheus/GuiFunctions/GuiFunctions.csproj @@ -16,7 +16,7 @@ - + diff --git a/MetaMorpheus/GuiFunctions/MetaDraw/DrawnSequence.cs b/MetaMorpheus/GuiFunctions/MetaDraw/DrawnSequence.cs index 1dfb9f5fa..11009fb7d 100644 --- a/MetaMorpheus/GuiFunctions/MetaDraw/DrawnSequence.cs +++ b/MetaMorpheus/GuiFunctions/MetaDraw/DrawnSequence.cs @@ -381,25 +381,26 @@ public static void ClearCanvas(Canvas cav) public static SolidColorBrush ParseColorBrushFromOxyColor(OxyColor color) { - var colorVal = color.ToByteString().Split(','); - return new SolidColorBrush(System.Windows.Media.Color.FromArgb(Byte.Parse(colorVal[0]), Byte.Parse(colorVal[1]), Byte.Parse(colorVal[2]), Byte.Parse(colorVal[3]))); + return new SolidColorBrush(Color.FromArgb(color.A, color.R, color.G, color.B)); } public static SolidColorBrush ParseColorBrushFromName(string name) { - OxyColor color = MetaDrawSettings.PossibleColors.Keys.Where(p => p.GetColorName().Equals(name.Replace(" ", ""))).First(); - return ParseColorBrushFromOxyColor(color); + string cleanedName = name.Replace(" ", ""); + var foundColor = MetaDrawSettings.PossibleColors.FirstOrDefault(p => p.Value == cleanedName).Key; + return ParseColorBrushFromOxyColor(foundColor == default ? MetaDrawSettings.FallbackColor : foundColor); } public static OxyColor ParseOxyColorFromName(string name) { - return MetaDrawSettings.PossibleColors.Keys.Where(p => p.GetColorName().Equals(name.Replace(" ", ""))).First(); + string cleanedName = name.Replace(" ", ""); + var foundColor = MetaDrawSettings.PossibleColors.FirstOrDefault(p => p.Value == cleanedName).Key; + return foundColor == default ? MetaDrawSettings.FallbackColor : foundColor; } public static Color ParseColorFromOxyColor(OxyColor color) { - var colorVal = color.ToByteString().Split(','); - return System.Windows.Media.Color.FromArgb(Byte.Parse(colorVal[0]), Byte.Parse(colorVal[1]), Byte.Parse(colorVal[2]), Byte.Parse(colorVal[3])); + return Color.FromArgb(color.A, color.R, color.G, color.B); } /// diff --git a/MetaMorpheus/GuiFunctions/MetaDraw/MetaDrawSettings.cs b/MetaMorpheus/GuiFunctions/MetaDraw/MetaDrawSettings.cs index a38b939b7..e6607cd0f 100644 --- a/MetaMorpheus/GuiFunctions/MetaDraw/MetaDrawSettings.cs +++ b/MetaMorpheus/GuiFunctions/MetaDraw/MetaDrawSettings.cs @@ -37,6 +37,7 @@ public static class MetaDrawSettings public static bool AnnotationBold { get; set; } = false; public static bool DisplayInternalIons { get; set; } = true; public static bool DisplayInternalIonAnnotations { get; set; }= true; + public static OxyColor FallbackColor { get; } = OxyColors.Aqua; public static Dictionary PossibleColors { get; set; } public static Dictionary ProductTypeToColor { get; set; } public static Dictionary BetaProductTypeToColor { get; set; } diff --git a/MetaMorpheus/GuiFunctions/MzLibExtensions.cs b/MetaMorpheus/GuiFunctions/MzLibExtensions.cs new file mode 100644 index 000000000..07fc8fc60 --- /dev/null +++ b/MetaMorpheus/GuiFunctions/MzLibExtensions.cs @@ -0,0 +1,36 @@ +using System; +using MassSpectrometry; + +namespace GuiFunctions +{ + /// + /// Provides additional functionality for the MzLib library. + /// + public static class MzLibExtensions + { + + /// + /// Converts the given to a . + /// + /// The deconvolution parameters to convert. + /// A representing the given parameters. + /// + /// Thrown when the type of is not supported. + /// + public static DeconParamsViewModel ToViewModel(this DeconvolutionParameters parameters) + { + if (parameters is ClassicDeconvolutionParameters classicParams) + { + return new ClassicDeconParamsViewModel(classicParams); + } + //else if (parameters is IsoDeconvolutionParameters isoParams) + //{ + // return new IsoDecDeconParamsViewModel(isoParams); + //} + else + { + throw new NotImplementedException(); + } + } + } +} diff --git a/MetaMorpheus/GuiFunctions/ViewModels/CoverageTypeForTreeViewModel.cs b/MetaMorpheus/GuiFunctions/ViewModels/CoverageTypeForTreeViewModel.cs index 72914c988..5ecee4abb 100644 --- a/MetaMorpheus/GuiFunctions/ViewModels/CoverageTypeForTreeViewModel.cs +++ b/MetaMorpheus/GuiFunctions/ViewModels/CoverageTypeForTreeViewModel.cs @@ -51,7 +51,7 @@ public CoverageTypeForTreeViewModel(string name) { Name = name; OxyColor color = MetaDrawSettings.CoverageTypeToColor[name]; - SelectedColor = AddSpaces(color.GetColorName()); + SelectedColor = AddSpaces(MetaDrawSettings.PossibleColors[color]); ColorBrush = DrawnSequence.ParseColorBrushFromOxyColor(color); } diff --git a/MetaMorpheus/GuiFunctions/ViewModels/Deconvolution/ClassicDeconParamsViewModel.cs b/MetaMorpheus/GuiFunctions/ViewModels/Deconvolution/ClassicDeconParamsViewModel.cs new file mode 100644 index 000000000..87374963f --- /dev/null +++ b/MetaMorpheus/GuiFunctions/ViewModels/Deconvolution/ClassicDeconParamsViewModel.cs @@ -0,0 +1,44 @@ +using MassSpectrometry; + +namespace GuiFunctions; + +public sealed class ClassicDeconParamsViewModel : DeconParamsViewModel +{ + private ClassicDeconvolutionParameters _parameters; + public override DeconvolutionParameters Parameters + { + get => _parameters; + protected set + { + _parameters = (ClassicDeconvolutionParameters)value; + OnPropertyChanged(nameof(Parameters)); + } + } + + public ClassicDeconParamsViewModel(ClassicDeconvolutionParameters parameters) + { + Parameters = parameters; + } + + public double DeconvolutionTolerancePpm + { + get => _parameters.DeconvolutionTolerancePpm; + set + { + _parameters.DeconvolutionTolerancePpm = value; + OnPropertyChanged(nameof(DeconvolutionTolerancePpm)); + } + } + + public double IntensityRatioLimit + { + get => _parameters.IntensityRatioLimit; + set + { + _parameters.IntensityRatioLimit = value; + OnPropertyChanged(nameof(IntensityRatioLimit)); + } + } + + public override string ToString() => "Classic"; +} \ No newline at end of file diff --git a/MetaMorpheus/GuiFunctions/ViewModels/Deconvolution/DeconHostViewModel.cs b/MetaMorpheus/GuiFunctions/ViewModels/Deconvolution/DeconHostViewModel.cs new file mode 100644 index 000000000..411f572c7 --- /dev/null +++ b/MetaMorpheus/GuiFunctions/ViewModels/Deconvolution/DeconHostViewModel.cs @@ -0,0 +1,188 @@ +#nullable enable +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using Easy.Common.Extensions; +using EngineLayer; +using MassSpectrometry; + +namespace GuiFunctions; + +/// +/// This class holds all of the information in the Deconvolution tab of the GUI +/// One instance will be create per Task Window +/// +/// The Task window will populate this view model with the appropriate parameters from +/// The user can then modify these parameters as needed via the gui +/// The Task window will use the PrecursorDeconvolutionParameters and teh ProductDeconvolutionParameters to create a new object +/// +public class DeconHostViewModel : BaseViewModel +{ + /// + /// This is where default deconvolution parameters are set for GUI display + /// + /// precursor params to display first + /// product params to display first + /// + /// + /// + public DeconHostViewModel(DeconvolutionParameters? initialPrecursorParameters = null, DeconvolutionParameters? initialProductParameters = null, + bool useProvidedPrecursor = false, bool deconvolutePrecursors = true) + { + UseProvidedPrecursors = useProvidedPrecursor; + DoPrecursorDeconvolution = deconvolutePrecursors; + + // Order matters here, construct the lists before setting the selected parameters + PrecursorDeconvolutionParametersList = new ObservableCollection(); + ProductDeconvolutionParametersList = new ObservableCollection(); + + // populate the lists by adding the default parameters for each deconvolution type or the provided parameters + foreach (var deconType in Enum.GetValues()) + { + switch (deconType) + { + case DeconvolutionType.ExampleNewDeconvolutionTemplate: + continue; + + case DeconvolutionType.ClassicDeconvolution: + + if (initialPrecursorParameters is { DeconvolutionType: DeconvolutionType.ClassicDeconvolution }) + PrecursorDeconvolutionParametersList.Add(initialPrecursorParameters.ToViewModel()); + else + { + var toAdd = GlobalVariables.AnalyteType switch + { + AnalyteType.Peptide => new ClassicDeconvolutionParameters(1, 12, 4, 3), + AnalyteType.Proteoform => new ClassicDeconvolutionParameters(1, 60, 4, 3), + AnalyteType.Oligo => new ClassicDeconvolutionParameters(-20, -1, 4, 3), + _ => throw new ArgumentOutOfRangeException() + }; + PrecursorDeconvolutionParametersList.Add(toAdd.ToViewModel()); + } + + if (initialProductParameters is { DeconvolutionType: DeconvolutionType.ClassicDeconvolution }) + ProductDeconvolutionParametersList.Add(initialProductParameters.ToViewModel()); + else + { + var toAdd = GlobalVariables.AnalyteType switch + { + AnalyteType.Peptide => new ClassicDeconvolutionParameters(1, 10, 4, 3), + AnalyteType.Proteoform => new ClassicDeconvolutionParameters(1, 10, 4, 3), + AnalyteType.Oligo => new ClassicDeconvolutionParameters(-10, -1, 4, 3), + _ => throw new ArgumentOutOfRangeException() + }; + ProductDeconvolutionParametersList.Add(toAdd.ToViewModel()); + } + + break; + + case DeconvolutionType.IsoDecDeconvolution: + // TODO: fill in IsoDec region in follow-up pull request + break; + + default: // This will only be hit if a new deconvolution type is added to mzlib and not handled here + throw new ArgumentOutOfRangeException(); + } + } + + // If deconvolution parameters are not set, default to MetaMorpheus defaults + PrecursorDeconvolutionParameters = initialPrecursorParameters is null + ? PrecursorDeconvolutionParametersList.First(x => x.DeconvolutionType == DeconvolutionType.ClassicDeconvolution) + : PrecursorDeconvolutionParametersList.First(x => x.Parameters == initialPrecursorParameters); + + ProductDeconvolutionParameters = initialProductParameters is null + ? ProductDeconvolutionParametersList.First(x => x.DeconvolutionType == DeconvolutionType.ClassicDeconvolution) + : ProductDeconvolutionParametersList.First(x => x.Parameters == initialProductParameters); + } + + #region Common Parameters + + private bool _useProvidedPrecursors; + public bool UseProvidedPrecursors + { + get => _useProvidedPrecursors; + set + { + _useProvidedPrecursors = value; + OnPropertyChanged(nameof(UseProvidedPrecursors)); + } + } + + private bool _doPrecursorDeconvolution; + public bool DoPrecursorDeconvolution + { + get => _doPrecursorDeconvolution; + set + { + _doPrecursorDeconvolution = value; + OnPropertyChanged(nameof(DoPrecursorDeconvolution)); + } + } + + #endregion + + /// + /// All of the possible precursor deconvolution parameters that can be selected + /// + /// Their ToString() method sets the name of the combo box + /// Stored in memory while task window is open, only the selected one is used for + /// This enables the user to set parameters, switch to another, and switch back without losing their settings + /// + public ObservableCollection PrecursorDeconvolutionParametersList { get; protected set; } + private DeconParamsViewModel? _precursorDeconvolutionParameters; + + /// + /// The selected precursor deconvolution parameters + /// + public DeconParamsViewModel PrecursorDeconvolutionParameters + { + get => _precursorDeconvolutionParameters!; + set + { + _precursorDeconvolutionParameters = value; + OnPropertyChanged(nameof(PrecursorDeconvolutionParameters)); + } + } + + /// + /// All of the possible product deconvolution parameters that can be selected + /// + /// Their ToString() method sets the name of the combo box + /// Stored in memory while task window is open, only the selected one is used for + /// This enables the user to set parameters, switch to another, and switch back without losing their settings + /// + public ObservableCollection ProductDeconvolutionParametersList { get; protected set; } + private DeconParamsViewModel? _productDeconvolutionParameters; + + /// + /// The selected product deconvolution parameters + /// + public DeconParamsViewModel ProductDeconvolutionParameters + { + get => _productDeconvolutionParameters!; + set + { + _productDeconvolutionParameters = value; + OnPropertyChanged(nameof(ProductDeconvolutionParameters)); + } + } + + /// + /// Hides the decon type selection combo box if only one options is present + /// + public bool DisplayDeconSelectionComboBox => PrecursorDeconvolutionParametersList.Count > 1 || ProductDeconvolutionParametersList.Count > 1; +} + +[ExcludeFromCodeCoverage] // Model used only for visualizing the view in visual studio +public class DeconHostModel : DeconHostViewModel +{ + public static DeconHostModel Instance => new DeconHostModel(); + + public DeconHostModel() : base (DeconParamsModel.Instance.Parameters, DeconParamsModel.Instance.Parameters) + { + UseProvidedPrecursors = false; + DoPrecursorDeconvolution = true; + } +} \ No newline at end of file diff --git a/MetaMorpheus/GuiFunctions/ViewModels/Deconvolution/DeconParamsViewModel.cs b/MetaMorpheus/GuiFunctions/ViewModels/Deconvolution/DeconParamsViewModel.cs new file mode 100644 index 000000000..a09e00169 --- /dev/null +++ b/MetaMorpheus/GuiFunctions/ViewModels/Deconvolution/DeconParamsViewModel.cs @@ -0,0 +1,178 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using MassSpectrometry; + +namespace GuiFunctions; + +/// +/// Base Deconvolution Parameters view model +/// Used to wrap the DeconvolutionParameters object +/// Contains only shared information between different DeconvolutionParameters +/// +public abstract class DeconParamsViewModel : BaseViewModel, IEquatable +{ + + private int _previousMinAssumedChargeState; + private int _previousMaxAssumedChargeState; + + public DeconvolutionType DeconvolutionType => Parameters.DeconvolutionType; + public abstract DeconvolutionParameters Parameters { get; protected set; } + + + /// + /// Gets or sets the minimum assumed charge state. + /// Ensures the value is within valid range based on the polarity. + /// + public int MinAssumedChargeState + { + get => Parameters.MinAssumedChargeState; + set + { + if (value == 0) + return; + switch (Polarity) + { + case Polarity.Positive when value < 0: + case Polarity.Positive when value > MaxAssumedChargeState: + case Polarity.Negative when value > 0: + case Polarity.Negative when value > MaxAssumedChargeState: + return; + + default: + _previousMinAssumedChargeState = Parameters.MinAssumedChargeState; + Parameters.MinAssumedChargeState = value; + OnPropertyChanged(nameof(MinAssumedChargeState)); + break; + } + } + } + + + /// + /// Gets or sets the maximum assumed charge state. + /// Ensures the value is within valid range based on the polarity. + /// + public int MaxAssumedChargeState + { + get => Parameters.MaxAssumedChargeState; + set + { + if (value == 0) + return; + switch (Polarity) + { + case Polarity.Positive when value < 0: + case Polarity.Positive when value < MinAssumedChargeState: + case Polarity.Negative when value > 0: + case Polarity.Negative when value < MinAssumedChargeState: + return; + + default: + _previousMaxAssumedChargeState = Parameters.MaxAssumedChargeState; + Parameters.MaxAssumedChargeState = value; + OnPropertyChanged(nameof(MaxAssumedChargeState)); + break; + } + } + } + + // TODO: When RNA is added to MetaMorpheus, add the polarity to the GUI + public Polarity Polarity + { + get => Parameters.Polarity; + set + { + // Update based upon the new polarity + Parameters.Polarity = value; + OnPropertyChanged(nameof(Polarity)); + + // Update min and max charge to be valid with the new polarity + // switch from negative to positive + if (value == Polarity.Positive) + { + if (MaxAssumedChargeState < 0) + { + if (_previousMaxAssumedChargeState > 0) + MaxAssumedChargeState = _previousMaxAssumedChargeState; + else + MaxAssumedChargeState = 12; + } + + if (MinAssumedChargeState < 1) + { + if (_previousMinAssumedChargeState > 0 && _previousMinAssumedChargeState < MaxAssumedChargeState) + MinAssumedChargeState = _previousMinAssumedChargeState; + else + MinAssumedChargeState = 1; + } + } + + // switch from positive to negative + if (value == Polarity.Negative) + { + if (MinAssumedChargeState > 0) + { + if (_previousMinAssumedChargeState < 0) + MinAssumedChargeState = _previousMinAssumedChargeState; + else + MinAssumedChargeState = -20; + } + + if (MaxAssumedChargeState > 0) + { + if (_previousMaxAssumedChargeState < 0 && _previousMaxAssumedChargeState > MinAssumedChargeState) + MaxAssumedChargeState = _previousMaxAssumedChargeState; + else + MaxAssumedChargeState = -1; + } + } + + } + } + + public override string ToString() => DeconvolutionType.ToString(); + + public bool Equals(DeconParamsViewModel other) + { + if (ReferenceEquals(null, other)) return false; + if (ReferenceEquals(this, other)) return true; + + if (Parameters.DeconvolutionType != other.Parameters.DeconvolutionType) + return false; + if (Parameters.Polarity != other.Parameters.Polarity) + return false; + if (Parameters.MinAssumedChargeState != other.Parameters.MinAssumedChargeState) + return false; + if (Parameters.MaxAssumedChargeState != other.Parameters.MaxAssumedChargeState) + return false; + return true; + } + + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != this.GetType()) return false; + return Equals((DeconParamsViewModel)obj); + } + + public override int GetHashCode() + { + return (Parameters != null ? Parameters.DeconvolutionType.GetHashCode() + Parameters.Polarity.GetHashCode() + MaxAssumedChargeState.GetHashCode() : 0); + } +} + + +[ExcludeFromCodeCoverage] // Model used only for visualizing the view in visual studio +public class DeconParamsModel : DeconParamsViewModel +{ + public static DeconParamsModel Instance => new DeconParamsModel(); + + public sealed override DeconvolutionParameters Parameters { get; protected set; } + + public DeconParamsModel() + { + Parameters = new ClassicDeconvolutionParameters(1, 20, 5, 3, Polarity.Negative); + } +} \ No newline at end of file diff --git a/MetaMorpheus/GuiFunctions/ViewModels/Deconvolution/IsoDecDeconParamsViewModel.cs b/MetaMorpheus/GuiFunctions/ViewModels/Deconvolution/IsoDecDeconParamsViewModel.cs new file mode 100644 index 000000000..1a09d8090 --- /dev/null +++ b/MetaMorpheus/GuiFunctions/ViewModels/Deconvolution/IsoDecDeconParamsViewModel.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using MassSpectrometry; + +namespace GuiFunctions +{ + // Coming Soon + [ExcludeFromCodeCoverage] + public sealed class IsoDecDeconParamsViewModel : DeconParamsViewModel + { + public override DeconvolutionParameters Parameters { get; protected set; } + + + public override string ToString() => "IsoDec"; + } +} diff --git a/MetaMorpheus/GuiFunctions/ViewModels/IonForTreeViewModel.cs b/MetaMorpheus/GuiFunctions/ViewModels/IonForTreeViewModel.cs index cdc3cf98d..843c23a67 100644 --- a/MetaMorpheus/GuiFunctions/ViewModels/IonForTreeViewModel.cs +++ b/MetaMorpheus/GuiFunctions/ViewModels/IonForTreeViewModel.cs @@ -66,7 +66,7 @@ public IonForTreeViewModel(ProductType type, bool beta) color = MetaDrawSettings.BetaProductTypeToColor[IonType]; else color = MetaDrawSettings.ProductTypeToColor[IonType]; - SelectedColor = AddSpaces(color.GetColorName()); + SelectedColor = AddSpaces(MetaDrawSettings.PossibleColors[color]); ColorBrush = DrawnSequence.ParseColorBrushFromOxyColor(color); } diff --git a/MetaMorpheus/GuiFunctions/ViewModels/ModForTreeViewModel.cs b/MetaMorpheus/GuiFunctions/ViewModels/ModForTreeViewModel.cs index b1f4080e4..2ee06aa00 100644 --- a/MetaMorpheus/GuiFunctions/ViewModels/ModForTreeViewModel.cs +++ b/MetaMorpheus/GuiFunctions/ViewModels/ModForTreeViewModel.cs @@ -14,6 +14,7 @@ public class ModForTreeViewModel : BaseViewModel private bool _isChecked; private string _selectedColor; private SolidColorBrush _colorBrush; + private bool _colorDataLoaded; #endregion @@ -23,10 +24,7 @@ public class ModForTreeViewModel : BaseViewModel public bool Use { - get - { - return _isChecked; - } + get => _isChecked; set { _isChecked = value; @@ -40,17 +38,26 @@ public bool Use public Brush Background { get; } public string SelectedColor { - get { return _selectedColor; } + get + { + EnsureColorDataLoaded(); + return _selectedColor; + } set { _selectedColor = value; ColorBrush = DrawnSequence.ParseColorBrushFromName(_selectedColor); + _colorDataLoaded = true; OnPropertyChanged(nameof(SelectedColor)); } } public SolidColorBrush ColorBrush { - get { return _colorBrush; } + get + { + EnsureColorDataLoaded(); + return _colorBrush; + } set { _colorBrush = value; @@ -69,16 +76,6 @@ public ModForTreeViewModel(string toolTip, bool use, string modName, bool bad, M Use = use; ModName = modName; DisplayName = modName; - if (MetaDrawSettings.ModificationTypeToColor != null) - { - // This if statement prevents a crash from loading a search task modifications not found on launch - // This can occur due to new custom modifications or a mod in the xml database that was not in our initial list - if (!MetaDrawSettings.ModificationTypeToColor.TryGetValue(modName, out OxyColor color)) - color = OxyColors.Aqua; - SelectedColor = AddSpaces(color.GetColorName()); - ColorBrush = DrawnSequence.ParseColorBrushFromOxyColor(color); - } - if (toolTip.ToLower().Contains("terminal")) { @@ -104,6 +101,27 @@ public ModForTreeViewModel(string toolTip, bool use, string modName, bool bad, M #endregion + /// + /// Ensures the color data is loaded. This is necessary because the color data is not loaded until the first time it is accessed. + /// This enables the use of the same control in MetaDraw and Task Windows without loading the color data for task windows. + /// + private void EnsureColorDataLoaded() + { + if (!_colorDataLoaded) + { + if (MetaDrawSettings.ModificationTypeToColor != null) + { + // This if statement prevents a crash from loading a search task modifications not found on launch + // This can occur due to new custom modifications or a mod in the xml database that was not in our initial list + if (!MetaDrawSettings.ModificationTypeToColor.TryGetValue(ModName, out OxyColor color)) + color = MetaDrawSettings.FallbackColor; + _selectedColor = AddSpaces(MetaDrawSettings.PossibleColors[color]); + _colorBrush = DrawnSequence.ParseColorBrushFromOxyColor(color); + } + _colorDataLoaded = true; + } + } + public void SelectionChanged(string newColor) { SelectedColor = newColor; diff --git a/MetaMorpheus/MetaMorpheus.sln.DotSettings b/MetaMorpheus/MetaMorpheus.sln.DotSettings index 3cb2a8c2a..2b8fe6816 100644 --- a/MetaMorpheus/MetaMorpheus.sln.DotSettings +++ b/MetaMorpheus/MetaMorpheus.sln.DotSettings @@ -1,4 +1,5 @@  + True True True True @@ -6,6 +7,8 @@ True True True + True + True True True True @@ -20,9 +23,11 @@ True True True + True True True True + True True True True diff --git a/MetaMorpheus/MetaMorpheusSetup/Product.wxs b/MetaMorpheus/MetaMorpheusSetup/Product.wxs index fc7b69b92..3bbf33f48 100644 --- a/MetaMorpheus/MetaMorpheusSetup/Product.wxs +++ b/MetaMorpheus/MetaMorpheusSetup/Product.wxs @@ -315,6 +315,9 @@ + + + diff --git a/MetaMorpheus/TaskLayer/MetaMorpheusTask.cs b/MetaMorpheus/TaskLayer/MetaMorpheusTask.cs index 16c86ad4b..44bb83da6 100644 --- a/MetaMorpheus/TaskLayer/MetaMorpheusTask.cs +++ b/MetaMorpheus/TaskLayer/MetaMorpheusTask.cs @@ -1143,11 +1143,11 @@ public static void DetermineAnalyteType(CommonParameters commonParameters) && commonParameters.DigestionParams.Protease != null && commonParameters.DigestionParams.Protease.Name == "top-down") { - GlobalVariables.AnalyteType = "Proteoform"; + GlobalVariables.AnalyteType = AnalyteType.Proteoform; } else { - GlobalVariables.AnalyteType = "Peptide"; + GlobalVariables.AnalyteType = AnalyteType.Peptide; } } diff --git a/MetaMorpheus/TaskLayer/SearchTask/PostSearchAnalysisTask.cs b/MetaMorpheus/TaskLayer/SearchTask/PostSearchAnalysisTask.cs index e30b4549a..bf6734e70 100644 --- a/MetaMorpheus/TaskLayer/SearchTask/PostSearchAnalysisTask.cs +++ b/MetaMorpheus/TaskLayer/SearchTask/PostSearchAnalysisTask.cs @@ -136,11 +136,11 @@ private void CalculatePsmAndPeptideFdr(List psms, string analysis // for example, here it may be treated as a decoy PSM, where as in parsimony it will be determined by the parsimony algorithm which is agnostic of target/decoy assignments // this could cause weird PSM FDR issues - Status("Estimating PSM FDR...", Parameters.SearchTaskId); + Status($"Estimating {GlobalVariables.AnalyteType.GetSpectralMatchLabel()} FDR...", Parameters.SearchTaskId); new FdrAnalysisEngine(psms, Parameters.NumNotches, CommonParameters, this.FileSpecificParameters, new List { Parameters.SearchTaskId }, analysisType: analysisType, doPEP: doPep, outputFolder: Parameters.OutputFolder).Run(); - Status("Done estimating PSM FDR!", Parameters.SearchTaskId); + Status($"Done estimating {GlobalVariables.AnalyteType.GetSpectralMatchLabel()} FDR!", Parameters.SearchTaskId); } private void ProteinAnalysis() @@ -150,7 +150,7 @@ private void ProteinAnalysis() return; } - Status("Constructing protein groups...", Parameters.SearchTaskId); + Status($"Constructing {GlobalVariables.AnalyteType.GetBioPolymerLabel().ToLower()} groups...", Parameters.SearchTaskId); //if SILAC, modify the proteins to appear only light (we want a protein sequence to look like PROTEINK instead of PROTEINa) if (Parameters.SearchParameters.SilacLabels != null && Parameters.AllPsms.First() is PeptideSpectralMatch) @@ -178,7 +178,7 @@ private void ProteinAnalysis() ProteinGroups = proteinScoringAndFdrResults.SortedAndScoredProteinGroups; - Status("Done constructing protein groups!", Parameters.SearchTaskId); + Status($"Done constructing {GlobalVariables.AnalyteType.GetBioPolymerLabel().ToLower()} groups!", Parameters.SearchTaskId); } private void DoMassDifferenceLocalizationAnalysis() @@ -593,7 +593,7 @@ protected void WritePsmsToTsv(IEnumerable psms, string filePath, } private void WritePsmResults() { - Status("Writing PSM results...", Parameters.SearchTaskId); + Status($"Writing {GlobalVariables.AnalyteType.GetSpectralMatchLabel()} results...", Parameters.SearchTaskId); var psmsForPsmResults = FilteredPsms.Filter(Parameters.AllPsms, CommonParameters, includeDecoys: Parameters.SearchParameters.WriteDecoys, @@ -602,13 +602,13 @@ private void WritePsmResults() includeHighQValuePsms: Parameters.SearchParameters.WriteHighQValuePsms); // write PSMs - string writtenFile = Path.Combine(Parameters.OutputFolder, "AllPSMs.psmtsv"); + string writtenFile = Path.Combine(Parameters.OutputFolder, $"All{GlobalVariables.AnalyteType.GetSpectralMatchLabel()}s.{GlobalVariables.AnalyteType.GetSpectralMatchExtension()}"); WritePsmsToTsv(psmsForPsmResults.OrderByDescending(p=>p).ToList(), writtenFile, writePeptideLevelResults: false); FinishedWritingFile(writtenFile, new List { Parameters.SearchTaskId }); // write PSMs for percolator // percolator native read format is .tab - writtenFile = Path.Combine(Parameters.OutputFolder, "AllPSMs_FormattedForPercolator.tab"); + writtenFile = Path.Combine(Parameters.OutputFolder, $"All{GlobalVariables.AnalyteType.GetSpectralMatchLabel()}s_FormattedForPercolator.tab"); WritePsmsForPercolator(psmsForPsmResults.OrderByDescending(p=>p).ToList(), writtenFile); FinishedWritingFile(writtenFile, new List { Parameters.SearchTaskId }); @@ -617,16 +617,16 @@ private void WritePsmResults() { Parameters.SearchTaskResults.AddPsmPeptideProteinSummaryText( - "PEP could not be calculated due to an insufficient number of PSMs. Results were filtered by q-value." + + $"PEP could not be calculated due to an insufficient number of {GlobalVariables.AnalyteType.GetSpectralMatchLabel()}s. Results were filtered by q-value." + Environment.NewLine); } - string psmResultsText = "All target PSMs with " + psmsForPsmResults.GetFilterTypeString() + " <= " + Math.Round(psmsForPsmResults.FilterThreshold, 2) + ": " + + string psmResultsText = $"All target {GlobalVariables.AnalyteType.GetSpectralMatchLabel()}s with " + psmsForPsmResults.GetFilterTypeString() + " <= " + Math.Round(psmsForPsmResults.FilterThreshold, 2) + ": " + psmsForPsmResults.TargetPsmsAboveThreshold; - ResultsDictionary[("All", "PSMs")] = psmResultsText; + ResultsDictionary[("All", $"{GlobalVariables.AnalyteType.GetSpectralMatchLabel()}s")] = psmResultsText; } private void WritePeptideResults() { - Status("Writing peptide results...", Parameters.SearchTaskId); + Status($"Writing {GlobalVariables.AnalyteType.GetUniqueFormLabel().ToLower()} results...", Parameters.SearchTaskId); var peptidesForPeptideResults = FilteredPsms.Filter(Parameters.AllPsms, CommonParameters, @@ -637,7 +637,7 @@ private void WritePeptideResults() filterAtPeptideLevel: true); // write PSMs - string writtenFile = Path.Combine(Parameters.OutputFolder, $"All{GlobalVariables.AnalyteType}s.psmtsv"); + string writtenFile = Path.Combine(Parameters.OutputFolder, $"All{GlobalVariables.AnalyteType}s.{GlobalVariables.AnalyteType.GetSpectralMatchExtension()}"); WritePsmsToTsv(peptidesForPeptideResults.OrderByDescending(p => p).ToList(), writtenFile, writePeptideLevelResults: true); FinishedWritingFile(writtenFile, new List { Parameters.SearchTaskId }); @@ -645,16 +645,16 @@ private void WritePeptideResults() if (peptidesForPeptideResults.FilteringNotPerformed) { Parameters.SearchTaskResults.AddPsmPeptideProteinSummaryText( - "PEP could not be calculated due to an insufficient number of PSMs. Results were filtered by q-value." + Environment.NewLine); + $"PEP could not be calculated due to an insufficient number of {GlobalVariables.AnalyteType.GetSpectralMatchLabel()}s. Results were filtered by q-value." + Environment.NewLine); } - string peptideResultsText = $"All target {GlobalVariables.AnalyteType.ToLower()}s with " + peptidesForPeptideResults.GetFilterTypeString() + " <= " + Math.Round(peptidesForPeptideResults.FilterThreshold, 2) + ": " + + string peptideResultsText = $"All target {GlobalVariables.AnalyteType.GetUniqueFormLabel().ToLower()}s with " + peptidesForPeptideResults.GetFilterTypeString() + " <= " + Math.Round(peptidesForPeptideResults.FilterThreshold, 2) + ": " + peptidesForPeptideResults.TargetPsmsAboveThreshold; - ResultsDictionary[("All", GlobalVariables.AnalyteType)] = peptideResultsText; + ResultsDictionary[("All", GlobalVariables.AnalyteType.GetUniqueFormLabel())] = peptideResultsText; } private void WriteIndividualPsmResults() { - Status("Writing Individual PSM results...", Parameters.SearchTaskId); + Status($"Writing Individual {GlobalVariables.AnalyteType.GetSpectralMatchLabel()} results...", Parameters.SearchTaskId); var psmsGroupedByFile = Parameters.AllPsms.GroupBy(p => p.FullFilePath); foreach (var psmFileGroup in psmsGroupedByFile) @@ -674,24 +674,24 @@ private void WriteIndividualPsmResults() int count = psmsToWrite.Where(psm => psm.PsmFdrInfo.PEP <= 0.01).Count(); // write PSMs - string writtenFile = Path.Combine(Parameters.IndividualResultsOutputFolder, strippedFileName + "_PSMs.psmtsv"); + string writtenFile = Path.Combine(Parameters.IndividualResultsOutputFolder, strippedFileName + $"_{GlobalVariables.AnalyteType.GetSpectralMatchLabel()}s.{GlobalVariables.AnalyteType.GetSpectralMatchExtension()}"); WritePsmsToTsv(psmsToWrite, writtenFile); FinishedWritingFile(writtenFile, new List { Parameters.SearchTaskId, "Individual Spectra Files", psmFileGroup.Key }); // write PSMs for percolator - writtenFile = Path.Combine(Parameters.IndividualResultsOutputFolder, strippedFileName + "_PSMsFormattedForPercolator.tab"); + writtenFile = Path.Combine(Parameters.IndividualResultsOutputFolder, strippedFileName + $"_{GlobalVariables.AnalyteType.GetSpectralMatchLabel()}sFormattedForPercolator.tab"); WritePsmsForPercolator(psmsToWrite.FilteredPsmsList, writtenFile); FinishedWritingFile(writtenFile, new List { Parameters.SearchTaskId, "Individual Spectra Files", psmFileGroup.Key }); // write summary text - string psmResultsText = strippedFileName + " - Target PSMs with " + psmsToWrite.GetFilterTypeString() + " <= " + Math.Round(psmsToWrite.FilterThreshold, 2) + ": " + + string psmResultsText = strippedFileName + $" - Target {GlobalVariables.AnalyteType.GetSpectralMatchLabel()}s with " + psmsToWrite.GetFilterTypeString() + " <= " + Math.Round(psmsToWrite.FilterThreshold, 2) + ": " + psmsToWrite.TargetPsmsAboveThreshold; - ResultsDictionary[(strippedFileName, "PSMs")] = psmResultsText; + ResultsDictionary[(strippedFileName, $"{GlobalVariables.AnalyteType.GetSpectralMatchLabel()}s")] = psmResultsText; } } private void WriteIndividualPeptideResults() { - Status("Writing Individual Peptide results...", Parameters.SearchTaskId); + Status($"Writing Individual {GlobalVariables.AnalyteType} results...", Parameters.SearchTaskId); var peptidesGroupedByFile = Parameters.AllPsms.GroupBy(p => p.FullFilePath); foreach (var psmFileGroup in peptidesGroupedByFile) @@ -715,14 +715,14 @@ private void WriteIndividualPeptideResults() filterAtPeptideLevel: true); // write PSMs - string writtenFile = Path.Combine(Parameters.IndividualResultsOutputFolder, strippedFileName + $"_{GlobalVariables.AnalyteType}s.psmtsv"); + string writtenFile = Path.Combine(Parameters.IndividualResultsOutputFolder, strippedFileName + $"_{GlobalVariables.AnalyteType}s.{GlobalVariables.AnalyteType.GetSpectralMatchExtension()}"); WritePsmsToTsv(peptidesToWrite, writtenFile, writePeptideLevelResults: true); FinishedWritingFile(writtenFile, new List { Parameters.SearchTaskId, "Individual Spectra Files", psmFileGroup.Key }); // write summary text - string peptideResultsText = strippedFileName + $" - Target {GlobalVariables.AnalyteType.ToLower()}s with " + peptidesToWrite.GetFilterTypeString() + " <= " + Math.Round(peptidesToWrite.FilterThreshold, 2) + ": " + + string peptideResultsText = strippedFileName + $" - Target {GlobalVariables.AnalyteType.GetUniqueFormLabel().ToLower()}s with " + peptidesToWrite.GetFilterTypeString() + " <= " + Math.Round(peptidesToWrite.FilterThreshold, 2) + ": " + peptidesToWrite.TargetPsmsAboveThreshold; - ResultsDictionary[(strippedFileName, GlobalVariables.AnalyteType)] = peptideResultsText; + ResultsDictionary[(strippedFileName, GlobalVariables.AnalyteType.GetUniqueFormLabel())] = peptideResultsText; } } @@ -835,14 +835,14 @@ private void WriteProteinResults() } else { - string proteinResultsText = "All target protein groups with q-value <= 0.01 (1% FDR): " + ProteinGroups.Count(b => b.QValue <= 0.01 && !b.IsDecoy); - ResultsDictionary[("All", "Proteins")] = proteinResultsText; + string proteinResultsText = $"All target {GlobalVariables.AnalyteType.GetBioPolymerLabel().ToLower()} groups with q-value <= 0.01 (1% FDR): " + ProteinGroups.Count(b => b.QValue <= 0.01 && !b.IsDecoy); + ResultsDictionary[("All", $"{GlobalVariables.AnalyteType.GetBioPolymerLabel()}s")] = proteinResultsText; } - string fileName = "AllProteinGroups.tsv"; + string fileName = $"All{GlobalVariables.AnalyteType.GetBioPolymerLabel()}Groups.tsv"; if (Parameters.SearchParameters.DoLabelFreeQuantification) { - fileName = "AllQuantifiedProteinGroups.tsv"; + fileName = $"AllQuantified{GlobalVariables.AnalyteType.GetBioPolymerLabel()}Groups.tsv"; } //set peptide output values @@ -909,10 +909,10 @@ private void WriteProteinResults() { // write summary text string proteinResultsText = strippedFileName + " - Target protein groups within 1 % FDR: " + subsetProteinGroupsForThisFile.Count(b => b.QValue <= 0.01 && !b.IsDecoy); - ResultsDictionary[(strippedFileName, "Proteins")] = proteinResultsText; + ResultsDictionary[(strippedFileName, $"{GlobalVariables.AnalyteType.GetBioPolymerLabel()}s")] = proteinResultsText; // write result files - writtenFile = Path.Combine(Parameters.IndividualResultsOutputFolder, strippedFileName + "_ProteinGroups.tsv"); + writtenFile = Path.Combine(Parameters.IndividualResultsOutputFolder, strippedFileName + $"_{GlobalVariables.AnalyteType.GetBioPolymerLabel()}Groups.tsv"); WriteProteinGroupsToTsv(subsetProteinGroupsForThisFile, writtenFile, new List { Parameters.SearchTaskId, "Individual Spectra Files", fullFilePath }); } @@ -1790,7 +1790,7 @@ private static void WritePsmsForPercolator(List psmList, string w string header = "SpecId\tLabel\tScanNr\t"; header += String.Join("\t", PsmData.trainingInfos[searchType]); - header += "\tPeptide\tProteins"; + header += $"\t{GlobalVariables.AnalyteType.GetUniqueFormLabel()}s\t{GlobalVariables.AnalyteType.GetBioPolymerLabel()}s"; output.WriteLine(header); @@ -1860,8 +1860,8 @@ private void ConstructResultsDictionary() { ResultsDictionary = new() { - { ("All", "PSMs"), "" }, - { ("All", GlobalVariables.AnalyteType), "" } + { ("All", $"{GlobalVariables.AnalyteType.GetSpectralMatchLabel()}s"), "" }, + { ("All", GlobalVariables.AnalyteType.GetUniqueFormLabel()), "" } }; if (Parameters.CurrentRawFileList.Count > 1 && Parameters.SearchParameters.WriteIndividualFiles) @@ -1869,20 +1869,20 @@ private void ConstructResultsDictionary() foreach (var rawFile in Parameters.CurrentRawFileList) { string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(rawFile); - ResultsDictionary.Add((fileNameWithoutExtension, "PSMs"), ""); - ResultsDictionary.Add((fileNameWithoutExtension, GlobalVariables.AnalyteType), ""); + ResultsDictionary.Add((fileNameWithoutExtension, $"{GlobalVariables.AnalyteType.GetSpectralMatchLabel()}s"), ""); + ResultsDictionary.Add((fileNameWithoutExtension, GlobalVariables.AnalyteType.GetUniqueFormLabel()), ""); } } if (Parameters.SearchParameters.DoParsimony) { - ResultsDictionary.Add(("All", "Proteins"), ""); + ResultsDictionary.Add(("All", $"{GlobalVariables.AnalyteType.GetBioPolymerLabel()}s"), ""); if (Parameters.CurrentRawFileList.Count > 1 && Parameters.SearchParameters.WriteIndividualFiles) { foreach (var rawFile in Parameters.CurrentRawFileList) { string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(rawFile); - ResultsDictionary.Add((fileNameWithoutExtension, "Proteins"), ""); + ResultsDictionary.Add((fileNameWithoutExtension, $"{GlobalVariables.AnalyteType.GetBioPolymerLabel()}s"), ""); } } } diff --git a/MetaMorpheus/TaskLayer/TaskLayer.csproj b/MetaMorpheus/TaskLayer/TaskLayer.csproj index 8a7446de9..0cf7bb570 100644 --- a/MetaMorpheus/TaskLayer/TaskLayer.csproj +++ b/MetaMorpheus/TaskLayer/TaskLayer.csproj @@ -21,7 +21,7 @@ - + diff --git a/MetaMorpheus/Test/AveragingTests.cs b/MetaMorpheus/Test/AveragingTests.cs index 64a567b98..948849f05 100644 --- a/MetaMorpheus/Test/AveragingTests.cs +++ b/MetaMorpheus/Test/AveragingTests.cs @@ -7,6 +7,7 @@ using FlashLFQ; using MassSpectrometry; using NUnit.Framework; +using NUnit.Framework.Legacy; using SpectralAveraging; using TaskLayer; using Mzml = IO.MzML.Mzml; @@ -160,7 +161,17 @@ public static void TestAveragingDdaScans() Assert.That(originalMs1Scans.Count == averagedMs1Scans.Count); for (var i = 0; i < averagedMs2Scans.Count; i++) { - Assert.That(originalMs2Scans[i].MassSpectrum.Equals(averagedMs2Scans[i].MassSpectrum)); + CollectionAssert.AreEqual(originalMs2Scans[i].MassSpectrum.YArray, averagedMs2Scans[i].MassSpectrum.YArray); + + var originalX = originalMs2Scans[i].MassSpectrum.XArray; + var averagedX = averagedMs2Scans[i].MassSpectrum.XArray; + Assert.That(originalX.Length, Is.EqualTo(averagedX.Length)); + + // check that the x values are the same within mzLib writer rounding toleranceS + for (var j = 0; j < originalX.Length; j++) + { + Assert.That(originalX[j], Is.EqualTo(averagedX[j]).Within(0.0001)); + } } Directory.Delete(testPath, true); diff --git a/MetaMorpheus/Test/GlobalVariablesTest.cs b/MetaMorpheus/Test/GlobalVariablesTest.cs index 88bf0f1fb..4ad665468 100644 --- a/MetaMorpheus/Test/GlobalVariablesTest.cs +++ b/MetaMorpheus/Test/GlobalVariablesTest.cs @@ -79,5 +79,40 @@ public static void TestCustomFileExtensionGetter() Assert.That(GlobalVariables.GetFileExtension(test7, getUncompressedExtension: true) == ".fasta"); Assert.That(GlobalVariables.GetFilenameWithoutExtension(test7) == "my.Fi.le"); } + + [Test] + public static void TestGetSpectralMatchLabel() + { + Assert.That(AnalyteType.Peptide.GetSpectralMatchLabel(), Is.EqualTo("PSM")); + Assert.That(AnalyteType.Proteoform.GetSpectralMatchLabel(), Is.EqualTo("PSM")); + Assert.That(AnalyteType.Oligo.GetSpectralMatchLabel(), Is.EqualTo("OSM")); + } + + [Test] + public static void TestGetSpectralMatchExtension() + { + Assert.That(AnalyteType.Peptide.GetSpectralMatchExtension(), Is.EqualTo("psmtsv")); + Assert.That(AnalyteType.Proteoform.GetSpectralMatchExtension(), Is.EqualTo("psmtsv")); + Assert.That(AnalyteType.Oligo.GetSpectralMatchExtension(), Is.EqualTo("osmtsv")); + } + + [Test] + public static void TestGetUniqueFormLabel() + { + Assert.That(AnalyteType.Peptide.GetUniqueFormLabel(), Is.EqualTo("Peptide")); + Assert.That(AnalyteType.Peptide.ToString(), Is.EqualTo("Peptide")); + Assert.That(AnalyteType.Proteoform.GetUniqueFormLabel(), Is.EqualTo("Proteoform")); + Assert.That(AnalyteType.Proteoform.ToString(), Is.EqualTo("Proteoform")); + Assert.That(AnalyteType.Oligo.GetUniqueFormLabel(), Is.EqualTo("Oligo")); + Assert.That(AnalyteType.Oligo.ToString(), Is.EqualTo("Oligo")); + } + + [Test] + public static void TestGetBioPolymerLabel() + { + Assert.That(AnalyteType.Peptide.GetBioPolymerLabel(), Is.EqualTo("Protein")); + Assert.That(AnalyteType.Proteoform.GetBioPolymerLabel(), Is.EqualTo("Protein")); + Assert.That(AnalyteType.Oligo.GetBioPolymerLabel(), Is.EqualTo("Transcript")); + } } } diff --git a/MetaMorpheus/Test/GuiTests/ClassicDeconParamsViewModelTest.cs b/MetaMorpheus/Test/GuiTests/ClassicDeconParamsViewModelTest.cs new file mode 100644 index 000000000..4d8a6c112 --- /dev/null +++ b/MetaMorpheus/Test/GuiTests/ClassicDeconParamsViewModelTest.cs @@ -0,0 +1,43 @@ +using GuiFunctions; +using MassSpectrometry; +using NUnit.Framework; + +namespace Test.GuiTests; + +[TestFixture] +public class ClassicDeconParamsViewModelTest +{ + private ClassicDeconParamsViewModel _viewModel; + private ClassicDeconvolutionParameters _parameters; + + [SetUp] + public void SetUp() + { + _parameters = new ClassicDeconvolutionParameters(1, 12, 10, 0.5); + _viewModel = new ClassicDeconParamsViewModel(_parameters); + } + + [Test] + public void TestDeconvolutionTolerancePpm() + { + Assert.That(_viewModel.DeconvolutionTolerancePpm, Is.EqualTo(10.0)); + _viewModel.DeconvolutionTolerancePpm = 20.0; + Assert.That(_viewModel.DeconvolutionTolerancePpm, Is.EqualTo(20.0)); + Assert.That(_parameters.DeconvolutionTolerancePpm, Is.EqualTo(20.0)); + } + + [Test] + public void TestIntensityRatioLimit() + { + Assert.That(_viewModel.IntensityRatioLimit, Is.EqualTo(0.5)); + _viewModel.IntensityRatioLimit = 1.0; + Assert.That(_viewModel.IntensityRatioLimit, Is.EqualTo(1.0)); + Assert.That(_parameters.IntensityRatioLimit, Is.EqualTo(1.0)); + } + + [Test] + public void TestToString() + { + Assert.That(_viewModel.ToString(), Is.EqualTo("Classic")); + } +} \ No newline at end of file diff --git a/MetaMorpheus/Test/GuiTests/DeconHostViewModelTest.cs b/MetaMorpheus/Test/GuiTests/DeconHostViewModelTest.cs new file mode 100644 index 000000000..abb4c905c --- /dev/null +++ b/MetaMorpheus/Test/GuiTests/DeconHostViewModelTest.cs @@ -0,0 +1,224 @@ +using System; +using System.Linq; +using EngineLayer; +using GuiFunctions; +using MassSpectrometry; +using NUnit.Framework; + +namespace Test.GuiTests; + +[TestFixture] +public class DeconHostViewModelTests +{ + internal ClassicDeconvolutionParameters ClassicPrecursorDeconvolutionParameters = new ClassicDeconvolutionParameters(1, 12, 4, 3); + internal ClassicDeconvolutionParameters ClassicProductDeconvolutionParameters = new ClassicDeconvolutionParameters(1, 10, 4, 3); + + [Test] + public void Constructor_DefaultParameters_ShouldInitializeCorrectly() + { + // Arrange + var initialPrecursorParameters = ClassicPrecursorDeconvolutionParameters; + var initialProductParameters = ClassicProductDeconvolutionParameters; + + // Act + var viewModel = new DeconHostViewModel(initialPrecursorParameters, initialProductParameters); + + // Assert + Assert.That(viewModel.UseProvidedPrecursors, Is.False); + Assert.That(viewModel.DoPrecursorDeconvolution, Is.True); + Assert.That(viewModel.PrecursorDeconvolutionParametersList, Is.Not.Null); + Assert.That(viewModel.ProductDeconvolutionParametersList, Is.Not.Null); + Assert.That(viewModel.PrecursorDeconvolutionParametersList.Any(), Is.True); + Assert.That(viewModel.ProductDeconvolutionParametersList.Any(), Is.True); + } + + [Test] + public void Constructor_WithProvidedParameters_ShouldSetCorrectly() + { + // Arrange + var initialPrecursorParameters = ClassicPrecursorDeconvolutionParameters; + var initialProductParameters = ClassicProductDeconvolutionParameters; + + // Act + var viewModel = new DeconHostViewModel(initialPrecursorParameters, initialProductParameters, true, false); + + // Assert + Assert.That(viewModel.UseProvidedPrecursors, Is.True); + Assert.That(viewModel.DoPrecursorDeconvolution, Is.False); + Assert.That(viewModel.PrecursorDeconvolutionParameters, Is.EqualTo(initialPrecursorParameters.ToViewModel())); + Assert.That(viewModel.ProductDeconvolutionParameters, Is.EqualTo(initialProductParameters.ToViewModel())); + } + + [Test] + public void TestDeconHostViewModel_DefaultParameters() + { + // Arrange + DeconHostViewModel viewModel = new DeconHostViewModel(null, null); + + // Act + var precursorParams = viewModel.PrecursorDeconvolutionParameters; + var productParams = viewModel.ProductDeconvolutionParameters; + + // Assert + Assert.That(precursorParams, Is.Not.Null); + Assert.That(productParams, Is.Not.Null); + Assert.That(precursorParams.DeconvolutionType, Is.EqualTo(DeconvolutionType.ClassicDeconvolution)); + Assert.That(productParams.DeconvolutionType, Is.EqualTo(DeconvolutionType.ClassicDeconvolution)); + } + + [Test] + public void PrecursorDeconvolutionParameters_Setter_ShouldTriggerPropertyChanged() + { + // Arrange + var viewModel = new DeconHostViewModel(); + var newParameters = new ClassicDeconParamsViewModel(ClassicPrecursorDeconvolutionParameters); + bool propertyChangedTriggered = false; + viewModel.PropertyChanged += (sender, args) => + { + if (args.PropertyName == nameof(viewModel.PrecursorDeconvolutionParameters)) + propertyChangedTriggered = true; + }; + + // Act + viewModel.PrecursorDeconvolutionParameters = newParameters; + + // Assert + Assert.That(propertyChangedTriggered, Is.True); + } + + [Test] + public void ProductDeconvolutionParameters_Setter_ShouldTriggerPropertyChanged() + { + // Arrange + var viewModel = new DeconHostViewModel(); + var newParameters = new ClassicDeconParamsViewModel(ClassicProductDeconvolutionParameters); + bool propertyChangedTriggered = false; + viewModel.PropertyChanged += (sender, args) => + { + if (args.PropertyName == nameof(viewModel.ProductDeconvolutionParameters)) + propertyChangedTriggered = true; + }; + + // Act + viewModel.ProductDeconvolutionParameters = newParameters; + + // Assert + Assert.That(propertyChangedTriggered, Is.True); + } + + + [Test] + [NonParallelizable] + public void TestDeconHostViewModel_GlobalVariables_Proteoform() + { + // Arrange + GlobalVariables.AnalyteType = AnalyteType.Proteoform; + DeconHostViewModel viewModel = new DeconHostViewModel(null, null); + + // Act + var precursorParams = viewModel.PrecursorDeconvolutionParameters; + var productParams = viewModel.ProductDeconvolutionParameters; + + // Assert + Assert.That(precursorParams, Is.Not.Null); + Assert.That(productParams, Is.Not.Null); + Assert.That(precursorParams.DeconvolutionType, Is.EqualTo(DeconvolutionType.ClassicDeconvolution)); + Assert.That(productParams.DeconvolutionType, Is.EqualTo(DeconvolutionType.ClassicDeconvolution)); + Assert.That(precursorParams.Parameters, Is.InstanceOf()); + Assert.That(productParams.Parameters, Is.InstanceOf()); + Assert.That(((ClassicDeconvolutionParameters)precursorParams.Parameters).MaxAssumedChargeState, Is.EqualTo(60)); + Assert.That(((ClassicDeconvolutionParameters)productParams.Parameters).MaxAssumedChargeState, Is.EqualTo(10)); + + // Revert back to default + GlobalVariables.AnalyteType = AnalyteType.Peptide; + } + + [Test] + [NonParallelizable] + public void TestDeconHostViewModel_GlobalVariables_Oligo() + { + // Arrange + GlobalVariables.AnalyteType = AnalyteType.Oligo; + DeconHostViewModel viewModel = new DeconHostViewModel(null, null); + + // Act + var precursorParams = viewModel.PrecursorDeconvolutionParameters; + var productParams = viewModel.ProductDeconvolutionParameters; + + // Assert + Assert.That(precursorParams, Is.Not.Null); + Assert.That(productParams, Is.Not.Null); + Assert.That(precursorParams.DeconvolutionType, Is.EqualTo(DeconvolutionType.ClassicDeconvolution)); + Assert.That(productParams.DeconvolutionType, Is.EqualTo(DeconvolutionType.ClassicDeconvolution)); + Assert.That(precursorParams.Parameters, Is.InstanceOf()); + Assert.That(productParams.Parameters, Is.InstanceOf()); + Assert.That(((ClassicDeconvolutionParameters)precursorParams.Parameters).MinAssumedChargeState, Is.EqualTo(-20)); + Assert.That(((ClassicDeconvolutionParameters)productParams.Parameters).MinAssumedChargeState, Is.EqualTo(-10)); + + // Revert back to default + GlobalVariables.AnalyteType = AnalyteType.Peptide; + } + + [Test] + [NonParallelizable] + public void TestDeconHostViewModel_GlobalVariables_Unknown() + { + // Arrange + GlobalVariables.AnalyteType = (AnalyteType)(-1); + + // Act & Assert + Assert.Throws(() => + { + var deconHostViewModel = new DeconHostViewModel(null, null); + }); + + Assert.Throws(() => + { + var deconHostViewModel = new DeconHostViewModel(ClassicPrecursorDeconvolutionParameters, null); + }); + + // Revert back to default + GlobalVariables.AnalyteType = AnalyteType.Peptide; + } + + [Test] + public void TestDisplayDeconSelectionComboBox_MultipleOptions_Precursor() + { + // Arrange + var viewModel = new DeconHostViewModel(); + viewModel.PrecursorDeconvolutionParametersList.Add(ClassicPrecursorDeconvolutionParameters.ToViewModel()); + + // Act + var result = viewModel.DisplayDeconSelectionComboBox; + + // Assert + Assert.That(result, Is.True); + } + + [Test] + public void TestDisplayDeconSelectionComboBox_MultipleOptions_Product() + { + // Arrange + var viewModel = new DeconHostViewModel(); + viewModel.ProductDeconvolutionParametersList.Add(ClassicProductDeconvolutionParameters.ToViewModel()); + + // Act + var result = viewModel.DisplayDeconSelectionComboBox; + + // Assert + Assert.That(result, Is.True); + } + + [Test] + public void TestDisplayDeconSelectionComboBox_SingleOption() + { + // Arrange + var viewModel = new DeconHostViewModel(); + + // Act + var result = viewModel.DisplayDeconSelectionComboBox; + + // Assert + Assert.That(result, Is.False); + } +} \ No newline at end of file diff --git a/MetaMorpheus/Test/GuiTests/DeconParamsViewModelTest.cs b/MetaMorpheus/Test/GuiTests/DeconParamsViewModelTest.cs new file mode 100644 index 000000000..1093d9d1e --- /dev/null +++ b/MetaMorpheus/Test/GuiTests/DeconParamsViewModelTest.cs @@ -0,0 +1,267 @@ +using GuiFunctions; +using MassSpectrometry; +using NUnit.Framework; + +namespace Test.GuiTests; + +[TestFixture] +public class DeconParamsViewModelTest +{ + private class TestDeconParamsViewModel : DeconParamsViewModel + { + public sealed override DeconvolutionParameters Parameters { get; protected set; } + + public TestDeconParamsViewModel(DeconvolutionParameters parameters) + { + Parameters = parameters; + } + } + + private DeconvolutionParameters _negativeModeParameters; + private TestDeconParamsViewModel _negativeModeViewModel; + private DeconvolutionParameters _positiveModeParameters; + private TestDeconParamsViewModel _positiveModeViewModel; + + [SetUp] + public void SetUp() + { + _negativeModeParameters = new ClassicDeconvolutionParameters(-20, -2, 5, 3, Polarity.Negative); + _negativeModeViewModel = new TestDeconParamsViewModel(_negativeModeParameters); + + _positiveModeParameters = new ClassicDeconvolutionParameters(2, 20, 5, 3, Polarity.Positive); + _positiveModeViewModel = new TestDeconParamsViewModel(_positiveModeParameters); + } + + [TestCase(0, false, TestName = "MinAssumedChargeState_SetToZero_DoesNotChange")] + [TestCase(-1, false, TestName = "MinAssumedChargeState_SetToNegativeInPositiveMode_DoesNotChange")] + [TestCase(21, false, TestName = "MinAssumedChargeState_SetAboveMaxInPositiveMode_DoesNotChange")] + [TestCase(3, true, TestName = "MinAssumedChargeState_SetToValidPositiveValue_Changes")] + public void TestMinAssumedChargeState_PositiveMode(int newValue, bool shouldChange) + { + _positiveModeViewModel.MinAssumedChargeState = newValue; + if (shouldChange) + { + Assert.That(_positiveModeViewModel.MinAssumedChargeState, Is.EqualTo(newValue)); + } + else + { + Assert.That(_positiveModeViewModel.MinAssumedChargeState, Is.EqualTo(2)); + } + } + + [TestCase(0, false, TestName = "MaxAssumedChargeState_SetToZero_DoesNotChange")] + [TestCase(-4, false, TestName = "MaxAssumedChargeState_SetToNegativeInPositiveMode_DoesNotChange")] + [TestCase(1, false, TestName = "MaxAssumedChargeState_SetBelowMinInPositiveMode_DoesNotChange")] + [TestCase(25, true, TestName = "MaxAssumedChargeState_SetToValidPositiveValue_Changes")] + public void TestMaxAssumedChargeState_PositiveMode(int newValue, bool shouldChange) + { + _positiveModeViewModel.MaxAssumedChargeState = newValue; + if (shouldChange) + { + Assert.That(_positiveModeViewModel.MaxAssumedChargeState, Is.EqualTo(newValue)); + } + else + { + Assert.That(_positiveModeViewModel.MaxAssumedChargeState, Is.EqualTo(20)); + } + } + + [TestCase(0, false, TestName = "MinAssumedChargeState_SetToZero_DoesNotChange")] + [TestCase(1, false, TestName = "MinAssumedChargeState_SetToPositiveInNegativeMode_DoesNotChange")] + [TestCase(-1, false, TestName = "MinAssumedChargeState_SetAboveMaxInNegativeMode_DoesNotChange")] + [TestCase(-21, true, TestName = "MinAssumedChargeState_SetToValidNegativeValue_Changes")] + public void TestMinAssumedChargeState_NegativeMode(int newValue, bool shouldChange) + { + _negativeModeViewModel.MinAssumedChargeState = newValue; + if (shouldChange) + { + Assert.That(_negativeModeViewModel.MinAssumedChargeState, Is.EqualTo(newValue)); + } + else + { + Assert.That(_negativeModeViewModel.MinAssumedChargeState, Is.EqualTo(-20)); + } + } + + [TestCase(0, false, TestName = "MaxAssumedChargeState_SetToZero_DoesNotChange")] + [TestCase(1, false, TestName = "MaxAssumedChargeState_SetToPositiveInNegativeMode_DoesNotChange")] + [TestCase(-21, false, TestName = "MaxAssumedChargeState_SetBelowMinInNegativeMode_DoesNotChange")] + [TestCase(-1, true, TestName = "MaxAssumedChargeState_SetToValidNegativeValue_Changes")] + public void TestMaxAssumedChargeState_NegativeMode(int newValue, bool shouldChange) + { + _negativeModeViewModel.MaxAssumedChargeState = newValue; + if (shouldChange) + { + Assert.That(_negativeModeViewModel.MaxAssumedChargeState, Is.EqualTo(newValue)); + } + else + { + Assert.That(_negativeModeViewModel.MaxAssumedChargeState, Is.EqualTo(-2)); + } + } + + [TestCase(Polarity.Positive, Polarity.Positive, 5, 12, TestName = "Polarity_SwitchFromPositiveToPositive_NoChange")] + [TestCase(Polarity.Negative, Polarity.Negative, -25, -5, TestName = "Polarity_SwitchFromNegativeToNegative_NoChange")] + [TestCase(Polarity.Positive, Polarity.Negative, -20, -1, TestName = "Polarity_SwitchFromPositiveToNegative_UpdatesChargeStates")] + [TestCase(Polarity.Negative, Polarity.Positive, 1, 12, TestName = "Polarity_SwitchFromNegativeToPositive_UpdatesChargeStates")] + public void TestPolaritySwitch(Polarity initialPolarity, Polarity newPolarity, int expectedMinChargeState, int expectedMaxChargeState) + { + var parameters = new ClassicDeconvolutionParameters(initialPolarity == Polarity.Positive ? 5 : -25, initialPolarity == Polarity.Positive ? 12 : -5, 5, 3, initialPolarity); + var viewModel = new TestDeconParamsViewModel(parameters); + + viewModel.Polarity = newPolarity; + + Assert.That(viewModel.Polarity, Is.EqualTo(newPolarity)); + Assert.That(viewModel.MinAssumedChargeState, Is.EqualTo(expectedMinChargeState)); + Assert.That(viewModel.MaxAssumedChargeState, Is.EqualTo(expectedMaxChargeState)); + } + + [Test] + public void TestPolaritySwitchWithPreviousValues_PositiveMode() + { + // Initial setup with positive polarity + var parameters = new ClassicDeconvolutionParameters(1, 12, 5, 3, Polarity.Positive); + var viewModel = new TestDeconParamsViewModel(parameters); + + // Set previous values + viewModel.MinAssumedChargeState = 5; + viewModel.MaxAssumedChargeState = 10; + + // Change to negative polarity + viewModel.Polarity = Polarity.Negative; + + // Check that defaults got set properly + Assert.That(viewModel.MinAssumedChargeState, Is.EqualTo(-20)); + Assert.That(viewModel.MaxAssumedChargeState, Is.EqualTo(-1)); + + // Change back to positive polarity + viewModel.Polarity = Polarity.Positive; + + // Assert that previous values are restored correctly + Assert.That(viewModel.MinAssumedChargeState, Is.EqualTo(5)); + Assert.That(viewModel.MaxAssumedChargeState, Is.EqualTo(10)); + } + + [Test] + public void TestPolaritySwitchWithPreviousValues_NegativeMode() + { + // Initial setup with negative polarity + var parameters = new ClassicDeconvolutionParameters(-20, -1, 5, 3, Polarity.Negative); + var viewModel = new TestDeconParamsViewModel(parameters); + + // Set previous values + viewModel.MinAssumedChargeState = -10; + viewModel.MaxAssumedChargeState = -5; + + // Change to positive polarity + viewModel.Polarity = Polarity.Positive; + + // Check that defaults got set properly + Assert.That(viewModel.MinAssumedChargeState, Is.EqualTo(1)); + Assert.That(viewModel.MaxAssumedChargeState, Is.EqualTo(12)); + + // Change back to negative polarity + viewModel.Polarity = Polarity.Negative; + + // Assert that previous values are restored correctly + Assert.That(viewModel.MinAssumedChargeState, Is.EqualTo(-10)); + Assert.That(viewModel.MaxAssumedChargeState, Is.EqualTo(-5)); + } + + [Test] + public void TestToString() + { + var parameters = new ClassicDeconvolutionParameters(1, 12, 5, 3, Polarity.Positive); + var viewModel = new TestDeconParamsViewModel(parameters); + Assert.That(viewModel.ToString(), Is.EqualTo(parameters.DeconvolutionType.ToString())); + } + + [Test] + public void TestEquals_SameObject() + { + var parameters = new ClassicDeconvolutionParameters(1, 12, 5, 3, Polarity.Positive); + var viewModel = new TestDeconParamsViewModel(parameters); + Assert.That(viewModel.Equals(viewModel), Is.True); + Assert.That(viewModel.Equals((object)viewModel), Is.True); + } + + [Test] + public void TestEquals_NullObject() + { + var parameters = new ClassicDeconvolutionParameters(1, 12, 5, 3, Polarity.Positive); + var viewModel = new TestDeconParamsViewModel(parameters); + Assert.That(viewModel.Equals(null), Is.False); + Assert.That(viewModel.Equals((object)null), Is.False); + } + + [Test] + public void TestEquals_DifferentType() + { + var parameters = new ClassicDeconvolutionParameters(1, 12, 5, 3, Polarity.Positive); + var viewModel = new TestDeconParamsViewModel(parameters); + Assert.That(viewModel.Equals(new object()), Is.False); + Assert.That(viewModel.Equals((object)new BaseViewModel()), Is.False); + } + + [Test] + [TestCase(1, 15, Polarity.Negative, TestName = "MinChargeDiffers_NotEqual")] + [TestCase(2, 12, Polarity.Negative, TestName = "MaxChargeDiffers_NotEqual")] + [TestCase(2, 15, Polarity.Positive, TestName = "PolarityDiffers_NotEqual")] + public void TestEquals_DifferentParameters(int minCharge, int maxCharge, Polarity polarity) + { + var parameters1 = new ClassicDeconvolutionParameters(minCharge, maxCharge, 5, 3, polarity); + var viewModel1 = new TestDeconParamsViewModel(parameters1); + + var parameters2 = new ClassicDeconvolutionParameters(2, 15, 5, 3, Polarity.Negative); + var viewModel2 = new TestDeconParamsViewModel(parameters2); + Assert.That(viewModel1.Equals(viewModel2), Is.False); + Assert.That(viewModel1.Equals(null), Is.False); + } + + [Test] + [TestCase(1, 15, Polarity.Negative, TestName = "MinChargeDiffers_NotEqual")] + [TestCase(2, 12, Polarity.Negative, TestName = "MaxChargeDiffers_NotEqual")] + [TestCase(2, 15, Polarity.Positive, TestName = "PolarityDiffers_NotEqual")] + public void TestEquals_DifferentParameters_obj(int minCharge, int maxCharge, Polarity polarity) + { + var parameters1 = new ClassicDeconvolutionParameters(minCharge, maxCharge, 5, 3, polarity); + var viewModel1 = new TestDeconParamsViewModel(parameters1); + + var parameters2 = new ClassicDeconvolutionParameters(2, 15, 5, 3, Polarity.Negative); + var viewModel2 = new TestDeconParamsViewModel(parameters2); + Assert.That(viewModel1.Equals((object)viewModel2), Is.False); + Assert.That(viewModel1.Equals((object)null), Is.False); + } + + [Test] + public void TestEquals_SameParameters() + { + var parameters1 = new ClassicDeconvolutionParameters(1, 12, 5, 3, Polarity.Positive); + var viewModel1 = new TestDeconParamsViewModel(parameters1); + var parameters2 = new ClassicDeconvolutionParameters(1, 12, 5, 3, Polarity.Positive); + var viewModel2 = new TestDeconParamsViewModel(parameters2); + Assert.That(viewModel1.Equals(viewModel2), Is.True); + } + + [Test] + public void TestEquals_SameParameters_Obj() + { + var parameters1 = new ClassicDeconvolutionParameters(1, 12, 5, 3, Polarity.Positive); + var viewModel1 = new TestDeconParamsViewModel(parameters1); + var parameters2 = new ClassicDeconvolutionParameters(1, 12, 5, 3, Polarity.Positive); + var viewModel2 = new TestDeconParamsViewModel(parameters2); + Assert.That(viewModel1.Equals((object)viewModel2), Is.True); + } + + [Test] + public void TestGetHashCode() + { + var parameters = new ClassicDeconvolutionParameters(1, 12, 5, 3, Polarity.Positive); + var viewModel = new TestDeconParamsViewModel(parameters); + var expectedHashCode = parameters.DeconvolutionType.GetHashCode() + parameters.Polarity.GetHashCode() + parameters.MaxAssumedChargeState.GetHashCode(); + Assert.That(viewModel.GetHashCode(), Is.EqualTo(expectedHashCode)); + + viewModel = new TestDeconParamsViewModel(null); + Assert.That(viewModel.GetHashCode(), Is.EqualTo(0)); + } +} \ No newline at end of file diff --git a/MetaMorpheus/Test/GuiFunctionsTest.cs b/MetaMorpheus/Test/GuiTests/GuiFunctionsTest.cs similarity index 94% rename from MetaMorpheus/Test/GuiFunctionsTest.cs rename to MetaMorpheus/Test/GuiTests/GuiFunctionsTest.cs index 5bc8f7687..1ee503eb8 100644 --- a/MetaMorpheus/Test/GuiFunctionsTest.cs +++ b/MetaMorpheus/Test/GuiTests/GuiFunctionsTest.cs @@ -8,7 +8,7 @@ using System.Threading.Tasks; using UsefulProteomicsDatabases; -namespace Test +namespace Test.GuiTests { [TestFixture] public static class GuiFunctionsTest @@ -28,7 +28,7 @@ public static class GuiFunctionsTest [TestCase("UP000000625", false, false, false, false, "\\UP000000625_withUnreviewed.fasta")] public static void TestGetUniprotFilename(string proteomeID, bool reviewed, bool isoforms, bool xmlFormat, bool compressed, string expectedResult) { - if(expectedResult.Equals("\\UP000000625_reviewed.xml.gz") && isoforms) // This should only be written once, during the first test case + if (expectedResult.Equals("\\UP000000625_reviewed.xml.gz") && isoforms) // This should only be written once, during the first test case { Console.WriteLine("Beginning Uniprot database test."); } @@ -101,12 +101,12 @@ public static async Task UniprotHtmlQueryTest(string proteomeID, bool reviewed, File.Delete(filePath); - if(testName.Equals("11.fasta")) // only triggers for last test cases + if (testName.Equals("11.fasta")) // only triggers for last test cases { Console.WriteLine("Finished with Uniprot HTML query test."); } - Assert.That(reader.Count == listCount); + NUnit.Framework.Assert.That(reader.Count == listCount); } } } \ No newline at end of file diff --git a/MetaMorpheus/Test/GuiTests/MzLibExtensionsTests.cs b/MetaMorpheus/Test/GuiTests/MzLibExtensionsTests.cs new file mode 100644 index 000000000..6d063bbba --- /dev/null +++ b/MetaMorpheus/Test/GuiTests/MzLibExtensionsTests.cs @@ -0,0 +1,34 @@ +using System; +using GuiFunctions; +using MassSpectrometry; +using NUnit.Framework; +using Assert = NUnit.Framework.Assert; + +namespace Test.GuiTests; + +[TestFixture] +public class MzLibExtensionsTests +{ + [Test] + public void ToViewModel_WithClassicDeconvolutionParameters_ReturnsClassicDeconParamsViewModel() + { + // Arrange + var classicParams = new ClassicDeconvolutionParameters(1, 12, 10, 1); + + // Act + var result = classicParams.ToViewModel(); + + // Assert + Assert.That(result, Is.InstanceOf()); + } + + [Test] + public void ToViewModel_WithUnsupportedParameters_ThrowsNotImplementedException() + { + // Arrange + var unsupportedParams = new ExampleNewDeconvolutionParametersTemplate(1, 20); + + // Act & Assert + Assert.That(() => unsupportedParams.ToViewModel(), Throws.TypeOf()); + } +} \ No newline at end of file diff --git a/MetaMorpheus/Test/MatchIonsOfAllCharges.cs b/MetaMorpheus/Test/MatchIonsOfAllCharges.cs index 49de53381..7388b3d02 100644 --- a/MetaMorpheus/Test/MatchIonsOfAllCharges.cs +++ b/MetaMorpheus/Test/MatchIonsOfAllCharges.cs @@ -132,7 +132,7 @@ public static void TestMatchIonsOfAllChargesTopDown() MetaMorpheusTask.DetermineAnalyteType(CommonParameters); // test output file name (should be proteoform and not peptide) - Assert.That(GlobalVariables.AnalyteType == "Proteoform"); + Assert.That(GlobalVariables.AnalyteType.ToString() == "Proteoform"); var variableModifications = new List(); var fixedModifications = new List(); diff --git a/MetaMorpheus/Test/MetaDraw/MetaDrawSettingsAndViewsTest.cs b/MetaMorpheus/Test/MetaDraw/MetaDrawSettingsAndViewsTest.cs index 9e9bfbf6c..91d9ba161 100644 --- a/MetaMorpheus/Test/MetaDraw/MetaDrawSettingsAndViewsTest.cs +++ b/MetaMorpheus/Test/MetaDraw/MetaDrawSettingsAndViewsTest.cs @@ -595,9 +595,13 @@ public static void TestDrawnSequenceColorConversions() var colorBrushfromName = DrawnSequence.ParseColorBrushFromName(oxyBlue.GetColorName()); Assert.That(colorBrushfromName.Color == brushBlue.Color); + var colorBrushfromNameBad = DrawnSequence.ParseColorBrushFromName("humbug"); + Assert.That(colorBrushfromNameBad.Color == Colors.Aqua); var oxyFromName = DrawnSequence.ParseOxyColorFromName(oxyBlue.GetColorName()); Assert.That(oxyFromName == oxyBlue); + var oxyFromNameBad = DrawnSequence.ParseOxyColorFromName("gobbledygook"); + Assert.That(oxyFromNameBad == MetaDrawSettings.FallbackColor); var colorFromOxy = DrawnSequence.ParseColorFromOxyColor(oxyBlue); Assert.That(colorFromOxy == colorBlue); diff --git a/MetaMorpheus/Test/SearchEngineTests.cs b/MetaMorpheus/Test/SearchEngineTests.cs index abc83c43a..7f7446c9d 100644 --- a/MetaMorpheus/Test/SearchEngineTests.cs +++ b/MetaMorpheus/Test/SearchEngineTests.cs @@ -979,6 +979,29 @@ public static void TestNonSpecificEnzymeSearchEngineSingleN() Assert.That(allPsmsArray[0].BaseSequence, Is.EqualTo("QQQGGGG")); } + [Test] + public static void TestNonSpecificEnzymeSearchEngine() + { + var myTomlPath = Path.Combine(TestContext.CurrentContext.TestDirectory, @"TestData\NonSpecificSearchToml.toml"); + var searchTaskLoaded = Toml.ReadFile(myTomlPath, MetaMorpheusTask.tomlConfig); + string outputFolder = Path.Combine(TestContext.CurrentContext.TestDirectory, @"TestData\NonSpecificSearchTest"); + Directory.CreateDirectory(outputFolder); + string myFile = Path.Combine(TestContext.CurrentContext.TestDirectory, @"TestData\TaGe_SA_A549_3_snip.mzML"); + string myDatabase = Path.Combine(TestContext.CurrentContext.TestDirectory, @"TestData\bosTaurusEnamPruned.xml"); + + var engineToml = new EverythingRunnerEngine(new List<(string, MetaMorpheusTask)> { ("SearchTOML", searchTaskLoaded) }, new List { myFile }, new List { new DbForTask(myDatabase, false) }, outputFolder); + engineToml.Run(); + + string psmFile = Path.Combine(outputFolder, @"SearchTOML\AllPSMs.psmtsv"); + + List parsedPsms = PsmTsvReader.ReadTsv(psmFile, out var warnings); + + Assert.That(parsedPsms.Count, Is.EqualTo(38)); //total psm count + + Directory.Delete(outputFolder, true); + + } + [Test] public static void TestNonSpecificEnzymeSearchEngineSingleNLowCID() diff --git a/MetaMorpheus/Test/Test.csproj b/MetaMorpheus/Test/Test.csproj index 3c3e7e879..acf1fbba5 100644 --- a/MetaMorpheus/Test/Test.csproj +++ b/MetaMorpheus/Test/Test.csproj @@ -24,7 +24,7 @@ - + @@ -217,6 +217,9 @@ Always + + Always + Always @@ -325,6 +328,9 @@ Always + + Always + Always diff --git a/MetaMorpheus/Test/TestData/NonSpecificSearchToml.toml b/MetaMorpheus/Test/TestData/NonSpecificSearchToml.toml new file mode 100644 index 000000000..368d88329 --- /dev/null +++ b/MetaMorpheus/Test/TestData/NonSpecificSearchToml.toml @@ -0,0 +1,100 @@ +TaskType = "Search" + +[SearchParameters] +DisposeOfFileWhenDone = true +DoParsimony = true +ModPeptidesAreDifferent = false +NoOneHitWonders = false +MatchBetweenRuns = false +Normalize = false +QuantifyPpmTol = 5.0 +DoHistogramAnalysis = false +SearchTarget = true +DecoyType = "Reverse" +MassDiffAcceptorType = "OneMM" +WritePrunedDatabase = true +KeepAllUniprotMods = true +DoLocalizationAnalysis = false +DoLabelFreeQuantification = false +UseSharedPeptidesForLFQ = false +DoMultiplexQuantification = false +MultiplexModId = "TMT10" +DoSpectralRecovery = false +SearchType = "NonSpecific" +LocalFdrCategories = ["FullySpecific", "SemiSpecific", "NonSpecific"] +MaxFragmentSize = 10800.0 +MinAllowedInternalFragmentLength = 0 +HistogramBinTolInDaltons = 0.003 +MaximumMassThatFragmentIonScoreIsDoubled = 0.0 +WriteMzId = true +WritePepXml = false +WriteHighQValuePsms = true +WriteDecoys = true +WriteContaminants = true +WriteIndividualFiles = true +WriteSpectralLibrary = false +UpdateSpectralLibrary = false +CompressIndividualFiles = false +TCAmbiguity = "RemoveContaminant" +IncludeModMotifInMzid = false + +[SearchParameters.ModsToWriteSelection] +'N-linked glycosylation' = 3 +'O-linked glycosylation' = 3 +'Other glycosylation' = 3 +'Common Biological' = 3 +'Less Common' = 3 +Metal = 3 +'2+ nucleotide substitution' = 3 +'1 nucleotide substitution' = 3 +UniProt = 2 + +[CommonParameters] +TaskDescriptor = "SearchTask" +MaxThreadsToUsePerFile = 63 +ListOfModsFixed = "" +ListOfModsVariable = "Common Variable\tOxidation on M" +DoPrecursorDeconvolution = true +UseProvidedPrecursorInfo = true +DeconvolutionMaxAssumedChargeState = 12 +TotalPartitions = 1 +ProductMassTolerance = "±20.0000 PPM" +PrecursorMassTolerance = "±15.0000 PPM" +AddCompIons = true +QValueThreshold = 0.01 +PepQValueThreshold = 1.0 +ScoreCutoff = 5.0 +QValueCutoffForPepCalculation = 0.005 +ReportAllAmbiguity = true +NumberOfPeaksToKeepPerWindow = 200 +MinimumAllowedIntensityRatioToBasePeak = 0.01 +NormalizePeaksAccrossAllWindows = false +TrimMs1Peaks = false +TrimMsMsPeaks = true +CustomIons = [] +AssumeOrphanPeaksAreZ1Fragments = true +MaxHeterozygousVariants = 4 +MinVariantDepth = 1 +AddTruncations = false +DissociationType = "HCD" +SeparationType = "HPLC" +MS2ChildScanDissociationType = "Unknown" +MS3ChildScanDissociationType = "Unknown" +UseMostAbundantPrecursorIntensity = true + +[CommonParameters.DigestionParams] +InitiatorMethionineBehavior = "Variable" +MaxMissedCleavages = 35 +MaxModificationIsoforms = 1024 +SearchModeType = "None" +FragmentationTerminus = "C" +SpecificProtease = "singleC" +GeneratehUnlabeledProteinsForSilac = true +KeepNGlycopeptide = false +KeepOGlycopeptide = false +Protease = "singleC" +MinPeptideLength = 7 +MaxPeptideLength = 36 +MaxModsForPeptide = 2 + +[[FileSpecificParameters]] diff --git a/MetaMorpheus/Test/TestData/bosTaurusEnamPruned.xml b/MetaMorpheus/Test/TestData/bosTaurusEnamPruned.xml new file mode 100644 index 000000000..9a5508e6c --- /dev/null +++ b/MetaMorpheus/Test/TestData/bosTaurusEnamPruned.xml @@ -0,0 +1,5181 @@ + + + ID Acetylation on K +MT Common Biological +TG K +PP Anywhere. +CF C2H2O +MM 42.010564684 +DR Unimod; 1 +NL ETD:45.0204 +DI HCD:125.084063979 + +// + ID ADP-ribosylation on S +MT Common Biological +TG S +PP Anywhere. +CF C15H21N5O13P2 +MM 541.06110975 +DR Unimod; 213 + +// + ID Ammonia loss on N +MT Common Artifact +TG N +PP Anywhere. +CF H-3N-1 +MM -17.026549101 +DR Unimod; 385 + +// + ID Butyrylation on K +MT Common Biological +TG K +PP Anywhere. +CF C4H6O +MM 70.041864813 +DR Unimod; 1289 +DI HCD:153.115323533 + +// + ID Calcium on E +MT Metal +TG E +PP Anywhere. +CF H-2Ca +MM 37.946940799 +DR Unimod; 951 + +// + ID Carbamyl on K +MT Common Artifact +TG K +PP Anywhere. +CF CHNO +MM 43.005813656 +DR Unimod; 5 + +// + ID Carbamyl on M +MT Common Artifact +TG M +PP Anywhere. +CF CHNO +MM 43.005813656 +DR Unimod; 5 + +// + ID Carbamyl on R +MT Common Artifact +TG R +PP Anywhere. +CF CHNO +MM 43.005813656 +DR Unimod; 5 + +// + ID Carbamyl on X +MT Common Artifact +TG X +PP Peptide N-terminal. +CF CHNO +MM 43.005813656 +DR Unimod; 5 + +// + ID Carboxylation on D +MT Common Biological +TG D +PP Anywhere. +CF CO2 +MM 43.989829239 +DR Unimod; 299 + +// + ID Carboxylation on E +MT Common Biological +TG E +PP Anywhere. +CF CO2 +MM 43.989829239 +DR Unimod; 299 + +// + ID Carboxylation on K +MT Common Biological +TG K +PP Anywhere. +CF CO2 +MM 43.989829239 +DR Unimod; 299 + +// + ID Citrullination on R +MT Common Biological +TG R +PP Anywhere. +CF H-1N-1O +MM 0.984015583 +DR Unimod; 7 +NL HCD:43.0058 +DI HCD:129.090223533 + +// + ID Cu[I] on D +MT Metal +TG D +PP Anywhere. +CF H-1Cu +MM 61.921772688 +DR Unimod; 531 + +// + ID Cu[I] on E +MT Metal +TG E +PP Anywhere. +CF H-1Cu +MM 61.921772688 +DR Unimod; 531 + +// + ID Deamidation on N +MT Common Artifact +TG N +PP Anywhere. +CF H-1N-1O +MM 0.984015583 +DR Unimod; 7 + +// + ID Deamidation on Q +MT Common Artifact +TG Q +PP Anywhere. +CF H-1N-1O +MM 0.984015583 +DR Unimod; 7 + +// + ID Dimethylation on K +MT Common Biological +TG K +PP Anywhere. +CF C2H4 +MM 28.031300129 +DR Unimod; 36 + +// + ID Dimethylation on R +MT Common Biological +TG R +PP Anywhere. +CF C2H4 +MM 28.031300129 +DR Unimod; 36 +NL ETD:31.0422 or ETD:45.0579 + +// + ID Fe[II] on D +MT Metal +TG D +PP Anywhere. +CF H-2Fe +MM 53.919286266 +DR Unimod; 952 + +// + ID Fe[II] on E +MT Metal +TG E +PP Anywhere. +CF H-2Fe +MM 53.919286266 +DR Unimod; 952 + +// + ID Formylation on K +MT Common Biological +TG K +PP Anywhere. +CF CO +MM 27.99491462 +DR Unimod; 122 +DI HCD:111.068423533 + +// + ID Glutarylation on K +MT Common Biological +TG K +PP Anywhere. +CF C5H6O3 +MM 114.031694052 +DR Unimod; 1848 +NL ETD:115.0395 +DI HCD:181.110323533 + +// + ID HexNAc on Nxs +MT Common Biological +TG Nxs +PP Anywhere. +CF C8H13NO5 +MM 203.079372521 +DR Unimod; 43 +NL AnyActivationType:203.079372521 + +// + ID HexNAc on S +MT Common Biological +TG S +PP Anywhere. +CF C8H13NO5 +MM 203.079372521 +DR Unimod; 43 +NL AnyActivationType:203.079372521 + +// + ID HexNAc on T +MT Common Biological +TG T +PP Anywhere. +CF C8H13NO5 +MM 203.079372521 +DR Unimod; 43 +NL AnyActivationType:203.079372521 + +// + ID Hydroxybutyrylation on K +MT Common Biological +TG K +PP Anywhere. +CF C4H6O2 +MM 86.036779433 +DI HCD:169.110323533 + +// + ID Hydroxylation on K +MT Common Biological +TG K +PP Anywhere. +CF O +MM 15.99491462 +DR Unimod; 35 + +// + ID Hydroxylation on N +MT Common Biological +TG N +PP Anywhere. +CF O +MM 15.99491462 +DR Unimod; 35 + +// + ID Hydroxylation on P +MT Common Biological +TG P +PP Anywhere. +CF O +MM 15.99491462 +DR Unimod; 35 +DI HCD:170.069143 + +// + ID Magnesium on D +MT Metal +TG D +PP Anywhere. +CF H-2Mg +MM 21.969391633 +DR Unimod; 956 + +// + ID Magnesium on E +MT Metal +TG E +PP Anywhere. +CF H-2Mg +MM 21.969391633 +DR Unimod; 956 + +// + ID Malonylation on K +MT Common Biological +TG K +PP Anywhere. +CF C3H2O3 +MM 86.000393923 +DR Unimod; 747 +NL ETD:87.0082 +NL HCD:43.9898 +DI HCD:125.084063979 or HCD:169.073923533 + +// + ID Methylation on K +MT Common Biological +TG K +PP Anywhere. +CF CH2 +MM 14.015650064 +DR Unimod; 34 + +// + ID Methylation on R +MT Common Biological +TG R +PP Anywhere. +CF CH2 +MM 14.015650064 +DR Unimod; 34 + +// + ID Phosphorylation on S +MT Common Biological +TG S +PP Anywhere. +CF HO3P +MM 79.966330889 +DR Unimod; 21 +NL HCD:0 or HCD:97.976895573 + +// + ID Phosphorylation on T +MT Common Biological +TG T +PP Anywhere. +CF HO3P +MM 79.966330889 +DR Unimod; 21 +NL HCD:0 or HCD:97.976895573 + +// + ID Phosphorylation on Y +MT Common Biological +TG Y +PP Anywhere. +CF HO3P +MM 79.966330889 +DR Unimod; 21 +NL HCD:0 or HCD:97.976895573 +DI HCD:215.034744803 + +// + ID Potassium on E +MT Metal +TG E +PP Anywhere. +CF H-1K +MM 37.955881454 +DR Unimod; 530 + +// + ID Pyridoxal phosphate on K +MT Common Biological +TG K +PP Anywhere. +CF C8H8NO5P +MM 229.014009359 +DR Unimod; 46 + +// + ID Sodium on D +MT Metal +TG D +PP Anywhere. +CF H-1Na +MM 21.98194425 +DR Unimod; 30 + +// + ID Sodium on E +MT Metal +TG E +PP Anywhere. +CF H-1Na +MM 21.98194425 +DR Unimod; 30 + +// + ID Succinylation on K +MT Common Biological +TG K +PP Anywhere. +CF C4H4O3 +MM 100.016043988 +DR Unimod; 64 +NL ETD:101.0239 +DI HCD:183.089523533 + +// + ID Sulfonation on Y +MT Common Biological +TG Y +PP Anywhere. +CF O3S +MM 79.956815033 +DR Unimod; 40 +NL AnyActivationType:79.956815033 + +// + ID Trimethylation on K +MT Common Biological +TG K +PP Anywhere. +CF C3H6 +MM 42.046950193 +DR Unimod; 37 +NL ETD:45.0204 + +// + ID Water Loss on E +MT Common Artifact +TG E +PP Peptide N-terminal. +CF H-2O-1 +MM -18.010564684 +DR Unimod; 23 + +// + ID Zinc on D +MT Metal +TG D +PP Anywhere. +CF H-2Zn +MM 61.913491946 +DR Unimod; 954 + +// + ID Zinc on E +MT Metal +TG E +PP Anywhere. +CF H-2Zn +MM 61.913491946 +DR Unimod; 954 + +// + + Q9XSX7 + Ameloblastin + + + Ameloblastin + + + + AMBN + + + Bos taurus + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + MPALKIPLFKMKDMILILCLLKMSSAVPAFPQQPGIPGMASLSLETMRQLGSLQGLNLLSQYSRFGFGKSFNSLWMNGLLPPHSSFPWMRPREHETQQPSLQPQQPGQKPFLQPTVVTSMQNAVQKGVPQPPIYQGHPPLQQAEGPMVEQQVAPSEKPPTTELPGMDFADLQDPPMFPIAHLISRGPMPQNKPSQLYPGIFYVTYGANQLGGRGDPLAYGAIFPGFGGMRPRLGGMPHNPDMGGDFTLEFDSPVAATKGPEKGEGGAQDSPVPEAHLADPESPALLSELAPGALEGLLANPEGNIPNLARGPAGRSRGFLRGVTPAAADPLMTPGLAEVYETYGADETTTLGLQEETTVDSTATPDTQHTLMPRNKAQQPQIKHDAWHFQEP + + + P02817 + Amelogenin, X isoform + + + Amelogenin, X isoform + + + + AMELX + + + Bos taurus + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + MGTWILFACLLGAAFSMPLPPHPGHPGYINFSYEVLTPLKWYQSMIRHPYPSYGYEPMGGWLHHQIIPVVSQQTPQNHALQPHHHIPMVPAQQPVVPQQPMMPVPGQHSMTPTQHHQPNLPLPAQQPFQPQSIQPQPHQPLQPHQPLQPMQPMQPLQPLQPLQPQPPVHPIQPLPPQPPLPPIFPMQPLPPMLPDLPLEAWPATDKTKREEVD + + + Q99004 + Amelogenin, Y isoform + + + Amelogenin, Y isoform + + + + AMELY + + + Bos taurus + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + MGTWILFACLLGAAYSMPLPPHPGHPGYINFSYEVLTPLKWYQNMLRYPYPSYGYEPVGGWLHHQIIPVVSQQSPQNHALQPHHHNPMVPAQQPVVPQQPMMPVPGQHSMTPIQHHQPNLPLPAQQSFQPQPIQPQPHQPLQPQPPVHPIQRLPPQPPLPPIFPMQPLPPVLPDLPLEAWPATDKTKREEVD + + + F1MKR5 + Enamelin + + + Enamelin + + + + ENAM + + + Bos taurus + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + KMLLQCRHEASSPKLDYLVPSGKMKILLVFLSLLGYSIAMPLQMHMPRIPGFSSKSEEMMRYGHFNFMNFPHLAHLSPFYGNGIQLPQLFPQYQMPMWPQPPPNKKSPQKPSSPAAPKQTDQAPETPSPNQPQPTDSPPNQHLKQPSTTTAQPQEEETQTPQAFPPFGNGLFPYQQPPWHIPHVSIPPGFGRPPGSNEEGGNPFFGFFGYHGFGGRPPYYSEEMFEDFEKPKEEDPPKTETPATDPSVNSTVPETNSTQPGAPSPRAGQGGNDTSPAGNNGQDPNTVSNPTVQNNPVVNVSGQGVPRSQTPWRPSQTNIHENYPYPNIRNFPAGRQWHPTGTSMGNRRNGPFYRNQQIQRAPRWNSFVLEGKQAIRLGYPIYRRAYASTVRGNYPNYAGNPVNFRRKPEGPSKQPEGTIAPLGPKHGTTGHNENIQNPKEKPVSQKERIVIPTRDPNGPWRNSQDYGVTKSNYKLPHPEGNILVPNFNSIDQHENSYYPRGDSRGTPNSNGQTQSQNLPKGIILEPRRIPYESEINQPEIKHSTHQPVYPEGSPSPARERFPAGRNTWNQQEISPPFKEDPGRKEEHLPHPSLGSRGRIYYTDYNPYDRRENPPYLRSNSWDERNDPPNTMGQSENPHYPMNTPDPKETIPYNEEGPADPTGDETFPGQTRWSVDESNFKTAPTARYEGKQYTSNQPKEYSPYSLDNLPKPREYFPYGEFYPWSPDENFPSYNTAPTIPLLVENRGYYPTNAVGQEENTMFPSWNSWDHMVQVQGQKERRPYFTRTFWGQPTNLPKAPASPPYHKENQPYFSNSPTGLQKDPTWHEGENLNYGMQITRLNSPEGGHLAFPDLIPPHYPGSQKETRLFHLSQRGPCCAGGSIGPKDNPLALQDYTLFFGLAPGENQDTSPLYTEDSHTKHERYTISPTSILPGQRNSSEKRLPGESQNPSPFRDDVSTLRRNTPCSINNQLSQRGIRPLPEASSLQSKNIPCLKSDLEDGNHVLEQTLEGNQLNERPVDLTPEQLVMDTPDEGPKPEGIPSEVQGNGGKRQQQRPSTILKLPCFDSKLTKYYTSSTGTPSSLGRQGSFDGDPIMPTEIPNSLAELATGAQFQNINVDPLNADDHTPFDPLQVGTNPQDQVQDCLLLQA + + + O18767 + Matrix metalloproteinase-20 + + + Matrix metalloproteinase-20 + + + + MMP20 + + + Bos taurus + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + MLPASGLAVLLVTALKFSTAAPSLPAASPRTSRNNYRLAQAYLDKYYTKKGGPQIGEMVARGGNSTVKKIKELQEFFGLRVTGKLDRATMDVIKRPRCGVPDVANYRLFPGEPKWKKNTLTYRISKYTPSMTPAEVDRAMEMALRAWSSAVPLNFVRINAGEADIMISFETGDHGDSYPFDGPRGTLAHAFAPGEGLGGDTHFDNAEKWTMGTNGFNLFTVAAHEFGHALGLAHSTDPSALMFPTYKYQNPYGFRLPKDDVKGIQALYGPRRAFSGKPTAPHGPPHNPSIPDLCDSNLSFDAVTMLGKELLLFRDRIFWRRQVHLMSGIRPSTITSSFPQLMSNVDAAYEVAERGTAYFFKGPHYWITRGFQMQGPPRTIYDFGFPRYVQRIDAAVYLKDAQKTLFFVGDEYYSYDERKRKMEKDYPKSTEEEFSGVNGQIDAAVELNGYIYFFSGPKAYKSDTEKEDVVSELKSSSWIGC + + + F1MLB5 + Kallikrein B1 + + + Kallikrein B1 + + + + KLK4 + + + Bos taurus + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + MTTAGNSWGWFLGHLLLSVTGSLAWGGSSRIINGEDCRPHSQPWQAALFLENEFFCGGVLVHPQWVLSAAHCFQKSYTIGLGLHSLEADQEPGSQMIEAHLSIQHPEYNKPSLANDLMLIKLEESVPPSDTIQDISIASQCPAAGGDSCLVSGWGRLVNGKLPKVLQCVNISVVSEKICSELYAHVYHPSMFCAGGGQDQKDSCHGDSGGPLVCNGSLQGLVSFGQAQCGQPYVPSVYTNLCKFTDWIQKTIQAS + + + A1YQ93 + Odontogenic ameloblast-associated protein + + + Odontogenic ameloblast-associated protein + + + + ODAM + + + Bos taurus + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + MRTLILLGILGATMSAPLIPQHLMSASNSNELLLNLNNAQLRPLQLQGPFNSWFPPFPGILQQQQQNQVPGLSPFSLSTREWFAGLVPNQIFVPGQVSFAQGTQAGQLDPSQPQTPQQTQRGPKNVMPSVFFKMPQEQAQMLQYYPVYMFLPWEQPQQTVAQSPPQTREQLFEKQMPFYTEFGYIPQQVEPVMPVEQQQPVFDPFLGTAPEIAAMPAEVSPYLQKEMINFQHTNAGIFIPSTSQKPSTTIFFTSAVDPIITRELTEKKAKTDSLKEP + + \ No newline at end of file diff --git a/MetaMorpheus/Test/TestTopDown.cs b/MetaMorpheus/Test/TestTopDown.cs index c76f95057..13b5e4c8a 100644 --- a/MetaMorpheus/Test/TestTopDown.cs +++ b/MetaMorpheus/Test/TestTopDown.cs @@ -30,7 +30,7 @@ public static void TestClassicSearchEngineTopDown() MetaMorpheusTask.DetermineAnalyteType(CommonParameters); // test output file name (should be proteoform and not peptide) - Assert.That(GlobalVariables.AnalyteType == "Proteoform"); + Assert.That(GlobalVariables.AnalyteType == AnalyteType.Proteoform); var variableModifications = new List(); var fixedModifications = new List();