PMTを作りたい(BuildPMT

 1G4LogicalVolume *BuildPMT()
 2{
 3    // パラメーター設定
 4    G4String logical_name{"PMTWindow"};
 5    G4String material_name{"G4_PLEXIGLASS"};
 6    G4double radius{3.81 * cm};  // 3in.管
 7    G4double thickness{1.0 * mm};
 8
 9    // 形状を定義
10    // PMTの入射窓を、平たい円柱で作成
11    G4double r_min{0. * cm};
12    G4double r_max{radius};
13    G4double half_z{0.5 * thickness};
14    G4double s_phi{0. * deg};
15    G4double d_phi{360. * deg};
16
17    auto solid = new G4Tubs{
18        "pmtSolid",
19        r_min,    // 内径
20        r_max,    // 外径
21        half_z,   // 高さ(厚み)
22        s_phi,    // 開始角度
23        d_phi,    // 回転角
24    };
25
26    // 材料を定義
27    // 入射窓はプレキシガラス(アクリル)に設定
28    auto nm = G4NistManager::Instance();
29    auto material = nm->FindOrBuildMaterial("G4_PLEXIGLASS");
30
31    // 論理ボリュームを定義
32    auto logical = new G4LogicalVolume(
33        solid,        // G4VSolid
34        material,     // G4Material
35        logical_name  // 名前
36    );
37
38    return logical;
39}

光電子増倍管(PMT)の入射窓だけを作成しました。 PMTに入射した光子の数を知りたい場合は、G4SensitiveDetectorを追加し、データを残す必要があります。

光子数を数えたい(PMTSD

光子数を数えるためには、最低限つぎの設定が必要です。

  1. G4VSensitiveDetectorを継承したクラスを作成する ProcessHits()をオーバーライドし、入射してきたトラックがG4OpticalPhotonかどうかを判定します。

  2. 入射窓の論理ボリュームにSetSensitiveDetector()で登録する

  3. G4SDManagerにセンシティブディテクターを登録する

  4. ヒット数をカウントするコンテナ(G4THitsCollectionなど)を用意する イベントごとの光子数を集計し、EventActionなどで取り出せるようにします。

光子はほとんどの場合、入射窓に到達した時点で吸収・終了させたいので、 ProcessHits()内でtrack->SetTrackStatus(fStopAndKill)するのが一般的です。

 1// PMTSD.hh
 2#pragma once
 3
 4#include "G4VSensitiveDetector.hh"
 5
 6class PMTSD : public G4VSensitiveDetector
 7{
 8    public:
 9        PMTSD(const G4String& name);
10        G4bool ProcessHits(G4Step* step, G4TouchableHistory*) override;
11        G4int GetNumPhotons() const { return fNumPhotons; }
12
13    private:
14        G4int fNumPhotons = 0;
15};
 1// PMTSD.cc
 2#include "PMTSD.hh"
 3
 4#include "G4OpticalPhoton.hh"
 5#include "G4Step.hh"
 6#include "G4Track.hh"
 7
 8PMTSD::PMTSD(const G4String& name)
 9    : G4VSensitiveDetector(name)
10{
11}
12
13G4bool PMTSD::ProcessHits(G4Step* step, G4TouchableHistory*)
14{
15    auto track = step->GetTrack();
16
17    // 光子以外のトラックは無視する
18    if (track->GetDefinition() != G4OpticalPhoton::OpticalPhotonDefinition()) {
19        return false;
20    }
21
22    fNumPhotons++;
23    track->SetTrackStatus(fStopAndKill);  // 光子はここで吸収・終了させる
24
25    return true;
26}

PMTSDProcessHits()内でトラックがG4OpticalPhotonかどうかを判定し、 該当する場合のみfNumPhotonsをインクリメントします。

注釈

センシティブディテクターの登録は、BuildPMT()(ジオメトリ構築側)ではなく、 DetectorConstruction::ConstructSDandField()で行うのがおすすめです。

マルチスレッド版のGeant4では、Construct()(およびBuildPMT()のような配下の関数)は マスタースレッドで1回だけ呼ばれてジオメトリを構築します。 一方、センシティブディテクターは各ワーカースレッドごとに個別のインスタンスが必要なため、 Construct()側で登録しても実際にイベント処理を行うワーカースレッドには反映されません。 ConstructSDandField()はワーカースレッドごとに呼ばれるため、 SDの登録はかならずここで行ってください。

センシティブディテクターの登録は、DetectorConstruction::ConstructSDandField()でおこないます。 BuildPMT()はジオメトリの構築のみをおこない、SDの登録はおこないません。

1void DetectorConstruction::ConstructSDandField()
2{
3    auto sd = new PMTSD("PMTSD");
4    G4SDManager::GetSDMpointer()->AddNewDetector(sd);
5
6    // 名前でジオメトリ構築時の論理ボリュームを検索して登録する
7    auto logical = G4LogicalVolumeStore::GetInstance()->GetVolume("PMTWindow");
8    logical->SetSensitiveDetector(sd);
9}

これで、PMTの入射窓に光子が入射するたびにfNumPhotonsがカウントされます。 イベントごとの光子数を集計したい場合は、EventActionなどからGetNumPhotons()を取得してください。

PMTを配置したい

 1G4LogicalVolume* SetupPmtArray()
 2{
 3    // 親ボリューム(別途作成済みのものを使う)
 4    auto container = BuildWorld();
 5
 6    // 子ボリューム = PMTを準備する
 7    auto element = BuildPMT();
 8
 9    // PMTを5本並べる
10    std::vector<int> elements{101, 102, 103, 104, 105};
11    for (G4int id: elements) {
12        auto rotation = G4RotationMatrix{};
13        auto direction = G4ThreeVector{};
14        auto origin = G4Transform3D{rotation, direction};
15        new G4PVPlacement(
16            origin,
17            element,
18            "Container",
19            container,
20            false,
21            id,  // copy_number
22            true
23        );
24    }
25
26    return container;
27}

複数本のPMTを配置したいケースは多いと思います。 ここでは横一列に並べようとしています。

注釈

このページでは「入射窓+光子数カウント」というシンプルな構成にしていますが、 より本格的なPMTジオメトリを設計する場合は、つぎのような改良が考えられます。

  • 光電面(フォトカソード)を別コンポーネントにする 入射窓の裏面にG4LogicalSkinSurfaceG4OpticalSurfaceを貼り、 波長依存の検出効率(EFFICIENCYプロパティ)を設定すると、 実機のQE(量子効率)曲線を再現しやすくなります。

  • PMT全体をG4AssemblyVolumeでまとめる 入射窓・光電面・筐体を個別のボリュームとして作り、 ひとつの「PMT」としてまとめて配置できるようにします。

  • 大量配置にはG4PVPlacementのループよりG4PVParameterised スーパーカミオカンデ規模(PMT約11,000本)を配置する場合、 ループでのG4PVPlacementはメモリを消費しやすいため、 G4VPVParameterisationを使ったG4PVParameterisedのほうが効率的です。

  • パラメーターを構造体やクラスにまとめる PMTの種類(ID用・OD用など)が複数ある場合、 半径や厚みなどの値を構造体にまとめておくと見通しがよくなります。