LArSoft  v06_85_00
Liquid Argon Software toolkit - http://larsoft.org/
SpacePointSolver_module.cc
Go to the documentation of this file.
1 // Christopher Backhouse - bckhouse@fnal.gov
2 
3 // Test file at Caltech: /nfs/raid11/dunesam/prodgenie_nu_dune10kt_1x2x6_mcc7.0/prodgenie_nu_dune10kt_1x2x6_63_20160811T171439_merged.root
4 
5 // C/C++ standard libraries
6 #include <string>
7 #include <vector>
8 #include <iostream>
9 
10 // framework libraries
11 #include "fhiclcpp/ParameterSet.h"
19 
20 // LArSoft libraries
21 #include "larcoreobj/SimpleTypesAndConstants/RawTypes.h" // raw::ChannelID_t
23 
27 
33 
35 
36 #include "TGraph.h"
37 #include "TH1.h"
38 #include "TPad.h"
39 
40 #include "Solver.h"
41 #include "HashTuple.h"
42 
43 template<class T> T sqr(T x){return x*x;}
44 
45 namespace reco3d
46 {
47 
51 {
53 
54  bool operator<(const InductionWireWithXPos& w) const {return xpos < w.xpos;}
55 
57  double xpos;
58 };
59 
61 {
62 public:
63 
64  explicit SpacePointSolver(const fhicl::ParameterSet& pset);
65  virtual ~SpacePointSolver();
66 
67  void produce(art::Event& evt);
68  void beginJob();
69  void endJob();
70 
71 protected:
72  double HitToXPos(const recob::Hit& hit, geo::TPCID tpc) const;
73 
74  bool CloseDrift(double xa, double xb) const;
75 
76  bool CloseSpace(geo::WireIDIntersection ra,
77  geo::WireIDIntersection rb) const;
78 
80  double target,
82 
83  bool ISect(int chanA, int chanB, geo::TPCID tpc,
85 
86  bool ISect(int chanA, int chanB, geo::TPCID tpc) const;
87 
88  void AddNeighbours(const std::vector<SpaceCharge*>& spaceCharges) const;
89 
90  typedef std::map<const WireHit*, art::Ptr<recob::Hit>> HitMap_t;
91 
92  void BuildSystemXUV(const std::vector<art::Ptr<recob::Hit>>& xhits,
93  const std::vector<art::Ptr<recob::Hit>>& uhits,
94  const std::vector<art::Ptr<recob::Hit>>& vhits,
95  std::vector<CollectionWireHit*>& cwires,
96  std::vector<InductionWireHit*>& iwires,
97  bool incNei,
98  HitMap_t& hitmap) const;
99 
100  void BuildSystemXU(const std::vector<art::Ptr<recob::Hit>>& xhits,
101  const std::vector<art::Ptr<recob::Hit>>& uhits,
102  std::vector<CollectionWireHit*>& cwires,
103  std::vector<InductionWireHit*>& iwires,
104  bool incNei,
105  HitMap_t& hitmap) const;
106 
108  bool AddSpacePoint(const SpaceCharge& sc,
109  int id,
111 
112  void FillSystemToSpacePoints(const std::vector<CollectionWireHit*>& cwires,
114 
115  void FillSystemToSpacePointsAndAssns(const std::vector<CollectionWireHit*>& cwires,
116  const HitMap_t& hitmap,
119 
120  std::string fHitLabel;
121 
122  bool fFit;
123 
124  double fAlpha;
125 
126  TH1* fDeltaX;
127 
130 };
131 
133 
134 // ---------------------------------------------------------------------------
135 SpacePointSolver::SpacePointSolver(const fhicl::ParameterSet& pset)
136  : fHitLabel(pset.get<std::string>("HitLabel")),
137  fFit(pset.get<bool>("Fit")),
138  fAlpha(pset.get<double>("Alpha"))
139 {
141  if(fFit){
143  produces<art::Assns<recob::SpacePoint, recob::Hit>>();
145  }
146 }
147 
148 // ---------------------------------------------------------------------------
150 {
151 }
152 
153 // ---------------------------------------------------------------------------
155 {
157  geom = art::ServiceHandle<geo::Geometry>()->provider();
158 
160  fDeltaX = tfs->make<TH1F>("deltax", ";#Deltax (cm)", 100, -2, +2);
161 }
162 
163 // ---------------------------------------------------------------------------
165 {
166 }
167 
168 // ---------------------------------------------------------------------------
169 // tpc makes sure the intersection is on the side we were expecting
170 bool SpacePointSolver::ISect(int chanA, int chanB, geo::TPCID tpc,
172 {
173  // string has a default implementation for hash. Perhaps TPCID should
174  // implement a hash function directly.
175  typedef std::tuple<int, int, std::string/*geo::TPCID*/> Key_t;
176  static std::unordered_map<Key_t, bool> bCache;
177  static std::unordered_map<Key_t, geo::WireIDIntersection> pCache;
178 
179  // Prevent cache from growing without bound
180  if(bCache.size() > 1e8){
181  std::cout << "Clearing Intersection caches" << std::endl;
182  bCache.clear();
183  pCache.clear();
184  }
185 
186  const Key_t key = std::make_tuple(chanA, chanB, std::string(tpc));
187  if(bCache.count(key)){
188  if(bCache[key]) pt = pCache[key];
189  return bCache[key];
190  }
191 
192  const std::vector<geo::WireID> awires = geom->ChannelToWire(chanA);
193  const std::vector<geo::WireID> bwires = geom->ChannelToWire(chanB);
194 
195  for(geo::WireID awire: awires){
196  if(geo::TPCID(awire) != tpc) continue;
197  for(geo::WireID bwire: bwires){
198  if(geo::TPCID(bwire) != tpc) continue;
199 
200  if(geom->WireIDsIntersect(awire, bwire, pt)){
201  bCache[key] = true;
202  pCache[key] = pt;
203  return true;
204  }
205  }
206  }
207 
208  bCache[key] = false;
209  return false;
210 }
211 
212 // ---------------------------------------------------------------------------
213 bool SpacePointSolver::ISect(int chanA, int chanB, geo::TPCID tpc) const
214 {
216  return ISect(chanA, chanB, tpc, junk);
217 }
218 
219 // ---------------------------------------------------------------------------
220 bool SpacePointSolver::CloseDrift(double xa, double xb) const
221 {
222  // Used to cut at 10 ticks (for basically empirical reasons). Reproduce that
223  // in x.
224  // Sampling rate is in ns/ticks
225  // Drift velocity is in cm/us
226  // static const double k = 10*detprop->SamplingRate()*1e-3*detprop->DriftVelocity();
227  const double k = 0.2;//0.4; // 1 sigma on deltax plot
228 
229  // TODO - figure out cut value
230  return fabs(xa-xb) < k;
231 }
232 
233 // ---------------------------------------------------------------------------
235  geo::WireIDIntersection rb) const
236 {
237  TVector3 pa(ra.y, ra.z, 0);
238  TVector3 pb(rb.y, rb.z, 0);
239 
240  // TODO - figure out cut value. Empirically .25 is a bit small
241  // return (pa-pb).Mag() < .5;
242 
243  return (pa-pb).Mag() < .35;
244 }
245 
246 // ---------------------------------------------------------------------------
249  double target,
251 {
252  while(it != end && it->xpos < target && !CloseDrift(it->xpos, target)) ++it;
253 }
254 
255 // ---------------------------------------------------------------------------
257 {
258  const std::vector<geo::WireID> ws = geom->ChannelToWire(hit.Channel());
259  for(geo::WireID w: ws){
260  if(geo::TPCID(w) == tpc)
261  return detprop->ConvertTicksToX(hit.PeakTime(), w);
262  }
263 
264  std::cout << "Wire does not exist on given TPC!" << std::endl;
265  abort();
266 }
267 
268 // ---------------------------------------------------------------------------
270 AddNeighbours(const std::vector<SpaceCharge*>& spaceCharges) const
271 {
272  static const double kCritDist = 5;
273 
274  // Could use a QuadTree or VPTree etc, but seems like overkill
275  class IntCoord
276  {
277  public:
278  IntCoord(const SpaceCharge& sc)
279  : fX(sc.fX/kCritDist),
280  fY(sc.fY/kCritDist),
281  fZ(sc.fZ/kCritDist)
282  {
283  }
284 
285  bool operator<(const IntCoord& i) const
286  {
287  return std::make_tuple(fX, fY, fZ) < std::make_tuple(i.fX, i.fY, i.fZ);
288  }
289 
290  std::vector<IntCoord> Neighbours() const
291  {
292  std::vector<IntCoord> ret;
293  for(int dx = -1; dx <= +1; ++dx){
294  for(int dy = -1; dy <= +1; ++dy){
295  for(int dz = -1; dz <= +1; ++dz){
296  ret.push_back(IntCoord(fX+dx, fY+dy, fZ+dz));
297  }
298  }
299  }
300  return ret;
301  }
302  protected:
303  IntCoord(int x, int y, int z) : fX(x), fY(y), fZ(z) {}
304 
305  int fX, fY, fZ;
306  };
307 
308  std::map<IntCoord, std::vector<SpaceCharge*>> scMap;
309  for(SpaceCharge* sc: spaceCharges){
310  scMap[IntCoord(*sc)].push_back(sc);
311  }
312 
313  std::cout << "Neighbour search..." << std::endl;
314  std::cout << spaceCharges.size() << std::endl;
315  // Now that we know all the space charges, can go through and assign neighbours
316 
317  int Ntests = 0;
318  int Nnei = 0;
319  for(SpaceCharge* sc1: spaceCharges){
320  IntCoord ic(*sc1);
321  for(IntCoord icn: ic.Neighbours()){
322  for(SpaceCharge* sc2: scMap[icn]){
323 
324  ++Ntests;
325 
326  if(sc1 == sc2) continue;
327  /*const*/ double dist2 = sqr(sc1->fX-sc2->fX) + sqr(sc1->fY-sc2->fY) + sqr(sc1->fZ-sc2->fZ);
328 
329  if(dist2 > sqr(kCritDist)) continue;
330 
331  if(dist2 == 0){
332  std::cout << "ZERO DISTANCE SOMEHOW?" << std::endl;
333  std::cout << sc1->fCWire << " " << sc1->fWire1 << " " << sc1->fWire2 << std::endl;
334  std::cout << sc2->fCWire << " " << sc2->fWire1 << " " << sc2->fWire2 << std::endl;
335  std::cout << dist2 << " " << sc1->fX << " " << sc2->fX << " " << sc1->fY << " " << sc2->fY << " " << sc1->fZ << " " << sc2->fZ << std::endl;
336  continue;
337  dist2 = sqr(kCritDist);
338  }
339 
340  ++Nnei;
341 
342  // This is a pretty random guess
343  const double coupling = exp(-sqrt(dist2)/2);
344  sc1->fNeighbours.emplace_back(sc2, coupling);
345 
346  if(isnan(1/sqrt(dist2)) || isinf(1/sqrt(dist2))){
347  std::cout << dist2 << " " << sc1->fX << " " << sc2->fX << " " << sc1->fY << " " << sc2->fY << " " << sc1->fZ << " " << sc2->fZ << std::endl;
348  abort();
349  }
350  } // end for sc2
351  } // end for icn
352 
353  // The neighbours lists use the most memory, so be careful to trim
354  sc1->fNeighbours.shrink_to_fit();
355  } // end for sc1
356 
357  for(SpaceCharge* sc: spaceCharges){
358  for(Neighbour& nei: sc->fNeighbours){
359  sc->fNeiPotential += nei.fCoupling * nei.fSC->fPred;
360  }
361  }
362 
363  std::cout << Ntests << " tests to find " << Nnei << std::endl;
364 }
365 
366 // ---------------------------------------------------------------------------
369  const std::vector<art::Ptr<recob::Hit>>& uhits,
370  const std::vector<art::Ptr<recob::Hit>>& vhits,
371  std::vector<CollectionWireHit*>& cwires,
372  std::vector<InductionWireHit*>& iwires,
373  bool incNei,
374  HitMap_t& hitmap) const
375 {
376  std::map<geo::TPCID, std::vector<art::Ptr<recob::Hit>>> xhits_by_tpc;
377  for(auto& xhit: xhits){
378  const std::vector<geo::TPCID> tpcs = geom->ROPtoTPCs(geom->ChannelToROP(xhit->Channel()));
379  assert(tpcs.size() == 1);
380  const geo::TPCID tpc = tpcs[0];
381  xhits_by_tpc[tpc].push_back(xhit);
382  }
383 
384  // Maps from TPC to the induction wires. Normally want to access them this
385  // way.
386  std::map<geo::TPCID, std::vector<InductionWireWithXPos>> uwires, vwires;
387 
388  for(auto& ihits: {uhits, vhits}){
389  for(auto& hit: ihits){
390  const std::vector<geo::TPCID> tpcs = geom->ROPtoTPCs(geom->ChannelToROP(hit->Channel()));
391 
392  // TODO: Empirically, total collection charge is about 5% high of total
393  // induction charge, which might cause "spare" charge to go where it's
394  // not wanted.
395  InductionWireHit* iwire = new InductionWireHit(hit->Channel(), hit->Integral() * .95);
396  iwires.emplace_back(iwire);
397  hitmap[iwire] = hit;
398 
399  for(geo::TPCID tpc: tpcs){
400  if(xhits_by_tpc.count(tpc) == 0) continue;
401 
402  const double xpos = HitToXPos(*hit, tpc);
403 
404  if(hit->View() == geo::kU) uwires[tpc].emplace_back(iwire, xpos);
405  if(hit->View() == geo::kV) vwires[tpc].emplace_back(iwire, xpos);
406  } // end for tpc
407  } // end for hit
408  } // end for U/V
409 
410  for(auto it = uwires.begin(); it != uwires.end(); ++it){
411  std::sort(it->second.begin(), it->second.end());
412  }
413  for(auto it = vwires.begin(); it != vwires.end(); ++it){
414  std::sort(it->second.begin(), it->second.end());
415  }
416 
417  for(auto it = xhits_by_tpc.begin(); it != xhits_by_tpc.end(); ++it){
418  const geo::TPCID tpc = it->first;
419  std::sort(it->second.begin(), it->second.end(),
420  [this, tpc](art::Ptr<recob::Hit>& a, art::Ptr<recob::Hit>& b)
421  {
422  return HitToXPos(*a, tpc) < HitToXPos(*b, tpc);
423  });
424  }
425 
426 
427  struct UVCrossing
428  {
429  geo::TPCID tpc;
430  InductionWireHit *u, *v;
431 
432  bool operator<(const UVCrossing& x) const
433  {
434  return std::make_tuple(tpc, u, v) < std::make_tuple(x.tpc, x.u, x.v);
435  }
436  };
437 
438  // Build a table of UV crossers up front
439  std::cout << "Building UV table..." << std::endl;
440  std::map<UVCrossing, bool> isectUV;
441  std::map<UVCrossing, geo::WireIDIntersection> ptsUV;
442 
443  for(auto it: uwires){
444  const geo::TPCID tpc = it.first;
445 
446  auto vwires_begin = vwires[tpc].begin();
447 
448  for(InductionWireWithXPos uwire: uwires[tpc]){
449 
450  // Fast-forward up to the first vwire that could be relevant
451  FastForward(vwires_begin, uwire.xpos, vwires[tpc].end());
452 
453  for(auto vit = vwires_begin; vit != vwires[tpc].end(); ++vit){
454  const InductionWireWithXPos vwire = *vit;
455 
456  // No more vwires can be relevant, bail out
457  if(vwire.xpos > uwire.xpos &&
458  !CloseDrift(uwire.xpos, vwire.xpos)) break;
459 
460  const UVCrossing key = {tpc, uwire.iwire, vwire.iwire};
461 
462  isectUV[key] = ISect(uwire.iwire->fChannel, vwire.iwire->fChannel, tpc,
463  ptsUV[key]);
464  } // end for vwire
465  } // end for uwire
466  } // end for tpc
467 
468  std::cout << "Finding XUV coincidences..." << std::endl;
469  std::vector<SpaceCharge*> spaceCharges;
470 
471  for(auto it: xhits_by_tpc){
472  const geo::TPCID tpc = it.first;
473 
474  auto uwires_begin = uwires[tpc].begin();
475  auto vwires_begin = vwires[tpc].begin();
476 
477  for(auto& hit: it.second){
478  const double xpos = HitToXPos(*hit, tpc);
479 
480  FastForward(uwires_begin, xpos, uwires[tpc].end());
481  FastForward(vwires_begin, xpos, vwires[tpc].end());
482 
483  // Figure out which vwires intersect this xwire here so we don't do N^2
484  // nesting inside the uwire loop below.
485  std::vector<InductionWireWithXPos> vwires_cross;
486  std::unordered_map<InductionWireHit*, geo::WireIDIntersection> ptsXV;
487  vwires_cross.reserve(vwires[tpc].size()); // avoid reallocations
488  for(auto vit = vwires_begin; vit != vwires[tpc].end(); ++vit){
489  InductionWireWithXPos vwire = *vit;
490 
491  if(vwire.xpos > xpos && !CloseDrift(vwire.xpos, xpos)) break;
492 
493  if(ISect(hit->Channel(), vwire.iwire->fChannel, tpc, ptsXV[vwire.iwire]))
494  vwires_cross.push_back(vwire);
495  } // end for vwire
496 
497  std::vector<SpaceCharge*> crossers;
498  for(auto uit = uwires_begin; uit != uwires[tpc].end(); ++uit){
499  const InductionWireWithXPos uwire = *uit;
500 
501  if(uwire.xpos > xpos && !CloseDrift(uwire.xpos, xpos)) break;
502 
504  if(!ISect(hit->Channel(), uwire.iwire->fChannel, tpc, ptXU)) continue;
505 
506  for(const InductionWireWithXPos& vwire: vwires_cross){
507 
508  const geo::WireIDIntersection ptXV = ptsXV[vwire.iwire];
509  if(!CloseSpace(ptXU, ptXV)) continue;
510 
511  if(!isectUV[{tpc, uwire.iwire, vwire.iwire}]) continue;
512 
513  const geo::WireIDIntersection ptUV = ptsUV[{tpc, uwire.iwire, vwire.iwire}];
514 
515  if(!CloseSpace(ptXU, ptUV) ||
516  !CloseSpace(ptXV, ptUV)) continue;
517 
518  fDeltaX->Fill(xpos-uwire.xpos);
519  fDeltaX->Fill(xpos-vwire.xpos);
520  fDeltaX->Fill(uwire.xpos-vwire.xpos);
521 
522  // TODO exactly which 3D position to set for this point? This average
523  // aleviates the problem with a single collection wire matching
524  // multiple hits on an induction wire at different times.
525 
526  // Don't have a cwire object yet, set it later
527  SpaceCharge* sc = new SpaceCharge((xpos+uwire.xpos+vwire.xpos)/3,
528  ptXU.y, ptXU.z,
529  0, uwire.iwire, vwire.iwire);
530  spaceCharges.push_back(sc);
531  crossers.push_back(sc);
532  } // end for vwire
533  } // end for uwire
534 
535  CollectionWireHit* cwire = new CollectionWireHit(hit->Channel(), hit->Integral(), crossers);
536  hitmap[cwire] = hit;
537  cwires.push_back(cwire);
538  for(SpaceCharge* sc: crossers) sc->fCWire = cwire;
539  } // end for hit
540  } // end for it (tpc)
541 
542  if(incNei) AddNeighbours(spaceCharges);
543 }
544 
545 // ---------------------------------------------------------------------------
548  const std::vector<art::Ptr<recob::Hit>>& uhits,
549  std::vector<CollectionWireHit*>& cwires,
550  std::vector<InductionWireHit*>& iwires,
551  bool incNei,
552  HitMap_t& hitmap) const
553 {
554  std::map<geo::TPCID, std::vector<art::Ptr<recob::Hit>>> xhits_by_tpc;
555  for(auto& xhit: xhits){
556  const std::vector<geo::TPCID> tpcs = geom->ROPtoTPCs(geom->ChannelToROP(xhit->Channel()));
557  assert(tpcs.size() == 1);
558  const geo::TPCID tpc = tpcs[0];
559  xhits_by_tpc[tpc].push_back(xhit);
560  }
561 
562  // Maps from TPC to the induction wires. Normally want to access them this
563  // way.
564  std::map<geo::TPCID, std::vector<InductionWireWithXPos>> uwires;
565 
566  for(auto& hit: uhits){
567  const std::vector<geo::TPCID> tpcs = geom->ROPtoTPCs(geom->ChannelToROP(hit->Channel()));
568 
569  InductionWireHit* iwire = new InductionWireHit(hit->Channel(), hit->Integral());
570  iwires.emplace_back(iwire);
571  hitmap[iwire] = hit;
572 
573  for(geo::TPCID tpc: tpcs){
574  if(xhits_by_tpc.count(tpc) == 0) continue;
575 
576  const double xpos = HitToXPos(*hit, tpc);
577 
578  uwires[tpc].emplace_back(iwire, xpos);
579  } // end for tpc
580  } // end for hit
581 
582  for(auto it = uwires.begin(); it != uwires.end(); ++it){
583  std::sort(it->second.begin(), it->second.end());
584  }
585 
586  for(auto it = xhits_by_tpc.begin(); it != xhits_by_tpc.end(); ++it){
587  const geo::TPCID tpc = it->first;
588  std::sort(it->second.begin(), it->second.end(),
589  [this, tpc](art::Ptr<recob::Hit>& a, art::Ptr<recob::Hit>& b)
590  {
591  return HitToXPos(*a, tpc) < HitToXPos(*b, tpc);
592  });
593  }
594 
595 
596  std::cout << "Finding UV coincidences..." << std::endl;
597  std::vector<SpaceCharge*> spaceCharges;
598 
599  for(auto it: xhits_by_tpc){
600  const geo::TPCID tpc = it.first;
601 
602  auto uwires_begin = uwires[tpc].begin();
603 
604  for(auto& hit: it.second){
605  const double xpos = HitToXPos(*hit, tpc);
606 
607  std::vector<SpaceCharge*> crossers;
608 
609  FastForward(uwires_begin, xpos, uwires[tpc].end());
610 
611  // Figure out which uwires intersect this xwire here.
612  for(auto uit = uwires_begin; uit != uwires[tpc].end(); ++uit){
613  InductionWireWithXPos uwire = *uit;
614 
615  if(uwire.xpos > xpos && !CloseDrift(uwire.xpos, xpos)) break;
616 
618  if(ISect(hit->Channel(), uwire.iwire->fChannel, tpc, ptXU)){
619 
620  // Don't have a cwire object yet, set it later
621  SpaceCharge* sc = new SpaceCharge((xpos+uwire.xpos)/2, ptXU.y, ptXU.z,
622  0, 0, uwire.iwire);
623  spaceCharges.push_back(sc);
624  crossers.push_back(sc);
625  } // end for uwire
626  } // end for uit
627 
628  CollectionWireHit* cwire = new CollectionWireHit(hit->Channel(), hit->Integral(), crossers);
629  hitmap[cwire] = hit;
630  cwires.push_back(cwire);
631  for(SpaceCharge* sc: crossers) sc->fCWire = cwire;
632  } // end for hit
633  } // end for it (tpc)
634 
635  if(incNei) AddNeighbours(spaceCharges);
636 }
637 
638 // ---------------------------------------------------------------------------
641  int id,
643 {
644  static const double err[6] = {0,};
645 
646  const float charge = sc.fPred;
647  if(charge == 0) return false;
648 
649  const double xyz[3] = {sc.fX, sc.fY, sc.fZ};
650  points.add({ xyz, err, 0.0, id }, charge);
651 
652  return true;
653 }
654 
655 // ---------------------------------------------------------------------------
657 FillSystemToSpacePoints(const std::vector<CollectionWireHit*>& cwires,
659 {
660  int iPoint = 0;
661  for(const CollectionWireHit* cwire: cwires){
662  for(const SpaceCharge* sc: cwire->fCrossings){
663  AddSpacePoint(*sc, iPoint++, points);
664  } // for sc
665  } // for cwire
666 }
667 
668 
669 // ---------------------------------------------------------------------------
671 FillSystemToSpacePointsAndAssns(const std::vector<CollectionWireHit*>& cwires,
672  const HitMap_t& hitmap,
675 {
676  int iPoint = 0;
677  for(const CollectionWireHit* cwire: cwires){
678  for(const SpaceCharge* sc: cwire->fCrossings){
679  // fill the space point and reconstructed charge information;
680  // if the point is filtered out, it's not inserted (no association either)
681  if(!AddSpacePoint(*sc, iPoint++, points)) continue;
682 
683  // now fill the associations to the last added space point
684  const auto& spsPtr = points.lastSpacePointPtr();
685 
686  const auto& hit = hitmap.at(cwire);
687  assn.addSingle(spsPtr, hit);
688 
689  if(sc->fWire1){
690  assn.addSingle(spsPtr, hitmap.at(sc->fWire1));
691  }
692  if(sc->fWire2){
693  assn.addSingle(spsPtr, hitmap.at(sc->fWire2));
694  }
695  } // for sc
696  } // for cwire
697 }
698 
699 
700 // ---------------------------------------------------------------------------
702 {
704  std::vector<art::Ptr<recob::Hit> > hitlist;
705  if(evt.getByLabel(fHitLabel, hits))
706  art::fill_ptr_vector(hitlist, hits);
707 
708  recob::ChargedSpacePointCollectionCreator spcol_pre(evt, *this, "pre");
709  recob::ChargedSpacePointCollectionCreator spcol_noreg(evt, *this, "noreg");
711  auto assns = std::make_unique<art::Assns<recob::SpacePoint, recob::Hit>>();
712 
713  // Skip very small events
714  if(hits->size() < 20){
715  spcol_pre.put();
716  if(fFit){
717  spcol.put();
718  evt.put(std::move(assns));
719  spcol_noreg.put();
720  }
721  return;
722  }
723 
725 
726  bool is2view = false;
727  std::vector<art::Ptr<recob::Hit>> xhits, uhits, vhits;
728  for(auto& hit: hitlist){
729  if(isnan(hit->Integral()) || isinf(hit->Integral())){
730  std::cout << "WARNING: bad recob::Hit::Integral() = "
731  << hit->Integral()
732  << ". Skipping." << std::endl;
733  continue;
734  }
735 
736  if(hit->SignalType() == geo::kCollection){
737  // For DualPhase, both view are collection. Arbitrarily map V to the main
738  // "X" view. For Argoneut and Lariat, collection=V is also the right
739  // convention.
740  if(hit->View() == geo::kZ){
741  xhits.push_back(hit);
742  }
743  if(hit->View() == geo::kV){
744  xhits.push_back(hit);
745  is2view = true;
746  }
747  if(hit->View() == geo::kU || hit->View() == geo::kY){
748  uhits.push_back(hit);
749  is2view = true;
750  }
751  }
752  else{
753  if(hit->View() == geo::kU) uhits.push_back(hit);
754  if(hit->View() == geo::kV) vhits.push_back(hit);
755  }
756  } // end for hit
757 
758  std::vector<CollectionWireHit*> cwires;
759  // So we can find them all to free the memory
760  std::vector<InductionWireHit*> iwires;
761 
762  HitMap_t hitmap;
763  if(is2view)
764  BuildSystemXU(xhits, uhits, cwires, iwires, fAlpha != 0, hitmap);
765  else
766  BuildSystemXUV(xhits, uhits, vhits, cwires, iwires, fAlpha != 0, hitmap);
767 
768  FillSystemToSpacePoints(cwires, spcol_pre);
769  spcol_pre.put();
770 
771  if(fFit){
772  std::cout << "Iterating..." << std::endl;
773  double prevMetric = Metric(cwires, 0);//fAlpha);
774  std::cout << "Begin: " << prevMetric << std::endl;
775  for(int i = 0;; ++i){
776  Iterate(cwires, 0);//fAlpha);
777  const double metric = Metric(cwires, 0);//fAlpha);
778  std::cout << i << " " << metric << std::endl;
779  if(fabs(metric-prevMetric) < 1e-3*fabs(prevMetric)) break;
780  if(i > 100) break;
781  // if(metric/prevMetric > .9999) break;
782  prevMetric = metric;
783  }
784 
785  FillSystemToSpacePoints(cwires, spcol_noreg);
786  spcol_noreg.put();
787 
788  prevMetric = Metric(cwires, fAlpha);
789  std::cout << "Begin: " << prevMetric << std::endl;
790  for(int i = 0;; ++i){
791  Iterate(cwires, fAlpha);
792  const double metric = Metric(cwires, fAlpha);
793  std::cout << i << " " << metric << std::endl;
794  if(fabs(metric-prevMetric) < 1e-3*fabs(prevMetric)) break;
795  if(i > 100) break;
796  // if(metric/prevMetric > .9999) break;
797  prevMetric = metric;
798  }
799 
800  FillSystemToSpacePointsAndAssns(cwires, hitmap, spcol, *assns);
801  spcol.put();
802  evt.put(std::move(assns));
803  } // end if fFit
804 
805  for(InductionWireHit* i: iwires) delete i;
806  for(CollectionWireHit* c: cwires) delete c;
807 }
808 
809 } // end namespace reco3d
Float_t x
Definition: compare.C:6
double z
z position of intersection
Definition: geo_types.h:494
const geo::GeometryCore * geom
intermediate_table::iterator iterator
cout<< "-> Edep in the target
Definition: analysis.C:54
Planes which measure V.
Definition: geo_types.h:77
art::Ptr< recob::SpacePoint > lastSpacePointPtr() const
Returns an art pointer to the last inserted space point (no check!).
Declaration of signal hit object.
Float_t y
Definition: compare.C:6
Double_t z
Definition: plot.C:279
const detinfo::DetectorProperties * detprop
double fCoupling
Definition: Solver.h:37
std::map< const WireHit *, art::Ptr< recob::Hit > > HitMap_t
void AddNeighbours(const std::vector< SpaceCharge * > &spaceCharges) const
STL namespace.
Planes which measure Z direction.
Definition: geo_types.h:79
Information about charge reconstructed in the active volume.
InductionWireWithXPos(InductionWireHit *w, double x)
h2bis Fit("gaus")
Planes which measure Y direction.
Definition: geo_types.h:80
static void produces(art::ProducerBase &producer, std::string const &instanceName={})
Declares the data products being produced.
ProductID put(std::unique_ptr< PROD > &&product)
Definition: Event.h:102
void FillSystemToSpacePointsAndAssns(const std::vector< CollectionWireHit * > &cwires, const HitMap_t &hitmap, recob::ChargedSpacePointCollectionCreator &points, art::Assns< recob::SpacePoint, recob::Hit > &assn) const
auto vector(Vector const &v)
Returns a manipulator which will print the specified array.
Definition: DumpUtils.h:265
Planes which measure U.
Definition: geo_types.h:76
double fZ
Definition: Solver.h:52
void hits()
Definition: readHits.C:15
bool CloseDrift(double xa, double xb) const
intermediate_table::const_iterator const_iterator
#define DEFINE_ART_MODULE(klass)
Definition: ModuleMacros.h:42
void beginJob()
Definition: Breakpoints.cc:14
void Iterate(CollectionWireHit *cwire, double alpha)
Definition: Solver.cxx:235
InductionWireHit * fWire2
Definition: Solver.h:54
T sqr(T x)
double fY
Definition: Solver.h:52
parameter set interface
bool AddSpacePoint(const SpaceCharge &sc, int id, recob::ChargedSpacePointCollectionCreator &points) const
return whether the point was inserted (only happens when it has charge)
TMarker * pt
Definition: egs.C:25
bool ISect(int chanA, int chanB, geo::TPCID tpc, geo::WireIDIntersection &pt) const
InductionWireHit * fWire1
Definition: Solver.h:54
double fX
Definition: Solver.h:52
double Metric(double q, double p)
Definition: Solver.cxx:70
void BuildSystemXU(const std::vector< art::Ptr< recob::Hit >> &xhits, const std::vector< art::Ptr< recob::Hit >> &uhits, std::vector< CollectionWireHit * > &cwires, std::vector< InductionWireHit * > &iwires, bool incNei, HitMap_t &hitmap) const
bool operator<(const InductionWireWithXPos &w) const
The data type to uniquely identify a TPC.
Definition: geo_types.h:195
Description of geometry of one entire detector.
void BuildSystemXUV(const std::vector< art::Ptr< recob::Hit >> &xhits, const std::vector< art::Ptr< recob::Hit >> &uhits, const std::vector< art::Ptr< recob::Hit >> &vhits, std::vector< CollectionWireHit * > &cwires, std::vector< InductionWireHit * > &iwires, bool incNei, HitMap_t &hitmap) const
Detector simulation of raw signals on wires.
float PeakTime() const
Time of the signal peak, in tick units.
Definition: Hit.h:219
T * make(ARGS...args) const
Creates a collection of space points with associated charge.
Utility object to perform functions of association.
bool CloseSpace(geo::WireIDIntersection ra, geo::WireIDIntersection rb) const
void FillSystemToSpacePoints(const std::vector< CollectionWireHit * > &cwires, recob::ChargedSpacePointCollectionCreator &pts) const
bool getByLabel(std::string const &label, std::string const &productInstanceName, Handle< PROD > &result) const
Definition: DataViewImpl.h:344
double y
y position of intersection
Definition: geo_types.h:493
void addSingle(Ptr< left_t > const &left, Ptr< right_t > const &right, data_t const &data)
Definition: Assns.h:489
void FastForward(std::vector< InductionWireWithXPos >::iterator &it, double target, const std::vector< InductionWireWithXPos >::const_iterator &end) const
object containing MC truth information necessary for making RawDigits and doing back tracking ...
Declaration of basic channel signal object.
Helpers to create space points with associated charge.
std::vector< evd::details::RawDigitInfo_t >::const_iterator end(RawDigitCacheDataClass const &cache)
2D representation of charge deposited in the TDC/wire plane
Definition: Hit.h:49
double HitToXPos(const recob::Hit &hit, geo::TPCID tpc) const
void put()
Puts all data products into the event, leaving the creator empty().
void fill_ptr_vector(std::vector< Ptr< T >> &ptrs, H const &h)
Definition: Ptr.h:464
Float_t e
Definition: plot.C:34
double fPred
Definition: Solver.h:58
Float_t w
Definition: plot.C:23
void add(recob::SpacePoint const &spacePoint, recob::PointCharge const &charge)
Inserts the specified space point and associated data into the collection.
raw::ChannelID_t Channel() const
ID of the readout channel the hit was extracted from.
Definition: Hit.h:231
art framework interface to geometry description
Signal from collection planes.
Definition: geo_types.h:93
SpaceCharge * fSC
Definition: Solver.h:36