All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
DisambigCheater_module.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 // Class: DisambigCheater
3 // Module Type: producer
4 // File: DisambigCheater_module.cc
5 //
6 // tylerdalion@gmail.com
7 //
8 ////////////////////////////////////////////////////////////////////////
9 
10 #include "art/Framework/Core/EDProducer.h"
11 #include "art/Framework/Core/ModuleMacros.h"
12 #include "art/Framework/Principal/Event.h"
13 #include "art/Framework/Services/Registry/ServiceHandle.h"
14 #include "canvas/Persistency/Common/FindOneP.h"
15 #include "messagefacility/MessageLogger/MessageLogger.h"
16 
28 
29 namespace hit {
30 
31  class DisambigCheater : public art::EDProducer {
32  public:
33  explicit DisambigCheater(fhicl::ParameterSet const& p);
34 
35  private:
36  void produce(art::Event& e) override;
37  void endJob() override;
38 
39  art::ServiceHandle<geo::Geometry const> geom;
40  art::ServiceHandle<cheat::BackTrackerService const> bt_serv;
41 
42  std::string fChanHitLabel;
43  std::string fWidHitLabel;
44 
45  std::map<std::pair<double, double>, std::vector<geo::WireID>> fHitToWids;
46  void InitHitToWids(detinfo::DetectorClocksData const& clockData,
47  const std::vector<art::Ptr<recob::Hit>>& ChHits);
48 
49  void MakeDisambigHit(art::Ptr<recob::Hit> const& hit,
50  geo::WireID const& wid,
51  art::Ptr<recob::Wire> const& wire,
53 
54  unsigned int fFalseChanHits =
55  0; // hits with no IDEs - could be noise or other technical problems
56  unsigned int fBadIDENearestWire = 0; // Just to count the inconsistent IDE wire returns
57 
58  std::vector<unsigned int> fMaxWireShift; // shift to account for space charge and diffusion
59  };
60 
61  //-------------------------------------------------------------------
62  DisambigCheater::DisambigCheater(fhicl::ParameterSet const& p) : EDProducer{p}
63  {
64  fChanHitLabel = p.get<std::string>("ChanHitLabel");
65 
66  // let HitCollectionCreator declare that we are going to produce
67  // hits and associations with wires and raw digits
68  // (with no particular product label)
69  recob::HitCollectionCreator::declare_products(producesCollector(), "", true, false);
70 
71  // Space charge can shift true IDE postiion to far-off channels.
72  // Calculate maximum number of wires to shift hit in order to be on correct channel.
73  // Shift no more than half of the number of channels, as beyond there will
74  // have been a closer wire segment.
75  if (geom->Ncryostats() != 1 || geom->NTPC() < 1) {
76  fMaxWireShift.resize(3);
77  fMaxWireShift[0] = 1;
78  fMaxWireShift[1] = 1;
79  fMaxWireShift[2] = 1;
80  }
81  else {
82  // assume TPC 0 is typical of all in terms of number of channels
83  unsigned int np = geom->Cryostat(0).TPC(0).Nplanes();
84  fMaxWireShift.resize(np);
85  for (unsigned int p = 0; p < np; ++p) {
86  double xyz[3] = {0.};
87  double xyz_next[3] = {0.};
88  unsigned int nw = geom->Cryostat(0).TPC(0).Plane(p).Nwires();
89  for (unsigned int w = 0; w < nw; ++w) {
90 
91  // for vertical planes
92  if (geom->Cryostat(0).TPC(0).Plane(p).View() == geo::kZ) {
93  fMaxWireShift[2] = geom->Cryostat(0).TPC(0).Plane(p).Nwires();
94  break;
95  }
96 
97  geom->Cryostat(0).TPC(0).Plane(p).Wire(w).GetCenter(xyz);
98  geom->Cryostat(0).TPC(0).Plane(p).Wire(w + 1).GetCenter(xyz_next);
99 
100  if (xyz[2] == xyz_next[2]) {
101  fMaxWireShift[p] = w;
102  break;
103  }
104  } // end wire loop
105  } // end plane loop
106 
107  for (unsigned int i = 0; i < np; i++)
108  fMaxWireShift[i] = std::floor(fMaxWireShift[i] / 2);
109  }
110  }
111 
112  //-------------------------------------------------------------------
113  void
115  {
116  // get hits on channels
117  art::Handle<std::vector<recob::Hit>> ChanHits;
118  evt.getByLabel(fChanHitLabel, ChanHits);
119  std::vector<art::Ptr<recob::Hit>> ChHits;
120  art::fill_ptr_vector(ChHits, ChanHits);
121 
122  // also get the associated wires and raw digits;
123  // we assume they have been created by the same module as the hits
124  const bool doRawDigitAssns = false;
125 
126  art::FindOneP<recob::Wire> ChannelHitWires(ChanHits, evt, fChanHitLabel);
127  const bool doWireAssns = ChannelHitWires.isValid();
128 
129  // this object contains the hit collection
130  // and its associations to wires and raw digits
131  // (if the original objects have them):
132  recob::HitCollectionCreator hits(evt, doWireAssns, doRawDigitAssns);
133 
134  // find the wireIDs each hit is on
135  auto const clockData = art::ServiceHandle<detinfo::DetectorClocksService const>()->DataFor(evt);
136  this->InitHitToWids(clockData, ChHits);
137 
138  // make all of the hits
139  for (size_t h = 0; h < ChHits.size(); h++) {
140 
141  // get the objects associated with this hit
142  art::Ptr<recob::Wire> wire;
143  if (doWireAssns) wire = ChannelHitWires.at(h);
144 
145  // the trivial Z hits
146  if (ChHits[h]->View() == geo::kZ) {
147  this->MakeDisambigHit(ChHits[h], ChHits[h]->WireID(), wire, hits);
148  continue;
149  }
150 
151  // make U/V hits if any wire IDs are associated
152  // count hits without a wireID
153  /// \todo: Decide how to handle the hits with multiple-wid activity. For now, randomly choose.
154  std::pair<double, double> ChanTime(ChHits[h]->Channel() * 1., ChHits[h]->PeakTime() * 1.);
155  if (fHitToWids[ChanTime].size() == 1)
156  this->MakeDisambigHit(ChHits[h], fHitToWids[ChanTime][0], wire, hits);
157  else if (fHitToWids[ChanTime].size() == 0)
158  fFalseChanHits++;
159  else if (fHitToWids[ChanTime].size() > 1)
160  this->MakeDisambigHit(ChHits[h], fHitToWids[ChanTime][0], wire, hits); // same thing for now
161 
162  } // for
163 
164  // put the hit collection and associations into the event
165  hits.put_into(evt);
166 
167  fHitToWids.clear();
168  }
169 
170  //-------------------------------------------------
171  void
173  art::Ptr<recob::Hit> const& original_hit,
174  geo::WireID const& wid,
175  art::Ptr<recob::Wire> const& wire, // art::Ptr<raw::RawDigit> const& rawdigits,
177  {
178 
179  if (!wid.isValid) {
180  mf::LogWarning("InvalidWireID") << "wid is invalid, hit not being made\n";
181  return;
182  }
183 
184  // create a hit copy of the original one, but with a different wire ID
185  recob::HitCreator hit(*original_hit, wid);
186  hcol.emplace_back(hit.move(), wire);
187  }
188 
189  //-------------------------------------------------------------------
190  void
192  const std::vector<art::Ptr<recob::Hit>>& ChHits)
193  {
194 
195  unsigned int Ucount(0), Vcount(0);
196  for (size_t h = 0; h < ChHits.size(); h++) {
197  recob::Hit const& chit = *(ChHits[h]);
198  if (ChHits[h]->View() == geo::kZ) continue;
199  if (ChHits[h]->View() == geo::kU)
200  Ucount++;
201  else if (ChHits[h]->View() == geo::kV)
202  Vcount++;
203  std::vector<geo::WireID> cwids = geom->ChannelToWire(chit.Channel());
204  std::pair<double, double> ChanTime((double)chit.Channel(),
205  (double)chit.PeakTime()); // hit key value
206 
207  // get hit IDEs
208  std::vector<const sim::IDE*> ides;
209  try {
210  ides = bt_serv->HitToSimIDEs_Ps(clockData, chit);
211  }
212  catch (...) {
213  };
214 
215  // catch the hits that have no IDEs
216  bool hasIDEs = !ides.empty();
217  if (hasIDEs) {
218  try {
219  bt_serv->SimIDEsToXYZ(ides);
220  } //What is this supposed to be doing? It get a vector, but never assigns it anywhere. There has to be a better way to do this check
221  catch (...) {
222  hasIDEs = false;
223  }
224  } // if
225  if (!hasIDEs) {
226  mf::LogVerbatim("DisambigCheat")
227  << "Hit on channel " << chit.Channel() << " between " << chit.PeakTimeMinusRMS()
228  << " and " << chit.PeakTimePlusRMS() << " matches no IDEs.";
229  fHitToWids[ChanTime] = std::vector<geo::WireID>();
230  continue;
231  } // if no IDEs
232 
233  // see what wire ID(s) the hit-IDEs are on
234  // if none: hit maps to empty vector
235  // if one: we have a unique hit, vector of size 1
236  // if more than one: make a vector of all wids
237  std::vector<geo::WireID> widsWithIdes;
238  for (size_t i = 0; i < ides.size(); i++) {
239  const double xyzIde[] = {ides[i]->x, ides[i]->y, ides[i]->z};
240 
241  // Occasionally, ide position is not in TPC
242  /// \todo: Why would an IDE xyz position be outside of a TPC?
243  geo::TPCID tpcID = geom->FindTPCAtPosition(xyzIde);
244  if (!tpcID.isValid) {
245  mf::LogWarning("DisambigCheat")
246  << "IDE at x = " << xyzIde[0] << ", y = " << xyzIde[1] << ", z = " << xyzIde[2]
247  << " does not correspond to a TPC.";
248  continue;
249  }
250  unsigned int tpc = tpcID.TPC, cryo = tpcID.Cryostat;
251 
252  // NearestWire seems to be missing some correction that is applied in LArG4, and is
253  // sometimes off by one or two wires. Use it and then correct it given channel
254  /// \todo: Why would an IDE ossociated with a hit return a nearest wire not on the hit's channel? Usually only one off.
255  geo::WireID IdeWid;
256  try {
257  IdeWid = geom->NearestWireID(xyzIde, cwids[0].Plane, tpc, cryo);
258  }
259  catch (geo::InvalidWireError const& e) { // adopt suggestion if possible
260  if (!e.hasSuggestedWire()) throw;
261  IdeWid = e.suggestedWireID();
262  mf::LogError("DisambigCheat") << "Detected a point out of its wire plane:\n"
263  << e.what() << "\nUsing suggested wire " << IdeWid << "\n";
264  }
265  geo::WireID storethis = IdeWid; // default...
266  bool foundmatch(false);
267  for (size_t w = 0; w < cwids.size(); w++) {
268  if (cwids[w].TPC != tpc || cwids[w].Cryostat != cryo) continue;
269  if ((unsigned int)std::abs((int)(IdeWid.Wire) - (int)(cwids[w].Wire)) <=
270  fMaxWireShift[cwids[0].Plane]) {
271  storethis = cwids[w]; // ...apply correction
272  foundmatch = true;
273  break;
274  }
275  }
276  if (!foundmatch) {
277  mf::LogWarning("DisambigCheat")
278  << "IDE NearestWire return more than 1 off from channel wids: wire " << IdeWid.Wire;
280  }
281 
282  bool alreadyStored(false);
283  for (size_t wid = 0; wid < widsWithIdes.size(); wid++)
284  if (storethis == widsWithIdes[wid]) alreadyStored = true;
285  if (!alreadyStored) widsWithIdes.push_back(storethis);
286  } // end loop through ides from HitToSimIdes
287 
288  fHitToWids[ChanTime] = widsWithIdes;
289 
290  } // end U/V channel hit loop
291 
292  if (fHitToWids.size() != Ucount + Vcount) {
293  mf::LogWarning("DisambigCheat")
294  << "Nhits mismatch: " << fHitToWids.size() << " " << Ucount + Vcount;
295  }
296  }
297 
298  //-------------------------------------------------------------------
299  void
301  {
302 
303  if (fFalseChanHits > 0)
304  mf::LogWarning("DisambigCheater")
305  << fFalseChanHits << " hits had no associated IDE or WireIDs";
306  }
307 
308  DEFINE_ART_MODULE(DisambigCheater)
309 
310 } // end hit namespace
BEGIN_PROLOG true icarus_rawdigitfilter FilterTools FilterPlane1 Plane
void produce(art::Event &e) override
DisambigCheater(fhicl::ParameterSet const &p)
art::ServiceHandle< cheat::BackTrackerService const > bt_serv
void InitHitToWids(detinfo::DetectorClocksData const &clockData, const std::vector< art::Ptr< recob::Hit >> &ChHits)
Planes which measure V.
Definition: geo_types.h:130
Declaration of signal hit object.
pdgs p
Definition: selectors.fcl:22
std::vector< unsigned int > fMaxWireShift
bool isValid
Whether this ID points to a valid element.
Definition: geo_types.h:211
CryostatID_t Cryostat
Index of cryostat.
Definition: geo_types.h:212
std::size_t size(FixedBins< T, C > const &) noexcept
Definition: FixedBins.h:561
Planes which measure Z direction.
Definition: geo_types.h:132
WireID_t Wire
Index of the wire within its plane.
Definition: geo_types.h:580
process_name hit
Definition: cheaterreco.fcl:51
BEGIN_PROLOG TPC
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
art::ServiceHandle< geo::Geometry const > geom
while getopts h
auto vector(Vector const &v)
Returns a manipulator which will print the specified array.
Definition: DumpUtils.h:265
Class managing the creation of a new recob::Hit object.
Definition: HitCreator.h:83
T abs(T value)
Planes which measure U.
Definition: geo_types.h:129
Helper functions to create a hit.
Collection of exceptions for Geometry system.
A class handling a collection of hits and its associations.
Definition: HitCreator.h:508
IDparameter< geo::WireID > WireID
Member type of validated geo::WireID parameter.
std::map< std::pair< double, double >, std::vector< geo::WireID > > fHitToWids
void emplace_back(recob::Hit &&hit, art::Ptr< recob::Wire > const &wire=art::Ptr< recob::Wire >(), art::Ptr< raw::RawDigit > const &digits=art::Ptr< raw::RawDigit >())
Adds the specified hit to the data collection.
Definition: HitCreator.cxx:290
The data type to uniquely identify a TPC.
Definition: geo_types.h:386
Definition of data types for geometry description.
float PeakTimeMinusRMS(float sigmas=+1.) const
Definition: Hit.h:239
void put_into(art::Event &)
Moves the data into an event.
Definition: HitCreator.h:652
float PeakTime() const
Time of the signal peak, in tick units.
Definition: Hit.h:218
Encapsulate the construction of a single detector plane.
Contains all timing reference information for the detector.
object containing MC truth information necessary for making RawDigits and doing back tracking ...
do i e
Exception thrown on invalid wire number.
Definition: Exceptions.h:42
Declaration of basic channel signal object.
2D representation of charge deposited in the TDC/wire plane
Definition: Hit.h:48
float PeakTimePlusRMS(float sigmas=+1.) const
Returns a time sigmas RMS away from the peak time.
Definition: Hit.h:236
TCEvent evt
Definition: DataStructs.cxx:8
TPCID_t TPC
Index of the TPC within its cryostat.
Definition: geo_types.h:406
void MakeDisambigHit(art::Ptr< recob::Hit > const &hit, geo::WireID const &wid, art::Ptr< recob::Wire > const &wire, recob::HitCollectionCreator &hcol)
geo::WireID suggestedWireID() const
Returns a better wire ID.
Definition: Exceptions.h:120
bool hasSuggestedWire() const
Returns whether we known a better wire number.
Definition: Exceptions.h:114
recob::Hit && move()
Prepares the constructed hit to be moved away.
Definition: HitCreator.h:343
raw::ChannelID_t Channel() const
ID of the readout channel the hit was extracted from.
Definition: Hit.h:230
art framework interface to geometry description
Encapsulate the construction of a single detector plane.