adding availability check for a list of OCDB objects, code cleanup and updated docume...
[u/mrichter/AliRoot.git] / HLT / rec / AliHLTEsdManagerImplementation.cxx
1 // $Id$
2
3 //**************************************************************************
4 //* This file is property of and copyright by the ALICE HLT Project        * 
5 //* ALICE Experiment at CERN, All rights reserved.                         *
6 //*                                                                        *
7 //* Primary Authors: Matthias Richter <Matthias.Richter@ift.uib.no>        *
8 //*                  for The ALICE HLT Project.                            *
9 //*                                                                        *
10 //* Permission to use, copy, modify and distribute this software and its   *
11 //* documentation strictly for non-commercial purposes is hereby granted   *
12 //* without fee, provided that the above copyright notice appears in all   *
13 //* copies and that both the copyright notice and this permission notice   *
14 //* appear in the supporting documentation. The authors make no claims     *
15 //* about the suitability of this software for any purpose. It is          *
16 //* provided "as is" without express or implied warranty.                  *
17 //**************************************************************************
18
19 /** @file   AliHLTEsdManagerImplementation.cxx
20     @author Matthias Richter
21     @date   
22     @brief  Manager for merging and writing of HLT ESDs
23 */
24
25 #include "AliHLTEsdManagerImplementation.h"
26 #include "AliHLTComponent.h"
27 #include "AliESDEvent.h"
28 #include "AliHLTMessage.h"
29 #include "AliESDEvent.h"
30 #include "AliESDtrack.h"
31 #include "AliESDFMD.h"
32 #include "AliESDVZERO.h"
33 #include "AliESDTZERO.h"
34 #include "AliESDCaloCells.h"
35 #include "AliMultiplicity.h"
36 #include "AliESDACORDE.h"
37 #include "TFile.h"
38 #include "TTree.h"
39 #include "TClass.h"
40 #include "TObject.h"
41 #include "TObjectTable.h"
42 #include "TSystem.h"
43 #include "TChain.h"
44 #include "TList.h"
45
46 /** ROOT macro for the implementation of ROOT specific class methods */
47 ClassImp(AliHLTEsdManagerImplementation)
48
49 AliHLTEsdManagerImplementation::AliHLTEsdManagerImplementation()
50   :
51   fESDs()
52   , fDirectory()
53   , fWriteLocal(false)
54 {
55   // see header file for class documentation
56   // or
57   // refer to README to build package
58   // or
59   // visit http://web.ift.uib.no/~kjeks/doc/alice-hlt
60 }
61
62 AliHLTEsdManagerImplementation::~AliHLTEsdManagerImplementation()
63 {
64   // see header file for class documentation
65   for (unsigned int i=0; i<fESDs.size(); i++) {
66     if (fESDs[i]) {
67       delete fESDs[i];
68     }
69     fESDs[i]=NULL;
70   }
71 }
72
73 int AliHLTEsdManagerImplementation::SetOption(const char* option)
74 {
75   // see header file for class documentation
76   int iResult=0;
77   TString strOptions=option;
78   TObjArray* pTokens=strOptions.Tokenize(" ");
79   if (pTokens) {
80     if (pTokens->GetEntriesFast()>0) {
81       for (int n=0; n<pTokens->GetEntriesFast(); n++) {
82         TString data=((TObjString*)pTokens->At(n))->GetString();
83         if (data.IsNull()) continue;
84
85         if (data.CompareTo("-writelocal")==0) {
86           fWriteLocal=true;
87         } else if (data.Contains("-directory=")) {
88           data.ReplaceAll("-directory=", "");
89           SetDirectory(data.Data());
90         } else {
91           HLTError("unknown argument %s", data.Data());
92           iResult=-EINVAL;
93           break;
94         }
95       }
96     }
97     delete pTokens;
98   }
99   return iResult;
100 }
101
102 AliHLTEsdManagerImplementation::AliHLTEsdListEntry* AliHLTEsdManagerImplementation::Find(AliHLTComponentDataType dt) const
103 {
104   // see header file for class documentation
105   AliHLTEsdListEntry* pEntry=NULL;
106   for (unsigned int i=0; i<fESDs.size(); i++) {
107     if (fESDs[i] && *(fESDs[i])==dt) {
108       pEntry=const_cast<AliHLTEsdListEntry*>(fESDs[i]);
109     }
110   }
111   return pEntry;
112 }
113
114 int AliHLTEsdManagerImplementation::WriteESD(const AliHLTUInt8_t* pBuffer, AliHLTUInt32_t size,
115                                AliHLTComponentDataType dt, AliESDEvent* tgtesd, int eventno)
116 {
117   // see header file for class documentation
118   if (!pBuffer && size<=0) return -EINVAL;
119   int iResult=0;
120   AliHLTUInt32_t firstWord=*((AliHLTUInt32_t*)pBuffer);
121   if (firstWord==size-sizeof(AliHLTUInt32_t)) {
122     HLTDebug("create object from block %s size %d", AliHLTComponent::DataType2Text(dt).c_str(), size);
123     AliHLTMessage msg(const_cast<AliHLTUInt8_t*>(pBuffer), size);
124     TClass* objclass=msg.GetClass();
125     TObject* pObj=msg.ReadObject(objclass);
126     if (pObj && objclass) {
127       HLTDebug("object %p type %s created", pObj, objclass->GetName());
128       AliESDEvent* pESD=dynamic_cast<AliESDEvent*>(pObj);
129       TTree* pTree=NULL;
130       if (!pESD) {
131         pTree=dynamic_cast<TTree*>(pObj);
132         if (pTree) {
133           pESD=new AliESDEvent;
134           pESD->CreateStdContent();
135           if (pTree->GetEntries()>0) {
136             if (pTree->GetEntries()>1) {
137               HLTWarning("only one entry allowed for ESD embedded into tree, data block %s contains tree with %d entires, taking first entry",
138                          AliHLTComponent::DataType2Text(dt).c_str(), pTree->GetEntries());
139             }
140             pESD->ReadFromTree(pTree);
141             pTree->GetEvent(0);
142           }
143         } else {
144           HLTWarning("tree of data block %s has no events, skipping data block", AliHLTComponent::DataType2Text(dt).c_str());
145         }
146       }
147       if (pESD) {
148         AliHLTEsdListEntry* entry=Find(dt);
149         if (!entry) {
150           if ((entry=new AliHLTEsdListEntry(dt))!=NULL) {
151             if (!fDirectory.IsNull()) {
152               entry->SetDirectory(fDirectory);
153             }
154             fESDs.push_back(entry);
155           }
156         }
157         if (entry) {
158           if (tgtesd) {
159 #if !defined(HAVE_NOT_ESD_COPY)
160             Merge(tgtesd, pESD);
161 #else //HAVE_NOT_ESD_COPY
162             static bool warningPrinted=false;
163             if (!warningPrinted) {
164               HLTWarning("old version of AliESDEvent does not provide assignment operator, skip merging to global hltEsd");
165             }
166             warningPrinted=true;
167 #endif //HAVE_NOT_ESD_COPY
168           }
169
170           // Matthias 2009-06-06: writing of individual ESD files for the different origins was a
171           // first attempt when functionality was missing in the AliRoot framework and remained as
172           // debugging feature. ESD merging is now implemented and data written to the hltEsd, so
173           // the feature is now disabled by default because it causes increasing memory consumption.
174           // Presumably not because of a memory leak but the way the internal TTree is used and kept
175           // in memory.
176           // Writing of local files can be optionally switched on as e.g. by the EsdCollector component.
177           if (fWriteLocal) entry->WriteESD(pESD, eventno);
178         } else {
179           HLTError("internal mismatch, can not create list entry");
180           iResult=-ENOMEM;
181         }
182       } else {
183         HLTWarning("data block %s is not of class type AliESDEvent, ignoring ...", AliHLTComponent::DataType2Text(dt).c_str());
184       }
185       if (pTree) {
186         // ESD has been created and must be cleaned up
187         pESD->Reset();
188         delete pESD;
189         pESD=NULL;
190       }
191       delete pObj;
192       pObj=NULL;
193     } else {
194     }
195   }
196   return iResult;
197 }
198
199 int AliHLTEsdManagerImplementation::PadESDs(int eventno)
200 {
201   // see header file for class documentation
202   int iResult=0;
203   for (unsigned int i=0; i<fESDs.size(); i++) {
204     if (fESDs[i]) {
205       int res=fESDs[i]->WriteESD(NULL, eventno);
206       if (res<0 && iResult>=0) iResult=res;
207     }
208   }
209   return iResult;
210 }
211
212 void AliHLTEsdManagerImplementation::SetDirectory(const char* directory)
213 {
214   // see header file for class documentation
215   if (!directory) return;
216   fDirectory=directory;
217   for (unsigned int i=0; i<fESDs.size(); i++) {
218     if (fESDs[i]) {
219       fESDs[i]->SetDirectory(directory);
220     }
221   }
222 }
223
224 TString AliHLTEsdManagerImplementation::GetFileNames(AliHLTComponentDataType dt) const
225 {
226   TString result;
227   for (unsigned int i=0; i<fESDs.size(); i++) {
228     if (fESDs[i] && *(fESDs[i])==dt) {
229       if (!result.IsNull()) result+=" ";
230       result+=fESDs[i]->GetFileName();
231     }
232   }
233   return result;
234 }
235
236 TTree* AliHLTEsdManagerImplementation::EmbedIntoTree(AliESDEvent* pESD, const char* name, const char* title)
237 {
238   // see header file for class documentation
239   int iResult=0;
240   TTree* pTree=new TTree(name, title);
241   if (pTree) {
242     pESD->WriteToTree(pTree);
243     pTree->Fill();
244     pTree->GetUserInfo()->Add(pESD);
245   } else {
246     iResult=-ENOMEM;
247   }
248
249   if (iResult<0) {
250     pTree->GetUserInfo()->Clear();
251     delete pTree;
252   }
253
254   return pTree;
255 }
256
257 AliHLTEsdManagerImplementation::AliHLTEsdListEntry::AliHLTEsdListEntry(AliHLTComponentDataType dt)
258   :
259   fName(),
260   fDirectory(),
261   fDt(dt),
262   fpFile(NULL),
263   fpTree(NULL),
264   fpEsd(NULL),
265   fPrefix()
266 {
267   // see header file for class documentation
268 }
269
270 AliHLTEsdManagerImplementation::AliHLTEsdListEntry::~AliHLTEsdListEntry()
271 {
272   // see header file for class documentation
273   if (fpEsd) delete fpEsd;
274   fpEsd=NULL;
275
276   if (fpTree) delete fpTree;
277   fpTree=NULL;
278
279   if (fpFile) {
280     fpFile->Close();
281     delete fpFile;
282   }
283   fpFile=NULL;
284 }
285
286 bool AliHLTEsdManagerImplementation::AliHLTEsdListEntry::operator==(AliHLTComponentDataType dt) const
287 {
288   // see header file for class documentation
289   return fDt==dt;
290 }
291
292 int AliHLTEsdManagerImplementation::AliHLTEsdListEntry::WriteESD(AliESDEvent* pSrcESD, int eventno)
293 {
294   // see header file for class documentation
295   int iResult=0;
296
297 #ifndef HAVE_NOT_ESD_COPY
298   if (fName.IsNull()) {
299     // this is the first event, create the file name
300     fName="";
301     if (!fDirectory.IsNull()) {
302       fName+=fDirectory; fName+="/";
303     }
304     fName+="Ali"; fName+=GetPrefix();
305     if (fDt!=kAliHLTDataTypeESDObject &&
306         fDt!=kAliHLTDataTypeESDTree) {
307
308       HLTWarning("non-standard ESD type %s", AliHLTComponent::DataType2Text(fDt).c_str());
309       TString id;
310       id.Insert(0, fDt.fID, kAliHLTComponentDataTypefIDsize);
311       id.Remove(TString::kTrailing, ' ');
312       id.ToUpper();
313       fName+="_"; fName+=id; fName+=".root";
314     } else {
315       fName+="ESDs.root";
316     }
317
318     fpFile=new TFile(fName, "RECREATE");
319     fpTree=new TTree("esdTree", "Tree with HLT ESD objects");
320     fpTree->SetDirectory(0);
321     fpEsd=new AliESDEvent;
322     if (fpEsd) {
323       fpEsd->CreateStdContent();
324       *fpEsd=*pSrcESD;
325       if (fpTree) {
326         fpEsd->WriteToTree(fpTree);
327       }
328     }
329   }
330
331   if (fpFile && fpTree && fpEsd) {
332     // synchronize and add empty events
333     fpEsd->Reset();
334     int nofCurrentEvents=fpTree->GetEntries();
335     if (nofCurrentEvents<eventno) {
336       iResult=1; // indicate tree to be written
337       HLTDebug("adding %d empty events to file %s", eventno-nofCurrentEvents, fName.Data());
338       for (int i=nofCurrentEvents; i<eventno; i++) {
339         fpTree->Fill();
340       }
341     }
342
343     if (iResult>=0 && pSrcESD) {
344       int nofObjects=fpEsd->GetList()->GetEntries();
345       *fpEsd=*pSrcESD;
346       if (nofObjects!=fpEsd->GetList()->GetEntries()) {
347         // The source ESD contains object not present in the target ESD
348         // before. Those objects will not be written to the tree since
349         // the branch layout has been created earlier.
350         // Create new tree with the additional branches, copy the entries
351         // of the current tree into the new tree, and continue.
352         TTree* pNewTree=new TTree("esdTree", "Tree with HLT ESD objects");
353         pNewTree->SetDirectory(0);
354         AliESDEvent* readESD=new AliESDEvent;
355         readESD->CreateStdContent();
356         readESD->ReadFromTree(fpTree);
357         fpEsd->Reset();
358         fpEsd->WriteToTree(pNewTree);
359         HLTDebug("cloning tree with %d entries", fpTree->GetEntries());
360         for (int event=0; event<fpTree->GetEntries(); event++) {
361           fpTree->GetEntry(event);
362           *fpEsd=*readESD;
363           pNewTree->Fill();
364           fpEsd->Reset();
365         }
366         fpFile->Close();
367         delete fpFile;
368         delete readESD;
369         delete fpTree;
370         fpFile=new TFile(fName, "RECREATE");
371         fpTree=pNewTree;
372         *fpEsd=*pSrcESD;
373         HLTDebug("new ESD with %d objects", fpEsd->GetList()->GetEntries());
374       }
375       fpTree->Fill();
376       iResult=1; // indicate tree to be written
377     }
378
379     if (iResult>0) {
380       fpFile->cd();
381       fpTree->GetUserInfo()->Add(fpEsd);
382       fpTree->Write(fpTree->GetName(),TObject::kOverwrite);
383       fpTree->GetUserInfo()->Clear();
384     }
385   }
386 #else //HAVE_NOT_ESD_COPY
387   // this is the old workaround, necessary for older AliRoot versions
388   // version<=v4-12-Release
389
390   // we need to copy the ESD, I did not find an approptiate
391   // method, the workaround is to save the ESD in a temporary
392   // tree, read the content back into the ESD structure
393   // used for filling.
394   // Unfortunately the following code crashes at the second event.
395   // The expert on the ESD (Christian Klein Boesig) does not have
396   // a solution either. It seems to be a problem in ROOT.
397   //  TTree* dummy=new TTree("dummy","dummy");
398   //  dummy->SetDirectory(0);
399   //  pESD->WriteToTree(dummy);
400   //  dummy->Fill();
401   //  dummy->GetUserInfo()->Add(pESD);
402   //  fpEsd->ReadFromTree(dummy);
403   //  dummy->GetEvent(0);
404   //  fpEsd->WriteToTree(fpTree);
405   //  fpTree->Fill();
406   //  dummy->GetUserInfo()->Clear();
407   //  delete dummy;
408   //
409   // The only way is via TChain, which is working on files only at the
410   // time of writing.
411   // We use temporary files for the new event to be copied into the
412   // existing tree.
413   //
414   if (fName.IsNull()) {
415     // this is the first event, create the file on disk and write ESD
416     TString origin;
417     origin.Insert(0, fDt.fOrigin, kAliHLTComponentDataTypefOriginSize);
418     origin.Remove(TString::kTrailing, ' ');
419     origin.ToUpper();
420     fName="";
421     if (!fDirectory.IsNull()) {
422       fName+=fDirectory; fName+="/";
423     }
424     fName+="AliHLT"; fName+=origin;
425     if (fDt!=kAliHLTDataTypeESDObject &&
426         fDt!=kAliHLTDataTypeESDTree) {
427
428       HLTWarning("non-standard ESD type %s", AliHLTComponent::DataType2Text(fDt).c_str());
429       TString id;
430       id.Insert(0, fDt.fID, kAliHLTComponentDataTypefIDsize);
431       id.Remove(TString::kTrailing, ' ');
432       id.ToUpper();
433       fName+="_"; fName+=id; fName+=".root";
434     } else {
435       fName+="ESDs.root";
436     }
437
438     if (!gSystem->AccessPathName(fName)) {
439       // file exists, delete
440       TString shellcmd="rm -f ";
441       shellcmd+=fName;
442       gSystem->Exec(shellcmd);
443     }
444   }
445
446   TChain chain("esdTree");
447   TList cleanup;
448   cleanup.SetOwner();
449
450   int nofCurrentEvents=0;
451   if (iResult>=0) {
452     if (!gSystem->AccessPathName(fName)) {
453       // these are the other events, use the target file and temporary files to merge
454       // with TChain
455       chain.Add(fName);
456
457       if (eventno>=0) {
458         TFile file(fName);
459         if (!file.IsZombie()) {
460           TTree* pSrcTree;
461           file.GetObject("esdTree", pSrcTree);
462           if (pSrcTree) {
463             nofCurrentEvents=pSrcTree->GetEntries();
464           }
465           file.Close();
466         }
467       }
468     }
469   }
470
471   // synchronize and add empty events
472   if (nofCurrentEvents<eventno) {
473     iResult=1; // indicate files to merge
474     TTree* pTgtTree=new TTree("esdTree", "Tree with HLT ESD objects");
475     if (pTgtTree) {
476       pTgtTree->SetDirectory(0);
477       AliESDEvent* pTmpESD=new AliESDEvent;
478       if (pTmpESD) {
479         TString tmpfilename;
480         FILE* pTmpFile=gSystem->TempFileName(tmpfilename);
481         if (pTmpFile) {
482           fclose(pTmpFile);
483           pTmpFile=NULL;
484           cleanup.Add(new TObjString(tmpfilename));
485           TFile emptyevents(tmpfilename, "RECREATE");
486           if (!emptyevents.IsZombie()) {
487             pTmpESD->CreateStdContent();
488             pTmpESD->WriteToTree(pTgtTree);
489             HLTDebug("adding %d empty events to file %s", eventno-nofCurrentEvents, fName.Data());
490             for (int i=nofCurrentEvents; i<eventno; i++) {
491               pTgtTree->Fill();
492             }
493             pTgtTree->GetUserInfo()->Add(pTmpESD);
494             emptyevents.cd();
495             pTgtTree->Write();
496             emptyevents.Close();
497             chain.Add(tmpfilename);
498             pTgtTree->GetUserInfo()->Clear();
499           }
500         }
501         delete pTmpESD;
502       } else {
503         iResult=-ENOMEM;
504       }
505       delete pTgtTree;
506     } else {
507       iResult=-ENOMEM;
508     }
509   }
510
511   if (iResult>=0 && pSrcESD) {
512     // add the new event to the chain
513     iResult=1; // indicate files to merge
514     TString tmpfilename=WriteTempFile(pSrcESD);
515     if (!tmpfilename.IsNull()) {
516       chain.Add(tmpfilename);
517       cleanup.Add(new TObjString(tmpfilename));
518     }
519   }
520
521   if (iResult>0) {
522     // build temporary file name for chain output
523     TString tgtName;
524     FILE* pTmpFile=gSystem->TempFileName(tgtName);
525     if (pTmpFile) {
526       fclose(pTmpFile);
527       pTmpFile=NULL;
528
529       // there have been problems with the memory consumption when using
530       // TChain::Merge
531       // but using a separate loop soemtimes crashes in AliESDEvent::ReadFromTree
532       // since this is for backward compatiblity only, we take the TChain::Merge
533       chain.Merge(tgtName);
534 //       TFile tgtFile(tgtName, "RECREATE");
535 //       TTree* pTgtTree=new TTree("esdTree", "Tree with HLT ESD objects");
536 //       AliESDEvent* pTgtESD=new AliESDEvent;
537 //       if (pTgtTree && pTgtESD) {
538 //      pTgtESD->ReadFromTree(&chain);
539 //      pTgtESD->WriteToTree(pTgtTree);
540
541 //      int nofEvents=chain.GetEntries();
542 //      for (int event=0; event<nofEvents; event++) {
543 //        chain.GetEntry(event);
544 //        pTgtTree->Fill();
545 //      }
546
547 //      pTgtTree->GetUserInfo()->Add(pTgtESD);
548 //      tgtFile.cd();
549 //      pTgtTree->Write();
550 //      pTgtTree->GetUserInfo()->Clear();
551 //       } else {
552 //      iResult=-ENOMEM;
553 //       }
554
555 //       if (pTgtTree) delete pTgtTree;
556 //       if (pTgtESD) delete pTgtESD;
557 //       tgtFile.Close();
558
559       // rename the merged file to the original file
560       TString shellcmd="mv ";
561       shellcmd+=tgtName + " " + fName;
562       if (gSystem->Exec(shellcmd)==0) {
563         HLTDebug("renaming %s to %s", tgtName.Data(), fName.Data());
564       } else {
565         HLTError("can not rename temporary file %s to %s", tgtName.Data(), fName.Data());
566       }
567     } else {
568       HLTError("can not get temporary file name from system");
569       iResult=-EBADF;
570     }
571   }
572
573   // delete temporary files
574   // the list objects are cleaned up by the TList destructor as the
575   // list is owner
576   TIter entry(&cleanup);
577   while (TObject* pObj=entry.Next()) {
578     if (dynamic_cast<TObjString*>(pObj)) {
579       TString shellcmd="rm -f ";
580       shellcmd+=(dynamic_cast<TObjString*>(pObj))->GetString();
581       gSystem->Exec(shellcmd);
582     }
583   }
584 #endif //HAVE_NOT_ESD_COPY
585
586   return iResult;
587 }
588
589 TString AliHLTEsdManagerImplementation::AliHLTEsdListEntry::WriteTempFile(AliESDEvent* pESD) const
590 {
591   // see header file for class documentation
592   int iResult=0;
593   TString tmpfilename;
594   FILE* pTmpFile=gSystem->TempFileName(tmpfilename);
595   if (pTmpFile) {
596     fclose(pTmpFile);
597     pTmpFile=NULL;
598
599     TFile file(tmpfilename, "RECREATE");
600     if (!file.IsZombie()) {
601       TTree* pTree=AliHLTEsdManagerImplementation::EmbedIntoTree(pESD);
602       if (pTree) {
603         file.cd();
604         if (pTree->Write()>0) {
605         } else {
606           HLTError("can not write esd tree to temporary file %s", tmpfilename.Data());
607         }
608
609         pTree->GetUserInfo()->Clear();
610         delete pTree;
611       } else {
612         iResult=-ENOMEM;
613       }
614       file.Close();
615     } else {
616       HLTError("can not open file %s", tmpfilename.Data());
617       iResult=-EBADF;
618     }
619   } else {
620     HLTError("can not get temporary file name from system");
621     iResult=-EBADF;
622   }
623
624   if (iResult<0) {
625     if (gSystem->AccessPathName(tmpfilename)==0) {
626       TString shellcmd="rm -f ";
627       shellcmd+=tmpfilename;
628       gSystem->Exec(shellcmd);
629     }
630     tmpfilename="";
631   }
632   return tmpfilename;
633 }
634
635 void AliHLTEsdManagerImplementation::AliHLTEsdListEntry::SetDirectory(const char* directory)
636 {
637   // see header file for class documentation
638   if (!directory) return;
639   if (!fName.IsNull()) {
640     HLTWarning("ESD entry already in writing mode (%s), ignoring directory", fName.Data());
641     return;
642   }
643   fDirectory=directory;
644 }
645
646 void AliHLTEsdManagerImplementation::AliHLTEsdListEntry::Delete()
647 {
648   // see header file for class documentation
649   if (fName.IsNull()) return;
650   if (gSystem->AccessPathName(fName)!=0) return;
651
652   TString shellcmd="rm -f ";
653   shellcmd+=fName;
654   gSystem->Exec(shellcmd);
655   fName="";
656 }
657
658 const char* AliHLTEsdManagerImplementation::AliHLTEsdListEntry::GetFileName() const
659 {
660   // see header file for class documentation
661   return fName.Data();
662 }
663
664 const char* AliHLTEsdManagerImplementation::AliHLTEsdListEntry::GetPrefix()
665 {
666   // see header file for class documentation
667   if (fPrefix.IsNull()) {
668     fPrefix.Insert(0, fDt.fOrigin, kAliHLTComponentDataTypefOriginSize);
669     fPrefix.Remove(TString::kTrailing, ' ');
670     fPrefix.ToUpper();
671     if (!fPrefix.Contains("HLT")) {
672       fPrefix.Insert(0, "HLT");
673     }
674   }
675   return fPrefix.Data();
676 }
677
678 int AliHLTEsdManagerImplementation::Merge(AliESDEvent* pTgt, AliESDEvent* pSrc) const
679 {
680   // see header file for class documentation
681   int iResult=0;
682   if (!pTgt || !pSrc) return -EINVAL;
683
684   TIter next(pSrc->GetList());
685   TObject* pSrcObject=NULL;
686   static int warningCount=0;
687   while ((pSrcObject=next())) {
688     if(!pSrcObject->InheritsFrom("TCollection")){
689       // simple objects
690       // for every type of object we have to find out whether it is empty or not
691       // objects are only copied if non-empty, otherwise valid content would be
692       // overridden by empty objects during the merging
693       bool copy=false;
694       TString name=pSrcObject->GetName();
695       if(pSrcObject->InheritsFrom("AliHLTTriggerDecision")){
696         copy=true;
697       } else if (pSrcObject->IsA()==AliESDRun::Class()) {
698         AliESDRun* pESDRun=dynamic_cast<AliESDRun*>(pSrcObject);
699         // zero might be a valid run no in simulation, so we check also whether the CTP trigger classes are set
700         copy=(pESDRun && (pESDRun->GetRunNumber()>0 || !pESDRun->GetActiveTriggerClasses().IsNull()));
701       } else if (pSrcObject->IsA()==AliESDHeader::Class()) {
702         AliESDHeader* pESDHeader=dynamic_cast<AliESDHeader*>(pSrcObject);
703         copy=(pESDHeader && pESDHeader->GetTriggerMask()!=0);
704       } else if (pSrcObject->IsA()==AliESDVertex::Class()) {
705         AliESDVertex* pESDVertex=dynamic_cast<AliESDVertex*>(pSrcObject);
706         copy=(pESDVertex && pESDVertex->GetNContributors()>0);
707       } else if (pSrcObject->IsA()==AliESDTZERO::Class()) {
708         AliESDTZERO* pESDTZero=dynamic_cast<AliESDTZERO*>(pSrcObject);
709         copy=(pESDTZero && (pESDTZero->GetT0zVertex()!=0.0 || pESDTZero->GetT0()!=0.0));
710       } else if (pSrcObject->IsA()==AliESDVZERO::Class()) {
711         AliESDVZERO* pESDVZero=dynamic_cast<AliESDVZERO*>(pSrcObject);
712         copy=(pESDVZero && false); // could not find an easy valid condition
713       } else if (pSrcObject->IsA()==AliESDFMD::Class()) {
714         AliESDFMD* pESDFMD=dynamic_cast<AliESDFMD*>(pSrcObject);
715         copy=(pESDFMD && false); // have to find an easy valid condition
716       } else if (pSrcObject->IsA()==AliESDZDC::Class()) {
717         AliESDZDC* pESDZDC=dynamic_cast<AliESDZDC*>(pSrcObject);
718         copy=(pESDZDC && false); // have to find an easy valid condition
719       } else if (pSrcObject->IsA()==AliMultiplicity::Class()) {
720         AliMultiplicity* pMultiplicity=dynamic_cast<AliMultiplicity*>(pSrcObject);
721         copy=(pMultiplicity && pMultiplicity->GetNumberOfTracklets()>0);
722       } else if (pSrcObject->IsA()==AliESDCaloTrigger::Class()) {
723         AliESDCaloTrigger* pESDCaloTrigger=dynamic_cast<AliESDCaloTrigger*>(pSrcObject);
724         copy=(pESDCaloTrigger && false); // have to find an easy valid condition
725       } else if (pSrcObject->IsA()==AliESDCaloCells::Class()) {
726         AliESDCaloCells* pESDCaloCells=dynamic_cast<AliESDCaloCells*>(pSrcObject);
727         copy=(pESDCaloCells && false); // have to find an easy valid condition
728       } else if (pSrcObject->IsA()==AliESDACORDE::Class()) {
729         AliESDACORDE* pESDACORDE=dynamic_cast<AliESDACORDE*>(pSrcObject);
730         copy=(pESDACORDE && false); // have to find an easy valid condition
731       } else {
732           HLTError("no merging implemented for object %s, omitting", name.Data());
733       }
734       if (copy) {
735         //pSrcObject->Print();
736         TObject* pTgtObject=pTgt->FindListObject(name);
737         if (pTgtObject) {
738           pSrcObject->Copy(*pTgtObject);
739         } else {
740           pTgt->AddObject(pSrcObject->Clone());
741         }
742       }
743     } else if(pSrcObject->InheritsFrom("TClonesArray")){
744       TClonesArray* pTClA=dynamic_cast<TClonesArray*>(pSrcObject);
745       if (pTClA!=NULL && pTClA->GetEntriesFast()>0) {
746         TString name=pTClA->GetName();
747         TObject* pTgtObject=pTgt->GetList()->FindObject(name);
748         TClonesArray* pTgtArray=NULL;
749         if (pTgtObject!=NULL && pTgtObject->InheritsFrom("TClonesArray")){
750           pTgtArray=dynamic_cast<TClonesArray*>(pTgtObject);
751           if (pTgtArray) {
752             TString classType=pTClA->Class()->GetName();
753             if (classType.CompareTo(pTgtArray->Class()->GetName())==0) {
754               if (pTgtArray->GetEntries()==0) {
755                 pTgtArray->ExpandCreate(pTClA->GetEntries());
756                 for(int i=0; i<pTClA->GetEntriesFast(); ++i){
757                   (*pTClA)[i]->Copy(*((*pTgtArray)[i]));
758                 }
759               } else {
760                 if (warningCount++<10) {
761                   HLTWarning("TClonesArray \"%s\"  in target ESD %p is already filled with %d entries",
762                              name.Data(), pTgt, pTgtArray->GetEntries());
763                 }
764                 iResult=-EBUSY;
765               }
766             } else {
767               if (warningCount++<10) {
768                 HLTWarning("TClonesArray \"%s\" exists in target ESD %p, but describes incompatible class type %s instead of %s",
769                            name.Data(), pTgt, pTgtArray->GetClass()->GetName(), pTClA->GetClass()->GetName());
770               }
771               iResult=-EBUSY;
772             }
773           } else {
774             if (warningCount++<10) {
775               HLTError("internal error: dynamic cast failed for object %s %p", pTgtObject->GetName(), pTgtObject);
776             }
777             iResult=-EBUSY;
778           }
779         } else if (pTgtObject) {
780           if (warningCount++<10) {
781             HLTWarning("object \"%s\" does already exist in target ESD %p, but is %s rather than TClonesArray"
782                        " skipping data",
783                        name.Data(), pTgt, pTgtObject->Class()->GetName());
784           }
785           iResult=-EBUSY;
786         } else {
787           if (warningCount++<10) {
788             HLTWarning("object \"%s\" does not exist in target ESD %p, data can not be copied because it will be lost when filling the tree",
789                        name.Data(), pTgt);
790           }
791           iResult=-ENOENT;
792         }
793       }
794     }
795   }
796   return iResult;
797 }