GGS(GenericGEANT4Simulation)Software  2.7.0
 All Data Structures Namespaces Files Functions Variables Typedefs Macros
GGSGunGeneratorAction.cpp
Go to the documentation of this file.
1 /*
2  * GGSGunGeneratorAction.cpp
3  *
4  * Created on: 09 Oct 2013
5  * Author: Nicola Mori
6  */
7 
10 // GGS headers
16 #include "utils/GGSSmartLog.h"
17 
18 // Geant4/CLHEP headers
19 #include "G4Event.hh"
20 #include "G4IonTable.hh"
21 #include "G4ParticleDefinition.hh"
22 #include "G4ParticleGun.hh"
23 #include "G4SystemOfUnits.hh"
24 #include "G4UImanager.hh"
25 #include "Randomize.hh"
26 
27 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
28 
30 
31 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
32 
34  : _shootAxis(0, 0, 1), _acceptanceFlag(false), _rndmMinPositionFlag(false), _rndmMaxPositionFlag(false),
35  _rndmFromFlat(false), _rndmFromSphere(false), _rndmSphereCenter(0., 0., 0.), _rndmSphereCapExtRand(0.),
36  _rndmSphereCapAlpha(0.), _rndmSphereCapBeta(0.), _rndmSphereCapRotMat(G4RotationMatrix::IDENTITY),
37  _rndmSphereRadius(0.), _rndmMinEnergyFlag(false), _rndmMaxEnergyFlag(false), _spectralIndexFlag(false),
38  _rndmMinThetaFlag(false), _rndmMaxThetaFlag(false), _rndmMinPhiFlag(false), _rndmMaxPhiFlag(false),
39  _rndmPosFlag(false), _rndmDirFlag(false), _position(0., 0., 0.), _minPosition(0., 0., 0.),
40  _maxPosition(0., 0., 0.), _energy(10. * GeV), _minEnergy(10. * GeV), _maxEnergy(10. * GeV), _spectralIndex(-3.2),
41  _sinTheta(0.), _cosTheta(1.), _minThetaRand(0.), _maxThetaRand(.5), _minCos2ThetaRand(0.), _maxCos2ThetaRand(1.),
42  _sinPhi(0.), _cosPhi(1.), _minPhi(0.), _maxPhi(2 * CLHEP::pi), _direction(0., 0., 0.) {
43 
44  _SetShootingDir();
45 
46  _gunGenerator = new G4ParticleGun(1);
47  _gunGenerator->SetParticleDefinition(G4ParticleTable::GetParticleTable()->FindParticle("geantino"));
48 
49  // Create the messenger for this class
50  _messenger = new GGSGunGeneratorActionMessenger(this);
51 }
52 
53 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
54 
56  delete _gunGenerator;
57  delete _messenger;
58 }
59 
60 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
61 
62 void GGSGunGeneratorAction::SetGunParticle(const G4String &particle) {
63  if (particle == "C12") {
64  // G4ParticleTable* pTable = G4ParticleTable::GetParticleTable();
65  G4ParticleDefinition *c12 = G4ParticleTable::GetParticleTable()->GetIonTable()->GetIon(6, 12, 0.);
66  ((G4ParticleGun *)_gunGenerator)->SetParticleDefinition(c12);
67  ((G4ParticleGun *)_gunGenerator)->SetParticleCharge(6 * eplus);
68  } else if (particle == "Fe56") {
69  // G4ParticleTable* pTable = G4ParticleTable::GetParticleTable();
70  G4ParticleDefinition *fe56 = G4ParticleTable::GetParticleTable()->GetIonTable()->GetIon(26, 56, 0.);
71  ((G4ParticleGun *)_gunGenerator)->SetParticleDefinition(fe56);
72  ((G4ParticleGun *)_gunGenerator)->SetParticleCharge(26 * eplus);
73  } else
74  G4UImanager::GetUIpointer()->ApplyCommand(G4String("/gun/particle ").append(particle));
75 }
76 
77 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
78 
79 G4RotationMatrix &GGSGunGeneratorAction::_ComputeRotMatrix(double cosAlpha, double sinAlpha, double cosBeta,
80  double sinBeta) {
81 
82  // A small helper class which allows to directly specify the rotation matrix elements
83  class Rot3 : public G4RotationMatrix {
84  public:
85  void SetMatrix(double mxx, double mxy, double mxz, double myx, double myy, double myz, double mzx, double mzy,
86  double mzz) {
87  rxx = mxx;
88  rxy = mxy;
89  rxz = mxz;
90  ryx = myx;
91  ryy = myy;
92  ryz = myz;
93  rzx = mzx;
94  rzy = mzy;
95  rzz = mzz;
96  }
97  };
98 
99  static Rot3 retMatrix;
100 
101  /* The rotation is computed as the composition of the following operations (in this order):
102  *
103  * 1) rotate the vector so that beta = 0
104  * 2) rotate about the new y axis of an angle alpha
105  * 3) invert 1
106  * The matrices are:
107  *
108  * | cosb sinb 0|
109  * 1 = |-sinb cosb 0|
110  * | 0 0 1|
111  *
112  * | cosa 0 sina|
113  * 2 = | 0 1 0|
114  * |-sina 0 cosa|
115  *
116  * | cosb -sinb 0|
117  * 3 = | sinb cosb 0|
118  * | 0 0 1|
119  *
120  *
121  * The resulting matrix is obtained as M = 3*2*1.
122  */
123 
124  double xx = cosAlpha * cosBeta * cosBeta + sinBeta * sinBeta;
125  double xy = cosBeta * cosAlpha * sinBeta - cosBeta * sinBeta; // 1st row 2nd column
126  double xz = cosBeta * sinAlpha;
127  double yx = sinBeta * cosAlpha * cosBeta - sinBeta * cosBeta; // 2nd row 1st column
128  double yy = sinBeta * cosAlpha * sinBeta + cosBeta * cosBeta;
129  double yz = sinBeta * sinAlpha;
130  double zx = -sinAlpha * cosBeta;
131  double zy = -sinAlpha * sinBeta;
132  double zz = cosAlpha;
133 
134  retMatrix.SetMatrix(xx, xy, xz, yx, yy, yz, zx, zy, zz);
135 
136  return retMatrix;
137 }
138 
139 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
140 
141 void GGSGunGeneratorAction::_ResetFlat() {
142 
143  _rndmFromFlat = false;
144  _minPosition = _maxPosition = G4ThreeVector(0., 0., 0.);
145  _shootAxis = G4ThreeVector(0, 0, 1);
146 }
147 
148 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
149 
150 void GGSGunGeneratorAction::_ResetSphere() {
151 
152  _rndmFromSphere = false;
153  _rndmSphereCenter = G4ThreeVector(0., 0., 0.);
154  _rndmSphereRadius = 0;
155  _rndmSphereCapExtRand = 0.;
156  _rndmSphereCapRotMat = G4RotationMatrix::IDENTITY;
157 }
158 
159 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
160 
161 void GGSGunGeneratorAction::_SetRndmFromSurface(int surfType) {
162 
163  if (surfType == 0) { // No generation from surface
164  _ResetFlat();
165  _ResetSphere();
166  } else if (surfType == 1) { // Flat surface
167  if (_minPosition[0] < _maxPosition[0] && _minPosition[1] < _maxPosition[1] && _minPosition[2] == _maxPosition[2]) {
168  _rndmFromFlat = true;
169  _shootAxis = G4ThreeVector(0, 0, 1);
170  } else if (_minPosition[0] == _maxPosition[0] && _minPosition[1] < _maxPosition[1] &&
171  _minPosition[2] < _maxPosition[2]) {
172  _rndmFromFlat = true;
173  _shootAxis = G4ThreeVector(1, 0, 0);
174  } else if (_minPosition[0] < _maxPosition[0] && _minPosition[1] == _maxPosition[1] &&
175  _minPosition[2] < _maxPosition[2]) {
176  _rndmFromFlat = true;
177  _shootAxis = G4ThreeVector(0, 1, 0);
178  } else {
179  _rndmFromFlat = false;
180  _shootAxis = G4ThreeVector(0, 0, 1); // Default shoot axis along Z
181  }
182  if (_rndmFromFlat)
183  _rndmPosFlag = true;
184  _ResetSphere();
185  } else if (surfType == 2) { // Spherical surface
186  if (_rndmSphereRadius > 0. && _rndmSphereCapExtRand > 0.) {
187  _rndmFromSphere = true;
188  _rndmPosFlag = true;
189  _rndmSphereCapRotMat = _ComputeRotMatrix(cos(_rndmSphereCapAlpha), sin(_rndmSphereCapAlpha),
190  cos(_rndmSphereCapBeta), sin(_rndmSphereCapBeta));
191  SetMinPhi(0);
192  SetMaxPhi(360. * deg);
193  }
194  _ResetFlat();
195  }
196 }
197 
198 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
199 
200 void GGSGunGeneratorAction::_SetRndmDirFlag() {
201  if ((_rndmMinThetaFlag && _rndmMaxThetaFlag) || (_rndmMinPhiFlag && _rndmMaxPhiFlag))
202  _rndmDirFlag = true;
203  else
204  _rndmDirFlag = false;
205 }
206 
207 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
208 
209 void GGSGunGeneratorAction::_SetRndmPosFlag() {
210  if (_rndmMinPositionFlag && _rndmMaxPositionFlag)
211  _rndmPosFlag = true;
212  else
213  _rndmPosFlag = false;
214 }
215 
216 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
217 
219 
220  static const std::string routineName("GGSGunGeneratorAction::GeneratePrimaries");
221  static const G4ThreeVector xDirection(1, 0, 0);
222  static const G4ThreeVector yDirection(0, 1, 0);
223 
224  _nDiscarded = 0;
225 
226  // Initialize shooting parameters with default values
227  G4ThreeVector position(_position);
228  G4ThreeVector direction(_direction);
229  G4double energy(_energy);
230 
231  bool acceptanceCheck = true;
232  do { // Acceptance check loop
233 
234  // ++++++++++++++ Randomize direction ++++++++++++++
235  // The random direction computed here is always referred to the shooting frame.
236  // Since the shooting frame may depend on shooting point (eg., shooting
237  // from a sphere) the transformation from shooting frame to absolute
238  // frame is done after random position have been chosen.
239  if (_rndmDirFlag) {
240  G4double cosPhi(_cosPhi);
241  G4double sinPhi(_sinPhi);
242  if (_rndmMinPhiFlag && _rndmMaxPhiFlag) {
243  double phi = CLHEP::RandFlat::shoot(_minPhi, _maxPhi); // (0,2pi) or (-2pi,2pi) if shooting along -Z or -X
244  cosPhi = cos(phi);
245  sinPhi = sin(phi);
246  }
247 
248  G4double sinTheta(_sinTheta);
249  G4double cosTheta(_cosTheta);
250  if (_rndmMinThetaFlag && _rndmMaxThetaFlag) {
251  if (_rndmFromFlat || _rndmFromSphere) {
252  // To generate an isotropic flux from a flat surface, the random angle must be uniform in cos^2 theta
253  float cos2Theta = CLHEP::RandFlat::shoot(_minCos2ThetaRand, _maxCos2ThetaRand);
254  cosTheta = sqrt(cos2Theta);
255  sinTheta = sqrt(1 - cos2Theta);
256  } else {
257  // This will sample a uniform theta distribution on the sphere. This formula comes from the inverse CDF
258  // method. See eg. http://en.wikibooks.org/wiki/Mathematica/Uniform_Spherical_Distribution
259  // The form reported here is slightly different but equivalent (it can be easily seen using the
260  // identity (sin x/2)^2 = (1 - cos x)/2 ).
261  cosTheta = 1 - 2 * CLHEP::RandFlat::shoot(_minThetaRand, _maxThetaRand);
262  sinTheta = sqrt(1 - cosTheta * cosTheta);
263  }
264  }
265 
266  // Compute position std::vector and direction versor (Z is shoot axis in the shooting frame)
267  direction[0] = -sinTheta * cosPhi; // momentum direction (unitary vectors)
268  direction[1] = -sinTheta * sinPhi;
269  direction[2] = -cosTheta;
270  }
271 
272  // ++++++++++++++ Randomize position ++++++++++++++
273  if (_rndmPosFlag) {
274  if (_rndmMinPositionFlag && _rndmMaxPositionFlag) {
275  // This works for all "flat" domains (point, line, plane, parallelepiped)
276  position[0] = CLHEP::RandFlat::shoot(_minPosition(0), _maxPosition(0));
277  position[1] = CLHEP::RandFlat::shoot(_minPosition(1), _maxPosition(1));
278  position[2] = CLHEP::RandFlat::shoot(_minPosition(2), _maxPosition(2));
279  if (_rndmFromFlat) { // Transform shoot direction to absolute reference frame
280  // Transform direction if shoot axis is not the Z axis.
281  // 3rd coordinate is relative to shooting axis so it is x when shooting along X,
282  // so the coordinate transformation to go to absolute reference frame is:
283  // (y, z, x) -> (x, y, z) when shooting along X
284  // (z, x, y) -> (x, y, z) when shooting along X
285  if (_shootAxis == xDirection) {
286  double buf = direction[0];
287  direction[0] = direction[2];
288  direction[2] = direction[1];
289  direction[1] = buf;
290  } else if (_shootAxis == yDirection) {
291  double buf = direction[0];
292  direction[0] = direction[1];
293  direction[1] = direction[2];
294  direction[2] = buf;
295  }
296  }
297  } else if (_rndmFromSphere) {
298  // Randomize position on the spherical cap (in the reference frame of the generation sphere).
299  // Gamma and delta are the polar and azimuth angle of the position vector w.r.t. the
300  // sphere center.
301  float cosGamma = 1 - 2 * CLHEP::RandFlat::shoot(0., _rndmSphereCapExtRand);
302  float delta = CLHEP::RandFlat::shoot(0., 2 * CLHEP::pi);
303  float sinGamma = sqrt(1 - cosGamma * cosGamma);
304  float sinDelta = sin(delta);
305  float cosDelta = cos(delta);
306 
307  // Position vector in cap frame
308  position[0] = _rndmSphereRadius * sinGamma * cosDelta;
309  position[1] = _rndmSphereRadius * sinGamma * sinDelta;
310  position[2] = _rndmSphereRadius * cosGamma;
311 
312  // Position vector in absolute (world) frame
313  position *= _rndmSphereCapRotMat;
314  position += _rndmSphereCenter;
315 
316  // Direction vector in absolute (world) frame
317  // At this point, the direction vector is built so that the distribution of its polar angle with
318  // respect to the normal incidence is flat in cos^2 (isotropic flux). The vector coordinates have
319  // been constructed in the reference frame of the generation point on the sphere, so they must be
320  // rotated to the reference frame of the cap center and then to the world reference frame, in this
321  // order.
322  direction *= _ComputeRotMatrix(cosGamma, sinGamma, cosDelta, sinDelta); // Direction
323  direction *= _rndmSphereCapRotMat;
324  }
325  }
326 
327  // ++++++++++++++ Check acceptance ++++++++++++++
328  if (_acceptanceFlag && (_rndmPosFlag || _rndmDirFlag)) {
329  GGSDetectorConstruction *detConst =
330  (GGSDetectorConstruction *)(GGSRunManager::GetRunManager()->GetUserDetectorConstruction());
331  acceptanceCheck = detConst->GetGeometry()->IsInsideAcceptance(position, direction);
332  if (!acceptanceCheck)
333  _nDiscarded++;
334  }
335 
336  } while (!acceptanceCheck);
337 
338  // ++++++++++++++ Randomize energy ++++++++++++++
339  if (_rndmMinEnergyFlag && _rndmMaxEnergyFlag) {
340  if (_spectralIndexFlag) {
341  energy = _GenSpectrumPowerLaw(_minEnergy, _maxEnergy, _spectralIndex);
342  } else {
343  energy = CLHEP::RandFlat::shoot(_minEnergy, _maxEnergy);
344  }
345  }
346 
347  COUT(DEEPDEB) << "Generated primary:" << ENDL;
348  CCOUT(DEEPDEB) << " PDG code: " << _gunGenerator->GetParticleDefinition()->GetPDGEncoding() << ENDL;
349  CCOUT(DEEPDEB) << " position: " << position << ENDL;
350  CCOUT(DEEPDEB) << " direction: " << direction << ENDL;
351  CCOUT(DEEPDEB) << " energy: " << energy << ENDL;
352 
353  //
354  // Set values for primary particle and shoot
355  //
356  _gunGenerator->SetParticlePosition(position);
357  _gunGenerator->SetParticleMomentumDirection(direction);
358  _gunGenerator->SetParticleEnergy(energy);
359 
360  // Shoot
361  _gunGenerator->GeneratePrimaryVertex(anEvent);
362 }
363 
365  GGSParameters params;
366  params.SetParam("generator", std::string("gun"));
367 
368  params.SetParam("acceptanceCheck", _acceptanceFlag);
369 
370  // Particle
371  params.SetParam("particlePdgCode", _gunGenerator->GetParticleDefinition()->GetPDGEncoding());
372 
373  // Position
374  if (_rndmPosFlag) {
375  if (_rndmMinPositionFlag && _rndmMaxPositionFlag) {
376  params.SetParam("minPosition", std::vector<double>{_minPosition[0] / CLHEP::cm, _minPosition[1] / CLHEP::cm,
377  _minPosition[2] / CLHEP::cm});
378  params.SetParam("maxPosition", std::vector<double>{_maxPosition[0] / CLHEP::cm, _maxPosition[1] / CLHEP::cm,
379  _maxPosition[2] / CLHEP::cm});
380  if (_rndmFromFlat) {
381  params.SetParam("genPosition", std::string("plane"));
382  } else {
383  params.SetParam("genPosition", std::string("box"));
384  }
385  } else if (_rndmFromSphere) {
386  params.SetParam("genPosition", std::string("sphere"));
387  params.SetParam("sphereCenter",
388  std::vector<double>{_rndmSphereCenter[0] / CLHEP::cm, _rndmSphereCenter[1] / CLHEP::cm,
389  _rndmSphereCenter[2] / CLHEP::cm});
390  params.SetParam("sphereCapPosition",
391  std::vector<double>{_rndmSphereCapPosition[0] / CLHEP::cm, _rndmSphereCapPosition[1] / CLHEP::cm,
392  _rndmSphereCapPosition[2] / CLHEP::cm});
393  params.SetParam("sphereCapExtension", acos(-2. * _rndmSphereCapExtRand + 1) / CLHEP::rad);
394  }
395  } else {
396  params.SetParam("genPosition", std::string("point"));
397  params.SetParam("position",
398  std::vector<double>{_position[0] / CLHEP::cm, _position[1] / CLHEP::cm, _position[2] / CLHEP::cm});
399  }
400 
401  // Direction
402  if (_rndmDirFlag) {
403  bool isotropic = false;
404  if (_rndmMinPhiFlag && _rndmMaxPhiFlag) {
405  params.SetParam("minPhi", _minPhi / CLHEP::rad);
406  params.SetParam("maxPhi", _maxPhi / CLHEP::rad);
407  }
408  if (_rndmMinThetaFlag && _rndmMaxThetaFlag) {
409  params.SetParam("minTheta", acos(-2. * _minThetaRand + 1) / CLHEP::rad);
410  params.SetParam("maxTheta", acos(-2. * _maxThetaRand + 1) / CLHEP::rad);
411  if (_rndmFromFlat || _rndmFromSphere) {
412  isotropic = true;
413  }
414  }
415  if (isotropic) {
416  params.SetParam("genDirection", std::string("isotropic"));
417  } else {
418  params.SetParam("genDirection", std::string("uniform"));
419  }
420  } else {
421  params.SetParam("genDirection", std::string("fixed"));
422  params.SetParam("theta", acos(_cosTheta) / CLHEP::rad);
423  params.SetParam("phi", acos(_cosPhi) / CLHEP::rad);
424  }
425 
426  // Energy
427  if (_rndmMinEnergyFlag && _rndmMaxEnergyFlag) {
428  params.SetParam("minEnergy", _minEnergy / CLHEP::GeV);
429  params.SetParam("maxEnergy", _maxEnergy / CLHEP::GeV);
430  if (_spectralIndexFlag) {
431  params.SetParam("genSpectrum", std::string("powerLaw"));
432  params.SetParam("spectralIndex", _spectralIndex);
433  } else {
434  params.SetParam("genSpectrum", std::string("flat"));
435  }
436  } else {
437  params.SetParam("genSpectrum", std::string("monochromatic"));
438  params.SetParam("energy", _energy / CLHEP::GeV);
439  }
440 
441  return params;
442 }
443 
444 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
445 
446 // Generate spectrum power law f(E)= E^gamma (when gamma==0 then is uniform generation).
447 G4double GGSGunGeneratorAction::_GenSpectrumPowerLaw(G4double Emin, G4double Emax, G4double gamma) {
448  G4double energy;
449  // Uniform generation
450  if (gamma == 0.) {
451  energy = CLHEP::RandFlat::shoot(Emin, Emax);
452  return energy;
453  }
454  G4double alpha = 1. + gamma; // integral spectral index
455  if (alpha == 0.) {
456  energy = exp(log(Emin) + CLHEP::RandFlat::shoot(0., 1.) * (log(Emax) - log(Emin)));
457  } else {
458  if (Emin == 0.)
459  Emin = 1.E-10;
460  energy =
461  pow((CLHEP::RandFlat::shoot(0., 1.) * (pow(Emax, alpha) - pow(Emin, alpha)) + pow(Emin, alpha)), 1. / alpha);
462  }
463 
464  return energy;
465 }
GGSGunGeneratorAction()
Constructor.
#define ENDL
Definition: GGSSmartLog.h:105
#define COUT(level)
Smart log macro. It writes on stdout only if the specified verbosity level is lesser than the maximum...
Definition: GGSSmartLog.h:76
Class for GGS detector construction.
void SetMaxPhi(G4double val)
Sets the maximum value for phi.
Messenger class for gun generator action.
A single-particle generator.
void SetParam(const std::string &name, T value)
Sets a parameter.
Class for storing parameters.
Definition: GGSParameters.h:29
const GGSVGeometryConstruction * GetGeometry() const
Returns a pointer to the geometry.
#define CCOUT(level)
Smart log utility which prints no header at the beginning of the line.
Definition: GGSSmartLog.h:100
void SetGunParticle(const G4String &particle)
Sets the particle to be used by G4ParticleGun.
GGSParameters GetParameters() const
Gets the generation parameters.
static GGSRunManager * GetRunManager()
Static getter function the run manager.
#define RegisterGA(gaClassName, gaName)
Macro for registration of user generator actions.
void GeneratePrimaries(G4Event *)
GeneratePrimaries.
void SetMinPhi(G4double val)
Sets the minimum value for phi.
virtual bool IsInsideAcceptance(const G4ThreeVector &, const G4ThreeVector &) const
Checks if a particle is inside the instrument&#39;s acceptance.