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 /*
370 *
371 XtandemInputSaxHandler wrap_input(
372 mzxml_data_file_name, wrapped_tandem_input, wrapped_tandem_output);
373 QFile qfile(tandem_input_file);
374 if(!qfile.exists())
375 {
376 throw pappso::PappsoException(
377 QObject::tr("Tandem input file %1 does not exists")
378 .arg(QFileInfo(tandem_input_file).absoluteFilePath()));
379 }
380 QXmlInputSource xmlInputSource(&qfile);
381 QXmlSimpleReader simplereader;
382 simplereader.setContentHandler(&wrap_input);
383 simplereader.setErrorHandler(&wrap_input);
384
385 if(simplereader.parse(xmlInputSource))
386 {
387 }
388 else
389 {
390 throw pappso::PappsoException(
391 QObject::tr("Error reading %1 X!Tandem input file :\n %2")
392 .arg(tandem_input_file)
393 .arg(wrap_input.errorString()));
394 }
395*/
396 // get number of threads and centroid parameters from tandem preset
398
399
400 // convert to mzXML
401 QString original_msdata_file_name =
402 wrap_tandem_input.getOriginalMsDataFileName();
403 if(convertOrginalMsData2mzXmlData(original_msdata_file_name,
404 mzxml_data_file_name))
405 {
406
407
408 // launch tandem
409 runTandem(wrapped_tandem_input);
410
411 // rewrite tandem result file
413 wrapped_tandem_output,
414 wrap_tandem_input.getOriginalTandemOutputFileName(),
415 original_msdata_file_name);
416 }
417 else
418 {
419 // launch tandem on original file
420 runTandem(tandem_input_file);
421 }
422}
423
424bool
426 const QString &target)
427{
428 qDebug();
429 pappso::MsFileAccessor origin_access(origin, "runa1");
432 origin_access.getMsRunIds();
433 m_mzFormat = origin_access.getFileFormat();
435 {
437 QObject::tr("%1 file format not known").arg(origin));
438 }
439
440 if(origin_access.getFileFormat() == pappso::MzFormat::brukerTims)
441 {
443 }
444
445 if((origin_access.getFileFormat() == pappso::MzFormat::mzML) ||
446 (origin_access.getFileFormat() == pappso::MzFormat::brukerTims))
447 {
449 QObject::tr("Converting %1 to mzXML %2").arg(origin).arg(target));
451 p_reader =
452 origin_access.msRunReaderSp(origin_access.getMsRunIds().front());
453
454 pappso::TimsMsRunReaderMs2 *tims2_reader =
455 dynamic_cast<pappso::TimsMsRunReaderMs2 *>(p_reader.get());
456 if(tims2_reader != nullptr)
457 {
458 qDebug();
459 tims2_reader->setMs2BuiltinCentroid(true);
460
461 if(msp_ms2FilterSuiteString != nullptr)
462 {
464 }
465 qDebug();
466 }
467
468
469 pappso::MzxmlOutput *p_mzxml_output;
470 QFile output_file(target);
471 // qDebug() << " TsvDirectoryWriter::writeSheet " <<
472 // QFileInfo(*_p_ofile).absoluteFilePath();
473 if(output_file.open(QIODevice::WriteOnly))
474 {
475 QElapsedTimer timer;
477 timer.start();
478 p_mzxml_output = new pappso::MzxmlOutput(
479 *mp_monitor, QTextStream(&output_file).device());
480
481 p_mzxml_output->maskMs1(true);
482
483 p_mzxml_output->setReadAhead(true);
484
485 p_mzxml_output->write(p_reader.get());
486
487 p_mzxml_output->close();
488
489 delete p_mzxml_output;
490 m_conversionTime = timer.elapsed();
491
492 mp_monitor->setStatus(QObject::tr("Conversion finished in %1 seconds")
493 .arg(m_conversionTime / 1000));
494 }
495 else
496 {
498 QObject::tr("unable to write into %1 mzXML output file")
499 .arg(target));
500 }
501
502 qDebug();
503 return true;
504 }
505 else
506 { // other mz data formats
507 return false;
508 }
509 return true;
510}
511
512void
514 const QString &tandem_input_file)
515{
516 mp_monitor = &monitor;
517
518 wrapTandemInputFile(tandem_input_file);
519 mp_monitor = nullptr;
520}
521void
522TandemWrapperRun::runTandem(const QString &tandem_input_file)
523{
525 {
527 QObject::tr("X!Tandem stopped by the user processing on file %1")
528 .arg(tandem_input_file));
529 }
530 m_xtProcess = new QProcess();
531 QStringList arguments;
532
533 qDebug() << m_tandemBinary << " " << m_xtProcess->arguments();
534
535 arguments << tandem_input_file;
536 // hk_process->setWorkingDirectory(QFileInfo(_hardklor_exe).absolutePath());
537 m_xtProcess->start(m_tandemBinary, arguments);
538
539 qDebug() << m_tandemBinary << " " << m_xtProcess->arguments();
540
541 connect(m_xtProcess,
542 &QProcess::readyReadStandardOutput,
543 this,
545 connect(m_xtProcess,
546 &QProcess::readyReadStandardError,
547 this,
549
550
551 qDebug() << m_tandemBinary << " " << m_xtProcess->arguments();
552
553 mp_monitor->setStatus(QObject::tr("Running X!Tandem"));
554
555 if(!m_xtProcess->waitForStarted())
556 {
558 QObject::tr("X!Tandem process failed to start"));
559 }
560
561 qDebug() << m_tandemBinary << " " << m_xtProcess->arguments();
562 while(m_xtProcess->waitForFinished(m_maxTandemRunTimeMs) == false)
563 {
564 //_p_monitor->appendText(xt_process->readAll().data());
565 // data.append(xt_process->readAll());
567 {
568 m_xtProcess->kill();
569 delete m_xtProcess;
570 m_xtProcess = nullptr;
572 QObject::tr("X!Tandem stopped by the user processing on file %1")
573 .arg(tandem_input_file));
574 }
575 }
576
577 QProcess::ExitStatus Status = m_xtProcess->exitStatus();
578
579 delete m_xtProcess;
580 if(Status != QProcess::ExitStatus::NormalExit)
581 {
582 // != QProcess::NormalExit
584 QObject::tr("error executing X!Tandem Status != 0 : %1")
585 .arg(m_tandemBinary));
586 }
587 m_xtProcess = nullptr;
588}
589
590QString
592{
593 if(msp_ms2FilterSuiteString == nullptr)
594 return "";
595 return msp_ms2FilterSuiteString.get()->toString();
596}
597
598} // namespace pappso
MzFormat getFileFormat() const
get the raw format of mz data
MsRunReaderSPtr msRunReaderSp(MsRunIdCstSPtr ms_run_id)
void setPreferedFileReaderType(MzFormat format, FileReaderType reader_type)
given an mz format, explicitly set the prefered reader
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
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