光センサーしたい
半導体光センサーの実装サンプルです。 光子を数えるためのヒット用クラスと、 ヒットを判定する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