All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
LArG4ParticleFilter_module.cc
Go to the documentation of this file.
1 //Author: Dom Brailsford
2 //An ART filter that selects events which contain 'interesting' simb::MCParticles. Interesting is user-defined.
3 //The filter parameters are FHICL configurable but can select based on, momentum, particle flavour, TPC trajectory length and whether the particle stops/starts in the TPC.
4 //The user can ask for events which contain multiple types of interesting particles, each with their own requirements.
5 
6 //ART
7 #include "art/Framework/Core/EDFilter.h"
8 #include "art/Framework/Core/ModuleMacros.h"
9 #include "art/Framework/Principal/Event.h"
10 #include "art/Framework/Services/Registry/ServiceHandle.h"
11 
12 //LArSoft
15 #include "nusimdata/SimulationBase/MCParticle.h"
16 
17 // ROOT
18 #include "TLorentzVector.h"
19 #include "TVector3.h"
20 
21 namespace filt{
22 
23  class LArG4ParticleFilter : public art::EDFilter {
24  public:
25  explicit LArG4ParticleFilter(fhicl::ParameterSet const & pset);
26  virtual bool filter(art::Event& e);
27 
28  private:
29 
30  bool IsInterestingParticle(const art::Ptr<simb::MCParticle> &particle, const unsigned int index) const;
31  bool PDGCheck(const art::Ptr<simb::MCParticle> &particle, const unsigned int index) const;
32  bool IsPrimaryCheck(const art::Ptr<simb::MCParticle> &particle, const unsigned int index) const;
33  bool MinMomentumCheck(const art::Ptr<simb::MCParticle> &particle, const unsigned int index) const;
34  bool MaxMomentumCheck(const art::Ptr<simb::MCParticle> &particle, const unsigned int index) const;
35  bool StartInTPCCheck(const art::Ptr<simb::MCParticle> &particle, const unsigned int index) const;
36  bool StopInTPCCheck(const art::Ptr<simb::MCParticle> &particle, const unsigned int index) const;
37  bool TPCTrajLengthCheck(const art::Ptr<simb::MCParticle> &particle, const unsigned int index) const;
38 
39  double CalculateLength(const std::vector<TVector3> &position_segment) const;
40 
41  void VerifyDataMembers() const;
42  void VerifyElementRequest(const unsigned int index) const;
43 
44  art::ServiceHandle<geo::Geometry const> fGeom;
45 
46  const std::string fLArG4ModuleLabel;
47  const std::vector<int> fInterestingPDGs;
48  const std::vector<int> fIsPrimary;
49  const std::vector<double> fParticleMinMomentum;
50  const std::vector<double> fParticleMaxMomentum;
51  const std::vector<int> fStartInTPC;
52  const std::vector<int> fStopInTPC;
53  const std::vector<double> fParticleMinTPCLength;
55 
56  std::vector<bool> fFoundInterestingParticles;
57 
58  };
59 
60  LArG4ParticleFilter::LArG4ParticleFilter::LArG4ParticleFilter(fhicl::ParameterSet const & pset) :
61  EDFilter{pset},
62  fLArG4ModuleLabel(pset.get<std::string>("LArG4ModuleLabel")),
63  fInterestingPDGs(pset.get<std::vector<int> >("InterestingPDGs")),
64  fIsPrimary(pset.get<std::vector<int> >("IsPrimary")),
65  fParticleMinMomentum(pset.get<std::vector<double> >("ParticleMinMomentum")),
66  fParticleMaxMomentum(pset.get<std::vector<double> >("ParticleMaxMomentum")),
67  fStartInTPC(pset.get<std::vector<int> >("StartInTPC")),
68  fStopInTPC(pset.get<std::vector<int> >("StopInTPC")),
69  fParticleMinTPCLength(pset.get<std::vector<double> >("ParticleMinTPCLength")),
70  fRequireAllInterestingParticles(pset.get<bool>("RequireAllInterestingParticles")),
71  fFoundInterestingParticles(fInterestingPDGs.size(), false)
72  {
73  VerifyDataMembers();
74  }
75 
76  bool LArG4ParticleFilter::filter(art::Event & e)
77  {
78  //Reset the found vector
79  for (unsigned int i = 0; i < fFoundInterestingParticles.size(); i++){
80  fFoundInterestingParticles[i] = false;
81  }
82 
83  //Get the vector of particles
84  art::Handle<std::vector<simb::MCParticle> > particles;
85  e.getByLabel(fLArG4ModuleLabel, particles);
86  //Loop through the particles
87  for (unsigned int part_i = 0; part_i < particles->size(); part_i++){
88  //Get the particle
89  const art::Ptr<simb::MCParticle> particle(particles,part_i);
90  //Loop over the list of particles we want and compare it with the particle we are looking it
91  for (unsigned int interest_i = 0; interest_i < fInterestingPDGs.size(); interest_i++){
92  if (IsInterestingParticle(particle,interest_i)) {
93  if (!fRequireAllInterestingParticles) return true; //If we only require at least one of the particles be found then we have already done our job
94  fFoundInterestingParticles[interest_i] = true;
95  bool foundThemAll = true;
96  for (unsigned int found_i = 0; found_i < fFoundInterestingParticles.size(); found_i++){
97  if (fFoundInterestingParticles[found_i] == false){
98  foundThemAll = false;
99  break;
100  }
101  }
102  if (foundThemAll){
103  return true;
104  }
105  }
106  }
107  }
108  //Assume that the event is not worth saving
109  return false;
110  }
111 
112  bool LArG4ParticleFilter::IsInterestingParticle(const art::Ptr<simb::MCParticle> &particle, const unsigned int index) const
113  {
114  VerifyElementRequest(index);
115  //Run the checks
116  if (!PDGCheck(particle,index)) return false;
117  if (!IsPrimaryCheck(particle,index)) return false;
118  if (!MinMomentumCheck(particle,index)) return false;
119  if (!MaxMomentumCheck(particle,index)) return false;
120  if (!StartInTPCCheck(particle,index)) return false;
121  if (!StopInTPCCheck(particle,index)) return false;
122  if (!TPCTrajLengthCheck(particle,index)) return false;
123 
124  return true;
125  }
126 
127  bool LArG4ParticleFilter::PDGCheck(const art::Ptr<simb::MCParticle> &particle, const unsigned int index) const
128  {
129  int pdg = fInterestingPDGs[index];
130  if (pdg == 0) return true; //User does not care what the PDG is
131  if (particle->PdgCode() != pdg) return false;
132  return true;
133  }
134 
135  bool LArG4ParticleFilter::IsPrimaryCheck(const art::Ptr<simb::MCParticle> &particle, const unsigned int index) const
136  {
137  const int isPrimaryCondition(fIsPrimary[index]);
138  if (isPrimaryCondition==-1) return true;
139  bool particlePrimaryStatus(particle->Mother() > 0 ? false: true);
140  if (particlePrimaryStatus != isPrimaryCondition) return false;
141  return true;
142  }
143 
144  bool LArG4ParticleFilter::MinMomentumCheck(const art::Ptr<simb::MCParticle> &particle, const unsigned int index) const
145  {
146  if (fParticleMinMomentum[index] > 0 && particle->Momentum(0).Vect().Mag() < fParticleMinMomentum[index]) return false;
147  return true;
148  }
149 
150  bool LArG4ParticleFilter::MaxMomentumCheck(const art::Ptr<simb::MCParticle> &particle, const unsigned int index) const
151  {
152  if (fParticleMaxMomentum[index] > 0 && particle->Momentum(0).Vect().Mag() > fParticleMaxMomentum[index]) return false;
153  return true;
154  }
155 
156  bool LArG4ParticleFilter::StartInTPCCheck(const art::Ptr<simb::MCParticle> &particle, const unsigned int index) const
157  {
158  //Firstly check if we even care if the particle starts in the TPC or not
159  int demand = fStartInTPC[index];
160  if (demand == 0) return true; //We don't care if the particle starts in the TPC or not so pass the check
161  //Get starting position of particle
162  TLorentzVector starting_position_4vect = particle->Position(0);
163  double starting_position[3];
164  starting_position[0] = starting_position_4vect.X();
165  starting_position[1] = starting_position_4vect.Y();
166  starting_position[2] = starting_position_4vect.Z();
167 
168  geo::TPCID tpcid = fGeom->FindTPCAtPosition(starting_position);
169  bool validtpc = tpcid.isValid;
170  //Now we need to compare if we have a TPC that we started in with whether we wanted to start in a TPC at all
171  if (validtpc){
172  //The particle DID start in a TPC. Now, did we WANT this to happen
173  if (demand == 1) return true; //We DID want this to happen
174  else return false;
175  }
176  else{
177  //The particle did NOT start in a TPC. Did we WANT this to happen?
178  if (demand == 2) return true; //We DID want this to happen
179  else return false;
180  }
181 
182  //Assume true by default
183  return true;
184  }
185 
186 
187  bool LArG4ParticleFilter::StopInTPCCheck(const art::Ptr<simb::MCParticle> &particle, const unsigned int index) const
188  {
189  //Firstly check if we even care if the particle stops in the TPC or not
190  int demand = fStopInTPC[index];
191  if (demand == 0) return true; //We don't care if the particle stops in the TPC or not so pass the check
192  //Get final position of particle
193  TLorentzVector final_position_4vect = particle->Position(particle->NumberTrajectoryPoints()-1);
194  double final_position[3];
195  final_position[0] = final_position_4vect.X();
196  final_position[1] = final_position_4vect.Y();
197  final_position[2] = final_position_4vect.Z();
198 
199  geo::TPCID tpcid = fGeom->FindTPCAtPosition(final_position);
200  bool validtpc = tpcid.isValid;
201  //Now we need to compare if we have a TPC that we stopped in with whether we wanted to stop in a TPC at all
202  if (validtpc){
203  //The particle DID stop in a TPC. Now, did we WANT this to happen
204  if (demand == 1) return true; //We DID want this to happen
205  else return false;
206  }
207  else{
208  //The particle did NOT stop in a TPC. Did we WANT this to happen?
209  if (demand == 2) return true; //We DID want this to happen
210  else return false;
211  }
212 
213  //Assume true by default
214  return true;
215  }
216 
217  bool LArG4ParticleFilter::TPCTrajLengthCheck(const art::Ptr<simb::MCParticle> &particle, const unsigned int index) const
218  {
219  double min_traj_length = fParticleMinTPCLength[index];
220 
221  //Firstly, if we don't care about the TPC trajectory length then pass the check
222  if (min_traj_length < 0) return true;
223 
224  //Now the hard bit
225  //To do this, we need to collect the sequential particle positions which are contained in the TPC into segments. The reason for doing this is that the particle may enter a TPC, leave it and enter it again and if this isn't taken into account, the length might be grossly overestimated
226  //It is easiest to store the positions in a vector of vectors
227  bool OK = false;
228  std::vector< std::vector<TVector3> > position_segments;
229  //We are also going to need an empty vector to store in the above vector
230  std::vector<TVector3> position_segment;
231  //Loop through the trajectory points
232  for (unsigned int i = 0; i < particle->NumberTrajectoryPoints(); i++){
233  //Extract the current position of the particle
234  double curr_pos[3];
235  curr_pos[0] = particle->Position(i).X();
236  curr_pos[1] = particle->Position(i).Y();
237  curr_pos[2] = particle->Position(i).Z();
238  geo::TPCID curr_tpcid = fGeom->FindTPCAtPosition(curr_pos);
239  //There are a couple of things to check here. If the particle is currently in the TPC, then we need to store that particular position. If it is NOT in the TPC, then its either exited the TPC or has not yet entered. If it has just exited, then the position_segment should have some positions stored in it, it which case we now need to store this segment. If it has not yet entered the TPC, then we don't need to do anything
240  //If it is currently in the TPC
241  if (curr_tpcid.isValid) position_segment.push_back(particle->Position(i).Vect());
242  //It has just exited the TPC
243  else if (position_segment.size() > 0){
244  //Store the segment
245  position_segments.push_back(position_segment);
246  //Now reset the segment
247  position_segment.clear();
248  }
249  //There is nothing to do because the particle has remained outside of the TPC
250  }
251  //We need to check once more if the position_segment vector has been filled
252  if (position_segment.size() > 0){
253  position_segments.push_back(position_segment);
254  position_segment.clear();
255  }
256  //Now lets check the length of each segment
257  //Firstly, if we didn't store a segment then the particle fails the check
258  if (position_segments.size() == 0) return false;
259  //Now loop through the segments and check if they are above threshold
260  for (unsigned int i = 0; i < position_segments.size(); i++){
261  double segment_length = CalculateLength(position_segments[i]);
262  if (segment_length > min_traj_length){
263  //We found a track segment in the TPC which passes the length threshold so don't flag as bad
264  OK = true;
265  break;
266  }
267  }
268  if (!OK) return false;
269 
270  return true;
271  }
272 
273  double LArG4ParticleFilter::CalculateLength(const std::vector<TVector3> &position_segment) const
274  {
275  double length = 0;
276  //Check how many points we have in the segment. If it is one or less, there is nothing to calculate so return 0
277  if (position_segment.size() <= 1) return length;
278 
279  //Now we need to compare every adjacent pair of positions to work out the length of this segment
280  for (unsigned int i = 1; i < position_segment.size(); i++){
281  length += (position_segment[i] - position_segment[i-1]).Mag();
282  }
283 
284  return length;
285  }
286 
288  {
289  if (fInterestingPDGs.size() != fIsPrimary.size())
290  throw art::Exception(art::errors::Configuration) << "Config error: InterestingPDGs and IsPrimary FCL vectors are different sizes\n";
291  if (fInterestingPDGs.size() != fParticleMinMomentum.size())
292  throw art::Exception(art::errors::Configuration) << "Config error: InterestingPDGs and ParticleMinMomentum FCL vectors are different sizes\n";
293  if (fInterestingPDGs.size() != fParticleMaxMomentum.size())
294  throw art::Exception(art::errors::Configuration) << "Config error: InterestingPDGs and ParticleMaxMomentum FCL vectors are different sizes\n";
295  if (fInterestingPDGs.size() != fStartInTPC.size())
296  throw art::Exception(art::errors::Configuration) << "Config error: InterestingPDGs and StartInTPC FCL vectors are different sizes\n";
297  if (fInterestingPDGs.size() != fStopInTPC.size())
298  throw art::Exception(art::errors::Configuration) << "Config error: InterestingPDGs and StopInTPC FCL vectors are different sizes\n";
299  if (fInterestingPDGs.size() != fParticleMinTPCLength.size())
300  throw art::Exception(art::errors::Configuration) << "Config error: InterestingPDGs and ParticleMinTPCLength FCL vectors are different sizes\n";
301 
302  for (unsigned int iIsPrimary = 0; iIsPrimary < fIsPrimary.size(); iIsPrimary++)
303  if (!(-1 == fIsPrimary[iIsPrimary] || 0 == fIsPrimary[iIsPrimary] || 1 == fIsPrimary[iIsPrimary]))
304  throw art::Exception(art::errors::Configuration) << "Config error: Element " << iIsPrimary << " of the IsPrimary vector equals "
305  << fIsPrimary[iIsPrimary] << ". Valid options are -1 (not set), 0 (not primary) or 1 (is primary)" << std::endl;
306 
307  for (unsigned int iStartInTPC = 0; iStartInTPC < fStartInTPC.size(); iStartInTPC++)
308  if (!(0 == fStartInTPC[iStartInTPC] || 1 == fStartInTPC[iStartInTPC] || 2 == fStartInTPC[iStartInTPC]))
309  throw art::Exception(art::errors::Configuration) << "Config error: Element " << iStartInTPC << " of the StartInTPC vector equals "
310  << fStartInTPC[iStartInTPC] << ". Valid options are 0 (not set), 1 (start in TPC) or 2 (do not start in TPC)" << std::endl;
311 
312  for (unsigned int iStopInTPC = 0; iStopInTPC < fStopInTPC.size(); iStopInTPC++)
313  if (!(0 == fStopInTPC[iStopInTPC] || 1 == fStopInTPC[iStopInTPC] || 2 == fStopInTPC[iStopInTPC]))
314  throw art::Exception(art::errors::Configuration) << "Config error: Element " << iStopInTPC << " of the StopInTPC vector equals "
315  << fStopInTPC[iStopInTPC] << ". Valid options are 0 (not set), 1 (stop in TPC) or 2 (do not stop in TPC)" << std::endl;
316 
317  return;
318  }
319 
320  void LArG4ParticleFilter::VerifyElementRequest(const unsigned int index) const
321  {
322  if (index > fInterestingPDGs.size())
323  throw art::Exception(art::errors::InvalidNumber) << "Bounds error: Requested element " << index <<" from InterestingPDGs vector which is size "
324  << fInterestingPDGs.size() << "\n";
325  if (index > fIsPrimary.size())
326  throw art::Exception(art::errors::InvalidNumber) << "Bounds error: Requested element " << index <<" from IsPrimary vector which is size "
327  << fIsPrimary.size() << "\n";
328  if (index > fParticleMinMomentum.size())
329  throw art::Exception(art::errors::InvalidNumber) << "Bounds error: Requested element " << index <<" from ParticleMinMomentum vector which is size "
330  << fParticleMinMomentum.size() << "\n";
331  if (index > fParticleMaxMomentum.size())
332  throw art::Exception(art::errors::InvalidNumber) << "Bounds error: Requested element " << index <<" from ParticleMaxMomentum vector which is size "
333  << fParticleMaxMomentum.size() << "\n";
334  if (index > fStartInTPC.size())
335  throw art::Exception(art::errors::InvalidNumber) << "Bounds error: Requested element " << index <<" from StartInTPC vector which is size "
336  << fStartInTPC.size() << "\n";
337  if (index > fStopInTPC.size())
338  throw art::Exception(art::errors::InvalidNumber) << "Bounds error: Requested element " << index <<" from StopInTPC vector which is size "
339  << fStopInTPC.size() << "\n";
340  if (index > fParticleMinTPCLength.size())
341  throw art::Exception(art::errors::InvalidNumber) << "Bounds error: Requested element " << index <<" from ParticleMinTPCLength vector which is size "
342  << fParticleMinTPCLength.size() << "\n";
343  return;
344  }
345  DEFINE_ART_MODULE(LArG4ParticleFilter)
346 }
var pdg
Definition: selectors.fcl:14
std::vector< bool > fFoundInterestingParticles
bool IsInterestingParticle(const art::Ptr< simb::MCParticle > &particle, const unsigned int index) const
art::ServiceHandle< geo::Geometry const > fGeom
bool isValid
Whether this ID points to a valid element.
Definition: geo_types.h:211
double CalculateLength(const std::vector< TVector3 > &position_segment) const
const std::vector< int > fInterestingPDGs
bool IsPrimaryCheck(const art::Ptr< simb::MCParticle > &particle, const unsigned int index) const
const std::vector< double > fParticleMaxMomentum
bool MaxMomentumCheck(const art::Ptr< simb::MCParticle > &particle, const unsigned int index) const
void VerifyElementRequest(const unsigned int index) const
bool StartInTPCCheck(const art::Ptr< simb::MCParticle > &particle, const unsigned int index) const
bool MinMomentumCheck(const art::Ptr< simb::MCParticle > &particle, const unsigned int index) const
bool TPCTrajLengthCheck(const art::Ptr< simb::MCParticle > &particle, const unsigned int index) const
The data type to uniquely identify a TPC.
Definition: geo_types.h:386
const std::vector< int > fStopInTPC
Definition of data types for geometry description.
const std::vector< double > fParticleMinMomentum
const std::vector< int > fIsPrimary
then filt
const std::vector< double > fParticleMinTPCLength
do i e
virtual bool filter(art::Event &e)
const std::vector< int > fStartInTPC
art framework interface to geometry description
bool PDGCheck(const art::Ptr< simb::MCParticle > &particle, const unsigned int index) const
bool StopInTPCCheck(const art::Ptr< simb::MCParticle > &particle, const unsigned int index) const
LArG4ParticleFilter(fhicl::ParameterSet const &pset)