GGS(GenericGEANT4Simulation)Software  2.6.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 "G4ParticleGun.hh"
21 #include "G4IonTable.hh"
22 #include "G4ParticleDefinition.hh"
23 #include "Randomize.hh"
24 #include "G4UImanager.hh"
25 #include "G4SystemOfUnits.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), _rndmFromFlat(
35  false), _rndmFromSphere(false), _rndmSphereCenter(0., 0., 0.), _rndmSphereCapExtRand(0.), _rndmSphereCapAlpha(
36  0.), _rndmSphereCapBeta(0.), _rndmSphereCapRotMat(G4RotationMatrix::IDENTITY), _rndmSphereRadius(0.), _rndmMinEnergyFlag(
37  false), _rndmMaxEnergyFlag(false), _spectralIndexFlag(false), _rndmMinThetaFlag(false), _rndmMaxThetaFlag(
38  false), _rndmMinPhiFlag(false), _rndmMaxPhiFlag(false), _rndmPosFlag(false), _rndmDirFlag(false), _position(0.,
39  0., 0.), _minPosition(0., 0., 0.), _maxPosition(0., 0., 0.), _energy(10. * GeV), _minEnergy(10. * GeV), _maxEnergy(
40  10. * GeV), _spectralIndex(-3.2), _sinTheta(0.), _cosTheta(1.), _minThetaRand(0.), _maxThetaRand(.5), _minCos2ThetaRand(
41  0.), _maxCos2ThetaRand(1.), _sinPhi(0.), _cosPhi(1.), _minPhi(0.), _maxPhi(2 * CLHEP::pi), _direction(0., 0.,
42  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 
61 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
62 
63 void GGSGunGeneratorAction::SetGunParticle(const G4String &particle) {
64  if (particle == "C12") {
65  //G4ParticleTable* pTable = G4ParticleTable::GetParticleTable();
66  G4ParticleDefinition* c12 = G4ParticleTable::GetParticleTable()->GetIonTable()->GetIon(6, 12, 0.);
67  ((G4ParticleGun*) _gunGenerator)->SetParticleDefinition(c12);
68  ((G4ParticleGun*) _gunGenerator)->SetParticleCharge(6 * eplus);
69  }
70  else if (particle == "Fe56") {
71  //G4ParticleTable* pTable = G4ParticleTable::GetParticleTable();
72  G4ParticleDefinition* fe56 = G4ParticleTable::GetParticleTable()->GetIonTable()->GetIon(26, 56, 0.);
73  ((G4ParticleGun*) _gunGenerator)->SetParticleDefinition(fe56);
74  ((G4ParticleGun*) _gunGenerator)->SetParticleCharge(26 * eplus);
75  }
76  else
77  G4UImanager::GetUIpointer()->ApplyCommand(G4String("/gun/particle ").append(particle));
78 }
79 
80 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
81 
82 G4RotationMatrix& GGSGunGeneratorAction::_ComputeRotMatrix(double cosAlpha, double sinAlpha, double cosBeta,
83  double sinBeta) {
84 
85  // A small helper class which allows to directly specify the rotation matrix elements
86  class Rot3: public G4RotationMatrix {
87  public:
88  void SetMatrix(double mxx, double mxy, double mxz, double myx, double myy, double myz, double mzx, double mzy,
89  double mzz) {
90  rxx = mxx;
91  rxy = mxy;
92  rxz = mxz;
93  ryx = myx;
94  ryy = myy;
95  ryz = myz;
96  rzx = mzx;
97  rzy = mzy;
98  rzz = mzz;
99  }
100  };
101 
102  static Rot3 retMatrix;
103 
104  /* The rotation is computed as the composition of the following operations (in this order):
105  *
106  * 1) rotate the vector so that beta = 0
107  * 2) rotate about the new y axis of an angle alpha
108  * 3) invert 1
109  * The matrices are:
110  *
111  * | cosb sinb 0|
112  * 1 = |-sinb cosb 0|
113  * | 0 0 1|
114  *
115  * | cosa 0 sina|
116  * 2 = | 0 1 0|
117  * |-sina 0 cosa|
118  *
119  * | cosb -sinb 0|
120  * 3 = | sinb cosb 0|
121  * | 0 0 1|
122  *
123  *
124  * The resulting matrix is obtained as M = 3*2*1.
125  */
126 
127  double xx = cosAlpha * cosBeta * cosBeta + sinBeta * sinBeta;
128  double xy = cosBeta * cosAlpha * sinBeta - cosBeta * sinBeta; // 1st row 2nd column
129  double xz = cosBeta * sinAlpha;
130  double yx = sinBeta * cosAlpha * cosBeta - sinBeta * cosBeta; // 2nd row 1st column
131  double yy = sinBeta * cosAlpha * sinBeta + cosBeta * cosBeta;
132  double yz = sinBeta * sinAlpha;
133  double zx = -sinAlpha * cosBeta;
134  double zy = -sinAlpha * sinBeta;
135  double zz = cosAlpha;
136 
137  retMatrix.SetMatrix(xx, xy, xz, yx, yy, yz, zx, zy, zz);
138 
139  return retMatrix;
140 
141 }
142 
143 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
144 
145 void GGSGunGeneratorAction::_ResetFlat() {
146 
147  _rndmFromFlat = false;
148  _minPosition = _maxPosition = G4ThreeVector(0., 0., 0.);
149  _shootAxis = G4ThreeVector(0, 0, 1);
150 }
151 
152 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
153 
154 void GGSGunGeneratorAction::_ResetSphere() {
155 
156  _rndmFromSphere = false;
157  _rndmSphereCenter = G4ThreeVector(0., 0., 0.);
158  _rndmSphereRadius = 0;
159  _rndmSphereCapExtRand = 0.;
160  _rndmSphereCapRotMat = G4RotationMatrix::IDENTITY;
161 }
162 
163 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
164 
165 void GGSGunGeneratorAction::_SetRndmFromSurface(int surfType) {
166 
167  if (surfType == 0) { // No generation from surface
168  _ResetFlat();
169  _ResetSphere();
170  }
171  else if (surfType == 1) { // Flat surface
172  if (_minPosition[0] < _maxPosition[0] && _minPosition[1] < _maxPosition[1] && _minPosition[2] == _maxPosition[2]) {
173  _rndmFromFlat = true;
174  _shootAxis = G4ThreeVector(0, 0, 1);
175  }
176  else if (_minPosition[0] == _maxPosition[0] && _minPosition[1] < _maxPosition[1]
177  && _minPosition[2] < _maxPosition[2]) {
178  _rndmFromFlat = true;
179  _shootAxis = G4ThreeVector(1, 0, 0);
180  }
181  else if (_minPosition[0] < _maxPosition[0] && _minPosition[1] == _maxPosition[1]
182  && _minPosition[2] < _maxPosition[2]) {
183  _rndmFromFlat = true;
184  _shootAxis = G4ThreeVector(0, 1, 0);
185  }
186  else {
187  _rndmFromFlat = false;
188  _shootAxis = G4ThreeVector(0, 0, 1); // Default shoot axis along Z
189  }
190  if (_rndmFromFlat)
191  _rndmPosFlag = true;
192  _ResetSphere();
193  }
194  else if (surfType == 2) { // Spherical surface
195  if (_rndmSphereRadius > 0. && _rndmSphereCapExtRand > 0.) {
196  _rndmFromSphere = true;
197  _rndmPosFlag = true;
198  _rndmSphereCapRotMat = _ComputeRotMatrix(cos(_rndmSphereCapAlpha), sin(_rndmSphereCapAlpha),
199  cos(_rndmSphereCapBeta), sin(_rndmSphereCapBeta));
200  SetMinPhi(0);
201  SetMaxPhi(360. * deg);
202  }
203  _ResetFlat();
204  }
205 }
206 
207 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
208 
209 void GGSGunGeneratorAction::_SetRndmDirFlag() {
210  if ((_rndmMinThetaFlag && _rndmMaxThetaFlag) || (_rndmMinPhiFlag && _rndmMaxPhiFlag))
211  _rndmDirFlag = true;
212  else
213  _rndmDirFlag = false;
214 }
215 
216 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
217 
218 void GGSGunGeneratorAction::_SetRndmPosFlag() {
219  if (_rndmMinPositionFlag && _rndmMaxPositionFlag)
220  _rndmPosFlag = true;
221  else
222  _rndmPosFlag = false;
223 }
224 
225 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
226 
228 
229  static const std::string routineName("GGSGunGeneratorAction::GeneratePrimaries");
230  static const G4ThreeVector xDirection(1, 0, 0);
231  static const G4ThreeVector yDirection(0, 1, 0);
232 
233  _nDiscarded = 0;
234 
235  // Initialize shooting parameters with default values
236  G4ThreeVector position(_position);
237  G4ThreeVector direction(_direction);
238  G4double energy(_energy);
239 
240  bool acceptanceCheck = true;
241  do { // Acceptance check loop
242 
243  // ++++++++++++++ Randomize direction ++++++++++++++
244  // The random direction computed here is always referred to the shooting frame.
245  // Since the shooting frame may depend on shooting point (eg., shooting
246  // from a sphere) the transformation from shooting frame to absolute
247  // frame is done after random position have been chosen.
248  if (_rndmDirFlag) {
249  G4double cosPhi(_cosPhi);
250  G4double sinPhi(_sinPhi);
251  if (_rndmMinPhiFlag && _rndmMaxPhiFlag) {
252  double phi = CLHEP::RandFlat::shoot(_minPhi, _maxPhi); // (0,2pi) or (-2pi,2pi) if shooting along -Z or -X
253  cosPhi = cos(phi);
254  sinPhi = sin(phi);
255  }
256 
257  G4double sinTheta(_sinTheta);
258  G4double cosTheta(_cosTheta);
259  if (_rndmMinThetaFlag && _rndmMaxThetaFlag) {
260  if (_rndmFromFlat || _rndmFromSphere) {
261  // To generate an isotropic flux from a flat surface, the random angle must be uniform in cos^2 theta
262  float cos2Theta = CLHEP::RandFlat::shoot(_minCos2ThetaRand, _maxCos2ThetaRand);
263  cosTheta = sqrt(cos2Theta);
264  sinTheta = sqrt(1 - cos2Theta);
265  }
266  else {
267  // This will sample a uniform theta distribution on the sphere. This formula comes from the inverse CDF
268  // method. See eg. http://en.wikibooks.org/wiki/Mathematica/Uniform_Spherical_Distribution
269  // The form reported here is slightly different but equivalent (it can be easily seen using the
270  // identity (sin x/2)^2 = (1 - cos x)/2 ).
271  cosTheta = 1 - 2 * CLHEP::RandFlat::shoot(_minThetaRand, _maxThetaRand);
272  sinTheta = sqrt(1 - cosTheta * cosTheta);
273  }
274 
275  }
276 
277  // Compute position std::vector and direction versor (Z is shoot axis in the shooting frame)
278  direction[0] = -sinTheta * cosPhi; // momentum direction (unitary vectors)
279  direction[1] = -sinTheta * sinPhi;
280  direction[2] = -cosTheta;
281  }
282 
283  // ++++++++++++++ Randomize position ++++++++++++++
284  if (_rndmPosFlag) {
285  if (_rndmMinPositionFlag && _rndmMaxPositionFlag) {
286  // This works for all "flat" domains (point, line, plane, parallelepiped)
287  position[0] = CLHEP::RandFlat::shoot(_minPosition(0), _maxPosition(0));
288  position[1] = CLHEP::RandFlat::shoot(_minPosition(1), _maxPosition(1));
289  position[2] = CLHEP::RandFlat::shoot(_minPosition(2), _maxPosition(2));
290  if (_rndmFromFlat) { // Transform shoot direction to absolute reference frame
291  // Transform direction if shoot axis is not the Z axis.
292  // 3rd coordinate is relative to shooting axis so it is x when shooting along X,
293  // so the coordinate transformation to go to absolute reference frame is:
294  // (y, z, x) -> (x, y, z) when shooting along X
295  // (z, x, y) -> (x, y, z) when shooting along X
296  if (_shootAxis == xDirection) {
297  double buf = direction[0];
298  direction[0] = direction[2];
299  direction[2] = direction[1];
300  direction[1] = buf;
301  }
302  else if (_shootAxis == yDirection) {
303  double buf = direction[0];
304  direction[0] = direction[1];
305  direction[1] = direction[2];
306  direction[2] = buf;
307  }
308  }
309  }
310  else if (_rndmFromSphere) {
311  // Randomize position on the spherical cap (in the reference frame of the generation sphere).
312  // Gamma and delta are the polar and azimuth angle of the position vector w.r.t. the
313  // sphere center.
314  float cosGamma = 1 - 2 * CLHEP::RandFlat::shoot(0., _rndmSphereCapExtRand);
315  float delta = CLHEP::RandFlat::shoot(0., 2 * CLHEP::pi);
316  float sinGamma = sqrt(1 - cosGamma * cosGamma);
317  float sinDelta = sin(delta);
318  float cosDelta = cos(delta);
319 
320  // Position vector in cap frame
321  position[0] = _rndmSphereRadius * sinGamma * cosDelta;
322  position[1] = _rndmSphereRadius * sinGamma * sinDelta;
323  position[2] = _rndmSphereRadius * cosGamma;
324 
325  // Position vector in absolute (world) frame
326  position *= _rndmSphereCapRotMat;
327  position += _rndmSphereCenter;
328 
329  // Direction vector in absolute (world) frame
330  // At this point, the direction vector is built so that the distribution of its polar angle with
331  // respect to the normal incidence is flat in cos^2 (isotropic flux). The vector coordinates have
332  // been constructed in the reference frame of the generation point on the sphere, so they must be
333  // rotated to the reference frame of the cap center and then to the world reference frame, in this
334  // order.
335  direction *= _ComputeRotMatrix(cosGamma, sinGamma, cosDelta, sinDelta); // Direction
336  direction *= _rndmSphereCapRotMat;
337  }
338  }
339 
340  // ++++++++++++++ Check acceptance ++++++++++++++
341  if (_acceptanceFlag && (_rndmPosFlag || _rndmDirFlag)) {
342  GGSDetectorConstruction *detConst =
343  (GGSDetectorConstruction*) (GGSRunManager::GetRunManager()->GetUserDetectorConstruction());
344  acceptanceCheck = detConst->GetGeometry()->IsInsideAcceptance(position, direction);
345  if (!acceptanceCheck)
346  _nDiscarded++;
347  }
348 
349  } while (!acceptanceCheck);
350 
351  // ++++++++++++++ Randomize energy ++++++++++++++
352  if (_rndmMinEnergyFlag && _rndmMaxEnergyFlag) {
353  if (_spectralIndexFlag) {
354  energy = _GenSpectrumPowerLaw(_minEnergy, _maxEnergy, _spectralIndex);
355  }
356  else {
357  energy = CLHEP::RandFlat::shoot(_minEnergy, _maxEnergy);
358  }
359  }
360 
361  COUT(DEEPDEB) << "Generated primary:" << ENDL;
362  CCOUT(DEEPDEB) << " PDG code: " << _gunGenerator->GetParticleDefinition()->GetPDGEncoding() << ENDL;
363  CCOUT(DEEPDEB) << " position: " << position << ENDL;
364  CCOUT(DEEPDEB) << " direction: " << direction << ENDL;
365  CCOUT(DEEPDEB) << " energy: " << energy << ENDL;
366 
367  //
368  // Set values for primary particle and shoot
369  //
370  _gunGenerator->SetParticlePosition(position);
371  _gunGenerator->SetParticleMomentumDirection(direction);
372  _gunGenerator->SetParticleEnergy(energy);
373 
374  // Shoot
375  _gunGenerator->GeneratePrimaryVertex(anEvent);
376 }
377 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
378 
379 // Generate spectrum power law f(E)= E^gamma (when gamma==0 then is uniform generation).
380 G4double GGSGunGeneratorAction::_GenSpectrumPowerLaw(G4double Emin, G4double Emax, G4double gamma) {
381  G4double energy;
382 // Uniform generation
383  if (gamma == 0.) {
384  energy = CLHEP::RandFlat::shoot(Emin, Emax);
385  return energy;
386  }
387  G4double alpha = 1. + gamma; //integral spectral index
388  if (alpha == 0.) {
389  energy = exp(log(Emin) + CLHEP::RandFlat::shoot(0., 1.) * (log(Emax) - log(Emin)));
390  }
391  else {
392  if (Emin == 0.)
393  Emin = 1.E-10;
394  energy = pow((CLHEP::RandFlat::shoot(0., 1.) * (pow(Emax, alpha) - pow(Emin, alpha)) + pow(Emin, alpha)),
395  1. / alpha);
396  }
397 
398  return energy;
399 }
400 
GGSGunGeneratorAction()
Constructor.
#define ENDL
Definition: GGSSmartLog.h:93
#define COUT(level)
Smart log macro. It writes on stdout only if the specified verbosity level is lesser than the maximum...
Definition: GGSSmartLog.h:66
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.
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:88
void SetGunParticle(const G4String &particle)
Sets the particle to be used by G4ParticleGun.
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.