9 #include <framework/pybasf2/Framework.h> 
   11 #include <framework/core/PyObjConvUtils.h> 
   12 #include <framework/core/Environment.h> 
   13 #include <framework/core/RandomNumbers.h> 
   14 #include <framework/core/EventProcessor.h> 
   15 #include <framework/core/ModuleManager.h> 
   16 #include <framework/datastore/DataStore.h> 
   17 #include <framework/database/DBStore.h> 
   18 #include <framework/database/Database.h> 
   19 #include <framework/pcore/pEventProcessor.h> 
   20 #include <framework/pcore/ZMQEventProcessor.h> 
   21 #include <framework/pcore/zmq/utils/ZMQAddressUtils.h> 
   22 #include <framework/utilities/FileSystem.h> 
   23 #include <framework/database/Configuration.h> 
   25 #include <framework/logging/Logger.h> 
   26 #include <framework/logging/LogSystem.h> 
   28 #include <boost/algorithm/string.hpp> 
   29 #include <boost/algorithm/string/join.hpp> 
   30 #include <boost/python.hpp> 
   35 using namespace boost::python;
 
   39 Framework::Framework()
 
   41   DataStore::s_DoCleanup = 
true;
 
   42   LogSystem::Instance().enableErrorSummary(
true);
 
   44   if (!RandomNumbers::isInitialized()) {
 
   45     RandomNumbers::initialize();
 
   47   Environment::Instance();
 
   51 Framework::~Framework()
 
   57   ModuleManager::Instance().reset();
 
   58   DataStore::s_DoCleanup = 
false;
 
   60   Conditions::Configuration::getInstance().reset();
 
   64 void Framework::addModuleSearchPath(
const std::string& path)
 
   66   ModuleManager::Instance().addModuleSearchPath(path);
 
   70 void Framework::setExternalsPath(
const std::string& path)
 
   72   Environment::Instance().setExternalsPath(path);
 
   76 ModulePtr Framework::registerModule(
const std::string& moduleName)
 
   78   return ModuleManager::Instance().registerModule(moduleName);
 
   82 ModulePtr Framework::registerModule(
const std::string& moduleName, 
const std::string& sharedLibPath)
 
   84   return ModuleManager::Instance().registerModule(moduleName, sharedLibPath);
 
   88 void Framework::process(
PathPtr startPath, 
long maxEvent)
 
   90   if (Environment::Instance().getDryRun()) {
 
   91     Environment::Instance().setJobInformation(startPath);
 
   95   static bool already_executed = 
false;
 
   96   static std::set<const Module*> previously_run_modules; 
 
   97   static int errors_from_previous_run = 0;
 
   98   const auto moduleListUnique = startPath->buildModulePathList(
true);
 
   99   if (already_executed) {
 
  100     B2WARNING(
"Calling process() more than once per steering file is still experimental, please check results carefully! Python modules especially should reinitialise their state in initialise() to avoid problems");
 
  101     if (startPath->buildModulePathList(
true) != startPath->buildModulePathList(
false)) {
 
  102       B2FATAL(
"Your path contains the same module instance in multiple places. Calling process() multiple times is not implemented for this case.");
 
  106     for (
const auto& m : moduleListUnique) {
 
  107       if (previously_run_modules.count(m.get()) > 0) {
 
  109         startPath = std::static_pointer_cast<Path>(startPath->clone());
 
  114   for (
const auto& m : moduleListUnique) {
 
  115     previously_run_modules.insert(m.get());
 
  118   int numLogError = LogSystem::Instance().getMessageCounter(LogConfig::c_Error);
 
  119   if (numLogError != errors_from_previous_run) {
 
  120     B2FATAL(numLogError << 
" ERROR(S) occurred! The processing of events will not be started.");
 
  124     LogSystem::Instance().resetMessageCounter();
 
  125     DataStore::Instance().reset();
 
  126     DataStore::Instance().setInitializeActive(
true);
 
  128     auto& environment = Environment::Instance();
 
  130     already_executed = 
true;
 
  131     if (environment.getNumberProcesses() == 0) {
 
  134       processor.
process(startPath, maxEvent);
 
  136       if (environment.getUseZMQ()) {
 
  138         if (environment.getZMQSocketAddress().empty()) {
 
  139           environment.setZMQSocketAddress(ZMQAddressUtils::randomSocketName());
 
  142         processor.
process(startPath, maxEvent);
 
  145         processor.
process(startPath, maxEvent);
 
  148     errors_from_previous_run = LogSystem::Instance().getMessageCounter(LogConfig::c_Error);
 
  150     DBStore::Instance().reset();
 
  154     Database::Instance().reset(
true);
 
  155   } 
catch (std::exception& e) {
 
  156     B2ERROR(
"Uncaught exception encountered: " << e.what()); 
 
  157     DataStore::Instance().reset(); 
 
  160     B2ERROR(
"Uncaught exception encountered!"); 
 
  161     DataStore::Instance().reset(); 
 
  168 void Framework::setNumberProcesses(
int numProcesses)
 
  170   Environment::Instance().setNumberProcesses(numProcesses);
 
  174 int Framework::getNumberProcesses()
 
  176   return Environment::Instance().getNumberProcesses();
 
  180 void Framework::setPicklePath(
const std::string& path)
 
  182   Environment::Instance().setPicklePath(path);
 
  186 std::string Framework::getPicklePath()
 
  188   return Environment::Instance().getPicklePath();
 
  191 void Framework::setStreamingObjects(
const boost::python::list& streamingObjects)
 
  193   auto vec = PyObjConvUtils::convertPythonObject(streamingObjects, std::vector<std::string>());
 
  194   Environment::Instance().setStreamingObjects(vec);
 
  197 void Framework::setRealm(
const std::string& realm)
 
  200   std::vector<std::string> realms;
 
  201   for (
int i = LogConfig::c_None; i <= LogConfig::c_Production; i++) {
 
  203     realms.push_back(thisRealm);
 
  204     if (boost::iequals(realm, thisRealm)) { 
 
  210     B2ERROR(
"Invalid realm! Needs to be one of " << boost::join(realms, 
", "));
 
  217 std::string Framework::findFile(
const std::string& filename, 
const std::string& type, 
bool ignore_errors)
 
  222     result = FileSystem::findFile(filename, ignore_errors);
 
  224     result = FileSystem::findFile(filename, type, ignore_errors);
 
  226   if (!ignore_errors and result.empty()) {
 
  231     PyErr_SetFromErrnoWithFilename(PyExc_FileNotFoundError, filename.c_str());
 
  232     boost::python::throw_error_already_set();
 
  241 boost::python::list Framework::getModuleSearchPathsPython()
 
  243   boost::python::list returnList;
 
  245   for (
const std::string& path : ModuleManager::Instance().getModuleSearchPaths())
 
  246     returnList.append(boost::python::object(path));
 
  251 boost::python::dict Framework::getAvailableModulesPython()
 
  253   boost::python::dict returnDict;
 
  254   for (
const auto& modulePair : ModuleManager::Instance().getAvailableModules())
 
  255     returnDict[boost::python::object(modulePair.first)] = boost::python::object(modulePair.second);
 
  260 boost::python::list Framework::getRegisteredModulesPython()
 
  262   boost::python::list returnList;
 
  264   for (
const ModulePtr& mod : ModuleManager::Instance().getCreatedModules())
 
  265     returnList.append(boost::python::object(mod));
 
  270 #if !defined(__GNUG__) || defined(__ICC) 
  272 #pragma GCC diagnostic push 
  273 #pragma GCC diagnostic ignored "-Wunused-local-typedefs" 
  275 BOOST_PYTHON_FUNCTION_OVERLOADS(process_overloads, Framework::process, 1, 2)
 
  276 #if !defined(__GNUG__) || defined(__ICC) 
  278 #pragma GCC diagnostic pop 
  282   PyObject* PyExc_ModuleNotCreatedError{
nullptr};
 
  285   void moduleNotCreatedTranslator(
const ModuleManager::ModuleNotCreatedError& e)
 
  287     PyErr_SetString(PyExc_ModuleNotCreatedError, e.what());
 
  291 void Framework::exposePythonAPI()
 
  293   PyExc_ModuleNotCreatedError = PyErr_NewExceptionWithDoc(
"basf2.ModuleNotCreatedError",
 
  294                                                           "This exception is raised when a basf2 module could not be created for any reason",
 
  295                                                           PyExc_RuntimeError, 
nullptr);
 
  296   scope().attr(
"ModuleNotCreatedError") = handle<>(borrowed(PyExc_ModuleNotCreatedError));
 
  297   register_exception_translator<ModuleManager::ModuleNotCreatedError>(moduleNotCreatedTranslator);
 
  299   ModulePtr(*registerModule1)(
const std::string&) = &Framework::registerModule;
 
  300   ModulePtr(*registerModule2)(
const std::string&, 
const std::string&) = &Framework::registerModule;
 
  303   docstring_options options(
true, 
true, 
false);
 
  306   class_<Framework, std::shared_ptr<Framework>, boost::noncopyable>(
"Framework", 
"Initialize and Cleanup functions", no_init);
 
  307   std::shared_ptr<Framework> initguard{
new Framework()};
 
  308   scope().attr(
"__framework") = initguard;
 
  310   def(
"add_module_search_path", &Framework::addModuleSearchPath, R
"DOCSTRING( 
  311 Add a directory in which to search for compiled basf2 C++ `Modules <Module>`. 
  313 This directory needs to contain the shared libraries containing the compiled 
  314 modules as well as companion files ending in ``.b2modmap`` which contain a list 
  315 of the module names contained in each library. 
  318   The newly added path will not override existing modules 
  321   path (str): directory containing the modules. 
  322 )DOCSTRING", args("path"));
 
  323   def(
"set_externals_path", &Framework::setExternalsPath, R
"DOCSTRING( 
  324 Set the path to the externals to be used. 
  327   This will not change the library and executable paths but will just change 
  328   the directory where to look for certain data files like the Evtgen particle 
  329   definition file. Don't use this unless you really know what you are doing. 
  332   path (str): new top level directory for the externals 
  333 )DOCSTRING", args("path"));
 
  334   def(
"list_module_search_paths", &Framework::getModuleSearchPathsPython, R
"DOCSTRING( 
  335 Return a python list containing all the directories included in the module 
  339   `add_module_search_path` 
  341   def("list_available_modules", &Framework::getAvailableModulesPython, R
"DOCSTRING( 
  342 Return a dictionary containing the names of all known modules 
  343 as keys and the name of the shared library containing these modules as values. 
  345   def("list_registered_modules", &Framework::getRegisteredModulesPython, R
"DOCSTRING( 
  346 Return a list with pointers to all previously created module instances by calling `register_module()` 
  348   def("get_pickle_path", &Framework::getPicklePath, R
"DOCSTRING( 
  349 Return the filename where the pickled path is or should be stored 
  351   def("set_pickle_path", &Framework::setPicklePath, R
"DOCSTRING( 
  352 Set the filename where the pickled path should be stored or retrieved from 
  353 )DOCSTRING", args("path"));
 
  354   def(
"set_nprocesses", &Framework::setNumberProcesses, R
"DOCSTRING( 
  355 Sets number of worker processes for parallel processing. 
  357 Can be overridden using the ``-p`` argument to basf2. 
  360   Setting this to 1 will have one parallel worker job which is almost always 
  361   slower than just running without parallel processing but is still provided to 
  362   allow debugging of parallel execution. 
  365   nproc (int): number of worker processes. 0 to disable parallel processing. 
  367   def("get_nprocesses", &Framework::getNumberProcesses, R
"DOCSTRING( 
  368 Gets number of worker processes for parallel processing. 0 disables parallel processing 
  370   def("set_streamobjs", &Framework::setStreamingObjects, R
"DOCSTRING( 
  371 Set the names of all DataStore objects which should be sent between the 
  372 parallel processes. This can be used to improve parallel processing performance 
  373 by removing objects not required. 
  378     docstring_options param_options(
true, 
false, 
false);
 
  379     def(
"_register_module", registerModule1);
 
  380     def(
"_register_module", registerModule2, R
"DOCSTRING(register_module(name, library=None) 
  381 Register a new Module. 
  383 This function will try to create a new instance of a module with the given name. If no library is given it will try to find the module by itself from the module search path. Optionally one can specify the name of a shared library containing the module code then this library will be loaded 
  386   `list_module_search_paths()`, `add_module_search_path()` 
  389   name (str): Type of the module to create 
  390   library (str): Optional, name of a shared library containing the module 
  393   An instance of the module if successful. 
  396   will raise a `ModuleNotCreatedError` if there is any problem creating the module. 
  398   def("set_realm", &Framework::setRealm, R
"DOCSTRING( 
  399 Set the basf2 execution realm. 
  401 The severity of log messages sometimes depends on where basf2 runs. This is controlled by the execution realm. 
  403 Usually the realm does not have to be set explicitly. On the HLT or express reco it should be set to 'online' and for official productions to 'production'. 
  404 )DOCSTRING", args("realm"));
 
  405   def(
"_process", &Framework::process, process_overloads(R
"DOCSTRING(process(path, num_events=0) 
  406 Processes up to max_events events by starting with the first module in the specified path. 
  408  This method starts processing events only if there is a module in the path 
  409  which is capable of specifying the end of the data flow. 
  412    path (Path): The processing starts with the first module of this path. 
  413    max_events (int): The maximum number of events that will be processed. 
  414        If the number is smaller than 1, all events will be processed (default). 
  419   def("find_file", &Framework::findFile, (arg(
"filename"), arg(
"data_type") = 
"", arg(
"silent") = 
false), R
"DOC( 
  420   Try to find a file and return its full path 
  422   If ``data_type`` is empty this function will try to find the file 
  424   1. in ``$BELLE2_LOCAL_DIR``, 
  425   2. in ``$BELLE2_RELEASE_DIR`` 
  426   3. relative to the current working directory. 
  428   Other known ``data_type`` values are 
  431       Example data for examples and tutorials. Will try to find the file 
  433       1. in ``$BELLE2_EXAMPLES_DATA_DIR`` 
  434       2. relative to the current working directory 
  437       Data for Validation purposes. Will try to find the file in 
  439       1. in ``$BELLE2_VALIDATION_DATA_DIR`` 
  440       2. relative to the current working directory 
  442   .. versionadded:: release-03-00-00 
  445     filename (str): relative filename to look for, either in a central place or 
  446         in the current working directory 
  447     data_type (str): case insensitive data type to find. Either empty string or 
  448         one of ``"examples"`` or ``"validation"`` 
  449     silent (bool): If True don't print any errors and just return an empty 
  450         string if the file cannot be found 
provides the core event processing loop.
void setProfileModuleName(const std::string &name)
Set the name of the module we want to profile.
void process(const PathPtr &startPath, long maxEvent=0)
Processes the full module chain, starting with the first module in the given path.
This class combines all subsystems of the framework, and exports the main interface to Python.
ELogRealm
Definition of the supported execution realms.
This class provides the core event processing loop for parallel processing with ZMQ.
void process(const PathPtr &spath, long maxEvent)
Processes the full module chain using parallel processing, starting with the first module in the give...
This class provides the core event processing loop for parallel processing.
void process(const PathPtr &spath, long maxEvent)
Processes the full module chain, starting with the first module in the given 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.
Abstract base class for different kinds of events.