KAHIBARO
Discord Login Register

10.1. PrimaryGeneratorAction

Purpose of the primary generator

In a Geant4 application, the primary generator is the component that tells the simulation which particles enter your geometry, where they come from, and how they move and with what energy. Geant4 itself does not decide this. Instead, you define a user class that inherits from G4VUserPrimaryGeneratorAction. This class is commonly called PrimaryGeneratorAction in example codes, and it is the central place where primary events are created.

The run manager calls the GeneratePrimaries(G4Event* event) method of your PrimaryGeneratorAction once for every event. Each call is responsible for filling that event with one or more primary vertices and primary particles. If you want one particle per event, you generate one primary. If you want a bunch of particles in the same event, you generate several primaries before returning from GeneratePrimaries.

Inside your PrimaryGeneratorAction you normally keep one or more particle source objects, such as a G4ParticleGun or a G4GeneralParticleSource (GPS). The primary generator does not transport particles or apply physics, it only creates the starting conditions. After that, Geant4 uses the physics list to transport and interact those particles in the geometry.

Your PrimaryGeneratorAction is registered with the run manager through the ActionInitialization class. During initialization, the master or worker run manager calls your ActionInitialization::Build() method, where you create an instance of PrimaryGeneratorAction and hand it to the run manager. From that point on, for each event, Geant4 will automatically call GeneratePrimaries.

It is important to keep all event specific particle configuration inside GeneratePrimaries, and leave construction, allocation, and basic configuration of the particle gun or GPS to the constructor of PrimaryGeneratorAction. This separation keeps your code efficient and easy to understand.

The only place where you must create primary particles for each event is GeneratePrimaries(G4Event*) in your class derived from G4VUserPrimaryGeneratorAction. Never try to create primaries in other user action classes.

Creating particles

To create particles, you first need a primary generator object, most simply a G4ParticleGun. In the constructor of your PrimaryGeneratorAction, you typically create the gun and set default properties that will apply to all events unless you change them later.

A minimal pattern looks like this in the header and source files.

In the header file:

cpp
// PrimaryGeneratorAction.hh
#ifndef PrimaryGeneratorAction_hh
#define PrimaryGeneratorAction_hh
#include "G4VUserPrimaryGeneratorAction.hh"
#include "G4ThreeVector.hh"
class G4ParticleGun;
class G4Event;
class PrimaryGeneratorAction : public G4VUserPrimaryGeneratorAction
{
  public:
    PrimaryGeneratorAction();
    ~PrimaryGeneratorAction() override;
    void GeneratePrimaries(G4Event* event) override;
  private:
    G4ParticleGun* fParticleGun;
};
#endif

In the source file constructor you create and configure the gun.

cpp
// PrimaryGeneratorAction.cc
#include "PrimaryGeneratorAction.hh"
#include "G4ParticleGun.hh"
#include "G4ParticleTable.hh"
#include "G4ParticleDefinition.hh"
#include "G4SystemOfUnits.hh"
PrimaryGeneratorAction::PrimaryGeneratorAction()
: G4VUserPrimaryGeneratorAction(),
  fParticleGun(nullptr)
{
  // Create a particle gun that will shoot one particle per event
  G4int nParticle = 1;
  fParticleGun = new G4ParticleGun(nParticle);
  // Choose the particle type
  G4ParticleTable* particleTable = G4ParticleTable::GetParticleTable();
  G4ParticleDefinition* gamma = particleTable->FindParticle("gamma");
  fParticleGun->SetParticleDefinition(gamma);
  // Set a default energy
  fParticleGun->SetParticleEnergy(1.0 * MeV);
  // Set a default starting position
  fParticleGun->SetParticlePosition(G4ThreeVector(0., 0., -10.*cm));
  // Set a default direction (along +z)
  fParticleGun->SetParticleMomentumDirection(G4ThreeVector(0., 0., 1.));
}
PrimaryGeneratorAction::~PrimaryGeneratorAction()
{
  delete fParticleGun;
}

In GeneratePrimaries, you use the configured gun to add the particle to the current event. You can also modify properties on an event by event basis before generating the primary.

cpp
void PrimaryGeneratorAction::GeneratePrimaries(G4Event* event)
{
  // If needed, change energy, position, or direction here
  // For example, a simple scan in energy:
  // G4double eventID = event->GetEventID();
  // G4double energy = (0.5 + 0.01*eventID) * MeV;
  // fParticleGun->SetParticleEnergy(energy);
  // Finally, generate the primary vertex in this event
  fParticleGun->GeneratePrimaryVertex(event);
}

The G4ParticleTable is the standard way to obtain a G4ParticleDefinition for built in particles. You request a particle by name, such as "e-", "e+", "proton", "neutron", "gamma", and many others. The particle definition tells Geant4 the mass, charge, and other properties. The particle gun then uses this definition together with the energy, position, and direction to create the primary particle.

The most common particle properties you control are summarized here.

PropertySetter in G4ParticleGunTypical example
TypeSetParticleDefinition()FindParticle("e-"), FindParticle("proton")
Kinetic energySetParticleEnergy(G4double)1.0 MeV, 100. keV
PositionSetParticlePosition(const G4ThreeVector&)G4ThreeVector(0., 0., 0.)
Momentum directionSetParticleMomentumDirection(const G4ThreeVector&)G4ThreeVector(0., 0., 1.)
Number per eventConstructor argument of G4ParticleGunnew G4ParticleGun(1);

Inside GeneratePrimaries, you can introduce randomness by using Geant4 random utilities. For example, to randomize the starting position within a circle you might write:

cpp
#include "Randomize.hh"
void PrimaryGeneratorAction::GeneratePrimaries(G4Event* event)
{
  G4double r = 1.0 * cm;
  G4double phi = 2.*CLHEP::pi * G4UniformRand();
  G4double x = r * std::cos(phi);
  G4double y = r * std::sin(phi);
  G4double z = -10. * cm;
  fParticleGun->SetParticlePosition(G4ThreeVector(x, y, z));
  fParticleGun->GeneratePrimaryVertex(event);
}

For more complex sources, such as spatial, angular, or energy distributions defined in macro files, you typically replace or supplement the particle gun with a G4GeneralParticleSource. The overall role of PrimaryGeneratorAction stays the same: it owns the source object, configures it, and calls it in GeneratePrimaries to populate each event with primary particles.

Before calling GeneratePrimaryVertex(event), you must set a valid particle definition, position, and direction. If any of these are missing or invalid, the simulation can behave incorrectly or crash.

Views: 10

Comments

Please login to add a comment.

Don't have an account? Register now!