8296912930f9bd3a54ef847fde45a22dfb18ae68
[u/mrichter/AliRoot.git] / HLT / TRD / AliHLTTRDTrackerV1Component.cxx
1 // $Id: AliHLTTRDTrackerV1Component.cxx 23618 2008-01-29 13:07:38Z hristov $
2
3 /**************************************************************************
4  * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
5  *                                                                        *
6  * Authors: Matthias Richter <Matthias.Richter@ift.uib.no>                *
7  *          Timm Steinbeck <timm@kip.uni-heidelberg.de>                   *
8  *          for The ALICE Off-line 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   AliHLTTRDTrackerV1Component.cxx
20     @author Timm Steinbeck, Matthias Richter
21     @date   
22     @brief  A TRDTrackerV1 processing component for the HLT. */
23
24 #if __GNUC__ >= 3
25 using namespace std;
26 #endif
27
28 #include "AliHLTTRDTrackerV1Component.h"
29 #include "AliHLTTRDDefinitions.h"
30 #include "AliHLTTRDCluster.h"
31 #include "AliHLTTRDTrack.h"
32
33 #include "TFile.h"
34 #include "TChain.h"
35
36 #include "AliGeomManager.h"
37 #include "AliCDBManager.h"
38 #include "AliESDEvent.h"
39 #include "AliMagF.h"
40 #include "AliESDfriend.h"
41
42 #include "AliTRDcalibDB.h"
43 #include "AliTRDReconstructor.h"
44 #include "AliTRDtrackerV1.h"
45 #include "AliTRDrecoParam.h"
46
47 #include <cstdlib>
48 #include <cerrno>
49 #include <string>
50
51 #ifdef HAVE_VALGRIND_CALLGRIND_H
52 #include <valgrind/callgrind.h>
53 #else
54 #define CALLGRIND_START_INSTRUMENTATION() do { } while (0)
55 #define CALLGRIND_STOP_INSTRUMENTATION() do { } while (0)
56 #endif
57
58 ClassImp(AliHLTTRDTrackerV1Component);
59     
60 AliHLTTRDTrackerV1Component::AliHLTTRDTrackerV1Component():
61   AliHLTProcessor(),
62   fOutputPercentage(100), // By default we copy to the output exactly what we got as input  
63   fStrorageDBpath("local://$ALICE_ROOT/OCDB"),
64   fCDB(NULL),
65   fGeometryFileName(""),
66   fUseHLTClusters(kFALSE),
67   fUseHLTTracks(kFALSE),
68   fTracker(NULL),
69   fRecoParam(NULL),
70   fReconstructor(NULL)
71 {
72   // Default constructor
73
74   fGeometryFileName = getenv("ALICE_ROOT");
75   fGeometryFileName += "/HLT/TRD/geometry.root";
76 }
77
78 AliHLTTRDTrackerV1Component::~AliHLTTRDTrackerV1Component()
79 {
80   // Destructor
81 }
82
83 const char* AliHLTTRDTrackerV1Component::GetComponentID()
84 {
85   // Return the component ID const char *
86   return "TRDTrackerV1"; // The ID of this component
87 }
88
89 void AliHLTTRDTrackerV1Component::GetInputDataTypes( vector<AliHLTComponent_DataType>& list)
90 {
91   // Get the list of input data  
92   list.clear(); // We do not have any requirements for our input data type(s).
93   list.push_back( AliHLTTRDDefinitions::fgkClusterDataType );
94 }
95
96 AliHLTComponent_DataType AliHLTTRDTrackerV1Component::GetOutputDataType()
97 {
98   // Get the output data type
99   return AliHLTTRDDefinitions::fgkClusterDataType;
100 }
101
102 void AliHLTTRDTrackerV1Component::GetOutputDataSize( unsigned long& constBase, double& inputMultiplier )
103 {
104   // Get the output data size
105   constBase = 0;
106   inputMultiplier = ((double)fOutputPercentage)/100.0;
107 }
108
109 // Spawn function, return new instance of this class
110 AliHLTComponent* AliHLTTRDTrackerV1Component::Spawn()
111 {
112   return new AliHLTTRDTrackerV1Component;
113 };
114
115 /**
116  * Convert AliTRDtrackV1 to AliHLTTRDTrack 
117  * Add HLTTrack to the output, defined by pointer
118  * Fill block desctiptors 
119  * Return size of the added to ouput objects
120  */
121 //============================================================================
122 AliHLTUInt32_t AliHLTTRDTrackerV1Component::AddToOutput(TClonesArray* inTrackArray, AliHLTUInt8_t* output)
123 {
124   cout << "\nWriting tracks to the Memory\n ============= \n";
125   AliTRDtrackV1* track = 0;
126   AliHLTUInt32_t addedSize = 0;
127   AliHLTUInt8_t *iterPtr = output;
128   AliHLTTRDTrack * outPtr = (AliHLTTRDTrack*)iterPtr;
129   
130   if (inTrackArray){
131     Int_t nbTracks  = inTrackArray->GetEntries();
132     for (Int_t iTrack = 0; iTrack<nbTracks; iTrack++){
133       AliHLTUInt32_t trackSize=0;
134       
135       track = dynamic_cast<AliTRDtrackV1*>(inTrackArray->At(iTrack));
136       //track->Print();
137       
138       AliHLTTRDTrack *hltTrack = new (outPtr) AliHLTTRDTrack(track);
139       trackSize = hltTrack->GetSize();
140       addedSize += trackSize;
141       HLTDebug("addedSize %i, trackSize %i", addedSize, trackSize);
142       
143       iterPtr += trackSize;
144       outPtr = (AliHLTTRDTrack*)iterPtr;
145     }
146   }
147   return addedSize;
148   
149 }
150
151 int AliHLTTRDTrackerV1Component::DoInit( int argc, const char** argv )
152 {
153   // perform initialization. We check whether our relative output size is specified in the arguments.
154   fOutputPercentage = 100;
155   int i = 0;
156   char* cpErr;
157   
158
159   Int_t iRecoParamType = -1; // default will be the low flux
160   Int_t iNtimeBins = -1;     // number of time bins for the tracker to use
161   Int_t iMagneticField = -1; // magnetic field: 0==OFF and 1==ON
162   Bool_t bHLTMode = kTRUE, bWriteClusters = kFALSE;
163   
164   while ( i < argc )
165     {
166       HLTDebug("argv[%d] == %s", i, argv[i] );
167       if ( !strcmp( argv[i], "output_percentage" ) )
168         {
169           if ( i+1>=argc )
170             {
171               HLTError("Missing output_percentage parameter");
172               return ENOTSUP;
173             }
174           HLTDebug("argv[%d+1] == %s", i, argv[i+1] );
175           fOutputPercentage = strtoul( argv[i+1], &cpErr, 0 );
176           if ( *cpErr )
177             {
178               HLTError("Cannot convert output_percentage parameter '%s'", argv[i+1] );
179               return EINVAL;
180             }
181           HLTInfo("Output percentage set to %lu %%", fOutputPercentage );
182           i += 2;
183           
184         }
185
186       else if ( !strcmp( argv[i], "-NTimeBins" ) )
187         {
188           if ( i+1>=argc )
189             {
190               HLTError("Missing -NTimeBins parameter");
191               return ENOTSUP;
192             }
193           HLTDebug("Arguments", "argv[%d+1] == %s", i, argv[i+1] );
194           iNtimeBins = strtoul( argv[i+1], &cpErr, 0 );
195           if ( *cpErr )
196             {
197               HLTError("Wrong Argument. Cannot convert -NTimeBins parameter '%s'", argv[i+1] );
198               return EINVAL;
199             }     
200           i += 2;
201           
202         }
203
204       else if ( strcmp( argv[i], "-cdb" ) == 0)
205         {
206           if ( i+1 >= argc )
207             {
208               HLTError( "Missing -cdb argument");
209               return ENOTSUP;         
210             }
211           fStrorageDBpath = argv[i+1];
212           HLTInfo("DB storage is %s", fStrorageDBpath.c_str() );          
213           i += 2;
214           
215         }      
216
217       else if ( strcmp( argv[i], "-geometry" ) == 0)
218         {
219           if ( i+1 >= argc )
220             {
221               HLTError("Missing -geometry argument");
222               return ENOTSUP;         
223             }
224           fGeometryFileName = argv[i+1];
225           HLTInfo("GeomFile storage is %s", 
226                   fGeometryFileName.c_str() );    
227           i += 2;
228           
229         }      
230
231       // the flux parametrizations
232       else if ( strcmp( argv[i], "-lowflux" ) == 0)
233         {
234           iRecoParamType = 0;     
235           HLTDebug("Low flux reco selected.");
236           i++;
237           
238         }      
239       
240       else if ( strcmp( argv[i], "-highflux" ) == 0)
241         {
242           iRecoParamType = 1;     
243           HLTDebug("Low flux reco selected.");
244           i++;
245         }      
246
247       else if ( strcmp( argv[i], "-cosmics" ) == 0)
248         {
249           iRecoParamType = 2;     
250           HLTDebug("Cosmic test reco selected.");
251           i++;
252         }      
253
254       else if ( strcmp( argv[i], "-magnetic_field_ON" ) == 0)
255         {
256           iMagneticField = 1;
257           i++;
258         }
259       else if ( strcmp( argv[i], "-magnetic_field_OFF" ) == 0)
260         {
261           iMagneticField = 0;
262           i++;
263         }
264       else if ( strcmp( argv[i], "-writeClusters" ) == 0)
265         {
266           bWriteClusters = kTRUE;
267           HLTDebug("input clusters are expected to be in a TTree.");
268           i++;
269         }
270       else if ( strcmp( argv[i], "-offlineMode" ) == 0)
271         {
272           bHLTMode=kFALSE;
273           HLTDebug("Using standard offline tracking.");
274           i++;
275         }
276       else if ( strcmp( argv[i], "-useHLTClusters" ) == 0)
277         {
278           fUseHLTClusters = kTRUE;
279           i++;
280           HLTInfo("expecting AliHLTCluster as input");
281         }
282       else if ( strcmp( argv[i], "-useHLTTracks" ) == 0)
283         {
284           fUseHLTTracks = kTRUE;
285           i++;
286           HLTInfo("Using AliHLTTrack to pass data further in the chain");
287         }
288       else {
289         HLTError("Unknown option '%s'", argv[i] );
290         return EINVAL;
291       }
292       
293     }
294
295   // THE "REAL" INIT COMES HERE
296   // offline condition data base
297   fCDB = AliCDBManager::Instance();
298   if (!fCDB)
299     {
300       HLTError("Could not get CDB instance", "fCDB 0x%x", fCDB);
301       return -1;
302     }
303   else
304     {
305       fCDB->SetRun(0); // THIS HAS TO BE RETRIEVED !!!
306       fCDB->SetDefaultStorage(fStrorageDBpath.c_str());
307       HLTDebug("CDB instance", "fCDB 0x%x", fCDB);
308     }
309
310   // check if the N of time bins make sense
311   if (iNtimeBins <= 0)
312     {
313       HLTError("Sorry. Tracker needs number of time bins. At the moment you have to provide it with -NTimeBins <value>. The simulation always had 24 and the real data 30. Take your pick. Make sure the information is correct. Ask offline to implement how to propagate this information into clusters/cluster tree.");
314       return -1;
315     }
316
317   if (iNtimeBins < 24 || iNtimeBins > 30)
318     {
319       HLTWarning("The number of time bins seems to be strange = %d. But okay. Let's try it...", iNtimeBins);
320     }
321
322   HLTDebug("The number of time bins = %d.", iNtimeBins);
323   AliTRDtrackerV1::SetNTimeBins(iNtimeBins);
324
325   // !!!! THIS IS IMPORTANT
326   // init alifield map - temporarly via parameter - should come from a DB or DCS ?
327   // !!!! 
328   if (iMagneticField < 0)
329     {
330       iMagneticField = 0;
331       HLTWarning("No magnetic field switch stated. Use -magnetic_field_ON or -magnetic_field_OFF flag. Defaulting to OFF = NO MAGNETIC FIELD");
332     }
333   
334   if (!TGeoGlobalMagField::Instance()->IsLocked()) {
335     if (iMagneticField == 0)
336       {
337         // magnetic field OFF
338         AliMagF* field = new AliMagF("Maps","Maps",2,0.,0., 10.,AliMagF::k5kGUniform);
339         TGeoGlobalMagField::Instance()->SetField(field);
340         HLTDebug("Magnetic field is OFF.");
341       }
342     
343     if (iMagneticField == 1)
344       {
345         // magnetic field ON
346         AliMagF* field = new AliMagF("Maps","Maps",2,1.,1., 10.,AliMagF::k5kG);
347         TGeoGlobalMagField::Instance()->SetField(field);
348         HLTDebug("Magnetic field is ON.");
349       }
350   }
351   else {
352     HLTError("Magnetic field is already set and locked, cannot redefine it." );
353   }
354
355   // reconstruction parameters
356   if (iRecoParamType < 0 || iRecoParamType > 2)
357     {
358       HLTWarning("No reco param selected. Use -lowflux -highflux -cosmics flags. Defaulting to low flux.");
359       iRecoParamType = 0;
360     }
361
362   if (iRecoParamType == 0)
363     {
364       fRecoParam = AliTRDrecoParam::GetLowFluxParam();
365       HLTDebug("Low flux params init.");
366     }
367
368   if (iRecoParamType == 1)
369     {
370       fRecoParam = AliTRDrecoParam::GetHighFluxParam();
371       HLTDebug("High flux params init.");
372     }
373   
374   if (iRecoParamType == 2)
375     {
376       fRecoParam = AliTRDrecoParam::GetCosmicTestParam();
377       HLTDebug("Cosmic Test params init.");
378     }
379
380   if (fRecoParam == 0)
381     {
382       HLTError("No reco params initialized. Sniffing big trouble!");
383       return -1;
384     }
385
386   fReconstructor = new AliTRDReconstructor();
387   //   fRecoParam->SetChi2Y(.1);
388   //   fRecoParam->SetChi2Z(5.);
389   fReconstructor->SetRecoParam(fRecoParam);
390   // write clusters [cw] = true
391   // track seeding (stand alone tracking) [sa] = true
392   // PID method in reconstruction (NN) [nn] = true
393   // write online tracklets [tw] = false
394   // drift gas [ar] = false
395   // sl_tr_0 = StreamLevel_task_Level
396   //  fReconstructor->SetOption("sa,!cw,hlt,sl_tr_0");
397   TString recoOptions="sa,sl_tr_0";
398   
399   if (bWriteClusters)
400     {
401       recoOptions += ",cw";
402     } 
403   else
404     {
405       recoOptions += ",!cw";
406     }
407   if (bHLTMode)
408     recoOptions += ",hlt";
409   
410   fReconstructor->SetOption(recoOptions.Data());
411   HLTDebug("Reconstructor options are: %s",recoOptions.Data());
412   
413   if((AliGeomManager::GetGeometry()) == NULL){
414     
415     if ( TFile::Open(fGeometryFileName.c_str())) {
416       AliGeomManager::LoadGeometry(fGeometryFileName.c_str());
417     }
418     else {
419       HLTError("Cannot load geometry from file %s",fGeometryFileName.c_str());
420       return EINVAL;
421     }
422   }
423   else
424     HLTInfo("Geometry Already Loaded");
425   
426   // create the tracker
427   fTracker = new AliTRDtrackerV1();
428   fTracker->SetReconstructor(fReconstructor);
429   HLTDebug("TRDTracker at 0x%x", fTracker);
430
431   if (fTracker == 0)
432     {
433       HLTError("Unable to create the tracker!");
434       return -1;
435     }
436
437   return 0;
438 }
439
440 int AliHLTTRDTrackerV1Component::DoDeinit()
441 {
442   // Deinitialization of the component
443
444   fTracker->SetClustersOwner(kFALSE);
445   delete fTracker;
446   fTracker = 0x0;
447   
448   // We need to set clusters in Reconstructor to null to prevent from 
449   // double deleting, since we delete TClonesArray by ourself in DoEvent.
450   fReconstructor->SetClusters(0x0);
451   delete fReconstructor;
452   fReconstructor = 0x0;
453   
454   AliTRDcalibDB::Terminate();
455
456   return 0;
457 }
458
459 int AliHLTTRDTrackerV1Component::DoEvent( const AliHLTComponentEventData& evtData, 
460                                           const AliHLTComponentBlockData* blocks, 
461                                           AliHLTComponent_TriggerData& /*trigData*/, 
462                                           AliHLTUInt8_t* outputPtr, 
463                                           AliHLTUInt32_t& size, 
464                                           vector<AliHLTComponent_BlockData>& outputBlocks )
465 {
466   // Process an event
467   Bool_t bWriteClusters = fReconstructor->IsWritingClusters();
468
469   HLTDebug("NofBlocks %lu", evtData.fBlockCnt );
470   
471   AliHLTUInt32_t totalSize = 0, offset = 0;
472   AliHLTUInt32_t dBlockSpecification = 0;
473
474   vector<AliHLTComponent_DataType> expectedDataTypes;
475   GetInputDataTypes(expectedDataTypes);
476   if (evtData.fEventID == 1)
477     CALLGRIND_START_INSTRUMENTATION();
478   for ( unsigned long iBlock = 0; iBlock < evtData.fBlockCnt; iBlock++ ) 
479     {
480       const AliHLTComponentBlockData &block = blocks[iBlock];
481       offset = totalSize;
482       AliHLTComponentDataType inputDataType = block.fDataType;
483       Bool_t correctDataType = kFALSE;
484       
485       for(UInt_t i = 0; i < expectedDataTypes.size(); i++)
486         if( expectedDataTypes.at(i) == inputDataType)
487           correctDataType = kTRUE;
488       if (!correctDataType)
489         {
490           HLTDebug( "Block # %i/%i; Event 0x%08LX (%Lu) Wrong received datatype: %s - Skipping",
491                     iBlock, evtData.fBlockCnt-1,
492                     evtData.fEventID, evtData.fEventID, 
493                     DataType2Text(inputDataType).c_str());
494           continue;
495         }
496       else 
497         HLTDebug("We get the right data type: Block # %i/%i; Event 0x%08LX (%Lu) Received datatype: %s",
498                     iBlock, evtData.fBlockCnt-1,
499                     evtData.fEventID, evtData.fEventID, 
500                     DataType2Text(inputDataType).c_str());
501       
502       
503       TTree *clusterTree = 0x0;
504       TClonesArray* clusterArray = 0x0;
505       ReadAndLoadClusters(clusterTree, clusterArray, &block);
506       
507       // maybe it is not so smart to create it each event? clear is enough ?
508       AliESDEvent *esd = new AliESDEvent();
509       esd->CreateStdContent();
510       fTracker->Clusters2Tracks(esd);
511
512       //here transport the esd tracks further
513       Int_t nTracks = esd->GetNumberOfTracks();
514       Int_t nTRDTracks = esd->GetNumberOfTrdTracks();
515       HLTInfo("Number of tracks  == %d == Number of TRD tracks %d", nTracks, nTRDTracks);  
516
517       TClonesArray* trdTracks = fTracker->GetListOfTracks();
518    
519       if (trdTracks)
520         totalSize += TransportTracks(trdTracks, outputPtr, outputBlocks, offset, dBlockSpecification);
521       else 
522         HLTDebug("Bad array trdTracks = 0x%x", trdTracks);
523       HLTDebug("totalSize: %i", totalSize);
524       
525 //       if ( totalSize > allocSize )
526 //      {
527 //        HLTError("Too much data; Data written over allowed buffer. Amount written: %lu, allowed amount: %lu.",
528 //        totalSize, size );
529 //        return EMSGSIZE;
530 //      }
531
532       //here we are deleting clusters (but not the TClonesArray itself)
533       fTracker->UnloadClusters();
534
535       AliTRDReconstructor::SetClusters(0x0);
536       delete esd;
537       if (bWriteClusters)
538         delete clusterTree;
539       else{
540         //clusterArray->Delete();
541         delete clusterArray;
542       }
543       
544     }
545   size = totalSize;
546   HLTDebug("Event is done. size written to the output is %i", size);
547   //  CALLGRIND_STOP_INSTRUMENTATION();
548   return 0;
549 }
550
551
552 /**
553  * ReadClusters from the component input and load them to the tracker
554  */
555 //============================================================================
556 void AliHLTTRDTrackerV1Component::ReadAndLoadClusters(TTree *inClusterTree, 
557                                                       TClonesArray *inClusterArray, const AliHLTComponentBlockData *inBlock)
558 {
559   Bool_t bWriteClusters = fReconstructor->IsWritingClusters();
560   const AliHLTComponentBlockData &block = *inBlock;
561
562
563   TObject *tobjin = 0x0;
564   int ibForce = 0; // almost obsolet
565
566   if (bWriteClusters){
567     tobjin = (TObject *)GetFirstInputObject( AliHLTTRDDefinitions::fgkClusterDataType, "TTree", ibForce);
568     HLTDebug("1stBLOCK; Pointer = 0x%x", tobjin);
569     inClusterTree = (TTree*)tobjin;
570     if (inClusterTree)
571       {
572         HLTDebug("CLUSTERS; Pointer to TTree = 0x%x Name = %s", inClusterTree, inClusterTree->GetName());
573         HLTDebug("TTree of clusters: nbEntries = %i", inClusterTree->GetEntriesFast());
574         fTracker->LoadClusters(inClusterTree);
575       }
576     else
577       {
578         HLTError("First Input Block is not a TTree 0x%x", tobjin);
579       }
580   }
581   else if (fUseHLTClusters)
582     {
583       inClusterArray = new TClonesArray("AliTRDcluster"); // would be nice to allocate memory for all clusters here.
584       ReadClusters(inClusterArray, block.fPtr, block.fSize);
585       HLTDebug("TClonesArray of clusters: nbEntries = %i", inClusterArray->GetEntriesFast());
586       fTracker->LoadClusters(inClusterArray);
587     }
588   else
589     {
590       tobjin = (TObject *)GetFirstInputObject( AliHLTTRDDefinitions::fgkClusterDataType, "TClonesArray", ibForce);
591       HLTDebug("1stBLOCK; Pointer = 0x%x", tobjin);
592       inClusterArray = (TClonesArray*)tobjin;
593       if (inClusterArray)
594         {
595           HLTDebug("CLUSTERS; Pointer to TClonesArray = 0x%x Name = %s", inClusterArray, inClusterArray->GetName());
596           HLTDebug("TClonesArray of clusters: nbEntries = %i", inClusterArray->GetEntriesFast());
597           fTracker->LoadClusters(inClusterArray);
598         }
599       else
600         {
601           HLTError("First Input Block not a TClonesArray 0x%x", tobjin);
602         }
603     }
604 }
605
606 /**
607  * Read cluster to the TClonesArray from the memory 
608  */
609 //============================================================================
610 Int_t AliHLTTRDTrackerV1Component::ReadClusters(TClonesArray *outArray, void* inputPtr, AliHLTUInt32_t size)
611 {
612   //HLTDebug("\nReading clusters from the Memory\n ============= \n");
613   AliHLTTRDCluster * curCluster;
614   UInt_t clusterSize = sizeof(AliHLTTRDCluster), curSize = 0;
615   Int_t i=0;
616   
617   curCluster = (AliHLTTRDCluster*) inputPtr;
618   while (curSize + clusterSize <= size)
619     {
620       //  HLTDebug(" fX = %f; fY = %f; fZ = %f", curCluster->fX, curCluster->fY, curCluster->fZ);
621
622       AliTRDcluster* curTRDCluster = new((*outArray)[i]) AliTRDcluster();
623       curCluster->ExportTRDCluster(curTRDCluster);
624       //      HLTDebug(" fX = %f; fY = %f; fZ = %f", curTRDCluster->GetX(), curTRDCluster->GetY(), curTRDCluster->GetZ());
625       curSize += clusterSize; 
626       i++;
627       curCluster++;
628       //cout << " current readed size is " << curSize << "/" << size << endl;
629     }
630   
631   return i;
632 }
633 /**
634  * Transport tracks to the next component
635  * Return Numbers of bytes written to the output
636  */
637 //============================================================================
638 AliHLTUInt32_t AliHLTTRDTrackerV1Component::TransportTracks(TClonesArray *inTracksArray, AliHLTUInt8_t* output,
639                                                     vector<AliHLTComponent_BlockData>& outputBlocks, AliHLTUInt32_t inOffset, AliHLTUInt32_t inSpec)
640 {
641   Int_t nbTracks=inTracksArray->GetEntriesFast();
642   if (nbTracks>0)
643     {
644       HLTDebug("We have an output array: pointer to inTracksArray = 0x%x, nbEntries = %i", inTracksArray, nbTracks);
645       if (fUseHLTTracks){
646         // Using low-level interface 
647         // with interface classes
648         AliHLTUInt32_t addedSize = AddToOutput(inTracksArray, output);
649         
650         // Fill block 
651         AliHLTComponentBlockData bd;
652         FillBlockData( bd );
653
654         bd.fPtr = output;
655         bd.fOffset = inOffset;
656         bd.fSize = addedSize;
657         bd.fSpecification = inSpec;
658         bd.fDataType = AliHLTTRDDefinitions::fgkTRDSATracksDataType;
659         outputBlocks.push_back( bd );
660         HLTDebug("BD fPtr 0x%x, fOffset %i, fSize %i, fSpec 0x%x", bd.fPtr, bd.fOffset, bd.fSize, bd.fSpecification);
661         
662         return addedSize;
663       }
664       else{
665         inTracksArray->BypassStreamer(kFALSE);
666         PushBack(inTracksArray, AliHLTTRDDefinitions::fgkTRDSATracksDataType);
667         return 0;
668       }
669           
670     }
671   return 0;
672   
673 }