ATLAS Offline Software
DecayParser.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2025 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 (!sc || !PyLong_Check (sc)) {
117  Py_XDECREF (sc);
118  Py_DECREF (res);
119  std::string error = "corrupted return code";
120  throw std::runtime_error (error);
121  }
122 
123  Py_ssize_t status = PyLong_AsSsize_t (sc);
124  if (status != 0) {
125  Py_DECREF (sc);
126  Py_DECREF (res);
127  std::string error = "failed to parse command ["+inputCmd+"]";
128  throw std::runtime_error (error);
129  }
130  Py_DECREF (sc);
131 
132  PyObject *parents = PyTuple_GET_ITEM (res, 1);
133  Py_XINCREF (parents);
134  if (!parents) {
135  Py_DECREF (res);
136  std::string error = "corrupted parents' list";
137  throw std::runtime_error (error);
138  }
139 
140  PyObject *children= PyTuple_GET_ITEM (res, 2);
141  Py_XINCREF (children);
142  if (!children) {
143  Py_DECREF (parents);
144  Py_DECREF (res);
145  std::string error = "corrupted children' list";
146  throw std::runtime_error (error);
147  }
148  Py_DECREF (res);
149 
150  if (parents==Py_None && children==Py_None) {
151  // special case of a single arrow without any parent nor child :
152  // this decay pattern will select every single vertex
153  Py_DECREF (parents);
154  Py_DECREF (children);
155  return;
156  }
157 
158  if (!py_to_cpp (parents, m_parents)) {
159  Py_DECREF (parents);
160  Py_DECREF (children);
161  std::string error = "could not translate parents' list";
162  throw std::runtime_error (error);
163  }
164 
165  if (!py_to_cpp (children, m_children)) {
166  Py_DECREF (parents);
167  Py_DECREF (children);
168  std::string error = "could not translate children' list";
169  throw std::runtime_error (error);
170  }
171 
172  return;
173 }
174 
175 
179 
180 
181 void
182 DecayParser::printMcUtilsStrings( const std::vector<McUtils::Strings>& list ) const
183 {
184  unsigned int iSlot = 0;
185  for( std::vector<McUtils::Strings>::const_iterator itr = list.begin();
186  itr != list.end();
187  ++itr,++iSlot ) {
188  std::stringstream iSlotStr;
189  iSlotStr << iSlot;
190  const McUtils::Strings::const_iterator candEnd = itr->end();
191  std::cout << "slot #" << iSlotStr.str() << ": candidates= [ ";
192  for( McUtils::Strings::const_iterator candidate = itr->begin();
193  candidate != candEnd;
194  ++candidate ) {
195  std::cout << *candidate;
196  if ( candidate+1 != candEnd ) {
197  std::cout << " | ";
198  }
199  }
200  std::cout << " ]" << std::endl;
201  }
202  return;
203 }
204 
205 
207 // Operators:
209 // cppcheck-suppress operatorEqVarError; m_parseFct deliberately not copied.
211 {
212  if ( this != &rhs ) {
213  m_parents = rhs.m_parents;
214  m_children = rhs.m_children;
215  }
216  return *this;
217 }
218 
219 namespace {
220 
221 PyObject*
222 fetch_py_parse_fct()
223 {
224  // need to ensure the python interpreter has been initialized...
225  if (!Py_IsInitialized()) {
226  Py_Initialize();
227  }
228 
229  const std::string n = "McParticleUtils.DecayParser";
230  PyObject *module = PyImport_ImportModule (const_cast<char*>(n.c_str()));
231  if (!module || !PyModule_Check (module)) {
232  Py_XDECREF (module);
233  std::string error = "could not import module ["+n+"]";
234  throw std::runtime_error (error);
235  }
236 
237  const std::string fct_name = "py_parse";
238  PyObject *fct = PyDict_GetItemString (PyModule_GetDict (module),
239  const_cast<char*>(fct_name.c_str()));
240  // borrowed ref.
241  Py_XINCREF (fct);
242  // don't need the module anymore
243  Py_DECREF (module);
244 
245  if (!fct || !PyFunction_Check (fct)) {
246  std::string error = "could not get '"+fct_name+"' from module ["+n+"] or not a function";
247  throw std::runtime_error (error);
248  }
249 
250  return fct;
251 }
252 
253 bool
254 py_to_cpp (PyObject* candidates,
255  std::vector<McUtils::Strings>& parsed)
256 {
257  bool all_good = true;
258  if (candidates==Py_None) {
259  // nothing to do
260  return true;
261  }
262 
263  if (!PySequence_Check (candidates)) {
264  return false;
265  }
266  Py_ssize_t isz = PySequence_Size (candidates);
267  if (isz==-1) {
268  return false;
269  }
270  parsed.resize (isz);
271 
272  for (Py_ssize_t i = 0; i!=isz; ++i) {
273  PyObject *cand = PySequence_GetItem(candidates, i);
274  if (!cand) {
275  return false;
276  }
277  if (!PySequence_Check (cand)) {
278  Py_DECREF (cand);
279  return false;
280  }
281  Py_ssize_t jsz = PySequence_Size (cand);
282  if (jsz==-1) {
283  Py_DECREF (cand);
284  return false;
285  }
286 
287  parsed[i].resize(jsz);
288 
289  for (Py_ssize_t j = 0; j!=jsz; ++j) {
290  PyObject *pdgid = PySequence_GetItem(cand, j);
291  if (!pdgid) {
292  Py_DECREF (cand);
293  return false;
294  }
295 
296  parsed[i][j] = RootUtils::PyGetString (pdgid).first;
297  }
298 
299  Py_DECREF (cand);
300  }
301  return all_good;
302 }
303 } //> 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:42
DecayParser::operator=
DecayParser & operator=(const DecayParser &obj)
Assignment operator:
Definition: DecayParser.cxx:210
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:729
res
std::pair< std::vector< unsigned int >, bool > res
Definition: JetGroupProductTest.cxx:11
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:182
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:16
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