GGS(GenericGEANT4Simulation)Software  2.7.1
 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::_ChangeOfBasisMatrix(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 columns of the change-of-basis matrix M from F' to F are the coordinates of the vector of the basis (X', Y',Z')
102  * of F' expressed in the frame F.
103  *
104  * | xx xy xz |
105  * M = | yx yy yz |
106  * | zx zy zz |
107  */
108 
109  // Coordinates of X' in F
110  double xx = cosAlpha * cosBeta;
111  double yx = sinBeta * cosAlpha; // 2nd row 1st column
112  double zx = -sinAlpha;
113 
114  // Coordinates of Y' in F
115  double xy = -sinBeta; // 1st row 2nd column
116  double yy = cosBeta;
117  double zy = 0;
118 
119  // Coordinates of Z' in F
120  double xz = cosBeta * sinAlpha;
121  double yz = sinBeta * sinAlpha;
122  double zz = cosAlpha;
123 
124  retMatrix.SetMatrix(xx, xy, xz, yx, yy, yz, zx, zy, zz);
125 
126  return retMatrix;
127 }
128 
129 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
130 
131 void GGSGunGeneratorAction::_ResetFlat() {
132 
133  _rndmFromFlat = false;
134  _minPosition = _maxPosition = G4ThreeVector(0., 0., 0.);
135  _shootAxis = G4ThreeVector(0, 0, 1);
136 }
137 
138 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
139 
140 void GGSGunGeneratorAction::_ResetSphere() {
141 
142  _rndmFromSphere = false;
143  _rndmSphereCenter = G4ThreeVector(0., 0., 0.);
144  _rndmSphereRadius = 0;
145  _rndmSphereCapExtRand = 0.;
146  _rndmSphereCapRotMat = G4RotationMatrix::IDENTITY;
147 }
148 
149 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
150 
151 void GGSGunGeneratorAction::_SetRndmFromSurface(int surfType) {
152 
153  if (surfType == 0) { // No generation from surface
154  _ResetFlat();
155  _ResetSphere();
156  } else if (surfType == 1) { // Flat surface
157  if (_minPosition[0] < _maxPosition[0] && _minPosition[1] < _maxPosition[1] && _minPosition[2] == _maxPosition[2]) {
158  _rndmFromFlat = true;
159  _shootAxis = G4ThreeVector(0, 0, 1);
160  } else if (_minPosition[0] == _maxPosition[0] && _minPosition[1] < _maxPosition[1] &&
161  _minPosition[2] < _maxPosition[2]) {
162  _rndmFromFlat = true;
163  _shootAxis = G4ThreeVector(1, 0, 0);
164  } else if (_minPosition[0] < _maxPosition[0] && _minPosition[1] == _maxPosition[1] &&
165  _minPosition[2] < _maxPosition[2]) {
166  _rndmFromFlat = true;
167  _shootAxis = G4ThreeVector(0, 1, 0);
168  } else {
169  _rndmFromFlat = false;
170  _shootAxis = G4ThreeVector(0, 0, 1); // Default shoot axis along Z
171  }
172  if (_rndmFromFlat)
173  _rndmPosFlag = true;
174  _ResetSphere();
175  } else if (surfType == 2) { // Spherical surface
176  if (_rndmSphereRadius > 0. && _rndmSphereCapExtRand > 0.) {
177  _rndmFromSphere = true;
178  _rndmPosFlag = true;
179  _rndmSphereCapRotMat = _ChangeOfBasisMatrix(cos(_rndmSphereCapAlpha), sin(_rndmSphereCapAlpha),
180  cos(_rndmSphereCapBeta), sin(_rndmSphereCapBeta));
181  SetMinPhi(0);
182  SetMaxPhi(360. * deg);
183  }
184  _ResetFlat();
185  }
186 }
187 
188 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
189 
190 void GGSGunGeneratorAction::_SetRndmDirFlag() {
191  if ((_rndmMinThetaFlag && _rndmMaxThetaFlag) || (_rndmMinPhiFlag && _rndmMaxPhiFlag))
192  _rndmDirFlag = true;
193  else
194  _rndmDirFlag = false;
195 }
196 
197 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
198 
199 void GGSGunGeneratorAction::_SetRndmPosFlag() {
200  if (_rndmMinPositionFlag && _rndmMaxPositionFlag)
201  _rndmPosFlag = true;
202  else
203  _rndmPosFlag = false;
204 }
205 
206 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
207 
209 
210  static const std::string routineName("GGSGunGeneratorAction::GeneratePrimaries");
211  static const G4ThreeVector xDirection(1, 0, 0);
212  static const G4ThreeVector yDirection(0, 1, 0);
213 
214  _nDiscarded = 0;
215 
216  // Initialize shooting parameters with default values
217  G4ThreeVector position(_position);
218  G4ThreeVector direction(_direction);
219  G4double energy(_energy);
220 
221  bool acceptanceCheck = true;
222  do { // Acceptance check loop
223 
224  // ++++++++++++++ Randomize direction ++++++++++++++
225  // The random direction computed here is always referred to the shooting frame.
226  // Since the shooting frame may depend on shooting point (eg., shooting
227  // from a sphere) the transformation from shooting frame to absolute
228  // frame is done after random position have been chosen.
229  if (_rndmDirFlag) {
230  G4double cosPhi(_cosPhi);
231  G4double sinPhi(_sinPhi);
232  if (_rndmMinPhiFlag && _rndmMaxPhiFlag) {
233  double phi = CLHEP::RandFlat::shoot(_minPhi, _maxPhi); // (0,2pi) or (-2pi,2pi) if shooting along -Z or -X
234  cosPhi = cos(phi);
235  sinPhi = sin(phi);
236  }
237 
238  G4double sinTheta(_sinTheta);
239  G4double cosTheta(_cosTheta);
240  if (_rndmMinThetaFlag && _rndmMaxThetaFlag) {
241  if (_rndmFromFlat || _rndmFromSphere) {
242  // To generate an isotropic flux from a flat surface, the random angle must be uniform in cos^2 theta
243  float cos2Theta = CLHEP::RandFlat::shoot(_minCos2ThetaRand, _maxCos2ThetaRand);
244  cosTheta = sqrt(cos2Theta);
245  sinTheta = sqrt(1 - cos2Theta);
246  } else {
247  // This will sample a uniform theta distribution on the sphere. This formula comes from the inverse CDF
248  // method. See eg. http://en.wikibooks.org/wiki/Mathematica/Uniform_Spherical_Distribution
249  // The form reported here is slightly different but equivalent (it can be easily seen using the
250  // identity (sin x/2)^2 = (1 - cos x)/2 ).
251  cosTheta = 1 - 2 * CLHEP::RandFlat::shoot(_minThetaRand, _maxThetaRand);
252  sinTheta = sqrt(1 - cosTheta * cosTheta);
253  }
254  }
255 
256  // Compute position std::vector and direction versor (Z is shoot axis in the shooting frame)
257  direction[0] = -sinTheta * cosPhi; // momentum direction (unitary vectors)
258  direction[1] = -sinTheta * sinPhi;
259  direction[2] = -cosTheta;
260  }
261 
262  // ++++++++++++++ Randomize position ++++++++++++++
263  if (_rndmPosFlag) {
264  if (_rndmMinPositionFlag && _rndmMaxPositionFlag) {
265  // This works for all "flat" domains (point, line, plane, parallelepiped)
266  position[0] = CLHEP::RandFlat::shoot(_minPosition(0), _maxPosition(0));
267  position[1] = CLHEP::RandFlat::shoot(_minPosition(1), _maxPosition(1));
268  position[2] = CLHEP::RandFlat::shoot(_minPosition(2), _maxPosition(2));
269  if (_rndmFromFlat) { // Transform shoot direction to absolute reference frame
270  // Transform direction if shoot axis is not the Z axis.
271  // 3rd coordinate is relative to shooting axis so it is x when shooting along X,
272  // so the coordinate transformation to go to absolute reference frame is:
273  // (y, z, x) -> (x, y, z) when shooting along X
274  // (z, x, y) -> (x, y, z) when shooting along X
275  if (_shootAxis == xDirection) {
276  double buf = direction[0];
277  direction[0] = direction[2];
278  direction[2] = direction[1];
279  direction[1] = buf;
280  } else if (_shootAxis == yDirection) {
281  double buf = direction[0];
282  direction[0] = direction[1];
283  direction[1] = direction[2];
284  direction[2] = buf;
285  }
286  }
287  } else if (_rndmFromSphere) {
288  // Randomize position on the spherical cap (in the reference frame of the generation sphere).
289  // Gamma and delta are the polar and azimuth angle of the position vector w.r.t. the
290  // sphere center.
291  float cosGamma = 1 - 2 * CLHEP::RandFlat::shoot(0., _rndmSphereCapExtRand);
292  float delta = CLHEP::RandFlat::shoot(0., 2 * CLHEP::pi);
293  float sinGamma = sqrt(1 - cosGamma * cosGamma);
294  float sinDelta = sin(delta);
295  float cosDelta = cos(delta);
296 
297  // Position vector in cap frame
298  position[0] = _rndmSphereRadius * sinGamma * cosDelta;
299  position[1] = _rndmSphereRadius * sinGamma * sinDelta;
300  position[2] = _rndmSphereRadius * cosGamma;
301 
302  // Position vector in absolute (world) frame
303  position *= _rndmSphereCapRotMat;
304  position += _rndmSphereCenter;
305 
306  // Direction vector in absolute (world) frame
307  // At this point, the direction vector is built so that the distribution of its polar angle with
308  // respect to the normal incidence is flat in cos^2 (isotropic flux). The vector coordinates have
309  // been constructed in the reference frame of the generation point on the sphere, so they must be
310  // rotated to the reference frame of the cap center and then to the world reference frame, in this
311  // order.
312  direction *= _ChangeOfBasisMatrix(cosGamma, sinGamma, cosDelta, sinDelta); // Direction
313  direction *= _rndmSphereCapRotMat;
314  }
315  }
316 
317  // ++++++++++++++ Check acceptance ++++++++++++++
318  if (_acceptanceFlag && (_rndmPosFlag || _rndmDirFlag)) {
319  GGSDetectorConstruction *detConst =
320  (GGSDetectorConstruction *)(GGSRunManager::GetRunManager()->GetUserDetectorConstruction());
321  acceptanceCheck = detConst->GetGeometry()->IsInsideAcceptance(position, direction);
322  if (!acceptanceCheck)
323  _nDiscarded++;
324  }
325 
326  } while (!acceptanceCheck);
327 
328  // ++++++++++++++ Randomize energy ++++++++++++++
329  if (_rndmMinEnergyFlag && _rndmMaxEnergyFlag) {
330  if (_spectralIndexFlag) {
331  energy = _GenSpectrumPowerLaw(_minEnergy, _maxEnergy, _spectralIndex);
332  } else {
333  energy = CLHEP::RandFlat::shoot(_minEnergy, _maxEnergy);
334  }
335  }
336 
337  COUT(DEEPDEB) << "Generated primary:" << ENDL;
338  CCOUT(DEEPDEB) << " PDG code: " << _gunGenerator->GetParticleDefinition()->GetPDGEncoding() << ENDL;
339  CCOUT(DEEPDEB) << " position: " << position << ENDL;
340  CCOUT(DEEPDEB) << " direction: " << direction << ENDL;
341  CCOUT(DEEPDEB) << " energy: " << energy << ENDL;
342 
343  //
344  // Set values for primary particle and shoot
345  //
346  _gunGenerator->SetParticlePosition(position);
347  _gunGenerator->SetParticleMomentumDirection(direction);
348  _gunGenerator->SetParticleEnergy(energy);
349 
350  // Shoot
351  _gunGenerator->GeneratePrimaryVertex(anEvent);
352 }
353 
355  GGSParameters params;
356  params.SetParam("generator", std::string("gun"));
357 
358  params.SetParam("acceptanceCheck", _acceptanceFlag);
359 
360  // Particle
361  params.SetParam("particlePdgCode", _gunGenerator->GetParticleDefinition()->GetPDGEncoding());
362 
363  // Position
364  if (_rndmPosFlag) {
365  if (_rndmMinPositionFlag && _rndmMaxPositionFlag) {
366  params.SetParam("minPosition", std::vector<double>{_minPosition[0] / CLHEP::cm, _minPosition[1] / CLHEP::cm,
367  _minPosition[2] / CLHEP::cm});
368  params.SetParam("maxPosition", std::vector<double>{_maxPosition[0] / CLHEP::cm, _maxPosition[1] / CLHEP::cm,
369  _maxPosition[2] / CLHEP::cm});
370  if (_rndmFromFlat) {
371  params.SetParam("genPosition", std::string("plane"));
372  } else {
373  params.SetParam("genPosition", std::string("box"));
374  }
375  } else if (_rndmFromSphere) {
376  params.SetParam("genPosition", std::string("sphere"));
377  params.SetParam("sphereCenter",
378  std::vector<double>{_rndmSphereCenter[0] / CLHEP::cm, _rndmSphereCenter[1] / CLHEP::cm,
379  _rndmSphereCenter[2] / CLHEP::cm});
380  params.SetParam("sphereCapPosition",
381  std::vector<double>{_rndmSphereCapPosition[0] / CLHEP::cm, _rndmSphereCapPosition[1] / CLHEP::cm,
382  _rndmSphereCapPosition[2] / CLHEP::cm});
383  params.SetParam("sphereCapExtension", acos(-2. * _rndmSphereCapExtRand + 1) / CLHEP::rad);
384  }
385  } else {
386  params.SetParam("genPosition", std::string("point"));
387  params.SetParam("position",
388  std::vector<double>{_position[0] / CLHEP::cm, _position[1] / CLHEP::cm, _position[2] / CLHEP::cm});
389  }
390 
391  // Direction
392  if (_rndmDirFlag) {
393  bool isotropic = false;
394  if (_rndmMinPhiFlag && _rndmMaxPhiFlag) {
395  params.SetParam("minPhi", _minPhi / CLHEP::rad);
396  params.SetParam("maxPhi", _maxPhi / CLHEP::rad);
397  }
398  if (_rndmMinThetaFlag && _rndmMaxThetaFlag) {
399  params.SetParam("minTheta", acos(-2. * _minThetaRand + 1) / CLHEP::rad);
400  params.SetParam("maxTheta", acos(-2. * _maxThetaRand + 1) / CLHEP::rad);
401  if (_rndmFromFlat || _rndmFromSphere) {
402  isotropic = true;
403  }
404  }
405  if (isotropic) {
406  params.SetParam("genDirection", std::string("isotropic"));
407  } else {
408  params.SetParam("genDirection", std::string("uniform"));
409  }
410  } else {
411  params.SetParam("genDirection", std::string("fixed"));
412  params.SetParam("theta", acos(_cosTheta) / CLHEP::rad);
413  params.SetParam("phi", acos(_cosPhi) / CLHEP::rad);
414  }
415 
416  // Energy
417  if (_rndmMinEnergyFlag && _rndmMaxEnergyFlag) {
418  params.SetParam("minEnergy", _minEnergy / CLHEP::GeV);
419  params.SetParam("maxEnergy", _maxEnergy / CLHEP::GeV);
420  if (_spectralIndexFlag) {
421  params.SetParam("genSpectrum", std::string("powerLaw"));
422  params.SetParam("spectralIndex", _spectralIndex);
423  } else {
424  params.SetParam("genSpectrum", std::string("flat"));
425  }
426  } else {
427  params.SetParam("genSpectrum", std::string("monochromatic"));
428  params.SetParam("energy", _energy / CLHEP::GeV);
429  }
430 
431  return params;
432 }
433 
434 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
435 
436 // Generate spectrum power law f(E)= E^gamma (when gamma==0 then is uniform generation).
437 G4double GGSGunGeneratorAction::_GenSpectrumPowerLaw(G4double Emin, G4double Emax, G4double gamma) {
438  G4double energy;
439  // Uniform generation
440  if (gamma == 0.) {
441  energy = CLHEP::RandFlat::shoot(Emin, Emax);
442  return energy;
443  }
444  G4double alpha = 1. + gamma; // integral spectral index
445  if (alpha == 0.) {
446  energy = exp(log(Emin) + CLHEP::RandFlat::shoot(0., 1.) * (log(Emax) - log(Emin)));
447  } else {
448  if (Emin == 0.)
449  Emin = 1.E-10;
450  energy =
451  pow((CLHEP::RandFlat::shoot(0., 1.) * (pow(Emax, alpha) - pow(Emin, alpha)) + pow(Emin, alpha)), 1. / alpha);
452  }
453 
454  return energy;
455 }
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.