Distinguish between alternative interaction processes and competing processes
We need to distinguish between alternative processes and competing processes to not unnecessarily sacrifice performance in the process loop.
I am talking about sibyll::Interaction and sibyll::NuclearInteraction. I already wrote in #221 (closed) that I think these should be merged. These are alternatives: one handles the particle or the other, depending on the particle type. They are never competing. Competing processes differ from alternative processes: both have a finite interaction length for the particle and the MC simulation has to pick one randomly.
Selecting a competing process requires more computational work: one has to calculate the inverse interaction length for each process, sum it to the running inverse lambda and compare it with the RNG value. These are many more CPU cycles than a simple if
on the particle type, which is all that is needed for two alternative processes.
SelectInteraction(...)
of the ProcessSequence currently handles both competing and alternative processes in the same way, which is possible since alternatives can be handled like competing processes. The process which is not handling the particle returns an infinite interaction length and never gets selected. Still, more instructions are needed that necessary in this case.
Minimal pseudo-code that has to be executed to generate an interaction for two alternative processes
if (particle is type A) {
processA.DoInteraction(particle);
ret = EProcessReturn::eInteracted;
}
else {
// identical else branch, only one is executed
}
Minimal pseudo-code that has to be executed by the ProcessSequence to generate an interaction for two competing processes
// lambda_inv_count and lambda_select are set elsewhere
auto ret = EProcessReturn::eOk;
lambda_inv_count += processA.GetInverseInteractionLength(particle);
if (lambda_select < lambda_inv_count) { // if-A
processA.DoInteraction(vS);
ret = EProcessReturn::eInteracted;
}
if (ret == EProcessReturn::eOk) {
lambda_inv_count += processB.GetInverseInteractionLength(particle);
if (lambda_select < lambda_inv_count) { // if-B
processA.DoInteraction(vS);
ret = EProcessReturn::eInteracted;
}
}
If if-A is not successful because of if (lambda_select < lambda_inv_count)
fails although processA
is the right one to handle this particle, then if-B has to be executed even though it is already clear at this point that processB.GetInverseInteractionLength(particle)
is 0 and the second process is also not selected.
If we generally want to be able to handle nuclei with a different process classes, merging sibyll::Interaction and sibyll::NuclearInteraction is only an intermediate the solution. In this case, we could have something like the SwitchProcess
that selects an alternative based on the particle type. It would switch on the particle being a nucleus or not.