ATLAS Offline Software
DecayParser.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration
3 */
4 
6 // DecayParser.cxx
7 // Implementation file for class DecayParser
8 // Author: S.Binet<binet@cern.ch>
10 
11 // Python includes
12 #include "Python.h"
13 #include "RootUtils/PyGetString.h"
14 
15 // STL includes
16 #include <iostream>
17 #include <list>
18 #include <stdexcept>
19 #include <sstream>
20 
21 // McParticleUtils includes
23 
24 
25 
26 namespace {
27  PyObject *fetch_py_parse_fct();
28  bool py_to_cpp (PyObject* candidates,
29  std::vector<McUtils::Strings>& parsed);
30 }
31 
35 
38 
39 DecayParser::DecayParser( const std::string& cmd ) :
40  m_parseFct (0),
41  m_parents ( ),
42  m_children ( )
43 {
44  m_parseFct = ::fetch_py_parse_fct();
45  parse(cmd);
46 }
47 
48 
52 {
53  Py_XDECREF (m_parseFct);
54 }
55 
59 void DecayParser::dump() const
60 {
61  std::cout << "--- Parents ---" << std::endl;
63 
64  std::cout << "--- Children ---" << std::endl;
66 }
67 
68 int DecayParser::pdgId( const std::string& pdgIdString ) const
69 {
70  int pdgID = 0;
71  int iPDG = 0;
72  std::stringstream( pdgIdString ) >> iPDG;
73  pdgID = iPDG;
74 
75  return pdgID;
76 }
80 void DecayParser::parse( const std::string& inputCmd )
81 {
82  if ( inputCmd.empty() ) {
83  return;
84  }
85 
86  // Reset the parents and children lists
87  m_parents.clear();
88  m_children.clear();
89 
90 
91 
92  // real parsing takes place now.
93  PyObject *res = PyObject_CallFunction (m_parseFct,
94  (char*)"s",
95  inputCmd.c_str());
96  if (!res) {
97  Py_XDECREF (res);
98  std::string error = "problem while parsing command [" + inputCmd +"]";
99  throw std::runtime_error (error);
100  }
101 
102  if (!PyTuple_Check (res)) {
103  Py_DECREF (res);
104  std::string error = "expected a python tuple";
105  throw std::runtime_error (error);
106  }
107 
108  if (PyTuple_GET_SIZE (res) != 3) {
109  Py_DECREF (res);
110  std::string error = "expected a python tuple of size 3";
111  throw std::runtime_error (error);
112  }
113 
114  PyObject *sc = PyTuple_GET_ITEM (res, 0);
115  Py_XINCREF (sc);
116 #if PY_MAJOR_VERSION < 3
117  if (!sc || !PyInt_Check (sc)) {
118 #else
119  if (!sc || !PyLong_Check (sc)) {
120 #endif
121  Py_XDECREF (sc);
122  Py_DECREF (res);
123  std::string error = "corrupted return code";
124  throw std::runtime_error (error);
125  }
126 
127 #if PY_MAJOR_VERSION < 3
128  Py_ssize_t status = PyInt_AsSsize_t (sc);
129 #else
130  Py_ssize_t status = PyLong_AsSsize_t (sc);
131 #endif
132  if (status != 0) {
133  Py_DECREF (sc);
134  Py_DECREF (res);
135  std::string error = "failed to parse command ["+inputCmd+"]";
136  throw std::runtime_error (error);
137  }
138  Py_DECREF (sc);
139 
140  PyObject *parents = PyTuple_GET_ITEM (res, 1);
141  Py_XINCREF (parents);
142  if (!parents) {
143  Py_DECREF (res);
144  std::string error = "corrupted parents' list";
145  throw std::runtime_error (error);
146  }
147 
148  PyObject *children= PyTuple_GET_ITEM (res, 2);
149  Py_XINCREF (children);
150  if (!children) {
151  Py_DECREF (parents);
152  Py_DECREF (res);
153  std::string error = "corrupted children' list";
154  throw std::runtime_error (error);
155  }
156  Py_DECREF (res);
157 
158  if (parents==Py_None && children==Py_None) {
159  // special case of a single arrow without any parent nor child :
160  // this decay pattern will select every single vertex
161  Py_DECREF (parents);
162  Py_DECREF (children);
163  return;
164  }
165 
166  if (!py_to_cpp (parents, m_parents)) {
167  Py_DECREF (parents);
168  Py_DECREF (children);
169  std::string error = "could not translate parents' list";
170  throw std::runtime_error (error);
171  }
172 
173  if (!py_to_cpp (children, m_children)) {
174  Py_DECREF (parents);
175  Py_DECREF (children);
176  std::string error = "could not translate children' list";
177  throw std::runtime_error (error);
178  }
179 
180  return;
181 }
182 
183 
187 
188 
189 void
190 DecayParser::printMcUtilsStrings( const std::vector<McUtils::Strings>& list ) const
191 {
192  unsigned int iSlot = 0;
193  for( std::vector<McUtils::Strings>::const_iterator itr = list.begin();
194  itr != list.end();
195  ++itr,++iSlot ) {
196  std::stringstream iSlotStr;
197  iSlotStr << iSlot;
198  const McUtils::Strings::const_iterator candEnd = itr->end();
199  std::cout << "slot #" << iSlotStr.str() << ": candidates= [ ";
200  for( McUtils::Strings::const_iterator candidate = itr->begin();
201  candidate != candEnd;
202  ++candidate ) {
203  std::cout << *candidate;
204  if ( candidate+1 != candEnd ) {
205  std::cout << " | ";
206  }
207  }
208  std::cout << " ]" << std::endl;
209  }
210  return;
211 }
212 
213 
215 // Operators:
217 // cppcheck-suppress operatorEqVarError; m_parseFct deliberately not copied.
219 {
220  if ( this != &rhs ) {
221  m_parents = rhs.m_parents;
222  m_children = rhs.m_children;
223  }
224  return *this;
225 }
226 
227 namespace {
228 
229 PyObject*
230 fetch_py_parse_fct()
231 {
232  // need to ensure the python interpreter has been initialized...
233  if (!Py_IsInitialized()) {
234  Py_Initialize();
235  }
236 
237  const std::string n = "McParticleUtils.DecayParser";
238  PyObject *module = PyImport_ImportModule (const_cast<char*>(n.c_str()));
239  if (!module || !PyModule_Check (module)) {
240  Py_XDECREF (module);
241  std::string error = "could not import module ["+n+"]";
242  throw std::runtime_error (error);
243  }
244 
245  const std::string fct_name = "py_parse";
246  PyObject *fct = PyDict_GetItemString (PyModule_GetDict (module),
247  const_cast<char*>(fct_name.c_str()));
248  // borrowed ref.
249  Py_XINCREF (fct);
250  // don't need the module anymore
251  Py_DECREF (module);
252 
253  if (!fct || !PyFunction_Check (fct)) {
254  std::string error = "could not get '"+fct_name+"' from module ["+n+"] or not a function";
255  throw std::runtime_error (error);
256  }
257 
258  return fct;
259 }
260 
261 bool
262 py_to_cpp (PyObject* candidates,
263  std::vector<McUtils::Strings>& parsed)
264 {
265  bool all_good = true;
266  if (candidates==Py_None) {
267  // nothing to do
268  return true;
269  }
270 
271  if (!PySequence_Check (candidates)) {
272  return false;
273  }
274  Py_ssize_t isz = PySequence_Size (candidates);
275  if (isz==-1) {
276  return false;
277  }
278  parsed.resize (isz);
279 
280  for (Py_ssize_t i = 0; i!=isz; ++i) {
281  PyObject *cand = PySequence_GetItem(candidates, i);
282  if (!cand) {
283  return false;
284  }
285  if (!PySequence_Check (cand)) {
286  Py_DECREF (cand);
287  return false;
288  }
289  Py_ssize_t jsz = PySequence_Size (cand);
290  if (jsz==-1) {
291  Py_DECREF (cand);
292  return false;
293  }
294 
295  parsed[i].resize(jsz);
296 
297  for (Py_ssize_t j = 0; j!=jsz; ++j) {
298  PyObject *pdgid = PySequence_GetItem(cand, j);
299  if (!pdgid) {
300  Py_DECREF (cand);
301  return false;
302  }
303 
304  parsed[i][j] = RootUtils::PyGetString (pdgid).first;
305  }
306 
307  Py_DECREF (cand);
308  }
309  return all_good;
310 }
311 } //> anon-namespace
DecayParser::m_parseFct
PyObject * m_parseFct
python function to parse the input string modeling the decay pattern to look for.
Definition: DecayParser.h:93
DecayParser::parse
void parse(const std::string &cmd)
Non-const methods:
Definition: DecayParser.cxx:80
drawFromPickle.candidates
candidates
Definition: drawFromPickle.py:271
python.DecayParser.parents
parents
print ("==> buf:",buf)
Definition: DecayParser.py:31
rerun_display.cmd
string cmd
Definition: rerun_display.py:67
DecayParser.h
python.PyAthena.fct_name
fct_name
Definition: PyAthena.py:135
python.AthDsoLogger.fct
fct
Definition: AthDsoLogger.py:43
DecayParser::operator=
DecayParser & operator=(const DecayParser &obj)
Assignment operator:
Definition: DecayParser.cxx:218
AthenaPoolTestRead.sc
sc
Definition: AthenaPoolTestRead.py:27
DecayParser::m_parents
std::vector< McUtils::Strings > m_parents
List of parents : each slot of the vector is a list of candidates So one could have something like : ...
Definition: DecayParser.h:99
python.PyAthena.module
module
Definition: PyAthena.py:131
DecayParser::m_children
std::vector< McUtils::Strings > m_children
List of children : each slot of the vector is a list of candidates So one could have something like :...
Definition: DecayParser.h:105
DecayParser::~DecayParser
virtual ~DecayParser()
Destructor:
Definition: DecayParser.cxx:51
lumiFormat.i
int i
Definition: lumiFormat.py:85
beamspotman.n
n
Definition: beamspotman.py:731
res
std::pair< std::vector< unsigned int >, bool > res
Definition: JetGroupProductTest.cxx:14
IDTPMcnv.parsed
parsed
Definition: IDTPMcnv.py:28
histSizes.list
def list(name, path='/')
Definition: histSizes.py:38
DecayParser::printMcUtilsStrings
void printMcUtilsStrings(const std::vector< McUtils::Strings > &list) const
Print the content of a vector of McUtils::Strings to std::cout.
Definition: DecayParser.cxx:190
DecayParser::DecayParser
DecayParser()
Default constructor:
PyGetString.h
Convert python string -> C++ string for py2 and py3.
RootUtils::PyGetString
std::pair< std::string, bool > PyGetString(PyObject *s)
Convert python string -> C++ string for py2 and py3.
Definition: PyGetString.h:40
DecayParser::pdgId
int pdgId(const std::string &pdgIdString) const
Definition: DecayParser.cxx:68
python.DecayParser.children
children
Definition: DecayParser.py:32
merge.status
status
Definition: merge.py:17
error
Definition: IImpactPoint3dEstimator.h:70
DecayParser::dump
void dump() const
Const methods:
Definition: DecayParser.cxx:59
PyObject
_object PyObject
Definition: IPyComponent.h:26
DecayParser
Definition: DecayParser.h:34