GEMC  2.3
Geant4 Monte-Carlo Framework
MPrimaryGeneratorAction.cc
Go to the documentation of this file.
1 // G4 headers
2 #include "G4Event.hh"
3 #include "G4ParticleGun.hh"
4 #include "G4ParticleTable.hh"
5 #include "G4ParticleDefinition.hh"
6 #include "G4UnitsTable.hh"
7 #include "Randomize.hh"
8 
9 // gemc headers
11 #include "string_utilities.h"
12 
13 // C++ headers
14 #include <iostream>
15 using namespace std;
16 
17 // CLHEP units
18 #include "CLHEP/Units/PhysicalConstants.h"
19 using namespace CLHEP;
20 
22 {
23  gemcOpt = opts;
24  hd_msg = gemcOpt->optMap["LOG_MSG"].args + " Beam Settings >> " ;
25  input_gen = gemcOpt->optMap["INPUT_GEN_FILE"].args;
26  background_gen = gemcOpt->optMap["MERGE_LUND_BG"].args;
27  cosmics = gemcOpt->optMap["COSMICRAYS"].args;
28  string cArea = gemcOpt->optMap["COSMICAREA"].args;
29  GEN_VERBOSITY = gemcOpt->optMap["GEN_VERBOSITY"].arg;
30 
31 
32  particleTable = G4ParticleTable::GetParticleTable();
33 
34  beamPol = 0;
35 
36  setBeam();
37 
38  particleGun = new G4ParticleGun(1);
39 
40  if(input_gen == "gemc_internal")
41  {
42  vector<string> cvalues = get_info(gemcOpt->optMap["COSMICAREA"].args, string(",\""));
43 
44  if(cvalues.size() != 4)
45  cout << " !!! Warning: COSMICAREA flag not set correctly. It should be 4 numbers: x,y,z and R." << endl;
46 
47  cosmicTarget = G4ThreeVector(get_number(cvalues[0]), get_number(cvalues[1]), get_number(cvalues[2]));
48  cosmicRadius = get_number(cvalues[3]);
49 
50  if(cosmics == "no")
51  {
52  cout << endl << hd_msg << " Beam Type: " << Particle->GetParticleName() << endl;
53  cout << hd_msg << " Beam Momentum: " << G4BestUnit(mom, "Energy") ;
54  if(dmom > 0) cout << " +- " << G4BestUnit(dmom, "Energy") ;
55  cout << endl;
56  cout << hd_msg << " Beam Direction: (theta, phi) = (" << theta/deg << ", " << phi/deg << ") deg" ;
57  if(dtheta > 0 || dphi > 0) cout << " +- (" << dtheta/deg << ", " << dphi/deg << ") deg ";
58  cout << endl << hd_msg << " Beam Vertex: (" << vx/cm << ", " << vy/cm << ", " << vz/cm << ") cm" ;
59  if(dvr + dvz > 0) cout << " (radius, z-spread) = (" << dvr/cm << ", " << dvz/cm << ") cm" ;
60  cout << endl << hd_msg << " Beam polarization: " << polDeg << "%" << endl ;
61  cout << hd_msg << " Polarization Direction: (theta, phi) = (" << polTheta/deg << ", " << polPhi/deg << ")" ;
62  cout << endl;
63  }
64  else
65  {
66  cout << endl << hd_msg << " Beam Type: Cosmic rays." << endl;
67  cout << hd_msg << " Beam Parameters :" << cosmics << endl;
68  cout << hd_msg << " a = :" << cosmicA << endl;
69  cout << hd_msg << " b = :" << cosmicB << endl;
70  cout << hd_msg << " c = :" << cosmicC << endl;
71  cout << hd_msg << " Momentum Range: [" << cminp/GeV << " - " << cmaxp/GeV << "] GeV" << endl ;
72  cout << hd_msg << " Cosmic Area :" << cosmicTarget << endl;
73  cout << hd_msg << " Cosmic Radius :" << cosmicRadius/cm << " cm " << endl;
74  }
75  }
76 
77 
78  if(NP>0)
79  {
80  cout << endl << hd_msg << " Luminosity Particle Type: " << L_Particle->GetParticleName() << endl;
81  cout << hd_msg << " Luminosity Particle Momentum: " << G4BestUnit(L_mom, "Energy") ;
82  if(L_dmom > 0) cout << " +- " << G4BestUnit(L_dmom, "Energy") ;
83  cout << endl;
84  cout << hd_msg << " Luminosity Particle Direction: (theta, phi) = (" << L_theta/deg << ", " << L_phi/deg << ") deg" ;
85  if(L_dtheta > 0 || L_dphi > 0) cout << " +- (" << L_dtheta/deg << ", " << L_dphi/deg << ") deg" ;
86  cout << endl << hd_msg << " Luminosity Particle Vertex: (" << L_vx/cm << ", " << L_vy/cm << ", " << L_vz/cm << ") cm" ;
87  if(L_dvr + L_dvz > 0) cout << " (radius, z-spread) = (" << L_dvr/cm << ", " << L_dvz/cm << ")" ;
88  cout << endl << hd_msg << " Number of Luminosity Particles: " << NP << endl;
89  cout << hd_msg << " Luminosity Time Window: " << TWINDOW/ns << " nanoseconds." << endl ;
90  cout << hd_msg << " Luminosity Time Between Bunches: " << TBUNCH/ns << " nanoseconds." << endl;
91  }
92 
93  if(NP2>0)
94  {
95  cout << endl << hd_msg << " Luminosity Particle 2 Type: " << L2_Particle->GetParticleName() << endl;
96  cout << hd_msg << " Luminosity Particle 2 Momentum: " << G4BestUnit(L2_mom, "Energy") ;
97  if(L2_dmom > 0) cout << " +- " << G4BestUnit(L2_dmom, "Energy") ;
98  cout << endl;
99  cout << hd_msg << " Luminosity Particle 2 Direction: (theta, phi) = (" << L2_theta/deg << ", " << L2_phi/deg << ") deg" ;
100  if(L2_dtheta > 0 || L2_dphi > 0) cout << " +- (" << L2_dtheta/deg << ", " << L2_dphi/deg << ") deg" ;
101  cout << endl << hd_msg << " Luminosity Particle Vertex: (" << L2_vx/cm << ", " << L2_vy/cm << ", " << L2_vz/cm << ") cm" ;
102  if(L2_dvr + L2_dvz > 0) cout << " (radius, z-spread) = (" << L2_dvr/cm << ", " << L2_dvz/cm << ") cm" ;
103  cout << endl << hd_msg << " Number of Luminosity Particles 2: " << NP2 << endl;
104  cout << hd_msg << " Luminosity Time Between Bunches: " << TBUNCH2/ns << " nanoseconds." << endl;
105  }
106 
107 }
108 
109 
111 {
112  // internal generator. Particle defined by command line
113  if(input_gen == "gemc_internal")
114  {
115  lundUserDefined.clear();
116  for(unsigned i=0; i<8; i++) lundUserDefined.push_back(0);
117 
118  if(cosmics == "no")
119  {
120  // redefining particle if in graphic mode
121  if( gemcOpt->optMap["USE_GUI"].arg > 0)
122  setBeam();
123 
124  // Primary Particle
125  particleGun->SetParticleDefinition(Particle);
126 
127  G4ThreeVector beam_dir;
128 
129  // 4-momenta
130  double Mom = mom/MeV + (2.0*G4UniformRand()-1.0)*dmom/MeV;
131  double Theta = acos(G4UniformRand()*(cos(theta/rad-dtheta/rad)-cos(theta/rad+dtheta/rad)) + cos(theta/rad+dtheta/rad))/rad;
132  if(primaryFlat)
133  Theta = theta/rad + (2.0*G4UniformRand()-1.0)*dtheta/rad;
134 
135  double Phi = phi/rad + (2.0*G4UniformRand()-1.0)*dphi/rad;
136  double mass = Particle->GetPDGMass();
137  double akine = sqrt(Mom*Mom + mass*mass) - mass ;
138  if(gemcOpt->optMap["ALIGN_ZAXIS"].args == "no")
139  beam_dir = G4ThreeVector(cos(Phi/rad)*sin(Theta/rad), sin(Phi/rad)*sin(Theta/rad), cos(Theta/rad));
140  else if(gemcOpt->optMap["ALIGN_ZAXIS"].args == "beamp")
141  {
142  beam_dir = G4ThreeVector(cos(phi/rad)*sin(theta/rad), sin(phi/rad)*sin(theta/rad), cos(theta/rad));
143  const G4ThreeVector beam_axis(cos(phi/rad)*sin(theta/rad), sin(phi/rad)*sin(theta/rad), cos(theta/rad));
144  const G4ThreeVector rotx1(cos(phi/rad), -sin(phi/rad), 0);
145  beam_dir.rotate((2.0*G4UniformRand()-1.0)*dtheta/rad, rotx1);
146  beam_dir.rotate((2.0*G4UniformRand()-1.0)*dphi/rad, beam_axis);
147  }
148  else
149  {
150  beam_dir = G4ThreeVector(cos(cphi/rad)*sin(ctheta/rad), sin(cphi/rad)*sin(ctheta/rad), cos(ctheta/rad));
151  // const G4ThreeVector beam_axis(cos(cphi/rad)*sin(ctheta/rad), sin(cphi/rad)*sin(ctheta/rad), cos(ctheta/rad));
152  const G4ThreeVector beam_axis(beam_dir);
153  const G4ThreeVector rotx1(cos(cphi/rad), -sin(cphi/rad), 0);
154  beam_dir.rotate(Theta, rotx1);
155  beam_dir.rotate(Phi, beam_axis);
156  }
157 
158  particleGun->SetParticleEnergy(akine);
159  particleGun->SetParticleMomentumDirection(beam_dir);
160 
161  // vertex
162  double VR = sqrt(G4UniformRand())*dvr/mm;
163  double PHI = 2.0*pi*G4UniformRand();
164  double Vx = vx/mm + VR*cos(PHI);
165  double Vy = vy/mm + VR*sin(PHI);
166  double Vz = vz/mm + (2.0*G4UniformRand()-1.0)*dvz/mm;
167  G4ThreeVector beam_vrt(Vx, Vy, Vz);
168  particleGun->SetParticlePosition(beam_vrt);
169 
170  // polarization
171  double partPol = 0.0;
172  double polCast = 100.0 * G4UniformRand();
173  if( polCast <= polDeg ) partPol = 1;
174  double polX = partPol * sin( polTheta/rad ) * cos( polPhi/rad );
175  double polY = partPol * sin( polTheta/rad ) * sin( polPhi/rad );
176  double polZ = partPol * cos( polTheta/rad );
177  particleGun->SetParticlePolarization(G4ThreeVector( polX, polY, polZ ));
178 
179  // Primary particle generated int the middle of Time window
180  particleGun->SetParticleTime(TWINDOW/2);
181  particleGun->SetNumberOfParticles(1);
182  particleGun->GeneratePrimaryVertex(anEvent);
183  if(GEN_VERBOSITY > 3)
184  {
185  cout << hd_msg << " Particle id=" << Particle->GetParticleName()
186  << " Vertex=" << beam_vrt/cm << "cm, momentum=" << Mom/GeV << " GeV, theta="
187  << Theta/deg << " degrees, phi=" << Phi/deg << " degrees" << endl;
188  if( partPol > 0 )
189  cout << hd_msg << " with polarization angles: polar - " << polTheta/deg << " degrees, "
190  << "azimuthal - " << polPhi/deg << " degrees " ;
191  cout << endl;
192  }
193  }
194  // cosmic model
195  // paper: A. Dar, Phys.Rev.Lett, 51,3,p.227 (1983)
196  else
197  {
198  // first randomly pick a number inside the sphere
199  double cosmicVX = 100000;
200  double cosmicVY = 100000;
201  double cosmicVZ = 100000;
202 
203  while( (cosmicVX - cosmicTarget.x() )*(cosmicVX - cosmicTarget.x() ) +
204  (cosmicVY - cosmicTarget.y() )*(cosmicVY - cosmicTarget.y() ) +
205  (cosmicVZ - cosmicTarget.z() )*(cosmicVZ - cosmicTarget.z() ) >= cosmicRadius*cosmicRadius )
206  {
207  cosmicVX = -cosmicRadius + 2*cosmicRadius*G4UniformRand();
208  cosmicVY = -cosmicRadius + 2*cosmicRadius*G4UniformRand();
209  cosmicVZ = -cosmicRadius + 2*cosmicRadius*G4UniformRand();
210  }
211  // now generating random momentum, cos(theta)
212  // the maximum of the distribution is the lowest momentum and 0 theta
213  // normalizing by that number
214  double cosmicProb = G4UniformRand()*cosmicBeam(0, cminp/GeV);
215 
216  double thisMom = (cminp + (cmaxp-cminp)*G4UniformRand());
217  double thisthe = pi*G4UniformRand()/2.0;
218  while (cosmicBeam(thisthe, thisMom/GeV) < cosmicProb)
219  {
220  thisMom = (cminp + (cmaxp-cminp)*G4UniformRand());
221  thisthe = pi*G4UniformRand()/2.0;
222  }
223  // isotropic in phi
224  double thisPhi = -pi + 2*pi*G4UniformRand();
225 
226  // now finding the vertex. Assuming twice the radius as starting point
227  // attention:
228  // axis transformation, z <> y, x <> -x
229  // cause the cosmics come from the sky
230  double pvx = cosmicVX - 2*cosmicRadius*sin(thisthe)*cos(thisPhi);
231  double pvy = cosmicVY + 2*cosmicRadius*cos(thisthe);
232  double pvz = cosmicVZ + 2*cosmicRadius*sin(thisthe)*sin(thisPhi);
233  particleGun->SetParticlePosition(G4ThreeVector(pvx, pvy, pvz));
234 
235 
236  // choosing charge of the muons
237  string muonType = "mu+";
238  if(G4UniformRand() <= 0.5)
239  muonType = "mu-";
240 
241  Particle = particleTable->FindParticle(muonType);
242  double mass = Particle->GetPDGMass();
243  double akine = sqrt(thisMom*thisMom + mass*mass) - mass ;
244 
245  particleGun->SetParticleDefinition(Particle);
246 
247  // when assigning momentum the direction is reversed
248  G4ThreeVector beam_dir(cos(thisPhi)*sin(thisthe), -cos(thisthe), -sin(thisPhi)*sin(thisthe));
249 
250  if(GEN_VERBOSITY > 3)
251  {
252  cout << hd_msg << " Particle id=" << Particle->GetParticleName()
253  << " Vertex=" << G4ThreeVector(pvx, pvy, pvz)/cm << "cm, momentum=" << thisMom/GeV << " GeV, theta="
254  << thisthe/deg << " degrees, phi=" << thisPhi/deg << " degrees" << endl;
255  cout << endl;
256  }
257 
258 
259  particleGun->SetParticleEnergy(akine);
260  particleGun->SetParticleMomentumDirection(beam_dir);
261  particleGun->SetNumberOfParticles(1);
262  particleGun->GeneratePrimaryVertex(anEvent);
263  }
264  }
265  else
266  // external generator: input file
267  {
268  // LUND format:
269  // Header (Event Info):
270  // These are the original LUND variables, however after # particles, and except beam polarization, these can be user defined.
271  // 1 2 3 4 5 6 7 8 9 10
272  // # of Particles, # of Target Nucleons, # of Target Protons, Pol. of Target, Pol. of Electron, x, y, W2, Q2, nu
273  //
274  // Body (Particle Info):
275  // 1 2 3 4 5 6 7 8 9 10 11 12 13 14
276  // index, charge, type, particle id, parent, daughter, p_x, p_y, p_z, p_t, mass, x vertex, y vertex, z vertex
277  // type is 1 for particles in the detector
278  if((gformat == "LUND" || gformat == "lund") && !gif.eof())
279  {
280  lundUserDefined.clear();
281  int nparticles;
282 
283  gif >> nparticles ;
284  for(unsigned i=0; i<9; i++)
285  {
286  double tmp;
287 
288  if(i==3)
289  {
290  gif >> beamPol;
291  if(beamPol>1)
292  beamPol = 1;
293  }
294  else
295  {
296  gif >> tmp;
297  lundUserDefined.push_back(tmp);
298  }
299  }
300 
301  for(int p=0; p<nparticles; p++)
302  {
303  double tmp, px, py, pz;
304  int pdef, type, parent, daughter, pindex;
305  double Vx, Vy, Vz;
306  gif >> pindex >> tmp >> type >> pdef >> parent >> daughter >> px >> py >> pz >> tmp >> tmp >> Vx >> Vy >> Vz;
307  if(type == 1 && pindex == p+1)
308  {
309  // Primary Particle
310  Particle = particleTable->FindParticle(pdef);
311  if(!Particle)
312  {
313  cout << hd_msg << " Particle id " << pdef << " not found in G4 table." << endl << endl;
314 
315  return;
316  }
317  particleGun->SetParticleDefinition(Particle);
318 
319  // 4-momenta
320  G4ThreeVector pmom(px*GeV, py*GeV, pz*GeV);
321  double Mom = pmom.mag();
322  double Phi = pmom.getPhi();
323  double Theta = pmom.getTheta();
324  double mass = Particle->GetPDGMass();
325  double akine = sqrt(Mom*Mom + mass*mass) - mass ;
326 
327  particleGun->SetParticleEnergy(akine);
328  particleGun->SetParticleMomentumDirection(G4ThreeVector(cos(Phi/rad)*sin(Theta/rad), sin(Phi/rad)*sin(Theta/rad), cos(Theta/rad)));
329 
330  // vertex
331  G4ThreeVector beam_vrt(Vx*cm, Vy*cm, Vz*cm);
332  particleGun->SetParticlePosition(beam_vrt);
333 
334 
335  // beam polarization only along the beam
336  // only for the first particle
337  if(p==0)
338  {
339  particleGun->SetParticlePolarization(G4ThreeVector( 0, 0, beamPol ));
340  }
341 
342  // Primary particle generated int the middle of Time window
343  particleGun->SetParticleTime(TWINDOW/2);
344  particleGun->SetNumberOfParticles(1);
345  particleGun->GeneratePrimaryVertex(anEvent);
346  if(GEN_VERBOSITY > 3)
347  cout << hd_msg << " Particle Number: " << p+1 << ", id=" << pdef << " (" << Particle->GetParticleName() << ")"
348  << " Vertex=" << beam_vrt << "cm, momentum=" << pmom/GeV << " GeV" << endl;
349  }
350  else if(pindex != p+1)
351  if(GEN_VERBOSITY > 3)
352  cout << hd_msg << " Warning: file particle index " << tmp << " does not match read particle index " << p+1 << endl;
353 
354  }
355  }
356  else if((gformat == "stdhep" || gformat == "STDHEP" || gformat == "StdHep" || gformat == "StdHEP"))
357  {
358  //
359  // StdHep is an (old like LUND) MC generator format in binary form.
360  //
361 
362  long lerr=stdhep_reader->readEvent(); // Read the next event from the file.
363 
364  if( lerr == LSH_ENDOFFILE)
365  {
366  return;
367  }
368  else if(lerr != LSH_SUCCESS)
369  {
370  cout << hd_msg << " -- Error reading stdhep file: " << lerr << "\n";
371  return;
372  }
373 
374  int NPART = stdhep_reader->nTracks();
375 
376  for(int p=0;p<NPART;p++)
377  {
378  if( stdhep_reader->daughter1(p)>0)
379  {
380  // The particle has daughters, so we do not want to generate this one.
381  continue;
382  }
383  else
384  {
385 
386  Particle = particleTable->FindParticle(stdhep_reader->pid(p));
387  if(!Particle)
388  {
389  cout << hd_msg << " Particle id " << stdhep_reader->pid(p) << " not found in G4 table." << endl << endl;
390 
391  return;
392  }
393 
394  particleGun->SetParticleDefinition(Particle);
395 
396  // 4-momenta
397  G4ThreeVector pmom(stdhep_reader->Px(p)*GeV,stdhep_reader->Py(p)*GeV, stdhep_reader->Pz(p)*GeV);
398  double Mom = pmom.mag();
399  double Phi = pmom.getPhi();
400  double Theta = pmom.getTheta();
401  double mass = Particle->GetPDGMass();
402  double akine = sqrt(Mom*Mom + mass*mass) - mass ;
403 
404  G4ThreeVector beam_dir(cos(Phi/rad)*sin(Theta/rad), sin(Phi/rad)*sin(Theta/rad), cos(Theta/rad));
405 
406  if(gemcOpt->optMap["STEER_BEAM"].arg != 0)
407  {
408  beam_dir.rotateY(theta);
409  beam_dir.rotateZ(phi);
410  }
411 
412  particleGun->SetParticleEnergy(akine);
413  particleGun->SetParticleMomentumDirection(beam_dir);
414 
415  G4ThreeVector beam_vrt;
416 
417  // vertex
418  if(gemcOpt->optMap["STEER_BEAM"].arg == 0)
419  {
420  beam_vrt = G4ThreeVector(stdhep_reader->X(p)*cm,
421  stdhep_reader->Y(p)*cm,
422  stdhep_reader->Z(p)*cm);
423  }
424  else
425  {
426  // vertex smear and offset
427  double VR = sqrt(G4UniformRand())*dvr/mm;
428  double PHI = 2.0*pi*G4UniformRand();
429 
430  beam_vrt = G4ThreeVector(stdhep_reader->X(p)*cm + vx/mm + VR*cos(PHI),
431  stdhep_reader->Y(p)*cm + vy/mm + VR*sin(PHI),
432  stdhep_reader->Z(p)*cm + vz/mm + (2.0*G4UniformRand()-1.0)*dvz/mm);
433 
434  }
435  particleGun->SetParticlePosition(beam_vrt);
436 
437 
438  // beam polarization only along the beam
439  // only for the first particle
440  if(p==0)
441  {
442  particleGun->SetParticlePolarization(G4ThreeVector( 0, 0, beamPol ));
443  }
444 
445  // Primary particle generated int the middle of Time window
446  particleGun->SetParticleTime(TWINDOW/2);
447  particleGun->GeneratePrimaryVertex(anEvent);
448  if(GEN_VERBOSITY > 3)
449  cout << hd_msg << " Particle Number: " << p << ", id=" << stdhep_reader->pid(p) << "(" << Particle->GetParticleName() << ")"
450  << " Vertex=" << beam_vrt << "cm, momentum=" << pmom/GeV << " GeV" << endl;
451  }
452  }
453  }
454  }
455 
456  // merging (background) events from LUND format
457  if(background_gen != "no")
458  {
459  int nparticles;
460  double tmp;
461 
462  bgif >> nparticles ;
463  for(unsigned i=0; i<9; i++)
464  bgif >> tmp;
465 
466  for(int p=0; p<nparticles; p++)
467  {
468  double px, py, pz;
469  int pdef, pindex;
470  double time;
471  double Vx, Vy, Vz;
472  bgif >> pindex >> tmp >> tmp >> pdef >> tmp >> tmp >> px >> py >> pz >> time >> tmp >> Vx >> Vy >> Vz;
473  if(pindex == p+1)
474  {
475  // Primary Particle
476  Particle = particleTable->FindParticle(pdef);
477  if(!Particle)
478  {
479  cout << hd_msg << " Particle id " << pdef << " not found in G4 table." << endl << endl;
480 
481  return;
482  }
483  particleGun->SetParticleDefinition(Particle);
484 
485  // 4-momenta
486  G4ThreeVector pmom(px*GeV, py*GeV, pz*GeV);
487  double Mom = pmom.mag();
488  double Phi = pmom.getPhi();
489  double Theta = pmom.getTheta();
490  double mass = Particle->GetPDGMass();
491  double akine = sqrt(Mom*Mom + mass*mass) - mass ;
492 
493  particleGun->SetParticleEnergy(akine);
494  particleGun->SetParticleMomentumDirection(G4ThreeVector(cos(Phi/rad)*sin(Theta/rad), sin(Phi/rad)*sin(Theta/rad), cos(Theta/rad)));
495 
496  // vertex
497  G4ThreeVector beam_vrt(Vx*cm, Vy*cm, Vz*cm);
498  particleGun->SetParticlePosition(beam_vrt);
499 
500 
501  // Primary particle generated int the middle of Time window
502  particleGun->SetParticleTime(time);
503  particleGun->GeneratePrimaryVertex(anEvent);
504  if(GEN_VERBOSITY > 3)
505  cout << hd_msg << " Merged Particle Number: " << p+1 << ", id=" << pdef << " (" << Particle->GetParticleName() << ")"
506  << " Vertex=" << beam_vrt << "cm, momentum=" << pmom/GeV << " GeV" << endl;
507  }
508  else if(pindex != p+1)
509  if(GEN_VERBOSITY > 3)
510  cout << hd_msg << " Warning: file particle index " << tmp << " does not match read particle index " << p+1 << endl;
511 
512  }
513 
514  }
515 
516  // Luminosity Particles
517  int NBUNCHES = (int) floor(TWINDOW/TBUNCH);
518  int PBUNCH = (int) floor((double)NP/NBUNCHES);
519 
520  if(PBUNCH > 0)
521  {
522  particleGun->SetParticleDefinition(L_Particle);
523  particleGun->SetNumberOfParticles(PBUNCH);
524 
525  // getting kinematics
526  double L_mass = L_Particle->GetPDGMass();
527  double L_Mom = L_mom;
528  double L_Theta = L_theta;
529  double L_Phi = L_phi;
530 
531  // all particles in a bunch are identical
532  for(int b=0; b<NBUNCHES; b++)
533  {
534  particleGun->SetParticleTime(TBUNCH*b);
535  // spread momentum if requested
536  if(L_dmom > 0)
537  {
538  L_Mom += (2.0*G4UniformRand()-1.0)*L_dmom;
539  L_Theta = acos(G4UniformRand()*(cos(L_theta/rad-L_dtheta/rad)-cos(L_theta/rad+L_dtheta/rad)) + cos(L_theta/rad+L_dtheta/rad))/rad;
540  if(lumiFlat)
541  L_Theta += (2.0*G4UniformRand()-1.0)*L_dtheta;
542 
543  L_Phi += (2.0*G4UniformRand()-1.0)*L_dphi;
544  }
545  double L_akine = sqrt(L_Mom*L_Mom + L_mass*L_mass) - L_mass ;
546  particleGun->SetParticleEnergy(L_akine);
547  particleGun->SetParticleMomentumDirection(G4ThreeVector(cos(L_Phi/rad)*sin(L_Theta/rad), sin(L_Phi/rad)*sin(L_Theta/rad), cos(L_Theta/rad)));
548 
549  // luminosity vertex
550  double L_VR = G4UniformRand()*L_dvr;
551  double L_PHI = 2.0*pi*G4UniformRand();
552  L_vx += L_VR*cos(L_PHI);
553  L_vy += L_VR*sin(L_PHI);
554 
555  // spread vertex if requested
556  if(L_dvz > 0)
557  {
558  L_vz += (2.0*G4UniformRand()-1.0)*L_dvz;
559  }
560 
561  particleGun->SetParticlePosition(G4ThreeVector(L_vx, L_vy, L_vz));
562 
563  particleGun->GeneratePrimaryVertex(anEvent);
564  }
565  }
566 
567  // Luminosity Particles2
568  int NBUNCHES2 = (int) floor(TWINDOW/TBUNCH2);
569  int PBUNCH2 = (int) floor((double)NP2/NBUNCHES2);
570 
571  if(PBUNCH2 > 0)
572  {
573  particleGun->SetParticleDefinition(L2_Particle);
574  particleGun->SetNumberOfParticles(PBUNCH);
575 
576  // getting kinematics
577  double L2_mass = L2_Particle->GetPDGMass();
578  double L2_Mom = L2_mom;
579  double L2_Theta = L2_theta;
580  double L2_Phi = L2_phi;
581 
582 
583  // all particles in a bunch are identical
584  for(int b=0; b<NBUNCHES2; b++)
585  {
586  particleGun->SetParticleTime(TBUNCH2*b);
587  // spread momentum if requested
588  if(L2_dmom > 0)
589  {
590  L2_Mom += (2.0*G4UniformRand()-1.0)*L2_dmom;
591  L2_Theta = acos(G4UniformRand()*(cos(L2_theta/rad-L2_dtheta/rad)-cos(L2_theta/rad+L2_dtheta/rad)) + cos(L2_theta/rad+L2_dtheta/rad))/rad;
592  if(lumi2Flat)
593  L2_Theta += (2.0*G4UniformRand()-1.0)*L2_dtheta;
594  L2_Phi += (2.0*G4UniformRand()-1.0)*L2_dphi;
595  }
596  double L2_akine = sqrt(L2_Mom*L2_Mom + L2_mass*L2_mass) - L2_mass ;
597  particleGun->SetParticleEnergy(L2_akine);
598  particleGun->SetParticleMomentumDirection(G4ThreeVector(cos(L2_Phi/rad)*sin(L2_Theta/rad), sin(L2_Phi/rad)*sin(L2_Theta/rad), cos(L2_Theta/rad)));
599 
600  // luminosity vertex 2
601  double L2_VR = G4UniformRand()*L2_dvr/mm;
602  double L2_PHI = 2.0*pi*G4UniformRand();
603  L2_vx += L2_VR*cos(L2_PHI);
604  L2_vy += L2_VR*sin(L2_PHI);
605 
606  // spread vertex if requested
607  if(L2_dvz > 0)
608  {
609  L2_vz += (2.0*G4UniformRand()-1.0)*L2_dvz;
610  }
611  particleGun->SetParticlePosition(G4ThreeVector(L2_vx, L2_vy, L2_vz));
612 
613  particleGun->GeneratePrimaryVertex(anEvent);
614  }
615 
616  }
617 
618 
619 
620 
621  if(GEN_VERBOSITY > 5)
622  cout << " Generation done " << endl;
623 }
624 
625 
626 
627 void MPrimaryGeneratorAction::setBeam()
628 {
629  string hd_msg = gemcOpt->optMap["LOG_MSG"].args + " Beam Settings >> " ;
630 
631  // vector of string - filled from the various option
632  vector<string> values;
633  string units;
634 
635  if(input_gen == "gemc_internal")
636  {
637  if(cosmics == "no")
638  {
639  // Getting particle name, momentum from option value
640  values = get_info(gemcOpt->optMap["BEAM_P"].args, string(",\""));
641  string pname = TrimSpaces(values[0]);
642 
643  if(values.size() == 4)
644  {
645  mom = get_number(values[1]);
646  theta = get_number(values[2]);
647  phi = get_number(values[3]);
648  }
649 
650  // making sure the particle exists
651  Particle = particleTable->FindParticle(pname);
652  if(!Particle)
653  {
654  // it may be the "show_all" option. In this case print all available particle names
655  if(pname == "show_all")
656  {
657  for(int i=0; i<particleTable->entries(); i++)
658  cout << hd_msg << " g4 particle: " << particleTable->GetParticleName(i)
659  << " pdg encoding: " << particleTable->GetParticle(i)->GetPDGEncoding() << endl;
660  }
661  // otherwise it's not found. Need to exit here.
662  else
663  cout << hd_msg << " Particle " << pname << " not found in G4 table. Exiting" << endl << endl;
664 
665  exit(0);
666  }
667 
668  // Getting custom beam direction if it's set
669  values = get_info(gemcOpt->optMap["ALIGN_ZAXIS"].args);
670  string align = TrimSpaces(values[0]);
671  if(align == "custom")
672  {
673  ctheta = get_number(values[1]);
674  cphi = get_number(values[2]);
675  }
676 
677  // Getting momentum spread from option value
678  primaryFlat = 0;
679  values = get_info(gemcOpt->optMap["SPREAD_P"].args);
680  dmom = get_number(values[0]);
681  dtheta = get_number(values[1]);
682  dphi = get_number(values[2]);
683  if(values.size() == 4)
684  if(TrimSpaces(values[3]) == "flat")
685  primaryFlat = 1;
686 
687  // Getting vertex from option value
688  values = get_info(gemcOpt->optMap["BEAM_V"].args);
689  units = TrimSpaces(values[3]);
690  vx = get_number(values[0] + "*" + units);
691  vy = get_number(values[1] + "*" + units);
692  vz = get_number(values[2] + "*" + units);
693 
694  // Getting vertex spread from option value
695  values = get_info(gemcOpt->optMap["SPREAD_V"].args);
696  units = TrimSpaces(values[2]);
697  dvr = get_number(values[0] + "*" + units);
698  dvz = get_number(values[1] + "*" + units);
699 
700  // Getting polarization from option value
701  values = get_info(gemcOpt->optMap["POLAR"].args);
702  polDeg = get_number(values[0]);
703  polTheta = get_number(values[1]);
704  polPhi = get_number(values[2]);
705  }
706  else
707  {
708  vector<string> csettings = get_info(cosmics, string(",\""));
709 
710  // parsing information for COSMIC RAYS option
711  if(csettings[0] == "default")
712  {
713  cosmicA = 55.6;
714  cosmicB = 1.04;
715  cosmicC = 64;
716 
717  cminp = get_number(csettings[1], 0)*GeV;
718  cmaxp = get_number(csettings[2], 0)*GeV;
719 
720  // model is valid only starting at 1 GeV for now
721  if(cminp < 1) cminp = 1;
722  }
723  else
724  {
725  cosmicA = get_number(csettings[0], 0);
726  cosmicB = get_number(csettings[1], 0);
727  cosmicC = get_number(csettings[2], 0);
728 
729  cminp = get_number(csettings[3], 0)*GeV;
730  cmaxp = get_number(csettings[4], 0)*GeV;
731 
732  // model is valid only starting at 1 GeV for now
733  if(cminp < 1) cminp = 1;
734 
735  }
736  }
737  }
738 
739  else if( input_gen.compare(0,4,"LUND")==0 || input_gen.compare(0,4,"lund")==0 )
740  {
741  gformat.assign( input_gen, 0, input_gen.find(",")) ;
742  gfilename.assign(input_gen, input_gen.find(",") + 1, input_gen.size()) ;
743  cout << hd_msg << "LUND: Opening " << gformat << " file: " << TrimSpaces(gfilename).c_str() << endl;
744  gif.open(TrimSpaces(gfilename).c_str());
745  if(!gif)
746  {
747  cerr << hd_msg << " Can't open input file " << TrimSpaces(gfilename).c_str() << ". Exiting. " << endl;
748  exit(1);
749  }
750  }
751 
752  else if( input_gen.compare(0,6,"stdhep")==0 || input_gen.compare(0,6,"STDHEP")==0 ||
753  input_gen.compare(0,6,"StdHep")==0 || input_gen.compare(0,6,"StdHEP")==0 )
754  {
755  // StdHep is an (old like LUND) MC generator format in binary form.
756  gformat.assign( input_gen, 0, input_gen.find(",")) ;
757  gfilename.assign(input_gen, input_gen.find(",") + 1, input_gen.size()) ;
758  cout << hd_msg << "StdHEP: Opening " << gformat << " file: " << TrimSpaces(gfilename).c_str() << endl;
759  stdhep_reader = new lStdHep(TrimSpaces(gfilename).c_str());
760 
761  if(!stdhep_reader)
762  {
763  cerr << hd_msg << " Can't open input file " << TrimSpaces(gfilename).c_str() << ". Exiting. " << endl;
764  exit(1);
765  }
766 
767  // For the STEER_BEAM option, we need to have the angles and vertex of the GCARD in BEAM_P and BEAM_V, SPREAD_V
768  // Getting particle name, momentum from option value
769  values = get_info(gemcOpt->optMap["BEAM_P"].args);
770  string pname = TrimSpaces(values[0]);
771  mom = get_number(values[1]);
772  theta = get_number(values[2]);
773  phi = get_number(values[3]);
774 
775  // Getting vertex from option value
776  values = get_info(gemcOpt->optMap["BEAM_V"].args);
777  units = TrimSpaces(values[3]);
778  vx = get_number(values[0] + "*" + units);
779  vy = get_number(values[1] + "*" + units);
780  vz = get_number(values[2] + "*" + units);
781 
782  // Getting vertex spread from option value
783  values = get_info(gemcOpt->optMap["SPREAD_V"].args);
784  units = TrimSpaces(values[2]);
785  dvr = get_number(values[0] + "*" + units);
786  dvz = get_number(values[1] + "*" + units);
787 
788  }
789 
790 
791  // merging (background) events from LUND format
792  if(background_gen != "no")
793  {
794  // file may be already opened cause setBeam is called again in graphic mode
795  if(!bgif.is_open() )
796  {
797  bgif.open(TrimSpaces(background_gen).c_str());
798  if(!bgif)
799  {
800  cerr << hd_msg << " Can't open background input file >" << TrimSpaces(background_gen).c_str() << "<. Exiting. " << endl;
801  exit(1);
802  }
803  }
804  }
805 
806 
807  // %%%%%%%%%%%%%%%
808  // Luminosity Beam
809  // %%%%%%%%%%%%%%%
810 
811  // Getting particle name, momentum from option value
812  values = get_info(gemcOpt->optMap["LUMI_P"].args);
813  string L_pname = TrimSpaces(values[0]);
814  L_mom = get_number(values[1]);
815  L_theta = get_number(values[2]);
816  L_phi = get_number(values[3]);
817 
818 
819  // Getting momentum spread from option value
820  lumiFlat = 0;
821  values = get_info(gemcOpt->optMap["LUMI_SPREAD_P"].args);
822  L_dmom = get_number(values[0]);
823  L_dtheta = get_number(values[1]);
824  L_dphi = get_number(values[2]);
825  if(values.size() == 4)
826  if(TrimSpaces(values[3]) == "flat")
827  lumiFlat = 1;
828 
829 
830  // making sure the particle exists
831  L_Particle = particleTable->FindParticle(L_pname);
832  if(!L_Particle)
833  {
834  // it may be the "show_all" option. In this case print all available particle names
835  if(L_pname == "show_all")
836  {
837  for(int i=0; i<particleTable->entries(); i++)
838  cout << hd_msg << " g4 particle: " << particleTable->GetParticleName(i) << endl;
839  }
840  // otherwise it's not found. Need to exit here.
841  else
842  cout << hd_msg << " Particle " << L_pname << " not found in G4 table. Exiting" << endl << endl;
843 
844  exit(0);
845  }
846 
847  // Getting vertex from option value
848  values = get_info(gemcOpt->optMap["LUMI_V"].args);
849  units = TrimSpaces(values[3]);
850  L_vx = get_number(values[0] + "*" + units);
851  L_vy = get_number(values[1] + "*" + units);
852  L_vz = get_number(values[2] + "*" + units);
853 
854  // Getting vertex spread from option value
855  values = get_info(gemcOpt->optMap["LUMI_SPREAD_V"].args);
856  units = TrimSpaces(values[2]);
857  L_dvr = get_number(values[0] + "*" + units);
858  L_dvz = get_number(values[1] + "*" + units);
859 
860  // Getting parameters from option value
861  values = get_info(gemcOpt->optMap["LUMI_EVENT"].args);
862  NP = (int) get_number(values[0]);
863  TWINDOW = get_number(values[1]);
864  TBUNCH = get_number(values[2]);
865 
866 
867 
868  // %%%%%%%%%%%%%%%%%
869  // Luminosity Beam 2
870  // %%%%%%%%%%%%%%%%%
871 
872  // Getting particle name, momentum from option value
873  values = get_info(gemcOpt->optMap["LUMI2_P"].args);
874  string L2_pname = TrimSpaces(values[0]);
875  L2_mom = get_number(values[1]);
876  L2_theta = get_number(values[2]);
877  L2_phi = get_number(values[3]);
878 
879  // Getting momentum spread from option value
880  lumi2Flat = 0;
881  values = get_info(gemcOpt->optMap["LUMI2_SPREAD_P"].args);
882  L2_dmom = get_number(values[0]);
883  L2_dtheta = get_number(values[1]);
884  L2_dphi = get_number(values[2]);
885  if(values.size() == 4)
886  if(TrimSpaces(values[3]) == "flat")
887  lumi2Flat = 1;
888 
889 
890  // making sure the particle exists
891  L2_Particle = particleTable->FindParticle(L2_pname);
892  if(!L2_Particle)
893  {
894  // it may be the "show_all" option. In this case print all available particle names
895  if(L_pname == "show_all")
896  {
897  for(int i=0; i<particleTable->entries(); i++)
898  cout << hd_msg << " g4 particle: " << particleTable->GetParticleName(i) << endl;
899  }
900  // otherwise it's not found. Need to exit here.
901  else
902  cout << hd_msg << " Particle " << L2_pname << " not found in G4 table. Exiting" << endl << endl;
903 
904  exit(0);
905  }
906 
907  // Getting vertex from option value
908  values = get_info(gemcOpt->optMap["LUMI2_V"].args);
909  units = TrimSpaces(values[3]);
910  L2_vx = get_number(values[0] + "*" + units);
911  L2_vy = get_number(values[1] + "*" + units);
912  L2_vz = get_number(values[2] + "*" + units);
913 
914 
915  // Getting vertex spread from option value
916  values = get_info(gemcOpt->optMap["LUMI2_SPREAD_V"].args);
917  units = TrimSpaces(values[2]);
918  L2_dvr = get_number(values[0] + "*" + units);
919  L2_dvz = get_number(values[1] + "*" + units);
920 
921  // Getting parameters from option value
922  values = get_info(gemcOpt->optMap["LUMI2_EVENT"].args);
923  NP2 = (int) get_number(values[0]);
924  TBUNCH2 = get_number(values[1]);
925 
926 }
927 
928 
930 {
931  delete particleGun;
932  gif.close();
933  bgif.close();
934 }
935 
936 
937 double MPrimaryGeneratorAction::cosmicBeam(double t, double p)
938 {
939  return pow(cosmicA, cosmicB*cos(t))/(cosmicC*p*p);
940 }
941 
942 
943 
944 
945 
946 
947 
STL namespace.
vector< string > get_info(string input, string chars)
get information from strings such as "5*GeV, 2*deg, 10*deg", parses out strings in second argument ...
double get_number(string v, int warn_no_unit)
Returns number with dimension from string, i.e. 100*cm.
map< string, aopt > optMap
Options map.
Definition: options.h:75
void GeneratePrimaries(G4Event *anEvent)
string TrimSpaces(string in)
Removes leading and trailing spaces.