libpappsomspp
Library for mass spectrometry
Loading...
Searching...
No Matches
tandemwrapperrun.cpp
Go to the documentation of this file.
1/**
2 * \file pappsomspp/processing/tandemwrapper/tandemwrapperrun.cpp
3 * \date 25/01/2020
4 * \author Olivier Langella
5 * \brief actually does really run tandem directly on Bruker's data
6 */
7
8/*******************************************************************************
9 * Copyright (c) 2020 Olivier Langella <Olivier.Langella@u-psud.fr>.
10 *
11 * This file is part of PAPPSOms-tools.
12 *
13 * PAPPSOms-tools is free software: you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation, either version 3 of the License, or
16 * (at your option) any later version.
17 *
18 * PAPPSOms-tools is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with PAPPSOms-tools. If not, see <http://www.gnu.org/licenses/>.
25 *
26 ******************************************************************************/
27
28#include "tandemwrapperrun.h"
29#include <QDebug>
30#include <QFileInfo>
31#include <QSettings>
32#include <QThread>
33#include <QThreadPool>
34#include <QElapsedTimer>
35#include <QRegularExpression>
42#include "wraptandemresults.h"
43#include "xtandempresetreader.h"
44#include "wraptandeminput.h"
45
46namespace pappso
47{
48
49
50TandemWrapperRun::TandemWrapperRun(const QString &tandem_binary, const QString &tmp_dir)
51{
52
53 setTandemBinaryPath(tandem_binary);
54
55 if(!tmp_dir.isEmpty())
56 {
57 mpa_temporaryDirectory = new QTemporaryDir(tmp_dir + "/xtpwrp");
58 }
59 else
60 {
61 mpa_temporaryDirectory = new QTemporaryDir(QDir::tempPath() + "/xtpwrp");
62 }
63 mpa_temporaryDirectory->setAutoRemove(true);
64 if(!mpa_temporaryDirectory->isValid())
65 {
67 QObject::tr("ERROR: unable to create temporary directory %1\n Please "
68 "check file system permissions")
69 .arg(mpa_temporaryDirectory->path()));
70 }
71}
72
74{
75 if(mpa_temporaryDirectory != nullptr)
76 {
78 }
79
80 if(m_xtProcess != nullptr)
81 {
82 m_xtProcess->deleteLater();
83 }
84}
85
86void
87TandemWrapperRun::setTandemBinaryPath(const QString &tandem_binary_path)
88{
89
90
91 m_tandemBinary = tandem_binary_path;
92 QSettings settings;
93 if(m_tandemBinary.isEmpty())
94 {
95 m_tandemBinary = settings.value("path/tandem_binary", "/usr/bin/tandem").toString();
96 }
97 // check for tandem executable
99
100 qDebug() << m_tandemVersion;
101 settings.setValue("path/tandem_binary", m_tandemBinary);
102}
103
104
105const QString
106TandemWrapperRun::checkXtandemVersion(const QString &tandem_bin_path)
107{
108 qDebug();
109 // check tandem path
110 QFileInfo tandem_exe(tandem_bin_path);
111 if(!tandem_exe.exists())
112 {
113 // dir.path() returns the unique directory path
115 QObject::tr("X!Tandem software not found at %1.\nPlease check the X!Tandem "
116 "installation on your computer and set tandem.exe path.")
117 .arg(tandem_exe.absoluteFilePath()));
118 }
119 if(!tandem_exe.isReadable())
120 {
121 // dir.path() returns the unique directory path
123 QObject::tr("Please check permissions on X!Tandem software found at %1 "
124 "(file not readable).")
125 .arg(tandem_exe.absoluteFilePath()));
126 }
127 if(!tandem_exe.isExecutable())
128 {
129 // dir.path() returns the unique directory path
131 QObject::tr("Please check permissions on X!Tandem software found at %1 "
132 "(file not executable).")
133 .arg(tandem_exe.absoluteFilePath()));
134 }
135
136
137 QString version_return;
138 QStringList arguments;
139
140 arguments << "-v";
141
142 QProcess *xt_process = new QProcess();
143 // hk_process->setWorkingDirectory(QFileInfo(_hardklor_exe).absolutePath());
144
145 xt_process->start(tandem_bin_path, arguments);
146
147 if(!xt_process->waitForStarted())
148 {
150 QObject::tr("X!Tandem %1 process failed to start").arg(m_tandemVersion));
151 }
152
153 while(xt_process->waitForReadyRead(1000))
154 {
155 }
156 /*
157 if (!xt_process->waitForFinished(_max_xt_time_ms)) {
158 throw pappso::PappsoException(QObject::tr("can't wait for X!Tandem process
159 to finish : timeout at %1").arg(_max_xt_time_ms));
160 }
161 */
162 QByteArray result = xt_process->readAll();
163
164
165 qDebug() << result.constData();
166
167 // X! TANDEM Jackhammer TPP (2013.06.15.1 - LabKey, Insilicos, ISB)
168
169 QRegularExpression parse_version("(.*) TANDEM ([A-Z,a-z, ]+) \\(([^ ,^\\)]*)(.*)");
170 qDebug() << parse_version;
171 // Pattern patt = Pattern.compile("X! TANDEM [A-Z]+ \\‍((.*)\\‍)",
172 // Pattern.CASE_INSENSITIVE);
173 QRegularExpressionMatch match_parse_version = parse_version.match(result.constData());
174 if(match_parse_version.hasMatch())
175 {
176 version_return = QString("X!Tandem %1 %2")
177 .arg(match_parse_version.captured(2))
178 .arg(match_parse_version.captured(3)); //.join(" ");
179 }
180 else
181 {
183 QObject::tr("This executable %1 may not be a valid X!Tandem software. "
184 "Please check your X!Tandem installation.")
185 .arg(tandem_bin_path));
186 }
187
188 QProcess::ExitStatus Status = xt_process->exitStatus();
189 delete xt_process;
190 if(Status != 0)
191 {
192 // != QProcess::NormalExit
193 throw pappso::PappsoException(QObject::tr("error executing X!Tandem Status != 0 : %1 %2\n%3")
194 .arg(tandem_bin_path)
195 .arg(arguments.join(" ").arg(result.data())));
196 }
197 qDebug();
198 return version_return;
199}
200
201void
203{
204 QString message(m_xtProcess->readAllStandardOutput());
205 mp_monitor->appendText(message);
206
207 if(message.toLower().contains("error"))
208 {
209 throw pappso::XtandemError(message);
210 }
211
212 if(mp_monitor->shouldIstop())
213 {
214 m_xtProcess->kill();
215 delete m_xtProcess;
216 m_xtProcess = nullptr;
217 throw pappso::ExceptionInterrupted(QObject::tr("X!Tandem stopped by the user"));
218 }
219}
220
221void
223{
224 mp_monitor->appendText(m_xtProcess->readAllStandardError());
225 if(mp_monitor->shouldIstop())
226 {
227 m_xtProcess->kill();
228 delete m_xtProcess;
229 m_xtProcess = nullptr;
230 throw pappso::ExceptionInterrupted(QObject::tr("X!Tandem stopped by the user"));
231 }
232}
233
234void
235TandemWrapperRun::writeFinalTandemOutput(const QString &tmp_tandem_output,
236 const QString &final_tandem_output,
237 const QString &original_msdata_file_name)
238{
239 mp_monitor->setStatus(QObject::tr("Rewriting X!Tandem XML result file"));
240
241 WrapTandemResults wrap_output(final_tandem_output, original_msdata_file_name);
242
243 wrap_output.setInputParameters("spectrum, timstof MS2 filters", getMs2FilterSuiteString());
244 wrap_output.setInputParameters("spectrum, mzFormat", QString("%1").arg((int)m_mzFormat));
245
247 {
248 wrap_output.setInputParameters("output, spectrum index", "true");
249 }
250 else
251 {
252 }
253
254 if(m_conversionTime != 0)
255 {
256 wrap_output.setInputParameters("timing, tandemwrapper conversion time (sec)",
257 QString("%1").arg(m_conversionTime / 1000));
258 }
259
260 if(wrap_output.readFile(tmp_tandem_output))
261 {
262 }
263 else
264 {
265 throw pappso::PappsoException(QObject::tr("Error reading %1 X!Tandem output file :\n %2")
266 .arg(tmp_tandem_output)
267 .arg(wrap_output.errorString()));
268 }
269}
270
271void
272TandemWrapperRun::readTandemPresetFile(const QString &tandem_preset_file)
273{
274 // get number of threads and centroid parameters from tandem preset
275
276 XtandemPresetReader preset_handler;
277
278
279 if(preset_handler.readFile(tandem_preset_file))
280 {
281
282 int ideal_number_of_thread = QThread::idealThreadCount();
283 int cpu_number = preset_handler.getNumberOfThreads();
284 qDebug() << " cpu_number=" << cpu_number;
285 // QThreadPool::globalInstance()->setMaxThreadCount(1);
286 if(cpu_number > ideal_number_of_thread)
287 {
288 cpu_number = ideal_number_of_thread;
289 }
290 else
291 {
292 if(cpu_number > 0)
293 {
294 QThreadPool::globalInstance()->setMaxThreadCount(cpu_number);
295
296 qDebug() << " maxThreadCount=" << QThreadPool::globalInstance()->maxThreadCount();
297 }
298 }
299
300 QString ms2_filters_str = preset_handler.getMs2FiltersOptions();
301 if(!ms2_filters_str.isEmpty())
302 {
303 msp_ms2FilterSuiteString = std::make_shared<pappso::FilterSuiteString>(ms2_filters_str);
304 }
305 else
306 {
307 msp_ms2FilterSuiteString = std::make_shared<pappso::FilterSuiteString>(
308 "chargeDeconvolution|0.02dalton mzExclusion|0.01dalton");
309 }
310 }
311 else
312 {
313 throw pappso::PappsoException(QObject::tr("Error reading %1 X!Tandem preset file :\n %2")
314 .arg(tandem_preset_file)
315 .arg(preset_handler.errorString()));
316 }
317}
318
319
320void
321TandemWrapperRun::wrapTandemInputFile(const QString &tandem_input_file)
322{
323 // read original tandem input file
324 // store original ms data file name
325 // create new mzXML data file in temporary directory
326 // create new tandem input file based on new mzXML file
327
328
329 QString mzxml_data_file_name = mpa_temporaryDirectory->filePath("msdata.mzxml");
330 QString wrapped_tandem_input = mpa_temporaryDirectory->filePath("input_tandem.xml");
331 QString wrapped_tandem_output = mpa_temporaryDirectory->filePath("output_tandem.xml");
332
333 WrapTandemInput wrap_tandem_input(
334 mzxml_data_file_name, wrapped_tandem_input, wrapped_tandem_output);
335
336
337 if(wrap_tandem_input.readFile(tandem_input_file))
338 {
339 }
340 else
341 {
342 throw pappso::PappsoException(QObject::tr("Error reading %1 X!Tandem input file :\n %2")
343 .arg(tandem_input_file)
344 .arg(wrap_tandem_input.errorString()));
345 }
346
347
348 if(m_tandemBinary.endsWith("tandemng") || m_tandemBinary.endsWith("tandemng.exe") ||
349 m_tandemBinary.endsWith("tandemng2015") || m_tandemBinary.endsWith("tandemng2015.exe") ||
350 m_tandemBinary.endsWith("tandemng2015p") || m_tandemBinary.endsWith("tandemng2015p.exe"))
351 {
352 // no wrapper
353 // launch tandem on original file
354 runTandem(tandem_input_file);
355 }
356 else
357 {
358 /*
359 *
360 XtandemInputSaxHandler wrap_input(
361 mzxml_data_file_name, wrapped_tandem_input, wrapped_tandem_output);
362 QFile qfile(tandem_input_file);
363 if(!qfile.exists())
364 {
365 throw pappso::PappsoException(
366 QObject::tr("Tandem input file %1 does not exists")
367 .arg(QFileInfo(tandem_input_file).absoluteFilePath()));
368 }
369 QXmlInputSource xmlInputSource(&qfile);
370 QXmlSimpleReader simplereader;
371 simplereader.setContentHandler(&wrap_input);
372 simplereader.setErrorHandler(&wrap_input);
373
374 if(simplereader.parse(xmlInputSource))
375 {
376 }
377 else
378 {
379 throw pappso::PappsoException(
380 QObject::tr("Error reading %1 X!Tandem input file :\n %2")
381 .arg(tandem_input_file)
382 .arg(wrap_input.errorString()));
383 }
384 */
385 // get number of threads and centroid parameters from tandem preset
387
388
389 // convert to mzXML
390 QString original_msdata_file_name = wrap_tandem_input.getOriginalMsDataFileName();
391 if(convertOrginalMsData2mzXmlData(original_msdata_file_name, mzxml_data_file_name))
392 {
393
394
395 // launch tandem
396 runTandem(wrapped_tandem_input);
397
398 // rewrite tandem result file
399 writeFinalTandemOutput(wrapped_tandem_output,
400 wrap_tandem_input.getOriginalTandemOutputFileName(),
401 original_msdata_file_name);
402 }
403 else
404 {
405 // launch tandem on original file
406 runTandem(tandem_input_file);
407 }
408 }
409}
410
411bool
412TandemWrapperRun::convertOrginalMsData2mzXmlData(const QString &origin, const QString &target)
413{
414 qDebug();
415 pappso::MsFileAccessor origin_access(origin, "runa1");
418 origin_access.getMsRunIds();
419 m_mzFormat = origin_access.getFileFormat();
421 {
422 throw pappso::PappsoException(QObject::tr("%1 file format not known").arg(origin));
423 }
424
426 {
428 }
429
430 if((origin_access.getFileFormat() == Enums::MsDataFormat::mzML) ||
432 {
433 mp_monitor->setStatus(QObject::tr("Converting %1 to mzXML %2").arg(origin).arg(target));
435 p_reader = origin_access.msRunReaderSPtr(origin_access.getMsRunIds().front());
436
437 pappso::TimsMsRunReaderMs2 *tims2_reader =
438 dynamic_cast<pappso::TimsMsRunReaderMs2 *>(p_reader.get());
439 if(tims2_reader != nullptr)
440 {
441 qDebug();
442 tims2_reader->setMs2BuiltinCentroid(true);
443
444 if(msp_ms2FilterSuiteString != nullptr)
445 {
447 }
448 qDebug();
449 }
450
451
452 pappso::MzxmlOutput *p_mzxml_output;
453 QFile output_file(target);
454 // qDebug() << " TsvDirectoryWriter::writeSheet " <<
455 // QFileInfo(*_p_ofile).absoluteFilePath();
456 if(output_file.open(QIODevice::WriteOnly))
457 {
458 QElapsedTimer timer;
460 timer.start();
461 p_mzxml_output = new pappso::MzxmlOutput(*mp_monitor, QTextStream(&output_file).device());
462
463 p_mzxml_output->maskMs1(true);
464
465 p_mzxml_output->setReadAhead(true);
466
467 p_mzxml_output->write(p_reader.get());
468
469 p_mzxml_output->close();
470
471 delete p_mzxml_output;
472 m_conversionTime = timer.elapsed();
473
474 mp_monitor->setStatus(
475 QObject::tr("Conversion finished in %1 seconds").arg(m_conversionTime / 1000));
476 }
477 else
478 {
480 QObject::tr("unable to write into %1 mzXML output file").arg(target));
481 }
482
483 qDebug();
484 return true;
485 }
486 else
487 { // other mz data formats
488 return false;
489 }
490 return true;
491}
492
493void
494TandemWrapperRun::run(UiMonitorInterface &monitor, const QString &tandem_input_file)
495{
496 mp_monitor = &monitor;
497
498 wrapTandemInputFile(tandem_input_file);
499 mp_monitor = nullptr;
500}
501void
502TandemWrapperRun::runTandem(const QString &tandem_input_file)
503{
504 if(mp_monitor->shouldIstop())
505 {
507 QObject::tr("X!Tandem stopped by the user processing on file %1").arg(tandem_input_file));
508 }
509 m_xtProcess = new QProcess();
510 QStringList arguments;
511
512 qDebug() << m_tandemBinary << " " << m_xtProcess->arguments();
513
514 arguments << tandem_input_file;
515 // hk_process->setWorkingDirectory(QFileInfo(_hardklor_exe).absolutePath());
516 m_xtProcess->start(m_tandemBinary, arguments);
517
518 qDebug() << m_tandemBinary << " " << m_xtProcess->arguments();
519
520 connect(m_xtProcess,
521 &QProcess::readyReadStandardOutput,
522 this,
524 connect(m_xtProcess,
525 &QProcess::readyReadStandardError,
526 this,
528
529
530 qDebug() << m_tandemBinary << " " << m_xtProcess->arguments();
531
532 mp_monitor->setStatus(QObject::tr("Running X!Tandem"));
533
534 if(!m_xtProcess->waitForStarted())
535 {
536 throw pappso::PappsoException(QObject::tr("X!Tandem process failed to start"));
537 }
538
539 qDebug() << m_tandemBinary << " " << m_xtProcess->arguments();
540 while(m_xtProcess->waitForFinished(m_maxTandemRunTimeMs) == false)
541 {
542 //_p_monitor->appendText(xt_process->readAll().data());
543 // data.append(xt_process->readAll());
544 if(mp_monitor->shouldIstop())
545 {
546 m_xtProcess->kill();
547 delete m_xtProcess;
548 m_xtProcess = nullptr;
550 QObject::tr("X!Tandem stopped by the user processing on file %1")
551 .arg(tandem_input_file));
552 }
553 }
554
555 QProcess::ExitStatus Status = m_xtProcess->exitStatus();
556
557 delete m_xtProcess;
558 if(Status != QProcess::ExitStatus::NormalExit)
559 {
560 // != QProcess::NormalExit
562 QObject::tr("error executing X!Tandem Status != 0 : %1").arg(m_tandemBinary));
563 }
564 m_xtProcess = nullptr;
565}
566
567QString
569{
570 if(msp_ms2FilterSuiteString == nullptr)
571 return "";
572 return msp_ms2FilterSuiteString.get()->toString();
573}
574
575} // namespace pappso
MsRunReaderSPtr msRunReaderSPtr(MsRunIdCstSPtr ms_run_id)
void setPreferredFileReaderType(Enums::MsDataFormat format, Enums::FileReaderType reader_type)
given an mz format, explicitly set the preferred reader
Enums::MsDataFormat getFileFormat() const
get the raw format of mz data
std::vector< MsRunIdCstSPtr > getMsRunIds()
void setReadAhead(bool read_ahead)
void write(MsRunReader *p_msrunreader)
void maskMs1(bool mask_ms1)
QTemporaryDir * mpa_temporaryDirectory
void run(UiMonitorInterface &monitor, const QString &tandem_input_file)
run a tandem job
void setTandemBinaryPath(const QString &tandem_binary_path)
UiMonitorInterface * mp_monitor
bool convertOrginalMsData2mzXmlData(const QString &origin, const QString &target)
void readTandemPresetFile(const QString &tandem_preset_file)
std::shared_ptr< FilterSuiteString > msp_ms2FilterSuiteString
void wrapTandemInputFile(const QString &tandem_input_file)
void writeFinalTandemOutput(const QString &tmp_tandem_output, const QString &final_tandem_output, const QString &original_msdata_file_name)
tandem output modification tandem output is modified to contain the Bruker's file as input and centro...
TandemWrapperRun(const QString &tandem_binary, const QString &tmp_dir)
prepare a tandem run
QString getMs2FilterSuiteString() const
gets the list of filters used on MS2 spectrum
void runTandem(const QString &tandem_input_file)
run a tandem job
Enums::MsDataFormat m_mzFormat
const QString checkXtandemVersion(const QString &tandem_bin_path)
void setMs2FilterCstSPtr(pappso::FilterInterfaceCstSPtr filter)
void setMs2BuiltinCentroid(bool centroid)
enable or disable simple centroid filter on raw tims data for MS2
const QString & getOriginalTandemOutputFileName() const
const QString & getOriginalTandemPresetFileName() const
const QString & getOriginalMsDataFileName() const
void setInputParameters(const QString &label_name_attribute, const QString &input_value)
virtual bool readFile(const QString &fileName)
const QString getMs2FiltersOptions() const
@ unknown
unknown format
Definition types.h:149
tries to keep as much as possible monoisotopes, removing any possible C13 peaks and changes multichar...
Definition aa.cpp:39
std::shared_ptr< MsRunReader > MsRunReaderSPtr
Definition msrunreader.h:57