HitFinderCounter35t_module.cc
Go to the documentation of this file.
1 #ifndef HITFINDERCOUNTER35T_H
2 #define HITFINDERCOUNTER35T_H
3 
4 ////////////////////////////////////////////////////////////////////////
5 //
6 // HitFinderCounter35t class
7 //
8 // k.warburton@sheffield.ac.uk
9 //
10 // Michelle Stancari had the idea to use the 35 ton counters to aid in
11 // disambiguation. This module attempts to do that.
12 // First only hits within a window around the counter coincidence are
13 // considered.
14 // Then an unambigious wire segment is searched for for the hit.
15 //
16 // Uses the normal 35 ton disambiguation module as a base.
17 //
18 ////////////////////////////////////////////////////////////////////////
19 
20 #include <string>
21 #include <vector>
22 #include <utility> // std::move()
23 #include <memory> // std::unique_ptr<>
24 
25 
26 // Framework includes
30 #include "art_root_io/TFileService.h"
31 #include "art_root_io/TFileDirectory.h"
32 
33 // LArSoft Includes
40 #include "lardataobj/RawData/raw.h"
48 
49 // Seed Service
50 #include "nurandom/RandomUtils/NuRandomService.h"
51 #include "CLHEP/Random/RandomEngine.h"
52 
53 // Want to include the CounterPositionMapFunction
55 
56 #include "HitLineFitAlg.h"
57 
58 // ROOT Includes
59 #include "TH1D.h"
60 #include "TH2F.h"
61 #include "TMath.h"
62 #include "TF1.h"
63 #include "TTree.h"
64 #include "TVectorD.h"
65 #include "TVector2.h"
66 #include "TVector3.h"
67 
68 namespace dune{
70 
71  public:
72 
73  explicit HitFinderCounter35t(fhicl::ParameterSet const& pset);
74 
75  void produce(art::Event& evt) override;
76  void beginJob() override;
77 
78  private:
79 
80  //bool DoesIntersect( double A0, double B0, double A1, double B1, double A2, double B2, double A3, double B3 );
81  int pnpoly( int nvert, float *vertx, float *verty, float testx, float testy );
82  void FindXZGradient ( std::vector < recob::Hit > HitVector, float &Gradient, float& Intercept );
83  void FindPlaneGradient( std::vector < recob::Hit > HitVector, float &Gradient, float& Intercept );
84  void MatrixGradient ( TMatrixD X, TMatrixD Y, size_t MatSize, float &Gradient, float &Intercept );
85  double DistToLine ( float Gradient, float Intercept, double X, double Y);
86  std::vector<recob::Hit> FindUniqueHits( std::vector < recob::Hit > const GoodHits, unsigned int Plane, unsigned int TPC );
87  int CheckWhichIndex( std::vector<int> CloseHits );
88  std::vector<int> ClosestDistance( std::vector<double> CloseHits );
89  void OutAndClearVector ( std::vector < std::pair < std::vector < recob::Hit >, size_t > > &InitialBad,
90  std::vector < std::pair < std::vector < recob::Hit >, size_t > > &NewBad,
91  std::vector < std::pair < recob::Hit, size_t > > & NewGood, size_t HitsSize );
92  void CrossCollection ( std::vector < recob::Hit > const GoodHits,
93  std::vector < std::pair < std::vector < recob::Hit >, size_t > > &InputBadVector,
94  std::vector < std::pair < std::vector < recob::Hit >, size_t > > &OutputBadVector,
95  std::vector < std::pair < recob::Hit, size_t > > &OutputGoodVector );
96  void AdjacentWireWidth ( std::vector < recob::Hit > const GoodHits,
97  std::vector < std::pair < std::vector < recob::Hit >, size_t > > &InputBadVector,
98  std::vector < std::pair < std::vector < recob::Hit >, size_t > > &OutputBadVector,
99  std::vector < std::pair < recob::Hit, size_t > > &OutputGoodVector );
100  void TwoDimXZLineFit ( std::vector < recob::Hit > const GoodHits,
101  std::vector < std::pair < std::vector < recob::Hit >, size_t > > &InputBadVector,
102  std::vector < std::pair < std::vector < recob::Hit >, size_t > > &OutputBadVector,
103  std::vector < std::pair < recob::Hit, size_t > > &OutputGoodVector );
104  void TwoDimPlaneLineFit( std::vector < recob::Hit > const GoodHits,
105  std::vector < std::pair < std::vector < recob::Hit >, size_t > > &InputBadVector,
106  std::vector < std::pair < std::vector < recob::Hit >, size_t > > &OutputBadVector,
107  std::vector < std::pair < recob::Hit, size_t > > &OutputGoodVector );
108 
110 
111  bool fDebug;
119  unsigned int fAdjacentWireWidth;
120  unsigned int fAdjacentTimeWidth;
121  unsigned int fCollectionTimeWidth;
122 
125 
126  std::map< unsigned int, std::pair < TVector3, std::vector< TVector3 > > > CounterPositionMap; // The map of counter positions....
127  std::vector< std::pair< unsigned int, unsigned int > > ExternalTrigIndexVec; // My vector of counter coincidence indexes...
128  double UVStartEndPointsX[4];
129 
131  int TrigTime=0;
132 
134  CLHEP::HepRandomEngine& fEngine;
135  }; // class HitFinderCounter35t
136 
137 
138  //-------------------------------------------------
139  //-------------------------------------------------
141  : EDProducer{pset}
142  , fDebug (pset.get<bool>("Debug"))
143  , fHitsModuleLabel (pset.get< std::string >("HitsModuleLabel" ))
144  , fCounterModuleLabel (pset.get< std::string >("CounterModuleLabel"))
145  , fCounterDir (pset.get< std::string >("CounterDir" ))
146  , fCounterFile (pset.get< std::string >("CounterFile"))
147  , fCoincidenceTolerance(pset.get<int>("CoincidenceTolerance")) // num PENN board ticks
148  , fConvCountTimeToTicks(pset.get<double>("fConvCountTimeToTicks"))
149  , fExtendCounters (pset.get<double>("ExtendCounters"))
150  , fAdjacentWireWidth (pset.get<unsigned int>("AdjacentWireWidth"))
151  , fAdjacentTimeWidth (pset.get<unsigned int>("AdjacentTimeWidth"))
152  , fCollectionTimeWidth (pset.get<unsigned int>("CollectionTimeWidth"))
153  , fFitAlg (pset.get<fhicl::ParameterSet>("HitLineFitAlg"))
154  , fDoHitLineFitAlg (pset.get<bool>("DoHitLineFitAlg",false))
155  , fEngine(art::ServiceHandle<rndm::NuRandomService>{}->createEngine(*this,"HepJamesRandom","Seed"))
156  {
158  }
159  //-------------------------------------------------
161 
162  // Want to know the X co-ords for the short and long induction wires, only want to calculate this once as all wires have the same X position.
163  double UWireLongDriftStart[3], UWireLongDriftEnd[3], UWireShortDriftStart[3], UWireShortDriftEnd[3];
164  double VWireLongDriftStart[3], VWireLongDriftEnd[3], VWireShortDriftStart[3], VWireShortDriftEnd[3];
165  fGeom->WireEndPoints( 0, 0, 0, 0, UWireShortDriftStart, UWireShortDriftEnd );
166  fGeom->WireEndPoints( 0, 1, 0, 0, UWireLongDriftStart , UWireLongDriftEnd );
167  fGeom->WireEndPoints( 0, 0, 1, 0, VWireShortDriftStart, VWireShortDriftEnd );
168  fGeom->WireEndPoints( 0, 1, 1, 0, VWireLongDriftStart , VWireLongDriftEnd );
169  UVStartEndPointsX[0] = UWireShortDriftStart[0];
170  UVStartEndPointsX[1] = UWireLongDriftStart[0];
171  UVStartEndPointsX[2] = VWireShortDriftStart[0];
172  UVStartEndPointsX[3] = VWireLongDriftStart[0];
173 
175 
177  TwoDLineHist = tfs->make<TH2F>("TwoDLineHist","Plot of collection plane hit positions in the XZ plane; Z position (cm); X position (cm)", 320, -5, 155, 800, -50, 350 );
178  TwoDLineHist->SetMarkerStyle(6);
179  TwoDLineHist->SetMarkerSize(1);
180 
181  }
182  //-------------------------------------------------
184 
185  if (fDebug) std::cout << "\n\nLooking at event " << evt.event() << std::endl;
186 
187  fFitAlg.SetSeed(fEngine.getSeed());
188 
189  // get raw::ExternalTriggers
190  art::Handle< std::vector< raw::ExternalTrigger> > externalTriggerListHandle;
191  std::vector< art::Ptr< raw::ExternalTrigger> > trigs;
192  if (evt.getByLabel(fCounterModuleLabel, externalTriggerListHandle) )
193  art::fill_ptr_vector(trigs,externalTriggerListHandle);
194 
195  // get raw::ExternalTriggers
197  std::vector< art::Ptr< recob::Hit> > hits;
198  if (evt.getByLabel(fHitsModuleLabel, HitListHandle) )
199  art::fill_ptr_vector(hits,HitListHandle);
200 
201  auto const* detprop = lar::providerFrom<detinfo::DetectorPropertiesService>();
202  fDriftVelocity = detprop->DriftVelocity(); // cm / us
203 
204  // Loop through counter hits, to look for external trigger pairs.
205  ExternalTrigIndexVec.clear();
206  for (size_t CLoop=0; CLoop < trigs.size(); ++CLoop) {
207  for (size_t CLoop2=0; CLoop2 < trigs.size(); ++CLoop2) {
208  if ( fabs( trigs[CLoop]->GetTrigTime() - trigs[CLoop2]->GetTrigTime()) > fCoincidenceTolerance ) continue;
209  if ( CLoop == CLoop2 ) continue;
210  // for c2: GetTrigID() is an unsigned int and always >= 0
211  //if ( ( trigs[CLoop]->GetTrigID() >= 6 && trigs[CLoop]->GetTrigID() <= 15 && trigs[CLoop2]->GetTrigID() >= 28 && trigs[CLoop2]->GetTrigID() <= 37 ) // East Lower, West Upper
212  // || ( trigs[CLoop]->GetTrigID() >= 0 && trigs[CLoop]->GetTrigID() <= 5 && trigs[CLoop2]->GetTrigID() >= 22 && trigs[CLoop2]->GetTrigID() <= 27 ) // South Lower, North Upper
213  // || ( trigs[CLoop]->GetTrigID() >= 16 && trigs[CLoop]->GetTrigID() <= 21 && trigs[CLoop2]->GetTrigID() >= 38 && trigs[CLoop2]->GetTrigID() <= 43 ) // North Lower, South Upper
214  if ( ( trigs[CLoop]->GetTrigID() >= 6 && trigs[CLoop]->GetTrigID() <= 15 && trigs[CLoop2]->GetTrigID() >= 28 && trigs[CLoop2]->GetTrigID() <= 37 ) // East Lower, West Upper
215  || ( trigs[CLoop]->GetTrigID() <= 5 && trigs[CLoop2]->GetTrigID() >= 22 && trigs[CLoop2]->GetTrigID() <= 27 ) // South Lower, North Upper
216  || ( trigs[CLoop]->GetTrigID() >= 16 && trigs[CLoop]->GetTrigID() <= 21 && trigs[CLoop2]->GetTrigID() >= 38 && trigs[CLoop2]->GetTrigID() <= 43 ) // North Lower, South Upper
217  ) {
218  if (fDebug) std::cout << "I have a match..."
219  << "CLoop " << CLoop << ", ID " << trigs[CLoop]->GetTrigID() << ", time " << trigs[CLoop]->GetTrigTime() << "..."
220  << "CLoop2 " << CLoop2 << ", ID " << trigs[CLoop2]->GetTrigID() << ", Time " << trigs[CLoop2]->GetTrigTime()
221  << std::endl;
222  ExternalTrigIndexVec.push_back( std::make_pair( CLoop, CLoop2 ) );
223  } // If a good coincidence
224  } // CLoop2
225  } // CLoop
226 
227  std::cout << "ExternalTrigIndexVec has size " << ExternalTrigIndexVec.size() << std::endl;
228  for (size_t aa=0; aa< ExternalTrigIndexVec.size(); ++aa) {
229  int IDA = trigs.at(ExternalTrigIndexVec[aa].first)->GetTrigID();
230  double TimeA = trigs.at(ExternalTrigIndexVec[aa].first)->GetTrigTime();
231  double TickA = trigs.at(ExternalTrigIndexVec[aa].first)->GetTrigTime() / fConvCountTimeToTicks;
232  int IDB = trigs.at(ExternalTrigIndexVec[aa].second)->GetTrigID();
233  double TimeB = trigs.at(ExternalTrigIndexVec[aa].second)->GetTrigTime();
234  double TickB = trigs.at(ExternalTrigIndexVec[aa].second)->GetTrigTime() / fConvCountTimeToTicks;
235  if (fDebug) std::cout << "ExternalTrigIndexVec["<<aa<<"] has indexes " << ExternalTrigIndexVec[aa].first << " and " << ExternalTrigIndexVec[aa].second
236  << ". They correspond to TrigIDs " << IDA << " and " << IDB << ", and times " << TimeA << " (" << TickA << ") and " << TimeB << " (" << TickB << ")"
237  << std::endl;
238  }
239 
240  // also get the associated wires and raw digits;
241  // we assume they have been created by the same module as the hits
242  art::FindOneP<raw::RawDigit> ChannelHitRawDigits (HitListHandle, evt, fHitsModuleLabel);
243  art::FindOneP<recob::Wire> ChannelHitWires (HitListHandle, evt, fHitsModuleLabel);
244 
245  // this object contains the hit collection
246  // and its associations to wires and raw digits:
248  /* doWireAssns */ ChannelHitWires.isValid(),
249  /* doRawDigitAssns */ ChannelHitRawDigits.isValid()
250  );
251 
252  // I want a vector of a vector of hits, to store my undisambiguated hits.
253  std::vector < std::pair < std::vector < recob::Hit >, size_t > > UnDisambigHits;
254 
255  // FIXME:::::I am unsure of the best way to handle showers - lots of trigger indexes at the same time.
256  // The easiest ( and laziest ) thing to do, is to just discount events which have many triggers.
257  if ( ExternalTrigIndexVec.size() > 1 ) {
258  std::cout << "Voiding this event as I have a vector of size " << ExternalTrigIndexVec.size() << std::endl;
259  hcol.put_into(evt);
260  return;
261  }
262 
263 
264 
265  // Loop through all the indexes to see whether to keep the hit.
266  for (size_t TrigInd=0; TrigInd< ExternalTrigIndexVec.size(); ++TrigInd) {
267  // Make my Corner arrays.
268  std::map< unsigned int, std::pair < TVector3, std::vector< TVector3 > > >::iterator it1 = CounterPositionMap.find( trigs.at(ExternalTrigIndexVec[TrigInd].first)->GetTrigID() );
269  std::map< unsigned int, std::pair < TVector3, std::vector< TVector3 > > >::iterator it2 = CounterPositionMap.find( trigs.at(ExternalTrigIndexVec[TrigInd].second)->GetTrigID() );
270  float VertexX[4] = { (float)it1->second.second[0][0], (float)it1->second.second[1][0], (float)it2->second.second[1][0], (float)it2->second.second[0][0]};
271  float VertexY[4] = { (float)it1->second.second[0][1], (float)it1->second.second[2][1], (float)it2->second.second[2][1], (float)it2->second.second[0][1]};
272  float VertexZ[4] = { (float)it1->second.second[0][2], (float)it1->second.second[1][2], (float)it2->second.second[1][2], (float)it2->second.second[0][2]};
273 
274  float SmallestX = std::min( VertexX[0], std::min( VertexX[1], std::min( VertexX[2], VertexX[3] ) ) );
275  float BiggestX = std::max( VertexX[0], std::max( VertexX[1], std::max( VertexX[2], VertexX[3] ) ) );
276 
277  TrigTime = ( trigs.at(ExternalTrigIndexVec[TrigInd].first)->GetTrigTime() + trigs.at(ExternalTrigIndexVec[TrigInd].second)->GetTrigTime() ) / (2*fConvCountTimeToTicks);
278  ///*
279  if (fDebug) std::cout << "\nCounter1, with TrigID " << trigs.at(ExternalTrigIndexVec[TrigInd].first)->GetTrigID() << " (" << it1->first << ") has corners......"
280  << "( " << it1->second.second[0][0] << ", " << it1->second.second[0][1] << ", " << it1->second.second[0][2] << ") and "
281  << "( " << it1->second.second[1][0] << ", " << it1->second.second[1][1] << ", " << it1->second.second[1][2] << ") and "
282  << "( " << it1->second.second[2][0] << ", " << it1->second.second[2][1] << ", " << it1->second.second[2][2] << ") and "
283  << "( " << it1->second.second[3][0] << ", " << it1->second.second[3][1] << ", " << it1->second.second[3][2] << ") "
284  << "\nCounter2, with TrigID " << trigs.at(ExternalTrigIndexVec[TrigInd].second)->GetTrigID() << " (" << it2->first << ") has corners......"
285  << "( " << it2->second.second[0][0] << ", " << it2->second.second[0][1] << ", " << it2->second.second[0][2] << ") and "
286  << "( " << it2->second.second[1][0] << ", " << it2->second.second[1][1] << ", " << it2->second.second[1][2] << ") and "
287  << "( " << it2->second.second[2][0] << ", " << it2->second.second[2][1] << ", " << it2->second.second[2][2] << ") and "
288  << "( " << it2->second.second[3][0] << ", " << it2->second.second[3][1] << ", " << it2->second.second[3][2] << ") "
289  <<"\nVertexX has co-ords " << VertexX[0] << " " << VertexX[1] << " " << VertexX[2] << " " << VertexX[3]
290  <<"\nVertexY has co-ords " << VertexY[0] << " " << VertexY[1] << " " << VertexY[2] << " " << VertexY[3]
291  <<"\nVertexZ has co-ords " << VertexZ[0] << " " << VertexZ[1] << " " << VertexZ[2] << " " << VertexZ[3]
292  << std::endl;
293 
294  bool doHitLineFitAlg = fDoHitLineFitAlg;
295  int trignum = -1;
296  if ( trigs.at(ExternalTrigIndexVec[TrigInd].first)->GetTrigID() >= 6 && trigs.at(ExternalTrigIndexVec[TrigInd].first)->GetTrigID() <= 15 && trigs.at(ExternalTrigIndexVec[TrigInd].second)->GetTrigID() >= 28 && trigs.at(ExternalTrigIndexVec[TrigInd].second)->GetTrigID() <= 37 ) trignum=111; // East Lower, West Upper
297  // for c2: GetTrigID() is an unsigned int and always >= 0
298  //else if ( trigs.at(ExternalTrigIndexVec[TrigInd].first)->GetTrigID() >= 0 && trigs.at(ExternalTrigIndexVec[TrigInd].first)->GetTrigID() <= 5 && trigs.at(ExternalTrigIndexVec[TrigInd].second)->GetTrigID() >= 22 && trigs.at(ExternalTrigIndexVec[TrigInd].second)->GetTrigID() <= 27 ) trignum=112; // South Lower, North Upper
299  else if ( trigs.at(ExternalTrigIndexVec[TrigInd].first)->GetTrigID() <= 5 && trigs.at(ExternalTrigIndexVec[TrigInd].second)->GetTrigID() >= 22 && trigs.at(ExternalTrigIndexVec[TrigInd].second)->GetTrigID() <= 27 ) trignum=112; // South Lower, North Upper
300  else if ( trigs.at(ExternalTrigIndexVec[TrigInd].first)->GetTrigID() >= 16 && trigs.at(ExternalTrigIndexVec[TrigInd].first)->GetTrigID() <= 21 && trigs.at(ExternalTrigIndexVec[TrigInd].second)->GetTrigID() >= 38 && trigs.at(ExternalTrigIndexVec[TrigInd].second)->GetTrigID() <= 43 ) trignum=113; // North Lower, South Upper
301 
302  float c1x = it1->second.first.X();
303  float c1z = it1->second.first.Z();
304  float c2x = it2->second.first.X();
305  float c2z = it2->second.first.Z();
306  if (trignum == 111)
307  {
308  float slope = ((c1x-c2x)/(c1z-c2z));
309  fFitAlg.SetParameter(0,10,-50,250);
310  fFitAlg.SetParameter(1,1,slope-0.2,slope+0.2);
311  fFitAlg.SetParameter(2,0,-0.0002,0.0002);
312  fFitAlg.SetHorizVertRanges(-10,170,-50,250);
313  }
314  else if (trignum == 112 || trignum == 113)
315  {
316  float slope = ((c1z-c2z)/(c1x-c2x));
317  fFitAlg.SetParameter(0,10,-10,170);
318  fFitAlg.SetParameter(1,1,slope-0.2,slope+0.2);
319  fFitAlg.SetParameter(2,0,-0.0002,0.0002);
320  fFitAlg.SetHorizVertRanges(-50,250,-10,170);
321  }
322  else
323  {
324  doHitLineFitAlg = false;
325  }
326  if (ExternalTrigIndexVec.size() != 1) doHitLineFitAlg = false;
327 
328  std::vector<dune::HitLineFitAlg::HitLineFitData> fitdata;
330  std::map<unsigned int, size_t> index_convert;
331  unsigned int fitdataindex = 0;
332 
333  //*/
334  // ------------------------- Get Collection wires -------------------------
335  // Loop through collection plane hits first, as can use that information to help decide which TPC an induction plane hit should be on.
336  for( size_t HitInd = 0; HitInd < hits.size(); HitInd++ ) {
337  if ( hits[HitInd]->PeakTime()-TrigTime < 0 ) continue; // If in PreTriggerTick window then can't deduce the X position.
338  if( hits[HitInd]->View() != geo::kZ ) continue;
339 
340  // Collection plane wires mainly discriminated against using XZ plane
341  bool KeepHit = false;
342  //art::Ptr<recob::Wire> wire = ChannelHitWires.at(HitInd);
343  //art::Ptr<raw::RawDigit> rawdigits = ChannelHitRawDigits.at(HitInd);
344 
345  double WireStart[3], WireEnd[3];
346  fGeom->WireEndPoints( hits[HitInd]->WireID(), WireStart, WireEnd );
347  float DriftDist = (0.5 *(hits[HitInd]->PeakTime()-TrigTime) * fDriftVelocity );
348  if ( hits[HitInd]->WireID().TPC % 2 == 0) { // If short TPC
349  DriftDist = -DriftDist;
350  }
351  float HitXPos = DriftDist + WireStart[0];
352 
353  KeepHit = pnpoly( 4, VertexX, VertexZ, HitXPos, (float)WireEnd[2] );
354  if ( KeepHit ) {
355  //std::cout << "\nGood collection plane hit on Channel " << hits[HitInd]->Channel() << ", Wire " << hits[HitInd]->WireID().Wire << ", Plane " << hits[HitInd]->WireID().Plane
356  // << ", TPC" << hits[HitInd]->WireID().TPC << " at time " << hits[HitInd]->PeakTime()-TrigTime << " has X pos " << HitXPos << " and Z pos " << (float)WireEnd[2]
357  // << "\nI used the following cuts... X " << VertexX[0] << " " << VertexX[1] << " " << VertexX[2] << " " << VertexX[3]
358  // << ", and Z " << VertexZ[0] << " " << VertexZ[1] << " " << VertexZ[2] << " " << VertexZ[3]
359  // << std::endl;
360 
362  if (trignum == 111)
363  {
364  hlfd.hitHoriz = (float)WireEnd[2];
365  hlfd.hitVert = HitXPos;
366  hlfd.hitHorizErrLo = 0.25;
367  hlfd.hitHorizErrHi = 0.25;
368  hlfd.hitVertErrLo = 0.25;
369  hlfd.hitVertErrHi = 0.25;
370  }
371  else if (trignum == 112 || trignum == 113)
372  {
373  hlfd.hitHoriz = HitXPos;
374  hlfd.hitVert = (float)WireEnd[2];
375  hlfd.hitHorizErrLo = 0.25;
376  hlfd.hitHorizErrHi = 0.25;
377  hlfd.hitVertErrLo = 0.25;
378  hlfd.hitVertErrHi = 0.25;
379  }
380  hlfd.hitREAL = false;
381  fitdata.push_back(hlfd);
382  index_convert[fitdataindex] = HitInd;
383  ++fitdataindex;
384 
385  //hcol.emplace_back(*hits[HitInd], wire, rawdigits);
386  }
387  }
388 
389  int retval = -1;
390  if (doHitLineFitAlg) retval = fFitAlg.FitLine(fitdata,bestfit);
391 
392  if (!doHitLineFitAlg)
393  {
394  for (unsigned int i_fd = 0; i_fd < fitdata.size(); ++i_fd)
395  {
396  art::Ptr<recob::Wire> wire = ChannelHitWires.at(index_convert[i_fd]);
397  art::Ptr<raw::RawDigit> rawdigits = ChannelHitRawDigits.at(index_convert[i_fd]);
398  hcol.emplace_back(*hits[index_convert[i_fd]],wire,rawdigits);
399  }
400  }
401  else if (retval != 1 && doHitLineFitAlg)
402  {
403  std::cout << "No line fit could be found, or not enough hits in counter shadow to make a line" << std::endl;
404  hcol.put_into(evt);
405  return;
406  }
407  else
408  {
409  for (unsigned int i_fd = 0; i_fd < fitdata.size(); ++i_fd)
410  {
411  if (fitdata[i_fd].hitREAL)
412  {
413  art::Ptr<recob::Wire> wire = ChannelHitWires.at(index_convert[i_fd]);
414  art::Ptr<raw::RawDigit> rawdigits = ChannelHitRawDigits.at(index_convert[i_fd]);
415  hcol.emplace_back(*hits[index_convert[i_fd]],wire,rawdigits);
416  }
417  }
418  }
419 
420  std::cout << "After collection wires for TrigInd " << TrigInd << ", hcol has size " << hcol.size() << std::endl;
421  // Got all the collection hits, so now loop through the induction plane hits.
422  // ------------------------- Get Collection wires -------------------------
423 
424  // ------------------------- Get Induction wires -------------------------
425  for( size_t HitInd = 0; HitInd < hits.size(); HitInd++ ) {
426  if ( hits[HitInd]->PeakTime()-TrigTime < 0 ) continue; // If in PreTriggerTick window then can't deduce the X position.
427  if ( hits[HitInd]->View() == geo::kZ ) continue; // If a collection wire continue...
428  //if ( hits[HitInd]->PeakAmplitude() < 8 ) continue;
429 
430 
431  // An induction signal can be in either long or short drift volume...Work out X position for each of them...
432  float DriftDist = (0.5 *(hits[HitInd]->PeakTime()-TrigTime) * fDriftVelocity );
433  float HitPosShortDrift = UVStartEndPointsX[ hits[HitInd]->View()*2 ] - DriftDist;
434  float HitPosLongDrift = UVStartEndPointsX[ 1 + hits[HitInd]->View()*2 ] + DriftDist;
435  // If outside the hit X window for both long and short, then no point considering this hit...
436  bool CouldBeShortDrift = true;
437  bool CouldBeLongDrift = true;
438  if ( HitPosShortDrift < SmallestX ) CouldBeShortDrift = false;
439  if ( HitPosLongDrift > BiggestX ) CouldBeLongDrift = false;
440  if ( !CouldBeShortDrift && !CouldBeLongDrift ) continue;
441  /*
442  std::cout << "\nLooking at an induction wire hit at time " << hits[HitInd]->PeakTime()-TrigTime << ", DriftDist is " << DriftDist
443  << " HitPosShort is " << HitPosShortDrift << " ("<<UVStartEndPointsX[ hits[HitInd]->View()*2 ]<<"), and HitPosLong is " << HitPosLongDrift << " ("<<UVStartEndPointsX[ 1 + hits[HitInd]->View()*2 ]<<")"
444  << "\nI used the following X cut " << VertexX[0] << " " << VertexX[1] << " " << VertexX[2] << " " << VertexX[3] << " min " << SmallestX << ", max " << BiggestX
445  << "\nCan hit be in the short drift? " << CouldBeShortDrift << ", and the long drift? " << CouldBeLongDrift
446  << std::endl;
447  */
448  // Have deduced that my hit can be in either the short drift, the long drift or both...
449  // Now want to evaluate which wire segments for this channel are in my 3D window.
450  // I want to consider all wire segments because the original hit may be assigned to the wrong wire segment.
451  std::vector< recob::Hit > TempHitsVec;
452  int Channel = hits[HitInd]->Channel();
453  std::vector< geo::WireID > WireList = fGeom->ChannelToWire( Channel );
454  for (unsigned int ch=0; ch<WireList.size(); ++ch) {
455  if ( !CouldBeShortDrift && (WireList[ch].TPC%2 == 0) ) continue; // If have ruled out short drift, then no point considering any short drift TPCs
456  if ( !CouldBeLongDrift && (WireList[ch].TPC%2 != 0) ) continue; // If have ruled out long drift, then no point considering any long drift TPCs
457  // Work out start / end positions for this wire segment.
458  double WStart[3], WEnd[3];
459  fGeom->WireEndPoints( WireList[ch], WStart, WEnd );
460  //double WireLength = pow ( (pow(WStart[1]-WEnd[1],2)) + (pow(WStart[2]-WEnd[2],2)) , 0.5 );
461  //std::cout << "Wire " << ch << " for channel " << Channel << " is in TPC " << WireList[ch].TPC << " " << " Plane " << WireList[ch].Plane << " Wire " << WireList[ch].Wire << ", length " << WireLength << std::endl;
462 
463  // I want to iterate through the wire looking if points along the wire are within the YZ projection.
464  int NPoints = 5;
465  for (int WPass=0; WPass < NPoints; ++WPass) {
466  double ThisXPos = HitPosLongDrift;
467  if (WireList[ch].TPC%2 == 0) ThisXPos = HitPosShortDrift;
468  double ThisYPos = WStart[1] + ( WPass * (WEnd[1]-WStart[1])/(NPoints-1) );
469  double ThisZPos = WStart[2] + ( WPass * (WEnd[2]-WStart[2])/(NPoints-1) );
470 
471  bool GoodWire = false;
472  // First test if it is in the XZ window
473  GoodWire = pnpoly ( 4, VertexX, VertexZ, ThisXPos, ThisZPos );
474  if (!GoodWire) continue; // If outside XZ window
475 
476  // If have EW coincidence, want to compare in YZ.
477  // If have NS coincidence, want to compare in XY
478  if ( trigs.at(ExternalTrigIndexVec[TrigInd].first)->GetTrigID() >= 6 && trigs.at(ExternalTrigIndexVec[TrigInd].first)->GetTrigID() <= 15 ) {
479  GoodWire = pnpoly ( 4, VertexY, VertexZ, ThisYPos, ThisZPos ); // If EW do this
480  } else { // If NS do this
481  GoodWire = pnpoly ( 4, VertexX, VertexY, ThisXPos, ThisYPos );
482  }
483  if (!GoodWire) continue; // If outside window
484 
485  // If this hit is the original one, then add it to TempHitsVec
486  if ( WireList[ch].Wire == hits[HitInd]->WireID().Wire && WireList[ch].TPC == hits[HitInd]->WireID().TPC ) {
487  TempHitsVec.push_back( *hits[HitInd] );
488  } else { // If it isn't the origianl hit, then I need to make a new one.
489  recob::Hit hit( hits[HitInd]->Channel(), hits[HitInd]->StartTick(), hits[HitInd]->EndTick(), hits[HitInd]->PeakTime(),
490  hits[HitInd]->SigmaPeakTime(), hits[HitInd]->RMS(), hits[HitInd]->PeakAmplitude(),
491  hits[HitInd]->SigmaPeakAmplitude(), hits[HitInd]->SummedADC(), hits[HitInd]->Integral(),
492  hits[HitInd]->SigmaIntegral(), hits[HitInd]->Multiplicity(), hits[HitInd]->LocalIndex(),
493  hits[HitInd]->GoodnessOfFit(), hits[HitInd]->DegreesOfFreedom(), hits[HitInd]->View(),
494  hits[HitInd]->SignalType(), WireList[ch]
495  );
496  TempHitsVec.push_back( hit );
497  }
498  break; // Only want one hit per wire segment.
499  } // Test X positions along the wire to see if within 3D volume
500  } // Loop through all possible wires for this channel
501  if (TempHitsVec.size() == 0) continue; // No Wire crossings, so throw this hit out.
502  if (TempHitsVec.size() == 1) { // Only one possible hit!!
503  art::Ptr<recob::Wire> wire = ChannelHitWires.at(HitInd);
504  art::Ptr<raw::RawDigit> rawdigits = ChannelHitRawDigits.at(HitInd);
505  hcol.emplace_back(TempHitsVec[0], wire, rawdigits);
506  } else { // If have more than 1 possible wire hit then I need to work out which one to keep...
507  UnDisambigHits.push_back( std::make_pair(TempHitsVec, HitInd) );
508  } // If TempHitsVec is large
509  } // Loop through hits
510  std::cout << "After Induction planes for TrigInd " << TrigInd << " hcol now has size " << hcol.size() << std::endl;
511  } // Loop through trigger indexes
512  std::cout << "After all trigger indexes the vectors have sizes: hits -> " << hits.size() << ", hcol -> " << hcol.size() << ", UnDisambigHits -> " << UnDisambigHits.size() << std::endl;
513  // ------------------------- Get Induction wires -------------------------
514 
515  std::vector<recob::Hit> const &Peak = hcol.peek();
516  int TPC1, TPC2, TPC3, TPC4, TPC5, TPC6, TPC7, TPC0;
517  TPC1 = TPC2 = TPC3 = TPC4 = TPC5 = TPC6 = TPC7 = TPC0 = 0;
518  for (size_t qq=0; qq<Peak.size(); ++qq) {
519  if (Peak[qq].WireID().TPC == 0) ++TPC0;
520  else if (Peak[qq].WireID().TPC == 1) ++TPC1;
521  else if (Peak[qq].WireID().TPC == 2) ++TPC2;
522  else if (Peak[qq].WireID().TPC == 3) ++TPC3;
523  else if (Peak[qq].WireID().TPC == 4) ++TPC4;
524  else if (Peak[qq].WireID().TPC == 5) ++TPC5;
525  else if (Peak[qq].WireID().TPC == 6) ++TPC6;
526  else if (Peak[qq].WireID().TPC == 7) ++TPC7;
527  }
528  if (fDebug) std::cout << "\n\nI have these hits in each TPC " << TPC0 << " " << TPC1 << " " << TPC2 << " " << TPC3 << " " << TPC4 << " " << TPC5 << " " << TPC6 << " " << TPC7 << "\n\n" << std::endl;
529  // Now that I have gone through the trigger indexes I want to see if I can fix some of the undisambiguated hits.
530  // 1) Look for any hits where there were collection plane hits at the same time.
531  // 2) Look for any hits on adjacent induction plane wires at the same time.
532 
533  std::vector < std::pair < std::vector <recob::Hit>, size_t > > StillUnDisambigHits; // Want to clear this each time
534  std::vector < std::pair < recob::Hit, size_t > > NowGoodHits; // Want to clear this each time
535 
536  // ------------------------- Make a 2D line in XZ and fit --------------------------
537  std::cout << "\nNow to do my next step....fit hits to a 2D line in XZ and find which ambiguous hit is closer..." << std::endl;
538  std::vector < recob::Hit > const &NextGoodHits = hcol.peek();
539 
540  TwoDimXZLineFit( NextGoodHits, UnDisambigHits, StillUnDisambigHits, NowGoodHits );
541  for ( size_t NowDisambig=0; NowDisambig < NowGoodHits.size(); ++NowDisambig ) {
542  size_t WhichRawHit = NowGoodHits[NowDisambig].second;
543  art::Ptr<recob::Wire> wire = ChannelHitWires.at(WhichRawHit);
544  art::Ptr<raw::RawDigit> rawdigits = ChannelHitRawDigits.at(WhichRawHit);
545  hcol.emplace_back(NowGoodHits[NowDisambig].first, wire, rawdigits);
546  }
547  OutAndClearVector( UnDisambigHits, StillUnDisambigHits, NowGoodHits, hcol.size() );
548  // ------------------------- Make a 2D line in XZ and fit --------------------------
549 
550  // ------------------------- Make a 2D line in XZ and fit --------------------------
551  std::cout << "\nNow to do my next step....fit hits to a 2D line in each TPC / Plane combination and find which ambiguous hit is closer..." << std::endl;
552  std::vector < recob::Hit > const &NewerGoodHits = hcol.peek();
553 
554  TwoDimPlaneLineFit( NewerGoodHits, UnDisambigHits, StillUnDisambigHits, NowGoodHits );
555  for ( size_t NowDisambig=0; NowDisambig < NowGoodHits.size(); ++NowDisambig ) {
556  size_t WhichRawHit = NowGoodHits[NowDisambig].second;
557  art::Ptr<recob::Wire> wire = ChannelHitWires.at(WhichRawHit);
558  art::Ptr<raw::RawDigit> rawdigits = ChannelHitRawDigits.at(WhichRawHit);
559  hcol.emplace_back(NowGoodHits[NowDisambig].first, wire, rawdigits);
560  }
561  OutAndClearVector( UnDisambigHits, StillUnDisambigHits, NowGoodHits, hcol.size() );
562  // ------------------------- Make a 2D line in XZ and fit --------------------------
563 
564  // ------------------------- Collection Wire Crosses -------------------------
565  std::cout << "\nNow to do my next step....if induction wire crosses a collection wire with a good hit..." << std::endl;
566  std::vector < recob::Hit > const &NewHits = hcol.peek();
567 
568  CrossCollection( NewHits, UnDisambigHits, StillUnDisambigHits, NowGoodHits );
569  for ( size_t NowDisambig=0; NowDisambig < NowGoodHits.size(); ++NowDisambig ) {
570  size_t WhichRawHit = NowGoodHits[NowDisambig].second;
571  art::Ptr<recob::Wire> wire = ChannelHitWires.at(WhichRawHit);
572  art::Ptr<raw::RawDigit> rawdigits = ChannelHitRawDigits.at(WhichRawHit);
573  hcol.emplace_back(NowGoodHits[NowDisambig].first, wire, rawdigits);
574  }
575  OutAndClearVector( UnDisambigHits, StillUnDisambigHits, NowGoodHits, hcol.size() );
576  // ------------------------- Collection Wire Crosses -------------------------
577 
578  // --------------------------- Any adjacent wires? --------------------------- Do any of the questionable hits have real hits next to them at roughly the same time?
579  std::cout << "\nNow to do my next step....if any adjacent wires have hits on them..." << std::endl;
580  std::vector < recob::Hit > const &NewGoodHits = hcol.peek();
581 
582  AdjacentWireWidth( NewGoodHits, UnDisambigHits, StillUnDisambigHits, NowGoodHits );
583  for ( size_t NowDisambig=0; NowDisambig < NowGoodHits.size(); ++NowDisambig ) {
584  size_t WhichRawHit = NowGoodHits[NowDisambig].second;
585  art::Ptr<recob::Wire> wire = ChannelHitWires.at(WhichRawHit);
586  art::Ptr<raw::RawDigit> rawdigits = ChannelHitRawDigits.at(WhichRawHit);
587  hcol.emplace_back(NowGoodHits[NowDisambig].first, wire, rawdigits);
588  }
589  OutAndClearVector( UnDisambigHits, StillUnDisambigHits, NowGoodHits, hcol.size() );
590  // --------------------------- Any adjacent wires? ---------------------------
591 
592  std::cout << "\nAfter all that the vectors have sizes: hits -> " << hits.size() << ", hcol -> " << hcol.size() << std::endl;
593  hcol.put_into(evt);
594  } // The produce function
595  //-------------------------------------------------
596  /*
597  bool HitFinderCounter35t::DoesIntersect( double A0, double B0, double A1, double B1, double A2, double B2, double A3, double B3 ) {
598  // Given are two lines l1=((A0, B0), (A1, B1)) and l2=((A2, B2), (A3, B3)); Ax, Bx are integers and (Ax, Bx) specify the starts and ends of the lines.
599  // We want to check whether both endpoins of l1 are on different sides of l2, and both endpoints of l2 are on opposite sides of l1.
600  // To check on which side of l1=((A0, B0), (A1, B1)) a point (A, B) lies, we take:
601  // an arbitrary normal vector N perpendicular to the line; one such vector is (B1-B0, A1-A0)
602  // the vector P from the start of the line to the point (A, B), which is (A-A0, B-B0)
603  // We then compute the dot product:
604  // N · P = (A-A0, B-B0) · (B1-B0, A1-A0) = (A-A0) * (B1-B0) + (B-B0) * (A1-A0)
605  // We're only interested in the sign: if it's positive, the point is on one side of the line; if it's negative, it's on the other.
606 
607  std::cout << "My counter line goes from (" << A0 << ", " << B0 << ") to (" << A1 << ", " << B1 <<"). "
608  << "My wire line goes from (" << A2 << ", " << B2 << ") to (" << A3 << ", " << B3 <<")."
609  << std::endl;
610 
611  if ( ((A2-A0)*(B1-B0) - (B2-B0)*(A1-A0)) * ((A3-A0)*(B1-B0) - (B3-B0)*(A1-A0)) < 0 ) {
612  if ( ((A0-A2)*(B3-B2) - (B0-B2)*(A3-A2)) * ((A1-A2)*(B3-B2) - (B1-B2)*(A3-A2)) < 0 ) {
613  return true;
614  }
615  }
616  return false;
617  } // Work out if two lines intersect each other
618  */
619  //-------------------------------------------------
620  int HitFinderCounter35t::pnpoly(int nvert, float *vertx, float *verty, float testx, float testy) {
621  int i, j, c = 0;
622  for (i = 0, j = nvert-1; i < nvert; j = i++) {
623  if ( ((verty[i]>testy) != (verty[j]>testy)) &&
624  (testx < (vertx[j]-vertx[i]) * (testy-verty[i]) / (verty[j]-verty[i]) + vertx[i]) )
625  c = !c;
626  }
627  return c;
628  } // Work out whether a point is within a polygon
629  //-------------------------------------------------
630  void HitFinderCounter35t::FindXZGradient( std::vector < recob::Hit > HitVector, float &Gradient, float& Intercept ) {
631  // I want to find the line of best fit using Matrices.
632  TMatrixD X(HitVector.size(), 2); // Want to reserve a size of HitVector.size()
633  TMatrixD Y(HitVector.size(), 1); // Want to reserve a size of HitVector.size()
634  for ( size_t HitLoop=0; HitLoop<HitVector.size(); ++HitLoop) {
635  double WireEnd[3], WireStart[3];
636  fGeom->WireEndPoints( HitVector[HitLoop].WireID(), WireStart, WireEnd );
637  float DriftDist = (0.5 *(HitVector[HitLoop].PeakTime()-TrigTime) * fDriftVelocity );
638  if ( HitVector[HitLoop].WireID().TPC % 2 == 0) { // If short TPC
639  DriftDist = -DriftDist;
640  }
641  // Want to fit to Z on X, and X on Y
642  X[HitLoop][0] = WireStart[2];
643  X[HitLoop][1] = 1;
644  Y[HitLoop].Assign(DriftDist + WireStart[0]);
645  TwoDLineHist->Fill(WireStart[2], DriftDist + WireStart[0]);
646  } // HitLoop
647  MatrixGradient( X, Y, HitVector.size(), Gradient, Intercept );
648  } // Find the gradient of the hits for the XZ configuration
649  //-------------------------------------------------
650  void HitFinderCounter35t::FindPlaneGradient( std::vector < recob::Hit > HitVector, float &Gradient, float& Intercept ) {
651  TMatrixD X(HitVector.size(), 2); // Want to reserve a size of HitVector.size()
652  TMatrixD Y(HitVector.size(), 1); // Want to reserve a size of HitVector.size()
653  for ( size_t HitLoop=0; HitLoop<HitVector.size(); ++HitLoop) {
654  X[HitLoop][0] = HitVector[HitLoop].WireID().Wire;
655  X[HitLoop][1] = 1;
656  Y[HitLoop][0] = HitVector[HitLoop].PeakTime();
657  }
658  MatrixGradient( X, Y, HitVector.size(), Gradient, Intercept );
659  } // Find the gradient of hits for the TPC/Plane configuration
660  //-------------------------------------------------
661  void HitFinderCounter35t::MatrixGradient( TMatrixD X, TMatrixD Y, size_t MatSize, float &Gradient, float &Intercept ) {
662  if (MatSize < 2) {
663  std::cout << "Can't construct a line, so giving null values." << std::endl;
664  Gradient = Intercept = 0;
665  } else {
666  //We need the transpose of X
667  TMatrixD X_T(2,MatSize);
668  X_T.Transpose(X);
669 
670  //We also need the inverse of X_T*X
671  TMatrixD X_T_x_X_inv = X_T*X;
672  X_T_x_X_inv.Invert();
673 
674  //The final equation for the params is (X^T*X)^-1 * X^T*Y
675  TMatrixD params = X_T_x_X_inv * X_T * Y;
676  Gradient = params[0][0];
677  Intercept = params[1][0];
678  if (fDebug) std::cout << "My line is of form: y = " << Gradient << "x + " << Intercept << std::endl;
679  }
680  } // Work out the gradient of a line using matricies
681  //-------------------------------------------------
682  double HitFinderCounter35t::DistToLine ( float Gradient, float Intercept, double X, double Y) {
683  // Shortest distance to a line is d = | Am + Bn + C| / sqrt( A^2 + B^2 ) where the line is Ax + By + C = 0, and the point is ( m, n )
684  double Dist = fabs( (Gradient*X) - Y + Intercept ) / pow( 1 + (Gradient*Gradient), 0.5);
685  return Dist;
686  } // Caluclate the distance of a point to a line
687  //-------------------------------------------------
688  std::vector<recob::Hit> HitFinderCounter35t::FindUniqueHits( std::vector < recob::Hit > const GoodHits, unsigned int Plane, unsigned int TPC ) {
689  // I want to get a vector of only Collection wire hits.
690  std::vector<recob::Hit> PlaneHits;
691  for ( size_t HitLoop=0; HitLoop<GoodHits.size(); ++HitLoop) {
692  if ( GoodHits[HitLoop].WireID().Plane != Plane ) continue;
693  if ( TPC != 10 && GoodHits[HitLoop].WireID().TPC != TPC ) continue;
694  PlaneHits.emplace_back(GoodHits[HitLoop]);
695  }
696  // I want to make a vector of only single occupancy collection plane wires.
697  std::vector<recob::Hit> UniqPlaneHits;
698  for ( size_t HitLoop=0; HitLoop<PlaneHits.size(); ++HitLoop) {
699  unsigned int ThisChannel = PlaneHits[HitLoop].Channel();
700  int NHits = 0;
701  for ( size_t HitLoop2=0; HitLoop2<PlaneHits.size(); ++HitLoop2) {
702  if (PlaneHits[HitLoop2].Channel() == ThisChannel) ++NHits;
703  }
704  if (NHits==1) UniqPlaneHits.emplace_back(PlaneHits[HitLoop]);
705  }
706 
707  int NLong=0;
708  for (size_t Q=0; Q<UniqPlaneHits.size(); ++Q)
709  if ( UniqPlaneHits[Q].WireID().TPC%2 != 0 ) ++NLong;
710  double rat = (double)UniqPlaneHits.size() / (double)NLong;
711  if ( rat > 0.8 ) {
712  std::vector<recob::Hit> LongHit;
713  for (size_t W=0; W<UniqPlaneHits.size(); ++W)
714  if ( UniqPlaneHits[W].WireID().TPC%2 != 0 )
715  LongHit.emplace_back(UniqPlaneHits[W]);
716  return LongHit;
717  } else
718  return UniqPlaneHits;
719  } // Return only the hits which are unique on a given channel
720  //-------------------------------------------------
721  int HitFinderCounter35t::CheckWhichIndex( std::vector<int> CloseHits ) {
722  int GoodHit = -1;
723  // Work out if one and only one of the wire possibilities crosses collection plane hits.
724  for (size_t CloseLoop=0; CloseLoop < CloseHits.size(); ++CloseLoop) {
725  if (CloseHits[CloseLoop] == 0) continue;
726  GoodHit = CloseLoop;
727  for (size_t CloseLoop2=0; CloseLoop2 < CloseHits.size(); ++CloseLoop2) {
728  if (CloseLoop == CloseLoop2 ) continue;
729  if (CloseHits[CloseLoop2]!=0) GoodHit = -1;
730  } //CloseLoop2
731  } // CloseLoop
732  return GoodHit;
733  } // Work out whether one and only one index has good hits
734  //-------------------------------------------------
735  std::vector<int> HitFinderCounter35t::ClosestDistance( std::vector<double> CloseHits ) {
736  int GoodHit = -1;
737  double MinDist = DBL_MAX;
738  // Work out if there is a closest wire
739  for (size_t CloseLoop=0; CloseLoop < CloseHits.size(); ++CloseLoop) {
740  if ( CloseHits[CloseLoop] == MinDist ) {
741  GoodHit = -1;
742  }
743  if ( CloseHits[CloseLoop] < MinDist ) {
744  MinDist = CloseHits[CloseLoop];
745  GoodHit = CloseLoop;
746  }
747  }
748  // If there is a closest then return a vector of size 1
749  std::vector<int> ReturnVec;
750  if (GoodHit != -1)
751  ReturnVec.push_back( GoodHit );
752  else { // If there are more, make a vector of the closest hits.
753  for (size_t CloseLoop=0; CloseLoop < CloseHits.size(); ++CloseLoop)
754  if ( CloseHits[CloseLoop] == MinDist )
755  ReturnVec.push_back( CloseLoop );
756  }
757  return ReturnVec;
758  } // Work out which index is the closest to a line
759  //-------------------------------------------------
760  void HitFinderCounter35t::OutAndClearVector ( std::vector < std::pair < std::vector < recob::Hit >, size_t > > &InitialBad,
761  std::vector < std::pair < std::vector < recob::Hit >, size_t > > &NewBad,
762  std::vector < std::pair < recob::Hit, size_t > > &NewGood, size_t HitsSize ) {
763  std::cout << "The vectors have sizes: UnDisambigHits -> " << InitialBad.size()
764  << ", StillUndisambigHits -> " << NewBad.size()
765  << ", NowGoodHits -> " << NewGood.size() << ", hcol -> " << HitsSize << std::endl;
766  InitialBad = NewBad;
767  NewBad.clear();
768  NewGood.clear();
769  } // Produce some output and clear vectors
770  //-------------------------------------------------
771  void HitFinderCounter35t::CrossCollection( std::vector < recob::Hit > const GoodHits,
772  std::vector < std::pair < std::vector < recob::Hit >, size_t > > &InputBadVector,
773  std::vector < std::pair < std::vector < recob::Hit >, size_t > > &OutputBadVector,
774  std::vector < std::pair < recob::Hit, size_t > > &OutputGoodVector ) {
775  if (!InputBadVector.size()) return; // If no bad hits are given, then I'm done already!
776  for (size_t QuestHit=0; QuestHit<InputBadVector.size(); ++QuestHit) {
777  std::vector<int> CloseHits;
778  std::vector< recob::Hit > Hitting = InputBadVector[QuestHit].first;
779  for (size_t ThisQuest=0; ThisQuest<Hitting.size(); ++ThisQuest) {
780  int ThisNearHit = 0;
781  for (size_t HitLoop=0; HitLoop<GoodHits.size(); ++HitLoop) {
782  if ( GoodHits[HitLoop].View() != geo::kZ ) continue;
783  if ( Hitting[ThisQuest].WireID().TPC != GoodHits[HitLoop].WireID().TPC ) continue;
784  if ( fabs( Hitting[ThisQuest].PeakTime() - GoodHits[HitLoop].PeakTime() ) >= fCollectionTimeWidth ) continue;
785  // If the collection hit is within the time window on the correct TPC etc, want to work out whether the wires in question cross...
786  geo::WireIDIntersection Intersect;
787  if (!fGeom->WireIDsIntersect( Hitting[ThisQuest].WireID(), GoodHits[HitLoop].WireID(), Intersect ) ) continue;
788  ++ThisNearHit;
789  } // Loop through certain hits....HitLoop
790  CloseHits.push_back(ThisNearHit);
791  } // Loop through UnDisambigHits[QuestHit].....ThisQuest
792  int GoodHit = CheckWhichIndex( CloseHits );
793  // If only one has wire has adjacent hits then it is a good hit.
794  if (GoodHit != -1) {
795  OutputGoodVector.emplace_back( std::make_pair(Hitting[GoodHit], InputBadVector[QuestHit].second ) );
796  } else {
797  OutputBadVector.push_back(InputBadVector[QuestHit]);
798  }
799  } // Loop through StillUnDisambigHits......QuestHit
800  } // Checking if the wires cross collection planes with hits
801  //-------------------------------------------------
802  void HitFinderCounter35t::AdjacentWireWidth( std::vector < recob::Hit > const GoodHits,
803  std::vector < std::pair < std::vector < recob::Hit >, size_t > > &InputBadVector,
804  std::vector < std::pair < std::vector < recob::Hit >, size_t > > &OutputBadVector,
805  std::vector < std::pair < recob::Hit, size_t > > &OutputGoodVector ) {
806  if (!InputBadVector.size()) return; // If no bad hits are given, then I'm done already!
807  for (size_t QuestHit=0; QuestHit<InputBadVector.size(); ++QuestHit) {
808  std::vector<int> CloseHits;
809  std::vector< recob::Hit > Hitting = InputBadVector[QuestHit].first;
810  for (size_t ThisQuest=0; ThisQuest<Hitting.size(); ++ThisQuest) {
811  int ThisNearHit = 0;
812  for (size_t HitLoop=0; HitLoop<GoodHits.size(); ++HitLoop) {
813  if ( Hitting[ThisQuest].WireID().TPC != GoodHits[HitLoop].WireID().TPC ) continue;
814  if ( Hitting[ThisQuest].WireID().Plane != GoodHits[HitLoop].WireID().Plane ) continue;
815  if ( fabs( Hitting[ThisQuest].WireID().Wire - GoodHits[HitLoop].WireID().Wire ) >= fAdjacentWireWidth ) continue;
816  if ( fabs( Hitting[ThisQuest].PeakTime() - GoodHits[HitLoop].PeakTime() ) >= fAdjacentTimeWidth ) continue;
817  ++ThisNearHit;
818  } // Loop through certain hits....HitLoop
819  CloseHits.push_back(ThisNearHit);
820  } // Loop through UnDisambigHits[QuestHit].....ThisQuest
821  int GoodHit = CheckWhichIndex( CloseHits );
822  // If only one has wire has adjacent hits then it is a good hit.
823  if (GoodHit != -1) {
824  OutputGoodVector.emplace_back( std::make_pair(Hitting[GoodHit], InputBadVector[QuestHit].second ) );
825  } else {
826  OutputBadVector.push_back(InputBadVector[QuestHit]);
827  }
828  } // Loop through UnDisambigHits......QuestHit
829  } // Checking if adjacent wires have hits
830  //-------------------------------------------------
831  void HitFinderCounter35t::TwoDimXZLineFit( std::vector < recob::Hit > const GoodHits,
832  std::vector < std::pair < std::vector < recob::Hit >, size_t > > &InputBadVector,
833  std::vector < std::pair < std::vector < recob::Hit >, size_t > > &OutputBadVector,
834  std::vector < std::pair < recob::Hit, size_t > > &OutputGoodVector ) {
835  if (!InputBadVector.size()) return; // If no bad hits are given, then I'm done already!
836 
837  std::vector<recob::Hit> UniqColHits = FindUniqueHits( GoodHits, 2, 10 );
838  if (!UniqColHits.size()) {
839  std::cout << "I have no unique collection plane wires, so can't do anything..." << std::endl;
840  for (size_t q=0; q<InputBadVector.size(); ++q)
841  OutputBadVector.push_back(InputBadVector[q]);
842  return;
843  } else {
844  if (fDebug) std::cout << "I have " << UniqColHits.size() << " unique collection plane hits " << std::endl;
845  }
846  float Gradient, Intercept;
847  FindXZGradient( UniqColHits, Gradient, Intercept );
848 
849  // What if I can't construct a line? Then I want to put these into my bad hits.
850  if ( Gradient == 0 && Intercept == 0 ) {
851  for (size_t BadLoop=0; BadLoop < InputBadVector.size(); ++BadLoop) {
852  OutputBadVector.push_back( InputBadVector[BadLoop]);
853  }
854  } else {
855  // Now use the line of best fit to determine which of the hits is the best one....
856  for (size_t BadLoop=0; BadLoop < InputBadVector.size(); ++BadLoop) {
857  //std::cout << "\nNow looking at BadLoop index " << BadLoop << std::endl;
858  std::vector<double> CloseHits;
859  std::vector< recob::Hit > Hitting = InputBadVector[BadLoop].first;
860  for (size_t ThisQuest=0; ThisQuest<Hitting.size(); ++ThisQuest) {
861  //.....Determine X and Z positions.....
862  double WireEnd[3], WireStart[3];
863  fGeom->WireEndPoints( Hitting[ThisQuest].WireID(), WireStart, WireEnd );
864  float DriftDist = (0.5 *(Hitting[ThisQuest].PeakTime()-TrigTime) * fDriftVelocity );
865  if ( Hitting[ThisQuest].WireID().TPC % 2 == 0) { // If short TPC
866  DriftDist = -DriftDist;
867  }
868  double HitPosX = DriftDist + WireStart[0];
869  double HitPosZ = (WireStart[2] + WireEnd[2])/2; // Just take the Z of the middle of the wire...
870  double distance = DistToLine ( Gradient, Intercept, HitPosZ, HitPosX ); // I am confusingly using Z as X and X as Y....
871 
872  CloseHits.push_back(distance);
873  //std::cout << "Looking at index " << ThisQuest << ". The hit was on channel, TPC, Plane, Wire "
874  // << Hitting[ThisQuest].Channel() << " " << Hitting[ThisQuest].WireID().TPC << ", " << Hitting[ThisQuest].WireID().Plane << ", " << Hitting[ThisQuest].WireID().Wire
875  // << ".\nStartZ " << WireStart[2] << ", EndZ " << WireEnd[2] << ", ZPos " << HitPosZ << ", XPos = " << HitPosX << " = " << DriftDist << " + " << WireStart[0]
876  // << ".\nIt was " << distance << " cm from my Coll line."
877  // << std::endl;
878  } // Each hit in BadLoop...ThisQuest
879  std::vector<int> WhichIndexes = ClosestDistance(CloseHits);
880  if (WhichIndexes.size() == 1 ) {
881  //std::cout << "I returned index " << WhichIndexes[0] << std::endl;
882  OutputGoodVector.emplace_back( std::make_pair(Hitting[WhichIndexes[0]], InputBadVector[BadLoop].second ) );
883  } else {
884  //std::cout << "I returned indexes with size " << WhichIndexes.size() << std::endl;
885  // If haven't removed any ambiguties.
886  if ( WhichIndexes.size() == Hitting.size() ) {
887  OutputBadVector.push_back(InputBadVector[BadLoop]);
888  } else { // If I have removed at least one ambiguity.
889  std::vector<recob::Hit> BadHits;
890  for (size_t aa=0; aa<WhichIndexes.size(); ++aa) {
891  BadHits.push_back( Hitting[ WhichIndexes[aa] ] );
892  }
893  OutputBadVector.push_back( std::make_pair( BadHits, InputBadVector[BadLoop].second ) );
894  } // If removed one ambiguity
895  } // If need to put in bad vector
896  } // BadLoop
897  } // If can make line.
898  } // Two dimensional line in XZ
899  //-------------------------------------------------
900  void HitFinderCounter35t::TwoDimPlaneLineFit( std::vector < recob::Hit > const GoodHits,
901  std::vector < std::pair < std::vector < recob::Hit >, size_t > > &InputBadVector,
902  std::vector < std::pair < std::vector < recob::Hit >, size_t > > &OutputBadVector,
903  std::vector < std::pair < recob::Hit, size_t > > &OutputGoodVector ) {
904  if (!InputBadVector.size()) return; // If no bad hits are given, then I'm done already!
905 
906  // If the ambiguties are not in the same TPC then I can't reliably tell the difference.
907  // Also want to figure out which TPC, Plane combinations to do.
908  std::vector< std::pair< unsigned int, unsigned int > > WhichTPCPl;
909  std::vector< std::pair < std::vector < recob::Hit >, size_t > > TPCPlaneCombs;
910  for (size_t HitLoop=0; HitLoop < InputBadVector.size(); ++HitLoop) {
911  std::vector< recob::Hit > Hits = InputBadVector[HitLoop].first;
912  unsigned int FirstTPC = Hits[0].WireID().TPC;
913  for ( size_t ThisHit=0; ThisHit<Hits.size(); ++ThisHit ) {
914  if ( Hits[ThisHit].WireID().TPC != FirstTPC ) {
915  if (fDebug) std::cout << "First hit is in TPC " << FirstTPC << ", whilst hit " << ThisHit << " is in TPC " << Hits[ThisHit].WireID().TPC << " giving up on this hit" << std::endl;
916  OutputBadVector.push_back( InputBadVector[HitLoop]);
917  break;
918  }
919  }
920  // This index has all hits in same TPC, so add it to my new combination vector
921  std::vector<recob::Hit> CombHits;
922  for (size_t aa=0; aa<Hits.size(); ++aa) {
923  CombHits.push_back( Hits[aa] );
924  }
925  TPCPlaneCombs.push_back( std::make_pair( CombHits, InputBadVector[HitLoop].second ) );
926  // Does this represent a new TPC/Plane combination though?
927  bool TPCPl = true;
928  for (size_t aa=0; aa<WhichTPCPl.size(); ++aa)
929  if (WhichTPCPl[aa].first == FirstTPC && WhichTPCPl[aa].second == Hits[0].WireID().Plane )
930  TPCPl = false;
931  if (TPCPl)
932  WhichTPCPl.push_back( std::make_pair( FirstTPC, Hits[0].WireID().Plane ) );
933  } // HitLoop
934  //std::cout << "After that TPCPlaneCombs has size " << TPCPlaneCombs.size() << ", OutputBadVector has size " << OutputBadVector.size() << ", and I want to look at these TPC Plane combinations." << std::endl;
935  //for (size_t aa=0; aa<WhichTPCPl.size(); ++aa)
936  //std::cout << "TPC " << WhichTPCPl[aa].first << ", Plane " << WhichTPCPl[aa].second << std::endl;
937 
938  for (size_t LineIndex=0; LineIndex<WhichTPCPl.size(); ++LineIndex) {
939  unsigned int ThisTPC = WhichTPCPl[LineIndex].first;
940  unsigned int ThisPl = WhichTPCPl[LineIndex].second;
941  std::vector<recob::Hit> UniqHits = FindUniqueHits( GoodHits, ThisPl, ThisTPC );
942  if ( !UniqHits.size() ) {
943  std::cout << "I have no unique hits on TPC " << ThisTPC << ", Plane " << ThisPl << std::endl;
944  // I need to put these hits into my badhits vector....
945  break;
946  } else {
947  if (fDebug) std::cout << "I have " << UniqHits.size() << " unique hits on TPC " << ThisTPC << ", Plane " << ThisPl << std::endl;
948  }
949  // Work out the gradient in this wire tick space.
950  float Gradient, Intercept;
951  FindPlaneGradient( UniqHits, Gradient, Intercept );
952 
953  // Got my line fit, now to work out which hit is the best.
954  for (size_t HitLoop=0; HitLoop < TPCPlaneCombs.size(); ++HitLoop) {
955  std::vector< recob::Hit > Hits = TPCPlaneCombs[HitLoop].first;
956  // Check that I'm looking at the right TPC/Plane configuration.
957  if ( Hits[0].WireID().TPC != ThisTPC || Hits[0].WireID().Plane != ThisPl ) continue;
958  // What if I can't construct a line? Then I want to put these into my bad hits.
959  if ( Gradient == 0 && Intercept == 0 ) {
960  OutputBadVector.push_back( TPCPlaneCombs[HitLoop]);
961  break;
962  }
963  int WhichIndex = -1;
964  double MinDist = DBL_MAX;
965  for ( size_t ThisHit=0; ThisHit<Hits.size(); ++ThisHit ) {
966  double distance = DistToLine( Gradient, Intercept, (double)Hits[ThisHit].WireID().Wire, (double)Hits[ThisHit].PeakTime() );
967  //std::cout << "Distance for " << HitLoop << " " << ThisHit << " is " << distance << std::endl;
968  if ( distance < MinDist ) { // Get the hit with the lowest distance
969  MinDist = distance;
970  WhichIndex = ThisHit;
971  }
972  } // ThisHit
973  // I know which hit I want to use now.
974  //std::cout << "Pushing back index " << WhichIndex << " as it was only " << MinDist << " away " << std::endl;
975  OutputGoodVector.emplace_back( std::make_pair(Hits[WhichIndex], TPCPlaneCombs[HitLoop].second ) );
976  } // HitLoop
977  } // Loop through WhichTPCPl
978  } // Two dimensional fit in wire tick space
979  //-------------------------------------------------
981 } // end of dune namespace
982 #endif // COUNTERHITFINDER35T_H
Pedestal provider class for DUNE.
void FindPlaneGradient(std::vector< recob::Hit > HitVector, float &Gradient, float &Intercept)
intermediate_table::iterator iterator
EventNumber_t event() const
Definition: DataViewImpl.cc:96
std::string string
Definition: nybbler.cc:12
int pnpoly(int nvert, float *vertx, float *verty, float testx, float testy)
Declaration of signal hit object.
void CrossCollection(std::vector< recob::Hit > const GoodHits, std::vector< std::pair< std::vector< recob::Hit >, size_t > > &InputBadVector, std::vector< std::pair< std::vector< recob::Hit >, size_t > > &OutputBadVector, std::vector< std::pair< recob::Hit, size_t > > &OutputGoodVector)
EDProducer(fhicl::ParameterSet const &pset)
Definition: EDProducer.h:20
constexpr T pow(T x)
Definition: pow.h:72
struct vector vector
int FitLine(std::vector< HitLineFitData > &data, HitLineFitResults &bestfit)
std::vector< geo::WireID > ChannelToWire(raw::ChannelID_t const channel) const
Returns a list of wires connected to the specified TPC channel.
Definition of basic raw digits.
Planes which measure Z direction.
Definition: geo_types.h:128
void TwoDimXZLineFit(std::vector< recob::Hit > const GoodHits, std::vector< std::pair< std::vector< recob::Hit >, size_t > > &InputBadVector, std::vector< std::pair< std::vector< recob::Hit >, size_t > > &OutputBadVector, std::vector< std::pair< recob::Hit, size_t > > &OutputGoodVector)
std::vector< recob::Hit > FindUniqueHits(std::vector< recob::Hit > const GoodHits, unsigned int Plane, unsigned int TPC)
std::map< unsigned int, std::pair< TVector3, std::vector< TVector3 > > > CounterPositionMap
static void declare_products(art::ProducesCollector &collector, std::string instance_name="", bool doWireAssns=true, bool doRawDigitAssns=true)
Declares the hit products we are going to fill.
Definition: HitCreator.cxx:248
std::vector< std::pair< unsigned int, unsigned int > > ExternalTrigIndexVec
void SetSeed(UInt_t seed)
Definition: HitLineFitAlg.h:58
Helper functions to create a hit.
bool getByLabel(std::string const &label, std::string const &instance, Handle< PROD > &result) const
Definition: DataViewImpl.h:446
void produce(art::Event &evt) override
void MatrixGradient(TMatrixD X, TMatrixD Y, size_t MatSize, float &Gradient, float &Intercept)
A class handling a collection of hits and its associations.
Definition: HitCreator.h:508
#define DEFINE_ART_MODULE(klass)
Definition: ModuleMacros.h:69
Collect all the RawData header files together.
void SetParameter(int i, double startValue, double minValue, double maxValue)
void OutAndClearVector(std::vector< std::pair< std::vector< recob::Hit >, size_t > > &InitialBad, std::vector< std::pair< std::vector< recob::Hit >, size_t > > &NewBad, std::vector< std::pair< recob::Hit, size_t > > &NewGood, size_t HitsSize)
static int max(int a, int b)
HitFinderCounter35t(fhicl::ParameterSet const &pset)
Definition of data types for geometry description.
Detector simulation of raw signals on wires.
Encapsulate the geometry of an auxiliary detector.
Encapsulate the geometry of a wire.
ProducesCollector & producesCollector() noexcept
void AdjacentWireWidth(std::vector< recob::Hit > const GoodHits, std::vector< std::pair< std::vector< recob::Hit >, size_t > > &InputBadVector, std::vector< std::pair< std::vector< recob::Hit >, size_t > > &OutputBadVector, std::vector< std::pair< recob::Hit, size_t > > &OutputGoodVector)
std::vector< int > ClosestDistance(std::vector< double > CloseHits)
std::vector< reco::ClusterHit2D * > HitVector
What follows are several highly useful typedefs which we want to expose to the outside world...
bool WireIDsIntersect(WireID const &wid1, WireID const &wid2, geo::Point_t &intersection) const
Computes the intersection between two wires.
art::PtrVector< recob::Hit > Hits
Utility object to perform functions of association.
T min(sqlite3 *const db, std::string const &table_name, std::string const &column_name)
Definition: statistics.h:55
Encapsulate the construction of a single detector plane.
int CheckWhichIndex(std::vector< int > CloseHits)
ChannelMappingService::Channel Channel
void TwoDimPlaneLineFit(std::vector< recob::Hit > const GoodHits, std::vector< std::pair< std::vector< recob::Hit >, size_t > > &InputBadVector, std::vector< std::pair< std::vector< recob::Hit >, size_t > > &OutputBadVector, std::vector< std::pair< recob::Hit, size_t > > &OutputGoodVector)
void SetHorizVertRanges(float hmin, float hmax, float vmin, float vmax)
void WireEndPoints(geo::WireID const &wireid, double *xyzStart, double *xyzEnd) const
Fills two arrays with the coordinates of the wire end points.
double DistToLine(float Gradient, float Intercept, double X, double Y)
Declaration of basic channel signal object.
void MakeCounterPositionMap(std::string CounterDir, std::string CounterFile, std::map< unsigned int, std::pair< TVector3, std::vector< TVector3 > > > &CounterPositionMap, double fExtendCountersX=0, double fExtendCountersY=0, double fExtendCountersZ=0)
2D representation of charge deposited in the TDC/wire plane
Definition: Hit.h:48
TCEvent evt
Definition: DataStructs.cxx:7
art::ServiceHandle< geo::Geometry > fGeom
void fill_ptr_vector(std::vector< Ptr< T >> &ptrs, H const &h)
Definition: Ptr.h:291
second_as<> second
Type of time stored in seconds, in double precision.
Definition: spacetime.h:80
recob::tracking::Plane Plane
Definition: TrackState.h:17
void FindXZGradient(std::vector< recob::Hit > HitVector, float &Gradient, float &Intercept)
QTextStream & endl(QTextStream &s)
Encapsulate the construction of a single detector plane.