1 /**************************************************************************
2 * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
4 * Author: The ALICE Off-line Project. *
5 * Contributors are mentioned in the code where appropriate. *
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 **************************************************************************/
16 ///////////////////////////////////////////////////////////////////////////////
18 // TRD MCM (Multi Chip Module) simulator //
20 ///////////////////////////////////////////////////////////////////////////////
26 New release on 2007/08/17
28 AliTRDmcmSim is now stably working and zero suppression function seems ok.
29 From now, the default version of raw data is set to 3 in AliTRDfeeParam.
31 The following internal parameters were abolished because it is useless and
37 GetCol member was modified accordingly.
39 New member function DumpData was prepared for diagnostics.
41 ZSMapping member function was debugged. It was causing crash due to
42 wrong indexing in 1 dimensional numbering. Also code was shaped up better.
46 /*Semi-final version of TRD raw data simulation code with zero suppression (ZS)
47 similar to TRD FEE. ZS is realized by the class group:
53 AliTRDfeeParam has been modified to have more parameters like raw data
54 production version and so on. AliTRDmcmSim is new class and this is the core
55 of MCM (PASA+TRAP) simulator. It has still very simple function and it will be
56 another project to improve this to make it closer to the reall FEE.
57 AliTRDrawData has been modified to use new class AliTRDmcmSim.
59 These modifications were tested on Aug. 02 HEAD version that code itself
60 compiles. I'm sure there must be still bugs and we need testing by as many as
61 possible persons now. Especially it seems HLT part is impacted by problems
62 because some parameters were moved from AliTRDrawData to AliTRDfeeParam (like
63 fRawVersion disappeared from AliTRDrawData).
65 In TRD definition, we have now 4 raw data versions.
67 0 very old offline version (by Bogdan)
68 1 test version (no zero suppression)
69 2 final version (no zero suppression)
70 3 test version (with zero suppression)
72 The default is still set to 2 in AliTRDfeeParam::fgkRAWversion and it uses
73 previously existing codes. If you set this to 3, AliTRDrawData changes behavior
74 to use AliTRDmcmSim with ZS.
76 Plan is after we make sure it works stably, we delete AliTRDmcm which is obsolete.
77 However it still take time because tracklet part is not yet touched.
78 The default raw version is 2.
83 // if no histo is drawn, these are obsolete
87 // only needed if I/O of tracklets is activated
99 #include "AliTRDmcmSim.h"
100 #include "AliTRDfeeParam.h"
101 #include "AliTRDSimParam.h"
102 #include "AliTRDgeometry.h"
103 #include "AliTRDcalibDB.h"
104 #include "AliTRDdigitsManager.h"
106 // additional for new tail filter and/or tracklet
107 #include "AliTRDtrapAlu.h"
108 #include "AliTRDpadPlane.h"
109 #include "AliTRDtrackletMCM.h"
112 #include "AliLoader.h"
114 ClassImp(AliTRDmcmSim)
116 //_____________________________________________________________________________
117 AliTRDmcmSim::AliTRDmcmSim() :TObject()
118 ,fInitialized(kFALSE)
143 // AliTRDmcmSim default constructor
146 // By default, nothing is initialized.
147 // It is necessary to issue Init before use.
150 //_____________________________________________________________________________
151 AliTRDmcmSim::AliTRDmcmSim(const AliTRDmcmSim &m)
153 ,fInitialized(kFALSE)
179 // AliTRDmcmSim copy constructor
182 // By default, nothing is initialized.
183 // It is necessary to issue Init before use.
186 //_____________________________________________________________________________
187 AliTRDmcmSim::~AliTRDmcmSim()
190 // AliTRDmcmSim destructor
193 if( fADCR != NULL ) {
194 for( Int_t iadc = 0 ; iadc < fNADC; iadc++ ) {
195 delete [] fADCR[iadc];
196 delete [] fADCF[iadc];
197 delete [] fADCT[iadc];
198 delete [] fZSM [iadc];
216 //_____________________________________________________________________________
217 AliTRDmcmSim &AliTRDmcmSim::operator=(const AliTRDmcmSim &m)
220 // Assignment operator
224 ((AliTRDmcmSim &) m).Copy(*this);
230 //_____________________________________________________________________________
231 void AliTRDmcmSim::Copy(TObject &m) const
236 ((AliTRDmcmSim &) m).fNextEvent = 0; //new
237 ((AliTRDmcmSim &) m).fMaxTracklets = 0; //new
238 ((AliTRDmcmSim &) m).fInitialized = 0;
239 ((AliTRDmcmSim &) m).fChaId = 0;
240 ((AliTRDmcmSim &) m).fSector = 0;
241 ((AliTRDmcmSim &) m).fStack = 0;
242 ((AliTRDmcmSim &) m).fLayer = 0;
243 ((AliTRDmcmSim &) m).fRobPos = 0;
244 ((AliTRDmcmSim &) m).fMcmPos = 0;
245 ((AliTRDmcmSim &) m).fNADC = 0;
246 ((AliTRDmcmSim &) m).fNTimeBin = 0;
247 ((AliTRDmcmSim &) m).fRow = 0;
248 ((AliTRDmcmSim &) m).fADCR = 0;
249 ((AliTRDmcmSim &) m).fADCF = 0;
250 ((AliTRDmcmSim &) m).fADCT = 0; //new
251 ((AliTRDmcmSim &) m).fPosLUT = 0; //new
252 ((AliTRDmcmSim &) m).fMCMT = 0; //new
253 ((AliTRDmcmSim &) m).fZSM = 0;
254 ((AliTRDmcmSim &) m).fZSM1Dim = 0;
255 ((AliTRDmcmSim &) m).fFeeParam = 0;
256 ((AliTRDmcmSim &) m).fSimParam = 0;
257 ((AliTRDmcmSim &) m).fCal = 0;
258 ((AliTRDmcmSim &) m).fGeo = 0;
262 //_____________________________________________________________________________
264 //void AliTRDmcmSim::Init( Int_t chaId, Int_t robPos, Int_t mcmPos )
265 void AliTRDmcmSim::Init( Int_t chaId, Int_t robPos, Int_t mcmPos, Bool_t newEvent = kFALSE ) // only for readout tree (new event)
268 // Initialize the class with new geometry information
269 // fADC array will be reused with filled by zero
273 fFeeParam = AliTRDfeeParam::Instance();
274 fSimParam = AliTRDSimParam::Instance();
275 fCal = AliTRDcalibDB::Instance();
276 fGeo = new AliTRDgeometry();
278 fSector = fGeo->GetSector( fChaId );
279 fStack = fGeo->GetStack( fChaId );
280 fLayer = fGeo->GetLayer( fChaId );
283 fNADC = fFeeParam->GetNadcMcm();
284 fNTimeBin = fCal->GetNumberOfTimeBins();
285 fRow = fFeeParam->GetPadRowFromMCM( fRobPos, fMcmPos );
287 fMaxTracklets = fFeeParam->GetMaxNrOfTracklets();
292 if (newEvent == kTRUE) {
298 // Allocate ADC data memory if not yet done
299 if( fADCR == NULL ) {
300 fADCR = new Int_t *[fNADC];
301 fADCF = new Int_t *[fNADC];
302 fADCT = new Int_t *[fNADC]; //new
303 fZSM = new Int_t *[fNADC];
304 fZSM1Dim = new Int_t [fNADC];
305 for( Int_t iadc = 0 ; iadc < fNADC; iadc++ ) {
306 fADCR[iadc] = new Int_t[fNTimeBin];
307 fADCF[iadc] = new Int_t[fNTimeBin];
308 fADCT[iadc] = new Int_t[fNTimeBin]; //new
309 fZSM [iadc] = new Int_t[fNTimeBin];
313 // Initialize ADC data
314 for( Int_t iadc = 0 ; iadc < fNADC; iadc++ ) {
315 for( Int_t it = 0 ; it < fNTimeBin ; it++ ) {
318 fADCT[iadc][it] = -1; //new
319 fZSM [iadc][it] = 1; // Default unread = 1
321 fZSM1Dim[iadc] = 1; // Default unread = 1
325 fPosLUT = new Int_t[128];
326 for(Int_t i = 0; i<128; i++){
330 fMCMT = new UInt_t[fMaxTracklets];
331 for(Int_t i = 0; i < fMaxTracklets; i++) {
336 fInitialized = kTRUE;
339 //_____________________________________________________________________________
340 Bool_t AliTRDmcmSim::CheckInitialized()
343 // Check whether object is initialized
346 if( ! fInitialized ) {
347 AliDebug(2, Form ("AliTRDmcmSim is not initialized but function other than Init() is called."));
352 //_____________________________________________________________________________
355 void AliTRDmcmSim::SetPosLUT() {
356 Double_t iHi = (Double_t)fCal->GetPRFhi();
357 Double_t iLo = (Double_t)fCal->GetPRFlo();
358 Int_t nBin = fCal->GetPRFbin();
359 Int_t iOff = fLayer * nBin;
360 Int_t kNlayer = fGeo->Nlayer();
362 Float_t *sPRFsmp = new Float_t[nBin*kNlayer];
363 Double_t *sPRFlayer = new Double_t[nBin];
366 for(Int_t i = 0; i<nBin*kNlayer; i++){
368 //printf("%f\n",fCal->GetSampledPRF()[i]);
369 sPRFsmp[i] = fCal->GetSampledPRF()[i];
373 Double_t sWidth = (iHi-iLo)/((Double_t) nBin);
374 Int_t sPad = (Int_t) (1.0/sWidth);
376 // get the PRF for actual layer (interpolated to ibin data-points; 61 measured)
377 for(Int_t iBin = 0; iBin < nBin; iBin++){
378 sPRFlayer[iBin] = (Double_t)sPRFsmp[iOff+iBin];
381 Int_t bin0 = (Int_t)(-iLo / sWidth - 0.5); // bin-nr. for pad-position 0
383 Int_t bin1 = (Int_t)((Double_t)(0.5 - iLo) / sWidth - 0.5); // bin-nr. for pad-position 0.5
385 bin0 = bin0 + 1; //avoid negative values in aYest (start right of symmetry center)
386 while (bin0-sPad<0) {
389 while (bin1+sPad>=nBin) {
393 Double_t* aYest = new Double_t[bin1-bin0+1];
395 /*TH1F* hist1 = new TH1F("h1","yest(y)",128,0,0.5);
396 TH1F* hist2 = new TH1F("h2","y(yest)",128,0,0.5);
397 TH1F* hist3 = new TH1F("h3","y(yest)-yest",128,0,0.5);
398 TH1F* hist4 = new TH1F("h4","y(yest)-yest,discrete",128,0,0.5);
400 TCanvas *c1 = new TCanvas("c1","c1",800,1000);
402 TCanvas *c2 = new TCanvas("c2","c2",800,1000);
404 TCanvas *c3 = new TCanvas("c3","c3",800,1000);
406 TCanvas *c4 = new TCanvas("c4","c4",800,1000);
409 for(Int_t iBin = bin0; iBin <= bin1; iBin++){
410 aYest[iBin-bin0] = 0.5*(sPRFlayer[iBin-sPad] - sPRFlayer[iBin+sPad])/(sPRFlayer[iBin]); // estimated position from PRF; between 0 and 1
411 //Double_t position = ((Double_t)(iBin)+0.5)*sWidth+iLo;
412 // hist1->Fill(position,aYest[iBin-bin0]);
417 Double_t aY[128]; // reversed function
422 for(Int_t j = 0; j<128; j++) { // loop over all Yest; LUT has 128 entries;
423 Double_t yest = ((Double_t)j)/256;
426 while (yest>aYest[iBin] && iBin<(bin1-bin0)) {
429 if((iBin == bin1 - bin0)&&(yest>aYest[iBin])) {
430 aY[j] = 0.5; // yest too big
431 //hist2->Fill(yest,aY[j]);
435 Int_t bin_d = iBin + bin0 - 1;
436 Int_t bin_u = iBin + bin0;
437 Double_t y_d = ((Double_t)bin_d + 0.5)*sWidth + iLo; // lower y
438 Double_t y_u = ((Double_t)bin_u + 0.5)*sWidth + iLo; // upper y
439 Double_t yest_d = aYest[iBin-1]; // lower estimated y
440 Double_t yest_u = aYest[iBin]; // upper estimated y
442 aY[j] = ((yest-yest_d)/(yest_u-yest_d))*(y_u-y_d) + y_d;
443 //hist2->Fill(yest,aY[j]);
446 aY[j] = aY[j] - yest;
447 //hist3->Fill(yest,aY[j]);
449 a.AssignDouble(aY[j]);
451 fPosLUT[j] = a.GetValue(); // 1+8Bit value;128 entries;LUT is steered by abs(Q(i+1)-Q(i-1))/Q(i)=COG and gives the correction to COG/2
452 //hist4->Fill(yest,fPosLUT[j]);
465 //_____________________________________________________________________________
466 Int_t* AliTRDmcmSim::GetPosLUT(){
472 void AliTRDmcmSim::SetData( Int_t iadc, Int_t *adc )
475 // Store ADC data into array of raw data
478 if( !CheckInitialized() ) return;
480 if( iadc < 0 || iadc >= fNADC ) {
481 //Log (Form ("Error: iadc is out of range (should be 0 to %d).", fNADC-1));
485 for( int it = 0 ; it < fNTimeBin ; it++ ) {
486 fADCR[iadc][it] = (Int_t)(adc[it]);
490 //_____________________________________________________________________________
491 void AliTRDmcmSim::SetData( Int_t iadc, Int_t it, Int_t adc )
494 // Store ADC data into array of raw data
497 if( !CheckInitialized() ) return;
499 if( iadc < 0 || iadc >= fNADC ) {
500 //Log (Form ("Error: iadc is out of range (should be 0 to %d).", fNADC-1));
504 fADCR[iadc][it] = adc;
507 //_____________________________________________________________________________
508 void AliTRDmcmSim::SetDataPedestal( Int_t iadc )
511 // Store ADC data into array of raw data
514 if( !CheckInitialized() ) return;
516 if( iadc < 0 || iadc >= fNADC ) {
517 //Log (Form ("Error: iadc is out of range (should be 0 to %d).", fNADC-1));
521 for( Int_t it = 0 ; it < fNTimeBin ; it++ ) {
522 fADCR[iadc][it] = fSimParam->GetADCbaseline();
526 //_____________________________________________________________________________
527 Int_t AliTRDmcmSim::GetCol( Int_t iadc )
530 // Return column id of the pad for the given ADC channel
533 if( !CheckInitialized() ) return -1;
535 return fFeeParam->GetPadColFromADC(fRobPos, fMcmPos, iadc);
538 //_____________________________________________________________________________
539 Int_t AliTRDmcmSim::ProduceRawStream( UInt_t *buf, Int_t maxSize )
542 // Produce raw data stream from this MCM and put in buf
543 // Returns number of words filled, or negative value
544 // with -1 * number of overflowed words
549 Int_t nw = 0; // Number of written words
550 Int_t of = 0; // Number of overflowed words
551 Int_t rawVer = fFeeParam->GetRAWversion();
554 if( !CheckInitialized() ) return 0;
556 if( fFeeParam->GetRAWstoreRaw() ) {
562 // Produce MCM header
563 x = ((fRobPos * fFeeParam->GetNmcmRob() + fMcmPos) << 24) | ((iEv % 0x100000) << 4) | 0xC;
574 for( Int_t iAdc = 0 ; iAdc < fNADC ; iAdc++ ) {
575 if( fZSM1Dim[iAdc] == 0 ) { // 0 means not suppressed
587 // Produce ADC data. 3 timebins are packed into one 32 bits word
588 // In this version, different ADC channel will NOT share the same word
590 UInt_t aa=0, a1=0, a2=0, a3=0;
592 for (Int_t iAdc = 0; iAdc < 21; iAdc++ ) {
593 if( rawVer>= 3 && fZSM1Dim[iAdc] != 0 ) continue; // suppressed
594 aa = !(iAdc & 1) + 2;
595 for (Int_t iT = 0; iT < fNTimeBin; iT+=3 ) {
596 a1 = ((iT ) < fNTimeBin ) ? adc[iAdc][iT ] : 0;
597 a2 = ((iT + 1) < fNTimeBin ) ? adc[iAdc][iT+1] : 0;
598 a3 = ((iT + 2) < fNTimeBin ) ? adc[iAdc][iT+2] : 0;
599 x = (a3 << 22) | (a2 << 12) | (a1 << 2) | aa;
609 if( of != 0 ) return -of; else return nw;
612 //_____________________________________________________________________________
613 Int_t AliTRDmcmSim::ProduceTrackletStream( UInt_t *buf, Int_t maxSize )
616 // Produce tracklet data stream from this MCM and put in buf
617 // Returns number of words filled, or negative value
618 // with -1 * number of overflowed words
622 Int_t nw = 0; // Number of written words
623 Int_t of = 0; // Number of overflowed words
625 if( !CheckInitialized() ) return 0;
627 // Produce tracklet data. A maximum of four 32 Bit words will be written per MCM
628 // fMCMT is filled continuously until no more tracklet words available
631 while ( (wd < fMaxTracklets) && (fMCMT[wd] > 0) ){
642 if( of != 0 ) return -of; else return nw;
646 //_____________________________________________________________________________
647 void AliTRDmcmSim::Filter()
650 // Apply digital filter
653 if( !CheckInitialized() ) return;
655 // Initialize filtered data array with raw data
656 for( Int_t iadc = 0 ; iadc < fNADC; iadc++ ) {
657 for( Int_t it = 0 ; it < fNTimeBin ; it++ ) {
658 fADCF[iadc][it] = fADCR[iadc][it];
662 // Then apply fileters one by one to filtered data array
663 if( fFeeParam->IsPFon() ) FilterPedestal();
664 if( fFeeParam->IsGFon() ) FilterGain();
665 if( fFeeParam->IsTFon() ) FilterTail();
668 //_____________________________________________________________________________
669 void AliTRDmcmSim::FilterPedestal()
674 // Apply pedestal filter
677 Int_t ap = fSimParam->GetADCbaseline(); // ADC instrinsic pedestal
678 Int_t ep = fFeeParam->GetPFeffectPedestal(); // effective pedestal
679 //Int_t tc = fFeeParam->GetPFtimeConstant(); // this makes no sense yet
681 for( Int_t iadc = 0 ; iadc < fNADC; iadc++ ) {
682 for( Int_t it = 0 ; it < fNTimeBin ; it++ ) {
683 fADCF[iadc][it] = fADCF[iadc][it] - ap + ep;
688 //_____________________________________________________________________________
689 void AliTRDmcmSim::FilterGain()
692 // Apply gain filter (not implemented)
693 // Later it will be implemented because gain digital filiter will
694 // increase noise level.
699 //_____________________________________________________________________________
700 void AliTRDmcmSim::FilterTail()
703 // Apply exponential tail filter (Bogdan's version)
706 Double_t *dtarg = new Double_t[fNTimeBin];
707 Int_t *itarg = new Int_t[fNTimeBin];
708 Int_t nexp = fFeeParam->GetTFnExp();
709 Int_t tftype = fFeeParam->GetTFtype();
713 case 0: // Exponential Filter Analog Bogdan
714 for (Int_t iCol = 0; iCol < fNADC; iCol++) {
715 FilterSimDeConvExpA( fADCF[iCol], dtarg, fNTimeBin, nexp);
716 for (Int_t iTime = 0; iTime < fNTimeBin; iTime++) {
717 fADCF[iCol][iTime] = (Int_t) TMath::Max(0.0,dtarg[iTime]);
722 case 1: // Exponential filter digital Bogdan
723 for (Int_t iCol = 0; iCol < fNADC; iCol++) {
724 FilterSimDeConvExpD( fADCF[iCol], itarg, fNTimeBin, nexp);
725 for (Int_t iTime = 0; iTime < fNTimeBin; iTime++) {
726 fADCF[iCol][iTime] = itarg[iTime];
731 case 2: // Exponential filter Marian special
732 for (Int_t iCol = 0; iCol < fNADC; iCol++) {
733 FilterSimDeConvExpMI( fADCF[iCol], dtarg, fNTimeBin);
734 for (Int_t iTime = 0; iTime < fNTimeBin; iTime++) {
735 fADCF[iCol][iTime] = (Int_t) TMath::Max(0.0,dtarg[iTime]);
741 case 3: // Exponential filter using AliTRDtrapAlu class
742 for (Int_t iCol = 0; iCol < fNADC; iCol++) {
743 FilterSimDeConvExpEl( fADCF[iCol], itarg, fNTimeBin, nexp);
744 for (Int_t iTime = 0; iTime < fNTimeBin; iTime++) {
745 fADCF[iCol][iTime] = itarg[iTime]>>2; // to be used for raw-data
746 fADCT[iCol][iTime] = itarg[iTime]; // 12bits; to be used for tracklet; tracklet will have own container;
753 AliError(Form("Invalid filter type %d ! \n", tftype ));
761 //_____________________________________________________________________________
762 void AliTRDmcmSim::ZSMapping()
765 // Zero Suppression Mapping implemented in TRAP chip
767 // See detail TRAP manual "Data Indication" section:
768 // http://www.kip.uni-heidelberg.de/ti/TRD/doc/trap/TRAP-UserManual.pdf
771 Int_t eBIS = fFeeParam->GetEBsglIndThr(); // TRAP default = 0x4 (Tis=4)
772 Int_t eBIT = fFeeParam->GetEBsumIndThr(); // TRAP default = 0x28 (Tit=40)
773 Int_t eBIL = fFeeParam->GetEBindLUT(); // TRAP default = 0xf0
774 // (lookup table accept (I2,I1,I0)=(111)
775 // or (110) or (101) or (100))
776 Int_t eBIN = fFeeParam->GetEBignoreNeighbour(); // TRAP default = 1 (no neighbor sensitivity)
777 Int_t ep = AliTRDfeeParam::GetPFeffectPedestal();
779 if( !CheckInitialized() ) return;
781 for( Int_t iadc = 1 ; iadc < fNADC-1; iadc++ ) {
782 for( Int_t it = 0 ; it < fNTimeBin ; it++ ) {
784 // Get ADC data currently in filter buffer
785 Int_t ap = fADCF[iadc-1][it] - ep; // previous
786 Int_t ac = fADCF[iadc ][it] - ep; // current
787 Int_t an = fADCF[iadc+1][it] - ep; // next
789 // evaluate three conditions
790 Int_t i0 = ( ac >= ap && ac >= an ) ? 0 : 1; // peak center detection
791 Int_t i1 = ( ap + ac + an > eBIT ) ? 0 : 1; // cluster
792 Int_t i2 = ( ac > eBIS ) ? 0 : 1; // absolute large peak
794 Int_t i = i2 * 4 + i1 * 2 + i0; // Bit position in lookup table
795 Int_t d = (eBIL >> i) & 1; // Looking up (here d=0 means true
796 // and d=1 means false according to TRAP manual)
799 if( eBIN == 0 ) { // turn on neighboring ADCs
800 fZSM[iadc-1][it] &= d;
801 fZSM[iadc+1][it] &= d;
807 // do 1 dim projection
808 for( Int_t iadc = 0 ; iadc < fNADC; iadc++ ) {
809 for( Int_t it = 0 ; it < fNTimeBin ; it++ ) {
810 fZSM1Dim[iadc] &= fZSM[iadc][it];
816 //_____________________________________________________________________________
817 void AliTRDmcmSim::DumpData( char *f, char *target )
820 // Dump data stored (for debugging).
821 // target should contain one or multiple of the following characters
823 // F for filtered data
824 // Z for zero suppression map
826 // other characters are simply ignored
829 UInt_t tempbuf[1024];
831 if( !CheckInitialized() ) return;
833 std::ofstream of( f, std::ios::out | std::ios::app );
834 of << Form("AliTRDmcmSim::DumpData det=%03d sm=%02d stack=%d layer=%d rob=%d mcm=%02d\n",
835 fChaId, fSector, fStack, fLayer, fRobPos, fMcmPos );
837 for( int t=0 ; target[t] != 0 ; t++ ) {
838 switch( target[t] ) {
841 of << Form("fADCR (raw ADC data)\n");
842 for( Int_t iadc = 0 ; iadc < fNADC; iadc++ ) {
843 of << Form(" ADC %02d: ", iadc);
844 for( Int_t it = 0 ; it < fNTimeBin ; it++ ) {
845 of << Form("% 4d", fADCR[iadc][it]);
852 of << Form("fADCF (filtered ADC data)\n");
853 for( Int_t iadc = 0 ; iadc < fNADC; iadc++ ) {
854 of << Form(" ADC %02d: ", iadc);
855 for( Int_t it = 0 ; it < fNTimeBin ; it++ ) {
856 of << Form("% 4d", fADCF[iadc][it]);
863 of << Form("fZSM and fZSM1Dim (Zero Suppression Map)\n");
864 for( Int_t iadc = 0 ; iadc < fNADC; iadc++ ) {
865 of << Form(" ADC %02d: ", iadc);
866 if( fZSM1Dim[iadc] == 0 ) { of << " R " ; } else { of << " . "; } // R:read .:suppressed
867 for( Int_t it = 0 ; it < fNTimeBin ; it++ ) {
868 if( fZSM[iadc][it] == 0 ) { of << " R"; } else { of << " ."; } // R:read .:suppressed
875 Int_t s = ProduceRawStream( tempbuf, 1024 );
876 of << Form("Stream for Raw Simulation size=%d rawver=%d\n", s, fFeeParam->GetRAWversion());
877 of << Form(" address data\n");
878 for( int i = 0 ; i < s ; i++ ) {
879 of << Form(" %04x %08x\n", i, tempbuf[i]);
885 //_____________________________________________________________________________
886 void AliTRDmcmSim::FilterSimDeConvExpA(Int_t *source, Double_t *target
887 , Int_t n, Int_t nexp)
890 // Exponential filter "analog"
891 // source will not be changed
896 Double_t reminder[2];
900 Double_t coefficients[2];
902 // Initialize (coefficient = alpha, rates = lambda)
903 // FilterOpt.C (aliroot@pel:/homel/aliroot/root/work/beamt/CERN02)
905 Double_t r1 = (Double_t)fFeeParam->GetTFr1();
906 Double_t r2 = (Double_t)fFeeParam->GetTFr2();
907 Double_t c1 = (Double_t)fFeeParam->GetTFc1();
908 Double_t c2 = (Double_t)fFeeParam->GetTFc2();
910 coefficients[0] = c1;
911 coefficients[1] = c2;
914 rates[0] = TMath::Exp(-dt/(r1));
915 rates[1] = TMath::Exp(-dt/(r2));
917 // Attention: computation order is important
919 for (k = 0; k < nexp; k++) {
923 for (i = 0; i < n; i++) {
925 result = ((Double_t)source[i] - correction); // no rescaling
928 for (k = 0; k < nexp; k++) {
929 reminder[k] = rates[k] * (reminder[k] + coefficients[k] * result);
933 for (k = 0; k < nexp; k++) {
934 correction += reminder[k];
939 //_____________________________________________________________________________
940 void AliTRDmcmSim::FilterSimDeConvExpD(Int_t *source, Int_t *target, Int_t n
944 // Exponential filter "digital"
945 // source will not be changed
955 // FilterOpt.C (aliroot@pel:/homel/aliroot/root/work/beamt/CERN02)
956 // initialize (coefficient = alpha, rates = lambda)
959 Double_t r1 = (Double_t)fFeeParam->GetTFr1();
960 Double_t r2 = (Double_t)fFeeParam->GetTFr2();
961 Double_t c1 = (Double_t)fFeeParam->GetTFc1();
962 Double_t c2 = (Double_t)fFeeParam->GetTFc2();
964 Int_t fLambdaL = (Int_t)((TMath::Exp(-dt/r1) - 0.75) * 2048.0);
965 Int_t fLambdaS = (Int_t)((TMath::Exp(-dt/r2) - 0.25) * 2048.0);
966 Int_t iLambdaL = fLambdaL & 0x01FF; iLambdaL |= 0x0600; // 9 bit paramter + fixed bits
967 Int_t iLambdaS = fLambdaS & 0x01FF; iLambdaS |= 0x0200; // 9 bit paramter + fixed bits
970 fAlphaL = (Int_t) (c1 * 2048.0);
971 iAlphaL = fAlphaL & 0x03FF; // 10 bit paramter
974 fAlphaL = (Int_t) (c1 * 2048.0);
975 fAlphaS = (Int_t) ((c2 - 0.5) * 2048.0);
976 iAlphaL = fAlphaL & 0x03FF; // 10 bit paramter
977 iAlphaS = fAlphaS & 0x03FF; iAlphaS |= 0x0400; // 10 bit paramter + fixed bits
980 Double_t iAl = iAlphaL / 2048.0; // alpha L: correspondence to floating point numbers
981 Double_t iAs = iAlphaS / 2048.0; // alpha S: correspondence to floating point numbers
982 Double_t iLl = iLambdaL / 2048.0; // lambda L: correspondence to floating point numbers
983 Double_t iLs = iLambdaS / 2048.0; // lambda S: correspondence to floating point numbers
991 Int_t iFactor = ((Int_t) fFeeParam->GetPFeffectPedestal() ) << 2;
993 Double_t xi = 1 - (iLl*iAs + iLs*iAl); // Calculation of equilibrium values of the
994 rem1 = (Int_t) ((iFactor/xi) * ((1-iLs)*iLl*iAl)); // Internal registers to prevent switch on effects.
995 rem2 = (Int_t) ((iFactor/xi) * ((1-iLl)*iLs*iAs));
997 // further initialization
998 if ((rem1 + rem2) > 0x0FFF) {
1002 correction = (rem1 + rem2) & 0x0FFF;
1005 fTailPed = iFactor - correction;
1007 for (i = 0; i < n; i++) {
1009 result = (source[i] - correction);
1010 if (result < 0) { // Too much undershoot
1016 h1 = (rem1 + ((iAlphaL * result) >> 11));
1024 h2 = (rem2 + ((iAlphaS * result) >> 11));
1032 rem1 = (iLambdaL * h1 ) >> 11;
1033 rem2 = (iLambdaS * h2 ) >> 11;
1035 if ((rem1 + rem2) > 0x0FFF) {
1036 correction = 0x0FFF;
1039 correction = (rem1 + rem2) & 0x0FFF;
1046 //_____________________________________________________________________________
1047 void AliTRDmcmSim::FilterSimDeConvExpMI(Int_t *source, Double_t *target
1051 // Exponential filter (M. Ivanov)
1052 // source will not be changed
1060 for (i = 0; i < n; i++) {
1061 sig1[i] = (Double_t)source[i];
1065 Float_t lambda0 = (1.0 / fFeeParam->GetTFr2()) * dt;
1066 Float_t lambda1 = (1.0 / fFeeParam->GetTFr1()) * dt;
1068 FilterSimTailMakerSpline( sig1, sig2, lambda0, n);
1069 FilterSimTailCancelationMI( sig2, sig3, 0.7, lambda1, n);
1071 for (i = 0; i < n; i++) {
1072 target[i] = sig3[i];
1077 //______________________________________________________________________________
1078 void AliTRDmcmSim::FilterSimTailMakerSpline(Double_t *ampin, Double_t *ampout
1079 , Double_t lambda, Int_t n)
1082 // Special filter (M. Ivanov)
1086 Double_t l = TMath::Exp(-lambda*0.5);
1090 // Initialize in[] and out[] goes 0 ... 2*n+19
1091 for (i = 0; i < n*2+20; i++) {
1097 in[1] = (ampin[0] + ampin[1]) * 0.5;
1099 // Add charge to the end
1100 for (i = 0; i < 22; i++) {
1101 in[2*(n-1)+i] = ampin[n-1]; // in[] goes 2*n-2, 2*n-1, ... , 2*n+19
1104 // Use arithmetic mean
1105 for (i = 1; i < n-1; i++) {
1106 in[2*i] = ampin[i]; // in[] goes 2, 3, ... , 2*n-4, 2*n-3
1107 in[2*i+1] = ((ampin[i]+ampin[i+1]))/2.;
1113 for (i = 2*n; i >= 0; i--) {
1114 out[i] = in[i] + temp;
1115 temp = l*(temp+in[i]);
1118 for (i = 0; i < n; i++){
1119 //ampout[i] = out[2*i+1]; // org
1120 ampout[i] = out[2*i];
1125 //______________________________________________________________________________
1126 void AliTRDmcmSim::FilterSimTailCancelationMI(Double_t *ampin, Double_t *ampout
1127 , Double_t norm, Double_t lambda
1131 // Special filter (M. Ivanov)
1136 Double_t l = TMath::Exp(-lambda*0.5);
1137 Double_t k = l*(1.0 - norm*lambda*0.5);
1141 // Initialize in[] and out[] goes 0 ... 2*n+19
1142 for (i = 0; i < n*2+20; i++) {
1148 in[1] = (ampin[0]+ampin[1])*0.5;
1150 // Add charge to the end
1151 for (i =-2; i < 22; i++) {
1152 // in[] goes 2*n-4, 2*n-3, ... , 2*n+19
1153 in[2*(n-1)+i] = ampin[n-1];
1156 for (i = 1; i < n-2; i++) {
1157 // in[] goes 2, 3, ... , 2*n-6, 2*n-5
1159 in[2*i+1] = (9.0 * (ampin[i]+ampin[i+1]) - (ampin[i-1]+ampin[i+2])) / 16.0;
1160 //in[2*i+1] = ((ampin[i]+ampin[i+1]))/2.0;
1166 for (i = 1; i <= 2*n; i++) {
1167 out[i] = in[i] + (k-l)*temp;
1168 temp = in[i] + k *temp;
1171 for (i = 0; i < n; i++) {
1172 //ampout[i] = out[2*i+1]; // org
1173 //ampout[i] = TMath::Max(out[2*i+1],0.0); // org
1174 ampout[i] = TMath::Max(out[2*i],0.0);
1179 //_____________________________________________________________________________________
1180 //the following filter uses AliTRDtrapAlu-class
1182 void AliTRDmcmSim::FilterSimDeConvExpEl(Int_t *source, Int_t *target, Int_t n, Int_t nexp) {
1183 //static Int_t count = 0;
1186 Double_t r1 = (Double_t)fFeeParam->GetTFr1();
1187 Double_t r2 = (Double_t)fFeeParam->GetTFr2();
1188 Double_t c1 = (Double_t)fFeeParam->GetTFc1();
1189 Double_t c2 = (Double_t)fFeeParam->GetTFc2();
1193 //it is assumed that r1,r2,c1,c2 are given such, that the configuration values are in the ranges according to TRAP-manual
1194 //parameters need to be adjusted
1195 AliTRDtrapAlu lambdaL;
1196 AliTRDtrapAlu lambdaS;
1197 AliTRDtrapAlu alphaL;
1198 AliTRDtrapAlu alphaS;
1200 AliTRDtrapAlu correction;
1201 AliTRDtrapAlu result;
1205 AliTRDtrapAlu bSource;
1214 lambdaL.AssignDouble(TMath::Exp(-dt/r1));
1215 lambdaS.AssignDouble(TMath::Exp(-dt/r2));
1216 alphaL.AssignDouble(c1); // in AliTRDfeeParam the number of exponentials is set and also the according time constants
1217 alphaS.AssignDouble(c2); // later it should be: alphaS=1-alphaL
1219 //data is enlarged to 12 bits, including 2 bits after the comma; class AliTRDtrapAlu is used to handle arithmetics correctly
1220 correction.Init(10,2);
1226 for(Int_t i = 0; i < n; i++) {
1227 bSource.AssignInt(source[i]);
1228 result = bSource - correction; // subtraction can produce an underflow
1229 if(result.GetSign() == kTRUE) {
1230 result.AssignInt(0);
1233 //target[i] = result.GetValuePre(); // later, target and source should become AliTRDtrapAlu,too in order to simulate the 10+2Bits through the filter properly
1235 target[i] = result.GetValue(); // 12 bit-value; to get the corresponding integer value, target must be shifted: target>>2
1237 //printf("target-Wert zur Zeit %d : %d",i,target[i]);
1240 bufL = bufL + (result * alphaL);
1241 bufL = bufL * lambdaL;
1243 bufS = bufS + (result * alphaS);
1244 bufS = bufS * lambdaS; // eventually this should look like:
1245 // bufS = (bufS + (result - result * alphaL)) * lambdaS // alphaS=1-alphaL; then alphaS-variable is not needed any more
1247 correction = bufL + bufS; //check for overflow intrinsic; if overflowed, correction is set to 0x03FF
1259 //__________________________________________________________________________________
1262 // in order to use the Tracklets, please first
1263 // -- set AliTRDfeeParam::fgkTracklet to kTRUE, in order to switch on Tracklet-calculation
1264 // -- set AliTRDfeeParam::fgkTFtype to 3, in order to use the new tail cancellation filter
1265 // currently tracklets from filtered digits are only given when setting fgkTFtype (AliTRDfeeParam) to 3
1266 // -- set AliTRDfeeParam::fgkMCTrackletOutput to kTRUE, if you want to use the Tracklet output container with information about the Tracklet position (MCM, channel number)
1268 // The code is designed such that the less possible calculations with AliTRDtrapAlu class-objects are performed; whenever possible calculations are done with doubles or integers and the results are transformed into the right format
1270 void AliTRDmcmSim::Tracklet(){
1271 // tracklet calculation
1272 // if you use this code after a simulation, please make sure the same filter-settings as in the simulation are set in AliTRDfeeParam
1274 if(!CheckInitialized()){ return; }
1276 Bool_t filtered = kTRUE;
1282 if(fADCT[0][0]==-1){ // check if filter was applied
1284 for( Int_t iadc = 0 ; iadc < fNADC; iadc++ ) {
1285 for( Int_t iT = 0 ; iT < fNTimeBin ; iT++ ) {
1286 data.AssignInt(fADCR[iadc][iT]);
1287 fADCT[iadc][iT] = data.GetValue(); // all incoming values are positive 10+2 bit values; if el.filter was called, this is done correctly
1293 // the online ordering of mcm's is reverse to the TRAP-manual-ordering! reverse fADCT (to be consistent to TRAP), then do all calculations
1295 Int_t** rev0 = new Int_t *[fNADC];
1296 Int_t** rev1 = new Int_t *[fNADC];
1298 for( Int_t iadc = 0 ; iadc < fNADC; iadc++ ) {
1299 rev0[iadc] = new Int_t[fNTimeBin];
1300 rev1[iadc] = new Int_t[fNTimeBin];
1301 for( Int_t iT = 0; iT < fNTimeBin; iT++) {
1302 if( iadc <= fNADC-iadc-1 ) {
1303 rev0[iadc][iT] = fADCT[fNADC-iadc-1][iT];
1304 rev1[iadc][iT] = fADCT[iadc][iT];
1305 fADCT[iadc][iT] = rev0[iadc][iT];
1308 rev0[iadc][iT] = rev1[fNADC-iadc-1][iT];
1309 fADCT[iadc][iT] = rev0[iadc][iT];
1313 for( Int_t iadc = 0 ; iadc < fNADC; iadc++ ) {
1314 delete[] rev0[iadc];
1315 delete[] rev1[iadc];
1324 // get the filtered pedestal; supports only electronic tail-cancellation filter
1325 AliTRDtrapAlu filPed;
1327 Int_t *ieffped = new Int_t[fNTimeBin];
1328 for(Int_t iT = 0; iT < fNTimeBin; iT++){
1332 if( filtered == kTRUE ) {
1333 if( fFeeParam->IsPFon() ){
1334 ep = fFeeParam->GetPFeffectPedestal();
1336 Int_t nexp = fFeeParam->GetTFnExp();
1337 Int_t *isource = new Int_t[fNTimeBin];
1339 filPed.AssignInt(ep);
1340 Int_t epf = filPed.GetValue();
1341 for(Int_t iT = 0; iT < fNTimeBin; iT++){
1346 if( fFeeParam->IsTFon() ) {
1347 FilterSimDeConvExpEl( isource, ieffped, fNTimeBin, nexp);
1353 //the following values should go to AliTRDfeeParam once they are defined; then they have to be read in properly
1354 //naming follows conventions in TRAP-manual
1357 Bool_t bVBY = kTRUE; // cluster-verification bypass
1359 Double_t cQTParam = 0; // cluster quality threshold; granularity 2^-10; range: 0<=cQT/2^-10<=2^-4 - 2^-10
1360 AliTRDtrapAlu cQTAlu;
1361 cQTAlu.Init(1,10,0,63);
1362 cQTAlu.AssignDouble(cQTParam);
1363 Int_t cQT = cQTAlu.GetValue();
1366 Int_t tFS = fFeeParam->GetLinearFitStart(); // linear fit start
1367 Int_t tFE = fFeeParam->GetLinearFitEnd(); // linear fit stop
1369 // charge accumulators
1370 Int_t tQS0 = fFeeParam->GetQacc0Start(); // start-time for charge-accumulator 0
1371 Int_t tQE0 = fFeeParam->GetQacc0End(); // stop-time for charge-accumulator 0
1372 Int_t tQS1 = fFeeParam->GetQacc1Start(); // start-time for charge-accumulator 1
1373 Int_t tQE1 = fFeeParam->GetQacc1End(); // stop-time for charge-accumulator 1
1374 // values set such that tQS0=tFS; tQE0=tQS1-1; tFE=tQE1; want to do (QS0+QS1)/N
1376 Double_t cTHParam = (Double_t)fFeeParam->GetMinClusterCharge(); // cluster charge threshold
1377 AliTRDtrapAlu cTHAlu;
1379 cTHAlu.AssignDouble(cTHParam);
1380 Int_t cTH = cTHAlu.GetValue(); // cTH used for comparison
1388 List_t selection[7]; // list with 7 elements
1389 List_t *list = NULL;
1390 List_t *listLeft = NULL;
1392 Int_t* qsum = new Int_t[fNADC];
1395 AliTRDtrapAlu qsumAlu;
1396 qsumAlu.Init(12,2); // charge sum will be 12+2 bits
1397 AliTRDtrapAlu dCOGAlu;
1398 dCOGAlu.Init(1,7,0,127); // COG will be 1+7 Bits; maximum 1 - 2^-7 for LUT
1399 AliTRDtrapAlu yrawAlu;
1400 yrawAlu.Init(1,8,-1,255);
1402 yAlu.Init(1,16,-1,0xFF00); // only first 8 past-comma bits filled;additional 8 bits for accuracy;maximum 1 - 2^-8; sign is given by + or -
1404 xAlu.Init(5,8); // 8 past-comma bits because value will be added/multiplied to another value with this accuracy
1405 AliTRDtrapAlu xxAlu;
1407 AliTRDtrapAlu yyAlu;
1408 yyAlu.Init(1,16,0,0xFFFF); // maximum is 2^16-1; 16Bit for past-commas
1409 AliTRDtrapAlu xyAlu;
1413 AliTRDtrapAlu XXAlu;
1416 YAlu.Init(5,8); // 14 bit, 1 is sign-bit; therefore only 13 bit
1417 AliTRDtrapAlu YYAlu;
1419 AliTRDtrapAlu XYAlu;
1420 XYAlu.Init(8,8); // 17 bit, 1 is sign-bit; therefore only 16 bit
1421 AliTRDtrapAlu qtruncAlu;
1422 qtruncAlu.Init(12,0);
1423 AliTRDtrapAlu QT0Alu;
1425 AliTRDtrapAlu QT1Alu;
1428 AliTRDtrapAlu oneAlu;
1432 AliTRDtrapAlu inverseNAlu;
1433 inverseNAlu.Init(1,8); // simulates the LUT for 1/N
1434 AliTRDtrapAlu MeanChargeAlu; // mean charge in ADC counts
1435 MeanChargeAlu.Init(8,0);
1436 AliTRDtrapAlu TotalChargeAlu;
1437 TotalChargeAlu.Init(17,8);
1438 //nr of post comma bits should be the same for inverseN and TotalCharge
1441 SetPosLUT(); // initialize the position correction LUT for this MCM;
1444 // fit-sums; remapping!; 0,1,2->0; 1,2,3->1; ... 18,19,20->18
1445 Int_t *X = new Int_t[fNADC-2];
1446 Int_t *XX = new Int_t[fNADC-2];
1447 Int_t *Y = new Int_t[fNADC-2];
1448 Int_t *YY = new Int_t[fNADC-2];
1449 Int_t *XY = new Int_t[fNADC-2];
1450 Int_t *N = new Int_t[fNADC-2];
1451 Int_t *QT0 = new Int_t[fNADC-2]; // accumulated charge
1452 Int_t *QT1 = new Int_t[fNADC-2]; // accumulated charge
1454 for (Int_t iCol = 0; iCol < fNADC-2; iCol++) {
1456 // initialize fit-sums
1468 filPed.Init(7,2); // convert filtered pedestal into 7+2Bits
1470 for(Int_t iT = 0; iT < fNTimeBin; iT++){
1472 if(iT<tFS || iT>=tFE) continue; // linear fit yes/no?
1475 Int_t portChannel[4] = {-1,-1,-1,-1};
1476 Int_t clusterCharge[4] = {0,0,0,0};
1477 Int_t leftCharge[4] = {0,0,0,0};
1478 Int_t centerCharge[4] = {0,0,0,0};
1479 Int_t rightCharge[4] = {0,0,0,0};
1483 filPed.AssignFormatted(ieffped[iT]); // no size-checking when using AssignFormatted; ieffped>=0
1484 filPed = filPed; // this checks the size
1486 ieffped[iT] = filPed.GetValue();
1488 for(Int_t i = 0; i<7; i++){
1489 selection[i].next = NULL;
1490 selection[i].iadc = -1; // value of -1: invalid adc
1491 selection[i].value = 0;
1494 // selection[0] is starting list-element; just for pointing
1496 // loop over inner adc's
1497 for (Int_t iCol = 1; iCol < fNADC-1; iCol++) {
1499 Int_t left = fADCT[iCol-1][iT];
1500 Int_t center = fADCT[iCol][iT];
1501 Int_t right = fADCT[iCol+1][iT];
1503 Int_t sum = left + center + right; // cluster charge sum
1504 qsumAlu.AssignFormatted(sum);
1505 qsumAlu = qsumAlu; // size-checking; redundant
1507 qsum[iCol] = qsumAlu.GetValue();
1509 //hit detection and masking
1512 if(qsum[iCol]>=(cTH + 3*ieffped[iT])){ // effective pedestal of all three channels must be added to cTH(+20); this is not parallel to TRAP manual; maybe cTH has to be adjusted in fFeeParam; therefore channels are not yet reduced by their pedestal
1513 mark |= 1; // marker
1522 // get selection of 6 adc's and sort,starting with greatest values
1524 //read three from right side and sort (primitive sorting algorithm)
1525 Int_t i = 0; // adc number
1526 Int_t j = 1; // selection number
1527 while(i<fNADC-2 && j<=3){
1529 if( ((mark>>(i-1)) & 1) == 1) {
1530 selection[j].iadc = fNADC-1-i;
1531 selection[j].value = qsum[fNADC-1-i]>>6; // for hit-selection only the first 8 out of the 14 Bits are used for comparison
1533 // insert into sorted list
1534 listLeft = &selection[0];
1535 list = listLeft->next;
1538 while((list->next != NULL) && (selection[j].value <= list->value)){
1543 if(selection[j].value<=list->value){
1544 selection[j].next = list->next;
1545 list->next = &selection[j];
1548 listLeft->next = &selection[j];
1549 selection[j].next = list;
1553 listLeft->next = &selection[j];
1554 selection[j].next = list;
1562 // read three from left side
1564 while(k>i && j<=6) {
1565 if( ((mark>>(k-1)) & 1) == 1) {
1566 selection[j].iadc = fNADC-1-k;
1567 selection[j].value = qsum[fNADC-1-k]>>6;
1569 listLeft = &selection[0];
1570 list = listLeft->next;
1573 while((list->next != NULL) && (selection[j].value <= list->value)){
1578 if(selection[j].value<=list->value){
1579 selection[j].next = list->next;
1580 list->next = &selection[j];
1583 listLeft->next = &selection[j];
1584 selection[j].next = list;
1588 listLeft->next = &selection[j];
1589 selection[j].next = list;
1597 // get the four with greatest charge-sum
1598 list = &selection[0];
1599 for(i = 0; i<4; i++){
1600 if(list->next == NULL) continue;
1602 if(list->iadc == -1) continue;
1603 Int_t adc = list->iadc; // channel number with selected hit
1605 // the following arrays contain the four chosen channels in 1 time-bin
1606 portChannel[i] = adc;
1607 clusterCharge[i] = qsum[adc];
1608 leftCharge[i] = fADCT[adc-1][iT] - ieffped[iT]; // reduce by filtered pedestal (pedestal is part of the signal)
1609 centerCharge[i] = fADCT[adc][iT] - ieffped[iT];
1610 rightCharge[i] = fADCT[adc+1][iT] - ieffped[iT];
1615 // cluster verification
1617 for(i = 0; i<4; i++){
1618 Int_t lr = leftCharge[i]*rightCharge[i]*1024;
1619 Int_t cc = centerCharge[i]*centerCharge[i]*cQT;
1621 portChannel[i] = -1; // set to invalid address
1622 clusterCharge[i] = 0;
1627 // fit-sums of valid channels
1628 // local hit position
1629 for(i = 0; i<4; i++){
1630 if (centerCharge[i] == 0) {
1631 portChannel[i] = -1;
1632 }// prevent division by 0
1634 if (portChannel[i] == -1) continue;
1636 Double_t dCOG = (Double_t)(rightCharge[i]-leftCharge[i])/centerCharge[i];
1638 Bool_t sign = (dCOG>=0.0) ? kFALSE : kTRUE;
1639 dCOG = (sign == kFALSE) ? dCOG : -dCOG; // AssignDouble doesn't allow for signed doubles
1640 dCOGAlu.AssignDouble(dCOG);
1641 Int_t iLUTpos = dCOGAlu.GetValue(); // steers position in LUT
1644 yrawAlu.AssignDouble(dCOG);
1645 Int_t iCOG = yrawAlu.GetValue();
1646 Int_t y = iCOG + fPosLUT[iLUTpos % 128]; // local position in pad-units
1647 yrawAlu.AssignFormatted(y); // 0<y<1
1648 yAlu = yrawAlu; // convert to 16 past-comma bits
1650 if(sign == kTRUE) yAlu.SetSign(-1); // buffer width of 9 bits; sign on real (not estimated) position
1651 xAlu.AssignInt(iT); // buffer width of 5 bits
1654 xxAlu = xAlu * xAlu; // buffer width of 10 bits -> fulfilled by x*x
1656 yyAlu = yAlu * yAlu; // buffer width of 16 bits
1658 xyAlu = xAlu * yAlu; // buffer width of 14 bits
1660 Int_t adc = portChannel[i]-1; // remapping! port-channel contains channel-nr. of inner adc's (1..19; mapped to 0..18)
1662 // calculate fit-sums recursively
1663 // interpretation of their bit-length is given as comment
1665 // be aware that the accuracy of the result of a calculation is always determined by the accuracy of the less accurate value
1667 XAlu.AssignFormatted(X[adc]);
1668 XAlu = XAlu + xAlu; // buffer width of 9 bits
1669 X[adc] = XAlu.GetValue();
1671 XXAlu.AssignFormatted(XX[adc]);
1672 XXAlu = XXAlu + xxAlu; // buffer width of 14 bits
1673 XX[adc] = XXAlu.GetValue();
1676 YAlu.AssignFormatted(-Y[adc]); // make sure that only positive values are assigned; sign-setting must be done by hand
1680 YAlu.AssignFormatted(Y[adc]);
1684 YAlu = YAlu + yAlu; // buffer width of 14 bits (8 past-comma);
1685 Y[adc] = YAlu.GetSignedValue();
1687 YYAlu.AssignFormatted(YY[adc]);
1688 YYAlu = YYAlu + yyAlu; // buffer width of 21 bits (16 past-comma)
1689 YY[adc] = YYAlu.GetValue();
1692 XYAlu.AssignFormatted(-XY[adc]);
1696 XYAlu.AssignFormatted(XY[adc]);
1700 XYAlu = XYAlu + xyAlu; // buffer allows 17 bits (8 past-comma)
1701 XY[adc] = XYAlu.GetSignedValue();
1703 N[adc] = N[adc] + 1;
1706 // accumulated charge
1707 qsumAlu.AssignFormatted(qsum[adc+1]); // qsum was not remapped!
1708 qtruncAlu = qsumAlu;
1710 if(iT>=tQS0 && iT<=tQE0){
1711 QT0Alu.AssignFormatted(QT0[adc]);
1712 QT0Alu = QT0Alu + qtruncAlu;
1713 QT0[adc] = QT0Alu.GetValue();
1714 //interpretation of QT0 as 12bit-value (all pre-comma); is this as it should be done?; buffer allows 15 Bit
1717 if(iT>=tQS1 && iT<=tQE1){
1718 QT1Alu.AssignFormatted(QT1[adc]);
1719 QT1Alu = QT1Alu + qtruncAlu;
1720 QT1[adc] = QT1Alu.GetValue();
1721 //interpretation of QT1 as 12bit-value; buffer allows 16 Bit
1725 // remapping is done!!
1731 // tracklet-assembly
1733 // put into AliTRDfeeParam and take care that values are in proper range
1734 const Int_t cTCL = 1; // left adc: number of hits; 8<=TCL<=31 (?? 1<=cTCL<+8 ??)
1735 const Int_t cTCT = 8; // joint number of hits; 8<=TCT<=31; note that according to TRAP manual this number cannot be lower than 8; however it should be adjustable to the number of hits in the fit time range (40%)
1737 Int_t mPair = 0; // marker for possible tracklet pairs
1738 Int_t* hitSum = new Int_t[fNADC-3];
1739 // hitSum[0] means: hit sum of remapped channels 0 and 1; hitSum[17]: 17 and 18;
1741 // check for all possible tracklet-pairs of adjacent channels (two are merged); mark the left channel of the chosen pairs
1742 for (Int_t iCol = 0; iCol < fNADC-3; iCol++) {
1743 hitSum[iCol] = N[iCol] + N[iCol+1];
1744 if ((N[iCol]>=cTCL) && (hitSum[iCol]>=cTCT)) {
1745 mPair |= 1; // mark as possible channel-pair
1752 List_t* selectPair = new List_t[fNADC-2]; // list with 18 elements (0..18) containing the left channel-nr and hit sums
1753 // selectPair[18] is starting list-element just for pointing
1754 for(Int_t k = 0; k<fNADC-2; k++){
1755 selectPair[k].next = NULL;
1756 selectPair[k].iadc = -1; // invalid adc
1757 selectPair[k].value = 0;
1764 // read marker and sort according to hit-sum
1766 Int_t adcL = 0; // left adc-channel-number (remapped)
1767 Int_t selNr = 0; // current number in list
1769 // insert marked channels into list and sort according to hit-sum
1770 while(adcL < fNADC-3 && selNr < fNADC-3){
1772 if( ((mPair>>((fNADC-4)-(adcL))) & 1) == 1) {
1773 selectPair[selNr].iadc = adcL;
1774 selectPair[selNr].value = hitSum[adcL];
1776 listLeft = &selectPair[fNADC-3];
1777 list = listLeft->next;
1780 while((list->next != NULL) && (selectPair[selNr].value <= list->value)){
1785 if(selectPair[selNr].value <= list->value){
1786 selectPair[selNr].next = list->next;
1787 list->next = &selectPair[selNr];
1790 listLeft->next = &selectPair[selNr];
1791 selectPair[selNr].next = list;
1796 listLeft->next = &selectPair[selNr];
1797 selectPair[selNr].next = list;
1805 //select up to 4 channels with maximum number of hits
1806 Int_t lpairChannel[4] = {-1,-1,-1,-1}; // save the left channel-numbers of pairs with most hit-sum
1807 Int_t rpairChannel[4] = {-1,-1,-1,-1}; // save the right channel, too; needed for detecting double tracklets
1808 list = &selectPair[fNADC-3];
1810 for (Int_t i = 0; i<4; i++) {
1811 if(list->next == NULL) continue;
1813 if(list->iadc == -1) continue;
1814 lpairChannel[i] = list->iadc; // channel number with selected hit
1815 rpairChannel[i] = lpairChannel[i]+1;
1818 // avoid submission of double tracklets
1819 for (Int_t i = 3; i>0; i--) {
1820 for (Int_t j = i-1; j>-1; j--) {
1821 if(lpairChannel[i] == rpairChannel[j]) {
1822 lpairChannel[i] = -1;
1823 rpairChannel[i] = -1;
1826 /* if(rpairChannel[i] == lpairChannel[j]) {
1827 lpairChannel[i] = -1;
1828 rpairChannel[i] = -1;
1834 // merging of the fit-sums of the remainig channels
1835 // assume same data-word-width as for fit-sums for 1 channel
1848 Int_t mMeanCharge[4];
1853 for (Int_t i = 0; i<4; i++){
1854 mADC[i] = -1; // set to invalid number
1868 oneAlu.AssignInt(1);
1869 one = oneAlu.GetValue(); // one with 8 past comma bits
1871 for (Int_t i = 0; i<4; i++){
1874 mADC[i] = lpairChannel[i]; // mapping of merged sums to left channel nr. (0,1->0; 1,2->1; ... 17,18->17)
1875 // the adc and pad-mapping should now be one to one: adc i is linked to pad i; TRAP-numbering
1876 Int_t madc = mADC[i];
1877 if (madc == -1) continue;
1879 YAlu.AssignInt(N[rpairChannel[i]]);
1880 Int_t wpad = YAlu.GetValue(); // enlarge hit counter of right channel by 8 past-comma bits; YAlu can have 5 pre-comma bits (values up to 63); hit counter<=nr of time bins (24)
1882 mN[i] = hitSum[madc];
1884 // don't merge fit sums in case of a stand-alone tracklet (consisting of only 1 channel); in that case only left channel makes up the fit sums
1885 if (N[madc+1] == 0) {
1886 mQT0[i] = QT0[madc];
1887 mQT1[i] = QT1[madc];
1892 // is it ok to do the size-checking for the merged fit-sums with the same format as for single-channel fit-sums?
1894 mQT0[i] = QT0[madc] + QT0[madc+1];
1895 QT0Alu.AssignFormatted(mQT0[i]);
1896 QT0Alu = QT0Alu; // size-check
1897 mQT0[i] = QT0Alu.GetValue(); // write back
1899 mQT1[i] = QT1[madc] + QT1[madc+1];
1900 QT1Alu.AssignFormatted(mQT1[i]);
1902 mQT1[i] = QT1Alu.GetValue();
1905 // calculate the mean charge in adc values; later to be replaced by electron likelihood
1906 mMeanCharge[i] = mQT0[i] + mQT1[i]; // total charge
1907 mMeanCharge[i] = mMeanCharge[i]>>2; // losing of accuracy; accounts for high mean charge
1908 // simulate LUT for 1/N; LUT is fed with the double-accurate pre-calculated value of 1/N; accuracy of entries has to be adjusted to real TRAP
1910 inverseNAlu.AssignDouble(invN);
1911 inverseN = inverseNAlu.GetValue();
1912 mMeanCharge[i] = mMeanCharge[i] * inverseN; // now to be interpreted with 8 past-comma bits
1913 TotalChargeAlu.AssignFormatted(mMeanCharge[i]);
1914 TotalChargeAlu = TotalChargeAlu;
1915 MeanChargeAlu = TotalChargeAlu;
1916 mMeanCharge[i] = MeanChargeAlu.GetValue();
1918 // this check is not necessary; it is just for efficiency reasons
1919 if (N[madc+1] == 0) {
1928 mX[i] = X[madc] + X[madc+1];
1929 XAlu.AssignFormatted(mX[i]);
1931 mX[i] = XAlu.GetValue();
1933 mXX[i] = XX[madc] + XX[madc+1];
1934 XXAlu.AssignFormatted(mXX[i]);
1936 mXX[i] = XXAlu.GetValue();
1939 mY[i] = Y[madc] + Y[madc+1] + wpad;
1941 YAlu.AssignFormatted(-mY[i]);
1945 YAlu.AssignFormatted(mY[i]);
1949 mY[i] = YAlu.GetSignedValue();
1951 mXY[i] = XY[madc] + XY[madc+1] + X[madc+1]*one; // multiplication by one to maintain the data format
1954 XYAlu.AssignFormatted(-mXY[i]);
1958 XYAlu.AssignFormatted(mXY[i]);
1962 mXY[i] = XYAlu.GetSignedValue();
1964 mYY[i] = YY[madc] + YY[madc+1] + 2*Y[madc+1]*one+ wpad*one;
1966 YYAlu.AssignFormatted(-mYY[i]);
1970 YYAlu.AssignFormatted(mYY[i]);
1975 mYY[i] = YYAlu.GetSignedValue();
1980 // calculation of offset and slope from the merged fit-sums;
1981 // YY is needed for some error measure only; still to be done
1982 // be aware that all values are relative values (scale: timebin-width; pad-width) and are integer values on special scale
1984 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1985 // !!important note: the offset is calculated from hits in the time bin range between tFS and tFE; it corresponds to the value at the height of the time bin tFS which does NOT need to correspond to the upper side of the drift !!
1986 // !!volume (cathode wire plane). The offset cannot be rescaled as long as it is unknown which is the first time bin that contains hits from the drift region and thus to which distance from the cathode plane tFS corresponds. !!
1987 // !!This has to be taken into account by the GTU. Furthermore a Lorentz correction might have to be applied to the offset (see below). !!
1988 // !!In this implementation it is assumed that no miscalibration containing changing drift velocities in the amplification region is used. !!
1989 // !!The corrections to the offset (e.g. no ExB correction applied as offset is supposed to be on top of drift region; however not at anode wire, so some inclination of drifting clusters due to Lorentz angle exists) are only !!
1990 // !!valid (in approximation) if tFS is close to the beginning of the drift region. !!
1991 // !!The slope however can be converted to a deflection length between electrode and cathode wire plane as it is clear that the drift region is sampled 20 times !!
1992 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1994 // which formats should be chosen?
1995 AliTRDtrapAlu denomAlu;
1996 denomAlu.Init(20,8);
1997 AliTRDtrapAlu numAlu;
1999 // is this enough pre-comma place? covers the range of the 13 bit-word of the transmitted offset
2000 // offset measured in coord. of left channel must be between -0.5 and 1.5; 14 pre-comma bits because numerator can be big
2002 for (Int_t i = 0; i<4; i++) {
2003 if (mADC[i] == -1) continue;
2005 Int_t num0 = (mN[i]*mXX[i]-mX[i]*mX[i]);
2007 denomAlu.AssignInt(-num0); // num0 does not have to be interpreted as having past-comma bits -> AssignInt
2008 denomAlu.SetSign(-1);
2011 denomAlu.AssignInt(num0);
2012 denomAlu.SetSign(1);
2015 Int_t num1 = mN[i]*mXY[i] - mX[i]*mY[i];
2017 numAlu.AssignFormatted(-num1); // value of num1 is already formatted to have 8 past-comma bits
2021 numAlu.AssignFormatted(num1);
2024 numAlu = numAlu/denomAlu;
2025 mSlope[i] = numAlu.GetSignedValue();
2027 Int_t num2 = mXX[i]*mY[i] - mX[i]*mXY[i];
2030 numAlu.AssignFormatted(-num2);
2034 numAlu.AssignFormatted(num2);
2038 numAlu = numAlu/denomAlu;
2041 mOffset[i] = numAlu.GetSignedValue();
2043 denomAlu.SetSign(1);
2046 //numAlu.AssignInt(mADC[i]+1); // according to TRAP-manual but trafo not to middle of chamber (0.5 channels away)
2047 numAlu.AssignDouble((Double_t)mADC[i] + 1.5); // numAlu has enough pre-comma place for that; correct trafo, best values
2048 mOffset[i] = mOffset[i] + numAlu.GetValue(); // transform offset to a coord.system relative to chip; +1 to avoid neg. values
2050 // up to here: adc-mapping according to TRAP manual and in line with pad-col mapping
2051 // reverse adc-counting to be again in line with the online mapping
2052 mADC[i] = fNADC - 4 - mADC[i]; // fNADC-4-mADC[i]: 0..17; remapping necessary;
2053 mADC[i] = mADC[i] + 2;
2054 // +2: mapping onto original ADC-online-counting: inner adc's corresponding to a chip's pasa: number 2..19
2057 // adc-counting is corresponding to online mapping; use AliTRDfeeParam::GetPadColFromADC to get the pad to which adc is connected;
2058 // pad-column mapping is reverse to adc-online mapping; TRAP adc-mapping is in line with pad-mapping (increase in same direction);
2060 // transform parameters to the local coordinate-system of a stack (used by GTU)
2061 AliTRDpadPlane* padPlane = fGeo->CreatePadPlane(fLayer,fStack);
2063 Double_t padWidthI = padPlane->GetWidthIPad()*10.0; // get values in cm; want them in mm
2064 //Double_t padWidthO = padPlane->GetWidthOPad()*10; // difference between outer pad-widths not included; in real TRAP??
2066 // difference between width of inner and outer pads of a row is not accounted for;
2068 Double_t magField = 0.4; // z-component of magnetic field in Tesla; adjust to current simulation!!; magnetic field can hardly be evaluated for the position of each mcm
2069 Double_t eCharge = 0.3; // unit charge in (GeV/c)/m*T
2070 Double_t ptMin = 2.3; // minimum transverse momentum (GeV/c); to be adjusted(?)
2072 Double_t granularityOffset = 0.160; // granularity for offset in mm
2073 Double_t granularitySlope = 0.140; // granularity for slope in mm
2075 // get the coordinates in SM-system; parameters:
2077 Double_t zPos = (padPlane->GetRowPos(fRow))*10.0; // z-position of the MCM; fRow is counted on a chamber; SM consists of 5
2078 // zPos is position of pad-borders;
2079 Double_t zOffset = 0.0;
2080 if ( fRow == 0 || fRow == 15 ) {
2081 zOffset = padPlane->GetLengthOPad();
2084 zOffset = padPlane->GetLengthIPad();
2086 zOffset = (-1.0) * zOffset/2.0;
2087 // turn zPos to be z-coordinate at middle of pad-row
2088 zPos = zPos + zOffset;
2091 Double_t xPos = 0.0; // x-position of the upper border of the drift-chamber of actual layer
2092 Int_t icol = 0; // column-number of adc-channel
2093 Double_t yPos[4]; // y-position of the pad to which ADC is connected
2094 Double_t dx = 30.0; // height of drift-chamber in mm; maybe retrieve from AliTRDGeometry
2095 Double_t freqSample = fFeeParam->GetSamplingFrequency(); // retrieve the sampling frequency (10.019750 MHz)
2096 Double_t vdrift = fCal->GetVdriftAverage(fChaId); // averaged drift velocity for this detector (1.500000 cm/us)
2097 Int_t nrOfDriftTimeBins = Int_t(dx/10.0*freqSample/vdrift); // the number of time bins in the drift region (20)
2098 Int_t nrOfAmplTimeBins = 2; // the number of time bins between anode wire and cathode wires in ampl.region (3.5mm)(guess)(suppose v_drift+3.5cm/us there=>all clusters arrive at anode wire within one time bin (100ns))
2099 Int_t nrOfOffsetCorrTimeBins = tFS - nrOfAmplTimeBins - 1; // -1 is to be conservative; offset correction will not remove the shift but is supposed to improve it; if tFS = 5, 2 drift time bins before tFS are assumed
2100 if(nrOfOffsetCorrTimeBins < 0) nrOfOffsetCorrTimeBins = 0;// don't apply offset correction if no drift time bins before tFS can be assumed
2101 Double_t lorTan = fCal->GetOmegaTau(vdrift,magField); // tan of the Lorentz-angle for this detector; could be evaluated and set as a parameter for each mcm
2102 //Double_t lorAngle = 7.0; // Lorentz-angle in degrees
2103 Double_t tiltAngle = padPlane->GetTiltingAngle(); // sign-respecting tilting angle of pads in actual layer
2104 Double_t tiltTan = TMath::Tan(TMath::Pi()/180.0 * tiltAngle);
2105 //Double_t lorTan = TMath::Tan(TMath::Pi()/180.0 * lorAngle);
2107 Double_t alphaMax[4]; // maximum deflection from the direction to the primary vertex; granularity of hit pads
2108 Double_t slopeMin[4]; // local limits for the deflection
2109 Double_t slopeMax[4];
2110 Int_t mslopeMin[4]; // in granularity units; to be compared to mSlope[i]
2114 // x coord. of upper side of drift chambers in local SM-system (in mm)
2115 // obtained by evaluating the x-range of the hits; should be crosschecked; only drift, not amplification region taken into account (30mm);
2116 // the y-deflection is given as difference of y between lower and upper side of drift-chamber, not pad-plane;
2139 // calculation of offset-correction n:
2141 Int_t nCorrectOffset = (fRobPos % 2 == 0) ? ((fMcmPos % 4)) : ( 4 + (fMcmPos % 4));
2143 nCorrectOffset = (nCorrectOffset - 4)*18 - 1;
2144 if (nCorrectOffset < 0) {
2145 numAlu.AssignInt(-nCorrectOffset);
2149 numAlu.AssignInt(nCorrectOffset);
2152 nCorrectOffset = numAlu.GetSignedValue();
2154 // the Lorentz correction to the offset
2155 Double_t lorCorrectOffset = lorTan *(Double_t)nrOfOffsetCorrTimeBins*vdrift*10.0/freqSample; // Lorentz offset correction in mm
2158 lorCorrectOffset = lorCorrectOffset/padWidthI; // Lorentz correction in pad width units
2160 if(lorCorrectOffset < 0) {
2161 numAlu.AssignDouble(-lorCorrectOffset);
2165 numAlu.AssignDouble(lorCorrectOffset);
2169 Int_t mlorCorrectOffset = numAlu.GetSignedValue();
2172 Double_t mCorrectOffset = padWidthI/granularityOffset; // >= 0.0
2174 // calculation of slope-correction
2176 // this is only true for tracks coming (approx.) from primary vertex
2177 // everything is evaluated for a tracklet covering the whole drift chamber
2178 Double_t cCorrectSlope = (-lorTan*dx + zPos/xPos*dx*tiltTan)/granularitySlope;
2179 // Double_t cCorrectSlope = zPos/xPos*dx*tiltTan/granularitySlope;
2180 // zPos can be negative! for track from primary vertex: zOut-zIn > 0 <=> zPos > 0
2182 if (cCorrectSlope < 0) {
2183 numAlu.AssignDouble(-cCorrectSlope);
2187 numAlu.AssignDouble(cCorrectSlope);
2190 cCorrectSlope = numAlu.GetSignedValue();
2192 // convert slope to deflection between upper and lower drift-chamber position (slope is given in pad-unit/time-bins)
2193 // different pad-width of outer pads of a pad-plane not taken into account
2194 // note that the fit was only done in the range tFS to tFE, however this range does not need to cover the whole drift region (neither start nor end of it)
2195 // however the tracklets are supposed to be a fit in the drift region thus the linear function is stretched to fit the drift region of 30 mm
2198 Double_t mCorrectSlope = (Double_t)(nrOfDriftTimeBins)*padWidthI/granularitySlope; // >= 0.0
2200 AliTRDtrapAlu correctAlu;
2201 correctAlu.Init(20,8);
2203 AliTRDtrapAlu offsetAlu;
2204 offsetAlu.Init(13,0,-0x1000,0x0FFF); // 13 bit-word; 2-complement (1 sign-bit); asymmetric range
2206 AliTRDtrapAlu slopeAlu;
2207 slopeAlu.Init(7,0,-0x40,0x3F); // 7 bit-word; 2-complement (1 sign-bit);
2209 for (Int_t i = 0; i<4; i++) {
2211 if (mADC[i] == -1) continue;
2213 icol = fFeeParam->GetPadColFromADC(fRobPos,fMcmPos,mADC[i]); // be aware that mADC[i] contains the ADC-number according to online-mapping
2214 yPos[i] = (padPlane->GetColPos(icol))*10.0;
2219 correctAlu.AssignDouble(mCorrectOffset); // done because max. accuracy is 8 bit
2220 mCorrectOffset = correctAlu.GetValueWhole(); // cut offset correction to 8 past-comma bit accuracy
2221 mOffset[i] = (Int_t)((mCorrectOffset)*(Double_t)(mOffset[i] + nCorrectOffset - mlorCorrectOffset));
2222 //mOffset[i] = mOffset[i]*(-1); // adjust to direction of y-axes in online simulation
2224 if (mOffset[i] < 0) {
2225 numAlu.AssignFormatted(-mOffset[i]);
2229 numAlu.AssignFormatted(mOffset[i]);
2234 mOffset[i] = offsetAlu.GetSignedValue();
2239 correctAlu.AssignDouble(mCorrectSlope);
2240 mCorrectSlope = correctAlu.GetValueWhole();
2242 mSlope[i] = (Int_t)((mCorrectSlope*(Double_t)mSlope[i]) + cCorrectSlope);
2244 if (mSlope[i] < 0) {
2245 numAlu.AssignFormatted(-mSlope[i]);
2249 numAlu.AssignFormatted(mSlope[i]);
2253 slopeAlu = numAlu; // here all past-comma values are cut, not rounded; alternatively add +0.5 before cutting (means rounding)
2254 mSlope[i] = slopeAlu.GetSignedValue();
2256 // local (LTU) limits for the deflection
2257 // ATan returns angles in radian
2258 alphaMax[i] = TMath::ASin(eCharge*magField/(2.0*ptMin)*(TMath::Sqrt(xPos*xPos + yPos[i]*yPos[i]))/1000.0); // /1000: mm->m
2259 slopeMin[i] = dx*(TMath::Tan(TMath::ATan(yPos[i]/xPos) - alphaMax[i]))/granularitySlope;
2260 slopeMax[i] = dx*(TMath::Tan(TMath::ATan(yPos[i]/xPos) + alphaMax[i]))/granularitySlope;
2262 if (slopeMin[i] < 0) {
2263 slopeAlu.AssignDouble(-slopeMin[i]);
2264 slopeAlu.SetSign(-1);
2267 slopeAlu.AssignDouble(slopeMin[i]);
2268 slopeAlu.SetSign(1);
2270 mslopeMin[i] = slopeAlu.GetSignedValue(); // the borders should lie inside the range of mSlope -> usage of slopeAlu again
2272 if (slopeMax[i] < 0) {
2273 slopeAlu.AssignDouble(-slopeMax[i]);
2274 slopeAlu.SetSign(-1);
2277 slopeAlu.AssignDouble(slopeMax[i]);
2278 slopeAlu.SetSign(1);
2280 mslopeMax[i] = slopeAlu.GetSignedValue();
2283 // suppress submission of tracks with low stiffness
2284 // put parameters in 32bit-word and submit (write to file as root-file; sort after SM, stack, layer, chamber)
2286 // sort tracklet-words in ascending y-order according to the offset (according to mADC would also be possible)
2287 // up to now they are sorted according to maximum hit sum
2288 // is the sorting really done in the TRAP-chip?
2290 Int_t order[4] = {-1,-1,-1,-1};
2291 Int_t wordnr = 0; // number of tracklet-words
2293 for(Int_t j = 0; j < fMaxTracklets; j++) {
2294 //if( mADC[j] == -1) continue;
2295 if( (mADC[j] == -1) || (mSlope[j] < mslopeMin[j]) || (mSlope[j] > mslopeMax[j])) continue; // this applies a pt-cut
2297 if( wordnr-1 == 0) {
2301 // wordnr-1>0, wordnr-1<4
2302 order[wordnr-1] = j;
2303 for( Int_t k = 0; k < wordnr-1; k++) {
2304 if( mOffset[j] < mOffset[order[k]] ) {
2305 for( Int_t l = wordnr-1; l > k; l-- ) {
2306 order[l] = order[l-1];
2315 // fill the bit-words in ascending order and without gaps
2316 UInt_t bitWord[4] = {0,0,0,0}; // attention: unsigned int to have real 32 bits (no 2-complement)
2317 for(Int_t j = 0; j < wordnr; j++) { // only "wordnr" tracklet-words
2318 //Bool_t rem1 = kTRUE;
2321 //bit-word is 2-complement and therefore without sign
2322 bitWord[j] = 1; // this is the starting 1 of the bit-word (at 33rd position); the 1 must be ignored
2330 /*printf("mean charge: %d\n",mMeanCharge[i]);
2331 printf("row: %d\n",fRow);
2332 printf("slope: %d\n",mSlope[i]);
2333 printf("pad position: %d\n",mOffset[i]);
2334 printf("channel: %d\n",mADC[i]);*/
2336 // electron probability (currently not implemented; the mean charge is just scaled)
2337 shift = (UInt_t)mMeanCharge[i];
2338 for(Int_t iBit = 0; iBit < 8; iBit++) {
2339 bitWord[j] = bitWord[j]<<1;
2340 bitWord[j] |= (shift>>(7-iBit))&1;
2345 shift = (UInt_t)fRow;
2346 for(Int_t iBit = 0; iBit < 4; iBit++) {
2347 bitWord[j] = bitWord[j]<<1;
2348 bitWord[j] |= (shift>>(3-iBit))&1;
2349 //printf("%d", (fRow>>(3-iBit))&1);
2352 // deflection length
2354 shift = (UInt_t)(-mSlope[i]);
2355 // shift2 is 2-complement of shift
2357 for(Int_t iBit = 1; iBit < 7; iBit++) {
2359 shift2 |= (1- (((shift)>>(6-iBit))&1) );
2360 //printf("%d",(1-((-mSlope[i])>>(6-iBit))&1));
2362 shift2 = shift2 + 1;
2364 for(Int_t iBit = 0; iBit < 7; iBit++) {
2365 bitWord[j] = bitWord[j]<<1;
2366 bitWord[j] |= (shift2>>(6-iBit))&1;
2367 //printf("%d",(1-((-mSlope[i])>>(6-iBit))&1));
2371 shift = (UInt_t)(mSlope[i]);
2372 bitWord[j] = bitWord[j]<<1;
2375 for(Int_t iBit = 1; iBit < 7; iBit++) {
2376 bitWord[j] = bitWord[j]<<1;
2377 bitWord[j] |= (shift>>(6-iBit))&1;
2378 //printf("%d",(mSlope[i]>>(6-iBit))&1);
2383 if(mOffset[i] < 0) {
2384 shift = (UInt_t)(-mOffset[i]);
2386 for(Int_t iBit = 1; iBit < 13; iBit++) {
2388 shift2 |= (1-(((shift)>>(12-iBit))&1));
2389 //printf("%d",(1-((-mOffset[i])>>(12-iBit))&1));
2391 shift2 = shift2 + 1;
2393 for(Int_t iBit = 0; iBit < 13; iBit++) {
2394 bitWord[j] = bitWord[j]<<1;
2395 bitWord[j] |= (shift2>>(12-iBit))&1;
2396 //printf("%d",(1-((-mSlope[i])>>(6-iBit))&1));
2400 shift = (UInt_t)mOffset[i];
2401 bitWord[j] = bitWord[j]<<1;
2404 for(Int_t iBit = 1; iBit < 13; iBit++) {
2405 bitWord[j] = bitWord[j]<<1;
2406 bitWord[j] |= (shift>>(12-iBit))&1;
2407 //printf("%d",(mOffset[i]>>(12-iBit))&1);
2413 //printf("bitWord: %u\n",bitWord[j]);
2414 //printf("adc: %d\n",mADC[i]);
2415 fMCMT[j] = bitWord[j];
2434 delete [] selectPair;
2438 //if you want to activate the MC tracklet output, set fgkMCTrackletOutput=kTRUE in AliTRDfeeParam
2440 if (!fFeeParam->GetMCTrackletOutput())
2443 AliLog::SetClassDebugLevel("AliTRDmcmSim", 10);
2444 AliLog::SetFileOutput("../log/tracklet.log");
2446 // testing for wordnr in order to speed up the simulation
2450 UInt_t *trackletWord = new UInt_t[fMaxTracklets];
2451 Int_t *adcChannel = new Int_t[fMaxTracklets];
2452 Int_t *trackRef = new Int_t[fMaxTracklets];
2456 AliTRDdigitsManager *digman = new AliTRDdigitsManager();
2457 digman->ReadDigits(gAlice->GetRunLoader()->GetLoader("TRDLoader")->TreeD());
2458 digman->SetUseDictionaries(kTRUE);
2459 AliTRDfeeParam *feeParam = AliTRDfeeParam::Instance();
2461 for (Int_t j = 0; j < fMaxTracklets; j++) {
2463 trackletWord[j] = 0;
2465 if (bitWord[j]!=0) {
2466 trackletWord[u] = bitWord[j];
2467 adcChannel[u] = mADC[i]; // mapping onto the original adc-array to be in line with the digits-adc-ordering (21 channels in total on 1 mcm, 18 belonging to pads); mADC[i] should be >-1 in case bitWord[i]>0
2469 // Finding label of MC track
2470 TH1F *hTrkRef = new TH1F("trackref", "trackref", 100000, 0, 100000);
2472 Int_t padcol = feeParam->GetPadColFromADC(fRobPos, fMcmPos, adcChannel[u]);
2473 Int_t padcol_ngb = feeParam->GetPadColFromADC(fRobPos, fMcmPos, adcChannel[u] - 1);
2474 Int_t padrow = 4 * (fRobPos / 2) + fMcmPos / 4;
2475 Int_t det = 30 * fSector + 6 * fStack + fLayer;
2476 for(Int_t iTimebin = feeParam->GetLinearFitStart(); iTimebin < feeParam->GetLinearFitEnd(); iTimebin++) {
2477 track[0] = digman->GetTrack(0, padrow, padcol, iTimebin, det);
2478 track[1] = digman->GetTrack(1, padrow, padcol, iTimebin, det);
2479 track[2] = digman->GetTrack(2, padrow, padcol, iTimebin, det);
2480 hTrkRef->Fill(track[0]);
2481 if (track[1] != track[0] && track[1] != -1)
2482 hTrkRef->Fill(track[1]);
2483 if (track[2] != track[0] && track[2] != track[1] && track[2] != -1)
2484 hTrkRef->Fill(track[2]);
2485 if (padcol_ngb >= 0) {
2486 track[0] = digman->GetTrack(0, padrow, padcol, iTimebin, det);
2487 track[1] = digman->GetTrack(1, padrow, padcol, iTimebin, det);
2488 track[2] = digman->GetTrack(2, padrow, padcol, iTimebin, det);
2489 hTrkRef->Fill(track[0]);
2490 if (track[1] != track[0] && track[1] != -1)
2491 hTrkRef->Fill(track[1]);
2492 if (track[2] != track[0] && track[2] != track[1] && track[2] != -1)
2493 hTrkRef->Fill(track[2]);
2496 trackRef[u] = hTrkRef->GetMaximumBin() - 1;
2502 AliDataLoader *dl = gAlice->GetRunLoader()->GetLoader("TRDLoader")->GetDataLoader("tracklets");
2504 AliError("Could not get the tracklets data loader!");
2507 TTree *trackletTree = dl->Tree();
2510 trackletTree = dl->Tree();
2512 AliTRDtrackletMCM *trkl = new AliTRDtrackletMCM();
2513 TBranch *trkbranch = trackletTree->GetBranch("mcmtrklbranch");
2515 trkbranch = trackletTree->Branch("mcmtrklbranch", "AliTRDtrackletMCM", &trkl, 32000);
2516 trkbranch->SetAddress(&trkl);
2518 for (Int_t iTracklet = 0; iTracklet < fMaxTracklets; iTracklet++) {
2519 if (trackletWord[iTracklet] == 0)
2521 trkl->SetTrackletWord(trackletWord[iTracklet]);
2522 trkl->SetDetector(30*fSector + 6*fStack + fLayer);
2523 trkl->SetROB(fRobPos);
2524 trkl->SetMCM(fMcmPos);
2525 trkl->SetLabel(trackRef[iTracklet]);
2526 trackletTree->Fill();
2529 dl->WriteData("OVERWRITE");
2532 delete [] trackletWord;
2533 delete [] adcChannel;
2538 // error measure for quality of fit (not necessarily needed for the trigger)
2539 // cluster quality threshold (not yet set)
2540 // electron probability