ATLAS Offline Software
Loading...
Searching...
No Matches
DecayParser.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 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"
14
15// STL includes
16#include <iostream>
17#include <list>
18#include <stdexcept>
19#include <sstream>
20
21// McParticleUtils includes
23
24
25
26namespace {
27 PyObject *fetch_py_parse_fct();
28 bool py_to_cpp (PyObject* candidates,
29 std::vector<McUtils::Strings>& parsed);
30}
31
35
38
39DecayParser::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
60{
61 std::cout << "--- Parents ---" << std::endl;
63
64 std::cout << "--- Children ---" << std::endl;
66}
67
68int 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}
77
80void 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 //coverity[COPY_PASTE_ERROR]
136 Py_DECREF (res);
137 std::string error = "corrupted parents' list";
138 throw std::runtime_error (error);
139 }
140
141 PyObject *children= PyTuple_GET_ITEM (res, 2);
142 Py_XINCREF (children);
143 if (!children) {
144 Py_DECREF (parents);
145 Py_DECREF (res);
146 std::string error = "corrupted children' list";
147 throw std::runtime_error (error);
148 }
149 Py_DECREF (res);
150
151 if (parents==Py_None && children==Py_None) {
152 // special case of a single arrow without any parent nor child :
153 // this decay pattern will select every single vertex
154 Py_DECREF (parents);
155 Py_DECREF (children);
156 return;
157 }
158
159 if (!py_to_cpp (parents, m_parents)) {
160 Py_DECREF (parents);
161 Py_DECREF (children);
162 std::string error = "could not translate parents' list";
163 throw std::runtime_error (error);
164 }
165
166 if (!py_to_cpp (children, m_children)) {
167 Py_DECREF (parents);
168 Py_DECREF (children);
169 std::string error = "could not translate children' list";
170 throw std::runtime_error (error);
171 }
172
173 return;
174}
175
176
180
181
182void
183DecayParser::printMcUtilsStrings( const std::vector<McUtils::Strings>& list ) const
184{
185 unsigned int iSlot = 0;
186 for( std::vector<McUtils::Strings>::const_iterator itr = list.begin();
187 itr != list.end();
188 ++itr,++iSlot ) {
189 std::stringstream iSlotStr;
190 iSlotStr << iSlot;
191 const McUtils::Strings::const_iterator candEnd = itr->end();
192 std::cout << "slot #" << iSlotStr.str() << ": candidates= [ ";
193 for( McUtils::Strings::const_iterator candidate = itr->begin();
194 candidate != candEnd;
195 ++candidate ) {
196 std::cout << *candidate;
197 if ( candidate+1 != candEnd ) {
198 std::cout << " | ";
199 }
200 }
201 std::cout << " ]" << std::endl;
202 }
203 return;
204}
205
206
208// Operators:
210// cppcheck-suppress operatorEqVarError; m_parseFct deliberately not copied.
212{
213 if ( this != &rhs ) {
214 m_parents = rhs.m_parents;
216 }
217 return *this;
218}
219
220namespace {
221
223fetch_py_parse_fct()
224{
225 // need to ensure the python interpreter has been initialized...
226 if (!Py_IsInitialized()) {
227 Py_Initialize();
228 }
229
230 const std::string n = "McParticleUtils.DecayParser";
231 PyObject *module = PyImport_ImportModule (const_cast<char*>(n.c_str()));
232 if (!module || !PyModule_Check (module)) {
233 Py_XDECREF (module);
234 std::string error = "could not import module ["+n+"]";
235 throw std::runtime_error (error);
236 }
237
238 const std::string fct_name = "py_parse";
239 PyObject *fct = PyDict_GetItemString (PyModule_GetDict (module),
240 const_cast<char*>(fct_name.c_str()));
241 // borrowed ref.
242 Py_XINCREF (fct);
243 // don't need the module anymore
244 Py_DECREF (module);
245
246 if (!fct || !PyFunction_Check (fct)) {
247 std::string error = "could not get '"+fct_name+"' from module ["+n+"] or not a function";
248 throw std::runtime_error (error);
249 }
250
251 return fct;
252}
253
254bool
255py_to_cpp (PyObject* candidates,
256 std::vector<McUtils::Strings>& parsed)
257{
258 bool all_good = true;
259 if (candidates==Py_None) {
260 // nothing to do
261 return true;
262 }
263
264 if (!PySequence_Check (candidates)) {
265 return false;
266 }
267 Py_ssize_t isz = PySequence_Size (candidates);
268 if (isz==-1) {
269 return false;
270 }
271 parsed.resize (isz);
272
273 for (Py_ssize_t i = 0; i!=isz; ++i) {
274 PyObject *cand = PySequence_GetItem(candidates, i);
275 if (!cand) {
276 return false;
277 }
278 if (!PySequence_Check (cand)) {
279 Py_DECREF (cand);
280 return false;
281 }
282 Py_ssize_t jsz = PySequence_Size (cand);
283 if (jsz==-1) {
284 Py_DECREF (cand);
285 return false;
286 }
287
288 parsed[i].resize(jsz);
289
290 for (Py_ssize_t j = 0; j!=jsz; ++j) {
291 PyObject *pdgid = PySequence_GetItem(cand, j);
292 if (!pdgid) {
293 Py_DECREF (cand);
294 return false;
295 }
296
297 parsed[i][j] = RootUtils::PyGetString (pdgid).first;
298 }
299
300 Py_DECREF (cand);
301 }
302 return all_good;
303}
304} //> anon-namespace
_object PyObject
std::pair< std::vector< unsigned int >, bool > res
static Double_t sc
Convert python string -> C++ string for py2 and py3.
DecayParser()
Default constructor:
void printMcUtilsStrings(const std::vector< McUtils::Strings > &list) const
Print the content of a vector of McUtils::Strings to std::cout.
void dump() const
Const methods:
virtual ~DecayParser()
Destructor:
DecayParser(const std::string &cmd)
Constructor with parameters:
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
void parse(const std::string &cmd)
Non-const methods:
int pdgId(const std::string &pdgIdString) const
DecayParser & operator=(const DecayParser &obj)
Assignment operator:
PyObject * m_parseFct
python function to parse the input string modeling the decay pattern to look for.
Definition DecayParser.h:93
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 :...
std::pair< std::string, bool > PyGetString(PyObject *s)
Convert python string -> C++ string for py2 and py3.
Definition PyGetString.h:40
float j(const xAOD::IParticle &, const xAOD::TrackMeasurementValidation &hit, const Eigen::Matrix3d &jab_inv)