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>
26using namespace boost::python;
39 if (path.get() ==
this) {
40 B2FATAL(
"Attempting to add a path to itself!");
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());
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());
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);
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);
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();
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)
251Insert another path at the end of this one.
254 >>> path.add_module('A')
255 >>> path.add_path(otherPath)
256 >>> path.add_module('B')
258would create a path [ A -> [ contents of otherPath ] -> B ].)
261 path (Path): path to add to this path)")
262 .def("modules", &_getModulesPython, R
"(modules()
264Returns an ordered list of all modules in this path.)")
265 .def("for_each", &
Path::forEach, R
"(for_each(loop_object_name, array_name, path)
267Similar to `add_path()`, this will
268execute the given ``path`` at the current position, but in each event it will
269execute it once for each object in the given StoreArray ``arrayName``. It will
270create a StoreObject named ``loop_object_name`` of same type as array which will
271point to each element in turn for each execution.
273This has the effect of calling the ``event()`` methods of modules in ``path``
274for each entry in ``arrayName``.
276The 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
278of 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``"
286For example, if 'RestOfEvents' contains two elements then ``roe_path`` will be
287executed twice and during the execution a StoreObjectPtr 'RestOfEvent' will be
288available, which will point to the first element in the first execution, and
289the 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.
297Changes 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
299the i'th item in the array looped over.)
301StoreArrays / StoreObjects (of event durability) *created* inside the loop will
302be removed at the end of each iteration. So if you create a new particle list
303inside a `for_each()` path execution the particle list will not exist for the
304next 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)
315Similar to `add_path()` this will execute a path at the current position but it
316will repeat execution of this path as long as the return value of the last
317module in the path fulfills the given ``condition``.
319This 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 ModuleManager & Instance()
Exception is thrown if the requested module could not be created by 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).
@ 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'.
std::list< std::shared_ptr< PathElement > > m_elements
The list of path elements (Modules and sub-Paths)
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.