CMS 3D CMS Logo

PixelTemplateSmearerBase.cc
Go to the documentation of this file.
1 
12 // SiPixel Gaussian Smearing
17 
18 // Pixel related stuff
20 
21 // Geometry
27 
28 // Famos
31 
32 // Framework (includes ESHandle<>)
36 
37 // ROOT
38 #include <TFile.h>
39 #include <TH1F.h>
40 #include <TH2F.h>
41 
42 using namespace std;
43 
44 const double microntocm = 0.0001;
45 
48  edm::ConsumesCollector& consumesCollector)
49  : TrackingRecHitAlgorithm(name, config, consumesCollector) {
50  //--- Basic stuff
51  mergeHitsOn = config.getParameter<bool>("MergeHitsOn");
52  isBarrel = config.getParameter<bool>("isBarrel");
53  int detType = (isBarrel) ? 1 : 0; // 1 for barrel, 0 for forward (or could we just promote bool into int...?)
54 
55  //--- Resolution file names.
56  theBigPixelResolutionFileName = config.getParameter<string>("BigPixelResolutionFile");
58 
59  theEdgePixelResolutionFileName = config.getParameter<string>("EdgePixelResolutionFile");
61 
62  theRegularPixelResolutionFileName = config.getParameter<string>("RegularPixelResolutionFile");
64 
65  //--- Create the resolution histogram objects, which will load the histograms
66  // and initialize random number generators.
67  //
68  int status = 0;
69  theRegularPixelResolutions = std::make_shared<PixelResolutionHistograms>(theRegularPixelResolutionFileName, "");
70  if ((status = theRegularPixelResolutions->status()) != 0) {
71  throw cms::Exception("PixelTemplateSmearerBase:")
72  << " constructing PixelResolutionHistograms file " << theRegularPixelResolutionFileName
73  << " failed with status = " << status << std::endl;
74  }
75 
76  theBigPixelResolutions = std::make_shared<PixelResolutionHistograms>(
77  theBigPixelResolutionFileName, "", detType, (!isBarrel), false, true); // can miss qBin
78  if ((status = theBigPixelResolutions->status()) != 0) {
79  throw cms::Exception("PixelTemplateSmearerBase:")
80  << " constructing PixelResolutionHistograms file " << theBigPixelResolutionFileName
81  << " failed with status = " << status << std::endl;
82  }
83 
84  theEdgePixelResolutions = std::make_shared<PixelResolutionHistograms>(
85  theEdgePixelResolutionFileName, "", detType, false, true, true); // can miss both single & qBin
86  if ((status = theEdgePixelResolutions->status()) != 0) {
87  throw cms::Exception("PixelTemplateSmearerBase:")
88  << " constructing PixelResolutionHistograms file " << theEdgePixelResolutionFileName
89  << " failed with status = " << status << std::endl;
90  }
91 
92  //--- Merging info.
93  theMergingProbabilityFileName = config.getParameter<string>("MergingProbabilityFile");
95  theMergingProbabilityFile = std::make_unique<TFile>(theMergingProbabilityFileName.c_str(), "READ");
96 
97  theMergedPixelResolutionXFileName = config.getParameter<string>("MergedPixelResolutionXFile");
99  theMergedPixelResolutionXFile = std::make_unique<TFile>(theMergedPixelResolutionXFileName.c_str(), "READ");
100 
101  theMergedPixelResolutionYFileName = config.getParameter<string>("MergedPixelResolutionYFile");
103  theMergedPixelResolutionYFile = std::make_unique<TFile>(theMergedPixelResolutionYFileName.c_str(), "READ");
104 
105  // const SiPixelTemplateDBObject & dbobject;
106  // const SiPixelTemplateDBObject dbobject; // dummy, just to make it compile &&&
107 
108  //--- Load the templates.
109  if (config.exists("templateId")) {
110  //--- Load template with ID=templateId from a local ascii file.
111  templateId = config.getParameter<int>("templateId");
112  if (templateId > 0) {
114  throw cms::Exception("PixelTemplateSmearerBase:")
115  << "SiPixel Template " << templateId << " Not Loaded Correctly!" << std::endl;
116  }
117  }
118  }
119 
120  //--- Else... The templates will be loaded from the DB...
121  // (They are needed for data and full sim MC, so in a production FastSim
122  // run, everything should already be in the DB.)
123  //
124  // But note that we can do it only at the beginning of the
125  // event. So nothing happens now.
126 }
127 
129 
130 //-------------------------------------------------------------------------------
131 // beginRun(); the templates are loaded in TrackingRecHitProducer, and unpacked
132 // into the template store. We get their references here, and use them. However,
133 // if we are loading a dedicated template ID from an ascii file just for this
134 // rechit smearing algorithm, then we use our own template store.
135 //-------------------------------------------------------------------------------
138  const SiPixelTemplateDBObject* pixelTemplateDBObjectPtr,
139  const std::vector<SiPixelTemplateStore>& tempStoreRef) {
140  //--- Check if we need to use the template from the DB (namely if
141  // id == -1). Otherwise the template has already been loaded from
142  // the ascii file in constructor, and thePixelTempRef wakes up
143  // pointing to thePixelTemp_, so then we use our own store.
144  //
145  if (templateId == -1) {
146  thePixelTempRef = &tempStoreRef; // we use the store from TrackingRecHitProducer
147  pixelTemplateDBObject_ = pixelTemplateDBObjectPtr; // needed for template<-->DetId map.
148  }
149 
150  //--- Commented code below (the DB interface) should say here, in case we need it:
151  // edm::ESHandle<SiPixelTemplateDBObject> templateDBobject;
152  // eventSetup.get<SiPixelTemplateDBObjectESProducerRcd>().get(templateDBobject);
153  // pixelTemplateDBObject_ = templateDBobject.product();
154 
155  // //--- Now that we have the DB object, load the correct templates from the DB.
156  // // (They are needed for data and full sim MC, so in a production FastSim
157  // // run, everything should already be in the DB.)
158  // if ( !SiPixelTemplate::pushfile( *pixelTemplateDBObject_ , thePixelTemp_) ) {
159  // throw cms::Exception("PixelTemplateSmearerPlugin:")
160  // <<"SiPixel Template " << templateId << " Not Loaded Correctly!"<<endl;
161  // }
162 }
163 
164 //-------------------------------------------------------------------------------
165 // Simulate one DetUnit:
166 // 1. figure out where the hits are
167 // 2. figure out which hits merge; merge them into "merge groups"
168 // 3. smear all individual (unmerged hits)
169 // 4. smear all merge groups.
170 //-------------------------------------------------------------------------------
172  std::vector<std::pair<unsigned int, const PSimHit*>>& simHitIdPairs = product->getSimHitIdPairs();
173  std::vector<const PSimHit*> simHits(simHitIdPairs.size());
174  for (unsigned int ihit = 0; ihit < simHitIdPairs.size(); ++ihit) {
175  simHits[ihit] = simHitIdPairs[ihit].second;
176  }
177 
178  RandomEngineAndDistribution const& randomEngine = getRandomEngine();
179 
180  const GeomDet* geomDet = getTrackerGeometry().idToDetUnit(product->getDetId());
181  const PixelGeomDetUnit* pixelGeomDet = dynamic_cast<const PixelGeomDetUnit*>(geomDet);
182  if (pixelGeomDet == nullptr) {
183  throw cms::Exception("FastSimulation/TrackingRecHitProducer")
184  << "The GeomDetUnit is not a PixelGeomDetUnit. This should never happen!";
185  }
186  const BoundPlane& theDetPlane = pixelGeomDet->surface();
187  const Bounds& theBounds = theDetPlane.bounds();
188  const double boundX = theBounds.width() / 2.;
189  const double boundY = theBounds.length() / 2.;
190 
191  std::vector<TrackingRecHitProduct::SimHitIdPair> listOfUnmergedHits;
192  std::vector<MergeGroup*> listOfMergeGroups;
193  int nHits = simHits.size();
194 
195  // fixed size array, 0 if hit is unmerged
196  MergeGroup* mergeGroupByHit[nHits];
197 
198  if (nHits == 0) {
199  return product;
200  } else if (nHits == 1) {
201  listOfUnmergedHits.push_back(simHitIdPairs[0]);
202  } else {
203  if (mergeHitsOn) {
204  for (int i = 0; i < nHits; ++i) {
205  //initialize this cell to a NULL pointer here
206  mergeGroupByHit[i] = nullptr;
207  }
208  for (int i = 0; i < nHits - 1; ++i) {
209  for (int j = i + 1; j < nHits; ++j) {
210  //--- Calculate the distance between hits i and j:
211  bool merged = hitsMerge(*simHitIdPairs[i].second, *simHitIdPairs[j].second);
212 
213  if (merged) {
214  // First, check if the other guy (j) is in some merge group already
215  if (mergeGroupByHit[j] != nullptr) {
216  if (mergeGroupByHit[i] == nullptr) {
217  mergeGroupByHit[i] = mergeGroupByHit[j];
218  mergeGroupByHit[i]->group.push_back(simHitIdPairs[i]);
219  mergeGroupByHit[i]->smearIt = true;
220  } else {
221  if (mergeGroupByHit[i] != mergeGroupByHit[j]) {
222  for (auto hit_it = mergeGroupByHit[j]->group.begin(); hit_it != mergeGroupByHit[j]->group.end();
223  ++hit_it) {
224  mergeGroupByHit[i]->group.push_back(*hit_it);
225  mergeGroupByHit[i]->smearIt = true;
226  }
227 
228  // Step 2: iterate over all hits, replace mgbh[j] by mgbh[i] (so that nobody points to i)
229  MergeGroup* mgbhj = mergeGroupByHit[j];
230  for (int k = 0; k < nHits; ++k) {
231  if (mgbhj == mergeGroupByHit[k]) {
232  // Hit k also uses the same merge group, tell them to switch to mgbh[i]
233  mergeGroupByHit[k] = mergeGroupByHit[i];
234  }
235  }
236  mgbhj->smearIt = false;
237  mergeGroupByHit[i]->smearIt = true;
238 
239  // Step 3 would have been to delete mgbh[j]... however, we'll do that at the end anyway.
240  // The key was to prevent mgbh[j] from being accessed further, and we have done that,
241  // since now no mergeGroupByHit[] points to mgbhj any more. Note that the above loop
242  // also set mergeGroupByHit[i] = mergeGroupByHit[j], too.
243  }
244  }
245  } else {
246  // j is not merged. Check if i is merged with another hit yet.
247  //
248  if (mergeGroupByHit[i] == nullptr) {
249  // This is the first time we realized i is merged with any
250  // other hit. Create a new merge group for i and j
251  mergeGroupByHit[i] = new MergeGroup();
252  listOfMergeGroups.push_back(mergeGroupByHit[i]); // keep track of it
253  //
254  // Add hit i as the first to its own merge group
255  // (simHits[i] is a const pointer to PSimHit).
256  mergeGroupByHit[i]->group.push_back(simHitIdPairs[i]);
257  mergeGroupByHit[i]->smearIt = true;
258  }
259  //--- Add hit j as well
260  mergeGroupByHit[i]->group.push_back(simHitIdPairs[j]);
261  mergeGroupByHit[i]->smearIt = true;
262 
263  mergeGroupByHit[j] = mergeGroupByHit[i];
264 
265  } // --- end of else if ( j has merge group )
266 
267  } //--- end of if (merged)
268 
269  } //--- end of loop over j
270 
271  //--- At this point, there are two possibilities. Either hit i
272  // was already chosen to be merged with some hit prior to it,
273  // or the loop over j found another merged hit. In either
274  // case, if mergeGroupByHit[i] is empty, then the hit is
275  // unmerged.
276  //
277  if (mergeGroupByHit[i] == nullptr) {
278  //--- Keep track of it.
279  listOfUnmergedHits.push_back(simHitIdPairs[i]);
280  }
281  } //--- end of loop over i
282  } // --- end of if (mergeHitsOn)
283  else {
284  // Now we've turned off hit merging, so all hits should be pushed
285  // back to listOfUnmergedHits
286  for (int i = 0; i < nHits; ++i) {
287  listOfUnmergedHits.push_back(simHitIdPairs[i]);
288  }
289  }
290  } // --- end of if (nHits == 1) else {...}
291 
292  //--- We now have two lists: a list of hits that are unmerged, and
293  // the list of merge groups. Process each separately.
294  //
295  product = processUnmergedHits(listOfUnmergedHits, product, pixelGeomDet, boundX, boundY, &randomEngine);
296 
297  product = processMergeGroups(listOfMergeGroups, product, pixelGeomDet, boundX, boundY, &randomEngine);
298 
299  //--- We're done with this det unit, and ought to clean up used
300  // memory. We don't own the PSimHits, and the vector of
301  // listOfUnmergedHits simply goes out of scope. However, we
302  // created the MergeGroups and thus we need to get rid of them.
303  //
304  for (auto mg_it = listOfMergeGroups.begin(); mg_it != listOfMergeGroups.end(); ++mg_it) {
305  delete *mg_it; // each MergeGroup is deleted; its ptrs to PSimHits we do not own...
306  }
307 
308  return product;
309 }
310 
311 //------------------------------------------------------------------------------
312 // Smear one hit. The main action is in here.
313 //------------------------------------------------------------------------------
315  const PixelGeomDetUnit* detUnit,
316  const double boundX,
317  const double boundY,
318  RandomEngineAndDistribution const* random) const {
319  //--- At the beginning the position is the Local Point in the local pixel module reference frame
320  // same code as in PixelCPEBase
321  //
322  LocalVector localDir = simHit.momentumAtEntry(); // don't need .unit(), we will take the ratio
323  float locx = localDir.x();
324  float locy = localDir.y();
325  float locz = localDir.z();
326 
327  //--- cotangent of local angles \alpha and \beta.
328  // alpha: angle with respect to local x axis in local (x,z) plane
329  // beta: angle with respect to local y axis in local (y,z) plane
330  //
331  float cotalpha = locx / locz;
332  float cotbeta = locy / locz;
333 
334  //--- Save the original signs of cot\alpha and cot\beta
335  int signOfCotalpha = (cotalpha < 0) ? -1 : 1; // sign(cotalpha);
336  int signOfCotbeta = (cotbeta < 0) ? -1 : 1; // sign(cotbeta);
337  //
338  //--- Use absolute values to find the templates from the list
339  cotalpha *= signOfCotalpha; // = abs(cotalpha)
340  cotbeta *= signOfCotbeta; // = abs(cotbeta)
341 
342  LogDebug("SmearHit") << "LocalVector=" << locx << "," << locy << "," << locz << " momentum=" << localDir.mag()
343  << " cotalpha=" << cotalpha << ", cotbeta=" << cotbeta;
344 
345  const PixelTopology* theSpecificTopology = &(detUnit->specificType().specificTopology());
346  const RectangularPixelTopology* rectPixelTopology = static_cast<const RectangularPixelTopology*>(theSpecificTopology);
347 
348  const int nrows = theSpecificTopology->nrows();
349  const int ncolumns = theSpecificTopology->ncolumns();
350 
351  const Local3DPoint lp = simHit.localPosition();
352  //Transform local position to measurement position
353  const MeasurementPoint mp = rectPixelTopology->measurementPosition(lp);
354  float mpy = mp.y();
355  float mpx = mp.x();
356  //Get the center of the struck pixel in measurement position
357  float pixelCenterY = 0.5 + (int)mpy;
358  float pixelCenterX = 0.5 + (int)mpx;
359 
360  const MeasurementPoint mpCenter(pixelCenterX, pixelCenterY);
361  //Transform the center of the struck pixel back into local position
362  const Local3DPoint lpCenter = rectPixelTopology->localPosition(mpCenter);
363 
364  //Get the relative position of struck point to the center of the struck pixel
365  float xtrk = lp.x() - lpCenter.x();
366  float ytrk = lp.y() - lpCenter.y();
367  //Pixel Y, X pitch
368  const float ysize = {0.015}, xsize = {0.01};
369  //Variables for SiPixelTemplate input, see SiPixelTemplate reco
370  float yhit = 20. + 8. * (ytrk / ysize);
371  float xhit = 20. + 8. * (xtrk / xsize);
372  int ybin = (int)yhit;
373  int xbin = (int)xhit;
374  float yfrac = yhit - (float)ybin;
375  float xfrac = xhit - (float)xbin;
376  //Protect againt ybin, xbin being outside of range [0-39] // &&& Why limit of 39?
377  if (ybin < 0)
378  ybin = 0;
379  if (ybin > 39)
380  ybin = 39;
381  if (xbin < 0)
382  xbin = 0;
383  if (xbin > 39)
384  xbin = 39;
385 
386  int ID = templateId;
387  if (templateId == -1) {
388  // We have loaded the whole template set from the DB,
389  // so ask the DB object to find us the right one.
390  ID = pixelTemplateDBObject_->getTemplateID(detUnit->geographicalId()); // need uint32_t detid
391  // theDetParam.theDet->geographicalId());
392  }
393 
394  //--- Make the template object
396 
397  //--- Produce the template that corresponds to our local angles.
398  templ.interpolate(ID, cotalpha, cotbeta);
399 
400  //Variables for SiPixelTemplate output
401  //qBin -- normalized pixel charge deposition
402  float qbin_frac[4];
403  //Single pixel cluster projection possibility
404  float ny1_frac, ny2_frac, nx1_frac, nx2_frac;
405  bool singlex = false, singley = false;
406  templ.qbin_dist(ID, cotalpha, cotbeta, qbin_frac, ny1_frac, ny2_frac, nx1_frac, nx2_frac);
407  int nqbin;
408 
409  double xsizeProbability = random->flatShoot();
410  double ysizeProbability = random->flatShoot();
411  bool hitbigx = rectPixelTopology->isItBigPixelInX((int)mpx); // pixel we hit in x
412  bool hitbigy = rectPixelTopology->isItBigPixelInY((int)mpy); // pixel we hit in y
413 
414  if (hitbigx)
415  if (xsizeProbability < nx2_frac)
416  singlex = true;
417  else
418  singlex = false;
419  else if (xsizeProbability < nx1_frac)
420  singlex = true;
421  else
422  singlex = false;
423 
424  if (hitbigy)
425  if (ysizeProbability < ny2_frac)
426  singley = true;
427  else
428  singley = false;
429  else if (ysizeProbability < ny1_frac)
430  singley = true;
431  else
432  singley = false;
433 
434  // random multiplicity for alpha and beta
435  double qbinProbability = random->flatShoot();
436  for (int i = 0; i < 4; ++i) {
437  nqbin = i;
438  if (qbinProbability < qbin_frac[i]) {
439  break;
440  }
441  }
442 
443  //Store interpolated pixel cluster profile
444  //BYSIZE, BXSIZE, const definition from SiPixelTemplate
445  float ytempl[41][BYSIZE] = {{0}}, xtempl[41][BXSIZE] = {{0}};
446  templ.ytemp(0, 40, ytempl);
447  templ.xtemp(0, 40, xtempl);
448 
449  std::vector<double> ytemp(BYSIZE);
450  for (int i = 0; i < BYSIZE; ++i) {
451  ytemp[i] = (1. - yfrac) * ytempl[ybin][i] + yfrac * ytempl[ybin + 1][i];
452  }
453 
454  std::vector<double> xtemp(BXSIZE);
455  for (int i = 0; i < BXSIZE; ++i) {
456  xtemp[i] = (1. - xfrac) * xtempl[xbin][i] + xfrac * xtempl[xbin + 1][i];
457  }
458 
459  //Pixel readout threshold
460  const float qThreshold = templ.s50() * 2.0;
461 
462  //Cut away pixels below readout threshold
463  //For cluster lengths calculation
464  int offsetX1 = 0, offsetX2 = 0, offsetY1 = 0, offsetY2 = 0;
465  int firstY, lastY, firstX, lastX;
466  for (firstY = 0; firstY < BYSIZE; ++firstY) {
467  bool yCluster = ytemp[firstY] > qThreshold;
468  if (yCluster) {
469  offsetY1 = BHY - firstY;
470  break;
471  }
472  }
473  for (lastY = firstY; lastY < BYSIZE; ++lastY) {
474  bool yCluster = ytemp[lastY] > qThreshold;
475  if (!yCluster) {
476  lastY = lastY - 1;
477  offsetY2 = lastY - BHY;
478  break;
479  }
480  }
481 
482  for (firstX = 0; firstX < BXSIZE; ++firstX) {
483  bool xCluster = xtemp[firstX] > qThreshold;
484  if (xCluster) {
485  offsetX1 = BHX - firstX;
486  break;
487  }
488  }
489  for (lastX = firstX; lastX < BXSIZE; ++lastX) {
490  bool xCluster = xtemp[lastX] > qThreshold;
491  if (!xCluster) {
492  lastX = lastX - 1;
493  offsetX2 = lastX - BHX;
494  break;
495  }
496  }
497 
498  //--- Prepare to return results
499  Local3DPoint thePosition;
500  double theShiftInX;
501  double theShiftInY;
502  double theShiftInZ;
503  LocalError theError;
504  double theErrorX;
505  double theErrorY;
506 
507  //------------------------------
508  // Check if the cluster is near an edge. If it protrudes
509  // outside the edge of the sensor, the truncate it and it will
510  // get significantly messed up.
511  //------------------------------
512  bool edge, edgex, edgey;
513  // bool bigx, bigy;
514 
515  int firstPixelInX = (int)mpx - offsetX1;
516  int firstPixelInY = (int)mpy - offsetY1;
517  int lastPixelInX = (int)mpx + offsetX2;
518  int lastPixelInY = (int)mpy + offsetY2;
519  firstPixelInX = (firstPixelInX >= 0) ? firstPixelInX : 0;
520  firstPixelInY = (firstPixelInY >= 0) ? firstPixelInY : 0;
521  lastPixelInX = (lastPixelInX < nrows) ? lastPixelInX : nrows - 1;
522  lastPixelInY = (lastPixelInY < ncolumns) ? lastPixelInY : ncolumns - 1;
523 
524  edgex = rectPixelTopology->isItEdgePixelInX(firstPixelInX) || rectPixelTopology->isItEdgePixelInX(lastPixelInX);
525  edgey = rectPixelTopology->isItEdgePixelInY(firstPixelInY) || rectPixelTopology->isItEdgePixelInY(lastPixelInY);
526  edge = edgex || edgey;
527 
528  // bigx = rectPixelTopology->isItBigPixelInX( firstPixelInX ) || rectPixelTopology->isItBigPixelInX( lastPixelInX );
529  // bigy = rectPixelTopology->isItBigPixelInY( firstPixelInY ) || rectPixelTopology->isItBigPixelInY( lastPixelInY );
530  bool hasBigPixelInX = rectPixelTopology->containsBigPixelInX(firstPixelInX, lastPixelInX);
531  bool hasBigPixelInY = rectPixelTopology->containsBigPixelInY(firstPixelInY, lastPixelInY);
532 
533  //Variables for SiPixelTemplate pixel hit error output
534  float sigmay, sigmax, sy1, sy2, sx1, sx2;
535  templ.temperrors(ID,
536  cotalpha,
537  cotbeta,
538  nqbin, // inputs
539  sigmay,
540  sigmax,
541  sy1,
542  sy2,
543  sx1,
544  sx2 // outputs
545  );
546 
547  if (edge) {
548  if (edgex && !edgey) {
549  theErrorX = 23.0 * microntocm;
550  theErrorY = 39.0 * microntocm;
551  } else if (!edgex && edgey) {
552  theErrorX = 24.0 * microntocm;
553  theErrorY = 96.0 * microntocm;
554  } else {
555  theErrorX = 31.0 * microntocm;
556  theErrorY = 90.0 * microntocm;
557  }
558  } else {
559  if (singlex) {
560  if (hitbigx) {
561  theErrorX = sx2 * microntocm;
562  } else {
563  theErrorX = sx1 * microntocm;
564  }
565  } else {
566  theErrorX = sigmax * microntocm;
567  }
568  if (singley) {
569  if (hitbigy) {
570  theErrorY = sy2 * microntocm;
571  } else {
572  theErrorY = sy1 * microntocm;
573  }
574  } else {
575  theErrorY = sigmay * microntocm;
576  }
577  }
578 
579  //add misalignment error
580  const TrackerGeomDet* misalignmentDetUnit = getMisalignedGeometry().idToDet(detUnit->geographicalId());
581  const LocalError& alignmentError = misalignmentDetUnit->localAlignmentError();
582  if (alignmentError.valid()) {
583  theError = LocalError(
584  theErrorX * theErrorX + alignmentError.xx(), alignmentError.xy(), theErrorY * theErrorY + alignmentError.yy());
585  } else {
586  theError = LocalError(theErrorX * theErrorX, 0.0, theErrorY * theErrorY);
587  }
588 
589  // Local Error is 2D: (xx,xy,yy), square of sigma in first an third position
590  // as for resolution matrix
591 
592  //--- Next, we need to generate the smeared position. First we need to figure
593  // out which kind of histograms we are supposed to use for this particular hit.
594  // These are pointers to the set of histograms used to generate the rec hit
595  // positions. (We need to handle X and Y separately.)
596  shared_ptr<PixelResolutionHistograms> resHistsX = nullptr;
597  shared_ptr<PixelResolutionHistograms> resHistsY = nullptr;
598 
599  if (edge) {
600  resHistsX = resHistsY = theEdgePixelResolutions;
601  singlex = singley = false; // no single resolutions for Edge
602  } else {
603  //--- Decide resolution histogram set for X
604  if ((singlex && hitbigx) || (isBarrel && hasBigPixelInX)) {
605  resHistsX = theBigPixelResolutions;
606  } else {
607  resHistsX = theRegularPixelResolutions;
608  }
609  //--- Decide resolution histogram set for Y
610  if ((singley && hitbigy) || (isBarrel && hasBigPixelInY)) {
611  resHistsY = theBigPixelResolutions;
612  } else {
613  resHistsY = theRegularPixelResolutions;
614  }
615  }
616 
617  //--- Get generators, separately for X and for Y.
618  const SimpleHistogramGenerator* xgen = resHistsX->getGeneratorX(cotalpha, cotbeta, nqbin, singlex);
619  const SimpleHistogramGenerator* ygen = resHistsY->getGeneratorY(cotalpha, cotbeta, nqbin, singley);
620 
621  //--- Check if we found a histogram. If nullptr, then throw up.
622  if (!xgen || !ygen) {
623  throw cms::Exception("FastSimulation/TrackingRecHitProducer")
624  << "Histogram (cot\alpha=" << cotalpha << ", cot\beta=" << cotbeta << ", nQbin=" << nqbin
625  << ") was not found for PixelTemplateSmearer. Check if the smearing resolution histogram exists.";
626  }
627 
628  //--- Smear the hit Position. We do it in the do-while loop in order to
629  //--- allow multiple tries, in case we generate a rec hit which is outside
630  //--- of the boundaries of the sensor.
631  unsigned int retry = 0;
632 
633  do {
634  // Generate the position (x,y of the rec hit).
635  theShiftInX = xgen->generate(random);
636  theShiftInY = ygen->generate(random);
637 
638  // Now multiply by the sign of the cotangent of appropriate angle
639  theShiftInX *= signOfCotalpha;
640  theShiftInY *= signOfCotbeta;
641 
642  theShiftInZ = 0.0; // set to the mid-plane of the sensor.
643 
644  thePosition = Local3DPoint(simHit.localPosition().x() + theShiftInX,
645  simHit.localPosition().y() + theShiftInY,
646  simHit.localPosition().z() + theShiftInZ);
647  retry++;
648  if (retry > 10) {
649  // If we tried to generate thePosition, and it's out of the bounds
650  // for 10 times, then take and return the simHit's location.
651  thePosition = Local3DPoint(simHit.localPosition().x(), simHit.localPosition().y(), simHit.localPosition().z());
652  break;
653  }
654  } while (fabs(thePosition.x()) > boundX || fabs(thePosition.y()) > boundY);
655 
656  FastSingleTrackerRecHit recHit(thePosition, theError, *detUnit, fastTrackerRecHitType::siPixel);
657  return recHit;
658 }
659 
660 //------------------------------------------------------------------------------
661 // Smear all umerged hits on this DetUnit
662 //------------------------------------------------------------------------------
664  std::vector<TrackingRecHitProduct::SimHitIdPair>& unmergedHits,
665  TrackingRecHitProductPtr product,
666  const PixelGeomDetUnit* detUnit,
667  const double boundX,
668  const double boundY,
669  RandomEngineAndDistribution const* random) const {
670  for (auto simHitIdPair : unmergedHits) {
671  FastSingleTrackerRecHit recHit = smearHit(*simHitIdPair.second, detUnit, boundX, boundY, random);
672  product->addRecHit(recHit, {simHitIdPair});
673  }
674  return product;
675 }
676 
677 //------------------------------------------------------------------------------
678 // Smear all MERGED hits on this DetUnit
679 //------------------------------------------------------------------------------
681  TrackingRecHitProductPtr product,
682  const PixelGeomDetUnit* detUnit,
683  const double boundX,
684  const double boundY,
685  RandomEngineAndDistribution const* random) const {
686  for (auto mg_it = mergeGroups.begin(); mg_it != mergeGroups.end(); ++mg_it) {
687  if ((*mg_it)->smearIt) {
688  FastSingleTrackerRecHit recHit = smearMergeGroup(*mg_it, detUnit, boundX, boundY, random);
689  product->addRecHit(recHit, (*mg_it)->group);
690  }
691  }
692  return product;
693 }
694 
695 //------------------------------------------------------------------------------
696 // Smear all hits MERGED together. This is called a MergeGroup.
697 //------------------------------------------------------------------------------
699  const PixelGeomDetUnit* detUnit,
700  const double boundX,
701  const double boundY,
702  RandomEngineAndDistribution const* random) const {
703  float loccx = 0;
704  float loccy = 0;
705  float loccz = 0;
706  float nHit = 0;
707  float locpx = 0;
708  float locpy = 0;
709  float locpz = 0;
710 
711  for (auto hit_it = mg->group.begin(); hit_it != mg->group.end(); ++hit_it) {
712  const PSimHit simHit = *hit_it->second;
713  //getting local momentum and adding all of the hits' momentums up
714  LocalVector localDir = simHit.momentumAtEntry().unit();
715  loccx += localDir.x();
716  loccy += localDir.y();
717  loccz += localDir.z();
718  //getting local position and adding all of the hits' positions up
719  const Local3DPoint lpos = simHit.localPosition();
720  locpx += lpos.x();
721  locpy += lpos.y();
722  locpz += lpos.z();
723  //counting how many sim hits are in the merge group
724  nHit += 1;
725  }
726  //averaging the momentums by diving momentums added up/number of hits
727  float locx = loccx / nHit;
728  float locy = loccy / nHit;
729  float locz = loccz / nHit;
730 
731  //--- cotangent of local angles \alpha and \beta.
732  // alpha: angle with respect to local x axis in local (x,z) plane
733  // beta: angle with respect to local y axis in local (y,z) plane
734  //
735  float cotalpha = locx / locz;
736  float cotbeta = locy / locz;
737 
738  //--- Save the original signs of cot\alpha and cot\beta
739  int signOfCotalpha = (cotalpha < 0) ? -1 : 1; // sign(cotalpha);
740  int signOfCotbeta = (cotbeta < 0) ? -1 : 1; // sign(cotbeta);
741  //
742  //--- Use absolute values to find the templates from the list
743  cotalpha *= signOfCotalpha; // = abs(cotalpha)
744  cotbeta *= signOfCotbeta; // = abs(cotbeta)
745 
746  float lpx = locpx / nHit;
747  float lpy = locpy / nHit;
748  float lpz = locpz / nHit;
749 
750  //Get the relative position of struck point to the center of the struck pixel
751  float xtrk = lpx;
752  float ytrk = lpy;
753  //Pixel Y, X pitch
754  const float ysize = {0.015}, xsize = {0.01};
755  //Variables for SiPixelTemplate input, see SiPixelTemplate reco
756  float yhit = 20. + 8. * (ytrk / ysize);
757  float xhit = 20. + 8. * (xtrk / xsize);
758  int ybin = (int)yhit;
759  int xbin = (int)xhit;
760  float yfrac = yhit - (float)ybin;
761  float xfrac = xhit - (float)xbin;
762  // Protect againt ybin, xbin being outside of range [0-39]
763  if (ybin < 0)
764  ybin = 0;
765  if (ybin > 39)
766  ybin = 39;
767  if (xbin < 0)
768  xbin = 0;
769  if (xbin > 39)
770  xbin = 39;
771 
772  int ID = templateId;
773  if (templateId == -1) {
774  // We have loaded the whole template set from the DB,
775  // so ask the DB object to find us the right one.
776  ID = pixelTemplateDBObject_->getTemplateID(detUnit->geographicalId()); // need uint32_t detid
777  // theDetParam.theDet->geographicalId());
778  }
779 
780  //--- Make the template object
782 
783  //--- Produce the template that corresponds to our local angles.
784  templ.interpolate(ID, cotalpha, cotbeta);
785 
786  // Variables for SiPixelTemplate output
787  // qBin -- normalized pixel charge deposition
788  float qbin_frac[4];
789  // Single pixel cluster projection possibility
790  float ny1_frac, ny2_frac, nx1_frac, nx2_frac;
791  bool singlex = false, singley = false;
792  templ.qbin_dist(ID, cotalpha, cotbeta, qbin_frac, ny1_frac, ny2_frac, nx1_frac, nx2_frac);
793  int nqbin;
794 
795  // double xsizeProbability = random->flatShoot();
796  //double ysizeProbability = random->flatShoot();
797  bool hitbigx = false;
798  bool hitbigy = false;
799 
800  // random multiplicity for alpha and beta
801 
802  double qbinProbability = random->flatShoot();
803  for (int i = 0; i < 4; ++i) {
804  nqbin = i;
805  if (qbinProbability < qbin_frac[i])
806  break;
807  }
808 
809  //Store interpolated pixel cluster profile
810  //BYSIZE, BXSIZE, const definition from SiPixelTemplate
811  float ytempl[41][BYSIZE] = {{0}}, xtempl[41][BXSIZE] = {{0}};
812  templ.ytemp(0, 40, ytempl);
813  templ.xtemp(0, 40, xtempl);
814 
815  std::vector<double> ytemp(BYSIZE);
816  for (int i = 0; i < BYSIZE; ++i) {
817  ytemp[i] = (1. - yfrac) * ytempl[ybin][i] + yfrac * ytempl[ybin + 1][i];
818  }
819 
820  std::vector<double> xtemp(BXSIZE);
821  for (int i = 0; i < BXSIZE; ++i) {
822  xtemp[i] = (1. - xfrac) * xtempl[xbin][i] + xfrac * xtempl[xbin + 1][i];
823  }
824 
825  //--- Prepare to return results
826  Local3DPoint thePosition;
827  double theShiftInX;
828  double theShiftInY;
829  double theShiftInZ;
830  LocalError theError;
831  double theErrorX;
832  double theErrorY;
833 
834  //------------------------------
835  // Check if the cluster is near an edge. If it protrudes
836  // outside the edge of the sensor, the truncate it and it will
837  // get significantly messed up.
838  //------------------------------
839  bool edge = false;
840  bool edgex = false;
841  bool edgey = false;
842 
843  //Variables for SiPixelTemplate pixel hit error output
844  float sigmay, sigmax, sy1, sy2, sx1, sx2;
845  templ.temperrors(ID,
846  cotalpha,
847  cotbeta,
848  nqbin, // inputs
849  sigmay,
850  sigmax,
851  sy1,
852  sy2,
853  sx1,
854  sx2); // outputs
855 
856  // define private mebers --> Errors
857  if (edge) {
858  if (edgex && !edgey) {
859  theErrorX = 23.0 * microntocm;
860  theErrorY = 39.0 * microntocm;
861  } else if (!edgex && edgey) {
862  theErrorX = 24.0 * microntocm;
863  theErrorY = 96.0 * microntocm;
864  } else {
865  theErrorX = 31.0 * microntocm;
866  theErrorY = 90.0 * microntocm;
867  }
868 
869  } else {
870  if (singlex) {
871  if (hitbigx) {
872  theErrorX = sx2 * microntocm;
873  } else {
874  theErrorX = sx1 * microntocm;
875  }
876  } else {
877  theErrorX = sigmax * microntocm;
878  }
879 
880  if (singley) {
881  if (hitbigy) {
882  theErrorY = sy2 * microntocm;
883  } else {
884  theErrorY = sy1 * microntocm;
885  }
886  } else {
887  theErrorY = sigmay * microntocm;
888  }
889  }
890 
891  theError = LocalError(theErrorX * theErrorX, 0., theErrorY * theErrorY);
892 
893  unsigned int retry = 0;
894  do {
895  const SimpleHistogramGenerator* xgen =
897  const SimpleHistogramGenerator* ygen =
899 
900  // Generate the position (x,y of the rec hit).
901  theShiftInX = xgen->generate(random);
902  theShiftInY = ygen->generate(random);
903 
904  // Now multiply by the sign of the cotangent of appropriate angle
905  theShiftInX *= signOfCotalpha;
906  theShiftInY *= signOfCotbeta;
907 
908  theShiftInZ = 0.0; // set at the centre of the active area
909 
910  thePosition = Local3DPoint(lpx + theShiftInX, lpy + theShiftInY, lpz + theShiftInZ);
911 
912  retry++;
913  if (retry > 10) {
914  // If we tried to generate thePosition, and it's out of the bounds
915  // for 10 times, then take and return the simHit's location.
916  thePosition = Local3DPoint(lpx, lpy, lpz);
917  break;
918  }
919  } while (fabs(thePosition.x()) > boundX || fabs(thePosition.y()) > boundY);
920 
921  FastSingleTrackerRecHit recHit(thePosition, theError, *detUnit, fastTrackerRecHitType::siPixel);
922  return recHit;
923 }
924 
925 bool PixelTemplateSmearerBase::hitsMerge(const PSimHit& simHit1, const PSimHit& simHit2) const {
926  LocalVector localDir = simHit1.momentumAtEntry().unit();
927  float locy1 = localDir.y();
928  float locz1 = localDir.z();
929  float cotbeta = locy1 / locz1;
930  float loceta = fabs(-log((double)(-cotbeta + sqrt((double)(1. + cotbeta * cotbeta)))));
931 
932  const Local3DPoint lp1 = simHit1.localPosition();
933  const Local3DPoint lp2 = simHit2.localPosition();
934  float lpy1 = lp1.y();
935  float lpx1 = lp1.x();
936  float lpy2 = lp2.y();
937  float lpx2 = lp2.x();
938  float locdis = 10000. * sqrt(pow(lpx1 - lpx2, 2) + pow(lpy1 - lpy2, 2));
939  TH2F* probhisto = (TH2F*)theMergingProbabilityFile->Get("h2bc");
940  float prob =
941  probhisto->GetBinContent(probhisto->GetXaxis()->FindFixBin(locdis), probhisto->GetYaxis()->FindFixBin(loceta));
942  return prob > 0;
943 }
LocalPoint localPosition(const MeasurementPoint &mp) const override
#define BXSIZE
const double microntocm
virtual float length() const =0
bool interpolate(int id, float cotalpha, float cotbeta, float locBz, float locBx)
const TrackerGeomDet * idToDetUnit(DetId) const override
Return the pointer to the GeomDetUnit corresponding to a given DetId.
bool valid() const
Definition: LocalError.h:20
#define BYSIZE
std::string fullPath() const
Definition: FileInPath.cc:161
virtual int ncolumns() const =0
T z() const
Definition: PV3DBase.h:61
uint32_t ID
Definition: Definitions.h:24
TrackingRecHitProductPtr processMergeGroups(std::vector< MergeGroup *> &mergeGroups, TrackingRecHitProductPtr product, const PixelGeomDetUnit *detUnit, const double boundX, const double boundY, RandomEngineAndDistribution const *random) const
TrackingRecHitProductPtr processUnmergedHits(std::vector< TrackingRecHitProduct::SimHitIdPair > &unmergedHits, TrackingRecHitProductPtr product, const PixelGeomDetUnit *detUnit, const double boundX, const double boundY, RandomEngineAndDistribution const *random) const
virtual int nrows() const =0
const SiPixelTemplateDBObject * pixelTemplateDBObject_
bool containsBigPixelInY(int iymin, int iymax) const override
std::vector< SiPixelTemplateStore > thePixelTemp_
Definition: config.py:1
T x() const
Definition: PV2DBase.h:43
const Int_t ysize
void beginRun(edm::Run const &run, const edm::EventSetup &eventSetup, const SiPixelTemplateDBObject *pixelTemplateDBObjectPtr, const std::vector< SiPixelTemplateStore > &tempStoreRef) override
bool containsBigPixelInX(int ixmin, int ixmax) const override
T y() const
Definition: PV2DBase.h:44
const RandomEngineAndDistribution & getRandomEngine() const
U second(std::pair< T, U > const &p)
void ytemp(int fybin, int lybin, float ytemplate[41][21+4])
float yy() const
Definition: LocalError.h:24
T x() const
Definition: PV3DBase.h:59
T y() const
Definition: PV3DBase.h:60
bool isItBigPixelInX(const int ixbin) const override
T sqrt(T t)
Definition: SSEVec.h:19
std::unique_ptr< TFile > theMergingProbabilityFile
#define BHX
void temperrors(int id, float cotalpha, float cotbeta, int qBin, float &sigmay, float &sigmax, float &sy1, float &sy2, float &sx1, float &sx2)
T mag() const
Definition: PV3DBase.h:64
const TrackerGeometry & getMisalignedGeometry() const
bool isItEdgePixelInY(int iybin) const override
DetId geographicalId() const
The label of this GeomDet.
Definition: GeomDet.h:64
const TrackerGeomDet * idToDet(DetId) const override
virtual const PixelGeomDetType & specificType() const
float s50()
1/2 of the pixel threshold signal in electrons
std::shared_ptr< TrackingRecHitProduct > TrackingRecHitProductPtr
std::unique_ptr< TFile > theMergedPixelResolutionXFile
float xy() const
Definition: LocalError.h:23
bool hitsMerge(const PSimHit &simHit1, const PSimHit &simHit2) const
const Plane & surface() const
The nominal surface of the GeomDet.
Definition: GeomDet.h:37
bool isItEdgePixelInX(int ixbin) const override
void xtemp(int fxbin, int lxbin, float xtemplate[41][13+4])
void qbin_dist(int id, float cotalpha, float cotbeta, float qbin_frac[4], float &ny1_frac, float &ny2_frac, float &nx1_frac, float &nx2_frac)
Local3DPoint localPosition() const
Definition: PSimHit.h:54
short getTemplateID(const uint32_t &detid) const
const std::vector< SiPixelTemplateStore > * thePixelTempRef
#define BHY
static bool pushfile(int filenum, std::vector< SiPixelTemplateStore > &pixelTemp, std::string dir="CalibTracker/SiPixelESProducers/data/")
double generate(RandomEngineAndDistribution const *) const
The random generation.
const TrackerGeometry & getTrackerGeometry() const
LocalError const & localAlignmentError() const
Return local alligment error.
std::shared_ptr< PixelResolutionHistograms > theBigPixelResolutions
FastSingleTrackerRecHit smearHit(const PSimHit &simHit, const PixelGeomDetUnit *detUnit, const double boundX, const double boundY, RandomEngineAndDistribution const *) const
std::unique_ptr< TFile > theMergedPixelResolutionYFile
std::shared_ptr< PixelResolutionHistograms > theEdgePixelResolutions
Definition: Bounds.h:18
FastSingleTrackerRecHit smearMergeGroup(MergeGroup *mg, const PixelGeomDetUnit *detUnit, const double boundX, const double boundY, const RandomEngineAndDistribution *random) const
Vector3DBase unit() const
Definition: Vector3DBase.h:54
bool isItBigPixelInY(const int iybin) const override
double flatShoot(double xmin=0.0, double xmax=1.0) const
TupleMultiplicity< TrackerTraits > const *__restrict__ uint32_t nHits
std::shared_ptr< PixelResolutionHistograms > theRegularPixelResolutions
std::vector< TrackingRecHitProduct::SimHitIdPair > group
const Int_t xsize
LocalVector momentumAtEntry() const
The momentum of the track that produced the hit, at entry point.
Definition: PSimHit.h:57
virtual float width() const =0
virtual const TopologyType & specificTopology() const
Power< A, B >::type pow(const A &a, const B &b)
Definition: Power.h:29
float xx() const
Definition: LocalError.h:22
PixelTemplateSmearerBase(const std::string &name, const edm::ParameterSet &config, edm::ConsumesCollector &consumesCollector)
Definition: Run.h:45
#define LogDebug(id)
TrackingRecHitProductPtr process(TrackingRecHitProductPtr product) const override
MeasurementPoint measurementPosition(const LocalPoint &lp) const override
Point3DBase< float, LocalTag > Local3DPoint
Definition: LocalPoint.h:9