SPMultiTpcDump_module.cc
Go to the documentation of this file.
1 //////////////////////////////////////////////////////////////////////////////////////////////////////
2 // Class: SPMultiTpcDump
3 // Author: P.Plonski, R.Sulej (Robert.Sulej@cern.ch), D.Stefan (Dorota.Stefan@cern.ch), May 2016
4 //
5 // Produces "global image" of events in multi-tpc detector, could be FD workspace or ProtoDUNE (SP).
6 // Projections of ADC are saved to 1-byte / pixel (TH1C) format, int-size (TH2I) projection of PDG
7 // truth and float-size (TH2F) projection of true charge deposits can be saved as well. We use this
8 // to dump deconvoluted ADC images for preparation of various classifiers and CNN based pattern reco.
9 //
10 // Moved from larreco/RecoAlg/ImagePatternAlgs since it became specific to DUNE geometries.
11 //
12 //////////////////////////////////////////////////////////////////////////////////////////////////////
13 
14 #ifndef SPMultiTpcDump_Module
15 #define SPMultiTpcDump_Module
16 
18 
23 
27 
28 // Framework includes
35 #include "art_root_io/TFileService.h"
37 #include "fhiclcpp/types/Atom.h"
38 #include "fhiclcpp/types/Table.h"
40 
41 // C++ Includes
42 #include <vector>
43 #include <string>
44 #include <cmath>
45 #include <fstream>
46 
47 #include "TFile.h"
48 #include "TTree.h"
49 #include "TH2C.h" // ADC map
50 #include "TH2I.h" // PDG+vertex info map
51 #include "TH2F.h" // deposit map
52 
53 namespace nnet
54 {
55 
56  struct NUVTX
57  {
59  int nupdg;
60  int cryo;
61  int tpc;
62  TVector2 position[3];
63  TVector3 vtx3d;
64  };
65 
67  {
68  public:
69 
70  struct Config {
71  using Name = fhicl::Name;
73 
75  fhicl::Atom<art::InputTag> GenModuleLabel { Name("GenModuleLabel"), Comment("Neutrino generator label.") };
76  fhicl::Atom<double> FidVolCut { Name("FidVolCut"), Comment("Take events with vertex inside this cut on volume.") };
77  fhicl::Atom<bool> SaveDepositMap { Name("SaveDepositMap"), Comment("Save projections of the true energy depositions.") };
78  fhicl::Atom<bool> SavePdgMap { Name("SavePdgMap"), Comment("Save vertex info and PDG codes map.") };
79  };
81 
82  explicit SPMultiTpcDump(Parameters const& config);
83 
84  void beginJob() override;
85 
86  void analyze(const art::Event& event) override;
87 
88  private:
89  void ResetVars();
90 
91  bool prepareEv(const art::Event& event,
92  detinfo::DetectorPropertiesData const& detProp);
93  bool InsideFidVol(TVector3 const & pvtx) const;
94  void CorrOffset(detinfo::DetectorPropertiesData const& detProp,
95  TVector3& vec, const simb::MCParticle& particle);
96 
97 
98  TVector2 GetProjVtx(detinfo::DetectorPropertiesData const& detProp,
99  TVector3 const & vtx3d, const size_t cryo, const size_t tpc, const size_t plane) const;
100 
103 
104  TTree *fTree;
105  TTree *fTree2D;
106  int fEvent; ///< number of the event being processed
107  int fRun; ///< number of the run being processed
108  int fSubRun; ///< number of the sub-run being processed
109 
110  bool fSaveDepositMap, fSavePdgMap;
111 
112  double fFidVolCut;
113 
115  int fCryo, fTpc, fPlane;
116  int fPdg, fInteraction;
117  int fPixX, fPixY;
118  float fPosX, fPosY;
119 
121  };
122 
123  //-----------------------------------------------------------------------
125  fTrainingDataAlg(config().TrainingDataAlg()),
126  fGenieGenLabel(config().GenModuleLabel()),
127  fSaveDepositMap(config().SaveDepositMap()),
128  fSavePdgMap(config().SavePdgMap()),
129  fFidVolCut(config().FidVolCut())
130  {
132  }
133 
134  //-----------------------------------------------------------------------
136  {
138 
139  fTree = tfs->make<TTree>("event","Event level info");
140  fTree->Branch("fRun", &fRun, "fRun/I");
141  fTree->Branch("fEvent", &fEvent, "fEvent/I");
142  fTree->Branch("fCryo", &fCryo, "fCryo/I");
143  fTree->Branch("fTpc", &fTpc, "fTpc/I");
144  fTree->Branch("fPdg", &fPdg, "fPdg/I");
145  fTree->Branch("fInteraction", &fInteraction, "fInteraction/I");
146 
147  fTree2D = tfs->make<TTree>("plane","Vertex 2D info");
148  fTree2D->Branch("fRun", &fRun, "fRun/I");
149  fTree2D->Branch("fEvent", &fEvent, "fEvent/I");
150  fTree2D->Branch("fPlane", &fPlane, "fPlane/I");
151  fTree2D->Branch("fPixX", &fPixX, "fPixX/I");
152  fTree2D->Branch("fPixY", &fPixY, "fPixY/I");
153  fTree2D->Branch("fPosX", &fPosX, "fPosX/F");
154  fTree2D->Branch("fPosY", &fPosY, "fPosY/F");
155  }
156 
157  //-----------------------------------------------------------------------
159  detinfo::DetectorPropertiesData const& detProp)
160  {
161  auto mctruthHandle = event.getHandle< std::vector<simb::MCTruth> >(fGenieGenLabel);
162  if (!mctruthHandle) { return false; }
163 
164  for (auto const & mc : (*mctruthHandle))
165  {
166  if (mc.Origin() == simb::kBeamNeutrino)
167  {
168  const TLorentzVector& pvtx = mc.GetNeutrino().Nu().Position();
169  TVector3 vtx(pvtx.X(), pvtx.Y(), pvtx.Z());
170 
171  CorrOffset(detProp, vtx, mc.GetNeutrino().Nu());
172 
173  fPointid.nupdg = mc.GetNeutrino().Nu().PdgCode();
174  fPointid.interaction = mc.GetNeutrino().CCNC();
175  fPointid.vtx3d = vtx;
176 
177  if (InsideFidVol(vtx))
178  {
179  double v[3] = {vtx.X(), vtx.Y(), vtx.Z()};
180  unsigned int cryo = fGeometry->FindCryostatAtPosition(v);
181  unsigned int tpc = fGeometry->FindTPCAtPosition(v).TPC;
182 
183  for (size_t i = 0; i < 3; ++i)
184  {
185  if (fGeometry->TPC(tpc, cryo).HasPlane(i))
186  { fPointid.position[i] = GetProjVtx(detProp, vtx, cryo, tpc, i); }
187  else
188  { fPointid.position[i] = TVector2(0, 0); }
189  }
190 
191  fPointid.cryo = cryo;
192  fPointid.tpc = tpc;
193 
194  fCryo = cryo;
195  fTpc = tpc;
196 
197  return true;
198  }
199  else
200  {
201  fPointid.cryo = -1;
202  fPointid.tpc = -1;
203  fCryo = -1; fTpc = -1;
204  return false;
205  }
206  }
207  }
208  return false;
209  }
210 
211  //-----------------------------------------------------------------------
213  {
214  fEvent = event.id().event();
215  fRun = event.run();
216  fSubRun = event.subRun();
217  ResetVars();
218 
219  auto const clockData = art::ServiceHandle<detinfo::DetectorClocksService const>()->DataFor(event);
220  auto const detProp = art::ServiceHandle<detinfo::DetectorPropertiesService const>()->DataFor(event, clockData);
221  prepareEv(event, detProp);
222 
223  std::ostringstream os;
224  os << "event_" << fEvent << "_run_" << fRun << "_subrun_" << fSubRun;
225  std::cout << "analyze " << os.str() << std::endl;
226 
227  size_t cryo = 0;
228  size_t plane_align0[3] = { 1, 0, 2 }; // offsets to align signals in drift direction between planes
229  size_t plane_align1[3] = { 2, 1, 0 };
230  size_t max_align = 0;
231  for (size_t i = 0; i < 3; ++i)
232  {
233  if (plane_align0[i] > max_align) max_align = plane_align0[i];
234  if (plane_align1[i] > max_align) max_align = plane_align1[i];
235  }
236 
237  size_t weff[3] = { 404, 404, 485 }; // effective offset in wires between consecutive tpc's, incl. dead spaces, per plane
238  size_t tpcs[3] = { 2, 2, 6 }; // FD workspace dimension in #tpc's
239  //size_t tpcs[3] = { 4, 1, 3 }; // the same for ProtoDUNE
240  size_t apa_gap = 29; // APA thickness (dead space in drift direction) in pixels
241 
242  bool goodEvent = false;
243  unsigned int gd0 = 0, gd1 = 0;
244  for (int p = 2; p >= 0; --p) // loop over planes and make global images
245  {
246  size_t drift_size = detProp.NumberTimeSamples() / fTrainingDataAlg.DriftWindow(); // tpc size in drift direction
247  size_t wire_size = fGeometry->Nwires(p, 0, cryo); // tpc size in wire direction
248  size_t max_offset = (p < 2) ? 752 : 0; // top-bottom projection max offset
249 
250  size_t ntotw = (tpcs[2] - 1) * weff[p] + wire_size + tpcs[1] * max_offset; // global image size in wire direction
251  size_t ntotd = tpcs[0] * drift_size + (apa_gap + max_align) * (tpcs[0] / 2); // global image size in drift direction
252 
253  std::cout << "Plane: " << p << ", wires: " << ntotw << " drift: " << ntotd << std::endl;
254  EventImageData fullimg(ntotw, ntotd, fSaveDepositMap);
255 
256  size_t a, maxArea = 0;
257  for (size_t t = 0; t < fGeometry->NTPC(cryo); ++t) // loop over tpc's
258  {
259  size_t tpc_z = t / (tpcs[0] * tpcs[1]);
260  size_t tpc_y = (t / tpcs[0]) % tpcs[1];
261  size_t tpc_x = t % tpcs[0];
262 
263  int dir = fGeometry->TPC(t, cryo).DetectDriftDirection();
264  bool flip_d = (dir > 0); // need the flip in drift direction?
265 
266  bool flip_w = false; // need the flip in wire direction?
267  size_t eff_p = p; // global plane
268  int offset = 0;
269  int p_align = 0;
270 
271  if (p < 2) // no wire flip nor top-bottom alignments in Z (collection) plane
272  {
273  if ((t % 4 == 0) || (t % 4 == 2))
274  {
275  eff_p = (p == 1) ? 0 : 1; // swap U and V
276  }
277 
278  if ((t % 4 == 0) || (t % 4 == 1)) // bottom tpc's
279  {
280  flip_w = (dir > 0) ? (eff_p == 1) : (eff_p == 0);
281  }
282  else // top tpc's
283  {
284  flip_w = (dir < 0) ? (eff_p == 1) : (eff_p == 0);
285  }
286 
287  offset = (p == 0) ? 48 : 752; // top-bottopm offsets
288  }
289 
290  if ((t % 4 == 0) || (t % 4 == 2))
291  {
292  p_align = plane_align0[p];
293  }
294  else
295  {
296  p_align = plane_align1[p];
297  }
298 
299  size_t gw = tpc_z * weff[p] + tpc_y * offset; // global wire
300  size_t gd = tpc_x * drift_size + apa_gap * (1 + tpc_x) / 2 + p_align; // global drift
301 
302  fTrainingDataAlg.setEventData(event, clockData, detProp, eff_p, t, cryo); // prepare ADC and truth projections for 1 plane in 1 tpc
303  std::cout << " TPC: " << t << " wires: " << fTrainingDataAlg.NWires() << std::endl;
305  if (a > 150)
306  {
307  fullimg.addTpc(fTrainingDataAlg, gw, flip_w, gd, flip_d);
308  if (a > maxArea)
309  {
310  TVector2 vtxProj = GetProjVtx(detProp, fPointid.vtx3d, cryo, t, p);
311  fullimg.setProjXY(fTrainingDataAlg, vtxProj.X(), vtxProj.Y(), gw, flip_w, gd, flip_d);
312  a = maxArea;
313  }
314  }
315  }
316 
317  std::cout << " find crop..." << std::endl;
318  unsigned int w0, w1, d0, d1;
319  if (fullimg.findCrop(80, w0, w1, d0, d1))
320  {
321  if (goodEvent)
322  {
323  d0 = gd0; d1 = gd1;
324  }
325  else
326  {
327  goodEvent = true;
328  gd0 = d0; gd1 = d1;
329  }
330  std::cout << " crop: " << w0 << " " << w1 << " " << d0 << " " << d1 << std::endl;
331  }
332  else { std::cout << " skip empty event" << std::endl; break; }
333 
334  std::ostringstream ss1;
335  ss1 << os.str() << "_plane_" << p; // TH2's name
336 
338  TH2C* rawHist = tfs->make<TH2C>((ss1.str() + "_raw").c_str(), "ADC",
339  (int)(w1 - w0), (double)w0, (double)w1, (int)(d1 - d0), (double)d0, (double)d1);
340 
341  float zero = fTrainingDataAlg.ZeroLevel();
342  for (size_t w = w0; w < w1; ++w)
343  {
344  auto const & raw = fullimg.wireAdc(w);
345  for (size_t d = d0; d < d1; ++d)
346  {
347  rawHist->Fill(w, d, (char)(raw[d] + zero));
348  }
349  }
350 
351  if (fSaveDepositMap)
352  {
353  TH2F* depHist = tfs->make<TH2F>((ss1.str() + "_deposit").c_str(), "Deposit",
354  (int)(w1 - w0), (double)w0, (double)w1, (int)(d1 - d0), (double)d0, (double)d1);
355  for (size_t w = w0; w < w1; ++w)
356  {
357  auto const & edep = fullimg.wireDep(w);
358  for (size_t d = d0; d < d1; ++d) { depHist->Fill(w, d, edep[d]); }
359  }
360  }
361 
362  if (fSavePdgMap)
363  {
364  TH2I* pdgHist = tfs->make<TH2I>((ss1.str() + "_pdg").c_str(), "PDG",
365  (int)(w1 - w0), (double)w0, (double)w1, (int)(d1 - d0), (double)d0, (double)d1);
366  for (size_t w = w0; w < w1; ++w)
367  {
368  auto const & pdg = fullimg.wirePdg(w);
369  for (size_t d = d0; d < d1; ++d) { pdgHist->Fill(w, d, pdg[d]); }
370  }
371  }
372 
373  if (goodEvent)
374  {
375  fPlane = p;
376 
377  if (fullimg.getVtxX() > -9999) fPixX = fullimg.getVtxX() - w0;
378  if (fullimg.getVtxY() > -9999) fPixY = fullimg.getVtxY() - d0;
379 
380  if (fullimg.getProjX() > -9999) fPosX = fullimg.getProjX() - w0;
381  if (fullimg.getProjY() > -9999) fPosY = fullimg.getProjY() - d0;
382 
383  std::cout << " *** plane:" << p << std::endl;
384  std::cout << " *** w0:" << w0 << ", w1:" << w1 << std::endl;
385  std::cout << " *** d0:" << d0 << ", d1:" << d1 << std::endl;
386  std::cout << " *** pix *** x:" << fPixX << ", y:" << fPixY << std::endl;
387  std::cout << " *** proj *** x:" << fPosX << ", y:" << fPosY << std::endl;
388  std::cout << " *** zero:" << zero << std::endl;
389 
390  fTree2D->Fill();
391  }
392  }
393  if (goodEvent)
394  {
395  fPdg = fPointid.nupdg;
397  fTree->Fill();
398  }
399  }
400 
401  //-----------------------------------------------------------------------
403  TVector3& vec, const simb::MCParticle& particle)
404  {
405  double vtx[3] = {vec.X(), vec.Y(), vec.Z()};
406  geo::TPCID tpcid = fGeometry->FindTPCAtPosition(vtx);
407 
408  if (tpcid.isValid)
409  {
410  float corrt0x = particle.T() * 1.e-3 * detProp.DriftVelocity();
411  if (fGeometry->TPC(tpcid).DetectDriftDirection() == 1) { corrt0x = corrt0x*(-1); }
412 
413  vtx[0] = vec.X() + corrt0x;
414  }
415 
416  vec.SetX(vtx[0]);
417  }
418 
419  //-----------------------------------------------------------------------
420  bool SPMultiTpcDump::InsideFidVol(TVector3 const & pvtx) const
421  {
422  double vtx[3] = {pvtx.X(), pvtx.Y(), pvtx.Z()};
423  bool inside = false;
424 
425  if (!fGeometry->FindTPCAtPosition(vtx).isValid) return false;
426 
427  geo::TPCID idtpc = fGeometry->FindTPCAtPosition(vtx);
428 
429  if (fGeometry->HasTPC(idtpc))
430  {
431  const geo::TPCGeo& tpcgeo = fGeometry->GetElement(idtpc);
432  double minx = tpcgeo.MinX(); double maxx = tpcgeo.MaxX();
433  double miny = tpcgeo.MinY(); double maxy = tpcgeo.MaxY();
434  double minz = tpcgeo.MinZ(); double maxz = tpcgeo.MaxZ();
435 
436  //x
437  double dista = fabs(minx - pvtx.X());
438  double distb = fabs(pvtx.X() - maxx);
439 
440  if ((pvtx.X() > minx) && (pvtx.X() < maxx) &&
441  (dista > fFidVolCut) && (distb > fFidVolCut))
442  {
443  inside = true;
444  }
445  else { inside = false; }
446 
447  //y
448  dista = fabs(maxy - pvtx.Y());
449  distb = fabs(pvtx.Y() - miny);
450  if (inside && (pvtx.Y() > miny) && (pvtx.Y() < maxy) &&
451  (dista > fFidVolCut) && (distb > fFidVolCut)) inside = true;
452  else inside = false;
453 
454  //z
455  dista = fabs(maxz - pvtx.Z());
456  distb = fabs(pvtx.Z() - minz);
457  if (inside && (pvtx.Z() > minz) && (pvtx.Z() < maxz) &&
458  (dista > fFidVolCut) && (distb > fFidVolCut)) inside = true;
459  else inside = false;
460  }
461 
462  return inside;
463  }
464 
465  //-----------------------------------------------------------------------
467  TVector3 const & vtx3d, const size_t cryo, const size_t tpc, const size_t plane) const
468  {
469 
470  TVector2 vtx2d = pma::GetProjectionToPlane(vtx3d, plane, tpc, cryo);
471  TVector2 vtxwd = pma::CmToWireDrift(detProp, vtx2d.X(), vtx2d.Y(), plane, tpc, cryo);
472 
473  return vtxwd;
474  }
475 
477  {
478  fCryo = 0;
479  fTpc = 0;
480  fPlane = 0;
481  fPdg = 0;
482  fInteraction = 0;
483  fPosX = 0.0;
484  fPosY = 0.0;
485  fPixX = 0;
486  fPixY = 0;
487  }
488 
490 
491 }
492 
493 #endif // SPMultiTpcDump_Module
def analyze(root, level, gtrees, gbranches, doprint)
Definition: rootstat.py:69
int fEvent
number of the event being processed
bool HasPlane(unsigned int iplane) const
Returns whether a plane with index iplane is present in this TPC.
Definition: TPCGeo.h:175
geo::GeometryCore const * fGeometry
CryostatGeo const & GetElement(geo::CryostatID const &cryoid) const
int getVtxY(void) const
const std::vector< float > & wireDep(size_t widx) const
SPMultiTpcDump(Parameters const &config)
bool setEventData(const art::Event &event, detinfo::DetectorClocksData const &clockData, detinfo::DetectorPropertiesData const &detProp, unsigned int plane, unsigned int tpc, unsigned int cryo)
Definition: PointIdAlg.cxx:859
float getProjX(void) const
double MinX() const
Returns the world x coordinate of the start of the box.
Definition: BoxBoundedGeo.h:88
bool isValid
Whether this ID points to a valid element.
Definition: geo_types.h:211
Geometry information for a single TPC.
Definition: TPCGeo.h:38
unsigned int DriftWindow() const
bool InsideFidVol(TVector3 const &pvtx) const
int getVtxX(void) const
ChannelGroupService::Name Name
float getProjY(void) const
bool findCrop(size_t max_area_cut, unsigned int &w0, unsigned int &w1, unsigned int &d0, unsigned int &d1) const
double MaxX() const
Returns the world x coordinate of the end of the box.
Definition: BoxBoundedGeo.h:91
Raw data description.
string dir
unsigned int Nwires(unsigned int p, unsigned int tpc=0, unsigned int cstat=0) const
Returns the total number of wires in the specified plane.
nnet::TrainingDataAlg fTrainingDataAlg
art framework interface to geometry description
TVector2 position[3]
geo::TPCID FindTPCAtPosition(double const worldLoc[3]) const
Returns the ID of the TPC at specified location.
unsigned int NWires() const
void CorrOffset(detinfo::DetectorPropertiesData const &detProp, TVector3 &vec, const simb::MCParticle &particle)
#define DEFINE_ART_MODULE(klass)
Definition: ModuleMacros.h:67
void beginJob()
Definition: Breakpoints.cc:14
static Config * config
Definition: config.cpp:1054
const double a
const std::vector< int > & wirePdg(size_t widx) const
double T(const int i=0) const
Definition: MCParticle.h:224
double MinZ() const
Returns the world z coordinate of the start of the box.
p
Definition: test.py:223
bool prepareEv(const art::Event &event, detinfo::DetectorPropertiesData const &detProp)
double DriftVelocity(double efield=0., double temperature=0.) const
cm/us
The data type to uniquely identify a TPC.
Definition: geo_types.h:386
Description of geometry of one entire detector.
Definition of data types for geometry description.
double MaxY() const
Returns the world y coordinate of the end of the box.
unsigned int NTPC(unsigned int cstat=0) const
Returns the total number of TPCs in the specified cryostat.
int fSubRun
number of the sub-run being processed
bool HasTPC(geo::TPCID const &tpcid) const
Returns whether we have the specified TPC.
void setProjXY(const TrainingDataAlg &dataAlg, float x, float y, size_t gw, bool flipw, size_t gd, bool flipd)
Implementation of the Projection Matching Algorithm.
#define Comment
short int DetectDriftDirection() const
Returns the expected drift direction based on geometry.
Definition: TPCGeo.cxx:157
int fRun
number of the run being processed
double MaxZ() const
Returns the world z coordinate of the end of the box.
void addTpc(const TrainingDataAlg &dataAlg, size_t gw, bool flipw, size_t gd, bool flipd)
TVector2 GetProjectionToPlane(const TVector3 &p, unsigned int plane, unsigned int tpc, unsigned int cryo)
Definition: Utilities.cxx:270
TVector2 CmToWireDrift(detinfo::DetectorPropertiesData const &detProp, float xw, float yd, unsigned int plane, unsigned int tpc, unsigned int cryo)
Definition: Utilities.cxx:307
Access the description of detector geometry.
float ZeroLevel() const
Level of zero ADC after scaling.
TPCGeo const & TPC(unsigned int const tpc=0, unsigned int const cstat=0) const
Returns the specified TPC.
TPCID_t TPC
Index of the TPC within its cryostat.
Definition: geo_types.h:406
const std::vector< float > & wireAdc(size_t widx) const
size_t getAdcArea() const
double MinY() const
Returns the world y coordinate of the start of the box.
geo::CryostatID::CryostatID_t FindCryostatAtPosition(geo::Point_t const &worldLoc) const
Returns the index of the cryostat at specified location.
TVector2 GetProjVtx(detinfo::DetectorPropertiesData const &detProp, TVector3 const &vtx3d, const size_t cryo, const size_t tpc, const size_t plane) const
void analyze(const art::Event &event) override
QTextStream & endl(QTextStream &s)
Event finding and building.
Beam neutrinos.
Definition: MCTruth.h:23