diff --git a/DDCore/include/DD4hep/Primitives.h b/DDCore/include/DD4hep/Primitives.h index 1fa133ad28b34da6ac16ce67c0d80319c52ed511..f68088aec49b06b72d7cf83fc3e1bf15170ed0fe 100644 --- a/DDCore/include/DD4hep/Primitives.h +++ b/DDCore/include/DD4hep/Primitives.h @@ -217,6 +217,39 @@ namespace DD4hep { template <typename M> ReleaseObjects<M> releaseObjects(M& m) { return ReleaseObjects<M>(m); } + + + /// Data structure to manipulate a bitmask held by reference and represented by an integer + /** + * @author M.Frank + * @version 1.0 + */ + template <typename T> class ReferenceBitMask { + public: + /// Reference to the data + T& mask; + /// Standard constructor + ReferenceBitMask(T& m); + T value() const { + return mask; + } + void set(const T& m) { + mask |= m; + } + bool isSet(const T& m) { + return (mask&m) == m; + } + bool testBit(int bit) const { + T m = T(1)<<bit; + return isSet(m); + } + bool isNull() const { + return mask == 0; + } + }; + /// Standard constructor + template <typename T> ReferenceBitMask<T>::ReferenceBitMask(T& m) : mask(m) {} + /* * Geometry namespace declaration */ diff --git a/DDG4/examples/CLICSidSimu.py b/DDG4/examples/CLICSidSimu.py index b16fb9ee56a34c68f3f7287ecc7d13ecd23b960c..b75a606496b9b30c0c6f3454f4f2b66d1672cc67 100644 --- a/DDG4/examples/CLICSidSimu.py +++ b/DDG4/examples/CLICSidSimu.py @@ -52,6 +52,10 @@ def run(): kernel.eventAction().add(evt1) kernel.eventAction().add(evt2) + prt = DDG4.EventAction(kernel,'Geant4ParticlePrint/ParticlePrint') + prt.OutputType = 3 # Print both: table and tree + kernel.eventAction().add(prt) + """ mc = DDG4.Action(kernel,"Geant4MonteCarloRecordManager/MonteCarloRecordManager") kernel.registerGlobalAction(mc) @@ -65,14 +69,12 @@ def run(): kernel.generatorAction().add(gen) # Setup particle gun - gun = simple.setupGun('Gun','pi-',100*GeV,True) + gun = simple.setupGun('Gun','pi-',energy=10*GeV,isotrop=True,multiplicity=3) trk = DDG4.GeneratorAction(kernel,"Geant4ParticleHandler/ParticleHandler") kernel.generatorAction().add(trk) - trk.SaveProcesses = ['conv','Decay'] + trk.saveProcesses = ['conv','Decay'] trk.enableUI() - """ - """ """ rdr = DDG4.GeneratorAction(kernel,"LcioGeneratorAction/Reader") diff --git a/DDG4/include/DDG4/Geant4Data.h b/DDG4/include/DDG4/Geant4Data.h index 410358033a97b0b6091f6321001dd26d1e2fe8c1..9cefc8c9978d1fc083eefc52a6579560f05e7e34 100644 --- a/DDG4/include/DDG4/Geant4Data.h +++ b/DDG4/include/DDG4/Geant4Data.h @@ -97,6 +97,43 @@ namespace DD4hep { virtual ~SimpleEvent(); }; + /// Track properties + enum ParticleProperties { + G4PARTICLE_CREATED_HIT = 1<<0, + G4PARTICLE_PRIMARY = 1<<1, + G4PARTICLE_HAS_SECONDARIES = 1<<2, + G4PARTICLE_ABOVE_ENERGY_THRESHOLD = 1<<3, + G4PARTICLE_KEEP_PROCESS = 1<<4, + G4PARTICLE_KEEP_PARENT = 1<<5, + G4PARTICLE_CREATED_CALORIMETER_HIT = 1<<6, + G4PARTICLE_CREATED_TRACKER_HIT = 1<<7, + G4PARTICLE_LAST_NOTHING = 1<<31 + }; + + /// Data structure to store the MC particle information + /** + * @author M.Frank + * @version 1.0 + */ + class Particle { + public: + int id, g4Parent, parent, reason, steps, secondaries; + double vsx, vsy, vsz; + double vex, vey, vez; + double psx, psy, psz, pex, pey, pez, energy, time; + const G4VProcess *process; + const G4ParticleDefinition *definition; + std::set<int> daughters; + /// Default constructor + Particle(); + /// Copy constructor + Particle(const Particle& c); + /// Default destructor + virtual ~Particle(); + /// Remove daughter from set + void removeDaughter(int id_daughter); + }; + /** @class SimpleHit Geant4Data.h DDG4/Geant4Data.h * * Base class for geant4 hit structures created by the diff --git a/DDG4/include/DDG4/Geant4MonteCarloTruth.h b/DDG4/include/DDG4/Geant4MonteCarloTruth.h index bd1d90f2eecf3e8581022c201bc134c93ce6ea11..3db9049faf06287d650803712dc99b22ede1a569 100644 --- a/DDG4/include/DDG4/Geant4MonteCarloTruth.h +++ b/DDG4/include/DDG4/Geant4MonteCarloTruth.h @@ -13,6 +13,7 @@ #include "DDG4/Geant4Action.h" // C/C++ include files +#include <map> // Forward declarations class G4Step; @@ -29,6 +30,9 @@ namespace DD4hep { */ namespace Simulation { + // Forward declarations + class Particle; + /** @class Geant4MonteCarloTruth Geant4MonteCarloTruth.h DDG4/Geant4MonteCarloTruth.h * * Default Interface class to handle monte carlo truth records @@ -37,20 +41,27 @@ namespace DD4hep { * @version 1.0 */ class Geant4MonteCarloTruth { + public: + typedef std::map<int,Particle*> ParticleMap; + typedef std::map<int,int> TrackEquivalents; protected: /// Standard constructor Geant4MonteCarloTruth(); public: /// Default destructor virtual ~Geant4MonteCarloTruth(); + /// Access the particle map + virtual const ParticleMap& particles() const = 0; + /// Access the map of track equivalents + virtual const TrackEquivalents& equivalents() const = 0; /// Mark a Geant4 track to be kept for later MC truth analysis virtual void mark(const G4Track* track) = 0; /// Store a track, with a flag - virtual void mark(const G4Track* track, bool created_hit) = 0; + virtual void mark(const G4Track* track, int reason) = 0; /// Mark a Geant4 track of the step to be kept for later MC truth analysis virtual void mark(const G4Step* step) = 0; /// Store a track produced in a step to be kept for later MC truth analysis - virtual void mark(const G4Step* step, bool created_hit) = 0; + virtual void mark(const G4Step* step, int reason) = 0; }; /** @class Geant4DummyTruthHandler Geant4DummyTruthHandler.h DDG4/Geant4DummyTruthHandler.h @@ -63,19 +74,28 @@ namespace DD4hep { class Geant4DummyTruthHandler : public Geant4Action, public Geant4MonteCarloTruth { + protected: + /// Map with stored MC Particles + ParticleMap m_particleMap; + /// Map associating the G4Track identifiers with identifiers of existing MCParticles + TrackEquivalents m_equivalentTracks; public: /// Standard constructor Geant4DummyTruthHandler(Geant4Context* ctxt,const std::string& nam); /// Default destructor virtual ~Geant4DummyTruthHandler(); - /// Mark a Geant4 track to be kept for later MC truth analysis + /// Access the particle map + virtual const ParticleMap& particles() const { return m_particleMap; } + /// Access the map of track equivalents + virtual const TrackEquivalents& equivalents() const { return m_equivalentTracks; } + /// Mark a Geant4 track to be kept for later MC truth analysis. Default flag: CREATED_HIT virtual void mark(const G4Track* track); /// Store a track, with a flag - virtual void mark(const G4Track* track, bool created_hit); - /// Mark a Geant4 track of the step to be kept for later MC truth analysis + virtual void mark(const G4Track* track, int reason); + /// Mark a Geant4 track of the step to be kept for later MC truth analysis. Default flag: CREATED_HIT virtual void mark(const G4Step* step); /// Store a track produced in a step to be kept for later MC truth analysis - virtual void mark(const G4Step* step, bool created_hit); + virtual void mark(const G4Step* step, int reason); }; } // End namespace Simulation diff --git a/DDG4/include/DDG4/Geant4ParticleHandler.h b/DDG4/include/DDG4/Geant4ParticleHandler.h index 6f384e25abea41808f7ad29f95f6e157a9cd224e..a31632779619165a0facb62be8d36cc5acbb7533 100644 --- a/DDG4/include/DDG4/Geant4ParticleHandler.h +++ b/DDG4/include/DDG4/Geant4ParticleHandler.h @@ -10,26 +10,15 @@ #define DD4HEP_DDG4_GEANT4PARTICLEHANDLER_H // Framework include files -#include "DDG4/Geant4Action.h" -#include "DDG4/Geant4EventAction.h" +#include "DDG4/Geant4Data.h" #include "DDG4/Geant4GeneratorAction.h" #include "DDG4/Geant4MonteCarloTruth.h" -#include "Math/PxPyPzE4D.h" -#include "G4VUserTrackInformation.hh" - -// C/C++ include files -#include <map> -#include <set> -#include <string> -#include <typeinfo> // Forward declarations class G4Step; class G4Track; class G4Event; -class G4VProcess; class G4SteppingManager; -class G4ParticleDefinition; /* * DD4hep namespace declaration @@ -42,88 +31,76 @@ namespace DD4hep { namespace Simulation { // Forward declarations + class Particle; - /** @class Geant4ParticleHandler Geant4ParticleHandler.h DDG4/Geant4ParticleHandler.h + /** Geant4Action to collect the MC particle information. * - * Default base class for all geant 4 actions and derivates thereof. * * @author M.Frank * @version 1.0 */ class Geant4ParticleHandler : public Geant4GeneratorAction, public Geant4MonteCarloTruth - { - public: - class Particle { - public: - int id, parent, theParent, reason; - double vx, vy, vz; - double px, py, pz, energy, time; - const G4VProcess *process; - const G4ParticleDefinition *definition; - std::set<int> daughters; - /// Default constructor - Particle(); - /// Copy constructor - Particle(const Particle& c); - /// Default destructor - virtual ~Particle(); - /// Remove daughter from set - void removeDaughter(int id_daughter); - }; - - typedef std::map<int,Particle*> ParticleMap; - typedef std::map<int,int> TrackEquivalents; - typedef std::vector<std::string> Processes; - protected: + { + public: + typedef std::vector<std::string> Processes; + protected: - /// Property: Steer printout at tracking action begin - bool m_printStartTracking; - /// Property: Steer printout at tracking action end - bool m_printEndTracking; - - Particle m_currTrack; - ParticleMap m_particleMap; - TrackEquivalents m_equivalentTracks; - Processes m_processNames; + /// Property: Steer printout at tracking action begin + bool m_printStartTracking; + /// Property: Steer printout at tracking action end + bool m_printEndTracking; + /// Property: Energy cut below which particles are not collected, but assigned to the parent + double m_kinEnergyCut; + /// Local buffer about the 'current' G4Track + Particle m_currTrack; + /// Map with stored MC Particles + ParticleMap m_particleMap; + /// Map associating the G4Track identifiers with identifiers of existing MCParticles + TrackEquivalents m_equivalentTracks; + /// All the processes of which the decay products will be explicitly stored + Processes m_processNames; - int recombineParents(); - /// Print record of kept particles - void printParticles(); - /// Clear particle maps - void clear(); - /// Check the record consistency - void checkConsistency() const; + /// Recombine particles and associate the to parents with cleanup + int recombineParents(); + /// Clear particle maps + void clear(); + /// Check the record consistency + void checkConsistency() const; + /// Get proper equivalent track from the particle map according to the given geant4 track ID + int equivalentTrack(int g4_id) const; - public: - /// Standard constructor - Geant4ParticleHandler(Geant4Context* context, const std::string& nam); - /// Default destructor - virtual ~Geant4ParticleHandler(); - /// Access the Geant4 tracking manager. Only use between tracking pre- and post action - G4TrackingManager* trackMgr() const { return m_context.trackMgr(); } - /// Event generation action callback - virtual void operator()(G4Event* event); - /// User stepping callback - virtual void step(const G4Step* step, G4SteppingManager* mgr); - /// Pre-event action callback - virtual void beginEvent(const G4Event* event); - /// Post-event action callback - virtual void endEvent(const G4Event* event); - /// Pre-track action callback - virtual void begin(const G4Track* track); - /// Post-track action callback - virtual void end(const G4Track* track); + public: + /// Standard constructor + Geant4ParticleHandler(Geant4Context* context, const std::string& nam); + /// Default destructor + virtual ~Geant4ParticleHandler(); + /// Event generation action callback + virtual void operator()(G4Event* event); + /// User stepping callback + virtual void step(const G4Step* step, G4SteppingManager* mgr); + /// Pre-event action callback + virtual void beginEvent(const G4Event* event); + /// Post-event action callback + virtual void endEvent(const G4Event* event); + /// Pre-track action callback + virtual void begin(const G4Track* track); + /// Post-track action callback + virtual void end(const G4Track* track); - /// Mark a Geant4 track to be kept for later MC truth analysis - virtual void mark(const G4Track* track); - /// Store a track - virtual void mark(const G4Track* track, bool created_hit); - /// Mark a Geant4 track of the step to be kept for later MC truth analysis - virtual void mark(const G4Step* step); - /// Store a track produced in a step to be kept for later MC truth analysis - virtual void mark(const G4Step* step, bool created_hit); + /// Access the particle map + virtual const ParticleMap& particles() const { return m_particleMap; } + /// Access the map of track equivalents + virtual const TrackEquivalents& equivalents() const { return m_equivalentTracks; } + /// Mark a Geant4 track to be kept for later MC truth analysis. Default flag: CREATED_HIT + virtual void mark(const G4Track* track); + /// Store a track + virtual void mark(const G4Track* track, int reason); + /// Mark a Geant4 track of the step to be kept for later MC truth analysis. Default flag: CREATED_HIT + virtual void mark(const G4Step* step); + /// Store a track produced in a step to be kept for later MC truth analysis + virtual void mark(const G4Step* step, int reason); - }; + }; } // End namespace Simulation } // End namespace DD4hep diff --git a/DDG4/include/DDG4/Geant4ParticlePrint.h b/DDG4/include/DDG4/Geant4ParticlePrint.h new file mode 100644 index 0000000000000000000000000000000000000000..1c5e2786e226a0bbe861e70ea2ee0cca68b587fd --- /dev/null +++ b/DDG4/include/DDG4/Geant4ParticlePrint.h @@ -0,0 +1,62 @@ +// $Id: Geant4Hits.h 513 2013-04-05 14:31:53Z gaede $ +//==================================================================== +// AIDA Detector description implementation +//-------------------------------------------------------------------- +// +// Author : M.Frank +// +//==================================================================== +#ifndef DD4HEP_DDG4_GEANT4PARTICLEPRINT_H +#define DD4HEP_DDG4_GEANT4PARTICLEPRINT_H + +// Framework include files +#include "DDG4/Geant4EventAction.h" +#include "DDG4/Geant4MonteCarloTruth.h" + +/* + * DD4hep namespace declaration + */ +namespace DD4hep { + + /* + * Simulation namespace declaration + */ + namespace Simulation { + + /** Geant4Action to collect the MC particle information. + * + * + * @author M.Frank + * @version 1.0 + */ + class Geant4ParticlePrint : public Geant4EventAction { + public: + typedef Geant4MonteCarloTruth::ParticleMap ParticleMap; + typedef Geant4MonteCarloTruth::TrackEquivalents TrackEquivalents; + protected: + /// Property: Flag to indicate output type: 1: TABLE, 2:TREE, 3:BOTH (default) + int m_outputType; + + void printParticle(const std::string& prefix, const Particle* p) const; + /// Print record of kept particles + void printParticles(const ParticleMap& particles) const; + /// Print tree of kept particles + void printParticleTree(const ParticleMap& particles, int level, const Particle* p) const; + /// Print tree of kept particles + void printParticleTree(const ParticleMap& particles) const; + + + public: + /// Standard constructor + Geant4ParticlePrint(Geant4Context* context, const std::string& nam); + /// Default destructor + virtual ~Geant4ParticlePrint(); + /// Pre-event action callback + virtual void begin(const G4Event* event); + /// Post-event action callback + virtual void end(const G4Event* event); + }; + } // End namespace Simulation +} // End namespace DD4hep + +#endif // DD4HEP_DDG4_GEANT4PARTICLEPRINT_H diff --git a/DDG4/include/DDG4/Geant4TrackPersistency.h b/DDG4/include/DDG4/Geant4TrackPersistency.h index 2aed25b6e4f5d6d435c8d4c838d8903e21361b49..4d050b60c3aa1912811204b85a8284d4f9c6fbba 100644 --- a/DDG4/include/DDG4/Geant4TrackPersistency.h +++ b/DDG4/include/DDG4/Geant4TrackPersistency.h @@ -88,6 +88,10 @@ namespace DD4hep { }; protected: + /// Map with stored MC Particles + ParticleMap m_particleMap; + /// Map associating the G4Track identifiers with identifiers of existing MCParticles + TrackEquivalents m_equivalentTracks; /// Information block for current track Geant4TrackPersistency::TrackInfo m_current; /// Property: Steer printout at tracking action begin @@ -105,7 +109,10 @@ namespace DD4hep { virtual ~Geant4TrackPersistency(); /// Access the Geant4 tracking manager. Only use between tracking pre- and post action G4TrackingManager* trackMgr() const { return m_context.trackMgr(); } - /// Event generation action callback + /// Access the particle map + virtual const ParticleMap& particles() const { return m_particleMap; } + /// Access the map of track equivalents + virtual const TrackEquivalents& equivalents() const { return m_equivalentTracks; } /// Event generation action callback virtual void operator()(G4Event* event); /// User stepping callback virtual void step(const G4Step* step, G4SteppingManager* mgr); @@ -121,11 +128,11 @@ namespace DD4hep { /// Mark a Geant4 track to be kept for later MC truth analysis virtual void mark(const G4Track* track); /// Store a track - virtual void mark(const G4Track* track, bool created_hit); + virtual void mark(const G4Track* track, int reason); /// Mark a Geant4 track of the step to be kept for later MC truth analysis virtual void mark(const G4Step* step); /// Store a track produced in a step to be kept for later MC truth analysis - virtual void mark(const G4Step* step, bool created_hit); + virtual void mark(const G4Step* step, int reason); }; } // End namespace Simulation diff --git a/DDG4/plugins/Geant4Factories.cpp b/DDG4/plugins/Geant4Factories.cpp index 70bfdccd17ae20b14f9468df5105d5bf4d1327df..169105fb561890a0ccc3dc72eba53fbb44cf4c87 100644 --- a/DDG4/plugins/Geant4Factories.cpp +++ b/DDG4/plugins/Geant4Factories.cpp @@ -49,6 +49,9 @@ DECLARE_GEANT4ACTION(Geant4MonteCarloRecordManager) #include "DDG4/Geant4ParticleHandler.h" DECLARE_GEANT4ACTION(Geant4ParticleHandler) +#include "DDG4/Geant4ParticlePrint.h" +DECLARE_GEANT4ACTION(Geant4ParticlePrint) + //============================= #include "DDG4/Geant4TrackingPreAction.h" DECLARE_GEANT4ACTION(Geant4TrackingPreAction) diff --git a/DDG4/src/Geant4Data.cpp b/DDG4/src/Geant4Data.cpp index 5f08fbe82188371dd18ed5b3082ce31db037943a..684d795679478304dffb586bf26dc5e32e7f6d39 100644 --- a/DDG4/src/Geant4Data.cpp +++ b/DDG4/src/Geant4Data.cpp @@ -41,6 +41,45 @@ SimpleEvent::~SimpleEvent() { InstanceCount::decrement(this); } +/// Copy constructor +Particle::Particle(const Particle& c) + : id(c.id), g4Parent(c.g4Parent), parent(c.parent), reason(c.reason), steps(c.steps), + vsx(c.vsx), vsy(c.vsy), vsz(c.vsz), + vex(c.vex), vey(c.vey), vez(c.vez), + psx(c.psx), psy(c.psy), psz(c.psz), + pex(c.pex), pey(c.pey), pez(c.pez), + energy(c.energy), time(c.time), + process(c.process), definition(c.definition), + daughters(c.daughters) +{ + InstanceCount::increment(this); +} + +/// Default constructor +Particle::Particle() + : id(0), g4Parent(0), parent(0), reason(0), steps(0), + vsx(0.0), vsy(0.0), vsz(0.0), + vex(0.0), vey(0.0), vez(0.0), + psx(0.0), psy(0.0), psz(0.0), + pex(0.0), pey(0.0), pez(0.0), + energy(0.0), time(0.0), + process(0), definition(0), + daughters() +{ + InstanceCount::increment(this); +} + +/// Default destructor +Particle::~Particle() { + InstanceCount::decrement(this); +} + +/// Remove daughter from set +void Particle::removeDaughter(int id_daughter) { + set<int>::iterator j = daughters.find(id_daughter); + if ( j != daughters.end() ) daughters.erase(j); +} + /// Default constructor SimpleHit::SimpleHit() : cellID(0) { diff --git a/DDG4/src/Geant4MonteCarloTruth.cpp b/DDG4/src/Geant4MonteCarloTruth.cpp index 0f4d9d96167e3fae69a8a77ee2f8e4a86af8eeb0..bfa1a452007a28e3bbc43a020a8d8fd8881e79a3 100644 --- a/DDG4/src/Geant4MonteCarloTruth.cpp +++ b/DDG4/src/Geant4MonteCarloTruth.cpp @@ -38,7 +38,7 @@ void Geant4DummyTruthHandler::mark(const G4Track*) { } /// Store a track, with a flag -void Geant4DummyTruthHandler::mark(const G4Track*, bool ) { +void Geant4DummyTruthHandler::mark(const G4Track*, int ) { } /// Mark a Geant4 track of the step to be kept for later MC truth analysis @@ -46,6 +46,6 @@ void Geant4DummyTruthHandler::mark(const G4Step*) { } /// Store a track produced in a step to be kept for later MC truth analysis -void Geant4DummyTruthHandler::mark(const G4Step*, bool ) { +void Geant4DummyTruthHandler::mark(const G4Step*, int ) { } diff --git a/DDG4/src/Geant4ParticleHandler.cpp b/DDG4/src/Geant4ParticleHandler.cpp index e0bbe8c1b5a4a7d13001159b663f793e935f01d8..033be704e85d8aea32ec84f4bd74dbccdd76f02d 100644 --- a/DDG4/src/Geant4ParticleHandler.cpp +++ b/DDG4/src/Geant4ParticleHandler.cpp @@ -10,13 +10,13 @@ #include "DD4hep/Printout.h" #include "DD4hep/Primitives.h" #include "DD4hep/InstanceCount.h" +#include "DDG4/Geant4StepHandler.h" #include "DDG4/Geant4TrackHandler.h" #include "DDG4/Geant4EventAction.h" #include "DDG4/Geant4TrackingAction.h" #include "DDG4/Geant4SteppingAction.h" #include "DDG4/Geant4MonteCarloRecordManager.h" #include "DDG4/Geant4ParticleHandler.h" -#include "DDG4/Geant4StepHandler.h" #include "G4TrackingManager.hh" #include "G4ParticleDefinition.hh" @@ -26,88 +26,30 @@ #include "G4PrimaryParticle.hh" #include "G4PrimaryVertex.hh" #include "G4Event.hh" +#include "CLHEP/Units/SystemOfUnits.h" #include <set> #include <stdexcept> using namespace std; -using DD4hep::InstanceCount; using namespace DD4hep; using namespace DD4hep::Simulation; +typedef ReferenceBitMask<int> PropertyMask; -static double m_kinEnergyCut = 500e0; - -enum { CREATED_HIT = 1<<0, - PRIMARY_PARTICLE = 1<<1, - SECONDARIES = 1<<2, - ENERGY = 1<<3, - KEEP_PROCESS = 1<<4, - KEEP_PARENT = 1<<5, - CREATED_CALORIMETER_HIT = 1<<6, - CREATED_TRACKER_HIT = 1<<7, - - LAST_NOTHING = 1<<31 -}; - - -template <typename T> class BitMask { -public: - T& refMask; - BitMask(T& m) : refMask(m) {} - T value() const { - return refMask; - } - void set(const T& m) { - refMask |= m; - } - bool isSet(const T& m) { - return (refMask&m) == m; - } - bool testBit(int bit) const { - T m = T(1)<<bit; - return isSet(m); - } - bool isNull() const { - return refMask == 0; +namespace { + G4PrimaryParticle* primary(int id, const G4Event& evt) { + for(int i=0, ni=evt.GetNumberOfPrimaryVertex(); i<ni; ++i) { + G4PrimaryVertex* v = evt.GetPrimaryVertex(i); + for(int j=0, nj=v->GetNumberOfParticle(); j<nj; ++j) { + G4PrimaryParticle* p = v->GetPrimary(j); + if ( id == p->GetTrackID() ) { + return p; + } + } + } + return 0; } -}; -template <typename T> inline BitMask<T> bitMask(T& m) { return BitMask<T>(m); } -template <typename T> inline BitMask<const T> bitMask(const T& m) { return BitMask<const T>(m); } - -/// Copy constructor -Geant4ParticleHandler::Particle::Particle(const Particle& c) - : id(c.id), parent(c.parent), theParent(c.theParent), reason(c.reason), - vx(c.vx), vy(c.vy), vz(c.vz), - px(c.px), py(c.py), pz(c.pz), - energy(c.energy), time(c.time), - process(c.process), definition(c.definition), - daughters(c.daughters) -{ - InstanceCount::increment(this); -} - -/// Default constructor -Geant4ParticleHandler::Particle::Particle() - : id(0), parent(0), theParent(0), reason(0), - vx(0.0), vy(0.0), vz(0.0), - px(0.0), py(0.0), pz(0.0), - energy(0.0), time(0.0), - process(0), definition(0), - daughters() -{ - InstanceCount::increment(this); -} - -/// Default destructor -Geant4ParticleHandler::Particle::~Particle() { - InstanceCount::decrement(this); -} - -/// Remove daughter from set -void Geant4ParticleHandler::Particle::removeDaughter(int id_daughter) { - set<int>::iterator j = daughters.find(id_daughter); - if ( j != daughters.end() ) daughters.erase(j); } /// Standard constructor @@ -116,14 +58,15 @@ Geant4ParticleHandler::Geant4ParticleHandler(Geant4Context* context, const std:: { //generatorAction().adopt(this); eventAction().callAtBegin(this,&Geant4ParticleHandler::beginEvent); - eventAction().callAtFinal(this,&Geant4ParticleHandler::endEvent); + eventAction().callAtEnd(this,&Geant4ParticleHandler::endEvent); trackingAction().callAtFinal(this,&Geant4ParticleHandler::end,CallbackSequence::FRONT); trackingAction().callUpFront(this,&Geant4ParticleHandler::begin,CallbackSequence::FRONT); steppingAction().call(this,&Geant4ParticleHandler::step); - declareProperty("PrintEndTracking",m_printEndTracking = false); - declareProperty("PrintStartTracking",m_printStartTracking = false); - declareProperty("SaveProcesses",m_processNames); + declareProperty("printEndTracking",m_printEndTracking = false); + declareProperty("printStartTracking",m_printStartTracking = false); + declareProperty("saveProcesses",m_processNames); + declareProperty("minimalKineticEnergy",m_kinEnergyCut = 100e0*MeV); InstanceCount::increment(this); } @@ -142,16 +85,20 @@ void Geant4ParticleHandler::clear() { } /// Mark a Geant4 track to be kept for later MC truth analysis -void Geant4ParticleHandler::mark(const G4Track* track, bool created_hit) { - mark(track); // Does all the checking... - if ( created_hit ) { +void Geant4ParticleHandler::mark(const G4Track* track, int reason) { + if ( track ) { + if ( reason != 0 ) { + PropertyMask(m_currTrack.reason).set(reason); + return; + } } + except("Cannot mark the G4Track if the pointer is invalid!", c_name()); } /// Store a track produced in a step to be kept for later MC truth analysis -void Geant4ParticleHandler::mark(const G4Step* step, bool created_hit) { +void Geant4ParticleHandler::mark(const G4Step* step, int reason) { if ( step ) { - mark(step->GetTrack(),created_hit); + mark(step->GetTrack(),reason); return; } except("Cannot mark the G4Track if the step-pointer is invalid!", c_name()); @@ -168,24 +115,20 @@ void Geant4ParticleHandler::mark(const G4Step* step) { /// Mark a Geant4 track of the step to be kept for later MC truth analysis void Geant4ParticleHandler::mark(const G4Track* track) { - BitMask<int> mask(m_currTrack.reason); - mask.set(CREATED_HIT); + PropertyMask mask(m_currTrack.reason); + mask.set(G4PARTICLE_CREATED_HIT); /// Check if the track origines from the calorimeter. // If yes, flag it, because it is a candidate fro removal. G4VPhysicalVolume* vol = track->GetVolume(); if ( strstr(vol->GetName().c_str(),"cal") ) { // just for test! - mask.set(CREATED_CALORIMETER_HIT); + mask.set(G4PARTICLE_CREATED_CALORIMETER_HIT); } - else if ( !mask.isSet(CREATED_TRACKER_HIT) ) { + else if ( !mask.isSet(G4PARTICLE_CREATED_TRACKER_HIT) ) { //printout(INFO,name(),"+++ Create TRACKER HIT: id=%d",m_currTrack.id); - mask.set(CREATED_TRACKER_HIT); + mask.set(G4PARTICLE_CREATED_TRACKER_HIT); } } -/// Check the record consistency -void Geant4ParticleHandler::checkConsistency() const { -} - /// Event generation action callback void Geant4ParticleHandler::operator()(G4Event*) { typedef Geant4MonteCarloTruth _MC; @@ -194,12 +137,153 @@ void Geant4ParticleHandler::operator()(G4Event*) { clear(); } +/// User stepping callback +void Geant4ParticleHandler::step(const G4Step* step, G4SteppingManager* /* mgr */) { + typedef std::vector<const G4Track*> _Sec; + ++m_currTrack.steps; + if ( m_currTrack.energy > m_kinEnergyCut ) { + // + // Tracks below the energy threshold are NOT stored. + // If these tracks produce hits or are selected due to another signature, + // this criterium will anyhow take precedence. + // + const _Sec* sec=step->GetSecondaryInCurrentStep(); + if ( sec->size() > 0 ) { + PropertyMask(m_currTrack.reason).set(G4PARTICLE_HAS_SECONDARIES); + } + } +} + +/// Pre-track action callback +void Geant4ParticleHandler::begin(const G4Track* track) { + Geant4TrackHandler h(track); + double kine = h.kineticEnergy(); + G4ThreeVector m = track->GetMomentum(); + + // Extract here all the information from the start of the tracking action + // which we will need later to create a proper MC particle. + m_currTrack.id = h.id(); + m_currTrack.reason = (kine > m_kinEnergyCut) ? G4PARTICLE_ABOVE_ENERGY_THRESHOLD : 0; + m_currTrack.energy = kine; + m_currTrack.g4Parent = h.parent(); + m_currTrack.parent = h.parent(); + m_currTrack.definition = h.trackDef(); + m_currTrack.process = h.creatorProcess(); + m_currTrack.time = h.globalTime(); + m_currTrack.vsx = h.vertex().x(); + m_currTrack.vsy = h.vertex().y(); + m_currTrack.vsz = h.vertex().z(); + m_currTrack.vex = 0.0; + m_currTrack.vey = 0.0; + m_currTrack.vez = 0.0; + m_currTrack.psx = m.x(); + m_currTrack.psy = m.y(); + m_currTrack.psz = m.z(); + m_currTrack.pex = 0.0; + m_currTrack.pey = 0.0; + m_currTrack.pez = 0.0; + // If the creator process of the track is in the list of process products to be kept, set the proper flag + if ( m_currTrack.process ) { + Processes::iterator i=find(m_processNames.begin(),m_processNames.end(),m_currTrack.process->GetProcessName()); + if ( i != m_processNames.end() ) { + PropertyMask(m_currTrack.reason).set(G4PARTICLE_KEEP_PROCESS); + } + } +} + +/// Post-track action callback +void Geant4ParticleHandler::end(const G4Track* track) { + Geant4TrackHandler h(track); + int id = h.id(); + PropertyMask mask(m_currTrack.reason); + G4PrimaryParticle* prim = primary(id,context()->event().event()); + + if ( prim ) { + m_currTrack.reason |= (G4PARTICLE_PRIMARY|G4PARTICLE_ABOVE_ENERGY_THRESHOLD); + const G4ParticleDefinition* def = m_currTrack.definition; + printout(INFO,name(),"+++ Add Primary particle %d def:%p [%s, %s] reason:%d", + id, def, + def ? def->GetParticleName().c_str() : "UNKNOWN", + def ? def->GetParticleType().c_str() : "UNKNOWN", m_currTrack.reason); + } + + if ( !mask.isNull() ) { + // These are candate tracks with a probability to be stored due to their properties: + // - primary particle + // - hits created + // - secondaries + // - above energy threshold + // - to be kept due to creator process + // + // Update vertex end point and final momentum + G4ThreeVector m = track->GetMomentum(); + m_currTrack.vex = h.vertex().x(); + m_currTrack.vey = h.vertex().y(); + m_currTrack.vez = h.vertex().z(); + m_currTrack.pex = m.x(); + m_currTrack.pey = m.y(); + m_currTrack.pez = m.z(); + + // Create a new MC particle from the current track information saved in the pre-tracking action + Particle* p = m_particleMap[id] = new Particle(m_currTrack); + // Add this track to it's parents list of daughters + ParticleMap::iterator ipar = m_particleMap.find(p->g4Parent); + if ( ipar != m_particleMap.end() ) { + Particle* p_par = (*ipar).second; + p_par->daughters.insert(id); + } + m_equivalentTracks[id] = id; +#if 0 + /// Some printout + const char* hit = mask.isSet(G4PARTICLE_CREATED_HIT) ? "CREATED_HIT" : ""; + const char* sec = mask.isSet(G4PARTICLE_HAS_SECONDARIES) ? "SECONDARIES" : ""; + const char* prim = mask.isSet(G4PARTICLE_PRIMARY) ? "PRIMARY" : ""; + printout(INFO,name(),"+++ Tracking postaction: %d/%d par:%d [%s, %s] created by:%s E:%e state:%s %s %s %s", + id,int(m_particleMap.size()), + h.parent(),h.name().c_str(),h.type().c_str(),h.creatorName().c_str(), + p->energy, h.statusName(), prim, hit, sec); +#endif + } + else { + // These are tracks without any special properties. + // + // We will not store them on the record, but have to memorise the + // track identifier in order to restore the history for the created hits. + m_equivalentTracks[id] = h.parent(); + } +} + /// Pre-event action callback void Geant4ParticleHandler::beginEvent(const G4Event* ) { - for(ParticleMap::const_iterator i=m_particleMap.begin(); i!=m_particleMap.end(); ++i) { - //Particle* part = (*i).second; - //int equiv_id = part->parent; +} + +/// Post-event action callback +void Geant4ParticleHandler::endEvent(const G4Event* ) { + int count = 0; + do { + printout(INFO,name(),"+++ Iteration:%d Tracks:%d Equivalents:%d",++count,m_particleMap.size(),m_equivalentTracks.size()); + } while( recombineParents() > 0 ); + // Update the particle's parents and replace the original Geant4 track with the + // equivalent particle still present in the record. + for(ParticleMap::const_iterator ipar, iend=m_particleMap.end(), i=m_particleMap.begin(); i!=iend; ++i) { + Particle* p = (*i).second; + p->parent = equivalentTrack(p->g4Parent); + if ( p->parent > 0 ) { + ipar = m_particleMap.find(p->parent); + if ( ipar != iend ) { + set<int>& daughters = (*ipar).second->daughters; + if ( daughters.find(p->id) == daughters.end() ) daughters.insert(p->id); + } + } + } + /// No we have to updte the map of equivalent tracks and assign the 'equivalentTrack' entry + for(TrackEquivalents::iterator i=m_equivalentTracks.begin(); i!=m_equivalentTracks.end(); ++i) { + int& track_id = (*i).second; + int equiv_id = equivalentTrack(track_id); + track_id = equiv_id; } + // Consistency check.... + checkConsistency(); } int Geant4ParticleHandler::recombineParents() { @@ -210,20 +294,20 @@ int Geant4ParticleHandler::recombineParents() { Particle* par = (*i).second; set<int>& daughters = par->daughters; if ( daughters.size() == 0 ) { - BitMask<const int> mask(par->reason); + PropertyMask mask(par->reason); int id = par->id; - bool secondaries = mask.isSet(SECONDARIES); - bool tracker_track = mask.isSet(CREATED_TRACKER_HIT); - bool calo_track = mask.isSet(CREATED_CALORIMETER_HIT); - bool hits_produced = mask.isSet(CREATED_HIT); - bool low_energy = !mask.isSet(ENERGY); - bool keep_process = mask.isSet(KEEP_PROCESS); - bool keep_parent = mask.isSet(KEEP_PARENT); - int parent_id = par->parent; + bool secondaries = mask.isSet(G4PARTICLE_HAS_SECONDARIES); + bool tracker_track = mask.isSet(G4PARTICLE_CREATED_TRACKER_HIT); + bool calo_track = mask.isSet(G4PARTICLE_CREATED_CALORIMETER_HIT); + bool hits_produced = mask.isSet(G4PARTICLE_CREATED_HIT); + bool low_energy = !mask.isSet(G4PARTICLE_ABOVE_ENERGY_THRESHOLD); + bool keep_process = mask.isSet(G4PARTICLE_KEEP_PROCESS); + bool keep_parent = mask.isSet(G4PARTICLE_KEEP_PARENT); + int parent_id = par->g4Parent; bool remove_me = false; /// Primary particles MUST be kept! - if ( mask.isSet(PRIMARY_PARTICLE) ) { + if ( mask.isSet(G4PARTICLE_PRIMARY) ) { continue; } else if ( keep_parent ) { @@ -233,9 +317,9 @@ int Geant4ParticleHandler::recombineParents() { ParticleMap::iterator ip = m_particleMap.find(parent_id); if ( ip != m_particleMap.end() ) { Particle* parent_part = (*ip).second; - BitMask<const int> parent_mask(parent_part->reason); - if ( parent_mask.isSet(ENERGY) ) { - parent_part->reason |= KEEP_PARENT; + PropertyMask parent_mask(parent_part->reason); + if ( parent_mask.isSet(G4PARTICLE_ABOVE_ENERGY_THRESHOLD) ) { + parent_mask.set(G4PARTICLE_KEEP_PARENT); continue; } } @@ -266,7 +350,7 @@ int Geant4ParticleHandler::recombineParents() { m_equivalentTracks[id] = parent_id; if ( ip != m_particleMap.end() ) { Particle* parent_part = (*ip).second; - bitMask(parent_part->reason).set(mask.value()); + PropertyMask(parent_part->reason).set(mask.value()); // Remove track from parent's list of daughters parent_part->removeDaughter(id); } @@ -284,173 +368,66 @@ int Geant4ParticleHandler::recombineParents() { return int(remove.size()); } -/// Pre-event action callback -void Geant4ParticleHandler::endEvent(const G4Event* ) { - int count = 0; - do { - printout(INFO,name(),"+++ Iteration:%d Tracks:%d Equivalents:%d",++count,m_particleMap.size(),m_equivalentTracks.size()); - } while( recombineParents() > 0 ); - - for(ParticleMap::const_iterator ipar, i=m_particleMap.begin(); i!=m_particleMap.end(); ++i) { - Particle* part = (*i).second; - int equiv_id = part->parent; - if ( equiv_id != 0 ) { - while( (ipar=m_particleMap.find(equiv_id)) == m_particleMap.end() ) { - TrackEquivalents::const_iterator iequiv = m_equivalentTracks.find(equiv_id); - equiv_id = (iequiv == m_equivalentTracks.end()) ? -1 : (*iequiv).second; - if ( equiv_id < 0 ) { - printout(INFO,name(),"+++ No Equivalent particle for track:%d last known is:%d",part->id,equiv_id); - break; - } +/// Check the record consistency +void Geant4ParticleHandler::checkConsistency() const { + int num_errors = 0; + + /// First check the consistency of the particle map itself + for(ParticleMap::const_iterator j, i=m_particleMap.begin(); i!=m_particleMap.end(); ++i) { + Particle* p = (*i).second; + PropertyMask mask(p->reason); + set<int>& daughters = p->daughters; + // For all particles, the set of daughters must be contained in the record. + for(set<int>::const_iterator id=daughters.begin(); id!=daughters.end(); ++id) { + int id_dau = *id; + j = m_particleMap.find(id_dau); + if ( j == m_particleMap.end() ) { + ++num_errors; + printout(INFO,name(),"+++ Particle:%d Daughter %d is not in particle map!",p->id,id_dau); } - if ( equiv_id>0 && equiv_id != part->parent ) part->theParent = equiv_id; } - } - checkConsistency(); - printParticles(); -} - -/// Print record of kept particles -void Geant4ParticleHandler::printParticles() { - char equiv[32]; - ParticleMap::const_iterator ipar; - printout(INFO,name(),"+++ MC Particles #Tracks:%6d %-12s Parent%-7s " - "Primary Secondaries Energy %9s Calo Tracker Process", - int(m_particleMap.size()),"ParticleType","","in [MeV]"); - for(ParticleMap::const_iterator i=m_particleMap.begin(); i!=m_particleMap.end(); ++i) { - Particle* part = (*i).second; - BitMask<const int> mask(part->reason); - equiv[0] = 0; - if ( part->parent != part->theParent ) { - ::snprintf(equiv,sizeof(equiv),"/%d",part->theParent); + // For all particles except the primaries, the parent must be contained in the record. + if ( !mask.isSet(G4PARTICLE_PRIMARY) ) { + int id_par = p->parent; + j = m_particleMap.find(id_par); + if ( j == m_particleMap.end() ) { + ++num_errors; + printout(INFO,name(),"+++ Particle:%d Parent %d is not in particle map!",p->id,id_par); + } } - printout(INFO,name(),"+++ MC Particle TrackID: %6d %-12s %6d%-7s " - "%-7s %-11s %-7s %8.3g %-4s %-7s %-7s [%s/%s]", - part->id, - part->definition->GetParticleName().c_str(), - part->parent,equiv, - yes_no(mask.isSet(PRIMARY_PARTICLE)), - yes_no(mask.isSet(SECONDARIES)), - yes_no(mask.isSet(ENERGY)), - part->energy, - yes_no(mask.isSet(CREATED_CALORIMETER_HIT)), - yes_no(mask.isSet(CREATED_TRACKER_HIT)), - yes_no(mask.isSet(KEEP_PROCESS)), - part->process ? part->process->GetProcessName().c_str() : "???", - part->process ? G4VProcess::GetProcessTypeName(part->process->GetProcessType()).c_str() : "" - ); } - printout(INFO,"Summary","+++ MC Particles #Tracks:%6d %-12s Parent%-7s " - "Primary Secondaries Energy %9s Calo Tracker Process", - int(m_particleMap.size()),"ParticleType","","in [MeV]"); -} -/// User stepping callback -void Geant4ParticleHandler::step(const G4Step* step, G4SteppingManager* /* mgr */) { - typedef std::vector<const G4Track*> _Sec; - if ( m_currTrack.energy > m_kinEnergyCut ) { - // - // Tracks below the energy threshold are NOT stored. - // If these tracks produce hits or are selected due to another signature, - // this criterium will anyhow take precedence. - // - const _Sec* sec=step->GetSecondaryInCurrentStep(); - if ( sec->size() > 0 ) { - bitMask(m_currTrack.reason).set(SECONDARIES); + /// No we have to check the consistency of the map of equivalent tracks used to assign the + /// proper MC particle to the created hits + for(TrackEquivalents::const_iterator i=m_equivalentTracks.begin(); i!=m_equivalentTracks.end(); ++i) { + int track_id = (*i).second; + int equiv_id = equivalentTrack(track_id); + ParticleMap::const_iterator j = m_particleMap.find(equiv_id); + if ( j == m_particleMap.end() ) { + int g4_id = (*i).first; + ++num_errors; + printout(INFO,name(),"+++ Geant4 Track:%d Track:%d Equivalent track %d is not in particle map!",g4_id,track_id,equiv_id); } } -} - -/// Pre-track action callback -void Geant4ParticleHandler::begin(const G4Track* track) { - Geant4TrackHandler h(track); - double kine = h.kineticEnergy(); - G4ThreeVector m = track->GetMomentum(); - // Extract here all the information from the start of the tracking action - // which we will need later to create a proper MC particle. - m_currTrack.id = h.id(); - m_currTrack.reason = (kine > m_kinEnergyCut) ? ENERGY : 0; - m_currTrack.energy = kine; - m_currTrack.parent = h.parent(); - m_currTrack.theParent = h.parent(); - m_currTrack.definition = h.trackDef(); - m_currTrack.process = h.creatorProcess(); - m_currTrack.time = h.globalTime(); - m_currTrack.vx = h.vertex().x(); - m_currTrack.vy = h.vertex().y(); - m_currTrack.vz = h.vertex().z(); - m_currTrack.px = m.x(); - m_currTrack.py = m.y(); - m_currTrack.pz = m.z(); - // If the creator process of the track is in the list of process products to be kept, set the proper flag - if ( m_currTrack.process ) { - Processes::iterator i=find(m_processNames.begin(),m_processNames.end(),m_currTrack.process->GetProcessName()); - if ( i != m_processNames.end() ) { - bitMask(m_currTrack.reason).set(KEEP_PROCESS); - } + if ( num_errors > 0 ) { + printout(ERROR,name(),"+++ Consistency check failed. Found %d problems.",num_errors); } } -static G4PrimaryParticle* primary(int id, const G4Event& evt) { - for(int i=0, ni=evt.GetNumberOfPrimaryVertex(); i<ni; ++i) { - G4PrimaryVertex* v = evt.GetPrimaryVertex(i); - for(int j=0, nj=v->GetNumberOfParticle(); j<nj; ++j) { - G4PrimaryParticle* p = v->GetPrimary(i); - if ( id == p->GetTrackID() ) { - return p; +/// Get proper equivalent track from the particle map according to the given geant4 track ID +int Geant4ParticleHandler::equivalentTrack(int g4_id) const { + int equiv_id = g4_id; + if ( g4_id != 0 ) { + ParticleMap::const_iterator ipar; + while( (ipar=m_particleMap.find(equiv_id)) == m_particleMap.end() ) { + TrackEquivalents::const_iterator iequiv = m_equivalentTracks.find(equiv_id); + equiv_id = (iequiv == m_equivalentTracks.end()) ? -1 : (*iequiv).second; + if ( equiv_id < 0 ) { + printout(INFO,name(),"+++ No Equivalent particle for track:%d last known is:%d",g4_id,equiv_id); + break; } } } - return 0; -} - -/// Post-track action callback -void Geant4ParticleHandler::end(const G4Track* track) { - Geant4TrackHandler h(track); - int id = h.id(); - BitMask<const int> mask(m_currTrack.reason); - G4PrimaryParticle* prim = primary(id,context()->event().event()); - - if ( prim ) { - m_currTrack.reason |= (PRIMARY_PARTICLE|ENERGY); - const G4ParticleDefinition* def = m_currTrack.definition; - printout(INFO,name(),"+++ Add Primary particle %d def:%p [%s, %s] reason:%d", - id, def, - def ? def->GetParticleName().c_str() : "UNKNOWN", - def ? def->GetParticleType().c_str() : "UNKNOWN", m_currTrack.reason); - } - - if ( !mask.isNull() ) { - // These are candate tracks with a probability to be stored due to their properties: - // - no primary particle - // - no hits created - // - no secondaries - // - not above energy threshold - // - // Create a new MC particle from the current track information saved in the pre-tracking action - Particle* p = m_particleMap[id] = new Particle(m_currTrack); - // Add this track to it's parents list of daughters - ParticleMap::iterator ipar = m_particleMap.find(p->parent); - if ( ipar != m_particleMap.end() ) { - (*ipar).second->daughters.insert(id); - } -#if 0 - /// Some printout - const char* hit = mask.isSet(CREATED_HIT) ? "CREATED_HIT" : ""; - const char* sec = mask.isSet(SECONDARIES) ? "SECONDARIES" : ""; - const char* prim = mask.isSet(PRIMARY_PARTICLE) ? "PRIMARY" : ""; - printout(INFO,name(),"+++ Tracking postaction: %d/%d par:%d [%s, %s] created by:%s E:%e state:%s %s %s %s", - id,int(m_particleMap.size()), - h.parent(),h.name().c_str(),h.type().c_str(),h.creatorName().c_str(), - p->energy, h.statusName(), prim, hit, sec); -#endif - } - else { - // These are tracks without any special properties. - // - // We will not store them on the record, but have to memorise the track identifier - // in order to restore the history for the created hits. - m_equivalentTracks[id] = h.parent(); - } + return equiv_id; } diff --git a/DDG4/src/Geant4ParticlePrint.cpp b/DDG4/src/Geant4ParticlePrint.cpp new file mode 100644 index 0000000000000000000000000000000000000000..152e08bec614977214c15b939da0f1a406c58cae --- /dev/null +++ b/DDG4/src/Geant4ParticlePrint.cpp @@ -0,0 +1,152 @@ +// $Id: Geant4Field.cpp 888 2013-11-14 15:54:56Z markus.frank@cern.ch $ +//==================================================================== +// AIDA Detector description implementation for LCD +//-------------------------------------------------------------------- +// +// Author : M.Frank +// +//==================================================================== +// Framework include files +#include "DD4hep/Printout.h" +#include "DD4hep/Primitives.h" +#include "DD4hep/InstanceCount.h" +#include "DDG4/Geant4ParticlePrint.h" +#include "DDG4/Geant4Data.h" + +#include "G4ParticleDefinition.hh" +#include "G4VProcess.hh" +#include "G4Event.hh" + +using namespace std; +using namespace DD4hep; +using namespace DD4hep::Simulation; + +typedef ReferenceBitMask<const int> PropertyMask; + +/// Standard constructor +Geant4ParticlePrint::Geant4ParticlePrint(Geant4Context* context, const std::string& nam) + : Geant4EventAction(context,nam) +{ + declareProperty("OutputType",m_outputType=3); + InstanceCount::increment(this); +} + +/// Default destructor +Geant4ParticlePrint::~Geant4ParticlePrint() { + InstanceCount::decrement(this); +} + +/// Pre-event action callback +void Geant4ParticlePrint::begin(const G4Event* ) { +} + +/// Post-event action callback +void Geant4ParticlePrint::end(const G4Event* ) { + Geant4MonteCarloTruth* truth = context()->event().extension<Geant4MonteCarloTruth>(); + const ParticleMap& particles = truth->particles(); + // Table printout.... + if ( (m_outputType&1) != 0 ) printParticles(particles); + // Tree printout.... + if ( (m_outputType&2) != 0 ) printParticleTree(particles); +} + +void Geant4ParticlePrint::printParticle(const std::string& prefix, const Particle* p) const { + char equiv[32]; + PropertyMask mask(p->reason); + const char* proc_name = "???"; + const char* proc_type = p->process ? G4VProcess::GetProcessTypeName(p->process->GetProcessType()).c_str() : ""; + + if ( p->process ) proc_name = p->process->GetProcessName().c_str(); + else if ( mask.isSet(G4PARTICLE_PRIMARY) ) proc_name = "Primary"; + + equiv[0] = 0; + if ( p->g4Parent != p->parent ) { + ::snprintf(equiv,sizeof(equiv),"/%d",p->g4Parent); + } + printout(INFO,name(),"+++ %sID: %6d %12s %6d%-7s %7s %3s %5d %6s %8.3g %4s %7s %7s %3s [%s%s%s]", + prefix.c_str(), + p->id, + p->definition->GetParticleName().c_str(), + p->parent,equiv, + yes_no(mask.isSet(G4PARTICLE_PRIMARY)), + yes_no(mask.isSet(G4PARTICLE_HAS_SECONDARIES)), + int(p->daughters.size()), + yes_no(mask.isSet(G4PARTICLE_ABOVE_ENERGY_THRESHOLD)), + p->energy, + yes_no(mask.isSet(G4PARTICLE_CREATED_CALORIMETER_HIT)), + yes_no(mask.isSet(G4PARTICLE_CREATED_TRACKER_HIT)), + yes_no(mask.isSet(G4PARTICLE_KEEP_PROCESS)), + mask.isSet(G4PARTICLE_KEEP_PARENT) ? "YES" : "", + proc_name, + p->process ? "/" : "", + proc_type + ); +} + +/// Print record of kept particles +void Geant4ParticlePrint::printParticles(const ParticleMap& particles) const { + int num_energy = 0; + int num_parent = 0; + int num_process = 0; + int num_primary = 0; + int num_secondaries = 0; + int num_calo_hits = 0; + int num_tracker_hits = 0; + + printout(INFO,name(),"+++ MC Particles #Tracks:%6d %-12s Parent%-7s " + "Primary Secondary Energy %-9s Calo Tracker Process/Par Details", + int(particles.size()),"ParticleType","","in [MeV]"); + for(ParticleMap::const_iterator i=particles.begin(); i!=particles.end(); ++i) { + const Particle* p = (*i).second; + PropertyMask mask(p->reason); + printParticle("MC Particle Track",p); + num_secondaries += int(p->daughters.size()); + if ( mask.isSet(G4PARTICLE_ABOVE_ENERGY_THRESHOLD) ) ++num_energy; + if ( mask.isSet(G4PARTICLE_PRIMARY) ) ++num_primary; + if ( mask.isSet(G4PARTICLE_CREATED_TRACKER_HIT) ) ++num_tracker_hits; + if ( mask.isSet(G4PARTICLE_CREATED_CALORIMETER_HIT) ) ++num_calo_hits; + if ( mask.isSet(G4PARTICLE_KEEP_PARENT) ) ++num_parent; + else if ( mask.isSet(G4PARTICLE_KEEP_PROCESS) ) ++num_process; + } + printout(INFO,name(),"+++ MC Particles #Tracks:%6d %-12s Parent%-7s " + "Primary Secondary Energy %-9s Calo Tracker Process/Parent", + int(particles.size()),"ParticleType","",""); + printout(INFO,name(),"+++ MC Particles #Tracks:%6d %-12s Parent%-7s " + "%7d %9d %6d %-9s %4d %7d %7d %6d", + int(particles.size()),"ParticleType","", + num_primary, num_secondaries, num_energy,"", + num_calo_hits,num_tracker_hits,num_process,num_parent); +} + +void Geant4ParticlePrint::printParticleTree(const ParticleMap& particles, int level, const Particle* p) const { + char txt[32]; + size_t len = sizeof(txt)-1; + // Ensure we do not overwrite the array + if ( level>int(len)-3 ) level=len-3; + + ::snprintf(txt,sizeof(txt),"%5d ",level); + ::memset(txt+6,' ',len-6); + txt[len] = 0; + txt[len-2] = '>'; + txt[level+6]='+'; + ::memset(txt+level+6+1,'-',len-level-3-6); + + printParticle(txt, p); + const set<int>& daughters = p->daughters; + // For all particles, the set of daughters must be contained in the record. + for(set<int>::const_iterator id=daughters.begin(); id!=daughters.end(); ++id) { + int id_dau = *id; + const Particle* dau = (*particles.find(id_dau)).second; + printParticleTree(particles,level+1,dau); + } +} + +/// Print tree of kept particles +void Geant4ParticlePrint::printParticleTree(const ParticleMap& particles) const { + printout(INFO,name(),"+++ MC Particle Parent daughter relationships. [%d particles]",int(particles.size())); + for(ParticleMap::const_iterator i=particles.begin(); i!=particles.end(); ++i) { + const Particle* p = (*i).second; + PropertyMask mask(p->reason); + if ( mask.isSet(G4PARTICLE_PRIMARY) ) printParticleTree(particles,0,p); + } +} diff --git a/DDG4/src/Geant4TrackPersistency.cpp b/DDG4/src/Geant4TrackPersistency.cpp index 01692ab8be6bdad2677f40f3a60a30a4bb96df7a..272542523814d5608c4d62f2a652520d77b63ae8 100644 --- a/DDG4/src/Geant4TrackPersistency.cpp +++ b/DDG4/src/Geant4TrackPersistency.cpp @@ -351,19 +351,19 @@ Geant4TrackPersistency::~Geant4TrackPersistency() { } /// Mark a Geant4 track to be kept for later MC truth analysis -void Geant4TrackPersistency::mark(const G4Track* track, bool created_hit) { +void Geant4TrackPersistency::mark(const G4Track* track, int reason) { mark(track); // Does all the checking... - if ( created_hit ) { + if ( reason ) { Track* trk = (Track*)m_current.info; trk->flag |= Track::CREATED_HIT; - m_current.createdHit = created_hit; + m_current.createdHit = reason != 0; } } /// Store a track produced in a step to be kept for later MC truth analysis -void Geant4TrackPersistency::mark(const G4Step* step, bool created_hit) { +void Geant4TrackPersistency::mark(const G4Step* step, int reason) { if ( step ) { - mark(step->GetTrack(),created_hit); + mark(step->GetTrack(),reason); return; } except("Cannot mark the G4Track if the step-pointer is invalid!", c_name());