-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathMPDGEMPlane.cxx
656 lines (531 loc) · 23 KB
/
MPDGEMPlane.cxx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
#include <iostream>
#include "MPDGEMPlane.h"
#include "TDatime.h"
#include "THaEvData.h"
#include <vector>
#include "GEMHit.h"
#define ALL(c) (c).begin(), (c).end()
MPDGEMPlane::MPDGEMPlane( const char *name, const char *description,
THaDetectorBase* parent ):
GEMPlane(name,description,parent),
// nch(0),fStrip(NULL),fPedestal(NULL),fcommon_mode(NULL),
trigger_time(-1),ev_num(-1)
{
// FIXME: To database
fZeroSuppress = kFALSE;
fZeroSuppressRMS = 5.0;
fMaxSamp = N_MPD_TIME_SAMP;
for( UInt_t i = 0; i < fMaxSamp; i++ ){
fADCForm[i] = NULL;
}
fADCSum = NULL;
return;
}
MPDGEMPlane::~MPDGEMPlane() {
if( fSigStrips.size() > 0 ){
fADC0 = NULL;
fADC1 = NULL;
fADC2 = NULL;
fADC3 = NULL;
fADC4 = NULL;
fADC5 = NULL;
fADCSum = NULL;
for( UInt_t i = 0; i < fMaxSamp; i++ ){
delete fADCForm[i];
fADCForm[i] = NULL;
}
/*
delete fcommon_mode;
fcommon_mode = NULL;
delete fPedestal;
fPedestal = NULL;
delete fStrip;
fStrip = NULL;
*/
}
return;
}
Int_t MPDGEMPlane::ReadDatabase( const TDatime& date ){
std::cout << "[MPDGEMPlane::ReadDatabase]" << std::endl;
// Read the database for the base class, quit if error
Int_t status = ReadDatabaseCommon(date);
if( status != kOK )
return status;
Int_t err;
FILE* file = OpenFile( date );
if( !file ) return kFileError;
TString mapping;
fMaxClusterSize = kMaxUInt;
fMinAmpl = 0.0;
fSplitFrac = 0.0;
fMapType = kOneToOne;
fMaxSamp = 6;
fChanMap.clear();
fPed.clear();
fAmplSigma = 0.36; // default, an educated guess
std::vector<Double_t> rawped;
std::vector<Double_t> rawrms;
Int_t gbl = GetDBSearchLevel(fPrefix);
const DBRequest request[] = {
{ "chanmap", &fChanMapData, kIntV, 0, 0},
{ "ped", &rawped, kDoubleV, 0, 1},
{ "rms", &rawrms, kDoubleV, 0, 1},
{ "strip.pos", &fStart },
{ "strip.pitch", &fPitch, kDouble, 0, 0, gbl },
{ "maxclustsiz", &fMaxClusterSize, kUInt, 0, 1, gbl },
{ "maxsamp", &fMaxSamp, kUInt, 0, 1, gbl },
{ "adc.min", &fMinAmpl, kDouble, 0, 1, gbl },
{ "split.frac", &fSplitFrac, kDouble, 0, 1, gbl },
{ "mapping", &mapping, kTString, 0, 1, gbl },
{}
};
err = LoadDB( file, date, request, fPrefix );
if( err ) return err;
fclose(file);
UInt_t nentry = fChanMapData.size()/MPDMAP_ROW_SIZE;
for( UInt_t mapline = 0; mapline < nentry; mapline++ ){
mpdmap_t thisdata;
thisdata.crate = fChanMapData[0+mapline*MPDMAP_ROW_SIZE];
thisdata.slot = fChanMapData[1+mapline*MPDMAP_ROW_SIZE];
thisdata.mpd_id = fChanMapData[2+mapline*MPDMAP_ROW_SIZE];
thisdata.gem_id = fChanMapData[3+mapline*MPDMAP_ROW_SIZE];
thisdata.adc_id = fChanMapData[4+mapline*MPDMAP_ROW_SIZE];
thisdata.i2c = fChanMapData[5+mapline*MPDMAP_ROW_SIZE];
thisdata.pos = fChanMapData[6+mapline*MPDMAP_ROW_SIZE];
thisdata.invert = fChanMapData[7+mapline*MPDMAP_ROW_SIZE];
fMPDmap.push_back(thisdata);
}
fNelem = N_APV25_CHAN*fMPDmap.size();
SafeDelete(fADCraw);
SafeDelete(fADC);
SafeDelete(fHitTime);
SafeDelete(fADCcor);
SafeDelete(fGoodHit);
std::cout << fName << " mapped to " << nentry << " APV25 chips" << std::endl;
for( UInt_t i = 0; i < fMaxSamp; i++ ){
fADCForm[i] = new Int_t [fNelem];
for( UInt_t j = 0; j < fMaxSamp; j++ ){
fADCForm[i][j] = 0.0;
}
}
fADC0 = fADCForm[0];
fADC1 = fADCForm[1];
fADC2 = fADCForm[2];
fADC3 = fADCForm[3];
fADC4 = fADCForm[4];
fADC5 = fADCForm[5];
fADCSum = new Int_t[fNelem];
// fcommon_mode = new Int_t[N_APV25_CHAN*nentry];
fPed.clear();
fRMS.clear();
for( UInt_t i = 0; i < rawped.size(); i++ ){
if( (i % 2) == 1 ) continue;
UInt_t idx = (UInt_t) rawped[i];
if( idx < (UInt_t) fNelem && fPed.size() == idx ){
fPed.push_back(rawped[i+1]);
} else {
std::cout << "[MPDGEMPlane::ReadDatabase] WARNING: " << " strip " << idx << " listed but not enough strips in cratemap" << std::endl;
}
}
for( UInt_t i = 0; i < fNelem-rawped.size(); i++ ){
fPed.push_back(0);
}
for( UInt_t i = 0; i < rawrms.size(); i++ ){
if( (i % 2) == 1 ) continue;
UInt_t idx = (UInt_t) rawrms[i];
if( idx < ((UInt_t) fNelem) && fRMS.size() == idx ){
fRMS.push_back(rawrms[i+1]);
} else {
std::cout << "[MPDGEMPlane::ReadDatabase] WARNING: " << " strip " << idx << " listed but not enough strips in cratemap" << std::endl;
}
}
for( UInt_t i = 0; i < fNelem-rawrms.size(); i++ ){
fRMS.push_back(0);
}
fADCraw = new Float_t[fNelem];
fADC = new Float_t[fNelem];
fHitTime = new Float_t[fNelem];
fADCcor = new Float_t[fNelem];
fGoodHit = new Byte_t[fNelem];
fSigStrips.reserve(fNelem);
fStripsSeen.resize(fNelem);
return 0;
}
Int_t MPDGEMPlane::DefineVariables( EMode mode ) {
if( mode == kDefine and fIsSetup ) return kOK;
fIsSetup = ( mode == kDefine );
RVarDef vars[] = {
{ "nrawstrips", "nstrips with decoder data", "fNrawStrips" },
{ "nhitstrips", "nstrips > 0", "fNhitStrips" },
{ "nstrips", "Num strips with hits > adc.min", "GetNsigStrips()" },
{ "hitocc", "strips > 0 / n_all_strips", "fHitOcc" },
{ "occupancy", "nstrips / n_all_strips", "fOccupancy" },
{ "strip.adcraw", "Raw strip ADC sum", "fADCraw" },
{ "strip.adc", "Deconvoluted strip ADC sum", "fADC" },
{ "strip.adc_c", "Pedestal-sub strip ADC sum", "fADCcor" },
{ "strip.time", "Leading time of strip signal (ns)","fHitTime" },
{ "strip.good", "Good pulse shape on strip", "fGoodHit" },
{ "nhits", "Num hits (clusters of strips)", "GetNhits()" },
{ "noise", "Noise level (avg below adc.min)", "fDnoise" },
{ "ncoords", "Num fit coords", "GetNcoords()" },
{ "coord.pos", "Position used in fit (m)", "fFitCoords.TreeSearch::FitCoord.fPos" },
{ "coord.trkpos", "Track pos from projection fit (m)","fFitCoords.TreeSearch::FitCoord.fTrackPos" },
{ "coord.trkslope", "Track slope from projection fit", "fFitCoords.TreeSearch::FitCoord.fTrackSlope" },
{ "coord.resid", "Residual of trkpos (m)", "fFitCoords.TreeSearch::FitCoord.GetResidual()" },
{ "coord.3Dpos", "Crossing position of fitted 3D track (m)", "fFitCoords.TreeSearch::FitCoord.f3DTrkPos" },
{ "coord.3Dresid", "Residual of 3D trkpos (m)", "fFitCoords.TreeSearch::FitCoord.Get3DTrkResid()" },
{ "coord.3Dslope", "Slope of fitted 3D track wrt projection", "fFitCoords.TreeSearch::FitCoord.f3DTrkSlope" },
//{ "nch", "Number of channels", "nch" },
{ "strip.number", "Strip number mapping", "fSigStrips" },
{ "adc0", "ADC sample", "fADC0" },
{ "adc1", "ADC sample", "fADC1" },
{ "adc2", "ADC sample", "fADC2" },
{ "adc3", "ADC sample", "fADC3" },
{ "adc4", "ADC sample", "fADC4" },
{ "adc5", "ADC sample", "fADC5" },
{ "adc_sum", "ADC samples sum", "fADCSum" },
//{ "common_mode", "Common Mode", "fcommon_mode" },
{ "trigger_time", "Trigger Time", "trigger_time" },
{ "ev_num","event counter","ev_num"},
{ 0 },
};
Int_t ret = DefineVarsFromList( vars, mode );
if( ret != kOK )
return ret;
RVarDef nonmcvars[] = {
{ "hit.pos", "Hit centroid (m)", "fHits.TreeSearch::GEMHit.fPos" },
{ "hit.adc", "Hit ADC sum", "fHits.TreeSearch::GEMHit.fADCsum" },
{ "hit.size", "Num strips ", "fHits.TreeSearch::GEMHit.fSize" },
{ "hit.type", "Hit analysis result", "fHits.TreeSearch::GEMHit.fType" },
{ 0 }
};
ret = DefineVarsFromList( nonmcvars, mode );
return kOK;
}
void MPDGEMPlane::Clear( Option_t* opt ){
TreeSearch::GEMPlane::Clear(opt);
return;
}
Int_t MPDGEMPlane::Decode( const THaEvData& evdata ){
// std::cout << "[MPDGEMPlane::Decode " << fName << "]" << std::endl;
Int_t nch = 0;
for (std::vector<mpdmap_t>::iterator it = fMPDmap.begin() ; it != fMPDmap.end(); ++it){
// Find channel for trigger time first
Int_t effChan = it->mpd_id << 5 ; // Channel reserved for trigger time
ULong_t coarse_time1 = evdata.GetData(it->crate,it->slot,effChan,0);
UInt_t coarse_time2 = evdata.GetData(it->crate,it->slot,effChan,1);
UInt_t fine_time = evdata.GetData(it->crate,it->slot,effChan,2);
trigger_time = ((coarse_time1<<20)|coarse_time2)+fine_time/6.0;
effChan = it->mpd_id<<4;
ev_num = evdata.GetData(it->crate,it->slot,effChan,0);
// Start reading data sample
effChan = it->mpd_id << 8 | it->adc_id;
// Find channel for this crate/slot
Int_t nchan = evdata.GetNumChan( it->crate, it->slot );
// printf("nchan = %d\n", nchan );
for( Int_t ichan = 0; ichan < nchan; ++ichan ) {
Int_t chan = evdata.GetNextChan( it->crate, it->slot, ichan );
if( chan != effChan ) continue; // not part of this detector
UInt_t nsamp = evdata.GetNumHits( it->crate, it->slot, chan );
//std::cout << fName << " MPD " << it->mpd_id << " ADC " << it->adc_id << " found " << nsamp << std::endl;
//std::cout << nsamp << " samples detected (" << nsamp/N_APV25_CHAN << ")" << std::endl;
assert( nsamp == N_APV25_CHAN*fMaxSamp );
Double_t arrADCSum[128]; // Copy of ADC sum for CMN Calculation
Int_t nchStartOfAPV = nch;
for( Int_t strip = 0; strip < N_APV25_CHAN; ++strip ) {
// data is packed like this
// [ts1 of 128 chan] [ts2 of 128chan] ... [ts6 of 128chan]
Int_t RstripPos = GetRStripNumber( strip, it->pos, it->invert );
// fStrip[nch] = RstripPos;
fADCSum[nch] = 0;
Vflt_t samples;
samples.clear();
for( UInt_t adc_samp = 0; adc_samp < fMaxSamp; adc_samp++ ){
UInt_t isamp = adc_samp*N_APV25_CHAN + strip;
assert(isamp < nsamp);
Int_t rawadc = evdata.GetData(it->crate, it->slot, chan, isamp);
fADCForm[adc_samp][nch] = rawadc - fPed[RstripPos];
fADCSum[nch] += fADCForm[adc_samp][nch];
assert( nch < fNelem );
samples.push_back((Float_t) rawadc);
// Note fMPDmap.size() equals to Number of APV Cards
}
MPDStripData_t stripdata = ChargeDep(samples);
// copy adc sum and its fNCH
arrADCSum[strip] = fADCSum[nch];
++fNrawStrips;
++fNhitStrips;
fADCraw[RstripPos] = stripdata.adcraw;
fADC[RstripPos] = stripdata.adc;
fHitTime[RstripPos] = stripdata.time;
fGoodHit[RstripPos] = stripdata.pass;
fADCcor[RstripPos] = stripdata.adc;
// Zero suppression
if( !fZeroSuppress ||
( fRMS[RstripPos] > 0.0 && fabs(fADCForm[2][nch])/fRMS[RstripPos] > fZeroSuppressRMS) ){
fSigStrips.push_back(RstripPos);
nch++;
}
}// End Strip Loop
// Common Mode Calculation starts after strip loop -- TY
// I calculate common mode noise within each APV, that is 128 channels
// Insertion sort arrADCSum
Double_t swap_buff;
for(Int_t i =1; i<N_APV25_CHAN;++i){
swap_buff = arrADCSum[i];
Int_t j = i-1;
while( j>=0 && arrADCSum[j]>swap_buff ){
arrADCSum[j+1] = arrADCSum[j];
j = j-1;
}
arrADCSum[j+1] = swap_buff;
}
// Average the channels with middle 1/3 signals
Double_t cm_noise = 0;
Int_t n_cutoff = 20 ;
Int_t n_cmn = N_APV25_CHAN - 2*n_cutoff;
for(Int_t strip =n_cutoff; strip< N_APV25_CHAN -n_cutoff ;++strip){
if(arrADCSum[strip+1]<arrADCSum[strip]) // Unless N_CMN_CHAN !=128
std::cout << "Sorting went Wrong ! " << std::endl;
cm_noise += arrADCSum[strip];
}
cm_noise = cm_noise/ n_cmn / fMaxSamp; // averaged to each sample
fDnoise = cm_noise;
// Correct superclass' variables for common mode noise
for(Int_t strip=0; strip<N_APV25_CHAN;++strip){
UInt_t RstripPos = GetRStripNumber( strip, it->pos, it->invert );
fADCcor[RstripPos] -= fPed[RstripPos] + cm_noise;
}
// Correct this class' variables for common mode noise
for(Int_t ch= nchStartOfAPV; ch < nch; ch++){
for( UInt_t adc_samp = 0; adc_samp < fMaxSamp; adc_samp++ ){
fADCForm[adc_samp][ch] -= cm_noise;
}
fADCSum[nch] -= cm_noise*fMaxSamp;
}
}// End ichan loop: nchan = total APVs
}
fHitOcc = static_cast<Double_t>(fNhitStrips) / fNelem;
fOccupancy = static_cast<Double_t>(GetNsigStrips()) / fNelem;
// std::cout << fName << " channels found " << nch << std::endl;
// return FindGEMHits();
}
Int_t MPDGEMPlane::GetRStripNumber( UInt_t strip, UInt_t pos, UInt_t invert ){
Int_t RstripNb = APVMAP[strip];
RstripNb=RstripNb+(127-2*RstripNb)*invert;
Int_t RstripPos = RstripNb + 128*pos;
return RstripPos;
}
Int_t MPDGEMPlane::FindGEMHits(){
// Find and analyze clusters. Clusters of active strips are considered
// a "Hit".
//
// The cluster analysis is a critical part of the GEM analysis. Various
// things can and probably need to be done right here already: splitting
// oversized clusters, detecting noise hits/bogus clusters, detecting and
// fitting overlapping clusters etc.
//
// This analysis may even need to be re-done after preliminary tracking to
// see if the clustering can be improved using candidate tracks.
// Additionally, correlated amplitude information from a second readout
// direction in the same readout plane could be used here. These advanced
// procedures would require significant redesign of the code:
// all raw strip info will have to be saved and prcessed at a later point,
// similar to the finding of hit pairs in like-oriented planes of the MWDC.
//
// For the moment, we implement a very simple algorithm: any cluster of
// strips larger than what a single cluster should be is assumed to be two or
// more overlapping hits, and the cluster will be split as follows: anything
// that looks like a local peak followed by a valley will be considered an
// actual cluster. The parameter frac = fSplitFrac (0.0 ... 1.0) can
// be used for some crude tuning. frac > 0.0 means that a peak is
// only a peak if the amplitude drops below (1-frac), so
// frac = 0.1 means: trigger on a drop below 90% etc. Likewise for the
// following valley: the bottom is found if the amplitude rises again
// by (1+frac), so frac = 0.1 means: trigger on a rise above 110% etc.
// The active strip numbers must be sorted for the clustering algorithm
UInt_t nHits = 0;
sort( ALL(fSigStrips) );
#ifndef NDEBUG
TreeSearch::GEMHit* prevHit = 0;
#endif
Double_t frac_down = 1.0 - fSplitFrac, frac_up = 1.0 + fSplitFrac;
typedef Vint_t::iterator viter_t;
Vint_t splits; // Strips with ampl split between 2 clusters
viter_t next = fSigStrips.begin();
while( next != fSigStrips.end() ) {
viter_t start = next, cur = next;
++next;
assert( next == fSigStrips.end() or *next > *cur );
while( next != fSigStrips.end() and (*next - *cur) == 1 ) {
++cur;
++next;
}
// Now the cluster candidate is between start and cur
assert( *cur >= *start );
// The "type" parameter indicates the result of the cluster analysis:
// 0: clean (i.e. smaller than fMaxClusterSize, no further analysis)
// 1: large, maximum at right edge, not split
// 2: large, no clear minimum on the right side found, not split
// 3: split, well-defined peak found (may still be larger than maxsize)
Int_t type = 0;
UInt_t size = *cur - *start + 1;
if( size > fMaxClusterSize ) {
Double_t maxadc = 0.0, minadc = kBig;
viter_t it = start, maxpos = start, minpos = start;
enum EStep { kFindMax = 1, kFindMin, kDone };
EStep step = kFindMax;
while( step != kDone and it != next ) {
Double_t adc = fADCcor[*it];
switch( step ) {
case kFindMax:
// Looking for maximum
if( adc > maxadc ) {
maxpos = it;
maxadc = adc;
} else if( adc < maxadc * frac_down ) {
assert( maxadc > 0.0 );
step = kFindMin;
continue;
}
break;
case kFindMin:
// Looking for minimum
if( adc < minadc ) {
minpos = it;
minadc = adc;
} else if( adc > minadc * frac_up ) {
assert( minadc < kBig );
step = kDone;
}
break;
case kDone:
assert( false ); // should never get here
break;
}
++it;
}
if( step == kDone ) {
// Found maximum followed by minimum
assert( minpos != start );
assert( minpos != cur );
assert( *minpos > *maxpos );
// Split the cluster at the position of the minimum, assuming that
// the strip with the minimum amplitude is shared between both clusters
cur = minpos;
next = minpos;
// In order not to double-count amplitude, we split the signal height
// of that strip evenly between the two clusters. This is a very
// crude way of doing what we really should be doing: "fitting" a peak
// shape and using the area and centroid of the curve
fADCcor[*minpos] /= 2.0;
splits.push_back(*minpos);
}
type = step;
size = *cur - *start + 1;
assert( *cur >= *start );
}
assert( size > 0 );
// Compute weighted position average. Again, a crude (but fast) substitute
// for fitting the centroid of the peak.
Double_t xsum = 0.0, adcsum = 0.0;
for( ; start != next; ++start ) {
Int_t istrip = *start;
Double_t pos = GetStart() + istrip * GetPitch();
Double_t adc = fADCcor[istrip];
xsum += pos * adc;
adcsum += adc;
}
assert( adcsum > 0.0 );
Double_t pos = xsum/adcsum;
// The resolution (sigma) of the position measurement depends on the
// cluster size. In particular, if the cluster consists of only a single
// hit, the resolution is much reduced
Double_t resolution = fResolution;
if( size == 1 ) {
resolution = TMath::Max( 0.25*GetPitch(), fResolution );
// The factor of 1/2*pitch is just a guess. Since with real GEMs
// there _should_ always be more than one strip per cluster, we must
// assume that the other strip(s) did not fire due to inefficiency.
// As a result, the error is bigger than it would be if only ever one
// strip fired per hit.
// resolution = TMath::Max( 0.5*GetPitch(), 2.0*fResolution );
// } else if( size == 2 ) {
// // Again, this is a guess, to be quantified with Monte Carlo
// resolution = 1.2*fResolution;
}
// Make a new hit
#ifndef NDEBUG
TreeSearch::GEMHit* theHit = 0;
#endif
#ifndef NDEBUG
theHit =
#endif
new( (*fHits)[nHits++] ) TreeSearch::GEMHit( pos,
adcsum,
size,
type,
resolution,
this
);
#ifndef NDEBUG
// Ensure hits are ordered by position (should be guaranteed by std::map)
assert( (prevHit == 0) or (theHit->Compare(prevHit) > 0) );
prevHit = theHit;
#endif
}
// Undo amplitude splitting, if any, so fADCcor contains correct ADC values
for( viter_t it = splits.begin(); it != splits.end(); ++it ) {
fADCcor[*it] *= 2.0;
}
// Negative return value indicates potential problem
if( nHits > fMaxHits )
nHits = -nHits;
return nHits;
}
Int_t MPDGEMPlane::Begin( THaRunBase* run ){
TreeSearch::GEMPlane::Begin(run);
return 0;
}
Int_t MPDGEMPlane::End( THaRunBase* run ){
TreeSearch::GEMPlane::End(run);
return 0;
}
MPDStripData_t MPDGEMPlane::ChargeDep( const std::vector<Float_t>& amp ) {
// Deconvolute signal given by samples in 'amp', return approximate integral.
// Currently analyzes exactly 3 samples.
// From Kalyan Allada
// NIM A326, 112 (1993)
//FIXME: from database, proper value for Tp
const Float_t delta_t = 25.0; // time interval between samples (ns)
const Float_t Tp = 50.0; // RC filter time constant (ns)
assert( amp.size() >= 3 );
Float_t adcraw = delta_t*(amp[0]+amp[1]+amp[2]);
// Weight factors calculated based on the response of the silicon microstrip
// detector:
// v(t) = (delta_t/Tp)*exp(-delta_t/Tp)
// Need to update this for GEM detector response(?):
// v(t) = A*(1-exp(-(t-t0)/tau1))*exp(-(t-t0)/tau2)
// where A is the amplitude, t0 the begin of the rise, tau1 the time
// parameter for the rising edge and tau2 the for the falling edge.
Float_t x = delta_t/Tp;
Float_t w1 = TMath::Exp(x-1)/x;
Float_t w2 = -2*TMath::Exp(-1)/x;
Float_t w3 = TMath::Exp(-x-1)/x;
// Deconvoluted signal samples, assuming measurements of zero before the
// leading edge
Float_t sig[3] = { amp[0]*w1,
amp[1]*w1+amp[0]*w2,
amp[2]*w1+amp[1]*w2+amp[0]*w3 };
Float_t adc = delta_t*(sig[0]+sig[1]+sig[2]);
Float_t time = 0; // TODO
Bool_t pass;
// Calculate ratios for 3 samples and check for bad signals
if( amp[2] > 0 ) {
Float_t r1 = amp[0]/amp[2];
Float_t r2 = amp[1]/amp[2];
pass = (r1 < 1.0 and r2 < 1.0 and r1 < r2);
} else
pass = false;
return MPDStripData_t(adcraw,adc,time,pass);
}