StRoot  1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
StFttClusterMaker.cxx
1 /***************************************************************************
2  *
3  * $Id: StFttClusterMaker.cxx,v 1.4 2019/03/08 18:45:40 fseck Exp $
4  *
5  * Author: Florian Seck, April 2018
6  ***************************************************************************
7  *
8  * Description: StFttClusterMaker - class to fill the StEvent from DAQ reader:
9  * unpack raw data & save StETofHeader & StETofDigis in StETofCollection
10  *
11  ***************************************************************************/
12 #include <vector>
13 #include <set>
14 #include <map>
15 #include <array>
16 #include <algorithm> // std::is_sorted
17 #include <climits>
18 
19 #include "StEvent.h"
20 #include "StEnumerations.h"
21 
22 #include "StFttClusterMaker.h"
23 
24 
25 #include "StEvent/StFttRawHit.h"
26 #include "StEvent/StFttCluster.h"
27 #include "StEvent/StEvent.h"
28 #include "StEvent/StFttCollection.h"
29 
30 #include "StFttDbMaker/StFttDb.h"
31 
32 
33 //_____________________________________________________________
34 StFttClusterMaker::StFttClusterMaker( const char* name )
35 : StMaker( name ),
36  mEvent( 0 ),
37  mRunYear( 0 ),
38  mDebug( false ),
39  mFttDb( nullptr )
40 {
41  LOG_DEBUG << "StFttClusterMaker::ctor" << endm;
42 }
43 
44 //_____________________________________________________________
45 StFttClusterMaker::~StFttClusterMaker()
46 { /* no op */
47 
48 }
49 
50 //_____________________________________________________________
51 Int_t
52 StFttClusterMaker::Init()
53 {
54  LOG_INFO << "StFttClusterMaker::Init" << endm;
55 
56  return kStOk;
57 }
58 
59 //_____________________________________________________________
60 Int_t
61 StFttClusterMaker::InitRun( Int_t runnumber )
62 {
63  mRunYear = ( runnumber + 727000 ) / 1000000 + 1999;
64 
65  LOG_INFO << "runnumber: " << runnumber << " --> year: " << mRunYear << endm;
66 
67  return kStOk;
68 }
69 
70 //_____________________________________________________________
71 Int_t
72 StFttClusterMaker::FinishRun( Int_t runnumber )
73 {
74  return kStOk;
75 }
76 
77 //_____________________________________________________________
78 Int_t
80 {
81  return kStOk;
82 }
83 
84 
85 //_____________________________________________________________
86 Int_t
88 {
89  mEvent = (StEvent*)GetInputDS("StEvent");
90  if(mEvent) {
91  } else {
92  LOG_WARN<<"No StEvent!"<<endm;
93  return kStWarn;
94  }
95  mFttCollection=mEvent->fttCollection();
96  if(!mFttCollection) {
97  LOG_WARN << "No StFttCollection" << endm;
98  return kStOk;
99  }
100 
101  mFttDb = static_cast<StFttDb*>(GetDataSet("fttDb"));
102  assert( mFttDb );
103 
104  LOG_DEBUG << "Found " << mFttCollection->rawHits().size() << " Ftt Hits" << endm;
105  ApplyHardwareMap();
106 
107 
108 
109  // InjectTestData();
110 
111  // next we need to sort the hits into 1D projections
112  // process 1 quadrant (ROB) at a time,
113  // process horizontal, vertical or diagonal strips one at a time
114 
115  // key == ROB
116  std::map< UChar_t, std::vector<StFttRawHit *> > hStripsPerRob; // Horizontal
117  std::map< UChar_t, std::vector<StFttRawHit *> > vStripsPerRob; // Vertical
118  std::map< UChar_t, std::vector<StFttRawHit *> > dhStripsPerRob; // Diagonal on Horizontal
119  std::map< UChar_t, std::vector<StFttRawHit *> > dvStripsPerRob; // Diagonal on Vertical
120 
121  size_t nStripsHit = 0;
122  for ( StFttRawHit* hit : mFttCollection->rawHits() ) {
123  UChar_t rob = mFttDb->rob( hit );
124  UChar_t so = mFttDb->orientation( hit );
125 
126  // Apply the time cut
127  if ( !PassTimeCut( hit ) ) continue;
128 
129  if ( kFttHorizontal == so ){
130  hStripsPerRob[ rob ].push_back(hit);
131  nStripsHit++;
132  }
133  if ( kFttVertical == so ){
134  vStripsPerRob[ rob ].push_back(hit);
135  nStripsHit++;
136  }
137  if ( kFttDiagonalH == so ){
138  dhStripsPerRob[ rob ].push_back(hit);
139  nStripsHit++;
140  }
141  if ( kFttDiagonalV == so ){
142  dvStripsPerRob[ rob ].push_back(hit);
143  nStripsHit++;
144  }
145  } // loop on hit
146 
147  size_t nClusters = 0;
148  LOG_DEBUG << "StFttClusterMaker::Make{ nStripsHit = " << nStripsHit << " }" << endm;
149  if ( nStripsHit > 0 ){ // could make more strict?
150  for ( UChar_t iRob = 1; iRob < StFttDb::nRob+1; iRob++ ){
151 
152  auto hClusters = FindClusters( hStripsPerRob[iRob] );
153  // Add them to StEvent
154  for ( StFttCluster * clu : hClusters ){
155  mFttCollection->addCluster( clu );
156  nClusters++;
157  }
158  auto vClusters = FindClusters( vStripsPerRob[iRob] );
159  // Add them to StEvent
160  for ( StFttCluster * clu : vClusters ){
161  mFttCollection->addCluster( clu );
162  nClusters++;
163  }
164  auto hdClusters = FindClusters( dhStripsPerRob[iRob] );
165  // Add them to StEvent
166  for ( StFttCluster * clu : hdClusters ){
167  mFttCollection->addCluster( clu );
168  nClusters++;
169  }
170  auto vdClusters = FindClusters( dvStripsPerRob[iRob] );
171  // Add them to StEvent
172  for ( StFttCluster * clu : vdClusters ){
173  mFttCollection->addCluster( clu );
174  nClusters++;
175  }
176  } // loop on iRob
177  } // nStripsHit
178  LOG_DEBUG << "Found " << nClusters << " clusters this event" << endm;
179 
180  return kStOk;
181 } // Make
182 
183 void StFttClusterMaker::InjectTestData(){
184  mFttCollection->rawHits().clear();
185 
186  StFttRawHit *hit = new StFttRawHit( 1, 1, 1, 1, 1, 55, 1, 1, 0 );
187  hit->setMapping( 1, 1, 1, 23, kFttHorizontal ); // LEFT 2
188  mFttCollection->addRawHit( hit );
189 
190  hit = new StFttRawHit( 1, 1, 1, 1, 1, 90, 1, 1, 0 );
191  hit->setMapping( 1, 1, 1, 24, kFttHorizontal ); // LEFT 1
192  mFttCollection->addRawHit( hit );
193 
194  hit = new StFttRawHit( 1, 1, 1, 1, 1, 60, 1, 1, 0 );
195  hit->setMapping( 1, 1, 1, 27, kFttHorizontal );
196  mFttCollection->addRawHit( hit );
197 
198  hit = new StFttRawHit( 1, 1, 1, 1, 1, 95, 1, 1, 0 );
199  hit->setMapping( 1, 1, 1, 25, kFttHorizontal ); // CENTER
200  mFttCollection->addRawHit( hit );
201 
202  hit = new StFttRawHit( 1, 1, 1, 1, 1, 93, 1, 1, 0 );
203  hit->setMapping( 1, 1, 1, 26, kFttHorizontal );
204  mFttCollection->addRawHit( hit );
205 
206  hit = new StFttRawHit( 1, 1, 1, 1, 1, 19, 1, 1, 0 );
207  hit->setMapping( 1, 1, 1, 28, kFttHorizontal );
208  mFttCollection->addRawHit( hit );
209 } // InjectTestData
210 
211 
228 bool StFttClusterMaker::PassTimeCut( StFttRawHit * hit ){
229  if (mTimeCutMode == kTimeCutModeAcceptAll)
230  return true;
231  else if (mTimeCutMode == kTimeCutModeDB ) {
232  int timeCutMin = INT_MIN;
233  int timeCutMax = INT_MAX;
234  int hitTimeMode = (int)kHitCalibratedTime;
235 
236  mFttDb->getTimeCut(hit, hitTimeMode, timeCutMin, timeCutMax);
237  LOG_DEBUG << TString::Format( "StFttClusterMaker::PassTimeCut - DB gave hit time mode: %d, time cut min: %d, time cut max: %d", hitTimeMode, timeCutMin, timeCutMax ) << endm;
238  if (hitTimeMode == kHitCalibratedTime) {
239  return (hit->time() >= timeCutMin && hit->time() <= timeCutMax);
240  } else if ( hitTimeMode == kHitTimebin ) {
241  return (hit->tb() >= timeCutMin && hit->tb() <= timeCutMax);
242  } else {
243  LOG_WARN << "StFttClusterMaker::PassTimeCut - Unknown hit time mode from database: " << hitTimeMode << endm;
244  LOG_WARN << "Accepting all hits" << endm;
245  return true;
246  }
247  } else if (mTimeCutMode == kTimeCutModeCalibratedTime) {
248  return (hit->time() >= mTimeCutMin && hit->time() <= mTimeCutMax);
249  } else if (mTimeCutMode == kTimeCutModeTimebin) {
250  return (hit->tb() >= mTimeCutMin && hit->tb() <= mTimeCutMax);
251  } else {
252  LOG_WARN << "StFttClusterMaker::PassTimeCut - Unknown time cut mode: " << mTimeCutMode << endm;
253  LOG_WARN << "Accepting all hits" << endm;
254  return true; // Default return value if no conditions are met
255  }
256  return true;
257 } // PassTimeCut
258 
259 
260 StFttRawHit * StFttClusterMaker::FindMaxAdc( std::vector<StFttRawHit *> hits, size_t &pos ){
261  auto itMax = std::max_element(hits.begin(),
262  hits.end(),
263  [](const StFttRawHit* a,const StFttRawHit* b) { return a->adc() < b->adc(); });
264 
265  pos = (itMax - hits.begin());
266  if ( itMax == hits.end() ) return nullptr;
267  return *itMax;
268 }
269 
270 void StFttClusterMaker::SearchClusterEdges( std::vector< StFttRawHit * > hits,
271  size_t start, // start index at MaxADC
272  size_t &left, size_t &right ){
273  // set initial values
274  left = start;
275  right = start;
276 
277  auto lastHitLeft = hits[start];
278  auto lastHitRight = hits[start];
279 
280  bool searchRight = true;
281  bool searchLeft = true;
282 
283  StFttRawHit *hitLeft = nullptr, *hitRight = nullptr;
284 
285  while ( searchRight || searchLeft ){
286  LOG_DEBUG << "LEFT: " << left << ", RIGHT: " << right << ", start = " << start << ", size=" << hits.size() << endm;
287  if ( searchRight ){
288  if ( right == hits.size() || right == hits.size() - 1 ){
289  searchRight = false;
290  }
291  else {
292 
293  hitRight = hits[right+1];
294  if ( hitRight->adc() > lastHitRight->adc() || hitRight->adc() < GetThresholdFor( hitRight ) ){
295  searchRight = false;
296  }
297  if ( hitRight->row() != lastHitRight->row() || abs( hitRight->strip() - lastHitRight->strip() ) > 1 ){
298  searchRight = false;
299  }
300 
301  if ( searchRight ){
302  right ++;
303  lastHitRight = hitRight;
304  }
305  } // right < size - 1
306  } // searchRight
307 
308  if ( searchLeft ){
309  if ( left == 0 ){
310  searchLeft = false;
311  } else {
312  hitLeft = hits[left-1];
313  if ( hitLeft->adc() > lastHitLeft->adc() || hitLeft->adc() < GetThresholdFor( hitLeft ) ){
314  searchLeft = false;
315  }
316  if ( hitLeft->row() != lastHitLeft->row() || abs( hitLeft->strip() - lastHitLeft->strip() ) > 1 ){
317  searchLeft = false;
318  }
319 
320  if (searchLeft){
321  left--;
322  lastHitLeft = hitLeft;
323  }
324  } // left != 0
325  } // searchLeft
326  } // while searching
327 } // SearchClusterEdges
328 
329 
330 void StFttClusterMaker::CalculateClusterInfo( StFttCluster * clu ){
331 
332  clu->setNStrips( clu->rawHits().size() );
333 
334  // Compute the sumAdc, strip gravity center, and variance
335  float m0Sum = 0;
336  float m1Sum = 0;
337  float m2Sum = 0;
338 
339  std::for_each (clu->rawHits().begin(), clu->rawHits().end(), [&](const StFttRawHit *h) {
340  float x = ( h->strip() * 3.2 - 1.6 ); // replace with CONST
341 
342  m0Sum += h->adc();
343  m1Sum += (h->adc() * x);
344  m2Sum += ( h->adc() * x * x );
345  });
346 
347  if ( mDebug ) {
348  LOG_INFO << "m0Sum = " << m0Sum << endm;
349  LOG_INFO << "m1Sum = " << m1Sum << endm;
350  LOG_INFO << "m2Sum = " << m2Sum << endm;
351  }
352 
353  // m0Sum = sumAdc
354  // m1Sum / m0Sum = gravity center (1st moment)
355  // m2Sum = accumulated variance (2nd moment)
356 
357  clu->setSumAdc( m0Sum );
358  clu->setX( m1Sum / m0Sum );
359  float var = (m2Sum - m1Sum*m1Sum / m0Sum) / m0Sum;
360  clu->setSigma( sqrt( var ) );
361 }
362 
363 
364 
365 std::vector<StFttCluster*> StFttClusterMaker::FindClusters( std::vector< StFttRawHit * > hits ){
366  std::vector<StFttCluster*> clusters;
367 
368  /* early data (i.e. cosmic data pre dec 10 2021)
369  * had duplicates where the hits are identical except
370  * a different tb. Tonko fixed at some point
371  * So this could be wrapped in a run range block, but
372  * does no harm.
373  */
374  const bool dedup = false;
375  if ( dedup ){
376  auto cmp = [](StFttRawHit* a, StFttRawHit* b) {
377 
378  return a->plane() < b->plane() ||
379  a->quadrant() < b->quadrant() ||
380  a->row() < b->row() ||
381  a->strip() < b->strip() ||
382  a->orientation() < b->orientation();
383  };
384 
385  // NOTE according to SO this is faster than using ctor
386  set<StFttRawHit*, decltype(cmp)> s(cmp);
387  unsigned size = hits.size();
388  for( auto h : hits ) s.insert( h );
389  hits.assign( s.begin(), s.end() );
390  }
391 
392  // Sort the hits by row and strip
393  sort(hits.begin(), hits.end(), [](const StFttRawHit * a, const StFttRawHit * b) -> bool {
394  size_t indexA = a->orientation() + StFttDb::nStripOrientations * ( a->strip() + a->row() * StFttDb::maxStripPerRow);
395  size_t indexB = b->orientation() + StFttDb::nStripOrientations * ( b->strip() + b->row() * StFttDb::maxStripPerRow);
396  return indexA < indexB;
397  });
398 
399  if ( mDebug ) {
400  LOG_INFO << "We have " << hits.size() << " hits after removing duplicates" << endm;
401  }
402 
403 
404  // Get the max ADC hit in this projection
405  size_t anchor = hits.size()+1;
406  auto maxAdcHit = FindMaxAdc( hits, anchor );
407 
408  // Loop as long as there is at least 1 hit left
409  while ( maxAdcHit ){
410  StFttCluster * clu = new StFttCluster();
411 
412  if ( Debug() ){
413  LOG_DEBUG << "CLUSTER FIND START WITH HITS:" << endm;
414  size_t i = 0;
415  for ( auto *h : hits ){
416  LOG_DEBUG << "[" << i << "]" << *h;
417  i++;
418  }
419  }
420 
421  // Set cluster "location" from max ADC hit
422  clu->setPlane ( maxAdcHit->plane ( ) );
423  clu->setQuadrant ( maxAdcHit->quadrant ( ) );
424  clu->setRow ( maxAdcHit->row ( ) );
425  clu->setOrientation ( maxAdcHit->orientation ( ) );
426 
427  // Now find the cluster edges
428  size_t left = anchor, right = anchor;
429  SearchClusterEdges( hits, anchor, left, right);
430 
431  LOG_DEBUG << "Cluster points ( " << left << ", " << anchor << ", " << right << " )" << endm;
432 
433 
434  // OK now add these hits to the cluster
435  for ( size_t i = left; i < right + 1; i++ ){
436  clu->addRawHit( hits[i] );
437  }
438 
439  // Compute cluster information from the added hits
440  CalculateClusterInfo( clu );
441 
442  if (mDebug){
443  LOG_INFO << *clu << endm;;
444  }
445  clusters.push_back( clu );
446 
447  // Now erase all hits from this cluster so that we can move on to find the next one
448  hits.erase( hits.begin() + left, hits.begin() + right + 1 );
449  maxAdcHit = FindMaxAdc( hits, anchor );
450  } // while maxAdcHit
451  return clusters;
452 }
453 
454 
455 
456 void StFttClusterMaker::ApplyHardwareMap(){
457  for ( StFttRawHit* rawHit : mFttCollection->rawHits() ) {
458  mFttDb->hardwareMap( rawHit );
459  }
460 
461 }
462 
Definition: Stypes.h:42
Definition: Stypes.h:41