ViewVC Help
View File | Revision Log | Show Annotations | Root Listing
root/cvsroot/UserCode/MitAna/TreeMod/src/OutputMod.cc
Revision: 1.19
Committed: Fri Mar 11 04:03:54 2011 UTC (14 years, 1 month ago) by bendavid
Content type: text/plain
Branch: MAIN
CVS Tags: Mit_025c_branch2, Mit_025c_branch1, Mit_025c_branch0, Mit_025d, Mit_025c, Mit_025b, Mit_025a, Mit_025, Mit_025pre2, Mit_024b, Mit_025pre1, Mit_024a, Mit_024, Mit_023, Mit_022a, Mit_022, Mit_020d, TMit_020d, Mit_020c, Mit_021, Mit_021pre2, Mit_021pre1, Mit_020b, Mit_020a, Mit_020, Mit_020pre1
Branch point for: Mit_025c_branch
Changes since 1.18: +4 -4 lines
Log Message:
various minor changes to acommodate new root and architecture

File Contents

# Content
1 // $Id: OutputMod.cc,v 1.18 2009/12/14 20:19:15 loizides Exp $
2
3 #include "MitAna/TreeMod/interface/OutputMod.h"
4 #include "MitAna/TreeMod/interface/HLTFwkMod.h"
5 #include "MitAna/DataUtil/interface/Debug.h"
6 #include "MitAna/DataTree/interface/BranchTable.h"
7 #include "MitAna/DataTree/interface/EventHeaderCol.h"
8 #include "MitAna/DataTree/interface/Names.h"
9 #include "MitAna/DataUtil/interface/TreeWriter.h"
10 #include "MitAna/TreeMod/interface/TreeBranchLoader.h"
11
12 using namespace mithep;
13 using namespace std;
14
15 ClassImp(mithep::OutputMod)
16
17 //--------------------------------------------------------------------------------------------------
18 OutputMod::OutputMod(const char *name, const char *title) :
19 BaseMod(name,title),
20 fTreeName(Names::gkEvtTreeName),
21 fPrefix("skimtest"),
22 fPathName("."),
23 fMaxSize(1024),
24 fCompLevel(9),
25 fSplitLevel(99),
26 fBranchSize(16*1024),
27 fDoReset(kFALSE),
28 fCheckBrDep(kTRUE),
29 fUseBrDep(kTRUE),
30 fCheckTamBr(kTRUE),
31 fKeepTamBr(kFALSE),
32 fTreeWriter(0),
33 fEventHeader(0),
34 fAllEventHeader(0),
35 fRunInfo(0),
36 fLaHeader(0),
37 fBranchTable(0),
38 fBranches(0),
39 fNBranchesMax(1024),
40 fRunTree(0),
41 fLATree(0),
42 fAllTree(0),
43 fSkimmedIn(0),
44 fHltTree(0),
45 fHLTTab(new vector<string>),
46 fHLTLab(new vector<string>),
47 fRunEntries(0),
48 fHltEntries(0),
49 fFileNum(-1),
50 fLastWrittenEvt(-1),
51 fLastSeenEvt(-1),
52 fCounter(0)
53 {
54 // Constructor.
55 }
56
57 //--------------------------------------------------------------------------------------------------
58 void OutputMod::BeginRun()
59 {
60 // Create HLT tree if HLTFwkMod is being run.
61
62 if (!HasHLTInfo())
63 return;
64
65 if (!fHltTree) {
66 HLTFwkMod *hm = const_cast<HLTFwkMod*>(GetHltFwkMod());
67 fTreeWriter->AddBranchToTree(hm->HLTTreeName(), hm->HLTTabName(),
68 TClass::GetClass(typeid(*fHLTTab))->GetName(),
69 &fHLTTab, 32000, 0);
70 fTreeWriter->AddBranchToTree(hm->HLTTreeName(), hm->HLTLabName(),
71 TClass::GetClass(typeid(*fHLTLab))->GetName(),
72 &fHLTLab, 32000, 0);
73 fTreeWriter->SetAutoFill(hm->HLTTreeName(), 0);
74 fHltTree = fTreeWriter->GetTree(hm->HLTTreeName());
75 }
76 }
77
78 //--------------------------------------------------------------------------------------------------
79 void OutputMod::CheckAndAddBranch(const char *bname, const char *cname)
80 {
81 // Check if the given branch should be kept or dropped.
82
83 if (IsAcceptedBranch(bname))
84 return;
85
86 // populate regular expression list if this was not yet done
87 if (fCmdReList.size() != fCmdList.size()) {
88 for (UInt_t i=0; i<fCmdList.size(); ++i) {
89 const char *ptr = fCmdList.at(i).c_str();
90 fCmdReList.push_back(TRegexp(ptr+5,kTRUE));
91 if (ptr[0]=='k')
92 fCmdDeList.push_back(kTRUE);
93 else
94 fCmdDeList.push_back(kFALSE);
95 }
96 }
97
98 // decide whether given branch name should be kept or dropped
99 TString brname(bname);
100 Bool_t decision = kFALSE;
101 Bool_t decision_found = kFALSE;
102
103 for (UInt_t i=0; i<fCmdList.size(); ++i) {
104 TRegexp &re(fCmdReList.at(i));
105 if (brname.Index(re) == kNPOS)
106 continue;
107 decision = fCmdDeList.at(i);
108 decision_found = kTRUE;
109 }
110
111 if (!decision_found) { // no decision found: still drop branch
112 Warning("CheckAndAddBranch",
113 "No decision found for branch '%s' and class '%s'. Branch therefore dropped!",
114 bname, cname);
115 return;
116 }
117
118 if (!decision) { // drop branch according to request
119 Info("CheckAndAddBranch",
120 "Dropped branch '%s' and class '%s'", bname, cname);
121 return;
122 }
123
124 // add branch to accepted branch list
125 Info("CheckAndAddBranch",
126 "Kept branch '%s' and class '%s'", bname, cname);
127
128 fBrNameList.push_back(string(bname));
129 fBrClassList.push_back(string(cname));
130 }
131
132 //--------------------------------------------------------------------------------------------------
133 Bool_t OutputMod::CheckAndResolveBranchDep()
134 {
135 // Checks dependency in BranchTable. Resolve dependency automatically if fUserBrDep is kTRUE.
136
137 TFile *cfile = const_cast<TFile*>(GetSel()->GetCurrentFile());
138 if (!cfile) {
139 SendError(kAbortAnalysis, "CheckAndResolveBranchDep", "Could not get pointer to current file!");
140 return kFALSE;
141 }
142
143 BranchTable *br = dynamic_cast<BranchTable*>(cfile->Get(Names::gkBranchTable));
144 if (!br) {
145 SendError(kAbortAnalysis, "CheckAndResolveBranchDep", "Could not get pointer to branch table!");
146 return kFALSE;
147 }
148
149 TList *blist = br->GetBranches();
150 if (!blist) {
151 SendError(kAbortAnalysis, "CheckAndResolveBranchDep", "Could not get list of branches!");
152 return kFALSE;
153 }
154
155 fBranchTable = new BranchTable;
156 fBranchTable->SetName(Names::gkBranchTable);
157 fBranchTable->SetOwner();
158
159 TList sht;
160 sht.SetOwner(kTRUE);
161 for (UInt_t i=0; i<fBrNameList.size(); ++i) {
162 sht.Add(new TObjString(fBrNameList.at(i).c_str()));
163 }
164
165 for (UInt_t i=0; i<fBrNameList.size(); ++i) {
166 TString brname(fBrNameList.at(i));
167 if (!blist->FindObject(brname))
168 continue;
169 TList *bdeps = br->GetDepBranches(brname);
170 if (!bdeps)
171 continue;
172
173 // check dependency
174 TIter iter(bdeps->MakeIterator());
175 const TObjString *n = dynamic_cast<const TObjString*>(iter.Next());
176 while (n) {
177 if (sht.FindObject(n->GetName())) {
178 // dependent branch is already accepted
179 fBranchTable->Add(new BranchName(brname,n->GetName()));
180 } else {
181 if (fUseBrDep) {
182 const TObjArray *arr = GetSel()->GetTree()->GetTree()->GetListOfBranches();
183 TBranch *br = dynamic_cast<TBranch*>(arr->FindObject(n->GetName()));
184 if (!br) {
185 Error("CheckAndResolveBranchDep",
186 "Could not get branch '%s' to resolve dependency for branch '%s'",
187 n->GetName(), brname.Data());
188 } else {
189 Info("CheckAndResolveBranchDep",
190 "Adding branch '%s' to resolve dependency for branch '%s'",
191 n->GetName(), brname.Data());
192 fBrNameList.push_back(string(n->GetName()));
193 fBrClassList.push_back(br->GetClassName());
194 sht.Add(new TObjString(n->GetName()));
195 fBranchTable->Add(new BranchName(brname,n->GetName()));
196 }
197 } else {
198 Warning("CheckAndResolveBranchDep",
199 "Unresolved dependency of branch '%s' and '%s' ",
200 n->GetName(), brname.Data());
201 }
202 }
203 n = dynamic_cast<const TObjString*>(iter.Next());
204 }
205 delete bdeps;
206 }
207 delete blist;
208 return kTRUE;
209 }
210
211 //--------------------------------------------------------------------------------------------------
212 void OutputMod::CheckAndResolveTAMDep(Bool_t solve)
213 {
214 // Check if TAM has loaded additional branches. If requested try to solve the the dependency
215 // by adding the branch to the list of branches.
216
217 const THashTable &ht = GetSel()->GetBranchTable();
218
219 TIter iter(ht.MakeIterator());
220 const TAMBranchInfo *next = dynamic_cast<const TAMBranchInfo*>(iter.Next());
221
222 while (next) {
223 const TAMBranchInfo *cur = next;
224 next = dynamic_cast<const TAMBranchInfo*>(iter.Next());
225 Bool_t isloaded = cur->IsLoaded();
226 if (!isloaded)
227 continue;
228
229 const char *bname = cur->GetName();
230 if (IsAcceptedBranch(bname))
231 continue;
232
233 TreeBranchLoader *loader = dynamic_cast<TreeBranchLoader*>(cur->GetLoader());
234 if (!loader)
235 continue;
236
237 TBranch *br = loader->GetBranch();
238 if (!br)
239 continue;
240
241 const char *cname = br->GetClassName();
242
243 if (solve) {
244 Info("CheckAndResolveTAMDep",
245 "Resolving dependency for loaded branch '%s' and class '%s'", bname,cname);
246
247 fBrNameList.push_back(string(bname));
248 fBrClassList.push_back(string(cname));
249 fBranches[GetNBranches()-1] = reinterpret_cast<TObject*>(loader->GetAddress());
250
251 } else {
252 Warning("CheckAndResolveTAMDep",
253 "Unresolved dependency for loaded branch '%s' and class '%s'",
254 bname,cname);
255 }
256 }
257 }
258
259 //--------------------------------------------------------------------------------------------------
260 void OutputMod::EndRun()
261 {
262 // Nothing to be done at this point.
263 }
264
265 //--------------------------------------------------------------------------------------------------
266 void OutputMod::FillAllEventHeader(Bool_t isremoved)
267 {
268 // Fill event header into the all-event-header tree.
269
270 if (!fTreeWriter->BeginEvent(kFALSE)) {
271 SendError(kAbortAnalysis, "FillAllEventHeader", "Begin event failed!");
272 return;
273 }
274
275 if (fSkimmedIn) { // copy alread skimmed headers if any there
276 const UInt_t n = fSkimmedIn->GetEntries();
277 for(UInt_t i=0; i<n; ++i) {
278 const EventHeader *eh = fSkimmedIn->At(i);
279 *fAllEventHeader = *eh;
280 fAllEventHeader->SetSkimmed(eh->Skimmed()+1);
281 fAllTree->Fill();
282 }
283 }
284
285 const EventHeader *eh = GetEventHeader();
286 *fAllEventHeader = *eh;
287 if (isremoved) {
288 fAllEventHeader->SetRunEntry(-1);
289 fAllEventHeader->SetSkimmed(eh->Skimmed()+1);
290 } else {
291 fAllEventHeader->SetRunEntry(eh->RunEntry());
292 fAllEventHeader->SetSkimmed(eh->Skimmed());
293 }
294
295 fAllTree->Fill();
296 }
297
298 //--------------------------------------------------------------------------------------------------
299 void OutputMod::FillHltInfo()
300 {
301 // Write HLT trigger table if needed.
302
303 if (!fHltTree)
304 return;
305
306 HLTFwkMod *hm = const_cast<HLTFwkMod*>(GetHltFwkMod());
307 vector<string> *trigtable = hm->fHLTTab;
308 vector<string> *labels = hm->fHLTLab;
309
310 Bool_t doCopy = kFALSE;
311 if (fHLTTab->size()==0) {
312 doCopy = kTRUE;
313 } else {
314 // check if existing table contains all necessary paths:
315 // if so keep it, otherwise store the new one
316
317 if ((fHLTTab->size() != trigtable->size()) ||
318 (fHLTLab->size() != labels->size())) {
319 doCopy = kTRUE;
320 } else {
321 // need to check more thoroughly
322
323 for (UInt_t i=0; i<trigtable->size(); ++i) {
324 if (trigtable->at(i) != fHLTTab->at(i)) {
325 doCopy = kTRUE;
326 break;
327 }
328 }
329 if (!doCopy) {
330 for (UInt_t i=0; i<labels->size(); ++i) {
331 if (labels->at(i) != fHLTLab->at(i)) {
332 doCopy = kTRUE;
333 break;
334 }
335 }
336 }
337 }
338 }
339
340 if (!doCopy)
341 return;
342
343 fHLTTab->resize(trigtable->size());
344 copy(trigtable->begin(),trigtable->end(), fHLTTab->begin());
345 fHLTLab->resize(labels->size());
346 copy(labels->begin(),labels->end(), fHLTLab->begin());
347
348 ++fHltEntries;
349 fHltTree->Fill();
350 }
351
352 //--------------------------------------------------------------------------------------------------
353 Bool_t OutputMod::IsAcceptedBranch(const char *bname)
354 {
355 // Return true if given branch is already in branch list. Also return true if a special
356 // branch like the "EventHeader" branch is reqested.
357
358 // search in branch list
359 for (UInt_t i=0; i<GetNBranches(); ++i) {
360 if (fBrNameList.at(i).compare(bname) == 0)
361 return kTRUE;
362 }
363
364 // check if special branch that we take care of ourselves
365 string name(bname);
366 if (name.compare("EventHeader") == 0) {
367 return kTRUE;
368 }
369
370 return kFALSE;
371 }
372
373 //--------------------------------------------------------------------------------------------------
374 Bool_t OutputMod::Notify()
375 {
376 // On first notify, loop over list of branches to determine the list of kept branches.
377
378 if (GetNEventsProcessed() != 0)
379 return kTRUE;
380
381 const TTree *tree=GetSel()->GetTree();
382 if (!tree)
383 return kFALSE;
384
385 const TObjArray *arr = tree->GetTree()->GetListOfBranches();
386 if (!arr)
387 return kFALSE;
388
389 for (Int_t i=0; i<arr->GetEntries(); ++i) {
390 TBranch *br = dynamic_cast<TBranch*>(arr->At(i));
391 if (!br && !br->GetMother())
392 continue;
393 br = br->GetMother();
394 TClass *cls = TClass::GetClass(br->GetClassName());
395 if (!cls)
396 continue;
397
398 if (!cls->InheritsFrom("TObject")) {
399 Warning("Notify", "Found branch '%s' where class '%s' does not derive from TObject",
400 br->GetName(), br->GetClassName());
401 continue;
402 }
403
404 CheckAndAddBranch(br->GetName(), br->GetClassName());
405 }
406
407 if (fCheckBrDep && !CheckAndResolveBranchDep())
408 return kFALSE;
409
410 RequestBranches();
411 return kTRUE;
412 }
413
414 //--------------------------------------------------------------------------------------------------
415 void OutputMod::LoadBranches()
416 {
417 // Loop over requested branches and load them.
418
419 for (UInt_t i=0; i<GetNBranches(); ++i) {
420 LoadBranch(fBrNameList.at(i).c_str());
421 }
422 }
423
424 //--------------------------------------------------------------------------------------------------
425 void OutputMod::Process()
426 {
427 // Write out the kept branches of the current event. Make sure the meta information is
428 // correctly updated.
429
430 if (GetSel()->GetCurEvt() == fLastSeenEvt) {
431 Warning("Process", "Event with %lld already seen", fLastSeenEvt);
432 return;
433 }
434 fLastSeenEvt = GetSel()->GetCurEvt();
435
436 if (GetSel()->GetCurEvt() == fLastWrittenEvt) {
437 Warning("Process", "Event with %lld already written", fLastWrittenEvt);
438 return;
439 }
440 fLastWrittenEvt = GetSel()->GetCurEvt();
441 ++fCounter;
442
443 // prepare for tree filling
444 if (!fTreeWriter->BeginEvent(fDoReset)) {
445 SendError(kAbortAnalysis, "Process", "Begin event failed!");
446 return;
447 }
448
449 if (GetNEventsProcessed() == 0 && fCheckTamBr) {
450 CheckAndResolveTAMDep(fKeepTamBr);
451 }
452
453 // load all our branches
454 LoadBranches();
455
456 // pass our branches to tree writer if on first event
457 if (GetNEventsProcessed() == 0) {
458 SetupBranches();
459 }
460
461 // reset per file quantities if a new file was opened
462 if (fTreeWriter->GetFileNumber()!=fFileNum) {
463 fRunmap.clear();
464 fHLTTab->clear();
465 fHLTLab->clear();
466 fRunEntries = 0;
467 fHltEntries = 0;
468 fFileNum = fTreeWriter->GetFileNumber();
469 if (fBranchTable)
470 fTreeWriter->StoreObject(fBranchTable);
471 }
472
473 UInt_t runnum = GetEventHeader()->RunNum();
474
475 // store look ahead information
476 if (fRunEntries>0) {
477 fLaHeader->SetRunNum(runnum);
478 fLATree->Fill();
479 }
480
481 // fill event header
482 *fEventHeader = *GetEventHeader();
483
484 // fill all event header
485 FillAllEventHeader(kFALSE);
486
487 // look-up if entry is in map
488 map<UInt_t,Int_t>::iterator riter = fRunmap.find(runnum);
489 if (riter != fRunmap.end()) { // found existing run info
490 Int_t runentry = riter->second;
491 fEventHeader->SetRunEntry(runentry);
492
493 IncNEventsProcessed();
494 fTreeWriter->EndEvent(fDoReset);
495 return;
496 }
497
498 // fill new run info
499 Int_t runentry = fRunEntries;
500 ++fRunEntries;
501 fEventHeader->SetRunEntry(runentry);
502 fRunmap.insert(pair<UInt_t,Int_t>(runnum,runentry));
503 fRunInfo->SetRunNum(runnum);
504
505 Int_t hltentry = fHltEntries;
506 FillHltInfo();
507 if (hltentry < fHltEntries)
508 fRunInfo->SetHltEntry(hltentry);
509 else
510 fRunInfo->SetHltEntry(hltentry-1);
511
512 fRunTree->Fill();
513
514 IncNEventsProcessed();
515
516 if (!fTreeWriter->EndEvent(fDoReset)) {
517 SendError(kAbortAnalysis, "Process", "End event failed!");
518 return;
519 }
520 }
521
522 //--------------------------------------------------------------------------------------------------
523 void OutputMod::ProcessAll()
524 {
525 // Called by the Selector class for events that were skipped.
526
527 if (GetSel()->GetCurEvt() == fLastSeenEvt)
528 return;
529
530 fLastSeenEvt = GetSel()->GetCurEvt();
531 ++fCounter;
532
533 // prepare for tree filling
534 FillAllEventHeader(kTRUE);
535 }
536
537 //--------------------------------------------------------------------------------------------------
538 void OutputMod::RequestBranches()
539 {
540 // Loop over requested branches and request them.
541
542 for (UInt_t i=0; i<GetNBranches(); ++i) {
543 if (i>=fNBranchesMax) {
544 SendError(kAbortAnalysis, "RequestBranches", "Cannot request branch '%s' "
545 "since maximum number of branches [%d] is reached",
546 fBrNameList.at(i).c_str(), fNBranchesMax);
547 return;
548 }
549 fBranches[i] = 0;
550 TAModule::ReqBranch(fBrNameList.at(i).c_str(), fBranches[i]);
551 }
552 }
553
554 //--------------------------------------------------------------------------------------------------
555 void OutputMod::SetupBranches()
556 {
557 // Setup branches in tree writer.
558
559 for (UInt_t i=0; i<GetNBranches(); ++i) {
560 const char *bname = fBrNameList.at(i).c_str();
561 const char *cname = fBrClassList.at(i).c_str();
562 if (!fBranches[i]) {
563 SendError(kWarning, "SetupBranches",
564 "Pointer for branch '%s' and class '%s' is NULL", bname, cname);
565 continue;
566 }
567 Int_t bsize = fBranchSize;
568 TString cnamestr(cname);
569 if ((bsize<128*1024) && (cnamestr.Contains("mithep::MCParticle"))) {
570 bsize=128*1024;
571 } else if ((bsize<32*1024) && (cnamestr.Contains("mithep::CaloTower"))) {
572 bsize=32*1024;
573 }
574
575 fTreeWriter->AddBranch(bname, cname, &fBranches[i], bsize);
576 }
577 }
578
579 //--------------------------------------------------------------------------------------------------
580 void OutputMod::SlaveBegin()
581 {
582 // Setup the tree writer and create branches that can already be created at this point.
583
584 // setup tree writer
585 fTreeWriter = new TreeWriter(fTreeName, kFALSE);
586 fTreeWriter->SetBaseURL(fPathName);
587 fTreeWriter->SetPrefix(fPrefix);
588 fTreeWriter->SetMaxSize(fMaxSize*1024*1024);
589 fTreeWriter->SetCompressLevel(fCompLevel);
590 fTreeWriter->SetDefaultSL(fSplitLevel);
591 fTreeWriter->SetDefaultBrSize(fBranchSize);
592 fTreeWriter->AddTree(fTreeName);
593 fTreeWriter->DoBranchRef(fTreeName);
594
595 // deal with my own tree objects
596 fEventHeader = new EventHeader;
597 fTreeWriter->AddBranch(GetSel()->GetEvtHdrName(), &fEventHeader);
598
599 // deal with other trees
600 const char *tname = 0;
601 fRunInfo = new RunInfo;
602 tname = GetSel()->GetRunTreeName();
603 fTreeWriter->AddBranchToTree(tname, GetSel()->GetRunInfoName(), &fRunInfo);
604 fTreeWriter->SetAutoFill(tname, 0);
605 fRunTree = fTreeWriter->GetTree(tname);
606 fLaHeader = new LAHeader;
607 tname = GetSel()->GetLATreeName();
608 fTreeWriter->AddBranchToTree(tname, GetSel()->GetLAHdrName(), &fLaHeader);
609 fTreeWriter->SetAutoFill(tname, 0);
610 fLATree = fTreeWriter->GetTree(tname);
611 fAllEventHeader = new EventHeader;
612 tname = GetSel()->GetAllEvtTreeName();
613 fTreeWriter->AddBranchToTree(tname, GetSel()->GetAllEvtHdrBrn(), &fAllEventHeader);
614 fAllTree = fTreeWriter->GetTree(tname);
615 fTreeWriter->SetAutoFill(tname, 0);
616
617 // get pointer to all event headers
618 fSkimmedIn = GetPublicObj<EventHeaderCol>(Names::gkSkimmedHeaders);
619
620 // create TObject space for TAM
621 fBranches = new TObject*[fNBranchesMax + fAddList.size()];
622
623 // deal here with additional published objects
624 for (UInt_t i=0; i<fAddList.size(); ++i) {
625 TString objname(fAddList.at(i));
626 TObject *obj = FindPublicObj(objname);
627 if (obj) {
628 fBranches[fNBranchesMax+i] = obj;
629 fTreeWriter->AddBranch(objname, &fBranches[fNBranchesMax+i]);
630 Info("SlaveBegin", "Adding additional branch named '%s' as requested", objname.Data());
631 } else {
632 SendError(kAbortAnalysis, "SlaveBegin",
633 "Object named '%s' for additional branch is NULL", objname.Data());
634 }
635 }
636
637 // adjust checks for TAM branches
638 if (fKeepTamBr)
639 fCheckTamBr = kTRUE;
640 }
641
642 //--------------------------------------------------------------------------------------------------
643 void OutputMod::SlaveTerminate()
644 {
645 // Terminate tree writing and do cleanup.
646
647 RetractObj(Names::gkSkimmedHeaders);
648
649 delete fTreeWriter;
650 fTreeWriter = 0;
651
652 delete fEventHeader;
653 delete fRunInfo;
654 delete fLaHeader;
655 delete fAllEventHeader;
656
657 delete[] fBranches;
658
659 Double_t frac = 100.*GetNEventsProcessed()/fCounter;
660 Info("SlaveTerminate", "Stored %.2f%% events (%d out of %lld)",
661 frac, GetNEventsProcessed(), fCounter);
662 }