CMS 3D CMS Logo

GflashHadronShowerProfile.cc
Go to the documentation of this file.
2 
6 
7 #include <CLHEP/GenericFunctions/IncompleteGamma.hh>
8 #include <CLHEP/GenericFunctions/LogGamma.hh>
9 #include <CLHEP/Random/RandGaussQ.h>
10 #include <CLHEP/Random/RandPoissonQ.h>
11 #include <CLHEP/Random/Randomize.h>
12 #include <CLHEP/Units/PhysicalConstants.h>
13 #include <CLHEP/Units/SystemOfUnits.h>
14 
15 #include <cmath>
16 
18  theBField = parSet.getParameter<double>("bField");
19  theGflashHcalOuter = parSet.getParameter<bool>("GflashHcalOuter");
20 
21  theShowino = new GflashShowino();
23 }
24 
26  if (theShowino)
27  delete theShowino;
28 }
29 
31  int showerType, double energy, double globalTime, double charge, Gflash3Vector &position, Gflash3Vector &momentum) {
32  // initialize GflashShowino for this track
33  theShowino->initialize(showerType, energy, globalTime, charge, position, momentum, theBField);
34 }
35 
37  // The skeleton of this method is based on the fortran code gfshow.F
38  // originally written by S. Peters and G. Grindhammer (also see NIM A290
39  // (1990) 469-488), but longitudinal parameterizations of hadron showers are
40  // significantly modified for the CMS calorimeter
41 
42  // unit convention: energy in [GeV] and length in [cm]
43  // intrinsic properties of hadronic showers (lateral shower profile)
44 
45  // The step size of showino along the helix trajectory in cm unit
46  double showerDepthR50 = 0.0;
47  bool firstHcalHit = true;
48 
49  // initial valuses that will be changed as the shower developes
50  double stepLengthLeft = theShowino->getStepLengthToOut();
51 
52  double deltaStep = 0.0;
53  double showerDepth = 0.0;
54 
56 
57  theGflashHitList.clear();
58 
59  GflashHit aHit;
60 
61  while (stepLengthLeft > 0.0) {
62  // update shower depth and stepLengthLeft
63  if (stepLengthLeft < Gflash::divisionStep) {
64  deltaStep = stepLengthLeft;
65  stepLengthLeft = 0.0;
66  } else {
67  deltaStep = Gflash::divisionStep;
68  stepLengthLeft -= deltaStep;
69  }
70 
71  showerDepth += deltaStep;
72  showerDepthR50 += deltaStep;
73 
74  // update GflashShowino
75  theShowino->updateShowino(deltaStep);
76 
77  // evaluate energy in this deltaStep along the longitudinal shower profile
78  double heightProfile = 0.;
79  double deltaEnergy = 0.;
80 
82 
83  // skip if Showino is outside envelopes
84  if (whichCalor == Gflash::kNULL)
85  continue;
86 
87  heightProfile = longitudinalProfile();
88 
89  // skip if the delta energy for this step will be very small
90  if (heightProfile < 1.00e-08)
91  continue;
92 
93  // get energy deposition for this step
94  deltaEnergy = heightProfile * Gflash::divisionStep * energyScale[whichCalor];
95  theShowino->addEnergyDeposited(deltaEnergy);
96 
97  // apply sampling fluctuation if showino is inside the sampling calorimeter
98  double hadronicFraction = 1.0;
99  double fluctuatedEnergy = deltaEnergy;
100 
101  int nSpotsInStep =
102  std::max(1, static_cast<int>(getNumberOfSpots(whichCalor) * (deltaEnergy / energyScale[whichCalor])));
103  double sampleSpotEnergy = hadronicFraction * fluctuatedEnergy / nSpotsInStep;
104 
105  // Lateral shape and fluctuations
106 
107  if ((whichCalor == Gflash::kHB || whichCalor == Gflash::kHE) && firstHcalHit) {
108  firstHcalHit = false;
109  // reset the showerDepth used in the lateral parameterization inside Hcal
110  showerDepthR50 = Gflash::divisionStep;
111  }
112 
113  // evaluate the fluctuated median of the lateral distribution, R50
114  double R50 = medianLateralArm(showerDepthR50, whichCalor);
115 
116  double hitEnergy = sampleSpotEnergy * CLHEP::GeV;
117  double hitTime = theShowino->getGlobalTime() * CLHEP::nanosecond;
118 
120 
121  for (int ispot = 0; ispot < nSpotsInStep; ispot++) {
122  // Compute global position of generated spots with taking into account
123  // magnetic field Divide deltaStep into nSpotsInStep and give a spot a
124  // global position
125  double incrementPath =
126  theShowino->getPathLength() + (deltaStep / nSpotsInStep) * (ispot + 0.5 - 0.5 * nSpotsInStep);
127 
128  // trajectoryPoint give a spot an imaginary point along the shower
129  // development
130  GflashTrajectoryPoint trajectoryPoint;
131  theShowino->getHelix()->getGflashTrajectoryPoint(trajectoryPoint, incrementPath);
132 
133  Gflash3Vector hitPosition = locateHitPosition(trajectoryPoint, R50);
134 
135  hitCalor = Gflash::getCalorimeterNumber(hitPosition);
136 
137  if (hitCalor == Gflash::kNULL)
138  continue;
139 
140  hitPosition *= CLHEP::cm;
141 
142  aHit.setTime(hitTime);
143  aHit.setEnergy(hitEnergy);
144  aHit.setPosition(hitPosition);
145  theGflashHitList.push_back(aHit);
146 
147  } // end of for spot iteration
148  } // end of while for longitudinal integration
149 
150  // HO parameterization
151 
154  // non zero ho fraction to simulate based on geant4
155  double nonzeroProb = 0.7 * fTanh(theShowino->getEnergy(), Gflash::ho_nonzero);
156  double r0 = CLHEP::HepUniformRand();
157  double leftoverE = theShowino->getEnergy() - theShowino->getEnergyDeposited();
158 
159  //@@@ nonzeroProb is not random - need further correlation for non-zero HO
160  // energy
161 
162  if (r0 < nonzeroProb && leftoverE > 0.0) {
163  // starting path Length and stepLengthLeft
165  stepLengthLeft = theShowino->getHelix()->getPathLengthAtRhoEquals(Gflash::Rmax[Gflash::kHO] + 10) - pathLength;
166  showerDepth = pathLength - theShowino->getPathLengthAtShower();
167 
168  theShowino->setPathLength(pathLength);
169 
172 
173  while (stepLengthLeft > 0.0) {
174  // update shower depth and stepLengthLeft
175  if (stepLengthLeft < Gflash::divisionStep) {
176  deltaStep = stepLengthLeft;
177  stepLengthLeft = 0.0;
178  } else {
179  deltaStep = Gflash::divisionStep;
180  stepLengthLeft -= deltaStep;
181  }
182 
183  showerDepth += deltaStep;
184 
185  // update GflashShowino
186  theShowino->updateShowino(deltaStep);
187 
188  // evaluate energy in this deltaStep along the longitudinal shower
189  // profile
190  double heightProfile = 0.;
191  double deltaEnergy = 0.;
192 
193  double hoScale = leftoverE * (pathLengthx - pathLengthy) / (pathLengthx - theShowino->getPathLengthAtShower());
194  double refDepth =
196 
197  if (refDepth > 0) {
198  heightProfile = hoProfile(theShowino->getPathLength(), refDepth);
199  deltaEnergy = heightProfile * Gflash::divisionStep * hoScale;
200  }
201 
202  int nSpotsInStep = std::max(
203  50, static_cast<int>((160. + 40 * CLHEP::RandGaussQ::shoot()) * std::log(theShowino->getEnergy()) + 50.));
204 
205  double hoFraction = 1.00;
206  double poissonProb = CLHEP::RandPoissonQ::shoot(1.0);
207 
208  double fluctuatedEnergy = deltaEnergy * poissonProb;
209  double sampleSpotEnergy = hoFraction * fluctuatedEnergy / nSpotsInStep;
210 
211  // Lateral shape and fluctuations
212 
213  // evaluate the fluctuated median of the lateral distribution, R50
214  double R50 = medianLateralArm(showerDepth, Gflash::kHB);
215 
216  double hitEnergy = sampleSpotEnergy * CLHEP::GeV;
217  double hitTime = theShowino->getGlobalTime() * CLHEP::nanosecond;
218 
219  for (int ispot = 0; ispot < nSpotsInStep; ispot++) {
220  double incrementPath =
221  theShowino->getPathLength() + (deltaStep / nSpotsInStep) * (ispot + 0.5 - 0.5 * nSpotsInStep);
222 
223  // trajectoryPoint give a spot an imaginary point along the shower
224  // development
225  GflashTrajectoryPoint trajectoryPoint;
226  theShowino->getHelix()->getGflashTrajectoryPoint(trajectoryPoint, incrementPath);
227 
228  Gflash3Vector hitPosition = locateHitPosition(trajectoryPoint, R50);
229  hitPosition *= CLHEP::cm;
230 
231  if (std::fabs(hitPosition.getZ() / CLHEP::cm) > Gflash::Zmax[Gflash::kHO])
232  continue;
233 
234  aHit.setTime(hitTime);
235  aHit.setEnergy(hitEnergy);
236  aHit.setPosition(hitPosition);
237  theGflashHitList.push_back(aHit);
238 
239  } // end of for HO spot iteration
240  } // end of while for HO longitudinal integration
241  }
242  }
243 
244  // delete theGflashNavigator;
245 }
246 
248  edm::LogInfo("SimGeneralGFlash") << "GflashHadronShowerProfile::loadParameters() "
249  << "should be implimented for each particle type";
250 }
251 
253  double lateralArm = 0.0;
254  if (kCalor != Gflash::kNULL) {
255  double showerDepthR50X = std::min(showerDepthR50 / 22.4, Gflash::maxShowerDepthforR50);
256  double R50 = lateralPar[kCalor][0] + std::max(0.0, lateralPar[kCalor][1]) * showerDepthR50X;
257  double varinanceR50 = std::pow((lateralPar[kCalor][2] + lateralPar[kCalor][3] * showerDepthR50X) * R50, 2);
258 
259  // Simulation of lognormal distribution
260 
261  if (R50 > 0) {
262  double sigmaSq = std::log(varinanceR50 / (R50 * R50) + 1.0);
263  double sigmaR50 = std::sqrt(sigmaSq);
264  double meanR50 = std::log(R50) - (sigmaSq / 2.);
265 
266  lateralArm = std::exp(meanR50 + sigmaR50 * CLHEP::RandGaussQ::shoot());
267  }
268  }
269  return lateralArm;
270 }
271 
273  // Smearing in r according to f(r)= 2.*r*R50**2/(r**2+R50**2)**2
274  double rnunif = CLHEP::HepUniformRand();
275  double rxPDF = std::sqrt(rnunif / (1. - rnunif));
276  double rShower = lateralArm * rxPDF;
277 
278  // rShower within maxLateralArmforR50
279  rShower = std::min(Gflash::maxLateralArmforR50, rShower);
280 
281  // Uniform smearing in phi
282  double azimuthalAngle = CLHEP::twopi * CLHEP::HepUniformRand();
283 
284  // actual spot position by adding a radial vector to a trajectoryPoint
285  Gflash3Vector position = point.getPosition() + rShower * std::cos(azimuthalAngle) * point.getOrthogonalUnitVector() +
286  rShower * std::sin(azimuthalAngle) * point.getCrossUnitVector();
287 
288  //@@@debugging histograms
289  if (theHisto->getStoreFlag()) {
290  theHisto->rshower->Fill(rShower);
291  theHisto->lateralx->Fill(rShower * std::cos(azimuthalAngle));
292  theHisto->lateraly->Fill(rShower * std::sin(azimuthalAngle));
293  }
294  return position;
295 }
296 
297 // double GflashHadronShowerProfile::longitudinalProfile(double showerDepth,
298 // double pathLength) {
300  double heightProfile = 0.0;
301 
303  int showerType = theShowino->getShowerType();
304  double showerDepth = theShowino->getDepth();
305  double transDepth = theShowino->getStepLengthToHcal();
306 
307  // Energy in a delta step (dz) = (energy to
308  // deposite)*[Gamma(z+dz)-Gamma(z)]*dz where the incomplete Gamma function
309  // gives an intergrate probability of the longitudinal shower up to the shower
310  // depth (z). Instead, we use approximated energy; energy in dz = (energy to
311  // deposite)*gamma(z)*dz where gamma is the Gamma-distributed probability
312  // function
313 
315 
316  if (showerType == 0 || showerType == 4) {
318  if (shiftDepth > 0) {
319  heightProfile = twoGammaProfile(longEcal, showerDepth - shiftDepth, whichCalor);
320  } else {
321  heightProfile = 0.;
322  // std::cout << "negative shiftDepth for showerType 0 " << shiftDepth
323  // << std::endl;
324  }
325  } else if (showerType == 1 || showerType == 5) {
326  if (whichCalor == Gflash::kESPM || whichCalor == Gflash::kENCA) {
327  heightProfile = twoGammaProfile(longEcal, showerDepth, whichCalor);
328  } else if (whichCalor == Gflash::kHB || whichCalor == Gflash::kHE) {
329  heightProfile = twoGammaProfile(longHcal, showerDepth - transDepth, whichCalor);
330  } else
331  heightProfile = 0.;
332  } else if (showerType == 2 || showerType == 6) {
333  // two gammas between crystal and Hcal
334  if ((showerDepth - transDepth) > 0.0) {
335  heightProfile = twoGammaProfile(longHcal, showerDepth - transDepth, Gflash::kHB);
336  } else
337  heightProfile = 0.;
338  } else if (showerType == 3 || showerType == 7) {
339  // two gammas inside Hcal
340  heightProfile = twoGammaProfile(longHcal, showerDepth, Gflash::kHB);
341  }
342 
343  return heightProfile;
344 }
345 
346 double GflashHadronShowerProfile::hoProfile(double pathLength, double refDepth) {
347  double heightProfile = 0;
348 
349  GflashTrajectoryPoint tempPoint;
350  theShowino->getHelix()->getGflashTrajectoryPoint(tempPoint, pathLength);
351 
352  double dint = 1.4 * Gflash::intLength[Gflash::kHO] * std::sin(tempPoint.getPosition().getTheta());
353  heightProfile = std::exp(-1.0 * refDepth / dint);
354 
355  return heightProfile;
356 }
357 
358 void GflashHadronShowerProfile::getFluctuationVector(double *lowTriangle, double *correlationVector) {
359  const int dim = Gflash::NPar;
360 
361  double **xr = new double *[dim];
362  double **xrho = new double *[dim];
363 
364  for (int j = 0; j < dim; j++) {
365  xr[j] = new double[dim];
366  xrho[j] = new double[dim];
367  }
368 
369  for (int i = 0; i < dim; i++) {
370  for (int j = 0; j < i + 1; j++) {
371  if (j == i)
372  xrho[i][j] = 1.0;
373  else {
374  xrho[i][j] = lowTriangle[i * (i - 1) / 2 + j];
375  xrho[j][i] = xrho[i][j];
376  }
377  }
378  }
379 
380  doCholeskyReduction(xrho, xr, dim);
381 
382  for (int i = 0; i < dim; i++) {
383  for (int j = 0; j < i + 1; j++) {
384  correlationVector[i * (i + 1) / 2 + j] = xr[i][j];
385  }
386  }
387 
388  for (int j = 0; j < dim; j++)
389  delete[] xr[j];
390  delete[] xr;
391  for (int j = 0; j < dim; j++)
392  delete[] xrho[j];
393  delete[] xrho;
394 }
395 
396 void GflashHadronShowerProfile::doCholeskyReduction(double **vv, double **cc, const int ndim) {
397  double sumCjkSquare;
398  double vjjLess;
399  double sumCikjk;
400 
401  cc[0][0] = std::sqrt(vv[0][0]);
402 
403  for (int j = 1; j < ndim; j++) {
404  cc[j][0] = vv[j][0] / cc[0][0];
405  }
406 
407  for (int j = 1; j < ndim; j++) {
408  sumCjkSquare = 0.0;
409  for (int k = 0; k < j; k++)
410  sumCjkSquare += cc[j][k] * cc[j][k];
411 
412  vjjLess = vv[j][j] - sumCjkSquare;
413 
414  // check for the case that vjjLess is negative
415  cc[j][j] = std::sqrt(std::fabs(vjjLess));
416 
417  for (int i = j + 1; i < ndim; i++) {
418  sumCikjk = 0.;
419  for (int k = 0; k < j; k++)
420  sumCikjk += cc[i][k] * cc[j][k];
421  cc[i][j] = (vv[i][j] - sumCikjk) / cc[j][j];
422  }
423  }
424 }
425 
427  // generator number of spots: energy dependent Gamma distribution of Nspots
428  // based on Geant4 replacing old parameterization of H1, int numberOfSpots =
429  // std::max( 50, static_cast<int>(80.*std::log(einc)+50.));
430 
431  double einc = theShowino->getEnergy();
432  int showerType = theShowino->getShowerType();
433 
434  int numberOfSpots = 0;
435  double nmean = 0.0;
436  double nsigma = 0.0;
437 
438  if (showerType == 0 || showerType == 1 || showerType == 4 || showerType == 5) {
439  if (kCalor == Gflash::kESPM || kCalor == Gflash::kENCA) {
440  nmean = 10000 + 5000 * log(einc);
441  nsigma = 1000;
442  }
443  if (kCalor == Gflash::kHB || kCalor == Gflash::kHE) {
444  nmean = 5000 + 2500 * log(einc);
445  nsigma = 500;
446  }
447  } else if (showerType == 2 || showerType == 3 || showerType == 6 || showerType == 7) {
448  if (kCalor == Gflash::kHB || kCalor == Gflash::kHE) {
449  nmean = 5000 + 2500 * log(einc);
450  nsigma = 500;
451  } else {
452  nmean = 10000;
453  nsigma = 1000;
454  }
455  }
456  //@@@need correlation and individual fluctuation on alphaNspots and betaNspots
457  // here: evaluating covariance should be straight forward since the
458  // distribution is 'one' Gamma
459 
460  numberOfSpots = std::max(500, static_cast<int>(nmean + nsigma * CLHEP::RandGaussQ::shoot()));
461 
462  // until we optimize the reduction scale in the number of Nspots
463 
464  if (kCalor == Gflash::kESPM || kCalor == Gflash::kENCA) {
465  numberOfSpots = static_cast<int>(numberOfSpots / 100);
466  } else {
467  numberOfSpots = static_cast<int>(numberOfSpots / 3.0);
468  }
469 
470  return numberOfSpots;
471 }
472 
473 double GflashHadronShowerProfile::fTanh(double einc, const double *par) {
474  double func = 0.0;
475  if (einc > 0.0)
476  func = par[0] + par[1] * std::tanh(par[2] * (std::log(einc) - par[3])) + par[4] * std::log(einc);
477  return func;
478 }
479 
480 double GflashHadronShowerProfile::fLnE1(double einc, const double *par) {
481  double func = 0.0;
482  if (einc > 0.0)
483  func = par[0] + par[1] * std::log(einc);
484  return func;
485 }
486 
487 double GflashHadronShowerProfile::depthScale(double ssp, double ssp0, double length) {
488  double func = 0.0;
489  if (length > 0.0)
490  func = std::pow((ssp - ssp0) / length, 2.0);
491  return func;
492 }
493 
494 double GflashHadronShowerProfile::gammaProfile(double alpha, double beta, double showerDepth, double lengthUnit) {
495  double gamma = 0.0;
496  // if(alpha > 0 && beta > 0 && lengthUnit > 0) {
497  if (showerDepth > 0.0) {
498  Genfun::LogGamma lgam;
499  double x = showerDepth * (beta / lengthUnit);
500  gamma = (beta / lengthUnit) * std::pow(x, alpha - 1.0) * std::exp(-x) / std::exp(lgam(alpha));
501  }
502  return gamma;
503 }
504 
506  double twoGamma = 0.0;
507 
508  longPar[0] = std::min(1.0, longPar[0]);
509  longPar[0] = std::max(0.0, longPar[0]);
510 
511  if (longPar[3] > 4.0 || longPar[4] > 4.0) {
512  double rfactor = 2.0 / std::max(longPar[3], longPar[4]);
513  longPar[3] = rfactor * (longPar[3] + 1.0);
514  longPar[4] *= rfactor;
515  }
516 
517  twoGamma = longPar[0] * gammaProfile(exp(longPar[1]), exp(longPar[2]), depth, Gflash::radLength[kIndex]) +
518  (1 - longPar[0]) * gammaProfile(exp(longPar[3]), exp(longPar[4]), depth, Gflash::intLength[kIndex]);
519  return twoGamma;
520 }
Gflash3Vector locateHitPosition(GflashTrajectoryPoint &point, double lateralArm)
double fTanh(double einc, const double *par)
static GflashHistogram * instance()
void setEnergy(const double energy)
Definition: GflashHit.h:17
T getParameter(std::string const &) const
Definition: ParameterSet.h:307
const double divisionStep
void tanh(data_T data[CONFIG_T::n_in], res_T res[CONFIG_T::n_in])
double lateralPar[Gflash::kNumberCalorimeter][Gflash::Nrpar]
const double Zmax[kNumberCalorimeter]
double twoGammaProfile(double *par, double depth, Gflash::CalorimeterNumber kIndex)
Gflash3Vector & getPosition()
Definition: GflashShowino.h:37
GflashTrajectory * getHelix()
Definition: GflashShowino.h:33
double medianLateralArm(double depth, Gflash::CalorimeterNumber kCalor)
uint32_t cc[maxCellsPerHit]
Definition: gpuFishbone.h:49
double getEnergy()
Definition: GflashShowino.h:27
int getShowerType()
Definition: GflashShowino.h:26
Sin< T >::type sin(const T &t)
Definition: Sin.h:22
double getPathLength()
Definition: GflashShowino.h:36
void setPosition(const Gflash3Vector &pos)
Definition: GflashHit.h:18
constexpr int pow(int x)
Definition: conifer.h:24
const double EtaMax[kNumberCalorimeter]
void doCholeskyReduction(double **cc, double **vv, const int ndim)
void addEnergyDeposited(double energy)
Definition: GflashShowino.h:44
double getStepLengthToHcal()
Definition: GflashShowino.h:31
void setTime(const double time)
Definition: GflashHit.h:16
const double ho_nonzero[5]
CalorimeterNumber getCalorimeterNumber(const Gflash3Vector &position)
double getPathLengthAtRhoEquals(double rho) const
double getPathLengthAtShower()
Definition: GflashShowino.h:29
double fLnE1(double einc, const double *par)
T sqrt(T t)
Definition: SSEVec.h:19
double getEnergyDeposited()
Definition: GflashShowino.h:38
Cos< T >::type cos(const T &t)
Definition: Cos.h:22
const double MinEnergyCutOffForHO
void setPathLength(double pathLength)
Definition: GflashShowino.h:42
double gammaProfile(double alpha, double beta, double depth, double lengthUnit)
Gflash3Vector & getPositionAtShower()
Definition: GflashShowino.h:30
const int NPar
const double intLength[kNumberCalorimeter]
void getGflashTrajectoryPoint(GflashTrajectoryPoint &point, double s) const
Log< level::Info, false > LogInfo
std::vector< GflashHit > theGflashHitList
const double maxShowerDepthforR50
double getDepth()
Definition: GflashShowino.h:39
const double radLength[kNumberCalorimeter]
GflashHadronShowerProfile(const edm::ParameterSet &parSet)
CLHEP::Hep3Vector Gflash3Vector
Definition: Gflash3Vector.h:6
double getGlobalTime()
Definition: GflashShowino.h:35
double getPathLengthOnEcal()
Definition: GflashShowino.h:28
Gflash3Vector & getPosition()
static int position[264][3]
Definition: ReadPGInfo.cc:289
const double maxLateralArmforR50
void getFluctuationVector(double *lowTriangle, double *correlationVector)
double depthScale(double ssp, double ssp0, double length)
const double Rmax[kNumberCalorimeter]
int getNumberOfSpots(Gflash::CalorimeterNumber kCalor)
double hoProfile(double pathLength, double refDepth)
double getStepLengthToOut()
Definition: GflashShowino.h:32
const double Rmin[kNumberCalorimeter]
*vegas h *****************************************************used in the default bin number in original ***version of VEGAS is ***a higher bin number might help to derive a more precise ***grade subtle point
Definition: invegas.h:5
void initialize(int showerType, double energy, double globalTime, double charge, Gflash3Vector &position, Gflash3Vector &momentum)
void initialize(int showerType, double energy, double globalTime, double charge, Gflash3Vector &position, Gflash3Vector &momentum, double magneticField)
double energyScale[Gflash::kNumberCalorimeter]
void updateShowino(double deltaStep)