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 <QRegularExpression>
35#include "../../exception/exceptioninterrupted.h"
36#include "../../msfile/msfileaccessor.h"
37#include "../../msrun/private/timsmsrunreaderms2.h"
38#include "../../processing/filters/filtertriangle.h"
39#include "../../processing/filters/filterchargedeconvolution.h"
40#include "../../msrun/output/mzxmloutput.h"
41#include "wraptandemresults.h"
42#include "xtandempresetreader.h"
43#include "wraptandeminput.h"
44
45namespace pappso
46{
47
48
49TandemWrapperRun::TandemWrapperRun(const QString &tandem_binary,
50 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 {
96 settings.value("path/tandem_binary", "/usr/bin/tandem").toString();
97 }
98 // check for tandem executable
100
101 qDebug() << m_tandemVersion;
102 settings.setValue("path/tandem_binary", m_tandemBinary);
103}
104
105
106const QString
107TandemWrapperRun::checkXtandemVersion(const QString &tandem_bin_path)
108{
109 qDebug();
110 // check tandem path
111 QFileInfo tandem_exe(tandem_bin_path);
112 if(!tandem_exe.exists())
113 {
114 // dir.path() returns the unique directory path
116 QObject::tr(
117 "X!Tandem software not found at %1.\nPlease check the X!Tandem "
118 "installation on your computer and set tandem.exe path.")
119 .arg(tandem_exe.absoluteFilePath()));
120 }
121 if(!tandem_exe.isReadable())
122 {
123 // dir.path() returns the unique directory path
125 QObject::tr("Please check permissions on X!Tandem software found at %1 "
126 "(file not readable).")
127 .arg(tandem_exe.absoluteFilePath()));
128 }
129 if(!tandem_exe.isExecutable())
130 {
131 // dir.path() returns the unique directory path
133 QObject::tr("Please check permissions on X!Tandem software found at %1 "
134 "(file not executable).")
135 .arg(tandem_exe.absoluteFilePath()));
136 }
137
138
139 QString version_return;
140 QStringList arguments;
141
142 arguments << "-v";
143
144 QProcess *xt_process = new QProcess();
145 // hk_process->setWorkingDirectory(QFileInfo(_hardklor_exe).absolutePath());
146
147 xt_process->start(tandem_bin_path, arguments);
148
149 if(!xt_process->waitForStarted())
150 {
152 QObject::tr("X!Tandem %1 process failed to start")
153 .arg(m_tandemVersion));
154 }
155
156 while(xt_process->waitForReadyRead(1000))
157 {
158 }
159 /*
160 if (!xt_process->waitForFinished(_max_xt_time_ms)) {
161 throw pappso::PappsoException(QObject::tr("can't wait for X!Tandem process
162 to finish : timeout at %1").arg(_max_xt_time_ms));
163 }
164 */
165 QByteArray result = xt_process->readAll();
166
167
168 qDebug() << result.constData();
169
170 // X! TANDEM Jackhammer TPP (2013.06.15.1 - LabKey, Insilicos, ISB)
171
172 QRegularExpression parse_version(
173 "(.*) TANDEM ([A-Z,a-z, ]+) \\(([^ ,^\\)]*)(.*)");
174 qDebug() << parse_version;
175 // Pattern patt = Pattern.compile("X! TANDEM [A-Z]+ \\‍((.*)\\‍)",
176 // Pattern.CASE_INSENSITIVE);
177 QRegularExpressionMatch match_parse_version =
178 parse_version.match(result.constData());
179 if(match_parse_version.hasMatch())
180 {
181 version_return = QString("X!Tandem %1 %2")
182 .arg(match_parse_version.captured(2))
183 .arg(match_parse_version.captured(3)); //.join(" ");
184 }
185 else
186 {
188 QObject::tr("This executable %1 may not be a valid X!Tandem software. "
189 "Please check your X!Tandem installation.")
190 .arg(tandem_bin_path));
191 }
192
193 QProcess::ExitStatus Status = xt_process->exitStatus();
194 delete xt_process;
195 if(Status != 0)
196 {
197 // != QProcess::NormalExit
199 QObject::tr("error executing X!Tandem Status != 0 : %1 %2\n%3")
200 .arg(tandem_bin_path)
201 .arg(arguments.join(" ").arg(result.data())));
202 }
203 qDebug();
204 return version_return;
205}
206
207void
209{
210 QString message(m_xtProcess->readAllStandardOutput());
211 mp_monitor->appendText(message);
212
213 if(message.toLower().contains("error"))
214 {
215 throw pappso::XtandemError(message);
216 }
217
219 {
220 m_xtProcess->kill();
221 delete m_xtProcess;
222 m_xtProcess = nullptr;
224 QObject::tr("X!Tandem stopped by the user"));
225 }
226}
227
228void
230{
231 mp_monitor->appendText(m_xtProcess->readAllStandardError());
233 {
234 m_xtProcess->kill();
235 delete m_xtProcess;
236 m_xtProcess = nullptr;
238 QObject::tr("X!Tandem stopped by the user"));
239 }
240}
241
242void
244 const QString &tmp_tandem_output,
245 const QString &final_tandem_output,
246 const QString &original_msdata_file_name)
247{
248 mp_monitor->setStatus(QObject::tr("Rewriting X!Tandem XML result file"));
249
250 WrapTandemResults wrap_output(final_tandem_output, original_msdata_file_name);
251
252 wrap_output.setInputParameters("spectrum, timstof MS2 filters",
254 wrap_output.setInputParameters("spectrum, mzFormat",
255 QString("%1").arg((int)m_mzFormat));
256
258 {
259 wrap_output.setInputParameters("output, spectrum index", "true");
260 }
261 else
262 {
263 }
264
265 if(m_conversionTime != 0)
266 {
267 wrap_output.setInputParameters(
268 "timing, tandemwrapper conversion time (sec)",
269 QString("%1").arg(m_conversionTime / 1000));
270 }
271
272 if(wrap_output.readFile(tmp_tandem_output))
273 {
274 }
275 else
276 {
278 QObject::tr("Error reading %1 X!Tandem output file :\n %2")
279 .arg(tmp_tandem_output)
280 .arg(wrap_output.errorString()));
281 }
282}
283
284void
285TandemWrapperRun::readTandemPresetFile(const QString &tandem_preset_file)
286{
287 // get number of threads and centroid parameters from tandem preset
288
289 XtandemPresetReader preset_handler;
290
291
292 if(preset_handler.readFile(tandem_preset_file))
293 {
294
295 int ideal_number_of_thread = QThread::idealThreadCount();
296 int cpu_number = preset_handler.getNumberOfThreads();
297 qDebug() << " cpu_number=" << cpu_number;
298 // QThreadPool::globalInstance()->setMaxThreadCount(1);
299 if(cpu_number > ideal_number_of_thread)
300 {
301 cpu_number = ideal_number_of_thread;
302 }
303 else
304 {
305 if(cpu_number > 0)
306 {
307 QThreadPool::globalInstance()->setMaxThreadCount(cpu_number);
308
309 qDebug() << " maxThreadCount="
310 << QThreadPool::globalInstance()->maxThreadCount();
311 }
312 }
313
314 QString ms2_filters_str = preset_handler.getMs2FiltersOptions();
315 if(!ms2_filters_str.isEmpty())
316 {
318 std::make_shared<pappso::FilterSuiteString>(ms2_filters_str);
319 }
320 else
321 {
323 std::make_shared<pappso::FilterSuiteString>(
324 "chargeDeconvolution|0.02dalton mzExclusion|0.01dalton");
325 }
326 }
327 else
328 {
330 QObject::tr("Error reading %1 X!Tandem preset file :\n %2")
331 .arg(tandem_preset_file)
332 .arg(preset_handler.errorString()));
333 }
334}
335
336
337void
338TandemWrapperRun::wrapTandemInputFile(const QString &tandem_input_file)
339{
340 // read original tandem input file
341 // store original ms data file name
342 // create new mzXML data file in temporary directory
343 // create new tandem input file based on new mzXML file
344
345
346 QString mzxml_data_file_name =
347 mpa_temporaryDirectory->filePath("msdata.mzxml");
348 QString wrapped_tandem_input =
349 mpa_temporaryDirectory->filePath("input_tandem.xml");
350 QString wrapped_tandem_output =
351 mpa_temporaryDirectory->filePath("output_tandem.xml");
352
353 WrapTandemInput wrap_tandem_input(
354 mzxml_data_file_name, wrapped_tandem_input, wrapped_tandem_output);
355
356
357 if(wrap_tandem_input.readFile(tandem_input_file))
358 {
359 }
360 else
361 {
363 QObject::tr("Error reading %1 X!Tandem input file :\n %2")
364 .arg(tandem_input_file)
365 .arg(wrap_tandem_input.errorString()));
366 }
367
368
369 if(m_tandemBinary.endsWith("tandemng") ||
370 m_tandemBinary.endsWith("tandemng.exe") ||
371 m_tandemBinary.endsWith("tandemng2015") ||
372 m_tandemBinary.endsWith("tandemng2015.exe") ||
373 m_tandemBinary.endsWith("tandemng2015p") ||
374 m_tandemBinary.endsWith("tandemng2015p.exe"))
375 {
376 // no wrapper
377 // launch tandem on original file
378 runTandem(tandem_input_file);
379 }
380 else
381 {
382 /*
383 *
384 XtandemInputSaxHandler wrap_input(
385 mzxml_data_file_name, wrapped_tandem_input, wrapped_tandem_output);
386 QFile qfile(tandem_input_file);
387 if(!qfile.exists())
388 {
389 throw pappso::PappsoException(
390 QObject::tr("Tandem input file %1 does not exists")
391 .arg(QFileInfo(tandem_input_file).absoluteFilePath()));
392 }
393 QXmlInputSource xmlInputSource(&qfile);
394 QXmlSimpleReader simplereader;
395 simplereader.setContentHandler(&wrap_input);
396 simplereader.setErrorHandler(&wrap_input);
397
398 if(simplereader.parse(xmlInputSource))
399 {
400 }
401 else
402 {
403 throw pappso::PappsoException(
404 QObject::tr("Error reading %1 X!Tandem input file :\n %2")
405 .arg(tandem_input_file)
406 .arg(wrap_input.errorString()));
407 }
408 */
409 // get number of threads and centroid parameters from tandem preset
411
412
413 // convert to mzXML
414 QString original_msdata_file_name =
415 wrap_tandem_input.getOriginalMsDataFileName();
416 if(convertOrginalMsData2mzXmlData(original_msdata_file_name,
417 mzxml_data_file_name))
418 {
419
420
421 // launch tandem
422 runTandem(wrapped_tandem_input);
423
424 // rewrite tandem result file
426 wrapped_tandem_output,
427 wrap_tandem_input.getOriginalTandemOutputFileName(),
428 original_msdata_file_name);
429 }
430 else
431 {
432 // launch tandem on original file
433 runTandem(tandem_input_file);
434 }
435 }
436}
437
438bool
440 const QString &target)
441{
442 qDebug();
443 pappso::MsFileAccessor origin_access(origin, "runa1");
446 origin_access.getMsRunIds();
447 m_mzFormat = origin_access.getFileFormat();
449 {
451 QObject::tr("%1 file format not known").arg(origin));
452 }
453
455 {
457 }
458
459 if((origin_access.getFileFormat() == pappso::MsDataFormat::mzML) ||
461 {
463 QObject::tr("Converting %1 to mzXML %2").arg(origin).arg(target));
465 p_reader =
466 origin_access.msRunReaderSPtr(origin_access.getMsRunIds().front());
467
468 pappso::TimsMsRunReaderMs2 *tims2_reader =
469 dynamic_cast<pappso::TimsMsRunReaderMs2 *>(p_reader.get());
470 if(tims2_reader != nullptr)
471 {
472 qDebug();
473 tims2_reader->setMs2BuiltinCentroid(true);
474
475 if(msp_ms2FilterSuiteString != nullptr)
476 {
478 }
479 qDebug();
480 }
481
482
483 pappso::MzxmlOutput *p_mzxml_output;
484 QFile output_file(target);
485 // qDebug() << " TsvDirectoryWriter::writeSheet " <<
486 // QFileInfo(*_p_ofile).absoluteFilePath();
487 if(output_file.open(QIODevice::WriteOnly))
488 {
489 QElapsedTimer timer;
491 timer.start();
492 p_mzxml_output = new pappso::MzxmlOutput(
493 *mp_monitor, QTextStream(&output_file).device());
494
495 p_mzxml_output->maskMs1(true);
496
497 p_mzxml_output->setReadAhead(true);
498
499 p_mzxml_output->write(p_reader.get());
500
501 p_mzxml_output->close();
502
503 delete p_mzxml_output;
504 m_conversionTime = timer.elapsed();
505
506 mp_monitor->setStatus(QObject::tr("Conversion finished in %1 seconds")
507 .arg(m_conversionTime / 1000));
508 }
509 else
510 {
512 QObject::tr("unable to write into %1 mzXML output file")
513 .arg(target));
514 }
515
516 qDebug();
517 return true;
518 }
519 else
520 { // other mz data formats
521 return false;
522 }
523 return true;
524}
525
526void
528 const QString &tandem_input_file)
529{
530 mp_monitor = &monitor;
531
532 wrapTandemInputFile(tandem_input_file);
533 mp_monitor = nullptr;
534}
535void
536TandemWrapperRun::runTandem(const QString &tandem_input_file)
537{
539 {
541 QObject::tr("X!Tandem stopped by the user processing on file %1")
542 .arg(tandem_input_file));
543 }
544 m_xtProcess = new QProcess();
545 QStringList arguments;
546
547 qDebug() << m_tandemBinary << " " << m_xtProcess->arguments();
548
549 arguments << tandem_input_file;
550 // hk_process->setWorkingDirectory(QFileInfo(_hardklor_exe).absolutePath());
551 m_xtProcess->start(m_tandemBinary, arguments);
552
553 qDebug() << m_tandemBinary << " " << m_xtProcess->arguments();
554
555 connect(m_xtProcess,
556 &QProcess::readyReadStandardOutput,
557 this,
559 connect(m_xtProcess,
560 &QProcess::readyReadStandardError,
561 this,
563
564
565 qDebug() << m_tandemBinary << " " << m_xtProcess->arguments();
566
567 mp_monitor->setStatus(QObject::tr("Running X!Tandem"));
568
569 if(!m_xtProcess->waitForStarted())
570 {
572 QObject::tr("X!Tandem process failed to start"));
573 }
574
575 qDebug() << m_tandemBinary << " " << m_xtProcess->arguments();
576 while(m_xtProcess->waitForFinished(m_maxTandemRunTimeMs) == false)
577 {
578 //_p_monitor->appendText(xt_process->readAll().data());
579 // data.append(xt_process->readAll());
581 {
582 m_xtProcess->kill();
583 delete m_xtProcess;
584 m_xtProcess = nullptr;
586 QObject::tr("X!Tandem stopped by the user processing on file %1")
587 .arg(tandem_input_file));
588 }
589 }
590
591 QProcess::ExitStatus Status = m_xtProcess->exitStatus();
592
593 delete m_xtProcess;
594 if(Status != QProcess::ExitStatus::NormalExit)
595 {
596 // != QProcess::NormalExit
598 QObject::tr("error executing X!Tandem Status != 0 : %1")
599 .arg(m_tandemBinary));
600 }
601 m_xtProcess = nullptr;
602}
603
604QString
606{
607 if(msp_ms2FilterSuiteString == nullptr)
608 return "";
609 return msp_ms2FilterSuiteString.get()->toString();
610}
611
612} // namespace pappso
MsRunReaderSPtr msRunReaderSPtr(MsRunIdCstSPtr ms_run_id)
void setPreferredFileReaderType(MsDataFormat format, FileReaderType reader_type)
given an mz format, explicitly set the preferred reader
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
pappso::MsDataFormat m_mzFormat
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
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
virtual void setStatus(const QString &status)=0
current status of the process
virtual void appendText(const QString &text)=0
append a text to a long report
virtual bool shouldIstop()=0
should the procces be stopped ? If true, then cancel process Use this function at strategic point of ...
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
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:56
@ unknown
unknown format
actually does really run tandem directly on Bruker's data
rewrites tandem xml input file with temporary files
rewrites tandem xml output file with temporary files
read tandem preset file to get centroid parameters and number of threads