ATLAS Offline Software
Loading...
Searching...
No Matches
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"
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 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
181void
182DecayParser::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;
215 }
216 return *this;
217}
218
219namespace {
220
222fetch_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
253bool
254py_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
_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