All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
icaruscode/icaruscode/Analysis/AnalysisTree_module.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 // $Id: DBSCANfinderAna.cxx,v 1.36 2010/09/15 bpage Exp $
3 //
4 // module to create a TTree for analysis
5 //
6 // \author tjyang@fnal.gov, sowjanyag@phys.ksu.edu
7 //
8 ////////////////////////////////////////////////////////////////////////
9 // To reduce memory usage:
10 // [x] create the data structure connected to the tree only when needed
11 // [x] reduce the size of the elemental items (Double_t => Float_t could damage precision)
12 // [x] create a different structure for each tracker, allocate only what needed
13 // [x] use variable size array buffers for each tracker datum instead of [kMaxTrack]
14 // [x] turn the truth/GEANT information into vectors
15 // [ ] move hit_trkid into the track information, remove kMaxTrackers
16 // [ ] turn the hit information into vectors (~1 MB worth), remove kMaxHits
17 // [ ] fill the tree branch by branch
18 //
19 // Current implementation:
20 // There is one tree only, with one set of branches for each tracking algorithm.
21 // The data structure which hosts the addresses of the tree branches is
22 // dynamically allocated on demand, and it can be optionally destroyed at the
23 // end of each event.
24 // The data structure (AnalysisTreeDataStruct) firectly contains the truth and
25 // simulation information as C arrays. The data from tracking algorithms is the
26 // largest, and it is contained in a C++ vector of structures (TrackDataStruct),
27 // one per algorithm. These structures can also be allocated on demand.
28 // Each of these structures is connected to a set of branches, one branch per
29 // data member. Data members are vectors of numbers or vectors of fixed-size
30 // C arrays. The vector index represents the tracks reconstructed by the
31 // algorithm, and each has a fixed size pool for hits (do ROOT t3rees support
32 // branches with more than one dimension with variable size?).
33 // The data structures can assign default values to their data, connect to a
34 // ROOT tree (creating the branches they need) and resize.
35 // The AnalysisTreeDataStruct is constructed with as many tracking algorithms as
36 // there are named in the module configuration (even if they are not backed by
37 // any available tracking data).
38 // By default construction, TrackDataStruct is initialized in a state which does
39 // not allow any track (maximum tracks number is zero), and in such state trying
40 // to connect to a tree has no effect. This is done so that the
41 // AnalysisTreeDataStruct can be initialized first (and with unusable track data
42 // structures), and then the TrackDataStruct instances are initialized one by
43 // one when the number of tracks needed is known.
44 // A similar mechanism is implemented for the truth information.
45 //
46 // The "UseBuffers: false" mode assumes that on each event a new
47 // AnalysisTreeDataStruct is created with unusable tracker data, connected to
48 // the ROOT tree (the addresses of the available branches are assigned), then
49 // each of the tracking algorithm data is resized to host the correct number
50 // of reconstructed tracks and connected to the tree. Then the normal process of
51 // filling the event data and then the tree take place. Finally, the whole
52 // data structure is freed and the tree is left in a invalid state (branch
53 // addresses are invalid). It could be possible to make the tree in a valid
54 // state by resetting the addresses, but there is no advantage in that.
55 //
56 // The "UseBuffers: true" mode assumes that on the first event a new
57 // AnalysisTreeDataStruct is created and used just as in the other mode
58 // described above. At the end of the first event, the data structure is left
59 // around (and the tree is in a valid state). On the next event, all the
60 // addresses are checked, then for each tracker the data is resized to
61 // accomodate the right number of tracks for tis event. If the memory is
62 // increased, the address will be changed. All the branches are reconnected to
63 // the data structure, and the procedure goes on as normal.
64 //
65 // Note that reducing the maximum number of tracks in a TrackDataStruct does not
66 // necessarily make memory available, because of how std::vector::resize()
67 // works; that feature can be implemented, but it currently has not been.
68 //
69 // The BoxedArray<> class is a wrapper around a normal C array; it is needed
70 // to be able to include such structure in a std::vector. This container
71 // requires its objects to be default-constructable and copy-constructable,
72 // and a C array is neither. BoxedArray<> is: the default construction leaves it
73 // uninitialized (for speed reasons) while the copy construction is performed
74 // as in a Plain Old Data structure (memcpy; really!).
75 //
76 ////////////////////////////////////////////////////////////////////////
77 
78 #ifndef ANALYSISTREE_H
79 #define ANALYSISTREE_H
80 
81 // Framework includes
82 #include "art/Framework/Core/ModuleMacros.h"
83 #include "art/Framework/Core/EDAnalyzer.h"
84 #include "art/Framework/Principal/Event.h"
85 #include "art/Framework/Principal/SubRun.h"
86 #include "art/Framework/Principal/Handle.h"
87 #include "art/Framework/Principal/View.h"
88 #include "canvas/Persistency/Common/Ptr.h"
89 #include "canvas/Persistency/Common/PtrVector.h"
90 #include "art/Framework/Services/Registry/ServiceHandle.h"
91 #include "art_root_io/TFileService.h"
92 #include "art_root_io/TFileDirectory.h"
93 #include "canvas/Persistency/Common/FindMany.h"
94 #include "canvas/Persistency/Common/FindOneP.h"
95 #include "fhiclcpp/ParameterSet.h"
96 #include "messagefacility/MessageLogger/MessageLogger.h"
97 
99 #include "larcore/CoreUtils/ServiceUtil.h" // lar::providerFrom()
100 #include "nusimdata/SimulationBase/MCTruth.h"
101 #include "nusimdata/SimulationBase/MCFlux.h"
108 // #include "larcore/DetectorInfoServices/LArPropertiesService.h"
109 // #include "larcore/Utilities/AssociationUtil.h"
116 #include "lardataobj/RecoBase/Hit.h"
120 //#include "lardata/RecoAlg/TrackMomentumCalculator.h"
123 
125 
126 #include <cstring> // std::memcpy()
127 #include <vector>
128 #include <map>
129 #include <iterator> // std::begin(), std::end()
130 #include <string>
131 #include <sstream>
132 #include <fstream>
133 #include <algorithm>
134 #include <functional> // std::mem_fun_ref
135 #include <typeinfo>
136 
137 #include "TTree.h"
138 #include "TTimeStamp.h"
139 
140 constexpr int kNplanes = 3; //number of wire planes
141 constexpr int kMaxHits = 25000; //maximum number of hits;
142 constexpr int kMaxTrackHits = 2000; //maximum number of hits on a track
143 constexpr int kMaxTrackers = 15; //number of trackers passed into fTrackModuleLabel
144 constexpr unsigned short kMaxVertices = 100; //max number of 3D vertices
145 constexpr unsigned short kMaxAuxDets = 4; ///< max number of auxiliary detector cells per MC particle
146 
147 /// total_extent<T>::value has the total number of elements of an array
148 template <typename T>
149 struct total_extent {
150  using value_type = size_t;
151  static constexpr value_type value
152  = sizeof(T) / sizeof(typename std::remove_all_extents<T>::type);
153 }; // total_extent<>
154 
155 
156 namespace icarus {
157 
158  /// Data structure with all the tree information.
159  ///
160  /// Can connect to a tree, clear its fields and resize its data.
162  public:
163 
164  /// A wrapper to a C array (needed to embed an array into a vector)
165  template <typename Array_t>
166  class BoxedArray {
167  protected:
168  Array_t array; // actual data
169 
170  public:
173 
174  BoxedArray() {} // no initialization
176  { std::memcpy((char*) &(data()), (char*) &(from.data()), sizeof(Array_t)); }
177 
178  Array_t& data() { return array; }
179  const Array_t& data() const { return array; }
180 
181  //@{
182  /// begin/end interface
183  static constexpr size_t size() { return total_extent<Array_t>::value; }
184  Data_t* begin() { return reinterpret_cast<Data_t*>(&array); }
185  const Data_t* begin() const { return reinterpret_cast<const Data_t*>(&array); }
186  Data_t* end() { return begin() + size(); }
187  const Data_t* end() const { return begin() + size(); }
188  //@}
189 
190  //@{
191  /// Array interface
192  auto operator[] (size_t index) -> decltype(*array) { return array[index]; }
193  auto operator[] (size_t index) const -> decltype(*array) { return array[index]; }
194  auto operator+ (ptrdiff_t index) -> decltype(&*array) { return array + index; }
195  auto operator+ (ptrdiff_t index) const -> decltype(&*array) { return array + index; }
196  auto operator- (ptrdiff_t index) -> decltype(&*array) { return array - index; }
197  auto operator- (ptrdiff_t index) const -> decltype(&*array) { return array - index; }
198  auto operator* () -> decltype(*array) { return *array; }
199  auto operator* () const -> decltype(*array) { return *array; }
200 
201  operator decltype(&array[0]) () { return &array[0]; }
202  operator decltype(&array[0]) () const { return &array[0]; }
203  //@}
204 
205  }; // BoxedArray
206 
207  /// Tracker algorithm result
208  ///
209  /// Can connect to a tree, clear its fields and resize its data.
211  public:
212  /* Data structure size:
213  *
214  * TrackData_t<Short_t> : 2 bytes/track
215  * TrackData_t<Float_t> : 4 bytes/track
216  * PlaneData_t<Float_t>, PlaneData_t<Int_t>: 12 bytes/track
217  * HitData_t<Float_t> : 24k bytes/track
218  * HitCoordData_t<Float_t> : 72k bytes/track
219  */
220  template <typename T>
221  using TrackData_t = std::vector<T>;
222  template <typename T>
223  using PlaneData_t = std::vector<BoxedArray<T[kNplanes]>>;
224  template <typename T>
225  using HitData_t = std::vector<BoxedArray<T[kNplanes][kMaxTrackHits]>>;
226  template <typename T>
227  using HitCoordData_t = std::vector<BoxedArray<T[kNplanes][kMaxTrackHits][3]>>;
228 
229  size_t MaxTracks; ///< maximum number of storable tracks
230 
231  Short_t ntracks; //number of reconstructed tracks
234  PlaneData_t<Int_t> trkidtruth_recoutils_totaltrueenergy; //true geant trackid from TrueParticleIDFromTotalTrueEnergy in RecoUtils
235  PlaneData_t<Int_t> trkidtruth_recoutils_totalrecocharge; //true geant trackid from TrueParticleIDFromTotalRecoCharge in RecoUtils
236  PlaneData_t<Int_t> trkidtruth_recoutils_totalrecohits; //true geant trackid from TrueParticleIDFromTotalTrueHits in RecoUtils
237  PlaneData_t<Int_t> trkidtruth; //true geant trackid
238  PlaneData_t<Short_t> trkorigin; //_ev_origin 0: unknown, 1: cosmic, 2: neutrino, 3: supernova, 4: singles
255 
256  // more track info
264  TrackData_t<Float_t> trkstartx; // starting x position.
265  TrackData_t<Float_t> trkstarty; // starting y position.
266  TrackData_t<Float_t> trkstartz; // starting z position.
267  TrackData_t<Float_t> trkstartd; // starting distance to boundary.
268  TrackData_t<Float_t> trkendx; // ending x position.
269  TrackData_t<Float_t> trkendy; // ending y position.
270  TrackData_t<Float_t> trkendz; // ending z position.
271  TrackData_t<Float_t> trkendd; // ending distance to boundary.
282  //TrackData_t<Float_t> trkmom; // momentum.
284  //TrackData_t<Float_t> trkmomrange; // track momentum from range using CSDA tables
285  //TrackData_t<Float_t> trkmommschi2; // track momentum from multiple scattering Chi2 method
286  //TrackData_t<Float_t> trkmommsllhd; // track momentum from multiple scattering LLHD method
287  TrackData_t<Short_t> trksvtxid; // Vertex ID associated with the track start
288  TrackData_t<Short_t> trkevtxid; // Vertex ID associated with the track end
289  PlaneData_t<Int_t> trkpidpdg; // particle PID pdg code
291  PlaneData_t<Float_t> trkpidchipr; // particle PID chisq for proton
292  PlaneData_t<Float_t> trkpidchika; // particle PID chisq for kaon
293  PlaneData_t<Float_t> trkpidchipi; // particle PID chisq for pion
294  PlaneData_t<Float_t> trkpidchimu; // particle PID chisq for muon
296  TrackData_t<Short_t> trkpidbestplane; // this is defined as the plane with most hits
297 
298  /// Creates an empty tracker data structure
300  /// Creates a tracker data structure allowing up to maxTracks tracks
301  TrackDataStruct(size_t maxTracks): MaxTracks(maxTracks) { Clear(); }
302  void Clear();
303  void SetMaxTracks(size_t maxTracks)
304  { MaxTracks = maxTracks; Resize(MaxTracks); }
305  void Resize(size_t nTracks);
306  void SetAddresses(TTree* pTree, std::string tracker, bool isCosmics);
307 
308  size_t GetMaxTracks() const { return MaxTracks; }
309  size_t GetMaxPlanesPerTrack(int /* iTrack */ = 0) const
310  { return (size_t) kNplanes; }
311  size_t GetMaxHitsPerTrack(int /* iTrack */ = 0, int /* ipl */ = 0) const
312  { return (size_t) kMaxTrackHits; }
313 
314  }; // class TrackDataStruct
315 
316 
317  enum DataBits_t: unsigned int {
318  tdAuxDet = 0x01,
319  tdCry = 0x02,
320  tdGenie = 0x04,
321  tdGeant = 0x08,
322  tdHit = 0x10,
323  tdTrack = 0x20,
324  tdVtx = 0x40,
326  }; // DataBits_t
327 
328 /* /// information from the run
329  struct RunData_t {
330  public:
331  RunData_t() { Clear(); }
332  void Clear() {}
333  }; // struct RunData_t
334 */
335  /// information from the subrun
336  struct SubRunData_t {
338  void Clear() { pot = -99999.; }
339  Double_t pot; //protons on target
340  }; // struct SubRunData_t
341 
342 // RunData_t RunData; ///< run data collected at begin of run
343  SubRunData_t SubRunData; ///< subrun data collected at begin of subrun
344 
345  //run information
346  Int_t run; //run number
347  Int_t subrun; //subrun number
348  Int_t event; //event number
349  Double_t evttime; //event time in sec
350  Double_t beamtime; //beam time
351  // Double_t pot; //protons on target moved in subrun data
352  // Double_t taulife; //electron lifetime
353  Char_t isdata; //flag, 0=MC 1=data
354 
355  // hit information (non-resizeable, 45x kMaxHits = 900k bytes worth)
356  Int_t no_hits; //number of hits
357  Short_t hit_tpc[kMaxHits]; //tpc number
358  Short_t hit_plane[kMaxHits]; //plane number
359  Short_t hit_wire[kMaxHits]; //wire number
360  Short_t hit_channel[kMaxHits]; //channel ID
361  Float_t hit_peakT[kMaxHits]; //peak time
362  Float_t hit_charge[kMaxHits]; //charge (area)
363  Float_t hit_ph[kMaxHits]; //amplitude
364  Float_t hit_startT[kMaxHits]; //hit start time
365  Float_t hit_endT[kMaxHits]; //hit end time
366  Float_t hit_nelec[kMaxHits]; //hit number of electrons
367  Float_t hit_energy[kMaxHits]; //hit energy
368  Short_t hit_trkid[kMaxHits]; //is this hit associated with a reco track?
369 
370  // vertex information
371  Short_t nvtx; //number of vertices
372  Float_t vtx[kMaxVertices][3]; //vtx[3]
373 
374  //track information
375  Char_t kNTracker;
376  std::vector<TrackDataStruct> TrackData;
377 
378  //mctruth information
379  size_t MaxMCNeutrinos; ///! The number of MCNeutrinos there is currently room for
380  Int_t mcevts_truth; //number of neutrino Int_teractions in the spill
381  std::vector<Int_t> nuID_truth; //Unique ID of each true neutrino
382  std::vector<Int_t> nuPDG_truth; //neutrino PDG code
383  std::vector<Int_t> ccnc_truth; //0=CC 1=NC
384  std::vector<Int_t> mode_truth; //0=QE/El, 1=RES, 2=DIS, 3=Coherent production
385  std::vector<Float_t> enu_truth; //true neutrino energy
386  std::vector<Float_t> Q2_truth; //Momentum transfer squared
387  std::vector<Float_t> W_truth; //hadronic invariant mass
388  std::vector<Int_t> hitnuc_truth; //hit nucleon
389  std::vector<Float_t> nuvtxx_truth; //neutrino vertex x
390  std::vector<Float_t> nuvtxy_truth; //neutrino vertex y
391  std::vector<Float_t> nuvtxz_truth; //neutrino vertex z
392  std::vector<Float_t> nu_dcosx_truth; //neutrino dcos x
393  std::vector<Float_t> nu_dcosy_truth; //neutrino dcos y
394  std::vector<Float_t> nu_dcosz_truth; //neutrino dcos z
395  std::vector<Float_t> lep_mom_truth; //lepton momentum
396  std::vector<Float_t> lep_dcosx_truth; //lepton dcos x
397  std::vector<Float_t> lep_dcosy_truth; //lepton dcos y
398  std::vector<Float_t> lep_dcosz_truth; //lepton dcos z
399 
400  //flux information
401  std::vector<Float_t> tpx_flux; //Px of parent particle leaving BNB target
402  std::vector<Float_t> tpy_flux; //Py of parent particle leaving BNB target
403  std::vector<Float_t> tpz_flux; //Pz of parent particle leaving BNB target
404  std::vector<Int_t> tptype_flux; //Type of parent particle leaving BNB target
405 
406  //genie information
407  size_t MaxGeniePrimaries = 0;
409  std::vector<Int_t> genie_primaries_pdg;
410  std::vector<Float_t> genie_Eng;
411  std::vector<Float_t> genie_Px;
412  std::vector<Float_t> genie_Py;
413  std::vector<Float_t> genie_Pz;
414  std::vector<Float_t> genie_P;
415  std::vector<Int_t> genie_status_code;
416  std::vector<Float_t> genie_mass;
417  std::vector<Int_t> genie_trackID;
418  std::vector<Int_t> genie_ND;
419  std::vector<Int_t> genie_mother;
420 
421  //cosmic cry information
422  Int_t mcevts_truthcry; //number of neutrino Int_teractions in the spill
424  std::vector<Int_t> cry_primaries_pdg;
425  std::vector<Float_t> cry_Eng;
426  std::vector<Float_t> cry_Px;
427  std::vector<Float_t> cry_Py;
428  std::vector<Float_t> cry_Pz;
429  std::vector<Float_t> cry_P;
430  std::vector<Float_t> cry_StartPointx;
431  std::vector<Float_t> cry_StartPointy;
432  std::vector<Float_t> cry_StartPointz;
433  std::vector<Int_t> cry_status_code;
434  std::vector<Float_t> cry_mass;
435  std::vector<Int_t> cry_trackID;
436  std::vector<Int_t> cry_ND;
437  std::vector<Int_t> cry_mother;
438 
439  //geant information
440  size_t MaxGEANTparticles = 0; ///! how many particles there is currently room for
441  Int_t no_primaries; //number of primary geant particles
442  Int_t geant_list_size; //number of all geant particles
444  std::vector<Int_t> pdg;
445  std::vector<Int_t> status;
446  std::vector<Float_t> Eng;
447  std::vector<Float_t> EndE;
448  std::vector<Float_t> Mass;
449  std::vector<Float_t> Px;
450  std::vector<Float_t> Py;
451  std::vector<Float_t> Pz;
452  std::vector<Float_t> P;
453  std::vector<Float_t> StartPointx;
454  std::vector<Float_t> StartPointy;
455  std::vector<Float_t> StartPointz;
456  std::vector<Float_t> StartT;
457  std::vector<Float_t> EndT;
458  std::vector<Float_t> EndPointx;
459  std::vector<Float_t> EndPointy;
460  std::vector<Float_t> EndPointz;
461  std::vector<Float_t> theta;
462  std::vector<Float_t> phi;
463  std::vector<Float_t> theta_xz;
464  std::vector<Float_t> theta_yz;
465  std::vector<Float_t> pathlen;
466  std::vector<Int_t> inTPCActive;
467  std::vector<Float_t> StartPointx_tpcAV;
468  std::vector<Float_t> StartPointy_tpcAV;
469  std::vector<Float_t> StartPointz_tpcAV;
470  std::vector<Float_t> EndPointx_tpcAV;
471  std::vector<Float_t> EndPointy_tpcAV;
472  std::vector<Float_t> EndPointz_tpcAV;
473  std::vector<Int_t> NumberDaughters;
474  std::vector<Int_t> TrackId;
475  std::vector<Int_t> Mother;
476  std::vector<Int_t> process_primary;
477  std::vector<std::string> processname;
478  std::vector<Int_t> MergedId; //geant track segments, which belong to the same particle, get the same
479  std::vector<Int_t> MotherNuId; //The unique ID of the mother neutrino
480 
481  // Auxiliary detector variables saved for each geant track
482  // This data is saved as a vector (one item per GEANT particle) of C arrays
483  // (wrapped in a BoxedArray for technical reasons), one item for each
484  // affected detector cell (which one is saved in AuxDetID
485  template <typename T>
486  using AuxDetMCData_t = std::vector<BoxedArray<T[kMaxAuxDets]>>;
487 
488  std::vector<UShort_t> NAuxDets; ///< Number of AuxDets crossed by this particle
489  AuxDetMCData_t<Short_t> AuxDetID; ///< Which AuxDet this particle went through
490  AuxDetMCData_t<Float_t> entryX; ///< Entry X position of particle into AuxDet
491  AuxDetMCData_t<Float_t> entryY; ///< Entry Y position of particle into AuxDet
492  AuxDetMCData_t<Float_t> entryZ; ///< Entry Z position of particle into AuxDet
493  AuxDetMCData_t<Float_t> entryT; ///< Entry T position of particle into AuxDet
494  AuxDetMCData_t<Float_t> exitX; ///< Exit X position of particle out of AuxDet
495  AuxDetMCData_t<Float_t> exitY; ///< Exit Y position of particle out of AuxDet
496  AuxDetMCData_t<Float_t> exitZ; ///< Exit Z position of particle out of AuxDet
497  AuxDetMCData_t<Float_t> exitT; ///< Exit T position of particle out of AuxDet
498  AuxDetMCData_t<Float_t> exitPx; ///< Exit x momentum of particle out of AuxDet
499  AuxDetMCData_t<Float_t> exitPy; ///< Exit y momentum of particle out of AuxDet
500  AuxDetMCData_t<Float_t> exitPz; ///< Exit z momentum of particle out of AuxDet
501  AuxDetMCData_t<Float_t> CombinedEnergyDep; ///< Sum energy of all particles with this trackID (+ID or -ID) in AuxDet
502 
503  unsigned int bits; ///< complementary information
504 
505  /// Returns whether we have auxiliary detector data
506  bool hasAuxDetector() const { return bits & tdAuxDet; }
507 
508  /// Returns whether we have Cry data
509  bool hasCryInfo() const { return bits & tdCry; }
510 
511  /// Returns whether we have Genie data
512  bool hasGenieInfo() const { return bits & tdGenie; }
513 
514  /// Returns whether we have Hit data
515  bool hasHitInfo() const { return bits & tdHit; }
516 
517  /// Returns whether we have Track data
518  bool hasTrackInfo() const { return bits & tdTrack; }
519 
520  /// Returns whether we have Vertex data
521  bool hasVertexInfo() const { return bits & tdVtx; }
522 
523  /// Returns whether we have Geant data
524  bool hasGeantInfo() const { return bits & tdGeant; }
525 
526  /// Sets the specified bits
527  void SetBits(unsigned int setbits, bool unset = false)
528  { if (unset) bits &= ~setbits; else bits |= setbits; }
529 
530  /// Constructor; clears all fields
531  AnalysisTreeDataStruct(size_t nTrackers = 0): bits(tdDefault)
532  { SetTrackers(nTrackers); Clear(); }
533 
534  TrackDataStruct& GetTrackerData(size_t iTracker)
535  { return TrackData.at(iTracker); }
536  const TrackDataStruct& GetTrackerData(size_t iTracker) const
537  { return TrackData.at(iTracker); }
538 
539 
540  /// Clear all fields if this object (not the tracker algorithm data)
541  void ClearLocalData();
542 
543  /// Clear all fields
544  void Clear();
545 
546 
547  /// Allocates data structures for the given number of trackers (no Clear())
548  void SetTrackers(size_t nTrackers) { TrackData.resize(nTrackers); }
549 
550  /// Resize the data structure for MCNeutrino particles
551  void ResizeMCNeutrino(int nNeutrinos);
552 
553  /// Resize the data strutcure for GEANT particles
554  void ResizeGEANT(int nParticles);
555 
556  /// Resize the data strutcure for Genie primaries
557  void ResizeGenie(int nPrimaries);
558 
559  /// Resize the data strutcure for Cry primaries
560  void ResizeCry(int nPrimaries);
561 
562  /// Connect this object with a tree
563  void SetAddresses(TTree* pTree, const std::vector<std::string>& trackers, bool isCosmics);
564 
565 
566  /// Returns the number of trackers for which data structures are allocated
567  size_t GetNTrackers() const { return TrackData.size(); }
568 
569  /// Returns the number of hits for which memory is allocated
570  size_t GetMaxHits() const { return kMaxHits; }
571 
572  /// Returns the number of trackers for which memory is allocated
573  size_t GetMaxTrackers() const { return TrackData.capacity(); }
574 
575  /// Returns the number of GEANT particles for which memory is allocated
576  size_t GetMaxGEANTparticles() const { return MaxGEANTparticles; }
577 
578  /// Returns the number of GENIE primaries for which memory is allocated
579  size_t GetMaxGeniePrimaries() const { return MaxGeniePrimaries; }
580 
581 
582  private:
583  /// Little helper functor class to create or reset branches in a tree
585  public:
586  TTree* pTree; ///< the tree to be worked on
587  BranchCreator(TTree* tree): pTree(tree) {}
588 
589  //@{
590  /// Create a branch if it does not exist, and set its address
591  void operator()
592  (std::string name, void* address, std::string leaflist /*, int bufsize = 32000 */)
593  {
594  if (!pTree) return;
595  TBranch* pBranch = pTree->GetBranch(name.c_str());
596  if (!pBranch) {
597  pTree->Branch(name.c_str(), address, leaflist.c_str() /*, bufsize */);
598  MF_LOG_DEBUG("AnalysisTreeStructure")
599  << "Creating branch '" << name << " with leaf '" << leaflist << "'";
600  }
601  else if (pBranch->GetAddress() != address) {
602  pBranch->SetAddress(address);
603  MF_LOG_DEBUG("AnalysisTreeStructure")
604  << "Reassigning address to branch '" << name << "'";
605  }
606  else {
607  MF_LOG_DEBUG("AnalysisTreeStructure")
608  << "Branch '" << name << "' is fine";
609  }
610  } // operator()
611  void operator()
612  (std::string name, void* address, const std::stringstream& leaflist /*, int bufsize = 32000 */)
613  { return this->operator() (name, address, leaflist.str() /*, int bufsize = 32000 */); }
614  template <typename T>
615  void operator()
616  (std::string name, std::vector<T>& data, std::string leaflist /*, int bufsize = 32000 */)
617  { return this->operator() (name, (void*) data.data(), leaflist /*, int bufsize = 32000 */); }
618 
619  template <typename T>
620  void operator() (std::string name, std::vector<T>& data)
621  {
622  // overload for a generic object expressed directly by reference
623  // (as opposed to a generic object expressed by a pointer or
624  // to a simple leaf sequence specification);
625  // TTree::Branch(name, T* obj, Int_t bufsize, splitlevel) and
626  // TTree::SetObject() are used.
627  if (!pTree) return;
628  TBranch* pBranch = pTree->GetBranch(name.c_str());
629  if (!pBranch) {
630  pTree->Branch(name.c_str(), &data);
631  // ROOT needs a TClass definition for T in order to create a branch,
632  // se we are sure that at this point the TClass exists
633  MF_LOG_DEBUG("AnalysisTreeStructure")
634  << "Creating object branch '" << name
635  << " with " << TClass::GetClass(typeid(T))->ClassName();
636  }
637  else if
638  (*(reinterpret_cast<std::vector<T>**>(pBranch->GetAddress())) != &data)
639  {
640  // when an object is provided directly, the address of the object
641  // is assigned in TBranchElement::fObject (via TObject::SetObject())
642  // and the address itself is set to the address of the fObject
643  // member. Here we check that the address of the object in fObject
644  // is the same as the address of our current data type
645  pBranch->SetObject(&data);
646  MF_LOG_DEBUG("AnalysisTreeStructure")
647  << "Reassigning object to branch '" << name << "'";
648  }
649  else {
650  MF_LOG_DEBUG("AnalysisTreeStructure")
651  << "Branch '" << name << "' is fine";
652  }
653  } // operator()
654  //@}
655  }; // class BranchCreator
656 
657  }; // class AnalysisTreeDataStruct
658 
659 
660  /**
661  * @brief Creates a simple ROOT tree with tracking and calorimetry information
662  *
663  * <h2>Configuration parameters</h2>
664  * - <b>UseBuffers</b> (default: false): if enabled, memory is allocated for
665  * tree data for all the run; otherwise, it's allocated on each event, used
666  * and freed; use "true" for speed, "false" to save memory
667  * - <b>SaveAuxDetInfo</b> (default: false): if enabled, auxiliary detector
668  * data will be extracted and included in the tree
669  */
670  class AnalysisTree : public art::EDAnalyzer {
671 
672  public:
673 
674  explicit AnalysisTree(fhicl::ParameterSet const& pset);
675  virtual ~AnalysisTree();
676 
677  /// read access to event
678  void analyze(const art::Event& evt);
679  // void beginJob() {}
680  void beginSubRun(const art::SubRun& sr);
681 
682  private:
683 
684  void HitsPurity(detinfo::DetectorClocksData const& clockData, std::vector< art::Ptr<recob::Hit> > const& hits, Int_t& trackid, Float_t& purity, double& maxe);
685  double length(const recob::Track& track);
686  double length(const simb::MCParticle& part, TVector3& start, TVector3& end);
687  double bdist(const recob::tracking::Point_t& pos);
688 
689  TTree* fTree;
690 
691  // event information is huge and dynamic;
692  // run information is much smaller and we still store it statically
693  // in the event
695 // AnalysisTreeDataStruct::RunData_t RunData;
697 
698  std::string fDigitModuleLabel;
699  std::string fHitsModuleLabel;
700  std::string fLArG4ModuleLabel;
701  std::string fCalDataModuleLabel;
702  std::string fGenieGenModuleLabel;
703  std::string fCryGenModuleLabel;
704  std::string fG4ModuleLabel;
705  std::string fVertexModuleLabel;
706  std::vector<std::string> fTrackModuleLabel;
707  std::vector<std::string> fCalorimetryModuleLabel;
708  std::vector<std::string> fParticleIDModuleLabel;
709  std::string fPOTModuleLabel;
710  bool fUseBuffer; ///< whether to use a permanent buffer (faster, huge memory)
711  bool fSaveAuxDetInfo; ///< whether to extract and save auxiliary detector data
712  bool fSaveCryInfo; ///whether to extract and save CRY particle data
713  bool fSaveGenieInfo; ///whether to extract and save Genie information
714  bool fSaveGeantInfo; ///whether to extract and save Geant information
715  bool fSaveHitInfo; ///whether to extract and save Hit information
716  bool fSaveTrackInfo; ///whether to extract and save Track information
717  bool fSaveVertexInfo; ///whether to extract and save Vertex information
718 
719  std::vector<std::string> fCosmicTaggerAssocLabel;
720  std::vector<std::string> fFlashMatchAssocLabel;
721 
722  bool isCosmics; ///< if it contains cosmics
723  bool fSaveCaloCosmics; ///< save calorimetry information for cosmics
724  float fG4minE; ///< Energy threshold to save g4 particle info
725  /// Returns the number of trackers configured
726  size_t GetNTrackers() const { return fTrackModuleLabel.size(); }
727 
728  /// Creates the structure for the tree data; optionally initializes it
729  void CreateData(bool bClearData = false)
730  {
731  if (!fData) {
737  }
738  else {
743  if (bClearData) fData->Clear();
744  }
745  } // CreateData()
746 
747  /// Sets the addresses of all the tree branches, creating the missing ones
749  {
750  CheckData("SetAddress()"); CheckTree("SetAddress()");
752  } // SetAddresses()
753 
754  /// Sets the addresses of all the tree branches of the specified tracking algo,
755  /// creating the missing ones
756  void SetTrackerAddresses(size_t iTracker)
757  {
758  CheckData("SetTrackerAddresses()"); CheckTree("SetTrackerAddresses()");
759  if (iTracker >= fData->GetNTrackers()) {
760  throw art::Exception(art::errors::LogicError)
761  << "AnalysisTree::SetTrackerAddresses(): no tracker #" << iTracker
762  << " (" << fData->GetNTrackers() << " available)";
763  }
764  fData->GetTrackerData(iTracker) \
766  } // SetTrackerAddresses()
767 
768  /// Create the output tree and the data structures, if needed
769  void CreateTree(bool bClearData = false);
770 
771  /// Destroy the local buffers (existing branches will point to invalid address!)
772  void DestroyData() { if (fData) { delete fData; fData = nullptr; } }
773 
774  /// Helper function: throws if no data structure is available
775  void CheckData(std::string caller) const
776  {
777  if (fData) return;
778  throw art::Exception(art::errors::LogicError)
779  << "AnalysisTree::" << caller << ": no data";
780  } // CheckData()
781  /// Helper function: throws if no tree is available
782  void CheckTree(std::string caller) const
783  {
784  if (fTree) return;
785  throw art::Exception(art::errors::LogicError)
786  << "AnalysisTree::" << caller << ": no tree";
787  } // CheckData()
788  }; // class icarus::AnalysisTree
789 } // namespace icarus
790 
791 
792 namespace { // local namespace
793  /// Simple stringstream which empties its buffer on operator() call
794  class AutoResettingStringSteam: public std::ostringstream {
795  public:
796  AutoResettingStringSteam& operator() () { str(""); return *this; }
797  }; // class AutoResettingStringSteam
798 
799  /// Fills a sequence of TYPE elements
800  template <typename ITER, typename TYPE>
801  inline void FillWith(ITER from, ITER to, TYPE value)
802  { std::fill(from, to, value); }
803 
804  /// Fills a sequence of TYPE elements
805  template <typename ITER, typename TYPE>
806  inline void FillWith(ITER from, size_t n, TYPE value)
807  { std::fill(from, from + n, value); }
808 
809  /// Fills a container with begin()/end() interface
810  template <typename CONT, typename V>
811  inline void FillWith(CONT& data, const V& value)
812  { FillWith(std::begin(data), std::end(data), value); }
813 
814 } // local namespace
815 
816 
817 //------------------------------------------------------------------------------
818 //--- AnalysisTreeDataStruct::TrackDataStruct
819 //---
820 
822 {
823  MaxTracks = nTracks;
824 
825  trkId.resize(MaxTracks);
832  trkstartx.resize(MaxTracks);
833  trkstarty.resize(MaxTracks);
834  trkstartz.resize(MaxTracks);
835  trkstartd.resize(MaxTracks);
836  trkendx.resize(MaxTracks);
837  trkendy.resize(MaxTracks);
838  trkendz.resize(MaxTracks);
839  trkendd.resize(MaxTracks);
840  trktheta.resize(MaxTracks);
841  trkphi.resize(MaxTracks);
842  trkstartdcosx.resize(MaxTracks);
843  trkstartdcosy.resize(MaxTracks);
844  trkstartdcosz.resize(MaxTracks);
845  trkenddcosx.resize(MaxTracks);
846  trkenddcosy.resize(MaxTracks);
847  trkenddcosz.resize(MaxTracks);
848  trkthetaxz.resize(MaxTracks);
849  trkthetayz.resize(MaxTracks);
850  //trkmom.resize(MaxTracks);
851  //trkmomrange.resize(MaxTracks);
852  //trkmommschi2.resize(MaxTracks);
853  //trkmommsllhd.resize(MaxTracks);
854  trklen.resize(MaxTracks);
855  trksvtxid.resize(MaxTracks);
856  trkevtxid.resize(MaxTracks);
857  // PID variables
858  trkpidpdg.resize(MaxTracks);
859  trkpidchi.resize(MaxTracks);
860  trkpidchipr.resize(MaxTracks);
861  trkpidchika.resize(MaxTracks);
862  trkpidchipi.resize(MaxTracks);
863  trkpidchimu.resize(MaxTracks);
864  trkpidpida.resize(MaxTracks);
865  trkpidbestplane.resize(MaxTracks);
866 
867  trkke.resize(MaxTracks);
868  trkrange.resize(MaxTracks);
872  trkidtruth.resize(MaxTracks);
873  trkorigin.resize(MaxTracks);
874  trkpdgtruth.resize(MaxTracks);
875  trkefftruth.resize(MaxTracks);
877  trksimIDExtruth.resize(MaxTracks);
878  trksimIDEytruth.resize(MaxTracks);
879  trksimIDEztruth.resize(MaxTracks);
880  trkpurtruth.resize(MaxTracks);
881  trkpitchc.resize(MaxTracks);
882  ntrkhits.resize(MaxTracks);
883 
884  trkdedx.resize(MaxTracks);
885  trkxp.resize(MaxTracks);
886  trkyp.resize(MaxTracks);
887  trkzp.resize(MaxTracks);
888  trkdqdx.resize(MaxTracks);
889  trkresrg.resize(MaxTracks);
890  trkxyz.resize(MaxTracks);
891 
892 } // icarus::AnalysisTreeDataStruct::TrackDataStruct::Resize()
893 
895  Resize(MaxTracks);
896  ntracks = 0;
897 
898  FillWith(trkId , -9999 );
899  FillWith(trkncosmictags_tagger, -9999 );
900  FillWith(trkcosmicscore_tagger, -99999.);
901  FillWith(trkcosmictype_tagger, -9999 );
902  FillWith(trkncosmictags_flashmatch, -9999 );
903  FillWith(trkcosmicscore_flashmatch, -99999.);
904  FillWith(trkcosmictype_flashmatch, -9999 );
905  FillWith(trkstartx , -99999.);
906  FillWith(trkstarty , -99999.);
907  FillWith(trkstartz , -99999.);
908  FillWith(trkstartd , -99999.);
909  FillWith(trkendx , -99999.);
910  FillWith(trkendy , -99999.);
911  FillWith(trkendz , -99999.);
912  FillWith(trkendd , -99999.);
913  FillWith(trktheta , -99999.);
914  FillWith(trkphi , -99999.);
915  FillWith(trkstartdcosx, -99999.);
916  FillWith(trkstartdcosy, -99999.);
917  FillWith(trkstartdcosz, -99999.);
918  FillWith(trkenddcosx , -99999.);
919  FillWith(trkenddcosy , -99999.);
920  FillWith(trkenddcosz , -99999.);
921  FillWith(trkthetaxz , -99999.);
922  FillWith(trkthetayz , -99999.);
923  //FillWith(trkmom , -99999.);
924  //FillWith(trkmomrange , -99999.);
925  //FillWith(trkmommschi2 , -99999.);
926  //FillWith(trkmommsllhd , -99999.);
927  FillWith(trklen , -99999.);
928  FillWith(trksvtxid , -1);
929  FillWith(trkevtxid , -1);
930  FillWith(trkpidbestplane, -1);
931 
932  for (size_t iTrk = 0; iTrk < MaxTracks; ++iTrk){
933 
934  // the following are BoxedArray's;
935  // their iterators traverse all the array dimensions
936  FillWith(trkke[iTrk] , -99999.);
937  FillWith(trkrange[iTrk] , -99999.);
938  FillWith(trkidtruth_recoutils_totaltrueenergy[iTrk] , -99999 );
939  FillWith(trkidtruth_recoutils_totalrecocharge[iTrk] , -99999 );
940  FillWith(trkidtruth_recoutils_totalrecohits[iTrk] , -99999 );
941  FillWith(trkidtruth[iTrk] , -99999 );
942  FillWith(trkorigin[iTrk] , -1 );
943  FillWith(trkpdgtruth[iTrk], -99999 );
944  FillWith(trkefftruth[iTrk], -99999.);
945  FillWith(trksimIDEenergytruth[iTrk], -99999.);
946  FillWith(trksimIDExtruth[iTrk], -99999.);
947  FillWith(trksimIDEytruth[iTrk], -99999.);
948  FillWith(trksimIDEztruth[iTrk], -99999.);
949  FillWith(trkpurtruth[iTrk], -99999.);
950  FillWith(trkpitchc[iTrk] , -99999.);
951  FillWith(ntrkhits[iTrk] , -9999 );
952 
953  FillWith(trkdedx[iTrk], 0.);
954  FillWith(trkxp[iTrk], 0.);
955  FillWith(trkyp[iTrk], 0.);
956  FillWith(trkzp[iTrk], 0.);
957  FillWith(trkdqdx[iTrk], 0.);
958  FillWith(trkresrg[iTrk], 0.);
959 
960  FillWith(trkxyz[iTrk], 0.);
961 
962  FillWith(trkpidpdg[iTrk] , -1);
963  FillWith(trkpidchi[iTrk] , -99999.);
964  FillWith(trkpidchipr[iTrk] , -99999.);
965  FillWith(trkpidchika[iTrk] , -99999.);
966  FillWith(trkpidchipi[iTrk] , -99999.);
967  FillWith(trkpidchimu[iTrk] , -99999.);
968  FillWith(trkpidpida[iTrk] , -99999.);
969  } // for track
970 
971 } // icarus::AnalysisTreeDataStruct::TrackDataStruct::Clear()
972 
973 
975  TTree* pTree, std::string tracker, bool isCosmics
976 ) {
977  if (MaxTracks == 0) return; // no tracks, no tree!
978 
980 
981  AutoResettingStringSteam sstr;
982  sstr() << kMaxTrackHits;
983  std::string MaxTrackHitsIndexStr("[" + sstr.str() + "]");
984 
985  std::string TrackLabel = tracker;
986  std::string BranchName;
987 
988  BranchName = "ntracks_" + TrackLabel;
989  CreateBranch(BranchName, &ntracks, BranchName + "/S");
990  std::string NTracksIndexStr = "[" + BranchName + "]";
991 
992  BranchName = "trkId_" + TrackLabel;
993  CreateBranch(BranchName, trkId, BranchName + NTracksIndexStr + "/S");
994 
995  BranchName = "trkncosmictags_tagger_" + TrackLabel;
996  CreateBranch(BranchName, trkncosmictags_tagger, BranchName + NTracksIndexStr + "/S");
997 
998  BranchName = "trkcosmicscore_tagger_" + TrackLabel;
999  CreateBranch(BranchName, trkcosmicscore_tagger, BranchName + NTracksIndexStr + "/F");
1000 
1001  BranchName = "trkcosmictype_tagger_" + TrackLabel;
1002  CreateBranch(BranchName, trkcosmictype_tagger, BranchName + NTracksIndexStr + "/S");
1003 
1004  BranchName = "trkncosmictags_flashmatch_" + TrackLabel;
1005  CreateBranch(BranchName, trkncosmictags_flashmatch, BranchName + NTracksIndexStr + "/S");
1006 
1007  BranchName = "trkcosmicscore_flashmatch_" + TrackLabel;
1008  CreateBranch(BranchName, trkcosmicscore_flashmatch, BranchName + NTracksIndexStr + "/F");
1009 
1010  BranchName = "trkcosmictype_flashmatch_" + TrackLabel;
1011  CreateBranch(BranchName, trkcosmictype_flashmatch, BranchName + NTracksIndexStr + "/S");
1012 
1013  BranchName = "trkke_" + TrackLabel;
1014  CreateBranch(BranchName, trkke, BranchName + NTracksIndexStr + "[3]/F");
1015 
1016  BranchName = "trkrange_" + TrackLabel;
1017  CreateBranch(BranchName, trkrange, BranchName + NTracksIndexStr + "[3]/F");
1018 
1019  BranchName = "trkidtruth_recoutils_totaltrueenergy_" + TrackLabel;
1020  CreateBranch(BranchName, trkidtruth_recoutils_totaltrueenergy, BranchName + NTracksIndexStr + "[3]/I");
1021 
1022  BranchName = "trkidtruth_recoutils_totalrecocharge_" + TrackLabel;
1023  CreateBranch(BranchName, trkidtruth_recoutils_totalrecocharge, BranchName + NTracksIndexStr + "[3]/I");
1024 
1025  BranchName = "trkidtruth_recoutils_totalrecohits_" + TrackLabel;
1026  CreateBranch(BranchName, trkidtruth_recoutils_totalrecohits, BranchName + NTracksIndexStr + "[3]/I");
1027 
1028  BranchName = "trkidtruth_" + TrackLabel;
1029  CreateBranch(BranchName, trkidtruth, BranchName + NTracksIndexStr + "[3]/I");
1030 
1031  BranchName = "trkorigin_" + TrackLabel;
1032  CreateBranch(BranchName, trkorigin, BranchName + NTracksIndexStr + "[3]/S");
1033 
1034  BranchName = "trkpdgtruth_" + TrackLabel;
1035  CreateBranch(BranchName, trkpdgtruth, BranchName + NTracksIndexStr + "[3]/I");
1036 
1037  BranchName = "trkefftruth_" + TrackLabel;
1038  CreateBranch(BranchName, trkefftruth, BranchName + NTracksIndexStr + "[3]/F");
1039 
1040  BranchName = "trksimIDEenergytruth_" + TrackLabel;
1041  CreateBranch(BranchName, trksimIDEenergytruth, BranchName + NTracksIndexStr + "[3]/F");
1042 
1043  BranchName = "trksimIDExtruth_" + TrackLabel;
1044  CreateBranch(BranchName, trksimIDExtruth, BranchName + NTracksIndexStr + "[3]/F");
1045 
1046  BranchName = "trksimIDEytruth_" + TrackLabel;
1047  CreateBranch(BranchName, trksimIDEytruth, BranchName + NTracksIndexStr + "[3]/F");
1048 
1049  BranchName = "trksimIDEztruth_" + TrackLabel;
1050  CreateBranch(BranchName, trksimIDEztruth, BranchName + NTracksIndexStr + "[3]/F");
1051 
1052  BranchName = "trkpurtruth_" + TrackLabel;
1053  CreateBranch(BranchName, trkpurtruth, BranchName + NTracksIndexStr + "[3]/F");
1054 
1055  BranchName = "trkpitchc_" + TrackLabel;
1056  CreateBranch(BranchName, trkpitchc, BranchName + NTracksIndexStr + "[3]/F");
1057 
1058  BranchName = "ntrkhits_" + TrackLabel;
1059  CreateBranch(BranchName, ntrkhits, BranchName + NTracksIndexStr + "[3]/S");
1060 
1061  if (!isCosmics){
1062  BranchName = "trkdedx_" + TrackLabel;
1063  CreateBranch(BranchName, trkdedx, BranchName + NTracksIndexStr + "[3]" + MaxTrackHitsIndexStr + "/F");
1064 
1065  BranchName = "trkxp_" + TrackLabel;
1066  CreateBranch(BranchName, trkxp, BranchName + NTracksIndexStr + "[3]" + MaxTrackHitsIndexStr + "/F");
1067 
1068  BranchName = "trkyp_" + TrackLabel;
1069  CreateBranch(BranchName, trkyp, BranchName + NTracksIndexStr + "[3]" + MaxTrackHitsIndexStr + "/F");
1070 
1071  BranchName = "trkzp_" + TrackLabel;
1072  CreateBranch(BranchName, trkzp, BranchName + NTracksIndexStr + "[3]" + MaxTrackHitsIndexStr + "/F");
1073 
1074  BranchName = "trkdqdx_" + TrackLabel;
1075  CreateBranch(BranchName, trkdqdx, BranchName + NTracksIndexStr + "[3]" + MaxTrackHitsIndexStr + "/F");
1076 
1077  BranchName = "trkresrg_" + TrackLabel;
1078  CreateBranch(BranchName, trkresrg, BranchName + NTracksIndexStr + "[3]" + MaxTrackHitsIndexStr + "/F");
1079 
1080  BranchName = "trkxyz_" + TrackLabel;
1081  CreateBranch(BranchName, trkxyz, BranchName + NTracksIndexStr + "[3]" + MaxTrackHitsIndexStr + "/F");
1082  }
1083 
1084  BranchName = "trkstartx_" + TrackLabel;
1085  CreateBranch(BranchName, trkstartx, BranchName + NTracksIndexStr + "/F");
1086 
1087  BranchName = "trkstarty_" + TrackLabel;
1088  CreateBranch(BranchName, trkstarty, BranchName + NTracksIndexStr + "/F");
1089 
1090  BranchName = "trkstartz_" + TrackLabel;
1091  CreateBranch(BranchName, trkstartz, BranchName + NTracksIndexStr + "/F");
1092 
1093  BranchName = "trkstartd_" + TrackLabel;
1094  CreateBranch(BranchName, trkstartd, BranchName + NTracksIndexStr + "/F");
1095 
1096  BranchName = "trkendx_" + TrackLabel;
1097  CreateBranch(BranchName, trkendx, BranchName + NTracksIndexStr + "/F");
1098 
1099  BranchName = "trkendy_" + TrackLabel;
1100  CreateBranch(BranchName, trkendy, BranchName + NTracksIndexStr + "/F");
1101 
1102  BranchName = "trkendz_" + TrackLabel;
1103  CreateBranch(BranchName, trkendz, BranchName + NTracksIndexStr + "/F");
1104 
1105  BranchName = "trkendd_" + TrackLabel;
1106  CreateBranch(BranchName, trkendd, BranchName + NTracksIndexStr + "/F");
1107 
1108  BranchName = "trktheta_" + TrackLabel;
1109  CreateBranch(BranchName, trktheta, BranchName + NTracksIndexStr + "/F");
1110 
1111  BranchName = "trkphi_" + TrackLabel;
1112  CreateBranch(BranchName, trkphi, BranchName + NTracksIndexStr + "/F");
1113 
1114  BranchName = "trkstartdcosx_" + TrackLabel;
1115  CreateBranch(BranchName, trkstartdcosx, BranchName + NTracksIndexStr + "/F");
1116 
1117  BranchName = "trkstartdcosy_" + TrackLabel;
1118  CreateBranch(BranchName, trkstartdcosy, BranchName + NTracksIndexStr + "/F");
1119 
1120  BranchName = "trkstartdcosz_" + TrackLabel;
1121  CreateBranch(BranchName, trkstartdcosz, BranchName + NTracksIndexStr + "/F");
1122 
1123  BranchName = "trkenddcosx_" + TrackLabel;
1124  CreateBranch(BranchName, trkenddcosx, BranchName + NTracksIndexStr + "/F");
1125 
1126  BranchName = "trkenddcosy_" + TrackLabel;
1127  CreateBranch(BranchName, trkenddcosy, BranchName + NTracksIndexStr + "/F");
1128 
1129  BranchName = "trkenddcosz_" + TrackLabel;
1130  CreateBranch(BranchName, trkenddcosz, BranchName + NTracksIndexStr + "/F");
1131 
1132  BranchName = "trkthetaxz_" + TrackLabel;
1133  CreateBranch(BranchName, trkthetaxz, BranchName + NTracksIndexStr + "/F");
1134 
1135  BranchName = "trkthetayz_" + TrackLabel;
1136  CreateBranch(BranchName, trkthetayz, BranchName + NTracksIndexStr + "/F");
1137 
1138  //BranchName = "trkmom_" + TrackLabel;
1139  //CreateBranch(BranchName, trkmom, BranchName + NTracksIndexStr + "/F");
1140 
1141  //BranchName = "trkmomrange_" + TrackLabel;
1142  //CreateBranch(BranchName, trkmomrange, BranchName + NTracksIndexStr + "/F");
1143 
1144  //BranchName = "trkmommschi2_" + TrackLabel;
1145  //CreateBranch(BranchName, trkmommschi2, BranchName + NTracksIndexStr + "/F");
1146 
1147  //BranchName = "trkmommsllhd_" + TrackLabel;
1148  //CreateBranch(BranchName, trkmommsllhd, BranchName + NTracksIndexStr + "/F");
1149 
1150  BranchName = "trklen_" + TrackLabel;
1151  CreateBranch(BranchName, trklen, BranchName + NTracksIndexStr + "/F");
1152 
1153  BranchName = "trksvtxid_" + TrackLabel;
1154  CreateBranch(BranchName, trksvtxid, BranchName + NTracksIndexStr + "/S");
1155 
1156  BranchName = "trkevtxid_" + TrackLabel;
1157  CreateBranch(BranchName, trkevtxid, BranchName + NTracksIndexStr + "/S");
1158 
1159  BranchName = "trkpidpdg_" + TrackLabel;
1160  CreateBranch(BranchName, trkpidpdg, BranchName + NTracksIndexStr + "[3]/I");
1161 
1162  BranchName = "trkpidchi_" + TrackLabel;
1163  CreateBranch(BranchName, trkpidchi, BranchName + NTracksIndexStr + "[3]/F");
1164 
1165  BranchName = "trkpidchipr_" + TrackLabel;
1166  CreateBranch(BranchName, trkpidchipr, BranchName + NTracksIndexStr + "[3]/F");
1167 
1168  BranchName = "trkpidchika_" + TrackLabel;
1169  CreateBranch(BranchName, trkpidchika, BranchName + NTracksIndexStr + "[3]/F");
1170 
1171  BranchName = "trkpidchipi_" + TrackLabel;
1172  CreateBranch(BranchName, trkpidchipi, BranchName + NTracksIndexStr + "[3]/F");
1173 
1174  BranchName = "trkpidchimu_" + TrackLabel;
1175  CreateBranch(BranchName, trkpidchimu, BranchName + NTracksIndexStr + "[3]/F");
1176 
1177  BranchName = "trkpidpida_" + TrackLabel;
1178  CreateBranch(BranchName, trkpidpida, BranchName + NTracksIndexStr + "[3]/F");
1179 
1180  BranchName = "trkpidbestplane_" + TrackLabel;
1181  CreateBranch(BranchName, trkpidbestplane, BranchName + NTracksIndexStr + "/S");
1182 
1183 } // icarus::AnalysisTreeDataStruct::TrackDataStruct::SetAddresses()
1184 
1185 //------------------------------------------------------------------------------
1186 //--- AnalysisTreeDataStruct
1187 //---
1188 
1190 
1191 // RunData.Clear();
1192  SubRunData.Clear();
1193 
1194  run = -99999;
1195  subrun = -99999;
1196  event = -99999;
1197  evttime = -99999;
1198  beamtime = -99999;
1199  isdata = -99;
1200  //taulife = -99999;
1201 
1202  no_hits = 0;
1203 
1204  std::fill(hit_tpc, hit_tpc + sizeof(hit_tpc)/sizeof(hit_tpc[0]), -9999);
1205  std::fill(hit_plane, hit_plane + sizeof(hit_plane)/sizeof(hit_plane[0]), -9999);
1206  std::fill(hit_wire, hit_wire + sizeof(hit_wire)/sizeof(hit_wire[0]), -9999);
1207  std::fill(hit_channel, hit_channel + sizeof(hit_channel)/sizeof(hit_channel[0]), -9999);
1208  std::fill(hit_peakT, hit_peakT + sizeof(hit_peakT)/sizeof(hit_peakT[0]), -99999.);
1209  std::fill(hit_charge, hit_charge + sizeof(hit_charge)/sizeof(hit_charge[0]), -99999.);
1210  std::fill(hit_ph, hit_ph + sizeof(hit_ph)/sizeof(hit_ph[0]), -99999.);
1211  std::fill(hit_startT, hit_startT + sizeof(hit_startT)/sizeof(hit_startT[0]), -99999.);
1212  std::fill(hit_endT, hit_endT + sizeof(hit_endT)/sizeof(hit_endT[0]), -99999.);
1213  std::fill(hit_trkid, hit_trkid + sizeof(hit_trkid)/sizeof(hit_trkid[0]), -9999);
1214  std::fill(hit_nelec, hit_nelec + sizeof(hit_nelec)/sizeof(hit_nelec[0]), -99999.);
1215  std::fill(hit_energy, hit_energy + sizeof(hit_energy)/sizeof(hit_energy[0]), -99999.);
1216 
1217  nvtx = 0;
1218  for (size_t ivtx = 0; ivtx < kMaxVertices; ++ivtx) {
1219  std::fill(vtx[ivtx], vtx[ivtx]+3, -99999.);
1220  }
1221 
1222  mcevts_truth = 0;
1223  mcevts_truthcry = -99999;
1224  FillWith(nuID_truth,-99999);
1225  FillWith(nuPDG_truth,-99999);
1226  FillWith(ccnc_truth,-99999);
1227  FillWith(mode_truth,-99999);
1228  FillWith(enu_truth,-99999);
1229  FillWith(Q2_truth,-99999);
1230  FillWith(W_truth,-99999);
1231  FillWith(hitnuc_truth,-99999);
1232  FillWith(nuvtxx_truth,-99999);
1233  FillWith(nuvtxy_truth,-99999);
1234  FillWith(nuvtxz_truth,-99999);
1235  FillWith(nu_dcosx_truth,-99999);
1236  FillWith(nu_dcosy_truth,-99999);
1237  FillWith(nu_dcosz_truth,-99999);
1238  FillWith(lep_mom_truth,-99999);
1239  FillWith(lep_dcosx_truth,-99999);
1240  FillWith(lep_dcosy_truth,-99999);
1241  FillWith(lep_dcosz_truth,-99999);
1242  FillWith(tpx_flux,-99999);
1243  FillWith(tpy_flux,-99999);
1244  FillWith(tpz_flux,-99999);
1245  FillWith(tptype_flux,-99999);
1246 
1247  genie_no_primaries = 0;
1248  cry_no_primaries = 0;
1249  no_primaries = 0;
1250  geant_list_size=0;
1252 
1253  FillWith(pdg, -99999);
1254  FillWith(status, -99999);
1255  FillWith(Mass, -99999.);
1256  FillWith(Eng, -99999.);
1257  FillWith(EndE, -99999.);
1258  FillWith(Px, -99999.);
1259  FillWith(Py, -99999.);
1260  FillWith(Pz, -99999.);
1261  FillWith(P, -99999.);
1262  FillWith(StartPointx, -99999.);
1263  FillWith(StartPointy, -99999.);
1264  FillWith(StartPointz, -99999.);
1265  FillWith(StartT, -99999.);
1266  FillWith(EndT, -99999.);
1267  FillWith(EndPointx, -99999.);
1268  FillWith(EndPointy, -99999.);
1269  FillWith(EndPointz, -99999.);
1270  FillWith(EndT, -99999.);
1271  FillWith(theta, -99999.);
1272  FillWith(phi, -99999.);
1273  FillWith(theta_xz, -99999.);
1274  FillWith(theta_yz, -99999.);
1275  FillWith(pathlen, -99999.);
1276  FillWith(inTPCActive, -99999);
1277  FillWith(StartPointx_tpcAV, -99999.);
1278  FillWith(StartPointy_tpcAV, -99999.);
1279  FillWith(StartPointz_tpcAV, -99999.);
1280  FillWith(EndPointx_tpcAV, -99999.);
1281  FillWith(EndPointy_tpcAV, -99999.);
1282  FillWith(EndPointz_tpcAV, -99999.);
1283  FillWith(NumberDaughters, -99999);
1284  FillWith(Mother, -99999);
1285  FillWith(TrackId, -99999);
1286  FillWith(process_primary, -99999);
1287  FillWith(processname, "noname");
1288  FillWith(MergedId, -99999);
1289  FillWith(MotherNuId, -99999);
1290  FillWith(genie_primaries_pdg, -99999);
1291  FillWith(genie_Eng, -99999.);
1292  FillWith(genie_Px, -99999.);
1293  FillWith(genie_Py, -99999.);
1294  FillWith(genie_Pz, -99999.);
1295  FillWith(genie_P, -99999.);
1296  FillWith(genie_status_code, -99999);
1297  FillWith(genie_mass, -99999.);
1298  FillWith(genie_trackID, -99999);
1299  FillWith(genie_ND, -99999);
1300  FillWith(genie_mother, -99999);
1301  FillWith(cry_primaries_pdg, -99999);
1302  FillWith(cry_Eng, -99999.);
1303  FillWith(cry_Px, -99999.);
1304  FillWith(cry_Py, -99999.);
1305  FillWith(cry_Pz, -99999.);
1306  FillWith(cry_P, -99999.);
1307  FillWith(cry_StartPointx, -99999.);
1308  FillWith(cry_StartPointy, -99999.);
1309  FillWith(cry_StartPointz, -99999.);
1310  FillWith(cry_status_code, -99999);
1311  FillWith(cry_mass, -99999.);
1312  FillWith(cry_trackID, -99999);
1313  FillWith(cry_ND, -99999);
1314  FillWith(cry_mother, -99999);
1315 
1316  // auxiliary detector information;
1317  FillWith(NAuxDets, 0);
1318  // - set to -9999 all the values of each of the arrays in AuxDetID;
1319  // this auto is BoxedArray<Short_t>
1320  for (auto& partInfo: AuxDetID) FillWith(partInfo, -9999);
1321  // - pythonish C++: as the previous line, for each one in a list of containers
1322  // of the same type (C++ is not python yet), using pointers to avoid copy;
1323  for (AuxDetMCData_t<Float_t>* cont: {
1324  &entryX, &entryY, &entryZ, &entryT,
1325  &exitX , &exitY , &exitZ, &exitT, &exitPx, &exitPy, &exitPz,
1327  })
1328  {
1329  // this auto is BoxedArray<Float_t>
1330  for (auto& partInfo: *cont) FillWith(partInfo, -99999.);
1331  } // for container
1332 
1333 } // icarus::AnalysisTreeDataStruct::ClearLocalData()
1334 
1335 
1337  ClearLocalData();
1338  std::for_each
1339  (TrackData.begin(), TrackData.end(), std::mem_fn(&TrackDataStruct::Clear));
1340 } // icarus::AnalysisTreeDataStruct::Clear()
1341 
1343 
1344  //min size is 1, to guarantee an address
1345  MaxMCNeutrinos = (size_t) std::max(nNeutrinos, 1);
1346  nuID_truth.resize(MaxMCNeutrinos);
1347  nuPDG_truth.resize(MaxMCNeutrinos);
1348  ccnc_truth.resize(MaxMCNeutrinos);
1349  mode_truth.resize(MaxMCNeutrinos);
1350  enu_truth.resize(MaxMCNeutrinos);
1351  Q2_truth.resize(MaxMCNeutrinos);
1352  W_truth.resize(MaxMCNeutrinos);
1353  hitnuc_truth.resize(MaxMCNeutrinos);
1354  nuvtxx_truth.resize(MaxMCNeutrinos);
1355  nuvtxy_truth.resize(MaxMCNeutrinos);
1356  nuvtxz_truth.resize(MaxMCNeutrinos);
1360  lep_mom_truth.resize(MaxMCNeutrinos);
1364  //Also resize the flux information here as it's a 1:1 with the MCNeutrino
1365  tpx_flux.resize(MaxMCNeutrinos);
1366  tpy_flux.resize(MaxMCNeutrinos);
1367  tpz_flux.resize(MaxMCNeutrinos);
1368  tptype_flux.resize(MaxMCNeutrinos);
1369 
1370  return;
1371 } // icarus::AnalysisTreeDataStruct::ResizeMCNeutrino()
1372 
1374 
1375  // minimum size is 1, so that we always have an address
1376  MaxGEANTparticles = (size_t) std::max(nParticles, 1);
1377 
1378  pdg.resize(MaxGEANTparticles);
1379  status.resize(MaxGEANTparticles);
1380  Mass.resize(MaxGEANTparticles);
1381  Eng.resize(MaxGEANTparticles);
1382  EndE.resize(MaxGEANTparticles);
1383  Px.resize(MaxGEANTparticles);
1384  Py.resize(MaxGEANTparticles);
1385  Pz.resize(MaxGEANTparticles);
1386  P.resize(MaxGEANTparticles);
1390  StartT.resize(MaxGEANTparticles);
1391  EndT.resize(MaxGEANTparticles);
1392  EndPointx.resize(MaxGEANTparticles);
1393  EndPointy.resize(MaxGEANTparticles);
1394  EndPointz.resize(MaxGEANTparticles);
1395  EndT.resize(MaxGEANTparticles);
1396  theta.resize(MaxGEANTparticles);
1397  phi.resize(MaxGEANTparticles);
1398  theta_xz.resize(MaxGEANTparticles);
1399  theta_yz.resize(MaxGEANTparticles);
1400  pathlen.resize(MaxGEANTparticles);
1409  Mother.resize(MaxGEANTparticles);
1410  TrackId.resize(MaxGEANTparticles);
1413  MergedId.resize(MaxGEANTparticles);
1414  MotherNuId.resize(MaxGEANTparticles);
1415 
1416  // auxiliary detector structure
1417  NAuxDets.resize(MaxGEANTparticles);
1418  AuxDetID.resize(MaxGEANTparticles);
1419  entryX.resize(MaxGEANTparticles);
1420  entryY.resize(MaxGEANTparticles);
1421  entryZ.resize(MaxGEANTparticles);
1422  entryT.resize(MaxGEANTparticles);
1423  exitX.resize(MaxGEANTparticles);
1424  exitY.resize(MaxGEANTparticles);
1425  exitZ.resize(MaxGEANTparticles);
1426  exitT.resize(MaxGEANTparticles);
1427  exitPx.resize(MaxGEANTparticles);
1428  exitPy.resize(MaxGEANTparticles);
1429  exitPz.resize(MaxGEANTparticles);
1431 
1432 } // icarus::AnalysisTreeDataStruct::ResizeGEANT()
1433 
1435 
1436  // minimum size is 1, so that we always have an address
1437  MaxGeniePrimaries = (size_t) std::max(nPrimaries, 1);
1439  genie_Eng.resize(MaxGeniePrimaries);
1440  genie_Px.resize(MaxGeniePrimaries);
1441  genie_Py.resize(MaxGeniePrimaries);
1442  genie_Pz.resize(MaxGeniePrimaries);
1443  genie_P.resize(MaxGeniePrimaries);
1445  genie_mass.resize(MaxGeniePrimaries);
1447  genie_ND.resize(MaxGeniePrimaries);
1449 
1450 } // icarus::AnalysisTreeDataStruct::ResizeGenie()
1451 
1453 
1454  cry_primaries_pdg.resize(nPrimaries);
1455  cry_Eng.resize(nPrimaries);
1456  cry_Px.resize(nPrimaries);
1457  cry_Py.resize(nPrimaries);
1458  cry_Pz.resize(nPrimaries);
1459  cry_P.resize(nPrimaries);
1460  cry_StartPointx.resize(nPrimaries);
1461  cry_StartPointy.resize(nPrimaries);
1462  cry_StartPointz.resize(nPrimaries);
1463  cry_status_code.resize(nPrimaries);
1464  cry_mass.resize(nPrimaries);
1465  cry_trackID.resize(nPrimaries);
1466  cry_ND.resize(nPrimaries);
1467  cry_mother.resize(nPrimaries);
1468 
1469 } // icarus::AnalysisTreeDataStruct::ResizeCry()
1470 
1472  TTree* pTree,
1473  const std::vector<std::string>& trackers,
1474  bool isCosmics
1475 ) {
1476  BranchCreator CreateBranch(pTree);
1477 
1478  CreateBranch("run",&run,"run/I");
1479  CreateBranch("subrun",&subrun,"subrun/I");
1480  CreateBranch("event",&event,"event/I");
1481  CreateBranch("evttime",&evttime,"evttime/D");
1482  CreateBranch("beamtime",&beamtime,"beamtime/D");
1483  CreateBranch("pot",&SubRunData.pot,"pot/D");
1484  CreateBranch("isdata",&isdata,"isdata/B");
1485  //CreateBranch("taulife",&taulife,"taulife/D");
1486 
1487  if (hasHitInfo()){
1488  CreateBranch("no_hits",&no_hits,"no_hits/I");
1489  CreateBranch("hit_tpc",hit_tpc,"hit_tpc[no_hits]/S");
1490  CreateBranch("hit_plane",hit_plane,"hit_plane[no_hits]/S");
1491  CreateBranch("hit_wire",hit_wire,"hit_wire[no_hits]/S");
1492  CreateBranch("hit_channel",hit_channel,"hit_channel[no_hits]/S");
1493  CreateBranch("hit_peakT",hit_peakT,"hit_peakT[no_hits]/F");
1494  CreateBranch("hit_charge",hit_charge,"hit_charge[no_hits]/F");
1495  CreateBranch("hit_ph",hit_ph,"hit_ph[no_hits]/F");
1496  CreateBranch("hit_startT",hit_startT,"hit_startT[no_hits]/F");
1497  CreateBranch("hit_endT",hit_endT,"hit_endT[no_hits]/F");
1498  CreateBranch("hit_trkid",hit_trkid,"hit_trkid[no_hits]/S");
1499  CreateBranch("hit_nelec",hit_nelec,"hit_nelec[no_hits]/F");
1500  CreateBranch("hit_energy",hit_energy,"hit_energy[no_hits]/F");
1501  }
1502 
1503  if (hasVertexInfo()){
1504  CreateBranch("nvtx",&nvtx,"nvtx/S");
1505  CreateBranch("vtx",vtx,"vtx[nvtx][3]/F");
1506  }
1507 
1508  if (hasTrackInfo()){
1509  AutoResettingStringSteam sstr;
1510  sstr() << kMaxTrackHits;
1511  std::string MaxTrackHitsIndexStr("[" + sstr.str() + "]");
1512 
1513  kNTracker = trackers.size();
1514  CreateBranch("kNTracker",&kNTracker,"kNTracker/B");
1515  for(int i=0; i<kNTracker; i++){
1516  std::string TrackLabel = trackers[i];
1517  std::string BranchName;
1518 
1519  // note that if the tracker data has maximum number of tracks 0,
1520  // nothing is initialized (branches are not even created)
1521  TrackData[i].SetAddresses(pTree, TrackLabel, isCosmics);
1522  } // for trackers
1523  }
1524 
1525  if (hasGenieInfo()){
1526  CreateBranch("mcevts_truth",&mcevts_truth,"mcevts_truth/I");
1527  CreateBranch("nuID_truth",nuID_truth,"nuID_truth[mcevts_truth]/I");
1528  CreateBranch("nuPDG_truth",nuPDG_truth,"nuPDG_truth[mcevts_truth]/I");
1529  CreateBranch("ccnc_truth",ccnc_truth,"ccnc_truth[mcevts_truth]/I");
1530  CreateBranch("mode_truth",mode_truth,"mode_truth[mcevts_truth]/I");
1531  CreateBranch("enu_truth",enu_truth,"enu_truth[mcevts_truth]/F");
1532  CreateBranch("Q2_truth",Q2_truth,"Q2_truth[mcevts_truth]/F");
1533  CreateBranch("W_truth",W_truth,"W_truth[mcevts_truth]/F");
1534  CreateBranch("hitnuc_truth",hitnuc_truth,"hitnuc_truth[mcevts_truth]/I");
1535  CreateBranch("nuvtxx_truth",nuvtxx_truth,"nuvtxx_truth[mcevts_truth]/F");
1536  CreateBranch("nuvtxy_truth",nuvtxy_truth,"nuvtxy_truth[mcevts_truth]/F");
1537  CreateBranch("nuvtxz_truth",nuvtxz_truth,"nuvtxz_truth[mcevts_truth]/F");
1538  CreateBranch("nu_dcosx_truth",nu_dcosx_truth,"nu_dcosx_truth[mcevts_truth]/F");
1539  CreateBranch("nu_dcosy_truth",nu_dcosy_truth,"nu_dcosy_truth[mcevts_truth]/F");
1540  CreateBranch("nu_dcosz_truth",nu_dcosz_truth,"nu_dcosz_truth[mcevts_truth]/F");
1541  CreateBranch("lep_mom_truth",lep_mom_truth,"lep_mom_truth[mcevts_truth]/F");
1542  CreateBranch("lep_dcosx_truth",lep_dcosx_truth,"lep_dcosx_truth[mcevts_truth]/F");
1543  CreateBranch("lep_dcosy_truth",lep_dcosy_truth,"lep_dcosy_truth[mcevts_truth]/F");
1544  CreateBranch("lep_dcosz_truth",lep_dcosz_truth,"lep_dcosz_truth[mcevts_truth]/F");
1545 
1546  CreateBranch("tpx_flux",tpx_flux,"tpx_flux[mcevts_truth]/F");
1547  CreateBranch("tpy_flux",tpy_flux,"tpy_flux[mcevts_truth]/F");
1548  CreateBranch("tpz_flux",tpz_flux,"tpz_flux[mcevts_truth]/F");
1549  CreateBranch("tptype_flux",tptype_flux,"tptype_flux[mcevts_truth]/I");
1550 
1551  CreateBranch("genie_no_primaries",&genie_no_primaries,"genie_no_primaries/I");
1552  CreateBranch("genie_primaries_pdg",genie_primaries_pdg,"genie_primaries_pdg[genie_no_primaries]/I");
1553  CreateBranch("genie_Eng",genie_Eng,"genie_Eng[genie_no_primaries]/F");
1554  CreateBranch("genie_Px",genie_Px,"genie_Px[genie_no_primaries]/F");
1555  CreateBranch("genie_Py",genie_Py,"genie_Py[genie_no_primaries]/F");
1556  CreateBranch("genie_Pz",genie_Pz,"genie_Pz[genie_no_primaries]/F");
1557  CreateBranch("genie_P",genie_P,"genie_P[genie_no_primaries]/F");
1558  CreateBranch("genie_status_code",genie_status_code,"genie_status_code[genie_no_primaries]/I");
1559  CreateBranch("genie_mass",genie_mass,"genie_mass[genie_no_primaries]/F");
1560  CreateBranch("genie_trackID",genie_trackID,"genie_trackID[genie_no_primaries]/I");
1561  CreateBranch("genie_ND",genie_ND,"genie_ND[genie_no_primaries]/I");
1562  CreateBranch("genie_mother",genie_mother,"genie_mother[genie_no_primaries]/I");
1563  }
1564 
1565  if (hasCryInfo()){
1566  CreateBranch("mcevts_truthcry",&mcevts_truthcry,"mcevts_truthcry/I");
1567  CreateBranch("cry_no_primaries",&cry_no_primaries,"cry_no_primaries/I");
1568  CreateBranch("cry_primaries_pdg",cry_primaries_pdg,"cry_primaries_pdg[cry_no_primaries]/I");
1569  CreateBranch("cry_Eng",cry_Eng,"cry_Eng[cry_no_primaries]/F");
1570  CreateBranch("cry_Px",cry_Px,"cry_Px[cry_no_primaries]/F");
1571  CreateBranch("cry_Py",cry_Py,"cry_Py[cry_no_primaries]/F");
1572  CreateBranch("cry_Pz",cry_Pz,"cry_Pz[cry_no_primaries]/F");
1573  CreateBranch("cry_P",cry_P,"cry_P[cry_no_primaries]/F");
1574  CreateBranch("cry_StartPointx",cry_StartPointx,"cry_StartPointx[cry_no_primaries]/F");
1575  CreateBranch("cry_StartPointy",cry_StartPointy,"cry_StartPointy[cry_no_primaries]/F");
1576  CreateBranch("cry_StartPointz",cry_StartPointz,"cry_StartPointz[cry_no_primaries]/F");
1577  CreateBranch("cry_status_code",cry_status_code,"cry_status_code[cry_no_primaries]/I");
1578  CreateBranch("cry_mass",cry_mass,"cry_mass[cry_no_primaries]/F");
1579  CreateBranch("cry_trackID",cry_trackID,"cry_trackID[cry_no_primaries]/I");
1580  CreateBranch("cry_ND",cry_ND,"cry_ND[cry_no_primaries]/I");
1581  CreateBranch("cry_mother",cry_mother,"cry_mother[cry_no_primaries]/I");
1582  }
1583 
1584  if (hasGeantInfo()){
1585  CreateBranch("no_primaries",&no_primaries,"no_primaries/I");
1586  CreateBranch("geant_list_size",&geant_list_size,"geant_list_size/I");
1587  CreateBranch("geant_list_size_in_tpcAV",&geant_list_size_in_tpcAV,"geant_list_size_in_tpcAV/I");
1588  CreateBranch("pdg",pdg,"pdg[geant_list_size]/I");
1589  CreateBranch("status",status,"status[geant_list_size]/I");
1590  CreateBranch("Mass",Mass,"Mass[geant_list_size]/F");
1591  CreateBranch("Eng",Eng,"Eng[geant_list_size]/F");
1592  CreateBranch("EndE",EndE,"EndE[geant_list_size]/F");
1593  CreateBranch("Px",Px,"Px[geant_list_size]/F");
1594  CreateBranch("Py",Py,"Py[geant_list_size]/F");
1595  CreateBranch("Pz",Pz,"Pz[geant_list_size]/F");
1596  CreateBranch("P",P,"P[geant_list_size]/F");
1597  CreateBranch("StartPointx",StartPointx,"StartPointx[geant_list_size]/F");
1598  CreateBranch("StartPointy",StartPointy,"StartPointy[geant_list_size]/F");
1599  CreateBranch("StartPointz",StartPointz,"StartPointz[geant_list_size]/F");
1600  CreateBranch("StartT",StartT,"StartT[geant_list_size]/F");
1601  CreateBranch("EndPointx",EndPointx,"EndPointx[geant_list_size]/F");
1602  CreateBranch("EndPointy",EndPointy,"EndPointy[geant_list_size]/F");
1603  CreateBranch("EndPointz",EndPointz,"EndPointz[geant_list_size]/F");
1604  CreateBranch("EndT",EndT,"EndT[geant_list_size]/F");
1605  CreateBranch("theta",theta,"theta[geant_list_size]/F");
1606  CreateBranch("phi",phi,"phi[geant_list_size]/F");
1607  CreateBranch("theta_xz",theta_xz,"theta_xz[geant_list_size]/F");
1608  CreateBranch("theta_yz",theta_yz,"theta_yz[geant_list_size]/F");
1609  CreateBranch("pathlen",pathlen,"pathlen[geant_list_size]/F");
1610  CreateBranch("inTPCActive",inTPCActive,"inTPCActive[geant_list_size]/I");
1611  CreateBranch("StartPointx_tpcAV",StartPointx_tpcAV,"StartPointx_tpcAV[geant_list_size]/F");
1612  CreateBranch("StartPointy_tpcAV",StartPointy_tpcAV,"StartPointy_tpcAV[geant_list_size]/F");
1613  CreateBranch("StartPointz_tpcAV",StartPointz_tpcAV,"StartPointz_tpcAV[geant_list_size]/F");
1614  CreateBranch("EndPointx_tpcAV",EndPointx_tpcAV,"EndPointx_tpcAV[geant_list_size]/F");
1615  CreateBranch("EndPointy_tpcAV",EndPointy_tpcAV,"EndPointy_tpcAV[geant_list_size]/F");
1616  CreateBranch("EndPointz_tpcAV",EndPointz_tpcAV,"EndPointz_tpcAV[geant_list_size]/F");
1617  CreateBranch("NumberDaughters",NumberDaughters,"NumberDaughters[geant_list_size]/I");
1618  CreateBranch("Mother",Mother,"Mother[geant_list_size]/I");
1619  CreateBranch("TrackId",TrackId,"TrackId[geant_list_size]/I");
1620  CreateBranch("MergedId", MergedId, "MergedId[geant_list_size]/I");
1621  CreateBranch("MotherNuId", MotherNuId, "MotherNuId[geant_list_size]/I");
1622  CreateBranch("process_primary",process_primary,"process_primary[geant_list_size]/I");
1623  CreateBranch("processname", processname);
1624  }
1625 
1626  if (hasAuxDetector()) {
1627  // Geant information is required to fill aux detector information.
1628  // if fSaveGeantInfo is not set to true, show an error message and quit!
1629  if (!hasGeantInfo()){
1630  throw art::Exception(art::errors::Configuration)
1631  << "Saving Auxiliary detector information requies saving GEANT information, "
1632  <<"please set fSaveGeantInfo flag to true in your fhicl file and rerun.\n";
1633  }
1634  std::ostringstream sstr;
1635  sstr << "[" << kMaxAuxDets << "]";
1636  std::string MaxAuxDetIndexStr = sstr.str();
1637  CreateBranch("NAuxDets", NAuxDets, "NAuxDets[geant_list_size]/s");
1638  CreateBranch("AuxDetID", AuxDetID, "AuxDetID[geant_list_size]" + MaxAuxDetIndexStr + "/S");
1639  CreateBranch("AuxDetEntryX", entryX, "AuxDetEntryX[geant_list_size]" + MaxAuxDetIndexStr + "/F");
1640  CreateBranch("AuxDetEntryY", entryY, "AuxDetEntryY[geant_list_size]" + MaxAuxDetIndexStr + "/F");
1641  CreateBranch("AuxDetEntryZ", entryZ, "AuxDetEntryZ[geant_list_size]" + MaxAuxDetIndexStr + "/F");
1642  CreateBranch("AuxDetEntryT", entryT, "AuxDetEntryT[geant_list_size]" + MaxAuxDetIndexStr + "/F");
1643  CreateBranch("AuxDetExitX", exitX, "AuxDetExitX[geant_list_size]" + MaxAuxDetIndexStr + "/F");
1644  CreateBranch("AuxDetExitY", exitY, "AuxDetExitY[geant_list_size]" + MaxAuxDetIndexStr + "/F");
1645  CreateBranch("AuxDetExitZ", exitZ, "AuxDetExitZ[geant_list_size]" + MaxAuxDetIndexStr + "/F");
1646  CreateBranch("AuxDetExitT", exitT, "AuxDetExitT[geant_list_size]" + MaxAuxDetIndexStr + "/F");
1647  CreateBranch("AuxDetExitPx", exitPx, "AuxDetExitPx[geant_list_size]" + MaxAuxDetIndexStr + "/F");
1648  CreateBranch("AuxDetExitPy", exitPy, "AuxDetExitPy[geant_list_size]" + MaxAuxDetIndexStr + "/F");
1649  CreateBranch("AuxDetExitPz", exitPz, "AuxDetExitPz[geant_list_size]" + MaxAuxDetIndexStr + "/F");
1650  CreateBranch("CombinedEnergyDep", CombinedEnergyDep,
1651  "CombinedEnergyDep[geant_list_size]" + MaxAuxDetIndexStr + "/F");
1652  } // if hasAuxDetector
1653 
1654 } // icarus::AnalysisTreeDataStruct::SetAddresses()
1655 
1656 
1657 //------------------------------------------------------------------------------
1658 //--- AnalysisTree
1659 //---
1660 
1661 icarus::AnalysisTree::AnalysisTree(fhicl::ParameterSet const& pset) :
1662  EDAnalyzer(pset),
1663  fTree(nullptr), fData(nullptr),
1664  fDigitModuleLabel (pset.get< std::string >("DigitModuleLabel") ),
1665  fHitsModuleLabel (pset.get< std::string >("HitsModuleLabel") ),
1666  fLArG4ModuleLabel (pset.get< std::string >("LArGeantModuleLabel") ),
1667  fCalDataModuleLabel (pset.get< std::string >("CalDataModuleLabel") ),
1668  fGenieGenModuleLabel (pset.get< std::string >("GenieGenModuleLabel") ),
1669  fCryGenModuleLabel (pset.get< std::string >("CryGenModuleLabel") ),
1670  fG4ModuleLabel (pset.get< std::string >("G4ModuleLabel") ),
1671  fVertexModuleLabel (pset.get< std::string> ("VertexModuleLabel") ),
1672  fTrackModuleLabel (pset.get< std::vector<std::string> >("TrackModuleLabel")),
1673  fCalorimetryModuleLabel (pset.get< std::vector<std::string> >("CalorimetryModuleLabel")),
1674  fParticleIDModuleLabel (pset.get< std::vector<std::string> >("ParticleIDModuleLabel") ),
1675  fPOTModuleLabel (pset.get< std::string >("POTModuleLabel") ),
1676  fUseBuffer (pset.get< bool >("UseBuffers", false)),
1677  fSaveAuxDetInfo (pset.get< bool >("SaveAuxDetInfo", false)),
1678  fSaveCryInfo (pset.get< bool >("SaveCryInfo", false)),
1679  fSaveGenieInfo (pset.get< bool >("SaveGenieInfo", false)),
1680  fSaveGeantInfo (pset.get< bool >("SaveGeantInfo", false)),
1681  fSaveHitInfo (pset.get< bool >("SaveHitInfo", false)),
1682  fSaveTrackInfo (pset.get< bool >("SaveTrackInfo", false)),
1683  fSaveVertexInfo (pset.get< bool >("SaveVertexInfo", false)),
1684  //fCosmicTaggerAssocLabel (pset.get<std::vector< std::string > >("CosmicTaggerAssocLabel") ),
1685  //fFlashMatchAssocLabel (pset.get<std::vector< std::string > >("FlashMatchAssocLabel") ),
1686  isCosmics(false),
1687  fSaveCaloCosmics (pset.get< bool >("SaveCaloCosmics",false)),
1688  fG4minE (pset.get< float>("G4minE",0.01))
1689 {
1690  if (fSaveAuxDetInfo == true) fSaveGeantInfo = true;
1691  mf::LogInfo("AnalysisTree") << "Configuration:"
1692  << "\n UseBuffers: " << std::boolalpha << fUseBuffer
1693  ;
1694  if (GetNTrackers() > kMaxTrackers) {
1695  throw art::Exception(art::errors::Configuration)
1696  << "AnalysisTree currently supports only up to " << kMaxTrackers
1697  << " tracking algorithms, but " << GetNTrackers() << " are specified."
1698  << "\nYou can increase kMaxTrackers and recompile.";
1699  } // if too many trackers
1700  if (fTrackModuleLabel.size() != fCalorimetryModuleLabel.size()){
1701  throw art::Exception(art::errors::Configuration)
1702  << "fTrackModuleLabel.size() = "<<fTrackModuleLabel.size()<<" does not match "
1703  << "fCalorimetryModuleLabel.size() = "<<fCalorimetryModuleLabel.size();
1704  }
1705  if (fTrackModuleLabel.size() != fParticleIDModuleLabel.size()){
1706  throw art::Exception(art::errors::Configuration)
1707  << "fTrackModuleLabel.size() = "<<fTrackModuleLabel.size()<<" does not match "
1708  << "fParticleIDModuleLabel.size() = "<<fParticleIDModuleLabel.size();
1709  }
1710 } // icarus::AnalysisTree::AnalysisTree()
1711 
1712 //-------------------------------------------------
1714 {
1715  DestroyData();
1716 }
1717 
1718 void icarus::AnalysisTree::CreateTree(bool bClearData /* = false */) {
1719  if (!fTree) {
1720  art::ServiceHandle<art::TFileService> tfs;
1721  fTree = tfs->make<TTree>("anatree","analysis tree");
1722  }
1723  CreateData(bClearData);
1724  SetAddresses();
1725 } // icarus::AnalysisTree::CreateTree()
1726 
1727 
1728 void icarus::AnalysisTree::beginSubRun(const art::SubRun& sr)
1729 {
1730 
1731  art::Handle< sumdata::POTSummary > potListHandle;
1732  //sr.getByLabel(fPOTModuleLabel,potListHandle);
1733 
1734  if(sr.getByLabel(fPOTModuleLabel,potListHandle))
1735  SubRunData.pot=potListHandle->totpot;
1736  else
1737  SubRunData.pot=0.;
1738 
1739 }
1740 
1741 void icarus::AnalysisTree::analyze(const art::Event& evt)
1742 {
1743  //services
1744  art::ServiceHandle<geo::Geometry> geom;
1745  art::ServiceHandle<cheat::BackTrackerService> backTracker;
1746  art::ServiceHandle<cheat::ParticleInventoryService> partInventory;
1747  // auto const* detprop = lar::providerFrom<detinfo::DetectorPropertiesService>();
1748  // auto const* LArProp = lar::providerFrom<detinfo::LArPropertiesService>();
1749 
1750  // collect the sizes which might me needed to resize the tree data structure:
1751  bool isMC = !evt.isRealData();
1752 
1753  // * hits
1754  art::Handle< std::vector<recob::Hit> > hitListHandle;
1755  std::vector<art::Ptr<recob::Hit> > hitlist;
1756  if (evt.getByLabel(fHitsModuleLabel,hitListHandle))
1757  art::fill_ptr_vector(hitlist, hitListHandle);
1758 
1759  // * vertices
1760  art::Handle< std::vector<recob::Vertex> > vtxListHandle;
1761  std::vector<art::Ptr<recob::Vertex> > vtxlist;
1762  if (evt.getByLabel(fVertexModuleLabel,vtxListHandle))
1763  art::fill_ptr_vector(vtxlist, vtxListHandle);
1764 
1765 
1766  // * MC truth information
1767  art::Handle< std::vector<simb::MCTruth> > mctruthListHandle;
1768  std::vector<art::Ptr<simb::MCTruth> > mclist;
1769  if (evt.getByLabel(fGenieGenModuleLabel,mctruthListHandle))
1770  art::fill_ptr_vector(mclist, mctruthListHandle);
1771 
1772  // *MC truth cosmic generator information
1773  art::Handle< std::vector<simb::MCTruth> > mctruthcryListHandle;
1774  std::vector<art::Ptr<simb::MCTruth> > mclistcry;
1775  if (fSaveCryInfo){
1776  if (evt.getByLabel(fCryGenModuleLabel,mctruthcryListHandle))
1777  art::fill_ptr_vector(mclistcry, mctruthcryListHandle);
1778  }
1779 
1780  art::Ptr<simb::MCTruth> mctruthcry;
1781  int nCryPrimaries = 0;
1782 
1783  if (fSaveCryInfo){
1784  mctruthcry = mclistcry[0];
1785  nCryPrimaries = mctruthcry->NParticles();
1786  }
1787 
1788  int nGeniePrimaries = 0, nGEANTparticles = 0, nMCNeutrinos = 0;
1789 
1790  auto const clockData = art::ServiceHandle<detinfo::DetectorClocksService const>()->DataFor(evt);
1791  art::Ptr<simb::MCTruth> mctruth;
1792  //Brailsford 2017/10/16
1793  //Fix for issue 17917
1794  //With the code change to accept multiple neutrinos per TTree::Entry into the TTree, this int is no longer needed (it makes compilation fail due to a warning)
1795  //int imc = 0;
1796  if (isMC) { //is MC
1797  // GENIE
1798  if (!mclist.empty()){//at least one mc record
1799  //if (fSaveGenieInfo){
1800  //if (mclist[0]->NeutrinoSet()){//is neutrino
1801  //sometimes there can be multiple neutrino interactions in one spill
1802  //this is trying to find the primary interaction
1803  //by looking for the highest energy deposition
1804  //std::map<art::Ptr<simb::MCTruth>,double> mctruthemap;
1805  static bool isfirsttime = true;
1806  if (isfirsttime){
1807  for (size_t i = 0; i<hitlist.size(); i++){
1808  //if (hitlist[i]->View() == geo::kV){//collection view
1809  std::vector<sim::TrackIDE> eveIDs = backTracker->HitToEveTrackIDEs(clockData, hitlist[i]);
1810  for (size_t e = 0; e<eveIDs.size(); e++){
1811  art::Ptr<simb::MCTruth> ev_mctruth = partInventory->TrackIdToMCTruth_P(eveIDs[e].trackID);
1812  //mctruthemap[ev_mctruth]+=eveIDs[e].energy;
1813  if (ev_mctruth->Origin() == simb::kCosmicRay) isCosmics = true;
1814  }
1815  //}
1816  }
1817  isfirsttime = false;
1818  if (fSaveCaloCosmics) isCosmics = false; //override to save calo info
1819  }
1820 
1821 // double maxenergy = -1;
1822 // int imc0 = 0;
1823 // for (std::map<art::Ptr<simb::MCTruth>,double>::iterator ii=mctruthemap.begin(); ii!=mctruthemap.end(); ++ii){
1824 // if ((ii->second)>maxenergy){
1825 // maxenergy = ii->second;
1826 // mctruth = ii->first;
1827 // imc = imc0;
1828 // }
1829 // imc0++;
1830 // }
1831 
1832  //imc = 0; //set imc to 0 to solve a confusion for BNB+cosmic files where there are two MCTruth
1833  mctruth = mclist[0];
1834 
1835  if (mctruth->NeutrinoSet()) nGeniePrimaries = mctruth->NParticles();
1836  //} //end (fSaveGenieInfo)
1837 
1838  const sim::ParticleList& plist = partInventory->ParticleList();
1839  nGEANTparticles = plist.size();
1840 
1841  // to know the number of particles in AV would require
1842  // looking at all of them; so we waste some memory here
1843  } // if have MC truth
1844  MF_LOG_DEBUG("AnalysisTree") << "Expected "
1845  << nGEANTparticles << " GEANT particles, "
1846  << nGeniePrimaries << " GENIE particles";
1847  } // if MC
1848 
1849  //Brailsford 2017/10/16
1850  //Initially call the number of neutrinos to be stored the number of MCTruth objects. This is not strictly true i.e. BNB + cosmic overlay but we will count the number of neutrinos later
1851  nMCNeutrinos = mclist.size();
1852 
1853  CreateData(); // tracker data is created with default constructor
1854  if (fSaveGenieInfo){
1855  fData->ResizeGenie(nGeniePrimaries);
1856  fData->ResizeMCNeutrino(nMCNeutrinos);
1857  }
1858  if (fSaveCryInfo)
1859  fData->ResizeCry(nCryPrimaries);
1860  if (fSaveGeantInfo)
1861  fData->ResizeGEANT(nGEANTparticles);
1862  fData->ClearLocalData(); // don't bother clearing tracker data yet
1863 
1864 // const size_t Nplanes = 3; // number of wire planes; pretty much constant...
1865  const size_t NTrackers = GetNTrackers(); // number of trackers passed into fTrackModuleLabel
1866  const size_t NHits = hitlist.size(); // number of hits
1867  const size_t NVertices = vtxlist.size(); // number of vertices
1868  // make sure there is the data, the tree and everything;
1869  CreateTree();
1870 
1871  /// transfer the run and subrun data to the tree data object
1872 // fData->RunData = RunData;
1873  fData->SubRunData = SubRunData;
1874 
1875  fData->isdata = int(!isMC);
1876 
1877  std::vector< art::Handle< std::vector<recob::Track> > > trackListHandle(NTrackers);
1878  std::vector< std::vector<art::Ptr<recob::Track> > > tracklist(NTrackers);
1879  for (unsigned int it = 0; it < NTrackers; ++it){
1880  if (evt.getByLabel(fTrackModuleLabel[it],trackListHandle[it]))
1881  art::fill_ptr_vector(tracklist[it], trackListHandle[it]);
1882  }
1883 
1884  art::Handle< std::vector<simb::MCFlux> > mcfluxListHandle;
1885  std::vector<art::Ptr<simb::MCFlux> > fluxlist;
1886  if (evt.getByLabel(fGenieGenModuleLabel,mcfluxListHandle))
1887  art::fill_ptr_vector(fluxlist, mcfluxListHandle);
1888 
1889  std::vector<const sim::AuxDetSimChannel*> fAuxDetSimChannels;
1890  if (fSaveAuxDetInfo && fSaveGeantInfo){
1891  evt.getView(fLArG4ModuleLabel, fAuxDetSimChannels);
1892  }
1893 
1894  std::vector<const sim::SimChannel*> fSimChannels;
1895  if (isMC && fSaveGeantInfo){
1896  evt.getView(fLArG4ModuleLabel, fSimChannels);
1897  }
1898 
1899  fData->run = evt.run();
1900  fData->subrun = evt.subRun();
1901  fData->event = evt.id().event();
1902 
1903  art::Timestamp ts = evt.time();
1904  TTimeStamp tts(ts.timeHigh(), ts.timeLow());
1905  fData->evttime = tts.AsDouble();
1906 
1907  //copied from MergeDataPaddles.cxx
1908  art::Handle< raw::BeamInfo > beam;
1909  if (evt.getByLabel("beam",beam)){
1910  fData->beamtime = (double)beam->get_t_ms();
1911  fData->beamtime/=1000.; //in second
1912  }
1913 
1914 // std::cout<<detprop->NumberTimeSamples()<<" "<<detprop->ReadOutWindowSize()<<std::endl;
1915 // std::cout<<geom->DetHalfHeight()*2<<" "<<geom->DetHalfWidth()*2<<" "<<geom->DetLength()<<std::endl;
1916 // std::cout<<geom->Nwires(0)<<" "<<geom->Nwires(1)<<" "<<geom->Nwires(2)<<std::endl;
1917 
1918  //hit information
1919  if (fSaveHitInfo){
1920  fData->no_hits = (int) NHits;
1921  if (NHits > kMaxHits) {
1922  // got this error? consider increasing kMaxHits
1923  // (or ask for a redesign using vectors)
1924  mf::LogError("AnalysisTree:limits") << "event has " << NHits
1925  << " hits, only kMaxHits=" << kMaxHits << " stored in tree";
1926  }
1927  for (size_t i = 0; i < NHits && i < kMaxHits ; ++i){//loop over hits
1928  fData->hit_channel[i] = hitlist[i]->Channel();
1929  fData->hit_tpc[i] = hitlist[i]->WireID().TPC;
1930  fData->hit_plane[i] = hitlist[i]->WireID().Plane;
1931  fData->hit_wire[i] = hitlist[i]->WireID().Wire;
1932  fData->hit_peakT[i] = hitlist[i]->PeakTime();
1933  fData->hit_charge[i] = hitlist[i]->Integral();
1934  fData->hit_ph[i] = hitlist[i]->PeakAmplitude();
1935  fData->hit_startT[i] = hitlist[i]->PeakTimeMinusRMS();
1936  fData->hit_endT[i] = hitlist[i]->PeakTimePlusRMS();
1937  /*
1938  for (unsigned int it=0; it<fTrackModuleLabel.size();++it){
1939  art::FindManyP<recob::Track> fmtk(hitListHandle,evt,fTrackModuleLabel[it]);
1940  if (fmtk.at(i).size()!=0){
1941  hit_trkid[it][i] = fmtk.at(i)[0]->ID();
1942  }
1943  else
1944  hit_trkid[it][i] = 0;
1945  }
1946  */
1947 
1948  if (!evt.isRealData()){
1949  fData -> hit_nelec[i] = 0;
1950  fData -> hit_energy[i] = 0;
1951  const sim::SimChannel* chan = 0;
1952  for(size_t sc = 0; sc < fSimChannels.size(); ++sc){
1953  if(fSimChannels[sc]->Channel() == hitlist[i]->Channel()) chan = fSimChannels[sc];
1954  }
1955  if (chan){
1956  for (auto const& tdcide: chan->TDCIDEMap()) {
1957  // loop over the vector of IDE objects.
1958  std::vector<sim::IDE> const& idevec = tdcide.second;
1959  for(auto const& ide: idevec) {
1960  fData -> hit_nelec[i] += ide.numElectrons;
1961  fData -> hit_energy[i] += ide.energy;
1962  } // all IDEs in the TDC tick
1963  } // all TDC ticks
1964  }
1965  }
1966  }
1967 
1968  if (evt.getByLabel(fHitsModuleLabel,hitListHandle)){
1969  //Find tracks associated with hits
1970  art::FindManyP<recob::Track> fmtk(hitListHandle,evt,fTrackModuleLabel[0]);
1971  for (size_t i = 0; i < NHits && i < kMaxHits ; ++i){//loop over hits
1972  if (fmtk.isValid()){
1973  if (fmtk.at(i).size()!=0){
1974  fData->hit_trkid[i] = fmtk.at(i)[0]->ID();
1975  }
1976  else
1977  fData->hit_trkid[i] = -1;
1978  }
1979  }
1980  }
1981  }// end (fSaveHitInfo)
1982 
1983  //vertex information
1984  if (fSaveVertexInfo){
1985  fData->nvtx = NVertices;
1986  if (NVertices > kMaxVertices){
1987  // got this error? consider increasing kMaxVerticestra
1988  // (or ask for a redesign using vectors)
1989  mf::LogError("AnalysisTree:limits") << "event has " << NVertices
1990  << " vertices, only kMaxVertices=" << kMaxVertices << " stored in tree";
1991  }
1992  for (size_t i = 0; i < NVertices && i < kMaxVertices ; ++i){//loop over hits
1993  Double_t xyz[3] = {};
1994  vtxlist[i]->XYZ(xyz);
1995  for (size_t j = 0; j<3; ++j) fData->vtx[i][j] = xyz[j];
1996  }
1997  }// end (fSaveVertexInfo)
1998 
1999  //track information for multiple trackers
2000  if (fSaveTrackInfo){
2001  for (unsigned int iTracker=0; iTracker < NTrackers; ++iTracker){
2002  AnalysisTreeDataStruct::TrackDataStruct& TrackerData = fData->GetTrackerData(iTracker);
2003 
2004  size_t NTracks = tracklist[iTracker].size();
2005  // allocate enough space for this number of tracks (but at least for one of them!)
2006  TrackerData.SetMaxTracks(std::max(NTracks, (size_t) 1));
2007  TrackerData.Clear(); // clear all the data
2008 
2009  TrackerData.ntracks = (int) NTracks;
2010 
2011  // now set the tree addresses to the newly allocated memory;
2012  // this creates the tree branches in case they are not there yet
2013  SetTrackerAddresses(iTracker);
2014  if (NTracks > TrackerData.GetMaxTracks()) {
2015  // got this error? it might be a bug,
2016  // since we are supposed to have allocated enough space to fit all tracks
2017  mf::LogError("AnalysisTree:limits") << "event has " << NTracks
2018  << " " << fTrackModuleLabel[iTracker] << " tracks, only "
2019  << TrackerData.GetMaxTracks() << " stored in tree";
2020  }
2021 
2022  //call the track momentum algorithm that gives you momentum based on track range
2023  //trkf::TrackMomentumCalculator trkm;
2024 
2025  for(size_t iTrk=0; iTrk < NTracks; ++iTrk){//loop over tracks
2026 
2027  //Cosmic Tagger information
2028  if (fCosmicTaggerAssocLabel.size() > iTracker) {
2029  art::FindManyP<anab::CosmicTag> fmct(trackListHandle[iTracker],evt,fCosmicTaggerAssocLabel[iTracker]);
2030  if (fmct.isValid()){
2031  TrackerData.trkncosmictags_tagger[iTrk] = fmct.at(iTrk).size();
2032  if (fmct.at(iTrk).size()>0){
2033  if(fmct.at(iTrk).size()>1)
2034  std::cerr << "\n Warning : more than one cosmic tag per track in module! assigning the first tag to the track" << fCosmicTaggerAssocLabel[iTracker];
2035  TrackerData.trkcosmicscore_tagger[iTrk] = fmct.at(iTrk).at(0)->CosmicScore();
2036  TrackerData.trkcosmictype_tagger[iTrk] = fmct.at(iTrk).at(0)->CosmicType();
2037  }
2038  }
2039  } // if we have matching fCosmicTaggerAssocLabel
2040 
2041  //Flash match compatibility information
2042  if (fFlashMatchAssocLabel.size() > iTracker) {
2043  //Unlike CosmicTagger, Flash match doesn't assign a cosmic tag for every track. For those tracks, AnalysisTree initializes them with -9999 or -99999
2044  art::FindManyP<anab::CosmicTag> fmbfm(trackListHandle[iTracker],evt,fFlashMatchAssocLabel[iTracker]);
2045  if (fmbfm.isValid()){
2046  TrackerData.trkncosmictags_flashmatch[iTrk] = fmbfm.at(iTrk).size();
2047  if (fmbfm.at(iTrk).size()>0){
2048  if(fmbfm.at(iTrk).size()>1)
2049  std::cerr << "\n Warning : more than one cosmic tag per track in module! assigning the first tag to the track" << fFlashMatchAssocLabel[iTracker];
2050  TrackerData.trkcosmicscore_flashmatch[iTrk] = fmbfm.at(iTrk).at(0)->CosmicScore();
2051  TrackerData.trkcosmictype_flashmatch[iTrk] = fmbfm.at(iTrk).at(0)->CosmicType();
2052  //std::cout<<"\n"<<evt.event()<<"\t"<<iTrk<<"\t"<<fmbfm.at(iTrk).at(0)->CosmicScore()<<"\t"<<fmbfm.at(iTrk).at(0)->CosmicType();
2053  }
2054  }
2055  } // if we have matching fFlashMatchAssocLabel
2056 
2057  art::Ptr<recob::Track> ptrack(trackListHandle[iTracker], iTrk);
2058  const recob::Track& track = *ptrack;
2059 
2060  //TVector3 pos, dir_start, dir_end, end;
2062  recob::tracking::Vector_t dir_start,dir_end;
2063 
2064  double tlen = 0.; //mom = 0.;
2065  int TrackID = -1;
2066 
2067  int ntraj = track.NumberTrajectoryPoints();
2068  if (ntraj > 0) {
2069  pos = track.Vertex();
2070  dir_start = track.VertexDirection();
2071  dir_end = track.EndDirection();
2072  end = track.End();
2073 
2074  tlen = length(track);
2075  TrackID = track.ID();
2076 
2077  double theta_xz = std::atan2(dir_start.X(), dir_start.Z());
2078  double theta_yz = std::atan2(dir_start.Y(), dir_start.Z());
2079  double dpos = bdist(pos);
2080  double dend = bdist(end);
2081 
2082  TrackerData.trkId[iTrk] = TrackID;
2083  TrackerData.trkstartx[iTrk] = pos.X();
2084  TrackerData.trkstarty[iTrk] = pos.Y();
2085  TrackerData.trkstartz[iTrk] = pos.Z();
2086  TrackerData.trkstartd[iTrk] = dpos;
2087  TrackerData.trkendx[iTrk] = end.X();
2088  TrackerData.trkendy[iTrk] = end.Y();
2089  TrackerData.trkendz[iTrk] = end.Z();
2090  TrackerData.trkendd[iTrk] = dend;
2091  TrackerData.trktheta[iTrk] = dir_start.Theta();
2092  TrackerData.trkphi[iTrk] = dir_start.Phi();
2093  TrackerData.trkstartdcosx[iTrk] = dir_start.X();
2094  TrackerData.trkstartdcosy[iTrk] = dir_start.Y();
2095  TrackerData.trkstartdcosz[iTrk] = dir_start.Z();
2096  TrackerData.trkenddcosx[iTrk] = dir_end.X();
2097  TrackerData.trkenddcosy[iTrk] = dir_end.Y();
2098  TrackerData.trkenddcosz[iTrk] = dir_end.Z();
2099  TrackerData.trkthetaxz[iTrk] = theta_xz;
2100  TrackerData.trkthetayz[iTrk] = theta_yz;
2101  //TrackerData.trkmom[iTrk] = mom;
2102  TrackerData.trklen[iTrk] = tlen;
2103  //TrackerData.trkmomrange[iTrk] = trkm.GetTrackMomentum(tlen,13);
2104  //TrackerData.trkmommschi2[iTrk] = trkm.GetMomentumMultiScatterChi2(ptrack);
2105  //TrackerData.trkmommsllhd[iTrk] = trkm.GetMomentumMultiScatterLLHD(ptrack);
2106  } // if we have trajectory
2107 
2108  // find vertices associated with this track
2109  /*
2110  art::FindMany<recob::Vertex> fmvtx(trackListHandle[iTracker], evt, fVertexModuleLabel[iTracker]);
2111  if(fmvtx.isValid()) {
2112  std::vector<const recob::Vertex*> verts = fmvtx.at(iTrk);
2113  // should have two at most
2114  for(size_t ivx = 0; ivx < verts.size(); ++ivx) {
2115  verts[ivx]->XYZ(xyz);
2116  // find the vertex in TrackerData to get the index
2117  short theVtx = -1;
2118  for(short jvx = 0; jvx < TrackerData.nvtx; ++jvx) {
2119  if(TrackerData.vtx[jvx][2] == xyz[2]) {
2120  theVtx = jvx;
2121  break;
2122  }
2123  } // jvx
2124  // decide if it should be assigned to the track Start or End.
2125  // A simple dz test should suffice
2126  if(fabs(xyz[2] - TrackerData.trkstartz[iTrk]) <
2127  fabs(xyz[2] - TrackerData.trkendz[iTrk])) {
2128  TrackerData.trksvtxid[iTrk] = theVtx;
2129  } else {
2130  TrackerData.trkevtxid[iTrk] = theVtx;
2131  }
2132  } // vertices
2133  } // fmvtx.isValid()
2134  */
2135  Float_t minsdist = 10000;
2136  Float_t minedist = 10000;
2137  for (int ivx = 0; ivx < fData->nvtx && ivx < kMaxVertices; ++ivx){
2138  Float_t sdist = sqrt(pow(TrackerData.trkstartx[iTrk]-fData->vtx[ivx][0],2)+
2139  pow(TrackerData.trkstarty[iTrk]-fData->vtx[ivx][1],2)+
2140  pow(TrackerData.trkstartz[iTrk]-fData->vtx[ivx][2],2));
2141  Float_t edist = sqrt(pow(TrackerData.trkendx[iTrk]-fData->vtx[ivx][0],2)+
2142  pow(TrackerData.trkendy[iTrk]-fData->vtx[ivx][1],2)+
2143  pow(TrackerData.trkendz[iTrk]-fData->vtx[ivx][2],2));
2144  if (sdist<minsdist){
2145  minsdist = sdist;
2146  if (minsdist<10) TrackerData.trksvtxid[iTrk] = ivx;
2147  }
2148  if (edist<minedist){
2149  minedist = edist;
2150  if (minedist<10) TrackerData.trkevtxid[iTrk] = ivx;
2151  }
2152  }
2153  // find particle ID info
2154  art::FindMany<anab::ParticleID> fmpid(trackListHandle[iTracker], evt, fParticleIDModuleLabel[iTracker]);
2155  if(fmpid.isValid()) {
2156  std::vector<const anab::ParticleID*> pids = fmpid.at(iTrk);
2157  if (pids.size() == 0){
2158  mf::LogError("AnalysisTree:limits")
2159  << "No track-PID association found for " << fTrackModuleLabel[iTracker]
2160  << " track " << iTrk << ". Not saving particleID information.";
2161  }
2162  // Set dummy values
2163  double pidpdg[3] = {0,0,0};
2164  double pidchi[3] = {0.,0.,0.};
2165  for(size_t planenum=0; planenum<3; ++planenum) {
2166  TrackerData.trkpidchimu[iTrk][planenum] = 0.;
2167  TrackerData.trkpidchipi[iTrk][planenum] = 0.;
2168  TrackerData.trkpidchika[iTrk][planenum] = 0.;
2169  TrackerData.trkpidchipr[iTrk][planenum] = 0.;
2170  TrackerData.trkpidpida[iTrk][planenum] = 0.;
2171  }
2172  for (size_t ipid=0; ipid<pids.size(); ipid++){
2173  std::vector<anab::sParticleIDAlgScores> AlgScoresVec = pids[ipid]->ParticleIDAlgScores();
2174 
2175  // Loop though AlgScoresVec and find the variables we want
2176  for (size_t i_algscore=0; i_algscore<AlgScoresVec.size(); i_algscore++){
2177  anab::sParticleIDAlgScores AlgScore = AlgScoresVec.at(i_algscore);
2178 
2179  /*std::cout << "\n ParticleIDAlg " << AlgScore.fAlgName
2180  << "\n -- Variable type: " << AlgScore.fVariableType
2181  << "\n -- Track direction: " << AlgScore.fTrackDir
2182  << "\n -- Assuming PDG: " << AlgScore.fAssumedPdg
2183  << "\n -- Number of degrees of freedom: " << AlgScore.fNdf
2184  << "\n -- Value: " << AlgScore.fValue
2185  << "\n -- Using planeMask: " << AlgScore.fPlaneMask << std::endl;*/
2186 
2187  if (AlgScore.fPlaneMask.none() || AlgScore.fPlaneMask.count() > 1) continue;
2188  int planenum = -1;
2189  if (AlgScore.fPlaneMask.test(0)) planenum = 0;
2190  if (AlgScore.fPlaneMask.test(1)) planenum = 1;
2191  if (AlgScore.fPlaneMask.test(2)) planenum = 2;
2192  if (planenum<0 || planenum>2) continue;
2193 
2194  if (AlgScore.fAlgName == "Chi2"){
2195  if (TMath::Abs(AlgScore.fAssumedPdg) == 13){ // chi2mu
2196  TrackerData.trkpidchimu[iTrk][planenum] = AlgScore.fValue;
2197  if (AlgScore.fValue<pidchi[planenum] || (pidchi[planenum] == 0. && AlgScore.fValue>0.)){
2198  pidchi[planenum] = AlgScore.fValue;
2199  pidpdg[planenum] = TMath::Abs(AlgScore.fAssumedPdg);
2200  }
2201  }
2202  else if (TMath::Abs(AlgScore.fAssumedPdg) == 2212){ // chi2pr
2203  TrackerData.trkpidchipr[iTrk][planenum] = AlgScore.fValue;
2204  if (AlgScore.fValue<pidchi[planenum] || (pidchi[planenum] == 0. && AlgScore.fValue>0.)){
2205  pidchi[planenum] = AlgScore.fValue;
2206  pidpdg[planenum] = TMath::Abs(AlgScore.fAssumedPdg);
2207  }
2208  }
2209  else if (TMath::Abs(AlgScore.fAssumedPdg) == 211){ // chi2pi
2210  TrackerData.trkpidchipi[iTrk][planenum] = AlgScore.fValue;
2211  if (AlgScore.fValue<pidchi[planenum] || (pidchi[planenum] == 0. && AlgScore.fValue>0.)){
2212  pidchi[planenum] = AlgScore.fValue;
2213  pidpdg[planenum] = TMath::Abs(AlgScore.fAssumedPdg);
2214  }
2215  }
2216  else if (TMath::Abs(AlgScore.fAssumedPdg) == 321){ // chi2ka
2217  TrackerData.trkpidchika[iTrk][planenum] = AlgScore.fValue;
2218  if (AlgScore.fValue<pidchi[planenum] || (pidchi[planenum] == 0. && AlgScore.fValue>0.)){
2219  pidchi[planenum] = AlgScore.fValue;
2220  pidpdg[planenum] = TMath::Abs(AlgScore.fAssumedPdg);
2221  }
2222  }
2223 
2224  }
2225  else if (AlgScore.fVariableType==anab::kPIDA){
2226  TrackerData.trkpidpida[iTrk][planenum] = AlgScore.fValue;
2227  }
2228 
2229  } // end loop though AlgScoresVec
2230  } // end loop over pid[ipid]
2231 
2232  // Finally, set min chi2
2233  for (size_t planenum=0; planenum<3; planenum++){
2234  TrackerData.trkpidchi[iTrk][planenum] = pidchi[planenum];
2235  TrackerData.trkpidpdg[iTrk][planenum] = pidpdg[planenum];
2236  }
2237  } // fmpid.isValid()
2238 
2239 
2240 
2241  art::FindMany<anab::Calorimetry> fmcal(trackListHandle[iTracker], evt, fCalorimetryModuleLabel[iTracker]);
2242  if (fmcal.isValid()){
2243  std::vector<const anab::Calorimetry*> calos = fmcal.at(iTrk);
2244  if (calos.size() > TrackerData.GetMaxPlanesPerTrack(iTrk)) {
2245  // if you get this message, there is probably a bug somewhere since
2246  // the calorimetry planes should be 3.
2247  mf::LogError("AnalysisTree:limits")
2248  << "the " << fTrackModuleLabel[iTracker] << " track #" << iTrk
2249  << " has " << calos.size() << " planes for calorimetry , only "
2250  << TrackerData.GetMaxPlanesPerTrack(iTrk) << " stored in tree";
2251  }
2252  for (size_t ical = 0; ical<calos.size(); ++ical){
2253  if (!calos[ical]) continue;
2254  if (!calos[ical]->PlaneID().isValid) continue;
2255  int planenum = calos[ical]->PlaneID().Plane;
2256  if (planenum<0||planenum>2) continue;
2257  TrackerData.trkke[iTrk][planenum] = calos[ical]->KineticEnergy();
2258  TrackerData.trkrange[iTrk][planenum] = calos[ical]->Range();
2259  //For now make the second argument as 13 for muons.
2260  TrackerData.trkpitchc[iTrk][planenum]= calos[ical] -> TrkPitchC();
2261  const size_t NHits = calos[ical] -> dEdx().size();
2262  TrackerData.ntrkhits[iTrk][planenum] = (int) NHits;
2263  if (NHits > TrackerData.GetMaxHitsPerTrack(iTrk, planenum)) {
2264  // if you get this error, you'll have to increase kMaxTrackHits
2265  mf::LogError("AnalysisTree:limits")
2266  << "the " << fTrackModuleLabel[iTracker] << " track #" << iTrk
2267  << " has " << NHits << " hits on calorimetry plane #" << planenum
2268  <<", only "
2269  << TrackerData.GetMaxHitsPerTrack(iTrk, planenum) << " stored in tree";
2270  }
2271  if (!isCosmics){
2272  for(size_t iTrkHit = 0; iTrkHit < NHits && iTrkHit < TrackerData.GetMaxHitsPerTrack(iTrk, planenum); ++iTrkHit) {
2273  TrackerData.trkdedx[iTrk][planenum][iTrkHit] = (calos[ical] -> dEdx())[iTrkHit];
2274  TrackerData.trkdqdx[iTrk][planenum][iTrkHit] = (calos[ical] -> dQdx())[iTrkHit];
2275  TrackerData.trkresrg[iTrk][planenum][iTrkHit] = (calos[ical] -> ResidualRange())[iTrkHit];
2276  const auto& TrkPos = (calos[ical] -> XYZ())[iTrkHit];
2277  auto& TrkXYZ = TrackerData.trkxyz[iTrk][planenum][iTrkHit];
2278  TrkXYZ[0] = TrkPos.X();
2279  TrkXYZ[1] = TrkPos.Y();
2280  TrkXYZ[2] = TrkPos.Z();
2281  TrackerData.trkxp[iTrk][planenum][iTrkHit] = TrkPos.X();
2282  TrackerData.trkyp[iTrk][planenum][iTrkHit] = TrkPos.Y();
2283  TrackerData.trkzp[iTrk][planenum][iTrkHit] = TrkPos.Z();
2284  } // for track hits
2285  }
2286  } // for calorimetry info
2287  if(TrackerData.ntrkhits[iTrk][0] > TrackerData.ntrkhits[iTrk][1] && TrackerData.ntrkhits[iTrk][0] > TrackerData.ntrkhits[iTrk][2]) TrackerData.trkpidbestplane[iTrk] = 0;
2288  else if(TrackerData.ntrkhits[iTrk][1] > TrackerData.ntrkhits[iTrk][0] && TrackerData.ntrkhits[iTrk][1] > TrackerData.ntrkhits[iTrk][2]) TrackerData.trkpidbestplane[iTrk] = 1;
2289  else if(TrackerData.ntrkhits[iTrk][2] > TrackerData.ntrkhits[iTrk][0] && TrackerData.ntrkhits[iTrk][2] > TrackerData.ntrkhits[iTrk][1]) TrackerData.trkpidbestplane[iTrk] = 2;
2290  else if(TrackerData.ntrkhits[iTrk][2] == TrackerData.ntrkhits[iTrk][0] && TrackerData.ntrkhits[iTrk][2] > TrackerData.ntrkhits[iTrk][1]) TrackerData.trkpidbestplane[iTrk] = 2;
2291  else if(TrackerData.ntrkhits[iTrk][2] == TrackerData.ntrkhits[iTrk][1] && TrackerData.ntrkhits[iTrk][2] > TrackerData.ntrkhits[iTrk][0]) TrackerData.trkpidbestplane[iTrk] = 2;
2292  else if(TrackerData.ntrkhits[iTrk][1] == TrackerData.ntrkhits[iTrk][0] && TrackerData.ntrkhits[iTrk][1] > TrackerData.ntrkhits[iTrk][2]) TrackerData.trkpidbestplane[iTrk] = 0;
2293  else if(TrackerData.ntrkhits[iTrk][1] == TrackerData.ntrkhits[iTrk][0] && TrackerData.ntrkhits[iTrk][1] == TrackerData.ntrkhits[iTrk][2]) TrackerData.trkpidbestplane[iTrk] = 2;
2294  } // if has calorimetry info
2295 
2296  //track truth information
2297  if (isMC){
2298  //get the hits on each plane
2299  art::FindManyP<recob::Hit> fmht(trackListHandle[iTracker], evt, fTrackModuleLabel[iTracker]);
2300  std::vector< art::Ptr<recob::Hit> > allHits = fmht.at(iTrk);
2301  std::vector< art::Ptr<recob::Hit> > hits[kNplanes];
2302 
2303  for(size_t ah = 0; ah < allHits.size(); ++ah){
2304  if (/* allHits[ah]->WireID().Plane >= 0 && */ // always true
2305  allHits[ah]->WireID().Plane < 3){
2306  hits[allHits[ah]->WireID().Plane].push_back(allHits[ah]);
2307  }
2308  }
2309 
2310  for (size_t ipl = 0; ipl < 3; ++ipl){
2311  TrackerData.trkidtruth_recoutils_totaltrueenergy[iTrk][ipl] = RecoUtils::TrueParticleIDFromTotalTrueEnergy(clockData, hits[ipl]);
2312  TrackerData.trkidtruth_recoutils_totalrecocharge[iTrk][ipl] = RecoUtils::TrueParticleIDFromTotalRecoCharge(clockData, hits[ipl]);
2313  TrackerData.trkidtruth_recoutils_totalrecohits[iTrk][ipl] = RecoUtils::TrueParticleIDFromTotalRecoHits(clockData, hits[ipl]);
2314  double maxe = 0;
2315  HitsPurity(clockData, hits[ipl],TrackerData.trkidtruth[iTrk][ipl],TrackerData.trkpurtruth[iTrk][ipl],maxe);
2316  //std::cout<<"\n"<<iTracker<<"\t"<<iTrk<<"\t"<<ipl<<"\t"<<trkidtruth[iTracker][iTrk][ipl]<<"\t"<<trkpurtruth[iTracker][iTrk][ipl]<<"\t"<<maxe;
2317  if (TrackerData.trkidtruth[iTrk][ipl]>0){
2318  const art::Ptr<simb::MCTruth> mc = partInventory->TrackIdToMCTruth_P(TrackerData.trkidtruth[iTrk][ipl]);
2319  TrackerData.trkorigin[iTrk][ipl] = mc->Origin();
2320  const simb::MCParticle *particle = partInventory->TrackIdToParticle_P(TrackerData.trkidtruth[iTrk][ipl]);
2321  double tote = 0;
2322  const std::vector<const sim::IDE*> vide(backTracker->TrackIdToSimIDEs_Ps(TrackerData.trkidtruth[iTrk][ipl]));
2323  for (auto ide: vide) {
2324  tote += ide->energy;
2325  TrackerData.trksimIDEenergytruth[iTrk][ipl] = ide->energy;
2326  TrackerData.trksimIDExtruth[iTrk][ipl] = ide->x;
2327  TrackerData.trksimIDEytruth[iTrk][ipl] = ide->y;
2328  TrackerData.trksimIDEztruth[iTrk][ipl] = ide->z;
2329  }
2330  TrackerData.trkpdgtruth[iTrk][ipl] = particle->PdgCode();
2331  TrackerData.trkefftruth[iTrk][ipl] = maxe/(tote/kNplanes); //tote include both induction and collection energies
2332  //std::cout<<"\n"<<trkpdgtruth[iTracker][iTrk][ipl]<<"\t"<<trkefftruth[iTracker][iTrk][ipl];
2333  }
2334  }
2335  }//end if (isMC)
2336  }//end loop over track
2337  }//end loop over track module labels
2338  }// end (fSaveTrackInfo)
2339 
2340  /*trkf::TrackMomentumCalculator trkm;
2341  std::cout<<"\t"<<trkm.GetTrackMomentum(200,2212)<<"\t"<<trkm.GetTrackMomentum(-10, 13)<<"\t"<<trkm.GetTrackMomentum(300,-19)<<"\n";
2342 */
2343  //mc truth information
2344  if (isMC){
2345  if (fSaveCryInfo){
2346  //store cry (cosmic generator information)
2347  fData->mcevts_truthcry = mclistcry.size();
2348  fData->cry_no_primaries = nCryPrimaries;
2349  //fData->cry_no_primaries;
2350  for(Int_t iPartc = 0; iPartc < mctruthcry->NParticles(); ++iPartc){
2351  const simb::MCParticle& partc(mctruthcry->GetParticle(iPartc));
2352  fData->cry_primaries_pdg[iPartc]=partc.PdgCode();
2353  fData->cry_Eng[iPartc]=partc.E();
2354  fData->cry_Px[iPartc]=partc.Px();
2355  fData->cry_Py[iPartc]=partc.Py();
2356  fData->cry_Pz[iPartc]=partc.Pz();
2357  fData->cry_P[iPartc]=partc.P();
2358  fData->cry_StartPointx[iPartc] = partc.Vx();
2359  fData->cry_StartPointy[iPartc] = partc.Vy();
2360  fData->cry_StartPointz[iPartc] = partc.Vz();
2361  fData->cry_status_code[iPartc]=partc.StatusCode();
2362  fData->cry_mass[iPartc]=partc.Mass();
2363  fData->cry_trackID[iPartc]=partc.TrackId();
2364  fData->cry_ND[iPartc]=partc.NumberDaughters();
2365  fData->cry_mother[iPartc]=partc.Mother();
2366  } // for cry particles
2367  }// end fSaveCryInfo
2368 
2369  fData->mcevts_truth = mclist.size();
2370  //Brailsford 2017/10/16
2371  //Issue 17917
2372  //To keep a 1:1 between neutrinos and 'flux' we need the assns
2373  art::FindOneP<simb::MCFlux> fmFluxNeutrino(mctruthListHandle, evt, fGenieGenModuleLabel);
2374 
2375  if (fData->mcevts_truth > 0){//at least one mc record
2376  if (fSaveGenieInfo){
2377 
2378  //Brailsford 2017/10/16
2379  //Issue 17917
2380  //Loop over every truth in the spill rather than just looking at the first one.
2381  //Because MCTruth could be a neutrino OR something else (e.g. cosmics) we are going to have to count up how many neutrinos there are
2382  fData->mcevts_truth = 0;
2383  for (unsigned int i_mctruth = 0; i_mctruth < mclist.size(); i_mctruth++){
2384  //fetch an mctruth
2385  art::Ptr<simb::MCTruth> curr_mctruth = mclist[i_mctruth];
2386  //Check if it's a neutrino
2387  if (!curr_mctruth->NeutrinoSet()) continue;
2388  fData->nuPDG_truth[i_mctruth] = curr_mctruth->GetNeutrino().Nu().PdgCode();
2389  fData->ccnc_truth[i_mctruth] = curr_mctruth->GetNeutrino().CCNC();
2390  fData->mode_truth[i_mctruth] = curr_mctruth->GetNeutrino().Mode();
2391  fData->Q2_truth[i_mctruth] = curr_mctruth->GetNeutrino().QSqr();
2392  fData->W_truth[i_mctruth] = curr_mctruth->GetNeutrino().W();
2393  fData->hitnuc_truth[i_mctruth] = curr_mctruth->GetNeutrino().HitNuc();
2394  fData->enu_truth[i_mctruth] = curr_mctruth->GetNeutrino().Nu().E();
2395  fData->nuvtxx_truth[i_mctruth] = curr_mctruth->GetNeutrino().Nu().Vx();
2396  fData->nuvtxy_truth[i_mctruth] = curr_mctruth->GetNeutrino().Nu().Vy();
2397  fData->nuvtxz_truth[i_mctruth] = curr_mctruth->GetNeutrino().Nu().Vz();
2398  if (curr_mctruth->GetNeutrino().Nu().P()){
2399  fData->nu_dcosx_truth[i_mctruth] = curr_mctruth->GetNeutrino().Nu().Px()/curr_mctruth->GetNeutrino().Nu().P();
2400  fData->nu_dcosy_truth[i_mctruth] = curr_mctruth->GetNeutrino().Nu().Py()/curr_mctruth->GetNeutrino().Nu().P();
2401  fData->nu_dcosz_truth[i_mctruth] = curr_mctruth->GetNeutrino().Nu().Pz()/curr_mctruth->GetNeutrino().Nu().P();
2402  }
2403  fData->lep_mom_truth[i_mctruth] = curr_mctruth->GetNeutrino().Lepton().P();
2404  if (curr_mctruth->GetNeutrino().Lepton().P()){
2405  fData->lep_dcosx_truth[i_mctruth] = curr_mctruth->GetNeutrino().Lepton().Px()/curr_mctruth->GetNeutrino().Lepton().P();
2406  fData->lep_dcosy_truth[i_mctruth] = curr_mctruth->GetNeutrino().Lepton().Py()/curr_mctruth->GetNeutrino().Lepton().P();
2407  fData->lep_dcosz_truth[i_mctruth] = curr_mctruth->GetNeutrino().Lepton().Pz()/curr_mctruth->GetNeutrino().Lepton().P();
2408  }
2409  //Brailsford
2410  //2017/10/17
2411  //Issue 12918
2412  //Use the art::Ptr key as the neutrino's unique ID
2413  fData->nuID_truth[i_mctruth] = curr_mctruth.key();
2414  //We need to also store N 'flux' neutrinos per event so now check that the FindOneP is valid and, if so, use it!
2415  if (fmFluxNeutrino.isValid()){
2416  art::Ptr<simb::MCFlux> curr_mcflux = fmFluxNeutrino.at(i_mctruth);
2417  fData->tpx_flux[i_mctruth] = curr_mcflux->ftpx;
2418  fData->tpy_flux[i_mctruth] = curr_mcflux->ftpy;
2419  fData->tpz_flux[i_mctruth] = curr_mcflux->ftpz;
2420  fData->tptype_flux[i_mctruth] = curr_mcflux->ftptype;
2421  }
2422 
2423  //Let's increase the neutrino count
2424  fData->mcevts_truth++;
2425  }
2426 
2427  if (mctruth->NeutrinoSet()){
2428  //Brailsford 2017/10/16
2429  //Issue 17917
2430  //Bypass this section of filling code as there can now be multiple neutrinos per TTree::entry stored in the TTree
2431  /*
2432  fData->nuPDG_truth = mctruth->GetNeutrino().Nu().PdgCode();
2433  fData->ccnc_truth = mctruth->GetNeutrino().CCNC();
2434  fData->mode_truth = mctruth->GetNeutrino().Mode();
2435  fData->Q2_truth = mctruth->GetNeutrino().QSqr();
2436  fData->W_truth = mctruth->GetNeutrino().W();
2437  fData->hitnuc_truth = mctruth->GetNeutrino().HitNuc();
2438  fData->enu_truth = mctruth->GetNeutrino().Nu().E();
2439  fData->nuvtxx_truth = mctruth->GetNeutrino().Nu().Vx();
2440  fData->nuvtxy_truth = mctruth->GetNeutrino().Nu().Vy();
2441  fData->nuvtxz_truth = mctruth->GetNeutrino().Nu().Vz();
2442  if (mctruth->GetNeutrino().Nu().P()){
2443  fData->nu_dcosx_truth = mctruth->GetNeutrino().Nu().Px()/mctruth->GetNeutrino().Nu().P();
2444  fData->nu_dcosy_truth = mctruth->GetNeutrino().Nu().Py()/mctruth->GetNeutrino().Nu().P();
2445  fData->nu_dcosz_truth = mctruth->GetNeutrino().Nu().Pz()/mctruth->GetNeutrino().Nu().P();
2446  }
2447  fData->lep_mom_truth = mctruth->GetNeutrino().Lepton().P();
2448  if (mctruth->GetNeutrino().Lepton().P()){
2449  fData->lep_dcosx_truth = mctruth->GetNeutrino().Lepton().Px()/mctruth->GetNeutrino().Lepton().P();
2450  fData->lep_dcosy_truth = mctruth->GetNeutrino().Lepton().Py()/mctruth->GetNeutrino().Lepton().P();
2451  fData->lep_dcosz_truth = mctruth->GetNeutrino().Lepton().Pz()/mctruth->GetNeutrino().Lepton().P();
2452  }
2453  //flux information
2454  art::Ptr<simb::MCFlux> mcflux = fluxlist[imc];
2455  fData->tpx_flux = mcflux->ftpx;
2456  fData->tpy_flux = mcflux->ftpy;
2457  fData->tpz_flux = mcflux->ftpz;
2458  fData->tptype_flux = mcflux->ftptype;
2459  */
2460 
2461  //genie particles information
2462  fData->genie_no_primaries = mctruth->NParticles();
2463 
2464  size_t StoreParticles = std::min((size_t) fData->genie_no_primaries, fData->GetMaxGeniePrimaries());
2465  if (fData->genie_no_primaries > (int) StoreParticles) {
2466  // got this error? it might be a bug,
2467  // since the structure should have enough room for everything
2468  mf::LogError("AnalysisTree:limits") << "event has "
2469  << fData->genie_no_primaries << " MC particles, only "
2470  << StoreParticles << " stored in tree";
2471  }
2472  for(size_t iPart = 0; iPart < StoreParticles; ++iPart){
2473  const simb::MCParticle& part(mctruth->GetParticle(iPart));
2474  fData->genie_primaries_pdg[iPart]=part.PdgCode();
2475  fData->genie_Eng[iPart]=part.E();
2476  fData->genie_Px[iPart]=part.Px();
2477  fData->genie_Py[iPart]=part.Py();
2478  fData->genie_Pz[iPart]=part.Pz();
2479  fData->genie_P[iPart]=part.P();
2480  fData->genie_status_code[iPart]=part.StatusCode();
2481  fData->genie_mass[iPart]=part.Mass();
2482  fData->genie_trackID[iPart]=part.TrackId();
2483  fData->genie_ND[iPart]=part.NumberDaughters();
2484  fData->genie_mother[iPart]=part.Mother();
2485  } // for particle
2486  } //if neutrino set
2487  }// end (fSaveGenieInfo)
2488 
2489  //GEANT particles information
2490  if (fSaveGeantInfo){
2491  const sim::ParticleList& plist = partInventory->ParticleList();
2492 
2493  std::string pri("primary");
2494  int primary=0;
2495  int active = 0;
2496  int geant_particle=0;
2497  sim::ParticleList::const_iterator itPart = plist.begin(),
2498  pend = plist.end(); // iterator to pairs (track id, particle)
2499 
2500  for(size_t iPart = 0; (iPart < plist.size()) && (itPart != pend); ++iPart){
2501  const simb::MCParticle* pPart = (itPart++)->second;
2502  if (!pPart) {
2503  throw art::Exception(art::errors::LogicError)
2504  << "GEANT particle #" << iPart << " returned a null pointer";
2505  }
2506 
2507  ++geant_particle;
2508  bool isPrimary = pPart->Process() == pri;
2509  if (isPrimary) ++primary;
2510 
2511  int TrackID = pPart->TrackId();
2512 
2513  TVector3 mcstart, mcend;
2514  double plen = length(*pPart, mcstart, mcend);
2515 
2516  bool isActive = plen != 0;
2517  if (plen) active++;
2518 
2519  if (iPart < fData->GetMaxGEANTparticles()) {
2520  if (pPart->E()>fG4minE||isPrimary){
2521  fData->process_primary[iPart] = int(isPrimary);
2522  fData->processname[iPart]= pPart->Process();
2523  fData->Mother[iPart]=pPart->Mother();
2524  fData->TrackId[iPart]=TrackID;
2525  fData->pdg[iPart]=pPart->PdgCode();
2526  fData->status[iPart] = pPart->StatusCode();
2527  fData->Eng[iPart]=pPart->E();
2528  fData->EndE[iPart]=pPart->EndE();
2529  fData->Mass[iPart]=pPart->Mass();
2530  fData->Px[iPart]=pPart->Px();
2531  fData->Py[iPart]=pPart->Py();
2532  fData->Pz[iPart]=pPart->Pz();
2533  fData->P[iPart]=pPart->Momentum().Vect().Mag();
2534  fData->StartPointx[iPart]=pPart->Vx();
2535  fData->StartPointy[iPart]=pPart->Vy();
2536  fData->StartPointz[iPart]=pPart->Vz();
2537  fData->StartT[iPart] = pPart->T();
2538  fData->EndPointx[iPart]=pPart->EndPosition()[0];
2539  fData->EndPointy[iPart]=pPart->EndPosition()[1];
2540  fData->EndPointz[iPart]=pPart->EndPosition()[2];
2541  fData->EndT[iPart] = pPart->EndT();
2542  fData->theta[iPart] = pPart->Momentum().Theta();
2543  fData->phi[iPart] = pPart->Momentum().Phi();
2544  fData->theta_xz[iPart] = std::atan2(pPart->Px(), pPart->Pz());
2545  fData->theta_yz[iPart] = std::atan2(pPart->Py(), pPart->Pz());
2546  fData->pathlen[iPart] = plen;
2547  fData->NumberDaughters[iPart]=pPart->NumberDaughters();
2548  fData->inTPCActive[iPart] = int(isActive);
2549  if (isActive){
2550  fData->StartPointx_tpcAV[iPart] = mcstart.X();
2551  fData->StartPointy_tpcAV[iPart] = mcstart.Y();
2552  fData->StartPointz_tpcAV[iPart] = mcstart.Z();
2553  fData->EndPointx_tpcAV[iPart] = mcend.X();
2554  fData->EndPointy_tpcAV[iPart] = mcend.Y();
2555  fData->EndPointz_tpcAV[iPart] = mcend.Z();
2556  }
2557  //Brailsford
2558  //2017/10/17
2559  //Issue 17918
2560  //Get the mother neutrino of this particle and use the hosting art::Ptr key as the matched ID
2561  const art::Ptr<simb::MCTruth>& matched_mctruth = partInventory->ParticleToMCTruth_P(pPart);
2562  fData->MotherNuId[iPart] = matched_mctruth.key();
2563  }
2564  //access auxiliary detector parameters
2565  if (fSaveAuxDetInfo) {
2566  unsigned short nAD = 0; // number of cells that particle hit
2567 
2568  // find deposit of this particle in each of the detector cells
2569  for (const sim::AuxDetSimChannel* c: fAuxDetSimChannels) {
2570 
2571  // find if this cell has a contribution (IDE) from this particle,
2572  // and which one
2573  const std::vector<sim::AuxDetIDE>& setOfIDEs = c->AuxDetIDEs();
2574  // using a C++ "lambda" function here; this one:
2575  // - sees only TrackID from the current scope
2576  // - takes one parameter: the AuxDetIDE to be tested
2577  // - returns if that IDE belongs to the track we are looking for
2578  std::vector<sim::AuxDetIDE>::const_iterator iIDE
2579  = std::find_if(
2580  setOfIDEs.begin(), setOfIDEs.end(),
2581  [TrackID](const sim::AuxDetIDE& IDE){ return IDE.trackID == TrackID; }
2582  );
2583  if (iIDE == setOfIDEs.end()) continue;
2584 
2585  // now iIDE points to the energy released by the track #i (TrackID)
2586 
2587  // look for IDE with matching trackID
2588  // find trackIDs stored in setOfIDEs with the same trackID, but negative,
2589  // this is an untracked particle who's energy should be added as deposited by this original trackID
2590  float totalE = 0.; // total energy deposited around by the GEANT particle in this cell
2591  for(const auto& adtracks: setOfIDEs) {
2592  if( fabs(adtracks.trackID) == TrackID )
2593  totalE += adtracks.energyDeposited;
2594  } // for
2595 
2596  // fill the structure
2597  if (nAD < kMaxAuxDets) {
2598  fData->AuxDetID[iPart][nAD] = c->AuxDetID();
2599  fData->entryX[iPart][nAD] = iIDE->entryX;
2600  fData->entryY[iPart][nAD] = iIDE->entryY;
2601  fData->entryZ[iPart][nAD] = iIDE->entryZ;
2602  fData->entryT[iPart][nAD] = iIDE->entryT;
2603  fData->exitX[iPart][nAD] = iIDE->exitX;
2604  fData->exitY[iPart][nAD] = iIDE->exitY;
2605  fData->exitZ[iPart][nAD] = iIDE->exitZ;
2606  fData->exitT[iPart][nAD] = iIDE->exitT;
2607  fData->exitPx[iPart][nAD] = iIDE->exitMomentumX;
2608  fData->exitPy[iPart][nAD] = iIDE->exitMomentumY;
2609  fData->exitPz[iPart][nAD] = iIDE->exitMomentumZ;
2610  fData->CombinedEnergyDep[iPart][nAD] = totalE;
2611  }
2612  ++nAD;
2613  } // for aux det sim channels
2614  fData->NAuxDets[iPart] = nAD;
2615 
2616  if (nAD > kMaxAuxDets) {
2617  // got this error? consider increasing kMaxAuxDets
2618  mf::LogError("AnalysisTree:limits") << "particle #" << iPart
2619  << " touches " << nAD << " auxiliary detector cells, only "
2620  << kMaxAuxDets << " of them are saved in the tree";
2621  } // if too many detector cells
2622  } // if (fSaveAuxDetInfo)
2623  }
2624  else if (iPart == fData->GetMaxGEANTparticles()) {
2625  // got this error? it might be a bug,
2626  // since the structure should have enough room for everything
2627  mf::LogError("AnalysisTree:limits") << "event has "
2628  << plist.size() << " MC particles, only "
2629  << fData->GetMaxGEANTparticles() << " will be stored in tree";
2630  }
2631  } // for particles
2632 
2633  fData->geant_list_size_in_tpcAV = active;
2634  fData->no_primaries = primary;
2635  fData->geant_list_size = geant_particle;
2636 
2637  MF_LOG_DEBUG("AnalysisTree") << "Counted "
2638  << fData->geant_list_size << " GEANT particles ("
2639  << fData->geant_list_size_in_tpcAV << " in AV), "
2640  << fData->no_primaries << " primaries, "
2641  << fData->genie_no_primaries << " GENIE particles";
2642 
2643  FillWith(fData->MergedId, 0);
2644 
2645  // helper map track ID => index
2646  std::map<int, size_t> TrackIDtoIndex;
2647  const size_t nTrackIDs = fData->TrackId.size();
2648  for (size_t index = 0; index < nTrackIDs; ++index)
2649  TrackIDtoIndex.emplace(fData->TrackId[index], index);
2650 
2651  // for each particle, consider all the direct ancestors with the same
2652  // PDG ID, and mark them as belonging to the same "group"
2653  // (having the same MergedId)
2654  int currentMergedId = 1;
2655  for(size_t iPart = fData->geant_list_size; iPart-- > 0; ) {
2656  // if the particle already belongs to a group, don't bother
2657  if (fData->MergedId[iPart]) continue;
2658  // the particle starts its own group
2659  fData->MergedId[iPart] = currentMergedId;
2660 
2661  // look in the ancestry, one by one
2662  int currentMotherTrackId = fData->Mother[iPart];
2663  while(currentMotherTrackId > 0) {
2664  // find the mother (we have its track ID in currentMotherTrackId)
2665  std::map<int, size_t>::const_iterator iMother
2666  = TrackIDtoIndex.find(currentMotherTrackId);
2667  if (iMother == TrackIDtoIndex.end()) break; // no mother found
2668  size_t currentMotherIndex = iMother->second;
2669  // if the mother particle is of a different type,
2670  // don't bother with iPart ancestry any further
2671  if (fData->pdg[iPart] != fData->pdg[currentMotherIndex]) break;
2672 
2673  // group the "current mother" (actually, ancestor) with iPart
2674  fData->MergedId[currentMotherIndex] = currentMergedId;
2675  // then consider the grandmother (one generation earlier)
2676  currentMotherTrackId = fData->Mother[currentMotherIndex];
2677  } // while ancestry exists
2678  ++currentMergedId;
2679  } // for merging check
2680  } // if (fSaveGeantInfo)
2681 
2682  }//if (mcevts_truth)
2683  }//if (isMC){
2684  //fData->taulife = detprop->ElectronLifetime();
2685  fTree->Fill();
2686 
2687  if (mf::isDebugEnabled()) {
2688  // use mf::LogDebug instead of MF_LOG_DEBUG because we reuse it in many lines;
2689  // thus, we protect this part of the code with the line above
2690  mf::LogDebug logStream("AnalysisTreeStructure");
2691  logStream
2692  << "Tree data structure contains:"
2693  << "\n - " << fData->no_hits << " hits (" << fData->GetMaxHits() << ")"
2694  << "\n - " << fData->genie_no_primaries << " genie primaries (" << fData->GetMaxGeniePrimaries() << ")"
2695  << "\n - " << fData->geant_list_size << " GEANT particles (" << fData->GetMaxGEANTparticles() << "), "
2696  << fData->no_primaries << " primaries"
2697  << "\n - " << fData->geant_list_size_in_tpcAV << " GEANT particles in AV "
2698  << "\n - " << ((int) fData->kNTracker) << " trackers:"
2699  ;
2700 
2701  size_t iTracker = 0;
2702  for (auto tracker = fData->TrackData.cbegin();
2703  tracker != fData->TrackData.cend(); ++tracker, ++iTracker
2704  ) {
2705  logStream
2706  << "\n -> " << tracker->ntracks << " " << fTrackModuleLabel[iTracker]
2707  << " tracks (" << tracker->GetMaxTracks() << ")"
2708  ;
2709  for (int iTrk = 0; iTrk < tracker->ntracks; ++iTrk) {
2710  logStream << "\n [" << iTrk << "] "<< tracker->ntrkhits[iTrk][0];
2711  for (size_t ipl = 1; ipl < tracker->GetMaxPlanesPerTrack(iTrk); ++ipl)
2712  logStream << " + " << tracker->ntrkhits[iTrk][ipl];
2713  logStream << " hits (" << tracker->GetMaxHitsPerTrack(iTrk, 0);
2714  for (size_t ipl = 1; ipl < tracker->GetMaxPlanesPerTrack(iTrk); ++ipl)
2715  logStream << " + " << tracker->GetMaxHitsPerTrack(iTrk, ipl);
2716  logStream << ")";
2717  } // for tracks
2718  } // for trackers
2719  } // if logging enabled
2720 
2721  // if we don't use a permanent buffer (which can be huge),
2722  // delete the current buffer, and we'll create a new one on the next event
2723  if (!fUseBuffer) {
2724  MF_LOG_DEBUG("AnalysisTreeStructure") << "Freeing the tree data structure";
2725  DestroyData();
2726  }
2727 } // icarus::AnalysisTree::analyze()
2728 
2729 void icarus::AnalysisTree::HitsPurity(detinfo::DetectorClocksData const& clockData, std::vector< art::Ptr<recob::Hit> > const& hits, Int_t& trackid, Float_t& purity, double& maxe){
2730 
2731  trackid = -1;
2732  purity = -1;
2733 
2734  art::ServiceHandle<cheat::BackTrackerService> backTracker;
2735 
2736  std::map<int,double> trkide;
2737 
2738  for(size_t h = 0; h < hits.size(); ++h){
2739 
2740  art::Ptr<recob::Hit> hit = hits[h];
2741  std::vector<sim::IDE> ides;
2742 
2743  std::vector<sim::TrackIDE> eveIDs = backTracker->HitToEveTrackIDEs(clockData, hit);
2744 
2745  for(size_t e = 0; e < eveIDs.size(); ++e){
2746  //std::cout<<h<<" "<<e<<" "<<eveIDs[e].trackID<<" "<<eveIDs[e].energy<<" "<<eveIDs[e].energyFrac<<std::endl;
2747  trkide[eveIDs[e].trackID] += eveIDs[e].energy;
2748  }
2749  }
2750 
2751  maxe = -1;
2752  double tote = 0;
2753  for (std::map<int,double>::iterator ii = trkide.begin(); ii!=trkide.end(); ++ii){
2754  tote += ii->second;
2755  if ((ii->second)>maxe){
2756  maxe = ii->second;
2757  trackid = ii->first;
2758  }
2759  }
2760 
2761  //std::cout << "the total energy of this reco track is: " << tote << std::endl;
2762 
2763 
2764  if (tote>0){
2765  purity = maxe/tote;
2766  }
2767 }
2768 
2769 // Calculate distance to boundary.
2771 {
2772  // Get geometry.
2773  art::ServiceHandle<geo::Geometry> geom;
2774 
2775  geo::CryostatGeo const& cryo0 = geom->Cryostat(0);
2776  geo::CryostatGeo const& cryo1 = geom->Cryostat(1);
2777 
2778  geo::TPCGeo const& tpc00 = cryo0.TPC(0);
2779  TVector3 xyzcenter00 = tpc00.GetActiveVolumeCenter();
2780  std::cout << xyzcenter00[0] << " " << xyzcenter00[1] << " " << xyzcenter00[2] << std::endl;
2781 
2782  geo::TPCGeo const& tpc01 = cryo0.TPC(1);
2783  TVector3 xyzcenter01 = tpc01.GetActiveVolumeCenter();
2784  std::cout << xyzcenter01[0] << " " << xyzcenter01[1] << " " << xyzcenter01[2] << std::endl;
2785 
2786  geo::TPCGeo const& tpc10 = cryo1.TPC(0);
2787  TVector3 xyzcenter10 = tpc10.GetActiveVolumeCenter();
2788  std::cout << xyzcenter10[0] << " " << xyzcenter10[1] << " " << xyzcenter10[2] << std::endl;
2789 
2790  geo::TPCGeo const& tpc11 = cryo1.TPC(1);
2791  TVector3 xyzcenter11 = tpc11.GetActiveVolumeCenter();
2792  std::cout << xyzcenter11[0] << " " << xyzcenter11[1] << " " << xyzcenter11[2] << std::endl;
2793 
2794  double h00=tpc00.ActiveHalfHeight();
2795  double w00=tpc00.ActiveHalfWidth();
2796  double l00=tpc00.ActiveLength();
2797  std::cout << h00 << " " << w00 << " " << l00 << std::endl;
2798 
2799 
2800  double xmin = xyzcenter10[0]-w00;
2801  double xmax = xyzcenter11[0]+w00;
2802  double ymin = xyzcenter00[1]-h00;
2803  double ymax = xyzcenter00[1]+h00;
2804  double zmin = xyzcenter00[2]-l00/2;
2805  double zmax = xyzcenter00[2]+l00/2;
2806 
2807  double d1; // Distance to right side (wires).
2808  double d2; // Distance to left side (cathode).
2809 
2810  if (pos.X()>0) {
2811  d1=pos.X()-xmin;
2812  d2=xmax-pos.X();
2813  }
2814  if (pos.X()<0) {
2815  d1=fabs(pos.X())-xmin;
2816  d2=xmax-fabs(pos.X());
2817  }
2818 
2819  double d3 = pos.Y() -ymin; // Distance to bottom.
2820  double d4 = ymax - pos.Y(); // Distance to top.
2821  double d5 = pos.Z()-zmin; // Distance to front.
2822  double d6 = zmax - pos.Z(); // Distance to back.
2823 
2824  double result = std::min(std::min(std::min(std::min(std::min(d1, d2), d3), d4), d5), d6);
2825  return result;
2826 }
2827 
2828 // Length of reconstructed track, trajectory by trajectory.
2830 {
2831  return track.Length();
2832 }
2833 
2834 // Length of MC particle, trajectory by trajectory.
2835 double icarus::AnalysisTree::length(const simb::MCParticle& part, TVector3& start, TVector3& end)
2836 {
2837  // Get geometry.
2838  art::ServiceHandle<geo::Geometry> geom;
2839  // auto const* detprop = lar::providerFrom<detinfo::DetectorPropertiesService>();
2840 
2841  // Get active volume boundary.
2842  //double xmin = 0.;
2843 
2844 
2845  geo::CryostatGeo const& cryo0 = geom->Cryostat(0);
2846  geo::CryostatGeo const& cryo1 = geom->Cryostat(1);
2847 
2848  geo::TPCGeo const& tpc00 = cryo0.TPC(0);
2849  TVector3 xyzcenter00 = tpc00.GetActiveVolumeCenter();
2850  std::cout << xyzcenter00[0] << " " << xyzcenter00[1] << " " << xyzcenter00[2] << std::endl;
2851 
2852  geo::TPCGeo const& tpc01 = cryo0.TPC(1);
2853  TVector3 xyzcenter01 = tpc01.GetActiveVolumeCenter();
2854  std::cout << xyzcenter01[0] << " " << xyzcenter01[1] << " " << xyzcenter01[2] << std::endl;
2855 
2856  geo::TPCGeo const& tpc10 = cryo1.TPC(0);
2857  TVector3 xyzcenter10 = tpc10.GetActiveVolumeCenter();
2858  std::cout << xyzcenter10[0] << " " << xyzcenter10[1] << " " << xyzcenter10[2] << std::endl;
2859 
2860  geo::TPCGeo const& tpc11 = cryo1.TPC(1);
2861  TVector3 xyzcenter11 = tpc11.GetActiveVolumeCenter();
2862  std::cout << xyzcenter11[0] << " " << xyzcenter11[1] << " " << xyzcenter11[2] << std::endl;
2863 
2864  double h00=tpc00.ActiveHalfHeight();
2865  double w00=tpc00.ActiveHalfWidth();
2866  double l00=tpc00.ActiveLength();
2867  std::cout << h00 << " " << w00 << " " << l00 << std::endl;
2868 
2869 
2870  double xmin = xyzcenter10[0]-w00;
2871  double xmax = xyzcenter11[0]+w00;
2872  double ymin = xyzcenter00[1]-h00;
2873  double ymax = xyzcenter00[1]+h00;
2874  double zmin = xyzcenter00[2]-l00/2;
2875  double zmax = xyzcenter00[2]+l00/2;
2876  //double vDrift = 160*pow(10,-6);
2877 
2878  std::cout << "DET DIMENSIONS: xmin = " << xmin << " xmax = " << xmax << " ymin = " << ymin << " ymax = " << ymax << " zmin = " << zmin << " zmax = " << zmax << std::endl;
2879 
2880  double result = 0.;
2881  TVector3 disp;
2882  int n = part.NumberTrajectoryPoints();
2883  bool first = true;
2884 
2885  for(int i = 0; i < n; ++i) {
2886  // check if the particle is inside a TPC
2887  double mypos[3] = {part.Vx(i), part.Vy(i), part.Vz(i)};
2888  if (fabs(mypos[0]) >= xmin && fabs(mypos[0]) <= xmax && mypos[1] >= ymin && mypos[1] <= ymax && mypos[2] >= zmin && mypos[2] <= zmax){
2889  //if (mypos[0] >= -300.0 && mypos[0] <= 200.0 && mypos[1] >= ymin && mypos[1] <= ymax && mypos[2] >= zmin && mypos[2] <= zmax){
2890  double xGen = part.Vx(i);
2891  //double tGen = part.T(i);
2892  // Doing some manual shifting to account for
2893  // an interaction not occuring with the beam dump
2894  // we will reconstruct an x distance different from
2895  // where the particle actually passed to to the time
2896  // being different from in-spill interactions
2897  //double newX = xGen+(tGen*vDrift);
2898  double newX = xGen;
2899  //if (newX < -xmax || newX > (2*xmax)) continue;
2900  //if (newX < (2.*xmin) || newX > (2*xmax)) continue;
2901 
2902  TVector3 pos(newX,part.Vy(i),part.Vz(i));
2903  if(first){
2904  start = pos;
2905  }
2906  else {
2907  disp -= pos;
2908  result += disp.Mag();
2909  }
2910  first = false;
2911  disp = pos;
2912  end = pos;
2913  }
2914  }
2915  return result;
2916 }
2917 
2918 
2919 namespace icarus{
2920 
2921  DEFINE_ART_MODULE(AnalysisTree)
2922 
2923 }
2924 
2925 #endif
void ClearLocalData()
Clear all fields if this object (not the tracker algorithm data)
bool hasHitInfo() const
Returns whether we have Hit data.
AnalysisTreeDataStruct(size_t nTrackers=0)
Constructor; clears all fields.
double std(const std::vector< short > &wf, const double ped_mean, size_t start, size_t nsample)
Definition: UtilFunc.cxx:42
Point GetActiveVolumeCenter() const
Returns the center of the TPC active volume in world coordinates [cm].
Definition: TPCGeo.h:288
A wrapper to a C array (needed to embed an array into a vector)
Utilities related to art service access.
std::vector< UShort_t > NAuxDets
Number of AuxDets crossed by this particle.
Energy deposited on a readout channel by simulated tracks.
Definition: SimChannel.h:145
int TrueParticleIDFromTotalTrueEnergy(detinfo::DetectorClocksData const &clockData, const std::vector< art::Ptr< recob::Hit > > &hits, bool rollup_unsaved_ids=1)
SubRunData_t SubRunData
subrun data collected at begin of subrun
void ResizeGenie(int nPrimaries)
Resize the data strutcure for Genie primaries.
BEGIN_PROLOG could also be cerr
void operator()(std::string name, void *address, std::string leaflist)
Create a branch if it does not exist, and set its address.
void ResizeMCNeutrino(int nNeutrinos)
Resize the data structure for MCNeutrino particles.
double ActiveHalfHeight() const
Half height (associated with y coordinate) of active TPC volume [cm].
Definition: TPCGeo.h:99
bool hasAuxDetector() const
Returns whether we have auxiliary detector data.
Creates a simple ROOT tree with tracking and calorimetry information.
Declaration of signal hit object.
bool fSaveTrackInfo
whether to extract and save Hit information
size_t GetMaxGEANTparticles() const
Returns the number of GEANT particles for which memory is allocated.
AuxDetMCData_t< Float_t > entryY
Entry Y position of particle into AuxDet.
constexpr unsigned short kMaxVertices
size_t GetMaxGeniePrimaries() const
Returns the number of GENIE primaries for which memory is allocated.
Geometry information for a single TPC.
Definition: TPCGeo.h:38
AuxDetMCData_t< Float_t > exitPz
Exit z momentum of particle out of AuxDet.
void SetAddresses()
Sets the addresses of all the tree branches, creating the missing ones.
size_t NumberTrajectoryPoints() const
Various functions related to the presence and the number of (valid) points.
Vector_t VertexDirection() const
double bdist(const recob::tracking::Point_t &pos)
static constexpr bool
Definition of basic raw digits.
bool fSaveAuxDetInfo
whether to extract and save auxiliary detector data
process_name use argoneut_mc_hitfinder track
AuxDetMCData_t< Float_t > entryX
Entry X position of particle into AuxDet.
process_name hit
Definition: cheaterreco.fcl:51
bool fUseBuffer
whether to use a permanent buffer (faster, huge memory)
float fValue
Result of Particle ID algorithm/test.
Definition: ParticleID.h:28
Geometry information for a single cryostat.
Definition: CryostatGeo.h:43
isCosmics(false)
void DestroyData()
Destroy the local buffers (existing branches will point to invalid address!)
std::vector< std::string > fCosmicTaggerAssocLabel
whether to extract and save Vertex information
AuxDetMCData_t< Float_t > entryZ
Entry Z position of particle into AuxDet.
Little helper functor class to create or reset branches in a tree.
bool hasGeantInfo() const
Returns whether we have Geant data.
AuxDetMCData_t< Float_t > exitPx
Exit x momentum of particle out of AuxDet.
void SetBits(unsigned int setbits, bool unset=false)
Sets the specified bits.
std::bitset< 8 > fPlaneMask
Bitset for PlaneID used by algorithm, allowing for multiple planes and up to 8 total planes...
Definition: ParticleID.h:29
total_extent&lt;T&gt;value has the total number of elements of an array
void SetAddresses(TTree *pTree, const std::vector< std::string > &trackers, bool isCosmics)
Connect this object with a tree.
AuxDetMCData_t< Float_t > entryT
Entry T position of particle into AuxDet.
void SetTrackers(size_t nTrackers)
Allocates data structures for the given number of trackers (no Clear())
IDparameter< geo::PlaneID > PlaneID
Member type of validated geo::PlaneID parameter.
process_name pandoraGausCryo1 vertexChargeCryo1 vertexStubCryo1 xmin
std::string fAlgName
&lt; determined particle ID
Definition: ParticleID.h:23
while getopts h
Collection of particles crossing one auxiliary detector cell.
void HitsPurity(detinfo::DetectorClocksData const &clockData, std::vector< art::Ptr< recob::Hit > > const &hits, Int_t &trackid, Float_t &purity, double &maxe)
void SetAddresses(TTree *pTree, std::string tracker, bool isCosmics)
auto vector(Vector const &v)
Returns a manipulator which will print the specified array.
Definition: DumpUtils.h:265
void ResizeGEANT(int nParticles)
Resize the data strutcure for GEANT particles.
kVariableType fVariableType
Variable type enum: defined in ParticleID_VariableTypeEnums.h. Set to kNotSet by default.
Definition: ParticleID.h:24
BEGIN_PROLOG V
ROOT::Math::DisplacementVector3D< ROOT::Math::Cartesian3D< Coord_t >, ROOT::Math::GlobalCoordinateSystemTag > Vector_t
Type for representation of momenta in 3D space. See recob::tracking::Coord_t for more details on the ...
Definition: TrackingTypes.h:29
object containing MC truth information necessary for making RawDigits and doing back tracking ...
Int_t no_primaries
! how many particles there is currently room for
Int_t mcevts_truth
! The number of MCNeutrinos there is currently room for
double Length(size_t p=0) const
Access to various track properties.
bool fSaveHitInfo
whether to extract and save Geant information
IDparameter< geo::WireID > WireID
Member type of validated geo::WireID parameter.
AuxDetMCData_t< Float_t > exitT
Exit T position of particle out of AuxDet.
double ActiveHalfWidth() const
Half width (associated with x coordinate) of active TPC volume [cm].
Definition: TPCGeo.h:95
bool hasVertexInfo() const
Returns whether we have Vertex data.
AuxDetMCData_t< Float_t > CombinedEnergyDep
Sum energy of all particles with this trackID (+ID or -ID) in AuxDet.
Point_t const & Vertex() const
AuxDetMCData_t< Float_t > exitX
Exit X position of particle out of AuxDet.
auto end(FixedBins< T, C > const &) noexcept
Definition: FixedBins.h:585
fSaveCaloCosmics(pset.get< bool >("SaveCaloCosmics", false))
size_t GetMaxTrackers() const
Returns the number of trackers for which memory is allocated.
const Cut kCosmicRay
void fill(const art::PtrVector< recob::Hit > &hits, int only_plane)
bool hasCryInfo() const
Returns whether we have Cry data.
int TrueParticleIDFromTotalRecoHits(detinfo::DetectorClocksData const &clockData, const std::vector< art::Ptr< recob::Hit > > &hits, bool rollup_unsaved_ids=1)
size_t GetMaxHits() const
Returns the number of hits for which memory is allocated.
TrackDataStruct(size_t maxTracks)
Creates a tracker data structure allowing up to maxTracks tracks.
Declaration of cluster object.
Definition of data types for geometry description.
float dEdx(detinfo::DetectorClocksData const &clockData, detinfo::DetectorPropertiesData const &detProp, const TCSlice &slc, TP3D &tp3d)
Definition: PFPUtils.cxx:2687
Provides recob::Track data product.
double ActiveLength() const
Length (associated with z coordinate) of active TPC volume [cm].
Definition: TPCGeo.h:103
bool hasGenieInfo() const
Returns whether we have Genie data.
AuxDetMCData_t< Float_t > exitZ
Exit Z position of particle out of AuxDet.
auto begin(FixedBins< T, C > const &) noexcept
Definition: FixedBins.h:573
bool hasTrackInfo() const
Returns whether we have Track data.
void ResizeCry(int nPrimaries)
Resize the data strutcure for Cry primaries.
size_t GetNTrackers() const
Returns the number of trackers configured.
void CreateTree(bool bClearData=false)
Create the output tree and the data structures, if needed.
void analyze(const art::Event &evt)
read access to event
Contains all timing reference information for the detector.
const TPCGeo & TPC(unsigned int itpc) const
Return the itpc&#39;th TPC in the cryostat.
Definition: CryostatGeo.cxx:93
void CheckTree(std::string caller) const
Helper function: throws if no tree is available.
AuxDetMCData_t< Float_t > exitY
Exit Y position of particle out of AuxDet.
AuxDetMCData_t< Short_t > AuxDetID
Which AuxDet this particle went through.
bool fSaveCaloCosmics
save calorimetry information for cosmics
auto operator[](size_t index) -> decltype(*array)
Array interface.
Vector_t EndDirection() const
MC truth information to make RawDigits and do back tracking.
const TrackDataStruct & GetTrackerData(size_t iTracker) const
std::vector< BoxedArray< T[kNplanes][kMaxTrackHits][3]>> HitCoordData_t
object containing MC truth information necessary for making RawDigits and doing back tracking ...
do i e
bool fSaveGenieInfo
whether to extract and save CRY particle data
Point_t const & End() const
then echo fcl name
TDCIDEs_t const & TDCIDEMap() const
Returns all the deposited energy information as stored.
Definition: SimChannel.h:334
void CheckData(std::string caller) const
Helper function: throws if no data structure is available.
int TrueParticleIDFromTotalRecoCharge(detinfo::DetectorClocksData const &clockData, const std::vector< art::Ptr< recob::Hit > > &hits, bool rollup_unsaved_ids=1)
temporary value
art::ServiceHandle< art::TFileService > tfs
bool fSaveGeantInfo
whether to extract and save Genie information
TCEvent evt
Definition: DataStructs.cxx:8
AuxDetMCData_t< Float_t > exitPy
Exit y momentum of particle out of AuxDet.
ROOT::Math::PositionVector3D< ROOT::Math::Cartesian3D< Coord_t >, ROOT::Math::GlobalCoordinateSystemTag > Point_t
Type for representation of position in physical 3D space. See recob::tracking::Coord_t for more detai...
Definition: TrackingTypes.h:26
void CreateData(bool bClearData=false)
Creates the structure for the tree data; optionally initializes it.
fG4minE(pset.get< float >("G4minE", 0.01))
art framework interface to geometry description
BEGIN_PROLOG could also be cout
bool fSaveVertexInfo
whether to extract and save Track information
Track from a non-cascading particle.A recob::Track consists of a recob::TrackTrajectory, plus additional members relevant for a &quot;fitted&quot; track:
int fAssumedPdg
PDG of particle hypothesis assumed by algorithm, if applicable. Set to 0 by default.
Definition: ParticleID.h:27
constexpr unsigned short kMaxAuxDets
max number of auxiliary detector cells per MC particle
size_t GetNTrackers() const
Returns the number of trackers for which data structures are allocated.