Belle II Software development
SensitiveDetector< SimHitClass, TrueHitClass > Class Template Reference

Sensitive Detector implementation of PXD and SVD. More...

#include <SensitiveDetector.h>

Inheritance diagram for SensitiveDetector< SimHitClass, TrueHitClass >:
SensitiveDetectorBase SensitiveDetectorBase

Public Member Functions

 SensitiveDetector (VXD::SensorInfoBase *sensorInfo)
 Construct instance and take over ownership of the sensorInfo pointer.
 
void setOptions (bool seeNeutrons, bool onlyPrimaryTrueHits, float distanceTolerance, float electronTolerance, float minimumElectrons)
 Set all common options.
 
SensorInfoBasegetSensorInfo ()
 Return a pointer to the SensorInfo associated with this instance.
 
VxdID getSensorID () const
 Return the VxdID belonging to this sensitive detector.
 

Static Public Member Functions

static const std::map< std::string, RelationArray::EConsolidationAction > & getMCParticleRelations ()
 Return a list of all registered Relations with MCParticles.
 
static void setActive (bool activeStatus)
 Enable/Disable all Sensitive Detectors.
 
static void registerMCParticleRelation (const std::string &name, RelationArray::EConsolidationAction ignoreAction=RelationArray::c_negativeWeight)
 Register an relation involving MCParticles.
 
static void registerMCParticleRelation (const RelationArray &relation, RelationArray::EConsolidationAction ignoreAction=RelationArray::c_negativeWeight)
 Overload to make it easer to register MCParticle relations.
 

Protected Member Functions

std::vector< unsigned int > simplifyEnergyDeposit (const SensorTraversal::range &points)
 Simplify the energy deposition profile using Douglas-Peuker-Algorithm We normally force a Geant4 step after 5µm but energy deposition does not necessarily vary much between these short steps.
 
StepInformation findMidPoint (const SensorTraversal &traversal)
 Find the mid-point of the track traversal.
 

Private Member Functions

int saveTrueHit (const SensorTraversal &traversal) override
 Save the actual TrueHit for a given sensor traversal information.
 
int saveSimHit (const SensorTraversal &traversal, const SensorTraversal::range &points) override
 Save a SimHit for a track along the given points.
 
void saveRelations (const SensorTraversal &traversal, int trueHitIndex, std::vector< std::pair< unsigned int, float > > simHitIndices) override
 Save the relations between MCParticle, TrueHit and SimHits.
 
std::array< float, 3 > vecToFloat (const G4ThreeVector &vec)
 Convert G4ThreeVector (aka Hep3Vector) to float array to store in TrueHit/SimHit classes.
 
bool step (G4Step *step, G4TouchableHistory *) override
 Process a single Geant4 Step.
 
bool finishTrack ()
 Process a track once all steps are known.
 
std::vector< std::pair< unsigned int, float > > createSimHits ()
 Determine which SimHits to create.
 
virtual bool ProcessHits (G4Step *aStep, G4TouchableHistory *aROhist)
 Check if recording hits is enabled and if so call step() and set the correct MCParticle flag.
 

Private Attributes

StoreArray< SimHitClass > m_simhits
 StoreArray for the SimHits.
 
StoreArray< TrueHitClass > m_truehits
 StoreArray for the TrueHits.
 
StoreArray< MCParticlem_mcparticles
 StoreArray for the MCParticles, needed by relations.
 
RelationArray m_relMCSimHits {m_mcparticles, m_simhits}
 Relation between MCParticle and SimHits.
 
RelationArray m_relMCTrueHits {m_mcparticles, m_truehits}
 Relation between MCParticle and TrueHits.
 
RelationArray m_relTrueSimHits {m_truehits, m_simhits}
 Relation between TrueHits and SimHits.
 
SensorInfoBasem_info {0}
 Pointer to the SensorInfo associated with this instance.
 
std::stack< SensorTraversalm_tracks
 stack of SensorTraversal information for all tracks not finished so far
 
float m_distanceTolerance {0}
 maximum distance between step point and linear interpolation of sensor traversal before a new simhit object is created
 
float m_electronTolerance {0}
 maximum relative difference between electron density of two steps where they can be considered similar enough to be merged
 
float m_minimumElectrons {0}
 minimum number of electrons a track must deposit for SimHit/TrueHits to be created
 
bool m_seeNeutrons {false}
 also create SimHit/TrueHit objects for neutrons (or charged particles which deposit less than m_minimumElectrons electrons
 
bool m_onlyPrimaryTrueHits {false}
 only create TrueHits for primary particles
 
Const::EDetector m_subdetector
 Subdetector the class belongs to.
 

Static Private Attributes

static std::map< std::string, RelationArray::EConsolidationActions_mcRelations
 Static set holding all relations which have to be updated at the end of the Event.
 
static bool s_active
 Static bool which indicates wether recording of hits is enabled.
 

Detailed Description

template<class SimHitClass, class TrueHitClass>
class Belle2::VXD::SensitiveDetector< SimHitClass, TrueHitClass >

Sensitive Detector implementation of PXD and SVD.

This class provides the actual implementation of the hit generation for PXD and SVD. It is templated to be able to create the corresponding output collection.

It generates two different kinds of Hits:

  • SimHits which correspond to Geant4 steps inside the sensitive volume. There will be several SimHits per traversal, since the step length of Geant4 is limited to provide detailed information about energy deposition.
  • TrueHits are aggregated objects which store the position where a particle crossed the detector plane (local z=0). There can be only one TrueHit per traversal of one sensor, but there may be more than one TrueHit for curling Tracks. TrueHits also carry information about the particle momenta before and after entering the silicon (or at start/end point if the track started/ended inside the silicon. MODIFIED July 2013 (based largely on suggestions by Martin Ritter):
    1. Every particle that either enters or leaves the sensitive volume and deposits some energy there, will create a TrueHit.
    2. The (u,v,w) position of the TrueHit are the coordinates of the midpoint of the track inside the sensitive volume (rather of the x-ing point with z=0): the w (z) coordinate is added to TrueHits.
    3. Each MC particle entering the sensitive volume will be un-ignored, so that the TrueHits created by secondaries entering the sensitive volume will be attributed to the correct MCParticle (that is, not to its primary ancestor).
    4. SimHit relations to MCParticles that don't produce a TrueHit and get re-attributed (to their primary ancestor) will have negative sign. This concerns the secondaries created inside the sensitive volume that don't reach another sensitive volume.
Template Parameters
SimHitClassClass to use when generating SimHits
TrueHitClassClass to use when generating TrueHits

Definition at line 64 of file SensitiveDetector.h.

Constructor & Destructor Documentation

◆ SensitiveDetector()

SensitiveDetector ( VXD::SensorInfoBase sensorInfo)
explicit

Construct instance and take over ownership of the sensorInfo pointer.

Definition at line 122 of file SensitiveDetector.h.

122 :
123 VXD::SensitiveDetectorBase(sensorInfo)
124 {
125 //Register output collections.
126 //m_mcparticles.isRequired();
134 }
@ c_negativeWeight
Flip the sign of the weight to become negative if the original element got re-attributed.
Definition: RelationArray.h:79
@ c_deleteElement
Delete the whole relation element if the original element got re-attributed.
Definition: RelationArray.h:81
static void registerMCParticleRelation(const std::string &name, RelationArray::EConsolidationAction ignoreAction=RelationArray::c_negativeWeight)
Register an relation involving MCParticles.
bool registerInDataStore(DataStore::EStoreFlags storeFlags=DataStore::c_WriteOut)
Register the object/array in the DataStore.
RelationArray m_relMCTrueHits
Relation between MCParticle and TrueHits.
RelationArray m_relMCSimHits
Relation between MCParticle and SimHits.
RelationArray m_relTrueSimHits
Relation between TrueHits and SimHits.
StoreArray< TrueHitClass > m_truehits
StoreArray for the TrueHits.
StoreArray< SimHitClass > m_simhits
StoreArray for the SimHits.

Member Function Documentation

◆ createSimHits()

std::vector< std::pair< unsigned int, float > > createSimHits ( )
privateinherited

Determine which SimHits to create.

A SimHit is a linear approximation of the particle trajectory. As such we try to combine as many Geant4 steps as possible by defining a distance tolerance and using the Douglas-Peucker algortihm to determine the required number of SimHits to keep the maximum distance of all Geant4 steps below that tolerance.

Returns
indices and electrons of all created simhits

Definition at line 126 of file SensitiveDetectorBase.cc.

127 {
128 SensorTraversal& traversal = m_tracks.top();
129 //List of created simhit indices to be able to create relations
130 std::vector<std::pair<unsigned int, float>> simhits;
131
132 //We need to check how close the steps would be to a linear approximation
133 //of the traversal and split the track if they are too far away. To do
134 //this we check the whole track and split it at the point with the
135 //largest distance recursively until the largest distance is inside the
136 //tolerance. For that we need a stack of segments and check each segment
137 //in turn until they fulfill the criteria.
138 static std::stack<SensorTraversal::range> stack;
139 //Lets push the full segment, first step point to last step point, on the
140 //stack. We use inclusive range, so the second iterator is still included
141 stack.push(make_pair(traversal.begin(), traversal.end() - 1));
142 //Iterators needed for checking
143 SensorTraversal::iterator firstPoint, finalPoint, splitPoint;
144
145 //Check all segments ...
146 while (!stack.empty()) {
147 //Get first and last point
148 std::tie(firstPoint, finalPoint) = stack.top();
149 //Remove segment from stack
150 stack.pop();
151 //Direction of the segment
152 const G4ThreeVector n = (finalPoint->position - firstPoint->position).unit();
153 //find largest distance to segment by looping over all intermediate points
154 double maxDistance(0);
155 for (auto nextPoint = firstPoint + 1; nextPoint != finalPoint; ++nextPoint) {
156 //Calculate distances between point p and line segment,
157 //x = a + t*n, where a is a point on the line and n is the unit vector
158 //pointing in line direction. distance = ||(p-a) - ((p-a)*n)*n||
159 const G4ThreeVector pa = nextPoint->position - firstPoint->position;
160 const double dist = (pa - (pa * n) * n).mag();
161 //Update splitpoint if distance is larger then previously known
162 if (dist > maxDistance) {
163 splitPoint = nextPoint;
164 maxDistance = dist;
165 }
166 }
167 //If we are above the tolerance we split the track
168 if (maxDistance > m_distanceTolerance) {
169 //If we split in this order, all created simhits will be in correct
170 //order. That is not a requirement but a nice side effect.
171 stack.push(make_pair(splitPoint, finalPoint));
172 stack.push(make_pair(firstPoint, splitPoint));
173 continue;
174 }
175 //Otherwise we create a SimHit
176 //FIXME: check for m_minimumElectrons?
177 int simHitIndex = saveSimHit(traversal, std::make_pair(firstPoint, finalPoint));
178 simhits.push_back(std::make_pair(simHitIndex, finalPoint->electrons - firstPoint->electrons));
179 }
180 return simhits;
181 }
float m_distanceTolerance
maximum distance between step point and linear interpolation of sensor traversal before a new simhit ...
virtual int saveSimHit(const SensorTraversal &traversal, const SensorTraversal::range &points)=0
Save a SimHit for this track including the given points.
std::stack< SensorTraversal > m_tracks
stack of SensorTraversal information for all tracks not finished so far

◆ findMidPoint()

StepInformation findMidPoint ( const SensorTraversal traversal)
protectedinherited

Find the mid-point of the track traversal.

This function will return the position and momentum at the center of the track traversal, using cubic spline interpolation between the actual geant4 steps. Center is defined as "half the flight length" in this case.

Parameters
traversalinformation on the particle traversal to be used when finding the midpoint
Returns
position and momentum at the mid point

Definition at line 274 of file SensitiveDetectorBase.cc.

275 {
276 //We want the middle of the track so we need to find the two steps
277 //which enclose this
278 const double midLength = traversal.getLength() * 0.5;
279 auto after = traversal.begin();
280 while (after->length < midLength) ++after;
281 //Now we have an iterator after the half length. We know that the first
282 //step contains length 0 so we can savely subtract one to get the one
283 //before
284 auto before = after - 1;
285 //the midpoint is in between so calculate the fractions from both sides
286 const double fl = (after->length - midLength) / (after->length - before->length);
287 const double fr = (1 - fl);
288 //we calculate the time and electrons using weighted average
289 const double midTime = fl * before->time + fr * after->time;
290 const double midElectrons = fl * before->electrons + fr * after->electrons;
291 //now we use 3rd order bezier curve to approximate mid position and momentum.
292 //The two base points are easy ...
293 const G4ThreeVector& p0 = before->position;
294 const G4ThreeVector& p3 = after->position;
295 //And the two control points are the base points +- the appropriately
296 //scaled momenta
297 const double momentumScale = (p3 - p0).mag() / before->momentum.mag() / 3;
298 const G4ThreeVector p1 = p0 + momentumScale * before->momentum;
299 const G4ThreeVector p2 = p3 - momentumScale * after->momentum;
300 // The curve is B(t) = (1-t)^3*P0 + 3*(1-t)^2*t*P1 + 3*(1-t)*t^2*P2 + t^3*P3
301 const G4ThreeVector midPos = (
302 fl * fl * fl * p0
303 + 3 * fl * fl * fr * p1
304 + 3 * fl * fr * fr * p2
305 + fr * fr * fr * p3
306 );
307 // The derivative is dB(t)/dt = 3*[(1-t)^2*(P1-P0)+2*(1-t)*t*(P2-P1)+t^2*(P3-P2)]
308 const G4ThreeVector midMom = 1.0 / momentumScale * (
309 fl * fl * (p1 - p0)
310 + 2 * fl * fr * (p2 - p1)
311 + fr * fr * (p3 - p2)
312 );
313 //Okay, we now have everything
314 return StepInformation(midPos, midMom, midElectrons, midTime, midLength);
315 }

◆ finishTrack()

bool finishTrack ( )
privateinherited

Process a track once all steps are known.

This function decides whether TrueHit/SimHits will be saved

Definition at line 94 of file SensitiveDetectorBase.cc.

95 {
96 SensorTraversal& traversal = m_tracks.top();
97#ifdef VXD_SENSITIVEDETECTOR_DEBUG
98 SensitiveDetectorDebugHelper& debug = SensitiveDetectorDebugHelper::getInstance();
99 debug.startTraversal(getSensorID(), traversal);
100#endif
101 bool save = traversal.getElectrons() >= m_minimumElectrons || (m_seeNeutrons
102 && (abs(traversal.getPDGCode()) == Const::neutron.getPDGCode()));
103 if (save) {
104 int trueHitIndex = -1;
105 if (!m_onlyPrimaryTrueHits || traversal.isPrimary()) {
106 trueHitIndex = saveTrueHit(traversal);
107 }
108 std::vector<std::pair<unsigned int, float>> simhits = createSimHits();
109 saveRelations(traversal, trueHitIndex, simhits);
110 }
111#ifdef VXD_SENSITIVEDETECTOR_DEBUG
112 debug.finishTraversal();
113#endif
114 //No we just need to take care of the stack of traversals
115 if (m_tracks.size() == 1) {
116 //reuse traversal to keep memory if this is the first one
117 traversal.reset();
118 } else {
119 //this should only happen if the parent track got suspended. As this
120 //rarely happens in PXD we do not care for re-usability here
121 m_tracks.pop();
122 }
123 return save;
124 }
int getPDGCode() const
PDG code.
Definition: Const.h:473
static const ParticleType neutron
neutron particle
Definition: Const.h:675
float m_minimumElectrons
minimum number of electrons a track must deposit for SimHit/TrueHits to be created
bool m_onlyPrimaryTrueHits
only create TrueHits for primary particles
std::vector< std::pair< unsigned int, float > > createSimHits()
Determine which SimHits to create.
virtual void saveRelations(const SensorTraversal &traversal, int trueHitIndex, std::vector< std::pair< unsigned int, float > > simHitIndices)=0
Save the relations between MCParticle, TrueHit and SimHits.
VxdID getSensorID() const
Return the VxdID belonging to this sensitive detector.
virtual int saveTrueHit(const SensorTraversal &traversal)=0
Save the actual TrueHit for this sensor traversal.
bool m_seeNeutrons
also create SimHit/TrueHit objects for neutrons (or charged particles which deposit less than m_minim...
static SensitiveDetectorDebugHelper & getInstance()
Singleton class: get instance.

◆ getMCParticleRelations()

static const std::map< std::string, RelationArray::EConsolidationAction > & getMCParticleRelations ( )
inlinestaticinherited

Return a list of all registered Relations with MCParticles.

Definition at line 42 of file SensitiveDetectorBase.h.

42{ return s_mcRelations; }
static std::map< std::string, RelationArray::EConsolidationAction > s_mcRelations
Static set holding all relations which have to be updated at the end of the Event.

◆ getSensorID()

VxdID getSensorID ( ) const
inlineinherited

Return the VxdID belonging to this sensitive detector.

Definition at line 80 of file SensitiveDetectorBase.h.

80{ return m_info->getID(); }
SensorInfoBase * m_info
Pointer to the SensorInfo associated with this instance.
VxdID getID() const
Return the ID of the Sensor.

◆ getSensorInfo()

SensorInfoBase * getSensorInfo ( )
inlineinherited

Return a pointer to the SensorInfo associated with this instance.

Definition at line 77 of file SensitiveDetectorBase.h.

77{ return m_info; }

◆ ProcessHits()

bool ProcessHits ( G4Step *  aStep,
G4TouchableHistory *  aROhist 
)
inlineprivatevirtualinherited

Check if recording hits is enabled and if so call step() and set the correct MCParticle flag.

Called by Geant4 for each step inside the sensitive volumes attached

Definition at line 94 of file SensitiveDetectorBase.h.

95 {
96 if (!s_active) return false;
97 bool result = step(aStep, aROhist);
98 // Do not include hits from invalid detector (beast,teastbeam, etc.)
99 if (result && (m_subdetector != Const::invalidDetector)) TrackInfo::getInfo(*aStep->GetTrack()).addSeenInDetector(m_subdetector);
100 return result;
101 }
virtual bool step(G4Step *step, G4TouchableHistory *ROhist)=0
Process a Geant4 step in any of the sensitive volumes attached to this sensitive detector.
Const::EDetector m_subdetector
Subdetector the class belongs to.
static bool s_active
Static bool which indicates wether recording of hits is enabled.
static Payload getInfo(Carrier &obj)
Static function to just return UserInformation attached to the obj of type Carrier.
Definition: UserInfo.h:100

◆ registerMCParticleRelation() [1/2]

static void registerMCParticleRelation ( const RelationArray relation,
RelationArray::EConsolidationAction  ignoreAction = RelationArray::c_negativeWeight 
)
inlinestaticinherited

Overload to make it easer to register MCParticle relations.

Parameters
relationRelationArray to register
ignoreAction

Definition at line 66 of file SensitiveDetectorBase.h.

67 { registerMCParticleRelation(relation.getName(), ignoreAction); }

◆ registerMCParticleRelation() [2/2]

void registerMCParticleRelation ( const std::string &  name,
RelationArray::EConsolidationAction  ignoreAction = RelationArray::c_negativeWeight 
)
staticinherited

Register an relation involving MCParticles.

All Relations which point from an MCParticle to something have to be registered with addMCParticleRelation() because the index of the MCParticles might change at the end of the event. During simulation, the TrackID should be used as index of the MCParticle

Parameters
nameName of the relation to register
ignoreAction

Definition at line 22 of file SensitiveDetectorBase.cc.

23 {
24 std::pair<std::map<std::string, RelationArray::EConsolidationAction>::iterator, bool> insert = s_mcRelations.insert(std::make_pair(
25 name, ignoreAction));
26 //If the relation already exists and the ignoreAction is different we do have a problem
27 if (!insert.second && insert.first->second != ignoreAction) {
28 B2FATAL("MCParticle Relation " << name << " already registered with different ignore action.");
29 }
30 }

◆ saveRelations()

void saveRelations ( const SensorTraversal traversal,
int  trueHitIndex,
std::vector< std::pair< unsigned int, float > >  simHitIndices 
)
overrideprivatevirtual

Save the relations between MCParticle, TrueHit and SimHits.

Parameters
traversalinformation on the particle traversal to be used when creating the Relations
trueHitIndexindex of the TrueHit, <0 if no TrueHit was created
simHitIndicesindices of the SimHits along with the number of electrons deposited in each SimHit

Implements SensitiveDetectorBase.

Definition at line 185 of file SensitiveDetector.h.

187 {
188 m_relMCSimHits.add(traversal.getTrackID(), simHitIndices.begin(), simHitIndices.end());
189 //If there is no truehit there are obviously no relations ;)
190 if (trueHitIndex >= 0) {
191 m_relMCTrueHits.add(traversal.getTrackID(), trueHitIndex, traversal.getElectrons());
192 m_relTrueSimHits.add(trueHitIndex, simHitIndices.begin(), simHitIndices.end());
193 }
194 }
void add(index_type from, index_type to, weight_type weight=1.0)
Add a new element to the relation.

◆ saveSimHit()

int saveSimHit ( const SensorTraversal traversal,
const SensorTraversal::range points 
)
overrideprivatevirtual

Save a SimHit for a track along the given points.

Parameters
traversalinformation on the particle traversal to be used when creating the SimHit
pointspair of iterators to the first and last step position to be used for the SimHit
Returns
the index of the created SimHit in its StoreArray

Implements SensitiveDetectorBase.

Definition at line 163 of file SensitiveDetector.h.

165 {
166 //Convert position to floats here
167 auto posIn = vecToFloat(points.first->position);
168 auto posOut = vecToFloat(points.second->position);
169 auto electronProfile = simplifyEnergyDeposit(points);
170
171 //Create the simhit
172 int simHitIndex = m_simhits.getEntries();
173 SimHitClass* simhit = m_simhits.appendNew(getSensorID(), traversal.getPDGCode(), points.first->time,
174 posIn.data(), posOut.data());
175 simhit->setEnergyDeposit(electronProfile);
176#ifdef VXD_SENSITIVEDETECTOR_DEBUG
177 int startPoint = std::distance(traversal.begin(), (SensorTraversal::const_iterator)points.first);
178 int endPoint = std::distance(traversal.begin(), (SensorTraversal::const_iterator)points.second);
179 SensitiveDetectorDebugHelper::getInstance().addSimHit(simhit, startPoint, endPoint);
180#endif
181 return simHitIndex;
182 }
T * appendNew()
Construct a new T object at the end of the array.
Definition: StoreArray.h:246
int getEntries() const
Get the number of objects in the array.
Definition: StoreArray.h:216
std::vector< unsigned int > simplifyEnergyDeposit(const SensorTraversal::range &points)
Simplify the energy deposition profile using Douglas-Peuker-Algorithm We normally force a Geant4 step...
void addSimHit(const VXDSimHit *simhit, int startPoint, int endPoint)
Write the information normally used when creating SimHits to the entry.
std::array< float, 3 > vecToFloat(const G4ThreeVector &vec)
Convert G4ThreeVector (aka Hep3Vector) to float array to store in TrueHit/SimHit classes.

◆ saveTrueHit()

int saveTrueHit ( const SensorTraversal traversal)
overrideprivatevirtual

Save the actual TrueHit for a given sensor traversal information.

Parameters
traversalinformation on the particle traversal to be used when creating the TrueHit
Returns
the index of the created TrueHit in its StoreArray

Implements SensitiveDetectorBase.

Definition at line 137 of file SensitiveDetector.h.

138 {
139 //We have the full sensor traversal information, we only lack the midpoint so lets get it
140 StepInformation midPoint = findMidPoint(traversal);
141
142 //By now everything is done: just convert the position and momenta in float[3] and create a truehit
143 auto posEntry = vecToFloat(traversal.front().position);
144 auto posMidPoint = vecToFloat(midPoint.position);
145 auto posExit = vecToFloat(traversal.back().position);
146 auto momEntry = vecToFloat(traversal.front().momentum);
147 auto momMidPoint = vecToFloat(midPoint.momentum);
148 auto momExit = vecToFloat(traversal.back().momentum);
149 //And we should convert the electrons back in energy ...
150 const double energyDep = traversal.getElectrons() * Const::ehEnergy;
151
152 //create the truehit
153 int trueHitIndex = m_truehits.getEntries();
154 m_truehits.appendNew(getSensorID(), posEntry.data(), posMidPoint.data(), posExit.data(),
155 momEntry.data(), momMidPoint.data(), momExit.data(), energyDep, midPoint.time);
156#ifdef VXD_SENSITIVEDETECTOR_DEBUG
158#endif
159 return trueHitIndex;
160 }
static const double ehEnergy
Energy needed to create an electron-hole pair in Si at std.
Definition: Const.h:697
StepInformation findMidPoint(const SensorTraversal &traversal)
Find the mid-point of the track traversal.
void addTrueHit(const VXDTrueHit *truehit)
Write the information normally used when creating TrueHits to the entry.

◆ setActive()

static void setActive ( bool  activeStatus)
inlinestaticinherited

Enable/Disable all Sensitive Detectors.

By default, all sensitive detectors won't create hits to make it possible to use the Geant4 Navigator for non-simulation purposes. Only during simulation the sensitive detectors will be enabled to record hits

Parameters
activeStatusbool to indicate wether hits should be recorded

Definition at line 50 of file SensitiveDetectorBase.h.

50{ s_active = activeStatus; }

◆ setOptions()

void setOptions ( bool  seeNeutrons,
bool  onlyPrimaryTrueHits,
float  distanceTolerance,
float  electronTolerance,
float  minimumElectrons 
)
inlineinherited

Set all common options.

Parameters
seeNeutronsif true, simhits are also stored for neutrons
onlyPrimaryTrueHitsif true, truehits will only be created for primary particles
distanceTolerancemaximal distance of step position from linear approximation.
electronTolerancemaximum deviation of energy deposition from linear approximation in electrons
minimumElectronsminimum number of electrons to be deposited before SimHits are created.

Definition at line 60 of file SensitiveDetectorBase.h.

62 {
63 m_seeNeutrons = seeNeutrons;
64 m_onlyPrimaryTrueHits = onlyPrimaryTrueHits;
65 m_distanceTolerance = distanceTolerance;
66 m_electronTolerance = electronTolerance;
67 m_minimumElectrons = minimumElectrons;
68 }
float m_electronTolerance
maximum relative difference between electron density of two steps where they can be considered simila...

◆ simplifyEnergyDeposit()

std::vector< unsigned int > simplifyEnergyDeposit ( const SensorTraversal::range points)
protectedinherited

Simplify the energy deposition profile using Douglas-Peuker-Algorithm We normally force a Geant4 step after 5µm but energy deposition does not necessarily vary much between these short steps.

Saving all steps would be a waste of space so we define a tolerance (in electrons) and keep only the points needed so that no point is further away from the profile than this tolerance.

Parameters
pointspair of iterators to the first and last point of the energy deposition profile
Returns
list of encoded EnergyDeposit values representing the simplified energy deposition profile.

Definition at line 183 of file SensitiveDetectorBase.cc.

184 {
185 //At the end we want a list of points indication how many electrons where
186 //deposited so far along the track, e.g. [(0.5,100), (1.0, 2000)] would
187 //indicate that after half the step length 100 electrons were deposited
188 //and at the end of the step we have 2000 electrons. To save some memory
189 //we encode this information as unsigned int using ElectronDeposit later
190 //on.
191 std::vector<unsigned int> electronProfile;
192
193 //We need an iterator to the first and last point in a segment
194 SensorTraversal::iterator firstPoint, finalPoint;
195 //for now let's extract the full segment
196 std::tie(firstPoint, finalPoint) = points;
197 //If this is not the first SimHit for a sensor traversal we need to
198 //subtract the electrons already taken care of
199 const double electronsOffset = (firstPoint->electrons);
200 //We also need the length of the step
201 const double length = finalPoint->length - firstPoint->length;
202 //And the start length
203 const double lengthOffset = firstPoint->length;
204
205 //We need to keep track of sub segments and where they should insert a
206 //midpoint if required. So we need a tuple of three iterators: insert
207 //position, first point and last point of the segment. We store those
208 //in a stack which we declare static to avoid some relocations if
209 //possible.
210 static std::stack <SensorTraversal::range> stack;
211 //And we push the full segment on the stack
212 stack.push(points);
213
214 //Now we check all segments we encounter until none exceed the maximum
215 //tolerance anymore
216 while (!stack.empty()) {
217 //Get next segment to be checked
218 std::tie(firstPoint, finalPoint) = stack.top();
219 //And remove it from the stack
220 stack.pop();
221
222 //Some variables we need
223 const double startElectrons = firstPoint->electrons;
224 const double startLength = firstPoint->length;
225 const double segmentLength = finalPoint->length - startLength;
226 const double segmentElectrons = finalPoint->electrons - startElectrons;
227 //We want to give the tolerance in electrons so we need to convert the
228 //step length into electrons. We do this by using the average number of
229 //electrons created per micrometer for a minimum ionizing particle.
230 const double lengthScale = 1. / Unit::um * 80;
231 //we need the slope for the linear approximation:
232 //electrons= slope*(length-startLength)*lengthScale+startElectrons;
233 const double slope = segmentElectrons / segmentLength / lengthScale;
234 //Distance between point x0,y0 and line a*x+b*y+c=0 is given as
235 //abs(a*x0+b*y0+c)/sqrt(a^2+b^2). In our case:
236 //x0=(length-startLength)*lengthScale, y0=electrons
237 //a=slope, b=-1, c=startElectrons.
238 //Nominator is independent of the actual point so we calculate it now
239 const double distanceConstant = std::sqrt(slope * slope + 1);
240
241 //Variable to remember maximum distance from linear approximation
242 double maxDistance(0);
243 //and also the point with the largest distance
244 SensorTraversal::iterator splitPoint;
245
246 //No go through all intermediate points
247 for (auto nextPoint = firstPoint + 1; nextPoint != finalPoint; ++nextPoint) {
248 //and check their distance from the linear approximation
249 const double x = (nextPoint->length - startLength) * lengthScale;
250 const double dist = fabs(x * slope - nextPoint->electrons + startElectrons) / distanceConstant;
251 //and remember if it is the largest distance
252 if (dist > maxDistance) {
253 splitPoint = nextPoint;
254 maxDistance = dist;
255 }
256 }
257 //if the largest distance is above the tolerance we split the segment
258 if (maxDistance > m_electronTolerance) {
259 //And add the two sub segments to the stack in the correcto order to
260 //ensure sorted processing: We always add the segments at the front
261 //last so they will be processed first
262 stack.push(make_pair(splitPoint, finalPoint));
263 stack.push(make_pair(firstPoint, splitPoint));
264 continue;
265 }
266 //otherwise we add the endpoint of the current segment to the list of points.
267 const double fraction = (finalPoint->length - lengthOffset) / length;
268 const double electrons = (finalPoint->electrons - electronsOffset);
269 electronProfile.push_back(VXDElectronDeposit(fraction, electrons));
270 }
271 return electronProfile;
272 }
static const double um
[micrometers]
Definition: Unit.h:71

◆ step()

bool step ( G4Step *  step,
G4TouchableHistory *   
)
overrideprivatevirtualinherited

Process a single Geant4 Step.

This function stores the necessary information to create the TrueHits and SimHits and will call finishTrack() if a track leaves the volume or is stopped inside the volume.

Implements SensitiveDetectorBase.

Definition at line 28 of file SensitiveDetectorBase.cc.

29 {
30 // Get track
31 const G4Track& track = *step->GetTrack();
32 // Get particle PDG code
33 const int pdgCode = track.GetDefinition()->GetPDGEncoding();
34 // Get particle charge (only keep charged tracks, photons and magnetic monopoles)
35 const bool isNeutral = track.GetDefinition()->GetPDGCharge() == 0;
36 const bool isAllowedNeutral = (pdgCode == Const::photon.getPDGCode()) || (m_seeNeutrons
37 && (abs(pdgCode) == Const::neutron.getPDGCode())) || (abs(pdgCode) == 99666);
38 //Not interested in neutral particles except photons, magnetic monopoles and maybe neutrons
39 if (isNeutral && !isAllowedNeutral) return false;
40
41 // Get track ID
42 const int trackID = track.GetTrackID();
43 //Get deposited energy
44 const double electrons = step->GetTotalEnergyDeposit() * Unit::MeV / Const::ehEnergy;
45 // Get step information
46 const G4StepPoint& postStep = *step->GetPostStepPoint();
47 const G4StepPoint& preStep = *step->GetPreStepPoint();
48 const G4AffineTransform& topTransform = preStep.GetTouchableHandle()->GetHistory()->GetTopTransform();
49 const G4ThreeVector postStepPos = topTransform.TransformPoint(postStep.GetPosition()) * Unit::mm;
50 const G4ThreeVector postStepMom = topTransform.TransformAxis(postStep.GetMomentum()) * Unit::MeV;
51
52 //Get the current track info
53 //if none present or not matching current trackID create one first
54 //if trackID is 0 we can reuse the existing top
55 if (m_tracks.empty() || (m_tracks.top().getTrackID() > 0 && m_tracks.top().getTrackID() != trackID)) {
56 m_tracks.push(SensorTraversal());
57 }
58 SensorTraversal& traversal = m_tracks.top();
59 if (traversal.getTrackID() == 0) {
60 bool isPrimary = Simulation::TrackInfo::getInfo(track).hasStatus(MCParticle::c_PrimaryParticle);
61 //If new track, remember values
62 traversal.setInitial(trackID, pdgCode, isPrimary);
63 //Remember if the track came from the outside
64 if (preStep.GetStepStatus() == fGeomBoundary) traversal.hasEntered();
65 //Add start position
66 const G4ThreeVector preStepPos = topTransform.TransformPoint(preStep.GetPosition()) * Unit::mm;
67 const G4ThreeVector preStepMom = topTransform.TransformAxis(preStep.GetMomentum()) * Unit::MeV;
68 traversal.add(preStepPos, preStepMom, 0, preStep.GetGlobalTime() * Unit::ns, 0);
69 }
70 //Add new track
71 traversal.add(postStepPos, postStepMom, electrons,
72 postStep.GetGlobalTime() * Unit::ns,
73 step->GetStepLength() * Unit::mm);
74 //check if we are leaving the volume
75 bool isLeaving = (postStep.GetStepStatus() == fGeomBoundary);
76 //remember that in the track info
77 if (isLeaving) traversal.hasLeft();
78 //If this step is to the boundary or track gets killed, save hits and
79 //return whether or not we saved something
80 if (isLeaving || track.GetTrackStatus() >= fStopAndKill) {
81 bool saved = finishTrack();
82 //If we saved at least one simhit and the track is not contained inside
83 //the sensor volume: keep MCParticle
84 if (saved && !traversal.isContained()) {
85 Simulation::TrackInfo::getInfo(track).setIgnore(false);
86 }
87 return saved;
88 }
89 //Track not finished so we do not save anything, let's return false for
90 //now
91 return false;
92 }
static const ParticleType photon
photon particle
Definition: Const.h:673
@ c_PrimaryParticle
bit 0: Particle is primary particle.
Definition: MCParticle.h:47
static const double mm
[millimeters]
Definition: Unit.h:70
static const double MeV
[megaelectronvolt]
Definition: Unit.h:114
static const double ns
Standard of [time].
Definition: Unit.h:48
bool finishTrack()
Process a track once all steps are known.
bool step(G4Step *step, G4TouchableHistory *) override
Process a single Geant4 Step.

◆ vecToFloat()

std::array< float, 3 > vecToFloat ( const G4ThreeVector &  vec)
inlineprivate

Convert G4ThreeVector (aka Hep3Vector) to float array to store in TrueHit/SimHit classes.

Parameters
vecvector to convert
Returns
array containing x,y,z as floats

Definition at line 102 of file SensitiveDetector.h.

103 {
104 return std::array<float, 3> {{(float)vec.x(), (float)vec.y(), (float)vec.z()}};
105 }

Member Data Documentation

◆ m_distanceTolerance

float m_distanceTolerance {0}
privateinherited

maximum distance between step point and linear interpolation of sensor traversal before a new simhit object is created

Definition at line 168 of file SensitiveDetectorBase.h.

◆ m_electronTolerance

float m_electronTolerance {0}
privateinherited

maximum relative difference between electron density of two steps where they can be considered similar enough to be merged

Definition at line 171 of file SensitiveDetectorBase.h.

◆ m_info

SensorInfoBase* m_info {0}
privateinherited

Pointer to the SensorInfo associated with this instance.

Definition at line 163 of file SensitiveDetectorBase.h.

◆ m_mcparticles

StoreArray<MCParticle> m_mcparticles
private

StoreArray for the MCParticles, needed by relations.

Definition at line 112 of file SensitiveDetector.h.

◆ m_minimumElectrons

float m_minimumElectrons {0}
privateinherited

minimum number of electrons a track must deposit for SimHit/TrueHits to be created

Definition at line 174 of file SensitiveDetectorBase.h.

◆ m_onlyPrimaryTrueHits

bool m_onlyPrimaryTrueHits {false}
privateinherited

only create TrueHits for primary particles

Definition at line 179 of file SensitiveDetectorBase.h.

◆ m_relMCSimHits

RelationArray m_relMCSimHits {m_mcparticles, m_simhits}
private

Relation between MCParticle and SimHits.

Definition at line 114 of file SensitiveDetector.h.

◆ m_relMCTrueHits

RelationArray m_relMCTrueHits {m_mcparticles, m_truehits}
private

Relation between MCParticle and TrueHits.

Definition at line 116 of file SensitiveDetector.h.

◆ m_relTrueSimHits

RelationArray m_relTrueSimHits {m_truehits, m_simhits}
private

Relation between TrueHits and SimHits.

Definition at line 118 of file SensitiveDetector.h.

◆ m_seeNeutrons

bool m_seeNeutrons {false}
privateinherited

also create SimHit/TrueHit objects for neutrons (or charged particles which deposit less than m_minimumElectrons electrons

Definition at line 177 of file SensitiveDetectorBase.h.

◆ m_simhits

StoreArray<SimHitClass> m_simhits
private

StoreArray for the SimHits.

Definition at line 108 of file SensitiveDetector.h.

◆ m_subdetector

Const::EDetector m_subdetector
privateinherited

Subdetector the class belongs to.

Definition at line 91 of file SensitiveDetectorBase.h.

◆ m_tracks

std::stack<SensorTraversal> m_tracks
privateinherited

stack of SensorTraversal information for all tracks not finished so far

Definition at line 165 of file SensitiveDetectorBase.h.

◆ m_truehits

StoreArray<TrueHitClass> m_truehits
private

StoreArray for the TrueHits.

Definition at line 110 of file SensitiveDetector.h.

◆ s_active

bool s_active
staticprivateinherited

Static bool which indicates wether recording of hits is enabled.

Definition at line 89 of file SensitiveDetectorBase.h.

◆ s_mcRelations

map< string, RelationArray::EConsolidationAction > s_mcRelations
staticprivateinherited

Static set holding all relations which have to be updated at the end of the Event.

Definition at line 87 of file SensitiveDetectorBase.h.


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