]> git.uio.no Git - u/mrichter/AliRoot.git/blame - STEER/AliAODHandler.cxx
corrected leftover modifications
[u/mrichter/AliRoot.git] / STEER / AliAODHandler.cxx
CommitLineData
3fbf06a3 1
ec4af4c1 2/**************************************************************************
3 * Copyright(c) 1998-2007, ALICE Experiment at CERN, All rights reserved. *
4 * *
5 * Author: The ALICE Off-line Project. *
6 * Contributors are mentioned in the code where appropriate. *
7 * *
8 * Permission to use, copy, modify and distribute this software and its *
9 * documentation strictly for non-commercial purposes is hereby granted *
10 * without fee, provided that the above copyright notice appears in all *
11 * copies and that both the copyright notice and this permission notice *
12 * appear in the supporting documentation. The authors make no claims *
13 * about the suitability of this software for any purpose. It is *
14 * provided "as is" without express or implied warranty. *
15 **************************************************************************/
16
17/* $Id$ */
18
19//-------------------------------------------------------------------------
20// Implementation of the Virtual Event Handler Interface for AOD
21// Author: Andreas Morsch, CERN
22//-------------------------------------------------------------------------
23
052994fb 24
ec4af4c1 25#include <TTree.h>
e910dd36 26#include <TFile.h>
7970f4ac 27#include <TString.h>
dce1b636 28#include <TList.h>
160959a9 29#include <TROOT.h>
e910dd36 30
da97a08a 31#include "AliLog.h"
ec4af4c1 32#include "AliAODHandler.h"
33#include "AliAODEvent.h"
da97a08a 34#include "AliAODTracklets.h"
35#include "AliStack.h"
36#include "AliAODMCParticle.h"
dce1b636 37#include "AliAODMCHeader.h"
da97a08a 38#include "AliMCEventHandler.h"
39#include "AliMCEvent.h"
dce1b636 40#include "AliGenEventHeader.h"
41#include "AliGenHijingEventHeader.h"
42#include "AliGenDPMjetEventHeader.h"
43#include "AliGenPythiaEventHeader.h"
44#include "AliGenCocktailEventHeader.h"
45
46
ec4af4c1 47
48ClassImp(AliAODHandler)
49
50//______________________________________________________________________________
51AliAODHandler::AliAODHandler() :
f3214a54 52 AliVEventHandler(),
78f7f935 53 fIsStandard(kTRUE),
da97a08a 54 fFillAOD(kTRUE),
7c3a9fbf 55 fNeedsHeaderReplication(kFALSE),
75754ba8 56 fNeedsTracksBranchReplication(kFALSE),
57 fNeedsVerticesBranchReplication(kFALSE),
58 fNeedsV0sBranchReplication(kFALSE),
59 fNeedsTrackletsBranchReplication(kFALSE),
60 fNeedsPMDClustersBranchReplication(kFALSE),
61 fNeedsJetsBranchReplication(kFALSE),
62 fNeedsFMDClustersBranchReplication(kFALSE),
63 fNeedsCaloClustersBranchReplication(kFALSE),
64 fAODIsReplicated(kFALSE),
ec4af4c1 65 fAODEvent(NULL),
da97a08a 66 fMCEventH(NULL),
e910dd36 67 fTreeA(NULL),
68 fFileA(NULL),
9066c676 69 fFileName(""),
70 fExtensions(NULL)
ec4af4c1 71{
72 // default constructor
73}
74
75//______________________________________________________________________________
76AliAODHandler::AliAODHandler(const char* name, const char* title):
f3214a54 77 AliVEventHandler(name, title),
78f7f935 78 fIsStandard(kTRUE),
da97a08a 79 fFillAOD(kTRUE),
7c3a9fbf 80 fNeedsHeaderReplication(kFALSE),
75754ba8 81 fNeedsTracksBranchReplication(kFALSE),
82 fNeedsVerticesBranchReplication(kFALSE),
83 fNeedsV0sBranchReplication(kFALSE),
84 fNeedsTrackletsBranchReplication(kFALSE),
85 fNeedsPMDClustersBranchReplication(kFALSE),
86 fNeedsJetsBranchReplication(kFALSE),
87 fNeedsFMDClustersBranchReplication(kFALSE),
88 fNeedsCaloClustersBranchReplication(kFALSE),
89 fAODIsReplicated(kFALSE),
ec4af4c1 90 fAODEvent(NULL),
da97a08a 91 fMCEventH(NULL),
e910dd36 92 fTreeA(NULL),
93 fFileA(NULL),
9066c676 94 fFileName(""),
95 fExtensions(NULL)
ec4af4c1 96{
97}
98
99//______________________________________________________________________________
100AliAODHandler::~AliAODHandler()
101{
9066c676 102 // Destructor.
6989bff3 103 delete fAODEvent;
104 if(fFileA){
105 // is already handled in TerminateIO
106 fFileA->Close();
107 delete fFileA;
108 }
109 delete fTreeA;
9066c676 110 if (fExtensions) delete fExtensions;
ec4af4c1 111}
112
7970f4ac 113//______________________________________________________________________________
300d5701 114Bool_t AliAODHandler::Init(Option_t* opt)
ec4af4c1 115{
6989bff3 116 // Initialize IO
117 //
118 // Create the AODevent object
119 if(!fAODEvent){
ec4af4c1 120 fAODEvent = new AliAODEvent();
78f7f935 121 if (fIsStandard) fAODEvent->CreateStdContent();
6989bff3 122 }
123 //
124 // File opening according to execution mode
7970f4ac 125 TString option(opt);
126 option.ToLower();
160959a9 127 TDirectory *owd = gDirectory;
7970f4ac 128 if (option.Contains("proof")) {
6989bff3 129 // proof
160959a9 130 // Merging via files. Need to access analysis manager via interpreter.
20653795 131 gROOT->ProcessLine(Form("AliAnalysisManager::GetAnalysisManager()->OpenProofFile(\"%s\", \"RECREATE\");", fFileName.Data()));
160959a9 132 gROOT->ProcessLine(Form("AliAnalysisManager::GetAnalysisManager()->GetCommonOutputContainer()->SetFile((TFile*)0x%lx);", gFile));
133 fFileA = gFile;
6989bff3 134 } else {
135 // local and grid
7970f4ac 136 fFileA = new TFile(fFileName.Data(), "RECREATE");
6989bff3 137 }
160959a9 138 CreateTree(1);
139 owd->cd();
9066c676 140 if (fExtensions) {
141 TIter next(fExtensions);
142 AliAODExtension *ext;
143 while ((ext=(AliAODExtension*)next())) ext->Init(option);
144 }
6989bff3 145 return kTRUE;
ec4af4c1 146}
147
9066c676 148//______________________________________________________________________________
da97a08a 149void AliAODHandler::StoreMCParticles(){
dce1b636 150
da97a08a 151 //
152 // Remap the labels from ESD stack and store
153 // the AODMCParticles, makes only sense if we have
154 // the mcparticles branch
155 // has to be done here since we cannot know in advance
156 // which particles are needed (e.g. by the tracks etc.)
157 //
158 // Particles have been selected by AliMCEventhanlder->SelectParticle()
159 // To use the MCEventhandler here we need to set it from the outside
160 // can vanish when Handler go to the ANALYSISalice library
dce1b636 161 //
162 // The Branch booking for mcParticles and mcHeader has to happen
163 // in an external task for now since the AODHandler does not have access
164 // the AnalysisManager. For the same reason the pointer t o the MCEventH
165 // has to passed to the AOD Handler by this task
166 // (doing this in the steering macro would not work on PROOF)
da97a08a 167
168 TClonesArray *mcarray = (TClonesArray*)fAODEvent->FindListObject(AliAODMCParticle::StdBranchName());
169 if(!mcarray)return;
170 mcarray->Delete();
171
dce1b636 172 AliAODMCHeader *mcHeader = (AliAODMCHeader*)fAODEvent->FindListObject(AliAODMCHeader::StdBranchName());
173 if(!mcHeader)return;
174
175 mcHeader->Reset();
176
da97a08a 177 // Get the MC Infos.. Handler needs to be set before
178 // while adding the branch
179 // This needs to be done, not to depend on the AnalysisManager
180
181 if(!fMCEventH)return;
182 if(!fMCEventH->MCEvent())return;
183 AliStack *pStack = fMCEventH->MCEvent()->Stack();
184 if(!pStack)return;
185
186 fMCEventH->CreateLabelMap();
187
dce1b636 188 //
189 // Get the Event Header
190 //
191
192 AliHeader* header = fMCEventH->MCEvent()->Header();
193 if (!header)return;
194
195 // get the MC vertex
196 AliGenEventHeader* genHeader = header->GenEventHeader();
197 TArrayF vtxMC(3);
198 genHeader->PrimaryVertex(vtxMC);
199 mcHeader->SetVertex(vtxMC[0],vtxMC[1],vtxMC[2]);
200
201 // we search the MCEventHeaders first
202 // Two cases, cocktail or not...
203 AliGenCocktailEventHeader* genCocktailHeader = dynamic_cast<AliGenCocktailEventHeader*>(genHeader);
204 if(genCocktailHeader){
205 // we have a coktail header
206 mcHeader->AddGeneratorName(genHeader->GetName());
207 // Loop from the back so that the first one sets the process type
208 TList* headerList = genCocktailHeader->GetHeaders();
209 for(int i = headerList->GetEntries()-1;i>=0;--i){
210 AliGenEventHeader *headerEntry = dynamic_cast<AliGenEventHeader*>(headerList->At(i));
211 SetMCHeaderInfo(mcHeader,headerEntry);
212 }
213 }
214 else{
215 // No Cocktail just take the first one
216 SetMCHeaderInfo(mcHeader,genHeader);
217 }
218
219
220
221
222 // Store the AliAODParticlesMC
da97a08a 223
224 Int_t np = pStack->GetNtrack();
225 Int_t nprim = pStack->GetNprimary();
226
227
228 Int_t j = 0;
229 TClonesArray& l = *mcarray;
230
231 for(int i = 0;i < np;++i){
232 if(fMCEventH->IsParticleSelected(i)){
233
234 Int_t flag = 0;
235 TParticle *part = pStack->Particle(i);
236 if(i<nprim)flag |= AliAODMCParticle::kPrimary;
237 if(pStack->IsPhysicalPrimary(i))flag |= AliAODMCParticle::kPhysicalPrim;
238
239 if(fMCEventH->GetNewLabel(i)!=j){
240 AliError(Form("MISMATCH New label %d j: %d",fMCEventH->GetNewLabel(i),j));
241 }
242 AliAODMCParticle mcpart_tmp(part,i,flag);
243
244 //
245 Int_t d0 = mcpart_tmp.GetDaughter(0);
246 Int_t d1 = mcpart_tmp.GetDaughter(1);
247 Int_t m = mcpart_tmp.GetMother();
248
249 // other than for the track labels, negative values mean
250 // no daughter/mother so preserve it
251
252 if(d0<0 && d1<0){
253 // no first daughter -> no second daughter
254 // nothing to be done
255 // second condition not needed just for sanity check at the end
256 mcpart_tmp.SetDaughter(0,d0);
257 mcpart_tmp.SetDaughter(1,d1);
258 }
259 else if(d1 < 0 && d0 >= 0){
260 // Only one daughter
261 // second condition not needed just for sanity check at the end
262 if(fMCEventH->IsParticleSelected(d0)){
263 mcpart_tmp.SetDaughter(0,fMCEventH->GetNewLabel(d0));
264 }
265 else{
266 mcpart_tmp.SetDaughter(0,-1);
267 }
268 mcpart_tmp.SetDaughter(1,d1);
269 }
270 else if (d0 > 0 && d1 > 0 ){
271 // we have two or more daughters loop on the stack to see if they are
272 // selected
273 Int_t d0_tmp = -1;
274 Int_t d1_tmp = -1;
275 for(int id = d0; id<=d1;++id){
276 if(fMCEventH->IsParticleSelected(id)){
277 if(d0_tmp==-1){
278 // first time
279 d0_tmp = fMCEventH->GetNewLabel(id);
280 d1_tmp = d0_tmp; // this is to have the same schema as on the stack i.e. with one daugther d0 and d1 are the same
281 }
282 else d1_tmp = fMCEventH->GetNewLabel(id);
283 }
284 }
285 mcpart_tmp.SetDaughter(0,d0_tmp);
286 mcpart_tmp.SetDaughter(1,d1_tmp);
287 }
288 else{
289 AliError(Form("Unxpected indices %d %d",d0,d1));
290 }
291
292 if(m<0){
293 mcpart_tmp.SetMother(m);
294 }
295 else{
296 if(fMCEventH->IsParticleSelected(m))mcpart_tmp.SetMother(fMCEventH->GetNewLabel(m));
297 else AliError("PROBLEM Mother not selected");
298 }
299
300 new (l[j++]) AliAODMCParticle(mcpart_tmp);
301
302 }
303 }
304 AliInfo(Form("AliAODHandler::StoreMCParticles: Selected %d (Primaries %d / total %d) after validation",
305 j,nprim,np));
306
307 // Set the labels in the AOD output...
308 // Remapping
309
310 // AODTracks
311 TClonesArray* tracks = fAODEvent->GetTracks();
312 if(tracks){
313 for(int it = 0; it < fAODEvent->GetNTracks();++it){
314 AliAODTrack *track = fAODEvent->GetTrack(it);
315
316 if(TMath::Abs(track->GetLabel())>np||track->GetLabel()==0){
317 AliWarning(Form("Wrong ESD track label %d",track->GetLabel()));
318 }
319 if(fMCEventH->GetNewLabel(track->GetLabel())==0){
320 AliWarning(Form("New label not found for %d",track->GetLabel()));
321 }
322 track->SetLabel(fMCEventH->GetNewLabel(track->GetLabel()));
323 }
324 }
325
326 // AOD calo cluster
327 TClonesArray *clusters = fAODEvent->GetCaloClusters();
328 if(clusters){
329 for (Int_t iClust = 0;iClust < fAODEvent->GetNCaloClusters(); ++iClust) {
330 AliAODCaloCluster * cluster = fAODEvent->GetCaloCluster(iClust);
331 UInt_t nLabel = cluster->GetNLabel();
332 // Ugly but do not want to fragment memory by creating
333 // new Int_t (nLabel)
334 Int_t* labels = const_cast<Int_t*>(cluster->GetLabels());
335 if (labels){
336 for(UInt_t i = 0;i < nLabel;++i){
337 labels[i] = fMCEventH->GetNewLabel(cluster->GetLabel(i));
338 }
339 }
340 // cluster->SetLabels(labels,nLabel);
341 }// iClust
342 }// clusters
343
344 // AOD tracklets
345 AliAODTracklets *tracklets = fAODEvent->GetTracklets();
346 if(tracklets){
347 for(int it = 0;it < tracklets->GetNumberOfTracklets();++it){
348 int label0 = tracklets->GetLabel(it,0);
349 int label1 = tracklets->GetLabel(it,1);
350 if(label0>=0)label0 = fMCEventH->GetNewLabel(label0);
351 if(label1>=0)label1 = fMCEventH->GetNewLabel(label1);
352 tracklets->SetLabel(it,0,label0);
353 tracklets->SetLabel(it,1,label1);
354 }
355 }
356
357}
358
9066c676 359//______________________________________________________________________________
5f380da9 360Bool_t AliAODHandler::FinishEvent()
ec4af4c1 361{
da97a08a 362 // Fill data structures
363 if(fFillAOD){
f4e5f8d5 364 fAODEvent->MakeEntriesReferencable();
da97a08a 365 StoreMCParticles();
ec4af4c1 366 FillTree();
9066c676 367 if (fExtensions) {
368 TIter next(fExtensions);
369 AliAODExtension *ext;
370 while ((ext=(AliAODExtension*)next())) {
371 ext->GetAOD()->MakeEntriesReferencable();
372 ext->GetTree()->Fill();
373 }
374 }
da97a08a 375 }
376
377 if (fIsStandard) fAODEvent->ResetStd();
378 // Reset AOD replication flag
379 fAODIsReplicated = kFALSE;
380 return kTRUE;
ec4af4c1 381}
382
7970f4ac 383//______________________________________________________________________________
ec4af4c1 384Bool_t AliAODHandler::Terminate()
385{
9066c676 386 // Terminate
387 AddAODtoTreeUserInfo();
388 if (fExtensions) {
389 TIter next(fExtensions);
390 AliAODExtension *ext;
391 while ((ext=(AliAODExtension*)next())) ext->GetTree()->GetUserInfo()->Add(ext->GetAOD());
392 }
393 return kTRUE;
ec4af4c1 394}
395
7970f4ac 396//______________________________________________________________________________
ec4af4c1 397Bool_t AliAODHandler::TerminateIO()
398{
9066c676 399 // Terminate IO
400 if (fFileA) {
401 fFileA->Close();
402 delete fFileA;
403 fFileA = 0;
404 }
405 if (fExtensions) {
406 TIter next(fExtensions);
407 AliAODExtension *ext;
408 while ((ext=(AliAODExtension*)next())) ext->TerminateIO();
409 }
410 return kTRUE;
ec4af4c1 411}
412
7970f4ac 413//______________________________________________________________________________
954526ed 414void AliAODHandler::CreateTree(Int_t flag)
ec4af4c1 415{
416 // Creates the AOD Tree
f3214a54 417 fTreeA = new TTree("aodTree", "AliAOD tree");
ec4af4c1 418 fTreeA->Branch(fAODEvent->GetList());
954526ed 419 if (flag == 0) fTreeA->SetDirectory(0);
ec4af4c1 420}
421
7970f4ac 422//______________________________________________________________________________
ec4af4c1 423void AliAODHandler::FillTree()
424{
425 // Fill the AOD Tree
da97a08a 426 fTreeA->Fill();
ec4af4c1 427}
428
7970f4ac 429//______________________________________________________________________________
ec4af4c1 430void AliAODHandler::AddAODtoTreeUserInfo()
431{
dce1b636 432 // Add aod event to tree user info
da97a08a 433 fTreeA->GetUserInfo()->Add(fAODEvent);
ec4af4c1 434}
490e9023 435
7970f4ac 436//______________________________________________________________________________
9066c676 437void AliAODHandler::AddBranch(const char* cname, void* addobj, const char* filename)
490e9023 438{
9066c676 439 // Add a new branch to the aod. Added optional filename parameter if the
440 // branch should be written to a separate file.
441 if (strlen(filename)) {
442 AliAODExtension *ext = AddExtension(filename);
443 ext->AddBranch(cname, addobj);
444 return;
445 }
490e9023 446 TDirectory *owd = gDirectory;
447 if (fFileA) {
dce1b636 448 fFileA->cd();
490e9023 449 }
0134949d 450 char** apointer = (char**) addobj;
451 TObject* obj = (TObject*) *apointer;
dce1b636 452
0134949d 453 fAODEvent->AddObject(obj);
dce1b636 454
455 const Int_t kSplitlevel = 99; // default value in TTree::Branch()
456 const Int_t kBufsize = 32000; // default value in TTree::Branch()
457
458 if (!fTreeA->FindBranch(obj->GetName())) {
459 // Do the same as if we book via
460 // TTree::Branch(TCollection*)
461
462 fTreeA->Bronch(obj->GetName(), cname, fAODEvent->GetList()->GetObjectRef(obj),
463 kBufsize, kSplitlevel - 1);
464 // fTreeA->Branch(obj->GetName(), cname, addobj);
465 }
490e9023 466 owd->cd();
467}
7970f4ac 468
9066c676 469//______________________________________________________________________________
470AliAODExtension *AliAODHandler::AddExtension(const char *filename, const char *title)
471{
472// Add an AOD extension with some branches in a different file.
473 TString fname(filename);
474 if (!fname.EndsWith(".root")) fname += ".root";
475 if (!fExtensions) {
476 fExtensions = new TObjArray();
477 fExtensions->SetOwner();
478 }
479 AliAODExtension *ext = (AliAODExtension*)fExtensions->FindObject(fname);
480 if (!ext) {
481 ext = new AliAODExtension(fname, title);
482 fExtensions->Add(ext);
483 }
484 return ext;
485}
486
7970f4ac 487//______________________________________________________________________________
488void AliAODHandler::SetOutputFileName(const char* fname)
489{
490// Set file name.
491 fFileName = fname;
492}
493
494//______________________________________________________________________________
495const char *AliAODHandler::GetOutputFileName()
496{
497// Get file name.
498 return fFileName.Data();
499}
dce1b636 500
9066c676 501//______________________________________________________________________________
dce1b636 502void AliAODHandler::SetMCHeaderInfo(AliAODMCHeader *mcHeader,AliGenEventHeader *genHeader){
503
504
505 // Utility function to cover different cases for the AliGenEventHeader
506 // Needed since different ProcessType and ImpactParamter are not
507 // in the base class...
508 // We don't encode process types for event cocktails yet
9066c676 509 // could be done e.g. by adding offsets depnding on the generator
dce1b636 510
511 mcHeader->AddGeneratorName(genHeader->GetName());
dce1b636 512 if(!genHeader)return;
513 AliGenPythiaEventHeader *pythiaGenHeader = dynamic_cast<AliGenPythiaEventHeader*>(genHeader);
514 if (pythiaGenHeader) {
515 mcHeader->SetEventType(pythiaGenHeader->ProcessType());
516 return;
517 }
518
519 AliGenDPMjetEventHeader* dpmJetGenHeader = dynamic_cast<AliGenDPMjetEventHeader*>(genHeader);
520
521 if (dpmJetGenHeader){
522 mcHeader->SetEventType(dpmJetGenHeader->ProcessType());
523 return;
524 }
525
526 AliGenHijingEventHeader* hijingGenHeader = dynamic_cast<AliGenHijingEventHeader*>(genHeader);
527 if(hijingGenHeader){
528 mcHeader->SetImpactParameter(hijingGenHeader->ImpactParameter());
529 return;
530 }
531
532 AliWarning(Form("MC Eventheader not known: %s",genHeader->GetName()));
533
534}
9066c676 535
536ClassImp(AliAODExtension)
537
538//-------------------------------------------------------------------------
539// Support class for AOD extensions. This is created by the user analysis
540// that requires a separate file for some AOD branches. The name of the
541// AliAODExtension object is the file name where the AOD branches will be
542// stored.
543//-------------------------------------------------------------------------
544
545//______________________________________________________________________________
546AliAODExtension::~AliAODExtension()
547{
548// Destructor.
549 delete fAODEvent;
550 if(fFileE){
551 // is already handled in TerminateIO
552 fFileE->Close();
553 delete fFileE;
554 }
555 delete fTreeE;
556}
557
558//______________________________________________________________________________
559void AliAODExtension::AddBranch(const char* cname, void* addobj)
560{
561 // Add a new branch to the aod
d29168d6 562 if (!fAODEvent) {
563 char type[20];
564 gROOT->ProcessLine(Form("TString s_tmp; AliAnalysisManager::GetAnalysisManager()->GetAnalysisTypeString(s_tmp); sprintf((char*)0x%lx, \"%%s\", s_tmp.Data());", type));
565 Init(type);
566 }
9066c676 567 TDirectory *owd = gDirectory;
568 if (fFileE) {
569 fFileE->cd();
570 }
571 char** apointer = (char**) addobj;
572 TObject* obj = (TObject*) *apointer;
573
574 fAODEvent->AddObject(obj);
575
576 const Int_t kSplitlevel = 99; // default value in TTree::Branch()
577 const Int_t kBufsize = 32000; // default value in TTree::Branch()
578
579 if (!fTreeE->FindBranch(obj->GetName())) {
580 // Do the same as if we book via
581 // TTree::Branch(TCollection*)
582
583 fTreeE->Bronch(obj->GetName(), cname, fAODEvent->GetList()->GetObjectRef(obj),
584 kBufsize, kSplitlevel - 1);
585 // fTreeA->Branch(obj->GetName(), cname, addobj);
586 }
587 owd->cd();
588}
589
590//______________________________________________________________________________
160959a9 591Bool_t AliAODExtension::Init(Option_t *option)
9066c676 592{
593// Initialize IO.
594 if(!fAODEvent) fAODEvent = new AliAODEvent();
595 TDirectory *owd = gDirectory;
160959a9 596 TString opt(option);
597 opt.ToLower();
598 if (opt.Contains("proof")) {
599 // proof
600 // Merging via files. Need to access analysis manager via interpreter.
20653795 601 gROOT->ProcessLine(Form("AliAnalysisManager::GetAnalysisManager()->OpenProofFile(\"%s\", \"RECREATE\");", fName.Data()));
160959a9 602 fFileE = gFile;
603 } else {
604 fFileE = new TFile(GetName(), "RECREATE");
605 }
9066c676 606 fTreeE = new TTree("aodTree", "AliAOD tree");
607 fTreeE->Branch(fAODEvent->GetList());
9066c676 608 owd->cd();
609 return kTRUE;
610}
611
612//______________________________________________________________________________
613Bool_t AliAODExtension::TerminateIO()
614{
615 // Terminate IO
616 if (fFileE) {
617 fFileE->Write();
618 fFileE->Close();
619 delete fFileE;
620 fFileE = 0;
621 }
622 return kTRUE;
623}