Classes | Public Member Functions | Private Member Functions | Private Attributes | List of all members
larg4::ParticleListActionService Class Reference

#include <ParticleListAction_service.h>

Inheritance diagram for larg4::ParticleListActionService:

Classes

struct  ParticleInfo_t
 

Public Member Functions

 ParticleListActionService (fhicl::ParameterSet const &)
 
void preUserTrackingAction (const G4Track *) override
 
void postUserTrackingAction (const G4Track *) override
 
void userSteppingAction (const G4Step *) override
 
simb::GeneratedParticleIndex_t GetPrimaryTruthIndex (int trackId) const
 Returns the index of primary truth (sim::NoGeneratorIndex if none). More...
 
void beginOfEventAction (const G4Event *) override
 
void endOfEventAction (const G4Event *) override
 
void setInputCollections (std::vector< art::Handle< std::vector< simb::MCTruth >>> const &mclists)
 
void setPtrInfo (art::ProductID pid, art::EDProductGetter const *productGetter)
 
std::unique_ptr< std::vector< simb::MCParticle > > ParticleCollection ()
 
std::unique_ptr< art::Assns< simb::MCTruth, simb::MCParticle, sim::GeneratedParticleInfo > > AssnsMCTruthToMCParticle ()
 

Private Member Functions

sim::ParticleList && YieldList ()
 
int GetParentage (int trackid) const
 
void AddPointToCurrentParticle (TLorentzVector const &pos, TLorentzVector const &mom, std::string const &process)
 Adds a trajectory point to the current particle, and runs the filter. More...
 

Private Attributes

G4double fenergyCut
 
ParticleInfo_t fCurrentParticle
 
sim::ParticleList fParticleList
 
G4bool fstoreTrajectories
 Whether to store particle trajectories with each particle. More...
 
std::vector< std::stringfkeepGenTrajectories
 
std::map< int, int > fParentIDMap
 key is current track ID, value is parent ID More...
 
int fCurrentTrackID
 
int fTrackIDOffset
 
bool fKeepEMShowerDaughters
 whether to keep EM shower secondaries, tertiaries, etc More...
 
std::vector< std::stringfNotStoredPhysics
 Physics processes that will not be stored. More...
 
bool fkeepOnlyPrimaryFullTraj
 
bool fSparsifyTrajectories
 help reduce the number of trajectory points. More...
 
double fSparsifyMargin
 set the sparsification margin More...
 
bool fKeepTransportation
 tell whether or not to keep the transportation process More...
 
bool fKeepSecondToLast
 tell whether or not to force keeping the second to last point More...
 
std::vector< art::Handle< std::vector< simb::MCTruth > > > const * fMCLists
 MCTruthCollection input lists. More...
 
std::map< int, simb::GeneratedParticleIndex_tfPrimaryTruthMap
 Map: particle track ID -> index of primary information in MC truth. More...
 
std::map< int, size_t > fMCTIndexMap
 Map: particle track ID -> index of primary parent in std::vector<simb::MCTruth> object. More...
 
std::map< int, boolfMCTPrimProcessKeepMap
 Map: particle trakc ID -> boolean decision to keep or not full trajectory points. More...
 
std::map< size_t, std::pair< std::string, G4bool > > fMCTIndexToGeneratorMap
 Map: MCTruthIndex -> generator, input label of generator and keepGenerator decision. More...
 
std::unordered_map< std::string, int > fNotStoredCounterUMap
 Map: not stored process and counter. More...
 
std::unique_ptr< std::vector< simb::MCParticle > > partCol_
 
std::unique_ptr< art::Assns< simb::MCTruth, simb::MCParticle, sim::GeneratedParticleInfo > > tpassn_
 
art::ProductID pid_ {art::ProductID::invalid()}
 
art::EDProductGetter const * productGetter_ {nullptr}
 

Detailed Description

Definition at line 44 of file ParticleListAction_service.h.

Constructor & Destructor Documentation

larg4::ParticleListActionService::ParticleListActionService ( fhicl::ParameterSet const &  p)
explicit

Definition at line 68 of file ParticleListAction_service.cxx.

69  : artg4tk::EventActionBase("PLASEventActionBase")
70  , artg4tk::TrackingActionBase("PLASTrackingActionBase")
71  , artg4tk::SteppingActionBase("PLASSteppingActionBase")
72  , fenergyCut(p.get<double>("EnergyCut", 0.0 * CLHEP::GeV))
73  , fstoreTrajectories(p.get<bool>("storeTrajectories", true))
74  , fkeepGenTrajectories(p.get<std::vector<std::string>>("keepGenTrajectories", {}))
75  , fKeepEMShowerDaughters(p.get<bool>("keepEMShowerDaughters", true))
76  , fNotStoredPhysics(p.get<std::vector<std::string>>("NotStoredPhysics", {}))
77  , fkeepOnlyPrimaryFullTraj(p.get<bool>("keepOnlyPrimaryFullTrajectories", false))
78  , fSparsifyTrajectories(p.get<bool>("SparsifyTrajectories", false))
79  , fSparsifyMargin(p.get<double>("SparsifyMargin"))
80  , fKeepTransportation(p.get<bool>("KeepTransportation", false))
81  , fKeepSecondToLast(p.get<bool>("KeepSecondToLast", false))
82  {
83  // -- D.R. If a custom list of not storable physics is provided, use it, otherwise
84  // use the default list. This preserves the behavior of the keepEmShowerDaughters
85  // parameter
86  bool customNotStored = not fNotStoredPhysics.empty();
88  // -- Don't keep all processes
89  if (!customNotStored) // -- Don't keep but haven't provided a list
90  { // -- default list of not stored physics
91  fNotStoredPhysics = {"conv",
92  "LowEnConversion",
93  "Pair",
94  "compt",
95  "Compt",
96  "Brem",
97  "phot",
98  "Photo",
99  "Ion",
100  "annihil"};
101  }
102 
103  std::stringstream sstored;
104  sstored << "The full tracking information will not be stored for particles"
105  << " resulting from the following processes: \n{ ";
106  for (auto const& i : fNotStoredPhysics) {
107  sstored << "\"" << i << "\" ";
108  fNotStoredCounterUMap.emplace(i, 0); // -- initialize counter
109  }
110  mf::LogInfo("ParticleListActionService") << sstored.str() << "}\n";
111  }
112  else { // -- Keep all processes
113  mf::LogInfo("ParticleListActionService")
114  << "Storing full tracking information for all processes. \n";
115  if (customNotStored) // -- custom list will be ignored
116  {
117  mf::LogWarning("StoredPhysics")
118  << "NotStoredPhysics provided, but will be ignored."
119  << " To use NotStoredPhysics, set keepEMShowerDaughters to false";
120  }
121  }
122 
123  // -- sparsify info
125  mf::LogInfo("ParticleListActionService")
126  << "Trajectory sparsification enabled with SparsifyMargin : " << fSparsifyMargin << "\n";
127  }
bool fKeepEMShowerDaughters
whether to keep EM shower secondaries, tertiaries, etc
MaybeLogger_< ELseverityLevel::ELsev_info, false > LogInfo
bool fKeepSecondToLast
tell whether or not to force keeping the second to last point
double fSparsifyMargin
set the sparsification margin
bool fKeepTransportation
tell whether or not to keep the transportation process
bool fSparsifyTrajectories
help reduce the number of trajectory points.
static constexpr double GeV
Definition: Units.h:28
std::unordered_map< std::string, int > fNotStoredCounterUMap
Map: not stored process and counter.
p
Definition: test.py:223
std::vector< std::string > fNotStoredPhysics
Physics processes that will not be stored.
std::vector< std::string > fkeepGenTrajectories
G4bool fstoreTrajectories
Whether to store particle trajectories with each particle.
MaybeLogger_< ELseverityLevel::ELsev_warning, false > LogWarning

Member Function Documentation

void larg4::ParticleListActionService::AddPointToCurrentParticle ( TLorentzVector const &  pos,
TLorentzVector const &  mom,
std::string const &  process 
)
private

Adds a trajectory point to the current particle, and runs the filter.

Definition at line 691 of file ParticleListAction_service.cxx.

694  {
695  // Add the first point in the trajectory.
697  }
simb::MCParticle * particle
simple structure representing particle
void AddTrajectoryPoint(TLorentzVector const &position, TLorentzVector const &momentum)
Definition: MCParticle.h:257
bool fKeepTransportation
tell whether or not to keep the transportation process
def process(f, kind)
Definition: search.py:254
std::unique_ptr<art::Assns<simb::MCTruth, simb::MCParticle, sim::GeneratedParticleInfo> > larg4::ParticleListActionService::AssnsMCTruthToMCParticle ( )
inline

Definition at line 91 of file ParticleListAction_service.h.

92  {
93  return std::move(tpassn_);
94  }
std::unique_ptr< art::Assns< simb::MCTruth, simb::MCParticle, sim::GeneratedParticleInfo > > tpassn_
def move(depos, offset)
Definition: depos.py:107
void larg4::ParticleListActionService::beginOfEventAction ( const G4Event *  )
override

Definition at line 132 of file ParticleListAction_service.cxx.

133  {
134  // Clear any previous particle information.
136  fParticleList.clear();
137  fParentIDMap.clear();
138  fMCTIndexMap.clear();
139  fMCTPrimProcessKeepMap.clear();
141  fTrackIDOffset = 0;
142 
143  fPrimaryTruthMap.clear();
144  fMCTIndexToGeneratorMap.clear();
145  fNotStoredCounterUMap.clear();
146 
147  // -- D.R. If a custom list of keepGenTrajectories is provided, use it, otherwise
148  // keep or drop decision made based storeTrajectories parameter. This preserves
149  // the behavior of the storeTrajectories fhicl param
150  bool customKeepTraj = not fkeepGenTrajectories.empty();
151  if (!fstoreTrajectories) { // -- fstoreTrajectories : false
152  mf::LogDebug("beginOfEventAction::Generator") << "Trajectory points will not be stored.";
153  }
154  else if (!customKeepTraj) { // -- fstoretrajectories : true and empty keepGenTrajectories list
155  mf::LogDebug("beginOfEventAction::Generator")
156  << "keepGenTrajectories list is empty. Will"
157  << " store trajectory points for all generators";
158  }
159 
160  // -- D.R. determine mapping between MCTruthIndex(s) and generator(s) for later reference
161  size_t nKeep = 0;
162  std::string generator_name = "unknown";
163  for (size_t mcti = 0; mcti < fMCLists->size(); ++mcti) {
164 
165  std::stringstream sskeepgen;
166  sskeepgen << "MCTruth object summary :";
167  sskeepgen << "\n\tPrimary MCTIndex : " << mcti;
168 
169  // -- Obtain the generator (provenance) corresponding to the mctruth index:
170  auto const& mclistHandle = (*fMCLists)[mcti];
171  generator_name = mclistHandle.provenance()->inputTag().label();
172  sskeepgen << "\n\tProvenance/Generator : " << generator_name;
173 
174  G4bool keepGen = false;
175  if (fstoreTrajectories) // -- storeTrajectories set to true; check which
176  {
177  if (!customKeepTraj) { // -- no custom list, so keep all
178  keepGen = true;
179  nKeep++;
180  }
181  else { // -- custom list, so check the ones in the event against provided keep list
182  for (auto keepableGen : fkeepGenTrajectories) {
183  if (generator_name == keepableGen) { // -- exit upon finding match; false by default
184  keepGen = true;
185  nKeep++;
186  break;
187  }
188  }
189  }
190  }
191  fMCTIndexToGeneratorMap.emplace(mcti, std::make_pair(generator_name, keepGen));
192  sskeepgen << "\n\tTrajectory points storable : " << (keepGen ? "true" : "false") << "\n";
193  mf::LogDebug("beginOfEventAction::Generator") << sskeepgen.str();
194  }
195 
196  if (nKeep == 0 && customKeepTraj && fstoreTrajectories) {
197  mf::LogWarning("beginOfEventAction::keepableGenerators")
198  << "storeTrajectories"
199  << " set to true and a non-empty keepGenTrajectories list provided in configuration file, "
200  "but"
201  << " none of the generators in this list are present in the event! Double check list or "
202  "don't"
203  << " provide keepGenTrajectories in the configuration to keep all trajectories from all"
204  << " generator labels. This may be expected for generators that have a nonzero probability "
205  "of"
206  << " producing no particles (e.g. some radiologicals)";
207  }
208  }
std::string string
Definition: nybbler.cc:12
std::map< int, size_t > fMCTIndexMap
Map: particle track ID -> index of primary parent in std::vector<simb::MCTruth> object.
static const int NoParticleId
Definition: sim.h:28
std::map< size_t, std::pair< std::string, G4bool > > fMCTIndexToGeneratorMap
Map: MCTruthIndex -> generator, input label of generator and keepGenerator decision.
std::unordered_map< std::string, int > fNotStoredCounterUMap
Map: not stored process and counter.
std::map< int, int > fParentIDMap
key is current track ID, value is parent ID
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. ...
MaybeLogger_< ELseverityLevel::ELsev_success, false > LogDebug
G4bool fstoreTrajectories
Whether to store particle trajectories with each particle.
MaybeLogger_< ELseverityLevel::ELsev_warning, false > LogWarning
std::map< int, simb::GeneratedParticleIndex_t > fPrimaryTruthMap
Map: particle track ID -> index of primary information in MC truth.
std::vector< art::Handle< std::vector< simb::MCTruth > > > const * fMCLists
MCTruthCollection input lists.
void larg4::ParticleListActionService::endOfEventAction ( const G4Event *  )
override

Definition at line 702 of file ParticleListAction_service.cxx.

703  {
704  // -- End of Run Report
705  if (!fNotStoredCounterUMap.empty()) { // -- Only if there is something to report
706  std::stringstream sscounter;
707  sscounter << "Not Stored Process summary:";
708  for (auto const& [process, count] : fNotStoredCounterUMap) {
709  sscounter << "\n\t" << process << " : " << count;
710  }
711  mf::LogInfo("ParticleListActionService") << sscounter.str();
712  }
713 
714  partCol_ = std::make_unique<std::vector<simb::MCParticle>>();
715  tpassn_ =
716  std::make_unique<art::Assns<simb::MCTruth, simb::MCParticle, sim::GeneratedParticleInfo>>();
717  // Set up the utility class for the "for_each" algorithm. (We only
718  // need a separate set-up for the utility class because we need to
719  // give it the pointer to the particle list. We're using the STL
720  // "for_each" instead of the C++ "for loop" because it's supposed
721  // to be faster.
722  std::for_each(
723  fParticleList.begin(), fParticleList.end(), UpdateDaughterInformation{fParticleList});
724 
725  MF_LOG_INFO("endOfEventAction") << "MCTruth Handles Size: " << fMCLists->size();
726 
727  unsigned int nGeneratedParticles = 0;
728  unsigned int nMCTruths = 0;
729  sim::ParticleList particleList = YieldList();
730 
731  for (size_t mcl = 0; mcl < fMCLists->size(); ++mcl) {
732  auto const& mclistHandle = (*fMCLists)[mcl];
733  MF_LOG_INFO("endOfEventAction") << "mclistHandle Size: " << mclistHandle->size();
734 
735  for (size_t m = 0; m < mclistHandle->size(); ++m) {
736  art::Ptr<simb::MCTruth> mct(mclistHandle, m);
737 
738  MF_LOG_INFO("endOfEventAction") << "Found " << mct->NParticles() << " particles";
739 
740  for (simb::MCParticle* p : particleList | ranges::views::values) {
741  auto gen_index = fMCTIndexMap[p->TrackId()];
742  if (gen_index != nMCTruths) continue;
743  assert(p->NumberTrajectoryPoints() != 0ull);
744 
745  ++nGeneratedParticles;
746  sim::GeneratedParticleInfo const truthInfo{GetPrimaryTruthIndex(p->TrackId())};
747  if (!truthInfo.hasGeneratedParticleIndex() && p->Mother() == 0) {
748  MF_LOG_WARNING("endOfEventAction") << "No GeneratedParticleIndex()!";
749  // this means it's primary but with no information; logic error!!
751  << "Failed to match primary particle:\n"
752  << "\nwith particles from the truth record '" << mclistHandle.provenance()->inputTag()
753  << "':\n\n";
754  }
755 
756  partCol_->push_back(std::move(*p));
758  tpassn_->addSingle(mct, mcp_ptr, truthInfo);
759  }
760  mf::LogDebug("Offset") << "nGeneratedParticles = " << nGeneratedParticles;
761  ++nMCTruths;
762  }
763  }
764 
765  fTrackIDOffset = 0;
766  }
MaybeLogger_< ELseverityLevel::ELsev_info, false > LogInfo
std::unique_ptr< art::Assns< simb::MCTruth, simb::MCParticle, sim::GeneratedParticleInfo > > tpassn_
simb::GeneratedParticleIndex_t GetPrimaryTruthIndex(int trackId) const
Returns the index of primary truth (sim::NoGeneratorIndex if none).
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.
def process(f, kind)
Definition: search.py:254
def move(depos, offset)
Definition: depos.py:107
std::unordered_map< std::string, int > fNotStoredCounterUMap
Map: not stored process and counter.
p
Definition: test.py:223
Q_UINT16 values[128]
#define MF_LOG_INFO(category)
cet::coded_exception< errors::ErrorCodes, ExceptionDetail::translate > Exception
Definition: Exception.h:66
art::EDProductGetter const * productGetter_
MaybeLogger_< ELseverityLevel::ELsev_success, false > LogDebug
Contains information about a generated particle.
#define MF_LOG_WARNING(category)
std::vector< art::Handle< std::vector< simb::MCTruth > > > const * fMCLists
MCTruthCollection input lists.
int larg4::ParticleListActionService::GetParentage ( int  trackid) const
private

Definition at line 216 of file ParticleListAction_service.cxx.

217  {
218  int parentid = sim::NoParticleId;
219 
220  // search the fParentIDMap recursively until we have the parent id
221  // of the first EM particle that led to this one
222  auto itr = fParentIDMap.find(trackid);
223  while (itr != fParentIDMap.end()) {
224 
225  // set the parentid to the current parent ID, when the loop ends
226  // this id will be the first EM particle
227  parentid = (*itr).second;
228  itr = fParentIDMap.find(parentid);
229  }
230 
231  return parentid;
232  }
static const int NoParticleId
Definition: sim.h:28
std::map< int, int > fParentIDMap
key is current track ID, value is parent ID
simb::GeneratedParticleIndex_t larg4::ParticleListActionService::GetPrimaryTruthIndex ( int  trackId) const

Returns the index of primary truth (sim::NoGeneratorIndex if none).

Definition at line 661 of file ParticleListAction_service.cxx.

662  {
663  auto const it = fPrimaryTruthMap.find(trackId);
664  return it == fPrimaryTruthMap.end() ? simb::NoGeneratedParticleIndex : it->second;
665  }
constexpr GeneratedParticleIndex_t NoGeneratedParticleIndex
Constant representing the absence of generator truth information.
Definition: simb.h:34
std::map< int, simb::GeneratedParticleIndex_t > fPrimaryTruthMap
Map: particle track ID -> index of primary information in MC truth.
std::unique_ptr<std::vector<simb::MCParticle> > larg4::ParticleListActionService::ParticleCollection ( )
inline

Definition at line 85 of file ParticleListAction_service.h.

86  {
87  return std::move(partCol_);
88  }
std::unique_ptr< std::vector< simb::MCParticle > > partCol_
def move(depos, offset)
Definition: depos.py:107
void larg4::ParticleListActionService::postUserTrackingAction ( const G4Track *  aTrack)
override

Definition at line 446 of file ParticleListAction_service.cxx.

447  {
448  if (!fCurrentParticle.hasParticle()) return;
449 
450  if (aTrack) {
451  fCurrentParticle.particle->SetWeight(aTrack->GetWeight());
452 
453  // Get the post-step information from the G4Step.
454  const G4StepPoint* postStepPoint = aTrack->GetStep()->GetPostStepPoint();
455  if (!postStepPoint->GetProcessDefinedStep()) {
456  // Now we get to do some awkward cleanup because the
457  // fparticleList was augmented during the
458  // preUserTrackingAction. We cannot call 'Archive' because
459  // that only sets the mapped type of the entry to
460  // nullptr...which is really bad whenever we iterate through
461  // entries in the endOfEventAction and dereference the mapped
462  // type. We have to entirely erase the entry.
463  auto key_to_erase = fParticleList.key(fCurrentParticle.particle);
464  fParticleList.erase(key_to_erase);
465  // after the particle is archived, it is deleted
467  return;
468  }
469 
470  G4String process = postStepPoint->GetProcessDefinedStep()->GetProcessName();
472 
473  // -- D.R. Store the final point only for particles that have not had intermediate trajectory
474  // points saved. This avoids double counting the final trajectory point for particles from
475  // generators with storable trajectory points.
476 
478  const G4ThreeVector position = postStepPoint->GetPosition();
479  G4double time = postStepPoint->GetGlobalTime();
480 
481  // Remember that LArSoft uses cm, ns, GeV.
482  TLorentzVector fourPos(position.x() / CLHEP::cm,
483  position.y() / CLHEP::cm,
484  position.z() / CLHEP::cm,
485  time / CLHEP::ns);
486 
487  const G4ThreeVector momentum = postStepPoint->GetMomentum();
488  const G4double energy = postStepPoint->GetTotalEnergy();
489  TLorentzVector fourMom(momentum.x() / CLHEP::GeV,
490  momentum.y() / CLHEP::GeV,
491  momentum.z() / CLHEP::GeV,
492  energy / CLHEP::GeV);
493 
494  // Add another point in the trajectory.
495  AddPointToCurrentParticle(fourPos, fourMom, std::string(process));
496  }
497  // -- particle has a full trajectory, apply SparsifyTrajectory method if enabled
498  else if (fSparsifyTrajectories) {
500  }
501  }
502 
503  // store truth record pointer, only if it is available
504  if (fCurrentParticle.isPrimary()) {
506  }
507 
508  return;
509  }
static constexpr double cm
Definition: Units.h:68
simb::MCParticle * particle
simple structure representing particle
std::string string
Definition: nybbler.cc:12
bool fKeepSecondToLast
tell whether or not to force keeping the second to last point
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.
int TrackId() const
Definition: MCParticle.h:210
def process(f, kind)
Definition: search.py:254
bool fSparsifyTrajectories
help reduce the number of trajectory points.
static constexpr double GeV
Definition: Units.h:28
bool isPrimary() const
Returns whether there is a particle.
void SetWeight(double wt)
Definition: MCParticle.h:271
void SetEndProcess(std::string s)
Definition: MCParticle.cxx:105
simb::GeneratedParticleIndex_t truthInfoIndex() const
Returns the index of the particle in the generator truth record.
void clear()
Resets the information (does not release memory it does not own)
bool hasParticle() const
Returns whether there is a particle.
std::map< int, simb::GeneratedParticleIndex_t > fPrimaryTruthMap
Map: particle track ID -> index of primary information in MC truth.
def momentum(x1, x2, x3, scale=1.)
void SparsifyTrajectory(double margin=0.1, bool keep_second_to_last=false)
Definition: MCParticle.h:265
QAsciiDict< Entry > ns
void larg4::ParticleListActionService::preUserTrackingAction ( const G4Track *  track)
override

Definition at line 237 of file ParticleListAction_service.cxx.

238  {
239  // Particle type.
240  G4ParticleDefinition* particleDefinition = track->GetDefinition();
241  G4int pdgCode = particleDefinition->GetPDGEncoding();
242 
243  // Get Geant4's ID number for this track. This will be the same
244  // ID number that we'll use in the ParticleList.
245  // It is offset by the number of tracks accumulated from the previous Geant4
246  // runs (if any)
247  int const trackID = track->GetTrackID() + fTrackIDOffset;
248  fCurrentTrackID = trackID;
249 
250  // And the particle's parent (same offset as above):
251  int parentID = track->GetParentID() + fTrackIDOffset;
252 
253  std::string process_name = "unknown";
254  std::string mct_primary_process = "unknown";
255  bool isFromMCTProcessPrimary = false;
256 
257  // Is there an MCTruth object associated with this G4Track? We
258  // have to go up a "chain" of information to find out:
259  const G4DynamicParticle* dynamicParticle = track->GetDynamicParticle();
260  const G4PrimaryParticle* primaryParticle = dynamicParticle->GetPrimaryParticle();
262  size_t primarymctIndex = 0;
263  if (primaryParticle != nullptr) {
264  const G4VUserPrimaryParticleInformation* gppi = primaryParticle->GetUserInformation();
265  const g4b::PrimaryParticleInformation* ppi =
266  dynamic_cast<const g4b::PrimaryParticleInformation*>(gppi);
267  if (ppi != nullptr) {
268  primaryIndex = ppi->MCParticleIndex();
269  primarymctIndex = ppi->MCTruthIndex();
270 
271  mct_primary_process = ppi->GetMCParticle()->Process();
272 
273  // If we've made it this far, a PrimaryParticleInformation
274  // object exists and we are using a primary particle, set the
275  // process name accordingly
276 
277  // -- D.R. : if process == "primary" exactly (this will most likely be the case), mark it as
278  // a primary with keepable trajectory for itself and its descendants.
279  // -- elsif it simply starts with "primary", accept it but mark it as non-keep
280  // -- else force it to be primary because we have determined that it is a primary particle
281  // This was the original behavior of the code i.e. process was _set_ to "primary"
282  // regardless of what the process name was in the generator MCTruth object.
283  //
284  // -- NOTE: This enforces a convention for process names assigned in the gen stage.
285  if (mct_primary_process.compare("primary") == 0) {
286  process_name = "primary";
287  isFromMCTProcessPrimary = true;
288  }
289  else if (mct_primary_process.find("primary") == 0) {
290  process_name = mct_primary_process;
291  isFromMCTProcessPrimary = false;
292  mf::LogDebug("PrimaryParticle") << "MCTruth primary process name contains \"primary\" "
293  << " but is not solely \"primary\" : " << process_name
294  << ".\nWill not store full set of trajectory points.";
295  }
296  else { // -- override it
297  process_name = "primary";
298  isFromMCTProcessPrimary = true;
299  mf::LogWarning("PrimaryParticle")
300  << "MCTruth primary process does not beging with string"
301  << " literal \"primary\" : " << process_name << "\nOVERRIDING it to \"primary\"";
302  }
303  // -- The process_name check is simply to allow an additional way to reduce memory usage,
304  // namely, by creating MCTruth input particles with multiple process labels (e.g. "primary"
305  // and "primaryBackground") that can be used to veto storage of trajectory points.
306 
307  // primary particles should have parentID = 0, even if there
308  // are multiple MCTruths for this event
309  parentID = 0;
310  } // end else no primary particle information
311  } // Is there a G4PrimaryParticle?
312  // If this is not a primary particle...
313  else {
314  // check if this particle was made in an undesirable process. For example:
315  // if one is not interested in EM shower particles, don't put it in the particle
316  // list as one wouldn't care about secondaries, tertiaries, etc. For these showers
317  // figure out what process is making this track - skip it if it is
318  // one of pair production, compton scattering, photoelectric effect
319  // bremstrahlung, annihilation, or ionization
320  process_name = track->GetCreatorProcess()->GetProcessName();
321  if (!fKeepEMShowerDaughters) {
322  bool notstore = false;
323  for (auto const& p : fNotStoredPhysics) {
324  if (process_name.find(p) != std::string::npos) {
325  notstore = true;
326  mf::LogDebug("NotStoredPhysics") << "Found process : " << process_name;
327 
328  int old = 0;
329  auto search = fNotStoredCounterUMap.find(p);
330  if (search != fNotStoredCounterUMap.end()) { old = search->second; }
331  fNotStoredCounterUMap.insert_or_assign(p, (old + 1));
332  break;
333  }
334  }
335 
336  if (notstore) {
337 
338  // figure out the ultimate parentage of this particle
339  // first add this track id and its parent to the fParentIDMap
340  fParentIDMap[trackID] = parentID;
341 
342  fCurrentTrackID = -1 * this->GetParentage(trackID);
343 
344  // check that fCurrentTrackID is in the particle list - it is possible
345  // that this particle's parent is a particle that did not get tracked.
346  // An example is a parent that was made due to muMinusCaptureAtRest
347  // and the daughter was made by the phot process. The parent likely
348  // isn't saved in the particle list because it is below the energy cut
349  // which will put a bogus track id value into the sim::IDE object for
350  // the sim::SimChannel if we don't check it.
352 
353  // clear current particle as we are not stepping this particle and
354  // adding trajectory points to it
356  return;
357  } // end if process matches an undesired process
358  } // end if keeping EM shower daughters
359 
360  // Check the energy of the particle. If it falls below the energy
361  // cut, don't add it to our list.
362  G4double energy = track->GetKineticEnergy();
363  if (energy < fenergyCut) {
365 
366  // do add the particle to the parent id map though
367  // and set the current track id to be it's ultimate parent
368  fParentIDMap[trackID] = parentID;
369  fCurrentTrackID = -1 * this->GetParentage(trackID);
370 
371  return;
372  }
373 
374  // check to see if the parent particle has been stored in the particle navigator
375  // if not, then see if it is possible to walk up the fParentIDMap to find the
376  // ultimate parent of this particle. Use that ID as the parent ID for this
377  // particle
378  if (!fParticleList.KnownParticle(parentID)) {
379  // do add the particle to the parent id map
380  // just in case it makes a daughter that we have to track as well
381  fParentIDMap[trackID] = parentID;
382  int pid = this->GetParentage(parentID);
383 
384  // if we still can't find the parent in the particle navigator,
385  // we have to give up
386  if (!fParticleList.KnownParticle(pid)) {
387  MF_LOG_WARNING("ParticleListActionService")
388  << "can't find parent id: " << parentID << " in the particle list, or fParentIDMap."
389  << " Make " << parentID << " the mother ID for"
390  << " track ID " << fCurrentTrackID << " in the hope that it will aid debugging.";
391  }
392  else
393  parentID = pid;
394  }
395 
396  // Once the parentID is secured, inherit the MCTruth Index
397  // which should have been set already
398  if (auto it = fMCTIndexMap.find(parentID); it != cend(fMCTIndexMap)) {
399  primarymctIndex = it->second;
400  }
401  else {
403  << "Could not locate MCT Index for parent trackID of " << parentID;
404  }
405 
406  // Inherit whether the parent is from a primary with MCTruth process_name == "primary"
407  isFromMCTProcessPrimary = fMCTPrimProcessKeepMap[parentID];
408  } // end if not a primary particle
409 
410  // This is probably the PDG mass, but just in case:
411  double mass = dynamicParticle->GetMass() / CLHEP::GeV;
412 
413  // Create the sim::Particle object.
416  new simb::MCParticle{trackID, pdgCode, process_name, parentID, mass};
417  fCurrentParticle.truthIndex = primaryIndex;
418 
419  fMCTIndexMap[trackID] = primarymctIndex;
420 
421  fMCTPrimProcessKeepMap[trackID] = isFromMCTProcessPrimary;
422 
423  // -- determine whether full set of trajectorie points should be stored or only the start and end points
425  (!fstoreTrajectories) ?
426  false : /*don't want trajectory points at all, bail*/
427  (!(fMCTIndexToGeneratorMap[primarymctIndex].second)) ?
428  false : /*particle is not from a storable generator*/
430  true : /*want all primaries tracked for a storable generator*/
431  (isFromMCTProcessPrimary) ?
432  true : /*only descendants from primaries with MCTruth process == "primary"*/
433  false; /*not from MCTruth process "primary"*/
434 
435  // Polarization.
436  const G4ThreeVector& polarization = track->GetPolarization();
438  TVector3{polarization.x(), polarization.y(), polarization.z()});
439 
440  // Save the particle in the ParticleList.
442  }
simb::MCParticle * particle
simple structure representing particle
decltype(auto) constexpr cend(T &&obj)
ADL-aware version of std::cend.
Definition: StdUtils.h:87
bool fKeepEMShowerDaughters
whether to keep EM shower secondaries, tertiaries, etc
std::string string
Definition: nybbler.cc:12
std::map< int, size_t > fMCTIndexMap
Map: particle track ID -> index of primary parent in std::vector<simb::MCTruth> object.
constexpr GeneratedParticleIndex_t NoGeneratedParticleIndex
Constant representing the absence of generator truth information.
Definition: simb.h:34
void SetPolarization(const TVector3 &p)
Definition: MCParticle.h:269
static constexpr double GeV
Definition: Units.h:28
static const int NoParticleId
Definition: sim.h:28
std::map< size_t, std::pair< std::string, G4bool > > fMCTIndexToGeneratorMap
Map: MCTruthIndex -> generator, input label of generator and keepGenerator decision.
std::unordered_map< std::string, int > fNotStoredCounterUMap
Map: not stored process and counter.
p
Definition: test.py:223
Definition: search.py:1
std::vector< std::string > fNotStoredPhysics
Physics processes that will not be stored.
cet::coded_exception< errors::ErrorCodes, ExceptionDetail::translate > Exception
Definition: Exception.h:66
std::map< int, int > fParentIDMap
key is current track ID, value is parent ID
void clear()
Resets the information (does not release memory it does not own)
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.
MaybeLogger_< ELseverityLevel::ELsev_success, false > LogDebug
G4bool fstoreTrajectories
Whether to store particle trajectories with each particle.
MaybeLogger_< ELseverityLevel::ELsev_warning, false > LogWarning
#define MF_LOG_WARNING(category)
second_as<> second
Type of time stored in seconds, in double precision.
Definition: spacetime.h:85
std::size_t GeneratedParticleIndex_t
Type of particle index in the generator truth record (simb::MCTruth).
Definition: simb.h:30
void larg4::ParticleListActionService::setInputCollections ( std::vector< art::Handle< std::vector< simb::MCTruth >>> const &  mclists)
inline

Definition at line 71 of file ParticleListAction_service.h.

72  {
73  fMCLists = &mclists;
74  }
std::vector< art::Handle< std::vector< simb::MCTruth > > > const * fMCLists
MCTruthCollection input lists.
void larg4::ParticleListActionService::setPtrInfo ( art::ProductID  pid,
art::EDProductGetter const *  productGetter 
)
inline

Definition at line 77 of file ParticleListAction_service.h.

79  {
80  pid_ = pid;
81  productGetter_ = productGetter;
82  }
art::EDProductGetter const * productGetter_
void larg4::ParticleListActionService::userSteppingAction ( const G4Step *  step)
override

Definition at line 514 of file ParticleListAction_service.cxx.

515  {
516  // N.B. G4 guarantees that following are non-null:
517  // - step
518  // - step->GetPostStepPoint()
519  if (!fCurrentParticle.hasParticle() || !step->GetPostStepPoint()->GetProcessDefinedStep()) {
520  return;
521  }
522  // Temporary fix for problem where DeltaTime on the first step
523  // of optical photon propagation is calculated incorrectly. -wforeman
524  double const globalTime = step->GetTrack()->GetGlobalTime();
525  double const velocity_G4 = step->GetTrack()->GetVelocity();
526  double const velocity_step = step->GetStepLength() / step->GetDeltaTime();
527  if ((step->GetTrack()->GetDefinition()->GetPDGEncoding() == 0) &&
528  fabs(velocity_G4 - velocity_step) > 0.0001) {
529  // Subtract the faulty step time from the global time,
530  // and add the correct step time based on G4 velocity.
531  step->GetPostStepPoint()->SetGlobalTime(globalTime - step->GetDeltaTime() +
532  step->GetStepLength() / velocity_G4);
533  }
534 
535  // For the most part, we just want to add the post-step
536  // information to the particle's trajectory. There's one
537  // exception: In PreTrackingAction, the correct time information
538  // is not available. So add the correct vertex information here.
539 
541 
542  // Get the pre/along-step information from the G4Step.
543  const G4StepPoint* preStepPoint = step->GetPreStepPoint();
544 
545  const G4ThreeVector position = preStepPoint->GetPosition();
546  G4double time = preStepPoint->GetGlobalTime();
547 
548  // Remember that LArSoft uses cm, ns, GeV.
549  TLorentzVector fourPos(position.x() / CLHEP::cm,
550  position.y() / CLHEP::cm,
551  position.z() / CLHEP::cm,
552  time / CLHEP::ns);
553 
554  const G4ThreeVector momentum = preStepPoint->GetMomentum();
555  const G4double energy = preStepPoint->GetTotalEnergy();
556  TLorentzVector fourMom(momentum.x() / CLHEP::GeV,
557  momentum.y() / CLHEP::GeV,
558  momentum.z() / CLHEP::GeV,
559  energy / CLHEP::GeV);
560 
561  // Add the first point in the trajectory.
562  AddPointToCurrentParticle(fourPos, fourMom, "Start");
563  } // end if this is the first step
564 
565  // At this point, the particle is being transported through the
566  // simulation. This method is being called for every voxel that
567  // the track passes through, but we don't want to update the
568  // trajectory information if we're just updating voxels. To check
569  // for this, look at the process name for the step, and compare it
570  // against the voxelization process name (set in PhysicsList.cxx).
571  G4String process = step->GetPostStepPoint()->GetProcessDefinedStep()->GetProcessName();
572  G4bool ignoreProcess = process.contains("LArVoxel") || process.contains("OpDetReadout");
573 
574  /*
575  mf::LogDebug("ParticleListActionService::SteppingAction")
576  << ": DEBUG - process='"
577  << process << "'"
578  << " ignoreProcess=" << ignoreProcess
579  << " fstoreTrajectories="
580  << fstoreTrajectories;
581  */
582 
583  // We store the initial creation point of the particle
584  // and its final position (ie where it has no more energy, or at least < 1 eV) no matter
585  // what, but whether we store the rest of the trajectory depends
586  // on the process, and on a user switch.
587  // -- D.R. Store additional trajectory points only for desired generators and processes
588  if (!ignoreProcess && fCurrentParticle.keepFullTrajectory) {
589 
590  // Get the post-step information from the G4Step.
591  const G4StepPoint* postStepPoint = step->GetPostStepPoint();
592 
593  const G4ThreeVector position = postStepPoint->GetPosition();
594  G4double time = postStepPoint->GetGlobalTime();
595 
596  // Remember that LArSoft uses cm, ns, GeV.
597  TLorentzVector fourPos(position.x() / CLHEP::cm,
598  position.y() / CLHEP::cm,
599  position.z() / CLHEP::cm,
600  time / CLHEP::ns);
601 
602  const G4ThreeVector momentum = postStepPoint->GetMomentum();
603  const G4double energy = postStepPoint->GetTotalEnergy();
604  TLorentzVector fourMom(momentum.x() / CLHEP::GeV,
605  momentum.y() / CLHEP::GeV,
606  momentum.z() / CLHEP::GeV,
607  energy / CLHEP::GeV);
608 
609  // Add another point in the trajectory.
610  AddPointToCurrentParticle(fourPos, fourMom, std::string(process));
611  }
612  }
static constexpr double cm
Definition: Units.h:68
unsigned int NumberTrajectoryPoints() const
Definition: MCParticle.h:218
simb::MCParticle * particle
simple structure representing particle
std::string string
Definition: nybbler.cc:12
double globalTime
void AddPointToCurrentParticle(TLorentzVector const &pos, TLorentzVector const &mom, std::string const &process)
Adds a trajectory point to the current particle, and runs the filter.
def process(f, kind)
Definition: search.py:254
static constexpr double GeV
Definition: Units.h:28
double velocity_step
bool hasParticle() const
Returns whether there is a particle.
double velocity_G4
def momentum(x1, x2, x3, scale=1.)
QAsciiDict< Entry > ns
sim::ParticleList && larg4::ParticleListActionService::YieldList ( )
private

Definition at line 670 of file ParticleListAction_service.cxx.

671  {
672  // check if the ParticleNavigator has entries, and if
673  // so grab the highest track id value from it to
674  // add to the fTrackIDOffset
675  int highestID = 0;
676  for (auto pn = fParticleList.begin(); pn != fParticleList.end(); pn++)
677  if ((*pn).first > highestID) highestID = (*pn).first;
678 
679  //Only change the fTrackIDOffset if there is in fact a particle to add to the event
680  if ((fParticleList.size()) != 0) {
681  fTrackIDOffset = highestID + 1;
682  mf::LogDebug("YieldList:fTrackIDOffset")
683  << "highestID = " << highestID << "\nfTrackIDOffset= " << fTrackIDOffset;
684  }
685 
686  return std::move(fParticleList);
687  } // ParticleList&& ParticleListActionService::YieldList()
def move(depos, offset)
Definition: depos.py:107
MaybeLogger_< ELseverityLevel::ELsev_success, false > LogDebug

Member Data Documentation

ParticleInfo_t larg4::ParticleListActionService::fCurrentParticle
private

information about the particle currently being simulated for a single particle.

Definition at line 145 of file ParticleListAction_service.h.

int larg4::ParticleListActionService::fCurrentTrackID
private

track ID of the current particle, set to eve ID for EM shower particles

Definition at line 157 of file ParticleListAction_service.h.

G4double larg4::ParticleListActionService::fenergyCut
private

The minimum energy for a particle to be included in the list.

Definition at line 143 of file ParticleListAction_service.h.

bool larg4::ParticleListActionService::fKeepEMShowerDaughters
private

whether to keep EM shower secondaries, tertiaries, etc

Definition at line 161 of file ParticleListAction_service.h.

std::vector<std::string> larg4::ParticleListActionService::fkeepGenTrajectories
private

List of generators for which fstoreTrajectories applies. if not provided and storeTrajectories is true, then all trajectories for all generators will be stored. If storeTrajectories is set to false, this list is ignored and all additional trajectory points are not stored.

Definition at line 151 of file ParticleListAction_service.h.

bool larg4::ParticleListActionService::fkeepOnlyPrimaryFullTraj
private

Whether to store trajectories only for primaries and their descendants with MCTruth process = "primary"

Definition at line 163 of file ParticleListAction_service.h.

bool larg4::ParticleListActionService::fKeepSecondToLast
private

tell whether or not to force keeping the second to last point

Definition at line 168 of file ParticleListAction_service.h.

bool larg4::ParticleListActionService::fKeepTransportation
private

tell whether or not to keep the transportation process

Definition at line 167 of file ParticleListAction_service.h.

std::vector<art::Handle<std::vector<simb::MCTruth> > > const* larg4::ParticleListActionService::fMCLists
private

MCTruthCollection input lists.

Definition at line 171 of file ParticleListAction_service.h.

std::map<int, size_t> larg4::ParticleListActionService::fMCTIndexMap
private

Map: particle track ID -> index of primary parent in std::vector<simb::MCTruth> object.

Definition at line 177 of file ParticleListAction_service.h.

std::map<size_t, std::pair<std::string, G4bool> > larg4::ParticleListActionService::fMCTIndexToGeneratorMap
private

Map: MCTruthIndex -> generator, input label of generator and keepGenerator decision.

Definition at line 183 of file ParticleListAction_service.h.

std::map<int, bool> larg4::ParticleListActionService::fMCTPrimProcessKeepMap
private

Map: particle trakc ID -> boolean decision to keep or not full trajectory points.

Definition at line 180 of file ParticleListAction_service.h.

std::unordered_map<std::string, int> larg4::ParticleListActionService::fNotStoredCounterUMap
private

Map: not stored process and counter.

Definition at line 186 of file ParticleListAction_service.h.

std::vector<std::string> larg4::ParticleListActionService::fNotStoredPhysics
private

Physics processes that will not be stored.

Definition at line 162 of file ParticleListAction_service.h.

std::map<int, int> larg4::ParticleListActionService::fParentIDMap
private

key is current track ID, value is parent ID

Definition at line 156 of file ParticleListAction_service.h.

sim::ParticleList larg4::ParticleListActionService::fParticleList
private

The accumulated particle information for all particles in the event.

Definition at line 147 of file ParticleListAction_service.h.

std::map<int, simb::GeneratedParticleIndex_t> larg4::ParticleListActionService::fPrimaryTruthMap
private

Map: particle track ID -> index of primary information in MC truth.

Definition at line 174 of file ParticleListAction_service.h.

double larg4::ParticleListActionService::fSparsifyMargin
private

set the sparsification margin

Definition at line 166 of file ParticleListAction_service.h.

bool larg4::ParticleListActionService::fSparsifyTrajectories
private

help reduce the number of trajectory points.

Definition at line 165 of file ParticleListAction_service.h.

G4bool larg4::ParticleListActionService::fstoreTrajectories
private

Whether to store particle trajectories with each particle.

Definition at line 149 of file ParticleListAction_service.h.

int larg4::ParticleListActionService::fTrackIDOffset
mutableprivate

offset added to track ids when running over multiple MCTruth objects.

Definition at line 159 of file ParticleListAction_service.h.

std::unique_ptr<std::vector<simb::MCParticle> > larg4::ParticleListActionService::partCol_
private

Definition at line 188 of file ParticleListAction_service.h.

art::ProductID larg4::ParticleListActionService::pid_ {art::ProductID::invalid()}
private

Definition at line 191 of file ParticleListAction_service.h.

art::EDProductGetter const* larg4::ParticleListActionService::productGetter_ {nullptr}
private

Definition at line 192 of file ParticleListAction_service.h.

std::unique_ptr<art::Assns<simb::MCTruth, simb::MCParticle, sim::GeneratedParticleInfo> > larg4::ParticleListActionService::tpassn_
private

Definition at line 190 of file ParticleListAction_service.h.


The documentation for this class was generated from the following files: