libpappsomspp
Library for mass spectrometry
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 "../../pappsoexception.h"
35 #include "../../msfile/msfileaccessor.h"
36 #include "../../msrun/private/timsmsrunreaderms2.h"
37 #include "../../processing/filters/filterpseudocentroid.h"
38 #include "../../processing/filters/filtertriangle.h"
39 #include "../../processing/filters/filterchargedeconvolution.h"
40 #include "../../msrun/output/mzxmloutput.h"
41 #include "xtandeminputsaxhandler.h"
44 
45 namespace pappso
46 {
47 TandemWrapperRun::TandemWrapperRun(const QString &tandem_binary,
48  const QString &tmp_dir)
49 {
50 
51  setTandemBinaryPath(tandem_binary);
52 
53  if(!tmp_dir.isEmpty())
54  {
55  mpa_temporaryDirectory = new QTemporaryDir(tmp_dir + "/xtpwrp");
56  }
57  else
58  {
59  mpa_temporaryDirectory = new QTemporaryDir(QDir::tempPath() + "/xtpwrp");
60  }
61  mpa_temporaryDirectory->setAutoRemove(true);
62  if(!mpa_temporaryDirectory->isValid())
63  {
65  QObject::tr("ERROR: unable to create temporary directory %1\n Please "
66  "check file system permissions")
67  .arg(mpa_temporaryDirectory->path()));
68  }
69 }
70 
72 {
73  if(mpa_temporaryDirectory != nullptr)
74  {
76  }
77 
78  if(m_xtProcess != nullptr)
79  {
80  m_xtProcess->deleteLater();
81  }
82 }
83 
84 void
85 TandemWrapperRun::setTandemBinaryPath(const QString &tandem_binary_path)
86 {
87 
88 
89  m_tandemBinary = tandem_binary_path;
90  QSettings settings;
91  if(m_tandemBinary.isEmpty())
92  {
94  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 
104 const QString
105 TandemWrapperRun::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(
115  "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")
151  .arg(m_tandemVersion));
152  }
153 
154  while(xt_process->waitForReadyRead(1000))
155  {
156  }
157  /*
158  if (!xt_process->waitForFinished(_max_xt_time_ms)) {
159  throw pappso::PappsoException(QObject::tr("can't wait for X!Tandem process
160  to finish : timeout at %1").arg(_max_xt_time_ms));
161  }
162  */
163  QByteArray result = xt_process->readAll();
164 
165 
166  qDebug() << result.constData();
167 
168  // X! TANDEM Jackhammer TPP (2013.06.15.1 - LabKey, Insilicos, ISB)
169 
170  QRegExp parse_version("(.*) TANDEM ([A-Z,a-z, ]+) \\(([^ ,^\\)]*)(.*)");
171  qDebug() << parse_version;
172  // Pattern patt = Pattern.compile("X! TANDEM [A-Z]+ \\‍((.*)\\‍)",
173  // Pattern.CASE_INSENSITIVE);
174 
175  if(parse_version.exactMatch(result.constData()))
176  {
177  version_return = QString("X!Tandem %1 %2")
178  .arg(parse_version.capturedTexts()[2])
179  .arg(parse_version.capturedTexts()[3]); //.join(" ");
180  }
181  else
182  {
184  QObject::tr("This executable %1 may not be a valid X!Tandem software. "
185  "Please check your X!Tandem installation.")
186  .arg(tandem_bin_path));
187  }
188 
189  QProcess::ExitStatus Status = xt_process->exitStatus();
190  delete xt_process;
191  if(Status != 0)
192  {
193  // != QProcess::NormalExit
195  QObject::tr("error executing X!Tandem Status != 0 : %1 %2\n%3")
196  .arg(tandem_bin_path)
197  .arg(arguments.join(" ").arg(result.data())));
198  }
199  qDebug();
200  return version_return;
201 }
202 
203 
204 bool
206 {
207  return false;
208 }
209 
210 
211 void
213 {
214  *mp_outputStream << m_xtProcess->readAllStandardOutput();
215  mp_outputStream->flush();
216 }
217 
218 void
220 {
221  *mp_errorStream << m_xtProcess->readAllStandardError();
222  mp_errorStream->flush();
223 }
224 
225 void
227  const QString &tmp_tandem_output,
228  const QString &final_tandem_output,
229  const QString &original_msdata_file_name)
230 {
231 
232  XtandemOutputSaxHandler wrap_output(final_tandem_output,
233  original_msdata_file_name);
234 
235  wrap_output.setInputParameters("spectrum, timstof MS2 filters",
237 
238  QFile qfile(tmp_tandem_output);
239  QXmlInputSource xmlInputSource(&qfile);
240  QXmlSimpleReader simplereader;
241  simplereader.setContentHandler(&wrap_output);
242  simplereader.setErrorHandler(&wrap_output);
243 
244  if(simplereader.parse(xmlInputSource))
245  {
246  }
247  else
248  {
250  QObject::tr("Error reading %1 X!Tandem output file :\n %2")
251  .arg(tmp_tandem_output)
252  .arg(wrap_output.errorString()));
253  }
254 }
255 
256 void
257 TandemWrapperRun::readTandemPresetFile(const QString &tandem_preset_file)
258 {
259  // get number of threads and centroid parameters from tandem preset
260 
261  XtandemPresetSaxHandler preset_handler;
262 
263  QFile qfile(tandem_preset_file);
264  QXmlInputSource xmlInputSource(&qfile);
265  QXmlSimpleReader simplereader;
266  simplereader.setContentHandler(&preset_handler);
267  simplereader.setErrorHandler(&preset_handler);
268 
269  if(simplereader.parse(xmlInputSource))
270  {
271 
272  int ideal_number_of_thread = QThread::idealThreadCount();
273  int cpu_number = preset_handler.getNumberOfThreads();
274  qDebug() << " cpu_number=" << cpu_number;
275  // QThreadPool::globalInstance()->setMaxThreadCount(1);
276  if(cpu_number > ideal_number_of_thread)
277  {
278  cpu_number = ideal_number_of_thread;
279  }
280  else
281  {
282  if(cpu_number > 0)
283  {
284  QThreadPool::globalInstance()->setMaxThreadCount(cpu_number);
285 
286  qDebug() << " maxThreadCount="
287  << QThreadPool::globalInstance()->maxThreadCount();
288  }
289  }
290 
291  QString ms2_filters_str = preset_handler.getMs2FiltersOptions();
292  if(!ms2_filters_str.isEmpty())
293  {
295  std::make_shared<pappso::FilterSuiteString>(ms2_filters_str);
296  }
297  else
298  {
300  std::make_shared<pappso::FilterSuiteString>(
301  "chargeDeconvolution|0.02dalton mzExclusion|0.01dalton");
302  }
303  }
304  else
305  {
307  QObject::tr("Error reading %1 X!Tandem preset file :\n %2")
308  .arg(tandem_preset_file)
309  .arg(preset_handler.errorString()));
310  }
311 }
312 
313 
314 void
315 TandemWrapperRun::wrapTandemInputFile(const QString &tandem_input_file)
316 {
317  // read original tandem input file
318  // store original ms data file name
319  // create new mzXML data file in temporary directory
320  // create new tandem input file based on new mzXML file
321  QString mzxml_data_file_name =
322  mpa_temporaryDirectory->filePath("msdata.mzxml");
323  QString wrapped_tandem_input =
324  mpa_temporaryDirectory->filePath("input_tandem.xml");
325  QString wrapped_tandem_output =
326  mpa_temporaryDirectory->filePath("output_tandem.xml");
327  XtandemInputSaxHandler wrap_input(
328  mzxml_data_file_name, wrapped_tandem_input, wrapped_tandem_output);
329 
330  QFile qfile(tandem_input_file);
331  if(!qfile.exists())
332  {
334  QObject::tr("Tandem input file %1 does not exists")
335  .arg(QFileInfo(tandem_input_file).absoluteFilePath()));
336  }
337  QXmlInputSource xmlInputSource(&qfile);
338  QXmlSimpleReader simplereader;
339  simplereader.setContentHandler(&wrap_input);
340  simplereader.setErrorHandler(&wrap_input);
341 
342  if(simplereader.parse(xmlInputSource))
343  {
344  }
345  else
346  {
348  QObject::tr("Error reading %1 X!Tandem input file :\n %2")
349  .arg(tandem_input_file)
350  .arg(wrap_input.errorString()));
351  }
352 
353  // get number of threads and centroid parameters from tandem preset
355 
356 
357  // convert to mzXML
358  QString original_msdata_file_name = wrap_input.getOriginalMsDataFileName();
359  convertOrginalMsData2mzXmlData(original_msdata_file_name,
360  mzxml_data_file_name);
361 
362 
363  // launch tandem
364  runTandem(wrapped_tandem_input);
365 
366  // rewrite tandem result file
367  writeFinalTandemOutput(wrapped_tandem_output,
368  wrap_input.getOriginalTandemOutputFileName(),
369  original_msdata_file_name);
370 }
371 
372 void
374  const QString &target) const
375 {
376  qDebug();
377  pappso::MsFileAccessor origin_access(origin, "runa1");
380  origin_access.getMsRunIds();
381 
382  pappso::MsRunReaderSPtr p_reader;
383  p_reader = origin_access.msRunReaderSp(origin_access.getMsRunIds().front());
384 
385  pappso::TimsMsRunReaderMs2 *tims2_reader =
386  dynamic_cast<pappso::TimsMsRunReaderMs2 *>(p_reader.get());
387  if(tims2_reader != nullptr)
388  {
389  qDebug();
390  tims2_reader->setMs2BuiltinCentroid(true);
391 
392  if(msp_ms2FilterSuiteString != nullptr)
393  {
395  }
396  qDebug();
397  }
398 
399 
400  pappso::MzxmlOutput *p_mzxml_output;
401  QFile output_file(target);
402  // qDebug() << " TsvDirectoryWriter::writeSheet " <<
403  // QFileInfo(*_p_ofile).absoluteFilePath();
404  if(output_file.open(QIODevice::WriteOnly))
405  {
406  p_mzxml_output =
407  new pappso::MzxmlOutput(QTextStream(&output_file).device());
408 
409  p_mzxml_output->maskMs1(true);
410 
411  p_mzxml_output->setReadAhead(true);
412 
413  p_mzxml_output->write(p_reader.get());
414 
415  p_mzxml_output->close();
416 
417  delete p_mzxml_output;
418  }
419  else
420  {
422  tr("unable to write into %1 mzXML output file").arg(target));
423  }
424 
425  qDebug();
426 }
427 
428 void
429 TandemWrapperRun::run(const QString &tandem_input_file,
430  QTextStream &output_stream,
431  QTextStream &error_stream)
432 {
433  mp_outputStream = &output_stream;
434  mp_errorStream = &error_stream;
435 
436  wrapTandemInputFile(tandem_input_file);
437  mp_outputStream = nullptr;
438  mp_errorStream = nullptr;
439 }
440 void
441 TandemWrapperRun::runTandem(const QString &tandem_input_file)
442 {
443 
444  m_xtProcess = new QProcess();
445  QStringList arguments;
446 
447  qDebug() << m_tandemBinary << " " << m_xtProcess->arguments();
448 
449  arguments << tandem_input_file;
450  // hk_process->setWorkingDirectory(QFileInfo(_hardklor_exe).absolutePath());
451  m_xtProcess->start(m_tandemBinary, arguments);
452 
453  qDebug() << m_tandemBinary << " " << m_xtProcess->arguments();
454 
455  connect(m_xtProcess,
456  &QProcess::readyReadStandardOutput,
457  this,
459  connect(m_xtProcess,
460  &QProcess::readyReadStandardError,
461  this,
463 
464 
465  qDebug() << m_tandemBinary << " " << m_xtProcess->arguments();
466 
467  if(!m_xtProcess->waitForStarted())
468  {
470  QObject::tr("X!Tandem process failed to start"));
471  }
472 
473  qDebug() << m_tandemBinary << " " << m_xtProcess->arguments();
474 
475  while(m_xtProcess->waitForFinished(m_maxTandemRunTimeMs))
476  {
477  //_p_monitor->appendText(xt_process->readAll().data());
478  // data.append(xt_process->readAll());
479  if(shouldIstop())
480  {
481  m_xtProcess->kill();
482  delete m_xtProcess;
484  QObject::tr("X!Tandem stopped by the user processing on file %1")
485  .arg(tandem_input_file));
486  }
487  }
488 
489  QProcess::ExitStatus Status = m_xtProcess->exitStatus();
490 
491  delete m_xtProcess;
492  if(Status != 0)
493  {
494  // != QProcess::NormalExit
496  QObject::tr("error executing X!Tandem Status != 0 : %1")
497  .arg(m_tandemBinary));
498  }
499  m_xtProcess = nullptr;
500 }
501 
502 QString
504 {
505  if(msp_ms2FilterSuiteString == nullptr)
506  return "";
507  return msp_ms2FilterSuiteString.get()->toString();
508 }
509 
510 } // namespace pappso
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)
Definition: mzxmloutput.cpp:90
void write(MsRunReader *p_msrunreader)
Definition: mzxmloutput.cpp:95
void maskMs1(bool mask_ms1)
QTemporaryDir * mpa_temporaryDirectory
void setTandemBinaryPath(const QString &tandem_binary_path)
void run(const QString &tandem_input_file, QTextStream &output_stream, QTextStream &error_stream)
run a tandem job
void readTandemPresetFile(const QString &tandem_preset_file)
std::shared_ptr< FilterSuiteString > msp_ms2FilterSuiteString
void wrapTandemInputFile(const QString &tandem_input_file)
void convertOrginalMsData2mzXmlData(const QString &origin, const QString &target) const
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
const QString & getOriginalTandemOutputFileName() const
const QString & getOriginalTandemPresetFileName() const
const QString & getOriginalMsDataFileName() const
void setInputParameters(const QString &label_name_attribute, const QString &input_value)
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:151
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