光センサーしたい

半導体光センサーの実装サンプルです。 光子を数えるためのヒット用クラスと、 ヒットを判定するSensitiveDetector用クラスを作成します。

ヒット用クラスしたい(SipmHit

光子1つあたりのヒット情報をまとめるためのクラスを作成します。 クラス名をSipmHitとし、 ヘッダーファイル(include/SipmHit.hh)と ソースファイル(src/SipmHit.cc)を作成します。

SipmHitクラスでは、 SiPMのID(fSipmID)、 光子のエネルギー(fEnergy)、 光子の波長(fWavelength)、 光子が到達した時刻(fArrivalTime)、 ヒットした位置(fPosition) を記録することにします。

注釈

SiPMはSilicone Photomultiplierの一般名称です。 浜松ホトニクスは「MPPC」の商標名で販売しています。

より汎用的にしたい場合はPhotonCounterHitクラス、 浜松ホトニクス製を明確にしたい場合はMppcHitクラス、 のように名付けてもよいかもしれません。

include/SipmHit.hh

 1#ifndef SipmHit_h
 2#define SipmHit_h 1
 3
 4#include "G4Allocator.h"
 5#include "G4THitsCollection.hh"
 6#include "G4ThreeVector.hh"
 7#include "G4VHit.hh"
 8#include "tls.h"
 9
10namespace NS
11{
12  class SipmHit : public G4VHit
13  {
14    public:
15      SipmHit() = default;
16      SipmHit(const SipmHit &) = default;
17      ~SipmHit() override = default;
18
19      SipmHit &operator(const SipmHit &) = default;
20      G4bool operator==(const SipmHit &) const;
21
22      inline void *operator new(size_t);
23      inline void operator delete(void *);
24
25      void Draw() override {};
26      void Print() override;
27
28      // Setters
29      void SetSipmID(G4int id) { fSipmId = id; }
30      void SetEnergy(G4double energy) { fEnergy = energy; }
31      void SetWavelength(G4double wavelength) { fWavelength = wavelength; }
32      void SetArrivalTime(G4double time) { fArrivalTime = time; }
33      void SetPosition(G4ThreeVector position) { fPosition = position; }
34
35      // Getters
36      G4int GetSipmID() const { return fSipmID; }
37      G4double GetEnergy() const { return fEnergy; }
38      G4double GetWavelength() const { return fWavelength; }
39      G4double GetArrivalTime() const { return fArrivalTime; }
40      G4ThreeVector GetPosition() const { return fPosition; }
41
42    private:
43      G4int fSipmID{-1};
44      G4double fEnergy{0.};    // eV
45      G4double fWavelength{0.};    // nm
46      G4double fArrivalTime{0.};   // ns
47      G4ThreeVector fPosition{};
48  };
49
50  using SipmHitsCollection = G4THitsCollection<SipmHit>;
51  extern G4ThreadLocal G4Allocator<SipmHit> *SipmHitAllocator;
52
53  inline void *SipmHit::operator new(size_t)
54  {
55    if (!SipmHitAllocator)
56      SipmHitAllocator = new G4Allocator<SipmHit>;
57    return static_cast<void *>(SipmHitAllocator->MallocSingle());
58  }
59
60  inline void SipmHit::operator delete(void *hit)
61  {
62    SipmHitAllocator->FreeSingle(static_cast<SipmHit *>(hit));
63  }
64}  // namespace NS
65
66#endif  // SipmHit_h

src/SipmHit.cc

 1#include "SipmHit.hh"
 2
 3#include "G4SystemOfUnits.hh"
 4
 5#include <loguru.hpp>
 6
 7namespace NS
 8{
 9  G4ThreadLocal G4Allocator<SipmHit> *SipmHitAllocator = nullptr;
10
11  // __________________________________________________
12  G4bool SipmHit::operator==(const SipmHit &right) const
13  {
14    return (this == &right);
15  }
16
17  // __________________________________________________
18  void SipmHit::Print()
19  {
20    VLOG_F(2, "[SipmHit] sipm_id=%d  E=%.2f eV  wl=%.1f nm  t=%.2f ns  pos=(%.1f,%.1f,%.1f) mm",
21      fSipmId,
22      fEnergy / eV,
23      fWavelength / nm,
24      fArrivalTime / ns,
25      fPosition.x / mm,
26      fPosition.y / mm,
27      fPosition.z / mm,
28    );
29  }
30
31  // __________________________________________________
32  PhotonData SipmHit::ToPhotonData() const
33  {
34    PhotonData p;
35    p.sipm_id = fSipmID;
36    p.energy = fEnergy / eV;
37    p.wavelength = fWavelength / nm;
38    p.arrival_time = fArrivalTime / ns;
39    p.pos_x = fPosition.x() / mm;
40    p.pos_y = fPosition.y() / mm;
41    p.pos_z = fPosition.z() / mm;
42    return p;
43  }
44}

SensitiveDetectorしたい(SipmSD

光子(G4OpticalPhoton)を検出できるようにSensitiveDetectorを作成します。

include/SipmSD.hh

 1#ifndef SipmSD_h
 2#define SipmSD_h 1
 3
 4#include "SipmHit.hh"
 5
 6#include "G4VSensitiveDetector.hh"
 7
 8namespace NS
 9{
10  class SipmSD : public G4VSensitiveDetector
11  {
12    public:
13      SipmSD(const G4String &name, const G4String &hitsCollectionName);
14      ~SipmSD() override = default;
15
16      void Initialize(G4HCofThisEvent *hce) override;
17      G4bool ProcessHits(G4Step *aStep, G4TouchableHistory *) override;
18      void EndOfEvent(G4HCofThisEvent *hce) override;
19
20    private:
21      SipmHitsCollection *fHitsCollection = nullptr;
22  };
23
24}  // namespace NS
25
26#endif  // SipmSD_h

src/SipmSD.cc

 1#include "SipmSD.hh"
 2
 3#include "G4Event.hh"
 4#include "G4EventManager.hh"
 5#include "G4OpticalPhoton.hh"
 6#include "G4SDManager.hh"
 7#include "G4Step.hh"
 8#include "G4SystemOfUnits.hh"
 9#include "G4Track.hh"
10
11#include <loguru.cpp>
12
13namespace NS
14{
15  SipmSD::SipmSD(const G4String &name, const G4String &hitsCollectionName) : G4VSensitiveDetector(name)
16  {
17    VLOG_F(2, "SipmSD: name=%s  collection=%s",
18      name.c_str(),
19      hitsCollectionName.c_str()
20    );
21    collectionName.insert(hitsCollectionName);
22  }
23
24  // __________________________________________________
25  void SipmSD::Initialize(G4HCofThisEvent * /*hce*/)
26  {
27    fHitsCollection = new SipmHitsCollection{SensitiveDetectorName, collectionName[0]};
28  }
29
30  // __________________________________________________
31  G4bool SipmSD::ProcessHits(G4Step *aStep, G4TouchableHistory *)
32  {
33    // Accept optical photons only
34    auto particle = aStep->GetTrack()->GetParticleDefinition();
35    if (particle != G4OpticalPhoton::OpticalPhotonDefinition())
36    {
37      return false;
38    }
39
40    auto pre = aStep->GetPreStepPoint();
41    auto track = aStep->GetTrack();
42
43    // Photon energy and wavelength
44    G4double energy = pre->GetTotalEnergy();    // MeV
45    G4double wavelength = (CLHEP::h_Planck * CLHEP::c_light) / energy;
46
47    auto hit = new SipmHit();
48    hit->SetSipmID(pre->GetTouchableHandle()->GetCopyNumber());
49    hit->SetEnergy(energy);
50    hit->SetWavelength(wavelength);
51    hit->SetArrivalTime(pre->GetGlobalTime());
52    hit->SetPosition(pre->GetPosition());
53    hit->Print();
54
55    fHitsCollection->insert(hit);
56
57    // Kill the photon after detection
58    track->SetTrackStatus(fStopAndKill);
59
60    return true;
61  }
62
63  // __________________________________________________
64  void SipmSD::EndOfEvent(G4HCofThisEvent * /*hce*/)
65  {
66    VLOG_SCOPE_F(1, "SipmSD::EndOfEvent");
67
68    G4int n_hits = fHitsCollection->entries();
69    VLOG_F(2, "n_photons: %d", n_hits);
70
71    const G4Event *event = G4EventManager::GetEventManager()->GetConstCurrentEvent();
72    G4int event_id = event->GetEventID();
73
74    std::vector<PhotonData> photons;
75    photons.reserve(n_hits);
76    for (G4int i = 0; i < n_hits; ++i)
77    {
78      auto *h = static_cast<SipmHit *>(fHitsCollection->GetHit(i));
79      photons.push_back(h->ToPhotonData());
80    }
81
82    // EventWriter::Instance()->AddPhotons(event_id, photons);
83  }
84
85}  // namespace NS