All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
SpacePointHit3DBuilder_tool.cc
Go to the documentation of this file.
1 /**
2  * @file SpacePointHit3DBuilder_tool.cc
3  *
4  * @brief This tool provides "standard" 3D hits built (by this tool) from 2D hits
5  *
6  */
7 
8 // Framework Includes
9 #include "art/Framework/Core/ProducesCollector.h"
10 #include "art/Framework/Principal/Event.h"
11 #include "art/Framework/Principal/Handle.h"
12 #include "art/Framework/Services/Registry/ServiceHandle.h"
13 #include "art/Persistency/Common/PtrMaker.h"
14 #include "art/Utilities/ToolMacros.h"
15 #include "art_root_io/TFileService.h"
16 #include "canvas/Persistency/Common/Assns.h"
17 #include "canvas/Persistency/Common/Ptr.h"
18 #include "canvas/Utilities/InputTag.h"
19 #include "cetlib/cpu_timer.h"
20 #include "fhiclcpp/ParameterSet.h"
21 #include "messagefacility/MessageLogger/MessageLogger.h"
22 
23 // LArSoft includes
34 
35 // std includes
36 #include <cmath>
37 #include <iostream>
38 #include <map>
39 #include <memory>
40 #include <unordered_map>
41 #include <utility>
42 #include <vector>
43 #include <numeric> // std::accumulate
44 
45 // Ack!
46 #include "TTree.h"
47 
48 //------------------------------------------------------------------------------------------------------------------------------------------
49 // implementation follows
50 
51 namespace lar_cluster3d {
52 
53  /**
54  * @brief SpacePointHit3DBuilder class definiton
55  */
56  class SpacePointHit3DBuilder : virtual public IHit3DBuilder {
57  public:
58  /**
59  * @brief Constructor
60  *
61  * @param pset
62  */
63  explicit SpacePointHit3DBuilder(fhicl::ParameterSet const& pset);
64 
65  /**
66  * @brief Destructor
67  */
69 
70  /**
71  * @brief Each algorithm may have different objects it wants "produced" so use this to
72  * let the top level producer module "know" what it is outputting
73  */
74  virtual void produces(art::ProducesCollector&) override;
75 
76  void configure(const fhicl::ParameterSet&) override;
77 
78  /**
79  * @brief Given a set of recob hits, run DBscan to form 3D clusters
80  *
81  * @param hitPairList The input list of 3D hits to run clustering on
82  * @param clusterParametersList A list of cluster objects (parameters from associated hits)
83  */
84  void Hit3DBuilder(art::Event& evt, reco::HitPairList& hitPairList, RecobHitToPtrMap&) override;
85 
86  /**
87  * @brief If monitoring, recover the time to execute a particular function
88  */
89  float
91  {
92  return fTimeVector.at(index);
93  }
94 
95  private:
96  /**
97  * @brief clear the tuple vectors before processing next event
98  */
99  void clear();
100 
101  /**
102  * @brief Perform charge integration between limits
103  */
104  float chargeIntegral(float, float, float, float, int, int) const;
105 
106  using Hit2DVector = std::vector<reco::ClusterHit2D>;
107 
108  /**
109  * @brief Data members to follow
110  */
112  art::InputTag fHitProducerLabel;
115  float m_maxHit3DChiSquare; ///< Provide ability to select hits based on "chi square"
116  bool m_outputHistograms; ///< Take the time to create and fill some histograms for diagnostics
117 
118  bool fEnableMonitoring; ///<
119  mutable std::vector<float> fTimeVector; ///<
120 
121  // Define some basic histograms
122  TTree* m_tupleTree; ///< output analysis tree
123 
124  mutable std::vector<float> m_deltaTimeVec;
125  mutable std::vector<float> m_chiSquare3DVec;
126  mutable std::vector<float> m_maxPullVec;
127  mutable std::vector<float> m_overlapFractionVec;
128  mutable std::vector<float> m_overlapRangeVec;
129  mutable std::vector<float> m_maxSideVecVec;
130  mutable std::vector<float> m_pairWireDistVec;
131  mutable std::vector<float> m_smallChargeDiffVec;
132  mutable std::vector<int> m_smallIndexVec;
133  mutable std::vector<float> m_qualityMetricVec;
134  mutable std::vector<float> m_spacePointChargeVec;
135  mutable std::vector<float> m_hitAsymmetryVec;
136 
137  // Get instances of the primary data structures needed
139 
141  };
142 
143  SpacePointHit3DBuilder::SpacePointHit3DBuilder(fhicl::ParameterSet const& pset)
144  {
145  this->configure(pset);
146  }
147 
148  //------------------------------------------------------------------------------------------------------------------------------------------
149 
151 
152  void
153  SpacePointHit3DBuilder::produces(art::ProducesCollector& collector)
154  {
155  collector.produces<std::vector<recob::Hit>>();
156 
157  if (fDoWireAssns) collector.produces<art::Assns<recob::Wire, recob::Hit>>();
158  if (fDoRawDigitAssns) collector.produces<art::Assns<raw::RawDigit, recob::Hit>>();
159  }
160 
161  //------------------------------------------------------------------------------------------------------------------------------------------
162 
163  void
164  SpacePointHit3DBuilder::configure(fhicl::ParameterSet const& pset)
165  {
166  fSpacePointProducerLabel = pset.get<art::InputTag>("SpacePointProducerLabel");
167  fHitProducerLabel = pset.get<art::InputTag>("HitProducerLabel");
168  fDoWireAssns = pset.get<bool>("DoWireAssns", true);
169  fDoRawDigitAssns = pset.get<bool>("DoRawDigitAssns", true);
170  fEnableMonitoring = pset.get<bool>("EnableMonitoring", true);
171  m_maxHit3DChiSquare = pset.get<float>("MaxHitChiSquare", 6.0);
172  m_outputHistograms = pset.get<bool>("OutputHistograms", false);
173 
174  // Access ART's TFileService, which will handle creating and writing
175  // histograms and n-tuples for us.
176  art::ServiceHandle<art::TFileService> tfs;
177 
178  if (m_outputHistograms) {
179  m_tupleTree = tfs->make<TTree>("Hit3DBuilderTree", "Tree by StandardHit3DBuilder");
180 
181  clear();
182 
183  m_tupleTree->Branch("DeltaTime2D", "std::vector<float>", &m_deltaTimeVec);
184  m_tupleTree->Branch("ChiSquare3D", "std::vector<float>", &m_chiSquare3DVec);
185  m_tupleTree->Branch("MaxPullValue", "std::vector<float>", &m_maxPullVec);
186  m_tupleTree->Branch("OverlapFraction", "std::vector<float>", &m_overlapFractionVec);
187  m_tupleTree->Branch("OverlapRange", "std::vector<float>", &m_overlapRangeVec);
188  m_tupleTree->Branch("MaxSideVec", "std::vector<float>", &m_maxSideVecVec);
189  m_tupleTree->Branch("PairWireDistVec", "std::vector<float>", &m_pairWireDistVec);
190  m_tupleTree->Branch("SmallChargeDiff", "std::vector<float>", &m_smallChargeDiffVec);
191  m_tupleTree->Branch("SmallChargeIdx", "std::vector<int>", &m_smallIndexVec);
192  m_tupleTree->Branch("QualityMetric", "std::vector<float>", &m_qualityMetricVec);
193  m_tupleTree->Branch("SPCharge", "std::vector<float>", &m_spacePointChargeVec);
194  m_tupleTree->Branch("HitAsymmetry", "std::vector<float>", &m_hitAsymmetryVec);
195  }
196 
197  fGeometry = art::ServiceHandle<geo::Geometry const>().get();
198  }
199 
200  void
202  {
203  m_deltaTimeVec.clear();
204  m_chiSquare3DVec.clear();
205  m_maxPullVec.clear();
206  m_overlapFractionVec.clear();
207  m_overlapRangeVec.clear();
208  m_maxSideVecVec.clear();
209  m_pairWireDistVec.clear();
210  m_smallChargeDiffVec.clear();
211  m_smallIndexVec.clear();
212  m_qualityMetricVec.clear();
213  m_spacePointChargeVec.clear();
214  m_hitAsymmetryVec.clear();
215 
216  return;
217  }
218 
219  void
221  reco::HitPairList& hitPairList,
222  RecobHitToPtrMap& recobHitToArtPtrMap)
223  {
224  /**
225  * @brief Recover the 2D hits from art and fill out the local data structures for the 3D clustering
226  */
227 
228  fTimeVector.resize(NUMTIMEVALUES, 0.);
229 
230  cet::cpu_timer theClockMakeHits;
231 
232  if (fEnableMonitoring) theClockMakeHits.start();
233 
234  // Start by recovering the associations between space points and hits
235  art::Handle<art::Assns<recob::Hit, recob::SpacePoint>> hitSpacePointAssnsHandle;
236  evt.getByLabel(fSpacePointProducerLabel, hitSpacePointAssnsHandle);
237 
238  if (!hitSpacePointAssnsHandle.isValid()) return;
239 
240  // Get a hit refiner for the output hit collection
242 
243  // We need to spin through the associations first to build a map between the SpacePoints and
244  // the WireID associated to the collection plane... where for APA style TPCs this will be
245  // unambiguous (note that this is not true for ICARUS!)
246  using SpacePointToWireIDMap = std::unordered_map<const recob::SpacePoint*, geo::WireID>;
247 
248  SpacePointToWireIDMap spacePointToWireIDMap;
249 
250  for (const auto& assnPair : *hitSpacePointAssnsHandle) {
251  if (assnPair.first->SignalType() == geo::kCollection)
252  spacePointToWireIDMap[assnPair.second.get()] = assnPair.first->WireID();
253  }
254 
255  // First step is to loop through and get a mapping between space points and associated hits
256  // and, importantly, a list of unique hits (and mapping between art ptr and hit)
257  using OldHitToNewHitMap = std::map<const recob::Hit*, const recob::Hit*>;
258  using SpacePointHitVecMap = std::map<const recob::SpacePoint*, std::vector<const recob::Hit*>>;
259 
260  OldHitToNewHitMap oldHitToNewHitMap;
261  SpacePointHitVecMap spacePointHitVecMap;
262 
263  // We need a container for our new hits...
264  std::unique_ptr<std::vector<recob::Hit>> newHitVecPtr(new std::vector<recob::Hit>);
265 
266  // reserve a chunk of memory... cannot be more hits than 3 x # spacer points...
267  newHitVecPtr->reserve(3 * hitSpacePointAssnsHandle->size());
268 
269  // Use this handy art utility to make art::Ptr objects to the new recob::Hits for use in the output phase
270  art::PtrMaker<recob::Hit> ptrMaker(evt);
271 
272  for (auto& assnPair : *hitSpacePointAssnsHandle) {
273  const art::Ptr<recob::SpacePoint> spacePoint = assnPair.second;
274  const art::Ptr<recob::Hit>& recobHit = assnPair.first;
275 
276  // If we have seen this hit before then no need to create new hit
277  if (oldHitToNewHitMap.find(recobHit.get()) == oldHitToNewHitMap.end()) {
278  // Recover the reference WireID from our previous map
279  geo::WireID refWireID = spacePointToWireIDMap[spacePoint.get()];
280  geo::WireID thisWireID = recobHit.get()->WireID();
281 
282  // Recover the list of possible WireIDs from the geometry service
283  const std::vector<geo::WireID>& wireIDs =
284  fGeometry->ChannelToWire(recobHit.get()->Channel());
285 
286  // Loop to find match
287  for (const auto& wireID : wireIDs) {
288  if (wireID.TPC != refWireID.TPC || wireID.Cryostat != refWireID.Cryostat) continue;
289  thisWireID = wireID;
290  break;
291  }
292 
293  // Create and save the new recob::Hit with the correct WireID
294  newHitVecPtr->emplace_back(recob::HitCreator(*recobHit.get(), thisWireID).copy());
295 
296  // Recover a pointer to it...
297  recob::Hit* newHit = &newHitVecPtr->back();
298 
299  spacePointHitVecMap[spacePoint.get()].push_back(newHit);
300 
301  recobHitToArtPtrMap[newHit] = ptrMaker(newHitVecPtr->size() - 1);
302  oldHitToNewHitMap[recobHit.get()] = newHit;
303  }
304  else
305  spacePointHitVecMap[spacePoint.get()].push_back(oldHitToNewHitMap[recobHit.get()]);
306  }
307 
308  // We'll want to correct the hit times for the plane offsets
309  // (note this is already taken care of when converting to position)
310  std::map<geo::PlaneID, double> planeOffsetMap;
311 
312  auto const clock_data =
313  art::ServiceHandle<detinfo::DetectorClocksService const>()->DataFor(evt);
314  auto const det_prop =
315  art::ServiceHandle<detinfo::DetectorPropertiesService const>()->DataFor(evt, clock_data);
316 
317  // Initialize the plane to hit vector map
318  for (size_t cryoIdx = 0; cryoIdx < fGeometry->Ncryostats(); cryoIdx++) {
319  for (size_t tpcIdx = 0; tpcIdx < fGeometry->NTPC(); tpcIdx++) {
320  // What we want here are the relative offsets between the planes
321  // Note that plane 0 is assumed the "first" plane and is the reference
322  planeOffsetMap[geo::PlaneID(cryoIdx, tpcIdx, 0)] = 0.;
323  planeOffsetMap[geo::PlaneID(cryoIdx, tpcIdx, 1)] =
324  det_prop.GetXTicksOffset(geo::PlaneID(cryoIdx, tpcIdx, 1)) -
325  det_prop.GetXTicksOffset(geo::PlaneID(cryoIdx, tpcIdx, 0));
326  planeOffsetMap[geo::PlaneID(cryoIdx, tpcIdx, 2)] =
327  det_prop.GetXTicksOffset(geo::PlaneID(cryoIdx, tpcIdx, 2)) -
328  det_prop.GetXTicksOffset(geo::PlaneID(cryoIdx, tpcIdx, 0));
329 
330  std::cout << "***> plane 0 offset: " << planeOffsetMap[geo::PlaneID(cryoIdx, tpcIdx, 0)]
331  << ", plane 1: " << planeOffsetMap[geo::PlaneID(cryoIdx, tpcIdx, 1)]
332  << ", plane 2: " << planeOffsetMap[geo::PlaneID(cryoIdx, tpcIdx, 2)] << std::endl;
333  std::cout << " Det prop plane 0: "
334  << det_prop.GetXTicksOffset(geo::PlaneID(cryoIdx, tpcIdx, 0))
335  << ", plane 1: " << det_prop.GetXTicksOffset(geo::PlaneID(cryoIdx, tpcIdx, 1))
336  << ", plane 2: " << det_prop.GetXTicksOffset(geo::PlaneID(cryoIdx, tpcIdx, 2))
337  << ", Trig: " << trigger_offset(clock_data) << std::endl;
338  }
339  }
340 
341  // We need temporary mapping from recob::Hit's to our 2D hits
342  using RecobHitTo2DHitMap = std::map<const recob::Hit*, const reco::ClusterHit2D*>;
343 
344  RecobHitTo2DHitMap recobHitTo2DHitMap;
345 
346  // Set the size of the container for our hits
347  m_clusterHit2DMasterVec.clear();
348  m_clusterHit2DMasterVec.reserve(oldHitToNewHitMap.size());
349 
350  // Now go throught the list of unique hits and create the 2D hits we'll use
351  for (auto& hitPair : oldHitToNewHitMap) {
352  const recob::Hit* recobHit = hitPair.second;
353  const geo::WireID& hitWireID(recobHit->WireID());
354 
355  double hitPeakTime(
356  recobHit->PeakTime() -
357  planeOffsetMap.at(hitWireID.planeID())); //planeOffsetMap[hitWireID.planeID()]);
358  double xPosition(det_prop.ConvertTicksToX(
359  recobHit->PeakTime(), hitWireID.Plane, hitWireID.TPC, hitWireID.Cryostat));
360 
361  m_clusterHit2DMasterVec.emplace_back(0, 0., 0., xPosition, hitPeakTime, hitWireID, recobHit);
362 
363  recobHitTo2DHitMap[recobHit] = &m_clusterHit2DMasterVec.back();
364  }
365 
366  // Now we can go through the space points and build our 3D hits
367  for (auto& pointPair : spacePointHitVecMap) {
368  const recob::SpacePoint* spacePoint = pointPair.first;
369  const std::vector<const recob::Hit*>& recobHitVec = pointPair.second;
370 
371  if (recobHitVec.size() != 3) {
372  std::cout << "************>>>>>> do not have 3 hits associated to space point! "
373  << recobHitVec.size() << " ***************" << std::endl;
374  continue;
375  }
376 
377  reco::ClusterHit2DVec hitVector(recobHitVec.size());
378 
379  for (const auto& recobHit : recobHitVec) {
380  const reco::ClusterHit2D* hit2D = recobHitTo2DHitMap.at(recobHit);
381 
382  hitVector[hit2D->WireID().Plane] = hit2D;
383  }
384 
385  // Set up to get average peak time, hitChiSquare, etc.
386  unsigned int statusBits(0x7);
387  float avePeakTime(0.);
388  float weightSum(0.);
389 
390  // And get the wire IDs
391  std::vector<geo::WireID> wireIDVec = {geo::WireID(), geo::WireID(), geo::WireID()};
392 
393  // First loop through the hits to get WireIDs and calculate the averages
394  for (size_t planeIdx = 0; planeIdx < 3; planeIdx++) {
395  const reco::ClusterHit2D* hit2D = hitVector[planeIdx];
396 
397  wireIDVec[planeIdx] = hit2D->WireID();
398 
401 
403 
404  float hitRMS = hit2D->getHit()->RMS();
405  float weight = 1. / (hitRMS * hitRMS);
406  float peakTime = hit2D->getTimeTicks();
407 
408  avePeakTime += peakTime * weight;
409  weightSum += weight;
410  }
411 
412  avePeakTime /= weightSum;
413 
414  // Armed with the average peak time, now get hitChiSquare and the sig vec
415  float hitChiSquare(0.);
416  float sigmaPeakTime(std::sqrt(1. / weightSum));
417  std::vector<float> hitDelTSigVec;
418 
419  for (const auto& hit2D : hitVector) {
420  float hitRMS = hit2D->getHit()->RMS();
421  float combRMS = std::sqrt(hitRMS * hitRMS - sigmaPeakTime * sigmaPeakTime);
422  float peakTime = hit2D->getTimeTicks();
423  float deltaTime = peakTime - avePeakTime;
424  float hitSig = deltaTime / combRMS;
425 
426  hitChiSquare += hitSig * hitSig;
427 
428  hitDelTSigVec.emplace_back(std::fabs(hitSig));
429  }
430 
431  if (m_outputHistograms) m_chiSquare3DVec.push_back(hitChiSquare);
432 
433  // Need to determine the hit overlap ranges
434  int lowMinIndex(std::numeric_limits<int>::max());
435  int lowMaxIndex(std::numeric_limits<int>::min());
436  int hiMinIndex(std::numeric_limits<int>::max());
437  int hiMaxIndex(std::numeric_limits<int>::min());
438 
439  // This loop through hits to find min/max values for the common overlap region
440  for (const auto& hit2D : hitVector) {
441  int hitStart = hit2D->getHit()->PeakTime() - 2. * hit2D->getHit()->RMS() - 0.5;
442  int hitStop = hit2D->getHit()->PeakTime() + 2. * hit2D->getHit()->RMS() + 0.5;
443 
444  lowMinIndex = std::min(hitStart, lowMinIndex);
445  lowMaxIndex = std::max(hitStart, lowMaxIndex);
446  hiMinIndex = std::min(hitStop + 1, hiMinIndex);
447  hiMaxIndex = std::max(hitStop + 1, hiMaxIndex);
448  }
449 
450  // Keep only "good" hits...
451  if (hitChiSquare < m_maxHit3DChiSquare && hiMinIndex > lowMaxIndex) {
452  // One more pass through hits to get charge
453  std::vector<float> chargeVec;
454 
455  for (const auto& hit2D : hitVector)
456  chargeVec.push_back(chargeIntegral(hit2D->getHit()->PeakTime(),
457  hit2D->getHit()->PeakAmplitude(),
458  hit2D->getHit()->RMS(),
459  1.,
460  lowMaxIndex,
461  hiMinIndex));
462 
463  float totalCharge =
464  std::accumulate(chargeVec.begin(), chargeVec.end(), 0.) / float(chargeVec.size());
465  float overlapRange = float(hiMinIndex - lowMaxIndex);
466  float overlapFraction = overlapRange / float(hiMaxIndex - lowMinIndex);
467 
468  // Set up to compute the charge asymmetry
469  std::vector<float> smallestChargeDiffVec;
470  std::vector<float> chargeAveVec;
471  float smallestDiff(std::numeric_limits<float>::max());
472  size_t chargeIndex(0);
473 
474  for (size_t idx = 0; idx < 3; idx++) {
475  size_t leftIdx = (idx + 2) % 3;
476  size_t rightIdx = (idx + 1) % 3;
477 
478  smallestChargeDiffVec.push_back(std::abs(chargeVec[leftIdx] - chargeVec[rightIdx]));
479  chargeAveVec.push_back(float(0.5 * (chargeVec[leftIdx] + chargeVec[rightIdx])));
480 
481  if (smallestChargeDiffVec.back() < smallestDiff) {
482  smallestDiff = smallestChargeDiffVec.back();
483  chargeIndex = idx;
484  }
485 
486  // Take opportunity to look at peak time diff
487  if (m_outputHistograms) {
488  float deltaPeakTime =
489  hitVector[leftIdx]->getTimeTicks() - hitVector[rightIdx]->getTimeTicks();
490 
491  m_deltaTimeVec.push_back(deltaPeakTime);
492  }
493  }
494 
495  float chargeAsymmetry = (chargeAveVec[chargeIndex] - chargeVec[chargeIndex]) /
496  (chargeAveVec[chargeIndex] + chargeVec[chargeIndex]);
497 
498  // If this is true there has to be a negative charge that snuck in somehow
499  if (chargeAsymmetry < -1. || chargeAsymmetry > 1.) {
500  const geo::WireID& hitWireID = hitVector[chargeIndex]->WireID();
501 
502  std::cout << "============> Charge asymmetry out of range: " << chargeAsymmetry
503  << " <============" << std::endl;
504  std::cout << " hit C: " << hitWireID.Cryostat << ", TPC: " << hitWireID.TPC
505  << ", Plane: " << hitWireID.Plane << ", Wire: " << hitWireID.Wire << std::endl;
506  std::cout << " charge: " << chargeVec[0] << ", " << chargeVec[1] << ", "
507  << chargeVec[2] << std::endl;
508  std::cout << " index: " << chargeIndex << ", smallest diff: " << smallestDiff
509  << std::endl;
510  continue;
511  }
512 
513  // Usurping "deltaPeakTime" to be the maximum pull
514  float deltaPeakTime = *std::max_element(hitDelTSigVec.begin(), hitDelTSigVec.end());
515 
516  if (m_outputHistograms) {
517  m_smallChargeDiffVec.push_back(smallestDiff);
518  m_smallIndexVec.push_back(chargeIndex);
519  m_maxPullVec.push_back(deltaPeakTime);
520  m_qualityMetricVec.push_back(hitChiSquare);
521  m_spacePointChargeVec.push_back(totalCharge);
522  m_overlapFractionVec.push_back(overlapFraction);
523  m_overlapRangeVec.push_back(overlapRange);
524  m_hitAsymmetryVec.push_back(chargeAsymmetry);
525  }
526 
527  Eigen::Vector3f position(
528  float(spacePoint->XYZ()[0]), float(spacePoint->XYZ()[1]), float(spacePoint->XYZ()[2]));
529 
530  // Create the 3D cluster hit
531  hitPairList.emplace_back(0,
532  statusBits,
533  position,
534  totalCharge,
535  avePeakTime,
536  deltaPeakTime,
537  sigmaPeakTime,
538  hitChiSquare,
539  overlapFraction,
540  chargeAsymmetry,
541  0.,
542  0.,
543  hitVector,
544  hitDelTSigVec,
545  wireIDVec);
546  }
547  }
548 
549  // Now we give the new hits to the refinery
550  // Note that one advantage of using this utility is that it handles the
551  // Hit/Wire and Hit/RawDigit associations all behind the scenes for us
552  hitRefiner.use_hits(std::move(newHitVecPtr));
553 
554  // Output the new hit collection to the event
555  hitRefiner.put_into();
556 
557  // Handle tree output too
558  m_tupleTree->Fill();
559 
560  clear();
561 
562  if (fEnableMonitoring) {
563  theClockMakeHits.stop();
564 
565  fTimeVector[BUILDTHREEDHITS] = theClockMakeHits.accumulated_real_time();
566  }
567 
568  mf::LogDebug("Cluster3D") << ">>>>> 3D hit building done, found " << hitPairList.size()
569  << " 3D Hits" << std::endl;
570 
571  return;
572  }
573 
574  float
576  float peakAmp,
577  float peakSigma,
578  float areaNorm,
579  int low,
580  int hi) const
581  {
582  float integral(0);
583 
584  for (int sigPos = low; sigPos < hi; sigPos++) {
585  float arg = (float(sigPos) - peakMean + 0.5) / peakSigma;
586  integral += peakAmp * std::exp(-0.5 * arg * arg);
587  }
588 
589  return integral;
590  }
591 
592  //------------------------------------------------------------------------------------------------------------------------------------------
593  //------------------------------------------------------------------------------------------------------------------------------------------
594 
595  DEFINE_ART_CLASS_TOOL(SpacePointHit3DBuilder)
596 } // namespace lar_cluster3d
bool m_outputHistograms
Take the time to create and fill some histograms for diagnostics.
std::list< reco::ClusterHit3D > HitPairList
Definition: Cluster3D.h:338
art::InputTag fSpacePointProducerLabel
Data members to follow.
float getTimeTicks() const
Definition: Cluster3D.h:75
float chargeIntegral(float, float, float, float, int, int) const
Perform charge integration between limits.
geo::WireID WireID() const
Definition: Hit.h:233
float RMS() const
RMS of the hit shape, in tick units.
Definition: Hit.h:220
Declaration of signal hit object.
The data type to uniquely identify a Plane.
Definition: geo_types.h:472
const geo::WireID & WireID() const
Definition: Cluster3D.h:76
std::vector< reco::ClusterHit2D > Hit2DVector
std::vector< geo::WireID > ChannelToWire(raw::ChannelID_t const channel) const
Returns a list of wires connected to the specified TPC channel.
CryostatID_t Cryostat
Index of cryostat.
Definition: geo_types.h:212
WireID_t Wire
Index of the wire within its plane.
Definition: geo_types.h:580
float getTimeToExecute(IHit3DBuilder::TimeValues index) const override
If monitoring, recover the time to execute a particular function.
unsigned int Ncryostats() const
Returns the number of cryostats in the detector.
void Hit3DBuilder(art::Event &evt, reco::HitPairList &hitPairList, RecobHitToPtrMap &) override
Given a set of recob hits, run DBscan to form 3D clusters.
standard_dbscan3dalg useful for diagnostics hits not in a line will not be clustered on on only for track like only for track like on on the smaller the less shower like tracks low
const recob::Hit * getHit() const
Definition: Cluster3D.h:77
IDparameter< geo::PlaneID > PlaneID
Member type of validated geo::PlaneID parameter.
void clear()
clear the tuple vectors before processing next event
Class managing the creation of a new recob::Hit object.
Definition: HitCreator.h:83
T abs(T value)
Helper functions to create a hit.
void use_hits(std::unique_ptr< std::vector< recob::Hit >> &&srchits)
Uses the specified collection as data product.
Definition: HitCreator.cxx:528
IDparameter< geo::WireID > WireID
Member type of validated geo::WireID parameter.
void put_into(art::Event &)
Moves the data into the event.
Definition: HitCreator.h:908
A class handling a collection of hits and its associations.
Definition: HitCreator.h:842
SpacePointHit3DBuilder class definiton.
const Double32_t * XYZ() const
Definition: SpacePoint.h:76
TimeValues
enumerate the possible values for time checking if monitoring timing
Definition: IHit3DBuilder.h:75
The geometry of one entire detector, as served by art.
Definition: Geometry.h:181
PlaneID_t Plane
Index of the plane within its TPC.
Definition: geo_types.h:493
Definition of data types for geometry description.
IHit3DBuilder interface class definiton.
Definition: IHit3DBuilder.h:38
This provides an art tool interface definition for tools which construct 3D hits used in 3D clusterin...
std::vector< const reco::ClusterHit2D * > ClusterHit2DVec
Definition: Cluster3D.h:91
unsigned int NTPC(unsigned int cstat=0) const
Returns the total number of TPCs in the specified cryostat.
virtual void produces(art::ProducesCollector &) override
Each algorithm may have different objects it wants &quot;produced&quot; so use this to let the top level produc...
float PeakTime() const
Time of the signal peak, in tick units.
Definition: Hit.h:218
float m_maxHit3DChiSquare
Provide ability to select hits based on &quot;chi square&quot;.
SpacePointHit3DBuilder(fhicl::ParameterSet const &pset)
Constructor.
T copy(T const &v)
int trigger_offset(DetectorClocksData const &data)
constexpr WireID()=default
Default constructor: an invalid TPC ID.
2D representation of charge deposited in the TDC/wire plane
Definition: Hit.h:48
art::ServiceHandle< art::TFileService > tfs
TCEvent evt
Definition: DataStructs.cxx:8
TPCID_t TPC
Index of the TPC within its cryostat.
Definition: geo_types.h:406
std::unordered_map< const recob::Hit *, art::Ptr< recob::Hit >> RecobHitToPtrMap
Defines a structure mapping art representation to internal.
Definition: IHit3DBuilder.h:62
art framework interface to geometry description
BEGIN_PROLOG could also be cout
void configure(const fhicl::ParameterSet &) override
Interface for configuring the particular algorithm tool.
Signal from collection planes.
Definition: geo_types.h:146
unsigned getStatusBits() const
Definition: Cluster3D.h:71
void setStatusBit(unsigned bits) const
Definition: Cluster3D.h:79