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