LDMX Software
simcore::HcalSD Class Reference

Class defining a sensitive detector of type HCal. More...

#include <HcalSD.h>

Public Member Functions

 HcalSD (const std::string &name, simcore::ConditionsInterface &ci, const framework::config::Parameters &params)
 Constructor.
 
virtual ~HcalSD ()=default
 Destructor.
 
bool isSensDet (G4LogicalVolume *volume) const override
 Check if the input logical volume is a part of the hcal sensitive volumes.
 
ldmx::HcalID decodeCopyNumber (const std::uint32_t copyNumber, const G4ThreeVector &localPosition, const G4Box *scint)
 Decode copy number of scintillator bar.
 
virtual G4bool ProcessHits (G4Step *aStep, G4TouchableHistory *ROhist) override
 Create a hit out of the energy deposition deposited during a step.
 
virtual void saveHits (framework::Event &event) override
 Add our hits to the event bus and then reset the container.
 
virtual void onFinishedEvent () override
 Cleanup SD and prepare a new-event state.
 
- Public Member Functions inherited from simcore::SensitiveDetector
 SensitiveDetector (const std::string &name, simcore::ConditionsInterface &ci, const framework::config::Parameters &parameters)
 Constructor.
 
 DECLARE_FACTORY_WITH_WAREHOUSE (SensitiveDetector, SensitiveDetector *, const std::string &, simcore::ConditionsInterface &, const framework::config::Parameters &)
 The SD Factory.
 
virtual ~SensitiveDetector ()=default
 Destructor.
 
virtual void EndOfEvent (G4HCofThisEvent *) override
 This is Geant4's handle to tell us the event is ending.
 

Static Public Attributes

static const std::string COLLECTION_NAME = "HcalSimHits"
 name of collection to be added to event bus
 

Private Attributes

std::vector< std::string > gdml_identifiers_
 
double birksc1_
 
double birksc2_
 
std::map< ldmx::HcalID, ldmx::SimCalorimeterHit > hits_
 map of hits to add to the event (will be squashed)
 
bool enable_hit_contribs_
 enable hit contribs
 
bool compress_hit_contribs_
 compress hit contribs
 
int max_origin_track_id_
 maximum track ID to be considered an "origin"
 

Additional Inherited Members

- Protected Member Functions inherited from simcore::SensitiveDetector
template<class T >
const T & getCondition (const std::string &condition_name)
 Record the configuration of this detector into the run header.
 
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.
 
 enableLogging ("SensitiveDetector")
 Enable logging for this class.
 

Detailed Description

Class defining a sensitive detector of type HCal.

Definition at line 21 of file HcalSD.h.

Constructor & Destructor Documentation

◆ HcalSD()

simcore::HcalSD::HcalSD ( const std::string & name,
simcore::ConditionsInterface & ci,
const framework::config::Parameters & params )

Constructor.

Parameters
nameThe name of the sensitive detector.
ciConditions interface handle
paramspython configuration parameters

Definition at line 24 of file HcalSD.cxx.

26 : SensitiveDetector(name, ci, p), birksc1_(1.29e-2), birksc2_(9.59e-6) {
27 gdml_identifiers_ = {p.get<std::vector<std::string>>("gdml_identifiers")};
28 enable_hit_contribs_ = p.get<bool>("enable_hit_contribs");
29 compress_hit_contribs_ = p.get<bool>("compress_hit_contribs");
30 max_origin_track_id_ = p.get<int>("max_origin_track_id");
31}
bool compress_hit_contribs_
compress hit contribs
Definition HcalSD.h:106
bool enable_hit_contribs_
enable hit contribs
Definition HcalSD.h:104
int max_origin_track_id_
maximum track ID to be considered an "origin"
Definition HcalSD.h:108
SensitiveDetector(const std::string &name, simcore::ConditionsInterface &ci, const framework::config::Parameters &parameters)
Constructor.

References compress_hit_contribs_, enable_hit_contribs_, framework::config::Parameters::get(), and max_origin_track_id_.

Member Function Documentation

◆ decodeCopyNumber()

ldmx::HcalID simcore::HcalSD::decodeCopyNumber ( const std::uint32_t copyNumber,
const G4ThreeVector & localPosition,
const G4Box * scint )

Decode copy number of scintillator bar.

Parameters
copyNumberThe copy number of the scintillator volume.
localPositionThe position of the hit (step mid-point).
scintThe G4Box of the scintillator volume.

Definition at line 33 of file HcalSD.cxx.

35 {
36 const unsigned int version{copyNumber / 0x01000000};
37 if (version != 0) {
39 return ldmx::HcalID{Index(copyNumber).field2(), Index(copyNumber).field1(),
40 Index(copyNumber).field0()};
41 }
42 const auto& geometry = getCondition<ldmx::HcalGeometry>(
44 unsigned int strip_id = 0;
45 const unsigned int section = copyNumber / 1000;
46 const unsigned int layer = copyNumber % 1000;
47
48 // 5cm wide bars are HARD-CODED
49 if (section == ldmx::HcalID::BACK) {
50 if (geometry.backLayerIsHorizontal(layer)) {
51 strip_id = int((localPosition.y() + scint->GetYHalfLength()) / 50.0);
52 } else {
53 strip_id = int((localPosition.x() + scint->GetXHalfLength()) / 50.0);
54 }
55 } else {
56 strip_id = int((localPosition.z() + scint->GetZHalfLength()) / 50.0);
57 }
58 return ldmx::HcalID{section, layer, strip_id};
59}
static constexpr const char * CONDITIONS_OBJECT_NAME
Conditions object: The name of the python configuration calling this class (Hcal/python/HcalGeometry....
Implements detector ids for HCal subdetector.
Definition HcalID.h:19
A maximally-packed index of up to four different fields.
Definition PackedIndex.h:32
const T & getCondition(const std::string &condition_name)
Record the configuration of this detector into the run header.

References ldmx::HcalGeometry::CONDITIONS_OBJECT_NAME, and simcore::SensitiveDetector::getCondition().

Referenced by ProcessHits().

◆ isSensDet()

bool simcore::HcalSD::isSensDet ( G4LogicalVolume * volume) const
inlineoverridevirtual

Check if the input logical volume is a part of the hcal sensitive volumes.

Note
This will match if a) the volume has the auxiliary tag "Region" set to contain to "CalorimeterRegion" and b) the volume name contains one of the identifiers in the gdml_identifiers parameter

Implements simcore::SensitiveDetector.

Definition at line 47 of file HcalSD.h.

47 {
48 auto region = volume->GetRegion();
49 if (region and region->GetName().contains("CalorimeterRegion")) {
50 const auto name{volume->GetName()};
51 return std::find_if(std::begin(gdml_identifiers_),
52 std::end(gdml_identifiers_),
53 [&name](const auto& identifier) {
54 return name.contains(identifier);
55 }) != std::end(gdml_identifiers_);
56 }
57 return false;
58 }

◆ onFinishedEvent()

virtual void simcore::HcalSD::onFinishedEvent ( )
inlineoverridevirtual

Cleanup SD and prepare a new-event state.

Implements simcore::SensitiveDetector.

Definition at line 86 of file HcalSD.h.

86{ hits_.clear(); }
std::map< ldmx::HcalID, ldmx::SimCalorimeterHit > hits_
map of hits to add to the event (will be squashed)
Definition HcalSD.h:102

References hits_.

◆ ProcessHits()

G4bool simcore::HcalSD::ProcessHits ( G4Step * aStep,
G4TouchableHistory * ROhist )
overridevirtual

Create a hit out of the energy deposition deposited during a step.

Parameters
[in]stepThe current step.
[in]historyThe readout history.

Implements simcore::SensitiveDetector.

Definition at line 61 of file HcalSD.cxx.

61 {
62 // Get the edep from the step.
63 G4double edep = aStep->GetTotalEnergyDeposit();
64
65 // Skip steps with no energy dep which come from non-Geantino particles.
66 if (edep == 0.0 and not isGeantino(aStep)) {
67 ldmx_log(trace) << "CalorimeterSD skipping step with zero edep.";
68 return false;
69 }
70
71 //---------------------------------------------------------------------------------------------------
72 // Birks' Law
73 // ===========
74 //
75 // In the case of Scintillator as active medium, we can
76 // describe the quenching effects with the Birks' law,
77 // using the expression and the coefficients taken from
78 // the paper NIM 80 (1970) 239-244 for the organic
79 // scintillator NE-102:
80 // S*dE/dr
81 // dL/dr = -----------------------------------
82 // 1 + C1*(dE/dr)
83 // with:
84 // S=1
85 // C1 = 1.29 x 10^-2 g*cm^-2*MeV^-1
86 // C2 = 9.59 x 10^-6 g^2*cm^-4*MeV^-2
87 // These are the same values used by ATLAS TileCal
88 // and CMS HCAL (and also the default in Geant3).
89 // You can try different values for these parameters,
90 // to have an idea on the uncertainties due to them,
91 // by uncommenting one of the lines below.
92 // To get the "dE/dr" that appears in the formula,
93 // which has the dimensions
94 // [ dE/dr ] = MeV * cm^2 / g
95 // we have to divide the energy deposit in MeV by the
96 // product of the step length (in cm) and the density
97 // of the scintillator:
98
99 G4double birks_factor(1.0);
100 G4double step_length = aStep->GetStepLength() / CLHEP::cm;
101 // Do not apply Birks for gamma deposits!
102 // Check, cut if necessary.
103 if (step_length > 1.0e-6) {
104 G4double rho = aStep->GetPreStepPoint()->GetMaterial()->GetDensity() /
105 (CLHEP::g / CLHEP::cm3);
106 G4double dedx = edep / (rho * step_length); //[MeV*cm^2/g]
107 birks_factor = 1.0 / (1.0 + birksc1_ * dedx + birksc2_ * dedx * dedx);
108 if (aStep->GetTrack()->GetDefinition() == G4Gamma::GammaDefinition())
109 birks_factor = 1.0;
110 if (aStep->GetTrack()->GetDefinition() == G4Neutron::NeutronDefinition())
111 birks_factor = 1.0;
112 }
113
114 // update edep to include birksFactor
115 edep *= birks_factor;
116
117 // Get the scintillator solid box
118 G4Box* scint = nullptr;
119
120 if (aStep) {
121 const auto* pre_step_point = aStep->GetPreStepPoint();
122 if (pre_step_point) {
123 const auto& touchable_handle = pre_step_point->GetTouchableHandle();
124 if (touchable_handle) {
125 const auto* volume = touchable_handle->GetVolume();
126
127 if (volume) {
128 const auto* logical_volume = volume->GetLogicalVolume();
129 if (logical_volume) {
130 auto* solid = logical_volume->GetSolid();
131 if (solid) {
132 scint = static_cast<G4Box*>(solid);
133 }
134 }
135 }
136 }
137 }
138 }
139
140 // Set the step mid-point as the hit position.
141 G4StepPoint* pre_point = aStep->GetPreStepPoint();
142 G4StepPoint* post_point = aStep->GetPostStepPoint();
143 // A Geant4 "touchable" is a way to uniquely identify a particular volume,
144 // short for touchable detector element. See the detector definition and
145 // response section of the Geant4 application developers manual for details.
146 //
147 // The TouchableHandle is just a reference counted pointer to a
148 // G4TouchableHistory object, which is a concrete implementation of a
149 // G4Touchable interface.
150 //
151 auto touchable_history{pre_point->GetTouchableHandle()->GetHistory()};
152 // Affine transform for converting between local and global coordinates
153 auto top_transform{touchable_history->GetTopTransform()};
154 G4ThreeVector position =
155 0.5 * (pre_point->GetPosition() + post_point->GetPosition());
156 G4ThreeVector local_position = top_transform.TransformPoint(position);
157
158 // Create the ID for the hit. Note 2 here corresponds to the "depth" of the
159 // geometry tree. If this changes in the GDML, this would have to be updated
160 // here. Currently, 0 corresponds to the world volume, 1 corresponds to the
161 // Hcal, and 2 to the bars/absorbers
162 int copy_num = touchable_history->GetVolume(2)->GetCopyNo();
163 ldmx::HcalID id = decodeCopyNumber(copy_num, local_position, scint);
164
165 if (hits_.find(id) == hits_.end()) {
166 // hit in empty cell/bar
167 auto& new_hit = hits_[id];
168 new_hit.setID(id.raw());
169 new_hit.setPosition(position[0], position[1], position[2]);
170 }
171
172 auto& hit = hits_[id];
173
174 // hit variables
175 const G4Track* track = aStep->GetTrack();
176 auto time = track->GetGlobalTime();
177 auto track_id = track->GetTrackID();
178 auto pdg = track->GetParticleDefinition()->GetPDGEncoding();
179
181 int contrib_i = hit.findContribIndex(track_id, pdg);
182 if (compress_hit_contribs_ and contrib_i != -1) {
183 hit.updateContrib(contrib_i, edep, time);
184 } else {
185 auto map{getTrackMap()};
186 auto incident{map.findIncident(track_id)};
187 // default "origin" is just the same as incident
188 // "origin" checks if a hit "originates" from one of the earliest
189 // track IDs (i.e. probably one of the primaries)
190 int origin{incident};
191 for (int i{1}; i < max_origin_track_id_; ++i) {
192 if (map.isDescendant(track_id, i, 100)) {
193 origin = i;
194 break;
195 }
196 }
197 hit.addContrib(incident, track_id, pdg, edep, time, origin);
198 }
199 } else {
200 // no hit contribs and hit already exists
201 hit.setEdep(hit.getEdep() + edep);
202 if (time < hit.getTime() or hit.getTime() == 0) {
203 hit.setTime(time);
204 }
205 }
206 // Pre/post step details for scintillator response simulation
207 // Note: These are set for each step, so the last step's details will be used
208 // if multiple steps occur in the same bar
209
210 // Convert back to mm
211 hit.setPathLength(step_length * CLHEP::cm / CLHEP::mm);
212 hit.setVelocity(track->GetVelocity());
213 const auto& geometry = getCondition<ldmx::HcalGeometry>(
215 // Convert pre/post step position from global coordinates to coordinates
216 // within the scintillator bar
217 const auto local_pre_step_point{
218 top_transform.TransformPoint(pre_point->GetPosition())};
219 const auto local_post_step_point{
220 top_transform.TransformPoint(post_point->GetPosition())};
221
222 // And rotate them to a local coordinate system for the bar that always has
223 // the same x/y/z definitions (see HcalGeometry for details)
224 auto local_pre_position_rotated{geometry.rotateGlobalToLocalBarPosition(
225 {local_pre_step_point[0], local_pre_step_point[1],
226 local_pre_step_point[2]},
227 id)};
228
229 auto local_post_position_rotated{geometry.rotateGlobalToLocalBarPosition(
230 {local_post_step_point[0], local_post_step_point[1],
231 local_post_step_point[2]},
232 id)};
233 hit.setPreStepPosition(local_pre_position_rotated[0],
234 local_pre_position_rotated[1],
235 local_pre_position_rotated[2]);
236 hit.setPostStepPosition(local_post_position_rotated[0],
237 local_post_position_rotated[1],
238 local_post_position_rotated[2]);
239 hit.setPreStepTime(pre_point->GetGlobalTime());
240 hit.setPostStepTime(post_point->GetGlobalTime());
241
242 ldmx_log(trace) << hit;
243
244 return true;
245}
ldmx::HcalID decodeCopyNumber(const std::uint32_t copyNumber, const G4ThreeVector &localPosition, const G4Box *scint)
Decode copy number of scintillator bar.
Definition HcalSD.cxx:33
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.

References compress_hit_contribs_, ldmx::HcalGeometry::CONDITIONS_OBJECT_NAME, decodeCopyNumber(), enable_hit_contribs_, simcore::SensitiveDetector::getCondition(), simcore::SensitiveDetector::getTrackMap(), hits_, simcore::SensitiveDetector::isGeantino(), and max_origin_track_id_.

◆ saveHits()

void simcore::HcalSD::saveHits ( framework::Event & event)
overridevirtual

Add our hits to the event bus and then reset the container.

Implements simcore::SensitiveDetector.

Definition at line 247 of file HcalSD.cxx.

247 {
248 // squash hits into list
249 std::vector<ldmx::SimCalorimeterHit> hits;
250 hits.reserve(hits_.size());
251 for (const auto& [id, hit] : hits_) hits.push_back(hit);
252 event.add(COLLECTION_NAME, hits);
253}
static const std::string COLLECTION_NAME
name of collection to be added to event bus
Definition HcalSD.h:24

References COLLECTION_NAME, and hits_.

Member Data Documentation

◆ birksc1_

double simcore::HcalSD::birksc1_
private

Definition at line 96 of file HcalSD.h.

◆ birksc2_

double simcore::HcalSD::birksc2_
private

Definition at line 99 of file HcalSD.h.

◆ COLLECTION_NAME

const std::string simcore::HcalSD::COLLECTION_NAME = "HcalSimHits"
static

name of collection to be added to event bus

Definition at line 24 of file HcalSD.h.

Referenced by saveHits().

◆ compress_hit_contribs_

bool simcore::HcalSD::compress_hit_contribs_
private

compress hit contribs

Definition at line 106 of file HcalSD.h.

Referenced by HcalSD(), and ProcessHits().

◆ enable_hit_contribs_

bool simcore::HcalSD::enable_hit_contribs_
private

enable hit contribs

Definition at line 104 of file HcalSD.h.

Referenced by HcalSD(), and ProcessHits().

◆ gdml_identifiers_

std::vector<std::string> simcore::HcalSD::gdml_identifiers_
private

Definition at line 94 of file HcalSD.h.

◆ hits_

std::map<ldmx::HcalID, ldmx::SimCalorimeterHit> simcore::HcalSD::hits_
private

map of hits to add to the event (will be squashed)

Definition at line 102 of file HcalSD.h.

Referenced by onFinishedEvent(), ProcessHits(), and saveHits().

◆ max_origin_track_id_

int simcore::HcalSD::max_origin_track_id_
private

maximum track ID to be considered an "origin"

Definition at line 108 of file HcalSD.h.

Referenced by HcalSD(), and ProcessHits().


The documentation for this class was generated from the following files: