31 #include <G4TrackStatus.hh>
32 #include <G4PrimaryVertex.hh>
33 #include <G4PrimaryParticle.hh>
34 #include <G4TrackingManager.hh>
35 #include <G4ParticleDefinition.hh>
36 #include <CLHEP/Units/SystemOfUnits.h>
50 InstanceCount::increment(
this);
52 eventAction().callAtBegin(
this, &Geant4ParticleHandler::beginEvent);
53 eventAction().callAtEnd(
this, &Geant4ParticleHandler::endEvent);
54 trackingAction().callAtFinal(
this, &Geant4ParticleHandler::end,CallbackSequence::FRONT);
55 trackingAction().callUpFront(
this, &Geant4ParticleHandler::begin,CallbackSequence::FRONT);
56 steppingAction().call(
this, &Geant4ParticleHandler::step);
57 m_globalParticleID = 0;
58 declareProperty(
"PrintEndTracking", m_printEndTracking =
false);
59 declareProperty(
"PrintStartTracking", m_printStartTracking =
false);
60 declareProperty(
"KeepAllParticles", m_keepAll =
false);
61 declareProperty(
"SaveProcesses", m_processNames);
62 declareProperty(
"MinimalKineticEnergy", m_kinEnergyCut = 100e0*CLHEP::MeV);
63 declareProperty(
"MinDistToParentVertex", m_minDistToParentVertex = 2.2e-14*CLHEP::mm);
64 m_needsControl =
true;
68 Geant4ParticleHandler::Geant4ParticleHandler()
71 m_globalParticleID = 0;
72 declareProperty(
"PrintEndTracking", m_printEndTracking =
false);
73 declareProperty(
"PrintStartTracking", m_printStartTracking =
false);
74 declareProperty(
"KeepAllParticles", m_keepAll =
false);
75 declareProperty(
"SaveProcesses", m_processNames);
76 declareProperty(
"MinimalKineticEnergy", m_kinEnergyCut = 100e0*CLHEP::MeV);
77 declareProperty(
"MinDistToParentVertex", m_minDistToParentVertex = 2.2e-14*CLHEP::mm);
78 m_needsControl =
true;
82 Geant4ParticleHandler::~Geant4ParticleHandler() {
85 detail::releasePtr(h);
86 this->m_userHandlers.clear();
99 this->m_userHandlers.push_back(h);
103 except(
"Cannot add an user particle handler object [Object-exists].");
105 except(
"Cannot add an invalid user particle handler object [NULL-object].");
114 assert(
m_suspendedPM.empty() &&
"There was something wrong with the particle record treatment, please open a bug report!");
126 except(
"Cannot mark the G4Track if the pointer is invalid!");
132 mark(step_value->GetTrack(),reason);
135 except(
"Cannot mark the G4Track if the step-pointer is invalid!");
141 this->
mark(step_value->GetTrack());
144 except(
"Cannot mark the G4Track if the step-pointer is invalid!");
153 G4LogicalVolume* vol = track->GetVolume()->GetLogicalVolume();
160 if ( typ ==
"calorimeter" ) {
163 else if ( typ ==
"tracker" ) {
170 if( !this->m_userHandlers.empty() ) {
171 for(
auto* h : this->m_userHandlers )
182 debug(
"+++ Event:%d Add EVENT extension of type Geant4ParticleHandler.....",event->GetEventID());
186 for(
auto* h : this->m_userHandlers )
187 h->generate(event,
this);
192 typedef std::vector<const G4Track*> _Sec;
200 const _Sec* sec=step_value->GetSecondaryInCurrentStep();
201 if ( not sec->empty() ) {
206 for(
auto* h : this->m_userHandlers )
213 double kine = h.kineticEnergy();
214 G4ThreeVector mom = h.momentum();
215 const G4ThreeVector&
v = h.vertex();
217 const G4PrimaryParticle* prim = h.primary();
233 delete (*existingParticle).second;
242 except(
"+++ Tracking preaction: Primary particle without generator particle!");
314 G4LogicalVolume* vol = track->GetVolume()->GetLogicalVolume();
319 if( typ ==
"calorimeter" ) {
325 for(
auto* handler : this->m_userHandlers )
333 const int g4_id = h.id();
338 G4ThreeVector mom = track->GetMomentum();
339 const G4ThreeVector& pos = track->GetPosition();
351 const G4Step* theLastStep = track->GetStep();
352 G4StepPoint* theLastPostStepPoint = NULL;
353 if( theLastStep ) theLastPostStepPoint = theLastStep->GetPostStepPoint();
354 if( theLastPostStepPoint &&
355 ( theLastPostStepPoint->GetStepStatus() == fWorldBoundary
362 if( track->GetKineticEnergy() <= 0. ) {
368 std::string end_volume_type;
371 G4LogicalVolume* vol = track->GetVolume()->GetLogicalVolume();
377 if( tracker_hits || end_volume_type ==
"tracker" ) {
379 debug(
"+++ Track: %6d back-scattered to tracking volume. Origin: calorimeter End: %s "
380 "CALO-hits:%s TRACKER-hits:%s --> keep particle in MC history",
381 g4_id, end_volume_type.c_str(), yes_no(calo_hits), yes_no(tracker_hits));
386 for(
auto* handler : this->m_userHandlers )
408 info(
"+++ Track: %6d Particle back-scattering to tracker --> keep particle in MC history.", g4_id);
413 else part = (*ip).second;
416 part->extension.reset(track_info->
release());
431 const int start_pid = pid;
432 ParticleMap::iterator ip;
435 pid = (*iequiv).second;
440 for(
int compress=start_pid; compress != pid; ) {
442 if(it == iend)
break;
443 int next = it->second;
447 (*ip).second->reason |= track_reason;
450 ph.dumpWithVertex(
outputLevel()+3,
name(),
"FATAL: No real particle parent present");
453 if( track->GetTrackStatus() == fSuspend ) {
468 info(
"+++ Event %d Begin event action. Access event related information.",event->GetEventID());
474 for(
auto* h : this->m_userHandlers )
480 const std::string& n =
name();
492 if ( level <= VERBOSE )
dumpMap(
"Particle ");
496 if ( level <= VERBOSE )
dumpMap(
"Recombined");
499 if ( level <= VERBOSE )
dumpMap(
"Rebased ");
503 for(
auto* h : this->m_userHandlers )
519 ParticleMap::const_iterator ipar, iend, i;
527 for(count = 0, iend=pm.end(), i=pm.begin(); i!=iend; ++i) {
529 orgParticles[p->id] = p->
id;
530 finalParticles[p->id] = p;
531 if ( p->id > count ) count = p->id;
541 orgParticles[p->id] = count;
542 finalParticles[count] = p;
549 int g4_equiv = (*ie).first;
552 if ( iequiv == ie_end ) {
555 g4_equiv = (*iequiv).second;
557 TrackEquivalents::mapped_type equiv = (*ie).second;
560 equivalents[(*ie).first] = p->
id;
561 const G4ParticleDefinition* def = p.
definition();
562 int pdg = int(std::abs(def->GetPDGEncoding())+0.1);
563 if ( pdg != 0 && pdg<36 && !(pdg > 10 && pdg < 17) && pdg != 22 ) {
564 error(
"+++ ERROR: Geant4 particle for track:%d last known is:%d -- is gluon or quark!",equiv,g4_equiv);
566 pdg = int(std::abs(p->
pdgID)+0.1);
567 if ( pdg != 0 && pdg<36 && !(pdg > 10 && pdg < 17) && pdg != 22 ) {
568 error(
"+++ ERROR(2): Geant4 particle for track:%d last known is:%d -- is gluon or quark!",equiv,g4_equiv);
572 error(
"+++ No Equivalent particle for track:%d last known is:%d",equiv,g4_equiv);
584 for(
auto& part : finalParticles ) {
585 auto& p = part.second;
587 TrackEquivalents::iterator iequ = equivalents.find(p->
g4Parent);
588 if ( iequ != equivalents.end() ) {
589 equiv_id = (*iequ).second;
590 if ( (ipar=finalParticles.find(equiv_id)) != finalParticles.end() ) {
599 int parent_id = (*p->
parents.begin());
600 if ( parent_id == q->id )
601 q->daughters.insert(p->
id);
603 error(
"+++ Inconsistency in equivalent record! Parent: %d Daughter:%d",q->id, p->
id);
606 error(
"+++ Inconsistency in parent relashionship: %d NO parent!", p->
id);
611 error(
"+++ Inconsistency in particle record: Geant4 parent %d "
612 "of particle %d not in record of final particles!",
617 for(iend=finalParticles.end(), i=finalParticles.begin(); i!=iend; ++i) {
619 if ( p->g4Parent > 0 ) {
620 int parent_id = (*p->parents.begin());
621 if ( (ipar=finalParticles.find(parent_id)) != finalParticles.end() ) {
626 if ( parent_id == q->id )
629 error(
"+++ Inconsistency in equivalent record! Parent: %d Daughter:%d",q->id, p->id);
632 error(
"+++ Inconsistency in particle record: Geant4 parent %d "
633 "of particle %d not in record of final particles!",
657 else if ( mask.isNull() || (secondaries && low_energy && !hits_produced) ) {
661 else if ( !hits_produced && low_energy ) {
665 else if ( !tracker_track && calo_track && low_energy ) {
677 std::set<int> remove;
691 bool remove_me =
false;
692 if ( !this->m_userHandlers.empty() ) {
693 for(
auto* h : this->m_userHandlers )
694 remove_me |= h->dropParticle(*p);
720 Particle* parent_part = (*ip).second;
733 int g4_id = (*i).first;
734 remove.insert(g4_id);
737 Particle* parent_part = (*ip).second;
739 parent_part->steps += p->steps;
740 parent_part->secondaries += p->secondaries;
742 for(
auto* h : this->m_userHandlers )
743 h->combine(*p, *parent_part);
747 for(
int r : remove ) {
749 (*ir).second->release();
753 return int(remove.size());
766 std::set<int>& daughters = p->daughters;
767 ParticleMap::const_iterator j;
769 for(
int id_dau : daughters ) {
772 error(
"+++ Particle:%d Daughter %d is not in particle map!",p->id,id_dau);
778 bool in_map =
false, in_parent_list =
false;
781 parent_id = (*eq_it).second;
783 in_parent_list = p->parents.find(parent_id) != p->parents.end();
785 if ( !in_map || !in_parent_list ) {
786 char parent_list[1024];
789 p.dumpWithMomentum(ERROR,
name(),
"INCONSISTENCY");
790 for(
int ip : p->parents )
791 ::snprintf(parent_list+strlen(parent_list),
sizeof(parent_list)-strlen(parent_list),
"%d ",ip);
792 error(
"+++ Particle:%d Parent %d (G4id:%d) In record:%s In parent list:%s [%s]",
793 p->id,parent_id,p->g4Parent,yes_no(in_map),yes_no(in_parent_list),parent_list);
798 if ( num_errors > 0 ) {
799 except(
"+++ Consistency check failed. Found %d problems.",num_errors);
805 auto* p = part.second;
806 if( !p->parents.empty() ) {
819 const double X( parent->vex - p->vsx );
820 const double Y( parent->vey - p->vsy );
821 const double Z( parent->vez - p->vsz );