]> git.uio.no Git - u/mrichter/AliRoot.git/blame - TRD/AliTRDclusterizer.cxx
Adding new class to calibrate TPC space point unlinearities
[u/mrichter/AliRoot.git] / TRD / AliTRDclusterizer.cxx
CommitLineData
f7336fa3 1/**************************************************************************
317b5644 2* Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
3* *
4* Author: The ALICE Off-line Project. *
5* Contributors are mentioned in the code where appropriate. *
6* *
7* Permission to use, copy, modify and distribute this software and its *
8* documentation strictly for non-commercial purposes is hereby granted *
9* without fee, provided that the above copyright notice appears in all *
10* copies and that both the copyright notice and this permission notice *
11* appear in the supporting documentation. The authors make no claims *
12* about the suitability of this software for any purpose. It is *
13* provided "as is" without express or implied warranty. *
14**************************************************************************/
f7336fa3 15
88cb7938 16/* $Id$ */
f7336fa3 17
18///////////////////////////////////////////////////////////////////////////////
19// //
3fe61b77 20// TRD cluster finder //
f7336fa3 21// //
22///////////////////////////////////////////////////////////////////////////////
23
3fe61b77 24#include <TF1.h>
94de3818 25#include <TTree.h>
3fe61b77 26#include <TH1.h>
793ff80c 27#include <TFile.h>
66f6bfd9 28#include <TClonesArray.h>
6d50f529 29#include <TObjArray.h>
f7336fa3 30
88cb7938 31#include "AliRunLoader.h"
32#include "AliLoader.h"
3fe61b77 33#include "AliRawReader.h"
6d50f529 34#include "AliLog.h"
3fe61b77 35#include "AliAlignObj.h"
88cb7938 36
f7336fa3 37#include "AliTRDclusterizer.h"
3e1a3ad8 38#include "AliTRDcluster.h"
fc546d21 39#include "AliTRDReconstructor.h"
793ff80c 40#include "AliTRDgeometry.h"
b65e5048 41#include "AliTRDarraySignal.h"
42#include "AliTRDarrayDictionary.h"
43#include "AliTRDarrayADC.h"
3fe61b77 44#include "AliTRDdigitsManager.h"
45#include "AliTRDrawData.h"
3551db50 46#include "AliTRDcalibDB.h"
fc546d21 47#include "AliTRDrecoParam.h"
b43a3e17 48#include "AliTRDCommonParam.h"
3fe61b77 49#include "AliTRDtransform.h"
50#include "AliTRDSignalIndex.h"
dfbb4bb9 51#include "AliTRDrawStreamBase.h"
3fe61b77 52#include "AliTRDfeeParam.h"
53
54#include "Cal/AliTRDCalROC.h"
55#include "Cal/AliTRDCalDet.h"
0e09df31 56#include "Cal/AliTRDCalSingleChamberStatus.h"
f7336fa3 57
58ClassImp(AliTRDclusterizer)
59
60//_____________________________________________________________________________
3a039a31 61AliTRDclusterizer::AliTRDclusterizer(AliTRDReconstructor *rec)
6d50f529 62 :TNamed()
3a039a31 63 ,fReconstructor(rec)
6d50f529 64 ,fRunLoader(NULL)
65 ,fClusterTree(NULL)
66 ,fRecPoints(NULL)
9c7c9ec1 67 ,fTrackletTree(NULL)
3fe61b77 68 ,fDigitsManager(NULL)
9c7c9ec1 69 ,fTrackletContainer(NULL)
3fe61b77 70 ,fAddLabels(kTRUE)
71 ,fRawVersion(2)
72 ,fIndexesOut(NULL)
73 ,fIndexesMaxima(NULL)
dfbb4bb9 74 ,fTransform(new AliTRDtransform(0))
fc546d21 75 ,fLUTbin(0)
76 ,fLUT(NULL)
f7336fa3 77{
78 //
79 // AliTRDclusterizer default constructor
80 //
81
a7ac01d2 82 AliTRDcalibDB *trd = 0x0;
83 if (!(trd = AliTRDcalibDB::Instance())) {
84 AliFatal("Could not get calibration object");
85 }
86
3fe61b77 87 fRawVersion = AliTRDfeeParam::Instance()->GetRAWversion();
88
3a039a31 89 // Initialize debug stream
90 if(fReconstructor){
91 if(fReconstructor->GetStreamLevel(AliTRDReconstructor::kClusterizer) > 1){
92 TDirectory *savedir = gDirectory;
93 //fgDebugStreamer = new TTreeSRedirector("TRD.ClusterizerDebug.root");
94 savedir->cd();
95 }
96 }
eb52b657 97
f7336fa3 98}
99
100//_____________________________________________________________________________
3a039a31 101AliTRDclusterizer::AliTRDclusterizer(const Text_t *name, const Text_t *title, AliTRDReconstructor *rec)
6d50f529 102 :TNamed(name,title)
3a039a31 103 ,fReconstructor(rec)
6d50f529 104 ,fRunLoader(NULL)
105 ,fClusterTree(NULL)
106 ,fRecPoints(NULL)
9c7c9ec1 107 ,fTrackletTree(NULL)
3fe61b77 108 ,fDigitsManager(new AliTRDdigitsManager())
9c7c9ec1 109 ,fTrackletContainer(NULL)
3fe61b77 110 ,fAddLabels(kTRUE)
111 ,fRawVersion(2)
112 ,fIndexesOut(NULL)
113 ,fIndexesMaxima(NULL)
114 ,fTransform(new AliTRDtransform(0))
fc546d21 115 ,fLUTbin(0)
116 ,fLUT(NULL)
f7336fa3 117{
118 //
6d50f529 119 // AliTRDclusterizer constructor
f7336fa3 120 //
121
a7ac01d2 122 AliTRDcalibDB *trd = 0x0;
123 if (!(trd = AliTRDcalibDB::Instance())) {
124 AliFatal("Could not get calibration object");
125 }
126
3a039a31 127 // Initialize debug stream
eb52b657 128 if (fReconstructor){
129 if (fReconstructor->GetStreamLevel(AliTRDReconstructor::kClusterizer) > 1){
3a039a31 130 TDirectory *savedir = gDirectory;
131 //fgDebugStreamer = new TTreeSRedirector("TRD.ClusterizerDebug.root");
132 savedir->cd();
133 }
134 }
135
3fe61b77 136 fDigitsManager->CreateArrays();
137
138 fRawVersion = AliTRDfeeParam::Instance()->GetRAWversion();
139
fc546d21 140 FillLUT();
023b669c 141
f7336fa3 142}
143
8230f242 144//_____________________________________________________________________________
6d50f529 145AliTRDclusterizer::AliTRDclusterizer(const AliTRDclusterizer &c)
146 :TNamed(c)
3a039a31 147 ,fReconstructor(c.fReconstructor)
6d50f529 148 ,fRunLoader(NULL)
149 ,fClusterTree(NULL)
150 ,fRecPoints(NULL)
9c7c9ec1 151 ,fTrackletTree(NULL)
3fe61b77 152 ,fDigitsManager(NULL)
66f6bfd9 153 ,fTrackletContainer(NULL)
3fe61b77 154 ,fAddLabels(kTRUE)
155 ,fRawVersion(2)
156 ,fIndexesOut(NULL)
157 ,fIndexesMaxima(NULL)
158 ,fTransform(NULL)
fc546d21 159 ,fLUTbin(0)
160 ,fLUT(0)
8230f242 161{
162 //
163 // AliTRDclusterizer copy constructor
164 //
165
fc546d21 166 FillLUT();
167
8230f242 168}
169
f7336fa3 170//_____________________________________________________________________________
171AliTRDclusterizer::~AliTRDclusterizer()
172{
8230f242 173 //
174 // AliTRDclusterizer destructor
175 //
f7336fa3 176
48f8adf3 177 if (fRecPoints/* && IsClustersOwner()*/){
66f6bfd9 178 fRecPoints->Delete();
179 delete fRecPoints;
180 }
3fe61b77 181
66f6bfd9 182 if (fDigitsManager) {
183 delete fDigitsManager;
184 fDigitsManager = NULL;
185 }
9c7c9ec1 186
66f6bfd9 187 if (fTrackletContainer){
188 delete fTrackletContainer;
189 fTrackletContainer = NULL;
190 }
3fe61b77 191
66f6bfd9 192 if (fIndexesOut){
193 delete fIndexesOut;
194 fIndexesOut = NULL;
195 }
3fe61b77 196
66f6bfd9 197 if (fIndexesMaxima){
198 delete fIndexesMaxima;
199 fIndexesMaxima = NULL;
200 }
6d50f529 201
66f6bfd9 202 if (fTransform){
203 delete fTransform;
204 fTransform = NULL;
205 }
fc546d21 206
66f6bfd9 207 if (fLUT) {
208 delete [] fLUT;
209 fLUT = NULL;
210 }
eb52b657 211
f7336fa3 212}
213
8230f242 214//_____________________________________________________________________________
dd9a6ee3 215AliTRDclusterizer &AliTRDclusterizer::operator=(const AliTRDclusterizer &c)
216{
217 //
218 // Assignment operator
219 //
220
3fe61b77 221 if (this != &c)
222 {
223 ((AliTRDclusterizer &) c).Copy(*this);
224 }
053767a4 225
dd9a6ee3 226 return *this;
227
228}
229
230//_____________________________________________________________________________
e0d47c25 231void AliTRDclusterizer::Copy(TObject &c) const
8230f242 232{
233 //
234 // Copy function
235 //
236
3fe61b77 237 ((AliTRDclusterizer &) c).fClusterTree = NULL;
238 ((AliTRDclusterizer &) c).fRecPoints = NULL;
9c7c9ec1 239 ((AliTRDclusterizer &) c).fTrackletTree = NULL;
3fe61b77 240 ((AliTRDclusterizer &) c).fDigitsManager = NULL;
9c7c9ec1 241 ((AliTRDclusterizer &) c).fTrackletContainer = NULL;
3fe61b77 242 ((AliTRDclusterizer &) c).fAddLabels = fAddLabels;
243 ((AliTRDclusterizer &) c).fRawVersion = fRawVersion;
244 ((AliTRDclusterizer &) c).fIndexesOut = NULL;
245 ((AliTRDclusterizer &) c).fIndexesMaxima = NULL;
246 ((AliTRDclusterizer &) c).fTransform = NULL;
fc546d21 247 ((AliTRDclusterizer &) c).fLUTbin = 0;
248 ((AliTRDclusterizer &) c).fLUT = NULL;
8230f242 249
250}
251
f7336fa3 252//_____________________________________________________________________________
3e1a3ad8 253Bool_t AliTRDclusterizer::Open(const Char_t *name, Int_t nEvent)
f7336fa3 254{
255 //
3e1a3ad8 256 // Opens the AliROOT file. Output and input are in the same file
f7336fa3 257 //
6d50f529 258
e191bb57 259 TString evfoldname = AliConfig::GetDefaultEventFolderName();
6d50f529 260 fRunLoader = AliRunLoader::GetRunLoader(evfoldname);
261
262 if (!fRunLoader) {
19dd5b2f 263 fRunLoader = AliRunLoader::Open(name);
6d50f529 264 }
265
266 if (!fRunLoader) {
267 AliError(Form("Can not open session for file %s.",name));
268 return kFALSE;
269 }
88cb7938 270
271 OpenInput(nEvent);
272 OpenOutput();
6d50f529 273
3e1a3ad8 274 return kTRUE;
f7336fa3 275
6d50f529 276}
3e1a3ad8 277
278//_____________________________________________________________________________
88cb7938 279Bool_t AliTRDclusterizer::OpenOutput()
3e1a3ad8 280{
281 //
282 // Open the output file
283 //
284
66f6bfd9 285 if (!fReconstructor->IsWritingClusters()) return kTRUE;
286
287 TObjArray *ioArray = 0x0;
88cb7938 288
289 AliLoader* loader = fRunLoader->GetLoader("TRDLoader");
290 loader->MakeTree("R");
6d50f529 291
88cb7938 292 fClusterTree = loader->TreeR();
66f6bfd9 293 fClusterTree->Branch("TRDcluster", "TObjArray", &ioArray, 32000, 0);
3e1a3ad8 294
3e1a3ad8 295 return kTRUE;
296
297}
298
25ca55ce 299//_____________________________________________________________________________
300Bool_t AliTRDclusterizer::OpenOutput(TTree *clusterTree)
301{
302 //
303 // Connect the output tree
304 //
305
66f6bfd9 306 // clusters writing
307 if (fReconstructor->IsWritingClusters()){
308 TObjArray *ioArray = 0x0;
309 fClusterTree = clusterTree;
310 fClusterTree->Branch("TRDcluster", "TObjArray", &ioArray, 32000, 0);
311 }
9c7c9ec1 312
313 // tracklet writing
3a039a31 314 if (fReconstructor->IsWritingTracklets()){
9c7c9ec1 315 TString evfoldname = AliConfig::GetDefaultEventFolderName();
316 fRunLoader = AliRunLoader::GetRunLoader(evfoldname);
317
318 if (!fRunLoader) {
319 fRunLoader = AliRunLoader::Open("galice.root");
320 }
321 if (!fRunLoader) {
322 AliError(Form("Can not open session for file galice.root."));
323 return kFALSE;
324 }
325
326 UInt_t **leaves = new UInt_t *[2];
327 AliDataLoader *dl = fRunLoader->GetLoader("TRDLoader")->GetDataLoader("tracklets");
328 if (!dl) {
329 AliError("Could not get the tracklets data loader!");
90cf7133 330 dl = new AliDataLoader("TRD.Tracklets.root","tracklets", "tracklets");
9c7c9ec1 331 fRunLoader->GetLoader("TRDLoader")->AddDataLoader(dl);
332 }
333 else {
334 fTrackletTree = dl->Tree();
335 if (!fTrackletTree)
336 {
317b5644 337 dl->MakeTree();
338 fTrackletTree = dl->Tree();
9c7c9ec1 339 }
340 TBranch *trkbranch = fTrackletTree->GetBranch("trkbranch");
341 if (!trkbranch)
342 fTrackletTree->Branch("trkbranch",leaves[0],"det/i:side/i:tracklets[256]/i");
343 }
344 }
345
25ca55ce 346 return kTRUE;
347
348}
349
3e1a3ad8 350//_____________________________________________________________________________
88cb7938 351Bool_t AliTRDclusterizer::OpenInput(Int_t nEvent)
f7336fa3 352{
353 //
354 // Opens a ROOT-file with TRD-hits and reads in the digits-tree
355 //
356
f7336fa3 357 // Import the Trees for the event nEvent in the file
bdbb05bb 358 fRunLoader->GetEvent(nEvent);
88cb7938 359
f7336fa3 360 return kTRUE;
361
362}
363
364//_____________________________________________________________________________
793ff80c 365Bool_t AliTRDclusterizer::WriteClusters(Int_t det)
f7336fa3 366{
367 //
3e1a3ad8 368 // Fills TRDcluster branch in the tree with the clusters
793ff80c 369 // found in detector = det. For det=-1 writes the tree.
a3c76cdc 370 //
793ff80c 371
6d50f529 372 if ((det < -1) ||
373 (det >= AliTRDgeometry::Ndet())) {
374 AliError(Form("Unexpected detector index %d.\n",det));
3e1a3ad8 375 return kFALSE;
793ff80c 376 }
317b5644 377
66f6bfd9 378 TObjArray *ioArray = new TObjArray(400);
3e1a3ad8 379 TBranch *branch = fClusterTree->GetBranch("TRDcluster");
380 if (!branch) {
3e1a3ad8 381 branch = fClusterTree->Branch("TRDcluster","TObjArray",&ioArray,32000,0);
66f6bfd9 382 } else branch->SetAddress(&ioArray);
66f6bfd9 383
384 Int_t nRecPoints = RecPoints()->GetEntriesFast();
385 if(det >= 0){
3e1a3ad8 386 for (Int_t i = 0; i < nRecPoints; i++) {
bdbb05bb 387 AliTRDcluster *c = (AliTRDcluster *) RecPoints()->UncheckedAt(i);
66f6bfd9 388 if(det != c->GetDetector()) continue;
389 ioArray->AddLast(c);
793ff80c 390 }
3e1a3ad8 391 fClusterTree->Fill();
66f6bfd9 392 } else {
eb52b657 393
66f6bfd9 394 Int_t detOld = -1;
395 for (Int_t i = 0; i < nRecPoints; i++) {
396 AliTRDcluster *c = (AliTRDcluster *) RecPoints()->UncheckedAt(i);
397 if(c->GetDetector() != detOld){
398 fClusterTree->Fill();
399 ioArray->Clear();
400 detOld = c->GetDetector();
401 }
402 ioArray->AddLast(c);
a6dd11e9 403 }
793ff80c 404 }
66f6bfd9 405 delete ioArray;
6d50f529 406
66f6bfd9 407 return kTRUE;
eb52b657 408
f7336fa3 409}
793ff80c 410
9c7c9ec1 411//_____________________________________________________________________________
412Bool_t AliTRDclusterizer::WriteTracklets(Int_t det)
413{
eb52b657 414 //
415 // Write the raw data tracklets into seperate file
416 //
9c7c9ec1 417
418 UInt_t **leaves = new UInt_t *[2];
419 for (Int_t i=0; i<2 ;i++){
317b5644 420 leaves[i] = new UInt_t[258];
421 leaves[i][0] = det; // det
422 leaves[i][1] = i; // side
423 memcpy(leaves[i]+2, fTrackletContainer[i], sizeof(UInt_t) * 256);
9c7c9ec1 424 }
425
9c7c9ec1 426 if (!fTrackletTree){
427 AliDataLoader *dl = fRunLoader->GetLoader("TRDLoader")->GetDataLoader("tracklets");
428 dl->MakeTree();
429 fTrackletTree = dl->Tree();
430 }
431
432 TBranch *trkbranch = fTrackletTree->GetBranch("trkbranch");
433 if (!trkbranch) {
434 trkbranch = fTrackletTree->Branch("trkbranch",leaves[0],"det/i:side/i:tracklets[256]/i");
435 }
436
437 for (Int_t i=0; i<2; i++){
317b5644 438 if (leaves[i][2]>0) {
439 trkbranch->SetAddress(leaves[i]);
440 fTrackletTree->Fill();
441 }
9c7c9ec1 442 }
443
444 AliDataLoader *dl = fRunLoader->GetLoader("TRDLoader")->GetDataLoader("tracklets");
445 dl->WriteData("OVERWRITE");
446 //dl->Unload();
447 delete [] leaves;
448
eb52b657 449 return kTRUE;
450
9c7c9ec1 451}
452
3551db50 453//_____________________________________________________________________________
3fe61b77 454void AliTRDclusterizer::ResetHelperIndexes(AliTRDSignalIndex *indexesIn)
455{
456 //
457 // Reset the helper indexes
458 //
459
460 if (fIndexesOut)
461 {
462 // carefull here - we assume that only row number may change - most probable
463 if (indexesIn->GetNrow() <= fIndexesOut->GetNrow())
317b5644 464 fIndexesOut->ResetContent();
3fe61b77 465 else
317b5644 466 fIndexesOut->ResetContentConditional(indexesIn->GetNrow()
467 , indexesIn->GetNcol()
468 , indexesIn->GetNtime());
3fe61b77 469 }
470 else
471 {
472 fIndexesOut = new AliTRDSignalIndex(indexesIn->GetNrow()
473 , indexesIn->GetNcol()
474 , indexesIn->GetNtime());
475 }
476
477 if (fIndexesMaxima)
478 {
479 // carefull here - we assume that only row number may change - most probable
480 if (indexesIn->GetNrow() <= fIndexesMaxima->GetNrow())
481 {
317b5644 482 fIndexesMaxima->ResetContent();
483 }
3fe61b77 484 else
317b5644 485 {
486 fIndexesMaxima->ResetContentConditional(indexesIn->GetNrow()
3fe61b77 487 , indexesIn->GetNcol()
488 , indexesIn->GetNtime());
317b5644 489 }
3fe61b77 490 }
491 else
492 {
493 fIndexesMaxima = new AliTRDSignalIndex(indexesIn->GetNrow()
317b5644 494 , indexesIn->GetNcol()
495 , indexesIn->GetNtime());
3fe61b77 496 }
497
498}
499
500//_____________________________________________________________________________
501Bool_t AliTRDclusterizer::ReadDigits()
502{
503 //
504 // Reads the digits arrays from the input aliroot file
505 //
506
507 if (!fRunLoader) {
508 AliError("No run loader available");
509 return kFALSE;
510 }
511
512 AliLoader* loader = fRunLoader->GetLoader("TRDLoader");
513 if (!loader->TreeD()) {
514 loader->LoadDigits();
515 }
516
517 // Read in the digit arrays
518 return (fDigitsManager->ReadDigits(loader->TreeD()));
519
520}
521
522//_____________________________________________________________________________
523Bool_t AliTRDclusterizer::ReadDigits(TTree *digitsTree)
524{
525 //
526 // Reads the digits arrays from the input tree
527 //
528
529 // Read in the digit arrays
530 return (fDigitsManager->ReadDigits(digitsTree));
531
532}
533
534//_____________________________________________________________________________
535Bool_t AliTRDclusterizer::ReadDigits(AliRawReader *rawReader)
536{
537 //
538 // Reads the digits arrays from the ddl file
539 //
540
541 AliTRDrawData raw;
542 fDigitsManager = raw.Raw2Digits(rawReader);
543
544 return kTRUE;
545
546}
547
548//_____________________________________________________________________________
549Bool_t AliTRDclusterizer::MakeClusters()
550{
551 //
552 // Creates clusters from digits
553 //
554
555 // Propagate info from the digits manager
66f6bfd9 556 if (fAddLabels == kTRUE){
557 fAddLabels = fDigitsManager->UsesDictionaries();
558 }
559
3fe61b77 560 Bool_t fReturn = kTRUE;
66f6bfd9 561 for (Int_t i = 0; i < AliTRDgeometry::kNdet; i++){
562
b65e5048 563 AliTRDarrayADC *digitsIn = (AliTRDarrayADC*) fDigitsManager->GetDigits(i); //mod
66f6bfd9 564 // This is to take care of switched off super modules
565 if (!digitsIn->HasData()) continue;
566 digitsIn->Expand();
0d64b05f 567 digitsIn->DeleteNegatives(); // Restore digits array to >=0 values
66f6bfd9 568 AliTRDSignalIndex* indexes = fDigitsManager->GetIndexes(i);
569 if (indexes->IsAllocated() == kFALSE){
570 fDigitsManager->BuildIndexes(i);
571 }
572
573 Bool_t fR = kFALSE;
574 if (indexes->HasEntry()){
575 if (fAddLabels){
576 for (Int_t iDict = 0; iDict < AliTRDdigitsManager::kNDict; iDict++){
b65e5048 577 AliTRDarrayDictionary *tracksIn = 0; //mod
578 tracksIn = (AliTRDarrayDictionary *) fDigitsManager->GetDictionary(i,iDict); //mod
66f6bfd9 579 tracksIn->Expand();
3fe61b77 580 }
66f6bfd9 581 }
582 fR = MakeClusters(i);
583 fReturn = fR && fReturn;
3fe61b77 584 }
66f6bfd9 585
586 //if (fR == kFALSE){
587 // if(IsWritingClusters()) WriteClusters(i);
588 // ResetRecPoints();
589 //}
590
591 // No compress just remove
592 fDigitsManager->RemoveDigits(i);
593 fDigitsManager->RemoveDictionaries(i);
594 fDigitsManager->ClearIndexes(i);
595 }
596
597 if(fReconstructor->IsWritingClusters()) WriteClusters(-1);
3fe61b77 598
66f6bfd9 599 AliInfo(Form("Number of found clusters : %d", RecPoints()->GetEntriesFast()));
3fe61b77 600
66f6bfd9 601 return fReturn;
eb52b657 602
3fe61b77 603}
604
605//_____________________________________________________________________________
606Bool_t AliTRDclusterizer::Raw2Clusters(AliRawReader *rawReader)
607{
608 //
609 // Creates clusters from raw data
610 //
611
fc546d21 612 return Raw2ClustersChamber(rawReader);
3fe61b77 613
3fe61b77 614}
615
616//_____________________________________________________________________________
617Bool_t AliTRDclusterizer::Raw2ClustersChamber(AliRawReader *rawReader)
618{
619 //
620 // Creates clusters from raw data
621 //
622
623 // Create the digits manager
66f6bfd9 624 if (!fDigitsManager){
625 fDigitsManager = new AliTRDdigitsManager();
626 fDigitsManager->CreateArrays();
627 }
3fe61b77 628
629 fDigitsManager->SetUseDictionaries(fAddLabels);
630
317b5644 631 // tracklet container for raw tracklet writing
632 if (!fTrackletContainer && fReconstructor->IsWritingTracklets()) {
633 // maximum tracklets for one HC
634 const Int_t kTrackletChmb=256;
635 fTrackletContainer = new UInt_t *[2];
636 fTrackletContainer[0] = new UInt_t[kTrackletChmb];
637 fTrackletContainer[1] = new UInt_t[kTrackletChmb];
638 }
639
640
dfbb4bb9 641 AliTRDrawStreamBase *pinput = AliTRDrawStreamBase::GetRawStream(rawReader);
642 AliTRDrawStreamBase &input = *pinput;
3fe61b77 643
644 AliInfo(Form("Stream version: %s", input.IsA()->GetName()));
645
646 Int_t det = 0;
317b5644 647 while ((det = input.NextChamber(fDigitsManager,fTrackletContainer)) >= 0){
66f6bfd9 648 Bool_t iclusterBranch = kFALSE;
649 if (fDigitsManager->GetIndexes(det)->HasEntry()){
650 iclusterBranch = MakeClusters(det);
3fe61b77 651 }
66f6bfd9 652
653 fDigitsManager->RemoveDigits(det);
654 fDigitsManager->RemoveDictionaries(det);
655 fDigitsManager->ClearIndexes(det);
317b5644 656
657 if (!fReconstructor->IsWritingTracklets()) continue;
658 if (*(fTrackletContainer[0]) > 0 || *(fTrackletContainer[1]) > 0) WriteTracklets(det);
9c7c9ec1 659 }
317b5644 660 if (fReconstructor->IsWritingTracklets()){
661 delete [] fTrackletContainer[0];
662 delete [] fTrackletContainer[1];
663 delete [] fTrackletContainer;
664 fTrackletContainer = NULL;
665 }
666
66f6bfd9 667 if(fReconstructor->IsWritingClusters()) WriteClusters(-1);
3fe61b77 668
669 delete fDigitsManager;
670 fDigitsManager = NULL;
dfbb4bb9 671
672 delete pinput;
673 pinput = NULL;
3fe61b77 674
66f6bfd9 675 AliInfo(Form("Number of found clusters : %d", RecPoints()->GetEntriesFast()));
676 return kTRUE;
eb52b657 677
3fe61b77 678}
679
fa7427d0 680//_____________________________________________________________________________
681UChar_t AliTRDclusterizer::GetStatus(Short_t &signal)
682{
023b669c 683 //
684 // Check if a pad is masked
685 //
686
317b5644 687 UChar_t status = 0;
688
689 if(signal>0 && TESTBIT(signal, 10)){
690 CLRBIT(signal, 10);
691 for(int ibit=0; ibit<4; ibit++){
692 if(TESTBIT(signal, 11+ibit)){
693 SETBIT(status, ibit);
694 CLRBIT(signal, 11+ibit);
695 }
696 }
697 }
698 return status;
fa7427d0 699}
700
6d9e79cc 701//_____________________________________________________________________________
702void AliTRDclusterizer::SetPadStatus(UChar_t status, UChar_t &out){
703 //
704 // Set the pad status into out
705 // First three bits are needed for the position encoding
706 //
707 status = status << 3;
708 out |= status;
709}
710
711//_____________________________________________________________________________
712UChar_t AliTRDclusterizer::GetPadStatus(UChar_t encoding){
713 //
714 // return the staus encoding of the corrupted pad
715 //
716 return static_cast<UChar_t>(encoding >> 3);
717}
718
719//_____________________________________________________________________________
720Int_t AliTRDclusterizer::GetCorruption(UChar_t encoding){
721 //
722 // Return the position of the corruption
723 //
724 return encoding & 7;
725}
726
3fe61b77 727//_____________________________________________________________________________
728Bool_t AliTRDclusterizer::MakeClusters(Int_t det)
729{
730 //
731 // Generates the cluster.
732 //
733
734 // Get the digits
735 // digits should be expanded beforehand!
736 // digitsIn->Expand();
b65e5048 737 AliTRDarrayADC *digitsIn = (AliTRDarrayADC *) fDigitsManager->GetDigits(det); //mod
f5375dcb 738
3fe61b77 739 // This is to take care of switched off super modules
625f5260 740 if (!digitsIn->HasData())
3fe61b77 741 {
742 return kFALSE;
743 }
744
745 AliTRDSignalIndex *indexesIn = fDigitsManager->GetIndexes(det);
746 if (indexesIn->IsAllocated() == kFALSE)
747 {
748 AliError("Indexes do not exist!");
749 return kFALSE;
750 }
751
752 AliTRDcalibDB *calibration = AliTRDcalibDB::Instance();
753 if (!calibration)
754 {
755 AliFatal("No AliTRDcalibDB instance available\n");
756 return kFALSE;
757 }
758
3fe61b77 759 // ADC thresholds
760 // There is no ADC threshold anymore, and simParam should not be used in clusterizer. KO
acc49af9 761 Float_t adcThreshold = 0;
3fe61b77 762
3a039a31 763 if (!fReconstructor){
764 AliError("Reconstructor not set\n");
765 return kFALSE;
766 }
c5f589b9 767
3fe61b77 768 // Threshold value for the maximum
eb52b657 769 Float_t maxThresh = fReconstructor->GetRecoParam()->GetClusMaxThresh();
3fe61b77 770 // Threshold value for the digit signal
eb52b657 771 Float_t sigThresh = fReconstructor->GetRecoParam()->GetClusSigThresh();
3fe61b77 772
df83a620 773 // Threshold value for the maximum ( cut noise)
eb52b657 774 Float_t minMaxCutSigma = fReconstructor->GetRecoParam()->GetMinMaxCutSigma();
df83a620 775 // Threshold value for the sum pad ( cut noise)
eb52b657 776 Float_t minLeftRightCutSigma = fReconstructor->GetRecoParam()->GetMinLeftRightCutSigma();
df83a620 777
3fe61b77 778 // Iteration limit for unfolding procedure
779 const Float_t kEpsilon = 0.01;
780 const Int_t kNclus = 3;
781 const Int_t kNsig = 5;
782
783 Int_t iUnfold = 0;
784 Double_t ratioLeft = 1.0;
785 Double_t ratioRight = 1.0;
786
787 Double_t padSignal[kNsig];
788 Double_t clusterSignal[kNclus];
789
053767a4 790 Int_t istack = indexesIn->GetStack();
791 Int_t ilayer = indexesIn->GetLayer();
792 Int_t isector = indexesIn->GetSM();
3fe61b77 793
794 // Start clustering in the chamber
795
053767a4 796 Int_t idet = AliTRDgeometry::GetDetector(ilayer,istack,isector);
b65e5048 797 if (idet != det) {
798 AliError("Strange Detector number Missmatch!");
799 return kFALSE;
800 }
3fe61b77 801
802 // TRD space point transformation
803 fTransform->SetDetector(det);
804
053767a4 805 Int_t iGeoLayer = AliGeomManager::kTRD1 + ilayer;
806 Int_t iGeoModule = istack + AliTRDgeometry::Nstack() * isector;
807 UShort_t volid = AliGeomManager::LayerToVolUID(iGeoLayer,iGeoModule);
3fe61b77 808
809 Int_t nColMax = digitsIn->GetNcol();
fa7427d0 810 Int_t nRowMax = digitsIn->GetNrow();
3fe61b77 811 Int_t nTimeTotal = digitsIn->GetNtime();
812
813 // Detector wise calibration object for the gain factors
0e09df31 814 const AliTRDCalDet *calGainFactorDet = calibration->GetGainFactorDet();
3fe61b77 815 // Calibration object with pad wise values for the gain factors
0e09df31 816 AliTRDCalROC *calGainFactorROC = calibration->GetGainFactorROC(idet);
3fe61b77 817 // Calibration value for chamber wise gain factor
0e09df31 818 Float_t calGainFactorDetValue = calGainFactorDet->GetValue(idet);
819
df83a620 820 // Detector wise calibration object for the noise
821 const AliTRDCalDet *calNoiseDet = calibration->GetNoiseDet();
822 // Calibration object with pad wise values for the noise
823 AliTRDCalROC *calNoiseROC = calibration->GetNoiseROC(idet);
824 // Calibration value for chamber wise noise
825 Float_t calNoiseDetValue = calNoiseDet->GetValue(idet);
826
3fe61b77 827 Int_t nClusters = 0;
828
b65e5048 829 AliTRDarraySignal *digitsOut = new AliTRDarraySignal(nRowMax, nColMax, nTimeTotal);
830 AliTRDarrayADC padStatus(nRowMax, nColMax, nTimeTotal);
3fe61b77 831
832 ResetHelperIndexes(indexesIn);
833
834 // Apply the gain and the tail cancelation via digital filter
835 TailCancelation(digitsIn
b65e5048 836 ,digitsOut
837 ,indexesIn
838 ,fIndexesOut
839 ,nTimeTotal
840 ,adcThreshold
841 ,calGainFactorROC
842 ,calGainFactorDetValue);
317b5644 843
3fe61b77 844 Int_t row = 0;
845 Int_t col = 0;
846 Int_t time = 0;
847 Int_t iPad = 0;
848
f5375dcb 849 UChar_t status[3]={0, 0, 0}, ipos = 0;
3fe61b77 850 fIndexesOut->ResetCounters();
eb52b657 851 while (fIndexesOut->NextRCTbinIndex(row, col, time)) {
49451fe0 852 // reset pad status
853 ipos = 0; for(Int_t is=3; is--;) status[is] = 0;
023b669c 854
b65e5048 855 Float_t signalM = TMath::Abs(digitsOut->GetData(row,col,time));
f5375dcb 856 status[1] = digitsIn->GetPadStatus(row,col,time);
857 if(status[1]) SETBIT(ipos, AliTRDcluster::kMaskedCenter);
858
df83a620 859 if(signalM < maxThresh) continue;
860
861 Float_t noiseMiddleThresh = minMaxCutSigma*calNoiseDetValue*calNoiseROC->GetValue(col,row);
862 if (signalM < noiseMiddleThresh) continue;
863
864 if (col + 1 >= nColMax || col-1 < 0) continue;
f5375dcb 865
b65e5048 866 Float_t signalL = TMath::Abs(digitsOut->GetData(row,col+1,time));
df83a620 867 status[0] = digitsIn->GetPadStatus(row,col+1,time);
868 if(status[0]) SETBIT(ipos, AliTRDcluster::kMaskedLeft);
f5375dcb 869
b65e5048 870 Float_t signalR = TMath::Abs(digitsOut->GetData(row,col-1,time));
df83a620 871 status[2] = digitsIn->GetPadStatus(row,col-1,time);
872 if(status[2]) SETBIT(ipos, AliTRDcluster::kMaskedRight);
f5375dcb 873
df83a620 874 // reject candidates with more than 1 problematic pad
875 if(ipos == 3 || ipos > 4) continue;
f5375dcb 876
b65e5048 877 if (!status[1]) { // good central pad
878 if (!ipos) { // all pads are OK
879 if ((signalL <= signalM) && (signalR < signalM)) {
880 if ((signalL >= sigThresh) || (signalR >= sigThresh)) {
881 Float_t noiseSumThresh = minLeftRightCutSigma
882 * calNoiseDetValue
883 * calNoiseROC->GetValue(col,row);
884 if ((signalL+signalR+signalM) >= noiseSumThresh) {
885 // Maximum found, mark the position by a negative signal
886 digitsOut->SetData(row,col,time,-signalM);
887 fIndexesMaxima->AddIndexTBin(row,col,time);
6d9e79cc 888 padStatus.SetData(row, col, time, ipos); // No corruption
b65e5048 889 }
890 }
891 }
49451fe0 892 } else { // one of the neighbouring pads are bad
b65e5048 893 if (status[0] && signalR < signalM && signalR >= sigThresh) {
894 digitsOut->SetData(row,col,time,-signalM);
895 digitsOut->SetData(row, col, time+1, 0.);
023b669c 896 fIndexesMaxima->AddIndexTBin(row,col,time);
6d9e79cc 897 SetPadStatus(status[0], ipos);
b65e5048 898 padStatus.SetData(row, col, time, ipos);
899 }
900 else if (status[2] && signalL <= signalM && signalL >= sigThresh) {
901 digitsOut->SetData(row,col,time,-signalM);
902 digitsOut->SetData(row, col, time-1, 0.);
903 fIndexesMaxima->AddIndexTBin(row,col,time);
6d9e79cc 904 SetPadStatus(status[2], ipos);
b65e5048 905 padStatus.SetData(row, col, time, ipos);
906 }
df83a620 907 }
b65e5048 908 }
909 else { // wrong maximum pad
df83a620 910 if ((signalL >= sigThresh) || (signalR >= sigThresh)) {
b65e5048 911 // Maximum found, mark the position by a negative signal
49451fe0 912 digitsOut->SetData(row,col,time,-maxThresh);
913 fIndexesMaxima->AddIndexTBin(row,col,time);
6d9e79cc 914 SetPadStatus(status[1], ipos);
49451fe0 915 padStatus.SetData(row, col, time, ipos);
f5375dcb 916 }
917 }
df83a620 918 }
f5375dcb 919
eb52b657 920 // The index to the first cluster of a given ROC
df83a620 921 Int_t firstClusterROC = -1;
eb52b657 922 // The number of cluster in a given ROC
923 Int_t nClusterROC = 0;
f5375dcb 924
eb52b657 925 // Now check the maxima and calculate the cluster position
926 fIndexesMaxima->ResetCounters();
927 while (fIndexesMaxima->NextRCTbinIndex(row, col, time)) {
3fe61b77 928
eb52b657 929 // Maximum found ?
b65e5048 930 if (digitsOut->GetData(row,col,time) < 0.0) {
023b669c 931
eb52b657 932 for (iPad = 0; iPad < kNclus; iPad++) {
933 Int_t iPadCol = col - 1 + iPad;
b65e5048 934 clusterSignal[iPad] = TMath::Abs(digitsOut->GetData(row,iPadCol,time));
eb52b657 935 }
3fe61b77 936
eb52b657 937 // Count the number of pads in the cluster
938 Int_t nPadCount = 0;
939 Int_t ii;
940 // Look to the right
941 ii = 0;
b65e5048 942 while (TMath::Abs(digitsOut->GetData(row,col-ii ,time)) >= sigThresh) {
eb52b657 943 nPadCount++;
944 ii++;
945 if (col-ii < 0) break;
946 }
947 // Look to the left
948 ii = 0;
b65e5048 949 while (TMath::Abs(digitsOut->GetData(row,col+ii+1,time)) >= sigThresh) {
eb52b657 950 nPadCount++;
951 ii++;
952 if (col+ii+1 >= nColMax) break;
953 }
954 nClusters++;
f5375dcb 955
eb52b657 956 // Look for 5 pad cluster with minimum in the middle
957 Bool_t fivePadCluster = kFALSE;
958 if (col < (nColMax - 3)){
b65e5048 959 if (digitsOut->GetData(row,col+2,time) < 0) {
eb52b657 960 fivePadCluster = kTRUE;
961 }
962 if ((fivePadCluster) && (col < (nColMax - 5))) {
b65e5048 963 if (digitsOut->GetData(row,col+4,time) >= sigThresh) {
eb52b657 964 fivePadCluster = kFALSE;
f5375dcb 965 }
eb52b657 966 }
967 if ((fivePadCluster) && (col > 1)) {
b65e5048 968 if (digitsOut->GetData(row,col-2,time) >= sigThresh) {
eb52b657 969 fivePadCluster = kFALSE;
f5375dcb 970 }
971 }
eb52b657 972 }
3fe61b77 973
eb52b657 974 // 5 pad cluster
975 // Modify the signal of the overlapping pad for the left part
976 // of the cluster which remains from a previous unfolding
977 if (iUnfold) {
978 clusterSignal[0] *= ratioLeft;
979 iUnfold = 0;
980 }
3fe61b77 981
eb52b657 982 // Unfold the 5 pad cluster
b65e5048 983 if (fivePadCluster) {
eb52b657 984 for (iPad = 0; iPad < kNsig; iPad++) {
b65e5048 985 padSignal[iPad] = TMath::Abs(digitsOut->GetData(row
986 ,col-1+iPad
987 ,time));
f5375dcb 988 }
eb52b657 989 // Unfold the two maxima and set the signal on
990 // the overlapping pad to the ratio
991 ratioRight = Unfold(kEpsilon,ilayer,padSignal);
992 ratioLeft = 1.0 - ratioRight;
993 clusterSignal[2] *= ratioRight;
994 iUnfold = 1;
995 }
3fe61b77 996
eb52b657 997 // The position of the cluster in COL direction relative to the center pad (pad units)
998 Double_t clusterPosCol = 0.0;
999 if (fReconstructor->GetRecoParam()->IsLUT()) {
1000 // Calculate the position of the cluster by using the
1001 // lookup table method
1002 clusterPosCol = LUTposition(ilayer,clusterSignal[0]
1003 ,clusterSignal[1]
1004 ,clusterSignal[2]);
1005 }
1006 else {
1007 // Calculate the position of the cluster by using the
1008 // center of gravity method
1009 for (Int_t i = 0; i < kNsig; i++) {
1010 padSignal[i] = 0.0;
1011 }
b65e5048 1012 padSignal[2] = TMath::Abs(digitsOut->GetData(row,col ,time)); // Central pad
1013 padSignal[3] = TMath::Abs(digitsOut->GetData(row,col+1,time)); // Left pad
1014 padSignal[1] = TMath::Abs(digitsOut->GetData(row,col-1,time)); // Right pad
eb52b657 1015 if ((col > 2) &&
b65e5048 1016 (TMath::Abs(digitsOut->GetData(row,col-2,time)) < padSignal[1])) {
1017 padSignal[4] = TMath::Abs(digitsOut->GetData(row,col-2,time));
f5375dcb 1018 }
eb52b657 1019 if ((col < nColMax - 3) &&
b65e5048 1020 (TMath::Abs(digitsOut->GetData(row,col+2,time)) < padSignal[3])) {
1021 padSignal[0] = TMath::Abs(digitsOut->GetData(row,col+2,time));
eb52b657 1022 }
1023 clusterPosCol = GetCOG(padSignal);
1024 }
3fe61b77 1025
eb52b657 1026 // Store the amplitudes of the pads in the cluster for later analysis
1027 // and check whether one of these pads is masked in the database
1028 Short_t signals[7] = { 0, 0, 0, 0, 0, 0, 0 };
1029 for (Int_t jPad = col-3; jPad <= col+3; jPad++) {
1030 if ((jPad < 0) ||
1031 (jPad >= nColMax-1)) {
1032 continue;
f5375dcb 1033 }
b65e5048 1034 signals[jPad-col+3] = TMath::Nint(TMath::Abs(digitsOut->GetData(row,jPad,time)));
eb52b657 1035 }
3fe61b77 1036
eb52b657 1037 // Transform the local cluster coordinates into calibrated
1038 // space point positions defined in the local tracking system.
1039 // Here the calibration for T0, Vdrift and ExB is applied as well.
1040 Double_t clusterXYZ[6];
1041 clusterXYZ[0] = clusterPosCol;
1042 clusterXYZ[1] = clusterSignal[2];
1043 clusterXYZ[2] = clusterSignal[1];
1044 clusterXYZ[3] = clusterSignal[0];
1045 clusterXYZ[4] = 0.0;
1046 clusterXYZ[5] = 0.0;
1047 Int_t clusterRCT[3];
1048 clusterRCT[0] = row;
1049 clusterRCT[1] = col;
1050 clusterRCT[2] = 0;
1051
1052 Bool_t out = kTRUE;
1053 if (fTransform->Transform(clusterXYZ,clusterRCT,((UInt_t) time),out,0)) {
f5375dcb 1054
1055 // Add the cluster to the output array
1056 // The track indices will be stored later
1057 Float_t clusterPos[3];
1058 clusterPos[0] = clusterXYZ[0];
1059 clusterPos[1] = clusterXYZ[1];
1060 clusterPos[2] = clusterXYZ[2];
1061 Float_t clusterSig[2];
1062 clusterSig[0] = clusterXYZ[4];
1063 clusterSig[1] = clusterXYZ[5];
1064 Double_t clusterCharge = clusterXYZ[3];
1065 Char_t clusterTimeBin = ((Char_t) clusterRCT[2]);
66f6bfd9 1066
1067 Int_t n = RecPoints()->GetEntriesFast();
49451fe0 1068 AliTRDcluster *cluster = new((*RecPoints())[n]) AliTRDcluster(
1069 idet,
1070 clusterCharge, clusterPos, clusterSig,
1071 0x0,
1072 ((Char_t) nPadCount),
1073 signals,
1074 ((UChar_t) col), ((UChar_t) row), ((UChar_t) time),
1075 clusterTimeBin, clusterPosCol,
1076 volid);
f5375dcb 1077 cluster->SetInChamber(!out);
023b669c 1078
6d9e79cc 1079 UChar_t maskPosition = GetCorruption(padStatus.GetData(row, col, time));
1080 UChar_t padstatus = GetPadStatus(padStatus.GetData(row, col, time));
023b669c 1081 if (maskPosition) {
f5375dcb 1082 cluster->SetPadMaskedPosition(maskPosition);
6d9e79cc 1083 cluster->SetPadMaskedStatus(padstatus);
f5375dcb 1084 }
3fe61b77 1085
f5375dcb 1086 // Temporarily store the row, column and time bin of the center pad
1087 // Used to later on assign the track indices
1088 cluster->SetLabel( row,0);
1089 cluster->SetLabel( col,1);
1090 cluster->SetLabel(time,2);
3fe61b77 1091
f5375dcb 1092 // Store the index of the first cluster in the current ROC
1093 if (firstClusterROC < 0) {
1094 firstClusterROC = RecPoints()->GetEntriesFast() - 1;
1095 }
1096
1097 // Count the number of cluster in the current ROC
1098 nClusterROC++;
1099
1100 } // if: Transform ok ?
eb52b657 1101
f5375dcb 1102 } // if: Maximum found ?
eb52b657 1103
f5375dcb 1104 }
3fe61b77 1105
1106 delete digitsOut;
1107
eb52b657 1108 if (fAddLabels) {
1109 AddLabels(idet,firstClusterROC,nClusterROC);
1110 }
3fe61b77 1111
1112 return kTRUE;
1113
1114}
1115
1116//_____________________________________________________________________________
1117Bool_t AliTRDclusterizer::AddLabels(Int_t idet, Int_t firstClusterROC, Int_t nClusterROC)
3551db50 1118{
1119 //
3fe61b77 1120 // Add the track indices to the found clusters
3551db50 1121 //
1122
3fe61b77 1123 const Int_t kNclus = 3;
1124 const Int_t kNdict = AliTRDdigitsManager::kNDict;
1125 const Int_t kNtrack = kNdict * kNclus;
1126
1127 Int_t iClusterROC = 0;
1128
1129 Int_t row = 0;
1130 Int_t col = 0;
1131 Int_t time = 0;
1132 Int_t iPad = 0;
1133
1134 // Temporary array to collect the track indices
1135 Int_t *idxTracks = new Int_t[kNtrack*nClusterROC];
1136
1137 // Loop through the dictionary arrays one-by-one
1138 // to keep memory consumption low
b65e5048 1139 AliTRDarrayDictionary *tracksIn = 0; //mod
3fe61b77 1140 for (Int_t iDict = 0; iDict < kNdict; iDict++) {
1141
1142 // tracksIn should be expanded beforehand!
b65e5048 1143 tracksIn = (AliTRDarrayDictionary *) fDigitsManager->GetDictionary(idet,iDict);
3fe61b77 1144
1145 // Loop though the clusters found in this ROC
1146 for (iClusterROC = 0; iClusterROC < nClusterROC; iClusterROC++) {
317b5644 1147
3fe61b77 1148 AliTRDcluster *cluster = (AliTRDcluster *)
b65e5048 1149 RecPoints()->UncheckedAt(firstClusterROC+iClusterROC);
3fe61b77 1150 row = cluster->GetLabel(0);
1151 col = cluster->GetLabel(1);
1152 time = cluster->GetLabel(2);
1153
1154 for (iPad = 0; iPad < kNclus; iPad++) {
b65e5048 1155 Int_t iPadCol = col - 1 + iPad;
1156 Int_t index = tracksIn->GetData(row,iPadCol,time); //Modification of -1 in Track
1157 idxTracks[3*iPad+iDict + iClusterROC*kNtrack] = index;
3fe61b77 1158 }
1159
1160 }
1161
1162 }
1163
1164 // Copy the track indices into the cluster
1165 // Loop though the clusters found in this ROC
1166 for (iClusterROC = 0; iClusterROC < nClusterROC; iClusterROC++) {
317b5644 1167
3fe61b77 1168 AliTRDcluster *cluster = (AliTRDcluster *)
1169 RecPoints()->UncheckedAt(firstClusterROC+iClusterROC);
1170 cluster->SetLabel(-9999,0);
1171 cluster->SetLabel(-9999,1);
1172 cluster->SetLabel(-9999,2);
1173
1174 cluster->AddTrackIndex(&idxTracks[iClusterROC*kNtrack]);
1175
1176 }
1177
1178 delete [] idxTracks;
1179
1180 return kTRUE;
1181
1182}
1183
1184//_____________________________________________________________________________
acc49af9 1185Double_t AliTRDclusterizer::GetCOG(Double_t signal[5]) const
3fe61b77 1186{
1187 //
1188 // Get COG position
1189 // Used for clusters with more than 3 pads - where LUT not applicable
1190 //
1191
1192 Double_t sum = signal[0]
317b5644 1193 + signal[1]
1194 + signal[2]
1195 + signal[3]
1196 + signal[4];
3fe61b77 1197
eb52b657 1198 // ???????????? CBL
1199 // Go to 3 pad COG ????
023b669c 1200 // ???????????? CBL
3fe61b77 1201 Double_t res = (0.0 * (-signal[0] + signal[4])
1202 + (-signal[1] + signal[3])) / sum;
1203
1204 return res;
1205
1206}
1207
1208//_____________________________________________________________________________
053767a4 1209Double_t AliTRDclusterizer::Unfold(Double_t eps, Int_t layer, Double_t *padSignal)
3fe61b77 1210{
1211 //
1212 // Method to unfold neighbouring maxima.
1213 // The charge ratio on the overlapping pad is calculated
1214 // until there is no more change within the range given by eps.
1215 // The resulting ratio is then returned to the calling method.
1216 //
1217
1218 AliTRDcalibDB *calibration = AliTRDcalibDB::Instance();
6d50f529 1219 if (!calibration) {
3fe61b77 1220 AliError("No AliTRDcalibDB instance available\n");
1221 return kFALSE;
6d50f529 1222 }
3fe61b77 1223
1224 Int_t irc = 0;
1225 Int_t itStep = 0; // Count iteration steps
1226
1227 Double_t ratio = 0.5; // Start value for ratio
1228 Double_t prevRatio = 0.0; // Store previous ratio
1229
1230 Double_t newLeftSignal[3] = { 0.0, 0.0, 0.0 }; // Array to store left cluster signal
1231 Double_t newRightSignal[3] = { 0.0, 0.0, 0.0 }; // Array to store right cluster signal
1232 Double_t newSignal[3] = { 0.0, 0.0, 0.0 };
1233
1234 // Start the iteration
1235 while ((TMath::Abs(prevRatio - ratio) > eps) && (itStep < 10)) {
1236
1237 itStep++;
1238 prevRatio = ratio;
1239
1240 // Cluster position according to charge ratio
1241 Double_t maxLeft = (ratio*padSignal[2] - padSignal[0])
1242 / (padSignal[0] + padSignal[1] + ratio*padSignal[2]);
1243 Double_t maxRight = (padSignal[4] - (1-ratio)*padSignal[2])
1244 / ((1.0 - ratio)*padSignal[2] + padSignal[3] + padSignal[4]);
1245
1246 // Set cluster charge ratio
053767a4 1247 irc = calibration->PadResponse(1.0,maxLeft ,layer,newSignal);
3fe61b77 1248 Double_t ampLeft = padSignal[1] / newSignal[1];
053767a4 1249 irc = calibration->PadResponse(1.0,maxRight,layer,newSignal);
3fe61b77 1250 Double_t ampRight = padSignal[3] / newSignal[1];
1251
1252 // Apply pad response to parameters
053767a4 1253 irc = calibration->PadResponse(ampLeft ,maxLeft ,layer,newLeftSignal );
1254 irc = calibration->PadResponse(ampRight,maxRight,layer,newRightSignal);
3fe61b77 1255
1256 // Calculate new overlapping ratio
1257 ratio = TMath::Min((Double_t) 1.0
1258 ,newLeftSignal[2] / (newLeftSignal[2] + newRightSignal[0]));
1259
b43a3e17 1260 }
88719a08 1261
3fe61b77 1262 return ratio;
1263
1264}
88719a08 1265
3fe61b77 1266//_____________________________________________________________________________
b65e5048 1267void AliTRDclusterizer::TailCancelation(AliTRDarrayADC *digitsIn
1268 , AliTRDarraySignal *digitsOut
1269 , AliTRDSignalIndex *indexesIn
1270 , AliTRDSignalIndex *indexesOut
1271 , Int_t nTimeTotal
1272 , Float_t adcThreshold
1273 , AliTRDCalROC *calGainFactorROC
1274 , Float_t calGainFactorDetValue)
3fe61b77 1275{
1276 //
1277 // Applies the tail cancelation and gain factors:
1278 // Transform digitsIn to digitsOut
1279 //
1280
1281 Int_t iRow = 0;
1282 Int_t iCol = 0;
1283 Int_t iTime = 0;
1284
3fe61b77 1285 Double_t *inADC = new Double_t[nTimeTotal]; // ADC data before tail cancellation
1286 Double_t *outADC = new Double_t[nTimeTotal]; // ADC data after tail cancellation
1287 indexesIn->ResetCounters();
1288 while (indexesIn->NextRCIndex(iRow, iCol))
1289 {
1290 Float_t calGainFactorROCValue = calGainFactorROC->GetValue(iCol,iRow);
1291 Double_t gain = calGainFactorDetValue
317b5644 1292 * calGainFactorROCValue;
3fe61b77 1293
f5375dcb 1294 Bool_t corrupted = kFALSE;
3fe61b77 1295 for (iTime = 0; iTime < nTimeTotal; iTime++)
b65e5048 1296 {
1297 // Apply gain gain factor
ce1fb7da 1298 inADC[iTime] = digitsIn->GetDataB(iRow,iCol,iTime);
b65e5048 1299 if (digitsIn->GetPadStatus(iRow, iCol, iTime)) corrupted = kTRUE;
1300 inADC[iTime] /= gain;
1301 outADC[iTime] = inADC[iTime];
1302 }
1303 if (!corrupted)
1304 {
1305 // Apply the tail cancelation via the digital filter
1306 // (only for non-coorupted pads)
1307 if (fReconstructor->GetRecoParam() ->IsTailCancelation())
1308 {
1309 DeConvExp(inADC,outADC,nTimeTotal,fReconstructor->GetRecoParam() ->GetTCnexp());
ce1fb7da 1310 }
b65e5048 1311 }
3fe61b77 1312
1313 indexesIn->ResetTbinCounter();
b65e5048 1314
3fe61b77 1315 while (indexesIn->NextTbinIndex(iTime))
b65e5048 1316 {
1317 // Store the amplitude of the digit if above threshold
1318 if (outADC[iTime] > adcThreshold)
1319 {
1320 digitsOut->SetData(iRow,iCol,iTime,outADC[iTime]);
1321 indexesOut->AddIndexTBin(iRow,iCol,iTime);
1322 }
1323 } // while itime
3fe61b77 1324
1325 } // while irow icol
1326
1327 delete [] inADC;
1328 delete [] outADC;
1329
1330 return;
1331
1332}
1333
1334//_____________________________________________________________________________
1335void AliTRDclusterizer::DeConvExp(Double_t *source, Double_t *target
b65e5048 1336 , Int_t n, Int_t nexp)
3fe61b77 1337{
1338 //
1339 // Tail cancellation by deconvolution for PASA v4 TRF
1340 //
1341
1342 Double_t rates[2];
1343 Double_t coefficients[2];
1344
1345 // Initialization (coefficient = alpha, rates = lambda)
1346 Double_t r1 = 1.0;
1347 Double_t r2 = 1.0;
1348 Double_t c1 = 0.5;
1349 Double_t c2 = 0.5;
1350
1351 if (nexp == 1) { // 1 Exponentials
1352 r1 = 1.156;
1353 r2 = 0.130;
1354 c1 = 0.066;
1355 c2 = 0.000;
1356 }
1357 if (nexp == 2) { // 2 Exponentials
181c7f7e 1358 Double_t par[4];
1359 fReconstructor->GetTCParams(par);
1360 r1 = par[0];//1.156;
1361 r2 = par[1];//0.130;
1362 c1 = par[2];//0.114;
1363 c2 = par[3];//0.624;
3fe61b77 1364 }
1365
1366 coefficients[0] = c1;
1367 coefficients[1] = c2;
1368
1369 Double_t dt = 0.1;
1370
1371 rates[0] = TMath::Exp(-dt/(r1));
1372 rates[1] = TMath::Exp(-dt/(r2));
1373
1374 Int_t i = 0;
1375 Int_t k = 0;
1376
1377 Double_t reminder[2];
1378 Double_t correction = 0.0;
1379 Double_t result = 0.0;
1380
1381 // Attention: computation order is important
1382 for (k = 0; k < nexp; k++) {
1383 reminder[k] = 0.0;
1384 }
1385
1386 for (i = 0; i < n; i++) {
1387
1388 result = (source[i] - correction); // No rescaling
1389 target[i] = result;
1390
1391 for (k = 0; k < nexp; k++) {
1392 reminder[k] = rates[k] * (reminder[k] + coefficients[k] * result);
1393 }
1394
1395 correction = 0.0;
1396 for (k = 0; k < nexp; k++) {
1397 correction += reminder[k];
1398 }
1399
1400 }
6d50f529 1401
1402}
1403
1404//_____________________________________________________________________________
1405void AliTRDclusterizer::ResetRecPoints()
1406{
1407 //
1408 // Resets the list of rec points
1409 //
1410
1411 if (fRecPoints) {
1412 fRecPoints->Delete();
48f8adf3 1413 delete fRecPoints;
6d50f529 1414 }
6d50f529 1415}
1416
1417//_____________________________________________________________________________
66f6bfd9 1418TClonesArray *AliTRDclusterizer::RecPoints()
6d50f529 1419{
1420 //
1421 // Returns the list of rec points
1422 //
1423
1424 if (!fRecPoints) {
48f8adf3 1425 if(!(fRecPoints = AliTRDReconstructor::GetClusters())){
8ae98148 1426 // determine number of clusters which has to be allocated
1427 Float_t nclusters = fReconstructor->GetRecoParam()->GetNClusters();
1428 if(fReconstructor->IsHLT()) nclusters /= AliTRDgeometry::kNsector;
1429
1430 fRecPoints = new TClonesArray("AliTRDcluster", Int_t(nclusters));
48f8adf3 1431 }
1432 //SetClustersOwner(kTRUE);
1433 AliTRDReconstructor::SetClusters(0x0);
6d50f529 1434 }
6d50f529 1435 return fRecPoints;
eb52b657 1436
3551db50 1437}
fc546d21 1438
1439//_____________________________________________________________________________
1440void AliTRDclusterizer::FillLUT()
1441{
1442 //
1443 // Create the LUT
1444 //
1445
1446 const Int_t kNlut = 128;
1447
053767a4 1448 fLUTbin = AliTRDgeometry::kNlayer * kNlut;
fc546d21 1449
1450 // The lookup table from Bogdan
053767a4 1451 Float_t lut[AliTRDgeometry::kNlayer][kNlut] = {
fc546d21 1452 {
1453 0.0070, 0.0150, 0.0224, 0.0298, 0.0374, 0.0454, 0.0533, 0.0611,
1454 0.0684, 0.0755, 0.0827, 0.0900, 0.0975, 0.1049, 0.1120, 0.1187,
1455 0.1253, 0.1318, 0.1385, 0.1453, 0.1519, 0.1584, 0.1646, 0.1704,
1456 0.1762, 0.1821, 0.1879, 0.1938, 0.1996, 0.2053, 0.2108, 0.2160,
1457 0.2210, 0.2260, 0.2310, 0.2361, 0.2411, 0.2461, 0.2509, 0.2557,
1458 0.2602, 0.2646, 0.2689, 0.2732, 0.2774, 0.2816, 0.2859, 0.2901,
1459 0.2942, 0.2983, 0.3022, 0.3061, 0.3099, 0.3136, 0.3172, 0.3207,
1460 0.3242, 0.3278, 0.3312, 0.3347, 0.3382, 0.3416, 0.3450, 0.3483,
1461 0.3515, 0.3547, 0.3579, 0.3609, 0.3639, 0.3669, 0.3698, 0.3727,
1462 0.3756, 0.3785, 0.3813, 0.3842, 0.3870, 0.3898, 0.3926, 0.3952,
1463 0.3979, 0.4005, 0.4032, 0.4057, 0.4082, 0.4108, 0.4132, 0.4157,
1464 0.4181, 0.4205, 0.4228, 0.4252, 0.4275, 0.4299, 0.4322, 0.4345,
1465 0.4367, 0.4390, 0.4412, 0.4434, 0.4456, 0.4478, 0.4499, 0.4520,
1466 0.4541, 0.4562, 0.4583, 0.4603, 0.4623, 0.4643, 0.4663, 0.4683,
1467 0.4702, 0.4722, 0.4741, 0.4758, 0.4774, 0.4790, 0.4805, 0.4824,
1468 0.4844, 0.4863, 0.4883, 0.4902, 0.4921, 0.4940, 0.4959, 0.4978
1469 },
1470 {
1471 0.0072, 0.0156, 0.0235, 0.0313, 0.0394, 0.0478, 0.0561, 0.0642,
1472 0.0718, 0.0792, 0.0868, 0.0947, 0.1025, 0.1101, 0.1172, 0.1241,
1473 0.1309, 0.1378, 0.1449, 0.1518, 0.1586, 0.1650, 0.1710, 0.1770,
1474 0.1830, 0.1891, 0.1952, 0.2011, 0.2070, 0.2125, 0.2177, 0.2229,
1475 0.2280, 0.2332, 0.2383, 0.2435, 0.2484, 0.2533, 0.2581, 0.2627,
1476 0.2670, 0.2714, 0.2757, 0.2799, 0.2842, 0.2884, 0.2927, 0.2968,
1477 0.3008, 0.3048, 0.3086, 0.3123, 0.3159, 0.3195, 0.3231, 0.3266,
1478 0.3301, 0.3335, 0.3370, 0.3404, 0.3438, 0.3471, 0.3504, 0.3536,
1479 0.3567, 0.3598, 0.3628, 0.3657, 0.3686, 0.3715, 0.3744, 0.3772,
1480 0.3800, 0.3828, 0.3856, 0.3884, 0.3911, 0.3938, 0.3965, 0.3991,
1481 0.4016, 0.4042, 0.4067, 0.4092, 0.4116, 0.4140, 0.4164, 0.4187,
1482 0.4211, 0.4234, 0.4257, 0.4280, 0.4302, 0.4325, 0.4347, 0.4369,
1483 0.4391, 0.4413, 0.4434, 0.4456, 0.4477, 0.4497, 0.4518, 0.4538,
1484 0.4558, 0.4578, 0.4598, 0.4618, 0.4637, 0.4656, 0.4675, 0.4694,
1485 0.4713, 0.4732, 0.4750, 0.4766, 0.4781, 0.4797, 0.4813, 0.4832,
1486 0.4851, 0.4870, 0.4888, 0.4906, 0.4925, 0.4942, 0.4960, 0.4978
1487 },
1488 {
1489 0.0075, 0.0163, 0.0246, 0.0328, 0.0415, 0.0504, 0.0592, 0.0674,
1490 0.0753, 0.0832, 0.0914, 0.0996, 0.1077, 0.1154, 0.1225, 0.1296,
1491 0.1369, 0.1442, 0.1515, 0.1585, 0.1652, 0.1714, 0.1776, 0.1839,
1492 0.1902, 0.1965, 0.2025, 0.2085, 0.2141, 0.2194, 0.2247, 0.2299,
1493 0.2352, 0.2405, 0.2457, 0.2507, 0.2557, 0.2604, 0.2649, 0.2693,
1494 0.2737, 0.2780, 0.2823, 0.2867, 0.2909, 0.2951, 0.2992, 0.3033,
1495 0.3072, 0.3110, 0.3146, 0.3182, 0.3218, 0.3253, 0.3288, 0.3323,
1496 0.3357, 0.3392, 0.3426, 0.3459, 0.3492, 0.3524, 0.3555, 0.3586,
1497 0.3616, 0.3645, 0.3674, 0.3703, 0.3731, 0.3759, 0.3787, 0.3815,
1498 0.3843, 0.3870, 0.3897, 0.3925, 0.3950, 0.3976, 0.4002, 0.4027,
1499 0.4052, 0.4076, 0.4101, 0.4124, 0.4148, 0.4171, 0.4194, 0.4217,
1500 0.4239, 0.4262, 0.4284, 0.4306, 0.4328, 0.4350, 0.4371, 0.4393,
1501 0.4414, 0.4435, 0.4455, 0.4476, 0.4496, 0.4516, 0.4536, 0.4555,
1502 0.4575, 0.4594, 0.4613, 0.4632, 0.4650, 0.4669, 0.4687, 0.4705,
1503 0.4723, 0.4741, 0.4758, 0.4773, 0.4789, 0.4804, 0.4821, 0.4839,
1504 0.4857, 0.4875, 0.4893, 0.4910, 0.4928, 0.4945, 0.4961, 0.4978
1505 },
1506 {
1507 0.0078, 0.0171, 0.0258, 0.0345, 0.0438, 0.0532, 0.0624, 0.0708,
1508 0.0791, 0.0875, 0.0962, 0.1048, 0.1130, 0.1206, 0.1281, 0.1356,
1509 0.1432, 0.1508, 0.1582, 0.1651, 0.1716, 0.1780, 0.1845, 0.1910,
1510 0.1975, 0.2038, 0.2099, 0.2155, 0.2210, 0.2263, 0.2317, 0.2371,
1511 0.2425, 0.2477, 0.2528, 0.2578, 0.2626, 0.2671, 0.2715, 0.2759,
1512 0.2803, 0.2846, 0.2890, 0.2933, 0.2975, 0.3016, 0.3056, 0.3095,
1513 0.3132, 0.3168, 0.3204, 0.3239, 0.3274, 0.3309, 0.3344, 0.3378,
1514 0.3412, 0.3446, 0.3479, 0.3511, 0.3543, 0.3574, 0.3603, 0.3633,
1515 0.3662, 0.3690, 0.3718, 0.3747, 0.3774, 0.3802, 0.3829, 0.3857,
1516 0.3883, 0.3910, 0.3936, 0.3962, 0.3987, 0.4012, 0.4037, 0.4061,
1517 0.4085, 0.4109, 0.4132, 0.4155, 0.4177, 0.4200, 0.4222, 0.4244,
1518 0.4266, 0.4288, 0.4309, 0.4331, 0.4352, 0.4373, 0.4394, 0.4414,
1519 0.4435, 0.4455, 0.4475, 0.4494, 0.4514, 0.4533, 0.4552, 0.4571,
1520 0.4590, 0.4608, 0.4626, 0.4645, 0.4662, 0.4680, 0.4698, 0.4715,
1521 0.4733, 0.4750, 0.4766, 0.4781, 0.4796, 0.4812, 0.4829, 0.4846,
1522 0.4863, 0.4880, 0.4897, 0.4914, 0.4930, 0.4946, 0.4963, 0.4979
1523 },
1524 {
1525 0.0081, 0.0178, 0.0270, 0.0364, 0.0463, 0.0562, 0.0656, 0.0744,
1526 0.0831, 0.0921, 0.1013, 0.1102, 0.1183, 0.1261, 0.1339, 0.1419,
1527 0.1499, 0.1576, 0.1648, 0.1715, 0.1782, 0.1849, 0.1917, 0.1984,
1528 0.2048, 0.2110, 0.2167, 0.2223, 0.2278, 0.2333, 0.2389, 0.2444,
1529 0.2497, 0.2548, 0.2598, 0.2645, 0.2691, 0.2735, 0.2780, 0.2824,
1530 0.2868, 0.2912, 0.2955, 0.2997, 0.3038, 0.3078, 0.3116, 0.3152,
1531 0.3188, 0.3224, 0.3259, 0.3294, 0.3329, 0.3364, 0.3398, 0.3432,
1532 0.3465, 0.3497, 0.3529, 0.3561, 0.3591, 0.3620, 0.3649, 0.3677,
1533 0.3705, 0.3733, 0.3761, 0.3788, 0.3816, 0.3843, 0.3869, 0.3896,
1534 0.3922, 0.3948, 0.3973, 0.3998, 0.4022, 0.4047, 0.4070, 0.4094,
1535 0.4117, 0.4139, 0.4162, 0.4184, 0.4206, 0.4227, 0.4249, 0.4270,
1536 0.4291, 0.4313, 0.4334, 0.4354, 0.4375, 0.4395, 0.4415, 0.4435,
1537 0.4455, 0.4474, 0.4493, 0.4512, 0.4531, 0.4550, 0.4568, 0.4586,
1538 0.4604, 0.4622, 0.4639, 0.4657, 0.4674, 0.4691, 0.4708, 0.4725,
1539 0.4742, 0.4758, 0.4773, 0.4788, 0.4803, 0.4819, 0.4836, 0.4852,
1540 0.4869, 0.4885, 0.4901, 0.4917, 0.4933, 0.4948, 0.4964, 0.4979
1541 },
1542 {
1543 0.0085, 0.0189, 0.0288, 0.0389, 0.0497, 0.0603, 0.0699, 0.0792,
1544 0.0887, 0.0985, 0.1082, 0.1170, 0.1253, 0.1336, 0.1421, 0.1505,
1545 0.1587, 0.1662, 0.1733, 0.1803, 0.1874, 0.1945, 0.2014, 0.2081,
1546 0.2143, 0.2201, 0.2259, 0.2316, 0.2374, 0.2431, 0.2487, 0.2541,
1547 0.2593, 0.2642, 0.2689, 0.2735, 0.2781, 0.2826, 0.2872, 0.2917,
1548 0.2961, 0.3003, 0.3045, 0.3086, 0.3125, 0.3162, 0.3198, 0.3235,
1549 0.3270, 0.3306, 0.3342, 0.3377, 0.3411, 0.3446, 0.3479, 0.3511,
1550 0.3543, 0.3575, 0.3605, 0.3634, 0.3663, 0.3691, 0.3720, 0.3748,
1551 0.3775, 0.3803, 0.3830, 0.3857, 0.3884, 0.3911, 0.3937, 0.3962,
1552 0.3987, 0.4012, 0.4036, 0.4060, 0.4084, 0.4107, 0.4129, 0.4152,
1553 0.4174, 0.4196, 0.4218, 0.4239, 0.4261, 0.4282, 0.4303, 0.4324,
1554 0.4344, 0.4365, 0.4385, 0.4405, 0.4425, 0.4445, 0.4464, 0.4483,
1555 0.4502, 0.4521, 0.4539, 0.4558, 0.4576, 0.4593, 0.4611, 0.4629,
1556 0.4646, 0.4663, 0.4680, 0.4697, 0.4714, 0.4730, 0.4747, 0.4759,
1557 0.4769, 0.4780, 0.4790, 0.4800, 0.4811, 0.4827, 0.4843, 0.4859,
1558 0.4874, 0.4889, 0.4905, 0.4920, 0.4935, 0.4950, 0.4965, 0.4979
1559 }
1560 };
1561
1562 if (fLUT) {
1563 delete [] fLUT;
1564 }
1565 fLUT = new Double_t[fLUTbin];
1566
053767a4 1567 for (Int_t ilayer = 0; ilayer < AliTRDgeometry::kNlayer; ilayer++) {
fc546d21 1568 for (Int_t ilut = 0; ilut < kNlut; ilut++ ) {
053767a4 1569 fLUT[ilayer*kNlut+ilut] = lut[ilayer][ilut];
fc546d21 1570 }
1571 }
1572
1573}
1574
1575//_____________________________________________________________________________
eb52b657 1576Double_t AliTRDclusterizer::LUTposition(Int_t ilayer
1577 , Double_t ampL
1578 , Double_t ampC
1579 , Double_t ampR) const
fc546d21 1580{
1581 //
1582 // Calculates the cluster position using the lookup table.
1583 // Method provided by Bogdan Vulpescu.
1584 //
1585
1586 const Int_t kNlut = 128;
1587
1588 Double_t pos;
1589 Double_t x = 0.0;
1590 Double_t xmin;
1591 Double_t xmax;
1592 Double_t xwid;
1593
1594 Int_t side = 0;
1595 Int_t ix;
1596
053767a4 1597 Double_t xMin[AliTRDgeometry::kNlayer] = { 0.006492, 0.006377, 0.006258
317b5644 1598 , 0.006144, 0.006030, 0.005980 };
053767a4 1599 Double_t xMax[AliTRDgeometry::kNlayer] = { 0.960351, 0.965870, 0.970445
317b5644 1600 , 0.974352, 0.977667, 0.996101 };
fc546d21 1601
1602 if (ampL > ampR) {
1603 x = (ampL - ampR) / ampC;
1604 side = -1;
1605 }
1606 else if (ampL < ampR) {
1607 x = (ampR - ampL) / ampC;
1608 side = +1;
1609 }
1610
1611 if (ampL != ampR) {
1612
053767a4 1613 xmin = xMin[ilayer] + 0.000005;
1614 xmax = xMax[ilayer] - 0.000005;
fc546d21 1615 xwid = (xmax - xmin) / 127.0;
1616
1617 if (x < xmin) {
1618 pos = 0.0000;
1619 }
1620 else if (x > xmax) {
1621 pos = side * 0.5000;
1622 }
1623 else {
1624 ix = (Int_t) ((x - xmin) / xwid);
053767a4 1625 pos = side * fLUT[ilayer*kNlut+ix];
fc546d21 1626 }
317b5644 1627
fc546d21 1628 }
1629 else {
1630
1631 pos = 0.0;
1632
1633 }
1634
1635 return pos;
1636
1637}