39 #include "TLorentzVector.h" 41 #include "CLHEP/Units/SystemOfUnits.h" 44 #include "Geant4/G4DynamicParticle.hh" 45 #include "Geant4/G4ParticleDefinition.hh" 46 #include "Geant4/G4PrimaryParticle.hh" 47 #include "Geant4/G4StepPoint.hh" 48 #include "Geant4/G4ThreeVector.hh" 49 #include "Geant4/G4Track.hh" 50 #include "Geant4/G4VProcess.hh" 51 #include "Geant4/G4VUserPrimaryParticleInformation.hh" 53 #include "range/v3/view.hpp" 67 :
artg4tk::EventActionBase(
"PLASEventActionBase")
68 ,
artg4tk::TrackingActionBase(
"PLASTrackingActionBase")
69 ,
artg4tk::SteppingActionBase(
"PLASSteppingActionBase")
70 , fenergyCut(p.
get<double>(
"EnergyCut", 0.0 *
CLHEP::GeV))
71 , fstoreTrajectories(p.
get<bool>(
"storeTrajectories", true))
72 , fkeepGenTrajectories(p.
get<
std::
vector<
std::string>>(
"keepGenTrajectories", {}))
82 p.get<std::vector<std::string>>(
"KeepDroppedParticlesInVolumes", {}))
90 <<
"ParticleListActionService: keepEMShowerDaughters and storeDroppedMCParticles cannot " 113 std::stringstream sstored;
114 sstored <<
"The full tracking information will not be stored for particles" 115 <<
" resulting from the following processes: \n{ ";
117 sstored <<
"\"" << i <<
"\" ";
120 mf::LogInfo(
"ParticleListActionService") << sstored.str() <<
"}\n";
124 <<
"Storing full tracking information for all processes. \n";
128 <<
"NotStoredPhysics provided, but will be ignored." 129 <<
" To use NotStoredPhysics, set keepEMShowerDaughters to false";
136 <<
"Trajectory sparsification enabled with SparsifyMargin : " <<
fSparsifyMargin <<
"\n";
162 mf::LogDebug(
"beginOfEventAction::Generator") <<
"Trajectory points will not be stored.";
164 else if (!customKeepTraj) {
166 <<
"keepGenTrajectories list is empty. Will" 167 <<
" store trajectory points for all generators";
172 std::string generator_name =
"unknown";
173 for (
size_t mcti = 0; mcti <
fMCLists->size(); ++mcti) {
175 std::stringstream sskeepgen;
176 sskeepgen <<
"MCTruth object summary :";
177 sskeepgen <<
"\n\tPrimary MCTIndex : " << mcti;
180 auto const& mclistHandle = (*fMCLists)[mcti];
181 generator_name = mclistHandle.provenance()->inputTag().label();
182 sskeepgen <<
"\n\tProvenance/Generator : " << generator_name;
184 G4bool keepGen =
false;
187 if (!customKeepTraj) {
193 if (generator_name == keepableGen) {
202 sskeepgen <<
"\n\tTrajectory points storable : " << (keepGen ?
"true" :
"false") <<
"\n";
203 mf::LogDebug(
"beginOfEventAction::Generator") << sskeepgen.str();
208 <<
"storeTrajectories" 209 <<
" set to true and a non-empty keepGenTrajectories list provided in configuration file, " 211 <<
" none of the generators in this list are present in the event! Double check list or " 213 <<
" provide keepGenTrajectories in the configuration to keep all trajectories from all" 214 <<
" generator labels. This may be expected for generators that have a nonzero probability " 216 <<
" producing no particles (e.g. some radiologicals)";
235 parentid = (*itr).second;
247 G4ParticleDefinition* particleDefinition = track->GetDefinition();
248 G4int pdgCode = particleDefinition->GetPDGEncoding();
260 std::string process_name =
"unknown";
261 std::string mct_primary_process =
"unknown";
262 bool isFromMCTProcessPrimary =
false;
263 bool notstore =
false;
267 const G4DynamicParticle* dynamicParticle = track->GetDynamicParticle();
268 const G4PrimaryParticle* primaryParticle = dynamicParticle->GetPrimaryParticle();
270 size_t primarymctIndex = 0;
271 if (primaryParticle !=
nullptr) {
272 const G4VUserPrimaryParticleInformation* gppi = primaryParticle->GetUserInformation();
275 if (ppi !=
nullptr) {
292 if (mct_primary_process.compare(
"primary") == 0) {
293 process_name =
"primary";
294 isFromMCTProcessPrimary =
true;
296 else if (mct_primary_process.find(
"primary") == 0) {
297 process_name = mct_primary_process;
298 isFromMCTProcessPrimary =
false;
299 mf::LogDebug(
"PrimaryParticle") <<
"MCTruth primary process name contains \"primary\" " 300 <<
" but is not solely \"primary\" : " << process_name
301 <<
".\nWill not store full set of trajectory points.";
304 process_name =
"primary";
305 isFromMCTProcessPrimary =
true;
307 <<
"MCTruth primary process does not beging with string" 308 <<
" literal \"primary\" : " << process_name <<
"\nOVERRIDING it to \"primary\"";
327 process_name = track->GetCreatorProcess()->GetProcessName();
330 if (process_name.find(p) != std::string::npos) {
332 mf::LogDebug(
"NotStoredPhysics") <<
"Found process : " << process_name;
375 G4double
energy = track->GetKineticEnergy();
409 <<
"can't find parent id: " << parentID <<
" in the particle list, or fParentIDMap." 410 <<
" Make " << parentID <<
" the mother ID for" 411 <<
" track ID " <<
fCurrentTrackID <<
" in the hope that it will aid debugging.";
420 primarymctIndex = it->second;
424 <<
"Could not locate MCT Index for parent trackID of " << parentID;
432 double mass = dynamicParticle->GetMass() / CLHEP::GeV;
454 (isFromMCTProcessPrimary) ?
458 const G4ThreeVector& polarization = track->GetPolarization();
460 TVector3{polarization.x(), polarization.y(), polarization.z()});
462 if (track->GetProperTime() != 0) {
return; }
487 const G4StepPoint* postStepPoint = aTrack->GetStep()->GetPostStepPoint();
488 if (!postStepPoint->GetProcessDefinedStep()) {
509 G4String process = postStepPoint->GetProcessDefinedStep()->GetProcessName();
517 const G4ThreeVector position = postStepPoint->GetPosition();
518 G4double time = postStepPoint->GetGlobalTime();
521 TLorentzVector fourPos(position.x() / CLHEP::cm,
522 position.y() / CLHEP::cm,
523 position.z() / CLHEP::cm,
526 const G4ThreeVector momentum = postStepPoint->GetMomentum();
527 const G4double
energy = postStepPoint->GetTotalEnergy();
528 TLorentzVector fourMom(momentum.x() / CLHEP::GeV,
529 momentum.y() / CLHEP::GeV,
530 momentum.z() / CLHEP::GeV,
531 energy / CLHEP::GeV);
581 double const globalTime = step->GetTrack()->GetGlobalTime();
582 double const velocity_G4 = step->GetTrack()->GetVelocity();
583 double const velocity_step = step->GetStepLength() / step->GetDeltaTime();
584 if ((step->GetTrack()->GetDefinition()->GetPDGEncoding() == 0) &&
585 fabs(velocity_G4 - velocity_step) > 0.0001) {
588 step->GetPostStepPoint()->SetGlobalTime(globalTime - step->GetDeltaTime() +
600 const G4StepPoint* preStepPoint = step->GetPreStepPoint();
602 const G4ThreeVector position = preStepPoint->GetPosition();
603 G4double time = preStepPoint->GetGlobalTime();
606 TLorentzVector fourPos(position.x() / CLHEP::cm,
607 position.y() / CLHEP::cm,
608 position.z() / CLHEP::cm,
611 const G4ThreeVector momentum = preStepPoint->GetMomentum();
612 const G4double
energy = preStepPoint->GetTotalEnergy();
613 TLorentzVector fourMom(momentum.x() / CLHEP::GeV,
614 momentum.y() / CLHEP::GeV,
615 momentum.z() / CLHEP::GeV,
616 energy / CLHEP::GeV);
628 G4String process = step->GetPostStepPoint()->GetProcessDefinedStep()->GetProcessName();
629 G4bool ignoreProcess = process.contains(
"StepLimiter");
639 const G4StepPoint* postStepPoint = step->GetPostStepPoint();
641 const G4ThreeVector position = postStepPoint->GetPosition();
642 G4double time = postStepPoint->GetGlobalTime();
645 TLorentzVector fourPos(position.x() / CLHEP::cm,
646 position.y() / CLHEP::cm,
647 position.z() / CLHEP::cm,
650 const G4ThreeVector momentum = postStepPoint->GetMomentum();
651 const G4double
energy = postStepPoint->GetTotalEnergy();
652 TLorentzVector fourMom(momentum.x() / CLHEP::GeV,
653 momentum.y() / CLHEP::GeV,
654 momentum.z() / CLHEP::GeV,
655 energy / CLHEP::GeV);
671 int particleID = particleListEntry.first;
676 int parentID = particleList->GetMotherOf(particleID);
679 if (parentID <= 0)
return;
687 if (parentEntry == particleList->end()) {
695 if (!parentEntry->second)
return;
722 if ((*pn).first > highestID) highestID = (*pn).first;
728 if ((*pn).first > highestID) highestID = (*pn).first;
735 <<
"highestID = " << highestID <<
"\nfTrackIDOffset= " <<
fTrackIDOffset;
745 <<
"ParticleListAction::YieldDroppedList(): dropped particle list not build by user " 753 if ((*pn).first > highestID) highestID = (*pn).first;
758 if ((*pn).first > highestID) highestID = (*pn).first;
764 <<
"highestID = " << highestID <<
"\nfTrackIDOffset= " <<
fTrackIDOffset;
777 TLorentzVector
const& mom,
778 std::string
const& process)
796 std::stringstream sscounter;
797 sscounter <<
"Not Stored Process summary:";
799 sscounter <<
"\n\t" << process <<
" : " << count;
801 mf::LogInfo(
"ParticleListActionService") << sscounter.str();
804 partCol_ = std::make_unique<std::vector<simb::MCParticle>>();
805 droppedCol_ = std::make_unique<sim::ParticleAncestryMap>();
808 std::make_unique<art::Assns<simb::MCTruth, simb::MCParticle, sim::GeneratedParticleInfo>>();
819 unsigned int nGeneratedParticles = 0;
820 unsigned int nMCTruths = 0;
825 for (
size_t mcl = 0; mcl <
fMCLists->size(); ++mcl) {
826 auto const& mclistHandle = (*fMCLists)[mcl];
827 MF_LOG_INFO(
"endOfEventAction") <<
"mclistHandle Size: " << mclistHandle->size();
828 for (
size_t m = 0; m < mclistHandle->size(); ++m) {
833 if (gen_index != nMCTruths)
continue;
838 assert(p->NumberTrajectoryPoints() != 0ull);
839 ++nGeneratedParticles;
841 if (!truthInfo.hasGeneratedParticleIndex() && p->Mother() == 0) {
842 MF_LOG_WARNING(
"endOfEventAction") <<
"No GeneratedParticleIndex()!";
845 <<
"Failed to match primary particle:\n" 846 <<
"\nwith particles from the truth record '" << mclistHandle.provenance()->inputTag()
851 tpassn_->addSingle(mct, mcp_ptr, truthInfo);
857 if (p->StatusCode() != 1)
continue;
859 droppedPartCol_->push_back(std::move(*p));
862 mf::LogDebug(
"Offset") <<
"nGeneratedParticles = " << nGeneratedParticles;
unsigned int NumberTrajectoryPoints() const
simb::MCParticle * particle
simple structure representing particle
bool isDropped(simb::MCParticle const *p)
void AddDaughter(const int trackID)
void userSteppingAction(const G4Step *) override
ParticleListActionService(fhicl::ParameterSet const &)
void beginOfEventAction(const G4Event *) override
void AddTrajectoryPoint(TLorentzVector const &position, TLorentzVector const &momentum)
decltype(auto) constexpr cend(T &&obj)
ADL-aware version of std::cend.
std::map< int, std::set< int > > fdroppedTracksMap
map <ParentID, set: list of track ids for which no MCParticle was created>
void preUserTrackingAction(const G4Track *) override
sim::ParticleList && YieldList()
std::unique_ptr< sim::ParticleList > fdroppedParticleList
bool fKeepEMShowerDaughters
whether to keep EM shower secondaries, tertiaries, etc
key_type key(mapped_type const &part) const
Extracts the key from the specified value.
MaybeLogger_< ELseverityLevel::ELsev_info, false > LogInfo
const simb::MCTrajectory & Trajectory() const
bool fKeepSecondToLast
tell whether or not to force keeping the second to last point
bool keepFullTrajectory
if there was decision to keep
list_type::value_type value_type
std::unique_ptr< art::Assns< simb::MCTruth, simb::MCParticle, sim::GeneratedParticleInfo > > tpassn_
list_type::iterator iterator
std::unique_ptr< util::PositionInVolumeFilter > fFilter
filter for particles to be kept
void Add(simb::MCParticle *value)
int GetParentage(int trackid) const
double fSparsifyMargin
set the sparsification margin
void AddPointToCurrentParticle(TLorentzVector const &pos, TLorentzVector const &mom, std::string const &process)
Adds a trajectory point to the current particle, and runs the filter.
void postUserTrackingAction(const G4Track *) override
std::string Process() const
simb::GeneratedParticleIndex_t GetPrimaryTruthIndex(int trackId) const
Returns the index of primary truth (sim::NoGeneratorIndex if none).
bool fKeepTransportation
tell whether or not to keep the transportation process
std::unique_ptr< std::vector< simb::MCParticle > > partCol_
std::map< int, size_t > fMCTIndexMap
Map: particle track ID -> index of primary parent in std::vector<simb::MCTruth> object.
auto vector(Vector const &v)
Returns a manipulator which will print the specified array.
std::vector< std::string > fKeepParticlesInVolumes
Only write particles that have trajectories through these volumes.
constexpr GeneratedParticleIndex_t NoGeneratedParticleIndex
Constant representing the absence of generator truth information.
bool fSparsifyTrajectories
help reduce the number of trajectory points.
void SetPolarization(const TVector3 &p)
sim::ParticleList && YieldDroppedList()
static const int NoParticleId
decltype(auto) values(Coll &&coll)
Range-for loop helper iterating across the values of the specified collection.
Use Geant4's user "hooks" to maintain a list of particles generated by Geant4.
bool isDropped
dropped by a physics process
std::map< size_t, std::pair< std::string, G4bool > > fMCTIndexToGeneratorMap
Map: MCTruthIndex -> generator, input label of generator and keepGenerator decision.
simb::MCParticle const * GetMCParticle() const
std::unordered_map< std::string, int > fNotStoredCounterUMap
Map: not stored process and counter.
bool fStoreDroppedMCParticles
Whether to keep a sim::MCParticle list of dropped particles.
std::unique_ptr< sim::ParticleAncestryMap > droppedCol_
std::map< int, int > fTargetIDMap
key is original track ID, value is ID to assign for downstream objs (e.g. SimEdeps) ...
std::unique_ptr< std::vector< simb::MCParticle > > droppedPartCol_
This collection will hold the MCParticleLite objects created from dropped particles.
void endOfEventAction(const G4Event *) override
#define MF_LOG_INFO(category)
std::vector< std::string > fKeepDroppedParticlesInVolumes
bool isInVolume
drop if not involume
std::unique_ptr< util::PositionInVolumeFilter > fDroppedFilter
bool isPrimary() const
Returns whether there is a particle.
void SetWeight(double wt)
void SetEndProcess(std::string s)
std::vector< std::string > fNotStoredPhysics
Physics processes that will not be stored.
cet::coded_exception< errors::ErrorCodes, ExceptionDetail::translate > Exception
std::map< int, int > fParentIDMap
key is current track ID, value is parent ID
simb::GeneratedParticleIndex_t truthInfoIndex() const
Returns the index of the particle in the generator truth record.
art::EDProductGetter const * productGetter_
decltype(auto) get(T &&obj)
ADL-aware version of std::to_string.
void clear()
Resets the information (does not release memory it does not own)
std::vector< std::string > fkeepGenTrajectories
std::map< int, bool > fMCTPrimProcessKeepMap
Map: particle trakc ID -> boolean decision to keep or not full trajectory points. ...
simb::GeneratedParticleIndex_t truthIndex
Index of the particle in the original generator truth record.
sim::ParticleList fParticleList
bool hasParticle() const
Returns whether there is a particle.
MaybeLogger_< ELseverityLevel::ELsev_success, false > LogDebug
Contains information about a generated particle.
G4bool fstoreTrajectories
Whether to store particle trajectories with each particle.
MaybeLogger_< ELseverityLevel::ELsev_warning, false > LogWarning
bool fkeepOnlyPrimaryFullTraj
std::map< int, simb::GeneratedParticleIndex_t > fPrimaryTruthMap
Map: particle track ID -> index of primary information in MC truth.
size_type erase(const key_type &key)
bool KnownParticle(int trackID) const
Returns whether we have had this particle, archived or live.
ParticleInfo_t fCurrentParticle
#define MF_LOG_WARNING(category)
void SparsifyTrajectory(double margin=0.1, bool keep_second_to_last=false)
std::vector< art::Handle< std::vector< simb::MCTruth > > > const * fMCLists
MCTruthCollection input lists.
Tools and modules for checking out the basics of the Monte Carlo.
size_t const & MCTruthIndex() const
GeneratedParticleIndex_t MCParticleIndex() const
Returns the index of the corresponding particle in truth record.
cet::coded_exception< error, detail::translate > exception
std::size_t GeneratedParticleIndex_t
Type of particle index in the generator truth record (simb::MCTruth).