Back to home page

EIC code displayed by LXR

 
 

    


Warning, file /jana2/src/plugins/janaroot/JEventProcessor_janaroot.cc was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

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