Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Search Neutral Mass Spectrum #2425

Draft
wants to merge 22 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion MetaMorpheus/CMD/CMD.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
<PackageReference Include="Microsoft.ML.CpuMath" Version="3.0.1" />
<PackageReference Include="Microsoft.ML.FastTree" Version="3.0.1" />
<PackageReference Include="Microsoft.NETCore.App" Version="2.2.8" />
<PackageReference Include="mzLib" Version="1.0.552" />
<PackageReference Include="mzLib" Version="5.2.8" />
<PackageReference Include="Nett" Version="0.15.0" />
</ItemGroup>

Expand Down
2 changes: 1 addition & 1 deletion MetaMorpheus/CMD/CommandLineSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public class CommandLineSettings
[Option('d', HelpText = "Protein sequence databases (.fasta, .xml, .fasta.gz, .xml.gz file formats); space-delimited")]
public IEnumerable<string> _databases { get; set; }

[Option('s', HelpText = "Spectra to analyze (.raw, .mzML, .mgf file formats) or folder(s) containing spectra; space-delimited")]
[Option('s', HelpText = "Spectra to analyze (.raw, .mzML, .mgf, ms2.msalign file formats) or folder(s) containing spectra; space-delimited")]
public IEnumerable<string> _spectra { get; set; }

[Option('o', HelpText = "[Optional] Output folder")]
Expand Down
2 changes: 1 addition & 1 deletion MetaMorpheus/EngineLayer/EngineLayer.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
<PackageReference Include="Microsoft.ML.CpuMath" Version="3.0.1" />
<PackageReference Include="Microsoft.ML.FastTree" Version="3.0.1" />
<PackageReference Include="Microsoft.NETCore.App" Version="2.2.8" />
<PackageReference Include="mzLib" Version="1.0.552" />
<PackageReference Include="mzLib" Version="5.2.8" />
<PackageReference Include="NETStandard.Library" Version="2.0.3" />
<PackageReference Include="Nett" Version="0.15.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
Expand Down
2 changes: 1 addition & 1 deletion MetaMorpheus/EngineLayer/GlobalVariables.cs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ public static void SetUpGlobalVariables()
{
Loaders.LoadElements();
AcceptedDatabaseFormats = new List<string> { ".fasta", ".fa", ".xml", ".msp" };
AcceptedSpectraFormats = new List<string> { ".raw", ".mzml", ".mgf" };
AcceptedSpectraFormats = new List<string> { ".raw", ".mzml", ".mgf", ".msalign" };
AnalyteType = "Peptide";
_InvalidAminoAcids = new char[] { 'X', 'B', 'J', 'Z', ':', '|', ';', '[', ']', '{', '}', '(', ')', '+', '-' };
ExperimentalDesignFileName = "ExperimentalDesign.tsv";
Expand Down
29 changes: 16 additions & 13 deletions MetaMorpheus/EngineLayer/Ms2ScanWithSpecificMass.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ namespace EngineLayer
{
public class Ms2ScanWithSpecificMass
{
// Most of the processing here is done on the deconvoluted masses. SO we can make the do all of the processing in mzlib with a derived class
// We just need to make sure all of the neutral mass outputs are correct. This should translate to charged fragment ions.
public Ms2ScanWithSpecificMass(MsDataScan mzLibScan, double precursorMonoisotopicPeakMz, int precursorCharge, string fullFilePath, CommonParameters commonParam,
IsotopicEnvelope[] neutralExperimentalFragments = null, double? precursorIntensity = null, int? envelopePeakCount = null, double? precursorFractionalIntensity = null)
{
Expand All @@ -23,6 +25,7 @@ public Ms2ScanWithSpecificMass(MsDataScan mzLibScan, double precursorMonoisotopi

TheScan = mzLibScan;


if (commonParam.DissociationType != DissociationType.LowCID)
{
ExperimentalFragments = neutralExperimentalFragments ?? GetNeutralExperimentalFragments(mzLibScan, commonParam);
Expand Down Expand Up @@ -65,22 +68,22 @@ public static IsotopicEnvelope[] GetNeutralExperimentalFragments(MsDataScan scan
var neutralExperimentalFragmentMasses =
Deconvoluter.Deconvolute(scan, commonParam.ProductDeconvolutionParameters, scan.MassSpectrum.Range).ToList();

if (commonParam.AssumeOrphanPeaksAreZ1Fragments)
if (!commonParam.AssumeOrphanPeaksAreZ1Fragments || scan.MassSpectrum is NeutralMassSpectrum)
return neutralExperimentalFragmentMasses.OrderBy(p => p.MonoisotopicMass).ToArray();

HashSet<double> alreadyClaimedMzs = new HashSet<double>(neutralExperimentalFragmentMasses
.SelectMany(p => p.Peaks.Select(v => ClassExtensions.RoundedDouble(v.mz).Value)));

for (int i = 0; i < scan.MassSpectrum.XArray.Length; i++)
{
HashSet<double> alreadyClaimedMzs = new HashSet<double>(neutralExperimentalFragmentMasses
.SelectMany(p => p.Peaks.Select(v => ClassExtensions.RoundedDouble(v.mz).Value)));
double mz = scan.MassSpectrum.XArray[i];
double intensity = scan.MassSpectrum.YArray[i];

for (int i = 0; i < scan.MassSpectrum.XArray.Length; i++)
if (!alreadyClaimedMzs.Contains(ClassExtensions.RoundedDouble(mz).Value))
{
double mz = scan.MassSpectrum.XArray[i];
double intensity = scan.MassSpectrum.YArray[i];

if (!alreadyClaimedMzs.Contains(ClassExtensions.RoundedDouble(mz).Value))
{
neutralExperimentalFragmentMasses.Add(new IsotopicEnvelope(
new List<(double mz, double intensity)> { (mz, intensity) },
mz.ToMass(1), 1, intensity, 0, 0));
}
neutralExperimentalFragmentMasses.Add(new IsotopicEnvelope(
new List<(double mz, double intensity)> { (mz, intensity) },
mz.ToMass(1), 1, intensity, 0));
}
}

Expand Down
2 changes: 1 addition & 1 deletion MetaMorpheus/GUI/GUI.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
<PackageReference Include="Microsoft.ML.CpuMath" Version="3.0.1" />
<PackageReference Include="Microsoft.ML.FastTree" Version="3.0.1" />
<PackageReference Include="Microsoft.NETCore.App" Version="2.2.8" />
<PackageReference Include="mzLib" Version="1.0.552" />
<PackageReference Include="mzLib" Version="5.2.8" />
<PackageReference Include="Nett" Version="0.15.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="OxyPlot.Core" Version="2.0.0" />
Expand Down
4 changes: 2 additions & 2 deletions MetaMorpheus/GUI/MainWindow.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@
<!--Text content-->
<TextBlock Grid.Row="3" Style="{StaticResource TextBlockStyle}">
MetaMorpheus is a search program for MS/MS proteomics data. It takes a protein database (.xml or .fasta)
as input,as well as spectra files in .mzML, .mgf, or Thermo .raw format. Optionally, a spectral library
as input,as well as spectra files in ms2.msalign, .mzML, .mgf, or Thermo .raw format. Optionally, a spectral library
(.msp) can be used to improve search results.

<LineBreak />
Expand Down Expand Up @@ -458,7 +458,7 @@

<!--Detail text-->
<TextBlock Grid.Row="1" Style="{StaticResource TextBlockStyle}">
Add spectra file(s) in .mzML, .mgf, or Thermo .raw format.
Add spectra file(s) in ms2.msalign .mzML, .mgf, or Thermo .raw format.
</TextBlock>

<!--Button to add spectra files-->
Expand Down
15 changes: 14 additions & 1 deletion MetaMorpheus/GUI/MainWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -516,7 +516,7 @@ private void Window_Drop(object sender, DragEventArgs e)
/// </summary>
private void AddSpectraFile_Click(object sender, RoutedEventArgs e)
{
var openPicker = StartOpenFileDialog("Spectra Files(*.raw;*.mzML;*.mgf)|*.raw;*.mzML;*.mgf");
var openPicker = StartOpenFileDialog("Spectra Files(*.raw;*.mzML;*.mgf;*.msalign)|*.raw;*.mzML;*.mgf;*.msalign");

if (openPicker.ShowDialog() == true)
{
Expand Down Expand Up @@ -710,6 +710,7 @@ private void AddGlycoSearchTask_Click(object sender, RoutedEventArgs e)
{
OpenNewTaskWindow(MyTask.GlycoSearch);
}

private void AddAveragingTaskButton_OnClick(object sender, RoutedEventArgs e)
{
OpenNewTaskWindow(MyTask.Average);
Expand Down Expand Up @@ -1578,6 +1579,18 @@ private void AddPreRunFile(string filePath)
NotificationHandler(null, new StringEventArgs(".mgf files lack MS1 spectra, which are needed for quantification and searching for coisolated peptides. All other features of MetaMorpheus will function.", null));
goto case ".mzml";

case ".msalign":
if (filePath.Contains("_ms2."))
{
NotificationHandler(null, new StringEventArgs("MS2-only msalign files lack MS1 spectra, which are needed for quantification and searching for coisolated peptides. All other features of MetaMorpheus will function.", null));
goto case ".mzml";
}
else if (filePath.Contains("_ms1."))
{
NotificationHandler(null, new StringEventArgs("MS1 align file type not currently supported " + theExtension, null));
}
break;

case ".mzml":
if (compressed) // not implemented yet
{
Expand Down
2 changes: 1 addition & 1 deletion MetaMorpheus/GUI/MetaDraw/MetaDraw.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public partial class MetaDraw : Window
public PtmLegendViewModel PtmLegend;
public ChimeraLegendViewModel ChimeraLegend;
private ObservableCollection<ModTypeForTreeViewModel> Modifications = new ObservableCollection<ModTypeForTreeViewModel>();
private static List<string> AcceptedSpectraFormats = new List<string> { ".mzml", ".raw", ".mgf" };
private static List<string> AcceptedSpectraFormats = new List<string> { ".mzml", ".raw", ".mgf", ".msalign" };
private static List<string> AcceptedResultsFormats = new List<string> { ".psmtsv", ".tsv" };
private static List<string> AcceptedSpectralLibraryFormats = new List<string> { ".msp" };
private MetaDrawSettingsViewModel SettingsView;
Expand Down
2 changes: 1 addition & 1 deletion MetaMorpheus/GuiFunctions/GuiFunctions.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
<ItemGroup>
<PackageReference Include="itext7" Version="8.0.5" />
<PackageReference Include="itext7.bouncy-castle-adapter" Version="8.0.5" />
<PackageReference Include="mzLib" Version="1.0.552" />
<PackageReference Include="mzLib" Version="5.2.8" />
<PackageReference Include="OxyPlot.Wpf" Version="2.0.0" />
<PackageReference Include="Svg" Version="3.4.7" />
</ItemGroup>
Expand Down
65 changes: 65 additions & 0 deletions MetaMorpheus/TaskLayer/MetaMorpheusTask.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
using SpectralAveraging;
using UsefulProteomicsDatabases;
using Easy.Common.Extensions;
using Readers;

namespace TaskLayer
{
Expand Down Expand Up @@ -129,6 +130,66 @@ public static List<Ms2ScanWithSpecificMass>[] _GetMs2Scans(MsDataFile myMSDataFi
return scansWithPrecursors;
}

// short circuit for already deconvoluted files
if (myMSDataFile is MsAlign align)
{
// if only ms2align, no precursor scans
if (align.All(scan => scan.MsnOrder == 2))
{
for (int i = 0; i < ms2Scans.Length; i++)
{

scansWithPrecursors[i] = new List<Ms2ScanWithSpecificMass>()
{
new Ms2ScanWithSpecificMass(ms2Scans[i], ms2Scans[i].SelectedIonMonoisotopicGuessMz!.Value,
ms2Scans[i].SelectedIonChargeStateGuess!.Value, fullFilePath, commonParameters, null,
ms2Scans[i].SelectedIonIntensity ?? 1)
};
}
return scansWithPrecursors;
}

// If precursor scans are present
var groups = align.GroupBy(p => p.OneBasedPrecursorScanNumber)
.ToDictionary(p => p.Key, p => p.ToArray());
scansWithPrecursors = new List<Ms2ScanWithSpecificMass>[groups.Count];

for (var index = 0; index < groups.Count; index++)
{
var precursorScanNumber = groups.ElementAt(index).Key;
var fragmentationScans = groups.ElementAt(index).Value;
var localScansWithPrecursors = new List<Ms2ScanWithSpecificMass>(fragmentationScans.Length);

// no precursor scan
if (precursorScanNumber is null)
{
for (int i = 0; i < fragmentationScans.Length; i++)
{
localScansWithPrecursors[i] = new Ms2ScanWithSpecificMass(ms2Scans[i],
ms2Scans[i].SelectedIonMonoisotopicGuessMz!.Value,
ms2Scans[i].SelectedIonChargeStateGuess!.Value, fullFilePath, commonParameters, null,
ms2Scans[i].SelectedIonIntensity ?? 1);
}
}
else
{
// TODO: use the ms1.align to determine if chimeric spectra occurred
double sumOfIntensity = fragmentationScans.Sum(p => p.SelectedIonIntensity ?? 1);
for (int i = 0; i < fragmentationScans.Length; i++)
{
localScansWithPrecursors[i] = new Ms2ScanWithSpecificMass(ms2Scans[i],
ms2Scans[i].SelectedIonMonoisotopicGuessMz!.Value,
ms2Scans[i].SelectedIonChargeStateGuess!.Value, fullFilePath, commonParameters, null,
ms2Scans[i].SelectedIonIntensity!.Value / sumOfIntensity);
}
}

scansWithPrecursors[index] = localScansWithPrecursors;
}

return scansWithPrecursors;
}

Parallel.ForEach(Partitioner.Create(0, ms2Scans.Length), new ParallelOptions { MaxDegreeOfParallelism = commonParameters.MaxThreadsToUsePerFile },
(partitionRange, loopState) =>
{
Expand All @@ -145,6 +206,9 @@ public static List<Ms2ScanWithSpecificMass>[] _GetMs2Scans(MsDataFile myMSDataFi
{
MsDataScan precursorSpectrum = myMSDataFile.GetOneBasedScan(ms2scan.OneBasedPrecursorScanNumber.Value);

if (precursorSpectrum is null)
goto PrecursorFromScanHeader;

try
{
ms2scan.RefineSelectedMzAndIntensity(precursorSpectrum.MassSpectrum);
Expand Down Expand Up @@ -191,6 +255,7 @@ public static List<Ms2ScanWithSpecificMass>[] _GetMs2Scans(MsDataFile myMSDataFi
}

//if use precursor info from scan header and scan header has charge state
PrecursorFromScanHeader:
if (commonParameters.UseProvidedPrecursorInfo && ms2scan.SelectedIonChargeStateGuess.HasValue)
{
int precursorCharge = ms2scan.SelectedIonChargeStateGuess.Value;
Expand Down
2 changes: 1 addition & 1 deletion MetaMorpheus/TaskLayer/SearchTask/SearchTask.cs
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ protected override MyTaskResults RunSpecific(string OutputFolder, List<DbForTask
if (SearchParameters.DoLabelFreeQuantification)
{
// disable quantification if a .mgf is being used
if (currentRawFileList.Any(x => Path.GetExtension(x).Equals(".mgf", StringComparison.OrdinalIgnoreCase)))
if (currentRawFileList.Any(x => x.EndsWith(".mgf", StringComparison.OrdinalIgnoreCase) || x.EndsWith("_ms2.msalign", StringComparison.OrdinalIgnoreCase)))
{
SearchParameters.DoLabelFreeQuantification = false;
}
Expand Down
2 changes: 1 addition & 1 deletion MetaMorpheus/TaskLayer/TaskLayer.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
<PackageReference Include="Microsoft.ML.CpuMath" Version="3.0.1" />
<PackageReference Include="Microsoft.ML.FastTree" Version="3.0.1" />
<PackageReference Include="Microsoft.NETCore.App" Version="2.2.8" />
<PackageReference Include="mzLib" Version="1.0.552" />
<PackageReference Include="mzLib" Version="5.2.8" />
<PackageReference Include="NetSerializer" Version="4.1.2" />
<PackageReference Include="Nett" Version="0.15.0" />
</ItemGroup>
Expand Down
2 changes: 1 addition & 1 deletion MetaMorpheus/Test/SearchEngineTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ public static void TestSearchEngineResultsPsmFromTsv()
public static void TestXCorrWithNoPeaks()
{
MsDataScan datascan = new MsDataScan(new MzSpectrum(new double[,] { }), 0, 0, true, Polarity.Positive, 0, new MzLibUtil.MzRange(0, 2000), "", MZAnalyzerType.FTICR, 1, null, null, "");
Ms2ScanWithSpecificMass scan = new Ms2ScanWithSpecificMass(datascan, 0, 0, "", new CommonParameters(), new IsotopicEnvelope[] { new IsotopicEnvelope(new List<(double mz, double intensity)> { (1, 1) }, 32, 2, 23, 1, 1) });
Ms2ScanWithSpecificMass scan = new Ms2ScanWithSpecificMass(datascan, 0, 0, "", new CommonParameters(), new IsotopicEnvelope[] { new IsotopicEnvelope(new List<(double mz, double intensity)> { (1, 1) }, 32, 2, 23, 1) });
scan.TheScan.MassSpectrum.XCorrPrePreprocessing(0, 1, 32);
MetaMorpheusEngine.MatchFragmentIons(scan, new List<Product> { (new Product(ProductType.y, FragmentationTerminus.C, 0, 1, 1, 0)) }, new CommonParameters(dissociationType: DissociationType.LowCID));
}
Expand Down
2 changes: 1 addition & 1 deletion MetaMorpheus/Test/Test.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
<PackageReference Include="Microsoft.ML" Version="3.0.1" />
<PackageReference Include="Microsoft.ML.CpuMath" Version="3.0.1" />
<PackageReference Include="Microsoft.ML.FastTree" Version="3.0.1" />
<PackageReference Include="mzLib" Version="1.0.552" />
<PackageReference Include="mzLib" Version="5.2.8" />
<PackageReference Include="NUnit" Version="4.1.0" />
<PackageReference Include="NUnit3TestAdapter" Version="4.6.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0" />
Expand Down
34 changes: 34 additions & 0 deletions MetaMorpheus/Test/TestMsAlign.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using EngineLayer;
using NUnit.Framework;
using Proteomics.ProteolyticDigestion;
using TaskLayer;

namespace Test
{
internal class TestMsAlign
{

[Test]
public static void TESTNAME()
{
var path =
@"B:\Users\Nic\Chimeras\TopDown_Analysis\Jurkat\DeconResults\TopFD\02-17-20_jurkat_td_rep2_fract4_ms2.msalign";
var fileManager = new MyFileManager(true);
var dataFile = fileManager.LoadFile(path, new CommonParameters());

dataFile.LoadAllStaticData();

foreach (var scanWithMass in MetaMorpheusTask.GetMs2Scans(dataFile, path, new CommonParameters()))
{
int expectedLength = scanWithMass.TheScan.MassSpectrum.XArray.Length;

Assert.That(scanWithMass.ExperimentalFragments.Length, Is.EqualTo(expectedLength));
}
}
}
}
Loading