]> Creatis software - clitk.git/blob - tools/GateMergeManager.cc
Set the Root Tree maximum size to 1TB instead of 1GB
[clitk.git] / tools / GateMergeManager.cc
1 /*----------------------
2    GATE version name: gate_v...
3
4    Copyright (C): OpenGATE Collaboration
5
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 ----------------------*/
10
11
12 #include <TROOT.h>
13 #include <TFile.h>
14 #include <TChain.h>
15 #include <TTree.h>
16 #include <TBranch.h>
17 #include <TIterator.h>
18 #include <TObject.h>
19 #include <TKey.h>
20 #include <TH1.h>
21 #include <TH2.h>
22
23 #include <iostream>
24 #include <fstream>
25 #include <string>
26 #include <glob.h>
27 #include <ctype.h>
28 #include <sstream>
29 #include <vector>
30 #include <cstdlib>
31 #include <cmath>
32 #include <list>
33
34 #include "GateMergeManager.hh"
35
36 using namespace std;
37
38 void GateMergeManager::StartMerging(string splitfileName){
39
40   // get the files to merge
41   ReadSplitFile(splitfileName);
42   //do the merging
43   if (m_fastMerge==true) FastMergeRoot();
44   else MergeRoot();
45
46   //if we are here the merging has been successful
47   //we mark the directory as ready for cleanup
48   //string dir   = splitfileName.substr(0,splitfileName.rfind("/"));
49   //string ready = "touch "+dir+"/ready_for_delete";
50   //const int res=system(ready.c_str());
51   //if(res) cout<<"Strange?? Can't mark "<<dir<<" as done!"<<endl;
52 };
53
54 void GateMergeManager::StartMergingFromFilenames(Strings filenames, string outputfile)
55 {
56         for (Strings::const_iterator iter=filenames.begin(); iter!=filenames.end(); iter++)
57         {
58                 m_vRootFileNames.push_back(*iter);
59                 if(m_verboseLevel>2) cout<<"Root input file name: "<<m_vRootFileNames.back()<<endl;
60         }
61
62         m_Nfiles = m_vRootFileNames.size();
63         m_RootTargetName=m_outDir+outputfile;
64         if(m_verboseLevel>2) cout<<"Root output file name: "<<m_RootTargetName<<endl;
65
66         if (m_fastMerge==true) FastMergeRoot();
67         else MergeRoot();
68 };
69
70 // to process the splitfile
71 void GateMergeManager::ReadSplitFile(string splitfileName){
72
73   ifstream splitfile;
74   splitfile.open(splitfileName.c_str());
75   if(!splitfile){
76      cout<<"Can't open split file: "<<splitfileName<<endl;
77      exit(0);
78   };
79
80   //avoid multiple calls
81   if(m_vRootFileNames.size()>0) return;
82
83   stringstream ssnfiles;
84   char cline[512];
85   while(splitfile){               //we allow for rubbish before "Number of files:"
86      splitfile.getline(cline,512);
87      if(!strncmp(cline,"Number of files:",16)){
88          ssnfiles.str(cline+16);
89          ssnfiles>>m_Nfiles;      // the number of files to merge
90          break;
91      }
92   }
93
94   // now we look for the file names
95   int iRoot=0;
96   while(splitfile){
97      splitfile.getline(cline,512);
98      // check for root
99      // input files
100      if(!strncmp(cline,"Root filename:",14)){
101         m_vRootFileNames.push_back(strtok(cline+15," "));
102         m_vRootFileNames[iRoot]+=".root";
103         if(m_verboseLevel>2) cout<<"Root input file name: "<<m_vRootFileNames[iRoot]<<endl;
104         iRoot++;
105      }
106      // output file
107      else if(!strncmp(cline,"Original Root filename:",23)){
108         m_RootTargetName=strtok(cline+23," ");
109         m_RootTargetName+=".root";
110         if(m_outDir!=""){// output directory option used
111            //replace path with outDir
112            size_t pos=m_RootTargetName.rfind('/',m_RootTargetName.length());
113            if(pos==string::npos) pos=-1;
114            m_RootTargetName=m_outDir+m_RootTargetName.substr(pos+1);
115         }
116         if(m_verboseLevel>2) cout<<"Root output file name: "<<m_RootTargetName<<endl;
117      }
118   }
119
120   // check if number of root files correct
121   if(iRoot && iRoot!=m_Nfiles) {
122        cout<<"Inconsistent number of root file entries in split file!"<<endl;
123        exit(0);
124   }
125 }
126
127 /************************************************************************************/
128 void GateMergeManager::FastMergeRoot()
129 {
130    //check target name
131    if(m_RootTargetName=="") {
132       cout<<"No root output file name given in split file"<<endl;
133       exit(0);
134    }
135
136    // number of files to merge
137    int nfiles=m_vRootFileNames.size();
138    if(nfiles<1){
139       cout<<"No files to merge!"<<endl;
140       exit(0);
141    }
142    //we try to recover the last_event_ID in all root files
143    for(int i=0;i<nfiles;i++) {
144       filearr.push_back(TFile::Open(m_vRootFileNames[i].c_str(),"OLD"));
145       if(filearr[i]==NULL){
146          cout<<"Not a readable file "<<m_vRootFileNames[i]<<" - exit!"<<endl;   
147          exit(0);
148       }
149    }  
150    m_lastEvents.resize(nfiles+1);
151    m_lastEvents[0]=0;
152    bool flgLstEvntID(false);
153
154    // latest_event_ID histogram
155    flgLstEvntID=true;
156    TH1* h=NULL;
157    for(int i=0;i<nfiles;i++){
158      h = (TH1*)filearr[i]->Get("latest_event_ID");
159      m_lastEvents[i+1]=int(h->GetMean());
160      }
161
162    if(!flgLstEvntID) {
163       cout<<"FastMerge: No latest_event_ID histogram - exit!"<<endl;
164       exit(0);
165    }
166
167  /*for (int i=0;i<nfiles;i++)
168   {
169    cout<<"Last ID is: "<<m_lastEvents[i+1]<<" File " <<i+1<<endl;
170   }*/
171
172    //find all trees
173    vector<string> treeNames;
174    TFile* node = TFile::Open(m_vRootFileNames[0].c_str(),"OLD");
175    TIter nextkey(node->GetListOfKeys());
176    TKey *key=0;
177    while ((key = (TKey*)nextkey()))
178    {
179      node->cd();
180      TObject* obj = (TObject*)key->ReadObj();
181      if(  obj->IsA()->InheritsFrom("TTree"))
182      {
183        //no doubles
184        bool singleName=true;
185        for(unsigned int i=0;i<treeNames.size();i++)
186        {
187          if(treeNames[i].compare(obj->GetName())==0)
188          {
189            singleName=false;
190            break;
191          }
192        }
193        if(singleName) treeNames.push_back(obj->GetName());
194      }
195    }
196    //take care of all trees
197    for(unsigned int i=0;i<treeNames.size();i++) 
198    {
199      if(!MergeTree(treeNames[i])) if(m_verboseLevel>1) cout<<"Problem with merging "<<treeNames[i]<<endl; 
200    }
201 }
202 /************************************************************************************/
203 void GateMergeManager::MergeRoot(){
204
205    //check target name
206    if(m_RootTargetName=="") {
207       cout<<"No root output file name given in split file"<<endl;
208       exit(0);
209    }
210
211    // number of files to merge
212    int nfiles=m_vRootFileNames.size();
213
214    // the root output file
215    if(m_forced) {
216       m_RootTarget = TFile::Open(m_RootTargetName.c_str(),"RECREATE");
217    } else {
218       m_RootTarget = TFile::Open(m_RootTargetName.c_str(),"NEW");
219       if(!m_RootTarget){
220           cout<<"The root ouput file already exists! Try -f to overwrite and erase the file."<<endl;
221           exit(0);
222       }
223    }
224
225    if(nfiles<1){
226       cout<<"No files to merge!"<<endl;
227       exit(0);
228    }
229
230    TFile* filearr[nfiles];
231    for(int i=1;i<nfiles;i++) {
232       filearr[i] = TFile::Open(m_vRootFileNames[i].c_str(),"OLD");
233       if(filearr[i]==NULL){
234          cout<<"Not a readable file "<<m_vRootFileNames[i]<<" - exit!"<<endl;   
235          exit(0);
236       }
237    }
238
239 // first we copy all histos (only top directory) 
240 // and look for the latestEventID
241 // and find out which  trees/ntuples  exist
242    m_lastEvents.resize(nfiles+1);
243        m_lastEvents[0]=0;
244
245    bool flgLstEvntID(false);
246
247    if(m_verboseLevel>0) {
248       cout<<"Combining: ";
249       for(int i=0;i<nfiles;i++) cout<<m_vRootFileNames[i]<<" ";
250       cout<<"-> "<<m_RootTarget->GetName()<<endl;
251    }
252
253    vector<string> treeNames;
254    TFile* node = TFile::Open(m_vRootFileNames[0].c_str(),"OLD");
255    if(node==NULL){
256        cout<<"Not a readable file "<<m_vRootFileNames[0]<<" - exit!"<<endl;   
257        exit(0);
258    }
259         TIter nextkey(node->GetListOfKeys());
260         TKey *key=0;
261         while ((key = (TKey*)nextkey())) {
262           node->cd();
263           TObject* obj = (TObject*)key->ReadObj();
264           if(  obj->IsA()->InheritsFrom("TH1")){
265              m_RootTarget->cd();
266              TH1 *h1 = (TH1 *)obj->Clone();
267              if(strcmp(h1->GetName(),"latest_event_ID")){
268                      //any other histogram
269                      for(int i=1;i<nfiles;i++){
270                           TH1 *h2 = (TH1*)filearr[i]->Get( h1->GetName() );
271                           h1->Add( h2 ); 
272                      }
273                      h1->Write();
274              } else {
275                           // latest_event_ID histogram
276                           flgLstEvntID=true;
277                           m_lastEvents[1]=int(h1->GetMean());
278                           TH1* h=NULL;
279                           for(int i=1;i<nfiles;i++){
280                                   h = (TH1*)filearr[i]->Get("latest_event_ID");
281                                   m_lastEvents[i+1]=int(h->GetMean());
282                           }
283                           if(h!=NULL) h->Write(); // we keep the highest latest_event_ID to allow for successive merging
284                           else h1->Write();
285               }
286          }
287          if(  obj->IsA()->InheritsFrom("TH2")){
288            m_RootTarget->cd();
289            TH2 *h1 = (TH2 *)obj->Clone();
290                         for(int i=1;i<nfiles;i++){
291                                 TH2 *h2 = (TH2*)filearr[i]->Get( h1->GetName() );
292                                 h1->Add( h2 ); 
293                         }
294                         h1->Write();
295                 }
296          if(  obj->IsA()->InheritsFrom("TTree")){
297            //no doubles
298            bool singleName=true;
299            for(unsigned int i=0;i<treeNames.size();i++) {
300               if(treeNames[i].compare(obj->GetName())==0){
301                  singleName=false;
302                  break;
303               }
304            }
305            if(singleName) treeNames.push_back(obj->GetName());
306          }
307    }
308    if(!flgLstEvntID) {
309       cout<<"Merge: No latest_event_ID histogram - exit!"<<endl;
310       exit(0);
311    }
312
313    //now we take care of the trees
314    for(unsigned int i=0;i<treeNames.size();i++) 
315      if(!MergeTree(treeNames[i])) if(m_verboseLevel>1) cout<<"Problem with merging "<<treeNames[i]<<endl; 
316
317    // everything is done
318 };
319
320 /*******************************************************************************************/
321 // cleanup after merging
322 void GateMergeManager::StartCleaning(string splitfileName,bool test){
323
324   // get the files to erase
325   ReadSplitFile(splitfileName);
326
327   string dir=splitfileName.substr(0,splitfileName.rfind("/"));
328
329   // test for the mark: ready_for_delete 
330   string touched=dir+"/ready_for_delete";
331   ifstream ready;
332   ready.open(touched.c_str());
333   if (!ready) {
334      cout<<"Cannot do the cleanup - directory "<<dir<<" not marked as ready!"<<endl;
335      if(!test) exit(0);
336   }
337
338   // print info
339   if(test)                    cout<<"I would like to erase:"<<endl;
340   if(!test&&m_verboseLevel>1) cout<<"Going to erase the following files:"<<endl;
341   if(m_verboseLevel>1||test){
342      cout<<" --> "<<dir<<endl;
343      // root
344      for(unsigned int i=0;i<m_vRootFileNames.size();i++){
345         cout<<" --> "<<m_vRootFileNames[i]<<endl;
346      }
347   }
348
349   // erase!
350   if(!test){
351      for(unsigned int i=0;i<m_vRootFileNames.size();i++){
352         const string rmfiles("rm -f "+m_vRootFileNames[i]);
353         const int res = system(rmfiles.c_str());
354         if(res) {
355                cout<<"Could not remove "<<m_vRootFileNames[i]<<endl;
356                cout<<"Please remove it manually!"<<endl;
357         }
358      }
359      const string rmfiles("rm -f "+dir+"/*");
360      system(rmfiles.c_str());
361      const string rmdir="rm -f -r "+dir;
362      const int res2 = system(rmdir.c_str());
363      if(res2) {
364             cout<<"Could not remove "<<dir<<endl;
365             cout<<"Please remove it manually!"<<endl;
366      }
367   }
368 }
369
370 /*******************************************************************************************/
371 //find out what kind of tree we have and call the right merger
372 bool GateMergeManager::MergeTree(string chainName){
373 if (m_fastMerge==false)
374  {
375    TChain* chain = new TChain(chainName.c_str());
376
377    // number of files to merge
378    int nfiles=m_vRootFileNames.size();
379
380    for(int i=0;i<nfiles;i++) chain->Add(m_vRootFileNames[i].c_str());
381    int nentries=chain->GetEntries();
382    if(nentries<=0) {
383       if(m_verboseLevel>1) cout<<chain->GetName()<<" is empty!"<<endl;
384       return false;
385    }
386
387    if(chainName=="Gate") MergeGate(chain);
388
389    if(chain->FindBranch("eventID1")!=NULL) {
390      if(  (chain->FindBranch("runID")==NULL)
391         ||(chain->FindBranch("time1")==NULL) 
392         ||(chain->FindBranch("time2")==NULL) ) {
393         cout<<"Cannot find one of:  runID, time1, time2 in "<<chain->GetName()<<endl;
394         return false;
395      }
396      // coincidence
397      return MergeCoin(chain);
398
399    } else if(  (chain->FindBranch("runID")==NULL)||(chain->FindBranch("eventID")==NULL)
400                                                   ||(chain->FindBranch("time")==NULL) )
401             {
402              cout<<"Cannot find one of: runID, eventID, time in "<<chain->GetName()<<endl;
403              return false;
404             }
405            // Singles or Hits
406            return MergeSing(chain);
407    }
408    else
409    {
410      if (chainName.find("Hits",0)!=string::npos) return FastMergeSing(chainName);
411      if (chainName.find("Singles",0)!=string::npos) return FastMergeSing(chainName);
412      if (chainName.find("Gate",0)!=string::npos) return FastMergeGate(chainName);
413      if (chainName.find("Coincidences",0)!=string::npos) return FastMergeCoin(chainName);
414    }
415    return 0;
416 }
417
418 /*******************************************************************************************/
419 bool GateMergeManager::FastMergeGate(string name)
420 {
421 //create the output file
422 float   event   = 0;
423 int offset      = 0;
424 int currentfile = 0;
425 float lastEvent =-1;
426 //float maxtime   =-999999999;
427 string clusterName=name+"_cluster";
428
429 for(int j=0;j<m_Nfiles;j++)
430  {
431    filearr[j]->ReOpen("UPDATE");
432    TTree *oldTree = (TTree*)gDirectory->Get(name.c_str());
433    TBranch *branch  = oldTree->GetBranch("event");
434    branch->SetAddress(&event);
435    TBranch* newBranch=oldTree->Branch("eventcluster",&event,"event");
436
437    Int_t nentries=(Int_t)oldTree->GetEntries();
438
439    if (j==0) offset=0;
440    else offset+=m_lastEvents[currentfile];
441    currentfile++;
442
443    for(int i=0;i<nentries;i++)
444       {
445        branch->GetEvent(i);
446        if(lastEvent!=event)
447         {
448          lastEvent=event;
449          event+=offset;
450          newBranch->Fill();
451         } 
452        else
453         {
454          if((i==nentries-1) && (j==m_Nfiles-1))
455           {
456            event+=offset;
457            newBranch->Fill();
458           }
459          else if (i!=nentries-1) 
460               { 
461                branch->GetEvent(i);
462                event+=offset;
463                newBranch->Fill();
464                lastEvent=0;
465                offset=0;
466               }
467         }
468       }
469     oldTree->Write();
470  }
471  return true;
472 }
473
474 /*******************************************************************************************/
475 bool GateMergeManager::FastMergeSing(string name)
476 {
477 int eventID = 0;
478 int runID = 0; 
479 int offset      = 0;
480 int currentfile = 0;
481 float lastRun =-1;
482 string clusterName=name+"_cluster"; 
483
484 for(int j=0;j<m_Nfiles;j++)
485  {
486    filearr[j]->ReOpen("UPDATE");
487    TTree *oldTree = (TTree*)gDirectory->Get(name.c_str());
488    TBranch *branch  = oldTree->GetBranch("eventID");
489    branch->SetAddress(&eventID);
490    TBranch *branch2  = oldTree->GetBranch("runID");
491    branch2->SetAddress(&runID);
492    TBranch* newBranch=oldTree->Branch("eventIDcluster",&eventID,"eventID/I");
493
494    Int_t nentries=(Int_t)oldTree->GetEntries();
495
496    if (j==0) offset=0;
497    else offset+=m_lastEvents[currentfile];
498    currentfile++;
499
500    for(int i=0;i<nentries;i++)
501      {
502       branch->GetEvent(i);
503       if(lastRun!=runID)
504         {
505          lastRun=runID;
506          offset=0;
507         }
508       eventID+=offset;
509       newBranch->Fill();
510     }
511   oldTree->Write();
512   }
513   return true;
514 }
515
516 /*******************************************************************************************/
517 bool GateMergeManager::FastMergeCoin(string name)
518 {
519 //create the output file
520 int eventID1 = 0;
521 int eventID2 = 0;
522 int runID = 0;
523 int offset      = 0;
524 int currentfile = 0;
525 float lastRun =-1;
526 string clusterName=name+"_cluster";
527 cout<<"starting coincidence merging..."<<endl;
528 for(int j=0;j<m_Nfiles;j++)
529  {
530 cout<<"working on file..."<<j<<endl;
531    filearr[j]->ReOpen("UPDATE");
532    TTree *oldTree = (TTree*)gDirectory->Get(name.c_str());
533    TBranch *branch1  = oldTree->GetBranch("eventID1");
534    branch1->SetAddress(&eventID1);
535    TBranch *branch2  = oldTree->GetBranch("eventID2");
536    branch2->SetAddress(&eventID2);
537    TBranch *branch3  = oldTree->GetBranch("runID");
538    branch3->SetAddress(&runID);
539
540    TBranch* newBranch1=oldTree->Branch("eventID1cluster",&eventID1,"eventID1/I");
541    TBranch* newBranch2=oldTree->Branch("eventID2cluster",&eventID2,"eventID2/I");
542
543    Int_t nentries=(Int_t)oldTree->GetEntries();
544
545    if (j==0) offset=0;
546    else offset+=m_lastEvents[currentfile];
547    cout<<"the offset in this file is: "<<offset<<endl;
548    currentfile++;
549
550    for(int i=0;i<nentries;i++){
551        branch1->GetEvent(i);
552        branch2->GetEvent(i);
553        branch3->GetEvent(i);
554        if(lastRun!=runID) 
555         {
556          lastRun=runID;
557          offset=0; 
558         }
559        eventID1+=offset;
560        eventID2+=offset;
561        newBranch1->Fill();
562        newBranch2->Fill();
563     }
564     oldTree->Write();
565  }
566     return true;
567 }
568
569 /*******************************************************************************************/
570 // Gate tree merger
571 bool GateMergeManager::MergeGate(TChain* chainG) {
572
573    int nentries=chainG->GetEntries();   
574
575    float   event   = 0;
576    chainG->SetBranchAddress("event",&event);
577    Float_t iontime = 0;
578    chainG->SetBranchAddress("iontime",&iontime);
579
580    //create the new tree
581    //Allow for large files and do not write every bit separately
582    m_RootTarget->cd();
583    TTree * newTree = chainG->CloneTree(0);
584    newTree->SetAutoSave(2000000000);
585    if(m_maxRoot!=0) newTree->SetMaxTreeSize(m_maxRoot);
586    else newTree->SetMaxTreeSize(17179869184LL);
587
588    // changing the compression level everywhere
589    TBranch *br;
590    TIter next(newTree->GetListOfBranches());
591    while ((br=(TBranch*)next())) br->SetCompressionLevel(m_CompLevel);
592
593    // the main part: modify the eventID
594    int offset      = 0;
595    int currentTree = 0;
596    float lastEvent =-1;
597    float maxtime   =-999999999;
598    for(int i=0;i<nentries;i++){
599        if (chainG->GetEntry(i) <= 0) break; //end of chain
600        if(chainG->GetTreeNumber()>currentTree) {
601            currentTree++;
602            offset+=m_lastEvents[currentTree];
603            // check for overlaping time intervalls between different files
604            // (not within the same file i.e. no time order assumed)
605            if(iontime<maxtime)
606               if(m_verboseLevel>0) 
607                  cout<<"Warning - overlapping Gate iontime ("
608                      <<iontime<<") in file: "<<m_vRootFileNames[currentTree].c_str()<<endl;
609        }
610        // run end is marked by repeating event
611        if(lastEvent!=event) {
612            lastEvent=event;
613 //           if (fpclassify(iontime)!=FP_NAN && fpclassify(iontime)!=FP_INFINITE) {
614            if(finite(iontime)){
615              if(maxtime<iontime) maxtime=iontime;
616              // the offset to get a unique event numbering
617              event+=offset;
618              newTree->Fill();
619            } else {
620              cout<<"Warning - inf or NaN in Gate tree for iontime! "<<m_vRootFileNames[currentTree].c_str()<<endl;
621              //we are lost anyhow
622              maxtime   =-999999999;
623            }
624         } else {
625            // run end 
626            if(chainG->GetEntry(i+1) <= 0)  {              //chain end fill the double event 
627               event+=offset;
628               newTree->Fill();
629            } else if(chainG->GetTreeNumber()==currentTree             //no new file or
630                     ||(chainG->GetTreeNumber()>currentTree
631                        &&m_lastEvents[chainG->GetTreeNumber()]==0) ) { //new file with no offset fill double event
632               chainG->GetEntry(i);
633               event+=offset;
634               newTree->Fill();
635               lastEvent=0;// we may have triple 1 (1 event run)
636               offset=0;
637            }
638         }
639       }
640       newTree->Write();
641       delete newTree;
642       return true;
643 }
644
645 /*******************************************************************************************/
646 // Singles and Hits tree merger
647 bool GateMergeManager::MergeSing(TChain* chainS){
648
649    int nentriesS=chainS->GetEntries();
650
651    int eventID = 0;
652    int runID   = 0;
653    double time = 0;
654
655    chainS->SetBranchAddress("eventID",&eventID);
656    chainS->SetBranchAddress("runID",&runID);
657    chainS->SetBranchAddress("time",&time);
658
659    m_RootTarget->cd();
660    TTree * newSing = chainS->CloneTree(0);
661    newSing->SetAutoSave(2000000000);
662    if(m_maxRoot!=0) newSing->SetMaxTreeSize(m_maxRoot);
663    else newSing->SetMaxTreeSize(17179869184LL);
664
665    // changing CompLevel everywhere
666    TBranch *br;
667    TIter next(newSing->GetListOfBranches());
668    while ((br=(TBranch*)next())) br->SetCompressionLevel(m_CompLevel);
669
670    //the main part: changing eventID
671    int offset      = 0;
672    int currentTree = 0;
673    float lastRun   = 0;
674    float maxtime   =-999999999;
675    for(int i=0;i<nentriesS;i++){
676          if(chainS->GetEntry(i) <= 0) break; //end of chain
677          if(chainS->GetTreeNumber()>currentTree) {
678            currentTree++;
679             offset+=m_lastEvents[currentTree];
680            // check for overlaping time intervalls between different files
681            // (not within the same file i.e. no time order assumed)
682            if(time<maxtime) 
683                if(m_verboseLevel>0) 
684                   cout<<"Warning - overlapping Singles time ("
685                       <<time<<") in file: "<<m_vRootFileNames[currentTree].c_str()<<endl;
686          }
687          // the offset to get a unique event numbering
688          if(lastRun!=runID) {
689             // run end 
690             lastRun=runID;
691             offset=0;     //new run in file we must not change the eventID anymore
692          }
693          eventID+=offset;
694          newSing->Fill();
695          if(maxtime<time)maxtime=time;
696     }
697     newSing->Write();
698     delete newSing;
699     return true;
700 };
701
702 /*******************************************************************************************/
703 // Coincidences tree merger
704 bool GateMergeManager::MergeCoin(TChain* chainC){
705
706    int nentriesC=chainC->GetEntries();
707
708     int eventID1 = 0;
709     chainC->SetBranchAddress("eventID1",&eventID1);
710     double time1 = 0;
711     chainC->SetBranchAddress("time1",&time1);
712     int eventID2 = 0;
713     chainC->SetBranchAddress("eventID2",&eventID2);
714     double time2 = 0;
715     chainC->SetBranchAddress("time2",&time2);
716     int runID    = 0;
717     chainC->SetBranchAddress("runID",&runID);
718
719     m_RootTarget->cd();
720     TTree * newCoin = chainC->CloneTree(0);
721     newCoin->SetAutoSave(2000000000);
722     if(m_maxRoot!=0) newCoin->SetMaxTreeSize(m_maxRoot);
723     else newCoin->SetMaxTreeSize(17179869184LL);
724
725     // changing CompLevel everywhere
726     TBranch *br;
727     TIter next(newCoin->GetListOfBranches());
728     while ((br=(TBranch*)next())) br->SetCompressionLevel(m_CompLevel);
729
730     int offset      = 0;
731     int currentTree = 0;
732     float lastRun   = 0;
733     float maxtime   =-999999999;
734     for(int i=0;i<nentriesC;i++){
735        if(chainC->GetEntry(i) <= 0) break; //end of chain
736        if(chainC->GetTreeNumber()>currentTree) {
737          currentTree++;
738          offset+=m_lastEvents[currentTree];
739          // check for overlaping time intervalls between different files
740          // (not within the same file i.e. no time order assumed)
741          if(time1<maxtime) 
742            if(m_verboseLevel>0)
743                cout<<"Warning - overlapping Coincidences time1 ("
744                    <<time1<<") in file: "<<m_vRootFileNames[currentTree].c_str()<<endl;
745          if(time2<maxtime) 
746            if(m_verboseLevel>0)
747                cout<<"Warning - overlapping Coincidences time2 ("
748                    <<time2<<") in file: "<<m_vRootFileNames[currentTree].c_str()<<endl;
749        }
750        // the offset to get a unique event numbering
751        if(lastRun!=runID) {
752           // run end
753           lastRun=runID;
754           offset=0; //new run in file we must not change the eventID anymore
755        }
756        eventID1+=offset;
757        eventID2+=offset;
758        newCoin->Fill();
759        if(maxtime<time1)maxtime=time1;
760        if(maxtime<time2)maxtime=time2;
761     }
762     newCoin->Write();
763     delete newCoin;
764     return true;
765 }
766 /*******************************************************************************************/