LDMX Software
EcalSD.cxx
2
4#include "G4StepPoint.hh"
5#include "G4VSolid.hh"
6#include "SimCore/G4User/TrackMap.h"
7
8namespace simcore {
9
10const std::string EcalSD::COLLECTION_NAME = "EcalSimHits";
11
12EcalSD::EcalSD(const std::string& name, simcore::ConditionsInterface& ci,
14 : SensitiveDetector(name, ci, p) {
15 enable_hit_contribs_ = p.get<bool>("enable_hit_contribs");
16 compress_hit_contribs_ = p.get<bool>("compress_hit_contribs");
17 max_origin_track_id_ = p.get<int>("max_origin_track_id");
18}
19
20G4bool EcalSD::ProcessHits(G4Step* aStep, G4TouchableHistory*) {
21 static const int layer_depth = 2; // index depends on GDML implementation
22 const auto& geometry = getCondition<ldmx::EcalGeometry>(
23 ldmx::EcalGeometry::CONDITIONS_OBJECT_NAME);
24
25 // Get the edep from the step.
26 G4double edep = aStep->GetTotalEnergyDeposit();
27
28 // Skip steps with no energy dep which come from non-Geantino particles.
29 if (edep == 0.0 and not isGeantino(aStep)) {
30 ldmx_log(trace) << "CalorimeterSD skipping step with zero edep.";
31 return false;
32 }
33
34 // Compute the hit position
35 G4StepPoint* pre_point = aStep->GetPreStepPoint();
36 G4StepPoint* post_point = aStep->GetPostStepPoint();
37 G4ThreeVector position =
38 0.5 * (pre_point->GetPosition() + post_point->GetPosition());
39
40 // Create the ID for the hit.
41 int cpynum{0}; // Initialize cpynum to 0
42
43 auto pre_step_point = aStep->GetPreStepPoint();
44 if (pre_step_point) {
45 const auto& touchable_handle = pre_step_point->GetTouchableHandle();
46 if (touchable_handle) {
47 auto history = touchable_handle->GetHistory();
48 if (history) {
49 auto volume = history->GetVolume(layer_depth);
50 if (volume) {
51 cpynum = volume->GetCopyNo();
52 }
53 }
54 }
55 }
56 int layer_number;
57 layer_number = cpynum / 7;
58 int module_position = cpynum % 7;
70 // fastest, but need to trust module number between GDML and EcalGeometry
71 // match
72 ldmx::EcalID id =
73 geometry.getID(position.x(), position.y(), layer_number, module_position);
74
75 // medium, only need to trust z-layer positions in GDML and EcalGeometry match
76 // helpful for debugging any issues where transverse position is not
77 // matching between the GDML and EcalGeometry
78 // ldmx::EcalID id = geometry.getID(position[0], position[1], layerNumber);
79
80 // slowest, completely rely on EcalGeometry
81 // this is helpful for validating the EcalGeometry implementation and
82 // configuration since this will be called with any hit position that
83 // is inside of the configured SD volumes from Geant4's point of view
84 // ldmx::EcalID id = geometry.getID(position[0], position[1], position[2]);
85
86 if (hits_.find(id) == hits_.end()) {
87 // hit in empty cell
88 auto& hit = hits_[id];
89 hit.setID(id.raw());
90 hit.setPosition(position.x(), position.y(), position.z());
91 }
92
93 auto& hit = hits_[id];
94
95 // hit variables
96 auto track = aStep->GetTrack();
97 auto time = track->GetGlobalTime();
98 auto track_id = track->GetTrackID();
99 auto pdg = track->GetParticleDefinition()->GetPDGEncoding();
100
102 int contrib_i = hit.findContribIndex(track_id, pdg);
103 if (compress_hit_contribs_ and contrib_i != -1) {
104 hit.updateContrib(contrib_i, edep, time);
105 } else {
106 auto map{getTrackMap()};
107 auto incident{map.findIncident(track_id)};
108 // default "origin" is just the same as incident
109 // "origin" checks if a hit "originates" from one of the earliest
110 // track IDs (i.e. probably one of the primaries)
111 int origin{incident};
112 for (int i{1}; i < max_origin_track_id_; ++i) {
113 if (map.isDescendant(track_id, i, 100)) {
114 origin = i;
115 break;
116 }
117 }
118 hit.addContrib(incident, track_id, pdg, edep, time, origin);
119 }
120 } else {
121 // no hit contribs and hit already exists
122 hit.setEdep(hit.getEdep() + edep);
123 if (time < hit.getTime() or hit.getTime() == 0) {
124 hit.setTime(time);
125 }
126 }
127
128 return true;
129}
130
132 // squash hits into list
133 std::vector<ldmx::SimCalorimeterHit> hits;
134 hits.reserve(hits_.size());
135 for (const auto& [id, hit] : hits_) hits.push_back(hit);
136 event.add(COLLECTION_NAME, hits);
137}
138
139} // namespace simcore
140
141DECLARE_SENSITIVEDETECTOR(simcore::EcalSD)
Class that translates raw positions of ECal module hits into cells in a hexagonal readout.
Class defining an ECal sensitive detector using an EcalHexReadout to create the hits_.
Implements an event buffer system for storing event data.
Definition Event.h:40
Class encapsulating parameters for configuring a processor.
Definition Parameters.h:26
const T & get(const std::string &name) const
Retrieve the parameter of the given name.
Definition Parameters.h:75
Extension of DetectorID providing access to ECal layers and cell numbers in a hex grid.
Definition EcalID.h:20
Handle to the conditions system, provided at construction to classes which require it.
ECal sensitive detector that uses an EcalHexReadout to create the hits_.
Definition EcalSD.h:29
static const std::string COLLECTION_NAME
Name of output collection of hits_.
Definition EcalSD.h:32
std::map< ldmx::EcalID, ldmx::SimCalorimeterHit > hits_
map of hits to add to the event (will be squashed)
Definition EcalSD.h:80
EcalSD(const std::string &name, simcore::ConditionsInterface &ci, const framework::config::Parameters &p)
Class constructor.
Definition EcalSD.cxx:12
virtual void saveHits(framework::Event &event) override
Add our hits to the event bus.
Definition EcalSD.cxx:131
int max_origin_track_id_
maximum track ID to be considered an "origin"
Definition EcalSD.h:86
bool enable_hit_contribs_
enable hit contribs
Definition EcalSD.h:82
G4bool ProcessHits(G4Step *aStep, G4TouchableHistory *ROhist) override
Process steps to create hits_.
Definition EcalSD.cxx:20
bool compress_hit_contribs_
compress hit contribs
Definition EcalSD.h:84
Dynamically loaded Geant4 SensitiveDetector for saving hits in specific volumes within the simulation...
bool isGeantino(const G4Step *step) const
Check if the passed step is a step of a geantino.
const TrackMap & getTrackMap() const
Get a handle to the current track map.
const T & getCondition(const std::string &condition_name)
Record the configuration of this detector into the run header.
Dynamically loadable photonuclear models either from SimCore or external libraries implementing this ...