9 #include <boost/python/register_ptr_to_python.hpp>
10 #include <boost/python/class.hpp>
11 #include <boost/python/list.hpp>
12 #include <boost/python/docstring_options.hpp>
15 #include <framework/core/Path.h>
16 #include <framework/core/Module.h>
17 #include <framework/core/ModuleManager.h>
18 #include <framework/core/SubEventModule.h>
19 #include <framework/core/SwitchDataStoreModule.h>
20 #include <framework/core/MergeDataStoreModule.h>
21 #include <framework/core/SteerRootInputModule.h>
22 #include <framework/core/CreateConsistencyInfoModule.h>
23 #include <framework/core/PyObjConvUtils.h>
26 using namespace boost::python;
34 m_elements.push_back(module);
39 if (path.get() ==
this) {
40 B2FATAL(
"Attempting to add a path to itself!");
42 m_elements.push_back(path);
47 return m_elements.empty();
52 std::list<ModulePtr> modules;
53 for (
const std::shared_ptr<PathElement>& elem : m_elements) {
54 if (
dynamic_cast<Module*
>(elem.get()) !=
nullptr) {
56 modules.push_back(std::static_pointer_cast<Module>(elem));
59 const std::list<ModulePtr>& modulesInElem = elem->getModules();
60 modules.insert(modules.end(), modulesInElem.begin(), modulesInElem.end());
70 for (
const ModulePtr& module : getModules()) {
71 if (!unique or find(modList.begin(), modList.end(), module) == modList.end()) {
72 modList.push_back(module);
75 if (module->hasCondition()) {
76 for (
const auto& conditionPath : module->getAllConditionPaths()) {
78 if (conditionPath.get() ==
this) B2FATAL(
"Found recursion in conditional path");
79 const std::list<ModulePtr>& modulesInElem = conditionPath->buildModulePathList(unique);
80 modList.insert(modList.end(), modulesInElem.begin(), modulesInElem.end());
91 m_elements.assign(mlist.begin(), mlist.end());
112 static int dscount = 1;
113 ds_ID =
"DS " + std::to_string(dscount++);
120 switchStart->setName(
"SwitchDataStore ('' -> '" + ds_ID +
"')");
121 switchEnd->setName(
"SwitchDataStore ('' <- '" + ds_ID +
"')");
126 switchStart->setPropertyFlags(flag);
127 switchEnd->setPropertyFlags(flag);
130 addModule(switchStart);
131 addPath(independent_path);
132 addModule(switchEnd);
136 std::string consistency_check,
bool event_mixing,
bool merge_same_file)
139 static int dscount = 1;
140 ds_ID =
"DS " + std::to_string(dscount++);
147 switchStart->setName(
"MergeDataStore ('' -> '" + ds_ID +
"')");
148 switchEnd->setName(
"MergeDataStore ('' <- '" + ds_ID +
"')");
159 switchStart->setPropertyFlags(flag);
160 switchEnd->setPropertyFlags(flag);
164 addModule(switchStart);
166 addPath(independent_path);
168 addModule(switchEnd);
170 addModule(fillConsistencyInfo);
172 addModule(steerInput);
175 steerInput->if_value(
"==0", std::make_shared<Path>());
180 const std::list<ModulePtr>& modules = getModules();
182 auto sameTypeFunc = [moduleType](
const ModulePtr & m) ->
bool {
return m->getType() == moduleType; };
183 return std::find_if(modules.begin(), modules.end(), sameTypeFunc) != modules.end();
189 for (
const auto& elem : m_elements) {
190 const auto* m =
dynamic_cast<const Module*
>(elem.get());
191 if (m and m->getType() ==
"PyModule") {
193 path->addModule(std::static_pointer_cast<Module>(elem));
195 path->m_elements.push_back(elem->clone());
209 bool firstElem =
true;
210 for (
const std::shared_ptr<PathElement>& elem : m_elements) {
217 out += elem->getPathString();
219 return "[" + out +
"]";
227 boost::python::list _getModulesPython(
const Path* path)
229 boost::python::list returnList;
231 for (
const ModulePtr& module : path->getModules())
232 returnList.append(boost::python::object(
ModulePtr(module)));
240 docstring_options options(
true,
false,
false);
241 using bparg = boost::python::arg;
244 R
"(Implements a path consisting of Module and/or Path objects (arranged in a linear order).
246 .. seealso:: :func:`basf2.process`)")
249 .def(
"add_path", &
Path::addPath, args(
"path"), R
"(add_path(path)
251 Insert another path at the end of this one.
254 >>> path.add_module('A')
255 >>> path.add_path(otherPath)
256 >>> path.add_module('B')
258 would create a path [ A -> [ contents of otherPath ] -> B ].)
261 path (Path): path to add to this path)")
262 .def("modules", &_getModulesPython, R
"(modules()
264 Returns an ordered list of all modules in this path.)")
265 .def("for_each", &
Path::forEach, R
"(for_each(loop_object_name, array_name, path)
267 Similar to `add_path()`, this will
268 execute the given ``path`` at the current position, but in each event it will
269 execute it once for each object in the given StoreArray ``arrayName``. It will
270 create a StoreObject named ``loop_object_name`` of same type as array which will
271 point to each element in turn for each execution.
273 This has the effect of calling the ``event()`` methods of modules in ``path``
274 for each entry in ``arrayName``.
276 The main use case is to use it after using the `RestOfEventBuilder` on a
277 ``ParticeList``, where you can use this feature to perform actions on only a part
278 of the event for a given list of candidates:
280 >>> path.for_each('RestOfEvent', 'RestOfEvents', roe_path)
284 "for each ``RestOfEvent`` in the array of "RestOfEvents", execute ``roe_path``"
286 For example, if 'RestOfEvents' contains two elements then ``roe_path`` will be
287 executed twice and during the execution a StoreObjectPtr 'RestOfEvent' will be
288 available, which will point to the first element in the first execution, and
289 the second element in the second execution.
292 A working example of this `for_each` RestOfEvent is to build a veto against
293 photons from :math:`\pi^0\to\gamma\gamma`. It is described in `HowToVeto`.
295 .. note:: This feature is used by both the `FlavorTagger` and :ref:`FullEventInterpretation` algorithms.
297 Changes to existing arrays / objects will be available to all modules after the
298 `for_each()`, including those made to the loop object itself (it will simply modify
299 the i'th item in the array looped over.)
301 StoreArrays / StoreObjects (of event durability) *created* inside the loop will
302 be removed at the end of each iteration. So if you create a new particle list
303 inside a `for_each()` path execution the particle list will not exist for the
304 next iteration or after the `for_each()` is complete.
307 loop_object_name (str): The name of the object in the datastore during each execution
308 array_name (str): The name of the StoreArray to loop over where the i-th
309 element will be available as ``loop_object_name`` during the i-th execution
311 path (basf2.Path): The path to execute for each element in ``array_name``)",
312 args("loop_object_name",
"array_name",
"path"))
313 .def(
"do_while", &
Path::doWhile, R
"(do_while(path, condition='<1', max_iterations=10000)
315 Similar to `add_path()` this will execute a path at the current position but it
316 will repeat execution of this path as long as the return value of the last
317 module in the path fulfills the given ``condition``.
319 This is useful for event generation with special cuts like inclusive particle generation.
322 `Module.if_value` for an explanation of the condition expression.
325 path (basf2.Path): sub path to execute repeatedly
326 condition (str): condition on the return value of the last module in ``path``.
327 The execution will be repeated as long as this condition is fulfilled.
328 max_iterations (int): Maximum number of iterations per event. If this number is exceeded
329 the execution is aborted.
330 )", (bparg("path"), bparg(
"condition") =
"<1", bparg(
"max_iterations") = 10000))
333 .def(
"__contains__", &
Path::contains, R
"(Does this Path contain a module of the given type?
335 >>> path = basf2.Path()
336 >>> 'RootInput' in path
338 >>> path.add_module('RootInput')
339 >>> 'RootInput' in path
340 True)", args("moduleType"))
343 register_ptr_to_python<PathPtr>();
If you want to merge two events with the 'MergeDataStoreModule', it might be necessary to make sure t...
void init(const std::string &option, bool eventMixing)
setter for Path.
Internal module used by Path.add_independent_merge_path().
void init(const std::string &to, bool doCopy, const std::vector< std::string > &mergeBack)
setter for Path.
std::shared_ptr< Module > registerModule(const std::string &moduleName, std::string sharedLibPath="") noexcept(false)
Creates an instance of a module and registers it to the ModuleManager.
static bool allModulesHaveFlag(const std::list< std::shared_ptr< Module >> &list, unsigned int flag)
Returns true if and only if all modules in list have the given flag (or list is empty).
static ModuleManager & Instance()
Exception is thrown if the requested module could not be created by the ModuleManager.
@ c_ParallelProcessingCertified
This module can be run in parallel processing mode safely (All I/O must be done through the data stor...
Implements a path consisting of Module and/or Path objects.
void addIndependentMergePath(const PathPtr &independent_path, std::string ds_ID, const boost::python::list &merge_back, std::string consistency_check, bool event_mixing, bool mergeSameFile)
See 'pydoc3 basf2.Path'.
void forEach(const std::string &loopObjectName, const std::string &arrayName, PathPtr path)
See 'pydoc3 basf2.Path'.
void doWhile(PathPtr path, const std::string &condition, unsigned int maxIterations)
See 'pydoc3 basf2.Path'.
std::list< std::shared_ptr< Module > > buildModulePathList(bool unique=true) const
Builds a list of all modules which could be executed during the data processing.
static void exposePythonAPI()
Exposes methods of the Path class to Python.
void putModules(const std::list< std::shared_ptr< Module > > &mlist)
Replaces all Modules and sub-Paths with the specified Module list.
void addPath(const PathPtr &path)
See 'pydoc3 basf2.Path'.
void addModule(const std::shared_ptr< Module > &module)
Adds a module to the path.
bool isEmpty() const
Returns true if this Path doesn't contain any elements.
std::shared_ptr< PathElement > clone() const override
Create an independent copy of this path, recreating all contained modules with the same parameters.
void addIndependentPath(const PathPtr &independent_path, std::string ds_ID, const boost::python::list &merge_back)
See 'pydoc3 basf2.Path'.
bool contains(const std::string &moduleType) const
Does this Path contain a module of the given type?
std::list< std::shared_ptr< Module > > getModules() const override
Returns a list of the modules in this path.
std::string getPathString() const override
return a string of the form [module a -> module b -> [another path]]
Framework-internal module that implements the functionality of Path::forEach() as well as Path::doWhi...
void initSubLoop(std::shared_ptr< Path > path, const std::string &condition, unsigned int maxIterations)
ised by Path::doWhile() to actually set parameters
void initSubEvent(const std::string &objectName, const std::string &loopOver, std::shared_ptr< Path > path)
used by Path::forEach() to actually set parameters.
Internal module used by Path.add_independent_path().
void init(const std::string &to, bool doCopy, const std::vector< std::string > &mergeBack)
setter for Path.
std::shared_ptr< Path > PathPtr
Defines a pointer to a path object as a boost shared pointer.
std::shared_ptr< Module > ModulePtr
Defines a pointer to a module object as a boost shared pointer.
std::list< ModulePtr > ModulePtrList
Defines a std::list of shared module pointers.
Scalar convertPythonObject(const boost::python::object &pyObject, Scalar)
Convert from Python to given type.
Abstract base class for different kinds of events.