Skip to content

Commit 079bbe1

Browse files
committed
Added support for bruker TOF files, still buggy
1 parent 5d10144 commit 079bbe1

22 files changed

Lines changed: 2796 additions & 27 deletions

MetaMorpheus/CMD/CommandLineSettings.cs

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -99,17 +99,17 @@ public void ValidateCommandLineSettings()
9999

100100
Spectra.AddRange(spectraFromDirectories);
101101

102-
// Correct .tdf/.tdf_bin file paths to their parent .d directory
103-
// This handles the case where a user provides a path to a .tdf file directly
102+
// Correct Bruker inner-file paths (.tdf/.tdf_bin for timsTOF, .baf for regular TOF) to their parent .d directory
103+
// This handles the case where a user provides a path to one of these files directly
104104
for (int i = 0; i < Spectra.Count; i++)
105105
{
106106
string ext = Path.GetExtension(Spectra[i]).ToLowerInvariant();
107-
if (ext == ".tdf" || ext == ".tdf_bin")
107+
if (ext == ".tdf" || ext == ".tdf_bin" || ext == ".baf")
108108
{
109109
string parentDir = Path.GetDirectoryName(Spectra[i]);
110-
if (parentDir != null &&
111-
parentDir.EndsWith(".d", StringComparison.OrdinalIgnoreCase) &&
112-
IsValidTimsTofDirectory(parentDir))
110+
if (parentDir != null &&
111+
parentDir.EndsWith(".d", StringComparison.OrdinalIgnoreCase) &&
112+
IsValidBrukerDirectory(parentDir))
113113
{
114114
Spectra[i] = parentDir;
115115
}
@@ -120,7 +120,7 @@ public void ValidateCommandLineSettings()
120120
Spectra = Spectra.Distinct().ToList();
121121

122122
// remove spectra directories, after their spectra files have been added
123-
// but keep .d directories as they are valid timsTOF spectra folders
123+
// but keep .d directories as they are valid Bruker spectra folders
124124
Spectra.RemoveAll(p => Directory.Exists(p) && !p.EndsWith(".d", StringComparison.OrdinalIgnoreCase));
125125

126126
IEnumerable<string> fileNames = Tasks.Concat(Databases).Concat(Spectra);
@@ -209,12 +209,13 @@ private static void FindSpectraFilesRecursive(string path, List<string> spectraF
209209
{
210210
if (GlobalVariables.AcceptedSpectraFormats.Contains(GlobalVariables.GetFileExtension(path).ToLowerInvariant()))
211211
{
212-
// If a .tdf or .tdf_bin file is found, check if the parent directory is a valid .d folder and add that instead
213-
if (new[] { ".tdf", ".tdf_bin" }.Contains(GlobalVariables.GetFileExtension(path).ToLowerInvariant()))
212+
// If a Bruker inner file is found (.tdf/.tdf_bin for timsTOF, .baf for regular TOF),
213+
// check if the parent directory is a valid .d folder and add that instead
214+
if (new[] { ".tdf", ".tdf_bin", ".baf" }.Contains(GlobalVariables.GetFileExtension(path).ToLowerInvariant()))
214215
{
215216
var parentDirectory = Directory.GetParent(path);
216-
if (GlobalVariables.GetFileExtension(parentDirectory.FullName).ToLowerInvariant() == ".d" && IsValidTimsTofDirectory(parentDirectory.FullName))
217-
path = parentDirectory.FullName; // add the .d folder instead of the individual tdf/tsf file
217+
if (GlobalVariables.GetFileExtension(parentDirectory.FullName).ToLowerInvariant() == ".d" && IsValidBrukerDirectory(parentDirectory.FullName))
218+
path = parentDirectory.FullName; // add the .d folder instead of the individual inner file
218219
}
219220

220221
spectraFiles.Add(path);
@@ -232,8 +233,8 @@ private static void FindSpectraFilesRecursive(string path, List<string> spectraF
232233
// Check if this is a .d folder
233234
if (path.EndsWith(".d", StringComparison.OrdinalIgnoreCase))
234235
{
235-
// Check if it's a valid timsTOF data folder
236-
if (IsValidTimsTofDirectory(path))
236+
// Check if it's a valid Bruker data folder (timsTOF or regular TOF)
237+
if (IsValidBrukerDirectory(path))
237238
{
238239
spectraFiles.Add(path);
239240

@@ -255,17 +256,24 @@ private static void FindSpectraFilesRecursive(string path, List<string> spectraF
255256
}
256257

257258
/// <summary>
258-
/// Checks if a .d directory is a valid timsTOF data folder.
259+
/// Checks if a .d directory is a valid Bruker data folder that MetaMorpheus can read,
260+
/// i.e. a timsTOF folder (analysis.tdf + analysis.tdf_bin) or a regular TOF folder (analysis.baf).
259261
/// </summary>
260-
private static bool IsValidTimsTofDirectory(string directoryPath)
262+
private static bool IsValidBrukerDirectory(string directoryPath)
261263
{
262-
// for data with tims enabled, we need to have both the .tdf and .tdf_bin files
264+
// timsTOF data: needs both the .tdf and .tdf_bin files
263265
if (File.Exists(Path.Combine(directoryPath, "analysis.tdf")) &&
264266
File.Exists(Path.Combine(directoryPath, "analysis.tdf_bin")))
265267
{
266268
return true;
267269
}
268270

271+
// regular TOF data: has a .baf file
272+
if (File.Exists(Path.Combine(directoryPath, "analysis.baf")))
273+
{
274+
return true;
275+
}
276+
269277
return false;
270278
}
271279
}

MetaMorpheus/EngineLayer/GlobalVariables.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ public static class GlobalVariables
7676
public static void SetUpGlobalVariables()
7777
{
7878
AcceptedDatabaseFormats = new List<string> { ".fasta", ".fa", ".xml", ".msp" };
79-
AcceptedSpectraFormats = new List<string> { ".raw", ".mzml", ".mgf", ".msalign", ".tdf", ".tdf_bin", ".d" };
79+
AcceptedSpectraFormats = new List<string> { ".raw", ".mzml", ".mgf", ".msalign", ".tdf", ".tdf_bin", ".baf", ".d" };
8080
AnalyteType = AnalyteType.Peptide;
8181
_InvalidAminoAcids = new char[] { 'X', 'B', 'J', 'Z', ':', '|', ';', '[', ']', '{', '}', '(', ')', '+', '-' };
8282
ExperimentalDesignFileName = "ExperimentalDesign.tsv";

MetaMorpheus/GUI/MainWindow.xaml.cs

Lines changed: 40 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -512,7 +512,7 @@ private void Window_Drop(object sender, DragEventArgs e)
512512
/// </summary>
513513
private void AddSpectraFile_Click(object sender, RoutedEventArgs e)
514514
{
515-
var openPicker = StartOpenFileDialog("Spectra Files(*.raw;*.mzML;*.mgf;*ms2.msalign;*.tdf;*.tdf_bin)|*.raw;*.mzML;*.mgf;*ms2.msalign;*.tdf;*.tdf_bin");
515+
var openPicker = StartOpenFileDialog("Spectra Files(*.raw;*.mzML;*.mgf;*ms2.msalign;*.tdf;*.tdf_bin;*.baf)|*.raw;*.mzML;*.mgf;*ms2.msalign;*.tdf;*.tdf_bin;*.baf");
516516

517517
if (openPicker.ShowDialog() == true)
518518
{
@@ -1679,25 +1679,25 @@ private void AddPreRunFileRecursiveHelper(string path)
16791679
}
16801680
if (Directory.Exists(path))
16811681
{
1682-
// .d folders are usually timsTOF data - if it's a valid timsTOF file, don't recurse into it
1683-
if (path.EndsWith(".d", StringComparison.OrdinalIgnoreCase)
1684-
&& AddOrWarnTimsTofDirectory(path))
1682+
// .d folders are Bruker data - if it's a valid Bruker data file, don't recurse into it
1683+
if (path.EndsWith(".d", StringComparison.OrdinalIgnoreCase)
1684+
&& AddOrWarnBrukerDirectory(path))
16851685
return; // base case 2
16861686
foreach (var entry in Directory.EnumerateFileSystemEntries(path))
16871687
AddPreRunFileRecursiveHelper(entry);
16881688
}
16891689
}
16901690

1691-
private bool AddOrWarnTimsTofDirectory(string directoryPath)
1691+
private bool AddOrWarnBrukerDirectory(string directoryPath)
16921692
{
1693-
if (IsValidTimsTofDirectory(directoryPath))
1693+
if (IsValidBrukerDirectory(directoryPath))
16941694
{
16951695
AddPreRunFile(directoryPath);
16961696
return true;
16971697
}
16981698
else
16991699
{
1700-
NotificationHandler(null, new StringEventArgs($"{directoryPath} is not a valid timsTOF data file.", null));
1700+
NotificationHandler(null, new StringEventArgs($"{directoryPath} is not a valid Bruker data file.", null));
17011701
}
17021702
return false;
17031703
}
@@ -1716,6 +1716,27 @@ public bool IsValidTimsTofDirectory(string directoryPath)
17161716
&& File.Exists(Path.Combine(directoryPath, "analysis.tdf_bin"));
17171717
}
17181718

1719+
/// <summary>
1720+
/// Determines whether the specified directory is a valid regular (non-tims) Bruker TOF data directory.
1721+
/// </summary>
1722+
/// <param name="directoryPath">The full path to the directory to validate. The path must end with the ".d" extension.</param>
1723+
/// <returns>true if the directory exists, ends with ".d", and contains an "analysis.baf" file; otherwise, false.</returns>
1724+
public bool IsValidBafDirectory(string directoryPath)
1725+
{
1726+
return directoryPath.EndsWith(".d", StringComparison.OrdinalIgnoreCase)
1727+
&& Directory.Exists(directoryPath)
1728+
&& File.Exists(Path.Combine(directoryPath, "analysis.baf"));
1729+
}
1730+
1731+
/// <summary>
1732+
/// Determines whether the specified .d directory is a Bruker data directory that MetaMorpheus can read,
1733+
/// i.e. either a timsTOF directory or a regular TOF directory.
1734+
/// </summary>
1735+
public bool IsValidBrukerDirectory(string directoryPath)
1736+
{
1737+
return IsValidTimsTofDirectory(directoryPath) || IsValidBafDirectory(directoryPath);
1738+
}
1739+
17191740
private void AddPreRunFile(string filePath)
17201741
{
17211742
if (!RunTasksButton.IsEnabled)
@@ -1794,7 +1815,7 @@ private void AddPreRunFile(string filePath)
17941815
break;
17951816
case ".tdf":
17961817
case ".tdf_bin":
1797-
// for Bruker timsTof files, the .tdf and .tdf_bin files are in a ".d" directory
1818+
// for Bruker timsTof files, the .tdf and .tdf_bin files are in a ".d" directory
17981819
// the fileReader is designed to take the path to the .d directory instead of the individual files
17991820
var parent = Path.GetDirectoryName(filePath);
18001821
if (!IsValidTimsTofDirectory(parent))
@@ -1804,6 +1825,17 @@ private void AddPreRunFile(string filePath)
18041825
}
18051826
filePath = parent; // change the file path to the .d directory so that it can be properly read by the file reader
18061827
goto case ".d";
1828+
case ".baf":
1829+
// for regular Bruker TOF files, the analysis.baf file is in a ".d" directory
1830+
// the fileReader is designed to take the path to the .d directory instead of the individual files
1831+
var bafParent = Path.GetDirectoryName(filePath);
1832+
if (!IsValidBafDirectory(bafParent))
1833+
{
1834+
NotificationHandler(null, new StringEventArgs($"{bafParent} is not a valid Bruker data file; {filePath} could not be added.", null));
1835+
return;
1836+
}
1837+
filePath = bafParent; // change the file path to the .d directory so that it can be properly read by the file reader
1838+
goto case ".d";
18071839
case ".d": // Bruker data files are directories that contain .d files
18081840
NotificationHandler(null, new StringEventArgs("Quantification and calibration are not currently supported for Bruker data files. All other features of MetaMorpheus will function.", null));
18091841
goto case ".mzml";

MetaMorpheus/GUI/MetaDraw/MetaDraw.xaml.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,8 +110,9 @@ private void AddFile(string filePath)
110110

111111
if (GlobalVariables.AcceptedSpectraFormats.Contains(theExtension))
112112
{
113-
// If a bruker timsTof file was selected, we actually want the parent folder
114-
if(theExtension == ".tdf" || theExtension == ".tdf_bin")
113+
// If a Bruker inner file was selected (.tdf/.tdf_bin for timsTOF, .baf for regular TOF),
114+
// we actually want the parent .d folder
115+
if(theExtension == ".tdf" || theExtension == ".tdf_bin" || theExtension == ".baf")
115116
{
116117
filePath = Path.GetDirectoryName(filePath);
117118
}

MetaMorpheus/MetaMorpheusSetup/Product.wxs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,14 @@
360360
<Component Id="src_timsdata.dll" Guid="22BAA8D2-623B-493E-932E-666A27ECC5A0">
361361
<File Id="src_timsdata.dll" Name="timsdata.dll" Source="$(var.GUI_TargetDir)timsdata.dll" />
362362
</Component>
363+
<!--Native Bruker baf2sql library (+ its vcomp110 dependency) for reading regular (non-tims)
364+
Bruker TOF .d files. mzLib P/Invokes baf2sql_c by bare name, so it loads from the app root.-->
365+
<Component Id="src_baf2sql_c.dll" Guid="ebbca9cb-0e89-4ce8-b540-04bd0d327da4">
366+
<File Id="src_baf2sql_c.dll" Name="baf2sql_c.dll" Source="$(var.GUI_TargetDir)baf2sql_c.dll" />
367+
</Component>
368+
<Component Id="src_vcomp110.dll" Guid="e18833e2-6562-43bf-9001-d148aa9da919">
369+
<File Id="src_vcomp110.dll" Name="vcomp110.dll" Source="$(var.GUI_TargetDir)vcomp110.dll" />
370+
</Component>
363371
<Component Id="src_ThermoFisher.CommonCore.BackgroundSubtraction.dll" Guid="F3DA60DB-CF5F-4671-9F3C-1033780261DD">
364372
<File Id="src_ThermoFisher.CommonCore.BackgroundSubtraction.dll" Name="ThermoFisher.CommonCore.BackgroundSubtraction.dll" Source="$(var.GUI_TargetDir)ThermoFisher.CommonCore.BackgroundSubtraction.dll" />
365373
</Component>

MetaMorpheus/Test/MsDataFileTest.cs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,37 @@ public static void Setup()
1919
Environment.CurrentDirectory = TestContext.CurrentContext.TestDirectory;
2020
}
2121

22+
/// <summary>
23+
/// Verifies that a regular (non-tims) centroided Bruker TOF .d folder (identified by
24+
/// analysis.baf) loads through MetaMorpheus's file manager and exposes the expected spectra.
25+
/// </summary>
26+
/// <remarks>
27+
/// Only centroid data is covered here. Profile-mode Bruker TOF data currently throws
28+
/// IndexOutOfRangeException in mzLib's BrukerFileReader.GetSpectraData when peak filtering
29+
/// is applied (which MyFileManager always does); add profile coverage once that mzLib bug is fixed.
30+
/// </remarks>
31+
[Test]
32+
public static void TestBrukerTofFileLoadsThroughMyFileManager()
33+
{
34+
string dotDPath = Path.Combine(TestContext.CurrentContext.TestDirectory, @"TestData\centroid_1x_MS1_4x_autoMS2.d");
35+
Assert.That(Directory.Exists(dotDPath), Is.True, "Test requires the centroid Bruker TOF .d folder to exist");
36+
37+
var dataFile = new MyFileManager(true).LoadFile(dotDPath, new CommonParameters());
38+
39+
Assert.That(dataFile.NumSpectra, Is.EqualTo(5));
40+
var secondScan = dataFile.Scans[1];
41+
Assert.That(secondScan.MsnOrder, Is.EqualTo(2));
42+
Assert.That(secondScan.Polarity, Is.EqualTo(Polarity.Positive));
43+
Assert.That(secondScan.DissociationType, Is.EqualTo(DissociationType.CID));
44+
Assert.That(secondScan.IsCentroid, Is.True);
45+
Assert.That(secondScan.NativeId, Is.EqualTo("scan=2"));
46+
Assert.That(secondScan.SelectedIonMZ, Is.EqualTo(721.86865).Within(0.001));
47+
}
48+
2249
[Test]
2350
[TestCase(@"TestData\ok.mgf", @"TestData\okk.xml")]
2451
[TestCase(@"TestData\snippet.d", @"TestData\gapdh.fasta")]
52+
[TestCase(@"TestData\centroid_1x_MS1_4x_autoMS2.d", @"TestData\gapdh.fasta")]
2553
[TestCase(@"TopDownTestData\JurkatTopDownRep2Fract1_ms2.msalign", @"TestData\gapdh.fasta")]
2654
public static void TestQuantificationDoesntCrashOnUnsupportedFiles(string filepath, string dbPath)
2755
{
@@ -54,6 +82,7 @@ public static void TestQuantificationDoesntCrashOnUnsupportedFiles(string filepa
5482
[Test]
5583
[TestCase(@"TestData\ok.mgf", @"TestData\okk.xml")]
5684
[TestCase(@"TestData\snippet.d", @"TestData\gapdh.fasta")]
85+
[TestCase(@"TestData\centroid_1x_MS1_4x_autoMS2.d", @"TestData\gapdh.fasta")]
5786
[TestCase(@"TopDownTestData\JurkatTopDownRep2Fract1_ms2.msalign", @"TestData\gapdh.fasta")]
5887
public static void TestCalibrationDoesntCrashOnUnsupportedFiles(string filepath, string dbPath)
5988
{
@@ -88,6 +117,7 @@ public static void TestCalibrationDoesntCrashOnUnsupportedFiles(string filepath,
88117
[Test]
89118
[TestCase(@"TestData\ok.mgf", @"TestData\okk.xml")]
90119
[TestCase(@"TestData\snippet.d", @"TestData\gapdh.fasta")]
120+
[TestCase(@"TestData\centroid_1x_MS1_4x_autoMS2.d", @"TestData\gapdh.fasta")]
91121
[TestCase(@"TopDownTestData\JurkatTopDownRep2Fract1_ms2.msalign", @"TestData\gapdh.fasta")]
92122
public static void TestAveragingDoesntCrashOnUnsupportedFiles(string filepath, string dbPath)
93123
{

0 commit comments

Comments
 (0)