Geant 4 的一个坑

本文主题在 Geant 4 的官方论坛讨论在此. 感谢论坛用户 maire 没有它的提醒我现在还没走出代码苦海.

遇到问题

因为给最近在学习 Geant 4, 在老师的要求下准备写一个程序模拟获得质子行进的 d𝐸d𝑥 数据, 一开始我直接记录下每个 Step 的能量损失以及 PostStepPoint 对应的坐标. 然后对于质子穿透范围划成多个 bin, 将能量沉积填入其中.

但是事与愿违: 我得到了这样的直方图:

图 1最初得到的能量沉积直方图

它不正常, 一个质子行进的 d𝐸d𝑥 作图应该表现为单峰结构: Bragg Peak. 但是可以看到在𝑥=5cm 上出现一个峰值.

OK, 出现了问题就去找问题.

寻找源头

理应𝑥=5cm附近不会有任何特殊性质, 至少在我的代码中 – 说明问题出在 Geant 4, 我有什么地方用错了! 于是作图寻找什么与我的预期不一致:

图 2提示模拟结果存在不一致的步长分布

这两张图是我觉得提示了不一致的地方:

OK, 问题成因就很容易了解了, 因为有相当事例的 Step 跨越了多个 bin, 并且有相当部分因为截断堆在了一起, 造成了一个 bin 取值很大.

查看源代码研究 hIoni 过程究竟怎么定义的

云里雾里的看了这里的众多代码 (点名批评 VScode, 打开这个代码, 看一会, 我的内存就没了), 勉强有了头绪.

那么我们就对于 G4hIonisation 的行为有了一些图像了:

怎么平均?

现在我期望将跨越多个 bin 的数据平均到其跨越的每个 bin, 可惜, 这件事情很麻烦, 因为 CERN ROOT 遍历一个 Tree 不是很方便(你可以很轻松的从 Tree 中获得直方图, 但是要遍历 Tree 却没有提供迭代器, 只能靠 TBranchAddress 来遍历)

这个时候出现论坛回复, 告诉我 TestEM11 可以做一样的事情, 还没有我遇到的问题.

跑去看一眼 TestEM11 的代码:

代码 1TestEM11 中随机化能量沉积位置的实现
void SteppingAction::UserSteppingAction(const G4Step* step)
{
...
 //longitudinal profile of deposited energy
 //randomize point of energy deposotion
 //
 G4StepPoint* prePoint  = step->GetPreStepPoint();
 G4StepPoint* postPoint = step->GetPostStepPoint();
 G4ThreeVector P1 = prePoint ->GetPosition();
 G4ThreeVector P2 = postPoint->GetPosition();
 G4ThreeVector point = P1 + G4UniformRand()*(P2 - P1);
 if (step->GetTrack()->GetDefinition()->GetPDGCharge() == 0.) point = P2;
 G4double x = point.x();
 G4double xshifted = x + 0.5*fDetector->GetAbsorSizeX();
 analysisManager->FillH1(1, xshifted, edep);
...
}

马上干一样的事情:

图 3随机化沉积位置后修正的直方图

修好了, 美妙.

经验