Geant4 Version: 11.2.1
Operating System: MacOS 15.3.1
Compiler/Version: AppleClang 16.0.0.16000026
CMake Version: 3.31.5
Dear developers,
I’d need some help to understand how to bias certain gamma processes with the more recent Geant4 versions.
I’m trying to build a custom biasing class based on the provided examples, e.g. GB07, GB04 and such.
In my application I created a biasing operation that creates N copies of the same muon pair created by a photon via GammaToMuPair. Similarly, I’d like to write a biasing class to change the cross section of the process.
My problem is that I noticed that the operator is never really called. I tracked down the reason to the fact that in more recent version of Geant4 the gamma process is treated differently than before.
If I’m not mistaken, now gamma only has Transportation
and GammaGeneralProc
, while before the processes were listed explicitly, such as conv
. For instance, the example GB07 has the lines
// ---- collect gamma conversion process:
auto gammaProcesses = G4Gamma::Definition()->GetProcessManager()->GetProcessList();
for (size_t i = 0; i < gammaProcesses->size(); ++i) {
auto procname = (*gammaProcesses)[i]->GetProcessName();
if ((*gammaProcesses)[i]->GetProcessName() == "biasWrapper(conv)") {
fConversion = (*gammaProcesses)[i];
break;
}
}
in which I noticed that the if condition is only met when using Geant4 11.0.4, where the biasWrapper(conv)
process exists.
So my question is: how can I register the “GammaToMuPair” process (or “conv”) for biasing? At the moment my implementation
// Introduce biasing
G4GenericBiasingPhysics *biasingPhysics = new G4GenericBiasingPhysics();
std::vector<G4String> processToBias{"GammaToMuPair"};
biasingPhysics->PhysicsBias("gamma", processToBias);
physicsList->RegisterPhysics(biasingPhysics);
does not result in a call of the biasing operator even when the process actually occurs.
On the other hand, if I change the process to bias to GammaGeneralProc
my biasing operator is called, but then I can’t find a way to filter the calls only for the process I need, not even by checking
if (subtype != G4EmProcessSubType::fGammaConversionToMuMu)
{
return processFinalState;
}
or similar.
Thank you for your help,
Davide
I seem to have figured out how to do it, so I’m going to post the solution here in case it’s useful for someone else. The examples provided in the code are probably not up to date with the latest implementation of gamma processes. The correct process to bias now is actually GammaGeneralProc
(not a more specific one like GammaToMuPair
) and then the process type and subtype (or derived object) need to be checked when the biasing is called. The way I’m doing it is, inside the ApplyFinalStateBiasing
function,
const G4VProcess *selectedProcess =
step->GetPostStepPoint()->GetProcessDefinedStep();
const G4GammaConversionToMuons *gammaToMuPair =
dynamic_cast<const G4GammaConversionToMuons *>(selectedProcess);
if (!gammaToMuPair)
{
return processFinalState;
}
The issue in the previous implementation was that checking for the wrapped process type and subtype with
callingProcess->GetWrappedProcess()->GetProcessType();
callingProcess->GetWrappedProcess()->GetProcessSubType();
always returns 2 and 16 respectively, that are the signature of the GammaGeneralProc
. The solution is either to check using polymorphism or using type and subtype on the process defined on the step. The specific gamma process, e.g., conv
, GammaToMuPair
, etc, is not exposed at the track level, but only selected at the step level. This brings me to a question. The way I’m now able to split the muon production is very inefficient, because I need to call the PostStepDoIt(*track, *step)
function of the wrapped process to generate N new pairs. But, because the code does not expose the GammaToMuPair
process explicitly, I basically need to invoke processFinalState = gammaGeneralProc->PostStepDoIt(*track, *step)
and reject everything that is not a muon pair, which is very inefficient. I could not find a way to explicitly force the muon pair production. Since this seems a very intentional design choice of the code, is there a reason why this approach would be discouraged? Is there a more efficient way of doing it? Otherwise, is it possible to expose the subprocess of the gamma process and invoke it directly?
Basically right now I’m stuck with
while (nCalls < m_SplittingFactor)
{
nWhileLoopIterations++;
// This is a call to the original PostStepDoIt process, renewed
// every time in the loop.
// This way new secondaries are created at every iteration
processFinalState =
gammaGeneralProc->PostStepDoIt(*track, *step);
firstmuontrack = processFinalState->GetSecondary(0);
secondmuontrack = processFinalState->GetSecondary(1);
if (!(IsMuon(*firstmuontrack) && IsMuon(*secondmuontrack)))
{
continue;
}
... Save muons in particle change ...
}
Thanks,
Davide