FairRoot/PandaRoot
PndLmdPairFinderTask.cxx
Go to the documentation of this file.
1 /*
2  * PairFinderTask.cpp
3  *
4  * Created on: Jul 22, 2014
5  * Author: Roman Klasen, roklasen@uni-mainz.de or klasen@kph.uni-mainz.de
6  */
7 
8 #include "PndLmdPairFinderTask.h"
9 
10 #include <PndGeoHandling.h>
11 #include <PndLmdAlignManager.h>
12 #include <PndLmdContFact.h>
13 #include <PndLmdHitPair.h>
14 #include <PndLmdGeometryHelper.h>
15 #include <PndSdsClusterPixel.h>
16 #include <PndSdsDigiPixel.h>
17 
18 #include <FairRootManager.h>
19 #include <FairRun.h>
20 #include <FairRuntimeDb.h>
21 #include <TClonesArray.h>
22 
23 #include <TCanvas.h>
24 #include <TH1D.h>
25 
26 //#include <algorithm>
27 #include <sstream>
28 #include <vector>
29 
30 using std::cout;
31 using std::cerr;
32 
34 
35 /*
36  * actually I don't need empty constructors, but fkn root crashes if no empty constructor is present
37  */
38 PndLmdPairFinderTask::PndLmdPairFinderTask() : // @suppress("Class members should be properly initialized")
39  PndSdsTask("pairfinder") {
40  digiArray = NULL;
41  recoArray = NULL;
42  clusterCandidateArray = NULL;
43  unsuitable = 0;
44  _ignoreClusters = false;
45 
46 }
47 
48 PndLmdPairFinderTask::PndLmdPairFinderTask(const char* name) : // @suppress("Class members should be properly initialized")
49  PndSdsTask("pairfinder with name") {
50  digiArray = NULL;
51  recoArray = NULL;
52  clusterCandidateArray = NULL;
53 
54  if (!strcmp(name, "")) SetName(name);
55  _ignoreClusters = false;
56 }
57 
59  std::cout << "PairFinderTask destructor called." << "\n";
60 }
61 
63 
64  noOfGoodPairs = 0;
65  noOfEvents = noOfCombos = 0;
67  hitsSinglePixel = 0;
68  hitsSinglePixel = 0;
71  plane0 = plane1 = plane2 = plane3 = 0;
72 
73  fInBranchName = "LMDPixelDigis";
74  fInRecoBranchName = "LMDHitsPixel";
75  fOutBranchName = "LMDPixelPairs";
76  fInClusterCandidates = "LMDPixelClusterCand";
77 
78  fFolderName = "pndsim";
79 
80  _maxDistance = 1250e-4;
81 
83 
84  FairRootManager* ioman = FairRootManager::Instance();
85 
86  if (!ioman) {
87  std::cout << "-E- LmdPairFinder::Init: " << "RootManager not instantiated!" << "\n";
88  return kFATAL;
89  }
90 
91  digiArray = (TClonesArray*) ioman->GetObject(fInBranchName);
92  recoArray = (TClonesArray*) ioman->GetObject(fInRecoBranchName);
93  clusterCandidateArray = (TClonesArray*) ioman->GetObject(fInClusterCandidates);
94 
95  if (!digiArray) {
96  std::cout << "-W- LmdPairFinder::Init: " << "ERROR, branch name " << fInBranchName
97  << " could not found!" << "\n";
98  return kERROR;
99  }
100 
101  if (!recoArray) {
102  std::cout << "-W- LmdPairFinder::Init: " << "ERROR, branch name " << fInRecoBranchName
103  << " not found!" << "\n";
104  return kERROR;
105  }
106 
107  if (!clusterCandidateArray) {
108  std::cout << "-W- LmdPairFinder::Init: " << "ERROR, branch name " << fInClusterCandidates
109  << " not found!" << "\n";
110  return kERROR;
111  }
112 
113  hitPairArray = new TClonesArray("PndLmdHitPair");
114  ioman->Register("PndLmdHitPair", "PndLmd", hitPairArray, kTRUE);
115 
117 
118  std::cout << "LmdPairFinder::Init(): Initialization successful." << "\n";
119  return kSUCCESS;
120 }
121 
123  std::cout << "branch names set to " << fInBranchName << "\n";
124 }
125 
127  return InitStatus();
128 }
129 
131 
132  FairRun* ana;
133  FairRuntimeDb* rtdb;
134 
135  std::cout << "PndLmdPixelClusterTask::SetParContainers() " << "\n";
136  // Get Base Container
137  ana = FairRun::Instance();
138  rtdb = ana->GetRuntimeDb();
139 
140  PndLmdContFact* themvdcontfact = (PndLmdContFact*) rtdb->getContFactory("PndLmdContFact");
141  //read params for lumi alignment
142  TList* theAlignLMDContNames = themvdcontfact->GetAlignParNames();
143  Info("SetParContainers()", "AlignLMD The container names list contains %i entries",
144  theAlignLMDContNames->GetEntries());
145  TIter cfAlIter(theAlignLMDContNames);
146  while (TObjString* contname = (TObjString*) cfAlIter()) {
147  TString parsetname = contname->String();
148  Info("SetParContainers()", "%s", parsetname.Data());
149  }
150 
152 }
153 
154 /*
155  * Main SensorHit filter. It stores the sensor row and column info to a PndLmdHitPair object,
156  * filters for valid hit pairs and stores the decoded hit in LMD coordinate system to the HitPair.
157  * The HitPair contains BOTH original row and col hits as well as LMD xyz Coordinates (as TVector3).
158  * This consumes a lot of storage, but storage is cheap and for now we want the info.
159  */
160 void PndLmdPairFinderTask::Exec(Option_t*) {
161 
162  //clear temporary array for next event
163  hitPairArray->Clear();
164 
165  //Int_t nPixels = digiArray->GetEntriesFast();
166  noOfEvents++;
167 
168  //display some kind of progress
169  if ((noOfEvents % 10000) == 0) {
170  cout << "processed " << noOfEvents << "\n";
171  }
172 
173  // ========== loop over recos in recoArray =========
174  Int_t nRecos = recoArray->GetEntriesFast();
175 
176  Int_t storedPairsPerEvent = 0;
177 
178  //try every cluster combination and check
179  for (auto iReco = 0; iReco < nRecos; iReco++) {
180  for (auto jReco = iReco + 1; jReco < nRecos; jReco++) {
181 
182  PndSdsHit *hitOne = (PndSdsHit*) recoArray->At(iReco);
183  PndSdsHit *hitTwo = (PndSdsHit*) recoArray->At(jReco);
184 
185  int id1 = hitOne->GetSensorID();
186  int id2 = hitTwo->GetSensorID();
187 
188  // sort hits so hitOne is ALWAYS upstream
189  auto &infoOne = helper->getHitLocationInfo(id1);
190  auto &infoTwo = helper->getHitLocationInfo(id2);
191 
192  if (infoOne.module_side > infoTwo.module_side) {
193  std::swap(hitOne, hitTwo);
194  id1 = hitOne->GetSensorID();
195  id2 = hitTwo->GetSensorID();
196  }
197 
198  //from here on, the hits are sorted so hitOne is ALWAYS upstream
199  const TVector3 vecOneGlobal = hitOne->GetPosition();
200  const TVector3 vecTwoGlobal = hitTwo->GetPosition();
201 
202  //make PndLmdHitPair and check for data sanity, then store to vector
203  PndLmdHitPair pairCanditate(vecOneGlobal, vecTwoGlobal, id1, id2);
204 
205  //is the candidate even on an overlapping area?
206  if (!candHitsOverlappingArea(pairCanditate)) {
207  noOverlap++;
208  continue;
209  }
210 
211  int overlapId = helper->getOverlapIdFromSensorIDs(pairCanditate.getId1(), pairCanditate.getId2());
212  pairCanditate.setOverlapId(overlapId);
213 
214  pixelHit pixelHitOne = getPixelHitFromSdsHit(hitOne);
215  pixelHit pixelHitTwo = getPixelHitFromSdsHit(hitTwo);
216 
217  pairCanditate.setPixelHits(pixelHitOne._col, pixelHitOne._row, pixelHitTwo._col, pixelHitTwo._row);
218 
219  pairCanditate.calculateDistance();
220  pairCanditate.check();
221 
222  if (!pairCanditate.isSane()) {
223  pairCanditate.PrintPair();
224  cerr << "==== WARNING: ====" << "\n";
225  cerr << "pair seems valid but did not pass sanity check!" << "\n";
226  cerr << "===============================================" << "\n";
227  continue;
228  }
229 
230  //pair must now be sane, in Panda Global and has overlapID et al.
231  if (!pairDistanceValid(pairCanditate)) {
232  unsuitable++;
233  continue;
234  }
235 
236  // if the pair survived to this point, it's valid. store!
237  getStatistics(pairCanditate);
238  new ((*hitPairArray)[storedPairsPerEvent]) PndLmdHitPair(pairCanditate);
239  storedPairsPerEvent++;
240  }
241  }
242  return;
243 }
244 
246 }
247 
249 
250  //also, write statistics
251  Int_t sumOfAllPlanes = plane0 + plane1 + plane2 + plane3;
252  double plane0Percent = ((double) plane0 / noOfGoodPairs) * 100;
253  double plane1Percent = ((double) plane1 / noOfGoodPairs) * 100;
254  double plane2Percent = ((double) plane2 / noOfGoodPairs) * 100;
255  double plane3Percent = ((double) plane3 / noOfGoodPairs) * 100;
256  double allPlanesPercent = ((double) sumOfAllPlanes / noOfGoodPairs) * 100;
257  double clusterRatio = ((double) hitsClustered / (double) (hitsSinglePixel + hitsClustered)) * 100;
258  double pixelsPerEvent = (double) sumOfPixelHits / (double) noOfEvents;
259  double goodPairsPerEvent = (double) noOfGoodPairs / (double) noOfEvents;
260 
261  cout << "\n";
262  cout << "*************************************************************" << "\n";
263  cout << " pair finder done " << "\n";
264  cout << "*************************************************************" << "\n";
265  cout << "\n";
266  cout << " counting statistics:" << "\n";
267  cout << "\n";
268  printf("total events: %d \n", noOfEvents);
269  printf("events that missed all sensors: %d \n", eventMissedAllPlanes);
270  printf("total pixel hits: %d \n", sumOfPixelHits);
271  printf("cluster ratio: %.2f %% \n", clusterRatio);
272  printf("pixel hits per event: %.2f \n", pixelsPerEvent);
273  printf("----------------------------\n");
274  printf("possible hit pair combinations: %d \n", noOfCombos);
275  printf("no overlap: %d \n", noOverlap);
276  printf("distance too high: %d \n", distanceTooHigh);
277  printf("----------------------------\n");
278  printf("good pairs: %d \n", noOfGoodPairs);
279  printf("good pairs per event: %.2f \n", goodPairsPerEvent);
280  printf("----------------------------\n");
281  printf("hits on plane 0: %.2f %% \n", plane0Percent);
282  printf("hits on plane 1: %.2f %%\n", plane1Percent);
283  printf("hits on plane 2: %.2f %%\n", plane2Percent);
284  printf("hits on plane 3: %.2f %%\n", plane3Percent);
285  printf("hits on all planes: %.2f %% (should be 100%%!) \n", allPlanesPercent);
286  cout << "\n";
287  cout << "*************************************************************" << "\n";
288 
289  return;
290 }
291 
293 }
294 
296 
297  //check distance squared
298  double distance = candidate.getDistance();
299  if (distance > _maxDistance) {
300  distanceTooHigh++;
301  return false;
302  }
303  return true;
304 }
305 
307 
308  //check for overlap
309  int fplane;
310 
311  auto &infoOne = helper->getHitLocationInfo(candidate.getId1());
312  fplane = infoOne.plane;
313 
314  //count events per plane
315  switch (fplane) {
316  case 0:
317  plane0++;
318  break;
319  case 1:
320  plane1++;
321  break;
322  case 2:
323  plane2++;
324  break;
325  case 3:
326  plane3++;
327  break;
328  default:
329  //should never happen, can only indicate decoding error
330  cerr << "WARNING: hit was deemed suitable but plane number is " << fplane << "\n";
331  cerr << "This should not happen!" << "\n";
332  }
333  noOfGoodPairs++;
334 }
335 
337 
338  pixelHit result;
339  int hitSensorId;
340  double row, col;
341 
342  int clusterIndex = sdsHit->GetClusterIndex();
343 
344  std::vector<pixelCluster> clusters;
345  PndSdsClusterPixel *clusterPixelCand = (PndSdsClusterPixel*) clusterCandidateArray->At(clusterIndex);
346 
347  int noOfClusters = clusterPixelCand->GetClusterSize();
348 
349  for (int iCluster = 0; iCluster < noOfClusters; iCluster++) {
350 
351  PndSdsDigiPixel* mcPixel = (PndSdsDigiPixel*) digiArray->At(
352  clusterPixelCand->GetDigiIndex(iCluster));
353 
354  if (!mcPixel) {
355  exit(1);
356  }
357 
358  hitSensorId = mcPixel->GetSensorID();
359 
360  col = mcPixel->GetPixelColumn();
361  row = mcPixel->GetPixelRow();
362 
363  //skip decoding errors
364  if (col < 0 || row < 0) {
365  continue;
366  }
367  else {
368  clusters.push_back(pixelCluster(pixelHit(hitSensorId, col, row)));
369  }
370  }
371 
372  sumOfPixelHits += clusters.size();
373 
374  //all hits are present in clusters
375 
376  /*
377  * ============ find clusters ============
378  * input: vector<pixelCluster>
379  * output vector<pixelCluster>
380  *
381  * algorithm: Hierarchical Clustering Algorithm, see https://en.wikipedia.org/wiki/Hierarchical_clustering
382  * start by putting every pixel hit in a separate cluster (done above).
383  * then merge every two clusters that are close enough (1-2 pixels, may be open to adjustment).
384  * terminate if no more clusters can be merged or after N iterations for N pixel hits.
385  * all remaining clusters contain every pixel hit.
386  */
387 
388  //for every cluster, check every other cluster
389  for (size_t i = 0; i < clusters.size(); i++) {
390  //clusters are interchangeable, check every pair only once
391  for (size_t j = i + 1; j < clusters.size(); j++) {
392 
393  //clusters must be on same sensor
394  if (clusters[i]._sensorId != clusters[j]._sensorId) {
395  continue;
396  }
397 
398  if (clusters[i].isNeighbour(clusters[j])) {
399  clusters[i].merge(clusters[j]);
400  clusters.erase(clusters.begin() + j);
401  j--;
402  }
403  }
404  }
405 
406  //calculate cluster centers and discard large clusters
407  //for statistis: count cluster ratio
408  for (size_t i = 0; i < clusters.size(); i++) {
409  clusters[i].calculateCenter();
410 
411  if (clusters[i].clusterSize > 1) {
412  hitsClustered++;
413 
414  if (_ignoreClusters || clusters[i].clusterSize > 3) {
415  clusters.erase(clusters.begin() + i);
416  /*
417  * this is important! when you erase cluster i, cluster i+1 becomes cluster i, but the first i
418  * becomes i+1 itself.
419  * that means, cluster i (former i+1) never gets checked in the first line of the outer for loop!
420  */
421  i--;
422  }
423  }
424  else {
425  hitsSinglePixel++;
426  }
427  }
428  return pixelHit(hitSensorId, clusters[0].centerCol, clusters[0].centerRow);
429 
430 }
431 
433  int firstSensorId, secondSensorId;
434  firstSensorId = candidate.getId1();
435  secondSensorId = candidate.getId2();
436 
437  //same sensor hit?
438  if (firstSensorId == secondSensorId) {
439  return false;
440  }
441  return helper->isOverlappingArea(firstSensorId, secondSensorId);
442 }
443 
445 }
446 
int row
Definition: anaLmdDigi.C:67
Int_t GetPixelRow() const
virtual InitStatus ReInit()
printf("RealTime=%f seconds, CpuTime=%f seconds\n", rtime, ctime)
Int_t GetClusterSize() const
Definition: PndSdsCluster.h:39
Int_t GetSensorID() const
Definition: PndSdsDigi.h:59
cout<< "-----------------------------------------------> Quarter VOLUME<<endl;name="QuarterShape";QuarterShape=newTGeoArb8(name,dz,vertQuar);name="Quarter4Vol";TStringmedium="air";QuarterVol=newTGeoVolumeAssembly(name);name="SubunitShape";SubunitShape=newTGeoArb8(name,dz,vertSub);TStringmedium="air";name="SubunitVol";name1="SubunitVol1";name2="SubunitVol2";name3="SubunitVol3";name4="SubunitVol4";name5="SubunitVol5";name6="SubunitVol6";name7="SubunitVol7";name8="SubunitVol8";name9="SubunitVol9";SubunitVol=newTGeoVolumeAssembly(name);SubunitVol1=newTGeoVolumeAssembly(name1);SubunitVol2=newTGeoVolumeAssembly(name2);SubunitVol3=newTGeoVolumeAssembly(name3);SubunitVol4=newTGeoVolumeAssembly(name4);SubunitVol5=newTGeoVolumeAssembly(name5);SubunitVol6=newTGeoVolumeAssembly(name6);SubunitVol7=newTGeoVolumeAssembly(name7);SubunitVol8=newTGeoVolumeAssembly(name8);SubunitVol9=newTGeoVolumeAssembly(name9);name="BoxShape";BoxShape=newTGeoArb8(name,dz,vertBox);TStringmedium="air";name="BoxVol";BoxVol=newTGeoVolumeAssembly(name);name1="BoxVol1";name2="BoxVol2";name3="BoxVol3";name4="BoxVol4";BoxVol1=newTGeoVolumeAssembly(name1);BoxVol2=newTGeoVolumeAssembly(name2);BoxVol3=newTGeoVolumeAssembly(name3);BoxVol4=newTGeoVolumeAssembly(name4);for(Int_tb=0;b<kNumOfBoxes;b++){cout<<""<<endl;cout<<"---------------->BOXnumber:"<<b<<endl;if(b==0){trBox=newTGeoTranslation(tr+kSpaceInSub+kAlveoleThickness+0.5*kSpaceInBox,tr+kSpaceInSub+kAlveoleThickness+0.5*kSpaceInBox,0.);rotBox=newTGeoRotation();rotBox.RotateX(0.465518);rotBox.RotateY(-0.465518);}if(b==1){trBox=newTGeoTranslation(-tr-kSpaceInSub-kAlveoleThickness-0.5*kSpaceInBox,-tr-kSpaceInSub-kAlveoleThickness-0.5*kSpaceInBox,0.);rotBox=newTGeoRotation();rotBox.RotateX(-0.465518);rotBox.RotateY(0.465518);}if(b==2){trBox=newTGeoTranslation(tr+kSpaceInSub+kAlveoleThickness+0.5*kSpaceInBox,-tr-kSpaceInSub-kAlveoleThickness-0.5*kSpaceInBox,0.);rotBox=newTGeoRotation();rotBox.RotateX(-0.465518);rotBox.RotateY(-0.465518);}if(b==3){trBox=newTGeoTranslation(-tr-kSpaceInSub-kAlveoleThickness-0.5*kSpaceInBox,tr+kSpaceInSub+kAlveoleThickness+0.5*kSpaceInBox,0.);rotBox=newTGeoRotation();rotBox.RotateX(0.465518);rotBox.RotateY(0.465518);}TGeoCombiTrans*trrotBox=newTGeoCombiTrans(trBox,rotBox);name="BoxVol";name+=b;trrotBox->SetName(name);trrotBox->RegisterYourself();SubunitVol->AddNode(BoxVol,b,trrotBox);if(b==1){name+=b;trrotBox->SetName(name);trrotBox->RegisterYourself();SubunitVol1->AddNode(BoxVol,b,trrotBox);}if(b==2){name+=b;trrotBox->SetName(name);trrotBox->RegisterYourself();SubunitVol2->AddNode(BoxVol1,b,trrotBox);}if(b==0){name+=b;trrotBox-> SetName(name)
TList * GetAlignParNames()
TString fOutBranchName
Definition: PndSdsTask.h:40
Int_t i
Definition: run_full.C:25
TVector3 GetPosition() const
Definition: PndSdsHit.h:93
exit(0)
bool pairDistanceValid(PndLmdHitPair &candidate)
Int_t GetPixelColumn() const
virtual void SetParContainers()
virtual InitStatus Init()
int col
Definition: anaLmdDigi.C:67
static PndLmdGeometryHelper & getInstance()
void getStatistics(PndLmdHitPair &candidate)
pixelHit getPixelHitFromSdsHit(PndSdsHit *sdsHit)
TClonesArray * clusterCandidateArray
PndLmdGeometryHelper * helper
Int_t GetDigiIndex(Int_t i) const
Definition: PndSdsCluster.h:40
Double_t getDistance() const
bool isSane() const
Definition: PndLmdHitPair.h:75
TString fInBranchName
Definition: PndSdsTask.h:39
Int_t getId2() const
Definition: PndLmdHitPair.h:60
FairRuntimeDb * rtdb
Definition: hit_dirc.C:66
const PndLmdHitLocationInfo & getHitLocationInfo(const std::string &volume_path)
TString fFolderName
Definition: PndSdsTask.h:41
ClassImp(PndLmdPairFinderTask)
static PndGeoHandling * Instance()
TString name
Int_t getId1() const
Definition: PndLmdHitPair.h:57
void setPixelHits(double col1, double row1, double col2, double row2)
Definition: PndLmdHitPair.h:99
void setOverlapId(Int_t overlapId)
void calculateDistance()
Data class to store the digi output of a pixel module.
Int_t GetClusterIndex() const
Definition: PndSdsHit.h:94
Int_t GetSensorID() const
Definition: PndSdsHit.h:90
int getOverlapIdFromSensorIDs(int id1, int id2)
bool candHitsOverlappingArea(const PndLmdHitPair &candidate)
bool isOverlappingArea(const int id1, const int id2)
void PrintPair() const
virtual void Exec(Option_t *opt)