Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-30 10:30:04

0001 //
0002 // Copyright 2020, Jefferson Science Associates, LLC.
0003 // Subject to the terms in the LICENSE file found in the top-level directory.
0004 
0005 
0006 #include <thread>
0007 #include <cstdio>
0008 #include <chrono>
0009 using namespace std;
0010 
0011 
0012 #include <JANA/JApplication.h>
0013 #include <JANA/CLI/JMain.h>
0014 #include <JANA/Utils/JCpuInfo.h>
0015 #include <JANA/Services/JParameterManager.h>
0016 
0017 #include <pybind11/pybind11.h>
0018 #include <pybind11/embed.h>
0019 namespace py = pybind11;
0020 #include "JEventProcessorPY.h"
0021 
0022 static py::module_ *PY_MODULE = nullptr;       // set at end of JANA_MODULE_DEF
0023 // static py::module_ PY_MODULE_JSON;          // set at end of JANA_MODULE_DEF
0024 bool PY_INITIALIZED = false;
0025 static bool PY_MODULE_INSTANTIATED_JAPPLICATION = false;
0026 static JApplication *pyjapp = nullptr;
0027 
0028 // Trivial wrappers for JApplication (and friends)
0029 // n.b. The default values here will NEVER be used. They must be passed in explicitly to
0030 // pybind11. They are only here for convenience!
0031 inline void     janapy_Start(void) { PY_INITIALIZED = true; }
0032 inline void     janapy_Quit(bool skip_join=false) { pyjapp->Quit(skip_join); }
0033 inline void     janapy_Stop(bool wait_until_idle=false) { pyjapp->Stop(wait_until_idle); }
0034 
0035 inline bool     janapy_IsInitialized(void) { return pyjapp->IsInitialized(); }
0036 inline bool     janapy_IsQuitting(void) { return pyjapp->IsQuitting(); }
0037 inline bool     janapy_IsDrainingQueues(void) { return pyjapp->IsDrainingQueues(); }
0038 
0039 inline void     janapy_AddPlugin(string plugin_name) { pyjapp->AddPlugin(plugin_name); }
0040 inline void     janapy_AddPluginPath(string path) { pyjapp->AddPluginPath(path); }
0041 inline void     janapy_AddEventSource(string source) { pyjapp->Add( source ); }
0042 inline void     janapy_SetTicker(bool ticker_on=true) { pyjapp->SetTicker(ticker_on); }
0043 inline uint64_t janapy_GetNeventsProcessed(void) { return pyjapp->GetNEventsProcessed(); }
0044 inline float    janapy_GetIntegratedRate(void) { return pyjapp->GetIntegratedRate(); }
0045 inline float    janapy_GetInstantaneousRate(void) { return pyjapp->GetInstantaneousRate(); }
0046 inline uint32_t janapy_GetNThreads(void) { return pyjapp->GetNThreads(); }
0047 inline uint32_t janapy_SetNThreads(int Nthreads) { auto prev = pyjapp->GetNThreads(); pyjapp->Scale(Nthreads); return prev; }
0048 inline size_t   janapy_GetNcores(void) { return JCpuInfo::GetNumCpus(); }
0049 inline void     janapy_PrintStatus(void) { pyjapp->PrintStatus(); }
0050 inline void     janapy_PrintParameters(bool all=false) { pyjapp->GetJParameterManager()->PrintParameters((all ? 3 : 1), 0); }
0051 inline string   janapy_GetParameterValue(string key) { return pyjapp->GetJParameterManager()->Exists(key) ? pyjapp->GetParameterValue<string>(key):"Not Defined"; }
0052 
0053 inline void     janapy_Run(void)
0054 {
0055     if(PY_MODULE_INSTANTIATED_JAPPLICATION) {
0056         // Being run as python module
0057         auto options = jana::ParseCommandLineOptions(0, nullptr, false);
0058         auto exit_code = jana::Execute(pyjapp, options);
0059         LOG << "JANA processing complete. Exit code: " << exit_code << LOG_END;
0060     }else{
0061         // Being run from C++ executable with janapy plugin
0062         janapy_Start();
0063     }
0064 }
0065 
0066 // Not sure of the clean way to have python cast val object to string before passing to us ...
0067 inline void     janapy_SetParameterValue(string key, py::object valobj)
0068 {
0069 //    const char* val = PyUnicode_AsUTF8( PyObject_Str(valobj) );
0070     stringstream ss;
0071     try {
0072         auto val = valobj.cast<string>();
0073         ss << val;
0074     }catch(...){
0075         try {
0076             auto val = valobj.cast<double>();
0077             ss << val;
0078         }catch(...) {
0079             try {
0080                 auto val = valobj.cast<long>();
0081                 ss << val;
0082             }catch(...){}
0083         }
0084     }
0085     pyjapp->SetParameterValue<string>( key, ss.str() );
0086 }
0087 
0088 //-----------------------------------------
0089 // janapy_AddProcessor
0090 //-----------------------------------------
0091 inline void janapy_AddProcessor(py::object &pyproc ) {
0092 
0093     // The JEventProcessorPY is instantiated from python by virtue of
0094     // it being a base class for whatever jana.JEventProcessor class
0095     // the python script defines. Here though we set some data members
0096     // only accessible via C++.
0097     JEventProcessorPY *proc = pyproc.cast<JEventProcessorPY *>();
0098     proc->pymodule = PY_MODULE;
0099     // proc->pymodule_json = &PY_MODULE_JSON;  // (see comment at bottom of file)
0100 
0101     if (pyjapp != nullptr) {
0102         cout << "[INFO] Adding JEventProcessorPY" << endl;
0103         pyjapp->Add( new JEventProcessorPYTrampoline(pyjapp, proc) );
0104     }else {
0105         cerr << "[ERROR] pyjapp not set before call to janapy_AddProcessor() !!" << endl;
0106     }
0107 }
0108 
0109 //================================================================================
0110 // Module definition
0111 //
0112 // The following macro is used to define the jana module in both the plugin
0113 // (embedded interpreter) and python module forms. These are built using
0114 // pybind11 macros PYBIND11_EMBEDDED_MODULE and PYBIND11_MODULE respectively.
0115 // Ideally, we could combine the JANA plugin and python module into a single
0116 // binary and wouldn't need to bother with the ugliness of using a macro like
0117 // this. Alas, that does not seem to be (easily) possible. Thus the macro is
0118 // defined here and used in both modules/jana/jana_module.cc and
0119 // plugins/janapy/janapy_plugin.cc
0120 
0121 #define JANA_MODULE_DEF \
0122 \
0123 /* JEventProcessor */ \
0124 py::class_<JEventProcessorPY>(m, "JEventProcessor")\
0125 .def(py::init<py::object&>())\
0126 .def("Init",       &JEventProcessorPY::Init)\
0127 .def("Process",    &JEventProcessorPY::Process)\
0128 .def("Finish",     &JEventProcessorPY::Finish)\
0129 .def("Prefetch",   &JEventProcessorPY::Prefetch, py::arg("fac_name"), py::arg("tag")="")\
0130 .def("Get",        &JEventProcessorPY::Get, py::arg("fac_name"), py::arg("tag")="");\
0131 \
0132 /* C-wrapper routines */ \
0133 m.def("Start",                       &janapy_Start,                       "Allow JANA system to start processing data. (Not needed for short scripts.)"); \
0134 m.def("Run",                         &janapy_Run,                         "Begin processing events (use when running python as an extension)"); \
0135 m.def("Quit",                        &janapy_Quit,                        "Tell JANA to quit gracefully", py::arg("skip_join")=false); \
0136 m.def("Stop",                        &janapy_Stop,                        "Tell JANA to (temporarily) stop event processing. If optional agrument is True then block until all threads are stopped."); \
0137 \
0138 m.def("IsInitialized",               &janapy_IsInitialized,               "Check if JApplication has already been initialized."); \
0139 m.def("IsQuitting",                  &janapy_IsQuitting,                  "Check if JApplication is in the process of quitting."); \
0140 m.def("IsDrainingQueues",            &janapy_IsDrainingQueues,            "Check if JApplication is in the process of draining the queues."); \
0141 \
0142 m.def("AddPlugin",                   &janapy_AddPlugin,                   "Add a plugin to the list of plugins to be attached (call before calling Run)"); \
0143 m.def("AddPluginPath",               &janapy_AddPluginPath,               "Add directory to plugin search path"); \
0144 m.def("AddEventSource",              &janapy_AddEventSource,              "Add an event source (e.g. filename). Can be given multiple arguments and/or called multiple times."); \
0145 m.def("SetTicker",                   &janapy_SetTicker,                   "Turn off/on the standard screen ticker", py::arg("ticker_on")=true); \
0146 m.def("GetNeventsProcessed",         &janapy_GetNeventsProcessed,         "Return the number of events processed so far."); \
0147 m.def("GetIntegratedRate",           &janapy_GetIntegratedRate,           "Return integrated rate."); \
0148 m.def("GetInstantaneousRate",        &janapy_GetInstantaneousRate,        "Return instantaneous rate."); \
0149 m.def("GetNThreads",                 &janapy_GetNThreads,                 "Return current number of JThread objects."); \
0150 m.def("SetNThreads",                 &janapy_SetNThreads,                 "Set number of JThread objects. (returns previous number)"); \
0151 m.def("GetNcores",                   &janapy_GetNcores,                   "Return number of cores reported by system (full + logical)."); \
0152 m.def("PrintStatus",                 &janapy_PrintStatus,                 "Print the status of the current job to the screen"); \
0153 m.def("PrintParameters",             &janapy_PrintParameters,             "Print config. parameters (give argument True to print all parameters)"); \
0154 m.def("GetParameterValue",           &janapy_GetParameterValue,           "Return value of given configuration parameter."); \
0155 m.def("SetParameterValue",           &janapy_SetParameterValue,           "Set configuration parameter."); \
0156 m.def("AddProcessor",                &janapy_AddProcessor,                "Add an event processor"); \
0157 \
0158 PY_MODULE = &m;\
0159 //================================================================================
0160 
0161 
0162 // The following is left over from an earlier effort to automatically make
0163 // the python json module available without having to import it. The exact
0164 // motivation for this has been lost. It has been disabled since the
0165 // PY_MODULE_JSON global was causing seg. faults at program exit.
0166 #if 0
0167 try{\
0168     PY_MODULE_JSON = py::module_::import("json");\
0169 }catch(pybind11::type_error &e){\
0170     _DBG_<<" Error importing python json module!"<<std::endl;\
0171 }catch(...){\
0172     _DBG_<<" Error importing python json module!"<<std::endl;\
0173 }\
0174 \
0175 
0176 #endif