週末はいつも晴れ

社会人3年目の日記です。プログラミングとか旅行とかラーメン。

Geant4を勉強したメモ

周りにGeant4Userがいない(英語が嫌いな)初心者が、一からGeant4に入門するためのメモ
間違いだらけだと思うので、内容は全く保証いたしません!

すごく参考になるリンク

上の2つ以外はあんまり見なかった(下は英語です)。
あとは直接Geant4のヘッダファイルを見に行った方がいいと思います。

Geant4ユーザーが決める事

  • 検出器や遮蔽体の配置
  • シミュレーションで起こす物理現象
  • アクション(最も重要、Phitsで言うtally)

f:id:ikarino99:20141110144244p:plain

検出器や遮蔽体の配置

Geant4を使ったプログラムを書く上で、最も簡単だが、体系によっては最も面倒な部分となる。

G4VUserDetectorConstructionクラスを継承したクラスを作る。
オーバーライドしなければならないメソッド

G4VphysicalVolume* Construct();

この関数の中で、検出器や遮蔽体、その構成物質等を指定する。
戻り値としては、シミュレーション空間全体をあらわすポインタを返す。


物体を定義するには3つのステップを踏む。

  • Solidを定義する
  • LogicalVolumeを定義する
  • 親Volumeの相対位置に配置する

WorldVolumeの定義(シミュレーション空間全体あらわす特別なVolume)

G4VPhysicalVolume* DetectorConstruction::Construct() {
  // NISTから構成物質の情報をfetchするためのマネージャ
  G4NistManager* nist = G4NistManager::Instance();
  

  // Solidを定義する。ここでは物体の形と大きさを指定する。この場合は箱形。
  // WorldVolumeは普通箱形にする。
  G4Box* solidWorld
    = new G4Box("World",  // 名前を決める
		40*cm,    // x方向の長さ。いわゆる直方体の縦の長さの半分の値なので注意!
		40*cm,    // y方向の長さ。いわゆる直方体の横の長さの半分の値なので注意!
		40*cm);   // z方向の長さ。いわゆる直方体の高さの長さの半分の値なので注意!

  // LogicalVolumeを定義する。ここでは構成物質を指定する。
  // NISTから空気の情報を取ってくる。
  G4Material* world_mat = nist->FindOrBuildMaterial("G4_AIR");
  G4LogicalVolume* logicWorld
    = new G4LogicalVolume(solidWorld,         // Solidのポインタ 
			  world_mat,          // 抗生物質のポインタ
			  "World");           // 名前を決める             
  G4VPhysicalVolume* physWorld
    = new G4PVPlacement(0,                     // 回転なし
			G4ThreeVector(),       // (0,0,0)の位置に配置する。といっても親Volumeは無い
			logicWorld,            // LogicalVolumeのポインタ
			"World",               // 名前を決める
			0,                     // 親Volumeは無いので0。
			false,                 
			0);                    
 
  /*
    ここにその他の物体を定義する。
  */
  return physWorld;   // これを返さなければならない。
}

子Volumeの定義

  // NISTから物質の情報をfetchするためのマネージャ
  G4NistManager* nist = G4NistManager::Instance();

  // Solidをつくる。ここでは物体の形と大きさを指定する。この場合は筒型(Tube型)。
  pRMin = 28.1*mm, pRMax=29.5*mm;
  pDz = 12.7*mm;
  pSPhi = 0*degree, pDPhi = 360*degree;
  G4Tubs* solidCaseTube
    = new G4Tubs("CaseTube",  // Solidの名前を決める
		 pRMin,       // 引数は物体の形状による
		 pRMax,
		 pDz/2,
		 pSPhi,
		 pDPhi);
  // Logical Volumeを作る。ここでは構成物質を指定する。この場合は炭素。
  // NISTから炭素の情報を取ってくる。
  G4Material* c_mat = nist->FindOrBuildMaterial("G4_C");
  G4LogicalVolume* logicCaseTube
    = new G4LogicalVolume(solidCaseTube,  // Solidのポインタ
			  c_mat,          // 抗生物質のポインタ
			  "CaseTube");    // LogicalVolumeの名前を決める
  // Placement
  G4ThreeVector pos = G4ThreeVector(0*cm, 0*cm, 0*cm);
  new G4PVPlacement(0,                    // 回転角度
		    pos,                  // 親Volumeに体する相対位置
		    logicCaseTube,        // LogicalVolumeのポインタ
		    "CaseTube",           // 名前を決める
		    logicWorld,           // 親VolumeのLogicalVolumeのポインタ
		    false,
		    0);

もちろん構成物質については、原子核の種類から指定することもできる。

シミュレーションで起こす物理現象

ここではシミュレーションに登場させる粒子の種類と、その相互作用の種類を指定する。
G4VUserPhysicsListクラスを継承したクラスを作る。

が、いろいろと面倒な場合が多い(忘れたりとか)。
そこで、標準のプリセットとしていろいろ提供されている。
このPDFの4ページがわかりやすかったです。
http://geant4.slac.stanford.edu/MSFC2012/ChoosePhys.pdf
粒子のエネルギーによって反応モデルを決める感じで、例えばFTFP_BERT_HPのように指定します。

Actionを決める

Actionは、例えば物理量を取得したりするところ。
Actionを定義するにはGeant4シミュレーション全体の構造を把握する必要がある。
下のような図がドキュメントになくて苦労した。

f:id:ikarino99:20141110125843p:plain

シミュレーションは初期化から始まる。

  • PhysicsListの初期化
  • DetectorConstructionの初期化
  • Actionの初期化

次にシミュレーション(Run)が始まる。
発射粒子を発生させ、二次粒子を含むすべての粒子の運動エネルギーがカットオフエネルギーに達するまでの一連の流れをEventと呼ぶ。
Eventは、一次粒子であるPrimaryから始まる。
相互作用が起こったり、物質と物質の境界に達する一瞬をTrackと呼ぶ。
TrackTrackの間では輸送情報などがStepとして取り込まれる。

Runが終わるごとに情報がMergeされる。
(マルチスレッドの場合、Runが複数になる。結果をMergeできる)

以上をふまえて、Run, Primary, Event, Step, Track, RunactionにおけるActionを、G4VUserActionInitializationクラスを継承した自作クラスに登録していく。

ActionInitializationクラス

G4VUserActionInitializationクラスを継承したクラスでは次のメソッドをオーバーライドする:

  void BuildForMaster() const;
  void Build() const;

上のBuildForMasterはマルチスレッド用の関数。
下のBuild()に登録してく。
例:

void GActionInitialization::Build() const {
  SetUserAction(new PrimaryGeneratorAction);
  SetUserAction(new RunAction);
  SetUserAction(new TrackingAction());
  SetUserAction(new SteppingAction());
  EventAction* eventAction = new EventAction;
  SetUserAction(eventAction);
}

G4VUserPrimaryGeneratorActionクラス

このクラスでは一次粒子を定義する。
オーバーライドしなければならないメソッド

void GeneratePrimaries(G4Event*);

このメソッドは特に工夫するところは無いと思います。
G4ParticleGunクラスのインスタンスを生成して、一次粒子についての情報を登録するだけです。

G4RunActionクラス

このクラスではシミュレーション(Run)の開始、終了時に行う処理を記述する。
オーバーライドするべきメソッド

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

前者は使い方があまり思いつきませんが、後者はシミュレーション終了時に結果を表示したりするのに使えそうです。
あとは経過時間を保持しておくのに使えそうです。

G4EventActionクラス

このクラスではEventの開始、終了時に行う処理を記述する。
オーバーライドするべきメソッド

void BeginOfEvent(const G4Event*);
void EndOfEvent(const G4Event*);

Actionに関するクラスのインスタンスはRunごとに1つしか生成されないので、自分はEvent開始時に変数を初期化するために使っています。
EndOfEventを使ってある程度(10000Eventとか)終わったら結果を小出しするようにしています。
終状態が重要なシミュレーション(あまり無いと思いますが)の場合、ここで物理量を取り出せそうです。

G4SteppingActionクラスとG4TrackingActionクラスとG4StackingActionクラス

G4SteppingActionには1つのオーバーライド可能なメソッドがあります。

void UserSteppingAction(const G4Step* step);

G4TrackingActionには2つのオーバーライド可能なメソッドがあります。

void PreUserTrackingAction(const G4Track*);
void PostUserTrackingAction(const G4Track*);

G4StackingActionには3つのオーバーライド可能なメソッドがあります。

G4ClassificationOfNewTrack ClassifyNewTrack(const G4Track*);
void NewStage();
void PrepareNewEvent();

これらのメソッドを使って必要な粒子の情報を集めていきます。
引数として持っているG4StepやG4Trackを利用したり、それぞれ持っているfp****Managerを通して様々なデータにアクセスします。


書きかけ
G4VSensitiveDetector
G4VHit