SensitiveDetectorしたい(G4VSensitiveDetector

測定器の有感検出器でのヒットを収集したい場合は、 G4VSensitiveDetectorクラスを継承したクラスを作成します。

親クラス

1explicit G4VSensitiveDetector(G4String name);
2virtual ~G4VSensitiveDetector() = default;
3virtual void Initialize(G4HCofThisEvent*) {};
4virtual void EndOfEvent(G4HCofThisEvent*) {};
5virtual G4bool ProcessHits(G4Step *aStep, G4TouchableHistory* /*ROhist*/) = 0;

親クラスのメンバー関数を抜粋しました。 コンストラクターとデストラクターは、このまま引き継げばよさそうです。

Initialize()は、イベントの開始時に実行される関数です。 EndOfEvent()は、イベントの終了時に実行される関数です。 これらの仮想関数は、目的に合わせて自作クラスでoverrideします。

ProcessHits()は、ステップが有感検出器の中にあるときに実行される関数です。 この純粋仮想関数は、自作クラスでoverrideが必要です。

Sensorクラス

 1// include/Sensor.hh
 2
 3#ifndef Sensor_h
 4#define Sensor_h 1
 5
 6#include "SensorHit.hh"
 7
 8#include "G4HCofThisEvent.hh"
 9#include "G4Step.hh"
10#include "G4TouchableHistory.hh"
11#include "G4VSensitiveDetector.hh"
12
13namespace ToyMC
14{
15
16class Sensor : public G4VSensitiveDetector
17{
18  public:
19    Sensor(const G4String &name);
20    ~Sensor() = default;
21
22  public:
23    void Initialize(G4HCofThisEvent *aHCE) override;
24    void EndOfEvent(G4HCofThisEvent *aHCE) override;
25    G4bool ProcessHits(G4Step *aStep, G4TouchableHistory *aTouchable) override;
26};
27
28  private:
29    // SensorHitクラスで定義した型エイリアスを使って
30    // 有感検出器で必要なヒット配列を準備する。
31    G4int fHcID = 0;
32    SensorHitsCollection *fHitsCollection{nullptr};
33
34};  // namespace ToyMC
35
36#endif // Sensor_h

上記サンプルでは、G4VSensitiveDetectorクラスを継承して、汎用的なセンサーを仮定したSensorクラスを作成しました。

G4VSensitiveDetectorクラスは抽象基底クラスで、 InitializeProcessHitsEndOfEventの3つの仮想関数を持っています。 これらのメソッドをoverrideして定義します。

コンストラクター(Sensor::Sensor

1Sensor::Sensor(const G4String &name) : G4VSensitiveDetector{name}
2{
3    ;
4}

SensorHitクラスのコンストラクターで、親のG4VSensitiveDetectorクラスの初期化が必要です。 引数(name)をそのまま使って、初期化リストで初期化しています。

注釈

G4VSensitiveDetectorのコンストラクターにはexplicitキーワードが付けられています。 これは、暗黙の型変換を防ぐ ためのキーワードです。

1// OK
2G4VSensitiveDetector detector{"DetectorName"};
3
4// NG
5// G4String -> G4VSensitiveDetector に勝手に変換されるのを防止
6G4VSensitiveDetector detector = "DetectorName";

初期化したい(Sensor::Initialize

 1// src/Sensor.cc
 2
 3#include "Sensor.hh"
 4
 5void Sensor::Initialize(G4HCofThisEvent *aHCE)
 6{
 7    // ヒット配列を初期化
 8    fHitsCollection = new SensorHitsCollection{};
 9    aHCE->AddHitsCollection(fHcID, fHitsCollection);
10};

Initializeは、G4EventManagerがイベント処理を開始する時に実行されます(BeginOfEventActionより先に実行されます)。

G4HCofThisEventは、ひとつイベント(G4Event)に紐づいたヒット配列(G4HitsCollection)です。

イベントの開始時に、このヒット配列を初期化しておきます。

集計したい(Sensor::EndOfEvent

 1// src/Sensor.cc
 2
 3#include "Sensor.hh"
 4
 5void Sensor::EndOfEvent(G4HCofThisEvent *aHCE)
 6{
 7    G4int entries = fHitsCollection->entries();
 8    // ヒット配列を取得
 9    aHCE->Get...
10
11};

EndOfEventはイベントの最後に呼ばれます。 G4HCofThisEventからヒット配列を取り出し、 ヒット配列のデータを集計したり、 ファイルに書き出したりできます。

ヒット処理したい(Sensor::ProcessHits

 1// src/Sensor.cc
 2
 3#include "Sensor.hh"
 4
 5#include "G4Step.hh"
 6
 7G4bool Sensor::ProcessHits(G4Step *aStep, G4TouchableHistory* /* aTouchable */) {
 8
 9    // ヒットを残さない場合
10
11    // 例1: エネルギー損失がない
12    if (aStep->GetTotalEnergy() <= 0) {
13        return false;
14    }
15
16    // 例2: 中性粒子
17    if (aStep->GetTrack()->...粒子の電荷を取得 == 0) {
18        return false;
19    }
20
21    // ヒット処理の準備
22    auto pre_step = aStep->GetPreStepPoint();
23    auto track = aStep->GetTrack();
24    auto pv = aStep->GetPreStepPoint()->GetPhysicalVolume();
25    auto lv = pv->GetLogicalVolume();
26
27    // SensorHitオブジェクトを作成
28    auto hit = new SensorHit{};
29
30    // ヒット情報を代入
31    // - SensorHit::Fill(G4Step *aStep)のカスタム関数を追加
32    // - SensorHitの内部変数に値を代入
33    hit->Fill(aStep);
34
35    // 代入したヒット情報を確認
36    hit->Print();
37
38    // ヒット配列にヒット(SensorHit)を追加
39    fHitsCollection->insert(hit);
40
41    return true;
42};

ProcessHitsはSensitiveDetectorのヒット情報を処理するときのメインの関数です。 データを残すかどうかの条件や、 どのようなデータを取得するかは、 ユーザーがこの関数の中で実装します。 この関数は、ステップが有感検出器の中にあるとき、自動的に呼ばれます。

ひとつめの引数は(G4Step *aStep)になっているので、 G4Step操作G4Track操作でできることを使って、 取得したい値を定義できます。 ふたつめの引数は(G4TouchableHistory*)となっていますが、 これはもう使われてない(obsolete)そうです。

ヒント

おそらくUserSteppingActionの亜種です。 (たぶん)G4SDManagerが管理してくれているため、ステップが有感検出器の中にあるとき、ユーザーが境界判断しなくても、自動的に呼ばれます。 SensitiveDetectorを使う方が楽ちんです。

測定器のヒット情報を知りたい場合は、SensitiveDetectorだけを定義すればOKです。

有感検出器を設定したい(SetSensitiveDetector

 1#include "Geometry.hh"
 2#include "Sensor.hh"
 3
 4#include "G4SDManager.hh"
 5
 6void Geometry::ConstructSDandField()
 7{
 8    // Sensorを作成
 9    auto sensor = new Sensor("検出器名");
10
11    // 論理ボリュームに割り当て
12    SetSensitiveDetector("論理ボリューム名", sensor);
13
14    // SDManagerに追加
15    auto sm = G4SDManager::GetSDMpointer();
16    sm->AddNewDetector(sensor);
17}

有感検出器として利用するためには、 Sensorクラスのオブジェクトを論理ボリュームに割り当て、 さらにG4SDManagerに登録します。

G4VUserDetectorConstructionから継承した ConstructSDandField関数の中で、 論理ボリュームを有感検出器(SensitiveDetector)に設定します。

ここではG4VUserDetectorConstructionが持っているprotectedなメンバー関数SetSensitiveDetectorを使っています。 この関数は、論理ボリュームの名前を使って有感検出器を設定できます。

参考

G4LogicalVolumeもpublicなメンバー関数SetSensitiveDetectorを持っています。 そちらを使って有感検出器を設定する方法もあります。

リファレンス