CMS 3D CMS Logo

HFGflash.cc
Go to the documentation of this file.
2 
3 #include "G4VPhysicalVolume.hh"
4 #include "G4Step.hh"
5 #include "G4Track.hh"
6 #include "G4Navigator.hh"
7 #include "G4NavigationHistory.hh"
8 #include "CLHEP/Units/PhysicalConstants.h"
9 #include "CLHEP/Units/SystemOfUnits.h"
10 
11 #include "Randomize.hh"
12 #include "G4TransportationManager.hh"
13 #include "G4VPhysicalVolume.hh"
14 #include "G4LogicalVolume.hh"
15 #include "G4VSensitiveDetector.hh"
16 #include "G4EventManager.hh"
17 #include "G4SteppingManager.hh"
18 #include "G4FastTrack.hh"
19 #include "G4ParticleTable.hh"
20 
21 #include "CLHEP/GenericFunctions/IncompleteGamma.hh"
22 
26 
29 
30 #include "CLHEP/Units/GlobalPhysicalConstants.h"
31 #include "CLHEP/Units/GlobalSystemOfUnits.h"
32 
33 #include <cmath>
34 
35 //#define EDM_ML_DEBUG
36 
38  edm::ParameterSet m_HF = p.getParameter<edm::ParameterSet>("HFGflash");
39  theBField = m_HF.getUntrackedParameter<double>("BField", 3.8);
40  theWatcherOn = m_HF.getUntrackedParameter<bool>("WatcherOn", true);
41  theFillHisto = m_HF.getUntrackedParameter<bool>("FillHisto", true);
42  edm::LogVerbatim("HFShower") << "HFGFlash:: Set B-Field to " << theBField << ", WatcherOn to " << theWatcherOn
43  << " and FillHisto to " << theFillHisto;
44 
45  theHelix = std::make_unique<GflashTrajectory>();
46  theGflashStep = std::make_unique<G4Step>();
47  theGflashNavigator = std::make_unique<G4Navigator>();
48  theGflashTouchableHandle = std::make_unique<G4TouchableHistory>();
49 
50 #ifdef EDM_ML_DEBUG
51  if (theFillHisto) {
53  if (tfile.isAvailable()) {
54  TFileDirectory showerDir = tfile->mkdir("GflashEMShowerProfile");
55 
56  em_incE = showerDir.make<TH1F>("em_incE", "Incoming energy (GeV)", 500, 0, 500.);
57  em_ssp_rho =
58  showerDir.make<TH1F>("em_ssp_rho", "Shower starting position;#rho (cm);Number of Events", 100, 100.0, 200.0);
59  em_ssp_z =
60  showerDir.make<TH1F>("em_ssp_z", "Shower starting position;z (cm);Number of Events", 2000, 0.0, 2000.0);
61  em_long =
62  showerDir.make<TH1F>("em_long", "Longitudinal Profile;Radiation Length;Number of Spots", 800, 800.0, 1600.0);
63  em_lateral = showerDir.make<TH1F>("em_lateral", "Lateral Profile;Radiation Length;Moliere Radius", 100, 0.0, 5.0);
64  em_2d = showerDir.make<TH2F>("em_2d",
65  "Lateral Profile vs. Shower Depth;Radiation Length;Moliere Radius",
66  800,
67  800.0,
68  1600.0,
69  100,
70  0.0,
71  5.0);
72  em_long_sd = showerDir.make<TH1F>("em_long_sd",
73  "Longitudinal Profile in Sensitive Detector;Radiation Length;Number of Spots",
74  800,
75  800.0,
76  1600.0);
78  showerDir.make<TH1F>("em_lateral_sd",
79  "Lateral Profile vs. Shower Depth in Sensitive Detector;Radiation Length;Moliere Radius",
80  100,
81  0.0,
82  5.0);
83  em_2d_sd =
84  showerDir.make<TH2F>("em_2d_sd",
85  "Lateral Profile vs. Shower Depth in Sensitive Detector;Radiation Length;Moliere Radius",
86  800,
87  800.0,
88  1600.0,
89  100,
90  0.0,
91  5.0);
92  em_ze = showerDir.make<TH2F>(
93  "em_ze", "Profile vs. Energy;Radiation Length;Moliere Radius", 800, 800.0, 1600.0, 1000, 0.0, 1.0);
94  em_ratio = showerDir.make<TH2F>(
95  "em_ratio", "Profile vs. Energy;Radiation Length;Moliere Radius", 800, 800.0, 1600.0, 1000, 0.0, 100.0);
96  em_ratio_selected = showerDir.make<TH2F>("em_ratio_selected",
97  "Profile vs. Energy;Radiation Length;Moliere Radius",
98  800,
99  800.0,
100  1600.0,
101  1000,
102  0.0,
103  100.0);
104  em_nSpots_sd =
105  showerDir.make<TH1F>("em_nSpots_sd",
106  "Number of Gflash Spots in Sensitive Detector;Number of Spots;Number of Events",
107  100,
108  0.0,
109  100);
110  em_ze_ratio = showerDir.make<TH1F>("em_ze_ratio", "Ratio of Energy and Z Position", 1000, 0.0, 0.001);
111  } else {
112  theFillHisto = false;
113  edm::LogVerbatim("HFShower") << "HFGFlash::No file is available for saving"
114  << " histos so the flag is set to false";
115  }
116  }
117 #endif
119 }
120 
122 
123 std::vector<HFGflash::Hit> HFGflash::gfParameterization(const G4Step* aStep, bool onlyLong) {
124  double tempZCalo = 26; // Gflash::Z[jCalorimeter]
125  double hfcriticalEnergy = 0.021; // Gflash::criticalEnergy
126 
127  std::vector<HFGflash::Hit> hit;
128  HFGflash::Hit oneHit;
129 
130  auto const preStepPoint = aStep->GetPreStepPoint();
131  auto const track = aStep->GetTrack();
132 
133  // This part of code is copied from the original GFlash Fortran code.
134  // reference : hep-ex/0001020v1
135 
136  const G4double energyCutoff = 1;
137  const G4int maxNumberOfSpots = 10000000;
138 
139  G4ThreeVector showerStartingPosition = track->GetPosition() / cm;
140  G4ThreeVector showerMomentum = preStepPoint->GetMomentum() / GeV;
142 
143  const G4double invgev = 1.0 / CLHEP::GeV;
144  G4double energy = preStepPoint->GetTotalEnergy() * invgev; // energy left in GeV
145  G4double logEinc = std::log(energy);
146 
147  G4double y = energy / hfcriticalEnergy; // y = E/Ec, criticalEnergy is in GeV
148  G4double logY = std::log(y);
149 
150  G4double nSpots = 93.0 * std::log(tempZCalo) * energy; // total number of spot due linearization
151  if (energy < 1.6)
152  nSpots = 140.4 * std::log(tempZCalo) * std::pow(energy, 0.876);
153 
154  // // implementing magnetic field effects
155  double charge = track->GetStep()->GetPreStepPoint()->GetCharge();
156  theHelix->initializeTrajectory(showerMomentum, showerStartingPosition, charge, theBField);
157 
158  G4double pathLength0 = theHelix->getPathLengthAtZ(showerStartingPosition.getZ());
159  G4double pathLength = pathLength0; // this will grow along the shower development
160 
161  //--- 2.2 Fix intrinsic properties of em. showers.
162 
163  G4double fluctuatedTmax = std::log(logY - 0.7157);
164  G4double fluctuatedAlpha = std::log(0.7996 + (0.4581 + 1.8628 / tempZCalo) * logY);
165 
166  G4double sigmaTmax = 1.0 / (-1.4 + 1.26 * logY);
167  G4double sigmaAlpha = 1.0 / (-0.58 + 0.86 * logY);
168  G4double rho = 0.705 - 0.023 * logY;
169  G4double sqrtPL = std::sqrt((1.0 + rho) / 2.0);
170  G4double sqrtLE = std::sqrt((1.0 - rho) / 2.0);
171 
172  G4double norm1 = G4RandGauss::shoot();
173  G4double norm2 = G4RandGauss::shoot();
174  G4double tempTmax = fluctuatedTmax + sigmaTmax * (sqrtPL * norm1 + sqrtLE * norm2);
175  G4double tempAlpha = fluctuatedAlpha + sigmaAlpha * (sqrtPL * norm1 - sqrtLE * norm2);
176 
177  // tmax, alpha, beta : parameters of gamma distribution
178  G4double tmax = std::exp(tempTmax);
179  G4double alpha = std::exp(tempAlpha);
180  G4double beta = (alpha - 1.0) / tmax;
181 
182  if (!alpha)
183  return hit;
184  if (!beta)
185  return hit;
186  if (alpha < 0.00001)
187  return hit;
188  if (beta < 0.00001)
189  return hit;
190 
191  // spot fluctuations are added to tmax, alpha, beta
192  G4double averageTmax = logY - 0.858;
193  G4double averageAlpha = 0.21 + (0.492 + 2.38 / tempZCalo) * logY;
194  G4double spotTmax = averageTmax * (0.698 + .00212 * tempZCalo);
195  G4double spotAlpha = averageAlpha * (0.639 + .00334 * tempZCalo);
196  G4double spotBeta = (spotAlpha - 1.0) / spotTmax;
197 
198  if (!spotAlpha)
199  return hit;
200  if (!spotBeta)
201  return hit;
202  if (spotAlpha < 0.00001)
203  return hit;
204  if (spotBeta < 0.00001)
205  return hit;
206 
207 #ifdef EDM_ML_DEBUG
208  edm::LogVerbatim("HFShower") << "HFGflash: Incoming energy = " << energy << " Position (rho,z) = ("
209  << showerStartingPosition.rho() << ", " << showerStartingPosition.z() << ")";
210 
211  if (theFillHisto) {
212  em_incE->Fill(energy);
213  em_ssp_rho->Fill(showerStartingPosition.rho());
214  em_ssp_z->Fill(std::abs(showerStartingPosition.z()));
215  }
216 #endif
217  // parameters for lateral distribution and fluctuation
218  G4double z1 = 0.0251 + 0.00319 * logEinc;
219  G4double z2 = 0.1162 - 0.000381 * tempZCalo;
220 
221  G4double k1 = 0.659 - 0.00309 * tempZCalo;
222  G4double k2 = 0.645;
223  G4double k3 = -2.59;
224  G4double k4 = 0.3585 + 0.0421 * logEinc;
225 
226  G4double p1 = 2.623 - 0.00094 * tempZCalo;
227  G4double p2 = 0.401 + 0.00187 * tempZCalo;
228  G4double p3 = 1.313 - 0.0686 * logEinc;
229 
230  // // @@@ dwjang, intial tuning by comparing 20-150GeV TB data
231  // // the width of energy response is not yet tuned.
232  const G4double e25Scale = 1.03551;
233  z1 *= 9.76972e-01 - 3.85026e-01 * std::tanh(1.82790e+00 * std::log(energy) - 3.66237e+00);
234  p1 *= 0.96;
235 
236 #ifdef EDM_ML_DEBUG
237  G4int nSpots_sd = 0; // count total number of spots in SD
238 #endif
239 
240  G4double stepLengthLeft = 10000;
241  G4double zInX0 = 0.0; // shower depth in X0 unit
242  G4double deltaZInX0 = 0.0; // segment of depth in X0 unit
243  G4double deltaZ = 0.0; // segment of depth in cm
244  G4double stepLengthLeftInX0 = 0.0; // step length left in X0 unit
245 
246  const G4double divisionStepInX0 = 0.1; //step size in X0 unit
247 
248  Genfun::IncompleteGamma gammaDist;
249 
250  G4double energyInGamma = 0.0; // energy in a specific depth(z) according to Gamma distribution
251  G4double preEnergyInGamma = 0.0; // energy calculated in a previous depth
252  G4double sigmaInGamma = 0.; // sigma of energy in a specific depth(z) according to Gamma distribution
253  G4double preSigmaInGamma = 0.0; // sigma of energy in a previous depth
254 
255  //energy segment in Gamma distribution of shower in each step
256  G4double deltaEnergy = 0.0; // energy in deltaZ
257  G4int spotCounter = 0; // keep track of number of spots generated
258 
259  //step increment along the shower direction
260  G4double deltaStep = 0.0;
261 
262  // Uniqueness of G4Step is important otherwise hits won't be created.
263  G4double timeGlobal = preStepPoint->GetGlobalTime();
264 
265  theGflashNavigator->SetWorldVolume(
266  G4TransportationManager::GetTransportationManager()->GetNavigatorForTracking()->GetWorldVolume());
267 
268  // // loop for longitudinal integration
269 
270 #ifdef EDM_ML_DEBUG
271  edm::LogVerbatim("HFShower") << "HFGflash: Energy = " << energy << " Step Length Left = " << stepLengthLeft;
272 #endif
273  while (energy > 0.0 && stepLengthLeft > 0.0) {
274  stepLengthLeftInX0 = stepLengthLeft / Gflash::radLength[jCalorimeter];
275 
276  if (stepLengthLeftInX0 < divisionStepInX0) {
277  deltaZInX0 = stepLengthLeftInX0;
278  deltaZ = deltaZInX0 * Gflash::radLength[jCalorimeter];
279  stepLengthLeft = 0.0;
280  } else {
281  deltaZInX0 = divisionStepInX0;
282  deltaZ = deltaZInX0 * Gflash::radLength[jCalorimeter];
283  stepLengthLeft -= deltaZ;
284  }
285 
286  zInX0 += deltaZInX0;
287 
288 #ifdef EDM_ML_DEBUG
289  edm::LogVerbatim("HFShower") << "HFGflash: zInX0 = " << zInX0 << " spotBeta*zInX0 = " << spotBeta * zInX0;
290 #endif
291  if ((!zInX0) || (!(spotBeta * zInX0 != 0)) || (zInX0 < 0.01) || (spotBeta * zInX0 < 0.00001) ||
292  (!(zInX0 * beta != 0)) || (zInX0 * beta < 0.00001))
293  return hit;
294 
295  G4int nSpotsInStep = 0;
296 
297 #ifdef EDM_ML_DEBUG
298  edm::LogVerbatim("HFShower") << "HFGflash: Energy - Energy Cut off = " << energy - energyCutoff;
299 #endif
300 
301  if (energy > energyCutoff) {
302  preEnergyInGamma = energyInGamma;
303  gammaDist.a().setValue(alpha); //alpha
304 
305  energyInGamma = gammaDist(beta * zInX0); //beta
306  G4double energyInDeltaZ = energyInGamma - preEnergyInGamma;
307  deltaEnergy = std::min(energy, energy * energyInDeltaZ);
308 
309  preSigmaInGamma = sigmaInGamma;
310  gammaDist.a().setValue(spotAlpha); //alpha spot
311  sigmaInGamma = gammaDist(spotBeta * zInX0); //beta spot
312  nSpotsInStep = std::max(1, int(nSpots * (sigmaInGamma - preSigmaInGamma)));
313  } else {
314  deltaEnergy = energy;
315  preSigmaInGamma = sigmaInGamma;
316  nSpotsInStep = std::max(1, int(nSpots * (1.0 - preSigmaInGamma)));
317  }
318 
319  if (deltaEnergy > energy || (energy - deltaEnergy) < energyCutoff)
320  deltaEnergy = energy;
321 
322  energy -= deltaEnergy;
323 
324  if (spotCounter + nSpotsInStep > maxNumberOfSpots) {
325  nSpotsInStep = maxNumberOfSpots - spotCounter;
326  if (nSpotsInStep < 1)
327  nSpotsInStep = 1;
328  }
329 
330  // // It begins with 0.5 of deltaZ and then icreases by 1 deltaZ
331  deltaStep += 0.5 * deltaZ;
332  pathLength += deltaStep;
333  deltaStep = 0.5 * deltaZ;
334 
335  //lateral shape and fluctuations for homogenous calo.
336  G4double tScale = tmax * alpha / (alpha - 1.0) * (1.0 - std::exp(-fluctuatedAlpha));
337  G4double tau = std::min(10.0, (zInX0 - 0.5 * deltaZInX0) / tScale);
338  G4double rCore = z1 + z2 * tau;
339  G4double rTail = k1 * (std::exp(k3 * (tau - k2)) + std::exp(k4 * (tau - k2))); // @@ check RT3 sign
340  G4double p23 = (p2 - tau) / p3;
341  G4double probabilityWeight = p1 * std::exp(p23 - std::exp(p23));
342 
343  // Deposition of spots according to lateral distr.
344  // Apply absolute energy scale
345  // Convert into MeV unit
346  G4double emSpotEnergy = deltaEnergy / (nSpotsInStep * e25Scale * GeV);
347 
348 #ifdef EDM_ML_DEBUG
349  edm::LogVerbatim("HFShower") << "HFGflash: nSpotsInStep = " << nSpotsInStep;
350 #endif
351 
352  for (G4int ispot = 0; ispot < nSpotsInStep; ispot++) {
353  spotCounter++;
354  G4double u1 = G4UniformRand();
355  G4double u2 = G4UniformRand();
356  G4double rInRM = 0.0;
357 
358  if (u1 < probabilityWeight) {
359  rInRM = rCore * std::sqrt(u2 / (1.0 - u2));
360  } else {
361  rInRM = rTail * std::sqrt(u2 / (1.0 - u2));
362  }
363 
364  G4double rShower = rInRM * Gflash::rMoliere[jCalorimeter];
365 
366  //Uniform & random rotation of spot along the azimuthal angle
367  G4double azimuthalAngle = twopi * G4UniformRand();
368 
369  //Compute global position of generated spots with taking into account magnetic field
370  //Divide deltaZ into nSpotsInStep and give a spot a global position
371  G4double incrementPath = (deltaZ / nSpotsInStep) * (ispot + 0.5 - 0.5 * nSpotsInStep);
372 
373  // trajectoryPoint give a spot an imaginary point along the shower development
374  GflashTrajectoryPoint trajectoryPoint;
375  theHelix->getGflashTrajectoryPoint(trajectoryPoint, pathLength + incrementPath);
376 
377  G4ThreeVector SpotPosition0 = trajectoryPoint.getPosition() +
378  rShower * std::cos(azimuthalAngle) * trajectoryPoint.getOrthogonalUnitVector() +
379  rShower * std::sin(azimuthalAngle) * trajectoryPoint.getCrossUnitVector();
380 
382  // Convert into mm unit
383  SpotPosition0 *= cm;
384 
385  //---------------------------------------------------
386  // fill a fake step to send it to hit maker
387  //---------------------------------------------------
388 
389  // to make a different time for each fake step. (0.03 nsec is corresponding to 1cm step size)
390  timeGlobal += 0.0001 * nanosecond;
391 
392  //fill equivalent changes to a (fake) step associated with a spot
393 
394  G4double zInX0_spot = std::abs(pathLength + incrementPath - pathLength0) / Gflash::radLength[jCalorimeter];
395 
396 #ifdef EDM_ML_DEBUG
397  edm::LogVerbatim("HFShower") << "HFGflash: zInX0_spot,emSpotEnergy/GeV =" << zInX0_spot << " , "
398  << emSpotEnergy / GeV << "emSpotEnergy/GeV =" << emSpotEnergy / GeV;
399 #endif
400 
401  if (zInX0_spot <= 0)
402  continue;
403  if (emSpotEnergy <= 0)
404  continue;
405  if (rShower / Gflash::rMoliere[jCalorimeter] <= 0)
406  continue;
407 
408  oneHit.depth = 1;
409 
410 #ifdef EDM_ML_DEBUG
411  if (theFillHisto) {
412  em_long->Fill(SpotPosition0.z() / cm, emSpotEnergy * invgev);
413  em_lateral->Fill(rShower / Gflash::rMoliere[jCalorimeter], emSpotEnergy * invgev);
414  em_2d->Fill(SpotPosition0.z() / cm, rShower / Gflash::rMoliere[jCalorimeter], emSpotEnergy * invgev);
415  }
416 #endif
417 
419  //if(SpotPosition0 == 0) continue;
420 
421  double energyratio = emSpotEnergy / (preStepPoint->GetTotalEnergy() / (nSpots * e25Scale));
422 
423  if (emSpotEnergy / GeV < 0.0001)
424  continue;
425  if (energyratio > 80)
426  continue;
427 
428  double zshift = 0;
429  if (SpotPosition0.z() > 0)
430  zshift = 18;
431  if (SpotPosition0.z() < 0)
432  zshift = -18;
433 
434  G4ThreeVector gfshift(0, 0, zshift * (pow(100, 0.1) / pow(energy, 0.1)));
435 
436  G4ThreeVector SpotPosition = gfshift + SpotPosition0;
437 
438  double LengthWeight = std::fabs(std::pow(SpotPosition0.z() / 11370, 1));
439  if (G4UniformRand() > 0.0021 * energyratio * LengthWeight)
440  continue;
441 
442  oneHit.position = SpotPosition;
443  oneHit.time = timeGlobal;
444  oneHit.edep = emSpotEnergy * invgev;
445  hit.push_back(oneHit);
446 #ifdef EDM_ML_DEBUG
447  nSpots_sd++;
448 #endif
449 
450  } // end of for spot iteration
451 
452  } // end of while for longitudinal integration
453 #ifdef EDM_ML_DEBUG
454  if (theFillHisto) {
455  em_nSpots_sd->Fill(nSpots_sd);
456  }
457 #endif
458  return hit;
459 }
Log< level::Info, true > LogVerbatim
virtual ~HFGflash()
Definition: HFGflash.cc:121
TH2F * em_ze
Definition: HFGflash.h:67
std::vector< Hit > gfParameterization(const G4Step *aStep, bool onlyLong=false)
Definition: HFGflash.cc:123
void tanh(data_T data[CONFIG_T::n_in], res_T res[CONFIG_T::n_in])
Gflash3Vector getCrossUnitVector()
TH1F * em_ssp_z
Definition: HFGflash.h:65
Sin< T >::type sin(const T &t)
Definition: Sin.h:22
constexpr int pow(int x)
Definition: conifer.h:24
Gflash::CalorimeterNumber jCalorimeter
Definition: HFGflash.h:52
G4double theBField
Definition: HFGflash.h:56
T getUntrackedParameter(std::string const &, T const &) const
bool theFillHisto
Definition: HFGflash.h:55
T * make(const Args &...args) const
make new ROOT object
const double rMoliere[kNumberCalorimeter]
static const float invgev
Definition: TimingSD.cc:32
std::unique_ptr< GflashTrajectory > theHelix
Definition: HFGflash.h:47
T sqrt(T t)
Definition: SSEVec.h:19
Definition: tfile.py:1
Cos< T >::type cos(const T &t)
Definition: Cos.h:22
TH2F * em_ratio_selected
Definition: HFGflash.h:67
Abs< T >::type abs(const T &t)
Definition: Abs.h:22
double edep
Definition: HFGflash.h:40
bool theWatcherOn
Definition: HFGflash.h:54
TH2F * em_ratio
Definition: HFGflash.h:67
TH1F * em_ze_ratio
Definition: HFGflash.h:66
HFGflash(edm::ParameterSet const &p)
Definition: HFGflash.cc:37
Gflash3Vector getOrthogonalUnitVector()
static const double tmax[3]
TH1F * em_ssp_rho
Definition: HFGflash.h:65
const double radLength[kNumberCalorimeter]
double time
Definition: HFGflash.h:39
TH1F * em_lateral_sd
Definition: HFGflash.h:66
TH1F * em_nSpots_sd
Definition: HFGflash.h:66
TH1F * em_lateral
Definition: HFGflash.h:65
TH1F * em_long
Definition: HFGflash.h:65
Gflash3Vector & getPosition()
G4ThreeVector position
Definition: HFGflash.h:37
std::unique_ptr< G4Navigator > theGflashNavigator
Definition: HFGflash.h:49
TH1F * em_incE
Definition: HFGflash.h:65
std::unique_ptr< G4TouchableHistory > theGflashTouchableHandle
Definition: HFGflash.h:50
TH1F * em_long_sd
Definition: HFGflash.h:66
TH2F * em_2d
Definition: HFGflash.h:67
std::unique_ptr< G4Step > theGflashStep
Definition: HFGflash.h:48
TH2F * em_2d_sd
Definition: HFGflash.h:67