LArSoft  v06_85_00
Liquid Argon Software toolkit - http://larsoft.org/
SpacePointAlg.cxx
Go to the documentation of this file.
1 
11 #include <cassert>
12 #include <iostream>
13 #include <sstream>
14 #include <cmath>
15 #include <map>
16 #include <algorithm>
17 #include "cetlib_except/exception.h"
29 //\todo Remove include of BackTrackerService.h once this algorithm is stripped of test for MC
35 
36 #include "TH1F.h"
37 
38 //----------------------------------------------------------------------
39 // Constructor.
40 //
41 namespace trkf{
42 
44  fMaxDT(0.),
45  fMaxS(0.),
46  fMinViews(1000),
47  fEnableU(false),
48  fEnableV(false),
49  fEnableW(false),
50  fFilter(false),
51  fMerge(false),
52  fPreferColl(false)
53  {
54  reconfigure(pset);
55  }
56 
57  //----------------------------------------------------------------------
58  // Destructor.
59  //
61  {
62  }
63 
64  //----------------------------------------------------------------------
65  // Update configuration parameters.
66  //
68  {
69  // Get configuration parameters.
70 
71  fMaxDT = pset.get<double>("MaxDT");
72  fMaxS = pset.get<double>("MaxS");
73 
74  fMinViews = pset.get<int>("MinViews");
75 
76  fEnableU = pset.get<bool>("EnableU");
77  fEnableV = pset.get<bool>("EnableV");
78  fEnableW = pset.get<bool>("EnableW");
79  fFilter = pset.get<bool>("Filter");
80  fMerge = pset.get<bool>("Merge");
81  fPreferColl = pset.get<bool>("PreferColl");
82 
83  // Only allow one of fFilter and fMerge to be true.
84 
85  if(fFilter && fMerge)
86  throw cet::exception("SpacePointAlg") << "Filter and Merge flags are both true.\n";
87 
88  // Report.
89 
90  mf::LogInfo("SpacePointAlg")
91  << "SpacePointAlg configured with the following parameters:\n"
92  << " MaxDT = " << fMaxDT << "\n"
93  << " MaxS = " << fMaxS << "\n"
94  << " MinViews = " << fMinViews << "\n"
95  << " EnableU = " << fEnableU << "\n"
96  << " EnableV = " << fEnableV << "\n"
97  << " EnableW = " << fEnableW << "\n"
98  << " Filter = " << fFilter << "\n"
99  << " Merge = " << fMerge;
100  }
101 
102  //----------------------------------------------------------------------
103  // Print geometry and properties constants.
104  //
106  {
107  // Generate info report on first call only.
108 
109  static bool first = true;
110  bool report = first;
111  first = false;
112 
113  // Get services.
114 
116  const detinfo::DetectorProperties* detprop = lar::providerFrom<detinfo::DetectorPropertiesService>();
117 
118  // Calculate and print geometry information.
119 
120  if(report)
121  mf::LogInfo("SpacePointAlg") << "Updating geometry constants.\n";
122 
123 
124  for(unsigned int cstat = 0; cstat < geom->Ncryostats(); ++cstat){
125 
126  // Loop over TPCs.
127 
128  unsigned int const ntpc = geom->Cryostat(cstat).NTPC();
129 
130  for(unsigned int tpc = 0; tpc < ntpc; ++tpc) {
131  const geo::TPCGeo& tpcgeom = geom->Cryostat(cstat).TPC(tpc);
132 
133  // Loop over planes.
134 
135  unsigned int const nplane = tpcgeom.Nplanes();
136 
137  for(unsigned int plane = 0; plane < nplane; ++plane) {
138  geo::PlaneID planeid(cstat, tpc, plane);
139  const geo::PlaneGeo& pgeom = tpcgeom.Plane(planeid);
140 
141  // Fill view-dependent quantities.
142 
143  geo::View_t view = pgeom.View();
144  std::string viewname = "?";
145  if(view == geo::kU) {
146  viewname = "U";
147  }
148  else if(view == geo::kV) {
149  viewname = "V";
150  }
151  else if(view == geo::kZ) {
152  viewname = "Z";
153  }
154  else
155  throw cet::exception("SpacePointAlg") << "Bad view = "
156  << view << "\n";
157 
158  std::string sigtypename = "?";
159  geo::SigType_t sigtype = geom->SignalType(planeid);
160  if(sigtype == geo::kInduction)
161  sigtypename = "Induction";
162  else if(sigtype == geo::kCollection)
163  sigtypename = "Collection";
164  else
165  throw cet::exception("SpacePointAlg") << "Bad signal type = "
166  << sigtype << "\n";
167 
168  std::string orientname = "?";
169  geo::Orient_t orient = pgeom.Orientation();
170  if(orient == geo::kVertical)
171  orientname = "Vertical";
172  else if(orient == geo::kHorizontal)
173  orientname = "Horizontal";
174  else
175  throw cet::exception("SpacePointAlg") << "Bad orientation = "
176  << orient << "\n";
177 
178  if(report) {
179  const double* xyz = tpcgeom.PlaneLocation(plane);
180  mf::LogInfo("SpacePointAlg") << "\nCryostat, TPC, Plane: "
181  << cstat << ","
182  << tpc << ", "
183  << plane << "\n"
184  << " View: " << viewname << "\n"
185  << " SignalType: " << sigtypename << "\n"
186  << " Orientation: " << orientname << "\n"
187  << " Plane location: " << xyz[0] << "\n"
188  << " Plane pitch: "
189  << tpcgeom.Plane0Pitch(plane) << "\n"
190  << " Wire angle: "
191  << tpcgeom.Plane(plane).Wire(0).ThetaZ() << "\n"
192  << " Wire pitch: " << tpcgeom.WirePitch() << "\n"
193  << " Time offset: "
194  << detprop->GetXTicksOffset(plane,tpc,cstat) << "\n";
195  }
196 
197  if(orient != geo::kVertical)
198  throw cet::exception("SpacePointAlg")
199  << "Horizontal wire geometry not implemented.\n";
200  }// end loop over planes
201  }// end loop over tpcs
202  }// end loop over cryostats
203  }
204 
205 
206 
207  //----------------------------------------------------------------------
208  // Get corrected time for the specified hit.
210  {
211  // Get services.
212 
214  const detinfo::DetectorProperties* detprop = lar::providerFrom<detinfo::DetectorPropertiesService>();
215 
216  // Correct time for trigger offset and plane-dependent time offsets.
217 
218  double t = hit.PeakTime() - detprop->GetXTicksOffset(hit.WireID().Plane,hit.WireID().TPC,hit.WireID().Cryostat);
219 
220  return t;
221  }
222 
223  //----------------------------------------------------------------------
224  // Spatial separation of hits (zero if two or fewer).
226  {
227  // Get geometry service.
228 
230 
231  // Trivial case - fewer than three hits.
232 
233  if(hits.size() < 3)
234  return 0.;
235 
236  // Error case - more than three hits.
237 
238  if(hits.size() > 3) {
239  mf::LogError("SpacePointAlg") << "Method separation called with more than three htis.";
240  return 0.;
241  }
242 
243  // Got exactly three hits.
244 
245  // Calculate angles and distance of each hit from origin.
246 
247  double dist[3] = {0., 0., 0.};
248  double sinth[3] = {0., 0., 0.};
249  double costh[3] = {0., 0., 0.};
250  unsigned int cstats[3];
251  unsigned int tpcs[3];
252  unsigned int planes[3];
253 
254  for(int i=0; i<3; ++i) {
255 
256  // Get tpc, plane, wire.
257 
258  const recob::Hit& hit = *(hits[i]);
259  const geo::WireGeo& wgeom = geom->WireIDToWireGeo(hit.WireID());
260  cstats[i] = hit.WireID().Cryostat;
261  tpcs[i] = hit.WireID().TPC;
262  planes[i] = hit.WireID().Plane;
263 
264  // Check tpc and plane errors.
265 
266  for(int j=0; j<i; ++j) {
267 
268  if(cstats[j] != hit.WireID().Cryostat) {
269  mf::LogError("SpacePointAlg") << "Method separation called with hits from multiple cryostats..";
270  return 0.;
271  }
272 
273  if(tpcs[j] != hit.WireID().TPC) {
274  mf::LogError("SpacePointAlg") << "Method separation called with hits from multiple tpcs..";
275  return 0.;
276  }
277 
278  if(planes[j] == hit.WireID().Plane ) {
279  mf::LogError("SpacePointAlg") << "Method separation called with hits from the same plane..";
280  return 0.;
281  }
282  }
283 
284  // Get angles and distance of wire.
285 
286  double hl = wgeom.HalfL();
287  double xyz[3];
288  double xyz1[3];
289  wgeom.GetCenter(xyz);
290  wgeom.GetCenter(xyz1, hl);
291  double s = (xyz1[1] - xyz[1]) / hl;
292  double c = (xyz1[2] - xyz[2]) / hl;
293  sinth[hit.WireID().Plane] = s;
294  costh[hit.WireID().Plane] = c;
295  dist[hit.WireID().Plane] = xyz[2] * s - xyz[1] * c;
296  }
297 
298  double S = ((sinth[1] * costh[2] - costh[1] * sinth[2]) * dist[0]
299  +(sinth[2] * costh[0] - costh[2] * sinth[0]) * dist[1]
300  +(sinth[0] * costh[1] - costh[0] * sinth[1]) * dist[2]);
301  return S;
302  }
303 
304  //----------------------------------------------------------------------
305  // Check hits for compatibility.
306  // Check hits pairwise for different views and maximum time difference.
307  // Check three hits for spatial compatibility.
309  bool useMC) const
310  {
311  // Get services.
312 
314  const detinfo::DetectorProperties* detprop = lar::providerFrom<detinfo::DetectorPropertiesService>();
315 
316  int nhits = hits.size();
317 
318  // Fewer than two or more than three hits can never be compatible.
319 
320  bool result = nhits >= 2 && nhits <= 3;
321  bool mc_ok = true;
322  unsigned int tpc = 0;
323  unsigned int cstat = 0;
324 
325  if(result) {
326 
327  // First do pairwise tests.
328  // Do double loop over hits.
329 
330  for(int ihit1 = 0; result && ihit1 < nhits-1; ++ihit1) {
331  const recob::Hit& hit1 = *(hits[ihit1]);
332  geo::WireID hit1WireID = hit1.WireID();
333  geo::View_t view1 = hit1.View();
334 
335  double t1 = hit1.PeakTime() - detprop->GetXTicksOffset(hit1WireID.Plane,hit1WireID.TPC,hit1WireID.Cryostat);
336 
337  // If using mc information, get a collection of track ids for hit 1.
338  // If not using mc information, this section of code will trigger the
339  // insertion of a single invalid HitMCInfo object into fHitMCMap.
340 
341  const HitMCInfo& mcinfo1 = fHitMCMap[(useMC ? &hit1 : 0)];
342  const std::vector<int>& tid1 = mcinfo1.trackIDs;
343  bool only_neg1 = tid1.size() > 0 && tid1.back() < 0;
344 
345  // Loop over second hit.
346 
347  for(int ihit2 = ihit1+1; result && ihit2 < nhits; ++ihit2) {
348  const recob::Hit& hit2 = *(hits[ihit2]);
349  geo::WireID hit2WireID = hit2.WireID();
350  geo::View_t view2 = hit2.View();
351 
352  // Test for same tpc and different views.
353 
354  result = result && hit1WireID.TPC == hit2WireID.TPC && view1 != view2 && hit1WireID.Cryostat == hit2WireID.Cryostat;
355  if(result) {
356 
357  // Remember which tpc and cryostat we are in.
358 
359  tpc = hit1WireID.TPC;
360  cstat = hit1WireID.Cryostat;
361 
362  double t2 = hit2.PeakTime() - detprop->GetXTicksOffset(hit2WireID.Plane,hit2WireID.TPC,hit2WireID.Cryostat);
363 
364  // Test maximum time difference.
365 
366  result = result && std::abs(t1-t2) <= fMaxDT;
367 
368  // Test mc truth.
369 
370  if(result && useMC) {
371 
372  // Test whether hits have a common parent track id.
373 
374  const HitMCInfo& mcinfo2 = fHitMCMap[&hit2];
375  std::vector<int> tid2 = mcinfo2.trackIDs;
376  bool only_neg2 = tid2.size() > 0 && tid2.back() < 0;
378  std::set_intersection(tid1.begin(), tid1.end(),
379  tid2.begin(), tid2.end(),
380  tid2.begin());
381  tid2.resize(it - tid2.begin());
382 
383  // Hits are compatible if they have parents in common.
384  // If the only parent id in common is negative (-999),
385  // then hits are compatible only if both hits have only
386  // negative parent tracks.
387 
388  bool only_neg3 = tid2.size() > 0 && tid2.back() < 0;
389  mc_ok = tid2.size() > 0 && (!only_neg3 || (only_neg1 && only_neg2));
390  result = result && mc_ok;
391 
392  // If we are still OK, check that either hit is
393  // the nearest neighbor of the other.
394 
395  if(result) {
396  result = mcinfo1.pchit[hit2WireID.Plane] == &hit2 ||
397  mcinfo2.pchit[hit1WireID.Plane] == &hit1;
398  }
399  }
400  }
401  }
402  }
403 
404  // If there are exactly three hits, and they pass pairwise tests, check
405  // for spatial compatibility.
406 
407  if(result && nhits == 3) {
408 
409  // Loop over hits.
410 
411  double dist[3] = {0., 0., 0.};
412  double sinth[3] = {0., 0., 0.};
413  double costh[3] = {0., 0., 0.};
414 
415  for(int i=0; i<3; ++i) {
416 
417  // Get tpc, plane, wire.
418 
419  const recob::Hit& hit = *(hits[i]);
420  geo::WireID hitWireID = hit.WireID();
421 
422  const geo::WireGeo& wgeom = geom->WireIDToWireGeo(hit.WireID());
423  if ((hitWireID.TPC != tpc) || (hitWireID.Cryostat != cstat))
424  throw cet::exception("SpacePointAlg") << "compatible(): geometry mismatch\n";
425 
426  // Get angles and distance of wire.
427 
428  double hl = wgeom.HalfL();
429  double xyz[3];
430  double xyz1[3];
431  wgeom.GetCenter(xyz);
432  wgeom.GetCenter(xyz1, hl);
433  double s = (xyz1[1] - xyz[1]) / hl;
434  double c = (xyz1[2] - xyz[2]) / hl;
435  sinth[hit.WireID().Plane] = s;
436  costh[hit.WireID().Plane] = c;
437  dist[hit.WireID().Plane] = xyz[2] * s - xyz[1] * c;
438  }
439 
440  // Do space cut.
441 
442  double S = ((sinth[1] * costh[2] - costh[1] * sinth[2]) * dist[0]
443  +(sinth[2] * costh[0] - costh[2] * sinth[0]) * dist[1]
444  +(sinth[0] * costh[1] - costh[0] * sinth[1]) * dist[2]);
445 
446  result = result && std::abs(S) < fMaxS;
447  }
448  }
449 
450  // Done.
451 
452  return result;
453  }
454 
455  //----------------------------------------------------------------------
456  // Fill one space point using a colleciton of hits.
457  // Assume points have already been tested for compatibility.
458  //
460  std::vector<recob::SpacePoint> &sptv,
461  int sptid) const
462  {
463  // Get services.
464 
466  const detinfo::DetectorProperties* detprop = lar::providerFrom<detinfo::DetectorPropertiesService>();
467 
468  double timePitch=detprop->GetXTicksCoefficient();
469 
470  int nhits = hits.size();
471 
472  // Remember associated hits internally.
473 
474  if (fSptHitMap.find(sptid) != fSptHitMap.end())
475  throw cet::exception("SpacePointAlg") << "fillSpacePoint(): hit already present!\n";
476  fSptHitMap[sptid] = hits;
477 
478  // Calculate position and error matrix.
479 
480  double xyz[3] = {0., 0., 0.};
481  double errxyz[6] = {0.,
482  0., 0.,
483  0., 0., 0.};
484 
485  // Calculate x using drift times.
486  // Loop over all hits and calculate the weighted average drift time.
487  // Also calculate time variance and chisquare.
488 
489  double sumt2w = 0.;
490  double sumtw = 0.;
491  double sumw = 0.;
492 
493 
495  ihit != hits.end(); ++ihit) {
496 
497  const recob::Hit& hit = **ihit;
498  geo::WireID hitWireID = hit.WireID();
499 
500  // Correct time for trigger offset and view-dependent time offsets.
501 
502  double t0 = detprop->GetXTicksOffset(hitWireID.Plane, hitWireID.TPC, hitWireID.Cryostat);
503  double t = hit.PeakTime() - t0;
504  double et = hit.SigmaPeakTime();
505  double w = 1./(et*et);
506 
507  sumt2w += w*t*t;
508  sumtw += w*t;
509  sumw += w;
510  }
511 
512  double drift_time = 0.;
513  double var_time = 0.;
514  double chisq = 0.;
515  if(sumw != 0.) {
516  drift_time = sumtw / sumw;
517  //var_time = sumt2w / sumw - drift_time * drift_time;
518  var_time = 1. / sumw;
519  if(var_time < 0.)
520  var_time = 0.;
521  chisq = sumt2w - sumtw * drift_time;
522  if(chisq < 0.)
523  chisq = 0.;
524  }
525  xyz[0] = drift_time * timePitch;
526  errxyz[0] = var_time * timePitch * timePitch;
527 
528  // Calculate y, z using wires (need at least two hits).
529 
530  if(nhits >= 2) {
531 
532  // Calculate y and z by chisquare minimization of wire coordinates.
533 
534  double sw = 0.; // sum w_i
535  double sus = 0.; // sum w_i u_i sin_th_i
536  double suc = 0.; // sum w_i u_i cos_th_i
537  double sc2 = 0.; // sum w_i cos2_th_i
538  double ss2 = 0.; // sum w_i sin2_th_i
539  double ssc = 0.; // sum w_i sin_th_i cos_th_i
540 
541  // Loop over points.
542 
544  ihit != hits.end(); ++ihit) {
545 
546  const recob::Hit& hit = **ihit;
547  geo::WireID hitWireID = hit.WireID();
548  const geo::WireGeo& wgeom = geom->WireIDToWireGeo(hit.WireID());
549 
550  // Calculate angle and wire coordinate in this view.
551 
552  double hl = wgeom.HalfL();
553  double cen[3];
554  double cen1[3];
555  wgeom.GetCenter(cen);
556  wgeom.GetCenter(cen1, hl);
557  double s = (cen1[1] - cen[1]) / hl;
558  double c = (cen1[2] - cen[2]) / hl;
559  double u = cen[2] * s - cen[1] * c;
560  double eu = geom->WirePitch(hitWireID.Plane, hitWireID.TPC) / std::sqrt(12.);
561  double w = 1. / (eu * eu);
562 
563  // Summations
564 
565  sw += w;
566  sus += w*u*s;
567  suc += w*u*c;
568  sc2 += w*c*c;
569  ss2 += w*s*s;
570  ssc += w*s*c;
571  }
572 
573  // Calculate y,z
574 
575  double denom = sc2 * ss2 - ssc * ssc;
576  if(denom != 0.) {
577  xyz[1] = (-suc * ss2 + sus * ssc) / denom;
578  xyz[2] = (sus * sc2 - suc * ssc) / denom;
579  errxyz[2] = ss2 / denom;
580  errxyz[4] = ssc / denom;
581  errxyz[5] = sc2 / denom;
582  }
583 
584  // Make space point.
585 
586  recob::SpacePoint spt(xyz, errxyz, chisq, sptid);
587  sptv.push_back(spt);
588  }
589  return;
590  }
591 
610  void SpacePointAlg::fillSpacePoints(std::vector<recob::SpacePoint>& spts,
611  std::multimap<double, KHitTrack> const& trackMap) const
612  {
613  // Loop over KHitTracks.
614 
616  art::PtrVector<recob::Hit> compatible_hits;
617  for(std::multimap<double, KHitTrack>::const_iterator it = trackMap.begin();
618  it != trackMap.end(); ++it) {
619  const KHitTrack& track = (*it).second;
620 
621  // Extrack Hit from track.
622 
623  const std::shared_ptr<const KHitBase>& hit = track.getHit();
624  const KHitWireX* phit = dynamic_cast<const KHitWireX*>(&*hit);
625  if(phit != 0) {
626  const art::Ptr<recob::Hit> prhit = phit->getHit();
627 
628  // Test this hit for compatibility.
629 
630  hits.push_back(prhit);
631  bool ok = this->compatible(hits);
632  if(!ok) {
633 
634  // The new hit is not compatible. Make a space point out of
635  // the last known compatible hits, provided there are at least
636  // two.
637 
638  if(compatible_hits.size() >= 2) {
639  this->fillSpacePoint(compatible_hits, spts, this->numHitMap());
640  compatible_hits.clear();
641  }
642 
643  // Forget about any previous hits.
644 
645  hits.clear();
646  hits.push_back(prhit);
647  }
648 
649  // Update the list of known compatible hits.
650 
651  compatible_hits = hits;
652  }
653  }
654 
655  // Maybe make one final space point.
656 
657  if(compatible_hits.size() >= 2) {
658  this->fillSpacePoint(compatible_hits, spts, this->numHitMap());
659  }
660  }
661 
662  //----------------------------------------------------------------------
663  // Fill one space point using a colleciton of hits.
664  // Assume points have already been tested for compatibility.
665  // This version assumes there can be multiple hits per view,
666  // and gives unequal weight to different hits.
667  //
668  void SpacePointAlg::
670  std::vector<recob::SpacePoint>& sptv,
671  int sptid) const
672  {
673  // Get services.
674 
676  const detinfo::DetectorProperties* detprop = lar::providerFrom<detinfo::DetectorPropertiesService>();
677 
678  // Calculate time pitch.
679 
680  double timePitch = detprop->GetXTicksCoefficient(); // cm / tick
681 
682  // Figure out which tpc we are in.
683 
684  unsigned int tpc0 = 0;
685  unsigned int cstat0 = 0;
686  int nhits = hits.size();
687  if(nhits > 0) {
688  tpc0 = hits.front()->WireID().TPC;
689  cstat0=hits.front()->WireID().Cryostat;
690  }
691 
692  // Remember associated hits internally.
693 
694  if(fSptHitMap.count(sptid) != 0)
695  throw cet::exception("SpacePointAlg") << "fillComplexSpacePoint(): hit already present!\n";
696  fSptHitMap[sptid] = hits;
697 
698  // Do a preliminary scan of hits.
699  // Determine weight given to hits in each view.
700 
701  unsigned int nplanes = geom->Cryostat(cstat0).TPC(tpc0).Nplanes();
702  std::vector<int> numhits(nplanes, 0);
703  std::vector<double> weight(nplanes, 0.);
704 
706  ihit != hits.end(); ++ihit) {
707 
708  const recob::Hit& hit = **ihit;
709  geo::WireID hitWireID = hit.WireID();
710  /* // kept as assertions for performance reasons
711  if (hitWireID.Cryostat != cstat0)
712  throw cet::exception("SpacePointAlg") << "fillComplexSpacePoint(): incompatible cryostat\n";
713  if (hitWireID.TPC != tpc0);
714  throw cet::exception("SpacePointAlg") << "fillComplexSpacePoint(): incompatible TPC\n";
715  if (hitWireID.Plane >= nplanes);
716  throw cet::exception("SpacePointAlg") << "fillComplexSpacePoint(): unknown plane\n";
717  */
718  assert(hitWireID.Cryostat == cstat0);
719  assert(hitWireID.TPC == tpc0);
720  assert(hitWireID.Plane < nplanes);
721  ++numhits[hitWireID.Plane];
722  }
723 
724  for(unsigned int plane = 0; plane < nplanes; ++plane) {
725  double np = numhits[plane];
726  if(np > 0.)
727  weight[plane] = 1. / (np*np*np);
728  }
729 
730  // Calculate position and error matrix.
731 
732  double xyz[3] = {0., 0., 0.};
733  double errxyz[6] = {0.,
734  0., 0.,
735  0., 0., 0.};
736 
737  // Calculate x using drift times.
738  // Loop over all hits and calculate the weighted average drift time.
739  // Also calculate time variance and chisquare.
740 
741  double sumt2w = 0.;
742  double sumtw = 0.;
743  double sumw = 0.;
744 
746  ihit != hits.end(); ++ihit) {
747 
748  const recob::Hit& hit = **ihit;
749  geo::WireID hitWireID = hit.WireID();
750 
751  // Correct time for trigger offset and view-dependent time offsets.
752 
753  double t0 = detprop->GetXTicksOffset(hitWireID.Plane,hitWireID.TPC,hitWireID.Cryostat);
754  double t = hit.PeakTime() - t0;
755  double et = hit.SigmaPeakTime();
756  double w = weight[hitWireID.Plane]/(et*et);
757 
758  sumt2w += w*t*t;
759  sumtw += w*t;
760  sumw += w;
761  }
762 
763  double drift_time = 0.;
764  double var_time = 0.;
765  double chisq = 0.;
766  if(sumw != 0.) {
767  drift_time = sumtw / sumw;
768  var_time = sumt2w / sumw - drift_time * drift_time;
769  if(var_time < 0.)
770  var_time = 0.;
771  chisq = sumt2w - sumtw * drift_time;
772  if(chisq < 0.)
773  chisq = 0.;
774  }
775  xyz[0] = drift_time * timePitch;
776  errxyz[0] = var_time * timePitch * timePitch;
777 
778  // Calculate y, z using wires (need at least two hits).
779 
780  if(nhits >= 2) {
781 
782  // Calculate y and z by chisquare minimization of wire coordinates.
783 
784  double sw = 0.; // sum w_i
785  double sus = 0.; // sum w_i u_i sin_th_i
786  double suc = 0.; // sum w_i u_i cos_th_i
787  double sc2 = 0.; // sum w_i cos2_th_i
788  double ss2 = 0.; // sum w_i sin2_th_i
789  double ssc = 0.; // sum w_i sin_th_i cos_th_i
790 
791  // Loop over points.
792 
794  ihit != hits.end(); ++ihit) {
795 
796  const recob::Hit& hit = **ihit;
797  geo::WireID hitWireID = hit.WireID();
798  const geo::WireGeo& wgeom = geom->WireIDToWireGeo(hit.WireID());
799 
800  // Calculate angle and wire coordinate in this view.
801 
802  double hl = wgeom.HalfL();
803  double cen[3];
804  double cen1[3];
805  wgeom.GetCenter(cen);
806  wgeom.GetCenter(cen1, hl);
807  double s = (cen1[1] - cen[1]) / hl;
808  double c = (cen1[2] - cen[2]) / hl;
809  double u = cen[2] * s - cen[1] * c;
810  double eu = geom->WirePitch(hitWireID.Plane, hitWireID.TPC) / std::sqrt(12.);
811  double w = weight[hitWireID.Plane] / (eu * eu);
812 
813  // Summations
814 
815  sw += w;
816  sus += w*u*s;
817  suc += w*u*c;
818  sc2 += w*c*c;
819  ss2 += w*s*s;
820  ssc += w*s*c;
821  }
822 
823  // Calculate y,z
824 
825  double denom = sc2 * ss2 - ssc * ssc;
826  if(denom != 0.) {
827  xyz[1] = (-suc * ss2 + sus * ssc) / denom;
828  xyz[2] = (sus * sc2 - suc * ssc) / denom;
829  errxyz[2] = ss2 / denom;
830  errxyz[4] = ssc / denom;
831  errxyz[5] = sc2 / denom;
832  }
833 
834  // Make space point.
835 
836  recob::SpacePoint spt(xyz, errxyz, chisq, sptid);
837  sptv.push_back(spt);
838  }
839  return;
840  }
841 
842  //----------------------------------------------------------------------
843  // Fill a vector of space points for all compatible combinations of hits
844  // from an input vector of hits (non-mc-truth version).
845  //
847  std::vector<recob::SpacePoint>& spts) const
848  {
849  makeSpacePoints(hits, spts, false);
850  }
851 
852  //----------------------------------------------------------------------
853  // Fill a vector of space points for all compatible combinations of hits
854  // from an input vector of hits (mc-truth version).
855  //
857  std::vector<recob::SpacePoint>& spts) const
858  {
859  makeSpacePoints(hits, spts, true);
860  }
861 
862  //----------------------------------------------------------------------
863  // Fill a vector of space points for all compatible combinations of hits
864  // from an input vector of hits (general version).
865  //
867  std::vector<recob::SpacePoint>& spts,
868  bool useMC) const
869  {
870  // Get services.
871 
873  const detinfo::DetectorProperties* detprop = lar::providerFrom<detinfo::DetectorPropertiesService>();
874 
875  // Clear space point to hit map.
876 
877  fSptHitMap.clear();
878 
879  // Print diagnostic information.
880 
881  update();
882 
883  // First make sure result vector is empty.
884 
885  spts.erase(spts.begin(), spts.end());
886 
887  // Statistics.
888 
889  int n2 = 0; // Number of two-hit space points.
890  int n3 = 0; // Number of three-hit space points.
891  int n2filt = 0; // Number of two-hit space points after filtering/merging.
892  int n3filt = 0; // Number of three-hit space pointe after filtering/merging.
893 
894  // Sort hits into maps indexed by [cryostat][tpc][plane][wire].
895  // If using mc information, also generate maps of sim::IDEs and mc
896  // position indexed by hit.
897 
898  std::vector< std::vector<std::vector<std::multimap<unsigned int, art::Ptr<recob::Hit> > > > > hitmap;
899  fHitMCMap.clear();
900 
901  unsigned int ncstat = geom->Ncryostats();
902  hitmap.resize(ncstat);
903  for(unsigned int cstat = 0; cstat < ncstat; ++cstat){
904  unsigned int ntpc = geom->Cryostat(cstat).NTPC();
905  hitmap[cstat].resize(ntpc);
906  for(unsigned int tpc = 0; tpc < ntpc; ++tpc) {
907  int nplane = geom->Cryostat(cstat).TPC(tpc).Nplanes();
908  hitmap[cstat][tpc].resize(nplane);
909  }
910  }
911 
912  for(art::PtrVector<recob::Hit>::const_iterator ihit = hits.begin(); ihit != hits.end(); ++ihit) {
913  const art::Ptr<recob::Hit>& phit = *ihit;
914  geo::View_t view = phit->View();
915  if((view == geo::kU && fEnableU) ||
916  (view == geo::kV && fEnableV) ||
917  (view == geo::kZ && fEnableW)) {
918  geo::WireID phitWireID = phit->WireID();
919  hitmap[phitWireID.Cryostat][phitWireID.TPC][phitWireID.Plane].insert(std::make_pair(phitWireID.Wire, phit));
920  }
921  }
922 
923  // Fill mc information, including IDEs and closest neighbors
924  // of each hit.
927  if(useMC) {
929 
930  // First loop over hits and fill track ids and mc position.
931  for(unsigned int cstat = 0; cstat < ncstat; ++cstat){
932  for(unsigned int tpc = 0; tpc < geom->Cryostat(cstat).NTPC(); ++tpc) {
933  int nplane = geom->Cryostat(cstat).TPC(tpc).Nplanes();
934  for(int plane = 0; plane < nplane; ++plane) {
935  for(std::map<unsigned int, art::Ptr<recob::Hit> >::const_iterator ihit = hitmap[cstat][tpc][plane].begin();
936  ihit != hitmap[cstat][tpc][plane].end(); ++ihit) {
937  const art::Ptr<recob::Hit>& phit = ihit->second;
938  const recob::Hit& hit = *phit;
939  HitMCInfo& mcinfo = fHitMCMap[&hit]; // Default HitMCInfo.
940 
941  // Fill default nearest neighbor information (i.e. none).
942 
943  mcinfo.pchit.resize(nplane, 0);
944  mcinfo.dist2.resize(nplane, 1.e20);
945 
946  // Get sim::IDEs for this hit.
947 
948  std::vector<sim::IDE> ides = bt_serv->HitToAvgSimIDEs(phit);
949 
950  // Get sorted track ids. for this hit.
951 
952  mcinfo.trackIDs.reserve(ides.size());
953  for(std::vector<sim::IDE>::const_iterator i = ides.begin();
954  i != ides.end(); ++i)
955  mcinfo.trackIDs.push_back(i->trackID);
956  sort(mcinfo.trackIDs.begin(), mcinfo.trackIDs.end());
957 
958  // Get position of ionization for this hit.
959 
960  try {
961  mcinfo.xyz = bt_serv->SimIDEsToXYZ(ides);
962  }
963  catch(cet::exception& x) {
964  mcinfo.xyz.clear();
965  }
966  } // end loop over ihit
967  }// end loop oer planes
968  }// end loop over TPCs
969  }// end loop over cryostats
970 
971  // Loop over hits again and fill nearest neighbor information for real.
972  for(unsigned int cstat = 0; cstat < ncstat; ++cstat){
973  for(unsigned int tpc = 0; tpc < geom->Cryostat(cstat).NTPC(); ++tpc) {
974  int nplane = geom->Cryostat(cstat).TPC(tpc).Nplanes();
975  for(int plane = 0; plane < nplane; ++plane) {
976  for(std::map<unsigned int, art::Ptr<recob::Hit> >::const_iterator ihit = hitmap[cstat][tpc][plane].begin();
977  ihit != hitmap[cstat][tpc][plane].end(); ++ihit) {
978  const art::Ptr<recob::Hit>& phit = ihit->second;
979  const recob::Hit& hit = *phit;
980  HitMCInfo& mcinfo = fHitMCMap[&hit];
981  if(mcinfo.xyz.size() != 0) {
982  assert(mcinfo.xyz.size() == 3);
983 
984  // Fill nearest neighbor information for this hit.
985 
986  for(int plane2 = 0; plane2 < nplane; ++plane2) {
987  for(std::map<unsigned int, art::Ptr<recob::Hit> >::const_iterator jhit = hitmap[cstat][tpc][plane2].begin();
988  jhit != hitmap[cstat][tpc][plane2].end(); ++jhit) {
989  const art::Ptr<recob::Hit>& phit2 = jhit->second;
990  const recob::Hit& hit2 = *phit2;
991  const HitMCInfo& mcinfo2 = fHitMCMap[&hit2];
992 
993 
994  if(mcinfo2.xyz.size() != 0) {
995  assert(mcinfo2.xyz.size() == 3);
996  double dx = mcinfo.xyz[0] - mcinfo2.xyz[0];
997  double dy = mcinfo.xyz[1] - mcinfo2.xyz[1];
998  double dz = mcinfo.xyz[2] - mcinfo2.xyz[2];
999  double dist2 = dx*dx + dy*dy + dz*dz;
1000  if(dist2 < mcinfo.dist2[plane2]) {
1001  mcinfo.dist2[plane2] = dist2;
1002  mcinfo.pchit[plane2] = &hit2;
1003  }
1004  }// end if mcinfo2.xyz valid
1005  }// end loop over jhit
1006  }// end loop over plane2
1007  }// end if mcinfo.xyz valid.
1008  }// end loop over ihit
1009  }// end loop over plane
1010  }// end loop over tpc
1011  }// end loop over cryostats
1012  }// end if MC
1013 
1014  // use mf::LogDebug instead of LOG_DEBUG because we reuse it in many lines
1015  // insertions are protected by mf::isDebugEnabled()
1016  mf::LogDebug debug("SpacePointAlg");
1017  if (mf::isDebugEnabled()) {
1018  debug << "Total hits = " << hits.size() << "\n\n";
1019 
1020  for(unsigned int cstat = 0; cstat < ncstat; ++cstat){
1021  for(unsigned int tpc = 0; tpc < geom->Cryostat(cstat).NTPC(); ++tpc) {
1022  int nplane = hitmap[cstat][tpc].size();
1023  for(int plane = 0; plane < nplane; ++plane) {
1024  debug << "TPC, Plane: " << tpc << ", " << plane
1025  << ", hits = " << hitmap[cstat][tpc][plane].size() << "\n";
1026  }
1027  }
1028  } // end loop over cryostats
1029  } // if debug
1030 
1031  // Make empty multimap from hit pointer on preferred
1032  // (most-populated or collection) plane to space points that
1033  // include that hit (used for sorting, filtering, and
1034  // merging).
1035 
1036  typedef const recob::Hit* sptkey_type;
1037  std::multimap<sptkey_type, recob::SpacePoint> sptmap;
1038  std::set<sptkey_type> sptkeys; // Keys of multimap.
1039 
1040  // Loop over TPCs.
1041  for(unsigned int cstat = 0; cstat < ncstat; ++cstat){
1042  for(unsigned int tpc = 0; tpc < geom->Cryostat(cstat).NTPC(); ++tpc) {
1043 
1044  geo::TPCID tpcid(cstat, tpc);
1045 
1046  // Sort maps in increasing order of number of hits.
1047  // This is so that we can do the outer loops over hits
1048  // over the views with fewer hits.
1049  //
1050  // If config parameter PreferColl is true, treat the colleciton
1051  // plane as if it had the most hits, regardless of how many
1052  // hits it actually has. This will force space points to be
1053  // filtered and merged with respect to the collection plane
1054  // wires. It will also force space points to be sorted by
1055  // collection plane wire.
1056 
1057  int nplane = hitmap[cstat][tpc].size();
1058  std::vector<int> index(nplane);
1059 
1060  for(int i=0; i<nplane; ++i)
1061  index[i] = i;
1062 
1063  for(int i=0; i<nplane-1; ++i) {
1064 
1065  for(int j=i+1; j<nplane; ++j) {
1066  bool icoll = fPreferColl &&
1067  geom->SignalType(geo::PlaneID(tpcid, index[i])) == geo::kCollection;
1068  bool jcoll = fPreferColl &&
1069  geom->SignalType(geo::PlaneID(tpcid, index[j])) == geo::kCollection;
1070  if((hitmap[cstat][tpc][index[i]].size() > hitmap[cstat][tpc][index[j]].size() &&
1071  !jcoll) || icoll) {
1072  int temp = index[i];
1073  index[i] = index[j];
1074  index[j] = temp;
1075  }
1076  }
1077  }// end loop over i
1078 
1079  // how many views with hits?
1080  // This will allow for the special case where we might have only 2 planes of information and
1081  // still want space points even if a three plane TPC
1082  std::vector<std::multimap<unsigned int, art::Ptr<recob::Hit>>>& hitsByPlaneVec = hitmap[cstat][tpc];
1083  int nViewsWithHits(0);
1084 
1085  for(int i = 0; i < nplane; i++)
1086  {
1087  if (hitsByPlaneVec[index[i]].size() > 0) nViewsWithHits++;
1088  }
1089 
1090  // If two-view space points are allowed, make a double loop
1091  // over hits and produce space points for compatible hit-pairs.
1092 
1093  if((nViewsWithHits == 2 || nplane == 2) && fMinViews <= 2) {
1094 
1095  // Loop over pairs of views.
1096  for(int i=0; i<nplane-1; ++i) {
1097  unsigned int plane1 = index[i];
1098 
1099  if (hitmap[cstat][tpc][plane1].empty()) continue;
1100 
1101  for(int j=i+1; j<nplane; ++j) {
1102  unsigned int plane2 = index[j];
1103 
1104  if (hitmap[cstat][tpc][plane2].empty()) continue;
1105 
1106  // Get angle, pitch, and offset of plane2 wires.
1107  const geo::WireGeo& wgeo2 = geom->Cryostat(cstat).TPC(tpc).Plane(plane2).Wire(0);
1108  double hl2 = wgeo2.HalfL();
1109  double xyz21[3];
1110  double xyz22[3];
1111  wgeo2.GetCenter(xyz21, -hl2);
1112  wgeo2.GetCenter(xyz22, hl2);
1113  double s2 = (xyz22[1] - xyz21[1]) / (2.*hl2);
1114  double c2 = (xyz22[2] - xyz21[2]) / (2.*hl2);
1115  double dist2 = -xyz21[1] * c2 + xyz21[2] * s2;
1116  double pitch2 = geom->WirePitch(plane2, tpc, cstat);
1117 
1118  if(!fPreferColl && hitmap[cstat][tpc][plane1].size() > hitmap[cstat][tpc][plane2].size())
1119  throw cet::exception("SpacePointAlg") << "makeSpacePoints(): hitmaps with incompatible size\n";
1120 
1121 
1122  // Loop over pairs of hits.
1123 
1125  hitvec.reserve(2);
1126 
1127  for(std::map<unsigned int, art::Ptr<recob::Hit> >::const_iterator
1128  ihit1 = hitmap[cstat][tpc][plane1].begin();
1129  ihit1 != hitmap[cstat][tpc][plane1].end(); ++ihit1) {
1130 
1131  const art::Ptr<recob::Hit>& phit1 = ihit1->second;
1132  geo::WireID phit1WireID = phit1->WireID();
1133  const geo::WireGeo& wgeo = geom->WireIDToWireGeo(phit1WireID);
1134 
1135  // Get endpoint coordinates of this wire.
1136  // (kept as assertions for performance reasons)
1137  assert(phit1WireID.Cryostat == cstat);
1138  assert(phit1WireID.TPC == tpc);
1139  assert(phit1WireID.Plane == plane1);
1140  double hl1 = wgeo.HalfL();
1141  double xyz1[3];
1142  double xyz2[3];
1143  wgeo.GetCenter(xyz1, -hl1);
1144  wgeo.GetCenter(xyz2, hl1);
1145 
1146  // Find the plane2 wire numbers corresponding to the endpoints.
1147 
1148  double wire21 = (-xyz1[1] * c2 + xyz1[2] * s2 - dist2) / pitch2;
1149  double wire22 = (-xyz2[1] * c2 + xyz2[2] * s2 - dist2) / pitch2;
1150 
1151  int wmin = std::max(0., std::min(wire21, wire22));
1152  int wmax = std::max(0., std::max(wire21, wire22) + 1.);
1153 
1154  std::map<unsigned int, art::Ptr<recob::Hit> >::const_iterator
1155  ihit2 = hitmap[cstat][tpc][plane2].lower_bound(wmin),
1156  ihit2end = hitmap[cstat][tpc][plane2].upper_bound(wmax);
1157 
1158  for(; ihit2 != ihit2end; ++ihit2) {
1159 
1160  const art::Ptr<recob::Hit>& phit2 = ihit2->second;
1161 
1162  // Check current pair of hits for compatibility.
1163  // By construction, hits should always have compatible views
1164  // and times, but may not have compatible mc information.
1165 
1166  hitvec.clear();
1167  hitvec.push_back(phit1);
1168  hitvec.push_back(phit2);
1169  bool ok = compatible(hitvec, useMC);
1170  if(ok) {
1171 
1172  // Add a space point.
1173 
1174  ++n2;
1175 
1176  // make a dummy vector of recob::SpacePoints
1177  // as we are filtering or merging and don't want to
1178  // add the created SpacePoint to the final collection just yet
1179  // This dummy vector will hold just one recob::SpacePoint,
1180  // which will go into the multimap and then the vector
1181  // will go out of scope.
1182 
1183  std::vector<recob::SpacePoint> sptv;
1184  fillSpacePoint(hitvec, sptv, sptmap.size());
1185  sptkey_type key = &*phit2;
1186  sptmap.insert(std::pair<sptkey_type, recob::SpacePoint>(key, sptv.back()));
1187  sptkeys.insert(key);
1188  }
1189  }
1190  }
1191  }
1192  }
1193  }// end if fMinViews <= 2
1194 
1195  // If three-view space points are allowed, make a triple loop
1196  // over hits and produce space points for compatible triplets.
1197 
1198  if(nplane >= 3 && fMinViews <= 3) {
1199 
1200  // Loop over triplets of hits.
1201 
1203  hitvec.reserve(3);
1204 
1205  unsigned int plane1 = index[0];
1206  unsigned int plane2 = index[1];
1207  unsigned int plane3 = index[2];
1208 
1209  // Get angle, pitch, and offset of plane1 wires.
1210 
1211  const geo::WireGeo& wgeo1 = geom->Cryostat(cstat).TPC(tpc).Plane(plane1).Wire(0);
1212  double hl1 = wgeo1.HalfL();
1213  double xyz11[3];
1214  double xyz12[3];
1215  wgeo1.GetCenter(xyz11, -hl1);
1216  wgeo1.GetCenter(xyz12, hl1);
1217  double s1 = (xyz12[1] - xyz11[1]) / (2.*hl1);
1218  double c1 = (xyz12[2] - xyz11[2]) / (2.*hl1);
1219  double dist1 = -xyz11[1] * c1 + xyz11[2] * s1;
1220  double pitch1 = geom->WirePitch(plane1, tpc, cstat);
1221  const double TicksOffset1 = detprop->GetXTicksOffset(plane1,tpc,cstat);
1222 
1223  // Get angle, pitch, and offset of plane2 wires.
1224 
1225  const geo::WireGeo& wgeo2 = geom->Cryostat(cstat).TPC(tpc).Plane(plane2).Wire(0);
1226  double hl2 = wgeo2.HalfL();
1227  double xyz21[3];
1228  double xyz22[3];
1229  wgeo2.GetCenter(xyz21, -hl2);
1230  wgeo2.GetCenter(xyz22, hl2);
1231  double s2 = (xyz22[1] - xyz21[1]) / (2.*hl2);
1232  double c2 = (xyz22[2] - xyz21[2]) / (2.*hl2);
1233  double dist2 = -xyz21[1] * c2 + xyz21[2] * s2;
1234  double pitch2 = geom->WirePitch(plane2, tpc, cstat);
1235  const double TicksOffset2 = detprop->GetXTicksOffset(plane2,tpc,cstat);
1236 
1237  // Get angle, pitch, and offset of plane3 wires.
1238 
1239  const geo::WireGeo& wgeo3 = geom->Cryostat(cstat).TPC(tpc).Plane(plane3).Wire(0);
1240  double hl3 = wgeo3.HalfL();
1241  double xyz31[3];
1242  double xyz32[3];
1243  wgeo3.GetCenter(xyz31, -hl3);
1244  wgeo3.GetCenter(xyz32, hl3);
1245  double s3 = (xyz32[1] - xyz31[1]) / (2.*hl3);
1246  double c3 = (xyz32[2] - xyz31[2]) / (2.*hl3);
1247  double dist3 = -xyz31[1] * c3 + xyz31[2] * s3;
1248  double pitch3 = geom->WirePitch(plane3, tpc, cstat);
1249  const double TicksOffset3 = detprop->GetXTicksOffset(plane3,tpc,cstat);
1250 
1251  // Get sine of angle differences.
1252 
1253  double s12 = s1 * c2 - s2 * c1; // sin(theta1 - theta2).
1254  double s23 = s2 * c3 - s3 * c2; // sin(theta2 - theta3).
1255  double s31 = s3 * c1 - s1 * c3; // sin(theta3 - theta1).
1256 
1257  // Loop over hits in plane1.
1258 
1259  std::map<unsigned int, art::Ptr<recob::Hit> >::const_iterator
1260  ihit1 = hitmap[cstat][tpc][plane1].begin(),
1261  ihit1end = hitmap[cstat][tpc][plane1].end();
1262  for(; ihit1 != ihit1end; ++ihit1) {
1263 
1264  unsigned int wire1 = ihit1->first;
1265  const art::Ptr<recob::Hit>& phit1 = ihit1->second;
1266  geo::WireID phit1WireID = phit1->WireID();
1267  const geo::WireGeo& wgeo = geom->WireIDToWireGeo(phit1WireID);
1268 
1269  // Get endpoint coordinates of this wire from plane1.
1270  // (kept as assertions for performance reasons)
1271  assert(phit1WireID.Cryostat == cstat);
1272  assert(phit1WireID.TPC == tpc);
1273  assert(phit1WireID.Plane == plane1);
1274  assert(phit1WireID.Wire == wire1);
1275  double hl1 = wgeo.HalfL();
1276  double xyz1[3];
1277  double xyz2[3];
1278  wgeo.GetCenter(xyz1, -hl1);
1279  wgeo.GetCenter(xyz2, hl1);
1280 
1281  // Get corrected time and oblique coordinate of first hit.
1282 
1283  double t1 = phit1->PeakTime() - TicksOffset1;
1284  double u1 = wire1 * pitch1 + dist1;
1285 
1286  // Find the plane2 wire numbers corresponding to the endpoints.
1287 
1288  double wire21 = (-xyz1[1] * c2 + xyz1[2] * s2 - dist2) / pitch2;
1289  double wire22 = (-xyz2[1] * c2 + xyz2[2] * s2 - dist2) / pitch2;
1290 
1291  int wmin = std::max(0., std::min(wire21, wire22));
1292  int wmax = std::max(0., std::max(wire21, wire22) + 1.);
1293 
1294  std::map<unsigned int, art::Ptr<recob::Hit> >::const_iterator
1295  ihit2 = hitmap[cstat][tpc][plane2].lower_bound(wmin),
1296  ihit2end = hitmap[cstat][tpc][plane2].upper_bound(wmax);
1297 
1298  for(; ihit2 != ihit2end; ++ihit2) {
1299 
1300  int wire2 = ihit2->first;
1301  const art::Ptr<recob::Hit>& phit2 = ihit2->second;
1302 
1303  // Get corrected time of second hit.
1304 
1305  double t2 = phit2->PeakTime() - TicksOffset2;
1306 
1307  // Check maximum time difference with first hit.
1308 
1309  bool dt12ok = std::abs(t1-t2) <= fMaxDT;
1310  if(dt12ok) {
1311 
1312  // Test first two hits for compatibility before looping
1313  // over third hit.
1314 
1315  hitvec.clear();
1316  hitvec.push_back(phit1);
1317  hitvec.push_back(phit2);
1318  bool h12ok = compatible(hitvec, useMC);
1319  if(h12ok) {
1320 
1321  // Get oblique coordinate of second hit.
1322 
1323  double u2 = wire2 * pitch2 + dist2;
1324 
1325  // Predict plane3 oblique coordinate and wire number.
1326 
1327  double u3pred = (-u1*s23 - u2*s31) / s12;
1328  double w3pred = (u3pred - dist3) / pitch3;
1329  double w3delta = std::abs(fMaxS / (s12 * pitch3));
1330  int w3min = std::max(0., std::ceil(w3pred - w3delta));
1331  int w3max = std::max(0., std::floor(w3pred + w3delta));
1332 
1333  std::map<unsigned int, art::Ptr<recob::Hit> >::const_iterator
1334  ihit3 = hitmap[cstat][tpc][plane3].lower_bound(w3min),
1335  ihit3end = hitmap[cstat][tpc][plane3].upper_bound(w3max);
1336 
1337  for(; ihit3 != ihit3end; ++ihit3) {
1338 
1339  int wire3 = ihit3->first;
1340  const art::Ptr<recob::Hit>& phit3 = ihit3->second;
1341 
1342  // Get corrected time of third hit.
1343 
1344  double t3 = phit3->PeakTime() - TicksOffset3;
1345 
1346  // Check time difference of third hit compared to first two hits.
1347 
1348  bool dt123ok = std::abs(t1-t3) <= fMaxDT && std::abs(t2-t3) <= fMaxDT;
1349  if(dt123ok) {
1350 
1351  // Get oblique coordinate of third hit and check spatial separation.
1352 
1353  double u3 = wire3 * pitch3 + dist3;
1354  double S = s23 * u1 + s31 * u2 + s12 * u3;
1355  bool sok = std::abs(S) <= fMaxS;
1356  if(sok) {
1357 
1358  // Test triplet for compatibility.
1359 
1360  hitvec.clear();
1361  hitvec.push_back(phit1);
1362  hitvec.push_back(phit2);
1363  hitvec.push_back(phit3);
1364  bool h123ok = compatible(hitvec, useMC);
1365  if(h123ok) {
1366 
1367  // Add a space point.
1368 
1369  ++n3;
1370 
1371  // make a dummy vector of recob::SpacePoints
1372  // as we are filtering or merging and don't want to
1373  // add the created SpacePoint to the final collection just yet
1374  // This dummy vector will hold just one recob::SpacePoint,
1375  // which will go into the multimap and then the vector
1376  // will go out of scope.
1377 
1378  std::vector<recob::SpacePoint> sptv;
1379  fillSpacePoint(hitvec, sptv, sptmap.size()-1);
1380  sptkey_type key = &*phit3;
1381  sptmap.insert(std::pair<sptkey_type, recob::SpacePoint>(key, sptv.back()));
1382  sptkeys.insert(key);
1383  }
1384  }
1385  }
1386  }
1387  }
1388  }
1389  }
1390  }
1391  }// end if fMinViews <= 3
1392 
1393  // Do Filtering.
1394 
1395  if(fFilter) {
1396 
1397  // Transfer (some) space points from sptmap to spts.
1398 
1399  spts.reserve(spts.size() + sptkeys.size());
1400 
1401  // Loop over keys of space point map.
1402  // Space points that have the same key are candidates for filtering.
1403 
1404  for(std::set<sptkey_type>::const_iterator i = sptkeys.begin();
1405  i != sptkeys.end(); ++i) {
1406  sptkey_type key = *i;
1407 
1408  // Loop over space points corresponding to the current key.
1409  // Choose the single best space point from among this group.
1410 
1411  double best_chisq = 0.;
1412  const recob::SpacePoint* best_spt = 0;
1413 
1414  for(std::multimap<sptkey_type, recob::SpacePoint>::const_iterator j = sptmap.lower_bound(key);
1415  j != sptmap.upper_bound(key); ++j) {
1416  const recob::SpacePoint& spt = j->second;
1417  if(best_spt == 0 || spt.Chisq() < best_chisq) {
1418  best_spt = &spt;
1419  best_chisq = spt.Chisq();
1420  }
1421  }
1422 
1423  // Transfer best filtered space point to result vector.
1424 
1425  if (!best_spt)
1426  throw cet::exception("SpacePointAlg") << "makeSpacePoints(): no best point\n";
1427  spts.push_back(*best_spt);
1428  if(fMinViews <= 2)
1429  ++n2filt;
1430  else
1431  ++n3filt;
1432  }
1433  }// end if filtering
1434 
1435  // Do merging.
1436 
1437  else if(fMerge) {
1438 
1439  // Transfer merged space points from sptmap to spts.
1440 
1441  spts.reserve(spts.size() + sptkeys.size());
1442 
1443  // Loop over keys of space point map.
1444  // Space points that have the same key are candidates for merging.
1445 
1446  for(std::set<sptkey_type>::const_iterator i = sptkeys.begin();
1447  i != sptkeys.end(); ++i) {
1448  sptkey_type key = *i;
1449 
1450  // Loop over space points corresponding to the current key.
1451  // Make a collection of hits that is the union of the hits
1452  // from each candidate space point.
1453 
1455  jSPT = sptmap.lower_bound(key), jSPTend = sptmap.upper_bound(key);
1456 
1457  art::PtrVector<recob::Hit> merged_hits;
1458  for(; jSPT != jSPTend; ++jSPT) {
1459  const recob::SpacePoint& spt = jSPT->second;
1460 
1461  // Loop over hits from this space points.
1462  // Add each hit to the collection of all hits.
1463 
1464  const art::PtrVector<recob::Hit>& spt_hits = getAssociatedHits(spt);
1465  merged_hits.reserve(merged_hits.size() + spt_hits.size()); // better than nothing, but not ideal
1467  k != spt_hits.end(); ++k) {
1468  const art::Ptr<recob::Hit>& hit = *k;
1469  merged_hits.push_back(hit);
1470  }
1471  }
1472 
1473  // Remove duplicates.
1474 
1475  std::sort(merged_hits.begin(), merged_hits.end());
1477  std::unique(merged_hits.begin(), merged_hits.end());
1478  merged_hits.erase(it, merged_hits.end());
1479 
1480  // Construct a complex space points using merged hits.
1481 
1482  fillComplexSpacePoint(merged_hits, spts, sptmap.size() + spts.size()-1);
1483 
1484  if(fMinViews <= 2)
1485  ++n2filt;
1486  else
1487  ++n3filt;
1488  }
1489  }// end if merging
1490 
1491  // No filter, no merge.
1492 
1493  else {
1494 
1495  // Transfer all space points from sptmap to spts.
1496 
1497  spts.reserve(spts.size() + sptkeys.size());
1498 
1499  // Loop over space points.
1500 
1502  j != sptmap.end(); ++j) {
1503  const recob::SpacePoint& spt = j->second;
1504  spts.push_back(spt);
1505  }
1506 
1507  // Update statistics.
1508 
1509  n2filt = n2;
1510  n3filt = n3;
1511  }
1512  }// end loop over tpcs
1513  }// end loop over cryostats
1514 
1515  if (mf::isDebugEnabled()) {
1516  debug << "\n2-hit space points = " << n2 << "\n"
1517  << "3-hit space points = " << n3 << "\n"
1518  << "2-hit filtered/merged space points = " << n2filt << "\n"
1519  << "3-hit filtered/merged space points = " << n3filt;
1520  } // if debug
1521  }
1522 
1523  //----------------------------------------------------------------------
1524  // Get hits associated with a particular space point, based on most recent
1525  // call of any make*SpacePoints method.
1528  {
1529  // It is an error if no hits are associated with this space point (throw exception).
1530 
1531  std::map<int, art::PtrVector<recob::Hit> >::const_iterator it =
1532  fSptHitMap.find(spt.ID());
1533  if(it == fSptHitMap.end())
1534  {
1535  mf::LogWarning("SpacePointAlg") <<"Looking for ID " << spt.ID()<< " from " << fSptHitMap.size()<<std::endl;
1536  throw cet::exception("SpacePointAlg") << "No Hits associated with space point.\n";
1537  }
1538  return (*it).second;
1539 
1540  }
1541 
1542 
1543 } // end namespace trkf
Float_t x
Definition: compare.C:6
code to link reconstructed objects back to the MC truth information
double correctedTime(const recob::Hit &hit) const
Geometry description of a TPC wireThe wire is a single straight segment on a wire plane...
Definition: WireGeo.h:61
Float_t s
Definition: plot.C:23
void reserve(size_type n)
Definition: PtrVector.h:343
Basic Kalman filter track class, plus one measurement on same surface.
const std::shared_ptr< const KHitBase > & getHit() const
Measurement.
Definition: KHitTrack.h:53
const std::vector< double > SimIDEsToXYZ(std::vector< sim::IDE > const &ides)
std::vector< const recob::Hit * > pchit
Pointer to nearest neighbor hit (indexed by plane).
std::map< const recob::Hit *, HitMCInfo > fHitMCMap
TTree * t1
Definition: plottest35.C:26
Encapsulate the construction of a single cyostat.
double fMaxDT
Maximum time difference between planes.
intermediate_table::iterator iterator
WireGeo const & Wire(unsigned int iwire) const
Definition: PlaneGeo.cxx:506
bool fFilter
Filter flag.
enum geo::_plane_proj View_t
Enumerate the possible plane projections.
MaybeLogger_< ELseverityLevel::ELsev_info, false > LogInfo
Planes which measure V.
Definition: geo_types.h:77
geo::WireID WireID() const
Initial tdc tick for hit.
Definition: Hit.h:234
enum geo::_plane_orient Orient_t
Enumerate the possible plane projections.
unsigned int Nplanes() const
Number of planes in this tpc.
Definition: TPCGeo.h:145
iterator begin()
Definition: PtrVector.h:223
Declaration of signal hit object.
Kalman filter wire-time measurement on a SurfWireX surface.
The data type to uniquely identify a Plane.
Definition: geo_types.h:250
std::vector< double > dist2
Distance to nearest neighbor hit (indexed by plane).
Geometry information for a single TPC.
Definition: TPCGeo.h:37
bool fEnableW
Enable flag (W).
iterator erase(iterator position)
Definition: PtrVector.h:508
std::vector< int > trackIDs
Parent trackIDs.
const art::Ptr< recob::Hit > & getHit() const
Get original hit.
Definition: KHitWireX.h:47
void update() const
CryostatID_t Cryostat
Index of cryostat.
Definition: geo_types.h:130
Planes which measure Z direction.
Definition: geo_types.h:79
geo::View_t View() const
View for the plane of the hit.
Definition: Hit.h:233
WireID_t Wire
Index of the wire within its plane.
Definition: geo_types.h:313
SigType_t SignalType(geo::PlaneID const &pid) const
Returns the type of signal on the channels of specified TPC plane.
MaybeLogger_< ELseverityLevel::ELsev_error, false > LogError
unsigned int Ncryostats() const
Returns the number of cryostats in the detector.
double ThetaZ() const
Returns angle of wire with respect to z axis in the Y-Z plane in radians.
Definition: WireGeo.h:192
geo::Length_t WirePitch(geo::PlaneID const &planeid) const
Returns the distance between two consecutive wires.
const art::PtrVector< recob::Hit > & getAssociatedHits(const recob::SpacePoint &spt) const
void makeMCTruthSpacePoints(const art::PtrVector< recob::Hit > &hits, std::vector< recob::SpacePoint > &spts) const
double separation(const art::PtrVector< recob::Hit > &hits) const
void fillSpacePoints(std::vector< recob::SpacePoint > &spts, std::multimap< double, KHitTrack > const &trackMap) const
Fill a collection of space points.
Planes which measure U.
Definition: geo_types.h:76
View_t View() const
Which coordinate does this plane measure.
Definition: PlaneGeo.h:171
Int_t max
Definition: plot.C:27
Planes that are in the horizontal plane.
Definition: geo_types.h:87
void hits()
Definition: readHits.C:15
SpacePointAlg(const fhicl::ParameterSet &pset)
TCanvas * c1
Definition: plotHisto.C:7
intermediate_table::const_iterator const_iterator
bool fEnableU
Enable flag (U).
TCanvas * c2
Definition: plot_hist.C:75
void push_back(Ptr< U > const &p)
Definition: PtrVector.h:441
Signal from induction planes.
Definition: geo_types.h:92
DebugStuff debug
Definition: DebugStruct.cxx:4
std::map< int, art::PtrVector< recob::Hit > > fSptHitMap
Planes that are in the vertical plane (e.g. ArgoNeuT).
Definition: geo_types.h:88
std::vector< double > xyz
Location of ionization (all tracks).
virtual double GetXTicksCoefficient(int t, int c) const =0
enum geo::_plane_sigtype SigType_t
Enumerate the possible plane projections.
T get(std::string const &key) const
Definition: ParameterSet.h:231
std::vector< evd::details::RawDigitInfo_t >::const_iterator begin(RawDigitCacheDataClass const &cache)
void fillSpacePoint(const art::PtrVector< recob::Hit > &hits, std::vector< recob::SpacePoint > &sptv, int sptid) const
Geometry information for a single wire plane.The plane is represented in the geometry by a solid whic...
Definition: PlaneGeo.h:78
iterator end()
Definition: PtrVector.h:237
unsigned int NTPC() const
Number of TPCs in this cryostat.
Definition: CryostatGeo.h:155
CryostatGeo const & Cryostat(geo::CryostatID const &cryoid) const
Returns the specified cryostat.
bool isDebugEnabled()
double WirePitch(unsigned plane=0) const
Returns the center of the TPC volume in world coordinates [cm].
Definition: TPCGeo.cxx:426
double fMaxS
Maximum space separation between wires.
The data type to uniquely identify a TPC.
Definition: geo_types.h:195
PlaneID_t Plane
Index of the plane within its TPC.
Definition: geo_types.h:258
bool fPreferColl
Sort by collection wire.
double Plane0Pitch(unsigned int p) const
Returns the center of the TPC volume in world coordinates [cm].
Definition: TPCGeo.cxx:354
data_t::iterator iterator
Definition: PtrVector.h:60
size_type size() const
Definition: PtrVector.h:308
Detector simulation of raw signals on wires.
TTree * t2
Definition: plottest35.C:36
void reconfigure(const fhicl::ParameterSet &pset)
Orient_t Orientation() const
What is the orientation of the plane.
Definition: PlaneGeo.h:174
Encapsulate the geometry of a wire.
data_t::const_iterator const_iterator
Definition: PtrVector.h:61
double HalfL() const
Returns half the length of the wire [cm].
Definition: WireGeo.h:106
reference front()
Definition: PtrVector.h:379
void makeSpacePoints(const art::PtrVector< recob::Hit > &hits, std::vector< recob::SpacePoint > &spts) const
Float_t sw
Definition: plot.C:23
double weight
Definition: plottest35.C:25
ID_t ID() const
Definition: SpacePoint.h:63
float PeakTime() const
Time of the signal peak, in tick units.
Definition: Hit.h:219
double Chisq() const
Definition: SpacePoint.h:66
Encapsulate the construction of a single detector plane.
const TPCGeo & TPC(unsigned int itpc) const
Return the itpc&#39;th TPC in the cryostat.
Int_t min
Definition: plot.C:26
void fillComplexSpacePoint(const art::PtrVector< recob::Hit > &hits, std::vector< recob::SpacePoint > &sptv, int sptid) const
MaybeLogger_< ELseverityLevel::ELsev_warning, false > LogWarning
int fMinViews
Mininum number of views per space point.
int numHitMap() const
float SigmaPeakTime() const
Uncertainty for the signal peak, in tick units.
Definition: Hit.h:220
PlaneGeo const & Plane(geo::View_t view) const
Return the plane in the tpc with View_t view.
Definition: TPCGeo.cxx:298
2D representation of charge deposited in the TDC/wire plane
Definition: Hit.h:49
void GetCenter(double *xyz, double localz=0.0) const
Fills the world coordinate of a point on the wire.
Definition: WireGeo.cxx:68
bool compatible(const art::PtrVector< recob::Hit > &hits, bool useMC=false) const
TPCID_t TPC
Index of the TPC within its cryostat.
Definition: geo_types.h:203
Algorithm for generating space points from hits.
bool fMerge
Merge flag.
Float_t track
Definition: plot.C:34
void clear()
Definition: PtrVector.h:537
Float_t w
Definition: plot.C:23
const double * PlaneLocation(unsigned int p) const
Returns the coordinates of the center of the specified plane [cm].
Definition: TPCGeo.cxx:412
const std::vector< sim::IDE > HitToAvgSimIDEs(recob::Hit const &hit)
art framework interface to geometry description
cet::coded_exception< error, detail::translate > exception
Definition: exception.h:33
Encapsulate the construction of a single detector plane.
Signal from collection planes.
Definition: geo_types.h:93
bool fEnableV
Enable flag (V).
WireGeo const & WireIDToWireGeo(geo::WireID const &wireid) const
Returns the specified wire.
virtual double GetXTicksOffset(int p, int t, int c) const =0