LArSoft  v06_85_00
Liquid Argon Software toolkit - http://larsoft.org/
TrackTimeAssoc_module.cc
Go to the documentation of this file.
1 // This module makes a set of hypotheses for track light profiles
2 // based on beizer tracks in the event.
3 //
4 // This module will likely be subsumed into the OpFlashFinder module
5 // eventually. But at present they are being developped in parallel.
6 //
7 //
8 // \file TrackTimeAssoc.cxx
9 // \author Ben Jones and Christie Chiu, MIT 2010
10 // Heavily revised by Ben Jones and Wes Ketchum, 2013
11 //
12 
13 
14 
17 
18 
19 // ROOT includes.
20 #include <Rtypes.h>
21 #ifndef TrackTimeAssoc_h
22 #define TrackTimeAssoc_h 1
23 
24 
25 
26 namespace trkf{
27  class BezierTrack;
28 }
29 
30 namespace recob{
31  class OpFlash;
32  class Track;
33 
34 }
35 
36 
37 namespace opdet {
38 
40 
42  public:
43 
45  virtual ~TrackTimeAssoc();
46 
47  void produce(art::Event&);
48  void reconfigure(fhicl::ParameterSet const& p);
49 
50  std::vector<double> GetMIPHypotheses(trkf::BezierTrack* BTrack, double XOffset=0);
51  std::vector<std::vector<double> > ScanMIPHypotheses(trkf::BezierTrack * Btrack);
52  void PrintHypotheses(std::vector<std::vector<double> > TrackHypotheses);
53  double GetChi2(std::vector<double> signal, std::vector<double> hypothesis, double UpperLim=0);
54  double GetMinChi2(std::vector<std::vector<double> > ScannedHypotheses, std::vector<double> FlashShape);
55 
56 
57  void StoreFlashMatches(std::vector<art::Ptr<recob::Track> >& Tracks, std::vector<art::Ptr<recob::OpFlash> >& Flashes, std::vector<anab::FlashMatch>& Matches, art::Event& evt);
58 
59 
60  void beginJob();
61 
62 
63  private:
64  std::string fTrackModuleLabel;
65  std::string fFlashModuleLabel;
68  double fLengthCut;
69  double fPECut;
70  };
71 
72 
73 
74 }
75 
76 #endif
77 
78 
79 
80 
86 // Framework includes
88 
89 namespace opdet{
90 
92 
93 }//end namespace opdet
95 
96 
97 
98 // This module makes a set of hypotheses for track light profiles
99 // based on beizer tracks in the event.
100 //
101 // This module will likely be subsumed into the OpFlashFinder module
102 // eventually. But at present they are being developped in parallel.
103 //
104 //
105 // \file TrackTimeAssoc.cxx
106 // \author Ben Jones and Christie Chiu, MIT 2010
107 //
108 //
109 
110 // LArSoft includes
115 
116 // FMWK includes
119 #include "fhiclcpp/ParameterSet.h"
128 #include "TH2D.h"
129 
130 // C++ language includes
131 #include <iostream>
132 #include <sstream>
133 #include <cstring>
134 #include <vector>
135 
136 #include "CLHEP/Random/RandFlat.h"
137 #include "CLHEP/Random/RandGaussQ.h"
138 
139 // Debug flag; only used during code development.
140 // const bool debug = true;
141 
142 namespace opdet {
143 
144  //-------------------------------------------------
145 
146  TrackTimeAssoc::TrackTimeAssoc(fhicl::ParameterSet const& pset)
147  {
148 
149  produces< std::vector<anab::FlashMatch> >();
150  produces< art::Assns<recob::Track, anab::FlashMatch> >();
151  produces< art::Assns<recob::OpFlash, anab::FlashMatch> >();
152 
153  this->reconfigure(pset);
154  }
155 
156 
157  //-------------------------------------------------
158 
159  void TrackTimeAssoc::reconfigure(fhicl::ParameterSet const& pset)
160  {
161  fTrackModuleLabel = pset.get<std::string>("TrackModuleLabel");
162  fFlashModuleLabel = pset.get<std::string>("FlashModuleLabel");
163  fBezierResolution = pset.get<int>("BezierResolution");
164  fLengthCut = pset.get<double>("LengthCut");
165  fPECut = pset.get<double>("PECut");
166  fPairingMode = pset.get<int>("PairingMode");
167 
168 
169  }
170 
171 
172  //-------------------------------------------------
173 
175  {
176  }
177 
178 
179 
180  //-------------------------------------------------
181 
182  TrackTimeAssoc::~TrackTimeAssoc()
183  {
184  }
185 
186 
187  //-------------------------------------------------
188  std::vector<std::vector<double> > TrackTimeAssoc::ScanMIPHypotheses(trkf::BezierTrack * Btrack)
189  {
190 
191  double MinX = 0; //temporary
192  double MaxX = 250; //temporary
193  size_t XSteps = 50; //temporary
194 
196 
197  std::vector<std::vector<double> > ReturnVector(XSteps);
198  for(size_t i=0; i!=XSteps; ++i)
199  ReturnVector[i].resize(geom->NOpDets());
200 
202 
203  float TrackLength = Btrack->GetTrajectory().Length();
204  float OldVertex = Btrack->GetTrajectory().Start().X();
205 
206  std::vector<bool> ValidTrajectory(XSteps, true);
207 
208  double xyz[3];
209  for (int b=0; b!=fBezierResolution; b++)
210  {
211  auto const* larp = lar::providerFrom<detinfo::LArPropertiesService>();
212 
213  double MIPYield = larp->ScintYield();
214  double QE = 0.01;
215  double MIPdQdx = 2.1;
216  double PromptFrac = 0.25;
217  double PromptMIPScintYield = MIPYield * QE * MIPdQdx * PromptFrac;
218 
219  // std::cout<<"check : " << PromptMIPScintYield<<std::endl;
220 
221  float s = float(b) / float(fBezierResolution);
222  float LightAmount = PromptMIPScintYield * TrackLength/float(fBezierResolution);
223 
224 
225  for(size_t i=0; i!=XSteps; ++i)
226  {
227  if(ValidTrajectory[i])
228  {
229  float NewVertex = MinX + float(i)/float(XSteps)*(MaxX-MinX);
230  Btrack->GetTrackPoint(s,xyz);
231  xyz[0] += NewVertex-OldVertex;
232 
233  if((xyz[0] > MaxX) || (xyz[0] < MinX) ) ValidTrajectory[i]=false;
234 
235  const float* PointVisibility = pvs->GetAllVisibilities(xyz);
236  if (!PointVisibility) continue; // point not covered by visibility service
237 
238  for(size_t OpDet =0; OpDet!=pvs->NOpChannels(); OpDet++)
239  {
240  ReturnVector.at(i).at(OpDet) += PointVisibility[OpDet] * LightAmount;
241  }
242  }
243  }
244  }
245  for(size_t i=0; i!=ReturnVector.size(); ++i)
246  if(!ValidTrajectory[i]) ReturnVector.at(i).clear();
247  return ReturnVector;
248  }
249 
250 
251 
252 
253 
254  //-------------------------------------------------
255  // This method gets the minimum chi2 achievable by marginalizing over the track x position
256  // The track dQdx is allowed to vary from the MIP value and upwards
257  //
258  double TrackTimeAssoc::GetMinChi2(std::vector<std::vector<double> > ScannedHypotheses, std::vector<double> FlashShape)
259  {
260  double MinChi2 = 10000;
261  if(FlashShape.size()==0) return MinChi2;
262 
263  for(size_t i=0; i!=ScannedHypotheses.size(); ++i)
264  {
265  if(ScannedHypotheses.at(i).size()>0)
266  {
267  double Chi2 = GetChi2(FlashShape, ScannedHypotheses.at(i), MinChi2);
268  if(Chi2 < MinChi2)
269  {
270  MinChi2 = Chi2;
271  }
272  }
273  }
274  return MinChi2;
275  }
276 
277  //-------------------------------------------------
278 
279 
280  // Get a hypothesis for the light collected for a bezier track
281  std::vector<double> TrackTimeAssoc::GetMIPHypotheses(trkf::BezierTrack* Btrack, double XOffset)
282  {
284  std::vector<double> ReturnVector(geom->NOpDets(),0);
285 
287 
288  float TrackLength = Btrack->GetLength();
289 
290  double xyz[3];
291  for (int b=0; b!=fBezierResolution; b++)
292  {
293  float s = float(b) / float(fBezierResolution);
294  float dQdx = 2.1; // Assume MIP value
295 
296  Btrack->GetTrackPoint(s,xyz);
297  xyz[0]+=XOffset;
298  const float* PointVisibility = pvs->GetAllVisibilities(xyz);
299  if (!PointVisibility) continue; // point not covered by the service
300  float LightAmount = dQdx*TrackLength/float(fBezierResolution);
301 
302  for(size_t OpDet =0; OpDet!=pvs->NOpChannels(); OpDet++)
303  {
304  ReturnVector.at(OpDet)+= PointVisibility[OpDet] * LightAmount;
305  }
306  }
307  return ReturnVector;
308  }
309 
310  //-------------------------------------------------
311 
312 
313  void TrackTimeAssoc::produce(art::Event& evt)
314  {
315 
316  // int EventID = evt.id().event();
317 
318 
319  // Read in flashes from the event
321  evt.getByLabel(fFlashModuleLabel, flashh);
322  std::vector<art::Ptr<recob::OpFlash> > Flashes;
323  for(unsigned int i=0; i < flashh->size(); ++i)
324  {
325  art::Ptr<recob::OpFlash> flash(flashh,i);
326  if(flash->TotalPE()>fPECut) Flashes.push_back(flash);
327  }
328 
329  // Read in tracks from the event
331  evt.getByLabel(fTrackModuleLabel, trackh);
332  std::vector<art::Ptr<recob::Track> > Tracks;
333  for(unsigned int i=0; i < trackh->size(); ++i)
334  {
335  art::Ptr<recob::Track> track(trackh,i);
336  if(track->Length()>fLengthCut) Tracks.push_back(track);
337  }
338 
339  std::sort(Tracks.begin(), Tracks.end(), TrackTimeAssoc_tracksort);
340 
341  // Use these to produce Bezier tracks
342  std::vector<bool> TracksToCut(Tracks.size(),false);
343  std::vector<trkf::BezierTrack*> BTracks;
344  BTracks.clear();
345  for(size_t i=0; i!=Tracks.size(); i++)
346  BTracks.push_back(new trkf::BezierTrack(*Tracks.at(i)));
347 
349  size_t NOpDets = geom->NOpDets();
350 
351  std::map<int, bool> OnBeamFlashes;
352 
353  std::vector<std::vector<std::vector<double> > > TrackHypotheses;
354  std::vector<std::vector<double> > FlashShapes;
355 
356 
357  // For each track
358  for (size_t i=0; i!=BTracks.size(); ++i)
359  {
360  TrackHypotheses.push_back(ScanMIPHypotheses(BTracks.at(i)));
361  }
362 
363 
364  for(size_t f=0; f!=Flashes.size(); ++f)
365  {
366 
367  std::vector<double> ThisFlashShape(NOpDets,0);
368 
369  // if(Flashes.at(f)->InBeamFrame())
370  // {
371  for (unsigned int c = 0; c < geom->NOpChannels(); c++){
372  unsigned int o = geom->OpDetFromOpChannel(c);
373  ThisFlashShape[o]+=Flashes.at(f)->PE(c);
374  }
375  if(Flashes.at(f)->OnBeamTime()) OnBeamFlashes[f]=true;
376  // }
377  FlashShapes.push_back(ThisFlashShape);
378 
379  }
380 
381  // This map stores the Chi2 for every match:
382  // Chi2Map[Track][Flash] = chi2
383  std::map<int, std::map<int, double> > Chi2Map;
384 
385  // This map sorts the preferences of each track for each flash
386  // SortedPrefs[TrackID][Chi2] = {flashid1, flashid2, ...}
387  std::vector<std::map<double, std::vector<int> > > SortedPrefs(Tracks.size());
388 
389 
390  for(size_t i=0; i!=TrackHypotheses.size(); ++i)
391  {
392  for(size_t j=0; j!=FlashShapes.size(); ++j)
393  {
394  double Chi2 = GetMinChi2(TrackHypotheses.at(i), FlashShapes.at(j));
395 
396  Chi2Map[i][j]=Chi2;
397  SortedPrefs[i][Chi2].push_back(j);
398 
399  }
400  }
401 
402 
403  // This will hold the list of matches
404  std::vector<anab::FlashMatch> Matches;
405 
406 
407 
408  if(fPairingMode==0)
409  {
410  // In pairing mode 0, store all combinatoric matches and let the user
411  // deal with Chi2s later
412  for(size_t i=0; i!=BTracks.size(); ++i)
413  for(size_t j=0; j!=Flashes.size(); ++j)
414  Matches.push_back( anab::FlashMatch(Chi2Map[i][j], j, i, (Flashes.at(j)->OnBeamTime()>0)));
415  }
416 
417  else if(fPairingMode==1)
418  {
419  // In pairing mode 1, use the stable marriage algorithm to make a guess
420  // at good 1<->1 pairings
421 
422  bool StillPairing =true;
423  std::vector<int> FlashesPaired(Flashes.size(),-1);
424  std::vector<int> TracksPaired(BTracks.size(),-1);
425 
426  // If we made a new match in the last round, don't stop
427  while(StillPairing)
428  {
429  StillPairing=false;
430  for(size_t i=0; i!=BTracks.size(); ++i)
431  {
432  // If this track still to be paired
433  if(TracksPaired[i]<0)
434  {
435  // Find the flash with best remaining chi2
436  bool MadeMatch = false;
437  for(auto itPref = SortedPrefs[i].begin(); itPref!=SortedPrefs[i].end(); ++itPref)
438  {
439  for(size_t iflash =0; iflash!=itPref->second.size(); ++iflash)
440  {
441  int FlashID = itPref->second.at(iflash);
442  int FlashExistingPref = FlashesPaired[FlashID];
443  if(FlashExistingPref < 0)
444  {
445  // This flash is available - make pairing
446  TracksPaired[i] = FlashID;
447 
448  // if the flash is on beam, claim to be
449  // satisfied, but don't occupy flash
450  // if flash is cosmic, claim it.
451  if(!OnBeamFlashes[FlashID])
452  FlashesPaired[FlashID] = i;
453 
454  StillPairing = true;
455  MadeMatch = true;
456  }
457  else
458  {
459  // This flash taken - flash gets to vote
460  if(Chi2Map[i][FlashID] < Chi2Map[FlashExistingPref][FlashID])
461  {
462  // If the flash prefers the new guy, switch
463  FlashesPaired[FlashID] = i;
464  TracksPaired[i] = FlashID;
465  TracksPaired[FlashExistingPref] = -1;
466  MadeMatch = true;
467  StillPairing = true;
468  break;
469  }
470  // or else just roll on...
471  }
472  }
473  if(MadeMatch) break;
474  } // end loop over chi2s
475  } // end if unpaired track
476  } // end loop over tracks
477  } // end loop until no more pairing
478 
479 
480  for(size_t i=0; i!=BTracks.size(); ++i)
481  {
482  if(TracksPaired[i]>0)
483  {
484  int TrackID = i;
485  int FlashID = TracksPaired[i];
486 
487  Matches.push_back( anab::FlashMatch(Chi2Map[TrackID][FlashID], FlashID, TrackID, Flashes.at(FlashID)->OnBeamTime() ));
488  }
489  }
490  }
491 
492 
493  StoreFlashMatches(Tracks, Flashes, Matches, evt);
494 
495  }
496 
497 
498  //--------------------------------------------------
499  // Get the chi2 between a flash hypothesis and a track
500  // Optional : stop counting if Chi2 bigger than UpperLim
501  //
502  double TrackTimeAssoc::GetChi2(std::vector<double> signal, std::vector<double> hypothesis, double UpperLim)
503  {
504 
505  double SignalIntegral = 0;
506  double HypoIntegral = 0;
507 
508  for(size_t i=0; i!=signal.size(); ++i)
509  {
510  SignalIntegral+=signal.at(i);
511  HypoIntegral+=hypothesis.at(i);
512  }
513 
514  // If light yield indicates >1 MIP light yield,
515  // Normalize the hypothesis to the signal size.
516  // We do not allow <1 MIP hypotheses.
517 
518  double NormFactor = SignalIntegral/HypoIntegral;
519  if(NormFactor > 1)
520  {
521  for(size_t i=0; i!=hypothesis.size(); ++i)
522  {
523  hypothesis.at(i) *= NormFactor;
524  }
525  }
526 
527  double Chi2=0;
528 
529  for(size_t i=0; i!=signal.size(); ++i)
530  {
531  // We assume width = sqrt(hypothesis)
532 
533  if(hypothesis.at(i)!=0)
534  Chi2 += pow(hypothesis.at(i) - signal.at(i),2)/(hypothesis.at(i));
535 
536  if(Chi2>UpperLim)
537  break;
538  }
539  return Chi2;
540  }
541 
542 
543  //--------------------------------------------------
544 
545  void TrackTimeAssoc::PrintHypotheses(std::vector<std::vector<double> > TrackHypotheses)
546  {
547  // List the light hypotheses per track, per PMT
548  for (size_t i=0; i!=TrackHypotheses.size(); ++i)
549  {
550  mf::LogVerbatim("TrackTimeAssoc")<< "Visbility for track " << i <<std::endl;
551 
552  for(size_t j=0; j!=TrackHypotheses.at(i).size(); ++j)
553  {
554  mf::LogVerbatim("TrackTimeAssoc") << "Signal at PMT " << j << ", " << TrackHypotheses.at(i).at(j)<<std::endl;
555  }
556  }
557 
558  }
559 
560 
561 
562  //--------------------------------------------------
563 
564  void TrackTimeAssoc::StoreFlashMatches(std::vector<art::Ptr<recob::Track> > & Tracks, std::vector<art::Ptr<recob::OpFlash> > & Flashes, std::vector<anab::FlashMatch>& Matches, art::Event& evt)
565  {
566  std::unique_ptr< std::vector<anab::FlashMatch> > flash_matches ( new std::vector<anab::FlashMatch>);
567  std::unique_ptr< art::Assns<recob::Track, anab::FlashMatch > > assn_track( new art::Assns<recob::Track, anab::FlashMatch>);
568  std::unique_ptr< art::Assns<recob::OpFlash, anab::FlashMatch > > assn_flash( new art::Assns<recob::OpFlash, anab::FlashMatch>);
569 
570  for(size_t i=0; i!=Matches.size(); ++i)
571  {
572  flash_matches->push_back(Matches.at(i));
573 
574  util::CreateAssn(*this, evt, *(flash_matches.get()), Tracks.at(Matches.at(i).SubjectID()), *(assn_track.get()), i);
575 
576  util::CreateAssn(*this, evt, *(flash_matches.get()), Flashes.at(Matches.at(i).FlashID()), *(assn_flash.get()), i);
577  }
578 
579 
580  evt.put(std::move(flash_matches));
581  evt.put(std::move(assn_track));
582  evt.put(std::move(assn_flash));
583  }
584 
585 
586  //-----------------------------------
587  // Helper function for performing track length sort
589  {
590  return (t1->Length()>t2->Length());
591 
592  }
593 
594 
595 }
596 
597 
Float_t s
Definition: plot.C:23
MaybeLogger_< ELseverityLevel::ELsev_info, true > LogVerbatim
TTree * t1
Definition: plottest35.C:26
Reconstruction base classes.
double Length(size_t startAt=0) const
Returns the approximate length of the trajectory.
Definition: Trajectory.cxx:103
unsigned int NOpChannels() const
Number of electronics channels for all the optical detectors.
void GetTrackPoint(double s, double *xyz) const
unsigned int OpDetFromOpChannel(int opChannel) const
Convert unique channel to detector number.
TFile f
Definition: plotHisto.C:6
ProductID put(std::unique_ptr< PROD > &&product)
Definition: Event.h:102
auto vector(Vector const &v)
Returns a manipulator which will print the specified array.
Definition: DumpUtils.h:265
double Length(size_t p=0) const
Access to various track properties.
Definition: Track.h:174
float const * GetAllVisibilities(double const *xyz, bool wantReflected=false) const
#define DEFINE_ART_MODULE(klass)
Definition: ModuleMacros.h:42
void beginJob()
Definition: Breakpoints.cc:14
recob::Trajectory const & GetTrajectory() const
Returns the current trajectory.
Definition: BezierTrack.h:96
T get(std::string const &key) const
Definition: ParameterSet.h:231
std::vector< evd::details::RawDigitInfo_t >::const_iterator begin(RawDigitCacheDataClass const &cache)
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.
unsigned int NOpDets() const
Number of OpDets in the whole detector.
TTree * t2
Definition: plottest35.C:36
Utility object to perform functions of association.
bool getByLabel(std::string const &label, std::string const &productInstanceName, Handle< PROD > &result) const
Definition: DataViewImpl.h:344
double TotalPE() const
Definition: OpFlash.cxx:56
Point_t const & Start() const
Returns the position of the first point of the trajectory [cm].
Definition: Trajectory.h:240
double GetLength() const
Float_t track
Definition: plot.C:34
Definition: Track.hh:43
bool TrackTimeAssoc_tracksort(art::Ptr< recob::Track > t1, art::Ptr< recob::Track > t2)
art framework interface to geometry description