diff --git a/MetaMorpheus/EngineLayer/CommonParameters.cs b/MetaMorpheus/EngineLayer/CommonParameters.cs index f95d6cb12..5c9371500 100644 --- a/MetaMorpheus/EngineLayer/CommonParameters.cs +++ b/MetaMorpheus/EngineLayer/CommonParameters.cs @@ -139,8 +139,8 @@ public int DeconvolutionMaxAssumedChargeState get => PrecursorDeconvolutionParameters.MaxAssumedChargeState; private set => PrecursorDeconvolutionParameters.MaxAssumedChargeState = value; } - [TomlIgnore] public DeconvolutionParameters PrecursorDeconvolutionParameters { get; private set; } - [TomlIgnore] public DeconvolutionParameters ProductDeconvolutionParameters { get; private set; } + public DeconvolutionParameters PrecursorDeconvolutionParameters { get; private set; } + public DeconvolutionParameters ProductDeconvolutionParameters { get; private set; } [TomlIgnore] public Tolerance DeconvolutionMassTolerance { get; private set; } public int TotalPartitions { get; set; } public Tolerance ProductMassTolerance { get; set; } // public setter required for calibration task diff --git a/MetaMorpheus/GUI/TaskWindows/CalibrateTaskWindow.xaml.cs b/MetaMorpheus/GUI/TaskWindows/CalibrateTaskWindow.xaml.cs index 2f7fc775a..411060e41 100644 --- a/MetaMorpheus/GUI/TaskWindows/CalibrateTaskWindow.xaml.cs +++ b/MetaMorpheus/GUI/TaskWindows/CalibrateTaskWindow.xaml.cs @@ -399,7 +399,8 @@ private void ProteaseSpecificUpdate(object sender, SelectionChangedEventArgs e) //uncheck all variable mods DeconHostViewModel.UseProvidedPrecursors = false; DeconHostViewModel.DoPrecursorDeconvolution = true; - DeconHostViewModel.PrecursorDeconvolutionParameters.MaxAssumedChargeState = 60; + DeconHostViewModel.SetAllPrecursorMaxChargeState(60); + DeconHostViewModel.SetAllProductMaxChargeState(20); foreach (var mod in VariableModTypeForTreeViewObservableCollection) { @@ -466,4 +467,4 @@ private void ProteaseSpecificUpdate(object sender, TextChangedEventArgs e) } } } -} \ No newline at end of file +} diff --git a/MetaMorpheus/GUI/TaskWindows/GPTMDTaskWindow.xaml.cs b/MetaMorpheus/GUI/TaskWindows/GPTMDTaskWindow.xaml.cs index bd6dd0639..97a3dc29a 100644 --- a/MetaMorpheus/GUI/TaskWindows/GPTMDTaskWindow.xaml.cs +++ b/MetaMorpheus/GUI/TaskWindows/GPTMDTaskWindow.xaml.cs @@ -264,7 +264,9 @@ private void ProteaseSpecificUpdate(object sender, SelectionChangedEventArgs e) if (UpdateGUISettings.UseTopDownRecommendedSettings()) { DeconHostViewModel.UseProvidedPrecursors = false; - DeconHostViewModel.PrecursorDeconvolutionParameters.MaxAssumedChargeState = 60; + DeconHostViewModel.DoPrecursorDeconvolution = true; + DeconHostViewModel.SetAllPrecursorMaxChargeState(60); + DeconHostViewModel.SetAllProductMaxChargeState(20); TrimMsMs.IsChecked = false; //uncheck all variable mods foreach (var mod in VariableModTypeForTreeViewObservableCollection) diff --git a/MetaMorpheus/GUI/TaskWindows/SearchTaskWindow.xaml.cs b/MetaMorpheus/GUI/TaskWindows/SearchTaskWindow.xaml.cs index 75326ce4f..f98996d3d 100644 --- a/MetaMorpheus/GUI/TaskWindows/SearchTaskWindow.xaml.cs +++ b/MetaMorpheus/GUI/TaskWindows/SearchTaskWindow.xaml.cs @@ -300,6 +300,7 @@ private void UpdateFieldsFromTask(SearchTask task) DeconHostViewModel = new DeconHostViewModel(TheTask.CommonParameters.PrecursorDeconvolutionParameters, TheTask.CommonParameters.ProductDeconvolutionParameters, TheTask.CommonParameters.UseProvidedPrecursorInfo, TheTask.CommonParameters.DoPrecursorDeconvolution); + DeisotopingControl.DataContext = DeconHostViewModel; 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); @@ -430,7 +431,6 @@ 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, @@ -895,7 +895,9 @@ private void ProteaseSpecificUpdate(object sender, SelectionChangedEventArgs e) if (UpdateGUISettings.UseTopDownRecommendedSettings()) { DeconHostViewModel.DoPrecursorDeconvolution = true; - DeconHostViewModel.PrecursorDeconvolutionParameters.MaxAssumedChargeState = 60; + DeconHostViewModel.UseProvidedPrecursors = false; + DeconHostViewModel.SetAllPrecursorMaxChargeState(60); + DeconHostViewModel.SetAllProductMaxChargeState(20); TrimMsMs.IsChecked = false; CheckBoxNoQuant.IsChecked = true; MassDiffAccept3mm.IsChecked = true; diff --git a/MetaMorpheus/GUI/Util/Converters/DeconvolutionTypeToControlConverter.cs b/MetaMorpheus/GUI/Util/Converters/DeconvolutionTypeToControlConverter.cs index 1daf97137..77277f5b7 100644 --- a/MetaMorpheus/GUI/Util/Converters/DeconvolutionTypeToControlConverter.cs +++ b/MetaMorpheus/GUI/Util/Converters/DeconvolutionTypeToControlConverter.cs @@ -29,6 +29,8 @@ public override object Convert(object value, Type targetType, object parameter, { case DeconvolutionType.ClassicDeconvolution: return new ClassicDeconParamsControl() { DataContext = value as ClassicDeconParamsViewModel }; + case DeconvolutionType.IsoDecDeconvolution: + return new IsoDecDeconParamControl() { DataContext = value as IsoDecDeconParamsViewModel }; case DeconvolutionType.ExampleNewDeconvolutionTemplate: default: diff --git a/MetaMorpheus/GUI/Views/Deconvolution/HostDeconParamControl.xaml b/MetaMorpheus/GUI/Views/Deconvolution/HostDeconParamControl.xaml index ca2a2f1fe..a6baf197c 100644 --- a/MetaMorpheus/GUI/Views/Deconvolution/HostDeconParamControl.xaml +++ b/MetaMorpheus/GUI/Views/Deconvolution/HostDeconParamControl.xaml @@ -25,7 +25,7 @@ - + @@ -66,7 +66,7 @@ - + @@ -79,13 +79,13 @@ - - + + Visibility="{Binding DisplayDeconSelectionComboBox, Converter={StaticResource BooleanToVisibilityConverter}}" + ToolTipService.ShowDuration="999999" ToolTipService.InitialShowDelay="500"> The type of deconvolution to perform. @@ -95,18 +95,34 @@ - - - - - - - + + + + + + + + + The type of deconvolution to perform. + + + + + + + + + diff --git a/MetaMorpheus/GUI/Views/Deconvolution/IsoDecDeconParamControl.xaml b/MetaMorpheus/GUI/Views/Deconvolution/IsoDecDeconParamControl.xaml new file mode 100644 index 000000000..ceaac4ab3 --- /dev/null +++ b/MetaMorpheus/GUI/Views/Deconvolution/IsoDecDeconParamControl.xaml @@ -0,0 +1,187 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + IsoDec can return all plausible Missed Monoisotopic masses. The correct mass will be resolved after the database search. + + CAREFUL! Having both this checked and missed monoisotipics in the Mass Difference Acceptor Criterion may result in redundant searches + + + + + \ No newline at end of file diff --git a/MetaMorpheus/GUI/Views/Deconvolution/IsoDecDeconParamControl.xaml.cs b/MetaMorpheus/GUI/Views/Deconvolution/IsoDecDeconParamControl.xaml.cs new file mode 100644 index 000000000..8379e95fb --- /dev/null +++ b/MetaMorpheus/GUI/Views/Deconvolution/IsoDecDeconParamControl.xaml.cs @@ -0,0 +1,15 @@ +using System.Windows.Controls; + +namespace MetaMorpheusGUI; + +/// +/// Interaction logic for IsoDecDeconParamControl.xaml +/// +public partial class IsoDecDeconParamControl : UserControl +{ + public IsoDecDeconParamControl() + { + InitializeComponent(); + } +} + diff --git a/MetaMorpheus/GuiFunctions/MzLibExtensions.cs b/MetaMorpheus/GuiFunctions/MzLibExtensions.cs index 07fc8fc60..df3f8f0c5 100644 --- a/MetaMorpheus/GuiFunctions/MzLibExtensions.cs +++ b/MetaMorpheus/GuiFunctions/MzLibExtensions.cs @@ -23,10 +23,10 @@ public static DeconParamsViewModel ToViewModel(this DeconvolutionParameters para { return new ClassicDeconParamsViewModel(classicParams); } - //else if (parameters is IsoDeconvolutionParameters isoParams) - //{ - // return new IsoDecDeconParamsViewModel(isoParams); - //} + else if (parameters is IsoDecDeconvolutionParameters isoParams) + { + return new IsoDecDeconParamsViewModel(isoParams); + } else { throw new NotImplementedException(); diff --git a/MetaMorpheus/GuiFunctions/ViewModels/BaseViewModel.cs b/MetaMorpheus/GuiFunctions/ViewModels/BaseViewModel.cs index fbe9b8453..9c2933740 100644 --- a/MetaMorpheus/GuiFunctions/ViewModels/BaseViewModel.cs +++ b/MetaMorpheus/GuiFunctions/ViewModels/BaseViewModel.cs @@ -1,12 +1,6 @@ -using OxyPlot; -using System; -using System.Collections.ObjectModel; +using System.Collections.ObjectModel; using System.ComponentModel; -using System.Linq; -using System.Linq.Expressions; using System.Text; -using System.Threading.Tasks; -using System.Windows.Media; namespace GuiFunctions { diff --git a/MetaMorpheus/GuiFunctions/ViewModels/Deconvolution/DeconHostViewModel.cs b/MetaMorpheus/GuiFunctions/ViewModels/Deconvolution/DeconHostViewModel.cs index 411f572c7..d5bac561c 100644 --- a/MetaMorpheus/GuiFunctions/ViewModels/Deconvolution/DeconHostViewModel.cs +++ b/MetaMorpheus/GuiFunctions/ViewModels/Deconvolution/DeconHostViewModel.cs @@ -12,7 +12,7 @@ namespace GuiFunctions; /// /// This class holds all of the information in the Deconvolution tab of the GUI -/// One instance will be create per Task Window +/// One instance will be created 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 @@ -48,6 +48,7 @@ public DeconHostViewModel(DeconvolutionParameters? initialPrecursorParameters = case DeconvolutionType.ClassicDeconvolution: + // Precursor if (initialPrecursorParameters is { DeconvolutionType: DeconvolutionType.ClassicDeconvolution }) PrecursorDeconvolutionParametersList.Add(initialPrecursorParameters.ToViewModel()); else @@ -62,6 +63,7 @@ public DeconHostViewModel(DeconvolutionParameters? initialPrecursorParameters = PrecursorDeconvolutionParametersList.Add(toAdd.ToViewModel()); } + // Product if (initialProductParameters is { DeconvolutionType: DeconvolutionType.ClassicDeconvolution }) ProductDeconvolutionParametersList.Add(initialProductParameters.ToViewModel()); else @@ -79,7 +81,37 @@ public DeconHostViewModel(DeconvolutionParameters? initialPrecursorParameters = break; case DeconvolutionType.IsoDecDeconvolution: - // TODO: fill in IsoDec region in follow-up pull request + + // Precursor + if (initialPrecursorParameters is { DeconvolutionType: DeconvolutionType.IsoDecDeconvolution }) + PrecursorDeconvolutionParametersList.Add(initialPrecursorParameters.ToViewModel()); + else + { + var toAdd = GlobalVariables.AnalyteType switch + { + AnalyteType.Peptide => new IsoDecDeconvolutionParameters() { MaxAssumedChargeState = 12}, + AnalyteType.Proteoform => new IsoDecDeconvolutionParameters() { MaxAssumedChargeState = 60 }, + AnalyteType.Oligo => new IsoDecDeconvolutionParameters(Polarity.Negative) { MaxAssumedChargeState = -20, MinAssumedChargeState = -1 }, + _ => throw new ArgumentOutOfRangeException() + }; + PrecursorDeconvolutionParametersList.Add(toAdd.ToViewModel()); + } + + // Product + if (initialProductParameters is { DeconvolutionType: DeconvolutionType.IsoDecDeconvolution }) + ProductDeconvolutionParametersList.Add(initialProductParameters.ToViewModel()); + else + { + var toAdd = GlobalVariables.AnalyteType switch + { + AnalyteType.Peptide => new IsoDecDeconvolutionParameters(reportMultipleMonoisos: false) { MaxAssumedChargeState = 10}, + AnalyteType.Proteoform => new IsoDecDeconvolutionParameters(reportMultipleMonoisos: false) { MaxAssumedChargeState = 10 }, + AnalyteType.Oligo => new IsoDecDeconvolutionParameters(Polarity.Negative, reportMultipleMonoisos: false) { MaxAssumedChargeState = -10, MinAssumedChargeState = -1 }, + _ => throw new ArgumentOutOfRangeException() + }; + ProductDeconvolutionParametersList.Add(toAdd.ToViewModel()); + } + break; default: // This will only be hit if a new deconvolution type is added to mzlib and not handled here @@ -121,6 +153,24 @@ public bool DoPrecursorDeconvolution } } + public void SetAllPrecursorMaxChargeState(int newMaxCharge) + { + foreach (var precursorParams in PrecursorDeconvolutionParametersList) + { + precursorParams.MaxAssumedChargeState = newMaxCharge; + } + OnPropertyChanged(nameof(PrecursorDeconvolutionParametersList)); + } + + public void SetAllProductMaxChargeState(int newMaxCharge) + { + foreach (var productParams in ProductDeconvolutionParametersList) + { + productParams.MaxAssumedChargeState = newMaxCharge; + } + OnPropertyChanged(nameof(ProductDeconvolutionParametersList)); + } + #endregion /// @@ -178,7 +228,7 @@ public DeconParamsViewModel ProductDeconvolutionParameters [ExcludeFromCodeCoverage] // Model used only for visualizing the view in visual studio public class DeconHostModel : DeconHostViewModel { - public static DeconHostModel Instance => new DeconHostModel(); + public static DeconHostModel Instance => new(); public DeconHostModel() : base (DeconParamsModel.Instance.Parameters, DeconParamsModel.Instance.Parameters) { diff --git a/MetaMorpheus/GuiFunctions/ViewModels/Deconvolution/DeconParamsViewModel.cs b/MetaMorpheus/GuiFunctions/ViewModels/Deconvolution/DeconParamsViewModel.cs index a09e00169..6369767b2 100644 --- a/MetaMorpheus/GuiFunctions/ViewModels/Deconvolution/DeconParamsViewModel.cs +++ b/MetaMorpheus/GuiFunctions/ViewModels/Deconvolution/DeconParamsViewModel.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using MassSpectrometry; @@ -10,16 +9,14 @@ namespace GuiFunctions; /// Used to wrap the DeconvolutionParameters object /// Contains only shared information between different DeconvolutionParameters /// -public abstract class DeconParamsViewModel : BaseViewModel, IEquatable +public abstract class DeconParamsViewModel : BaseViewModel { - private int _previousMinAssumedChargeState; private int _previousMaxAssumedChargeState; - + protected readonly Guid UniqueIdentifier = Guid.NewGuid(); // Used to map which updated decon params to the combobox selection via the GetHashCodeMethod 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. @@ -48,7 +45,6 @@ public int MinAssumedChargeState } } - /// /// Gets or sets the maximum assumed charge state. /// Ensures the value is within valid range based on the polarity. @@ -133,37 +129,12 @@ public Polarity Polarity 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); + return UniqueIdentifier.GetHashCode(); } } - [ExcludeFromCodeCoverage] // Model used only for visualizing the view in visual studio public class DeconParamsModel : DeconParamsViewModel { diff --git a/MetaMorpheus/GuiFunctions/ViewModels/Deconvolution/IsoDecDeconParamsViewModel.cs b/MetaMorpheus/GuiFunctions/ViewModels/Deconvolution/IsoDecDeconParamsViewModel.cs index 1a09d8090..a013c7447 100644 --- a/MetaMorpheus/GuiFunctions/ViewModels/Deconvolution/IsoDecDeconParamsViewModel.cs +++ b/MetaMorpheus/GuiFunctions/ViewModels/Deconvolution/IsoDecDeconParamsViewModel.cs @@ -1,20 +1,186 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using MassSpectrometry; - -namespace GuiFunctions +using MassSpectrometry; + +namespace GuiFunctions; + +// Todo: IsoDec has the ability to report all plausible MonoIsotopic masses for a peak (missed monos). +// This behavior is currently suppressed due to the complexities of interacting with our mass difference acceptor. +// The Isotpic Envelopes that IsoDec produces are labeled with an ID. +// This ID can be used in PostSearchAnalysis to ensure that no spectral match can be made from two deconvolution results of the same species. + +public sealed class IsoDecDeconParamsViewModel : DeconParamsViewModel +{ + public static IsoDecDeconParamsViewModel Instance => new (new IsoDecDeconvolutionParameters()); + private IsoDecDeconvolutionParameters _parameters; + public override DeconvolutionParameters Parameters + { + get => _parameters; + protected set + { + _parameters = (IsoDecDeconvolutionParameters)value; + OnPropertyChanged(nameof(Parameters)); + } + } + + public IsoDecDeconParamsViewModel(IsoDecDeconvolutionParameters parameters) + { + // Todo: remove this and reconcile the Missed Monoisotopics + parameters.ReportMulitpleMonoisos = false; + + Parameters = parameters; + } + + public bool PhaseResIsFour + { + get => _parameters.PhaseRes == 4; + set + { + if (value) + { + _parameters.PhaseRes = 4; + OnPropertyChanged(nameof(PhaseResIsFour)); + } + else + { + _parameters.PhaseRes = 8; + OnPropertyChanged(nameof(PhaseResIsFour)); + } + } + } + + /// + /// Minimum cosine similarity score for isotope distribution + /// + public float CssThreshold + { + get => _parameters.CssThreshold; + set + { + if (value is > 1 or < 0) + return; + + _parameters.CssThreshold = value; + OnPropertyChanged(nameof(CssThreshold)); + } + } + + /// + /// Match Tolerance for peak detection in ppm + /// + public float MatchTolerance + { + get => _parameters.MatchTolerance; + set + { + if (value <= 0) + return; + + _parameters.MatchTolerance = value; + OnPropertyChanged(nameof(MatchTolerance)); + } + } + + /// + /// Maximum shift allowed for isotope distribution + /// + public int MaximumShift + { + get => _parameters.MaxShift; + set + { + if (value is < 0 or > 8) + return; + + _parameters.MaxShift = value; + OnPropertyChanged(nameof(MaximumShift)); + } + } + + public float MzWindowForIsotopeDistributionMinimum + { + get => _parameters.MzWindow[0]; + set + { + if (value > 0) + return; + + _parameters.MzWindow[0] = value; + OnPropertyChanged(nameof(MzWindowForIsotopeDistributionMinimum)); + } + } + + public float MzWindowForIsotopeDistributionMaximum + { + get => _parameters.MzWindow[1]; + set + { + if (value < 0) + return; + + _parameters.MzWindow[1] = value; + OnPropertyChanged(nameof(MzWindowForIsotopeDistributionMaximum)); + } + } + + /// + /// Number of knockdown rounds + /// + public int KnockdownRounds + { + get => _parameters.KnockdownRounds; + set + { + if (value < 0) + return; + + _parameters.KnockdownRounds = value; + OnPropertyChanged(nameof(KnockdownRounds)); + } + } + + /// + /// Minimum area covered by isotope distribution. Use in or with css_thresh + /// + public float MinAreaCovered { - // Coming Soon - [ExcludeFromCodeCoverage] - public sealed class IsoDecDeconParamsViewModel : DeconParamsViewModel + get => _parameters.MinAreaCovered; + set + { + if (value is > 1 or < 0) + return; + + _parameters.MinAreaCovered = value; + OnPropertyChanged(nameof(MinAreaCovered)); + } + } + + /// + /// Threshold for data. Will remove relative intensities below this relative to max intensity in each cluster + /// + public float DataThreshold + { + get => _parameters.DataThreshold; + set { - public override DeconvolutionParameters Parameters { get; protected set; } + if (value is > 1 or < 0) + return; + _parameters.DataThreshold = value; + OnPropertyChanged(nameof(DataThreshold)); + } + } - public override string ToString() => "IsoDec"; + /// + /// Report multiple monoisotopic peaks + /// + public bool ReportMultipleMonoisotopicMasses + { + get => _parameters.ReportMulitpleMonoisos; + set + { + _parameters.ReportMulitpleMonoisos = value; + OnPropertyChanged(nameof(ReportMultipleMonoisotopicMasses)); + } } + + public override string ToString() => "IsoDec"; } diff --git a/MetaMorpheus/MetaMorpheus.sln.DotSettings b/MetaMorpheus/MetaMorpheus.sln.DotSettings index 2b8fe6816..c0f2e048e 100644 --- a/MetaMorpheus/MetaMorpheus.sln.DotSettings +++ b/MetaMorpheus/MetaMorpheus.sln.DotSettings @@ -17,6 +17,7 @@ True True True + True True True True diff --git a/MetaMorpheus/TaskLayer/MetaMorpheusTask.cs b/MetaMorpheus/TaskLayer/MetaMorpheusTask.cs index 44bb83da6..aac4ef999 100644 --- a/MetaMorpheus/TaskLayer/MetaMorpheusTask.cs +++ b/MetaMorpheus/TaskLayer/MetaMorpheusTask.cs @@ -70,7 +70,35 @@ public abstract class MetaMorpheusTask .IgnoreProperty(p => p.MaxMods) .IgnoreProperty(p => p.MaxLength) .IgnoreProperty(p => p.MinLength)) - ); + // Switch on DeconvolutionParameters + .ConfigureType(type => type + .WithConversionFor(c => c + .FromToml(tmlTable => tmlTable.Get("DeconvolutionType") switch + { + "ClassicDeconvolution" => tmlTable.Get(), + "IsoDecDeconvolution" => tmlTable.Get(), + _ => throw new MetaMorpheusException("Unrecognized deconvolution type in toml") + }))) + // Ignore all properties that are not user settable, instantiate with defaults. If the toml differs, defaults will be overridden. + .ConfigureType(type => type + .CreateInstance(() => new ClassicDeconvolutionParameters(1, 20, 4, 3)) + .IgnoreProperty(p => p.IntensityRatioLimit) + .IgnoreProperty(p => p.DeconvolutionTolerancePpm)) + .ConfigureType(type => type + .CreateInstance(() => new IsoDecDeconvolutionParameters()) + .IgnoreProperty(p => p.Verbose) + .IgnoreProperty(p => p.PeakWindow) + .IgnoreProperty(p => p.PeakThreshold) + .IgnoreProperty(p => p.MinPeaks) + .IgnoreProperty(p => p.PlusOneIntWindow) + .IgnoreProperty(p => p.MinScoreDiff) + .IgnoreProperty(p => p.IsoLength) + .IgnoreProperty(p => p.MassDiffC) + .IgnoreProperty(p => p.MinusOneAreasZero) + .IgnoreProperty(p => p.IsotopeThreshold) + .IgnoreProperty(p => p.ZScoreThreshold)) + + ); protected readonly StringBuilder ProseCreatedWhileRunning = new StringBuilder(); diff --git a/MetaMorpheus/Test/GuiTests/DeconHostViewModelTest.cs b/MetaMorpheus/Test/GuiTests/DeconHostViewModelTest.cs index abb4c905c..0e98e3216 100644 --- a/MetaMorpheus/Test/GuiTests/DeconHostViewModelTest.cs +++ b/MetaMorpheus/Test/GuiTests/DeconHostViewModelTest.cs @@ -12,9 +12,11 @@ public class DeconHostViewModelTests { internal ClassicDeconvolutionParameters ClassicPrecursorDeconvolutionParameters = new ClassicDeconvolutionParameters(1, 12, 4, 3); internal ClassicDeconvolutionParameters ClassicProductDeconvolutionParameters = new ClassicDeconvolutionParameters(1, 10, 4, 3); + internal IsoDecDeconvolutionParameters IsoDecPrecursorDeconvolutionParameters = new IsoDecDeconvolutionParameters(); + internal IsoDecDeconvolutionParameters IsoDecProductDeconvolutionParameters = new IsoDecDeconvolutionParameters(); [Test] - public void Constructor_DefaultParameters_ShouldInitializeCorrectly() + public void Constructor_DefaultParameters_ShouldInitializeCorrectly_Classic() { // Arrange var initialPrecursorParameters = ClassicPrecursorDeconvolutionParameters; @@ -31,9 +33,27 @@ public void Constructor_DefaultParameters_ShouldInitializeCorrectly() Assert.That(viewModel.PrecursorDeconvolutionParametersList.Any(), Is.True); Assert.That(viewModel.ProductDeconvolutionParametersList.Any(), Is.True); } + [Test] + public void Constructor_DefaultParameters_ShouldInitializeCorrectly_IsoDec() + { + // Arrange + var initialPrecursorParameters = IsoDecPrecursorDeconvolutionParameters; + var initialProductParameters = IsoDecProductDeconvolutionParameters; + + // 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() + public void Constructor_WithProvidedParameters_ShouldSetCorrectly_Classic() { // Arrange var initialPrecursorParameters = ClassicPrecursorDeconvolutionParameters; @@ -45,8 +65,34 @@ public void Constructor_WithProvidedParameters_ShouldSetCorrectly() // 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())); + Assert.That(viewModel.PrecursorDeconvolutionParameters.MaxAssumedChargeState, Is.EqualTo(initialPrecursorParameters.MaxAssumedChargeState)); + Assert.That(viewModel.ProductDeconvolutionParameters.MaxAssumedChargeState, Is.EqualTo(initialProductParameters.MaxAssumedChargeState)); + Assert.That(initialPrecursorParameters.DeconvolutionType, Is.EqualTo(DeconvolutionType.ClassicDeconvolution)); + Assert.That(initialProductParameters.DeconvolutionType, Is.EqualTo(DeconvolutionType.ClassicDeconvolution)); + Assert.That(viewModel.PrecursorDeconvolutionParameters.Parameters, Is.InstanceOf()); + Assert.That(viewModel.ProductDeconvolutionParameters.Parameters, Is.InstanceOf()); + } + + [Test] + public void Constructor_WithProvidedParameters_ShouldSetCorrectly_IsoDec() + { + // Arrange + var initialPrecursorParameters = IsoDecPrecursorDeconvolutionParameters; + var initialProductParameters = IsoDecProductDeconvolutionParameters; + + // 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.MaxAssumedChargeState, Is.EqualTo(initialPrecursorParameters.MaxAssumedChargeState)); + Assert.That(viewModel.ProductDeconvolutionParameters.MaxAssumedChargeState, Is.EqualTo(initialProductParameters.MaxAssumedChargeState)); + Assert.That(initialPrecursorParameters.DeconvolutionType, Is.EqualTo(DeconvolutionType.IsoDecDeconvolution)); + Assert.That(initialProductParameters.DeconvolutionType, Is.EqualTo(DeconvolutionType.IsoDecDeconvolution)); + Assert.That(viewModel.PrecursorDeconvolutionParameters.Parameters, Is.InstanceOf()); + Assert.That(viewModel.PrecursorDeconvolutionParameters.Parameters, Is.InstanceOf()); + Assert.That(viewModel.PrecursorDeconvolutionParameters.ToString(), Is.EqualTo("IsoDec")); } [Test] @@ -106,7 +152,32 @@ public void ProductDeconvolutionParameters_Setter_ShouldTriggerPropertyChanged() Assert.That(propertyChangedTriggered, Is.True); } - + [Test] + [NonParallelizable] + public void TestDeconHostViewModel_GlobalVariables_Proteoform_Classic() + { + // 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_Proteoform() @@ -177,6 +248,21 @@ public void TestDeconHostViewModel_GlobalVariables_Unknown() var deconHostViewModel = new DeconHostViewModel(ClassicPrecursorDeconvolutionParameters, null); }); + Assert.Throws(() => + { + var deconHostViewModel = new DeconHostViewModel(null, ClassicProductDeconvolutionParameters); + }); + + Assert.Throws(() => + { + var deconHostViewModel = new DeconHostViewModel(IsoDecPrecursorDeconvolutionParameters, null); + }); + + Assert.Throws(() => + { + var deconHostViewModel = new DeconHostViewModel(null, IsoDecProductDeconvolutionParameters); + }); + // Revert back to default GlobalVariables.AnalyteType = AnalyteType.Peptide; } @@ -214,6 +300,9 @@ public void TestDisplayDeconSelectionComboBox_SingleOption() { // Arrange var viewModel = new DeconHostViewModel(); + viewModel.PrecursorDeconvolutionParametersList.Clear(); + viewModel.ProductDeconvolutionParametersList.Clear(); + // Act var result = viewModel.DisplayDeconSelectionComboBox; @@ -221,4 +310,38 @@ public void TestDisplayDeconSelectionComboBox_SingleOption() // Assert Assert.That(result, Is.False); } + + [Test] + public void SetAllPrecursorMaxChargeState_ShouldUpdateAllPrecursorParams() + { + // Arrange + var viewModel = new DeconHostViewModel(); + int newMaxCharge = 5; + + // Act + viewModel.SetAllPrecursorMaxChargeState(newMaxCharge); + + // Assert + foreach (var precursorParams in viewModel.PrecursorDeconvolutionParametersList) + { + Assert.That(precursorParams.MaxAssumedChargeState, Is.EqualTo(newMaxCharge)); + } + } + + [Test] + public void SetAllProductMaxChargeState_ShouldUpdateAllProductParams() + { + // Arrange + var viewModel = new DeconHostViewModel(); + int newMaxCharge = 5; + + // Act + viewModel.SetAllProductMaxChargeState(newMaxCharge); + + // Assert + foreach (var productParams in viewModel.ProductDeconvolutionParametersList) + { + Assert.That(productParams.MaxAssumedChargeState, Is.EqualTo(newMaxCharge)); + } + } } \ No newline at end of file diff --git a/MetaMorpheus/Test/GuiTests/DeconParamsViewModelTest.cs b/MetaMorpheus/Test/GuiTests/DeconParamsViewModelTest.cs index 1093d9d1e..0af45046c 100644 --- a/MetaMorpheus/Test/GuiTests/DeconParamsViewModelTest.cs +++ b/MetaMorpheus/Test/GuiTests/DeconParamsViewModelTest.cs @@ -194,6 +194,15 @@ public void TestEquals_NullObject() Assert.That(viewModel.Equals((object)null), Is.False); } + [Test] + public void TestEquals_DifferentDeconTypes() + { + var classic = new ClassicDeconvolutionParameters(1, 12, 5, 3, Polarity.Positive).ToViewModel(); + var isoDec = new IsoDecDeconvolutionParameters().ToViewModel(); + Assert.That(classic.Equals(isoDec), Is.False); + Assert.That(classic.Equals((object)isoDec), Is.False); + } + [Test] public void TestEquals_DifferentType() { @@ -240,28 +249,38 @@ public void TestEquals_SameParameters() 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); + Assert.That(viewModel1.Equals(viewModel2), Is.False); + Assert.That(viewModel1.Equals((object)viewModel2), Is.False); } [Test] - public void TestEquals_SameParameters_Obj() + public void TestGetHashCode_UniqueIdentifier() { - 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); + var parameters = new ClassicDeconvolutionParameters(1, 12, 5, 3, Polarity.Positive); + var viewModel1 = new TestDeconParamsViewModel(parameters); + var viewModel2 = new TestDeconParamsViewModel(parameters); + + Assert.That(viewModel1.GetHashCode(), Is.Not.EqualTo(viewModel2.GetHashCode())); } [Test] - public void TestGetHashCode() + public void TestEquals_SameUniqueIdentifier() { 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)); + var viewModel1 = new TestDeconParamsViewModel(parameters); + var viewModel2 = viewModel1; + + Assert.That(viewModel1.Equals(viewModel2), Is.True); + } + + [Test] + public void TestEquals_DifferentUniqueIdentifier() + { + 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); - viewModel = new TestDeconParamsViewModel(null); - Assert.That(viewModel.GetHashCode(), Is.EqualTo(0)); + Assert.That(viewModel1.Equals(viewModel2), Is.False); } } \ No newline at end of file diff --git a/MetaMorpheus/Test/GuiTests/IsoDecDeconParamsViewModelTest.cs b/MetaMorpheus/Test/GuiTests/IsoDecDeconParamsViewModelTest.cs new file mode 100644 index 000000000..87478b734 --- /dev/null +++ b/MetaMorpheus/Test/GuiTests/IsoDecDeconParamsViewModelTest.cs @@ -0,0 +1,136 @@ +using NUnit.Framework; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using GuiFunctions; +using MassSpectrometry; + +namespace Test.GuiTests +{ + [TestFixture] + internal class IsoDecDeconParamsViewModelTest + { + private IsoDecDeconParamsViewModel _viewModel; + + [SetUp] + public void Setup() + { + _viewModel = new IsoDecDeconParamsViewModel(new IsoDecDeconvolutionParameters()); + } + + + + [Test] + public void TestCssThreshold() + { + _viewModel.CssThreshold = 0.5f; + Assert.That(_viewModel.CssThreshold, Is.EqualTo(0.5f)); + + _viewModel.CssThreshold = 1.1f; + Assert.That(_viewModel.CssThreshold, Is.EqualTo(0.5f)); // Should not change + + _viewModel.CssThreshold = -0.1f; + Assert.That(_viewModel.CssThreshold, Is.EqualTo(0.5f)); // Should not change + } + + [Test] + public void TestMatchTolerance() + { + _viewModel.MatchTolerance = 10f; + Assert.That(_viewModel.MatchTolerance, Is.EqualTo(10f)); + + _viewModel.MatchTolerance = -1f; + Assert.That(_viewModel.MatchTolerance, Is.EqualTo(10f)); // Should not change + } + + [Test] + public void TestMaximumShift() + { + _viewModel.MaximumShift = 5; + Assert.That(_viewModel.MaximumShift, Is.EqualTo(5)); + + _viewModel.MaximumShift = -1; + Assert.That(_viewModel.MaximumShift, Is.EqualTo(5)); // Should not change + } + + [Test] + public void TestMzWindowForIsotopeDistributionMinimum() + { + _viewModel.MzWindowForIsotopeDistributionMinimum = -0.5f; + Assert.That(_viewModel.MzWindowForIsotopeDistributionMinimum, Is.EqualTo(-0.5f)); + + _viewModel.MzWindowForIsotopeDistributionMinimum = 0.5f; + Assert.That(_viewModel.MzWindowForIsotopeDistributionMinimum, Is.EqualTo(-0.5f)); // Should not change + } + + [Test] + public void TestMzWindowForIsotopeDistributionMaximum() + { + _viewModel.MzWindowForIsotopeDistributionMaximum = 0.5f; + Assert.That(_viewModel.MzWindowForIsotopeDistributionMaximum, Is.EqualTo(0.5f)); + + _viewModel.MzWindowForIsotopeDistributionMaximum = -0.5f; + Assert.That(_viewModel.MzWindowForIsotopeDistributionMaximum, Is.EqualTo(0.5f)); // Should not change + } + + [Test] + public void TestKnockdownRounds() + { + _viewModel.KnockdownRounds = 3; + Assert.That(_viewModel.KnockdownRounds, Is.EqualTo(3)); + + _viewModel.KnockdownRounds = -1; + Assert.That(_viewModel.KnockdownRounds, Is.EqualTo(3)); // Should not change + } + + [Test] + public void TestMinAreaCovered() + { + _viewModel.MinAreaCovered = 0.5f; + Assert.That(_viewModel.MinAreaCovered, Is.EqualTo(0.5f)); + + _viewModel.MinAreaCovered = 1.1f; + Assert.That(_viewModel.MinAreaCovered, Is.EqualTo(0.5f)); // Should not change + + _viewModel.MinAreaCovered = -0.1f; + Assert.That(_viewModel.MinAreaCovered, Is.EqualTo(0.5f)); // Should not change + } + + [Test] + public void TestDataThreshold() + { + _viewModel.DataThreshold = 0.5f; + Assert.That(_viewModel.DataThreshold, Is.EqualTo(0.5f)); + + _viewModel.DataThreshold = 1.1f; + Assert.That(_viewModel.DataThreshold, Is.EqualTo(0.5f)); // Should not change + + _viewModel.DataThreshold = -0.1f; + Assert.That(_viewModel.DataThreshold, Is.EqualTo(0.5f)); // Should not change + } + + [Test] + public void TestReportMultipleMonoisotopicMasses() + { + _viewModel.ReportMultipleMonoisotopicMasses = true; + Assert.That(_viewModel.ReportMultipleMonoisotopicMasses, Is.True); + + _viewModel.ReportMultipleMonoisotopicMasses = false; + Assert.That(_viewModel.ReportMultipleMonoisotopicMasses, Is.False); + } + + [Test] + public void TestPhaseResIsFour() + { + _viewModel.PhaseResIsFour = true; + Assert.That(_viewModel.PhaseResIsFour, Is.True); + Assert.That((_viewModel.Parameters as IsoDecDeconvolutionParameters)!.PhaseRes, Is.EqualTo(4)); + + _viewModel.PhaseResIsFour = false; + Assert.That(_viewModel.PhaseResIsFour, Is.False); + Assert.That((_viewModel.Parameters as IsoDecDeconvolutionParameters)!.PhaseRes, Is.EqualTo(8)); + } + } +} diff --git a/MetaMorpheus/Test/GuiTests/MzLibExtensionsTests.cs b/MetaMorpheus/Test/GuiTests/MzLibExtensionsTests.cs index 6d063bbba..d1272999c 100644 --- a/MetaMorpheus/Test/GuiTests/MzLibExtensionsTests.cs +++ b/MetaMorpheus/Test/GuiTests/MzLibExtensionsTests.cs @@ -22,6 +22,19 @@ public void ToViewModel_WithClassicDeconvolutionParameters_ReturnsClassicDeconPa Assert.That(result, Is.InstanceOf()); } + [Test] + public void ToViewModel_WithIsoDecDeconvolutionParameters_ReturnsClassicDeconParamsViewModel() + { + // Arrange + var isoDecParams = new IsoDecDeconvolutionParameters(); + + // Act + var result = isoDecParams.ToViewModel(); + + // Assert + Assert.That(result, Is.InstanceOf()); + } + [Test] public void ToViewModel_WithUnsupportedParameters_ThrowsNotImplementedException() { diff --git a/MetaMorpheus/Test/SearchTaskTest.cs b/MetaMorpheus/Test/SearchTaskTest.cs index b1c928d8f..6be71cdcf 100644 --- a/MetaMorpheus/Test/SearchTaskTest.cs +++ b/MetaMorpheus/Test/SearchTaskTest.cs @@ -253,6 +253,9 @@ public static void PostSearchNormalizeTest() { Normalize = true }, + CommonParameters = new( precursorDeconParams:new IsoDecDeconvolutionParameters()) + { + } }; string myFile = Path.Combine(TestContext.CurrentContext.TestDirectory, @"TestData\PrunedDbSpectra.mzml");