LDMX Software
Public Member Functions | Static Public Attributes | Private Attributes | List of all members
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.
 
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 > gdmlIdentifiers_
 
double birksc1_
 
double birksc2_
 
std::vector< ldmx::SimCalorimeterHithits_
 

Additional Inherited Members

- Public Types inherited from simcore::SensitiveDetector
using Factory = ::simcore::Factory< SensitiveDetector, SensitiveDetector *, const std::string &, simcore::ConditionsInterface &, const framework::config::Parameters & >
 The SD Factory.
 
- 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 TrackMapgetTrackMap () const
 Get a handle to the current track map.
 

Detailed Description

Class defining a sensitive detector of type HCal.

Definition at line 23 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 22 of file HcalSD.cxx.

24 : SensitiveDetector(name, ci, p), birksc1_(1.29e-2), birksc2_(9.59e-6) {
25 gdmlIdentifiers_ = {
26 p.getParameter<std::vector<std::string>>("gdml_identifiers")};
27}
SensitiveDetector(const std::string &name, simcore::ConditionsInterface &ci, const framework::config::Parameters &parameters)
Constructor.

References framework::config::Parameters::getParameter().

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 29 of file HcalSD.cxx.

31 {
32 const unsigned int version{copyNumber / 0x01000000};
33 if (version != 0) {
35 return ldmx::HcalID{Index(copyNumber).field2(), Index(copyNumber).field1(),
36 Index(copyNumber).field0()};
37 }
38 const auto& geometry = getCondition<ldmx::HcalGeometry>(
40 unsigned int stripID = 0;
41 const unsigned int section = copyNumber / 1000;
42 const unsigned int layer = copyNumber % 1000;
43
44 // 5cm wide bars are HARD-CODED
45 if (section == ldmx::HcalID::BACK) {
46 if (geometry.backLayerIsHorizontal(layer)) {
47 stripID = int((localPosition.y() + scint->GetYHalfLength()) / 50.0);
48 } else {
49 stripID = int((localPosition.x() + scint->GetXHalfLength()) / 50.0);
50 }
51 } else {
52 stripID = int((localPosition.z() + scint->GetZHalfLength()) / 50.0);
53 }
54 return ldmx::HcalID{section, layer, stripID};
55}
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

References ldmx::HcalGeometry::CONDITIONS_OBJECT_NAME.

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 49 of file HcalSD.h.

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

◆ OnFinishedEvent()

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

Cleanup SD and prepare a new-event state.

Implements simcore::SensitiveDetector.

Definition at line 90 of file HcalSD.h.

90{ hits_.clear(); }

◆ 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 57 of file HcalSD.cxx.

57 {
58 // Get the edep from the step.
59 G4double edep = aStep->GetTotalEnergyDeposit();
60
61 // Skip steps with no energy dep which come from non-Geantino particles.
62 if (edep == 0.0 and not isGeantino(aStep)) {
63 if (verboseLevel > 2) {
64 std::cout << "CalorimeterSD skipping step with zero edep." << std::endl
65 << std::endl;
66 }
67 return false;
68 }
69
70 //---------------------------------------------------------------------------------------------------
71 // Birks' Law
72 // ===========
73 //
74 // In the case of Scintillator as active medium, we can
75 // describe the quenching effects with the Birks' law,
76 // using the expression and the coefficients taken from
77 // the paper NIM 80 (1970) 239-244 for the organic
78 // scintillator NE-102:
79 // S*dE/dr
80 // dL/dr = -----------------------------------
81 // 1 + C1*(dE/dr)
82 // with:
83 // S=1
84 // C1 = 1.29 x 10^-2 g*cm^-2*MeV^-1
85 // C2 = 9.59 x 10^-6 g^2*cm^-4*MeV^-2
86 // These are the same values used by ATLAS TileCal
87 // and CMS HCAL (and also the default in Geant3).
88 // You can try different values for these parameters,
89 // to have an idea on the uncertainties due to them,
90 // by uncommenting one of the lines below.
91 // To get the "dE/dr" that appears in the formula,
92 // which has the dimensions
93 // [ dE/dr ] = MeV * cm^2 / g
94 // we have to divide the energy deposit in MeV by the
95 // product of the step length (in cm) and the density
96 // of the scintillator:
97
98 G4double birksFactor(1.0);
99 G4double stepLength = aStep->GetStepLength() / CLHEP::cm;
100 // Do not apply Birks for gamma deposits!
101 // Check, cut if necessary.
102 if (stepLength > 1.0e-6) {
103 G4double rho = aStep->GetPreStepPoint()->GetMaterial()->GetDensity() /
104 (CLHEP::g / CLHEP::cm3);
105 G4double dedx = edep / (rho * stepLength); //[MeV*cm^2/g]
106 birksFactor = 1.0 / (1.0 + birksc1_ * dedx + birksc2_ * dedx * dedx);
107 if (aStep->GetTrack()->GetDefinition() == G4Gamma::GammaDefinition())
108 birksFactor = 1.0;
109 if (aStep->GetTrack()->GetDefinition() == G4Neutron::NeutronDefinition())
110 birksFactor = 1.0;
111 }
112
113 // update edep to include birksFactor
114 edep *= birksFactor;
115
116 // Create a new cal hit.
117 ldmx::SimCalorimeterHit& hit{hits_.emplace_back()};
118
119 // Get the scintillator solid box
120 G4Box* scint = nullptr;
121
122 if (aStep) {
123 const auto* preStepPoint = aStep->GetPreStepPoint();
124 if (preStepPoint) {
125 const auto& touchableHandle = preStepPoint->GetTouchableHandle();
126 if (touchableHandle) {
127 const auto* volume = touchableHandle->GetVolume();
128
129 if (volume) {
130 const auto* logicalVolume = volume->GetLogicalVolume();
131 if (logicalVolume) {
132 auto* solid = logicalVolume->GetSolid();
133 if (solid) {
134 scint = static_cast<G4Box*>(solid);
135 }
136 }
137 }
138 }
139 }
140 }
141
142 // Set the step mid-point as the hit position.
143 G4StepPoint* prePoint = aStep->GetPreStepPoint();
144 G4StepPoint* postPoint = aStep->GetPostStepPoint();
145 // A Geant4 "touchable" is a way to uniquely identify a particular volume,
146 // short for touchable detector element. See the detector definition and
147 // response section of the Geant4 application developers manual for details.
148 //
149 // The TouchableHandle is just a reference counted pointer to a
150 // G4TouchableHistory object, which is a concrete implementation of a
151 // G4Touchable interface.
152 //
153 auto touchableHistory{prePoint->GetTouchableHandle()->GetHistory()};
154 // Affine transform for converting between local and global coordinates
155 auto topTransform{touchableHistory->GetTopTransform()};
156 G4ThreeVector position =
157 0.5 * (prePoint->GetPosition() + postPoint->GetPosition());
158 G4ThreeVector localPosition = topTransform.TransformPoint(position);
159 hit.setPosition(position[0], position[1], position[2]);
160
161 // Create the ID for the hit. Note 2 here corresponds to the "depth" of the
162 // geometry tree. If this changes in the GDML, this would have to be updated
163 // here. Currently, 0 corresponds to the world volume, 1 corresponds to the
164 // Hcal, and 2 to the bars/absorbers
165 int copyNum = touchableHistory->GetVolume(2)->GetCopyNo();
166 ldmx::HcalID id = decodeCopyNumber(copyNum, localPosition, scint);
167 hit.setID(id.raw());
168
169 // add one contributor for this hit with
170 // ID of ancestor incident on Cal-Region
171 // ID of this track
172 // PDG of this track
173 // EDEP (including birks factor)
174 // time of this hit
175 const G4Track* track = aStep->GetTrack();
176 int track_id = track->GetTrackID();
177 hit.addContrib(getTrackMap().findIncident(track_id), track_id,
178 track->GetParticleDefinition()->GetPDGEncoding(), edep,
179 track->GetGlobalTime());
180 //
181 // Pre/post step details for scintillator response simulation
182
183 // Convert back to mm
184 hit.setPathLength(stepLength * CLHEP::cm / CLHEP::mm);
185 hit.setVelocity(track->GetVelocity());
186 const auto& geometry = getCondition<ldmx::HcalGeometry>(
188 // Convert pre/post step position from global coordinates to coordinates
189 // within the scintillator bar
190 const auto localPreStepPoint{
191 topTransform.TransformPoint(prePoint->GetPosition())};
192 const auto localPostStepPoint{
193 topTransform.TransformPoint(postPoint->GetPosition())};
194
195 // And rotate them to a local coordinate system for the bar that always has
196 // the same x/y/z definitions (see HcalGeometry for details)
197 auto localPrePositionRotated{geometry.rotateGlobalToLocalBarPosition(
198 {localPreStepPoint[0], localPreStepPoint[1], localPreStepPoint[2]}, id)};
199
200 auto localPostPositionRotated{geometry.rotateGlobalToLocalBarPosition(
201 {localPostStepPoint[0], localPostStepPoint[1], localPostStepPoint[2]},
202 id)};
203 hit.setPreStepPosition(localPrePositionRotated[0], localPrePositionRotated[1],
204 localPrePositionRotated[2]);
205 hit.setPostStepPosition(localPostPositionRotated[0],
206 localPostPositionRotated[1],
207 localPostPositionRotated[2]);
208 hit.setPreStepTime(prePoint->GetGlobalTime());
209 hit.setPostStepTime(postPoint->GetGlobalTime());
210
211 if (this->verboseLevel > 2) {
212 hit.Print();
213 }
214
215 return true;
216}
Stores simulated calorimeter hit information.
ldmx::HcalID decodeCopyNumber(const std::uint32_t copyNumber, const G4ThreeVector &localPosition, const G4Box *scint)
Decode copy number of scintillator bar.
Definition HcalSD.cxx:29
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 ldmx::HcalGeometry::CONDITIONS_OBJECT_NAME, decodeCopyNumber(), simcore::SensitiveDetector::getTrackMap(), and simcore::SensitiveDetector::isGeantino().

◆ saveHits()

virtual void simcore::HcalSD::saveHits ( framework::Event event)
inlineoverridevirtual

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

Implements simcore::SensitiveDetector.

Definition at line 86 of file HcalSD.h.

86 {
87 event.add(COLLECTION_NAME, hits_);
88 }
static const std::string COLLECTION_NAME
name of collection to be added to event bus
Definition HcalSD.h:26

References COLLECTION_NAME.

Member Data Documentation

◆ birksc1_

double simcore::HcalSD::birksc1_
private

Definition at line 100 of file HcalSD.h.

◆ birksc2_

double simcore::HcalSD::birksc2_
private

Definition at line 103 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 26 of file HcalSD.h.

Referenced by saveHits().

◆ gdmlIdentifiers_

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

Definition at line 98 of file HcalSD.h.

◆ hits_

std::vector<ldmx::SimCalorimeterHit> simcore::HcalSD::hits_
private

Definition at line 106 of file HcalSD.h.


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