geant4 灵敏探测器

geant4 灵敏探测器


 如何模拟探测器的响应?

  1. SteppingAction 统计每一个 step 在探测器中沉积的能量。
  2. 指定探测器为灵敏探测器,统计探测器内每一个 step 的能量沉积。

如何设置一个灵敏探测器?

  1. 指定某逻辑体为灵敏探测器
  2. 将灵敏探测器纳入 SD 管理器

  代码举例,取自 example B2a ---- 设置灵敏探测器,将灵敏探测器纳入 SD 管理器,指定某逻辑体为灵敏探测器。

 1 void B2aDetectorConstruction::ConstructSDandField()
 2 {
 3   // Sensitive detectors
 4 
 5   G4String trackerChamberSDname = "B2/TrackerChamberSD";
 6   B2TrackerSD* aTrackerSD = new B2TrackerSD(trackerChamberSDname,
 7                                             "TrackerHitsCollection");
 8   G4SDManager::GetSDMpointer()->AddNewDetector(aTrackerSD);
 9   // Setting aTrackerSD to all logical volumes with the same name 
10   // of "Chamber_LV".
11   SetSensitiveDetector("Chamber_LV", aTrackerSD, true);
12 
13   // Create global magnetic field messenger.
14   // Uniform magnetic field is then created automatically if
15   // the field value is not zero.
16   G4ThreeVector fieldValue = G4ThreeVector();
17   fMagFieldMessenger = new G4GlobalMagFieldMessenger(fieldValue);
18   fMagFieldMessenger->SetVerboseLevel(1);
19   
20   // Register the field messenger for deleting
21   G4AutoDelete::Register(fMagFieldMessenger);
22 }
  • 第 6 - 9 行,设置灵敏探测器, 并将其纳入灵敏探测器管理器。其中 “TrackerHitsCollection” 是设置的 hitcollectionName,便于在 G4HCofThisEvent 容器中索引。
  • 第 11 行,使用 方法 SetSensitiveDetector()设置逻辑体为灵敏探测器,该方法的构造函数如下,这里是将所有名字为 Chamber_LV 的逻辑体统统设置为灵敏探测器。
    void SetSensitiveDetector(const G4String& logVolName,
                    G4VSensitiveDetector* aSD,G4bool multi=false);
    void SetSensitiveDetector(G4LogicalVolume* logVol,
                    G4VSensitiveDetector* aSD);

如何从灵敏探测器中提取信息?

Hit、HitCollection、Event

  • Hit:记录 SD 中每个 G4Step 中的信息(能量,时间等),因此一个 SD 中将产生大量Hit对象。
  • HitCollection:一个 SD 中产生大量的 Hit,可以被记录在一个或者多个容器中, 该容器即为 HitCollection 对象。
  • G4HCofThisEvent:G4Event 的一个成员对象,为一容器;多个 SD 的多个 HitCollection 对象储存在该容器中。

一个 Hit 类的举例,代码取自 example B2a

 1 /// Tracker hit class
 2 ///
 3 /// It defines data members to store the trackID, chamberNb, energy deposit,
 4 /// and position of charged particles in a selected volume:
 5 /// - fTrackID, fChamberNB, fEdep, fPos
 6 
 7 class B2TrackerHit : public G4VHit
 8 {
 9   public:
10     B2TrackerHit();
11     B2TrackerHit(const B2TrackerHit&);
12     virtual ~B2TrackerHit();
13 
14     // operators
15     const B2TrackerHit& operator=(const B2TrackerHit&);
16     G4int operator==(const B2TrackerHit&) const;
17 
18     inline void* operator new(size_t);
19     inline void  operator delete(void*);
20 
21     // methods from base class
22     virtual void Draw();
23     virtual void Print();
24 
25     // Set methods
26     void SetTrackID  (G4int track)      { fTrackID = track; };
27     void SetChamberNb(G4int chamb)      { fChamberNb = chamb; };
28     void SetEdep     (G4double de)      { fEdep = de; };
29     void SetPos      (G4ThreeVector xyz){ fPos = xyz; };
30 
31     // Get methods
32     G4int GetTrackID() const     { return fTrackID; };
33     G4int GetChamberNb() const   { return fChamberNb; };
34     G4double GetEdep() const     { return fEdep; };
35     G4ThreeVector GetPos() const { return fPos; };
36 
37   private:
38 
39       G4int         fTrackID;
40       G4int         fChamberNb;
41       G4double      fEdep;
42       G4ThreeVector fPos;
43 };
44 
45 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
46 
47 typedef G4THitsCollection<B2TrackerHit> B2TrackerHitsCollection;
48 
49 extern G4ThreadLocal G4Allocator<B2TrackerHit>* B2TrackerHitAllocator;
50 
51 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
52 
53 inline void* B2TrackerHit::operator new(size_t)
54 {
55   if(!B2TrackerHitAllocator)
56       B2TrackerHitAllocator = new G4Allocator<B2TrackerHit>;
57   return (void *) B2TrackerHitAllocator->MallocSingle();
58 }
59 
60 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
61 
62 inline void B2TrackerHit::operator delete(void *hit)
63 {
64   B2TrackerHitAllocator->FreeSingle((B2TrackerHit*) hit);
65 }
  • 在上述例子中,提取了 tarckID,Chamber number,沉积能量,位置信息。
  • 选择在 hit 中记录哪些量,是在 hit 类中明确的。
  • 第 47 行,将存放 B2TrackerHit 的容器类型重命名为 B2TrackerHitsCollection,方便接下来定义使用。

一个 SD 类的举例,代码取自 example B2a

 1 #ifndef B2TrackerSD_h
 2 #define B2TrackerSD_h 1
 3 
 4 #include "G4VSensitiveDetector.hh"
 5 
 6 #include "B2TrackerHit.hh"
 7 
 8 #include <vector>
 9 
10 class G4Step;
11 class G4HCofThisEvent;
12 
13 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
14 
15 /// B2Tracker sensitive detector class
16 ///
17 /// The hits are accounted in hits in ProcessHits() function which is called
18 /// by Geant4 kernel at each step. A hit is created with each step with non zero 
19 /// energy deposit.
20 
21 class B2TrackerSD : public G4VSensitiveDetector
22 {
23   public:
24     B2TrackerSD(const G4String& name, 
25                 const G4String& hitsCollectionName);
26     virtual ~B2TrackerSD();
27   
28     // methods from base class
29     virtual void   Initialize(G4HCofThisEvent* hitCollection);
30     virtual G4bool ProcessHits(G4Step* step, G4TouchableHistory* history);
31     virtual void   EndOfEvent(G4HCofThisEvent* hitCollection);
32 
33   private:
34     B2TrackerHitsCollection* fHitsCollection;
35 };
36 
37 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
38 
39 #endif
 1 #include "B2TrackerSD.hh"
 2 #include "G4HCofThisEvent.hh"
 3 #include "G4Step.hh"
 4 #include "G4ThreeVector.hh"
 5 #include "G4SDManager.hh"
 6 #include "G4ios.hh"
 7 
 8 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
 9 
10 B2TrackerSD::B2TrackerSD(const G4String& name,
11                          const G4String& hitsCollectionName) 
12  : G4VSensitiveDetector(name),
13    fHitsCollection(NULL)
14 {
15   collectionName.insert(hitsCollectionName);
16 }
17 
18 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
19 
20 B2TrackerSD::~B2TrackerSD() 
21 {}
22 
23 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
24 
25 void B2TrackerSD::Initialize(G4HCofThisEvent* hce)
26 {
27   // Create hits collection
28 
29   fHitsCollection 
30     = new B2TrackerHitsCollection(SensitiveDetectorName, collectionName[0]); 
31 
32   // Add this collection in hce
33 
34   G4int hcID 
35     = G4SDManager::GetSDMpointer()->GetCollectionID(collectionName[0]);
36   hce->AddHitsCollection( hcID, fHitsCollection ); 
37 }
38 
39 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
40 
41 G4bool B2TrackerSD::ProcessHits(G4Step* aStep, 
42                                      G4TouchableHistory*)
43 {  
44   // energy deposit
45   G4double edep = aStep->GetTotalEnergyDeposit();
46 
47   if (edep==0.) return false;
48 
49   B2TrackerHit* newHit = new B2TrackerHit();
50 
51   newHit->SetTrackID  (aStep->GetTrack()->GetTrackID());
52   newHit->SetChamberNb(aStep->GetPreStepPoint()->GetTouchableHandle()
53                                                ->GetCopyNumber());
54   newHit->SetEdep(edep);
55   newHit->SetPos (aStep->GetPostStepPoint()->GetPosition());
56 
57   fHitsCollection->insert( newHit );
58 
59   //newHit->Print();
60 
61   return true;
62 }
63 
64 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
65 
66 void B2TrackerSD::EndOfEvent(G4HCofThisEvent*)
67 {
68   if ( verboseLevel>1 ) { 
69      G4int nofHits = fHitsCollection->entries();
70      G4cout << G4endl
71             << "-------->Hits Collection: in this event they are " << nofHits 
72             << " hits in the tracker chambers: " << G4endl;
73      for ( G4int i=0; i<nofHits; i++ ) (*fHitsCollection)[i]->Print();
74   }
75 }
76 
77 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
  • 当一个 step 的能量沉积不是 0 的时候,就会创建一个 hit,言外之意是,不是所有的 step 都有能量沉积。
  • 灵敏探测器类继承自 G4VSensitiveDetector 类,其中必须实现的方法是 ProcessHits(G4Step*aStep,G4TouchableHistory*ROhist) ,该方法是从 step 中提取信息,写入 hit 中,并且将 hit 放入到 HitCollection 的容器中。
  • 第 15 行,必须要设置 "collectionName" string vector,原文:In the derived class constructor, name(s) of hits collection(s) which are made by the sensitive detector must be set to "collectionName" string vector. 
  • EndOfEvent(G4HCofThisEvent*) 不是一定要实现的方法,在该例中,在 EndOfEvent() 方法中提取了每一个 Event 共产生了多少个hit.

一个 EventAction 类的举例,用于提取灵敏探测器的信息,代码取自 example B5(第一段代码取自 DetectorConstruction.cc)

 1 void B5DetectorConstruction::ConstructSDandField()
 2 {
 3   // sensitive detectors -----------------------------------------------------
 4   auto sdManager = G4SDManager::GetSDMpointer();
 5   G4String SDname;
 6   
 7   auto hodoscope1 = new B5HodoscopeSD(SDname="/hodoscope1");
 8   sdManager->AddNewDetector(hodoscope1);
 9   fHodoscope1Logical->SetSensitiveDetector(hodoscope1);
10 
11   auto hodoscope2 = new B5HodoscopeSD(SDname="/hodoscope2");
12   sdManager->AddNewDetector(hodoscope2);
13   fHodoscope2Logical->SetSensitiveDetector(hodoscope2);
14   
15   auto chamber1 = new B5DriftChamberSD(SDname="/chamber1");
16   sdManager->AddNewDetector(chamber1);
17   fWirePlane1Logical->SetSensitiveDetector(chamber1);
18 
19   auto chamber2 = new B5DriftChamberSD(SDname="/chamber2");
20   sdManager->AddNewDetector(chamber2);
21   fWirePlane2Logical->SetSensitiveDetector(chamber2);
22   
23   auto emCalorimeter = new B5EmCalorimeterSD(SDname="/EMcalorimeter");
24   sdManager->AddNewDetector(emCalorimeter);
25   fCellLogical->SetSensitiveDetector(emCalorimeter);
26   
27   auto hadCalorimeter = new B5HadCalorimeterSD(SDname="/HadCalorimeter");
28   sdManager->AddNewDetector(hadCalorimeter);
29   fHadCalScintiLogical->SetSensitiveDetector(hadCalorimeter);
30 
31   // magnetic field ----------------------------------------------------------
32   fMagneticField = new B5MagneticField();
33   fFieldMgr = new G4FieldManager();
34   fFieldMgr->SetDetectorField(fMagneticField);
35   fFieldMgr->CreateChordFinder(fMagneticField);
36   G4bool forceToAllDaughters = true;
37   fMagneticLogical->SetFieldManager(fFieldMgr, forceToAllDaughters);
38 
39   // Register the field and its manager for deleting
40   G4AutoDelete::Register(fMagneticField);
41   G4AutoDelete::Register(fFieldMgr);
42 }    
43 
44 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
  • 注意到,在这里初始化各个灵敏探测器时,没有设置其对应的 HitCollectionName,这是因为在对应的灵敏探测器类中,已经设置了该名称。
    1 B5EmCalorimeterSD::B5EmCalorimeterSD(G4String name)
    2 : G4VSensitiveDetector(name), 
    3   fHitsCollection(nullptr), fHCID(-1)
    4 {
    5   collectionName.insert("EMcalorimeterColl");
    6 }
 1 #ifndef B5EventAction_h
 2 #define B5EventAction_h 1
 3 
 4 
 5 #include "G4UserEventAction.hh"
 6 #include "globals.hh"
 7 
 8 #include <vector>
 9 
10 /// Event action
11 
12 class B5EventAction : public G4UserEventAction
13 {
14 public:
15     B5EventAction();
16     virtual ~B5EventAction();
17     
18     virtual void BeginOfEventAction(const G4Event*);
19     virtual void EndOfEventAction(const G4Event*);
20 
21     std::vector<G4double>& GetEmCalEdep() { return fEmCalEdep; }
22     std::vector<G4double>& GetHadCalEdep() { return fEmCalEdep; }
23     
24 private:
25     G4int fHodHC1ID;
26     G4int fHodHC2ID;
27     G4int fDriftHC1ID;
28     G4int fDriftHC2ID;
29     G4int fEmCalHCID;
30     G4int fHadCalHCID;
31     std::vector<G4double> fEmCalEdep;
32     std::vector<G4double> fHadCalEdep;
33 };
34 
35 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
36 
37 #endif
  1 #include "B5EventAction.hh"
  2 #include "B5HodoscopeHit.hh"
  3 #include "B5DriftChamberHit.hh"
  4 #include "B5EmCalorimeterHit.hh"
  5 #include "B5HadCalorimeterHit.hh"
  6 #include "B5Constants.hh"
  7 #include "B5Analysis.hh"
  8 
  9 #include "G4Event.hh"
 10 #include "G4RunManager.hh"
 11 #include "G4EventManager.hh"
 12 #include "G4HCofThisEvent.hh"
 13 #include "G4VHitsCollection.hh"
 14 #include "G4SDManager.hh"
 15 #include "G4SystemOfUnits.hh"
 16 #include "G4ios.hh"
 17 
 18 
 19 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
 20 
 21 B5EventAction::B5EventAction()
 22 : G4UserEventAction(), 
 23   fHodHC1ID(-1),
 24   fHodHC2ID(-1),
 25   fDriftHC1ID(-1),
 26   fDriftHC2ID(-1),
 27   fEmCalHCID(-1),
 28   fHadCalHCID(-1),
 29   fEmCalEdep(kNofEmCells, 0.), 
 30   fHadCalEdep(kNofHadCells, 0.)
 31 {
 32   // set printing per each event
 33   G4RunManager::GetRunManager()->SetPrintProgress(1);
 34 }
 35 
 36 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
 37 
 38 B5EventAction::~B5EventAction()
 39 {}
 40 
 41 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
 42 
 43 void B5EventAction::BeginOfEventAction(const G4Event*)
 44 {
 45   if (fHodHC1ID==-1) {
 46     auto sdManager = G4SDManager::GetSDMpointer();
 47     fHodHC1ID = sdManager->GetCollectionID("hodoscope1/hodoscopeColl");
 48     fHodHC2ID = sdManager->GetCollectionID("hodoscope2/hodoscopeColl");
 49     fDriftHC1ID = sdManager->GetCollectionID("chamber1/driftChamberColl");
 50     fDriftHC2ID = sdManager->GetCollectionID("chamber2/driftChamberColl");
 51     fEmCalHCID = sdManager->GetCollectionID("EMcalorimeter/EMcalorimeterColl");
 52     fHadCalHCID = sdManager->GetCollectionID("HadCalorimeter/HadCalorimeterColl");
 53   }
 54 }     
 55 
 56 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
 57 
 58 void B5EventAction::EndOfEventAction(const G4Event* event)
 59 {
 60   auto hce = event->GetHCofThisEvent();
 61   if (!hce) {
 62       G4ExceptionDescription msg;
 63       msg << "No hits collection of this event found." << G4endl; 
 64       G4Exception("B5EventAction::EndOfEventAction()",
 65                   "B5Code001", JustWarning, msg);
 66       return;
 67   }
 68 
 69   // Get hits collections 
 70   auto hHC1 
 71     = static_cast<B5HodoscopeHitsCollection*>(hce->GetHC(fHodHC1ID));
 72     
 73   auto hHC2 
 74     = static_cast<B5HodoscopeHitsCollection*>(hce->GetHC(fHodHC2ID));
 75     
 76   auto dHC1 
 77     = static_cast<B5DriftChamberHitsCollection*>(hce->GetHC(fDriftHC1ID));
 78     
 79   auto dHC2 
 80     = static_cast<B5DriftChamberHitsCollection*>(hce->GetHC(fDriftHC2ID));
 81     
 82   auto ecHC 
 83     = static_cast<B5EmCalorimeterHitsCollection*>(hce->GetHC(fEmCalHCID));
 84     
 85   auto hcHC 
 86     = static_cast<B5HadCalorimeterHitsCollection*>(hce->GetHC(fHadCalHCID));
 87     
 88   if ( (!hHC1) || (!hHC2) || (!dHC1) || (!dHC2) || (!ecHC) || (!hcHC) ) {
 89       G4ExceptionDescription msg;
 90       msg << "Some of hits collections of this event not found." << G4endl; 
 91       G4Exception("B5EventAction::EndOfEventAction()",
 92                   "B5Code001", JustWarning, msg);
 93       return;
 94   }   
 95   
 96   //
 97   // Fill histograms & ntuple
 98   // 
 99   
100   // Get analysis manager
101   auto analysisManager = G4AnalysisManager::Instance();
102  
103   // Fill histograms
104  
105   auto nhit  = dHC1->entries();
106   analysisManager->FillH1(0, nhit );
107 
108   for (auto i=0;i<nhit ;i++) {
109     auto hit = (*dHC1)[i];
110     auto localPos = hit->GetLocalPos();
111     analysisManager->FillH2(0, localPos.x(), localPos.y());
112   }
113  
114   nhit  = dHC2->entries();
115   analysisManager->FillH1(1, nhit );
116 
117   for (auto i=0;i<nhit ;i++) {
118     auto hit = (*dHC2)[i];
119     auto localPos = hit->GetLocalPos();
120     analysisManager->FillH2(1, localPos.x(), localPos.y());
121   }
122       
123   // Fill ntuple
124   
125   // Dc1Hits
126   analysisManager->FillNtupleIColumn(0, dHC1->entries());
127   // Dc2Hits
128   analysisManager->FillNtupleIColumn(1, dHC1->entries());
129   
130   // ECEnergy
131   G4int totalEmHit = 0;
132   G4double totalEmE = 0.;
133   for (auto i=0;i<kNofEmCells;i++) {
134     auto hit = (*ecHC)[i];
135     auto edep = hit->GetEdep();
136     if (edep>0.) {
137       totalEmHit++;
138       totalEmE += edep;
139     }
140     fEmCalEdep[i] = edep;
141   }
142   analysisManager->FillNtupleDColumn(2, totalEmE);
143 
144   // HCEnergy
145   G4int totalHadHit = 0;
146   G4double totalHadE = 0.;
147   for (auto i=0;i<kNofHadCells;i++) {
148     auto hit = (*hcHC)[i];
149     auto edep = hit->GetEdep();
150     if (edep>0.) {
151         totalHadHit++;
152         totalHadE += edep;
153     }
154     fHadCalEdep[i] = edep;
155   }
156   analysisManager->FillNtupleDColumn(3, totalHadE);
157 
158   // Time 1
159   for (auto i=0;i<hHC1->entries();i++) {
160     analysisManager->FillNtupleDColumn(4,(*hHC1)[i]->GetTime());
161   }
162     
163   // Time 2
164   for (auto i=0;i<hHC2->entries();i++) {
165     analysisManager->FillNtupleDColumn(5,(*hHC2)[i]->GetTime());
166   }
167   
168   analysisManager->AddNtupleRow();  
169   
170   //
171   // Print diagnostics
172   // 
173   
174   auto printModulo = G4RunManager::GetRunManager()->GetPrintProgress();
175   if ( printModulo==0 || event->GetEventID() % printModulo != 0) return;
176   
177   auto primary = event->GetPrimaryVertex(0)->GetPrimary(0);
178   G4cout 
179     << G4endl
180     << ">>> Event " << event->GetEventID() << " >>> Simulation truth : "
181     << primary->GetG4code()->GetParticleName()
182     << " " << primary->GetMomentum() << G4endl;
183   
184   // Hodoscope 1
185   nhit  = hHC1->entries();
186   G4cout << "Hodoscope 1 has " << nhit  << " hits." << G4endl;
187   for (auto i=0;i<nhit ;i++) {
188     auto hit = (*hHC1)[i];
189     hit->Print();
190   }
191 
192   // Hodoscope 2
193   nhit  = hHC2->entries();
194   G4cout << "Hodoscope 2 has " << nhit  << " hits." << G4endl;
195   for (auto i=0;i<nhit ;i++) {
196     auto hit = (*hHC2)[i];
197     hit->Print();
198   }
199 
200   // Drift chamber 1
201   nhit  = dHC1->entries();
202   G4cout << "Drift Chamber 1 has " << nhit  << " hits." << G4endl;
203   for (auto layer=0;layer<kNofChambers;layer++) {
204     for (auto i=0;i<nhit ;i++) {
205       auto hit = (*dHC1)[i];
206       if (hit->GetLayerID()==layer) hit->Print();
207     }
208   }
209 
210   // Drift chamber 2
211   nhit  = dHC2->entries();
212   G4cout << "Drift Chamber 2 has " << nhit  << " hits." << G4endl;
213   for (auto layer=0;layer<kNofChambers;layer++) {
214     for (auto i=0;i<nhit ;i++) {
215       auto hit = (*dHC2)[i];
216       if (hit->GetLayerID()==layer) hit->Print();
217     }
218   }
219 
220   // EM calorimeter
221   G4cout << "EM Calorimeter has " << totalEmHit << " hits. Total Edep is "
222     << totalEmE/MeV << " (MeV)" << G4endl;
223 
224   // Had calorimeter
225   G4cout << "Hadron Calorimeter has " << totalHadHit << " hits. Total Edep is "
226     << totalHadE/MeV << " (MeV)" << G4endl;
227 }
228 
229 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
  • 第 47 - 52 行,是为了得到不同的灵敏探测器所产生的 hitCollection 在 G4HCofThisEvent 容器中的位置,使用灵敏探测器管理器类的成员函数  GetCollectionID(G4String colName) 返回对应的 hitCollection 的 ID,其参数为 SDname/hitCollectionName,中间需要加"/",入示例中所示。
  • 在  EndOfEventAction() 中,首先需要定义一个  GetHCofThisEvent 容器对象,通过 hitCollectionID 索引得到 hitCollection 的容器,在文档中的第 69 - 94 行。
  • 第 130 - 156 行,这里用了累加,将每一个 hitCollection 容器中 hit 对象的能量相加,得到一个 Event 中,在一个灵敏探测器中沉积的总的能量。
原文地址:https://www.cnblogs.com/kurrrr/p/13661959.html