ヒット情報したい(G4VHit
)
有感検出器でのヒット情報を格納するためには
G4VHit
クラスを継承したクラスを作成します。
親クラス
1G4VHit() = default;
2virtual G4VHit() = default;
3virtual void Draw() {};
4virtual void Print() {};
コンストラクターとデストラクターはデフォルトのままでOKです。
Draw()
は、イベントを描画するときのヒット点の見た目を調整する関数です。
Print()
は、ヒットの情報を出力する関数です。
どちらも仮想関数になっているため、必要に応じて自作クラスでoverrideします。
SensorHitクラス
1#ifndef SensorHit_h
2#define SensorHit_h 1
3
4#include "G4VHit.hh"
5#include "G4Step.hh"
6
7namespace ToyMC
8{
9
10class SensorHit : public G4VHit
11{
12 public:
13 // 1. コンストラクターなどを定義
14 SensorHit() = default;
15 ~SensorHit() = default;
16
17 // 2. new / delete を実装
18 inline void* operator new(size_t);
19 inline void operator delete(void* hit);
20
21 // 3. 仮想関数 を実装
22 void Draw() override;
23 void Print() override;
24
25 // 4. カスタム関数
26 void Fill(G4Step *aStep);
27 G4String ToCsvString() const;
28 G4String ToLtsvString() const;
29
30 private:
31 // 5. 測定したい値を定義する
32 G4int fDetectorID{-1};
33 G4int fCopyNumber{-1};
34 G4int fReplicaNumber{-1};
35 G4int fTrackID{-1};
36 G4int fStepID{-1};
37 G4double fEnergyDeposit{0.};
38 G4ThreeVector fXYZ{};
39 G4double fGlobalTime{0.};
40 G4double fStepLength{0.};
41 G4double fTrackLength{0.};
42
43};
44
45// __________________________________________________
46// SensorHitクラス型のヒット配列テンプレートの型エイリアス
47using SensorHitsCollection = G4THitsCollection<SensorHit>;
48
49// __________________________________________________
50// スレッドローカルなメモリアロケーターの定義
51// マルチスレッド環境で、スレッドごとにメモリを確保
52extern G4ThreadLocal G4Allocator<SensorHit> *SensorHitAllocator;
53
54// __________________________________________________
55inline void *SensorHit::operator new(size_t)
56{
57 // new演算子:
58 // コンストラクターの前に実行される特殊関数
59 // SensorHitに必要なメモリをG4Allocatorで割り当てる
60
61 if (!SensorHitAllocator) {
62 SensorHitAllocator = new G4Allocator<SensorHit>;
63 }
64 return (void *)SensorHitAllocator->MallocSingle();
65}
66
67// __________________________________________________
68inline void SensorHit::operator delete(void *hit)
69{
70 // delete演算子
71 // デストラクターの後に実行される特殊関数
72 // new演算子で割り当てたメモリを解放する
73 SensorHitAllocator->FreeSingle((SensorHit *)hit);
74}
75
76}; // namespace ToyMC
77#endif
測定器のヒット情報はG4VHit
クラスを継承してユーザーが定義する必要があります。
ヒット情報の取得/ファイル出力はGeant4シミュレーションで結果を得るためにとても大事なアイテムです。
しかし、初心者向けの解説を見つけることができず、このクラスの役割を理解するのにかなり苦戦しました。
ここでは、その汗と涙と努力の結晶をまとめてみました。
サンプルコードはexamples/basic/B2a/TrackerHit.hh
を参考に改変しました。
有感検出器でヒットを取得するクラスをSensorHit
クラスと名づけました。
このクラスの役割は次のとおりです。
コンストラクター/デストラクターは親クラスを引き継ぐ
SensorHit
型のヒット配列の型エイリアスを定義する(SensorHitsCollection
)スレッドローカルなメモリ割り当てを定義する(
SensorHitAllocator
)最適なメモリ管理のため
new
演算子/delete
演算子を定義するDraw()
/Print()
をoverrideして定義するFill(G4Step *aStep)
と必要なprivate変数を定義する
たくさんの役割/処理が登場するので、順番に紹介します。
コンストラクターとデストラクター
1public:
2 SensorHit() = default;
3 ~SensorHit() = default;
SensorHit
クラスの初期化/削除するときに実行されるコンストラクターとデストラクターは、親クラス(G4VHit
)を引き継いでおきます。
ユーザーがカスタマイズする必要はありません。
型エイリアス: SensorHitsCollection
1using SensorHitsCollection = G4THitsCollection<SensorHit>;
SensorHitsCollection
という名前の型エイリアスを定義しています。
G4THitsCollection
は、親をたどるとstd:vector
型をベースにしたテンプレートクラスです。
なのでSensorHit
型を要素に持つstd:vector
配列とイメージしておけばよいと思います。
1// Sensor.cc
2auto fHitsCollection = new SensorHitsCollection{}
有感検出器のヒット情報(SensorHit
)を格納する配列(SensorHitsCollection
)として使います。
具体的な使い方はSensorクラスを参照してください。
G4ThreadLocalとG4Allocator
1extern G4ThreadLocal G4Allocator<SensorHit> *SensorHitAllocator;
SensorHitAllocator
という名前で、スレッド別にメモリ領域を割り当てるアロケーターを定義しています。
詳細はメモリ割り当てしたい(G4Allocator)に整理しました。
new
演算子とdelete
演算子
1public:
2 inline void* operator new(size_t);
3 inline void operator delete(void* hit);
クラスのインスタンスを作成するときにコンストラクターが呼ばれます。
コンストラクターの中では「メモリを確保する」処理と「メンバー変数を初期化する」処理が実行されます。
new
演算子は「メモリを確保する」処理のために実行される特殊関数です。
ここでSensorHitAllocator
を使って、SensorHit
クラスに必要なメモリ領域を割り当てます。
クラスのインスタンスを削除するときにデストラクターが呼ばれます。
デストラクターの中では「リソースを解放する」処理と「メモリを解放する」処理が実行されます。
delete
演算子は「メモリを解放する」処理のために実行される特殊関数です。
前述のnew
演算子で割り当てたメモリ領域を解放します。
Draw()
とPrint()
関数
Draw
とPrint
は仮想関数です。
必要であればこれらををoverrideして定義します。
Fill(G4Step *aStep)
関数
Fill
は僕が追加したカスタム関数です。
G4Step
を引数と渡し、Fill
の中でprivate変数に値を直接代入するという設計です。
これにより、private変数ごとのゲッター/セッターを作成する必要がなくなります。
有感検出器とヒット用クラス
このページでは「汎用的なヒット」という意味でSensorHit
としました。
可能な限りすべてのデータを取得してファイルに書き出し、
解析でフィルタリングしようという魂胆です。
こういうことができるのが、シミュレーションのおもしろい部分かなと思います。
もし、具体的な検出器があり、その完全再現を目指すならば、それらに特化したクラスを作成するとよいかもしれません。
ヒント
飛跡検出器 →
TrackerHit
カロリメーター →
CaloHit
ホドスコープ →
HodoHit
ピクセル検出器 →
PixelHit
光電子増倍管 →
PmtHit
MPPC →
MppcHit
イベントのヒットしたい(G4HCofThisEvent
)
1// SensitiveDetector: public G4VSensitiveDetector
2
3void SensitiveDetector::EndOfEvent(G4HCofThisEvent *aHC) {
4
5 // HitsCollectionの数を取得する
6 G4int nHC = aHC->GetNumberOfCollections();
7
8 for (G4int i=0; i<nHC; i++) {
9 auto hc = aHC->GetHC(i);
10 G4int nHit = hc->GetSize();
11 for (G4int j=0; j<nHit; j++) {
12 auto hit = hc->GetHit(j);
13 }
14 }
15}
G4Event
を処理する際に、たくさんのG4VHit
(の派生クラスの)オブジェクトが生成されます。
これらのヒット情報は、配列コンテナー(G4HitsCollection
と、そのテンプレートクラスG4THitsCollection
)に集めることができます。
G4Event
はG4HCofThisEvent
というヒット配列を持っています。
イベントごとのヒット情報は、このオブジェクト(のポインター)を介してアクセスてきます。
リファレンス
examples/basic/B2/B2a/TrackerHit.hh