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>
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
218 if(mp_monitor->shouldIstop())
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());
232 if(mp_monitor->shouldIstop())
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() == Enums::MsDataFormat::mzML) ||
461 {
462 mp_monitor->setStatus(
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{
538 if(mp_monitor->shouldIstop())
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());
580 if(mp_monitor->shouldIstop())
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(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:151
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