Skip to content
Snippets Groups Projects
Geant4ParticleGenerator.cpp 6.66 KiB
Newer Older
//==========================================================================
Markus Frank's avatar
Markus Frank committed
//  AIDA Detector description implementation 
//--------------------------------------------------------------------------
// Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN)
// All rights reserved.
Markus Frank's avatar
Markus Frank committed
//
// For the licensing terms see $DD4hepINSTALL/LICENSE.
// For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
Markus Frank's avatar
Markus Frank committed
//
// Author     : M.Frank
//
//==========================================================================
Markus Frank's avatar
Markus Frank committed

// Framework include files
#include <DD4hep/Printout.h>
#include <DD4hep/InstanceCount.h>
#include <DDG4/Geant4Context.h>
#include <DDG4/Geant4Primary.h>
#include <DDG4/Geant4ParticleGenerator.h>
#include <DDG4/Geant4Random.h>
#include <CLHEP/Units/SystemOfUnits.h>
Markus Frank's avatar
Markus Frank committed

#include <G4ParticleTable.hh>
#include <G4ParticleDefinition.hh>
Markus Frank's avatar
Markus Frank committed

// C/C++ include files
#include <stdexcept>
#include <cmath>

Markus Frank's avatar
Markus Frank committed
using namespace dd4hep::sim;
Markus Frank's avatar
Markus Frank committed

/// Standard constructor
Geant4ParticleGenerator::Geant4ParticleGenerator(Geant4Context* ctxt, const std::string& nam)
  : Geant4GeneratorAction(ctxt, nam), m_direction(0,1,0), m_position(0,0,0), m_particle(0)
Markus Frank's avatar
Markus Frank committed
{
  InstanceCount::increment(this);
  m_needsControl = true;
  declareProperty("Particle",      m_particleName = "e-");
  declareProperty("Energy",        m_energy = -1);
  declareProperty("energy",        m_energy = -1);
  declareProperty("MomentumMin",   m_momentumMin = 0.0);
  declareProperty("MomentumMax",   m_momentumMax = 50 * CLHEP::MeV);
Markus Frank's avatar
Markus Frank committed
  declareProperty("Multiplicity",  m_multiplicity = 1);
  declareProperty("Mask",          m_mask = 0);
  declareProperty("Position",      m_position = ROOT::Math::XYZVector(0.,0.,0.));
  declareProperty("Direction",     m_direction = ROOT::Math::XYZVector(1.,1.,1.));
Markus Frank's avatar
Markus Frank committed
}

/// Default destructor
Geant4ParticleGenerator::~Geant4ParticleGenerator() {
  InstanceCount::decrement(this);
}

/// Particle modification. Caller presets defaults to: ( direction = m_direction, momentum = [mMin, mMax])
void Geant4ParticleGenerator::getParticleDirection(int , ROOT::Math::XYZVector& , double& momentum) const {
  getParticleMomentumUniform(momentum);
}

/// Uniform momentum distribution
void Geant4ParticleGenerator::getParticleMomentumUniform(double& momentum) const {
  if (m_energy != -1) {
    momentum = m_energy;
    return;
  }
  Geant4Event&  evt = context()->event();
  Geant4Random& rnd = evt.random();
  if (m_momentumMax < m_momentumMin)
    // We no longer set m_momentumMax to -1 so, not entirely sure a) this will still happen, b) actually work
    momentum = m_momentumMin+(momentum-m_momentumMin)*rnd.rndm();
  else
    momentum = m_momentumMin+(m_momentumMax-m_momentumMin)*rnd.rndm();
Markus Frank's avatar
Markus Frank committed
}

/// Particle modification. Caller presets defaults to: (multiplicity=m_multiplicity)
void Geant4ParticleGenerator::getParticleMultiplicity(int& ) const   {
}

/// Particle modification. Caller presets defaults to: (multiplicity=m_multiplicity)
void Geant4ParticleGenerator::getVertexPosition(ROOT::Math::XYZVector& ) const   {
}

/// Print single particle interaction identified by its mask
void Geant4ParticleGenerator::printInteraction(int mask)  const  {
  Geant4PrimaryEvent* prim = context()->event().extension<Geant4PrimaryEvent>();
  if ( !prim )   {
    warning("printInteraction: Bad primary event [NULL-Pointer].");
    return;
  }
  Geant4PrimaryInteraction* inter = prim->get(mask);
  if ( !inter )   {
    warning("printInteraction: Bad interaction identifier 0x%08X [Unknown Mask].",mask);
    return;
  }
  printInteraction(inter);
}

/// Print single particle interaction identified by its reference
void Geant4ParticleGenerator::printInteraction(Geant4PrimaryInteraction* inter)  const  {
  if ( !inter )   {
    warning("printInteraction: Invalid interaction pointer [NULL-Pointer].");
    return;
  }
  for(const auto& iv : inter->vertices )   {
    for( Geant4Vertex* v : iv.second ){
      print("+-> Interaction [%d] [%.3f , %.3f] GeV %s pos:(%.3f %.3f %.3f)[mm]",
            count, m_momentumMin/CLHEP::GeV, m_momentumMax/CLHEP::GeV, m_particleName.c_str(),
            v->x/CLHEP::mm, v->y/CLHEP::mm, v->z/CLHEP::mm);
      for ( int i : v->out )  {
        Geant4ParticleHandle p = inter->particles[i];
        p.dumpWithVertex(outputLevel(),name(),"  +->");
Markus Frank's avatar
Markus Frank committed
/// Callback to generate primary particles
void Geant4ParticleGenerator::operator()(G4Event*) {
  typedef Geant4Particle Particle;

  if (0 == m_particle || m_particle->GetParticleName() != m_particleName.c_str()) {
    G4ParticleTable* particleTable = G4ParticleTable::GetParticleTable();
    m_particle = particleTable->FindParticle(m_particleName);
    if (0 == m_particle) {
      except("Geant4ParticleGenerator: Bad particle type: %s!", m_particleName.c_str());
Markus Frank's avatar
Markus Frank committed
    }
  }
  Geant4Event& evt = context()->event();
  Geant4PrimaryEvent* prim = evt.extension<Geant4PrimaryEvent>();
  Geant4PrimaryInteraction* inter = new Geant4PrimaryInteraction();
  prim->add(m_mask, inter);

  Geant4Vertex* vtx = new Geant4Vertex();
  int multiplicity = m_multiplicity;
  ROOT::Math::XYZVector unit_direction, position = m_position;
Markus Frank's avatar
Markus Frank committed
  getVertexPosition(position);
  getParticleMultiplicity(multiplicity);
  vtx->mask = m_mask;
  vtx->x = position.X();
  vtx->y = position.Y();
  vtx->z = position.Z();
  inter->vertices[m_mask].emplace_back( vtx );
Markus Frank's avatar
Markus Frank committed
  for(int i=0; i<m_multiplicity; ++i)   {
    ROOT::Math::XYZVector direction = m_direction;
Markus Frank's avatar
Markus Frank committed
    Particle* p = new Particle();
    getParticleDirection(i, direction, momentum);
    unit_direction  = direction.unit();
    p->id           = inter->nextPID();
    p->status      |= G4PARTICLE_GEN_STABLE;
    p->mask         = m_mask;
    p->pdgID        = m_particle->GetPDGEncoding();

    p->psx          = unit_direction.X()*momentum;
    p->psy          = unit_direction.Y()*momentum;
    p->psz          = unit_direction.Z()*momentum;
    p->mass         = m_particle->GetPDGMass();
    p->charge       = 3 * m_particle->GetPDGCharge();
    p->spin[0]      = 0;
    p->spin[1]      = 0;
    p->spin[2]      = 0;
    p->colorFlow[0] = 0;
    p->colorFlow[1] = 0;
Markus Frank's avatar
Markus Frank committed
    p->vsx        = vtx->x;
    p->vsy        = vtx->y;
    p->vsz        = vtx->z;
    //fg: do not set the endpoint to the start point of the particle
    // p->vex        = vtx->x;
    // p->vey        = vtx->y;
    // p->vez        = vtx->z;
    inter->particles.emplace(p->id,p);
Markus Frank's avatar
Markus Frank committed
    vtx->out.insert(p->id);
    printout(INFO,name(),"Particle [%d] %-12s Mom:%.3f GeV vertex:(%6.3f %6.3f %6.3f)[mm] direction:(%6.3f %6.3f %6.3f)",
             p->id, m_particleName.c_str(), momentum/CLHEP::GeV,
	     vtx->x/CLHEP::mm, vtx->y/CLHEP::mm, vtx->z/CLHEP::mm,
Markus Frank's avatar
Markus Frank committed
	     direction.X(), direction.Y(), direction.Z());
  }
}