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, const QString &tmp_dir)
50{
51
52 setTandemBinaryPath(tandem_binary);
53
54 if(!tmp_dir.isEmpty())
55 {
56 mpa_temporaryDirectory = new QTemporaryDir(tmp_dir + "/xtpwrp");
57 }
58 else
59 {
60 mpa_temporaryDirectory = new QTemporaryDir(QDir::tempPath() + "/xtpwrp");
61 }
62 mpa_temporaryDirectory->setAutoRemove(true);
63 if(!mpa_temporaryDirectory->isValid())
64 {
66 QObject::tr("ERROR: unable to create temporary directory %1\n Please "
67 "check file system permissions")
68 .arg(mpa_temporaryDirectory->path()));
69 }
70}
71
73{
74 if(mpa_temporaryDirectory != nullptr)
75 {
77 }
78
79 if(m_xtProcess != nullptr)
80 {
81 m_xtProcess->deleteLater();
82 }
83}
84
85void
86TandemWrapperRun::setTandemBinaryPath(const QString &tandem_binary_path)
87{
88
89
90 m_tandemBinary = tandem_binary_path;
91 QSettings settings;
92 if(m_tandemBinary.isEmpty())
93 {
94 m_tandemBinary = settings.value("path/tandem_binary", "/usr/bin/tandem").toString();
95 }
96 // check for tandem executable
98
99 qDebug() << m_tandemVersion;
100 settings.setValue("path/tandem_binary", m_tandemBinary);
101}
102
103
104const QString
105TandemWrapperRun::checkXtandemVersion(const QString &tandem_bin_path)
106{
107 qDebug();
108 // check tandem path
109 QFileInfo tandem_exe(tandem_bin_path);
110 if(!tandem_exe.exists())
111 {
112 // dir.path() returns the unique directory path
114 QObject::tr("X!Tandem software not found at %1.\nPlease check the X!Tandem "
115 "installation on your computer and set tandem.exe path.")
116 .arg(tandem_exe.absoluteFilePath()));
117 }
118 if(!tandem_exe.isReadable())
119 {
120 // dir.path() returns the unique directory path
122 QObject::tr("Please check permissions on X!Tandem software found at %1 "
123 "(file not readable).")
124 .arg(tandem_exe.absoluteFilePath()));
125 }
126 if(!tandem_exe.isExecutable())
127 {
128 // dir.path() returns the unique directory path
130 QObject::tr("Please check permissions on X!Tandem software found at %1 "
131 "(file not executable).")
132 .arg(tandem_exe.absoluteFilePath()));
133 }
134
135
136 QString version_return;
137 QStringList arguments;
138
139 arguments << "-v";
140
141 QProcess *xt_process = new QProcess();
142 // hk_process->setWorkingDirectory(QFileInfo(_hardklor_exe).absolutePath());
143
144 xt_process->start(tandem_bin_path, arguments);
145
146 if(!xt_process->waitForStarted())
147 {
149 QObject::tr("X!Tandem %1 process failed to start").arg(m_tandemVersion));
150 }
151
152 while(xt_process->waitForReadyRead(1000))
153 {
154 }
155 /*
156 if (!xt_process->waitForFinished(_max_xt_time_ms)) {
157 throw pappso::PappsoException(QObject::tr("can't wait for X!Tandem process
158 to finish : timeout at %1").arg(_max_xt_time_ms));
159 }
160 */
161 QByteArray result = xt_process->readAll();
162
163
164 qDebug() << result.constData();
165
166 // X! TANDEM Jackhammer TPP (2013.06.15.1 - LabKey, Insilicos, ISB)
167
168 QRegularExpression parse_version("(.*) TANDEM ([A-Z,a-z, ]+) \\(([^ ,^\\)]*)(.*)");
169 qDebug() << parse_version;
170 // Pattern patt = Pattern.compile("X! TANDEM [A-Z]+ \\‍((.*)\\‍)",
171 // Pattern.CASE_INSENSITIVE);
172 QRegularExpressionMatch match_parse_version = parse_version.match(result.constData());
173 if(match_parse_version.hasMatch())
174 {
175 version_return = QString("X!Tandem %1 %2")
176 .arg(match_parse_version.captured(2))
177 .arg(match_parse_version.captured(3)); //.join(" ");
178 }
179 else
180 {
182 QObject::tr("This executable %1 may not be a valid X!Tandem software. "
183 "Please check your X!Tandem installation.")
184 .arg(tandem_bin_path));
185 }
186
187 QProcess::ExitStatus Status = xt_process->exitStatus();
188 delete xt_process;
189 if(Status != 0)
190 {
191 // != QProcess::NormalExit
192 throw pappso::PappsoException(QObject::tr("error executing X!Tandem Status != 0 : %1 %2\n%3")
193 .arg(tandem_bin_path)
194 .arg(arguments.join(" ").arg(result.data())));
195 }
196 qDebug();
197 return version_return;
198}
199
200void
202{
203 QString message(m_xtProcess->readAllStandardOutput());
204 mp_monitor->appendText(message);
205
206 if(message.toLower().contains("error"))
207 {
208 throw pappso::XtandemError(message);
209 }
210
211 if(mp_monitor->shouldIstop())
212 {
213 m_xtProcess->kill();
214 delete m_xtProcess;
215 m_xtProcess = nullptr;
216 throw pappso::ExceptionInterrupted(QObject::tr("X!Tandem stopped by the user"));
217 }
218}
219
220void
222{
223 mp_monitor->appendText(m_xtProcess->readAllStandardError());
224 if(mp_monitor->shouldIstop())
225 {
226 m_xtProcess->kill();
227 delete m_xtProcess;
228 m_xtProcess = nullptr;
229 throw pappso::ExceptionInterrupted(QObject::tr("X!Tandem stopped by the user"));
230 }
231}
232
233void
234TandemWrapperRun::writeFinalTandemOutput(const QString &tmp_tandem_output,
235 const QString &final_tandem_output,
236 const QString &original_msdata_file_name)
237{
238 mp_monitor->setStatus(QObject::tr("Rewriting X!Tandem XML result file"));
239
240 WrapTandemResults wrap_output(final_tandem_output, original_msdata_file_name);
241
242 wrap_output.setInputParameters("spectrum, timstof MS2 filters", getMs2FilterSuiteString());
243 wrap_output.setInputParameters("spectrum, mzFormat", QString("%1").arg((int)m_mzFormat));
244
246 {
247 wrap_output.setInputParameters("output, spectrum index", "true");
248 }
249 else
250 {
251 }
252
253 if(m_conversionTime != 0)
254 {
255 wrap_output.setInputParameters("timing, tandemwrapper conversion time (sec)",
256 QString("%1").arg(m_conversionTime / 1000));
257 }
258
259 if(wrap_output.readFile(tmp_tandem_output))
260 {
261 }
262 else
263 {
264 throw pappso::PappsoException(QObject::tr("Error reading %1 X!Tandem output file :\n %2")
265 .arg(tmp_tandem_output)
266 .arg(wrap_output.errorString()));
267 }
268}
269
270void
271TandemWrapperRun::readTandemPresetFile(const QString &tandem_preset_file)
272{
273 // get number of threads and centroid parameters from tandem preset
274
275 XtandemPresetReader preset_handler;
276
277
278 if(preset_handler.readFile(tandem_preset_file))
279 {
280
281 int ideal_number_of_thread = QThread::idealThreadCount();
282 int cpu_number = preset_handler.getNumberOfThreads();
283 qDebug() << " cpu_number=" << cpu_number;
284 // QThreadPool::globalInstance()->setMaxThreadCount(1);
285 if(cpu_number > ideal_number_of_thread)
286 {
287 cpu_number = ideal_number_of_thread;
288 }
289 else
290 {
291 if(cpu_number > 0)
292 {
293 QThreadPool::globalInstance()->setMaxThreadCount(cpu_number);
294
295 qDebug() << " maxThreadCount=" << QThreadPool::globalInstance()->maxThreadCount();
296 }
297 }
298
299 QString ms2_filters_str = preset_handler.getMs2FiltersOptions();
300 if(!ms2_filters_str.isEmpty())
301 {
302 msp_ms2FilterSuiteString = std::make_shared<pappso::FilterSuiteString>(ms2_filters_str);
303 }
304 else
305 {
306 msp_ms2FilterSuiteString = std::make_shared<pappso::FilterSuiteString>(
307 "chargeDeconvolution|0.02dalton mzExclusion|0.01dalton");
308 }
309 }
310 else
311 {
312 throw pappso::PappsoException(QObject::tr("Error reading %1 X!Tandem preset file :\n %2")
313 .arg(tandem_preset_file)
314 .arg(preset_handler.errorString()));
315 }
316}
317
318
319void
320TandemWrapperRun::wrapTandemInputFile(const QString &tandem_input_file)
321{
322 // read original tandem input file
323 // store original ms data file name
324 // create new mzXML data file in temporary directory
325 // create new tandem input file based on new mzXML file
326
327
328 QString mzxml_data_file_name = mpa_temporaryDirectory->filePath("msdata.mzxml");
329 QString wrapped_tandem_input = mpa_temporaryDirectory->filePath("input_tandem.xml");
330 QString wrapped_tandem_output = mpa_temporaryDirectory->filePath("output_tandem.xml");
331
332 WrapTandemInput wrap_tandem_input(
333 mzxml_data_file_name, wrapped_tandem_input, wrapped_tandem_output);
334
335
336 if(wrap_tandem_input.readFile(tandem_input_file))
337 {
338 }
339 else
340 {
341 throw pappso::PappsoException(QObject::tr("Error reading %1 X!Tandem input file :\n %2")
342 .arg(tandem_input_file)
343 .arg(wrap_tandem_input.errorString()));
344 }
345
346
347 if(m_tandemBinary.endsWith("tandemng") || m_tandemBinary.endsWith("tandemng.exe") ||
348 m_tandemBinary.endsWith("tandemng2015") || m_tandemBinary.endsWith("tandemng2015.exe") ||
349 m_tandemBinary.endsWith("tandemng2015p") || m_tandemBinary.endsWith("tandemng2015p.exe"))
350 {
351 // no wrapper
352 // launch tandem on original file
353 runTandem(tandem_input_file);
354 }
355 else
356 {
357 /*
358 *
359 XtandemInputSaxHandler wrap_input(
360 mzxml_data_file_name, wrapped_tandem_input, wrapped_tandem_output);
361 QFile qfile(tandem_input_file);
362 if(!qfile.exists())
363 {
364 throw pappso::PappsoException(
365 QObject::tr("Tandem input file %1 does not exists")
366 .arg(QFileInfo(tandem_input_file).absoluteFilePath()));
367 }
368 QXmlInputSource xmlInputSource(&qfile);
369 QXmlSimpleReader simplereader;
370 simplereader.setContentHandler(&wrap_input);
371 simplereader.setErrorHandler(&wrap_input);
372
373 if(simplereader.parse(xmlInputSource))
374 {
375 }
376 else
377 {
378 throw pappso::PappsoException(
379 QObject::tr("Error reading %1 X!Tandem input file :\n %2")
380 .arg(tandem_input_file)
381 .arg(wrap_input.errorString()));
382 }
383 */
384 // get number of threads and centroid parameters from tandem preset
386
387
388 // convert to mzXML
389 QString original_msdata_file_name = wrap_tandem_input.getOriginalMsDataFileName();
390 if(convertOrginalMsData2mzXmlData(original_msdata_file_name, mzxml_data_file_name))
391 {
392
393
394 // launch tandem
395 runTandem(wrapped_tandem_input);
396
397 // rewrite tandem result file
398 writeFinalTandemOutput(wrapped_tandem_output,
399 wrap_tandem_input.getOriginalTandemOutputFileName(),
400 original_msdata_file_name);
401 }
402 else
403 {
404 // launch tandem on original file
405 runTandem(tandem_input_file);
406 }
407 }
408}
409
410bool
411TandemWrapperRun::convertOrginalMsData2mzXmlData(const QString &origin, const QString &target)
412{
413 qDebug();
414 pappso::MsFileAccessor origin_access(origin, "runa1");
417 origin_access.getMsRunIds();
418 m_mzFormat = origin_access.getFileFormat();
420 {
421 throw pappso::PappsoException(QObject::tr("%1 file format not known").arg(origin));
422 }
423
425 {
427 }
428
429 if((origin_access.getFileFormat() == Enums::MsDataFormat::mzML) ||
431 {
432 mp_monitor->setStatus(QObject::tr("Converting %1 to mzXML %2").arg(origin).arg(target));
434 p_reader = origin_access.msRunReaderSPtr(origin_access.getMsRunIds().front());
435
436 pappso::TimsMsRunReaderMs2 *tims2_reader =
437 dynamic_cast<pappso::TimsMsRunReaderMs2 *>(p_reader.get());
438 if(tims2_reader != nullptr)
439 {
440 qDebug();
441 tims2_reader->setMs2BuiltinCentroid(true);
442
443 if(msp_ms2FilterSuiteString != nullptr)
444 {
446 }
447 qDebug();
448 }
449
450
451 pappso::MzxmlOutput *p_mzxml_output;
452 QFile output_file(target);
453 // qDebug() << " TsvDirectoryWriter::writeSheet " <<
454 // QFileInfo(*_p_ofile).absoluteFilePath();
455 if(output_file.open(QIODevice::WriteOnly))
456 {
457 QElapsedTimer timer;
459 timer.start();
460 p_mzxml_output = new pappso::MzxmlOutput(*mp_monitor, QTextStream(&output_file).device());
461
462 p_mzxml_output->maskMs1(true);
463
464 p_mzxml_output->setReadAhead(true);
465
466 p_mzxml_output->write(p_reader.get());
467
468 p_mzxml_output->close();
469
470 delete p_mzxml_output;
471 m_conversionTime = timer.elapsed();
472
473 mp_monitor->setStatus(
474 QObject::tr("Conversion finished in %1 seconds").arg(m_conversionTime / 1000));
475 }
476 else
477 {
479 QObject::tr("unable to write into %1 mzXML output file").arg(target));
480 }
481
482 qDebug();
483 return true;
484 }
485 else
486 { // other mz data formats
487 return false;
488 }
489 return true;
490}
491
492void
493TandemWrapperRun::run(UiMonitorInterface &monitor, const QString &tandem_input_file)
494{
495 mp_monitor = &monitor;
496
497 wrapTandemInputFile(tandem_input_file);
498 mp_monitor = nullptr;
499}
500void
501TandemWrapperRun::runTandem(const QString &tandem_input_file)
502{
503 if(mp_monitor->shouldIstop())
504 {
506 QObject::tr("X!Tandem stopped by the user processing on file %1").arg(tandem_input_file));
507 }
508 m_xtProcess = new QProcess();
509 QStringList arguments;
510
511 qDebug() << m_tandemBinary << " " << m_xtProcess->arguments();
512
513 arguments << tandem_input_file;
514 // hk_process->setWorkingDirectory(QFileInfo(_hardklor_exe).absolutePath());
515 m_xtProcess->start(m_tandemBinary, arguments);
516
517 qDebug() << m_tandemBinary << " " << m_xtProcess->arguments();
518
519 connect(m_xtProcess,
520 &QProcess::readyReadStandardOutput,
521 this,
523 connect(m_xtProcess,
524 &QProcess::readyReadStandardError,
525 this,
527
528
529 qDebug() << m_tandemBinary << " " << m_xtProcess->arguments();
530
531 mp_monitor->setStatus(QObject::tr("Running X!Tandem"));
532
533 if(!m_xtProcess->waitForStarted())
534 {
535 throw pappso::PappsoException(QObject::tr("X!Tandem process failed to start"));
536 }
537
538 qDebug() << m_tandemBinary << " " << m_xtProcess->arguments();
539 while(m_xtProcess->waitForFinished(m_maxTandemRunTimeMs) == false)
540 {
541 //_p_monitor->appendText(xt_process->readAll().data());
542 // data.append(xt_process->readAll());
543 if(mp_monitor->shouldIstop())
544 {
545 m_xtProcess->kill();
546 delete m_xtProcess;
547 m_xtProcess = nullptr;
549 QObject::tr("X!Tandem stopped by the user processing on file %1")
550 .arg(tandem_input_file));
551 }
552 }
553
554 QProcess::ExitStatus Status = m_xtProcess->exitStatus();
555
556 delete m_xtProcess;
557 if(Status != QProcess::ExitStatus::NormalExit)
558 {
559 // != QProcess::NormalExit
561 QObject::tr("error executing X!Tandem Status != 0 : %1").arg(m_tandemBinary));
562 }
563 m_xtProcess = nullptr;
564}
565
566QString
568{
569 if(msp_ms2FilterSuiteString == nullptr)
570 return "";
571 return msp_ms2FilterSuiteString.get()->toString();
572}
573
574} // 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