LArSoft  v09_90_00
Liquid Argon Software toolkit - https://larsoft.org/
Track3DKalmanHit_module.cc
Go to the documentation of this file.
1 //
3 // Class: Track3DKalmanHit
4 // Module Type: producer
5 // File: Track3DKalmanHit_module.cc
6 //
7 // This module produces RecoBase/Track objects using KalmanFilterAlgorithm.
8 //
9 // Configuration parameters:
10 //
11 // Hist - Histogram flag (generate histograms if true).
12 // UseClusterHits - Use clustered hits if true.
13 // UsePFParticleHits - Use PFParticle hits if true.
14 // UsePFParticleSeeds - If true, use seeds associated with PFParticles.
15 // HitModuleLabel - Module label for unclustered Hits.
16 // ClusterModuleLabel - Module label for Clusters.
17 // PFParticleModuleLabel - Module label for PFParticles.
18 // Track3DKalmanHitAlg - Algorithm class for Track3DKalmanHit module
19 // SpacePointAlg - Parmaeter set for space points.
20 //
21 // Usage Notes.
22 //
23 // 1. It is an error if UseClusterHits and UsePFParticleHits are both
24 // true (throw exception in that case). However, both can be false,
25 // in which case all hits are used as input.
26 //
27 // 2. If clustered hits are used as input, then tracks can span clusters
28 // (cluster structure of hits is ignored).
29 //
30 // 3. If PFParticle hits are used as input, then tracks do not span
31 // PFParticles. However, it is possible for one the hits from
32 // one PFParticle to give rise to multiple Tracks.
33 //
34 // 4. UsePFParticleSeeds has no effect unless UsePFParticleHits is true.
35 //
37 
38 #include <cmath>
39 #include <deque>
40 
46 #include "art_root_io/TFileDirectory.h"
47 #include "art_root_io/TFileService.h"
52 #include "fhiclcpp/ParameterSet.h"
54 
68 
69 #include "TH1F.h"
70 
71 namespace trkf {
72 
74  public:
75  // Copnstructors, destructor.
76  explicit Track3DKalmanHit(fhicl::ParameterSet const& pset);
77 
78  private:
79  void produce(art::Event& e) override;
80  void beginJob() override;
81  void endJob() override;
82 
83  //Member functions that depend on art::event and use art::Assns
84  //note that return types are move aware
85  void prepareForInput();
86  KalmanInputs getInput(const art::Event& evt) const;
87  Hits getClusteredHits(const art::Event& evt) const;
88  KalmanInputs getPFParticleStuff(const art::Event& evt) const;
89  Hits getAllHits(const art::Event& evt) const;
90  void createOutputs(const art::Event& evt,
91  detinfo::DetectorPropertiesData const& detProp,
92  const std::vector<KalmanOutput>& outputs,
93  const KalmanInputs& inputs,
94  std::vector<recob::Track>& tracks,
95  std::vector<recob::SpacePoint>& spts,
101  void fillHistograms(std::vector<KalmanOutput>& outputs);
102 
103  // Fcl parameters.
104  bool fHist;
108  std::string fHitModuleLabel;
109  std::string fClusterModuleLabel;
113 
114  // Histograms.
115  TH1F* fHIncChisq;
116  TH1F* fHPull;
117 
118  // Statistics.
119  int fNumEvent;
120  };
122 } // namespace trkf
123 
124 //----------------------------------------------------------------------------
132  : EDProducer{pset}
133  , fHist(false)
134  , fUseClusterHits(false)
135  , fUsePFParticleHits(false)
136  , fUsePFParticleSeeds(false)
137  , fTKHAlg(pset.get<fhicl::ParameterSet>("Track3DKalmanHitAlg"))
138  , fSpacePointAlg(pset.get<fhicl::ParameterSet>("SpacePointAlg"))
139  , fHIncChisq(0)
140  , fHPull(0)
141  , fNumEvent(0)
142 {
143  fHist = pset.get<bool>("Hist");
144  fUseClusterHits = pset.get<bool>("UseClusterHits");
145  fUsePFParticleHits = pset.get<bool>("UsePFParticleHits");
146  fUsePFParticleSeeds = pset.get<bool>("UsePFParticleSeeds");
147  fHitModuleLabel = pset.get<std::string>("HitModuleLabel");
148  fClusterModuleLabel = pset.get<std::string>("ClusterModuleLabel");
149  fPFParticleModuleLabel = pset.get<std::string>("PFParticleModuleLabel");
150  if (fUseClusterHits && fUsePFParticleHits) {
151  throw cet::exception("Track3DKalmanHit")
152  << "Using input from both clustered and PFParticle hits.\n";
153  }
154 
155  produces<std::vector<recob::Track>>();
156  produces<std::vector<recob::SpacePoint>>();
158  recob::Hit>>(); // ****** REMEMBER to remove when FindMany improved ******
159  produces<art::Assns<recob::Track, recob::Hit, recob::TrackHitMeta>>();
160  produces<art::Assns<recob::Track, recob::SpacePoint>>();
161  produces<art::Assns<recob::SpacePoint, recob::Hit>>();
162  produces<art::Assns<recob::PFParticle, recob::Track>>();
163 
164  // Report.
165 
166  mf::LogInfo("Track3DKalmanHit") << "Track3DKalmanHit configured with the following parameters:\n"
167  << " UseClusterHits = " << fUseClusterHits << "\n"
168  << " HitModuleLabel = " << fHitModuleLabel << "\n"
169  << " ClusterModuleLabel = " << fClusterModuleLabel;
170 }
171 
172 //----------------------------------------------------------------------------
175 {
176  if (fHist) {
177  // Book histograms.
179  art::TFileDirectory dir = tfs->mkdir("hitkalman", "Track3DKalmanHit histograms");
180 
181  fHIncChisq = dir.make<TH1F>("IncChisq", "Incremental Chisquare", 100, 0., 20.);
182  fHPull = dir.make<TH1F>("Pull", "Hit Pull", 100, -10., 10.);
183  }
184 }
185 
186 //----------------------------------------------------------------------------
190 {
191  ++fNumEvent;
192  auto tracks = std::make_unique<std::vector<recob::Track>>();
193  auto th_assn = std::make_unique<art::Assns<recob::Track, recob::Hit>>();
194  auto thm_assn = std::make_unique<art::Assns<recob::Track, recob::Hit, recob::TrackHitMeta>>();
195  auto tsp_assn = std::make_unique<art::Assns<recob::Track, recob::SpacePoint>>();
196  auto pfPartTrack_assns = std::make_unique<art::Assns<recob::PFParticle, recob::Track>>();
197  auto spts = std::make_unique<std::vector<recob::SpacePoint>>();
198  auto sph_assn = std::make_unique<art::Assns<recob::SpacePoint, recob::Hit>>();
199 
200  prepareForInput();
201  auto inputs = getInput(evt);
202 
203  auto const clockData = art::ServiceHandle<detinfo::DetectorClocksService const>()->DataFor(evt);
204  auto const detProp =
206  auto outputs = fTKHAlg.makeTracks(clockData, detProp, inputs);
207 
208  if (fHist) { fillHistograms(outputs); }
209 
210  createOutputs(evt,
211  detProp,
212  outputs,
213  inputs,
214  *tracks,
215  *spts,
216  *th_assn,
217  *thm_assn,
218  *tsp_assn,
219  *sph_assn,
220  *pfPartTrack_assns);
221 
223 
224  evt.put(std::move(tracks));
225  evt.put(std::move(spts));
226  evt.put(std::move(th_assn));
227  evt.put(std::move(thm_assn));
228  evt.put(std::move(tsp_assn));
229  evt.put(std::move(sph_assn));
230  evt.put(std::move(pfPartTrack_assns));
231 }
232 
233 //----------------------------------------------------------------------------
236 {
237  mf::LogInfo("Track3DKalmanHit") << "Track3DKalmanHit statistics:\n"
238  << " Number of events = " << fNumEvent << "\n";
239 }
240 
241 //----------------------------------------------------------------------------
242 //A temporary method till we find an alternative
244 {
246 }
247 
248 //----------------------------------------------------------------------------
249 // There are three modes of operation:
250 // 1. Clustered hits (produces one hit collection).
251 // 2. PFParticle hits (products one hit collection for each PFParticle).
252 // 3. All hits (produces one hit collection).
253 
255 {
256  if (fUsePFParticleHits) return getPFParticleStuff(evt);
258 }
259 
260 //----------------------------------------------------------------------------
263 {
264  Hits hits;
266  evt.getByLabel(fClusterModuleLabel, clusterh);
267 
268  if (!clusterh.isValid()) return hits;
269  // Get hits from all clusters.
270  art::FindManyP<recob::Hit> hitsbycluster(clusterh, evt, fClusterModuleLabel);
271 
272  for (size_t i = 0; i < clusterh->size(); ++i) {
273  std::vector<art::Ptr<recob::Hit>> clushits = hitsbycluster.at(i);
274  hits.insert(hits.end(), clushits.begin(), clushits.end());
275  }
276  return hits;
277 }
278 
279 //----------------------------------------------------------------------------
282 {
283  Hits hits;
285  evt.getByLabel(fHitModuleLabel, hith);
286  if (!hith.isValid()) return hits;
287  size_t nhits = hith->size();
288  hits.reserve(nhits);
289 
290  for (size_t i = 0; i < nhits; ++i) {
291  hits.push_back(art::Ptr<recob::Hit>(hith, i));
292  }
293  return hits;
294 }
295 
296 //----------------------------------------------------------------------------
299 {
300  KalmanInputs inputs;
301  // Our program is to drive the track creation/fitting off the PFParticles in the data store
302  // We'll use the hits associated to the PFParticles for each track - and only those hits.
303  // Without a valid collection of PFParticles there is nothing to do here
304  // We need a handle to the collection of clusters in the data store so we can
305  // handle associations to hits.
307  evt.getByLabel(fPFParticleModuleLabel, pfParticleHandle);
308  if (!pfParticleHandle.isValid()) return inputs;
309 
311  evt.getByLabel(fClusterModuleLabel, clusterHandle);
312 
313  // If there are no clusters then something is really wrong
314  if (!clusterHandle.isValid()) return inputs;
315 
316  // Recover the collection of associations between PFParticles and clusters, this will
317  // be the mechanism by which we actually deal with clusters
318  art::FindManyP<recob::Cluster> clusterAssns(pfParticleHandle, evt, fPFParticleModuleLabel);
319 
320  // Associations to seeds.
321  art::FindManyP<recob::Seed> seedAssns(pfParticleHandle, evt, fPFParticleModuleLabel);
322 
323  // Likewise, recover the collection of associations to hits
324  art::FindManyP<recob::Hit> clusterHitAssns(clusterHandle, evt, fClusterModuleLabel);
325 
326  inputs.reserve(pfParticleHandle->size());
327 
328  // While PFParticle describes a hierarchal structure, for now we simply loop over the collection
329  for (size_t partIdx = 0; partIdx < pfParticleHandle->size(); partIdx++) {
330 
331  // Add a new empty hit collection.
332  inputs.emplace_back();
333  KalmanInput& kalman_input = inputs.back();
334  kalman_input.pfPartPtr = art::Ptr<recob::PFParticle>(pfParticleHandle, partIdx);
335  Hits& hits = kalman_input.hits;
336 
337  // Fill this hit vector by looping over associated clusters and finding the
338  // hits associated to them
339  std::vector<art::Ptr<recob::Cluster>> clusterVec = clusterAssns.at(partIdx);
340 
341  for (auto const& cluster : clusterVec) {
342  std::vector<art::Ptr<recob::Hit>> hitVec = clusterHitAssns.at(cluster.key());
343  hits.insert(hits.end(), hitVec.begin(), hitVec.end());
344  }
345 
346  // If requested, fill associated seeds.
347  if (!fUsePFParticleSeeds) continue;
348  art::PtrVector<recob::Seed>& seeds = kalman_input.seeds;
349  std::vector<art::Ptr<recob::Seed>> seedVec = seedAssns.at(partIdx);
350  seeds.insert(seeds.end(), seedVec.begin(), seedVec.end());
351  art::FindManyP<recob::Hit> seedHitAssns(seedVec, evt, fPFParticleModuleLabel);
352 
353  for (size_t seedIdx = 0; seedIdx < seedVec.size(); ++seedIdx) {
354  std::vector<art::Ptr<recob::Hit>> seedHitVec;
355  //SS: why seedIdx can have an invalid value?
356  try {
357  seedHitVec = seedHitAssns.at(seedIdx);
358  }
359  catch (art::Exception const&) {
360  seedHitVec.clear();
361  }
362  kalman_input.seedhits.emplace_back();
363  Hits& seedhits = kalman_input.seedhits.back();
364  seedhits.insert(seedhits.end(), seedHitVec.begin(), seedHitVec.end());
365  }
366  }
367  return inputs;
368 }
369 
370 //-------------------------------------------------------------------------------------
372  const art::Event& evt,
373  detinfo::DetectorPropertiesData const& detProp,
374  std::vector<KalmanOutput> const& outputs,
375  KalmanInputs const& inputs,
376  std::vector<recob::Track>& tracks,
377  std::vector<recob::SpacePoint>& spts,
383 {
384  if (outputs.size() != inputs.size()) return;
385 
386  size_t tracksSize(0);
387  for (auto const& kalman_output : outputs) {
388  tracksSize += kalman_output.tracks.size();
389  }
390  tracks.reserve(tracksSize);
391 
392  auto const tid = evt.getProductID<std::vector<recob::Track>>();
393  auto const tidgetter = evt.productGetter(tid);
394 
395  auto const spacepointId = evt.getProductID<std::vector<recob::SpacePoint>>();
396  auto const getter = evt.productGetter(spacepointId);
397 
398  for (size_t i = 0; i < outputs.size(); ++i) {
399  // Recover the kalman tracks double ended queue
400  const std::deque<KGTrack>& kalman_tracks = outputs[i].tracks;
401 
402  for (auto const& kalman_track : kalman_tracks) {
403 
404  // Add Track object to collection.
406  kalman_track.fillTrack(detProp, track, tracks.size());
407  if (track.NumberTrajectoryPoints() < 2) { continue; }
408  unsigned int numtrajpts = track.NumberTrajectoryPoints();
409  tracks.emplace_back(std::move(track));
410  // SS: tracks->size() does not change after this point in each iteration
411 
412  //fill hits from this track
413  Hits trhits;
414  std::vector<unsigned int> hittpindex; //hit-trajectory point index
415  kalman_track.fillHits(trhits, hittpindex);
416  if (hittpindex.back() >= numtrajpts) { //something is wrong
417  throw cet::exception("Track3DKalmanHit")
418  << "Last hit corresponds to trajectory point index " << hittpindex.back()
419  << " while the number of trajectory points is " << numtrajpts << '\n';
420  }
421 
422  // Make space points from this track.
423  auto nspt = spts.size();
424  fSpacePointAlg.fillSpacePoints(detProp, spts, kalman_track.TrackMap());
425 
426  std::vector<art::Ptr<recob::SpacePoint>> sptvec;
427  for (auto ispt = nspt; ispt < spts.size(); ++ispt) {
428  sptvec.emplace_back(spacepointId, ispt, getter);
429  // Associate newly created space points with hits.
430  // Make space point to hit associations.
431  auto const& sphits = fSpacePointAlg.getAssociatedHits((spts)[ispt]);
432  for (auto const& sphit : sphits) {
433  sph_assn.addSingle(sptvec.back(), sphit);
434  }
435  }
436 
437  art::Ptr<recob::Track> aptr(tid, tracks.size() - 1, tidgetter);
438 
439  // Make Track to Hit associations.
440  for (size_t h = 0; h < trhits.size(); ++h) {
441  th_assn.addSingle(aptr, trhits[h]);
442  recob::TrackHitMeta metadata(hittpindex[h], -1);
443  thm_assn.addSingle(aptr, trhits[h], metadata);
444  }
445 
446  // Make track to space point associations
447  for (auto const& spt : sptvec) {
448  tsp_assn.addSingle(aptr, spt);
449  }
450 
451  // Optionally fill track-to-PFParticle associations.
452  if (fUsePFParticleHits) { pfPartTrack_assns.addSingle(inputs[i].pfPartPtr, aptr); }
453  } // end of loop over a given collection
454  }
455 }
456 
457 //----------------------------------------------------------------------------
459 //fHPull and fHIncChisq are private data members of the class Track3DKalmanHit
460 
461 void trkf::Track3DKalmanHit::fillHistograms(std::vector<KalmanOutput>& outputs)
462 {
463  for (auto const& output : outputs) {
464  const std::deque<KGTrack>& kalman_tracks = output.tracks;
465  for (size_t i = 0; i < kalman_tracks.size(); ++i) {
466  const KGTrack& trg = kalman_tracks[i];
467  // Loop over measurements in this track.
468  const std::multimap<double, KHitTrack>& trackmap = trg.getTrackMap();
469  for (std::multimap<double, KHitTrack>::const_iterator ih = trackmap.begin();
470  ih != trackmap.end();
471  ++ih) {
472  const KHitTrack& trh = (*ih).second;
473  const std::shared_ptr<const KHitBase>& hit = trh.getHit();
474  double chisq = hit->getChisq();
475  fHIncChisq->Fill(chisq);
476  const KHit<1>* ph1 = dynamic_cast<const KHit<1>*>(&*hit);
477  if (ph1 != 0) {
478  double pull = ph1->getResVector()(0) / std::sqrt(ph1->getResError()(0, 0));
479  fHPull->Fill(pull);
480  }
481  }
482  }
483  }
484 }
art::Ptr< recob::PFParticle > pfPartPtr
void reserve(size_type n)
Definition: PtrVector.h:337
bool fUseClusterHits
Use clustered hits as input.
const std::shared_ptr< const KHitBase > & getHit() const
Measurement.
Definition: KHitTrack.h:51
std::string fHitModuleLabel
Unclustered Hits.
Track3DKalmanHitAlg fTKHAlg
Track3DKalmanHit algorithm.
bool fUsePFParticleSeeds
Use PFParticle seeds.
ProductID getProductID(std::string const &instance_name="") const
KalmanInputs getInput(const art::Event &evt) const
MaybeLogger_< ELseverityLevel::ELsev_info, false > LogInfo
void beginJob() override
Begin job method.
Declaration of signal hit object.
EDProducer(fhicl::ParameterSet const &pset)
Definition: EDProducer.cc:6
std::string fPFParticleModuleLabel
PFParticle label.
void produces(std::string const &instanceName={}, Persistable const persistable=Persistable::Yes)
size_t NumberTrajectoryPoints() const
Various functions related to the presence and the number of (valid) points.
Definition: Track.h:136
Class to keep data related to recob::Hit associated with recob::Track.
std::vector< trkf::KalmanOutput > makeTracks(detinfo::DetectorClocksData const &clockData, detinfo::DetectorPropertiesData const &detProp, KalmanInputs &kalman_inputs)
std::string fClusterModuleLabel
Clustered Hits.
intermediate_table::const_iterator const_iterator
Data related to recob::Hit associated with recob::Track.The purpose is to collect several variables t...
Definition: TrackHitMeta.h:43
Cluster finding and building.
Track3DKalmanHit(fhicl::ParameterSet const &pset)
const KVector< N >::type & getResVector() const
Residual vector.
Definition: KHit.h:113
Track3DKalmanHit Algorithm.
const art::PtrVector< recob::Hit > & getAssociatedHits(const recob::SpacePoint &spt) const
SpacePointAlg fSpacePointAlg
Space point algorithm.
const std::multimap< double, KHitTrack > & getTrackMap() const
KHitTrack collection, indexed by path distance.
Definition: KGTrack.h:54
bool isValid() const noexcept
Definition: Handle.h:203
PutHandle< PROD > put(std::unique_ptr< PROD > &&edp, std::string const &instance={})
Definition: Event.h:77
const KSymMatrix< N >::type & getResError() const
Residual error matrix.
Definition: KHit.h:116
Hits getClusteredHits(const art::Event &evt) const
Fill a collection using clustered hits.
void hits()
Definition: readHits.C:15
art::PtrVector< recob::Hit > hits
EDProductGetter const * productGetter(ProductID const pid) const
#define DEFINE_ART_MODULE(klass)
Definition: ModuleMacros.h:65
void push_back(Ptr< U > const &p)
Definition: PtrVector.h:435
Kalman filter measurement class template.
iterator end()
Definition: PtrVector.h:231
Hits getAllHits(const art::Event &evt) const
If both UseClusteredHits and UsePFParticles is false use this method to fill in hits.
std::vector< art::PtrVector< recob::Hit > > seedhits
Provides recob::Track data product.
void fillHistograms(std::vector< KalmanOutput > &outputs)
Fill Histograms method.
Declaration of cluster object.
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.
int fNumEvent
Number of events seen.
cet::coded_exception< errors::ErrorCodes, ExceptionDetail::translate > Exception
Definition: Exception.h:66
std::vector< TrajPoint > seeds
Definition: DataStructs.cxx:14
void clearHitMap() const
iterator insert(iterator position, Ptr< U > const &p)
bool getByLabel(std::string const &label, std::string const &instance, Handle< PROD > &result) const
bool fUsePFParticleHits
Use PFParticle hits as input.
TDirectory * dir
Definition: macro.C:5
void produce(art::Event &e) override
void addSingle(Ptr< left_t > const &left, Ptr< right_t > const &right, data_t const &data)
Definition: Assns.h:549
TrackCollectionProxyElement< TrackCollProxy > Track
Proxy to an element of a proxy collection of recob::Track objects.
Definition: Track.h:992
2D representation of charge deposited in the TDC/wire plane
Definition: Hit.h:46
TCEvent evt
Definition: DataStructs.cxx:8
Float_t e
Definition: plot.C:35
Algorithm for generating space points from hits.
Float_t track
Definition: plot.C:35
void createOutputs(const art::Event &evt, detinfo::DetectorPropertiesData const &detProp, const std::vector< KalmanOutput > &outputs, const KalmanInputs &inputs, std::vector< recob::Track > &tracks, std::vector< recob::SpacePoint > &spts, art::Assns< recob::Track, recob::Hit > &th_assn, art::Assns< recob::Track, recob::Hit, recob::TrackHitMeta > &thm_assn, art::Assns< recob::Track, recob::SpacePoint > &tsp_assn, art::Assns< recob::SpacePoint, recob::Hit > &sph_assn, art::Assns< recob::PFParticle, recob::Track > &pfPartTrack_assns)
std::vector< KalmanInput > KalmanInputs
void endJob() override
End job method.
TH1F * fHIncChisq
Incremental chisquare.
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
art::PtrVector< recob::Seed > seeds
KalmanInputs getPFParticleStuff(const art::Event &evt) const
If UsePFParticles is true use this method to fill in hits.