-
Notifications
You must be signed in to change notification settings - Fork 0
/
Program.cs
342 lines (297 loc) · 14.2 KB
/
Program.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
// This program converts search results from various MS/MS identification tools into a series
// of tab-delimited text files that organize the data in a similar format for each tool.
// It supports MS-GF+, MaxQuant, MSFragger, MODa, MODPlus, MSAlign, MSPathFinder,
// TopPIC, and X!Tandem, along with SEQUEST Synopsis/First Hits files.
//
// -------------------------------------------------------------------------------
// Written by Matthew Monroe for the Department of Energy (PNNL, Richland, WA)
// Program started January 2, 2006
//
// E-mail: [email protected] or [email protected]
// Website: https://github.com/PNNL-Comp-Mass-Spec/ or https://www.pnnl.gov/integrative-omics
// -------------------------------------------------------------------------------
using System;
using System.IO;
using System.Reflection;
using System.Threading;
using PeptideHitResultsProcessor;
using PeptideHitResultsProcessor.Processor;
using PRISM;
namespace PeptideHitResultsProcRunner
{
internal static class Program
{
// Ignore Spelling: conf, Prot, MaxQuant, MODa, txt
private static DateTime mLastProgressReportTime;
private static int mLastProgressReportValue;
private static DateTime mLastProgressReportValueTime;
private static bool mSkippedInitialProgressValue;
/// <summary>
/// Program entry point
/// </summary>
/// <returns>0 if no error, error code if an error</returns>
public static int Main(string[] args)
{
var exeName = Assembly.GetEntryAssembly()?.GetName().Name;
var parser = new CommandLineParser<PHRPOptions>(exeName, PHRPBaseClass.GetAppVersion())
{
ProgramInfo = "This program converts search results from various MS/MS identification tools " +
"into a series of tab-delimited text files that organize the data in a similar format for each tool. " +
"It supports MS-GF+, MaxQuant, MSFragger, MODa, MODPlus, MSAlign, " +
"MSPathFinder, TopPIC, and X!Tandem, along with SEQUEST Synopsis/First Hits files.",
ContactInfo = "Program written by Matthew Monroe for PNNL (Richland, WA)" + Environment.NewLine +
"E-mail: [email protected] or [email protected]" + Environment.NewLine +
"Website: https://github.com/PNNL-Comp-Mass-Spec/ or https://www.pnnl.gov/integrative-omics"
};
parser.UsageExamples.Add(string.Format(
"The input file should be one of the following:\n" +
" MaxQuant results files (msms.txt and peptides.txt)\n" +
" MS-GF+ results file ({0}.tsv or {1}.tsv or .tsv)\n" +
" MSGF-DB results file ({1}.txt)\n" +
" MSAlign results file ({2}.txt)\n" +
" MODa results file ({3}.txt)\n" +
" MODPlus results file ({4}.txt)\n" +
" MsFragger results file (_psm.tsv)\n" +
" MSPathFinder results file ({5}.txt)\n" +
" InSpecT results file ({6}.txt)\n" +
" SEQUEST Synopsis File ({7}.txt)\n" +
" SEQUEST First Hits file ({8}.txt)\n" +
" TopPIC results file ({9}.txt)\n" +
" X!Tandem Results file (_xt.xml)",
MSGFPlusResultsProcessor.FILENAME_SUFFIX_MSGFPLUS_FILE,
MSGFPlusResultsProcessor.FILENAME_SUFFIX_MSGFDB_FILE,
MSAlignResultsProcessor.FILENAME_SUFFIX_MSALIGN_FILE,
MODaResultsProcessor.FILENAME_SUFFIX_MODA_FILE,
MODPlusResultsProcessor.FILENAME_SUFFIX_MODPlus_FILE,
MSPathFinderResultsProcessor.FILENAME_SUFFIX_MSPathFinder_FILE,
InSpecTResultsProcessor.FILENAME_SUFFIX_INSPECT_FILE,
SequestResultsProcessor.FILENAME_SUFFIX_SYNOPSIS_FILE,
SequestResultsProcessor.FILENAME_SUFFIX_FIRST_HITS_FILE,
TopPICResultsProcessor.FILENAME_SUFFIX_TopPIC_PRSMs_FILE
));
// The default argument name for parameter files is /ParamFile or -ParamFile
// Also allow /Conf or /P
parser.AddParamFileKey("Conf");
parser.AddParamFileKey("P");
var result = parser.ParseArgs(args);
var options = result.ParsedResults;
if (!result.Success || !options.Validate())
{
if (parser.CreateParamFileProvided)
{
return 0;
}
// Delay for 750 msec in case the user double-clicked this file from within Windows Explorer (or started the program via a shortcut)
Thread.Sleep(750);
return -1;
}
try
{
if (InvalidParameterFile(parser.ParameterFilePath))
{
return -1;
}
var peptideHitResultsProcessor = new PeptideHitResultsProcRunner(options);
peptideHitResultsProcessor.DebugEvent += PeptideHitResultsProcRunner_DebugEvent;
peptideHitResultsProcessor.ErrorEvent += PeptideHitResultsProcRunner_ErrorEvent;
peptideHitResultsProcessor.StatusEvent += PeptideHitResultsProcRunner_MessageEvent;
peptideHitResultsProcessor.ProgressUpdate += PeptideHitResultsProcRunner_ProgressChanged;
peptideHitResultsProcessor.ProgressReset += PeptideHitResultsProcRunner_ProgressReset;
peptideHitResultsProcessor.WarningEvent += PeptideHitResultsProcRunner_WarningEvent;
if (options.LogMessagesToFile && args.Length > 0)
{
// Append the command line arguments to the log file
peptideHitResultsProcessor.SkipConsoleWriteIfNoStatusListener = true;
peptideHitResultsProcessor.LogAdditionalMessage(string.Join(" ", args));
peptideHitResultsProcessor.SkipConsoleWriteIfNoStatusListener = false;
}
int returnCode;
if (options.RecurseDirectories)
{
Console.WriteLine("Recursively processing files in the input file's directory and below");
if (peptideHitResultsProcessor.ProcessFilesAndRecurseDirectories(
options.InputFilePath,
options.OutputDirectoryPath,
string.Empty, // options.OutputDirectoryAlternatePath
false, // options.RecreateDirectoryHierarchyInAlternatePath
options.XmlParameterFile,
options.MaxLevelsToRecurse))
{
returnCode = 0;
}
else
{
returnCode = (int)peptideHitResultsProcessor.ErrorCode;
}
}
else
{
bool success;
if (options.InputFilePath.Contains("*") || options.InputFilePath.Contains("?"))
{
success = peptideHitResultsProcessor.ProcessFilesWildcard(
options.InputFilePath,
options.OutputDirectoryPath,
options.XmlParameterFile);
}
else
{
success = peptideHitResultsProcessor.ProcessFile(
options.InputFilePath,
options.OutputDirectoryPath,
options.XmlParameterFile);
}
if (success)
{
returnCode = 0;
}
else
{
var errorCode = (int)peptideHitResultsProcessor.ErrorCode;
if (errorCode == 0)
{
returnCode = -1;
ShowErrorMessage("ProcessFilesWildcard returned Success=False");
}
else
{
returnCode = errorCode;
ShowErrorMessage("Error while processing: " + peptideHitResultsProcessor.GetErrorMessage());
}
}
}
DisplayProgressPercent(mLastProgressReportValue, true);
return returnCode;
}
catch (Exception ex)
{
ShowErrorMessage("Error occurred in modMain->Main: " + Environment.NewLine + ex.Message);
return -1;
}
}
private static void DisplayProgressPercent(int percentComplete, bool addCarriageReturn)
{
if (addCarriageReturn)
{
Console.WriteLine();
}
if (percentComplete > 100)
{
percentComplete = 100;
}
Console.Write("Processing: " + percentComplete + "% ");
if (addCarriageReturn)
{
Console.WriteLine();
}
}
private static bool InvalidParameterFile(string parameterFilePath)
{
if (string.IsNullOrWhiteSpace(parameterFilePath))
{
return false;
}
// Assure that the user did not provide an old-style XML-based parameter file
var paramFile = new FileInfo(parameterFilePath);
if (!paramFile.Extension.Equals(".xml", StringComparison.OrdinalIgnoreCase))
{
return false;
}
using var paramFileReader = new StreamReader(new FileStream(paramFile.FullName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite));
var linesRead = 0;
while (!paramFileReader.EndOfStream && linesRead < 5)
{
var dataLine = paramFileReader.ReadLine();
if (string.IsNullOrWhiteSpace(dataLine))
{
continue;
}
linesRead++;
var trimmedLine = dataLine.Trim();
if (trimmedLine.StartsWith("<?xml", StringComparison.OrdinalIgnoreCase) ||
trimmedLine.StartsWith("<sections", StringComparison.OrdinalIgnoreCase))
{
ConsoleMsgUtils.ShowWarning(
"PeptideHitResultsProcRunner v3.1 uses Key=Value parameter files\n" +
"{0} is an XML file\n" +
"For an example parameter file, see file PHRP_Options.conf at {1}",
paramFile.Name, "https://github.com/PNNL-Comp-Mass-Spec/PHRP/tree/master/Data");
ConsoleMsgUtils.ShowWarning("Aborting");
return true;
}
}
return false;
}
private static void ShowErrorMessage(string message, Exception ex = null)
{
ConsoleMsgUtils.ShowError(message, ex);
}
private static void PeptideHitResultsProcRunner_DebugEvent(string message)
{
ConsoleMsgUtils.ShowDebug(message);
}
private static void PeptideHitResultsProcRunner_ErrorEvent(string message, Exception ex)
{
ShowErrorMessage(message, ex);
}
private static void PeptideHitResultsProcRunner_MessageEvent(string message)
{
Console.WriteLine(message);
}
private static void PeptideHitResultsProcRunner_ProgressChanged(string taskDescription, float percentComplete)
{
const int PERCENT_REPORT_INTERVAL = 25;
const int PROGRESS_DOT_INTERVAL_MSEC = 250;
const int PROGRESS_VALUE_INTERVAL_SEC = 60;
if (percentComplete >= mLastProgressReportValue)
{
if (!mSkippedInitialProgressValue)
{
mSkippedInitialProgressValue = true;
return;
}
if (mLastProgressReportValue > 0)
{
Console.WriteLine();
}
DisplayProgressPercent(mLastProgressReportValue, false);
mLastProgressReportValue += PERCENT_REPORT_INTERVAL;
mLastProgressReportTime = DateTime.UtcNow;
}
else
{
if (DateTime.UtcNow.Subtract(mLastProgressReportTime).TotalMilliseconds > PROGRESS_DOT_INTERVAL_MSEC)
{
mLastProgressReportTime = DateTime.UtcNow;
if (DateTime.UtcNow.Subtract(mLastProgressReportValueTime).TotalSeconds > PROGRESS_VALUE_INTERVAL_SEC)
{
mLastProgressReportValueTime = DateTime.UtcNow;
Console.WriteLine();
Console.Write(percentComplete.ToString("0.00") + "% complete ");
}
else
{
Console.Write(".");
}
}
}
}
private static void PeptideHitResultsProcRunner_ProgressReset()
{
mLastProgressReportTime = DateTime.UtcNow;
mLastProgressReportValueTime = DateTime.UtcNow;
mLastProgressReportValue = 0;
}
private static void PeptideHitResultsProcRunner_WarningEvent(string message)
{
if (message.StartsWith("Warning", StringComparison.OrdinalIgnoreCase))
{
ConsoleMsgUtils.ShowWarning(message);
}
else
{
ConsoleMsgUtils.ShowWarning("Warning: " + message);
}
}
}
}