// Author: Anna Kreshuk, March 2007 ///////////////////////////////////////////////////////////////// // //___A stress test for the TEntryList class and operations with it___ // // The functions below test different properties of TEntryList // - Test1() - assembling entry lists for smaller chains from the lists // for bigger chains and vice versa + using them in TTree::Draw // - Test2() - adding and subtracting entry lists in different order // and using ">>+elist" in TTree::Draw // - Test3() - transforming TEventList objects into TEntryList objects for a TChain // - Test4() - same as Test3() but for a TTree // // To run in batch mode, do // stressEntryList // stressEntryList 1000 // stressEntryList 1000 10 // Here the 1st parameter is the number of entries in each TTree, // 2nd parameter is the number of created files // Default values are 10000 10 // // An example of output when all tests pass: // ********************************************************************** // ***************Starting TEntryList stress test************************ // ********************************************************************** // **********Generating 10 data files, 2 trees of 10000 in each********** // ********************************************************************** // Test1: Applying different entry lists to different chains --------- OK // Test2: Adding and subtracting entry lists-------------------------- OK // Test3: TEntryList and TEventList for TChain------------------------ OK // Test4: TEntryList and TEventList for TTree------------------------- OK // ********************************************************************** // *******************Deleting the data files**************************** // ********************************************************************** #include #include "TApplication.h" #include "TEntryList.h" #include "TEventList.h" #include "TTree.h" #include "TChain.h" #include "TRandom.h" #include "TH1F.h" #include "TCut.h" #include "TFile.h" #include "TSystem.h" Int_t stressEntryList(Int_t nentries = 10000, Int_t nfiles = 10); void MakeTrees(Int_t nentries, Int_t nfiles); Bool_t Test1() { //Test the functionality of entry lists for chains: //making new entry lists out of parts of other entry lists //applying same entry lists to different chains, etc Int_t wrongentries1, wrongentries2, wrongentries3, wrongentries4, wrongentries5; TChain *bigchain = new TChain("bigchain", "bigchain"); bigchain->Add("stressEntryListTrees*.root/tree1"); bigchain->Add("stressEntryListTrees*.root/tree2"); TChain *smallchain = new TChain("smallchain", "smallchain"); smallchain->Add("stressEntryListTrees*.root/tree1"); //create an entry list for the small chain TCut cut = "x<0 && y>0"; smallchain->Draw(">>elist_small", cut, "entrylist"); TEntryList *elist_small = (TEntryList*)gDirectory->Get("elist_small"); //check if the entry list contains correct entries Int_t range = 100; TH1F *hx = new TH1F("hx", "hx", range, -range, range); smallchain->Draw("x >> hx", cut, "goff"); TH1F *hcheck = new TH1F("hcheck", "hcheck", range, -range, range); smallchain->SetEntryList(elist_small); smallchain->Draw("x >> hcheck", "", "goff"); wrongentries1 = 0; for (Int_t i=1; i<=range; i++){ if (TMath::Abs(hx->GetBinContent(i)-hcheck->GetBinContent(i)) > 0.1){ wrongentries1++; } } if (wrongentries1 >0) printf("\nsmall list and small chain: number of wrong bins=%d\n", wrongentries1); //set this small entry list to the big chain and check the results bigchain->SetEntryList(elist_small); bigchain->Draw("x >> hcheck_", "", "goff"); wrongentries2 = 0; for (Int_t i=1; i<=range; i++){ if (TMath::Abs(hx->GetBinContent(i)-hcheck->GetBinContent(i)) > 0.1){ wrongentries2++; } } if (wrongentries2 >0) printf("\nsmall elist and big chain: number of wrong bins=%d\n", wrongentries2); smallchain->SetEntryList(0); bigchain->SetEntryList(0); //make an entry list for a big chain bigchain->Draw(">>elist_big", cut, "entrylist"); TEntryList* elist_big = (TEntryList*)gDirectory->Get("elist_big"); //make a small entry list by extracting the lists, corresponding to the trees in //the small chain, from the big entry list TEntryList *list_extracted = new TEntryList("list_extracted", "list_extracted"); TEntryList *elist_temp; TList *lists = elist_big->GetLists(); TIter next(lists); while ((elist_temp = (TEntryList*)next())){ if (!strcmp(elist_temp->GetTreeName(),"tree1")) list_extracted->Add(elist_temp); } //compare this extracted list to the list, generated by smallchain->Draw() Long64_t entry1, entry2; Int_t n=list_extracted->GetN(); wrongentries3 = 0; for (Int_t i=0; iGetEntry(i); entry2 = elist_small->GetEntry(i); if (entry1 != entry2){ if (wrongentries3<10) printf("wrong entry: %d list2=%lld elist_small=%lld\n", i, entry1, entry2); wrongentries3++; } } if (wrongentries3 >0) printf("\nsmall list and extracted list: number of wrong entries = %d, n=%d\n", wrongentries3,n); //add another entry list to the extracted list elist_temp = (TEntryList*)lists->Last(); list_extracted->Add(elist_temp); smallchain->SetEntryList(list_extracted); smallchain->Draw("x>>hcheck", "", "goff"); wrongentries4 = 0; for (Int_t i=1; i<=range; i++){ if (TMath::Abs(hx->GetBinContent(i)-hcheck->GetBinContent(i)) > 0.1){ //printf("%d hx: %f hcheck %f\n", i, hx->GetBinContent(i), hcheck->GetBinContent(i)); wrongentries4++; } } if (wrongentries4 >0) printf("\nextracted list with 1 wrong: number of wrong bins=%d\n", wrongentries4); //set the big entry list to the small chain and compare the results with //the entry list, generated by smallchain->Draw() smallchain->SetEntryList(elist_big); smallchain->Draw("x >> hcheck", "", "goff"); wrongentries5 = 0; for (Int_t i=1; i<=range; i++){ if (TMath::Abs(hx->GetBinContent(i)-hcheck->GetBinContent(i)) > 0.1){ //printf("i=%d hx(i)=%f, hcheck(i)=%f\n", i, hx->GetBinContent(i), hcheck->GetBinContent(i)); wrongentries5++; } } if (wrongentries5 >0) printf("\nbig elist and small chain: number of wrong bins = %d\n", wrongentries5); delete bigchain; delete smallchain; delete hx; delete hcheck; delete elist_big; delete elist_small; delete list_extracted; if (wrongentries1>0 || wrongentries2>0 || wrongentries3>0 || wrongentries4>0 || wrongentries5>0) return kFALSE; return kTRUE; } Bool_t Test2() { //Test adding and subtracting entry lists Int_t wrongentries1, wrongentries2, wrongentries3, wrongentries4, wrongentries5; TChain *chain = new TChain("chain", "chain"); chain->Add("stressEntryListTrees_0.root/tree1"); chain->Add("stressEntryListTrees_0.root/tree2"); //chain->Add("stressEntryListTrees*.root/tree1"); //chain->Add("stressEntryListTrees*.root/tree2"); TCut cut1("cut1", "x>0"); TCut cut2("cut2", "y<0.1 && y>-0.1"); TEntryList *elist1 = new TEntryList("elist1", "elist1"); chain->Draw(">>elist1", cut1, "entrylist"); TEntryList *elist2 = new TEntryList("elist2", "elist2"); chain->Draw(">>elist2", cut2, "entrylist"); //add those 2 lists (1+2) TEntryList *elistsum = new TEntryList("elistsum", "elistsum"); elistsum->Add(elist1); elistsum->Add(elist2); TEntryList *elistcheck = new TEntryList("elistcheck", "elistcheck"); chain->Draw(">>elistcheck", cut1 || cut2, "entrylist"); Int_t n=elistcheck->GetN(); Long64_t entry1, entry2; wrongentries1=0; for (Int_t i=0; iGetEntry(i); entry2 = elistcheck->GetEntry(i); if (entry1 != entry2) { //printf("%d, sum=%lld, check=%lld\n", i, entry1, entry2); wrongentries1++; } } if (wrongentries1>0) printf("\nwrong entries (1+2)=%d\n", wrongentries1); //add in different order TEntryList *elistsum2 = new TEntryList("elistsum2", "elistsum2"); elistsum2->Add(elist2); elistsum2->Add(elist1); wrongentries2 = 0; for (Int_t i=0; iGetEntry(i); entry2 = elistcheck->GetEntry(i); if (entry1 != entry2) { //printf("%d, sum=%lld, check=%lld\n", i, entry1, entry2); wrongentries2++; } } if (wrongentries2>0) printf("\nwrong entries (2+1)=%d\n", wrongentries2); //add by using "+" in TTree::Draw TEntryList *elistsum3 = new TEntryList("elistsum3", "elistsum3"); chain->Draw(">>elistsum3", cut1, "entrylist"); chain->Draw(">>+elistsum3", cut2, "entrylist"); wrongentries3 = 0; for (Int_t i=0; iGetEntry(i); entry2 = elistcheck->GetEntry(i); if (entry1 != entry2) { //printf("%d, sum=%lld, check=%lld\n", i, entry1, entry2); wrongentries3++; } } if (wrongentries3>0) printf("\nwrong entries with \"+\" in TChain::Draw =%d\n", wrongentries3); //subtract the second list elistsum->Subtract(elist2); n = elistsum->GetN(); TEntryList *elistcheck2 = new TEntryList("elistcheck2","elistcheck2"); chain->Draw(">>elistcheck2", "x>0 && (y>0.1 || y<-0.1)", "entrylist"); wrongentries4 = 0; for (Int_t i=0; iGetEntry(i); entry2 = elistcheck2->GetEntry(i); if (entry1 != entry2){ //printf("%d elist1=%lld elistsum=%lld\n", i, entry1, entry2); wrongentries4++; } } if (wrongentries4>0) printf("\nwrong entries after subtract 2 = %d\n", wrongentries4); //subtract the first list elistsum2->Subtract(elist1); elistcheck2->Reset(); chain->Draw(">>elistcheck2", "x<0 && y<0.1 && y>-0.1", "entrylist"); wrongentries5 = 0; n = elistcheck2->GetN(); for (Int_t i=0; iGetEntry(i); entry2 = elistcheck2->GetEntry(i); if (entry1 != entry2){ //printf("%d elist1=%lld elistsum=%lld\n", i, entry1, entry2); wrongentries5++; } } if (wrongentries5>0) printf("\nwrong entries after subtract 1 = %d\n", wrongentries5); delete elist1; delete elist2; delete elistsum; delete elistsum2; delete elistsum3; delete elistcheck; delete elistcheck2; if (wrongentries1>0 || wrongentries2>0 || wrongentries3>0 || wrongentries4>0 || wrongentries5>0) return kFALSE; return kTRUE; } Bool_t Test3() { //Test correspondance of event lists and entry lists TChain *chain = new TChain("chain", "chain"); chain->Add("stressEntryListTrees*.root/tree1"); chain->Add("stressEntryListTrees*.root/tree2"); TCut cut = "x<0 && y>0"; chain->Draw(">>evlist", cut, ""); TEventList *evlist = (TEventList*)gDirectory->Get("evlist"); chain->Draw("x>>h1", cut, "goff"); TH1F *h1 = (TH1F*)gDirectory->Get("h1"); chain->SetEventList(evlist); chain->Draw("x>>h2", "", "goff"); TH1F *h2 = (TH1F*)gDirectory->Get("h2"); chain->SetEventList(0); chain->Draw(">>enlist", cut, "entrylist"); TEntryList *enlist = (TEntryList*)gDirectory->Get("enlist"); chain->SetEntryList(enlist); chain->Draw("x>>h3", "", "goff"); TH1F *h3 = (TH1F*)gDirectory->Get("h3"); Int_t wrongbins = 0; Int_t nbins1 = h1->GetNbinsX(); Double_t bin1,bin2,bin3; for (Int_t i=0; iGetBinContent(i); bin2 = h2->GetBinContent(i); bin3 = h3->GetBinContent(i); if (TMath::Abs(bin1-bin2) > 0.1 || TMath::Abs(bin1-bin3) || TMath::Abs(bin2-bin3) > 0.1) { //printf("bin1=%f, bin2=%f, bin3=%f\n", bin1, bin2, bin3); wrongbins++; } } if (wrongbins>0) printf("wrongbins=%d\n", wrongbins); delete chain; delete h1; delete h2; delete h3; delete evlist; delete enlist; if (wrongbins>0) return kFALSE; return kTRUE; } Bool_t Test4() { //Like Test3() but for trees TFile f("stressEntryListTrees_0.root"); TTree *tree = (TTree*)f.Get("tree1"); TCut cut = "x<0 && y>0"; tree->Draw(">>evlist", cut, ""); TEventList *evlist = (TEventList*)gDirectory->Get("evlist"); tree->Draw("x>>h1", cut, "goff"); TH1F *h1 = (TH1F*)gDirectory->Get("h1"); tree->SetEventList(evlist); tree->Draw("x>>h2", "", "goff"); TH1F *h2 = (TH1F*)gDirectory->Get("h2"); tree->SetEventList(0); tree->Draw(">>enlist", cut, "entrylist"); TEntryList *enlist = (TEntryList*)gDirectory->Get("enlist"); tree->SetEntryList(enlist); tree->Draw("x>>h3", "", "goff"); TH1F *h3 = (TH1F*)gDirectory->Get("h3"); Int_t wrongbins = 0; Int_t nbins1 = h1->GetNbinsX(); Double_t bin1,bin2,bin3; for (Int_t i=0; iGetBinContent(i); bin2 = h2->GetBinContent(i); bin3 = h3->GetBinContent(i); if (TMath::Abs(bin1-bin2) > 0.1 || TMath::Abs(bin1-bin3) || TMath::Abs(bin2-bin3) > 0.1) { //printf("bin1=%f, bin2=%f, bin3=%f\n", bin1, bin2, bin3); wrongbins++; } } if (wrongbins>0) printf("wrongbins=%d\n", wrongbins); delete h1; delete h2; delete h3; delete evlist; delete enlist; f.Close(); if (wrongbins>0) return kFALSE; return kTRUE; } Bool_t Test5() { //Test entry lists with very many or very few events //Only makes sense to check if there are > 64000 events TChain *chain = new TChain("chain", "chain"); chain->Add("stressEntryListTrees*.root/tree1"); chain->Add("stressEntryListTrees*.root/tree2"); Int_t wrongentries1=0; Int_t wrongentries2=0; Int_t wrongentries3=0; Int_t wrongentries4=0; Int_t wrongentries5=0; //Let's make a full entry list chain->Draw(">>elfull", "", "entrylist"); TEntryList *elfull = (TEntryList*)gDirectory->Get("elfull"); //printf("entries in the list: %lld\n", elfull->GetN()); //check the contents Long64_t cur, real; Int_t ntrees = chain->GetNtrees(); Long64_t *offset = chain->GetTreeOffset(); //This loop will check if TEntryList::Next() is correct for (Int_t itree=0; itreeGetEntry(i); if (TMath::Abs(real-cur)>0.1){ //printf("real=%lld, cur=%lld\n", real, cur); wrongentries1++; } } } //printf("wrongentries1=%d\n", wrongentries1); // //This loop will check if TEntryList::GetEntry() is correct for (Int_t itree=0; itreeGetEntry(i); if (TMath::Abs(real-cur)>0.1){ //printf("real=%lld, cur=%lld\n", real, cur); wrongentries2++; } } } //printf("wrongentries2=%d\n", wrongentries2); //now let's make an empty entry list chain->Draw(">>elempty", "x>0 && x<0", "entrylist"); TEntryList *elempty = (TEntryList*)gDirectory->Get("elempty"); //just a check Long64_t temp = elempty->GetEntry(3); if (TMath::Abs(temp+1)>0.1) wrongentries5++; //Merge the almost full list with the almost empty list //Note, how the chain pointer is passed to the Remove() and Enter() //functions. This is needed, because we want to remove entry #3 in //the chain, not entry that has #3 in the currently active sublist elfull->Remove(3, chain); elempty->Enter(3, chain); elfull->Add(elempty); //This loop will check if TEntryList::Next() is correct for (Int_t itree=0; itreeGetEntry(i); if (TMath::Abs(real-cur)>0.1){ //printf("real=%lld, cur=%lld\n", real, cur); wrongentries3++; } } } //printf("wrongentries3=%d\n", wrongentries3); //This loop will check if TEntryList::GetEntry() is correct for (Int_t itree=0; itreeGetEntry(i); if (TMath::Abs(real-cur)>0.1){ //printf("real=%lld, cur=%lld\n", real, cur); wrongentries4++; } } } // printf("wrongentries4=%d\n", wrongentries4); //Now let's use the full and empty lists on the chain chain->SetEntryList(elfull); chain->Draw("x>>hx", "", "goff"); TH1F *hx = (TH1F*)gDirectory->Get("hx"); if (TMath::Abs(hx->GetEntries()-chain->GetEntries())>0.1){ wrongentries5++; //printf("entries in chain: %lld, entries in histo: %f\n", chain->GetEntries(), hx->GetEntries()); } elempty->Remove(3); //elempty->Print("all"); chain->SetEntryList(elempty); Long64_t nen = chain->Draw("x", "", "goff"); if (nen!=0) wrongentries5++; //printf("wrongentries5=%d\n", wrongentries5); delete elempty; delete elfull; delete hx; if (wrongentries1>0 || wrongentries2>0 || wrongentries3>0 || wrongentries4>0 || wrongentries5>0) return kFALSE; else return kTRUE; } void MakeTrees(Int_t nentries, Int_t nfiles) { //Creates nfiles files with 2 trees of nentries each TFile *f1; TTree *tree1, *tree2; Double_t x, y, z; Double_t range = nentries/100.; char buffer[50]; for (Int_t ifile=0; ifileBranch("x", &x, "x/D"); tree1->Branch("y", &y, "y/D"); tree1->Branch("z", &z, "z/D"); tree2 = new TTree("tree2", "tree2"); tree2->Branch("x", &x, "x/D"); tree2->Branch("y", &y, "y/D"); tree2->Branch("z", &z, "z/D"); for (Int_t i=0; iUniform(-range, range); y = gRandom->Uniform(-range, range); z = gRandom->Uniform(-range, range); tree1->Fill(); x = gRandom->Uniform(-range, range); y = gRandom->Uniform(-range, range); z = gRandom->Uniform(-range, range); tree2->Fill(); } tree1->Write(); tree2->Write(); f1->Write(); f1->Close(); } } void CleanUp(Int_t nfiles) { char buffer[50]; for (Int_t i=0; iUnlink(buffer); } } Int_t stressEntryList(Int_t nentries, Int_t nfiles) { //Int_t nentries = 1000; //Int_t nfiles = 10; MakeTrees(nentries, nfiles); printf("**********************************************************************\n"); printf("***************Starting TEntryList stress test************************\n"); printf("**********************************************************************\n"); printf("**********Generating %d data files, 2 trees of %d in each**********\n", nfiles, nentries); printf("**********************************************************************\n"); Bool_t ok1=kTRUE; Bool_t ok2=kTRUE; Bool_t ok3=kTRUE; Bool_t ok4=kTRUE; Bool_t ok5=kTRUE; ok1 = Test1(); if (ok1) printf("Test1: Applying different entry lists to different chains --------- OK\n"); else{ printf("Test1: Applying different entry lists to different chains --------- FAILED\n"); } ok2 = Test2(); if (ok2) printf("Test2: Adding and subtracting entry lists-------------------------- OK\n"); else{ printf("Test1: Adding and subtracting entry lists-------------------------- FAILED\n"); } ok3 = Test3(); if (ok3) printf("Test3: TEntryList and TEventList for TChain------------------------ OK\n"); else{ printf("Test3: TEntryList and TEventList for TChain------------------------ FAILED\n"); } ok4 = Test4(); if (ok4) printf("Test4: TEntryList and TEventList for TTree------------------------- OK\n"); else{ printf("Test4: TEntryList and TEventList for TTree------------------------- FAILED\n"); } ok5 = Test5(); if (ok5) printf("Test5: Full and Empty TEntryList----------------------------------- OK\n"); else printf("Test5: Full and Empty TEntryList----------------------------------- FAILED\n"); printf("**********************************************************************\n"); printf("*******************Deleting the data files****************************\n"); printf("**********************************************************************\n"); CleanUp(nfiles); return 0; } //_____________________________batch only_____________________ #ifndef __CINT__ int main(int argc, char *argv[]) { TApplication theApp("App", &argc, argv); Int_t nentries = 10000; Int_t nfiles = 10; if (argc > 1) nentries = atoi(argv[1]); if (argc > 2) nfiles = atoi(argv[2]); stressEntryList(nentries, nfiles); return 0; } #endif