LArSoft  v09_90_00
Liquid Argon Software toolkit - https://larsoft.org/
FilterGenInTime_module.cc
Go to the documentation of this file.
1 
11 
12 // Framework includes
20 #include "cetlib_except/exception.h"
21 #include "fhiclcpp/ParameterSet.h"
22 
23 // LArSoft Includes
28 
29 // C++ Includes
30 #include <cstring>
31 #include <sys/stat.h>
32 
33 // Root includes
34 #include <TMath.h>
35 
36 namespace simfilter {
37 
38  class FilterGenInTime : public art::EDFilter {
39  public:
40  explicit FilterGenInTime(fhicl::ParameterSet const& pset);
41 
42  bool filter(art::Event&);
43 
44  virtual void beginJob();
45 
46  private:
47  bool KeepParticle(simb::MCParticle const& part) const;
48 
49  std::vector<std::array<double, 6>> fCryostatBoundaries;
50  double fMinKE; //<only keep based on particles with greater than this energy
51  bool fKeepOnlyMuons; //keep based only on muons if enabled
52  double fMinT, fMaxT; //<time range in which to keep particles
53  bool fSortParticles; //create new MCTruth collections with particles sorted by their timing
54  bool fAlwaysPass; // flag to have filter always pass (to be used with sorting...)
55  };
56 
57 } // namespace simfilter
58 
59 namespace simfilter {
60 
62  : EDFilter{pset}
63  , fMinKE(pset.get<double>("MinEnergy", 0.0))
64  , fKeepOnlyMuons(pset.get<bool>("KeepOnlyMuons", false))
65  , fMinT(pset.get<double>("MinT", 0.0))
66  , fMaxT(pset.get<double>("MaxT"))
67  , fSortParticles(pset.get<bool>("SortParticles", false))
68  , fAlwaysPass(pset.get<bool>("AlwaysPass", false))
69  {
70  if (fSortParticles) {
71  produces<std::vector<simb::MCTruth>>("intime");
72  produces<std::vector<simb::MCTruth>>("outtime");
73  }
74  std::cout << "New Filter!\n";
75  }
76 
78  {
79  auto const& geom = *art::ServiceHandle<geo::Geometry const>();
80  for (auto const& cryo : geom.Iterate<geo::CryostatGeo>()) {
81  std::array<double, 6> this_cryo_boundaries{};
82  cryo.Boundaries(&this_cryo_boundaries[0]);
83  fCryostatBoundaries.push_back(this_cryo_boundaries);
84  }
85  }
86 
88  {
89  const TLorentzVector& v4 = part.Position();
90  const TLorentzVector& p4 = part.Momentum();
91  // origin of particle
92  double x0[3] = {v4.X(), v4.Y(), v4.Z()};
93  // normalized direction of particle
94  double dx[3] = {
95  p4.Px() / p4.Vect().Mag(), p4.Py() / p4.Vect().Mag(), p4.Pz() / p4.Vect().Mag()};
96 
97  // tolernace for treating number as "zero"
98  double eps = 1e-5;
99 
100  //check to see if particle crosses boundary of any cryostat within appropriate time window
101  std::vector<bool> intersects_cryo(fCryostatBoundaries.size(), false);
102  std::vector<bool> inside_cryo(fCryostatBoundaries.size(), false);
103  std::vector<double> distance_to_cryo(fCryostatBoundaries.size(), 0.);
104 
105  // Check to see if particle intersects any cryostat
106  //
107  // Algorithmically, this is looking for ray-box intersection. This is a common problem in
108  // computer graphics. The algorithm below is taken from "Graphics Gems", Academic Press, 1990
109  for (size_t i_cryo = 0; i_cryo < fCryostatBoundaries.size(); i_cryo++) {
110  auto const& bound = fCryostatBoundaries[i_cryo];
111  std::array<int, 3> quadrant{}; // 0 == RIGHT, 1 == LEFT, 2 == MIDDLE
112  std::array<double, 3> candidatePlane{};
113  std::array<double, 3> coord{};
114 
115  std::array<double, 3> bound_lo = {{bound[0], bound[2], bound[4]}};
116  std::array<double, 3> bound_hi = {{bound[1], bound[3], bound[5]}};
117 
118  // First check if origin is inside box
119  // Also check which of the two planes in each dimmension is the
120  // "candidate" for the ray to hit
121  bool inside = true;
122  for (int i = 0; i < 3; i++) {
123  if (x0[i] < bound_lo[i]) {
124  quadrant[i] = 1; // LEFT
125  candidatePlane[i] = bound_lo[i];
126  inside = false;
127  }
128  else if (x0[i] > bound_hi[i]) {
129  quadrant[i] = 0; // RIGHT
130  candidatePlane[i] = bound_hi[i];
131  inside = false;
132  }
133  else {
134  quadrant[i] = 2; // MIDDLE
135  }
136  }
137 
138  if (inside) {
139  inside_cryo[i_cryo] = true;
140  // if we're inside the cryostat, then we do intersect it
141  intersects_cryo[i_cryo] = true;
142  continue;
143  }
144 
145  // ray origin is outside the box -- calculate the distance to the cryostat and see if it intersects
146 
147  // calculate distances to candidate planes
148  std::array<double, 3> maxT{};
149  for (int i = 0; i < 3; i++) {
150  if (quadrant[i] != 2 /* MIDDLE */ && abs(dx[i]) > eps) {
151  maxT[i] = (candidatePlane[i] - x0[i]) / dx[i];
152  }
153  // if a ray origin is between two the two planes in a dimmension, it would never hit that plane first
154  else {
155  maxT[i] = -1;
156  }
157  }
158 
159  // The plane on the box that the ray hits is the one with the largest distance
160  int whichPlane = 0;
161  for (int i = 1; i < 3; i++) {
162  if (maxT[whichPlane] < maxT[i]) whichPlane = i;
163  }
164 
165  // check if the candidate intersection point is inside the box
166 
167  // no intersection
168  if (maxT[whichPlane] < 0.) {
169  intersects_cryo[i_cryo] = false;
170  continue;
171  }
172 
173  for (int i = 0; i < 3; i++) {
174  if (whichPlane != i) { coord[i] = x0[i] + maxT[whichPlane] * dx[i]; }
175  else {
176  coord[i] = candidatePlane[i];
177  }
178  }
179 
180  // check if intersection is in box
181  intersects_cryo[i_cryo] = true;
182  for (int i = 0; i < 3; i++) {
183  if (coord[i] < bound_lo[i] || coord[i] > bound_hi[i]) { intersects_cryo[i_cryo] = false; }
184  }
185 
186  if (intersects_cryo[i_cryo]) { distance_to_cryo[i_cryo] = maxT[whichPlane]; }
187  }
188 
189  // check if any cryostats are intersected in-time
190  for (size_t i_cryo = 0; i_cryo < fCryostatBoundaries.size(); i_cryo++) {
191 
192  // If the particle originates inside the cryostat, then
193  // we can't really say when it will leave. Thus, accept
194  // the particle
195  if (inside_cryo[i_cryo]) { return true; }
196  // otherwise check arrival time at boundary of cryostat
197  if (intersects_cryo[i_cryo]) {
198  double ptime = (distance_to_cryo[i_cryo] * 1e-2 /* cm -> m */) /
199  (TMath::C() * sqrt(1 - pow(part.Mass() / part.E(), 2))) /* velocity */;
200  double totT = part.T() + ptime * 1e9 /* s -> ns */;
201  if (totT > fMinT && totT < fMaxT) { return true; }
202  }
203  }
204 
205  return false;
206  }
207 
209  {
210 
211  std::unique_ptr<std::vector<simb::MCTruth>> truthInTimePtr(new std::vector<simb::MCTruth>(1));
212  std::unique_ptr<std::vector<simb::MCTruth>> truthOutOfTimePtr(
213  new std::vector<simb::MCTruth>(1));
214 
215  simb::MCTruth& truthInTime = truthInTimePtr->at(0);
216  simb::MCTruth& truthOutOfTime = truthOutOfTimePtr->at(0);
217 
218  //get the list of particles from this event
220 
221  //std::vector< art::Handle< std::vector<simb::MCTruth> > > allmclists;
222  //evt.getManyByType(allmclists);
223  auto allmclists = evt.getMany<std::vector<simb::MCTruth>>();
224  bool keepEvent = false;
225  for (size_t mcl = 0; mcl < allmclists.size(); ++mcl) {
226  art::Handle<std::vector<simb::MCTruth>> mclistHandle = allmclists[mcl];
227  for (size_t m = 0; m < mclistHandle->size(); ++m) {
228  art::Ptr<simb::MCTruth> mct(mclistHandle, m);
229 
230  for (int ipart = 0; ipart < mct->NParticles(); ipart++) {
231  bool kp = KeepParticle(mct->GetParticle(ipart));
232 
233  if (kp && (!fKeepOnlyMuons || abs(mct->GetParticle(ipart).PdgCode()) == 13) &&
234  mct->GetParticle(ipart).E() - mct->GetParticle(ipart).Mass() > fMinKE) {
235  keepEvent = true;
236  if (!fSortParticles) break;
237  }
238 
239  if (fSortParticles) {
240  simb::MCParticle particle = mct->GetParticle(ipart);
241  if (kp) truthInTime.Add(particle);
242  if (!kp) truthOutOfTime.Add(particle);
243  }
244 
245  } //end loop over particles
246 
247  if (!fSortParticles && keepEvent) break;
248 
249  } //end loop over mctruth col
250 
251  if (!fSortParticles && keepEvent) break;
252 
253  } //end loop over all mctruth lists
254 
255  if (fSortParticles) {
256  evt.put(std::move(truthInTimePtr), "intime");
257  evt.put(std::move(truthOutOfTimePtr), "outtime");
258  }
259 
260  return (keepEvent || fAlwaysPass);
261  }
262 
263 } // namespace simfilter
264 
265 namespace simfilter {
266 
268 
269 } // namespace simfilter
double E(const int i=0) const
Definition: MCParticle.h:234
const TLorentzVector & Position(const int i=0) const
Definition: MCParticle.h:220
int PdgCode() const
Definition: MCParticle.h:213
Int_t ipart
Definition: Style.C:10
auto coord(Vector &v, unsigned int n) noexcept
Returns an object to manage the coordinate n of a vector.
double Mass() const
Definition: MCParticle.h:240
std::vector< std::array< double, 6 > > fCryostatBoundaries
boundaries of each cryostat
constexpr auto abs(T v)
Returns the absolute value of the argument.
int NParticles() const
Definition: MCTruth.h:75
Geometry information for a single cryostat.
Definition: CryostatGeo.h:43
PutHandle< PROD > put(std::unique_ptr< PROD > &&edp, std::string const &instance={})
Definition: Event.h:77
TString part[npart]
Definition: Style.C:32
#define DEFINE_ART_MODULE(klass)
Definition: ModuleMacros.h:65
double T(const int i=0) const
Definition: MCParticle.h:225
FilterGenInTime(fhicl::ParameterSet const &pset)
const simb::MCParticle & GetParticle(int i) const
Definition: MCTruth.h:76
void Add(simb::MCParticle const &part)
Definition: MCTruth.h:80
const TLorentzVector & Momentum(const int i=0) const
Definition: MCParticle.h:221
EDFilter(fhicl::ParameterSet const &pset)
Definition: EDFilter.cc:6
bool KeepParticle(simb::MCParticle const &part) const
TCEvent evt
Definition: DataStructs.cxx:8
Event generator information.
Definition: MCTruth.h:32
Framework includes.
Particle list in DetSim contains Monte Carlo particle information.
Float_t e
Definition: plot.C:35
Tools and modules for checking out the basics of the Monte Carlo.
art framework interface to geometry description
std::vector< Handle< PROD > > getMany(SelectorBase const &selector=MatchAllSelector{}) const