9#include <simulation/kernel/UserInfo.h>
10#include <vxd/simulation/SensitiveDetectorBase.h>
11#include <vxd/dataobjects/VXDElectronDeposit.h>
12#include <framework/gearbox/Const.h>
13#include <framework/gearbox/Unit.h>
15#ifdef VXD_SENSITIVEDETECTOR_DEBUG
16#include <vxd/simulation/SensitiveDetectorDebugHelper.h>
31 const G4Track& track = *
step->GetTrack();
33 const int pdgCode = track.GetDefinition()->GetPDGEncoding();
35 const bool isNeutral = track.GetDefinition()->GetPDGCharge() == 0;
37 && (abs(pdgCode) ==
Const::neutron.getPDGCode())) || (abs(pdgCode) == 99666);
39 if (isNeutral && !isAllowedNeutral)
return false;
42 const int trackID = track.GetTrackID();
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;
62 traversal.
setInitial(trackID, pdgCode, isPrimary);
64 if (preStep.GetStepStatus() == fGeomBoundary) traversal.
hasEntered();
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);
71 traversal.
add(postStepPos, postStepMom, electrons,
75 bool isLeaving = (postStep.GetStepStatus() == fGeomBoundary);
77 if (isLeaving) traversal.
hasLeft();
80 if (isLeaving || track.GetTrackStatus() >= fStopAndKill) {
97#ifdef VXD_SENSITIVEDETECTOR_DEBUG
104 int trueHitIndex = -1;
108 std::vector<std::pair<unsigned int, float>> simhits =
createSimHits();
111#ifdef VXD_SENSITIVEDETECTOR_DEBUG
112 debug.finishTraversal();
130 std::vector<std::pair<unsigned int, float>> simhits;
138 static std::stack<SensorTraversal::range> stack;
141 stack.push(make_pair(traversal.begin(), traversal.end() - 1));
143 SensorTraversal::iterator firstPoint, finalPoint, splitPoint;
146 while (!stack.empty()) {
148 std::tie(firstPoint, finalPoint) = stack.top();
152 const G4ThreeVector n = (finalPoint->position - firstPoint->position).unit();
154 double maxDistance(0);
155 for (
auto nextPoint = firstPoint + 1; nextPoint != finalPoint; ++nextPoint) {
159 const G4ThreeVector pa = nextPoint->position - firstPoint->position;
160 const double dist = (pa - (pa * n) * n).mag();
162 if (dist > maxDistance) {
163 splitPoint = nextPoint;
171 stack.push(make_pair(splitPoint, finalPoint));
172 stack.push(make_pair(firstPoint, splitPoint));
177 int simHitIndex =
saveSimHit(traversal, std::make_pair(firstPoint, finalPoint));
178 simhits.push_back(std::make_pair(simHitIndex, finalPoint->electrons - firstPoint->electrons));
191 std::vector<unsigned int> electronProfile;
194 SensorTraversal::iterator firstPoint, finalPoint;
196 std::tie(firstPoint, finalPoint) = points;
199 const double electronsOffset = (firstPoint->electrons);
201 const double length = finalPoint->length - firstPoint->length;
203 const double lengthOffset = firstPoint->length;
210 static std::stack <SensorTraversal::range> stack;
216 while (!stack.empty()) {
218 std::tie(firstPoint, finalPoint) = stack.top();
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;
230 const double lengthScale = 1. /
Unit::um * 80;
233 const double slope = segmentElectrons / segmentLength / lengthScale;
239 const double distanceConstant = std::sqrt(slope * slope + 1);
242 double maxDistance(0);
244 SensorTraversal::iterator splitPoint;
247 for (
auto nextPoint = firstPoint + 1; nextPoint != finalPoint; ++nextPoint) {
249 const double x = (nextPoint->length - startLength) * lengthScale;
250 const double dist = fabs(x * slope - nextPoint->electrons + startElectrons) / distanceConstant;
252 if (dist > maxDistance) {
253 splitPoint = nextPoint;
262 stack.push(make_pair(splitPoint, finalPoint));
263 stack.push(make_pair(firstPoint, splitPoint));
267 const double fraction = (finalPoint->length - lengthOffset) / length;
268 const double electrons = (finalPoint->electrons - electronsOffset);
271 return electronProfile;
278 const double midLength = traversal.
getLength() * 0.5;
279 auto after = traversal.begin();
280 while (after->length < midLength) ++after;
284 auto before = after - 1;
286 const double fl = (after->length - midLength) / (after->length - before->length);
287 const double fr = (1 - fl);
289 const double midTime = fl * before->time + fr * after->time;
290 const double midElectrons = fl * before->electrons + fr * after->electrons;
293 const G4ThreeVector& p0 = before->position;
294 const G4ThreeVector& p3 = after->position;
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;
301 const G4ThreeVector midPos = (
303 + 3 * fl * fl * fr * p1
304 + 3 * fl * fr * fr * p2
308 const G4ThreeVector midMom = 1.0 / momentumScale * (
310 + 2 * fl * fr * (p2 - p1)
311 + fr * fr * (p3 - p2)
314 return StepInformation(midPos, midMom, midElectrons, midTime, midLength);
int getPDGCode() const
PDG code.
static const ParticleType neutron
neutron particle
static const double ehEnergy
Energy needed to create an electron-hole pair in Si at std.
static const ParticleType photon
photon particle
@ c_PrimaryParticle
bit 0: Particle is primary particle.
Class to keep track of the traversal of the sensitive volume for one track.
int getPDGCode() const
get PDG code of the particle
double getElectrons() const
get total number of deposited electrons so far
void setInitial(int trackID, int pdgCode, bool primary)
set initial values for a new track
bool isPrimary() const
return whether the track belongs to a primary particle
void hasLeft()
indicate that the track left the current volume
int getTrackID() const
get Geant4 trackID
void add(const G4ThreeVector &position, const G4ThreeVector &momentum, double electrons, double time, double length)
add a new step
void reset()
reset to be used again
void hasEntered()
indicate that the track originated outisde the current volume
bool isContained() const
return whether the track was contained in the volume so far
std::pair< iterator, iterator > range
Iterator pair for a set of points.
double getLength() const
get flight length so far
static Payload getInfo(Carrier &obj)
Static function to just return UserInformation attached to the obj of type Carrier.
static const double mm
[millimeters]
static const double um
[micrometers]
static const double MeV
[megaelectronvolt]
static const double ns
Standard of [time].
Packed class to represent energy deposit along a path in electrons.
float m_minimumElectrons
minimum number of electrons a track must deposit for SimHit/TrueHits to be created
StepInformation findMidPoint(const SensorTraversal &traversal)
Find the mid-point of the track traversal.
bool finishTrack()
Process a track once all steps are known.
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.
bool m_onlyPrimaryTrueHits
only create TrueHits for primary particles
std::stack< SensorTraversal > m_tracks
stack of SensorTraversal information for all tracks not finished so far
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.
float m_electronTolerance
maximum relative difference between electron density of two steps where they can be considered simila...
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...
std::vector< unsigned int > simplifyEnergyDeposit(const SensorTraversal::range &points)
Simplify the energy deposition profile using Douglas-Peuker-Algorithm We normally force a Geant4 step...
bool step(G4Step *step, G4TouchableHistory *) override
Process a single Geant4 Step.
Small helper class to facilitate debugging of VXD::SensitiveDetector implementation.
static SensitiveDetectorDebugHelper & getInstance()
Singleton class: get instance.
Abstract base class for different kinds of events.