Declaring static TTree in base class

Dear Rooters,

I am trying to fill branches from a D3PD. To do this, I am using the extractor class, for which I have two derived classes (one for filling track variables and another for filling global variables). To correctly fill the branches for each derived class type, I must declare the TTree member of the parent class static.

However, doing this causes my parent class to crash during compilation. It compiles fine when I take out “static”, but this will result in the branches of my derived classes being incorrectly filled. The output is shown below

root [0] gROOT->ProcessLine(".L BranchBase.C+g")
Info in <TUnixSystem::ACLiC>: creating shared library /afs/cern.ch/user/t/tbalestr/public/17.2.2.2/HIDP3DAnalysis2011/MuonDPDSkimming/./BranchBase_C.so
In file included from /afs/cern.ch/user/t/tbalestr/public/17.2.2.2/HIDP3DAnalysis2011/MuonDPDSkimming/./BranchBase.C:3,
                 from /afs/cern.ch/user/t/tbalestr/public/17.2.2.2/HIDP3DAnalysis2011/MuonDPDSkimming/BranchBase_C_ACLiC_dict.h:34,
                 from /afs/cern.ch/user/t/tbalestr/public/17.2.2.2/HIDP3DAnalysis2011/MuonDPDSkimming/BranchBase_C_ACLiC_dict.cxx:17:
/afs/cern.ch/user/t/tbalestr/public/17.2.2.2/HIDP3DAnalysis2011/MuonDPDSkimming/./BranchBase.h:5349: warning: unused parameter 'tree'
/afs/cern.ch/user/t/tbalestr/public/17.2.2.2/HIDP3DAnalysis2011/MuonDPDSkimming/./BranchBase.h:5350: warning: unused parameter 'tree'
In file included from /afs/cern.ch/user/t/tbalestr/public/17.2.2.2/HIDP3DAnalysis2011/MuonDPDSkimming/BranchBase_C_ACLiC_dict.h:34,
                 from /afs/cern.ch/user/t/tbalestr/public/17.2.2.2/HIDP3DAnalysis2011/MuonDPDSkimming/BranchBase_C_ACLiC_dict.cxx:17:
/afs/cern.ch/user/t/tbalestr/public/17.2.2.2/HIDP3DAnalysis2011/MuonDPDSkimming/./BranchBase.C:203: warning: unused parameter 'entry'
dlopen error: /afs/cern.ch/user/t/tbalestr/public/17.2.2.2/HIDP3DAnalysis2011/MuonDPDSkimming/./BranchBase_C.so: undefined symbol: _ZN10BranchBase6fChainE
Load Error: Failed to load Dynamic link library /afs/cern.ch/user/t/tbalestr/public/17.2.2.2/HIDP3DAnalysis2011/MuonDPDSkimming/./BranchBase_C.so
In file included from /afs/cern.ch/user/t/tbalestr/public/17.2.2.2/HIDP3DAnalysis2011/MuonDPDSkimming/./BranchBase.C:3,
                 from /afs/cern.ch/user/t/tbalestr/public/17.2.2.2/HIDP3DAnalysis2011/MuonDPDSkimming/BranchBase_C_ACLiC_dict.h:34,
                 from /afs/cern.ch/user/t/tbalestr/public/17.2.2.2/HIDP3DAnalysis2011/MuonDPDSkimming/BranchBase_C_ACLiC_dict.cxx:17:
/afs/cern.ch/user/t/tbalestr/public/17.2.2.2/HIDP3DAnalysis2011/MuonDPDSkimming/./BranchBase.h:5349: warning: unused parameter 'tree'
/afs/cern.ch/user/t/tbalestr/public/17.2.2.2/HIDP3DAnalysis2011/MuonDPDSkimming/./BranchBase.h:5350: warning: unused parameter 'tree'
In file included from /afs/cern.ch/user/t/tbalestr/public/17.2.2.2/HIDP3DAnalysis2011/MuonDPDSkimming/BranchBase_C_ACLiC_dict.h:34,
                 from /afs/cern.ch/user/t/tbalestr/public/17.2.2.2/HIDP3DAnalysis2011/MuonDPDSkimming/BranchBase_C_ACLiC_dict.cxx:17:
/afs/cern.ch/user/t/tbalestr/public/17.2.2.2/HIDP3DAnalysis2011/MuonDPDSkimming/./BranchBase.C:203: warning: unused parameter 'entry'
/usr/lib/../lib/crt1.o: In function `_start':
(.text+0x18): undefined reference to `main'
/afs/cern.ch/user/t/tbalestr/public/17.2.2.2/HIDP3DAnalysis2011/MuonDPDSkimming/BranchBase_C_ACLiC_dict.o: In function `BranchBase::Show(long long)':
BranchBase_C_ACLiC_dict.cxx:(.text+0xa891): undefined reference to `BranchBase::fChain'
BranchBase_C_ACLiC_dict.cxx:(.text+0xa89d): undefined reference to `BranchBase::fChain'
BranchBase_C_ACLiC_dict.cxx:(.text+0xa8ae): undefined reference to `BranchBase::fChain'
/afs/cern.ch/user/t/tbalestr/public/17.2.2.2/HIDP3DAnalysis2011/MuonDPDSkimming/BranchBase_C_ACLiC_dict.o: In function `BranchBase::GetEntry(long long)':
BranchBase_C_ACLiC_dict.cxx:(.text+0xa911): undefined reference to `BranchBase::fChain'
BranchBase_C_ACLiC_dict.cxx:(.text+0xa926): undefined reference to `BranchBase::fChain'
/afs/cern.ch/user/t/tbalestr/public/17.2.2.2/HIDP3DAnalysis2011/MuonDPDSkimming/BranchBase_C_ACLiC_dict.o:BranchBase_C_ACLiC_dict.cxx:(.text+0xa937): more undefined references to `BranchBase::fChain' follow
collect2: ld returned 1 exit status
(Long_t)0

Hi,

You must have forgotten to declare the storage for the static data member. I.e. in the source code add:TTree *BranchBase::fChain = 0;

Cheers,
Philippe.

PS. However using a static for the purpose you describe is most likely the wrong solution, there is in most cases no reason to share the TTree pointer between the writer and the reader.

Hi,

Thanks for the help. It compiles now. But as for your warning, my main function looks something like

int main() {

        //get the run list ,set branch addresses and
        //intialize branches
        TString inputfiles="input.txt";
        BranchBase *t = new BranchBase(inputfiles);

        //get the tree holding the DPD variables
        TTree* itsTree = t->fChain;

        //output file and tree
        TFile *outfile   = new TFile("skimmed.root","recreate");
        TTree *MyTree    = new TTree("data","data");

        //Set the muon branches to be stored
        //in the output tree
        MuonBranch *mu = new MuonBranch;
        mu->Set_Muon_Branches(MyTree);

        //Set the global/trigger branches to be stored
        //in the output tree
        TrigGlobalBranch* glob = new TrigGlobalBranch;
        glob->Set_Trig_and_Global_Branches(MyTree);

        //set branch status and make sure
        //entries!=0
        int result = t->TurnOnBranches();

        if (result!=0) {

                std::cout << "Exiting program. " << std::endl;
                system("rm skimmed.root");
                exit(0);
        }

        int nentries = itsTree->GetEntries();
        if (nentries==0) {

                std::cout << "Zero entries in itsTree. Exiting program. " << std::endl;
                exit(0);
        }
        for (Long64_t jentry=0; jentry<nentries;jentry++){

                Long64_t ientry = itsTree->LoadTree(jentry);
                if (ientry < 0) break;

                itsTree->GetEntry(jentry); //  nbytes += nb;

                if(jentry%1000==0) printf("running event %5dk\n",(int) jentry/1000);

                bool event = t->EventCuts();
                if(!event) continue;

                glob->Fill_Trig_and_Global_Branches();
                std::cout << "After global fill" <<std::endl;
                mu->Fill_Muon_Branches();
                //Fill_FCal_Branches           ();
                //Fill_Track_Branches          (); 

                MyTree->Fill();

        } //event loop

        outfile->cd();
        MyTree->Write();
        outfile -> Close();

        delete mu;
        delete glob;
        delete t;
        return 0;

}                            

In the event loop I make a call to a MuonBranch and TrigGlobalBranch method, which assigns to their respective members values stored in the D3PD tree. This is why I thought I need a static TTree to store the D3PD variables, so that each member of MuonBranch and TrigGlobalBranch would be assigned correctly.

[quote]to store the D3PD variables, so that each member of MuonBranch and TrigGlobalBranch would be assigned correctly.[/quote]What does this code look like?

Philippe.

The function mu->Set_Muon_Branches(MyTree); looks like

//----------------------------------------------------------------------

void MuonBranch::Set_Muon_Branches( TTree *myTree)
{

 //const int index = TMath::Binomial(mu_muid_n,2);
 myTree->Branch("mu_muid_n",            &Mymu_muid_n,   "mu_muid_n/I");
 myTree->Branch("muid_npairs",          &muid_npairs,   "muid_npairs/I");
 myTree->Branch("isGoodMuon",           &isGoodMuon,    "isGoodMuon[mu_muid_n]/I");
 myTree->Branch("isGoodMuon2",          &isGoodMuon2,   "isGoodMuon2[mu_muid_n]/I");
 myTree->Branch("isGoodDiMuonOS",       &isGoodDiMuonOS,"isGoodDiMuonOS[muid_npairs]/I");
 myTree->Branch("isGoodDiMuonSS",       &isGoodDiMuonSS,"isGoodDiMuonSS[muid_npairs]/I");
 myTree->Branch("dimuid_indexOS1",      &dimuid_indexOS1,"[muid_npairs]/I");
 myTree->Branch("dimuid_indexOS2",      &dimuid_indexOS2,"[muid_npairs]/I");
 myTree->Branch("dimuid_indexSS1",      &dimuid_indexSS1,"[muid_npairs]/I");
 myTree->Branch("dimuid_indexSS2",      &dimuid_indexSS2,"[muid_npairs]/I");
 myTree->Branch("mu_muid_E",            &Mymu_muid_E,   "mu_muid_E[mu_muid_n]/F");
 myTree->Branch("mu_muid_pt",           &Mymu_muid_pt,  "mu_muid_pt[mu_muid_n]/F");
 myTree->Branch("mu_muid_m",            &Mymu_muid_m,   "mu_muid_m[mu_muid_n]/F");
 myTree->Branch("mu_muid_eta",          &Mymu_muid_eta, "mu_muid_eta[mu_muid_n]/F");
 myTree->Branch("mu_muid_phi",          &Mymu_muid_phi, "mu_muid_phi[mu_muid_n]/F");
 myTree->Branch("mu_muid_px",           &Mymu_muid_px,  "mu_muid_px[mu_muid_n]/F");
 myTree->Branch("mu_muid_py",           &Mymu_muid_py,  "mu_muid_py[mu_muid_n]/F");
 myTree->Branch("mu_muid_pz",           &Mymu_muid_pz,  "mu_muid_pz[mu_muid_n]/F");
 myTree->Branch("mu_muid_charge",       &Mymu_muid_charge,      "mu_muid_charge[mu_muid_n]/F");
.
.
.

and similarly, glob->Set_Trig_and_Global_Branches(MyTree);

//---------------------------------------------------------------

void TrigGlobalBranch::Set_Trig_and_Global_Branches( TTree *MyTree)
{

   MyTree->Branch("RunNumber", &RunNumber, "RunNumber/I");
   MyTree->Branch("EventNumber", &EventNumber, "EventNumber/I");
   MyTree->Branch("Fcal_Et", &Fcal_Et, "Fcal_Et/F");
   MyTree->Branch("Centrality", &Centrality, "Centrality/F");
   MyTree->Branch("vx_x"            , &Myvx_x            , "vx_x/F"                  );
   MyTree->Branch("vx_y"            , &Myvx_y            , "vx_y/F"                  );
   MyTree->Branch("vx_z"            , &Myvx_z            , "vx_z/F"                  );

   MyTree->Branch("mbtime_timeA"    , &mbtime_timeA      , "mbtime_timeA/F"          );
   MyTree->Branch("mbtime_timeC"    , &mbtime_timeC      , "mbtime_timeC/F"         );
   MyTree->Branch("mbtime_countA"   , &mbtime_countA     , "mbtime_countA/I"         );
   MyTree->Branch("mbtime_countC"   , &mbtime_countC     , "mbtime_countC/I"         );
.
.
.

The mu->Fill_Muon_Branches(); looks like

//----------------------------------------------------------------------

void MuonBranch::Fill_Muon_Branches(){
  //number of muid muons in the event
   Mymu_muid_n=mu_muid_n;
   //number of L3 muons in the event
   Mytrig_EF_trigmuonef_n = trig_EF_trigmuonef_n;

   for(int i=0;i<mu_muid_n;i++){
      isGoodMuon[i]                     =        SelectMuon(i);
      Mymu_muid_E[i]                    =      mu_muid_E->at(i);
      Mymu_muid_pt[i]                   =      mu_muid_pt->at(i);
      Mymu_muid_m[i]                    =      mu_muid_m->at(i);
      Mymu_muid_eta[i]                  =      mu_muid_eta->at(i);
      Mymu_muid_phi[i]                  =      mu_muid_phi->at(i);
}
.
.
.

and glob->Fill_Trig_and_Global_Branches();

void TrigGlobalBranch::Fill_Trig_and_Global_Branches()
{
 //Vertex info. the 0th vertex is always the primary one.
   Myvx_x=vx_x->at(0);
   Myvx_y=vx_y->at(0);
   Myvx_z=vx_z->at(0);

  if(Fcal_Et > 2.8038) {
    Centrality = 0.025; //0-5%
  }
  else if (Fcal_Et > 2.3102){
    Centrality = 0.075 ; //5-10%
  }
  else if (Fcal_Et > 1.9073){
    Centrality = 0.125 ; //10-15%
  }
  else if (Fcal_Et > 1.5707){
    Centrality = 0.175 ; //15-20%
  }
  else if (Fcal_Et > 1.0448){
    Centrality = 0.25 ; //20-30%
  }
  else if (Fcal_Et > 0.6624){
    Centrality = 0.35 ; //30-40%
  }
  else if (Fcal_Et > 0.3909){
    Centrality = 0.45 ;  //40-50%
  }
  else if (Fcal_Et > 0.2118){
    Centrality = 0.55 ; //50-60%
  }
  else if (Fcal_Et > 0.1024){
    Centrality = 0.65 ; //60-70%
  }
  else if (Fcal_Et > 0.0438){
    Centrality = 0.75 ; //70-80%
  }
  else {
    Centrality = 0.89;  //80-98%
  }
.
.
.

  

Hi,

I am confused … where is the global variable (fChain) used?

Philippe.

fChain is a member of the BranchBase class, so it is defined there and initialized in the BranchBase.C file using TTree *BranchBase::fChain = 0. The int main() program then calls BranchBase::TurnOnBranches(), which performs the SetBranchStatus method.

(main program)

int main() {

        //get the run list ,set branch addresses and
        //intialize branches
        TString inputfiles="input.txt";
        BranchBase *t = new BranchBase(inputfiles);

        //get the tree holding the DPD variables
        TTree* itsTree = t->fChain;

        //output file and tree
        TFile *outfile   = new TFile("skimmed.root","recreate");
        TTree *MyTree    = new TTree("data","data");

        //Set the muon branches to be stored
        //in the output tree
        MuonBranch *mu = new MuonBranch;
        mu->Set_Muon_Branches(MyTree);

        //Set the global/trigger branches to be stored
        //in the output tree
        TrigGlobalBranch* glob = new TrigGlobalBranch;
        glob->Set_Trig_and_Global_Branches(MyTree);

        //set branch status and make sure
        //entries!=0
        int result = t->TurnOnBranches();

        if (result!=0) {

                std::cout << "Exiting program. " << std::endl;
                system("rm skimmed.root");
                exit(0);
        }
        int nentries = itsTree->GetEntries();
        if (nentries==0) {

                std::cout << "Zero entries in itsTree. Exiting program. " << std::endl;
                exit(0);
        }

        //event loop
        for (Long64_t jentry=0; jentry<nentries;jentry++){

                Long64_t ientry = itsTree->LoadTree(jentry);
                if (ientry < 0) break;

                itsTree->GetEntry(jentry); //  nbytes += nb;

                if(jentry%1000==0) printf("running event %5dk\n",(int) jentry/1000);

                bool event = t->EventCuts();
                if(!event) continue;

                glob->Fill_Trig_and_Global_Branches();
                std::cout << "After global fill" <<std::endl;
                mu->Fill_Muon_Branches();
                //Fill_FCal_Branches           ();
                //Fill_Track_Branches          (); 

                MyTree->Fill();

        } //event loop

        outfile->cd();
        MyTree->Write();
        outfile -> Close();

        delete mu;
        delete glob;
        delete t;
        return 0;

}

(BranchBase method in source file)

int BranchBase::TurnOnBranches()
{
//-----------------------------------------------------------------------------------------------------------------------------------------
  fChain->SetBranchStatus("*",0);

  fChain->SetBranchStatus("RunNumber"                    , 1);
  fChain->SetBranchStatus("bcid"                         , 1);
  fChain->SetBranchStatus("lbn"                          , 1);
  fChain->SetBranchStatus("EventNumber"                  , 1);
  fChain->SetBranchStatus("mu_*"  ,1);
  fChain->SetBranchStatus("muid_*",1);
.
.
.
  Long64_t nentries = fChain->GetEntries();
  std::cout<<"NENTRIES="<<nentries<<std::endl;
  if(nentries==0){std::cout<<" ZERO ENTRIES IN PROGRAM. OUTPUT Wont be produced"<<std::endl;return 100;}

  return 0;
}

in the event loop of the main() program, I call
(event loop of main())

Long64_t ientry = itsTree->LoadTree(jentry);
itsTree->GetEntry(jentry);

which loads the active D3PD branches into fChain (since in my main() scope, I assign

However, fChain is a member of BranchBase. Therefore, I must make it a static member such that when I assign the branches of MyTree to those in fChain (the D3PD tree), all the branches are filled with the same values in each of the 3 classes (1 parent, 2 derived).

I then fill the branches using the TrigGlobalBranch and MuonBranch methods (as shown in the previous post)

(in main() event loop)

glob->Fill_Trig_and_Global_Branches();
mu->Fill_Muon_Branches();

At the end of the event loop in main(), I finally fill MyTree with the values assigned to its branches from the D3PD branches and increment to the next event.

[quote]TTree* itsTree = t->fChain;

However, fChain is a member of BranchBase. Therefore, I must make it a static member such that when I assign the branches of MyTree to those in fChain (the D3PD tree), all the branches are filled with the same values in each of the 3 classes (1 parent, 2 derived). [/quote]I must still be missing something essential. Precisely because of this assignment you do not need fChain to be static and it seems that you never use it ‘directly’ from the 2nd object …

Philippe.

I think I understand what you mean. I thought making the TTree from the D3PD static would allow me to access a particular variable from any derived class object (for example mu->mu_muid_n, where mu_muid_n is a D3PD branch). However, this doesn’t seem to be the case since only t->mu_muid_n results in the correct value. So do I need to make every branch in BranchBase.h static?

Hi Thomas,

This is the wrong approach. Instead you should have one object that really wrap/look at the TTree (your base class) and other object (not deriving from the base class) that use this wrapper object … and both client would have the same pointer to the wrapper object.

Cheers,
Philippe.

Hi Philippe,

Just to follow up, making every branch static seems to work. From the way I understand your suggestion, I should create a wrapper class that has a BranchBase member. I then declare an object of the wrapper class, thereby gaining access to the TTree I want to read in (the D3PD ttree). Then, I use this wrapper class object in the MuonBranch and TrigGlobalBranch classes? I am also writing a portion of the input tree to an output tree by using the MuonBranch and TrigGlobalBranch classes. Would there be any complications introduced in doing this with the use of a wrapper class?

[quote]Then, I use this wrapper class object in the MuonBranch and TrigGlobalBranch classes? [/quote]Yes.

Philippe.

So when assigning variables to be written to the output tree from the input tree, I would have the following:

Mymu_muid_truth_pt[i] is a member of the MuonBranch class, where mu_muid_truth_pt is a member of the BranchBase class. If my wrapper class is BranchBaseWrapper with a member named BranchBase branch, then in a MuonBranch method I would do

BranchBaseWrapper *wrapper = 0;
Mymu_muid_truth_pt[i]             =      wrapper->branch->mu_muid_truth_pt->at(i);

Is this the general idea, instead of using all static members and inheritance?

Hi,

I think it was more like:tree->SetBranchAddress( &(wrapper-> Mymu_muid_truth_pt[0]) );I.e the idea is to have the data that is read from one file just to be copied then into another file to be in the same location (somewhere in the wrapper).

Philippe.

Ain’t “branch name” in TTree::SetBranchAddress mandatory?

Yes, I forgot it here, you need:tree->SetBranchAddress(branchname , &(wrapper-> Mymu_muid_truth_pt[0]) );

Cheers,
Philippe.

branchname & (wrapper-> Mymu_muid_truth_pt[0]) :mrgreen: :wink:

yep … a missing comma …

Thanks,
Philippe.