TrackKalmanCheater_module.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 // Class: TrackKalmanCheater
3 // Module Type: producer
4 // File: TrackKalmanCheater.h
5 //
6 // This class produces RecoBase/Track objects using KalmanFilterService.
7 // MC truth information is used to associate Hits used as input to
8 // the Kalman filter.
9 //
10 // Configuration parameters:
11 //
12 // Hist - Histogram flag (generate histograms if true).
13 // UseClusterHits - Use clustered hits if true, use all hits if false.
14 // HitModuleLabel - Module label for unclustered Hits.
15 // ClusterModuleLabel - Module label for Clusters.
16 // MaxTcut - Maximum delta ray energy in Mev for dE/dx.
17 // KalmanFilterAlg - Parameter set for KalmanFilterAlg.
18 // SpacePointAlg - Parmaeter set for space points.
19 //
20 ////////////////////////////////////////////////////////////////////////
21 
22 #include <deque>
23 
26 #include "art_root_io/TFileService.h"
27 #include "canvas/Persistency/Common/FindManyP.h"
28 #include "cetlib_except/exception.h"
30 
47 
48 #include "TH1F.h"
49 
50 namespace {
51  bool
52  accepted_particle(int apdg)
53  {
54  return apdg == 13 || // Muon
55  apdg == 211 || // Charged pion
56  apdg == 321 || // Charged kaon
57  apdg == 2212; // (Anti)proton
58  }
59 }
60 
61 namespace trkf {
62 
64  public:
65  explicit TrackKalmanCheater(fhicl::ParameterSet const& pset);
66 
67  private:
68  void produce(art::Event& e) override;
69  void beginJob() override;
70  void endJob() override;
71 
72  // Fcl parameters.
73 
74  bool fHist; ///< Make histograms.
75  KalmanFilterAlg fKFAlg; ///< Kalman filter algorithm.
76  SpacePointAlg fSpacePointAlg; ///< Space point algorithm.
77  bool fUseClusterHits; ///< Use cluster hits or all hits?
78  std::string fHitModuleLabel; ///< Unclustered Hits.
79  std::string fClusterModuleLabel; ///< Clustered Hits.
80  double fMaxTcut; ///< Maximum delta ray energy in MeV for restricted dE/dx.
81 
82  // Histograms.
83 
84  TH1F* fHIncChisq{nullptr}; ///< Incremental chisquare.
85  TH1F* fHPull{nullptr}; ///< Hit pull.
86 
87  // Statistics.
88 
89  int fNumEvent{0}; ///< Number of events seen.
90  int fNumTrack{0}; ///< Number of tracks produced.
91  };
92 
94 
95 } // namespace trkf
96 
97 //------------------------------------------------------------------------------
98 /// Constructor.
99 ///
100 /// Arguments:
101 ///
102 /// p - Fcl parameters.
103 ///
105  : EDProducer{pset}
106  , fHist(pset.get<bool>("Hist"))
107  , fKFAlg(pset.get<fhicl::ParameterSet>("KalmanFilterAlg"))
108  , fSpacePointAlg(pset.get<fhicl::ParameterSet>("SpacePointAlg"))
109  , fUseClusterHits(pset.get<bool>("UseClusterHits"))
110  , fHitModuleLabel{pset.get<std::string>("HitModuleLabel")}
111  , fClusterModuleLabel{pset.get<std::string>("ClusterModuleLabel")}
112  , fMaxTcut(pset.get<double>("MaxTcut"))
113 {
114  produces<std::vector<recob::Track>>();
115  produces<std::vector<recob::SpacePoint>>();
116  produces<art::Assns<recob::Track, recob::Hit>>();
117  produces<art::Assns<recob::Track, recob::SpacePoint>>();
118  produces<art::Assns<recob::SpacePoint, recob::Hit>>();
119 
120  // Report.
121 
122  mf::LogInfo("TrackKalmanCheater")
123  << "TrackKalmanCheater configured with the following parameters:\n"
124  << " UseClusterHits = " << fUseClusterHits << "\n"
125  << " HitModuleLabel = " << fHitModuleLabel << "\n"
126  << " ClusterModuleLabel = " << fClusterModuleLabel;
127 }
128 
129 //------------------------------------------------------------------------------
130 /// Begin job method.
131 void
133 {
134  if (fHist) {
135 
136  // Book histograms.
137 
139  art::TFileDirectory dir = tfs->mkdir("hitkalman", "TrackKalmanCheater histograms");
140 
141  fHIncChisq = dir.make<TH1F>("IncChisq", "Incremental Chisquare", 100, 0., 20.);
142  fHPull = dir.make<TH1F>("Pull", "Hit Pull", 100, -10., 10.);
143  }
144 }
145 
146 //------------------------------------------------------------------------------
147 /// Produce method.
148 ///
149 /// Arguments:
150 ///
151 /// e - Art event.
152 ///
153 /// This method extracts Hit from the event and produces and adds
154 /// Track objects.
155 ///
156 void
158 {
159  ++fNumEvent;
160 
161  // Make a collection of tracks, plus associations, that will
162  // eventually be inserted into the event.
163 
164  std::unique_ptr<std::vector<recob::Track>> tracks(new std::vector<recob::Track>);
165  std::unique_ptr<art::Assns<recob::Track, recob::Hit>> th_assn(
167  std::unique_ptr<art::Assns<recob::Track, recob::SpacePoint>> tsp_assn(
169 
170  // Make a collection of space points, plus associations, that will
171  // be inserted into the event.
172 
173  std::unique_ptr<std::vector<recob::SpacePoint>> spts(new std::vector<recob::SpacePoint>);
174  std::unique_ptr<art::Assns<recob::SpacePoint, recob::Hit>> sph_assn(
176 
177  // Make a collection of KGTracks where we will save our results.
178 
179  std::deque<KGTrack> kalman_tracks;
180 
181  // Get Services.
182 
186  auto const clockData = art::ServiceHandle<detinfo::DetectorClocksService const>()->DataFor(evt);
187 
188  // Reset space point algorithm.
189 
191 
192  // Get Hits.
193 
195 
196  if (fUseClusterHits) {
197 
198  // Get clusters.
199 
201  evt.getByLabel(fClusterModuleLabel, clusterh);
202 
203  // Get hits from all clusters.
204  art::FindManyP<recob::Hit> fm(clusterh, evt, fClusterModuleLabel);
205 
206  if (clusterh.isValid()) {
207  int nclus = clusterh->size();
208 
209  for (int i = 0; i < nclus; ++i) {
210  art::Ptr<recob::Cluster> pclus(clusterh, i);
211  std::vector<art::Ptr<recob::Hit>> clushits = fm.at(i);
212  int nhits = clushits.size();
213  hits.reserve(hits.size() + nhits);
214 
215  for (std::vector<art::Ptr<recob::Hit>>::const_iterator ihit = clushits.begin();
216  ihit != clushits.end();
217  ++ihit) {
218  hits.push_back(*ihit);
219  }
220  }
221  }
222  }
223  else {
224 
225  // Get unclustered hits.
226 
228  evt.getByLabel(fHitModuleLabel, hith);
229  if (hith.isValid()) {
230  int nhits = hith->size();
231  hits.reserve(nhits);
232 
233  for (int i = 0; i < nhits; ++i)
234  hits.push_back(art::Ptr<recob::Hit>(hith, i));
235  }
236  }
237 
238  // Sort hits into separate PtrVectors based on track id.
239 
240  std::map<int, art::PtrVector<recob::Hit>> hitmap;
241 
242  // Loop over hits.
243 
244  for (art::PtrVector<recob::Hit>::const_iterator ihit = hits.begin(); ihit != hits.end(); ++ihit) {
245  //const recob::Hit& hit = **ihit;
246 
247  // Get track ids for this hit.
248 
249  std::vector<sim::TrackIDE> tids = bt_serv->HitToTrackIDEs(clockData, *ihit);
250 
251  // Loop over track ids.
252 
253  for (std::vector<sim::TrackIDE>::const_iterator itid = tids.begin(); itid != tids.end();
254  ++itid) {
255  int trackID = itid->trackID;
256 
257  // Add hit to PtrVector corresponding to this track id.
258 
259  hitmap[trackID].push_back(*ihit);
260  }
261  }
262 
263  // Extract geant mc particles.
264 
265  sim::ParticleList const& plist = pi_serv->ParticleList();
266 
267  auto const det_prop =
269 
270  PropYZPlane const prop{det_prop, fMaxTcut, true};
271 
272  // Loop over geant particles.
273 
274  {
275  // use mf::LogDebug instead of MF_LOG_DEBUG because we reuse it in many lines;
276  // insertions are protected by mf::isDebugEnabled()
277  mf::LogDebug log("TrackKalmanCheater");
278  for (sim::ParticleList::const_iterator ipart = plist.begin(); ipart != plist.end(); ++ipart) {
279  const simb::MCParticle* part = (*ipart).second;
280  if (!part) throw cet::exception("TrackKalmanCheater") << "no particle!\n";
281  int pdg = part->PdgCode();
282 
283  // Ignore everything except stable charged nonshowering particles.
284 
285  int apdg = std::abs(pdg);
286  if (not accepted_particle(apdg)) { continue; }
287 
288  int trackid = part->TrackId();
289  int stat = part->StatusCode();
290  int nhit = 0;
291  if (hitmap.count(trackid) != 0) nhit = hitmap[trackid].size();
292  const TLorentzVector& pos = part->Position();
293  const TLorentzVector& mom = part->Momentum();
294 
295  if (mf::isDebugEnabled()) {
296  log << "Trackid=" << trackid << ", pdgid=" << pdg << ", status=" << stat
297  << ", NHit=" << nhit << "\n"
298  << " x = " << pos.X() << ", y = " << pos.Y() << ", z = " << pos.Z() << "\n"
299  << " px= " << mom.Px() << ", py= " << mom.Py() << ", pz= " << mom.Pz() << "\n";
300  } // if debugging
301 
302  double x = pos.X();
303  double y = pos.Y();
304  double z = pos.Z();
305  double px = mom.Px();
306  double py = mom.Py();
307  double pz = mom.Pz();
308  double p = std::hypot(px, py, pz);
309 
310  if (nhit > 0 && pz != 0.) {
311  const art::PtrVector<recob::Hit>& trackhits = hitmap[trackid];
312  if (trackhits.empty()) throw cet::exception("TrackKalmanCheater") << "No hits in track\n";
313 
314  // Make a seed track (KTrack).
315 
316  std::shared_ptr<const Surface> psurf(new SurfYZPlane(0., y, z, 0.));
317  TrackVector vec(5);
318  vec(0) = x;
319  vec(1) = 0.;
320  vec(2) = px / pz;
321  vec(3) = py / pz;
322  vec(4) = 1. / p;
324  KTrack trk(psurf, vec, dir, pdg);
325 
326  // Fill KHitContainer with hits.
327 
328  KHitContainerWireX cont;
329  cont.fill(det_prop, trackhits, -1);
330 
331  // Count hits in each plane. Set the preferred plane to be
332  // the one with the most hits.
333 
334  std::vector<unsigned int> planehits(3, 0);
336  ih != trackhits.end();
337  ++ih) {
338  const recob::Hit& hit = **ih;
339  unsigned int plane = hit.WireID().Plane;
340 
341  if (plane >= planehits.size()) {
342  throw cet::exception("TrackKalmanCheater") << "plane " << plane << "...\n";
343  }
344  ++planehits[plane];
345  }
346  unsigned int prefplane = 0;
347  for (unsigned int i = 0; i < planehits.size(); ++i) {
348  if (planehits[i] > planehits[prefplane]) prefplane = i;
349  }
350  if (mf::isDebugEnabled()) log << "Preferred plane = " << prefplane << "\n";
351 
352  // Build and smooth track.
353 
354  KGTrack trg(prefplane);
355  fKFAlg.setPlane(prefplane);
356  if (fKFAlg.buildTrack(trk, trg, prop, Propagator::FORWARD, cont, false)) {
357  if (fKFAlg.smoothTrackIter(5, trg, prop)) {
358  KETrack tremom;
359  if (fKFAlg.fitMomentum(trg, prop, tremom)) { fKFAlg.updateMomentum(tremom, prop, trg); }
360  ++fNumTrack;
361  kalman_tracks.push_back(trg);
362  }
363  }
364  }
365  }
366  }
367 
368  // Fill histograms.
369 
370  if (fHist) {
371 
372  // First loop over tracks.
373 
374  for (auto const& trg : kalman_tracks) {
375 
376  // Loop over measurements in this track.
377 
378  const std::multimap<double, KHitTrack>& trackmap = trg.getTrackMap();
380  ih != trackmap.end();
381  ++ih) {
382  const KHitTrack& trh = (*ih).second;
383  const std::shared_ptr<const KHitBase>& hit = trh.getHit();
384  double chisq = hit->getChisq();
385  fHIncChisq->Fill(chisq);
386  const KHit<1>* ph1 = dynamic_cast<const KHit<1>*>(&*hit);
387  if (ph1 != 0) {
388  double pull = ph1->getResVector()(0) / std::sqrt(ph1->getResError()(0, 0));
389  fHPull->Fill(pull);
390  }
391  }
392  }
393  }
394 
395  // Process Kalman filter tracks into persistent objects.
396 
397  tracks->reserve(kalman_tracks.size());
398  for (auto const& kalman_track : kalman_tracks) {
399  tracks->push_back(recob::Track());
400  kalman_track.fillTrack(det_prop, tracks->back(), tracks->size() - 1);
401 
402  // Make Track to Hit associations.
403 
405  std::vector<unsigned int> hittpindex;
406  kalman_track.fillHits(hits, hittpindex);
407  util::CreateAssn(evt, *tracks, trhits, *th_assn, tracks->size() - 1);
408 
409  // Make space points from this track.
410 
411  int nspt = spts->size();
412  fSpacePointAlg.fillSpacePoints(det_prop, *spts, kalman_track.TrackMap());
413 
414  // Associate newly created space points with hits.
415  // Also associate track with newly created space points.
416 
418 
419  // Loop over newly created space points.
420 
421  for (unsigned int ispt = nspt; ispt < spts->size(); ++ispt) {
422  const recob::SpacePoint& spt = (*spts)[ispt];
423  art::ProductID sptid = evt.getProductID<std::vector<recob::SpacePoint>>();
424  art::Ptr<recob::SpacePoint> sptptr(sptid, ispt, evt.productGetter(sptid));
425  sptvec.push_back(sptptr);
426 
427  // Make space point to hit associations.
428 
430  util::CreateAssn(evt, *spts, sphits, *sph_assn, ispt);
431  }
432 
433  // Make track to space point associations.
434 
435  util::CreateAssn(evt, *tracks, sptvec, *tsp_assn, tracks->size() - 1);
436  }
437 
438  // Add tracks and associations to event.
439 
440  evt.put(std::move(tracks));
441  evt.put(std::move(spts));
442  evt.put(std::move(th_assn));
443  evt.put(std::move(tsp_assn));
444  evt.put(std::move(sph_assn));
445 }
446 
447 //------------------------------------------------------------------------------
448 /// End job method.
449 void
451 {
452  mf::LogInfo("TrackKalmanCheater") << "TrackKalmanCheater statistics:\n"
453  << " Number of events = " << fNumEvent << "\n"
454  << " Number of tracks created = " << fNumTrack;
455 }
void endJob() override
End job method.
void reserve(size_type n)
Definition: PtrVector.h:337
TrackDirection
Track direction enum.
Definition: Surface.h:56
const std::shared_ptr< const KHitBase > & getHit() const
Measurement.
Definition: KHitTrack.h:53
const TLorentzVector & Position(const int i=0) const
Definition: MCParticle.h:219
int PdgCode() const
Definition: MCParticle.h:212
Propagate to PropYZPlane surface.
void fill(const detinfo::DetectorPropertiesData &clock_data, const art::PtrVector< recob::Hit > &hits, int only_plane) override
ProductID getProductID(std::string const &instance_name="") const
Definition: DataViewImpl.h:338
A KHitContainer for KHitWireX type measurements.
std::vector< sim::TrackIDE > HitToTrackIDEs(detinfo::DetectorClocksData const &clockData, recob::Hit const &hit) const
bool smoothTrackIter(int niter, KGTrack &trg, const Propagator &prop) const
Iteratively smooth a track.
std::string string
Definition: nybbler.cc:12
MaybeLogger_< ELseverityLevel::ELsev_info, false > LogInfo
std::string fClusterModuleLabel
Clustered Hits.
geo::WireID WireID() const
Definition: Hit.h:233
iterator begin()
Definition: PtrVector.h:217
Planar surface parallel to x-axis.
EDProducer(fhicl::ParameterSet const &pset)
Definition: EDProducer.h:20
struct vector vector
int StatusCode() const
Definition: MCParticle.h:211
intermediate_table::const_iterator const_iterator
string dir
KalmanFilterAlg fKFAlg
Kalman filter algorithm.
Particle class.
const KVector< N >::type & getResVector() const
Residual vector.
Definition: KHit.h:138
const art::PtrVector< recob::Hit > & getAssociatedHits(const recob::SpacePoint &spt) const
int fNumEvent
Number of events seen.
art framework interface to geometry description
std::enable_if_t< std::is_arithmetic_v< T >, T > hypot(T x, T y)
Definition: hypot.h:60
int TrackId() const
Definition: MCParticle.h:210
std::string fHitModuleLabel
Unclustered Hits.
void produce(art::Event &e) override
bool isValid() const noexcept
Definition: Handle.h:191
decltype(auto) constexpr size(T &&obj)
ADL-aware version of std::size.
Definition: StdUtils.h:92
bool fUseClusterHits
Use cluster hits or all hits?
T abs(T value)
TrackKalmanCheater(fhicl::ParameterSet const &pset)
const KSymMatrix< N >::type & getResError() const
Residual error matrix.
Definition: KHit.h:145
bool getByLabel(std::string const &label, std::string const &instance, Handle< PROD > &result) const
Definition: DataViewImpl.h:633
typename data_t::const_iterator const_iterator
Definition: PtrVector.h:55
const double e
bool buildTrack(const KTrack &trk, KGTrack &trg, const Propagator &prop, const Propagator::PropDirection dir, KHitContainer &hits, bool linear) const
Make a new track.
#define DEFINE_ART_MODULE(klass)
Definition: ModuleMacros.h:67
void push_back(Ptr< U > const &p)
Definition: PtrVector.h:435
Kalman filter measurement class template.
uint8_t nhit
Definition: CRTFragment.hh:201
def move(depos, offset)
Definition: depos.py:107
EDProductGetter const * productGetter(ProductID const pid) const
iterator end()
Definition: PtrVector.h:231
p
Definition: test.py:223
ProductID put(std::unique_ptr< PROD > &&edp, std::string const &instance={})
Definition: DataViewImpl.h:686
bool CreateAssn(PRODUCER const &prod, art::Event &evt, std::vector< T > const &a, art::Ptr< U > const &b, art::Assns< U, T > &assn, std::string a_instance, size_t indx=UINT_MAX)
Creates a single one-to-one association.
bool isDebugEnabled()
void beginJob() override
Begin job method.
KVector< 5 >::type TrackVector
Track state vector, dimension 5.
PlaneID_t Plane
Index of the plane within its TPC.
Definition: geo_types.h:493
bool empty() const
Definition: PtrVector.h:330
Kalman Filter.
size_type size() const
Definition: PtrVector.h:302
void fillSpacePoints(detinfo::DetectorPropertiesData const &detProp, std::vector< recob::SpacePoint > &spts, std::multimap< double, KHitTrack > const &trackMap) const
Fill a collection of space points.
Detector simulation of raw signals on wires.
const sim::ParticleList & ParticleList() const
void clearHitMap() const
Declaration of signal hit object.
int fNumTrack
Number of tracks produced.
void setPlane(int plane)
Set preferred view plane.
const TLorentzVector & Momentum(const int i=0) const
Definition: MCParticle.h:220
SpacePointAlg fSpacePointAlg
Space point algorithm.
Provides recob::Track data product.
TH1F * fHIncChisq
Incremental chisquare.
list x
Definition: train.py:276
static constexpr double fm
Definition: Units.h:75
2D representation of charge deposited in the TDC/wire plane
Definition: Hit.h:48
TCEvent evt
Definition: DataStructs.cxx:7
double fMaxTcut
Maximum delta ray energy in MeV for restricted dE/dx.
Algorithm for generating space points from hits.
bool fitMomentum(const KGTrack &trg, const Propagator &prop, KETrack &tremom) const
Estimate track momentum using either range or multiple scattering.
bool updateMomentum(const KETrack &tremom, const Propagator &prop, KGTrack &trg) const
Set track momentum at each track surface.
Track from a non-cascading particle.A recob::Track consists of a recob::TrackTrajectory, plus additional members relevant for a "fitted" track:
Definition: Track.h:49
cet::coded_exception< error, detail::translate > exception
Definition: exception.h:33