ReadSpacePointAndCnn_module.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 // Class: ReadSpacePointAndCnn
3 // Module Type: analyzer
4 // File: ReadSpacePointAndCnn_module.cc
5 //
6 // Example prepared for the computing tutorial, saves SpacePoint
7 // coordinates in the ROOT tree, together with EM/track classification
8 // obtained from CNN. Output file to be displayed with SWAN example.
9 // Robert Sulej
10 ////////////////////////////////////////////////////////////////////////
11 
18 #include "art_root_io/TFileService.h"
19 #include "canvas/Persistency/Common/FindManyP.h"
21 #include "fhiclcpp/types/Atom.h"
23 
25 #define MVA_LENGTH 4
26 
31 
32 #include "TTree.h"
33 
34 namespace tutorial {
35 
37 public:
38 
39  struct Config {
40  using Name = fhicl::Name;
42 
44  Name("HitsModuleLabel"), Comment("tag of hits producer")
45  };
46 
48  Name("SpacePointModuleLabel"), Comment("tag of spacepoint producer")
49  };
50 
52  Name("CnnModuleLabel"), Comment("tag of CNN module for EM/track id")
53  };
54  };
56 
57  explicit ReadSpacePointAndCnn(Parameters const& config);
58 
63 
64  void analyze(art::Event const & e) override;
65 
66  void beginJob() override;
67  void endJob() override;
68 
69 private:
70  void clear();
71 
72  size_t fEvNumber;
73 
74  TTree *fEventTree;
75 
76  // just some summary info
77  size_t fNHits[3];
78  size_t fNPoints;
79 
80  // let's sort hits by planes already now, it really makes
81  // any downstream work easier
82  std::vector<unsigned char> fHitTpc[3];
83  std::vector<float> fHitWire[3], fHitTime[3], fHitCharge[3];
84 
85  // SpacePoint 3D positions, charge (uncalibrated!) and EM-like score
86  std::vector<float> fPointX, fPointY, fPointZ;
87  std::vector<float> fPointCharge;
88  std::vector<float> fPointEmScore;
89 
90  // ******* fcl parameters *******
94 };
95 
100 {
101 }
102 
104 {
105  art::ServiceHandle<art::TFileService> tfs; // TTree's are created in the memory managed by ROOT (you don't delete them)
106 
107  fEventTree = tfs->make<TTree>("EventTree", "event by event info");
108  fEventTree->Branch("event", &fEvNumber, "fEvNumber/I");
109  fEventTree->Branch("nhits", &fNHits, "fNHits[3]/I");
110  fEventTree->Branch("npoints", &fNPoints, "fNPoints/I");
111 
112  fEventTree->Branch("hit0tpc", &fHitTpc[0]);
113  fEventTree->Branch("hit0w", &fHitWire[0]);
114  fEventTree->Branch("hit0t", &fHitTime[0]);
115  fEventTree->Branch("hit0q", &fHitCharge[0]);
116 
117  fEventTree->Branch("hit1tpc", &fHitTpc[1]);
118  fEventTree->Branch("hit1w", &fHitWire[1]);
119  fEventTree->Branch("hit1t", &fHitTime[1]);
120  fEventTree->Branch("hit1q", &fHitCharge[1]);
121 
122  fEventTree->Branch("hit2tpc", &fHitTpc[2]);
123  fEventTree->Branch("hit2w", &fHitWire[2]);
124  fEventTree->Branch("hit2t", &fHitTime[2]);
125  fEventTree->Branch("hit2q", &fHitCharge[2]);
126 
127  fEventTree->Branch("pointx", &fPointX);
128  fEventTree->Branch("pointy", &fPointY);
129  fEventTree->Branch("pointz", &fPointZ);
130  fEventTree->Branch("pointq", &fPointCharge);
131  fEventTree->Branch("emscore", &fPointEmScore);
132 }
133 
135 {
136  for (size_t p = 0; p < 3; ++p)
137  {
138  fHitTpc[p].clear();
139  fHitWire[p].clear();
140  fHitTime[p].clear();
141  fHitCharge[p].clear();
142  }
143 }
144 
146 {
147  clear();
148 
149  fEvNumber = evt.id().event();
150  mf::LogVerbatim("ReadSpacePointAndCnn") << "ReadSpacePointAndCnn module on event #" << fEvNumber;
151 
152  // store 2D hits info, sorted by plane (but not by TPC, you need to select
153  // on that later in your analysis)
154  auto hitsHandle = evt.getValidHandle< std::vector<recob::Hit> >(fHitsModuleLabel);
155  fNHits[0] = 0; fNHits[1] = 0; fNHits[2] = 0;
156 
157  for (const auto & h : *hitsHandle)
158  {
159  size_t p = h.WireID().Plane;
160  fHitTpc[p].push_back(h.WireID().TPC);
161  fHitWire[p].push_back(h.WireID().Wire);
162  fHitTime[p].push_back(h.PeakTime());
163  fHitCharge[p].push_back(h.Integral());
164  fNHits[p]++;
165  }
166 
167  // store SpacePoints basic info
168  auto spHandle = evt.getValidHandle< std::vector<recob::SpacePoint> >(fSpacePointModuleLabel);
169  auto qHandle = evt.getValidHandle< std::vector<recob::PointCharge> >(fSpacePointModuleLabel);
170  if (spHandle->size() != qHandle->size())
171  {
172  throw cet::exception("tutorial::ReadSpacePointAndCnn")
173  << "size of point and charge containers must be equal" << std::endl;
174  }
175 
176  fNPoints = spHandle->size();
177  fPointX.resize(fNPoints); fPointY.resize(fNPoints); fPointZ.resize(fNPoints);
178  fPointCharge.resize(fNPoints);
179  fPointEmScore.resize(fNPoints);
180 
181  for (size_t i = 0; i < spHandle->size(); ++i)
182  {
183  fPointX[i] = (*spHandle)[i].XYZ()[0];
184  fPointY[i] = (*spHandle)[i].XYZ()[1];
185  fPointZ[i] = (*spHandle)[i].XYZ()[2];
186  fPointCharge[i] = (*qHandle)[i].charge();
187  fPointEmScore[i] = 0.5; // neutral P(EM-like) value
188  }
189 
190  // and tag SpacePoints with EM-like scores calculated by CNN on the cluster level
191  // connect these scores to SpacePoints throuh hits, and choose the score of the
192  // largest cluster containing the hit associated to SpacePoint;
193  // other option could be e.g.: use CNN scores on the hit level, multiplying scores
194  // from hits in all planes
196  if (cluResults)
197  {
198  size_t emLikeIdx = cluResults->getIndex("em"); // at which index EM-like is stored in CNN output vector
199 
200  const art::FindManyP<recob::Hit> hitsFromClusters(cluResults->dataHandle(), evt, cluResults->dataTag());
201  const art::FindManyP<recob::SpacePoint> spFromHits(hitsHandle, evt, fSpacePointModuleLabel);
202 
203  std::vector<size_t> sizeScore(fNPoints, 0); // keep track of the max size of a cluster containing hit associated to spacepoint
204 
205  for (size_t c = 0; c < cluResults->size(); ++c)
206  {
207  //const recob::Cluster & clu = cluResults->item(c); // one can get the cluster object in this way, here not really used
208 
209  const std::vector< art::Ptr<recob::Hit> > & hits = hitsFromClusters.at(c);
210  std::array<float, MVA_LENGTH> cnn_out = cluResults->getOutput(c);
211 
212  for (const auto & hptr : hits)
213  {
214  const std::vector< art::Ptr<recob::SpacePoint> > & sp = spFromHits.at(hptr.key());
215  for (const auto & spptr : sp) // with SpacePointSolver should be just 1 hit, but be prepared for any other algorithm
216  {
217  if (hits.size() > sizeScore[spptr.key()])
218  {
219  sizeScore[spptr.key()] = hits.size();
220  fPointEmScore[spptr.key()] = cnn_out[emLikeIdx];
221  }
222  }
223  }
224  }
225  }
226 
227  fEventTree->Fill();
228 
229  clear();
230 }
231 
233 {
234  mf::LogVerbatim("ReadSpacePointAndCnn") << "ReadSpacePointAndCnn finished job";
235 }
236 
237 } // tutorial namespace
238 
MaybeLogger_< ELseverityLevel::ELsev_info, true > LogVerbatim
void analyze(art::Event const &e) override
ChannelGroupService::Name Name
Information about charge reconstructed in the active volume.
EDAnalyzer(fhicl::ParameterSet const &pset)
Definition: EDAnalyzer.h:25
ReadSpacePointAndCnn & operator=(ReadSpacePointAndCnn const &)=delete
const double e
#define DEFINE_ART_MODULE(klass)
Definition: ModuleMacros.h:67
std::vector< unsigned char > fHitTpc[3]
static Config * config
Definition: config.cpp:1054
ValidHandle< PROD > getValidHandle(InputTag const &tag) const
Definition: DataViewImpl.h:441
p
Definition: test.py:223
Declaration of signal hit object.
#define Comment
EventNumber_t event() const
Definition: EventID.h:116
TCEvent evt
Definition: DataStructs.cxx:7
static std::unique_ptr< MVAReader > create(const art::Event &evt, const art::InputTag &tag)
Definition: MVAReader.h:110
EventID id() const
Definition: Event.cc:34
ReadSpacePointAndCnn(Parameters const &config)
cet::coded_exception< error, detail::translate > exception
Definition: exception.h:33
QTextStream & endl(QTextStream &s)