33 #include "nug4/G4Base/PrimaryParticleInformation.h"
36 #include "fhiclcpp/ParameterSet.h"
39 #include "TLorentzVector.h"
41 #include "CLHEP/Units/SystemOfUnits.h"
44 #include "Geant4/G4ParticleDefinition.hh"
45 #include "Geant4/G4DynamicParticle.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", {}))
101 std::stringstream sstored;
102 sstored <<
"The full tracking information will not be stored for particles"
103 <<
" resulting from the following processes: \n{ ";
105 sstored <<
"\"" << i <<
"\" ";
106 fNotStoredCounterUMap.emplace(i, 0);
108 mf::LogInfo(
"ParticleListActionService") << sstored.str() <<
"}\n";
111 mf::LogInfo(
"ParticleListActionService")
112 <<
"Storing full tracking information for all processes. \n";
115 mf::LogWarning(
"StoredPhysics")
116 <<
"NotStoredPhysics provided, but will be ignored."
117 <<
" To use NotStoredPhysics, set keepEMShowerDaughters to false";
123 mf::LogInfo(
"ParticleListActionService")
124 <<
"Trajectory sparsification enabled with SparsifyMargin : " <<
fSparsifyMargin <<
"\n";
130 ParticleListActionService::beginOfEventAction(
const G4Event*)
133 fCurrentParticle.clear();
134 fParticleList.clear();
135 fParentIDMap.clear();
136 fTargetIDMap.clear();
137 fMCTIndexMap.clear();
138 fMCTPrimProcessKeepMap.clear();
141 fPrimaryTruthMap.clear();
142 fMCTIndexToGeneratorMap.clear();
143 fNotStoredCounterUMap.clear();
144 fdroppedTracksMap.clear();
148 bool customKeepTraj = not fkeepGenTrajectories.empty();
149 if (!fstoreTrajectories) {
150 mf::LogDebug(
"beginOfEventAction::Generator") <<
"Trajectory points will not be stored.";
152 else if (!customKeepTraj) {
153 mf::LogDebug(
"beginOfEventAction::Generator")
154 <<
"keepGenTrajectories list is empty. Will"
155 <<
" store trajectory points for all generators";
160 std::string generator_name =
"unknown";
161 for (
size_t mcti = 0; mcti < fMCLists->size(); ++mcti) {
163 std::stringstream sskeepgen;
164 sskeepgen <<
"MCTruth object summary :";
165 sskeepgen <<
"\n\tPrimary MCTIndex : " << mcti;
168 auto const& mclistHandle = (*fMCLists)[mcti];
169 generator_name = mclistHandle.provenance()->inputTag().label();
170 sskeepgen <<
"\n\tProvenance/Generator : " << generator_name;
172 G4bool keepGen =
false;
173 if (fstoreTrajectories)
175 if (!customKeepTraj) {
180 for (
auto keepableGen : fkeepGenTrajectories) {
181 if (generator_name == keepableGen) {
189 fMCTIndexToGeneratorMap.emplace(mcti, std::make_pair(generator_name, keepGen));
190 sskeepgen <<
"\n\tTrajectory points storable : " << (keepGen ?
"true" :
"false") <<
"\n";
191 mf::LogDebug(
"beginOfEventAction::Generator") << sskeepgen.str();
194 if (nKeep == 0 && customKeepTraj && fstoreTrajectories) {
195 mf::LogWarning(
"beginOfEventAction::keepableGenerators")
196 <<
"storeTrajectories"
197 <<
" set to true and a non-empty keepGenTrajectories list provided in configuration file, "
199 <<
" none of the generators in this list are present in the event! Double check list or "
201 <<
" provide keepGenTrajectories in the configuration to keep all trajectories from all"
202 <<
" generator labels. This may be expected for generators that have a nonzero probability "
204 <<
" producing no particles (e.g. some radiologicals)";
215 ParticleListActionService::GetParentage(
int trackid)
const
221 auto itr = fParentIDMap.find(trackid);
222 while (itr != fParentIDMap.end()) {
225 parentid = (*itr).second;
226 itr = fParentIDMap.find(parentid);
235 ParticleListActionService::preUserTrackingAction(
const G4Track*
track)
238 G4ParticleDefinition* particleDefinition = track->GetDefinition();
239 G4int pdgCode = particleDefinition->GetPDGEncoding();
245 int const trackID = track->GetTrackID() + fTrackIDOffset;
246 fCurrentTrackID = trackID;
247 fTargetIDMap[trackID] = fCurrentTrackID;
249 int parentID = track->GetParentID() + fTrackIDOffset;
252 std::string mct_primary_process =
"unknown";
253 bool isFromMCTProcessPrimary =
false;
257 const G4DynamicParticle* dynamicParticle = track->GetDynamicParticle();
258 const G4PrimaryParticle* primaryParticle = dynamicParticle->GetPrimaryParticle();
259 simb::GeneratedParticleIndex_t primaryIndex = simb::NoGeneratedParticleIndex;
260 size_t primarymctIndex = 0;
261 if (primaryParticle !=
nullptr) {
262 const G4VUserPrimaryParticleInformation* gppi = primaryParticle->GetUserInformation();
263 const g4b::PrimaryParticleInformation* ppi =
264 dynamic_cast<const g4b::PrimaryParticleInformation*
>(gppi);
265 if (ppi !=
nullptr) {
266 primaryIndex = ppi->MCParticleIndex();
267 primarymctIndex = ppi->MCTruthIndex();
268 mct_primary_process = ppi->GetMCParticle()->Process();
282 if (mct_primary_process.compare(
"primary") == 0) {
283 process_name =
"primary";
284 isFromMCTProcessPrimary =
true;
286 else if (mct_primary_process.find(
"primary") == 0) {
287 process_name = mct_primary_process;
288 isFromMCTProcessPrimary =
false;
289 mf::LogDebug(
"PrimaryParticle") <<
"MCTruth primary process name contains \"primary\" "
290 <<
" but is not solely \"primary\" : " << process_name
291 <<
".\nWill not store full set of trajectory points.";
294 process_name =
"primary";
295 isFromMCTProcessPrimary =
true;
296 mf::LogWarning(
"PrimaryParticle")
297 <<
"MCTruth primary process does not beging with string"
298 <<
" literal \"primary\" : " << process_name <<
"\nOVERRIDING it to \"primary\"";
317 process_name = track->GetCreatorProcess()->GetProcessName();
319 bool notstore =
false;
321 if (process_name.find(
p) != std::string::npos) {
323 mf::LogDebug(
"NotStoredPhysics") <<
"Found process : " <<
process_name;
326 auto search = fNotStoredCounterUMap.find(
p);
327 if (search != fNotStoredCounterUMap.end()) { old = search->second; }
328 fNotStoredCounterUMap.insert_or_assign(
p, (old + 1));
335 fParentIDMap[trackID] = parentID;
336 fCurrentTrackID =-1 * this->GetParentage(trackID);
344 if (!fParticleList.KnownParticle(fCurrentTrackID)) fCurrentTrackID =
sim::NoParticleId;
345 fTargetIDMap[trackID] = fCurrentTrackID;
348 fdroppedTracksMap[this->GetParentage(trackID)].insert(trackID);
349 fCurrentParticle.clear();
356 G4double energy = track->GetKineticEnergy();
357 if (energy < fenergyCut) {
358 fdroppedTracksMap[this->GetParentage(trackID)].insert(trackID);
359 fCurrentParticle.clear();
362 fParentIDMap[trackID] = parentID;
363 fCurrentTrackID = -1 * this->GetParentage(trackID);
364 fTargetIDMap[trackID] = fCurrentTrackID;
372 if (!fParticleList.KnownParticle(parentID)) {
375 fParentIDMap[trackID] = parentID;
376 int pid = this->GetParentage(parentID);
380 if (!fParticleList.KnownParticle(pid)) {
382 <<
"can't find parent id: " << parentID <<
" in the particle list, or fParentIDMap."
383 <<
" Make " << parentID <<
" the mother ID for"
384 <<
" track ID " << fCurrentTrackID <<
" in the hope that it will aid debugging.";
392 if (
auto it = fMCTIndexMap.find(parentID); it !=
cend(fMCTIndexMap)) {
393 primarymctIndex = it->second;
396 throw art::Exception(art::errors::LogicError)
397 <<
"Could not locate MCT Index for parent trackID of " << parentID;
401 isFromMCTProcessPrimary = fMCTPrimProcessKeepMap[parentID];
408 fCurrentParticle.clear();
409 fCurrentParticle.particle =
410 new simb::MCParticle{trackID, pdgCode,
process_name, parentID, mass};
411 fCurrentParticle.truthIndex = primaryIndex;
413 fMCTIndexMap[trackID] = primarymctIndex;
415 fMCTPrimProcessKeepMap[trackID] = isFromMCTProcessPrimary;
418 fCurrentParticle.keepFullTrajectory =
419 (!fstoreTrajectories) ?
421 (!(fMCTIndexToGeneratorMap[primarymctIndex].
second)) ?
425 (isFromMCTProcessPrimary) ?
429 const G4ThreeVector& polarization = track->GetPolarization();
430 fCurrentParticle.particle->SetPolarization(
431 TVector3{polarization.x(), polarization.y(), polarization.z()});
433 fParticleList.Add(fCurrentParticle.particle);
438 ParticleListActionService::postUserTrackingAction(
const G4Track* aTrack)
440 if (!fCurrentParticle.hasParticle())
return;
443 fCurrentParticle.particle->SetWeight(aTrack->GetWeight());
446 const G4StepPoint* postStepPoint = aTrack->GetStep()->GetPostStepPoint();
447 if (!postStepPoint->GetProcessDefinedStep()) {
455 auto key_to_erase = fParticleList.key(fCurrentParticle.particle);
456 fParticleList.erase(key_to_erase);
458 fCurrentParticle.clear();
462 G4String process = postStepPoint->GetProcessDefinedStep()->GetProcessName();
463 fCurrentParticle.particle->SetEndProcess(process);
469 if (!fCurrentParticle.keepFullTrajectory) {
470 const G4ThreeVector position = postStepPoint->GetPosition();
471 G4double time = postStepPoint->GetGlobalTime();
474 TLorentzVector fourPos(position.x() / CLHEP::cm,
475 position.y() / CLHEP::cm,
476 position.z() / CLHEP::cm,
479 const G4ThreeVector momentum = postStepPoint->GetMomentum();
480 const G4double energy = postStepPoint->GetTotalEnergy();
481 TLorentzVector fourMom(momentum.x() /
CLHEP::GeV,
487 AddPointToCurrentParticle(fourPos, fourMom, std::string(process));
496 if (fCurrentParticle.isPrimary()) {
497 fPrimaryTruthMap[fCurrentParticle.particle->TrackId()] = fCurrentParticle.truthInfoIndex();
506 ParticleListActionService::userSteppingAction(
const G4Step* step)
511 if (!fCurrentParticle.hasParticle() || !step->GetPostStepPoint()->GetProcessDefinedStep()) {
516 double const globalTime = step->GetTrack()->GetGlobalTime();
517 double const velocity_G4 = step->GetTrack()->GetVelocity();
518 double const velocity_step = step->GetStepLength() / step->GetDeltaTime();
519 if ((step->GetTrack()->GetDefinition()->GetPDGEncoding() == 0) &&
520 fabs(velocity_G4 - velocity_step) > 0.0001) {
523 step->GetPostStepPoint()->SetGlobalTime(globalTime - step->GetDeltaTime() +
532 if (fCurrentParticle.particle->NumberTrajectoryPoints() == 0) {
535 const G4StepPoint* preStepPoint = step->GetPreStepPoint();
537 const G4ThreeVector position = preStepPoint->GetPosition();
538 G4double time = preStepPoint->GetGlobalTime();
541 TLorentzVector fourPos(position.x() / CLHEP::cm,
542 position.y() / CLHEP::cm,
543 position.z() / CLHEP::cm,
546 const G4ThreeVector momentum = preStepPoint->GetMomentum();
547 const G4double energy = preStepPoint->GetTotalEnergy();
548 TLorentzVector fourMom(momentum.x() /
CLHEP::GeV,
554 AddPointToCurrentParticle(fourPos, fourMom,
"Start");
563 G4String process = step->GetPostStepPoint()->GetProcessDefinedStep()->GetProcessName();
564 G4bool ignoreProcess = process.contains(
"StepLimiter");
571 if (!ignoreProcess && fCurrentParticle.keepFullTrajectory) {
574 const G4StepPoint* postStepPoint = step->GetPostStepPoint();
576 const G4ThreeVector position = postStepPoint->GetPosition();
577 G4double time = postStepPoint->GetGlobalTime();
580 TLorentzVector fourPos(position.x() / CLHEP::cm,
581 position.y() / CLHEP::cm,
582 position.z() / CLHEP::cm,
585 const G4ThreeVector momentum = postStepPoint->GetMomentum();
586 const G4double energy = postStepPoint->GetTotalEnergy();
587 TLorentzVector fourMom(momentum.x() /
CLHEP::GeV,
593 AddPointToCurrentParticle(fourPos, fourMom, std::string(process));
604 operator()(sim::ParticleList::value_type& particleListEntry)
const
607 int particleID = particleListEntry.first;
612 int parentID = particleList->GetMotherOf(particleID);
615 if (parentID <= 0)
return;
621 sim::ParticleList::iterator parentEntry = particleList->find(parentID);
623 if (parentEntry == particleList->end()) {
631 if (!parentEntry->second)
return;
634 simb::MCParticle* parent = parentEntry->second;
635 parent->AddDaughter(particleID);
643 simb::GeneratedParticleIndex_t
644 ParticleListActionService::GetPrimaryTruthIndex(
int trackId)
const
646 auto const it = fPrimaryTruthMap.find(trackId);
647 return it == fPrimaryTruthMap.end() ? simb::NoGeneratedParticleIndex : it->second;
653 ParticleListActionService::YieldList()
659 for (
auto pn = fParticleList.begin(); pn != fParticleList.end(); pn++)
660 if ((*pn).first > highestID) highestID = (*pn).first;
663 if ((fParticleList.size()) != 0) {
664 fTrackIDOffset = highestID + 1;
665 mf::LogDebug(
"YieldList:fTrackIDOffset")
666 <<
"highestID = " << highestID <<
"\nfTrackIDOffset= " << fTrackIDOffset;
669 return std::move(fParticleList);
674 ParticleListActionService::AddPointToCurrentParticle(TLorentzVector
const& pos,
675 TLorentzVector
const& mom,
676 std::string
const& process)
685 ParticleListActionService::endOfEventAction(
const G4Event*)
688 if (!fNotStoredCounterUMap.empty()) {
689 std::stringstream sscounter;
690 sscounter <<
"Not Stored Process summary:";
691 for (
auto const& [process,
count] : fNotStoredCounterUMap) {
692 sscounter <<
"\n\t" << process <<
" : " <<
count;
694 mf::LogInfo(
"ParticleListActionService") << sscounter.str();
697 partCol_ = std::make_unique<std::vector<simb::MCParticle>>();
698 droppedCol_ = std::make_unique<std::map<int,std::set<int>>>();
700 std::make_unique<art::Assns<simb::MCTruth, simb::MCParticle, sim::GeneratedParticleInfo>>();
709 MF_LOG_INFO(
"endOfEventAction") <<
"MCTruth Handles Size: " << fMCLists->size();
711 unsigned int nGeneratedParticles = 0;
712 unsigned int nMCTruths = 0;
713 sim::ParticleList particleList = YieldList();
714 for (
size_t mcl = 0; mcl < fMCLists->size(); ++mcl) {
715 auto const& mclistHandle = (*fMCLists)[mcl];
716 MF_LOG_INFO(
"endOfEventAction") <<
"mclistHandle Size: " << mclistHandle->size();
717 for (
size_t m = 0;
m < mclistHandle->size(); ++
m) {
718 art::Ptr<simb::MCTruth> mct(mclistHandle,
m);
719 MF_LOG_INFO(
"endOfEventAction") <<
"Found " << mct->NParticles() <<
" particles";
721 auto gen_index = fMCTIndexMap[
p->TrackId()];
722 if (gen_index != nMCTruths)
continue;
723 assert(
p->NumberTrajectoryPoints() != 0ull);
724 ++nGeneratedParticles;
726 if (!truthInfo.hasGeneratedParticleIndex() &&
p->Mother() == 0) {
727 MF_LOG_WARNING(
"endOfEventAction") <<
"No GeneratedParticleIndex()!";
729 throw art::Exception(art::errors::LogicError)
730 <<
"Failed to match primary particle:\n"
731 <<
"\nwith particles from the truth record '" << mclistHandle.provenance()->inputTag()
734 partCol_->push_back(std::move(*
p));
735 art::Ptr<simb::MCParticle> mcp_ptr{pid_, partCol_->size() - 1, productGetter_};
736 tpassn_->addSingle(mct, mcp_ptr, truthInfo);
738 mf::LogDebug(
"Offset") <<
"nGeneratedParticles = " << nGeneratedParticles;
739 for(
auto const& dropped : fdroppedTracksMap )
741 droppedCol_->insert(dropped);
util::quantities::gigaelectronvolt GeV
fKeepTransportation(p.get< bool >("KeepTransportation", false))
double std(const std::vector< short > &wf, const double ped_mean, size_t start, size_t nsample)
ParticleListActionService(fhicl::ParameterSet const &)
process_name use argoneut_mc_hitfinder track
tuple m
now if test mode generate materials, CRT shell, world, gdml header else just generate CRT shell for u...
auto cend(FixedBins< T, C > const &) noexcept
auto vector(Vector const &v)
Returns a manipulator which will print the specified array.
fSparsifyMargin(p.get< double >("SparsifyMargin", 0.015))
fNotStoredPhysics(p.get< std::vector< std::string >>("NotStoredPhysics",{}))
static const int NoParticleId
A value measured in the specified unit.
Use Geant4's user "hooks" to maintain a list of particles generated by Geant4.
MF_LOG_WARNING("SimWire")<< "SimWire is an example module that works for the "<< "MicroBooNE detector. Each experiment should implement "<< "its own version of this module to simulate electronics "<< "response."
fKeepEMShowerDaughters(p.get< bool >("keepEMShowerDaughters", true))
fSparsifyTrajectories(p.get< bool >("SparsifyTrajectories", false))
fKeepSecondToLast(p.get< bool >("KeepSecondToLast", false))
fkeepOnlyPrimaryFullTraj(p.get< bool >("keepOnlyPrimaryFullTrajectories", false))
Contains information about a generated particle.
std::size_t count(Cont const &cont)
Tools and modules for checking out the basics of the Monte Carlo.
BEGIN_PROLOG don t mess with this pandoraTrackGausCryoW true
BEGIN_PROLOG sequence::SlidingWindowTriggerPatternsOppositeWindows END_PROLOG process_name