Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-05-12 09:14:01

0001 // $Id$
0002 //
0003 //    File: JEventProcessor_janaroot.cc
0004 // Created: Fri Jul 11 03:39:49 EDT 2008
0005 // Creator: davidl (on Darwin Amelia.local 8.11.1 i386)
0006 //
0007 
0008 #include <iostream>
0009 #include <fstream>
0010 using namespace std;
0011 
0012 #include "JEventProcessor_janaroot.h"
0013 
0014 typedef JEventProcessor_janaroot::TreeInfo TreeInfo;
0015 
0016 // Routine used to allow us to register our JEventSourceGenerator
0017 extern "C"{
0018 void InitPlugin(JApplication *app){
0019     InitJANAPlugin(app);
0020     app->ProvideService(std::make_shared<JLockService>());
0021     app->Add(new JEventProcessor_janaroot());
0022 }
0023 } // "C"
0024 
0025 // Tokenize a string
0026 static inline void Tokenize(string str, vector<string> &tokens, const char delim=' ')
0027 {
0028     tokens.clear();
0029     unsigned int cutAt;
0030     while( (cutAt = str.find(delim)) != (unsigned int)str.npos ){
0031         if(cutAt > 0)tokens.push_back(str.substr(0,cutAt));
0032         str = str.substr(cutAt+1);
0033     }
0034     if(str.length() > 0)tokens.push_back(str);
0035 }
0036 
0037 //-----------------------------------------
0038 // JEventProcessor_janaroot (constructor)
0039 //-----------------------------------------
0040 JEventProcessor_janaroot::JEventProcessor_janaroot()
0041 {
0042     SetTypeName("JEventProcessor_janaroot");
0043     // Set maximum number of objects a factory can store in an event.
0044     // Note that this determines the size of the block in memory needed
0045     // for the the event so be conservative! (This may be overwritten
0046     // in init below via config. parameter.
0047     Nmax = 200;
0048 
0049     // Initialize event counter
0050     Nevents = 0;
0051     
0052     // Initialize warnings counter (used in FillTree)
0053     Nwarnings = 0;
0054     MaxWarnings=50;
0055     
0056     // Set TFile pointert to NULL. It will be created in evnt
0057     file = NULL;
0058     
0059 }
0060 
0061 //------------------
0062 // Init
0063 //------------------
0064 void JEventProcessor_janaroot::Init(void)
0065 {
0066     JANAROOT_VERBOSE=0;
0067     auto app = GetApplication();
0068     lock_svc = app->GetService<JLockService>();
0069     app->SetDefaultParameter("JANAROOT_VERBOSE", JANAROOT_VERBOSE);
0070 
0071     app->SetDefaultParameter("JANAROOT_MAX_OBJECTS", Nmax);
0072 }
0073 
0074 //------------------
0075 // BeginRun
0076 //------------------
0077 void JEventProcessor_janaroot::BeginRun(const std::shared_ptr<const JEvent>& event)
0078 {
0079     auto app = GetApplication();
0080     // Use the ROOT mutex to guarantee that other JEventLoops don't start
0081     // processing event before we have filled in the nametags_to_write_out member
0082     lock_svc->RootWriteLock();
0083 
0084     // Allow user to specify factories to write out via configuration parameter
0085     string factories_to_write_out="";
0086     app->SetDefaultParameter("WRITEOUT", factories_to_write_out);
0087 
0088     if(factories_to_write_out!=""){
0089         // Split list at commas
0090         size_t pos=0;
0091         string &str = factories_to_write_out;
0092         while( (pos = str.find(",")) != string::npos ){
0093             if(pos > 0){
0094                 nametags_to_write_out.push_back(str.substr(0,pos));
0095             }
0096             str = str.substr(pos+1);
0097         }
0098         if(str.length() > 0){
0099             nametags_to_write_out.push_back(str);
0100         }
0101         
0102         // Clean up nametags a bit in order to be moe forgiving of exact
0103         // format user gives us.
0104         for(unsigned int j=0; j<nametags_to_write_out.size(); j++){
0105         
0106             // Strip white space from front and back of nametag
0107             stringstream ss;
0108             ss<<nametags_to_write_out[j];
0109             ss>>nametags_to_write_out[j];
0110         
0111             // If the user decides to append a colon ":" to the object name,
0112             // but with no tag, then we should remove it here so the string
0113             // is matched properly in evnt().
0114             if(nametags_to_write_out[j].size()<1)continue;
0115             size_t pos_last = nametags_to_write_out[j].size()-1;
0116             if(nametags_to_write_out[j][pos_last] == ':'){
0117                 nametags_to_write_out[j].erase(pos_last);
0118             }
0119         }
0120         
0121         // At this point we have a list of nametags for factories whose
0122         // objects we wish to write to the ROOT file. However, this method
0123         // is only called for one JEventLoop and we can't rely on all others
0124         // to be up and running yet. So, we have to defer setting the WRITE_TO_OUTPUT
0125         // flag until evnt time. What we can do here is look to see which
0126         // factories both exist in the one JEventLoop that is up an running
0127         // AND were listed in the config parameter.
0128         
0129         jout<<"Factories whose objects will be written to ROOT file:"<<endl;
0130         
0131         // Loop over all factories
0132         for (auto factory : event->GetFactorySet()->GetAllFactories()) {
0133             auto nametag = factory->GetObjectName();
0134             auto tag = factory->GetTag();
0135 
0136             if (!tag.empty()) nametag += ":" + tag;
0137 
0138             // Look to see if this was one set to write out
0139             for(unsigned int j=0; j<nametags_to_write_out.size(); j++){
0140                 if(nametags_to_write_out[j] == nametag){
0141                     jout<<"  "<<nametag<<endl;
0142                 }
0143             }
0144         }
0145     }
0146     
0147     lock_svc->RootUnLock();
0148 }
0149 
0150 //------------------
0151 // Process
0152 //------------------
0153 void JEventProcessor_janaroot::Process(const std::shared_ptr<const JEvent>& event)
0154 {
0155     // We assume that all factories we want to record have already been
0156     // activated and so contain the objects (note that the toStrings()
0157     // method won't create them if they don't exist). Thus, we lock
0158     // the rootmutex to prevent other threads from accessing the TreeInfo
0159     // buffers and writing to the ROOT file while we do. Note that
0160     // this does not prevent other threads from accessing the ROOT
0161     // globals and mucking things up for us there.
0162     lock_svc->RootWriteLock();
0163 
0164     // Create ROOT file if not already done
0165     if( !file ){
0166         // Remember current working directory. We do this so we can restore it
0167         // and keep ROOT objects from other parts of the program from
0168         // showing up in out file.
0169         TDirectory *cwd = gDirectory;
0170     
0171         // Create ROOT file
0172         file = new TFile("janaroot.root","RECREATE");
0173     
0174         // Restore original ROOT directory
0175         cwd->cd();
0176     }
0177 
0178     // Get list of all foctories for this JEventLoop to be written out
0179     vector<JFactory*> allfactories = event->GetFactorySet()->GetAllFactories();
0180     vector<JFactory*> facs;
0181     for(unsigned int i=0; i<allfactories.size(); i++){
0182         // If nametags_to_write_out is empty, we assume the current state
0183         // of WRITE_TO_OUTPUT flags is valid. Otherwise, we set the flags
0184         // according to nametags_to_write_out. We do this here rather than
0185         // in brun since brun is called only once and if more than one thread
0186         // exists, the other threads will not have their WRITE_TO_OUTPUT
0187         // flags set properly.
0188         if(nametags_to_write_out.size()>0){
0189             allfactories[i]->ClearFactoryFlag(JFactory::WRITE_TO_OUTPUT);
0190             // Form nametag for factory to compare to ones listed in config. param.
0191             string nametag = allfactories[i]->GetObjectName();
0192             string tag = allfactories[i]->GetTag();
0193             if(!tag.empty()) nametag += ":" + tag;
0194             for(unsigned int j=0; j<nametags_to_write_out.size(); j++){
0195                 if(nametags_to_write_out[j] == nametag){
0196                     allfactories[i]->SetFactoryFlag(JFactory::WRITE_TO_OUTPUT);
0197                 }
0198             }
0199         }
0200 
0201         if(allfactories[i]->TestFactoryFlag(JFactory::WRITE_TO_OUTPUT)) facs.push_back(allfactories[i]);
0202     }
0203     
0204     // Clear all trees' "N" values for this event
0205     map<std::string, TreeInfo*>::iterator iter=trees.begin();
0206     for(; iter!=trees.end(); iter++)*(iter->second->Nptr) = 0;
0207     
0208     // Find ( or create) the tree and copy the objects into its buffers
0209     for(unsigned int i=0; i<facs.size(); i++){
0210 
0211         //=== TEMPORARY====
0212         //facs[i]->GetNrows();
0213         //=== TEMPORARY====
0214         TreeInfo *tinfo  = GetTreeInfo(facs[i]);
0215         if(!tinfo)continue;     
0216         
0217         FillTree(facs[i], tinfo);
0218     }
0219     
0220     // Fill all trees
0221     for(iter=trees.begin(); iter!=trees.end(); iter++)iter->second->tree->Fill();
0222     
0223     Nevents++;
0224     
0225     // Release the ROOT mutex lock
0226     lock_svc->RootUnLock(); 
0227 }
0228 
0229 //------------------
0230 // EndRun
0231 //------------------
0232 void JEventProcessor_janaroot::EndRun(void)
0233 {
0234 
0235 }
0236 
0237 //------------------
0238 // Finish
0239 //------------------
0240 void JEventProcessor_janaroot::Finish(void)
0241 {
0242     lock_svc->RootWriteLock();
0243     if(!file){
0244         lock_svc->RootUnLock();
0245     }
0246 
0247     // Remember the current ROOT directory and switch the file
0248     TDirectory *cwd = gDirectory;
0249     file->cd();
0250 
0251     // Create a "friend" tree that has no branches of its own, but contains
0252     // all other trees as friends. This will allow one to plot fields of objects
0253     // of different types against each other.
0254     TTree *event = new TTree("event","All objects");
0255     map<std::string, TreeInfo*>::iterator iter;
0256     for(iter=trees.begin(); iter!=trees.end(); iter++){
0257         event->AddFriend(iter->second->tree->GetName());
0258     }
0259 
0260     // Restore the original ROOT working directory
0261     cwd->cd();
0262 
0263     // Write the contents of the ROOT file to disk and close it.
0264     file->Write();
0265     delete file;
0266     file=NULL;
0267 
0268     lock_svc->RootUnLock();
0269 }
0270 
0271 //------------------
0272 // GetTreeInfo
0273 //------------------
0274 TreeInfo* JEventProcessor_janaroot::GetTreeInfo(JFactory *fac)
0275 {
0276     // n.b. This gets called while inside the ROOT mutex so it is not locked again here
0277 
0278     // Look for entry in our list of existing branches for this one
0279     string key = string(fac->GetObjectName())+":"+fac->GetTag();
0280     map<string, TreeInfo*>::iterator iter = trees.find(key);
0281     if(iter!=trees.end())return iter->second;
0282     
0283     // No branch currently exists. Try creating one.
0284     // Get factory objects summaries
0285     auto objs = fac->GetAs<JObject>();
0286     vector<vector<JObjectMember>> items;
0287     for (auto obj:objs) {
0288         JObjectSummary obj_sum;
0289         obj->Summarize(obj_sum);
0290         std::vector<JObjectMember> obj_fields = obj_sum.get_fields();
0291         items.push_back(obj_fields);
0292     }
0293 
0294     // If no objects currently exists for this factory (either because
0295     // it was activated, but produced zero objects or was never even
0296     // activated) then we have no information by which to create a branch.
0297     // In this case, just return NULL now.
0298     if(items.size()==0)return NULL;
0299     
0300     // Create TreeInfo structure
0301     TreeInfo *tinfo = new TreeInfo;
0302     
0303     // Remember the current ROOT directory and switch to the file
0304     TDirectory *cwd = gDirectory;
0305     file->cd();
0306 
0307     // Create tree to hold the objects from this factory.
0308     string tname = fac->GetObjectName();
0309     if(fac->GetTag().size()>0)tname += string("_") + fac->GetTag();
0310     tinfo->tree = new TTree(tname.c_str(),"Autogenerated from JANA objects");
0311     
0312     // Restore the original ROOT working directory
0313     cwd->cd();
0314     
0315     // Add "N" branch to hold num objects for the event
0316     tinfo->branches.push_back(tinfo->tree->Branch("N" , (void*)NULL, "N/I"));
0317         
0318     // Loop over data members and extract their name and type to form branches
0319     tinfo->obj_size=0;
0320     for(unsigned int i=0; i<items[0].size(); i++){
0321         // If units are appended using a form like "px(cm)", then chop
0322         // off the units part and just use the "px".
0323         auto field_name = items[0][i].name;
0324         unsigned int cutAt = field_name.find('(');
0325         string iname = (cutAt==(unsigned int)field_name.npos) ? field_name:field_name.substr(0,cutAt);
0326         
0327         // Sometimes the name can have special characters (spaces or "."s)
0328         // that aren't good for leaf names in branches
0329         for(size_t k=0; k<iname.size(); k++){
0330             if(iname[k]==' ')iname[k] = '_';
0331             if(iname[k]=='.')iname[k] = '_';
0332         }
0333         
0334         unsigned long item_size=0;
0335         data_type_t type = type_unknown;
0336         auto field_type = items[0][i].type;
0337         string branch_def;
0338         if(field_type=="int"){
0339             branch_def = iname + "[N]/I";
0340             item_size = sizeof(int);
0341             type = type_int;
0342         }else if(field_type=="uint"){
0343             branch_def = iname + "[N]/i";
0344             item_size = sizeof(unsigned int);
0345             type = type_uint;
0346         }else if(field_type=="long"){
0347             branch_def = iname + "[N]/L";
0348             item_size = sizeof(long);
0349             type = type_long;
0350         }else if(field_type=="ulong"){
0351             branch_def = iname + "[N]/l";
0352             item_size = sizeof(unsigned long);
0353             type = type_ulong;
0354         }else if(field_type=="short"){
0355             branch_def = iname + "[N]/S";
0356             item_size = sizeof(short);
0357             type = type_short;
0358         }else if(field_type=="ushort"){
0359             branch_def = iname + "[N]/s";
0360             item_size = sizeof(unsigned short);
0361             type = type_ushort;
0362         }else if(field_type=="float"){
0363             branch_def = iname + "[N]/F";
0364             item_size = sizeof(float);
0365             type = type_float;
0366         }else if(field_type=="double"){
0367             branch_def = iname + "[N]/D";
0368             item_size = sizeof(double);
0369             type = type_double;
0370         }else if(field_type=="string"){
0371             // Strings must be handled differently
0372             tinfo->StringMap[i]; // Create an element in the map with key "i"
0373             item_size = 0;
0374             type = type_string;
0375         }else{
0376             branch_def = iname + "[N]/F";
0377             item_size = sizeof(float);
0378             type = type_unknown;
0379         }
0380         
0381         // Record the address offest and increase object size
0382         tinfo->types.push_back(type);
0383         tinfo->item_sizes.push_back(item_size);
0384         tinfo->obj_size += item_size;
0385         
0386         // Create new branch
0387         TBranch *branch = NULL;
0388         if(type == type_string){
0389             branch = tinfo->tree->Branch(iname.c_str(), &tinfo->StringMap[i]);
0390         }else{
0391             branch = tinfo->tree->Branch(iname.c_str(), (void*)NULL, branch_def.c_str());
0392         }
0393         tinfo->branches.push_back(branch);
0394     }
0395     
0396     // Inform user if nothing useful in the object is found
0397     if(tinfo->item_sizes.size()<1){
0398         _DBG_<<"No usable data members in \""<<tname<<"\"!"<<endl;
0399     }
0400     
0401     // Fill in TreeInfo object
0402     tinfo->Nmax = Nmax;
0403     tinfo->buff_size = sizeof(int) + tinfo->Nmax*tinfo->obj_size;
0404     tinfo->buff = new char[tinfo->buff_size];
0405     tinfo->Nptr = (int*)tinfo->buff;// "N" is first element in buffer
0406     tinfo->Bptr = (unsigned long)&tinfo->Nptr[1]; // pointer to buffer starting AFTER "N"
0407     
0408     // Add to list
0409     trees[key] = tinfo;
0410     
0411     // At this point we may have already seen any number of events and other classes
0412     // may have already been added. We want to add Nevents of "NULL" events to the
0413     // current tree so they will be aligned and we can make them "friends".
0414     *tinfo->Nptr = 0;
0415     for(unsigned long i=0; i<Nevents; i++)tinfo->tree->Fill();
0416     
0417     if(JANAROOT_VERBOSE>0)tinfo->Print();
0418     
0419     return tinfo;
0420 }
0421 
0422 //------------------
0423 // FillTree
0424 //------------------
0425 void JEventProcessor_janaroot::FillTree(JFactory *fac, TreeInfo *tinfo)
0426 {
0427     // n.b. This gets called while inside the ROOT mutex so it is not locked again here
0428     
0429     // Get factory objects summaries
0430     auto objs = fac->GetAs<JObject>();
0431     vector<vector<JObjectMember>> items;
0432     for (auto obj:objs) {
0433         JObjectSummary obj_sum;
0434         obj->Summarize(obj_sum);
0435         std::vector<JObjectMember> obj_fields = obj_sum.get_fields();
0436         items.push_back(obj_fields);
0437     }
0438     
0439     // Verify each object has the right number of elements
0440     unsigned int Nitems = tinfo->types.size(); // Number of items used to define object in tree
0441     for(unsigned int i=0; i<items.size(); i++){
0442         if(items[i].size()!=Nitems){
0443             _DBG_<<"Number of items inconsistent for Tree "<<tinfo->tree->GetName()
0444             <<" Nitems="<<Nitems<<" items["<<i<<"].size()="<<items[i].size()<<endl;
0445             return;
0446         }
0447     }
0448     
0449     // Set number of objects in event
0450     *tinfo->Nptr = (int)items.size()<tinfo->Nmax ? (int)items.size():tinfo->Nmax;
0451 
0452     // Loop over items in class
0453     vector<string> tokens;
0454     unsigned long ptr =  tinfo->Bptr;
0455     for(unsigned int j=0; j<tinfo->types.size(); j++){
0456         
0457         if(tinfo->branches[j+1] == NULL)continue;
0458     
0459         // Set the branch address
0460         if(tinfo->types[j] == type_string){
0461             // String address should already be set. We just need to
0462             // clear the vector so it can be refilled below.
0463             tinfo->StringMap[j].clear();
0464         }else{
0465             tinfo->branches[j+1]->SetAddress((void*)ptr);
0466         }
0467 
0468         // Loop over objects
0469         for(unsigned int i=0; i<(unsigned int)*tinfo->Nptr; i++){
0470 
0471             stringstream ss(items[i][j].value);
0472             string str;
0473 
0474             switch(tinfo->types[j]){
0475                 case type_short:
0476                     ss>>(*(short*)ptr);
0477                     break;
0478                 case type_ushort:
0479                     ss>>(*(unsigned short*)ptr);
0480                     break;
0481                 case type_int:
0482                     ss>>(*(int*)ptr);
0483                     break;
0484                 case type_uint:
0485                     ss>>(*(unsigned int*)ptr);
0486                     break;
0487                 case type_long:
0488                     ss>>(*(long*)ptr);
0489                     break;
0490                 case type_ulong:
0491                     ss>>(*(unsigned long*)ptr);
0492                     break;
0493                 case type_float:
0494                     ss>>(*(float*)ptr);
0495                     break;
0496                 case type_double:
0497                     ss>>(*(double*)ptr);
0498                     break;
0499                 case type_string:
0500                     str = items[i][j].value;
0501                     //ss>>str;
0502                     tinfo->StringMap[j].push_back(str);
0503                     break;
0504                 default:
0505                     if(Nwarnings<MaxWarnings && JANAROOT_VERBOSE>0){
0506                         _DBG_<<"Unknown type: "<<tinfo->types[j];
0507                         Nwarnings++;
0508                         if(Nwarnings==MaxWarnings)cerr<<" --last warning! --";
0509                         cerr<<endl;
0510                     }
0511                     break;
0512             }
0513             ptr += tinfo->item_sizes[j];
0514         }
0515     }
0516 
0517     // Copy in number of objects
0518     tinfo->branches[0]->SetAddress((void*)tinfo->Nptr);
0519 }
0520