MC particle tracking

Dear all,

I am trying to get all MC particles entering a volume, e.g. sensor volume. Even better, passing a defined surface.
The purpose: A beam particle travels through air and interacts with the air and maybe e.g. a trigger counter, some PCB or silicon, before it reaches the detector. So the beam particle will loose energy and do some scattering before hitting the detector. I would like to know, which particle(s) (with what energy and position) actually enters the detector.

Therefore I looked through older threads and I found the following, giving me a starting point.

I started with looping over all MC particles associated with a sensor layer and selecting those without a parent. With this, I thought, I get all primary particles, which are particles coming from outside the volume.

std::vector<const MCParticle*> CaloOutputWriterModule::getPrimaryParticles(int lay) const {
  std::vector<const MCParticle*> primaries;
  // Loop over all MCParticles available
  if(<unsigned long>(lay)) != nullptr){
    for(const auto& mc_particle :<unsigned long>(lay))->getData()) {
      // Check for possible parents:
      const auto* parent = mc_particle.getParent();
      if(parent != nullptr) {
  return primaries;

Maybe I am doing something wrong, for me it seems (when looking at the selected primaries) these can’t be all MC Particles passing/entering the regarded layer.
Could it be, that primary particles are only those particle which came from outside the layer AND also interact with the active sensor volume from the layer?
If so, Is there any option or do you have an idea how to get the information I am looking for?

Many thanks in advance!
Best regards,

1 Like

Hi @trogosch

your approach seems correct to me, this type of lookup is even implemented for the PixelHit object, so if you have that you can simply ask pixel_hit->getPrimaryMCParticles() with the same result. Alternatively, there is some code in the FAQ section of the user manual describing the problem: 11 Frequently Asked Questions (unfortunately the HTML formatting is a bit broken, better check in the PDF version…)

I think the issue is rather what you hint to at the end: we only “see” particles and therefore consider them if they actually interact with the sensor. The reason for this is that we get this information from the Geant4 stepping information through the material - if there is no step, there is no particle. I presume you are looking at a whole bunch of photons and wonder where they went?

So in some sense the issue is related to the topic you linked above - we create particles in Geant4’s ProcessHit() routine which is only called when an interaction has happened: src/modules/DepositionGeant4/SensitiveDetectorActionG4.cpp · master · Allpix Squared / Allpix Squared · GitLab


Hey @simonspa,

many thanks for your reply!

If I understand this correctly, there is no chance to track a particle without interaction, right?
I try to clarify what I am trying to do:
For example a 5GeV electron flies through air and next enters a detector with alternating sensor and absorber layers. First of all there’s a chance that not the 5GeV electron enters the detector but rather an electron/positron or photon with lower energy produced by the 5GeV electron interacting with the air.
Secondly the particle(s) actually entering the detector could pass the first sensor without interacting and start showering somewhere later.
Therefore I was wondering, whether there’s a way to create something like a “virtual plane” in front of the detector to really know what is actually entering the detector with what energy. This “virtual plane” then giving me position and type of tracks passing it. If I understand correctly, my proposed “virtual plane” (even if I have no idea how to implement this) is not possible, because without interaction its not possible to track particles?


Hej @trogosch

it’s definitely possible, we just need to figure out how… :wink:

There is already some work done in the merge request but I’m not entirely sure it’s going in the right direction - just because I didn’t really dig into the relevant Geant4 code.