Custom user-defined ion with decay table never decays during tracking

Summary

My goal is to create ions with user-defined static properties and a user-defined decay scheme.
The new ion should transport and interact with matter like any other ion defined in Geant4.

Problem:
The ion never decays during tracking, even though its lifetime is extremely short.

—————————————————————————————————————————–-
Geant4 version: 11.3.2
Description: Ubuntu 24.04.2 LTS
Linux LT-25-0031 6.6.87.2-microsoft-standard-WSL2 #1 SMP PREEMPT_DYNAMIC Thu Jun 5 18:30:46 UTC 2025 x86_64 x86_64 x86_64 GNU/Linux
g++ (Ubuntu 13.3.0-6ubuntu2~24.04.1) 13.3.0
cmake version 3.28.3
——————————————————————————————————————————–

Greetings to the community,
I would like to define ions with the following parameters completely defined by the user.
G4Ions(
const G4String& aName, G4double mass,
G4double width, G4double charge,
G4int iSpin, G4int iParity,
G4int iConjugation, G4int iIsospin,
G4int iIsospin3, G4int gParity,
const G4String& pType, G4int lepton,
G4int baryon, G4int encoding,
G4bool stable, G4double lifetime,
G4DecayTable *decaytable, G4bool shortlived,
const G4String& subType =“”,
G4int anti_encoding =0,
G4double excitation = 0.0
);
including a user-defined decay scheme.
These ions should behave exactly like any other ion implemented in Geant4 (transportation, interaction with matter, etc.).

Below are the steps I followed.

1) I defined a custom ion type inheriting from G4Ions
#ifndef DRAGONION_HH
#define DRAGONION_HH

#include “G4Ions.hh”

namespace DRAGON
{
class DRAGONIon : public G4Ions {
public:
DRAGONIon(const G4String& name,
G4double mass,
G4double width,
G4double charge,
G4int iSpin,
G4int iParity,
G4int iConjugation,
G4int iIsospin,
G4int iIsospin3,
G4int gParity,
const G4String& type,
G4int lepton,
G4int baryon,
G4int encoding,
G4bool stable,
G4double lifetime,
G4DecayTable* decaytable,
G4bool shortlived,
G4int Z,
G4int A);
virtual ~DRAGONIon() = default;
};
}
#endif

#include “DRAGONIon.hh”

namespace DRAGON
{
DRAGONIon::DRAGONIon(const G4String& name,
G4double mass,
G4double width,
G4double charge,
G4int iSpin,
G4int iParity,
G4int iConjugation,
G4int iIsospin,
G4int iIsospin3,
G4int gParity,
const G4String& type,
G4int lepton,
G4int baryon,
G4int encoding,
G4bool stable,
G4double lifetime,
G4DecayTable* decaytable,
G4bool shortlived,
G4int Z,
G4int A)
: G4Ions(name, mass, width, charge, iSpin, iParity, iConjugation,
iIsospin, iIsospin3, gParity, type, lepton, baryon,
encoding, stable, lifetime, decaytable, shortlived)
{
SetAtomicNumber(Z);
SetAtomicMass(A);
}
}

2) Inside a method called ureact() (which is called from ConstructParticle()), I create the ions involved
//C
//C → Define Ne19++++ ion
//C

ipart = 61;
aamass = 19.*0.93149432;
ubuf[0] = 4;
tlif = 1000.;

if(!G4ParticleTable::GetParticleTable()->FindParticle("Ne19++++ "))
{
DRAGONIon* ion = new DRAGONIon(
"Ne19++++ ",
aamass*GeV,
0.0,
ubuf[0]eplus,
1, +1, 0, 0, 0, 0,
“nucleus”,
0, +19, ipart,
false,
tlif
s,
nullptr,
false,
10,
19
);
}

3) I define and assign the decay scheme with something like this
brat[0] = 95.;
mode[0] = 84;
brat[1] = 5.;
mode[1] = 83;

G4DecayTable* decayTable2 = new G4DecayTable();
for (int i = 0; i < 10; i++)
{
if(mode[i])
{
G4VDecayChannel* decayChannel = new G4PhaseSpaceDecayChannel(
G4ParticleTable::GetParticleTable()->FindParticle(82)->GetParticleName(),
brat[i]/100.,
1,
G4ParticleTable::GetParticleTable()->FindParticle(mode[i])->GetParticleName()
);
decayTable2->Insert(decayChannel);
}
}

DRAGONIon* part1 =
dynamic_cast<DRAGONIon*>(G4ParticleTable::GetParticleTable()->FindParticle(82));
part1->SetDecayTable(decayTable2);
decayTable2->DumpInfo();

4) Immediately after that, I print the ion information and obtain
===== Ion Properties =====
Name: 16O_3
Type: nucleus
SubType:
PDG Encoding: 89
Mass: 14.9061 GeV
Charge: 6 e
Spin: 0
Magnetic Moment: 0
Parity: 1
Isospin: 0
Isospin3: 0
Stable: No
Lifetime: 4.7e-15 s
Atomic Number (Z): 8
Atomic Mass (A): 16
Excitation Energy: 0 eV

G4DecayTable: 16O_3
0: BR: 0.9997 [Phase Space] : 16O_
1: BR: 0.00027 [Phase Space] : 16O_1
2: BR: 8e-05 [Phase Space] : 16O_2

However, during tracking I would expect these ions to decay almost immediately, given their extremely short lifetime. Nevertheless, they never decay.

5) This is the physics list implementation

DRAGONPhysicsList::~DRAGONPhysicsList()
{
delete fMessenger;
delete fDecPhysicsList;
delete fEmPhysicsList;
delete fIonPhysicsList;
delete fStepLimiterPhysics;
delete fHadElastPhysics;
delete fHadPhysicsFTFP_BERT;
}

void DRAGONPhysicsList::ConstructParticle()
{
// Particle table initialization
fEmPhysicsList->ConstructParticle();
fDecPhysicsList->ConstructParticle();
fIonPhysicsList->ConstructParticle();
fHadElastPhysics->ConstructParticle();
fHadPhysicsFTFP_BERT->ConstructParticle();
// Define radioactive ion reactions
ureact();
}

void DRAGONPhysicsList::ConstructProcess()
{
G4cout << “From Physics ConstructProcess()” << G4endl;
AddTransportation();
fEmPhysicsList->ConstructProcess();
fDecPhysicsList->ConstructProcess();
fIonPhysicsList->ConstructProcess();
fStepLimiterPhysics->ConstructProcess();
fHadElastPhysics->ConstructProcess();
fHadPhysicsFTFP_BERT->ConstructProcess();
AddIonGasModels();
}

Any help or suggestions would be greatly appreciated.

Best regards.

Dear @norach1991 ,

What is the purpose of these DRAGONIONS ? There are ways to use a “regular” Ne-19 ion and simply hijack it’s decay table. You can do so by “overriding” the file to be used as the decay table. Whether a short [too] short lived particle is transported or decayed immediately is another question.

/process/had/rdm/setRadioactiveDecayFile Z A FILE

you can copy the file from the regular dataset, just grab z7.a19, modify it and point to it.

/Pico