From: Pierre Gueth <pierre.gueth@creatis.insa-lyon.fr> Date: Thu, 7 Feb 2013 13:37:24 +0000 (+0100) Subject: copied gatemergemanager from gate-creatis X-Git-Tag: v1.4.0~164^2~21 X-Git-Url: https://git.creatis.insa-lyon.fr/pubgit/?a=commitdiff_plain;h=1ba290db3f08dc7754d76c5cfe5040448dadd04e;p=clitk.git copied gatemergemanager from gate-creatis --- diff --git a/tests_dav/GateMergeManager.cc b/tests_dav/GateMergeManager.cc new file mode 100644 index 0000000..0de9794 --- /dev/null +++ b/tests_dav/GateMergeManager.cc @@ -0,0 +1,750 @@ +/*---------------------- + GATE version name: gate_v... + + Copyright (C): OpenGATE Collaboration + +This software is distributed under the terms +of the GNU Lesser General Public Licence (LGPL) +See GATE/LICENSE.txt for further details +----------------------*/ + + +#include <TROOT.h> +#include <TFile.h> +#include <TChain.h> +#include <TTree.h> +#include <TBranch.h> +#include <TIterator.h> +#include <TObject.h> +#include <TKey.h> +#include <TH1.h> +#include <TH2.h> + +#include <iostream> +#include <fstream> +#include <string> +#include <glob.h> +#include <ctype.h> +#include <sstream> +#include <vector> +#include <cstdlib> +#include <cmath> + +#include "GateMergeManager.hh" + +using namespace std; + +void GateMergeManager::StartMerging(string splitfileName){ + + // get the files to merge + ReadSplitFile(splitfileName); + //do the merging + if (m_fastMerge==true) FastMergeRoot(); + else MergeRoot(); + + //if we are here the merging has been successful + //we mark the directory as ready for cleanup + //string dir = splitfileName.substr(0,splitfileName.rfind("/")); + //string ready = "touch "+dir+"/ready_for_delete"; + //const int res=system(ready.c_str()); + //if(res) cout<<"Strange?? Can't mark "<<dir<<" as done!"<<endl; +}; + +// to process the splitfile +void GateMergeManager::ReadSplitFile(string splitfileName){ + + ifstream splitfile; + splitfile.open(splitfileName.c_str()); + if(!splitfile){ + cout<<"Can't open split file: "<<splitfileName<<endl; + exit(0); + }; + + //avoid multiple calls + if(m_vRootFileNames.size()>0) return; + + stringstream ssnfiles; + char cline[512]; + while(splitfile){ //we allow for rubbish before "Number of files:" + splitfile.getline(cline,512); + if(!strncmp(cline,"Number of files:",16)){ + ssnfiles.str(cline+16); + ssnfiles>>m_Nfiles; // the number of files to merge + break; + } + } + + // now we look for the file names + int iRoot=0; + while(splitfile){ + splitfile.getline(cline,512); + // check for root + // input files + if(!strncmp(cline,"Root filename:",14)){ + m_vRootFileNames.push_back(strtok(cline+15," ")); + m_vRootFileNames[iRoot]+=".root"; + if(m_verboseLevel>2) cout<<"Root input file name: "<<m_vRootFileNames[iRoot]<<endl; + iRoot++; + } + // output file + else if(!strncmp(cline,"Original Root filename:",23)){ + m_RootTargetName=strtok(cline+23," "); + m_RootTargetName+=".root"; + if(m_outDir!=""){// output directory option used + //replace path with outDir + size_t pos=m_RootTargetName.rfind('/',m_RootTargetName.length()); + if(pos==string::npos) pos=-1; + m_RootTargetName=m_outDir+m_RootTargetName.substr(pos+1); + } + if(m_verboseLevel>2) cout<<"Root output file name: "<<m_RootTargetName<<endl; + } + } + + // check if number of root files correct + if(iRoot && iRoot!=m_Nfiles) { + cout<<"Inconsistent number of root file entries in split file!"<<endl; + exit(0); + } +} + +/************************************************************************************/ +void GateMergeManager::FastMergeRoot() +{ + //check target name + if(m_RootTargetName=="") { + cout<<"No root output file name given in split file"<<endl; + exit(0); + } + + // number of files to merge + int nfiles=m_vRootFileNames.size(); + if(nfiles<1){ + cout<<"No files to merge!"<<endl; + exit(0); + } + //we try to recover the last_event_ID in all root files + filearr=new TFile*[nfiles]; + for(int i=0;i<nfiles;i++) { + filearr[i] = TFile::Open(m_vRootFileNames[i].c_str(),"OLD"); + if(filearr[i]==NULL){ + cout<<"Not a readable file "<<m_vRootFileNames[i]<<" - exit!"<<endl; + exit(0); + } + } + m_lastEvents.resize(nfiles+1); + m_lastEvents[0]=0; + bool flgLstEvntID(false); + + // latest_event_ID histogram + flgLstEvntID=true; + TH1* h=NULL; + for(int i=0;i<nfiles;i++){ + h = (TH1*)filearr[i]->Get("latest_event_ID"); + m_lastEvents[i+1]=int(h->GetMean()); + } + + if(!flgLstEvntID) { + cout<<"FastMerge: No latest_event_ID histogram - exit!"<<endl; + exit(0); + } + + /*for (int i=0;i<nfiles;i++) + { + cout<<"Last ID is: "<<m_lastEvents[i+1]<<" File " <<i+1<<endl; + }*/ + + //find all trees + vector<string> treeNames; + TFile* node = TFile::Open(m_vRootFileNames[0].c_str(),"OLD"); + TIter nextkey(node->GetListOfKeys()); + TKey *key=0; + while ((key = (TKey*)nextkey())) + { + node->cd(); + TObject* obj = (TObject*)key->ReadObj(); + if( obj->IsA()->InheritsFrom("TTree")) + { + //no doubles + bool singleName=true; + for(unsigned int i=0;i<treeNames.size();i++) + { + if(treeNames[i].compare(obj->GetName())==0) + { + singleName=false; + break; + } + } + if(singleName) treeNames.push_back(obj->GetName()); + } + } + //take care of all trees + for(unsigned int i=0;i<treeNames.size();i++) + { + if(!MergeTree(treeNames[i])) if(m_verboseLevel>1) cout<<"Problem with merging "<<treeNames[i]<<endl; + } +} +/************************************************************************************/ +void GateMergeManager::MergeRoot(){ + + //check target name + if(m_RootTargetName=="") { + cout<<"No root output file name given in split file"<<endl; + exit(0); + } + + // number of files to merge + int nfiles=m_vRootFileNames.size(); + + // the root output file + if(m_forced) { + m_RootTarget = TFile::Open(m_RootTargetName.c_str(),"RECREATE"); + } else { + m_RootTarget = TFile::Open(m_RootTargetName.c_str(),"NEW"); + if(!m_RootTarget){ + cout<<"The root ouput file already exists! Try -f to overwrite and erase the file."<<endl; + exit(0); + } + } + + if(nfiles<1){ + cout<<"No files to merge!"<<endl; + exit(0); + } + + TFile* filearr[nfiles]; + for(int i=1;i<nfiles;i++) { + filearr[i] = TFile::Open(m_vRootFileNames[i].c_str(),"OLD"); + if(filearr[i]==NULL){ + cout<<"Not a readable file "<<m_vRootFileNames[i]<<" - exit!"<<endl; + exit(0); + } + } + +// first we copy all histos (only top directory) +// and look for the latestEventID +// and find out which trees/ntuples exist + m_lastEvents.resize(nfiles+1); + m_lastEvents[0]=0; + + bool flgLstEvntID(false); + + if(m_verboseLevel>0) { + cout<<"Combining: "; + for(int i=0;i<nfiles;i++) cout<<m_vRootFileNames[i]<<" "; + cout<<"-> "<<m_RootTarget->GetName()<<endl; + } + + vector<string> treeNames; + TFile* node = TFile::Open(m_vRootFileNames[0].c_str(),"OLD"); + if(node==NULL){ + cout<<"Not a readable file "<<m_vRootFileNames[0]<<" - exit!"<<endl; + exit(0); + } + TIter nextkey(node->GetListOfKeys()); + TKey *key=0; + while ((key = (TKey*)nextkey())) { + node->cd(); + TObject* obj = (TObject*)key->ReadObj(); + if( obj->IsA()->InheritsFrom("TH1")){ + m_RootTarget->cd(); + TH1 *h1 = (TH1 *)obj->Clone(); + if(strcmp(h1->GetName(),"latest_event_ID")){ + //any other histogram + for(int i=1;i<nfiles;i++){ + TH1 *h2 = (TH1*)filearr[i]->Get( h1->GetName() ); + h1->Add( h2 ); + } + h1->Write(); + } else { + // latest_event_ID histogram + flgLstEvntID=true; + m_lastEvents[1]=int(h1->GetMean()); + TH1* h=NULL; + for(int i=1;i<nfiles;i++){ + h = (TH1*)filearr[i]->Get("latest_event_ID"); + m_lastEvents[i+1]=int(h->GetMean()); + } + if(h!=NULL) h->Write(); // we keep the highest latest_event_ID to allow for successive merging + else h1->Write(); + } + } + if( obj->IsA()->InheritsFrom("TH2")){ + m_RootTarget->cd(); + TH2 *h1 = (TH2 *)obj->Clone(); + for(int i=1;i<nfiles;i++){ + TH2 *h2 = (TH2*)filearr[i]->Get( h1->GetName() ); + h1->Add( h2 ); + } + h1->Write(); + } + if( obj->IsA()->InheritsFrom("TTree")){ + //no doubles + bool singleName=true; + for(unsigned int i=0;i<treeNames.size();i++) { + if(treeNames[i].compare(obj->GetName())==0){ + singleName=false; + break; + } + } + if(singleName) treeNames.push_back(obj->GetName()); + } + } + if(!flgLstEvntID) { + cout<<"Merge: No latest_event_ID histogram - exit!"<<endl; + exit(0); + } + + //now we take care of the trees + for(unsigned int i=0;i<treeNames.size();i++) + if(!MergeTree(treeNames[i])) if(m_verboseLevel>1) cout<<"Problem with merging "<<treeNames[i]<<endl; + + // everything is done +}; + +/*******************************************************************************************/ +// cleanup after merging +void GateMergeManager::StartCleaning(string splitfileName,bool test){ + + // get the files to erase + ReadSplitFile(splitfileName); + + string dir=splitfileName.substr(0,splitfileName.rfind("/")); + + // test for the mark: ready_for_delete + string touched=dir+"/ready_for_delete"; + ifstream ready; + ready.open(touched.c_str()); + if (!ready) { + cout<<"Cannot do the cleanup - directory "<<dir<<" not marked as ready!"<<endl; + if(!test) exit(0); + } + + // print info + if(test) cout<<"I would like to erase:"<<endl; + if(!test&&m_verboseLevel>1) cout<<"Going to erase the following files:"<<endl; + if(m_verboseLevel>1||test){ + cout<<" --> "<<dir<<endl; + // root + for(unsigned int i=0;i<m_vRootFileNames.size();i++){ + cout<<" --> "<<m_vRootFileNames[i]<<endl; + } + } + + // erase! + if(!test){ + for(unsigned int i=0;i<m_vRootFileNames.size();i++){ + const string rmfiles("rm -f "+m_vRootFileNames[i]); + const int res = system(rmfiles.c_str()); + if(res) { + cout<<"Could not remove "<<m_vRootFileNames[i]<<endl; + cout<<"Please remove it manually!"<<endl; + } + } + const string rmfiles("rm -f "+dir+"/*"); + system(rmfiles.c_str()); + const string rmdir="rm -f -r "+dir; + const int res2 = system(rmdir.c_str()); + if(res2) { + cout<<"Could not remove "<<dir<<endl; + cout<<"Please remove it manually!"<<endl; + } + } +} + +/*******************************************************************************************/ +//find out what kind of tree we have and call the right merger +bool GateMergeManager::MergeTree(string chainName){ +if (m_fastMerge==false) + { + TChain* chain = new TChain(chainName.c_str()); + + // number of files to merge + int nfiles=m_vRootFileNames.size(); + + for(int i=0;i<nfiles;i++) chain->Add(m_vRootFileNames[i].c_str()); + int nentries=chain->GetEntries(); + if(nentries<=0) { + if(m_verboseLevel>1) cout<<chain->GetName()<<" is empty!"<<endl; + return false; + } + + if(chainName=="Gate") MergeGate(chain); + + if(chain->FindBranch("eventID1")!=NULL) { + if( (chain->FindBranch("runID")==NULL) + ||(chain->FindBranch("time1")==NULL) + ||(chain->FindBranch("time2")==NULL) ) { + cout<<"Cannot find one of: runID, time1, time2 in "<<chain->GetName()<<endl; + return false; + } + // coincidence + return MergeCoin(chain); + + } else if( (chain->FindBranch("runID")==NULL)||(chain->FindBranch("eventID")==NULL) + ||(chain->FindBranch("time")==NULL) ) + { + cout<<"Cannot find one of: runID, eventID, time in "<<chain->GetName()<<endl; + return false; + } + // Singles or Hits + return MergeSing(chain); + } + else + { + if (chainName.find("Hits",0)!=string::npos) return FastMergeSing(chainName); + if (chainName.find("Singles",0)!=string::npos) return FastMergeSing(chainName); + if (chainName.find("Gate",0)!=string::npos) return FastMergeGate(chainName); + if (chainName.find("Coincidences",0)!=string::npos) return FastMergeCoin(chainName); + } + return 0; +} + +/*******************************************************************************************/ +bool GateMergeManager::FastMergeGate(string name) +{ +//create the output file +float event = 0; +int offset = 0; +int currentfile = 0; +float lastEvent =-1; +//float maxtime =-999999999; +string clusterName=name+"_cluster"; + +for(int j=0;j<m_Nfiles;j++) + { + filearr[j]->ReOpen("UPDATE"); + TTree *oldTree = (TTree*)gDirectory->Get(name.c_str()); + TBranch *branch = oldTree->GetBranch("event"); + branch->SetAddress(&event); + TBranch* newBranch=oldTree->Branch("eventcluster",&event,"event"); + + Int_t nentries=(Int_t)oldTree->GetEntries(); + + if (j==0) offset=0; + else offset+=m_lastEvents[currentfile]; + currentfile++; + + for(int i=0;i<nentries;i++) + { + branch->GetEvent(i); + if(lastEvent!=event) + { + lastEvent=event; + event+=offset; + newBranch->Fill(); + } + else + { + if((i==nentries-1) && (j==m_Nfiles-1)) + { + event+=offset; + newBranch->Fill(); + } + else if (i!=nentries-1) + { + branch->GetEvent(i); + event+=offset; + newBranch->Fill(); + lastEvent=0; + offset=0; + } + } + } + oldTree->Write(); + } + return true; +} + +/*******************************************************************************************/ +bool GateMergeManager::FastMergeSing(string name) +{ +int eventID = 0; +int runID = 0; +int offset = 0; +int currentfile = 0; +float lastRun =-1; +string clusterName=name+"_cluster"; + +for(int j=0;j<m_Nfiles;j++) + { + filearr[j]->ReOpen("UPDATE"); + TTree *oldTree = (TTree*)gDirectory->Get(name.c_str()); + TBranch *branch = oldTree->GetBranch("eventID"); + branch->SetAddress(&eventID); + TBranch *branch2 = oldTree->GetBranch("runID"); + branch2->SetAddress(&runID); + TBranch* newBranch=oldTree->Branch("eventIDcluster",&eventID,"eventID/I"); + + Int_t nentries=(Int_t)oldTree->GetEntries(); + + if (j==0) offset=0; + else offset+=m_lastEvents[currentfile]; + currentfile++; + + for(int i=0;i<nentries;i++) + { + branch->GetEvent(i); + if(lastRun!=runID) + { + lastRun=runID; + offset=0; + } + eventID+=offset; + newBranch->Fill(); + } + oldTree->Write(); + } + return true; +} + +/*******************************************************************************************/ +bool GateMergeManager::FastMergeCoin(string name) +{ +//create the output file +int eventID1 = 0; +int eventID2 = 0; +int runID = 0; +int offset = 0; +int currentfile = 0; +float lastRun =-1; +string clusterName=name+"_cluster"; +cout<<"starting coincidence merging..."<<endl; +for(int j=0;j<m_Nfiles;j++) + { +cout<<"working on file..."<<j<<endl; + filearr[j]->ReOpen("UPDATE"); + TTree *oldTree = (TTree*)gDirectory->Get(name.c_str()); + TBranch *branch1 = oldTree->GetBranch("eventID1"); + branch1->SetAddress(&eventID1); + TBranch *branch2 = oldTree->GetBranch("eventID2"); + branch2->SetAddress(&eventID2); + TBranch *branch3 = oldTree->GetBranch("runID"); + branch3->SetAddress(&runID); + + TBranch* newBranch1=oldTree->Branch("eventID1cluster",&eventID1,"eventID1/I"); + TBranch* newBranch2=oldTree->Branch("eventID2cluster",&eventID2,"eventID2/I"); + + Int_t nentries=(Int_t)oldTree->GetEntries(); + + if (j==0) offset=0; + else offset+=m_lastEvents[currentfile]; + cout<<"the offset in this file is: "<<offset<<endl; + currentfile++; + + for(int i=0;i<nentries;i++){ + branch1->GetEvent(i); + branch2->GetEvent(i); + branch3->GetEvent(i); + if(lastRun!=runID) + { + lastRun=runID; + offset=0; + } + eventID1+=offset; + eventID2+=offset; + newBranch1->Fill(); + newBranch2->Fill(); + } + oldTree->Write(); + } + return true; +} + +/*******************************************************************************************/ +// Gate tree merger +bool GateMergeManager::MergeGate(TChain* chainG) { + + int nentries=chainG->GetEntries(); + + float event = 0; + chainG->SetBranchAddress("event",&event); + Float_t iontime = 0; + chainG->SetBranchAddress("iontime",&iontime); + + //create the new tree + //Allow for large files and do not write every bit separately + m_RootTarget->cd(); + TTree * newTree = chainG->CloneTree(0); + newTree->SetAutoSave(2000000000); + if(m_maxRoot!=0) newTree->SetMaxTreeSize(m_maxRoot); + else newTree->SetMaxTreeSize(17179869184LL); + + // changing the compression level everywhere + TBranch *br; + TIter next(newTree->GetListOfBranches()); + while ((br=(TBranch*)next())) br->SetCompressionLevel(m_CompLevel); + + // the main part: modify the eventID + int offset = 0; + int currentTree = 0; + float lastEvent =-1; + float maxtime =-999999999; + for(int i=0;i<nentries;i++){ + if (chainG->GetEntry(i) <= 0) break; //end of chain + if(chainG->GetTreeNumber()>currentTree) { + currentTree++; + offset+=m_lastEvents[currentTree]; + // check for overlaping time intervalls between different files + // (not within the same file i.e. no time order assumed) + if(iontime<maxtime) + if(m_verboseLevel>0) + cout<<"Warning - overlapping Gate iontime (" + <<iontime<<") in file: "<<m_vRootFileNames[currentTree].c_str()<<endl; + } + // run end is marked by repeating event + if(lastEvent!=event) { + lastEvent=event; +// if (fpclassify(iontime)!=FP_NAN && fpclassify(iontime)!=FP_INFINITE) { + if(finite(iontime)){ + if(maxtime<iontime) maxtime=iontime; + // the offset to get a unique event numbering + event+=offset; + newTree->Fill(); + } else { + cout<<"Warning - inf or NaN in Gate tree for iontime! "<<m_vRootFileNames[currentTree].c_str()<<endl; + //we are lost anyhow + maxtime =-999999999; + } + } else { + // run end + if(chainG->GetEntry(i+1) <= 0) { //chain end fill the double event + event+=offset; + newTree->Fill(); + } else if(chainG->GetTreeNumber()==currentTree //no new file or + ||(chainG->GetTreeNumber()>currentTree + &&m_lastEvents[chainG->GetTreeNumber()]==0) ) { //new file with no offset fill double event + chainG->GetEntry(i); + event+=offset; + newTree->Fill(); + lastEvent=0;// we may have triple 1 (1 event run) + offset=0; + } + } + } + newTree->Write(); + delete newTree; + return true; +} + +/*******************************************************************************************/ +// Singles and Hits tree merger +bool GateMergeManager::MergeSing(TChain* chainS){ + + int nentriesS=chainS->GetEntries(); + + int eventID = 0; + int runID = 0; + double time = 0; + + chainS->SetBranchAddress("eventID",&eventID); + chainS->SetBranchAddress("runID",&runID); + chainS->SetBranchAddress("time",&time); + + m_RootTarget->cd(); + TTree * newSing = chainS->CloneTree(0); + newSing->SetAutoSave(2000000000); + if(m_maxRoot!=0) newSing->SetMaxTreeSize(m_maxRoot); + else newSing->SetMaxTreeSize(17179869184LL); + + // changing CompLevel everywhere + TBranch *br; + TIter next(newSing->GetListOfBranches()); + while ((br=(TBranch*)next())) br->SetCompressionLevel(m_CompLevel); + + //the main part: changing eventID + int offset = 0; + int currentTree = 0; + float lastRun = 0; + float maxtime =-999999999; + for(int i=0;i<nentriesS;i++){ + if(chainS->GetEntry(i) <= 0) break; //end of chain + if(chainS->GetTreeNumber()>currentTree) { + currentTree++; + offset+=m_lastEvents[currentTree]; + // check for overlaping time intervalls between different files + // (not within the same file i.e. no time order assumed) + if(time<maxtime) + if(m_verboseLevel>0) + cout<<"Warning - overlapping Singles time (" + <<time<<") in file: "<<m_vRootFileNames[currentTree].c_str()<<endl; + } + // the offset to get a unique event numbering + if(lastRun!=runID) { + // run end + lastRun=runID; + offset=0; //new run in file we must not change the eventID anymore + } + eventID+=offset; + newSing->Fill(); + if(maxtime<time)maxtime=time; + } + newSing->Write(); + delete newSing; + return true; +}; + +/*******************************************************************************************/ +// Coincidences tree merger +bool GateMergeManager::MergeCoin(TChain* chainC){ + + int nentriesC=chainC->GetEntries(); + + int eventID1 = 0; + chainC->SetBranchAddress("eventID1",&eventID1); + double time1 = 0; + chainC->SetBranchAddress("time1",&time1); + int eventID2 = 0; + chainC->SetBranchAddress("eventID2",&eventID2); + double time2 = 0; + chainC->SetBranchAddress("time2",&time2); + int runID = 0; + chainC->SetBranchAddress("runID",&runID); + + m_RootTarget->cd(); + TTree * newCoin = chainC->CloneTree(0); + newCoin->SetAutoSave(2000000000); + if(m_maxRoot!=0) newCoin->SetMaxTreeSize(m_maxRoot); + else newCoin->SetMaxTreeSize(17179869184LL); + + // changing CompLevel everywhere + TBranch *br; + TIter next(newCoin->GetListOfBranches()); + while ((br=(TBranch*)next())) br->SetCompressionLevel(m_CompLevel); + + int offset = 0; + int currentTree = 0; + float lastRun = 0; + float maxtime =-999999999; + for(int i=0;i<nentriesC;i++){ + if(chainC->GetEntry(i) <= 0) break; //end of chain + if(chainC->GetTreeNumber()>currentTree) { + currentTree++; + offset+=m_lastEvents[currentTree]; + // check for overlaping time intervalls between different files + // (not within the same file i.e. no time order assumed) + if(time1<maxtime) + if(m_verboseLevel>0) + cout<<"Warning - overlapping Coincidences time1 (" + <<time1<<") in file: "<<m_vRootFileNames[currentTree].c_str()<<endl; + if(time2<maxtime) + if(m_verboseLevel>0) + cout<<"Warning - overlapping Coincidences time2 (" + <<time2<<") in file: "<<m_vRootFileNames[currentTree].c_str()<<endl; + } + // the offset to get a unique event numbering + if(lastRun!=runID) { + // run end + lastRun=runID; + offset=0; //new run in file we must not change the eventID anymore + } + eventID1+=offset; + eventID2+=offset; + newCoin->Fill(); + if(maxtime<time1)maxtime=time1; + if(maxtime<time2)maxtime=time2; + } + newCoin->Write(); + delete newCoin; + return true; +} +/*******************************************************************************************/ diff --git a/tests_dav/GateMergeManager.hh b/tests_dav/GateMergeManager.hh new file mode 100644 index 0000000..f7fb095 --- /dev/null +++ b/tests_dav/GateMergeManager.hh @@ -0,0 +1,91 @@ +/*---------------------- + GATE version name: gate_v... + + Copyright (C): OpenGATE Collaboration + +This software is distributed under the terms +of the GNU Lesser General Public Licence (LGPL) +See GATE/LICENSE.txt for further details +----------------------*/ + + +#ifndef GateMergeManager_h +#define GateMergeManager_h 1 +#include <iostream> +#include <string> +#include <vector> +#include <TFile.h> +#include <TChain.h> +#include <cstdlib> + +using namespace std; + +class GateMergeManager +{ +public: + + GateMergeManager(bool fastMerge,int verboseLevel,bool forced,Long64_t maxRoot,string outDir){ + m_verboseLevel = verboseLevel; + m_forced = forced; + m_maxRoot = maxRoot; + m_outDir = outDir; + m_CompLevel = 1; + m_fastMerge = fastMerge; + + //check if a .Gate directory can be found + if (!getenv("GC_DOT_GATE_DIR")) { + cout<<"Environment variable GC_DOT_GATE_DIR not set !"<<endl; + exit(1); + } + m_dir=getenv("GC_DOT_GATE_DIR"); + if (m_dir.substr(m_dir.length()-1,m_dir.length())=="/") m_dir=m_dir+".Gate/"; + else m_dir=m_dir+"/.Gate/"; + ifstream dirstream(m_dir.c_str()); + if (!dirstream) { + cout<<"Failed to open .Gate directory"<<endl; + exit(1); + } + dirstream.close(); + + }; + ~GateMergeManager() + { + if (filearr) delete filearr; + } + + + void StartMerging(string splitfileName); + void ReadSplitFile(string splitfileName); + bool MergeTree(string name); + bool MergeGate(TChain* chain); + bool MergeSing(TChain* chain); + bool MergeCoin(TChain* chain); + + // the cleanup after succesful merging + void StartCleaning(string splitfileName,bool test); + + // the merging methods + void MergeRoot(); + +private: + void FastMergeRoot(); + bool FastMergeGate(string name); + bool FastMergeSing(string name); + bool FastMergeCoin(string name); + bool m_forced; // if to overwrite existing files + int m_verboseLevel; + TFile** filearr; + Long64_t m_maxRoot; // maximum size of root output file + int m_CompLevel; // compression level for root output + string m_dir; // .Gate directory path + string m_outDir; // where to save the output files + int m_Nfiles; // number of files to mergw + vector<int> m_lastEvents; // latestevent from al files + vector<string> m_vRootFileNames; // names of root files to merge + TFile* m_RootTarget; // root output file + string m_RootTargetName; // name of target i.e. root output file + bool m_fastMerge; // fast merge option, corrects the eventIDs locally +}; + + +#endif