Geant4零基础学习记录4

B1实例代码学习记录

五、信息收集

前面讲了,G4中的运行根据Run、Event、Track和Step逐步进行运算,如果我们想要统计在一次Run的过程中所有粒子在某个体积内的沉积能量,我们该如何实现呢?

图1 G4的运算流程

首先我们先看一下图一中G4是如何实现运算的,如果我们使用命令/run/beamOn 100发射100个粒子源,那么在这次Run中就会有100个Event。但是这100个粒子并不是同时发射,而是逐个进行发射,在发射第一个粒子源后,其会与我们定义的模型发生反应并产生若干个次级粒子即n个Track。在每个Track的计算过程中,又是根据一个最基本的运算步长Step进行运算,每个Track中又会有若干个Step。G4就是根据上面流程逐步计算最终完成了所有粒子的模拟计算。

OK,我们回到最初的问题,如果我们想要统计在一次Run的过程中所有粒子在某个体积内的沉积能量,G4给我们提供的接口工具能够提取每一个Step的能量沉积,我们该如何实现上述需求呢?

我认为大体上可以分为以下几个步骤:

  1. 获取每个Stpe的能量沉积并判断这个Step是否在我们统计的体积内
  2. 将每个Step的能量沉积加和统计得到每个Track的能量沉积
  3. 将每个Track的能量沉积加和统计得到每个Event的能量沉积
  4. 将每个Event的能量沉积加和统计得到Run总的能量沉积

接下来我们来看一下B1是如何实现的。

1.获取每个Stpe的能量沉积并进行判断

同样我们先看一下头文件的内容:

class SteppingAction : public G4UserSteppingAction
{
  public:
    SteppingAction(EventAction* eventAction);
    ~SteppingAction() override = default;

    // method from the base class
    void UserSteppingAction(const G4Step*) override;

  private:
    EventAction* fEventAction = nullptr;
    G4LogicalVolume* fScoringVolume = nullptr;
};

从文件中可以看到,除了构造与析构函数,有一个UserSteppingAction,它的参数是G4Step*的一个指针,即通过这个接口我们可以获取每一个Step中的信息。另外还有两个参数fEventAction和fScoringVolume,具体作用在.cc文件中进行分析。

首先看一下如何实现获取Stpe的能量沉积:

G4double edepStep = step->GetTotalEnergyDeposit();

可以看到这一步的实现比较简单,直接利用step的成员函数GetTotalEnergyDeposit即可获得。

然后看一下如何判断这一Step是否在体积Shape2内,除了上述内容的实现,我们还可以学到如何通过G4RunManager和step来分别获取对应的逻辑体的指针。

  if (!fScoringVolume) {
    const auto detConstruction = static_cast<const DetectorConstruction*>(
      G4RunManager::GetRunManager()->GetUserDetectorConstruction());
    fScoringVolume = detConstruction->GetScoringVolume();
  }

可以看到在这一段代码中,首先通过G4RunManager获取得到了搭建的DetectorConstruction的指针(接口),之前在讲DetectorConstruction的时候我有提到过,它里面定义了一个方法可以提取Shape2的逻辑体指针,即GetScoringVolume这个方法返回了Shape2的逻辑体指针logicShape2。具体的实现代码在DetectorConstruction.hh与DetectorConstruction.hh文件内:

G4LogicalVolume* GetScoringVolume() const { return fScoringVolume; }
G4LogicalVolume* fScoringVolume = nullptr;
fScoringVolume = logicShape2;

上一步通过G4RunManager获取了我们定义的Shape2的逻辑体指针,接下来我们来获取当前Step所在体积的逻辑体指针:

  // get volume of the current step
  G4LogicalVolume* volume
    = step->GetPreStepPoint()->GetTouchableHandle()
      ->GetVolume()->GetLogicalVolume();

这一步不做过多解释,先记住通过以上方法可以获取当前Step所在体积的逻辑体指针。

接下来即可判断我们Stpe所在的体积是否在Shape2的内部,是的话就获取Step的沉积能量:

if (volume != fScoringVolume) return;

  // collect energy deposited in this step
  G4double edepStep = step->GetTotalEnergyDeposit();

首先判断两个逻辑体是否相等,如果不相等就直接返回结束,如果体积相同则获取该Step的沉积能量,通过以上步骤基本实现了我们第一步需要实现的目标。

2.统计每个Event的能量沉积

B1并没有像我预想的那样先统计Track的能量沉积再统计Event的能量沉积,而是跳过了Track直接统计Event的能量沉积。那么这里可以做一个小实验,是否可以跳过Event直接统计Run的能量沉积呢?我认为理论上是可行的,还是我讲的这个不是核心内容,我可能会在B1学习完后把前面挖的坑一起填一下,这里先学习一下B1是如何实现的。

首先看一下头文件的定义:

class EventAction : public G4UserEventAction
{
  public:
    EventAction(RunAction* runAction);
    ~EventAction() override = default;

    void BeginOfEventAction(const G4Event* event) override;
    void EndOfEventAction(const G4Event* event) override;

    void AddEdep(G4double edep) { fEdep += edep; }

  private:
    RunAction* fRunAction = nullptr;
    G4double   fEdep = 0.;
};

 这里有三个函数分别是BeginOfEventAction、EndOfEventAction以及AddEdep另外还有两个成员变量,一会结合具体的实现方法来解释其作用。这里简单可以解释一下两个Action的方法何时被调用:

 BeginOfEventAction是在每个Event开始之前被调用,EndOfEventAction是在每个Event所有的粒子全部运算结束后被调用。下面看一下其.cc文件如何定义的:

void EventAction::BeginOfEventAction(const G4Event*)
{    fEdep = 0.;    }

可以看到在每个Event开始之前,BeginOfEventAction会将EventAction中的成员变量fEdep赋值为0

然后运行到第一个Step后,在StepAction中的UserSteppingAction方法的最后一行会调用EventAction的AddEdep方法:

EventAction.hh

    void AddEdep(G4double edep) { fEdep += edep; }

 SteppingAction.cc

fEventAction->AddEdep(edepStep);

AddEdep方法会将它的参数edep加到EventAction中的成员变量fEdep中去,这样每运行一个Step,当能量沉积在Shape2中的话,都会将它的沉积能量加到EventAction中的成员变量fEdep中。当一个Event运行结束后,前面也说了Step是运算的最小步长,这样的话整个Event沉积在Shape2的能量就可以被统计。

3.统计Run的能量沉积

其实Run能量沉积的统计与Event的非常类似,先看一下头文件:

class RunAction : public G4UserRunAction
{
  public:
    RunAction();
    ~RunAction() override = default;

    void BeginOfRunAction(const G4Run*) override;
    void   EndOfRunAction(const G4Run*) override;

    void AddEdep (G4double edep);

  private:
    G4Accumulable<G4double> fEdep = 0.;
    G4Accumulable<G4double> fEdep2 = 0.;
};

其中BeginOfRunAction与EndOfRunAction的调用与前面EventAction中的类似,请类比一下进行理解。其AddEdep的作用一会结合具体实现方法进行解释,这里有一个新的数据类型G4Accumulable<G4double>这里再挖一个坑,这里可以先将其理解为一个double类型的变量。

这里RunAction与BeginOfRunAction中的有些内容涉及到多线程的问题,可以先忽略,先看AddEdep方法的定义:

void RunAction::AddEdep(G4double edep)
{
  fEdep  += edep;
  fEdep2 += edep*edep;
}

这里与EventAction的AddEdep方法类似,都是讲AddEdep的参数edep的值加给fEdep,只是这里的fEdep是RunAction的成员变量,并且在其声明的位置已经赋值为0。即当一个Run开始的时候其值为0,当遇到第一个Event在其结束以后后调用EndOfEventAction方法

void EventAction::EndOfEventAction(const G4Event*)
{
  // accumulate statistics in run action
  fRunAction->AddEdep(fEdep);
}

并将每一个Event统计的能量值加给Run中的变量,经过以上的工作就已经基本上完成了最初的目标:统计在一次Run的过程中所有粒子在某个体积内的沉积能量。当然这是一个很简单的例子,但是我认为在这个例子里我们应该去体会每一个RunAction、EventAction以及StepAction包括它们的方法在何时被调用,这样当我们想要统计自己的信息时,我们就可以自己去判断它是在运行的哪一个阶段可以被统计,然后可以去在相应的阶段去查找提取信息的方法。

到这里B1的主要内容基本上就完成了,接下来会将B1的初始化,还有一些未解释清楚地点再写一篇文章进行解释。最后还是希望如果发现有错误的地方帮忙指正,我也是在不断的学习和进步的过程。

  • 20
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值