1 /*----------------------
2 GATE version name: gate_v...
4 Copyright (C): OpenGATE Collaboration
6 This software is distributed under the terms
7 of the GNU Lesser General Public Licence (LGPL)
8 See GATE/LICENSE.txt for further details
9 ----------------------*/
17 #include <TIterator.h>
33 #include "GateMergeManager.hh"
37 void GateMergeManager::StartMerging(string splitfileName){
39 // get the files to merge
40 ReadSplitFile(splitfileName);
42 if (m_fastMerge==true) FastMergeRoot();
45 //if we are here the merging has been successful
46 //we mark the directory as ready for cleanup
47 //string dir = splitfileName.substr(0,splitfileName.rfind("/"));
48 //string ready = "touch "+dir+"/ready_for_delete";
49 //const int res=system(ready.c_str());
50 //if(res) cout<<"Strange?? Can't mark "<<dir<<" as done!"<<endl;
53 // to process the splitfile
54 void GateMergeManager::ReadSplitFile(string splitfileName){
57 splitfile.open(splitfileName.c_str());
59 cout<<"Can't open split file: "<<splitfileName<<endl;
63 //avoid multiple calls
64 if(m_vRootFileNames.size()>0) return;
66 stringstream ssnfiles;
68 while(splitfile){ //we allow for rubbish before "Number of files:"
69 splitfile.getline(cline,512);
70 if(!strncmp(cline,"Number of files:",16)){
71 ssnfiles.str(cline+16);
72 ssnfiles>>m_Nfiles; // the number of files to merge
77 // now we look for the file names
80 splitfile.getline(cline,512);
83 if(!strncmp(cline,"Root filename:",14)){
84 m_vRootFileNames.push_back(strtok(cline+15," "));
85 m_vRootFileNames[iRoot]+=".root";
86 if(m_verboseLevel>2) cout<<"Root input file name: "<<m_vRootFileNames[iRoot]<<endl;
90 else if(!strncmp(cline,"Original Root filename:",23)){
91 m_RootTargetName=strtok(cline+23," ");
92 m_RootTargetName+=".root";
93 if(m_outDir!=""){// output directory option used
94 //replace path with outDir
95 size_t pos=m_RootTargetName.rfind('/',m_RootTargetName.length());
96 if(pos==string::npos) pos=-1;
97 m_RootTargetName=m_outDir+m_RootTargetName.substr(pos+1);
99 if(m_verboseLevel>2) cout<<"Root output file name: "<<m_RootTargetName<<endl;
103 // check if number of root files correct
104 if(iRoot && iRoot!=m_Nfiles) {
105 cout<<"Inconsistent number of root file entries in split file!"<<endl;
110 /************************************************************************************/
111 void GateMergeManager::FastMergeRoot()
114 if(m_RootTargetName=="") {
115 cout<<"No root output file name given in split file"<<endl;
119 // number of files to merge
120 int nfiles=m_vRootFileNames.size();
122 cout<<"No files to merge!"<<endl;
125 //we try to recover the last_event_ID in all root files
126 for(int i=0;i<nfiles;i++) {
127 filearr.push_back(TFile::Open(m_vRootFileNames[i].c_str(),"OLD"));
128 if(filearr[i]==NULL){
129 cout<<"Not a readable file "<<m_vRootFileNames[i]<<" - exit!"<<endl;
133 m_lastEvents.resize(nfiles+1);
135 bool flgLstEvntID(false);
137 // latest_event_ID histogram
140 for(int i=0;i<nfiles;i++){
141 h = (TH1*)filearr[i]->Get("latest_event_ID");
142 m_lastEvents[i+1]=int(h->GetMean());
146 cout<<"FastMerge: No latest_event_ID histogram - exit!"<<endl;
150 /*for (int i=0;i<nfiles;i++)
152 cout<<"Last ID is: "<<m_lastEvents[i+1]<<" File " <<i+1<<endl;
156 vector<string> treeNames;
157 TFile* node = TFile::Open(m_vRootFileNames[0].c_str(),"OLD");
158 TIter nextkey(node->GetListOfKeys());
160 while ((key = (TKey*)nextkey()))
163 TObject* obj = (TObject*)key->ReadObj();
164 if( obj->IsA()->InheritsFrom("TTree"))
167 bool singleName=true;
168 for(unsigned int i=0;i<treeNames.size();i++)
170 if(treeNames[i].compare(obj->GetName())==0)
176 if(singleName) treeNames.push_back(obj->GetName());
179 //take care of all trees
180 for(unsigned int i=0;i<treeNames.size();i++)
182 if(!MergeTree(treeNames[i])) if(m_verboseLevel>1) cout<<"Problem with merging "<<treeNames[i]<<endl;
185 /************************************************************************************/
186 void GateMergeManager::MergeRoot(){
189 if(m_RootTargetName=="") {
190 cout<<"No root output file name given in split file"<<endl;
194 // number of files to merge
195 int nfiles=m_vRootFileNames.size();
197 // the root output file
199 m_RootTarget = TFile::Open(m_RootTargetName.c_str(),"RECREATE");
201 m_RootTarget = TFile::Open(m_RootTargetName.c_str(),"NEW");
203 cout<<"The root ouput file already exists! Try -f to overwrite and erase the file."<<endl;
209 cout<<"No files to merge!"<<endl;
213 TFile* filearr[nfiles];
214 for(int i=1;i<nfiles;i++) {
215 filearr[i] = TFile::Open(m_vRootFileNames[i].c_str(),"OLD");
216 if(filearr[i]==NULL){
217 cout<<"Not a readable file "<<m_vRootFileNames[i]<<" - exit!"<<endl;
222 // first we copy all histos (only top directory)
223 // and look for the latestEventID
224 // and find out which trees/ntuples exist
225 m_lastEvents.resize(nfiles+1);
228 bool flgLstEvntID(false);
230 if(m_verboseLevel>0) {
232 for(int i=0;i<nfiles;i++) cout<<m_vRootFileNames[i]<<" ";
233 cout<<"-> "<<m_RootTarget->GetName()<<endl;
236 vector<string> treeNames;
237 TFile* node = TFile::Open(m_vRootFileNames[0].c_str(),"OLD");
239 cout<<"Not a readable file "<<m_vRootFileNames[0]<<" - exit!"<<endl;
242 TIter nextkey(node->GetListOfKeys());
244 while ((key = (TKey*)nextkey())) {
246 TObject* obj = (TObject*)key->ReadObj();
247 if( obj->IsA()->InheritsFrom("TH1")){
249 TH1 *h1 = (TH1 *)obj->Clone();
250 if(strcmp(h1->GetName(),"latest_event_ID")){
251 //any other histogram
252 for(int i=1;i<nfiles;i++){
253 TH1 *h2 = (TH1*)filearr[i]->Get( h1->GetName() );
258 // latest_event_ID histogram
260 m_lastEvents[1]=int(h1->GetMean());
262 for(int i=1;i<nfiles;i++){
263 h = (TH1*)filearr[i]->Get("latest_event_ID");
264 m_lastEvents[i+1]=int(h->GetMean());
266 if(h!=NULL) h->Write(); // we keep the highest latest_event_ID to allow for successive merging
270 if( obj->IsA()->InheritsFrom("TH2")){
272 TH2 *h1 = (TH2 *)obj->Clone();
273 for(int i=1;i<nfiles;i++){
274 TH2 *h2 = (TH2*)filearr[i]->Get( h1->GetName() );
279 if( obj->IsA()->InheritsFrom("TTree")){
281 bool singleName=true;
282 for(unsigned int i=0;i<treeNames.size();i++) {
283 if(treeNames[i].compare(obj->GetName())==0){
288 if(singleName) treeNames.push_back(obj->GetName());
292 cout<<"Merge: No latest_event_ID histogram - exit!"<<endl;
296 //now we take care of the trees
297 for(unsigned int i=0;i<treeNames.size();i++)
298 if(!MergeTree(treeNames[i])) if(m_verboseLevel>1) cout<<"Problem with merging "<<treeNames[i]<<endl;
300 // everything is done
303 /*******************************************************************************************/
304 // cleanup after merging
305 void GateMergeManager::StartCleaning(string splitfileName,bool test){
307 // get the files to erase
308 ReadSplitFile(splitfileName);
310 string dir=splitfileName.substr(0,splitfileName.rfind("/"));
312 // test for the mark: ready_for_delete
313 string touched=dir+"/ready_for_delete";
315 ready.open(touched.c_str());
317 cout<<"Cannot do the cleanup - directory "<<dir<<" not marked as ready!"<<endl;
322 if(test) cout<<"I would like to erase:"<<endl;
323 if(!test&&m_verboseLevel>1) cout<<"Going to erase the following files:"<<endl;
324 if(m_verboseLevel>1||test){
325 cout<<" --> "<<dir<<endl;
327 for(unsigned int i=0;i<m_vRootFileNames.size();i++){
328 cout<<" --> "<<m_vRootFileNames[i]<<endl;
334 for(unsigned int i=0;i<m_vRootFileNames.size();i++){
335 const string rmfiles("rm -f "+m_vRootFileNames[i]);
336 const int res = system(rmfiles.c_str());
338 cout<<"Could not remove "<<m_vRootFileNames[i]<<endl;
339 cout<<"Please remove it manually!"<<endl;
342 const string rmfiles("rm -f "+dir+"/*");
343 system(rmfiles.c_str());
344 const string rmdir="rm -f -r "+dir;
345 const int res2 = system(rmdir.c_str());
347 cout<<"Could not remove "<<dir<<endl;
348 cout<<"Please remove it manually!"<<endl;
353 /*******************************************************************************************/
354 //find out what kind of tree we have and call the right merger
355 bool GateMergeManager::MergeTree(string chainName){
356 if (m_fastMerge==false)
358 TChain* chain = new TChain(chainName.c_str());
360 // number of files to merge
361 int nfiles=m_vRootFileNames.size();
363 for(int i=0;i<nfiles;i++) chain->Add(m_vRootFileNames[i].c_str());
364 int nentries=chain->GetEntries();
366 if(m_verboseLevel>1) cout<<chain->GetName()<<" is empty!"<<endl;
370 if(chainName=="Gate") MergeGate(chain);
372 if(chain->FindBranch("eventID1")!=NULL) {
373 if( (chain->FindBranch("runID")==NULL)
374 ||(chain->FindBranch("time1")==NULL)
375 ||(chain->FindBranch("time2")==NULL) ) {
376 cout<<"Cannot find one of: runID, time1, time2 in "<<chain->GetName()<<endl;
380 return MergeCoin(chain);
382 } else if( (chain->FindBranch("runID")==NULL)||(chain->FindBranch("eventID")==NULL)
383 ||(chain->FindBranch("time")==NULL) )
385 cout<<"Cannot find one of: runID, eventID, time in "<<chain->GetName()<<endl;
389 return MergeSing(chain);
393 if (chainName.find("Hits",0)!=string::npos) return FastMergeSing(chainName);
394 if (chainName.find("Singles",0)!=string::npos) return FastMergeSing(chainName);
395 if (chainName.find("Gate",0)!=string::npos) return FastMergeGate(chainName);
396 if (chainName.find("Coincidences",0)!=string::npos) return FastMergeCoin(chainName);
401 /*******************************************************************************************/
402 bool GateMergeManager::FastMergeGate(string name)
404 //create the output file
409 //float maxtime =-999999999;
410 string clusterName=name+"_cluster";
412 for(int j=0;j<m_Nfiles;j++)
414 filearr[j]->ReOpen("UPDATE");
415 TTree *oldTree = (TTree*)gDirectory->Get(name.c_str());
416 TBranch *branch = oldTree->GetBranch("event");
417 branch->SetAddress(&event);
418 TBranch* newBranch=oldTree->Branch("eventcluster",&event,"event");
420 Int_t nentries=(Int_t)oldTree->GetEntries();
423 else offset+=m_lastEvents[currentfile];
426 for(int i=0;i<nentries;i++)
437 if((i==nentries-1) && (j==m_Nfiles-1))
442 else if (i!=nentries-1)
457 /*******************************************************************************************/
458 bool GateMergeManager::FastMergeSing(string name)
465 string clusterName=name+"_cluster";
467 for(int j=0;j<m_Nfiles;j++)
469 filearr[j]->ReOpen("UPDATE");
470 TTree *oldTree = (TTree*)gDirectory->Get(name.c_str());
471 TBranch *branch = oldTree->GetBranch("eventID");
472 branch->SetAddress(&eventID);
473 TBranch *branch2 = oldTree->GetBranch("runID");
474 branch2->SetAddress(&runID);
475 TBranch* newBranch=oldTree->Branch("eventIDcluster",&eventID,"eventID/I");
477 Int_t nentries=(Int_t)oldTree->GetEntries();
480 else offset+=m_lastEvents[currentfile];
483 for(int i=0;i<nentries;i++)
499 /*******************************************************************************************/
500 bool GateMergeManager::FastMergeCoin(string name)
502 //create the output file
509 string clusterName=name+"_cluster";
510 cout<<"starting coincidence merging..."<<endl;
511 for(int j=0;j<m_Nfiles;j++)
513 cout<<"working on file..."<<j<<endl;
514 filearr[j]->ReOpen("UPDATE");
515 TTree *oldTree = (TTree*)gDirectory->Get(name.c_str());
516 TBranch *branch1 = oldTree->GetBranch("eventID1");
517 branch1->SetAddress(&eventID1);
518 TBranch *branch2 = oldTree->GetBranch("eventID2");
519 branch2->SetAddress(&eventID2);
520 TBranch *branch3 = oldTree->GetBranch("runID");
521 branch3->SetAddress(&runID);
523 TBranch* newBranch1=oldTree->Branch("eventID1cluster",&eventID1,"eventID1/I");
524 TBranch* newBranch2=oldTree->Branch("eventID2cluster",&eventID2,"eventID2/I");
526 Int_t nentries=(Int_t)oldTree->GetEntries();
529 else offset+=m_lastEvents[currentfile];
530 cout<<"the offset in this file is: "<<offset<<endl;
533 for(int i=0;i<nentries;i++){
534 branch1->GetEvent(i);
535 branch2->GetEvent(i);
536 branch3->GetEvent(i);
552 /*******************************************************************************************/
554 bool GateMergeManager::MergeGate(TChain* chainG) {
556 int nentries=chainG->GetEntries();
559 chainG->SetBranchAddress("event",&event);
561 chainG->SetBranchAddress("iontime",&iontime);
563 //create the new tree
564 //Allow for large files and do not write every bit separately
566 TTree * newTree = chainG->CloneTree(0);
567 newTree->SetAutoSave(2000000000);
568 if(m_maxRoot!=0) newTree->SetMaxTreeSize(m_maxRoot);
569 else newTree->SetMaxTreeSize(17179869184LL);
571 // changing the compression level everywhere
573 TIter next(newTree->GetListOfBranches());
574 while ((br=(TBranch*)next())) br->SetCompressionLevel(m_CompLevel);
576 // the main part: modify the eventID
580 float maxtime =-999999999;
581 for(int i=0;i<nentries;i++){
582 if (chainG->GetEntry(i) <= 0) break; //end of chain
583 if(chainG->GetTreeNumber()>currentTree) {
585 offset+=m_lastEvents[currentTree];
586 // check for overlaping time intervalls between different files
587 // (not within the same file i.e. no time order assumed)
590 cout<<"Warning - overlapping Gate iontime ("
591 <<iontime<<") in file: "<<m_vRootFileNames[currentTree].c_str()<<endl;
593 // run end is marked by repeating event
594 if(lastEvent!=event) {
596 // if (fpclassify(iontime)!=FP_NAN && fpclassify(iontime)!=FP_INFINITE) {
598 if(maxtime<iontime) maxtime=iontime;
599 // the offset to get a unique event numbering
603 cout<<"Warning - inf or NaN in Gate tree for iontime! "<<m_vRootFileNames[currentTree].c_str()<<endl;
609 if(chainG->GetEntry(i+1) <= 0) { //chain end fill the double event
612 } else if(chainG->GetTreeNumber()==currentTree //no new file or
613 ||(chainG->GetTreeNumber()>currentTree
614 &&m_lastEvents[chainG->GetTreeNumber()]==0) ) { //new file with no offset fill double event
618 lastEvent=0;// we may have triple 1 (1 event run)
628 /*******************************************************************************************/
629 // Singles and Hits tree merger
630 bool GateMergeManager::MergeSing(TChain* chainS){
632 int nentriesS=chainS->GetEntries();
638 chainS->SetBranchAddress("eventID",&eventID);
639 chainS->SetBranchAddress("runID",&runID);
640 chainS->SetBranchAddress("time",&time);
643 TTree * newSing = chainS->CloneTree(0);
644 newSing->SetAutoSave(2000000000);
645 if(m_maxRoot!=0) newSing->SetMaxTreeSize(m_maxRoot);
646 else newSing->SetMaxTreeSize(17179869184LL);
648 // changing CompLevel everywhere
650 TIter next(newSing->GetListOfBranches());
651 while ((br=(TBranch*)next())) br->SetCompressionLevel(m_CompLevel);
653 //the main part: changing eventID
657 float maxtime =-999999999;
658 for(int i=0;i<nentriesS;i++){
659 if(chainS->GetEntry(i) <= 0) break; //end of chain
660 if(chainS->GetTreeNumber()>currentTree) {
662 offset+=m_lastEvents[currentTree];
663 // check for overlaping time intervalls between different files
664 // (not within the same file i.e. no time order assumed)
667 cout<<"Warning - overlapping Singles time ("
668 <<time<<") in file: "<<m_vRootFileNames[currentTree].c_str()<<endl;
670 // the offset to get a unique event numbering
674 offset=0; //new run in file we must not change the eventID anymore
678 if(maxtime<time)maxtime=time;
685 /*******************************************************************************************/
686 // Coincidences tree merger
687 bool GateMergeManager::MergeCoin(TChain* chainC){
689 int nentriesC=chainC->GetEntries();
692 chainC->SetBranchAddress("eventID1",&eventID1);
694 chainC->SetBranchAddress("time1",&time1);
696 chainC->SetBranchAddress("eventID2",&eventID2);
698 chainC->SetBranchAddress("time2",&time2);
700 chainC->SetBranchAddress("runID",&runID);
703 TTree * newCoin = chainC->CloneTree(0);
704 newCoin->SetAutoSave(2000000000);
705 if(m_maxRoot!=0) newCoin->SetMaxTreeSize(m_maxRoot);
706 else newCoin->SetMaxTreeSize(17179869184LL);
708 // changing CompLevel everywhere
710 TIter next(newCoin->GetListOfBranches());
711 while ((br=(TBranch*)next())) br->SetCompressionLevel(m_CompLevel);
716 float maxtime =-999999999;
717 for(int i=0;i<nentriesC;i++){
718 if(chainC->GetEntry(i) <= 0) break; //end of chain
719 if(chainC->GetTreeNumber()>currentTree) {
721 offset+=m_lastEvents[currentTree];
722 // check for overlaping time intervalls between different files
723 // (not within the same file i.e. no time order assumed)
726 cout<<"Warning - overlapping Coincidences time1 ("
727 <<time1<<") in file: "<<m_vRootFileNames[currentTree].c_str()<<endl;
730 cout<<"Warning - overlapping Coincidences time2 ("
731 <<time2<<") in file: "<<m_vRootFileNames[currentTree].c_str()<<endl;
733 // the offset to get a unique event numbering
737 offset=0; //new run in file we must not change the eventID anymore
742 if(maxtime<time1)maxtime=time1;
743 if(maxtime<time2)maxtime=time2;
749 /*******************************************************************************************/