Geant 4 vs NIST results

_Geant4 Version: 10.7
_Operating System: Ubuntu WSL

Hi everyone,

As I proceed with the design of a PCB antenna for space applications, I decided—before analyzing the effects of space radiation on a multilayer structure—to first validate my simulation code by comparing its results with reference data from the literature.

In this particular case, I studied the depth-dose distribution for protons in an aluminum monolayer and obtained the following results:

we simulated single proton particles with energies ranging from 1 to 100 MeV.

However, I’m observing a discrepancy of about one order of magnitude compared to the expected values, and I haven’t yet identified the source of the error.

Here are some additional details:

a. PrimaryGenerationAction

PrimaryGeneratorAction::PrimaryGeneratorAction()
{
fParticleGun = new G4ParticleGun(1); // 1 particle per event

G4ParticleTable* particleTable = G4ParticleTable::GetParticleTable();
G4ParticleDefinition* proton = particleTable->FindParticle(“proton”);
fParticleGun->SetParticleDefinition(proton);

} […]

b. PhysicsList

#include “PhysicsList.hh”

#include “G4DecayPhysics.hh”
#include “G4EmStandardPhysics_option4.hh” // EM Opt4 for higher accurancy
//#include “G4EmLivermorePhysics.hh”
#include “G4VUserPhysicsList.hh”

#include “G4HadronPhysicsQGSP_BIC.hh” // Hadron Physics per space < 1.5 GeV
#include “G4IonPhysics.hh”
//#include “G4GenericIon”
#include “G4ParticleTable.hh”
#include “G4ProcessManager.hh”
#include “G4StoppingPhysics.hh”
#include “G4SystemOfUnits.hh”
#include “G4Transportation.hh”
#include “G4UnitsTable.hh”

// Particelle coinvolte
#include “G4Alpha.hh”
#include “G4Deuteron.hh”
#include “G4Electron.hh”
#include “G4Gamma.hh”
#include “G4GenericIon.hh”
#include “G4Neutron.hh”
#include “G4PionMinus.hh”
#include “G4PionPlus.hh”
#include “G4PionZero.hh”
#include “G4Positron.hh”
#include “G4Proton.hh”
#include “G4Triton.hh”

PhysicsList::PhysicsList()
{
// === Fisica elettromagnetica dettagliata (Opt4) ===
RegisterPhysics(new G4EmStandardPhysics_option4());
//RegisterPhysics(new G4EmLivermorePhysics());

// === Fisica adronica (Binary Cascade sotto 1.5 GeV) ===
RegisterPhysics(new G4HadronPhysicsQGSP_BIC());

// Decadimenti (muoni, pioni, nuclei ecc.)
RegisterPhysics(new G4DecayPhysics());

// Stopping physics (es. muoni o anti-protoni a riposo)
RegisterPhysics(new G4StoppingPhysics());

// Fisica degli ioni leggeri e pesanti
RegisterPhysics(new G4IonPhysics());
}

PhysicsList::~PhysicsList() {}

void PhysicsList::ConstructParticle()
{
// Definizione manuale delle particelle pių importanti
G4Proton::ProtonDefinition();
G4Neutron::NeutronDefinition();
G4Gamma::GammaDefinition();
G4Electron::ElectronDefinition();
G4Positron::PositronDefinition();
G4PionPlus::PionPlusDefinition();
G4PionMinus::PionMinusDefinition();
G4PionZero::PionZeroDefinition();
G4Deuteron::DeuteronDefinition();
G4Triton::TritonDefinition();
G4Alpha::AlphaDefinition();
G4GenericIon::GenericIonDefinition();

// Necessario per il trasporto nello spazio
AddTransportation();
}

void PhysicsList::ConstructProcess()
{
// Recupera il particle table
G4ParticleTable* particleTable = G4ParticleTable::GetParticleTable();

for (int i = 0; i < particleTable->entries(); ++i) {
G4ParticleDefinition* particle = particleTable->GetParticle(i);
G4ProcessManager* pManager = particle->GetProcessManager();

if (!pManager) continue;

// Aggiungi processo di trasporto
pManager->AddProcess(new G4Transportation(), -1, -1, 1);

}
}

void PhysicsList::SetCuts()
{
G4cout << “[DEBUG] SetCuts(): inizio impostazione cut values…” << G4endl;

if (G4ParticleTable::GetParticleTable()->FindParticle(“proton”)) SetCutValue(0.001 * mm, “proton”);

if (G4ParticleTable::GetParticleTable()->FindParticle(“e-”)) SetCutValue(0.001 * mm, “e-”);

if (G4ParticleTable::GetParticleTable()->FindParticle(“e+”)) SetCutValue(0.001 * mm, “e+”);

if (G4ParticleTable::GetParticleTable()->FindParticle(“gamma”)) SetCutValue(0.001 * mm, “gamma”);

DumpCutValuesTable();
G4cout << “[DEBUG] SetCuts(): completato” << G4endl;
}

c. Main.cc

[…]
// ===== [ User Initialization Classes ] =====
runManager->SetUserInitialization(new DetectorConstruction()); // Geometria
runManager->SetUserInitialization(new QBBC()); // Physics list
runManager->SetUserInitialization(new ActionInitialization()); //
[…]

do you have any suggestion?
I can share more detail about the code if necessary.

Hi @Simone_Ripandelli

Thanks for your post.

Is this discrepancy present in newer versions of Geant4?

Also, could you please confirm if the discrepancy is present when using the builtin physics lists provided by Geant4? You can register them easily as shown here [1]. It would be great if you could try out “FTFP_BERT” and “FTFP_BERT_EMZ”.

Thank you for your time.

Best,
Alvaro

[1] Geant4-Beginner-Course/applications/intermediate-application/yourMainApplication.cc at 6f7e3d17a5878f3154cd4a922f176bed891bffaa · mnovak42/Geant4-Beginner-Course · GitHub

Hi and thank you for your feedback.

Thanks to your response, we were able to identify the issue: it was simply an error made during the post-processing analysis.

Essentially, we were comparing two different quantities. With Geant4, we were deriving maximum dose values that were actually associated with peaks observed downstream in the simulation, related to particle-matter interactions, but not directly corresponding to the Bragg peak—and therefore not related to the actual penetration depth in the material. It was a conceptual mistake: we weren’t truly evaluating the point where dE/dx = 0, but instead making an estimate without considering that even during the initial interactions, the particles continue to propagate (secondary particles due to interactions).

After re-running the simulations and comparing the results with the NIST CSDA values, we found they match. We can now move forward with the design of the PCB for the antenna we’re developing.

Thank you very much for sparking the reasoning process.

1 Like