All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
sbndcode/sbndcode/AnalysisTree/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/FindManyP.h"
95 #include "canvas/Persistency/Common/FindOneP.h"
96 #include "fhiclcpp/ParameterSet.h"
97 #include "messagefacility/MessageLogger/MessageLogger.h"
98 
100 #include "nusimdata/SimulationBase/GTruth.h"
101 #include "nusimdata/SimulationBase/MCTruth.h"
102 #include "nusimdata/SimulationBase/MCFlux.h"
109 // #include "larcore/DetectorInfoServices/LArPropertiesService.h"
110 // #include "larcore/Utilities/AssociationUtil.h"
118 #include "lardataobj/RecoBase/Hit.h"
136 
137 #include <cstring> // std::memcpy()
138 #include <vector>
139 #include <map>
140 #include <utility>
141 #include <iterator> // std::begin(), std::end()
142 #include <string>
143 #include <sstream>
144 #include <fstream>
145 #include <iostream>
146 #include <algorithm>
147 #include <functional> // std::mem_fn()
148 #include <typeinfo>
149 #include <cmath>
150 
151 #include "TTree.h"
152 #include "TTimeStamp.h"
153 
154 constexpr int kNplanes = 3; //number of wire planes
155 constexpr int kMaxHits = 25000; //maximum number of hits;
156 constexpr int kMaxTrackHits = 2000; //maximum number of hits on a track
157 constexpr int kMaxPFPs = 1000; //maximum number of PFPs associated w/neutrino slice
158 constexpr int kMaxTrackers = 15; //number of trackers passed into fTrackModuleLabel
159 constexpr unsigned short kMaxVertices = 100; //max number of 3D vertices
160 constexpr unsigned short kMaxShowers = 100; //max number of 3D showers
161 constexpr unsigned short kMaxAuxDets = 4; ///< max number of auxiliary detector cells per MC particle
162 
163 /// total_extent<T>::value has the total number of elements of an array
164 template <typename T>
165 struct total_extent {
166  using value_type = size_t;
167  static constexpr value_type value
168  = sizeof(T) / sizeof(typename std::remove_all_extents<T>::type);
169 }; // total_extent<>
170 
171 
172 namespace sbnd {
173 
174  /// Data structure with all the tree information.
175  ///
176  /// Can connect to a tree, clear its fields and resize its data.
178  public:
179 
180  /// A wrapper to a C array (needed to embed an array into a vector)
181  template <typename Array_t>
182  class BoxedArray {
183  protected:
184  Array_t array; // actual data
185 
186  public:
189 
190  BoxedArray() {} // no initialization
192  { std::memcpy((char*) &(data()), (char*) &(from.data()), sizeof(Array_t)); }
193 
194  Array_t& data() { return array; }
195  const Array_t& data() const { return array; }
196 
197  //@{
198  /// begin/end interface
199  static constexpr size_t size() { return total_extent<Array_t>::value; }
200  Data_t* begin() { return reinterpret_cast<Data_t*>(&array); }
201  const Data_t* begin() const { return reinterpret_cast<const Data_t*>(&array); }
202  Data_t* end() { return begin() + size(); }
203  const Data_t* end() const { return begin() + size(); }
204  //@}
205 
206  //@{
207  /// Array interface
208  auto operator[] (size_t index) -> decltype(*array) { return array[index]; }
209  auto operator[] (size_t index) const -> decltype(*array) { return array[index]; }
210  auto operator+ (ptrdiff_t index) -> decltype(&*array) { return array + index; }
211  auto operator+ (ptrdiff_t index) const -> decltype(&*array) { return array + index; }
212  auto operator- (ptrdiff_t index) -> decltype(&*array) { return array - index; }
213  auto operator- (ptrdiff_t index) const -> decltype(&*array) { return array - index; }
214  auto operator* () -> decltype(*array) { return *array; }
215  auto operator* () const -> decltype(*array) { return *array; }
216 
217  operator decltype(&array[0]) () { return &array[0]; }
218  operator decltype(&array[0]) () const { return &array[0]; }
219  //@}
220 
221  }; // BoxedArray
222 
223  /// Tracker algorithm result
224  ///
225  /// Can connect to a tree, clear its fields and resize its data.
227  public:
228  /* Data structure size:
229  *
230  * TrackData_t<Short_t> : 2 bytes/track
231  * TrackData_t<Float_t> : 4 bytes/track
232  * PlaneData_t<Float_t>, PlaneData_t<Int_t>: 12 bytes/track
233  * HitData_t<Float_t> : 24k bytes/track
234  * HitCoordData_t<Float_t> : 72k bytes/track
235  */
236  template <typename T>
237  using TrackData_t = std::vector<T>;
238  template <typename T>
239  using PlaneData_t = std::vector<BoxedArray<T[kNplanes]>>;
240  template <typename T>
241  using HitData_t = std::vector<BoxedArray<T[kNplanes][kMaxTrackHits]>>;
242  template <typename T>
243  using HitCoordData_t = std::vector<BoxedArray<T[kNplanes][kMaxTrackHits][3]>>;
244 
245  size_t MaxTracks; ///< maximum number of storable tracks
246 
247  Short_t ntracks; //number of reconstructed tracks
250  PlaneData_t<Int_t> trkidtruth_recoutils_totaltrueenergy; //true geant trackid from TrueParticleIDFromTotalTrueEnergy in RecoUtils
251  PlaneData_t<Int_t> trkidtruth_recoutils_totalrecocharge; //true geant trackid from TrueParticleIDFromTotalRecoCharge in RecoUtils
252  PlaneData_t<Int_t> trkidtruth_recoutils_totalrecohits; //true geant trackid from TrueParticleIDFromTotalTrueHits in RecoUtils
253  PlaneData_t<Int_t> trkidtruth; //true geant trackid
254  PlaneData_t<Short_t> trkorigin; //_ev_origin 0: unknown, 1: cosmic, 2: neutrino, 3: supernova, 4: singles
268 
269  // more track info
277  TrackData_t<Float_t> trkstartx; // starting x position.
278  TrackData_t<Float_t> trkstarty; // starting y position.
279  TrackData_t<Float_t> trkstartz; // starting z position.
280  TrackData_t<Float_t> trkstartd; // starting distance to boundary.
281  TrackData_t<Float_t> trkendx; // ending x position.
282  TrackData_t<Float_t> trkendy; // ending y position.
283  TrackData_t<Float_t> trkendz; // ending z position.
284  TrackData_t<Float_t> trkendd; // ending distance to boundary.
297  TrackData_t<Float_t> trkmomrange; // track momentum from range using CSDA tables
298  TrackData_t<Float_t> trkmommschi2; // track momentum from multiple scattering Chi2 method
299  TrackData_t<Float_t> trkmommsllhd; // track momentum from multiple scattering LLHD method
300  TrackData_t<Short_t> trksvtxid; // Vertex ID associated with the track start
301  TrackData_t<Short_t> trkevtxid; // Vertex ID associated with the track end
302  PlaneData_t<Int_t> trkpidpdg; // particle PID pdg code
304  PlaneData_t<Float_t> trkpidchipr; // particle PID chisq for proton
305  PlaneData_t<Float_t> trkpidchika; // particle PID chisq for kaon
306  PlaneData_t<Float_t> trkpidchipi; // particle PID chisq for pion
307  PlaneData_t<Float_t> trkpidchimu; // particle PID chisq for muon
309  TrackData_t<Short_t> trkpidbestplane; // this is defined as the plane with most hits
310 
311  /// If SaveHierarchyInfo is true, there are additional variables:
312  TrackData_t<Int_t> trkisprimary; // If the track is a daughter of the neutrino
313  TrackData_t<Int_t> trkndaughters; // Number of daughters the track has
314  TrackData_t<Int_t> trkpfpid; // The track's pfparticle ID
315  TrackData_t<Int_t> trkparentpfpid; // The parent of the track's pfparticle ID
316 
317  /// Creates an empty tracker data structure
319  /// Creates a tracker data structure allowing up to maxTracks tracks
320  TrackDataStruct(size_t maxTracks): MaxTracks(maxTracks) { Clear(); }
321  void Clear();
322  void SetMaxTracks(size_t maxTracks)
323  { MaxTracks = maxTracks; Resize(MaxTracks); }
324  void Resize(size_t nTracks);
325  void SetAddresses(TTree* pTree, std::string tracker, bool isCosmics, bool saveHierarchyInfo);
326 
327  size_t GetMaxTracks() const { return MaxTracks; }
328  size_t GetMaxPlanesPerTrack(int /* iTrack */ = 0) const
329  { return (size_t) kNplanes; }
330  size_t GetMaxHitsPerTrack(int /* iTrack */ = 0, int /* ipl */ = 0) const
331  { return (size_t) kMaxTrackHits; }
332 
333  }; // class TrackDataStruct
334 
335  /*
336  * Added by Rhiannon 8th October 2018
337  */
338  /// Shower algorithm result
339  ///
340  /// Can connect to a tree, clear its fields and resize its data.
342  public:
343 
344  template <typename T>
345  using ShowerData_t = std::vector<T>;
346 
347  size_t MaxShowers; ///< maximum number of storable showers
348 
349  Short_t nshowers; // Number of reconstructed showers
351  ShowerData_t<Int_t> shwbestplane; // shower best plane
352  ShowerData_t<Float_t> shwlength; // Length of the shower
353  ShowerData_t<Float_t> shwopenangle; // Opening angle of the shower
354  ShowerData_t<Float_t> shwstartx; // Shower start position, x
355  ShowerData_t<Float_t> shwstarty; // Shower start position, y
356  ShowerData_t<Float_t> shwstartz; // Shower start position, z
357  ShowerData_t<Float_t> shwdirx; // Shower direction, x
358  ShowerData_t<Float_t> shwdiry; // Shower direction, y
359  ShowerData_t<Float_t> shwdirz; // Shower direction, z
360 
361  /// If SaveHierarchyInfo is true, there are additional variables:
362  ShowerData_t<Int_t> shwisprimary; // If the shower is a primary particle
363  ShowerData_t<Int_t> shwndaughters; // Number of daughters the shower has
364  ShowerData_t<Int_t> shwpfpid; // PFParticle shower ID
365  ShowerData_t<Int_t> shwparentpfpid; // PFParticle shower ID
366 
367  /// Creates an empty showerer data structure
369  /// Creates a shower data structure allowing up to maxShowers showers
370  ShowerDataStruct(size_t maxShowers): MaxShowers(maxShowers) { Clear(); }
371  void Clear();
372  void SetMaxShowers(size_t maxShowers)
373  { MaxShowers = maxShowers; Resize(MaxShowers); }
374  void Resize(size_t nShowers);
375  void SetShowerAddresses(TTree* pTree, std::string showerLabel, bool saveHierarchyInfo);
376 
377  size_t GetMaxShowers() const { return MaxShowers; }
378  size_t GetMaxPlanesPerShower(int /* iShower */ = 0) const
379  { return (size_t) kNplanes; }
380 
381  }; // class ShowerDataStruct
382 
383  /*
384  * Added by Rhiannon 8th October 2018
385  */
386  /// Vertices
387  ///
388  /// Can connect to a tree, clear its fields and resize its data.
390  public:
391 
392  template <typename T>
393  using VertexData_t = std::vector<T>;
394  template <typename T>
395  using VtxCoordData_t = std::vector<BoxedArray<T[3]> >;
396 
397  size_t MaxVertices; ///< maximum number of storable vertices
398 
399  // vertex information
400  Short_t nvtx; // Number of reconstructed vertices
401  VtxCoordData_t<Float_t> vtx; // 3D position of the vertex
402  VertexData_t<Int_t> primaryvtx; // Whether the vertex is primary or not
403 
404  /// Creates an empty tracker data structure
406  /// Creates a vertex data structure allowing up to maxVertices vertices
407  VertexDataStruct(size_t maxVertices): MaxVertices(maxVertices) { Clear(); }
408  void Clear();
409  void SetMaxVertices(size_t maxVertices)
410  { MaxVertices = maxVertices; Resize(MaxVertices); }
411  void Resize(size_t nVertices);
412  void SetAddresses(TTree* pTree, std::string vertexLabel, bool saveHierarchyInfo);
413 
414  size_t GetMaxVertices() const { return MaxVertices; }
415 
416  }; // class VertexDataStruct
417 
418  enum DataBits_t: unsigned int {
419  tdAuxDet = 0x01,
420  tdCry = 0x02,
421  tdGenie = 0x04,
422  tdGeant = 0x08,
423  tdHit = 0x10,
424  tdTrack = 0x20,
425  tdShower = 0x40,
426  tdVtx = 0x80,
427  tdSlice = 0x100, //is this right?
429  }; // DataBits_t
430 
431 /* /// information from the run
432  struct RunData_t {
433  public:
434  RunData_t() { Clear(); }
435  void Clear() {}
436  }; // struct RunData_t
437 */
438  /// information from the subrun
439  struct SubRunData_t {
441  void Clear() { pot = -99999.; }
442  Double_t pot; //protons on target
443  }; // struct SubRunData_t
444 
445 // RunData_t RunData; ///< run data collected at begin of run
446  SubRunData_t SubRunData; ///< subrun data collected at begin of subrun
447 
448  //run information
449  Int_t run; //run number
450  Int_t subrun; //subrun number
451  Int_t event; //event number
452  Double_t evttime; //event time in sec
453  Double_t beamtime; //beam time
454  // Double_t pot; //protons on target moved in subrun data
455  Float_t taulife; //electron lifetime
456  Char_t isdata; //flag, 0=MC 1=data
457 
458  // hit information (non-resizeable, 45x kMaxHits = 900k bytes worth)
459  Int_t no_hits; //number of hits
460  Short_t hit_tpc[kMaxHits]; //tpc number
461  Short_t hit_plane[kMaxHits]; //plane number
462  Short_t hit_wire[kMaxHits]; //wire number
463  Short_t hit_channel[kMaxHits]; //channel ID
464  Float_t hit_peakT[kMaxHits]; //peak time (tick)
465  Float_t hit_ph[kMaxHits]; //amplitude
466  Float_t hit_charge[kMaxHits]; //charge (area) in ADC units
467  Float_t hit_startT[kMaxHits]; //hit start time
468  Float_t hit_endT[kMaxHits]; //hit end time
469  Float_t hit_width[kMaxHits]; //shape RMS
470  Short_t hit_trkid[kMaxHits]; //is this hit associated with a reco track?
471  Int_t hit_mcid[kMaxHits]; //TrackID of leading MCParticle that created the hit
472  Float_t hit_frac[kMaxHits]; //fraction of hit energy from leading MCParticle
473  Float_t hit_energy[kMaxHits]; //true energy
474  Float_t hit_nelec[kMaxHits]; //true number of electrons (drift attenuated)
475  Float_t hit_reconelec[kMaxHits]; //reco number of electrons (area * CalConstant)
476 
477  // track information
478  Char_t kNTracker;
479  std::vector<TrackDataStruct> TrackData;
480 
481  // vertex information
482  std::vector<VertexDataStruct> VertexData;
483 
484  // shower information
486 
487  // PFParticle information
488  Int_t num_pfps; //number of PFParticles reconstructed
489  Int_t pfp_sliceid[kMaxPFPs]; //id of slice containing each PFP
490  Int_t pfp_pdg[kMaxPFPs]; //PDG code for each PFP
491 
492  // slice information
493  Int_t num_slices; //number of recob::Slices in the event
494  Int_t num_nuslices; //number of slices tagged as a neutrino
495  Int_t best_nuslice_id; //best-matched neutrino slice ID
496  Int_t best_nuslice_pfpid; //best-matched neutrino PFP ID: pfp->Self()
497  Int_t best_nuslice_pdg; //neutrino PDG
498  Int_t best_nuslice_origin; //0=unknown, 1=neutrino, 2=cosmic
499  Float_t best_nuslice_score; //neutrino slice nu-score
500  Float_t best_nuslice_hitcomp; //neutrino slice completeness
501  Float_t best_nuslice_hitpurity; //neutrino slice purity
502  Float_t best_nuslice_lephitcomp; //neutrino slice lepton completeness
503  Float_t best_nuslice_lephitpurity; //neutrino slice lepton purity
504 
505  //mctruth information
506  size_t MaxMCNeutrinos; ///! The number of MCNeutrinos there is currently room for
507  Int_t mcevts_truth; //number of neutrino Int_teractions in the spill
508  std::vector<Int_t> nuScatterCode_truth; //Scattering code given by Genie for each neutrino
509  std::vector<Int_t> nuID_truth; //Unique ID of each true neutrino
510  std::vector<Int_t> nuPDG_truth; //neutrino PDG code
511  std::vector<Int_t> ccnc_truth; //0=CC 1=NC
512  std::vector<Int_t> mode_truth; //0=QE/El, 1=RES, 2=DIS, 3=Coherent production
513  std::vector<Float_t> enu_truth; //true neutrino energy
514  std::vector<Float_t> Q2_truth; //Momentum transfer squared
515  std::vector<Float_t> W_truth; //hadronic invariant mass
516  std::vector<Int_t> hitnuc_truth; //hit nucleon
517  std::vector<Float_t> nuvtxx_truth; //neutrino vertex x
518  std::vector<Float_t> nuvtxy_truth; //neutrino vertex y
519  std::vector<Float_t> nuvtxz_truth; //neutrino vertex z
520  std::vector<Float_t> nu_dcosx_truth; //neutrino dcos x
521  std::vector<Float_t> nu_dcosy_truth; //neutrino dcos y
522  std::vector<Float_t> nu_dcosz_truth; //neutrino dcos z
523  std::vector<Float_t> lep_mom_truth; //lepton momentum
524  std::vector<Float_t> lep_dcosx_truth; //lepton dcos x
525  std::vector<Float_t> lep_dcosy_truth; //lepton dcos y
526  std::vector<Float_t> lep_dcosz_truth; //lepton dcos z
527 
528  //flux information
529  std::vector<Float_t> tpx_flux; //Px of parent particle leaving BNB target
530  std::vector<Float_t> tpy_flux; //Py of parent particle leaving BNB target
531  std::vector<Float_t> tpz_flux; //Pz of parent particle leaving BNB target
532  std::vector<Int_t> tptype_flux; //Type of parent particle leaving BNB target
533 
534  //genie information
535  size_t MaxGeniePrimaries = 0;
537  std::vector<Int_t> genie_primaries_pdg;
538  std::vector<Float_t> genie_Eng;
539  std::vector<Float_t> genie_Px;
540  std::vector<Float_t> genie_Py;
541  std::vector<Float_t> genie_Pz;
542  std::vector<Float_t> genie_P;
543  std::vector<Int_t> genie_status_code;
544  std::vector<Float_t> genie_mass;
545  std::vector<Int_t> genie_trackID;
546  std::vector<Int_t> genie_ND;
547  std::vector<Int_t> genie_mother;
548 
549  //cosmic cry information
550  Int_t mcevts_truthcry; //number of neutrino Int_teractions in the spill
552  std::vector<Int_t> cry_primaries_pdg;
553  std::vector<Float_t> cry_Eng;
554  std::vector<Float_t> cry_Px;
555  std::vector<Float_t> cry_Py;
556  std::vector<Float_t> cry_Pz;
557  std::vector<Float_t> cry_P;
558  std::vector<Float_t> cry_StartPointx;
559  std::vector<Float_t> cry_StartPointy;
560  std::vector<Float_t> cry_StartPointz;
561  std::vector<Int_t> cry_status_code;
562  std::vector<Float_t> cry_mass;
563  std::vector<Int_t> cry_trackID;
564  std::vector<Int_t> cry_ND;
565  std::vector<Int_t> cry_mother;
566 
567  //geant information
568  size_t MaxGEANTparticles = 0; ///! how many particles there is currently room for
569  Int_t no_primaries; //number of primary geant particles
570  Int_t geant_list_size; //number of all geant particles
572  std::vector<Int_t> pdg;
573  std::vector<Int_t> status;
574  std::vector<Float_t> Eng;
575  std::vector<Float_t> EndE;
576  std::vector<Float_t> Mass;
577  std::vector<Float_t> Px;
578  std::vector<Float_t> Py;
579  std::vector<Float_t> Pz;
580  std::vector<Float_t> P;
581  std::vector<Float_t> StartPointx;
582  std::vector<Float_t> StartPointy;
583  std::vector<Float_t> StartPointz;
584  std::vector<Float_t> StartT;
585  std::vector<Float_t> EndT;
586  std::vector<Float_t> EndPointx;
587  std::vector<Float_t> EndPointy;
588  std::vector<Float_t> EndPointz;
589  std::vector<Float_t> theta;
590  std::vector<Float_t> phi;
591  std::vector<Float_t> theta_xz;
592  std::vector<Float_t> theta_yz;
593  std::vector<Float_t> pathlen;
594  std::vector<Int_t> inTPCActive;
595  std::vector<Float_t> StartPointx_tpcAV;
596  std::vector<Float_t> StartPointy_tpcAV;
597  std::vector<Float_t> StartPointz_tpcAV;
598  std::vector<Float_t> EndPointx_tpcAV;
599  std::vector<Float_t> EndPointy_tpcAV;
600  std::vector<Float_t> EndPointz_tpcAV;
601  std::vector<Int_t> NumberDaughters;
602  std::vector<Int_t> TrackId;
603  std::vector<Int_t> Mother;
604  std::vector<Int_t> process_primary;
605  std::vector<std::string> processname;
606  std::vector<Int_t> MergedId; //geant track segments, which belong to the same particle, get the same
607  std::vector<Int_t> MotherNuId; //The unique ID of the mother neutrino
608  std::vector<Float_t> DepEnergy; //energy deposited by this particle in AV (based on sim::IDEs)
609  std::vector<Float_t> NumElectrons; //ionization electrons reaching anode for this particle
610 
611  // Total visible energy/electrons deposited in the AV for all particles
614 
615  // Auxiliary detector variables saved for each geant track
616  // This data is saved as a vector (one item per GEANT particle) of C arrays
617  // (wrapped in a BoxedArray for technical reasons), one item for each
618  // affected detector cell (which one is saved in AuxDetID
619  template <typename T>
620  using AuxDetMCData_t = std::vector<BoxedArray<T[kMaxAuxDets]>>;
621 
622  std::vector<UShort_t> NAuxDets; ///< Number of AuxDets crossed by this particle
623  AuxDetMCData_t<Short_t> AuxDetID; ///< Which AuxDet this particle went through
624  AuxDetMCData_t<Float_t> entryX; ///< Entry X position of particle into AuxDet
625  AuxDetMCData_t<Float_t> entryY; ///< Entry Y position of particle into AuxDet
626  AuxDetMCData_t<Float_t> entryZ; ///< Entry Z position of particle into AuxDet
627  AuxDetMCData_t<Float_t> entryT; ///< Entry T position of particle into AuxDet
628  AuxDetMCData_t<Float_t> exitX; ///< Exit X position of particle out of AuxDet
629  AuxDetMCData_t<Float_t> exitY; ///< Exit Y position of particle out of AuxDet
630  AuxDetMCData_t<Float_t> exitZ; ///< Exit Z position of particle out of AuxDet
631  AuxDetMCData_t<Float_t> exitT; ///< Exit T position of particle out of AuxDet
632  AuxDetMCData_t<Float_t> exitPx; ///< Exit x momentum of particle out of AuxDet
633  AuxDetMCData_t<Float_t> exitPy; ///< Exit y momentum of particle out of AuxDet
634  AuxDetMCData_t<Float_t> exitPz; ///< Exit z momentum of particle out of AuxDet
635  AuxDetMCData_t<Float_t> CombinedEnergyDep; ///< Sum energy of all particles with this trackID (+ID or -ID) in AuxDet
636 
637  unsigned int bits; ///< complementary information
638 
639  /// Returns whether we have auxiliary detector data
640  bool hasAuxDetector() const { return bits & tdAuxDet; }
641 
642  /// Returns whether we have Cry data
643  bool hasCryInfo() const { return bits & tdCry; }
644 
645  /// Returns whether we have Genie data
646  bool hasGenieInfo() const { return bits & tdGenie; }
647 
648  /// Returns whether we have Hit data
649  bool hasHitInfo() const { return bits & tdHit; }
650 
651  /// Returns whether we have Track data
652  bool hasTrackInfo() const { return bits & tdTrack; }
653 
654  /// Returns whether we have Shower data
655  bool hasShowerInfo() const { return bits & tdShower; }
656 
657  /// Returns whether we have Slice data
658  bool hasSliceInfo() const { return bits & tdSlice; }
659 
660  /// Returns whether we have Vertex data
661  bool hasVertexInfo() const { return bits & tdVtx; }
662 
663  /// Returns whether we have Geant data
664  bool hasGeantInfo() const { return bits & tdGeant; }
665 
666  /// Sets the specified bits
667  void SetBits(unsigned int setbits, bool unset = false)
668  { if (unset) bits &= ~setbits; else bits |= setbits; }
669 
670  /// Constructor; clears all fields
671  AnalysisTreeDataStruct(size_t nTrackers = 0): bits(tdDefault)
672  { SetTrackers(nTrackers); SetVertices(nTrackers); Clear(); }
673 
674  TrackDataStruct& GetTrackerData(size_t iTracker)
675  { return TrackData.at(iTracker); }
676  const TrackDataStruct& GetTrackerData(size_t iTracker) const
677  { return TrackData.at(iTracker); }
678 
679  VertexDataStruct& GetVertexData(size_t iTracker)
680  { return VertexData.at(iTracker); }
681 
683  { return ShowerData; }
684 
685  /// Clear all fields if this object (not the tracker algorithm data)
686  void ClearLocalData();
687 
688  /// Clear all fields
689  void Clear();
690 
691  /// Allocates data structures for the given number of trackers (no Clear())
692  void SetTrackers(size_t nTrackers) { TrackData.resize(nTrackers); }
693 
694  /// Allocates data structures for the given number of trackers (no Clear())
695  void SetVertices(size_t nTrackers) { VertexData.resize(nTrackers); }
696 
697  /// Resize the data structure for MCNeutrino particles
698  void ResizeMCNeutrino(int nNeutrinos);
699 
700  /// Resize the data strutcure for GEANT particles
701  void ResizeGEANT(int nParticles);
702 
703  /// Resize the data strutcure for Genie primaries
704  void ResizeGenie(int nPrimaries);
705 
706  /// Resize the data strutcure for Cry primaries
707  void ResizeCry(int nPrimaries);
708 
709  /// Connect this object with a tree
710  void SetAddresses(TTree* pTree, const std::vector<std::string>& trackers, std::string showerLabel, const std::vector< std::string> &vertexLabels, bool isCosmics, const std::vector<bool>& saveHierarchyInfo, bool saveShowerHierarchyInfo);
711 
712  /// Connect this object with a tree
713  void SetShowerAddresses(TTree* pTree, std::string showerLabel, bool saveHierarchyInfo);
714 
715  /// Returns the number of trackers for which data structures are allocated
716  size_t GetNTrackers() const { return TrackData.size(); }
717 
718  /// Returns the number of hits for which memory is allocated
719  size_t GetMaxHits() const { return kMaxHits; }
720 
721  /// Returns the number of trackers for which memory is allocated
722  size_t GetMaxTrackers() const { return TrackData.capacity(); }
723 
724  /// Returns the number of GEANT particles for which memory is allocated
725  size_t GetMaxGEANTparticles() const { return MaxGEANTparticles; }
726 
727  /// Returns the number of GENIE primaries for which memory is allocated
728  size_t GetMaxGeniePrimaries() const { return MaxGeniePrimaries; }
729 
730 
731  private:
732  /// Little helper functor class to create or reset branches in a tree
734  public:
735  TTree* pTree; ///< the tree to be worked on
736  BranchCreator(TTree* tree): pTree(tree) {}
737 
738  //@{
739  /// Create a branch if it does not exist, and set its address
740  void operator()
741  (std::string name, void* address, std::string leaflist /*, int bufsize = 32000 */)
742  {
743  if (!pTree) return;
744  TBranch* pBranch = pTree->GetBranch(name.c_str());
745  if (!pBranch) {
746  pTree->Branch(name.c_str(), address, leaflist.c_str() /*, bufsize */);
747  MF_LOG_DEBUG("AnalysisTreeStructure")
748  << "Creating branch '" << name << " with leaf '" << leaflist << "'";
749  }
750  else if (pBranch->GetAddress() != address) {
751  pBranch->SetAddress(address);
752  MF_LOG_DEBUG("AnalysisTreeStructure")
753  << "Reassigning address to branch '" << name << "'";
754  }
755  else {
756  MF_LOG_DEBUG("AnalysisTreeStructure")
757  << "Branch '" << name << "' is fine";
758  }
759  } // operator()
760  void operator()
761  (std::string name, void* address, const std::stringstream& leaflist /*, int bufsize = 32000 */)
762  { return this->operator() (name, address, leaflist.str() /*, int bufsize = 32000 */); }
763  template <typename T>
764  void operator()
765  (std::string name, std::vector<T>& data, std::string leaflist /*, int bufsize = 32000 */)
766  { return this->operator() (name, (void*) data.data(), leaflist /*, int bufsize = 32000 */); }
767 
768  template <typename T>
769  void operator() (std::string name, std::vector<T>& data)
770  {
771  // overload for a generic object expressed directly by reference
772  // (as opposed to a generic object expressed by a pointer or
773  // to a simple leaf sequence specification);
774  // TTree::Branch(name, T* obj, Int_t bufsize, splitlevel) and
775  // TTree::SetObject() are used.
776  if (!pTree) return;
777  TBranch* pBranch = pTree->GetBranch(name.c_str());
778  if (!pBranch) {
779  pTree->Branch(name.c_str(), &data);
780  // ROOT needs a TClass definition for T in order to create a branch,
781  // se we are sure that at this point the TClass exists
782  MF_LOG_DEBUG("AnalysisTreeStructure")
783  << "Creating object branch '" << name
784  << " with " << TClass::GetClass(typeid(T))->ClassName();
785  }
786  else if
787  (*(reinterpret_cast<std::vector<T>**>(pBranch->GetAddress())) != &data)
788  {
789  // when an object is provided directly, the address of the object
790  // is assigned in TBranchElement::fObject (via TObject::SetObject())
791  // and the address itself is set to the address of the fObject
792  // member. Here we check that the address of the object in fObject
793  // is the same as the address of our current data type
794  pBranch->SetObject(&data);
795  MF_LOG_DEBUG("AnalysisTreeStructure")
796  << "Reassigning object to branch '" << name << "'";
797  }
798  else {
799  MF_LOG_DEBUG("AnalysisTreeStructure")
800  << "Branch '" << name << "' is fine";
801  }
802  } // operator()
803  //@}
804  }; // class BranchCreator
805 
806  }; // class AnalysisTreeDataStruct
807 
808 
809  /**
810  * @brief Creates a simple ROOT tree with tracking and calorimetry information
811  *
812  * <h2>Configuration parameters</h2>
813  * - <b>UseBuffers</b> (default: false): if enabled, memory is allocated for
814  * tree data for all the run; otherwise, it's allocated on each event, used
815  * and freed; use "true" for speed, "false" to save memory
816  * - <b>SaveAuxDetInfo</b> (default: false): if enabled, auxiliary detector
817  * data will be extracted and included in the tree
818  */
819  class AnalysisTree : public art::EDAnalyzer {
820 
821  public:
822 
823  explicit AnalysisTree(fhicl::ParameterSet const& pset);
824  virtual ~AnalysisTree();
825 
826  /// read access to event
827  void analyze(const art::Event& evt);
828  // void beginJob() {}
829  void beginSubRun(const art::SubRun& sr);
830 
831  private:
832 
833  void HitsPurity(detinfo::DetectorClocksData const& clockData,
834  std::vector< art::Ptr<recob::Hit> > const& hits, Int_t& trackid, Float_t& purity, double& maxe);
835  void HitTruth(detinfo::DetectorClocksData const& clockData, art::Ptr<recob::Hit> const& hit,
836  Int_t& truthid, Float_t& frac, Float_t& energy, Float_t& numElectrons);
837  bool HitTruthId( detinfo::DetectorClocksData const& clockData, art::Ptr<recob::Hit> const& hit, Int_t& mcid);
838  bool TrackIdToMCTruth( Int_t const trkID, art::Ptr<simb::MCTruth>& mctruth );
839  bool DoesHitHaveSimChannel( std::vector<const sim::SimChannel*> chans, art::Ptr<recob::Hit> const& hit);
840  double length(const recob::Track& track);
841  double length(const simb::MCParticle& part, TVector3& start, TVector3& end);
842  double bdist(const recob::Track::Point_t& pos);
843 
844  TTree* fTree;
845 
846  // event information is huge and dynamic;
847  // run information is much smaller and we still store it statically
848  // in the event
850 // AnalysisTreeDataStruct::RunData_t RunData;
852 
853 
854  std::string fDigitModuleLabel;
855  std::string fHitsModuleLabel;
856  std::string fLArG4ModuleLabel;
858  std::string fCalDataModuleLabel;
859  std::string fGenieGenModuleLabel;
860  std::string fCryGenModuleLabel;
861  std::string fG4ModuleLabel;
863  std::string fShowerModuleLabel;
864  std::vector<std::string> fVertexModuleLabel;
865  std::vector<std::string> fTrackModuleLabel;
866  std::vector<std::string> fCalorimetryModuleLabel;
867  std::vector<std::string> fParticleIDModuleLabel;
868  std::string fPOTModuleLabel;
869  bool fUseBuffer; ///< whether to use a permanent buffer (faster, huge memory)
870  bool fSaveAuxDetInfo; ///< whether to extract and save auxiliary detector data
871  bool fSaveCryInfo; ///whether to extract and save CRY particle data
872  bool fSaveGenieInfo; ///whether to extract and save Genie information
873  bool fSaveGeantInfo; ///whether to extract and save Geant information
874  bool fSaveHitInfo; ///whether to extract and save Hit information
875  bool fSaveTrackInfo; ///whether to extract and save Track information
876  bool fSaveShowerInfo; ///whether to extract and save Shower information
877  bool fSaveVertexInfo; ///whether to extract and save Vertex information
878  bool fSaveSliceInfo; ///whether to extract and save Slice information
879  std::vector<bool> fSaveHierarchyInfo; ///< if the user wants to access the tracks with their hierarchy for each tracker
880  bool fSaveShowerHierarchyInfo; ///< if the user wants to access the showers with their hierarchy
881 
882  std::vector<std::string> fCosmicTaggerAssocLabel;
883  std::vector<std::string> fFlashMatchAssocLabel;
884 
885  bool isCosmics; ///< if it contains cosmics
886  bool fSaveCaloCosmics; ///< save calorimetry information for cosmics
887  float fG4minE; ///< Energy threshold to save g4 particle info
888 
890 
891  // ParticleInventoryService
892  art::ServiceHandle<cheat::ParticleInventoryService> pi_serv;
893 
894  // BackTrackerService
895  art::ServiceHandle<cheat::BackTrackerService> bt_serv;
896 
897  /// Returns the number of trackers configured
898  size_t GetNTrackers() const { return fTrackModuleLabel.size(); }
899 
900  /// Creates the structure for the tree data; optionally initializes it
901  void CreateData(bool bClearData = false)
902  {
903  if (!fData) {
909  }
910  else {
918  if (bClearData) fData->Clear();
919  }
920  } // CreateData()
921 
922  /// Sets the addresses of all the tree branches, creating the missing ones
924  {
925  CheckData("SetAddress()"); CheckTree("SetAddress()");
927  } // SetAddresses()
928 
929  /// Sets the addresses of all the tree branches of the specified tracking algo,
930  /// creating the missing ones
931  void SetTrackerAddresses(size_t iTracker)
932  {
933  CheckData("SetTrackerAddresses()"); CheckTree("SetTrackerAddresses()");
934  if (iTracker >= fData->GetNTrackers()) {
935  throw art::Exception(art::errors::LogicError)
936  << "AnalysisTree::SetTrackerAddresses(): no tracker #" << iTracker
937  << " (" << fData->GetNTrackers() << " available)";
938  }
939  fData->GetTrackerData(iTracker) \
941  } // SetTrackerAddresses()
942 
943  void SetVerticesAddresses(size_t iTracker)
944  {
945  CheckData("SetVerticesAddresses()"); CheckTree("SetVerticesAddresses()");
946  if (iTracker >= fData->GetNTrackers()) {
947  throw art::Exception(art::errors::LogicError)
948  << "AnalysisTree::SetVerticesAddresses(): no tracker #" << iTracker
949  << " (" << fData->GetNTrackers() << " available)";
950  }
951  fData->GetVertexData(iTracker) \
953  } // SetVerticesAddresses()
954 
955  /// Sets the addresses of all the tree branches, creating the missing ones
957  {
958  CheckData("SetShowerAddress()"); CheckTree("SetShowerAddress()");
960  } // SetShowerAddresses()
961 
962  /// Create the output tree and the data structures, if needed
963  void CreateTree(bool bClearData = false);
964 
965  /// Destroy the local buffers (existing branches will point to invalid address!)
966  void DestroyData() { if (fData) { delete fData; fData = nullptr; } }
967 
968  /// Helper function: throws if no data structure is available
969  void CheckData(std::string caller) const
970  {
971  if (fData) return;
972  throw art::Exception(art::errors::LogicError)
973  << "AnalysisTree::" << caller << ": no data";
974  } // CheckData()
975  /// Helper function: throws if no tree is available
976  void CheckTree(std::string caller) const
977  {
978  if (fTree) return;
979  throw art::Exception(art::errors::LogicError)
980  << "AnalysisTree::" << caller << ": no tree";
981  } // CheckData()
982  }; // class sbnd::AnalysisTree
983 } // namespace sbnd
984 
985 
986 namespace { // local namespace
987  /// Simple stringstream which empties its buffer on operator() call
988  class AutoResettingStringSteam: public std::ostringstream {
989  public:
990  AutoResettingStringSteam& operator() () { str(""); return *this; }
991  }; // class AutoResettingStringSteam
992 
993  /// Fills a sequence of TYPE elements
994  template <typename ITER, typename TYPE>
995  inline void FillWith(ITER from, ITER to, TYPE value)
996  { std::fill(from, to, value); }
997 
998  /// Fills a sequence of TYPE elements
999  template <typename ITER, typename TYPE>
1000  inline void FillWith(ITER from, size_t n, TYPE value)
1001  { std::fill(from, from + n, value); }
1002 
1003  /// Fills a container with begin()/end() interface
1004  template <typename CONT, typename V>
1005  inline void FillWith(CONT& data, const V& value)
1006  { FillWith(std::begin(data), std::end(data), value); }
1007 
1008 } // local namespace
1009 
1010 
1011 //------------------------------------------------------------------------------
1012 //--- AnalysisTreeDataStruct::TrackDataStruct
1013 //---
1014 
1016 {
1017  MaxTracks = nTracks;
1018 
1019  trkId.resize(MaxTracks);
1026  trkstartx.resize(MaxTracks);
1027  trkstarty.resize(MaxTracks);
1028  trkstartz.resize(MaxTracks);
1029  trkstartd.resize(MaxTracks);
1030  trkendx.resize(MaxTracks);
1031  trkendy.resize(MaxTracks);
1032  trkendz.resize(MaxTracks);
1033  trkendd.resize(MaxTracks);
1034  trktheta.resize(MaxTracks);
1035  trkphi.resize(MaxTracks);
1036  trkstartdcosx.resize(MaxTracks);
1037  trkstartdcosy.resize(MaxTracks);
1038  trkstartdcosz.resize(MaxTracks);
1039  trkenddcosx.resize(MaxTracks);
1040  trkenddcosy.resize(MaxTracks);
1041  trkenddcosz.resize(MaxTracks);
1042  trkthetaxz.resize(MaxTracks);
1043  trkthetayz.resize(MaxTracks);
1044  trkmom.resize(MaxTracks);
1045  trkmomrange.resize(MaxTracks);
1046  trkmommschi2.resize(MaxTracks);
1047  trkmommsllhd.resize(MaxTracks);
1048  trklen.resize(MaxTracks);
1049  trksvtxid.resize(MaxTracks);
1050  trkevtxid.resize(MaxTracks);
1051  // PID variables
1052  trkpidpdg.resize(MaxTracks);
1053  trkpidchi.resize(MaxTracks);
1054  trkpidchipr.resize(MaxTracks);
1055  trkpidchika.resize(MaxTracks);
1056  trkpidchipi.resize(MaxTracks);
1057  trkpidchimu.resize(MaxTracks);
1058  trkpidpida.resize(MaxTracks);
1059  trkpidbestplane.resize(MaxTracks);
1060 
1061  trkke.resize(MaxTracks);
1062  trkrange.resize(MaxTracks);
1066  trkidtruth.resize(MaxTracks);
1067  trkorigin.resize(MaxTracks);
1068  trkpdgtruth.resize(MaxTracks);
1069  trkefftruth.resize(MaxTracks);
1071  trksimIDExtruth.resize(MaxTracks);
1072  trksimIDEytruth.resize(MaxTracks);
1073  trksimIDEztruth.resize(MaxTracks);
1074  trkpurtruth.resize(MaxTracks);
1075  trkpitchc.resize(MaxTracks);
1076  ntrkhits.resize(MaxTracks);
1077 
1078  trkisprimary.resize(MaxTracks);
1079  trkndaughters.resize(MaxTracks);
1080  trkpfpid.resize(MaxTracks);
1081  trkparentpfpid.resize(MaxTracks);
1082 
1083  trkdedx.resize(MaxTracks);
1084  trkdqdx.resize(MaxTracks);
1085  trkresrg.resize(MaxTracks);
1086  trkxyz.resize(MaxTracks);
1087 
1088 } // sbnd::AnalysisTreeDataStruct::TrackDataStruct::Resize()
1089 
1091  Resize(MaxTracks);
1092  ntracks = 0;
1093 
1094  FillWith(trkId , -9999 );
1095  FillWith(trkncosmictags_tagger, -9999 );
1096  FillWith(trkcosmicscore_tagger, -99999.);
1097  FillWith(trkcosmictype_tagger, -9999 );
1098  FillWith(trkncosmictags_flashmatch, -9999 );
1099  FillWith(trkcosmicscore_flashmatch, -99999.);
1100  FillWith(trkcosmictype_flashmatch, -9999 );
1101  FillWith(trkstartx , -99999.);
1102  FillWith(trkstarty , -99999.);
1103  FillWith(trkstartz , -99999.);
1104  FillWith(trkstartd , -99999.);
1105  FillWith(trkendx , -99999.);
1106  FillWith(trkendy , -99999.);
1107  FillWith(trkendz , -99999.);
1108  FillWith(trkendd , -99999.);
1109  FillWith(trktheta , -99999.);
1110  FillWith(trkphi , -99999.);
1111  FillWith(trkstartdcosx, -99999.);
1112  FillWith(trkstartdcosy, -99999.);
1113  FillWith(trkstartdcosz, -99999.);
1114  FillWith(trkenddcosx , -99999.);
1115  FillWith(trkenddcosy , -99999.);
1116  FillWith(trkenddcosz , -99999.);
1117  FillWith(trkthetaxz , -99999.);
1118  FillWith(trkthetayz , -99999.);
1119  FillWith(trkmom , -99999.);
1120  FillWith(trkmomrange , -99999.);
1121  FillWith(trkmommschi2 , -99999.);
1122  FillWith(trkmommsllhd , -99999.);
1123  FillWith(trklen , -99999.);
1124  FillWith(trksvtxid , -1);
1125  FillWith(trkevtxid , -1);
1126  FillWith(trkpidbestplane, -1);
1127  FillWith(trkisprimary, -9999);
1128  FillWith(trkndaughters, -9999);
1129  FillWith(trkpfpid, -9999);
1130  FillWith(trkparentpfpid, -9999);
1131 
1132 
1133  for (size_t iTrk = 0; iTrk < MaxTracks; ++iTrk){
1134 
1135  // the following are BoxedArray's;
1136  // their iterators traverse all the array dimensions
1137  FillWith(trkke[iTrk] , -99999.);
1138  FillWith(trkrange[iTrk] , -99999.);
1139  FillWith(trkidtruth_recoutils_totaltrueenergy[iTrk] , -99999 );
1140  FillWith(trkidtruth_recoutils_totalrecocharge[iTrk] , -99999 );
1141  FillWith(trkidtruth_recoutils_totalrecohits[iTrk] , -99999 );
1142  FillWith(trkidtruth[iTrk] , -99999 );
1143  FillWith(trkorigin[iTrk] , -1 );
1144  FillWith(trkpdgtruth[iTrk], -99999 );
1145  FillWith(trkefftruth[iTrk], -99999.);
1146  FillWith(trksimIDEenergytruth[iTrk], -99999.);
1147  FillWith(trksimIDExtruth[iTrk], -99999.);
1148  FillWith(trksimIDEytruth[iTrk], -99999.);
1149  FillWith(trksimIDEztruth[iTrk], -99999.);
1150  FillWith(trkpurtruth[iTrk], -99999.);
1151  FillWith(trkpitchc[iTrk] , -99999.);
1152  FillWith(ntrkhits[iTrk] , -9999 );
1153 
1154  FillWith(trkdedx[iTrk], 0.);
1155  FillWith(trkdqdx[iTrk], 0.);
1156  FillWith(trkresrg[iTrk], 0.);
1157 
1158  FillWith(trkxyz[iTrk], 0.);
1159 
1160  FillWith(trkpidpdg[iTrk] , -1);
1161  FillWith(trkpidchi[iTrk] , -99999.);
1162  FillWith(trkpidchipr[iTrk] , -99999.);
1163  FillWith(trkpidchika[iTrk] , -99999.);
1164  FillWith(trkpidchipi[iTrk] , -99999.);
1165  FillWith(trkpidchimu[iTrk] , -99999.);
1166  FillWith(trkpidpida[iTrk] , -99999.);
1167 
1168  } // for track
1169 
1170 } // sbnd::AnalysisTreeDataStruct::TrackDataStruct::Clear()
1171 
1172 
1174  TTree* pTree, std::string tracker, bool isCosmics, bool saveHierarchyInfo
1175 ) {
1176  if (MaxTracks == 0) return; // no tracks, no tree!
1177 
1178  sbnd::AnalysisTreeDataStruct::BranchCreator CreateBranch(pTree);
1179 
1180  AutoResettingStringSteam sstr;
1181  sstr() << kMaxTrackHits;
1182  std::string MaxTrackHitsIndexStr("[" + sstr.str() + "]");
1183 
1184  std::string TrackLabel = tracker;
1185  std::string BranchName;
1186 
1187  BranchName = "ntracks_" + TrackLabel;
1188  CreateBranch(BranchName, &ntracks, BranchName + "/S");
1189  std::string NTracksIndexStr = "[" + BranchName + "]";
1190 
1191  BranchName = "trkId_" + TrackLabel;
1192  CreateBranch(BranchName, trkId, BranchName + NTracksIndexStr + "/S");
1193 
1194  BranchName = "trkncosmictags_tagger_" + TrackLabel;
1195  CreateBranch(BranchName, trkncosmictags_tagger, BranchName + NTracksIndexStr + "/S");
1196 
1197  BranchName = "trkcosmicscore_tagger_" + TrackLabel;
1198  CreateBranch(BranchName, trkcosmicscore_tagger, BranchName + NTracksIndexStr + "/F");
1199 
1200  BranchName = "trkcosmictype_tagger_" + TrackLabel;
1201  CreateBranch(BranchName, trkcosmictype_tagger, BranchName + NTracksIndexStr + "/S");
1202 
1203  BranchName = "trkncosmictags_flashmatch_" + TrackLabel;
1204  CreateBranch(BranchName, trkncosmictags_flashmatch, BranchName + NTracksIndexStr + "/S");
1205 
1206  BranchName = "trkcosmicscore_flashmatch_" + TrackLabel;
1207  CreateBranch(BranchName, trkcosmicscore_flashmatch, BranchName + NTracksIndexStr + "/F");
1208 
1209  BranchName = "trkcosmictype_flashmatch_" + TrackLabel;
1210  CreateBranch(BranchName, trkcosmictype_flashmatch, BranchName + NTracksIndexStr + "/S");
1211 
1212  BranchName = "trkke_" + TrackLabel;
1213  CreateBranch(BranchName, trkke, BranchName + NTracksIndexStr + "[3]/F");
1214 
1215  BranchName = "trkrange_" + TrackLabel;
1216  CreateBranch(BranchName, trkrange, BranchName + NTracksIndexStr + "[3]/F");
1217 
1218  BranchName = "trkidtruth_recoutils_totaltrueenergy_" + TrackLabel;
1219  CreateBranch(BranchName, trkidtruth_recoutils_totaltrueenergy, BranchName + NTracksIndexStr + "[3]/I");
1220 
1221  BranchName = "trkidtruth_recoutils_totalrecocharge_" + TrackLabel;
1222  CreateBranch(BranchName, trkidtruth_recoutils_totalrecocharge, BranchName + NTracksIndexStr + "[3]/I");
1223 
1224  BranchName = "trkidtruth_recoutils_totalrecohits_" + TrackLabel;
1225  CreateBranch(BranchName, trkidtruth_recoutils_totalrecohits, BranchName + NTracksIndexStr + "[3]/I");
1226 
1227  BranchName = "trkidtruth_" + TrackLabel;
1228  CreateBranch(BranchName, trkidtruth, BranchName + NTracksIndexStr + "[3]/I");
1229 
1230  BranchName = "trkorigin_" + TrackLabel;
1231  CreateBranch(BranchName, trkorigin, BranchName + NTracksIndexStr + "[3]/S");
1232 
1233  BranchName = "trkpdgtruth_" + TrackLabel;
1234  CreateBranch(BranchName, trkpdgtruth, BranchName + NTracksIndexStr + "[3]/I");
1235 
1236  BranchName = "trkefftruth_" + TrackLabel;
1237  CreateBranch(BranchName, trkefftruth, BranchName + NTracksIndexStr + "[3]/F");
1238 
1239  BranchName = "trksimIDEenergytruth_" + TrackLabel;
1240  CreateBranch(BranchName, trksimIDEenergytruth, BranchName + NTracksIndexStr + "[3]/F");
1241 
1242  BranchName = "trksimIDExtruth_" + TrackLabel;
1243  CreateBranch(BranchName, trksimIDExtruth, BranchName + NTracksIndexStr + "[3]/F");
1244 
1245  BranchName = "trksimIDEytruth_" + TrackLabel;
1246  CreateBranch(BranchName, trksimIDEytruth, BranchName + NTracksIndexStr + "[3]/F");
1247 
1248  BranchName = "trksimIDEztruth_" + TrackLabel;
1249  CreateBranch(BranchName, trksimIDEztruth, BranchName + NTracksIndexStr + "[3]/F");
1250 
1251  BranchName = "trkpurtruth_" + TrackLabel;
1252  CreateBranch(BranchName, trkpurtruth, BranchName + NTracksIndexStr + "[3]/F");
1253 
1254  BranchName = "trkpitchc_" + TrackLabel;
1255  CreateBranch(BranchName, trkpitchc, BranchName + NTracksIndexStr + "[3]/F");
1256 
1257  BranchName = "ntrkhits_" + TrackLabel;
1258  CreateBranch(BranchName, ntrkhits, BranchName + NTracksIndexStr + "[3]/S");
1259 
1260  if (!isCosmics){
1261  BranchName = "trkdedx_" + TrackLabel;
1262  CreateBranch(BranchName, trkdedx, BranchName + NTracksIndexStr + "[3]" + MaxTrackHitsIndexStr + "/F");
1263 
1264  BranchName = "trkdqdx_" + TrackLabel;
1265  CreateBranch(BranchName, trkdqdx, BranchName + NTracksIndexStr + "[3]" + MaxTrackHitsIndexStr + "/F");
1266 
1267  BranchName = "trkresrg_" + TrackLabel;
1268  CreateBranch(BranchName, trkresrg, BranchName + NTracksIndexStr + "[3]" + MaxTrackHitsIndexStr + "/F");
1269 
1270  BranchName = "trkxyz_" + TrackLabel;
1271  CreateBranch(BranchName, trkxyz, BranchName + NTracksIndexStr + "[3]" + MaxTrackHitsIndexStr + "/F");
1272  }
1273 
1274  BranchName = "trkstartx_" + TrackLabel;
1275  CreateBranch(BranchName, trkstartx, BranchName + NTracksIndexStr + "/F");
1276 
1277  BranchName = "trkstarty_" + TrackLabel;
1278  CreateBranch(BranchName, trkstarty, BranchName + NTracksIndexStr + "/F");
1279 
1280  BranchName = "trkstartz_" + TrackLabel;
1281  CreateBranch(BranchName, trkstartz, BranchName + NTracksIndexStr + "/F");
1282 
1283  BranchName = "trkstartd_" + TrackLabel;
1284  CreateBranch(BranchName, trkstartd, BranchName + NTracksIndexStr + "/F");
1285 
1286  BranchName = "trkendx_" + TrackLabel;
1287  CreateBranch(BranchName, trkendx, BranchName + NTracksIndexStr + "/F");
1288 
1289  BranchName = "trkendy_" + TrackLabel;
1290  CreateBranch(BranchName, trkendy, BranchName + NTracksIndexStr + "/F");
1291 
1292  BranchName = "trkendz_" + TrackLabel;
1293  CreateBranch(BranchName, trkendz, BranchName + NTracksIndexStr + "/F");
1294 
1295  BranchName = "trkendd_" + TrackLabel;
1296  CreateBranch(BranchName, trkendd, BranchName + NTracksIndexStr + "/F");
1297 
1298  BranchName = "trktheta_" + TrackLabel;
1299  CreateBranch(BranchName, trktheta, BranchName + NTracksIndexStr + "/F");
1300 
1301  BranchName = "trkphi_" + TrackLabel;
1302  CreateBranch(BranchName, trkphi, BranchName + NTracksIndexStr + "/F");
1303 
1304  BranchName = "trkstartdcosx_" + TrackLabel;
1305  CreateBranch(BranchName, trkstartdcosx, BranchName + NTracksIndexStr + "/F");
1306 
1307  BranchName = "trkstartdcosy_" + TrackLabel;
1308  CreateBranch(BranchName, trkstartdcosy, BranchName + NTracksIndexStr + "/F");
1309 
1310  BranchName = "trkstartdcosz_" + TrackLabel;
1311  CreateBranch(BranchName, trkstartdcosz, BranchName + NTracksIndexStr + "/F");
1312 
1313  BranchName = "trkenddcosx_" + TrackLabel;
1314  CreateBranch(BranchName, trkenddcosx, BranchName + NTracksIndexStr + "/F");
1315 
1316  BranchName = "trkenddcosy_" + TrackLabel;
1317  CreateBranch(BranchName, trkenddcosy, BranchName + NTracksIndexStr + "/F");
1318 
1319  BranchName = "trkenddcosz_" + TrackLabel;
1320  CreateBranch(BranchName, trkenddcosz, BranchName + NTracksIndexStr + "/F");
1321 
1322  BranchName = "trkthetaxz_" + TrackLabel;
1323  CreateBranch(BranchName, trkthetaxz, BranchName + NTracksIndexStr + "/F");
1324 
1325  BranchName = "trkthetayz_" + TrackLabel;
1326  CreateBranch(BranchName, trkthetayz, BranchName + NTracksIndexStr + "/F");
1327 
1328  BranchName = "trkmom_" + TrackLabel;
1329  CreateBranch(BranchName, trkmom, BranchName + NTracksIndexStr + "/F");
1330 
1331  BranchName = "trkmomrange_" + TrackLabel;
1332  CreateBranch(BranchName, trkmomrange, BranchName + NTracksIndexStr + "/F");
1333 
1334  BranchName = "trkmommschi2_" + TrackLabel;
1335  CreateBranch(BranchName, trkmommschi2, BranchName + NTracksIndexStr + "/F");
1336 
1337  BranchName = "trkmommsllhd_" + TrackLabel;
1338  CreateBranch(BranchName, trkmommsllhd, BranchName + NTracksIndexStr + "/F");
1339 
1340  BranchName = "trklen_" + TrackLabel;
1341  CreateBranch(BranchName, trklen, BranchName + NTracksIndexStr + "/F");
1342 
1343  BranchName = "trksvtxid_" + TrackLabel;
1344  CreateBranch(BranchName, trksvtxid, BranchName + NTracksIndexStr + "/S");
1345 
1346  BranchName = "trkevtxid_" + TrackLabel;
1347  CreateBranch(BranchName, trkevtxid, BranchName + NTracksIndexStr + "/S");
1348 
1349  BranchName = "trkpidpdg_" + TrackLabel;
1350  CreateBranch(BranchName, trkpidpdg, BranchName + NTracksIndexStr + "[3]/I");
1351 
1352  BranchName = "trkpidchi_" + TrackLabel;
1353  CreateBranch(BranchName, trkpidchi, BranchName + NTracksIndexStr + "[3]/F");
1354 
1355  BranchName = "trkpidchipr_" + TrackLabel;
1356  CreateBranch(BranchName, trkpidchipr, BranchName + NTracksIndexStr + "[3]/F");
1357 
1358  BranchName = "trkpidchika_" + TrackLabel;
1359  CreateBranch(BranchName, trkpidchika, BranchName + NTracksIndexStr + "[3]/F");
1360 
1361  BranchName = "trkpidchipi_" + TrackLabel;
1362  CreateBranch(BranchName, trkpidchipi, BranchName + NTracksIndexStr + "[3]/F");
1363 
1364  BranchName = "trkpidchimu_" + TrackLabel;
1365  CreateBranch(BranchName, trkpidchimu, BranchName + NTracksIndexStr + "[3]/F");
1366 
1367  BranchName = "trkpidpida_" + TrackLabel;
1368  CreateBranch(BranchName, trkpidpida, BranchName + NTracksIndexStr + "[3]/F");
1369 
1370  BranchName = "trkpidbestplane_" + TrackLabel;
1371  CreateBranch(BranchName, trkpidbestplane, BranchName + NTracksIndexStr + "/S");
1372 
1373  if(saveHierarchyInfo){
1374  BranchName = "trkisprimary_" + TrackLabel;
1375  CreateBranch(BranchName, trkisprimary, BranchName + NTracksIndexStr + "/O");
1376 
1377  BranchName = "trkndaughters_" + TrackLabel;
1378  CreateBranch(BranchName, trkndaughters, BranchName + NTracksIndexStr + "/I");
1379 
1380  BranchName = "trkpfpid_" + TrackLabel;
1381  CreateBranch(BranchName, trkpfpid, BranchName + NTracksIndexStr + "/I");
1382 
1383  BranchName = "trkparentpfpid_" + TrackLabel;
1384  CreateBranch(BranchName, trkparentpfpid, BranchName + NTracksIndexStr + "/I");
1385  }
1386 } // sbnd::AnalysisTreeDataStruct::TrackDataStruct::SetAddresses()
1387 
1388 //------------------------------------------------------------------------------
1389 //--- AnalysisTreeDataStruct::ShowerDataStruct
1390 //---
1391 
1393 {
1394  MaxShowers = nShowers;
1395 
1396  shwId.resize(MaxShowers);
1397  shwbestplane.resize(MaxShowers);
1398  shwlength.resize(MaxShowers);
1399  shwopenangle.resize(MaxShowers);
1400  shwstartx.resize(MaxShowers);
1401  shwstarty.resize(MaxShowers);
1402  shwstartz.resize(MaxShowers);
1403  shwdirx.resize(MaxShowers);
1404  shwdiry.resize(MaxShowers);
1405  shwdirz.resize(MaxShowers);
1406  shwisprimary.resize(MaxShowers);
1407  shwndaughters.resize(MaxShowers);
1408  shwpfpid.resize(MaxShowers);
1409  shwparentpfpid.resize(MaxShowers);
1410 
1411 } // AnalysisTreeDataStruct::ShowerDataStruct.Resize()
1412 
1414  Resize(MaxShowers);
1415  nshowers = 0;
1416 
1417  // For variables with the ShowerData_t form
1418  FillWith(shwId, -9999);
1419  FillWith(shwbestplane, -9999);
1420  FillWith(shwlength, -9999.);
1421  FillWith(shwopenangle, -9999.);
1422  FillWith(shwstartx, -9999.);
1423  FillWith(shwstarty, -9999.);
1424  FillWith(shwstartz, -9999.);
1425  FillWith(shwdirx, -9999.);
1426  FillWith(shwdiry, -9999.);
1427  FillWith(shwdirz, -9999.);
1428  FillWith(shwisprimary, -9999);
1429  FillWith(shwndaughters, -9999);
1430  FillWith(shwpfpid, -9999);
1431  FillWith(shwparentpfpid, -9999);
1432 
1433 } // sbnd::AnalysisTreeDataStruct::ShowerDataStruct::Clear()
1434 
1436  TTree* pTree, std::string showerLabel, bool saveHierarchyInfo
1437 ) {
1438  if (MaxShowers == 0) return; // no tracks, no tree!
1439 
1440  sbnd::AnalysisTreeDataStruct::BranchCreator CreateBranch(pTree);
1441 
1442  std::string ShowerLabel = showerLabel;
1443  std::string BranchName;
1444 
1445  BranchName = "nshowers_" + ShowerLabel;
1446  CreateBranch(BranchName, &nshowers, BranchName + "/S");
1447  std::string NShowersIndexStr = "[" + BranchName + "]";
1448 
1449  BranchName = "shwId_" + ShowerLabel;
1450  CreateBranch(BranchName, shwId, BranchName + NShowersIndexStr + "/I");
1451 
1452  BranchName = "shwbestplane_" + ShowerLabel;
1453  CreateBranch(BranchName, shwbestplane, BranchName + NShowersIndexStr + "/I");
1454 
1455  BranchName = "shwlength_" + ShowerLabel;
1456  CreateBranch(BranchName, shwlength, BranchName + NShowersIndexStr + "/F");
1457 
1458  BranchName = "shwlength_" + ShowerLabel;
1459  CreateBranch(BranchName, shwlength, BranchName + NShowersIndexStr + "/F");
1460 
1461  BranchName = "shwopenangle_" + ShowerLabel;
1462  CreateBranch(BranchName, shwopenangle, BranchName + NShowersIndexStr + "/F");
1463 
1464  BranchName = "shwstartx_" + ShowerLabel;
1465  CreateBranch(BranchName, shwstartx, BranchName + NShowersIndexStr + "/F");
1466 
1467  BranchName = "shwstarty_" + ShowerLabel;
1468  CreateBranch(BranchName, shwstarty, BranchName + NShowersIndexStr + "/F");
1469 
1470  BranchName = "shwstartz_" + ShowerLabel;
1471  CreateBranch(BranchName, shwstartz, BranchName + NShowersIndexStr + "/F");
1472 
1473  BranchName = "shwdirx_" + ShowerLabel;
1474  CreateBranch(BranchName, shwdirx, BranchName + NShowersIndexStr + "/F");
1475 
1476  BranchName = "shwdiry_" + ShowerLabel;
1477  CreateBranch(BranchName, shwdiry, BranchName + NShowersIndexStr + "/F");
1478 
1479  BranchName = "shwdirz_" + ShowerLabel;
1480  CreateBranch(BranchName, shwdirz, BranchName + NShowersIndexStr + "/F");
1481 
1482  if(saveHierarchyInfo){
1483  BranchName = "shwisprimary_" + ShowerLabel;
1484  CreateBranch(BranchName, shwisprimary, BranchName + NShowersIndexStr + "/O");
1485 
1486  BranchName = "shwndaughters_" + ShowerLabel;
1487  CreateBranch(BranchName, shwndaughters, BranchName + NShowersIndexStr + "/I");
1488 
1489  BranchName = "shwpfpid_" + ShowerLabel;
1490  CreateBranch(BranchName, shwpfpid, BranchName + NShowersIndexStr + "/I");
1491 
1492  BranchName = "shwparentpfpid_" + ShowerLabel;
1493  CreateBranch(BranchName, shwparentpfpid, BranchName + NShowersIndexStr + "/I");
1494  }
1495 } // sbnd::AnalysisTreeDataStruct::ShowerDataStruct::SetShowerAddresses()
1496 
1497 //------------------------------------------------------------------------------
1498 //--- AnalysisTreeDataStruct::VertexDataStruct
1499 //---
1500 
1502 {
1503  MaxVertices = nVertices;
1504 
1505  vtx.resize(MaxVertices);
1506  primaryvtx.resize(MaxVertices);
1507 } // AnalysisTreeDataStruct::VertexDataStruct::Resize()
1508 
1510  Resize(MaxVertices);
1511  nvtx = 0;
1512 
1513  for (size_t iVtx = 0; iVtx < MaxVertices; ++iVtx){
1514  FillWith(vtx[iVtx], -9999.);
1515  }
1516  FillWith(primaryvtx, -9999);
1517 } // AnalysisTreeDataStruct::VertexDataStruct::Clear()
1518 
1520  TTree* pTree, std::string vertices, bool saveHierarchyInfo
1521 ) {
1522  if (MaxVertices == 0) return; // no vertices, no tree!
1523 
1524  sbnd::AnalysisTreeDataStruct::BranchCreator CreateBranch(pTree);
1525 
1526  std::string VertexLabel = vertices;
1527  std::string BranchName;
1528 
1529  BranchName = "nvtx_" + VertexLabel;
1530  CreateBranch(BranchName, &nvtx, BranchName + "/S");
1531  std::string NVertexIndexStr = "[" + BranchName + "]";
1532 
1533  if(saveHierarchyInfo){
1534  BranchName = "primaryvtx_" + VertexLabel;
1535  CreateBranch(BranchName, primaryvtx, BranchName + NVertexIndexStr + "/I");
1536  }
1537 
1538  BranchName = "vtx_" + VertexLabel;
1539  CreateBranch(BranchName, vtx, BranchName + NVertexIndexStr + "[3]/F");
1540 } // AnalysisTreeDataStruct::VertexDataStruct::SetAddresses()
1541 
1542 //------------------------------------------------------------------------------
1543 //--- AnalysisTreeDataStruct
1544 //---
1545 
1547 
1548 // RunData.Clear();
1549  SubRunData.Clear();
1550 
1551  run = -99999;
1552  subrun = -99999;
1553  event = -99999;
1554  evttime = -99999;
1555  beamtime = -99999;
1556  isdata = -99;
1557  taulife = -999;
1558 
1559  // Clear hit info
1560  no_hits = 0;
1561  std::fill(hit_tpc, hit_tpc + sizeof(hit_tpc)/sizeof(hit_tpc[0]), -9999);
1562  std::fill(hit_plane, hit_plane + sizeof(hit_plane)/sizeof(hit_plane[0]), -9999);
1563  std::fill(hit_wire, hit_wire + sizeof(hit_wire)/sizeof(hit_wire[0]), -9999);
1564  std::fill(hit_channel, hit_channel + sizeof(hit_channel)/sizeof(hit_channel[0]), -9999);
1565  std::fill(hit_peakT, hit_peakT + sizeof(hit_peakT)/sizeof(hit_peakT[0]), -99999.);
1566  std::fill(hit_charge, hit_charge + sizeof(hit_charge)/sizeof(hit_charge[0]), -99999.);
1567  std::fill(hit_ph, hit_ph + sizeof(hit_ph)/sizeof(hit_ph[0]), -99999.);
1568  std::fill(hit_startT, hit_startT + sizeof(hit_startT)/sizeof(hit_startT[0]), -99999.);
1569  std::fill(hit_endT, hit_endT + sizeof(hit_endT)/sizeof(hit_endT[0]), -99999.);
1570  std::fill(hit_width, hit_width + sizeof(hit_width)/sizeof(hit_width[0]), -99999.);
1571  std::fill(hit_trkid, hit_trkid + sizeof(hit_trkid)/sizeof(hit_trkid[0]), -9999);
1572  std::fill(hit_mcid, hit_mcid + sizeof(hit_mcid)/sizeof(hit_mcid[0]), -9);
1573  std::fill(hit_frac, hit_frac + sizeof(hit_frac)/sizeof(hit_frac[0]), -9);
1574  std::fill(hit_nelec, hit_nelec + sizeof(hit_nelec)/sizeof(hit_nelec[0]), -9999);
1575  std::fill(hit_energy, hit_energy + sizeof(hit_energy)/sizeof(hit_energy[0]), -9999);
1576  std::fill(hit_reconelec, hit_reconelec + sizeof(hit_reconelec)/sizeof(hit_reconelec[0]), -9999);
1577 
1578  // Clear MCTruth info
1579  mcevts_truth = 0;
1580  mcevts_truthcry = -99999;
1581  FillWith(nuScatterCode_truth,-99999);
1582  FillWith(nuID_truth,-99999);
1583  FillWith(nuPDG_truth,-99999);
1584  FillWith(ccnc_truth,-99999);
1585  FillWith(mode_truth,-99999);
1586  FillWith(enu_truth,-99999);
1587  FillWith(Q2_truth,-99999);
1588  FillWith(W_truth,-99999);
1589  FillWith(hitnuc_truth,-99999);
1590  FillWith(nuvtxx_truth,-99999);
1591  FillWith(nuvtxy_truth,-99999);
1592  FillWith(nuvtxz_truth,-99999);
1593  FillWith(nu_dcosx_truth,-99999);
1594  FillWith(nu_dcosy_truth,-99999);
1595  FillWith(nu_dcosz_truth,-99999);
1596  FillWith(lep_mom_truth,-99999);
1597  FillWith(lep_dcosx_truth,-99999);
1598  FillWith(lep_dcosy_truth,-99999);
1599  FillWith(lep_dcosz_truth,-99999);
1600  FillWith(tpx_flux,-99999);
1601  FillWith(tpy_flux,-99999);
1602  FillWith(tpz_flux,-99999);
1603  FillWith(tptype_flux,-99999);
1604 
1605  genie_no_primaries = 0;
1606  cry_no_primaries = 0;
1607  no_primaries = 0;
1608  geant_list_size=0;
1610 
1611  FillWith(pdg, -99999);
1612  FillWith(status, -99999);
1613  FillWith(Mass, -99999.);
1614  FillWith(Eng, -99999.);
1615  FillWith(EndE, -99999.);
1616  FillWith(Px, -99999.);
1617  FillWith(Py, -99999.);
1618  FillWith(Pz, -99999.);
1619  FillWith(P, -99999.);
1620  FillWith(StartPointx, -99999.);
1621  FillWith(StartPointy, -99999.);
1622  FillWith(StartPointz, -99999.);
1623  FillWith(StartT, -9999999.);
1624  FillWith(EndT, -9999999.);
1625  FillWith(EndPointx, -99999.);
1626  FillWith(EndPointy, -99999.);
1627  FillWith(EndPointz, -99999.);
1628  FillWith(EndT, -99999.);
1629  FillWith(theta, -99999.);
1630  FillWith(phi, -99999.);
1631  FillWith(theta_xz, -99999.);
1632  FillWith(theta_yz, -99999.);
1633  FillWith(pathlen, -99999.);
1634  FillWith(inTPCActive, -99999);
1635  FillWith(StartPointx_tpcAV, -99999.);
1636  FillWith(StartPointy_tpcAV, -99999.);
1637  FillWith(StartPointz_tpcAV, -99999.);
1638  FillWith(EndPointx_tpcAV, -99999.);
1639  FillWith(EndPointy_tpcAV, -99999.);
1640  FillWith(EndPointz_tpcAV, -99999.);
1641  FillWith(NumberDaughters, -99999);
1642  FillWith(Mother, -99999);
1643  FillWith(TrackId, -99999);
1644  FillWith(process_primary, -99999);
1645  FillWith(processname, "noname");
1646  FillWith(MergedId, -99999);
1647  FillWith(MotherNuId, -99999);
1648  FillWith(DepEnergy, -9999);
1649  FillWith(NumElectrons, -9999);
1650  total_DepEnergy = -9999.;
1651  total_NumElectrons = -9999.;
1652  FillWith(genie_primaries_pdg, -99999);
1653  FillWith(genie_Eng, -99999.);
1654  FillWith(genie_Px, -99999.);
1655  FillWith(genie_Py, -99999.);
1656  FillWith(genie_Pz, -99999.);
1657  FillWith(genie_P, -99999.);
1658  FillWith(genie_status_code, -99999);
1659  FillWith(genie_mass, -99999.);
1660  FillWith(genie_trackID, -99999);
1661  FillWith(genie_ND, -99999);
1662  FillWith(genie_mother, -99999);
1663  FillWith(cry_primaries_pdg, -99999);
1664  FillWith(cry_Eng, -99999.);
1665  FillWith(cry_Px, -99999.);
1666  FillWith(cry_Py, -99999.);
1667  FillWith(cry_Pz, -99999.);
1668  FillWith(cry_P, -99999.);
1669  FillWith(cry_StartPointx, -99999.);
1670  FillWith(cry_StartPointy, -99999.);
1671  FillWith(cry_StartPointz, -99999.);
1672  FillWith(cry_status_code, -99999);
1673  FillWith(cry_mass, -99999.);
1674  FillWith(cry_trackID, -99999);
1675  FillWith(cry_ND, -99999);
1676  FillWith(cry_mother, -99999);
1677 
1678 
1679  // auxiliary detector information;
1680  FillWith(NAuxDets, 0);
1681  // - set to -9999 all the values of each of the arrays in AuxDetID;
1682  // this auto is BoxedArray<Short_t>
1683  for (auto& partInfo: AuxDetID) FillWith(partInfo, -9999);
1684  // - pythonish C++: as the previous line, for each one in a list of containers
1685  // of the same type (C++ is not python yet), using pointers to avoid copy;
1686  for (AuxDetMCData_t<Float_t>* cont: {
1687  &entryX, &entryY, &entryZ, &entryT,
1688  &exitX , &exitY , &exitZ, &exitT, &exitPx, &exitPy, &exitPz,
1690  })
1691  {
1692  // this auto is BoxedArray<Float_t>
1693  for (auto& partInfo: *cont) FillWith(partInfo, -99999.);
1694  } // for container
1695 
1696  // Clear PFP info
1697  num_pfps = 0;
1698  //FillWith(pfp_id,-999);
1699  FillWith(pfp_sliceid,-999);
1700  FillWith(pfp_pdg,-999);
1701 
1702  // Clear slice info
1703  num_slices = 0;
1704  num_nuslices = 0;
1705  best_nuslice_id = -999;
1706  best_nuslice_pdg = -999;
1707  best_nuslice_pfpid = -999;
1708  best_nuslice_origin = -9;
1709  best_nuslice_score = -9.;
1710  best_nuslice_hitcomp = -9.;
1711  best_nuslice_hitpurity = -9.;
1714 
1715 
1716 } // sbnd::AnalysisTreeDataStruct::ClearLocalData()
1717 
1718 
1720  ClearLocalData();
1721  std::for_each
1722  (TrackData.begin(), TrackData.end(), std::mem_fn(&TrackDataStruct::Clear));
1723  std::for_each
1724  (VertexData.begin(), VertexData.end(), std::mem_fn(&VertexDataStruct::Clear));
1725  std::mem_fn(&ShowerDataStruct::Clear);
1726 } // sbnd::AnalysisTreeDataStruct::Clear()
1727 
1729 
1730  //min size is 1, to guarantee an address
1731  MaxMCNeutrinos = (size_t) std::max(nNeutrinos, 1);
1733  nuID_truth.resize(MaxMCNeutrinos);
1734  nuPDG_truth.resize(MaxMCNeutrinos);
1735  ccnc_truth.resize(MaxMCNeutrinos);
1736  mode_truth.resize(MaxMCNeutrinos);
1737  enu_truth.resize(MaxMCNeutrinos);
1738  Q2_truth.resize(MaxMCNeutrinos);
1739  W_truth.resize(MaxMCNeutrinos);
1740  hitnuc_truth.resize(MaxMCNeutrinos);
1741  nuvtxx_truth.resize(MaxMCNeutrinos);
1742  nuvtxy_truth.resize(MaxMCNeutrinos);
1743  nuvtxz_truth.resize(MaxMCNeutrinos);
1747  lep_mom_truth.resize(MaxMCNeutrinos);
1751  //Also resize the flux information here as it's a 1:1 with the MCNeutrino
1752  tpx_flux.resize(MaxMCNeutrinos);
1753  tpy_flux.resize(MaxMCNeutrinos);
1754  tpz_flux.resize(MaxMCNeutrinos);
1755  tptype_flux.resize(MaxMCNeutrinos);
1756 
1757  return;
1758 } // sbnd::AnalysisTreeDataStruct::ResizeMCNeutrino()
1759 
1761 
1762  // minimum size is 1, so that we always have an address
1763  MaxGEANTparticles = (size_t) std::max(nParticles, 1);
1764 
1765  pdg.resize(MaxGEANTparticles);
1766  status.resize(MaxGEANTparticles);
1767  Mass.resize(MaxGEANTparticles);
1768  Eng.resize(MaxGEANTparticles);
1769  EndE.resize(MaxGEANTparticles);
1770  Px.resize(MaxGEANTparticles);
1771  Py.resize(MaxGEANTparticles);
1772  Pz.resize(MaxGEANTparticles);
1773  P.resize(MaxGEANTparticles);
1777  StartT.resize(MaxGEANTparticles);
1778  EndT.resize(MaxGEANTparticles);
1779  EndPointx.resize(MaxGEANTparticles);
1780  EndPointy.resize(MaxGEANTparticles);
1781  EndPointz.resize(MaxGEANTparticles);
1782  EndT.resize(MaxGEANTparticles);
1783  theta.resize(MaxGEANTparticles);
1784  phi.resize(MaxGEANTparticles);
1785  theta_xz.resize(MaxGEANTparticles);
1786  theta_yz.resize(MaxGEANTparticles);
1787  pathlen.resize(MaxGEANTparticles);
1788  DepEnergy.resize(MaxGEANTparticles);
1798  Mother.resize(MaxGEANTparticles);
1799  TrackId.resize(MaxGEANTparticles);
1802  MergedId.resize(MaxGEANTparticles);
1803  MotherNuId.resize(MaxGEANTparticles);
1804 
1805  // auxiliary detector structure
1806  NAuxDets.resize(MaxGEANTparticles);
1807  AuxDetID.resize(MaxGEANTparticles);
1808  entryX.resize(MaxGEANTparticles);
1809  entryY.resize(MaxGEANTparticles);
1810  entryZ.resize(MaxGEANTparticles);
1811  entryT.resize(MaxGEANTparticles);
1812  exitX.resize(MaxGEANTparticles);
1813  exitY.resize(MaxGEANTparticles);
1814  exitZ.resize(MaxGEANTparticles);
1815  exitT.resize(MaxGEANTparticles);
1816  exitPx.resize(MaxGEANTparticles);
1817  exitPy.resize(MaxGEANTparticles);
1818  exitPz.resize(MaxGEANTparticles);
1820 
1821 } // sbnd::AnalysisTreeDataStruct::ResizeGEANT()
1822 
1824 
1825  // minimum size is 1, so that we always have an address
1826  MaxGeniePrimaries = (size_t) std::max(nPrimaries, 1);
1828  genie_Eng.resize(MaxGeniePrimaries);
1829  genie_Px.resize(MaxGeniePrimaries);
1830  genie_Py.resize(MaxGeniePrimaries);
1831  genie_Pz.resize(MaxGeniePrimaries);
1832  genie_P.resize(MaxGeniePrimaries);
1834  genie_mass.resize(MaxGeniePrimaries);
1836  genie_ND.resize(MaxGeniePrimaries);
1838 
1839 } // sbnd::AnalysisTreeDataStruct::ResizeGenie()
1840 
1841 // minimum size is 1, so that we always have an address
1843 
1844  cry_primaries_pdg.resize(nPrimaries);
1845  cry_Eng.resize(nPrimaries);
1846  cry_Px.resize(nPrimaries);
1847  cry_Py.resize(nPrimaries);
1848  cry_Pz.resize(nPrimaries);
1849  cry_P.resize(nPrimaries);
1850  cry_StartPointx.resize(nPrimaries);
1851  cry_StartPointy.resize(nPrimaries);
1852  cry_StartPointz.resize(nPrimaries);
1853  cry_status_code.resize(nPrimaries);
1854  cry_mass.resize(nPrimaries);
1855  cry_trackID.resize(nPrimaries);
1856  cry_ND.resize(nPrimaries);
1857  cry_mother.resize(nPrimaries);
1858 
1859 } // sbnd::AnalysisTreeDataStruct::ResizeCry()
1860 
1862  TTree* pTree,
1863  const std::vector<std::string>& trackers,
1864  const std::string showerLabel,
1865  const std::vector<std::string>& vertexLabels,
1866  bool isCosmics,
1867  const std::vector<bool>& saveHierarchyInfo,
1868  bool saveShowerHierarchyInfo
1869  ) {
1870  BranchCreator CreateBranch(pTree);
1871 
1872  CreateBranch("run",&run,"run/I");
1873  CreateBranch("subrun",&subrun,"subrun/I");
1874  CreateBranch("event",&event,"event/I");
1875  CreateBranch("evttime",&evttime,"evttime/D");
1876  CreateBranch("beamtime",&beamtime,"beamtime/D");
1877  CreateBranch("pot",&SubRunData.pot,"pot/D");
1878 
1879  CreateBranch("isdata",&isdata,"isdata/B");
1880  CreateBranch("taulife",&taulife,"taulife/F");
1881 
1882  CreateBranch("no_hits",&no_hits,"no_hits/I");
1883  if (hasHitInfo()){
1884  CreateBranch("hit_tpc",hit_tpc,"hit_tpc[no_hits]/S");
1885  CreateBranch("hit_plane",hit_plane,"hit_plane[no_hits]/S");
1886  CreateBranch("hit_wire",hit_wire,"hit_wire[no_hits]/S");
1887  CreateBranch("hit_channel",hit_channel,"hit_channel[no_hits]/S");
1888  CreateBranch("hit_peakT",hit_peakT,"hit_peakT[no_hits]/F");
1889  CreateBranch("hit_charge",hit_charge,"hit_charge[no_hits]/F");
1890  CreateBranch("hit_ph",hit_ph,"hit_ph[no_hits]/F");
1891  CreateBranch("hit_startT",hit_startT,"hit_startT[no_hits]/F");
1892  CreateBranch("hit_endT",hit_endT,"hit_endT[no_hits]/F");
1893  CreateBranch("hit_width",hit_width,"hit_width[no_hits]/F");
1894  CreateBranch("hit_trkid",hit_trkid,"hit_trkid[no_hits]/S");
1895  CreateBranch("hit_mcid",hit_mcid,"hit_mcid[no_hits]/I");
1896  CreateBranch("hit_frac",hit_frac,"hit_frac[no_hits]/F");
1897  CreateBranch("hit_energy",hit_energy,"hit_energy[no_hits]/F");
1898  CreateBranch("hit_nelec",hit_nelec,"hit_nelec[no_hits]/F");
1899  CreateBranch("hit_reconelec",hit_reconelec,"hit_reconelec[no_hits]/F");
1900  }
1901 
1902  if (hasVertexInfo()){
1903  /*
1904  CreateBranch("nvtx",&nvtx,"nvtx/S");
1905  CreateBranch("vtx",vtx,"vtx[nvtx][3]/F");
1906  if(saveHierarchyInfo)
1907  CreateBranch("primaryvtx",primaryvtx,"primaryvtx[nvtx]/I");
1908  */
1909 
1910  kNTracker = trackers.size();
1911  for(int i=0; i<kNTracker; i++){
1912  std::string VertexLabel = vertexLabels[i];
1913 
1914  // note that if the tracker data has maximum number of tracks 0,
1915  // nothing is initialized (branches are not even created)
1916  VertexData[i].SetAddresses(pTree, VertexLabel, saveHierarchyInfo[i]);
1917  }
1918  }
1919 
1920  if (hasTrackInfo()){
1921  AutoResettingStringSteam sstr;
1922  sstr() << kMaxTrackHits;
1923  std::string MaxTrackHitsIndexStr("[" + sstr.str() + "]");
1924 
1925  kNTracker = trackers.size();
1926  CreateBranch("kNTracker",&kNTracker,"kNTracker/B");
1927  for(int i=0; i<kNTracker; i++){
1928  std::string TrackLabel = trackers[i];
1929  std::string BranchName;
1930 
1931  // note that if the tracker data has maximum number of tracks 0,
1932  // nothing is initialized (branches are not even created)
1933  TrackData[i].SetAddresses(pTree, TrackLabel, isCosmics, saveHierarchyInfo[i]);
1934  } // for trackers
1935  }
1936 
1937  if (hasShowerInfo()){
1938  std::string ShowerLabel = showerLabel;
1939  ShowerData.SetShowerAddresses(pTree, ShowerLabel, saveShowerHierarchyInfo);
1940  }
1941 
1942  if (hasSliceInfo()){
1943  CreateBranch("num_pfps",&num_pfps,"num_pfps/I");
1944  CreateBranch("pfp_sliceid",&pfp_sliceid,"pfp_sliceid[num_pfps]/I");
1945  CreateBranch("pfp_pdg",&pfp_pdg,"pfp_pdg[num_pfps]/I");
1946  CreateBranch("num_slices",&num_slices,"num_slices/I");
1947  CreateBranch("num_nuslices",&num_nuslices,"num_nuslices/I");
1948  CreateBranch("best_nuslice_id",&best_nuslice_id,"best_nuslice_id/I");
1949  CreateBranch("best_nuslice_pfpid",&best_nuslice_pfpid,"best_nuslice_pfpid/I");
1950  CreateBranch("best_nuslice_pdg",&best_nuslice_pdg,"best_nuslice_pdg/I");
1951  CreateBranch("best_nuslice_origin",&best_nuslice_origin,"best_nuslice_origin/I");
1952  CreateBranch("best_nuslice_score",&best_nuslice_score,"best_nuslice_score/F");
1953  CreateBranch("best_nuslice_hitcomp",&best_nuslice_hitcomp,"best_nuslice_hitcomp/F");
1954  CreateBranch("best_nuslice_hitpurity",&best_nuslice_hitpurity,"best_nuslice_hitpurity/F");
1955  CreateBranch("best_nuslice_lephitcomp",&best_nuslice_lephitcomp,"best_nuslice_lephitcomp/F");
1956  CreateBranch("best_nuslice_lephitpurity",&best_nuslice_lephitpurity,"best_nuslice_lephitpurity/F");
1957  }
1958 
1959  if (hasGenieInfo()){
1960  CreateBranch("mcevts_truth",&mcevts_truth,"mcevts_truth/I");
1961  CreateBranch("nuScatterCode_truth",nuScatterCode_truth,"nuScatterCode_truth[mcevts_truth]/I");
1962  CreateBranch("nuID_truth",nuID_truth,"nuID_truth[mcevts_truth]/I");
1963  CreateBranch("nuPDG_truth",nuPDG_truth,"nuPDG_truth[mcevts_truth]/I");
1964  CreateBranch("ccnc_truth",ccnc_truth,"ccnc_truth[mcevts_truth]/I");
1965  CreateBranch("mode_truth",mode_truth,"mode_truth[mcevts_truth]/I");
1966  CreateBranch("enu_truth",enu_truth,"enu_truth[mcevts_truth]/F");
1967  CreateBranch("Q2_truth",Q2_truth,"Q2_truth[mcevts_truth]/F");
1968  CreateBranch("W_truth",W_truth,"W_truth[mcevts_truth]/F");
1969  CreateBranch("hitnuc_truth",hitnuc_truth,"hitnuc_truth[mcevts_truth]/I");
1970  CreateBranch("nuvtxx_truth",nuvtxx_truth,"nuvtxx_truth[mcevts_truth]/F");
1971  CreateBranch("nuvtxy_truth",nuvtxy_truth,"nuvtxy_truth[mcevts_truth]/F");
1972  CreateBranch("nuvtxz_truth",nuvtxz_truth,"nuvtxz_truth[mcevts_truth]/F");
1973  CreateBranch("nu_dcosx_truth",nu_dcosx_truth,"nu_dcosx_truth[mcevts_truth]/F");
1974  CreateBranch("nu_dcosy_truth",nu_dcosy_truth,"nu_dcosy_truth[mcevts_truth]/F");
1975  CreateBranch("nu_dcosz_truth",nu_dcosz_truth,"nu_dcosz_truth[mcevts_truth]/F");
1976  CreateBranch("lep_mom_truth",lep_mom_truth,"lep_mom_truth[mcevts_truth]/F");
1977  CreateBranch("lep_dcosx_truth",lep_dcosx_truth,"lep_dcosx_truth[mcevts_truth]/F");
1978  CreateBranch("lep_dcosy_truth",lep_dcosy_truth,"lep_dcosy_truth[mcevts_truth]/F");
1979  CreateBranch("lep_dcosz_truth",lep_dcosz_truth,"lep_dcosz_truth[mcevts_truth]/F");
1980 
1981  CreateBranch("tpx_flux",tpx_flux,"tpx_flux[mcevts_truth]/F");
1982  CreateBranch("tpy_flux",tpy_flux,"tpy_flux[mcevts_truth]/F");
1983  CreateBranch("tpz_flux",tpz_flux,"tpz_flux[mcevts_truth]/F");
1984  CreateBranch("tptype_flux",tptype_flux,"tptype_flux[mcevts_truth]/I");
1985 
1986  CreateBranch("genie_no_primaries",&genie_no_primaries,"genie_no_primaries/I");
1987  CreateBranch("genie_primaries_pdg",genie_primaries_pdg,"genie_primaries_pdg[genie_no_primaries]/I");
1988  CreateBranch("genie_Eng",genie_Eng,"genie_Eng[genie_no_primaries]/F");
1989  CreateBranch("genie_Px",genie_Px,"genie_Px[genie_no_primaries]/F");
1990  CreateBranch("genie_Py",genie_Py,"genie_Py[genie_no_primaries]/F");
1991  CreateBranch("genie_Pz",genie_Pz,"genie_Pz[genie_no_primaries]/F");
1992  CreateBranch("genie_P",genie_P,"genie_P[genie_no_primaries]/F");
1993  CreateBranch("genie_status_code",genie_status_code,"genie_status_code[genie_no_primaries]/I");
1994  CreateBranch("genie_mass",genie_mass,"genie_mass[genie_no_primaries]/F");
1995  CreateBranch("genie_trackID",genie_trackID,"genie_trackID[genie_no_primaries]/I");
1996  CreateBranch("genie_ND",genie_ND,"genie_ND[genie_no_primaries]/I");
1997  CreateBranch("genie_mother",genie_mother,"genie_mother[genie_no_primaries]/I");
1998  }
1999 
2000  if (hasCryInfo()){
2001  CreateBranch("mcevts_truthcry",&mcevts_truthcry,"mcevts_truthcry/I");
2002  CreateBranch("cry_no_primaries",&cry_no_primaries,"cry_no_primaries/I");
2003  CreateBranch("cry_primaries_pdg",cry_primaries_pdg,"cry_primaries_pdg[cry_no_primaries]/I");
2004  CreateBranch("cry_Eng",cry_Eng,"cry_Eng[cry_no_primaries]/F");
2005  CreateBranch("cry_Px",cry_Px,"cry_Px[cry_no_primaries]/F");
2006  CreateBranch("cry_Py",cry_Py,"cry_Py[cry_no_primaries]/F");
2007  CreateBranch("cry_Pz",cry_Pz,"cry_Pz[cry_no_primaries]/F");
2008  CreateBranch("cry_P",cry_P,"cry_P[cry_no_primaries]/F");
2009  CreateBranch("cry_StartPointx",cry_StartPointx,"cry_StartPointx[cry_no_primaries]/F");
2010  CreateBranch("cry_StartPointy",cry_StartPointy,"cry_StartPointy[cry_no_primaries]/F");
2011  CreateBranch("cry_StartPointz",cry_StartPointz,"cry_StartPointz[cry_no_primaries]/F");
2012  CreateBranch("cry_status_code",cry_status_code,"cry_status_code[cry_no_primaries]/I");
2013  CreateBranch("cry_mass",cry_mass,"cry_mass[cry_no_primaries]/F");
2014  CreateBranch("cry_trackID",cry_trackID,"cry_trackID[cry_no_primaries]/I");
2015  CreateBranch("cry_ND",cry_ND,"cry_ND[cry_no_primaries]/I");
2016  CreateBranch("cry_mother",cry_mother,"cry_mother[cry_no_primaries]/I");
2017  }
2018 
2019  if (hasGeantInfo()){
2020  CreateBranch("no_primaries",&no_primaries,"no_primaries/I");
2021  CreateBranch("geant_list_size",&geant_list_size,"geant_list_size/I");
2022  CreateBranch("geant_list_size_in_tpcAV",&geant_list_size_in_tpcAV,"geant_list_size_in_tpcAV/I");
2023  CreateBranch("pdg",pdg,"pdg[geant_list_size]/I");
2024  CreateBranch("status",status,"status[geant_list_size]/I");
2025  CreateBranch("Mass",Mass,"Mass[geant_list_size]/F");
2026  CreateBranch("Eng",Eng,"Eng[geant_list_size]/F");
2027  CreateBranch("EndE",EndE,"EndE[geant_list_size]/F");
2028  CreateBranch("Px",Px,"Px[geant_list_size]/F");
2029  CreateBranch("Py",Py,"Py[geant_list_size]/F");
2030  CreateBranch("Pz",Pz,"Pz[geant_list_size]/F");
2031  CreateBranch("P",P,"P[geant_list_size]/F");
2032  CreateBranch("StartPointx",StartPointx,"StartPointx[geant_list_size]/F");
2033  CreateBranch("StartPointy",StartPointy,"StartPointy[geant_list_size]/F");
2034  CreateBranch("StartPointz",StartPointz,"StartPointz[geant_list_size]/F");
2035  CreateBranch("StartT",StartT,"StartT[geant_list_size]/F");
2036  CreateBranch("EndPointx",EndPointx,"EndPointx[geant_list_size]/F");
2037  CreateBranch("EndPointy",EndPointy,"EndPointy[geant_list_size]/F");
2038  CreateBranch("EndPointz",EndPointz,"EndPointz[geant_list_size]/F");
2039  CreateBranch("EndT",EndT,"EndT[geant_list_size]/F");
2040  CreateBranch("theta",theta,"theta[geant_list_size]/F");
2041  CreateBranch("phi",phi,"phi[geant_list_size]/F");
2042  CreateBranch("theta_xz",theta_xz,"theta_xz[geant_list_size]/F");
2043  CreateBranch("theta_yz",theta_yz,"theta_yz[geant_list_size]/F");
2044  CreateBranch("pathlen",pathlen,"pathlen[geant_list_size]/F");
2045  CreateBranch("inTPCActive",inTPCActive,"inTPCActive[geant_list_size]/I");
2046  CreateBranch("StartPointx_tpcAV",StartPointx_tpcAV,"StartPointx_tpcAV[geant_list_size]/F");
2047  CreateBranch("StartPointy_tpcAV",StartPointy_tpcAV,"StartPointy_tpcAV[geant_list_size]/F");
2048  CreateBranch("StartPointz_tpcAV",StartPointz_tpcAV,"StartPointz_tpcAV[geant_list_size]/F");
2049  CreateBranch("EndPointx_tpcAV",EndPointx_tpcAV,"EndPointx_tpcAV[geant_list_size]/F");
2050  CreateBranch("EndPointy_tpcAV",EndPointy_tpcAV,"EndPointy_tpcAV[geant_list_size]/F");
2051  CreateBranch("EndPointz_tpcAV",EndPointz_tpcAV,"EndPointz_tpcAV[geant_list_size]/F");
2052  CreateBranch("NumberDaughters",NumberDaughters,"NumberDaughters[geant_list_size]/I");
2053  CreateBranch("Mother",Mother,"Mother[geant_list_size]/I");
2054  CreateBranch("TrackId",TrackId,"TrackId[geant_list_size]/I");
2055  CreateBranch("MergedId", MergedId, "MergedId[geant_list_size]/I");
2056  CreateBranch("MotherNuId", MotherNuId, "MotherNuId[geant_list_size]/I");
2057  CreateBranch("process_primary",process_primary,"process_primary[geant_list_size]/I");
2058  CreateBranch("processname", processname);
2059  CreateBranch("DepEnergy", DepEnergy, "DepEnergy[geant_list_size]/F");
2060  CreateBranch("NumElectrons", NumElectrons, "NumElectrons[geant_list_size]/F");
2061  CreateBranch("total_DepEnergy", &total_DepEnergy, "total_DepEnergy/F");
2062  CreateBranch("total_NumElectrons", &total_NumElectrons,"total_NumElectrons/F");
2063  }
2064 
2065  if (hasAuxDetector()) {
2066  // Geant information is required to fill aux detector information.
2067  // if fSaveGeantInfo is not set to true, show an error message and quit!
2068  if (!hasGeantInfo()){
2069  throw art::Exception(art::errors::Configuration)
2070  << "Saving Auxiliary detector information requies saving GEANT information, "
2071  <<"please set fSaveGeantInfo flag to true in your fhicl file and rerun.\n";
2072  }
2073  std::ostringstream sstr;
2074  sstr << "[" << kMaxAuxDets << "]";
2075  std::string MaxAuxDetIndexStr = sstr.str();
2076  CreateBranch("NAuxDets", NAuxDets, "NAuxDets[geant_list_size]/s");
2077  CreateBranch("AuxDetID", AuxDetID, "AuxDetID[geant_list_size]" + MaxAuxDetIndexStr + "/S");
2078  CreateBranch("AuxDetEntryX", entryX, "AuxDetEntryX[geant_list_size]" + MaxAuxDetIndexStr + "/F");
2079  CreateBranch("AuxDetEntryY", entryY, "AuxDetEntryY[geant_list_size]" + MaxAuxDetIndexStr + "/F");
2080  CreateBranch("AuxDetEntryZ", entryZ, "AuxDetEntryZ[geant_list_size]" + MaxAuxDetIndexStr + "/F");
2081  CreateBranch("AuxDetEntryT", entryT, "AuxDetEntryT[geant_list_size]" + MaxAuxDetIndexStr + "/F");
2082  CreateBranch("AuxDetExitX", exitX, "AuxDetExitX[geant_list_size]" + MaxAuxDetIndexStr + "/F");
2083  CreateBranch("AuxDetExitY", exitY, "AuxDetExitY[geant_list_size]" + MaxAuxDetIndexStr + "/F");
2084  CreateBranch("AuxDetExitZ", exitZ, "AuxDetExitZ[geant_list_size]" + MaxAuxDetIndexStr + "/F");
2085  CreateBranch("AuxDetExitT", exitT, "AuxDetExitT[geant_list_size]" + MaxAuxDetIndexStr + "/F");
2086  CreateBranch("AuxDetExitPx", exitPx, "AuxDetExitPx[geant_list_size]" + MaxAuxDetIndexStr + "/F");
2087  CreateBranch("AuxDetExitPy", exitPy, "AuxDetExitPy[geant_list_size]" + MaxAuxDetIndexStr + "/F");
2088  CreateBranch("AuxDetExitPz", exitPz, "AuxDetExitPz[geant_list_size]" + MaxAuxDetIndexStr + "/F");
2089  CreateBranch("CombinedEnergyDep", CombinedEnergyDep,
2090  "CombinedEnergyDep[geant_list_size]" + MaxAuxDetIndexStr + "/F");
2091  } // if hasAuxDetector
2092 
2093 } // sbnd::AnalysisTreeDataStruct::SetAddresses()
2094 
2095 
2096 //------------------------------------------------------------------------------
2097 //--- AnalysisTree
2098 //---
2099 
2100 sbnd::AnalysisTree::AnalysisTree(fhicl::ParameterSet const& pset) :
2101  EDAnalyzer(pset),
2102  fTree(nullptr), fData(nullptr),
2103  fDigitModuleLabel (pset.get< std::string >("DigitModuleLabel") ),
2104  fHitsModuleLabel (pset.get< std::string >("HitsModuleLabel") ),
2105  fLArG4ModuleLabel (pset.get< std::string >("LArGeantModuleLabel") ),
2106  fTPCSimChannelModuleLabel (pset.get< std::string >("TPCSimChannelModuleLabel") ),
2107  fCalDataModuleLabel (pset.get< std::string >("CalDataModuleLabel") ),
2108  fGenieGenModuleLabel (pset.get< std::string >("GenieGenModuleLabel") ),
2109  fCryGenModuleLabel (pset.get< std::string >("CryGenModuleLabel") ),
2110  fG4ModuleLabel (pset.get< std::string >("G4ModuleLabel") ),
2111  fPFParticleModuleLabel (pset.get< std::string> ("PFParticleModuleLabel") ),
2112  fShowerModuleLabel (pset.get< std::string> ("ShowerModuleLabel") ),
2113  fVertexModuleLabel (pset.get< std::vector<std::string> >("VertexModuleLabel") ),
2114  fTrackModuleLabel (pset.get< std::vector<std::string> >("TrackModuleLabel") ),
2115  fCalorimetryModuleLabel (pset.get< std::vector<std::string> >("CalorimetryModuleLabel")),
2116  fParticleIDModuleLabel (pset.get< std::vector<std::string> >("ParticleIDModuleLabel") ),
2117  fPOTModuleLabel (pset.get< std::string >("POTModuleLabel") ),
2118 
2119  fUseBuffer (pset.get< bool >("UseBuffers", false)),
2120  fSaveAuxDetInfo (pset.get< bool >("SaveAuxDetInfo", false)),
2121  fSaveCryInfo (pset.get< bool >("SaveCryInfo", false)),
2122  fSaveGenieInfo (pset.get< bool >("SaveGenieInfo", false)),
2123  fSaveGeantInfo (pset.get< bool >("SaveGeantInfo", false)),
2124  fSaveHitInfo (pset.get< bool >("SaveHitInfo", false)),
2125  fSaveTrackInfo (pset.get< bool >("SaveTrackInfo", false)),
2126  fSaveShowerInfo (pset.get< bool >("SaveShowerInfo", false)),
2127  fSaveVertexInfo (pset.get< bool >("SaveVertexInfo", false)),
2128  fSaveSliceInfo (pset.get< bool >("SaveSliceInfo",true)),
2129  fSaveHierarchyInfo (pset.get< std::vector<bool> >("SaveHierarchyInfo", {false})),
2130  fSaveShowerHierarchyInfo (pset.get< bool >("SaveShowerHierarchyInfo", false)),
2131  //fCosmicTaggerAssocLabel (pset.get<std::vector< std::string > >("CosmicTaggerAssocLabel") ),
2132  //fFlashMatchAssocLabel (pset.get<std::vector< std::string > >("FlashMatchAssocLabel") ),
2133  isCosmics(false),
2134  fSaveCaloCosmics (pset.get< bool >("SaveCaloCosmics",false)),
2135  fG4minE (pset.get< float>("G4minE",0.01)),
2136  fCaloAlg (pset.get< fhicl::ParameterSet >("CaloAlg"))
2137 {
2138  if (fSaveAuxDetInfo == true) fSaveGeantInfo = true;
2139  mf::LogInfo("AnalysisTree") << "Configuration:"
2140  << "\n UseBuffers: " << std::boolalpha << fUseBuffer
2141  ;
2142  if (GetNTrackers() > kMaxTrackers) {
2143  throw art::Exception(art::errors::Configuration)
2144  << "AnalysisTree currently supports only up to " << kMaxTrackers
2145  << " tracking algorithms, but " << GetNTrackers() << " are specified."
2146  << "\nYou can increase kMaxTrackers and recompile.";
2147  } // if too many trackers
2148  if (fTrackModuleLabel.size() != fVertexModuleLabel.size()){
2149  throw art::Exception(art::errors::Configuration)
2150  << "fTrackModuleLabel.size() = "<<fTrackModuleLabel.size()<<" does not match "
2151  << "fVertexModuleLabel.size() = "<<fVertexModuleLabel.size();
2152  }
2153  if (fTrackModuleLabel.size() != fCalorimetryModuleLabel.size()){
2154  throw art::Exception(art::errors::Configuration)
2155  << "fTrackModuleLabel.size() = "<<fTrackModuleLabel.size()<<" does not match "
2156  << "fCalorimetryModuleLabel.size() = "<<fCalorimetryModuleLabel.size();
2157  }
2158  if (fTrackModuleLabel.size() != fParticleIDModuleLabel.size()){
2159  throw art::Exception(art::errors::Configuration)
2160  << "fTrackModuleLabel.size() = "<<fTrackModuleLabel.size()<<" does not match "
2161  << "fParticleIDModuleLabel.size() = "<<fParticleIDModuleLabel.size();
2162  }
2163  if (fTrackModuleLabel.size() != fSaveHierarchyInfo.size()){
2164  throw art::Exception(art::errors::Configuration)
2165  << "fTrackModuleLabel.size() = "<<fTrackModuleLabel.size()<<" does not match "
2166  << "fSaveHierarchyInfo.size() = "<<fSaveHierarchyInfo.size();
2167  }
2168 
2169 } // sbnd::AnalysisTree::AnalysisTree()
2170 
2171 //-------------------------------------------------
2173 {
2174  DestroyData();
2175 }
2176 
2177 void sbnd::AnalysisTree::CreateTree(bool bClearData /* = false */) {
2178  if (!fTree) {
2179  art::ServiceHandle<art::TFileService> tfs;
2180  fTree = tfs->make<TTree>("anatree","analysis tree");
2181  }
2182  CreateData(bClearData);
2183  SetAddresses();
2184 } // sbnd::AnalysisTree::CreateTree()
2185 
2186 
2187 void sbnd::AnalysisTree::beginSubRun(const art::SubRun& sr)
2188 {
2189  art::Handle< sumdata::POTSummary > potListHandle;
2190  //sr.getByLabel(fPOTModuleLabel,potListHandle);
2191 
2192  if(sr.getByLabel(fPOTModuleLabel,potListHandle))
2193  SubRunData.pot=potListHandle->totpot;
2194  else
2195  SubRunData.pot=0.;
2196 }
2197 
2198 void sbnd::AnalysisTree::analyze(const art::Event& evt)
2199 {
2200  //tell us what's going on
2201  std::cout<<"AnalysisTree: processing event "<<evt.id().event()<<"\n";
2202 
2203  //services
2204  art::ServiceHandle<geo::Geometry> geom;
2205  auto const detprop = art::ServiceHandle<detinfo::DetectorPropertiesService const>()->DataFor(evt);
2206  // auto const* LArProp = lar::providerFrom<detinfo::LArPropertiesService>();
2207 
2208  // collect the sizes which might me needed to resize the tree data structure:
2209  bool isMC = !evt.isRealData();
2210 
2211  // * MCFlux information
2212  art::Handle< std::vector<simb::MCFlux> > mcfluxListHandle;
2213  std::vector<art::Ptr<simb::MCFlux> > fluxlist;
2214  if (evt.getByLabel(fGenieGenModuleLabel,mcfluxListHandle))
2215  art::fill_ptr_vector(fluxlist, mcfluxListHandle);
2216 
2217  // * TPC SimChannels
2218  std::vector<const sim::SimChannel*> fSimChannels;
2219  if (isMC && fSaveGeantInfo)
2220  evt.getView(fTPCSimChannelModuleLabel, fSimChannels);
2221 
2222  // * AuxDetSimChannels
2223  std::vector<const sim::AuxDetSimChannel*> fAuxDetSimChannels;
2224  if (fSaveAuxDetInfo && fSaveGeantInfo)
2225  evt.getView(fLArG4ModuleLabel, fAuxDetSimChannels);
2226 
2227  // * hits
2228  art::Handle< std::vector<recob::Hit> > hitListHandle;
2229  std::vector<art::Ptr<recob::Hit> > hitlist;
2230  if (evt.getByLabel(fHitsModuleLabel,hitListHandle))
2231  art::fill_ptr_vector(hitlist, hitListHandle);
2232 
2233  // * MC truth information
2234  art::Handle< std::vector<simb::MCTruth> > mctruthListHandle;
2235  std::vector<art::Ptr<simb::MCTruth> > mclist;
2236  if (evt.getByLabel(fGenieGenModuleLabel,mctruthListHandle))
2237  art::fill_ptr_vector(mclist, mctruthListHandle);
2238 
2239  // *MC truth cosmic generator information
2240  art::Handle< std::vector<simb::MCTruth> > mctruthcryListHandle;
2241  std::vector<art::Ptr<simb::MCTruth> > mclistcry;
2242  if (fSaveCryInfo){
2243  if (evt.getByLabel(fCryGenModuleLabel,mctruthcryListHandle))
2244  art::fill_ptr_vector(mclistcry, mctruthcryListHandle);
2245  }
2246 
2247  art::Ptr<simb::MCTruth> mctruthcry;
2248  int nCryPrimaries = 0;
2249 
2250  if (fSaveCryInfo){
2251  mctruthcry = mclistcry[0];
2252  nCryPrimaries = mctruthcry->NParticles();
2253  }
2254 
2255  int nGeniePrimaries = 0, nGEANTparticles = 0, nMCNeutrinos = 0;
2256 
2257  auto const clockData = art::ServiceHandle<detinfo::DetectorClocksService const>()->DataFor(evt);
2258 
2259  art::Ptr<simb::MCTruth> mctruth;
2260 
2261  if (isMC) { //is MC
2262 
2263  // Determine if there are cosmics
2264  if (!mclist.empty()){ //at least one mc record
2265  static bool isfirsttime = true;
2266  if (isfirsttime){
2267  for (size_t i = 0; i<hitlist.size(); i++){
2268  // tbrooks: use TrackIDEs rather than eveTrackIDEs because the eve ID doesn't always seem
2269  // to correspond to the g4 track (FIXME may need further investigation)
2270  if(DoesHitHaveSimChannel(fSimChannels,hitlist[i])) {
2271  std::vector<sim::TrackIDE> eveIDs = bt_serv->HitToTrackIDEs(clockData, hitlist[i]);
2272  for (size_t e = 0; e<eveIDs.size(); e++){
2273  art::Ptr<simb::MCTruth> ev_mctruth;
2274  if( TrackIdToMCTruth(eveIDs[e].trackID, ev_mctruth)){
2275  if (ev_mctruth->Origin() == simb::kCosmicRay) isCosmics = true;
2276  break;
2277  }
2278  }
2279  }//check if simchan exists
2280  if( isCosmics ) break; // stop looping if we've already figured it out
2281  }//loop over hits
2282  isfirsttime = false;
2283  if (fSaveCaloCosmics) isCosmics = false; //override to save calo info
2284  }//isfirsttime
2285 
2286  mctruth = mclist[0];
2287  if (mctruth->NeutrinoSet()) nGeniePrimaries = mctruth->NParticles();
2288 
2289  const sim::ParticleList& plist = pi_serv->ParticleList();
2290  nGEANTparticles = plist.size();
2291 
2292  // to know the number of particles in AV would require
2293  // looking at all of them; so we waste some memory here
2294  } // if has MC truth
2295 
2296  MF_LOG_DEBUG("AnalysisTree") << "Expected "
2297  << nGEANTparticles << " GEANT particles, "
2298  << nGeniePrimaries << " GENIE particles";
2299  } // if MC
2300 
2301  //Brailsford 2017/10/16
2302  //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
2303  nMCNeutrinos = mclist.size();
2304 
2305  CreateData(); // tracker data is created with default constructor
2306  if (fSaveGenieInfo){
2307  fData->ResizeGenie(nGeniePrimaries);
2308  fData->ResizeMCNeutrino(nMCNeutrinos);
2309  }
2310  if (fSaveCryInfo)
2311  fData->ResizeCry(nCryPrimaries);
2312  if (fSaveGeantInfo)
2313  fData->ResizeGEANT(nGEANTparticles);
2314  fData->ClearLocalData(); // don't bother clearing tracker data yet
2315 
2316 // const size_t Nplanes = 3; // number of wire planes; pretty much constant...
2317  const size_t NTrackers = GetNTrackers(); // number of trackers passed into fTrackModuleLabel
2318  const size_t NHits = hitlist.size(); // number of hits
2319  // make sure there is the data, the tree and everything;
2320  CreateTree();
2321 
2322  /// transfer the run and subrun data to the tree data object
2323 // fData->RunData = RunData;
2324  fData->SubRunData = SubRunData;
2325 
2326  fData->isdata = int(!isMC);
2327 
2328  /*****************************************************************************/
2329  // Added by Rhiannon on 2nd October 2018 for MCP 0.9
2330  // If the user is requesting to save hierarchical information, the producers
2331  // must be from pandora and are therefore able to go via PFParticles to get
2332  // track and vertex associations and their corresponding hierarchy
2333  //
2334  // IF saving the hierarchy has been requested, check that the pfparticle
2335  // object exists, and that it has track and vertex associations
2336  // Fill maps with tracks and vertices as the key, and pfparticles as the object
2337  // When saving track and vertex information, add additional query for
2338  // saving the hierarchy and save the information
2339  //
2340  /// Declare the track handle and vector for all the different tracking producers
2341  std::vector< art::Handle< std::vector<recob::Track> > > trackListHandle(NTrackers);
2342  std::vector< art::Handle< std::vector<recob::Vertex> > > vtxListHandle(NTrackers);
2343  art::Handle< std::vector<recob::Shower> > showerHandle;
2344  std::vector< std::vector<art::Ptr<recob::Track> > > tracklist(NTrackers);
2345  std::vector< std::vector< art::Ptr<recob::Vertex> > > vtxlist(NTrackers);
2346  std::vector< art::Ptr<recob::Shower> > shwlist;
2347  std::vector< int > NVertices;
2348 
2349  // Declare maps for track and vertex to pfparticle associations
2350  // this is the opposite way around to how they are produced
2351  typedef std::map<art::Ptr<recob::Track>, art::Ptr<recob::PFParticle> > trkPfpMap;
2352  typedef std::map<art::Ptr<recob::Vertex>, art::Ptr<recob::PFParticle> > vtxPfpMap;
2353  typedef std::map<art::Ptr<recob::Shower>, art::Ptr<recob::PFParticle> > shwPfpMap;
2354  typedef std::map<art::Ptr<recob::Track>, art::Ptr<recob::PFParticle> >::const_iterator trkPfpMapIt;
2355  typedef std::map<art::Ptr<recob::Vertex>, art::Ptr<recob::PFParticle> >::const_iterator vtxPfpMapIt;
2356  typedef std::map<art::Ptr<recob::Shower>, art::Ptr<recob::PFParticle> >::const_iterator shwPfpMapIt;
2357 
2358  trkPfpMap trackPFParticleMap;
2359  vtxPfpMap vertexPFParticleMap;
2360  shwPfpMap showerPFParticleMap;
2363  std::vector< trkPfpMap > trackerPFParticleMaps;
2364  std::vector< vtxPfpMap > verticesPFParticleMaps;
2365 
2366  // Create the PFParticle handle and fill it
2367  art::Handle< std::vector<recob::PFParticle> > pfpHandle;
2368  if(evt.getByLabel(fPFParticleModuleLabel,pfpHandle)){
2369  if(pfpHandle->size()){
2370  art::fill_ptr_vector(pfplist, pfpHandle);
2372  } else {
2373  mf::LogError("AnalysisTree:limits") << " Event has no PFParticle information ";
2374  }
2375  }
2376 
2377  // Loop over trackers and see if the hierarchy information needs saving
2378  for (unsigned int iTracker=0; iTracker < NTrackers; ++iTracker){
2379  verticesPFParticleMaps.push_back(vertexPFParticleMap);
2380  trackerPFParticleMaps.push_back(trackPFParticleMap);
2381 
2382  if(!fSaveHierarchyInfo[iTracker]) continue;
2383 
2384  // Get and check that the pfparticle handle is valid and exists
2385  //if(pfpHandle->empty())
2386  // mf::LogError("AnalysisTree:limits") << " Event has no PFParticle information ";
2387 
2388  // Track and vertex associations
2389  art::FindManyP<recob::Vertex> fvtx(pfpHandle, evt, fVertexModuleLabel[iTracker]);
2390  art::FindManyP<recob::Track> fmtrk(pfpHandle, evt, fTrackModuleLabel[iTracker]);
2391 
2392  for(unsigned int i = 0; i < pfpHandle->size(); ++i) {
2393  const art::Ptr< recob::PFParticle > pfp( pfpHandle, i );
2394 
2395  // Get vertex association
2396  std::vector< art::Ptr<recob::Vertex> > vtxAssn = fvtx.at(pfp.key());
2397 
2398  // Make sure there is exactly 1 vertex associated to each pfparticle
2399  if(vtxAssn.size() > 1){
2400  throw cet::exception("AnalysisTree:limits") << "PFParticle has " << vtxAssn.size() << " associated vertices, should only have 1 or 0 ";
2401  }
2402  if(vtxAssn.size() == 0) continue;
2403  verticesPFParticleMaps.at(iTracker).emplace(vtxAssn.front(),pfp);
2404  }
2405  // Fill the vector of maps for each tracker
2406  for(unsigned int i = 0; i < pfpHandle->size(); ++i) {
2407  const art::Ptr< recob::PFParticle > pfp( pfpHandle, i );
2408 
2409  std::vector< art::Ptr<recob::Track> > trkAssn = fmtrk.at(pfp.key());
2410  if(trkAssn.size() > 1){
2411  throw cet::exception("AnalysisTree:limits") << "PFParticle has " << trkAssn.size() << " associated tracks, should only have 1 or 0 ";
2412  }
2413  if(trkAssn.size() == 0) continue;
2414  trackerPFParticleMaps.at(iTracker).emplace(trkAssn.front(),pfp);
2415  }
2416  }// end loop over trackers
2417 
2419  if(pfpHandle->size()) {
2420  art::FindManyP<recob::Shower> fshw(pfpHandle, evt, fShowerModuleLabel);
2421  for(unsigned int i = 0; i < pfpHandle->size(); ++i) {
2422  art::Ptr< recob::PFParticle > pfp( pfpHandle, i );
2423 
2424  // Get shower association
2425  std::vector< art::Ptr<recob::Shower> > shwAssn = fshw.at(pfp->Self());
2426 
2427  // Make sure there is maximum 1 shower associated to each pfparticle
2428  if(shwAssn.size() > 1){
2429  mf::LogError("AnalysisTree:limits") << "PFParticle has " << shwAssn.size() << " associated showers, should only have 1 or 0 ";
2430  continue;
2431  }
2432  if(shwAssn.size() == 0) continue;
2433  showerPFParticleMap.emplace(shwAssn[0],pfp);
2434 
2435  }
2436  }
2437  } // save maps for SaveShowerHierarchyInfo
2438 
2439  if (evt.getByLabel(fShowerModuleLabel,showerHandle))
2440  art::fill_ptr_vector(shwlist, showerHandle);
2441  const size_t NShowers = shwlist.size();
2442 
2443  for (unsigned int it = 0; it < NTrackers; ++it){
2444  if (evt.getByLabel(fTrackModuleLabel[it],trackListHandle[it]))
2445  art::fill_ptr_vector(tracklist[it], trackListHandle[it]);
2446  if (evt.getByLabel(fVertexModuleLabel[it],vtxListHandle[it]))
2447  art::fill_ptr_vector(vtxlist[it], vtxListHandle[it]);
2448  }
2449 
2450 
2451  fData->run = evt.run();
2452  fData->subrun = evt.subRun();
2453  fData->event = evt.id().event();
2454 
2455  art::Timestamp ts = evt.time();
2456  TTimeStamp tts(ts.timeHigh(), ts.timeLow());
2457  fData->evttime = tts.AsDouble();
2458 
2459 
2460  //copied from MergeDataPaddles.cxx
2461  art::Handle< raw::BeamInfo > beam;
2462  if (evt.getByLabel("beam",beam)){
2463  fData->beamtime = (double)beam->get_t_ms();
2464  fData->beamtime/=1000.; //in second
2465  }
2466 
2467 // std::cout<<detprop->NumberTimeSamples()<<" "<<detprop->ReadOutWindowSize()<<std::endl;
2468 // std::cout<<geom->DetHalfHeight()*2<<" "<<geom->DetHalfWidth()*2<<" "<<geom->DetLength()<<std::endl;
2469 // std::cout<<geom->Nwires(0)<<" "<<geom->Nwires(1)<<" "<<geom->Nwires(2)<<std::endl;
2470 
2471  //hit information
2472  fData->no_hits = (int) NHits; // save this # even if we aren't saving info for *every* hit
2473  if (fSaveHitInfo){
2474  if (NHits > kMaxHits) {
2475  // got this error? consider increasing kMaxHits
2476  // (or ask for a redesign using vectors)
2477  mf::LogError("AnalysisTree:limits") << "event has " << NHits
2478  << " hits, only kMaxHits=" << kMaxHits << " stored in tree";
2479  }
2480  for (size_t i = 0; i < NHits && i < kMaxHits ; ++i){//loop over hits
2481  fData->hit_channel[i] = hitlist[i]->Channel();
2482  fData->hit_tpc[i] = hitlist[i]->WireID().TPC;
2483  fData->hit_plane[i] = hitlist[i]->WireID().Plane;
2484  fData->hit_wire[i] = hitlist[i]->WireID().Wire;
2485  fData->hit_peakT[i] = hitlist[i]->PeakTime();
2486  fData->hit_charge[i] = hitlist[i]->Integral();
2487  fData->hit_ph[i] = hitlist[i]->PeakAmplitude();
2488  fData->hit_startT[i] = hitlist[i]->PeakTimeMinusRMS();
2489  fData->hit_endT[i] = hitlist[i]->PeakTimePlusRMS();
2490  fData->hit_width[i] = hitlist[i]->RMS();
2491  fData->hit_reconelec[i] = fCaloAlg.ElectronsFromADCArea(hitlist[i]->Integral(),hitlist[i]->WireID().Plane);
2492 
2493  /*
2494  for (unsigned int it=0; it<fTrackModuleLabel.size();++it){
2495  art::FindManyP<recob::Track> fmtk(hitListHandle,evt,fTrackModuleLabel[it]);
2496  if (fmtk.at(i).size()!=0){
2497  hit_trkid[it][i] = fmtk.at(i)[0]->ID();
2498  }
2499  else
2500  hit_trkid[it][i] = 0;
2501  }
2502  */
2503 
2504  if (!evt.isRealData()){
2505  // First determine if this hit matches to a simchannel (otherwise HitToTrackIDE will complain)
2506  if( DoesHitHaveSimChannel(fSimChannels,hitlist[i]) ) {
2507  // Get total energy and electrons by finding sim::TrackIDE associated with this hit
2508  HitTruth(clockData, hitlist[i], fData->hit_mcid[i], fData->hit_frac[i], fData->hit_energy[i], fData->hit_nelec[i]);
2509  }//endif simchan was found
2510  }//endif MC
2511 
2512  }//endloop over hits
2513 
2514  if (evt.getByLabel(fHitsModuleLabel,hitListHandle)){
2515  //Find tracks associated with hits
2516  art::FindManyP<recob::Track> fmtk(hitListHandle,evt,fTrackModuleLabel[0]);
2517  for (size_t i = 0; i < NHits && i < kMaxHits ; ++i){//loop over hits
2518  if (fmtk.isValid()){
2519  if (fmtk.at(i).size()!=0) fData->hit_trkid[i] = fmtk.at(i)[0]->ID();
2520  else fData->hit_trkid[i] = -1;
2521  }
2522  }
2523  }
2524 
2525  }// end (fSaveHitInfo)
2526 
2527  //vertex information
2528  if (fSaveVertexInfo){
2529  for (unsigned int iTracker=0; iTracker < NTrackers; ++iTracker){
2530  AnalysisTreeDataStruct::VertexDataStruct& VertexData = fData->GetVertexData(iTracker);
2531 
2532  size_t NVertices = vtxlist[iTracker].size();
2533  // allocate enough space for this number of tracks (but at least for one of them!)
2534  VertexData.SetMaxVertices(std::max(NVertices, (size_t) 1));
2535  VertexData.Clear(); // clear all the data
2536 
2537  VertexData.nvtx = static_cast<int>(NVertices);
2538 
2539  // now set the tree addresses to the newly allocated memory;
2540  // this creates the tree branches in case they are not there yet
2541  SetVerticesAddresses(iTracker);
2542  if (NVertices > VertexData.GetMaxVertices()) {
2543  // got this error? it might be a bug,
2544  // since we are supposed to have allocated enough space to fit all vertices
2545  mf::LogError("AnalysisTree:limits") << "event has " << NVertices
2546  << " " << fVertexModuleLabel[iTracker] << " vertices, only "
2547  << VertexData.GetMaxVertices() << " stored in tree";
2548  }
2549 
2550  for (size_t i = 0; i < NVertices && i < kMaxVertices ; ++i){//loop over vertices
2551  art::Ptr<recob::Vertex> pvertex(vtxListHandle[iTracker], i);
2552 // art::Ptr<recob::Vertex> pvertex = vtxlist[iTracker].at(i);
2553  Double_t xyz[3];
2554  pvertex->XYZ(xyz);
2555  for (size_t j = 0; j<3; ++j){
2556  VertexData.vtx[i][j] = xyz[j];
2557  }
2558 
2559  // If also saving the hierarchy info, set the primaryvtx boolean
2560  if(fSaveHierarchyInfo[iTracker]){
2561  vtxPfpMap vertexPFParticleMap = verticesPFParticleMaps.at(iTracker);
2562  vtxPfpMapIt it = vertexPFParticleMap.find(pvertex);
2563  // Check there is a map entry for this vertex
2564 
2565  if(it == vertexPFParticleMap.end()) continue;
2566 
2567  art::Ptr<recob::PFParticle> tempParticle = it->second;
2568  if(tempParticle->IsPrimary())
2569  VertexData.primaryvtx[i] = 1;
2570  else VertexData.primaryvtx[i] = 0;
2571  }// end (fSaveHierarchyInfo)
2572  }// end loop over vertices
2573  }// end loop over trackers
2574  }// end (fSaveVertexInfo)
2575 
2576  // shower information
2577  if (fSaveShowerInfo){
2578  AnalysisTreeDataStruct::ShowerDataStruct& ShowerData = fData->GetShowerData();
2579  if (NShowers > kMaxShowers){
2580  // got this error? consider increasing kMaxShowers
2581  // (or ask for a redesign using vectors)
2582  mf::LogError("AnalysisTree:limits") << "event has " << NShowers
2583  << " showers, only kMaxShowers=" << kMaxShowers << " stored in tree";
2584  }
2585  ShowerData.SetMaxShowers(std::max(NShowers, (size_t) 1));
2586  ShowerData.Clear();
2587 
2588  ShowerData.nshowers = (int) NShowers;
2589 
2590  SetShowerAddresses();
2591 
2592  for (size_t i = 0; i < NShowers && i < kMaxShowers ; ++i){//loop over showers
2593  const art::Ptr<recob::Shower> &shw = shwlist[i];
2594 
2595  ShowerData.shwId[i] = shw->ID();
2596  ShowerData.shwbestplane[i] = shw->best_plane();
2597  ShowerData.shwlength[i] = shw->Length();
2598  ShowerData.shwopenangle[i] = shw->OpenAngle();
2599  ShowerData.shwstartx[i] = shw->ShowerStart()[0];
2600  ShowerData.shwstarty[i] = shw->ShowerStart()[1];
2601  ShowerData.shwstartz[i] = shw->ShowerStart()[2];
2602  ShowerData.shwdirx[i] = shw->Direction()[0];
2603  ShowerData.shwdiry[i] = shw->Direction()[1];
2604  ShowerData.shwdirz[i] = shw->Direction()[2];
2605 
2606  // If also saving the hierarchy info, set the primaryvtx boolean
2608  shwPfpMapIt it;
2609  // Check there is a map entry for this vertex
2610  it = showerPFParticleMap.find(shw);
2611  if(it == showerPFParticleMap.end()) continue;
2612 
2613  art::Ptr<recob::PFParticle> tempParticle = it->second;
2614  ShowerData.shwisprimary[i] = std::round(static_cast<Int_t>(lar_pandora::LArPandoraHelper::IsFinalState(pfpmap,tempParticle)));
2615  ShowerData.shwndaughters[i] = tempParticle->NumDaughters();
2616  ShowerData.shwpfpid[i] = tempParticle->Self();
2617  ShowerData.shwparentpfpid[i] = tempParticle->Parent();
2618  }// end (fSaveHierarchyInfo)
2619  }
2620  }// end (fSaveShowerInfo)
2621 
2622  //track information for multiple trackers
2623  if (fSaveTrackInfo){
2624  for (unsigned int iTracker=0; iTracker < NTrackers; ++iTracker){
2625  AnalysisTreeDataStruct::TrackDataStruct& TrackerData = fData->GetTrackerData(iTracker);
2626 
2627  size_t NTracks = tracklist[iTracker].size();
2628  // allocate enough space for this number of tracks (but at least for one of them!)
2629  TrackerData.SetMaxTracks(std::max(NTracks, (size_t) 1));
2630  TrackerData.Clear(); // clear all the data
2631 
2632  TrackerData.ntracks = (int) NTracks;
2633 
2634  // now set the tree addresses to the newly allocated memory;
2635  // this creates the tree branches in case they are not there yet
2636  SetTrackerAddresses(iTracker);
2637  if (NTracks > TrackerData.GetMaxTracks()) {
2638  // got this error? it might be a bug,
2639  // since we are supposed to have allocated enough space to fit all tracks
2640  mf::LogError("AnalysisTree:limits") << "event has " << NTracks
2641  << " " << fTrackModuleLabel[iTracker] << " tracks, only "
2642  << TrackerData.GetMaxTracks() << " stored in tree";
2643  }
2644  AnalysisTreeDataStruct::VertexDataStruct& VertexData = fData->GetVertexData(iTracker);
2645 
2646  size_t NVertices = vtxlist[iTracker].size();
2647 
2648  // now set the tree addresses to the newly allocated memory;
2649  // this creates the tree branches in case they are not there yet
2650  SetVerticesAddresses(iTracker);
2651  if (NVertices > VertexData.GetMaxVertices()) {
2652  // got this error? it might be a bug,
2653  // since we are supposed to have allocated enough space to fit all tracks
2654  mf::LogError("AnalysisTree:limits") << "event has " << NVertices
2655  << " " << fVertexModuleLabel[iTracker] << " vertices, only "
2656  << VertexData.GetMaxVertices() << " stored in tree";
2657  }
2658 
2659  //call the track momentum algorithm that gives you momentum based on track range
2661 
2662  for(size_t iTrk=0; iTrk < NTracks; ++iTrk){//loop over tracks
2663  //Cosmic Tagger information
2664  if (fCosmicTaggerAssocLabel.size() > iTracker) {
2665  art::FindManyP<anab::CosmicTag> fmct(trackListHandle[iTracker],evt,fCosmicTaggerAssocLabel[iTracker]);
2666  if (fmct.isValid()){
2667  TrackerData.trkncosmictags_tagger[iTrk] = fmct.at(iTrk).size();
2668  if (fmct.at(iTrk).size()>0){
2669  if(fmct.at(iTrk).size()>1)
2670  std::cerr << "\n Warning : more than one cosmic tag per track in module! assigning the first tag to the track" << fCosmicTaggerAssocLabel[iTracker];
2671  TrackerData.trkcosmicscore_tagger[iTrk] = fmct.at(iTrk).at(0)->CosmicScore();
2672  TrackerData.trkcosmictype_tagger[iTrk] = fmct.at(iTrk).at(0)->CosmicType();
2673  }
2674  }
2675  } // if we have matching fCosmicTaggerAssocLabel
2676 
2677  //Flash match compatibility information
2678  if (fFlashMatchAssocLabel.size() > iTracker) {
2679  //Unlike CosmicTagger, Flash match doesn't assign a cosmic tag for every track. For those tracks, AnalysisTree initializes them with -9999 or -99999
2680  art::FindManyP<anab::CosmicTag> fmbfm(trackListHandle[iTracker],evt,fFlashMatchAssocLabel[iTracker]);
2681  if (fmbfm.isValid()){
2682  TrackerData.trkncosmictags_flashmatch[iTrk] = fmbfm.at(iTrk).size();
2683  if (fmbfm.at(iTrk).size()>0){
2684  if(fmbfm.at(iTrk).size()>1)
2685  std::cerr << "\n Warning : more than one cosmic tag per track in module! assigning the first tag to the track" << fFlashMatchAssocLabel[iTracker];
2686  TrackerData.trkcosmicscore_flashmatch[iTrk] = fmbfm.at(iTrk).at(0)->CosmicScore();
2687  TrackerData.trkcosmictype_flashmatch[iTrk] = fmbfm.at(iTrk).at(0)->CosmicType();
2688  //std::cout<<"\n"<<evt.event()<<"\t"<<iTrk<<"\t"<<fmbfm.at(iTrk).at(0)->CosmicScore()<<"\t"<<fmbfm.at(iTrk).at(0)->CosmicType();
2689  }
2690  }
2691  } // if we have matching fFlashMatchAssocLabel
2692 
2693  art::Ptr<recob::Track> ptrack(trackListHandle[iTracker], iTrk);
2694  const recob::Track& track = *ptrack;
2695 
2696  double tlen = 0.;
2697  double mom = 0.;
2698  int TrackID = -1;
2699 
2700  int ntraj = track.NumberTrajectoryPoints();
2701  if (ntraj > 0) {
2702  const auto& pos = track.Vertex();
2703  const auto& dir_start = track.VertexDirection();
2704  const auto& dir_end = track.EndDirection();
2705  const auto& end = track.End();
2706 
2707  tlen = length(track);
2708  if(track.HasMomentum() > 0)
2709  mom = track.VertexMomentum();
2710  TrackID = track.ID();
2711 
2712  double theta_xz = std::atan2(dir_start.X(), dir_start.Z());
2713  double theta_yz = std::atan2(dir_start.Y(), dir_start.Z());
2714  double dpos = bdist(pos);
2715  double dend = bdist(end);
2716 
2717  TrackerData.trkId[iTrk] = TrackID;
2718  TrackerData.trkstartx[iTrk] = pos.X();
2719  TrackerData.trkstarty[iTrk] = pos.Y();
2720  TrackerData.trkstartz[iTrk] = pos.Z();
2721  TrackerData.trkstartd[iTrk] = dpos;
2722  TrackerData.trkendx[iTrk] = end.X();
2723  TrackerData.trkendy[iTrk] = end.Y();
2724  TrackerData.trkendz[iTrk] = end.Z();
2725  TrackerData.trkendd[iTrk] = dend;
2726  TrackerData.trktheta[iTrk] = dir_start.Theta();
2727  TrackerData.trkphi[iTrk] = dir_start.Phi();
2728  TrackerData.trkstartdcosx[iTrk] = dir_start.X();
2729  TrackerData.trkstartdcosy[iTrk] = dir_start.Y();
2730  TrackerData.trkstartdcosz[iTrk] = dir_start.Z();
2731  TrackerData.trkenddcosx[iTrk] = dir_end.X();
2732  TrackerData.trkenddcosy[iTrk] = dir_end.Y();
2733  TrackerData.trkenddcosz[iTrk] = dir_end.Z();
2734  TrackerData.trkthetaxz[iTrk] = theta_xz;
2735  TrackerData.trkthetayz[iTrk] = theta_yz;
2736  TrackerData.trkmom[iTrk] = mom;
2737  TrackerData.trklen[iTrk] = tlen;
2738  TrackerData.trkmomrange[iTrk] = trkm.GetTrackMomentum(tlen,13);
2739  TrackerData.trkmommschi2[iTrk] = trkm.GetMomentumMultiScatterChi2(ptrack);
2740  TrackerData.trkmommsllhd[iTrk] = trkm.GetMomentumMultiScatterLLHD(ptrack);
2741  } // if we have trajectory
2742 
2743  // find vertices associated with this track
2744  /*
2745  art::FindMany<recob::Vertex> fmvtx(trackListHandle[iTracker], evt, fVertexModuleLabel[iTracker]);
2746  if(fmvtx.isValid()) {
2747  std::vector<const recob::Vertex*> verts = fmvtx.at(iTrk);
2748  // should have two at most
2749  for(size_t ivx = 0; ivx < verts.size(); ++ivx) {
2750  verts[ivx]->XYZ(xyz);
2751  // find the vertex in TrackerData to get the index
2752  short theVtx = -1;
2753  for(short jvx = 0; jvx < TrackerData.nvtx; ++jvx) {
2754  if(TrackerData.vtx[jvx][2] == xyz[2]) {
2755  theVtx = jvx;
2756  break;
2757  }
2758  } // jvx
2759  // decide if it should be assigned to the track Start or End.
2760  // A simple dz test should suffice
2761  if(fabs(xyz[2] - TrackerData.trkstartz[iTrk]) <
2762  fabs(xyz[2] - TrackerData.trkendz[iTrk])) {
2763  TrackerData.trksvtxid[iTrk] = theVtx;
2764  } else {
2765  TrackerData.trkevtxid[iTrk] = theVtx;
2766  }
2767  } // vertices
2768  } // fmvtx.isValid()
2769  */
2770  Float_t minsdist = 10000;
2771  Float_t minedist = 10000;
2772  for (int ivx = 0; ivx < VertexData.nvtx && ivx < kMaxVertices; ++ivx){
2773  Float_t sdist = sqrt(pow(TrackerData.trkstartx[iTrk]-VertexData.vtx[ivx][0],2)+
2774  pow(TrackerData.trkstarty[iTrk]-VertexData.vtx[ivx][1],2)+
2775  pow(TrackerData.trkstartz[iTrk]-VertexData.vtx[ivx][2],2));
2776  Float_t edist = sqrt(pow(TrackerData.trkendx[iTrk]-VertexData.vtx[ivx][0],2)+
2777  pow(TrackerData.trkendy[iTrk]-VertexData.vtx[ivx][1],2)+
2778  pow(TrackerData.trkendz[iTrk]-VertexData.vtx[ivx][2],2));
2779  if (sdist<minsdist){
2780  minsdist = sdist;
2781  if (minsdist<10) TrackerData.trksvtxid[iTrk] = ivx;
2782  }
2783  if (edist<minedist){
2784  minedist = edist;
2785  if (minedist<10) TrackerData.trkevtxid[iTrk] = ivx;
2786  }
2787  }
2788 
2789  // find particle ID info
2790  art::FindMany<anab::ParticleID> fmpid(trackListHandle[iTracker], evt, fParticleIDModuleLabel[iTracker]);
2791  if(fmpid.isValid()) {
2792  std::vector<const anab::ParticleID*> pids = fmpid.at(iTrk);
2793  if (pids.size() == 0){
2794  mf::LogError("AnalysisTree:limits")
2795  << "No track-PID association found for " << fTrackModuleLabel[iTracker]
2796  << " track " << iTrk << ". Not saving particleID information.";
2797  }
2798  // Set dummy values
2799  double pidpdg[3] = {0,0,0};
2800  double pidchi[3] = {0.,0.,0.};
2801  for(size_t planenum=0; planenum<3; ++planenum) {
2802  TrackerData.trkpidchimu[iTrk][planenum] = 0.;
2803  TrackerData.trkpidchipi[iTrk][planenum] = 0.;
2804  TrackerData.trkpidchika[iTrk][planenum] = 0.;
2805  TrackerData.trkpidchipr[iTrk][planenum] = 0.;
2806  TrackerData.trkpidpida[iTrk][planenum] = 0.;
2807  }
2808  for (size_t ipid=0; ipid<pids.size(); ipid++){
2809  std::vector<anab::sParticleIDAlgScores> AlgScoresVec = pids[ipid]->ParticleIDAlgScores();
2810 
2811  // Loop though AlgScoresVec and find the variables we want
2812  for (size_t i_algscore=0; i_algscore<AlgScoresVec.size(); i_algscore++){
2813  anab::sParticleIDAlgScores AlgScore = AlgScoresVec.at(i_algscore);
2814 
2815  /*std::cout << "\n ParticleIDAlg " << AlgScore.fAlgName
2816  << "\n -- Variable type: " << AlgScore.fVariableType
2817  << "\n -- Track direction: " << AlgScore.fTrackDir
2818  << "\n -- Assuming PDG: " << AlgScore.fAssumedPdg
2819  << "\n -- Number of degrees of freedom: " << AlgScore.fNdf
2820  << "\n -- Value: " << AlgScore.fValue
2821  << "\n -- Using planeMask: " << AlgScore.fPlaneMask << std::endl;*/
2822 
2823  if (AlgScore.fPlaneMask.none() || AlgScore.fPlaneMask.count() > 1) continue;
2824  int planenum = -1;
2825  if (AlgScore.fPlaneMask.test(0)) planenum = 0;
2826  if (AlgScore.fPlaneMask.test(1)) planenum = 1;
2827  if (AlgScore.fPlaneMask.test(2)) planenum = 2;
2828  if (planenum<0 || planenum>2) continue;
2829 
2830  if (AlgScore.fAlgName == "Chi2"){
2831  if (TMath::Abs(AlgScore.fAssumedPdg) == 13){ // chi2mu
2832  TrackerData.trkpidchimu[iTrk][planenum] = AlgScore.fValue;
2833  if (AlgScore.fValue<pidchi[planenum] || (pidchi[planenum] == 0. && AlgScore.fValue>0.)){
2834  pidchi[planenum] = AlgScore.fValue;
2835  pidpdg[planenum] = TMath::Abs(AlgScore.fAssumedPdg);
2836  }
2837  }
2838  else if (TMath::Abs(AlgScore.fAssumedPdg) == 2212){ // chi2pr
2839  TrackerData.trkpidchipr[iTrk][planenum] = AlgScore.fValue;
2840  if (AlgScore.fValue<pidchi[planenum] || (pidchi[planenum] == 0. && AlgScore.fValue>0.)){
2841  pidchi[planenum] = AlgScore.fValue;
2842  pidpdg[planenum] = TMath::Abs(AlgScore.fAssumedPdg);
2843  }
2844  }
2845  else if (TMath::Abs(AlgScore.fAssumedPdg) == 211){ // chi2pi
2846  TrackerData.trkpidchipi[iTrk][planenum] = AlgScore.fValue;
2847  if (AlgScore.fValue<pidchi[planenum] || (pidchi[planenum] == 0. && AlgScore.fValue>0.)){
2848  pidchi[planenum] = AlgScore.fValue;
2849  pidpdg[planenum] = TMath::Abs(AlgScore.fAssumedPdg);
2850  }
2851  }
2852  else if (TMath::Abs(AlgScore.fAssumedPdg) == 321){ // chi2ka
2853  TrackerData.trkpidchika[iTrk][planenum] = AlgScore.fValue;
2854  if (AlgScore.fValue<pidchi[planenum] || (pidchi[planenum] == 0. && AlgScore.fValue>0.)){
2855  pidchi[planenum] = AlgScore.fValue;
2856  pidpdg[planenum] = TMath::Abs(AlgScore.fAssumedPdg);
2857  }
2858  }
2859 
2860  }
2861  else if (AlgScore.fVariableType==anab::kPIDA){
2862  TrackerData.trkpidpida[iTrk][planenum] = AlgScore.fValue;
2863  }
2864 
2865  } // end loop though AlgScoresVec
2866  } // end loop over pid[ipid]
2867 
2868  // Finally, set min chi2
2869  for (size_t planenum=0; planenum<3; planenum++){
2870  TrackerData.trkpidchi[iTrk][planenum] = pidchi[planenum];
2871  TrackerData.trkpidpdg[iTrk][planenum] = pidpdg[planenum];
2872  }
2873  } // fmpid.isValid()
2874 
2875  art::FindMany<anab::Calorimetry> fmcal(trackListHandle[iTracker], evt, fCalorimetryModuleLabel[iTracker]);
2876  if (fmcal.isValid()){
2877  std::vector<const anab::Calorimetry*> calos = fmcal.at(iTrk);
2878  if (calos.size() > TrackerData.GetMaxPlanesPerTrack(iTrk)) {
2879  // if you get this message, there is probably a bug somewhere since
2880  // the calorimetry planes should be 3.
2881  mf::LogError("AnalysisTree:limits")
2882  << "the " << fTrackModuleLabel[iTracker] << " track #" << iTrk
2883  << " has " << calos.size() << " planes for calorimetry , only "
2884  << TrackerData.GetMaxPlanesPerTrack(iTrk) << " stored in tree";
2885  }
2886  for (size_t ical = 0; ical<calos.size(); ++ical){
2887  if (!calos[ical]) continue;
2888  if (!calos[ical]->PlaneID().isValid) continue;
2889  int planenum = calos[ical]->PlaneID().Plane;
2890  if (planenum<0||planenum>2) continue;
2891  TrackerData.trkke[iTrk][planenum] = calos[ical]->KineticEnergy();
2892  TrackerData.trkrange[iTrk][planenum] = calos[ical]->Range();
2893  //For now make the second argument as 13 for muons.
2894  TrackerData.trkpitchc[iTrk][planenum]= calos[ical] -> TrkPitchC();
2895  const size_t NHits = calos[ical] -> dEdx().size();
2896  TrackerData.ntrkhits[iTrk][planenum] = (int) NHits;
2897  if (NHits > TrackerData.GetMaxHitsPerTrack(iTrk, planenum)) {
2898  // if you get this error, you'll have to increase kMaxTrackHits
2899  mf::LogError("AnalysisTree:limits")
2900  << "the " << fTrackModuleLabel[iTracker] << " track #" << iTrk
2901  << " has " << NHits << " hits on calorimetry plane #" << planenum
2902  <<", only "
2903  << TrackerData.GetMaxHitsPerTrack(iTrk, planenum) << " stored in tree";
2904  }
2905  if (!isCosmics){
2906  for(size_t iTrkHit = 0; iTrkHit < NHits && iTrkHit < TrackerData.GetMaxHitsPerTrack(iTrk, planenum); ++iTrkHit) {
2907  TrackerData.trkdedx[iTrk][planenum][iTrkHit] = (calos[ical] -> dEdx())[iTrkHit];
2908  TrackerData.trkdqdx[iTrk][planenum][iTrkHit] = (calos[ical] -> dQdx())[iTrkHit];
2909  TrackerData.trkresrg[iTrk][planenum][iTrkHit] = (calos[ical] -> ResidualRange())[iTrkHit];
2910  const auto& TrkPos = (calos[ical] -> XYZ())[iTrkHit];
2911  auto& TrkXYZ = TrackerData.trkxyz[iTrk][planenum][iTrkHit];
2912  TrkXYZ[0] = TrkPos.X();
2913  TrkXYZ[1] = TrkPos.Y();
2914  TrkXYZ[2] = TrkPos.Z();
2915  } // for track hits
2916  }
2917  } // for calorimetry info
2918 
2919  // Find plane with most number of hits
2920  int bestPlane = 2, max = -999;
2921  for(size_t ipl = 0; ipl < 3; ipl++){
2922  int N = TrackerData.ntrkhits[iTrk][ipl];
2923  if( N > max ) { max = N; bestPlane = ipl;}
2924  }
2925  TrackerData.trkpidbestplane[iTrk] = bestPlane;
2926 
2927  } // if has calorimetry info
2928 
2929  //track truth information
2930  if (isMC){
2931  //get the hits on each plane
2932  art::FindManyP<recob::Hit> fmht(trackListHandle[iTracker], evt, fTrackModuleLabel[iTracker]);
2933  std::vector< art::Ptr<recob::Hit> > allHits = fmht.at(iTrk);
2934  std::vector< art::Ptr<recob::Hit> > hits[kNplanes];
2935 
2936  for(size_t ah = 0; ah < allHits.size(); ++ah){
2937  if (/* allHits[ah]->WireID().Plane >= 0 && */ // always true
2938  allHits[ah]->WireID().Plane < 3){
2939  hits[allHits[ah]->WireID().Plane].push_back(allHits[ah]);
2940  }
2941  }
2942 
2943  for (size_t ipl = 0; ipl < 3; ++ipl){
2944  TrackerData.trkidtruth_recoutils_totaltrueenergy[iTrk][ipl] = RecoUtils::TrueParticleIDFromTotalTrueEnergy(clockData, hits[ipl]);
2945  TrackerData.trkidtruth_recoutils_totalrecocharge[iTrk][ipl] = RecoUtils::TrueParticleIDFromTotalRecoCharge(clockData, hits[ipl]);
2946  TrackerData.trkidtruth_recoutils_totalrecohits[iTrk][ipl] = RecoUtils::TrueParticleIDFromTotalRecoHits(clockData, hits[ipl]);
2947  double maxe = 0;
2948  HitsPurity(clockData, hits[ipl],TrackerData.trkidtruth[iTrk][ipl],TrackerData.trkpurtruth[iTrk][ipl],maxe);
2949  //std::cout<<"\n"<<iTracker<<"\t"<<iTrk<<"\t"<<ipl<<"\t"<<trkidtruth[iTracker][iTrk][ipl]<<"\t"<<trkpurtruth[iTracker][iTrk][ipl]<<"\t"<<maxe;
2950  if (TrackerData.trkidtruth[iTrk][ipl]>0){
2951  const art::Ptr<simb::MCTruth> mc = pi_serv->TrackIdToMCTruth_P(TrackerData.trkidtruth[iTrk][ipl]);
2952  TrackerData.trkorigin[iTrk][ipl] = mc->Origin();
2953  const simb::MCParticle *particle = pi_serv->TrackIdToParticle_P(TrackerData.trkidtruth[iTrk][ipl]);
2954  double tote = 0;
2955  const std::vector<const sim::IDE*> vide(bt_serv->TrackIdToSimIDEs_Ps(TrackerData.trkidtruth[iTrk][ipl]));
2956  for (auto ide: vide) {
2957  tote += ide->energy;
2958  TrackerData.trksimIDEenergytruth[iTrk][ipl] = ide->energy;
2959  TrackerData.trksimIDExtruth[iTrk][ipl] = ide->x;
2960  TrackerData.trksimIDEytruth[iTrk][ipl] = ide->y;
2961  TrackerData.trksimIDEztruth[iTrk][ipl] = ide->z;
2962  }
2963  TrackerData.trkpdgtruth[iTrk][ipl] = particle->PdgCode();
2964  TrackerData.trkefftruth[iTrk][ipl] = maxe/(tote/kNplanes); //tote include both induction and collection energies
2965  //std::cout<<"\n"<<trkpdgtruth[iTracker][iTrk][ipl]<<"\t"<<trkefftruth[iTracker][iTrk][ipl];
2966  }
2967  }
2968  }//end if (isMC)
2969  // If saving the hierarchy info
2970  if(fSaveHierarchyInfo[iTracker]){
2971  trkPfpMap trackPFParticleMap = trackerPFParticleMaps[iTracker];
2972  trkPfpMapIt it;
2973  // Check there is a map entry for this vertex
2974  it = trackPFParticleMap.find(ptrack);
2975  if(it == trackPFParticleMap.end()) continue;
2976 
2977  art::Ptr<recob::PFParticle> tempParticle = it->second;
2978  // Get information, find the neutrino and then call its daughters
2979  // primary tracks
2980  TrackerData.trkisprimary[iTrk] = std::round(static_cast<Int_t>(lar_pandora::LArPandoraHelper::IsFinalState(pfpmap,tempParticle)));
2981  TrackerData.trkndaughters[iTrk] = tempParticle->NumDaughters();
2982  TrackerData.trkpfpid[iTrk] = tempParticle->Self();
2983  TrackerData.trkparentpfpid[iTrk] = tempParticle->Parent();
2984  } // end save hierarchy info
2985  }//end loop over track
2986  }//end loop over track module labels
2987  }// end (fSaveTrackInfo)
2988 
2989 
2990  //==================================================================
2991  // Added Apr 2021, wforeman
2992  //
2993  // Save PFParticle and slice information into the AnaTree. The slices
2994  // themselves are only useful for organizing associations between
2995  // other objects of common origin, so only info about the best-matched
2996  // neutrino slice is stored.
2997  //
2998  if( fSaveSliceInfo ) {
2999 
3000  // Get 'dem slices
3001  art::Handle< std::vector<recob::Slice> > sliceHandle;
3002  std::vector< art::Ptr<recob::Slice> > slicelist;
3003  if (evt.getByLabel(fPFParticleModuleLabel,sliceHandle))
3004  art::fill_ptr_vector(slicelist, sliceHandle);
3005 
3006  // Map PFPs to their slices
3007  art::FindManyP<recob::Slice> fm_pfpslice(pfpHandle, evt, fPFParticleModuleLabel);
3008  // Map slices to hits and PFParticles
3009  art::FindManyP<recob::PFParticle> fm_slicepfp(slicelist, evt, fPFParticleModuleLabel);
3010  art::FindManyP<recob::Hit> fm_slicehits(sliceHandle, evt, fPFParticleModuleLabel);
3011  // Map PFPs to their IDs for retrieval of nu scores
3012  art::FindManyP<larpandoraobj::PFParticleMetadata> fm_pfpmd(pfpHandle, evt, fPFParticleModuleLabel);
3013 
3014  // Loop over all PFPs, save PDG and associated slice id
3015  for(auto const &pfp : pfplist ) {
3016  std::vector< art::Ptr<recob::Slice> > slcAssn = fm_pfpslice.at(pfp.key());
3017  if(slcAssn.size() == 1) fData->pfp_sliceid[pfp.key()] = slcAssn.at(0)->ID();
3018  fData->pfp_pdg[pfp.key()] = pfp->PdgCode();
3019  }
3020 
3021  // Save the slice and PFP counts
3022  fData->num_pfps = (int) pfplist.size();
3023  fData->num_slices = (int) slicelist.size();
3024 
3025  // Loop over the slices, and check the PFPs in each (save nu slices and
3026  // PFPs into vectors so we can play with them later)
3027  std::vector<art::Ptr<recob::PFParticle>> nuPfpVec;
3028  std::vector<art::Ptr<recob::Slice>> nuSliceVec;
3029  for(auto const &slice : slicelist ) {
3030  std::vector<art::Ptr<recob::PFParticle>> slicePFPs = fm_slicepfp.at(slice.key());
3031  for (auto const &pfp : slicePFPs) {
3032  if ((pfp->PdgCode() == 12 || pfp->PdgCode() == 14)) { // look for neutrino
3033  nuPfpVec.push_back(pfp);
3034  nuSliceVec.push_back(slice);
3035  break; // should be 1 nu per slice
3036  }//endif neutrino
3037  }//endloop over slicePFPs
3038  }//endloop over slices
3039 
3040  fData->num_nuslices = (int)nuPfpVec.size();
3041 
3042  // If we found neutrino slices...
3043  if(nuPfpVec.size()){
3044 
3045  // ...find the best neutrino slice
3046  float bestScore = -999.;
3047  art::Ptr<recob::Slice> bestNuSlice;
3048  art::Ptr<recob::PFParticle> bestNuPfp;
3049  for(size_t i=0; i<nuPfpVec.size(); i++){
3050  float score = -999.;
3051  // Get the metadata to get the MVA score (there's probably a less clunky way to do this...)
3052  const std::vector<art::Ptr<larpandoraobj::PFParticleMetadata>> pfpMetaVec = fm_pfpmd.at(nuPfpVec.at(i)->Self());
3053  for (auto const pfpMeta : pfpMetaVec) {
3054  larpandoraobj::PFParticleMetadata::PropertiesMap propertiesMap = pfpMeta->GetPropertiesMap();
3055  score = propertiesMap.at("NuScore");
3056  if( score > bestScore ) {
3057  bestScore = score;
3058  bestNuPfp = nuPfpVec.at(i);
3059  bestNuSlice = nuSliceVec.at(i);
3060  }
3061  }
3062  }//endloop over nuPfpVec
3063 
3064  // Purity and completeness calculations
3065  //
3066  // Purity = % of hits from true nu interaction
3067  // = (# truth-matched hits in slice)/(total# hits in slice)
3068  //
3069  // Completeness = % of true nu-interaciton hits included in slice
3070  // = (# truth-matched hits in slice)/(total# true hits overall)
3071  //
3072  std::vector<art::Ptr<recob::Hit>> sliceHits = fm_slicehits.at(bestNuSlice.key());
3073  int nhits_slice = (int)sliceHits.size();
3074 
3075  // Count up hits that originate from the MCTrue neutrino,
3076  // also store the MCTruth corresponding to this neutrino.
3077  int nhits_originNu = 0;
3078  bool foundNu = false;
3079  Int_t origin = -9;
3080  art::Ptr<simb::MCTruth> mctrueNeutrino;
3081  for(auto const hit : sliceHits){
3082  Int_t trkId;
3083  if( HitTruthId(clockData,hit,trkId) ) {
3084  art::Ptr<simb::MCTruth> mctruth;
3085  if( TrackIdToMCTruth(trkId,mctruth) ) {
3086  if( origin < 0 ) origin = mctruth->Origin();
3087  if( mctruth->Origin() == simb::kBeamNeutrino ) {
3088  origin = mctruth->Origin();
3089  nhits_originNu++;
3090  if(!foundNu){
3091  mctrueNeutrino = mctruth;
3092  foundNu = true;
3093  }
3094  }//endif Origin=nu
3095  }
3096  }
3097  }
3098 
3099  // Now count up TOTAL hits in event that originate from *this* neutrino
3100  // (important in case there are multiple nu's interacting)
3101  int nhits_originNu_total = 0;
3102  for(auto const hit : hitlist){
3103  Int_t trkId;
3104  if( HitTruthId(clockData,hit,trkId) ) {
3105  art::Ptr<simb::MCTruth> mctruth;
3106  if( TrackIdToMCTruth(trkId,mctruth) ) {
3107  if( mctruth == mctrueNeutrino ) nhits_originNu_total++;
3108  }
3109  }
3110  }
3111 
3112  // Save best nuslice info to tree
3113  fData->best_nuslice_id = bestNuSlice->ID();
3114  fData->best_nuslice_pfpid = bestNuPfp->Self();
3115  fData->best_nuslice_pdg = bestNuPfp->PdgCode();
3116  fData->best_nuslice_score = bestScore;
3117  fData->best_nuslice_origin = origin;
3118  if( nhits_slice > 0 ) fData->best_nuslice_hitpurity = nhits_originNu/float(nhits_slice);
3119  if( nhits_originNu_total > 0 ) fData->best_nuslice_hitcomp = nhits_originNu/float(nhits_originNu_total);
3120  //std::cout
3121  //<<"Best nu slice ID: "<<bestNuSlice->ID()<<", PDG = "<<bestNuPfp->PdgCode()<<", score = "<<bestScore<<", origin = "<<origin<<"\n"
3122  //<<" - purity = "<<fData->best_nuslice_hitpurity<<"\n"
3123  //<<" - comp = "<<fData->best_nuslice_hitcomp<<"\n";
3124 
3125  }//if neutrino slices were found
3126 
3127  }//end SaveSliceInfo
3128 
3129  //mc truth information
3130  if (isMC){
3131  if (fSaveCryInfo){
3132  //store cry (cosmic generator information)
3133  fData->mcevts_truthcry = mclistcry.size();
3134  fData->cry_no_primaries = nCryPrimaries;
3135  //fData->cry_no_primaries;
3136  for(Int_t iPartc = 0; iPartc < mctruthcry->NParticles(); ++iPartc){
3137  const simb::MCParticle& partc(mctruthcry->GetParticle(iPartc));
3138  fData->cry_primaries_pdg[iPartc]=partc.PdgCode();
3139  fData->cry_Eng[iPartc]=partc.E();
3140  fData->cry_Px[iPartc]=partc.Px();
3141  fData->cry_Py[iPartc]=partc.Py();
3142  fData->cry_Pz[iPartc]=partc.Pz();
3143  fData->cry_P[iPartc]=partc.P();
3144  fData->cry_StartPointx[iPartc] = partc.Vx();
3145  fData->cry_StartPointy[iPartc] = partc.Vy();
3146  fData->cry_StartPointz[iPartc] = partc.Vz();
3147  fData->cry_status_code[iPartc]=partc.StatusCode();
3148  fData->cry_mass[iPartc]=partc.Mass();
3149  fData->cry_trackID[iPartc]=partc.TrackId();
3150  fData->cry_ND[iPartc]=partc.NumberDaughters();
3151  fData->cry_mother[iPartc]=partc.Mother();
3152  } // for cry particles
3153  }// end fSaveCryInfo
3154 
3155  fData->mcevts_truth = mclist.size();
3156  //Brailsford 2017/10/16
3157  //Issue 17917
3158  //To keep a 1:1 between neutrinos and 'flux' we need the assns
3159  art::FindOneP<simb::MCFlux> fmFluxNeutrino(mctruthListHandle, evt, fGenieGenModuleLabel);
3160  // Get GTruth information for scattering code
3161  art::FindManyP< simb::GTruth > fmgt( mctruthListHandle, evt, fGenieGenModuleLabel );
3162 
3163  if (fData->mcevts_truth > 0){//at least one mc record
3164 
3165  if (fSaveGenieInfo){
3166 
3167  //Brailsford 2017/10/16
3168  //Issue 17917
3169  //Loop over every truth in the spill rather than just looking at the first one.
3170  //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
3171  fData->mcevts_truth = 0;
3172  for (unsigned int i_mctruth = 0; i_mctruth < mclist.size(); i_mctruth++){
3173  //fetch an mctruth
3174  art::Ptr<simb::MCTruth> curr_mctruth = mclist[i_mctruth];
3175  //Check if it's a neutrino
3176  if (!curr_mctruth->NeutrinoSet()) continue;
3177 
3178  // Genie Truth association only for the neutrino
3179  std::vector< art::Ptr<simb::GTruth> > mcgtAssn = fmgt.at(i_mctruth);
3180 
3181  fData->nuScatterCode_truth[i_mctruth] = mcgtAssn[0]->fGscatter;
3182 
3183  fData->nuPDG_truth[i_mctruth] = curr_mctruth->GetNeutrino().Nu().PdgCode();
3184  fData->ccnc_truth[i_mctruth] = curr_mctruth->GetNeutrino().CCNC();
3185  fData->mode_truth[i_mctruth] = curr_mctruth->GetNeutrino().Mode();
3186  fData->Q2_truth[i_mctruth] = curr_mctruth->GetNeutrino().QSqr();
3187  fData->W_truth[i_mctruth] = curr_mctruth->GetNeutrino().W();
3188  fData->hitnuc_truth[i_mctruth] = curr_mctruth->GetNeutrino().HitNuc();
3189  fData->enu_truth[i_mctruth] = curr_mctruth->GetNeutrino().Nu().E();
3190  fData->nuvtxx_truth[i_mctruth] = curr_mctruth->GetNeutrino().Nu().Vx();
3191  fData->nuvtxy_truth[i_mctruth] = curr_mctruth->GetNeutrino().Nu().Vy();
3192  fData->nuvtxz_truth[i_mctruth] = curr_mctruth->GetNeutrino().Nu().Vz();
3193  if (curr_mctruth->GetNeutrino().Nu().P()){
3194  fData->nu_dcosx_truth[i_mctruth] = curr_mctruth->GetNeutrino().Nu().Px()/curr_mctruth->GetNeutrino().Nu().P();
3195  fData->nu_dcosy_truth[i_mctruth] = curr_mctruth->GetNeutrino().Nu().Py()/curr_mctruth->GetNeutrino().Nu().P();
3196  fData->nu_dcosz_truth[i_mctruth] = curr_mctruth->GetNeutrino().Nu().Pz()/curr_mctruth->GetNeutrino().Nu().P();
3197  }
3198  fData->lep_mom_truth[i_mctruth] = curr_mctruth->GetNeutrino().Lepton().P();
3199  if (curr_mctruth->GetNeutrino().Lepton().P()){
3200  fData->lep_dcosx_truth[i_mctruth] = curr_mctruth->GetNeutrino().Lepton().Px()/curr_mctruth->GetNeutrino().Lepton().P();
3201  fData->lep_dcosy_truth[i_mctruth] = curr_mctruth->GetNeutrino().Lepton().Py()/curr_mctruth->GetNeutrino().Lepton().P();
3202  fData->lep_dcosz_truth[i_mctruth] = curr_mctruth->GetNeutrino().Lepton().Pz()/curr_mctruth->GetNeutrino().Lepton().P();
3203  }
3204  //Brailsford
3205  //2017/10/17
3206  //Issue 12918
3207  //Use the art::Ptr key as the neutrino's unique ID
3208  fData->nuID_truth[i_mctruth] = curr_mctruth.key();
3209  //We need to also store N 'flux' neutrinos per event so now check that the FindOneP is valid and, if so, use it!
3210  if (fmFluxNeutrino.isValid()){
3211  art::Ptr<simb::MCFlux> curr_mcflux = fmFluxNeutrino.at(i_mctruth);
3212  fData->tpx_flux[i_mctruth] = curr_mcflux->ftpx;
3213  fData->tpy_flux[i_mctruth] = curr_mcflux->ftpy;
3214  fData->tpz_flux[i_mctruth] = curr_mcflux->ftpz;
3215  fData->tptype_flux[i_mctruth] = curr_mcflux->ftptype;
3216  }
3217 
3218  //Let's increase the neutrino count
3219  fData->mcevts_truth++;
3220  }
3221 
3222  if (mctruth->NeutrinoSet()){
3223  //Brailsford 2017/10/16
3224  //Issue 17917
3225  //Bypass this section of filling code as there can now be multiple neutrinos per TTree::entry stored in the TTree
3226  /*
3227  fData->nuPDG_truth = mctruth->GetNeutrino().Nu().PdgCode();
3228  fData->ccnc_truth = mctruth->GetNeutrino().CCNC();
3229  fData->mode_truth = mctruth->GetNeutrino().Mode();
3230  fData->Q2_truth = mctruth->GetNeutrino().QSqr();
3231  fData->W_truth = mctruth->GetNeutrino().W();
3232  fData->hitnuc_truth = mctruth->GetNeutrino().HitNuc();
3233  fData->enu_truth = mctruth->GetNeutrino().Nu().E();
3234  fData->nuvtxx_truth = mctruth->GetNeutrino().Nu().Vx();
3235  fData->nuvtxy_truth = mctruth->GetNeutrino().Nu().Vy();
3236  fData->nuvtxz_truth = mctruth->GetNeutrino().Nu().Vz();
3237  if (mctruth->GetNeutrino().Nu().P()){
3238  fData->nu_dcosx_truth = mctruth->GetNeutrino().Nu().Px()/mctruth->GetNeutrino().Nu().P();
3239  fData->nu_dcosy_truth = mctruth->GetNeutrino().Nu().Py()/mctruth->GetNeutrino().Nu().P();
3240  fData->nu_dcosz_truth = mctruth->GetNeutrino().Nu().Pz()/mctruth->GetNeutrino().Nu().P();
3241  }
3242  fData->lep_mom_truth = mctruth->GetNeutrino().Lepton().P();
3243  if (mctruth->GetNeutrino().Lepton().P()){
3244  fData->lep_dcosx_truth = mctruth->GetNeutrino().Lepton().Px()/mctruth->GetNeutrino().Lepton().P();
3245  fData->lep_dcosy_truth = mctruth->GetNeutrino().Lepton().Py()/mctruth->GetNeutrino().Lepton().P();
3246  fData->lep_dcosz_truth = mctruth->GetNeutrino().Lepton().Pz()/mctruth->GetNeutrino().Lepton().P();
3247  }
3248  //flux information
3249  art::Ptr<simb::MCFlux> mcflux = fluxlist[imc];
3250  fData->tpx_flux = mcflux->ftpx;
3251  fData->tpy_flux = mcflux->ftpy;
3252  fData->tpz_flux = mcflux->ftpz;
3253  fData->tptype_flux = mcflux->ftptype;
3254  */
3255 
3256  //genie particles information
3257  fData->genie_no_primaries = mctruth->NParticles();
3258 
3259  size_t StoreParticles = std::min((size_t) fData->genie_no_primaries, fData->GetMaxGeniePrimaries());
3260  if (fData->genie_no_primaries > (int) StoreParticles) {
3261  // got this error? it might be a bug,
3262  // since the structure should have enough room for everything
3263  mf::LogError("AnalysisTree:limits") << "event has "
3264  << fData->genie_no_primaries << " MC particles, only "
3265  << StoreParticles << " stored in tree";
3266  }
3267  for(size_t iPart = 0; iPart < StoreParticles; ++iPart){
3268  const simb::MCParticle& part(mctruth->GetParticle(iPart));
3269  fData->genie_primaries_pdg[iPart]=part.PdgCode();
3270  fData->genie_Eng[iPart]=part.E();
3271  fData->genie_Px[iPart]=part.Px();
3272  fData->genie_Py[iPart]=part.Py();
3273  fData->genie_Pz[iPart]=part.Pz();
3274  fData->genie_P[iPart]=part.P();
3275  fData->genie_status_code[iPart]=part.StatusCode();
3276  fData->genie_mass[iPart]=part.Mass();
3277  fData->genie_trackID[iPart]=part.TrackId();
3278  fData->genie_ND[iPart]=part.NumberDaughters();
3279  fData->genie_mother[iPart]=part.Mother();
3280  } // for particle
3281  } //if neutrino set
3282  }// end (fSaveGenieInfo)
3283 
3284  //GEANT particles information
3285  if (fSaveGeantInfo){
3286  const sim::ParticleList& plist = pi_serv->ParticleList();
3287 
3288  std::string pri("primary");
3289  int primary=0;
3290  int active = 0;
3291  int geant_particle=0;
3292  sim::ParticleList::const_iterator itPart = plist.begin(),
3293  pend = plist.end(); // iterator to pairs (track id, particle)
3294 
3295  for(size_t iPart = 0; (iPart < plist.size()) && (itPart != pend); ++iPart){
3296  const simb::MCParticle* pPart = (itPart++)->second;
3297  if (!pPart) {
3298  throw art::Exception(art::errors::LogicError)
3299  << "GEANT particle #" << iPart << " returned a null pointer";
3300  }
3301 
3302  ++geant_particle;
3303  bool isPrimary = pPart->Process() == pri;
3304  if (isPrimary) ++primary;
3305  int TrackID = pPart->TrackId();
3306 
3307  // calculate traj length in AV
3308  TVector3 mcstart, mcend;
3309  double plen = length(*pPart, mcstart, mcend);
3310  bool isActive = plen != 0;
3311  if (plen) active++;
3312 
3313  // Get the total energy deposited by this particle by looking at IDEs from 3 planes.
3314  // The value should be the same on all planes, but better safe than sorry...
3315  geo::View_t views[3]={geo::kU, geo::kV, geo::kW};
3316  int nPlanes = 0;
3317  float totalE_particle = 0;
3318  float totalne_particle = 0;
3319  for(const geo::View_t view : views ) {
3320  std::vector<const sim::IDE* > ides = bt_serv->TrackIdToSimIDEs_Ps(TrackID, view);
3321  if( ides.size() ){
3322  for (auto ide: ides) {
3323  totalE_particle += ide->energy;
3324  totalne_particle += ide->numElectrons;
3325  }
3326  nPlanes++;
3327  }
3328  }
3329  if(nPlanes) {
3330  totalE_particle /= nPlanes;
3331  totalne_particle /= nPlanes;
3332  }
3333 
3334  // Save particle info to tree
3335  if (iPart < fData->GetMaxGEANTparticles()) {
3336  if (pPart->E()>fG4minE||isPrimary){
3337  fData->process_primary[iPart] = int(isPrimary);
3338  fData->processname[iPart]= pPart->Process();
3339  fData->Mother[iPart]=pPart->Mother();
3340  fData->TrackId[iPart]=TrackID;
3341  fData->pdg[iPart]=pPart->PdgCode();
3342  fData->status[iPart] = pPart->StatusCode();
3343  fData->Eng[iPart]=pPart->E();
3344  fData->EndE[iPart]=pPart->EndE();
3345  fData->Mass[iPart]=pPart->Mass();
3346  fData->Px[iPart]=pPart->Px();
3347  fData->Py[iPart]=pPart->Py();
3348  fData->Pz[iPart]=pPart->Pz();
3349  fData->P[iPart]=pPart->Momentum().Vect().Mag();
3350  fData->StartPointx[iPart]=pPart->Vx();
3351  fData->StartPointy[iPart]=pPart->Vy();
3352  fData->StartPointz[iPart]=pPart->Vz();
3353  fData->StartT[iPart] = pPart->T();
3354  fData->EndPointx[iPart]=pPart->EndPosition()[0];
3355  fData->EndPointy[iPart]=pPart->EndPosition()[1];
3356  fData->EndPointz[iPart]=pPart->EndPosition()[2];
3357  fData->EndT[iPart] = pPart->EndT();
3358  fData->theta[iPart] = pPart->Momentum().Theta();
3359  fData->phi[iPart] = pPart->Momentum().Phi();
3360  fData->theta_xz[iPart] = std::atan2(pPart->Px(), pPart->Pz());
3361  fData->theta_yz[iPart] = std::atan2(pPart->Py(), pPart->Pz());
3362  fData->pathlen[iPart] = plen;
3363  fData->NumberDaughters[iPart]=pPart->NumberDaughters();
3364  fData->inTPCActive[iPart] = int(isActive);
3365  fData->DepEnergy[iPart] = totalE_particle;
3366  fData->NumElectrons[iPart] = totalne_particle;
3367  if (isActive){
3368  fData->StartPointx_tpcAV[iPart] = mcstart.X();
3369  fData->StartPointy_tpcAV[iPart] = mcstart.Y();
3370  fData->StartPointz_tpcAV[iPart] = mcstart.Z();
3371  fData->EndPointx_tpcAV[iPart] = mcend.X();
3372  fData->EndPointy_tpcAV[iPart] = mcend.Y();
3373  fData->EndPointz_tpcAV[iPart] = mcend.Z();
3374  }
3375  //Brailsford
3376  //2017/10/17
3377  //Issue 17918
3378  //Get the mother neutrino of this particle and use the hosting art::Ptr key as the matched ID
3379  const art::Ptr<simb::MCTruth> matched_mctruth = pi_serv->ParticleToMCTruth_P(pPart);
3380  fData->MotherNuId[iPart] = matched_mctruth.key();
3381 
3382  //access auxiliary detector parameters
3383  if (fSaveAuxDetInfo) {
3384  unsigned short nAD = 0; // number of cells that particle hit
3385 
3386  // find deposit of this particle in each of the detector cells
3387  for (const sim::AuxDetSimChannel* c: fAuxDetSimChannels) {
3388 
3389  // find if this cell has a contribution (IDE) from this particle,
3390  // and which one
3391  const std::vector<sim::AuxDetIDE>& setOfIDEs = c->AuxDetIDEs();
3392  // using a C++ "lambda" function here; this one:
3393  // - sees only TrackID from the current scope
3394  // - takes one parameter: the AuxDetIDE to be tested
3395  // - returns if that IDE belongs to the track we are looking for
3396  std::vector<sim::AuxDetIDE>::const_iterator iIDE
3397  = std::find_if( setOfIDEs.begin(), setOfIDEs.end(),
3398  [TrackID](const sim::AuxDetIDE& IDE){ return IDE.trackID == TrackID; }
3399  );
3400  if (iIDE == setOfIDEs.end()) continue;
3401 
3402  // now iIDE points to the energy released by the track #i (TrackID)
3403 
3404  // look for IDE with matching trackID
3405  // find trackIDs stored in setOfIDEs with the same trackID, but negative,
3406  // this is an untracked particle who's energy should be added as deposited by this original trackID
3407  float totalE = 0.; // total energy deposited around by the GEANT particle in this cell
3408  for(const auto& adtracks: setOfIDEs) {
3409  if( fabs(adtracks.trackID) == TrackID )
3410  totalE += adtracks.energyDeposited;
3411  } // for
3412 
3413  // fill the structure
3414  if (nAD < kMaxAuxDets) {
3415  fData->AuxDetID[iPart][nAD] = c->AuxDetID();
3416  fData->entryX[iPart][nAD] = iIDE->entryX;
3417  fData->entryY[iPart][nAD] = iIDE->entryY;
3418  fData->entryZ[iPart][nAD] = iIDE->entryZ;
3419  fData->entryT[iPart][nAD] = iIDE->entryT;
3420  fData->exitX[iPart][nAD] = iIDE->exitX;
3421  fData->exitY[iPart][nAD] = iIDE->exitY;
3422  fData->exitZ[iPart][nAD] = iIDE->exitZ;
3423  fData->exitT[iPart][nAD] = iIDE->exitT;
3424  fData->exitPx[iPart][nAD] = iIDE->exitMomentumX;
3425  fData->exitPy[iPart][nAD] = iIDE->exitMomentumY;
3426  fData->exitPz[iPart][nAD] = iIDE->exitMomentumZ;
3427  fData->CombinedEnergyDep[iPart][nAD] = totalE;
3428  }
3429  ++nAD;
3430  } // for aux det sim channels
3431 
3432  fData->NAuxDets[iPart] = nAD;
3433  if (nAD > kMaxAuxDets) {
3434  // got this error? consider increasing kMaxAuxDets
3435  mf::LogError("AnalysisTree:limits") << "particle #" << iPart
3436  << " touches " << nAD << " auxiliary detector cells, only "
3437  << kMaxAuxDets << " of them are saved in the tree";
3438  } // if too many detector cells
3439  } // if (fSaveAuxDetInfo)
3440 
3441  }//endif E>G4min || isPrimary
3442 
3443  } else if (iPart == fData->GetMaxGEANTparticles()) {
3444  // got this error? it might be a bug,
3445  // since the structure should have enough room for everything
3446  mf::LogError("AnalysisTree:limits") << "event has "
3447  << plist.size() << " MC particles, only "
3448  << fData->GetMaxGEANTparticles() << " will be stored in tree";
3449  }
3450 
3451  }//<-- end loop over particles
3452 
3453  // Find total visible energy deposited in the LAr AV by looking at the SimChannels
3454  // for all three planes (ideally we'd do the planes separately and pick the one that
3455  // had the highest energy, but I don't know an easy way to get a SimChannel's plane).
3456  float totalEdep = 0;
3457  float totalne = 0;
3458  for(auto const &chan : fSimChannels ) {
3459  for(auto const &tdcide : chan->TDCIDEMap() ) {
3460  for(const auto& ide : tdcide.second) {
3461  totalEdep += ide.energy;
3462  totalne += ide.numElectrons;
3463  }
3464  }
3465  }
3466  fData->total_DepEnergy = totalEdep/kNplanes;
3467  fData->total_NumElectrons = totalne/kNplanes;
3468 
3469  fData->geant_list_size_in_tpcAV = active;
3470  fData->no_primaries = primary;
3471  fData->geant_list_size = geant_particle;
3472 
3473  MF_LOG_DEBUG("AnalysisTree") << "Counted "
3474  << fData->geant_list_size << " GEANT particles ("
3475  << fData->geant_list_size_in_tpcAV << " in AV), "
3476  << fData->no_primaries << " primaries, "
3477  << fData->genie_no_primaries << " GENIE particles";
3478 
3479  FillWith(fData->MergedId, 0);
3480 
3481  // helper map track ID => index
3482  std::map<int, size_t> TrackIDtoIndex;
3483  const size_t nTrackIDs = fData->TrackId.size();
3484  for (size_t index = 0; index < nTrackIDs; ++index)
3485  TrackIDtoIndex.emplace(fData->TrackId[index], index);
3486 
3487  // for each particle, consider all the direct ancestors with the same
3488  // PDG ID, and mark them as belonging to the same "group"
3489  // (having the same MergedId)
3490  int currentMergedId = 1;
3491  for(size_t iPart = fData->geant_list_size; iPart-- > 0; ) {
3492  // if the particle already belongs to a group, don't bother
3493  if (fData->MergedId[iPart]) continue;
3494  // the particle starts its own group
3495  fData->MergedId[iPart] = currentMergedId;
3496 
3497  // look in the ancestry, one by one
3498  int currentMotherTrackId = fData->Mother[iPart];
3499  while(currentMotherTrackId > 0) {
3500  // find the mother (we have its track ID in currentMotherTrackId)
3501  std::map<int, size_t>::const_iterator iMother
3502  = TrackIDtoIndex.find(currentMotherTrackId);
3503  if (iMother == TrackIDtoIndex.end()) break; // no mother found
3504  size_t currentMotherIndex = iMother->second;
3505  // if the mother particle is of a different type,
3506  // don't bother with iPart ancestry any further
3507  if (fData->pdg[iPart] != fData->pdg[currentMotherIndex]) break;
3508 
3509  // group the "current mother" (actually, ancestor) with iPart
3510  fData->MergedId[currentMotherIndex] = currentMergedId;
3511  // then consider the grandmother (one generation earlier)
3512  currentMotherTrackId = fData->Mother[currentMotherIndex];
3513  } // while ancestry exists
3514  ++currentMergedId;
3515  } // for merging check
3516 
3517  }//if (fSaveGeantInfo)
3518  }//if (mcevts_truth)
3519  }//if (isMC)
3520 
3521  fData->taulife = detprop.ElectronLifetime();
3522  fTree->Fill();
3523 
3524  if (mf::isDebugEnabled()) {
3525  // use mf::LogDebug instead of MF_LOG_DEBUG because we reuse it in many lines;
3526  // thus, we protect this part of the code with the line above
3527  mf::LogDebug logStream("AnalysisTreeStructure");
3528  logStream
3529  << "Tree data structure contains:"
3530  << "\n - " << fData->no_hits << " hits (" << fData->GetMaxHits() << ")"
3531  << "\n - " << fData->genie_no_primaries << " genie primaries (" << fData->GetMaxGeniePrimaries() << ")"
3532  << "\n - " << fData->geant_list_size << " GEANT particles (" << fData->GetMaxGEANTparticles() << "), "
3533  << fData->no_primaries << " primaries"
3534  << "\n - " << fData->geant_list_size_in_tpcAV << " GEANT particles in AV "
3535  << "\n - " << ((int) fData->kNTracker) << " trackers:"
3536  ;
3537 
3538  size_t iTracker = 0;
3539  for (auto tracker = fData->TrackData.cbegin();
3540  tracker != fData->TrackData.cend(); ++tracker, ++iTracker
3541  ) {
3542  logStream
3543  << "\n -> " << tracker->ntracks << " " << fTrackModuleLabel[iTracker]
3544  << " tracks (" << tracker->GetMaxTracks() << ")"
3545  ;
3546  for (int iTrk = 0; iTrk < tracker->ntracks; ++iTrk) {
3547  logStream << "\n [" << iTrk << "] "<< tracker->ntrkhits[iTrk][0];
3548  for (size_t ipl = 1; ipl < tracker->GetMaxPlanesPerTrack(iTrk); ++ipl)
3549  logStream << " + " << tracker->ntrkhits[iTrk][ipl];
3550  logStream << " hits (" << tracker->GetMaxHitsPerTrack(iTrk, 0);
3551  for (size_t ipl = 1; ipl < tracker->GetMaxPlanesPerTrack(iTrk); ++ipl)
3552  logStream << " + " << tracker->GetMaxHitsPerTrack(iTrk, ipl);
3553  logStream << ")";
3554  } // for tracks
3555  } // for trackers
3556  } // if logging enabled
3557 
3558  // if we don't use a permanent buffer (which can be huge),
3559  // delete the current buffer, and we'll create a new one on the next event
3560  if (!fUseBuffer) {
3561  MF_LOG_DEBUG("AnalysisTreeStructure") << "Freeing the tree data structure";
3562  DestroyData();
3563  }
3564 } // sbnd::AnalysisTree::analyze()
3565 
3566 
3567 //===========================================================================================
3568 // FUNCTIONS
3569 //==========================================================================================
3570 
3572  std::vector< art::Ptr<recob::Hit> > const& hits, Int_t& trackid, Float_t& purity, double& maxe){
3573 
3574  trackid = -1;
3575  purity = -1;
3576 
3577  std::map<int,double> trkide;
3578 
3579  for(size_t h = 0; h < hits.size(); ++h){
3580 
3581  art::Ptr<recob::Hit> hit = hits[h];
3582  std::vector<sim::TrackIDE> eveIDs = bt_serv->HitToEveTrackIDEs(clockData, hit);
3583 
3584  for(size_t e = 0; e < eveIDs.size(); ++e){
3585  trkide[eveIDs[e].trackID] += eveIDs[e].energy;
3586  }
3587  }
3588 
3589  maxe = -1;
3590  double tote = 0;
3591  for (std::map<int,double>::iterator ii = trkide.begin(); ii!=trkide.end(); ++ii){
3592  tote += ii->second;
3593  if ((ii->second)>maxe){
3594  maxe = ii->second;
3595  trackid = ii->first;
3596  }
3597  }
3598 
3599  if (tote>0){
3600  purity = maxe/tote;
3601  }
3602 }
3603 
3604 
3605 // Function to check if there was a SimChannel made for a hit (useful when checking for noise hits)
3606 bool sbnd::AnalysisTree::DoesHitHaveSimChannel( std::vector<const sim::SimChannel*> chans, art::Ptr<recob::Hit> const& hit){
3607  bool isMatch = false;
3608  for(size_t sc = 0; sc < chans.size(); ++sc){
3609  if( chans[sc]->Channel() == hit->Channel() ) { isMatch = true; break; }
3610  }
3611  return isMatch;
3612 }
3613 
3614 
3615 // This function calculates the leading MCParticle ID contributing to a hit and the
3616 // fraction of that hit's energy comes from that particle.
3617 void sbnd::AnalysisTree::HitTruth( detinfo::DetectorClocksData const& clockData, art::Ptr<recob::Hit> const& hit,
3618  Int_t& truthid, Float_t& truthidEnergyFrac, Float_t& energy, Float_t& numElectrons){
3619 
3620  // Get associated sim::TrackIDEs for this hit
3621 // art::ServiceHandle<cheat::BackTrackerService> bt_serv;
3622  std::vector<sim::TrackIDE> trackIDEs = bt_serv->HitToTrackIDEs(clockData, hit);
3623  if( !trackIDEs.size() ) return;
3624  // Loop through and find the leading TrackIDE, and keep
3625  // track of the total energy of ALL IDEs.
3626  Float_t maxe = 0;
3627  Float_t bestfrac = 0;
3628  Int_t bestid = 0;
3629  Int_t ne = 0;
3630  for(size_t i = 0; i < trackIDEs.size(); ++i){
3631  ne += trackIDEs[i].numElectrons;
3632  if( trackIDEs[i].energy > maxe ) {
3633  maxe = trackIDEs[i].energy;
3634  bestfrac = trackIDEs[i].energyFrac;
3635  bestid = trackIDEs[i].trackID;
3636  }
3637  }
3638  // Save the results
3639  truthid = bestid;
3640  truthidEnergyFrac = bestfrac;
3641  energy = maxe;
3642  numElectrons = ne;
3643 
3644 }
3645 //
3646 // helper function to get TrackID (returns false if no match found)
3647 bool sbnd::AnalysisTree::HitTruthId( detinfo::DetectorClocksData const& clockData, art::Ptr<recob::Hit> const& hit, Int_t& mcid)
3648 {
3649  mcid = std::numeric_limits<int>::lowest();
3650  Float_t dummy1;
3651  Float_t dummy2;
3652  Float_t dummy3;
3653  HitTruth(clockData,hit,mcid,dummy1,dummy2,dummy3);
3654  if( mcid > std::numeric_limits<int>::lowest() ) return true;
3655  else return false;
3656 }
3657 
3658 
3659 // Get MCTruth associated with TrackID using a try bracket to avoid
3660 // fatal exceptions (return false if no match or exception thrown)
3661 bool sbnd::AnalysisTree::TrackIdToMCTruth( Int_t const trkID, art::Ptr<simb::MCTruth>& mctruth )
3662 {
3663 // art::ServiceHandle<cheat::ParticleInventoryService> pi_serv;
3664  bool matchFound = false;
3665  try {
3666  mctruth = pi_serv->TrackIdToMCTruth_P(trkID);
3667  matchFound = true;
3668  } catch(...) {
3669  std::cout<<"Exception thrown matching TrackID "<<trkID<<" to MCTruth\n";
3670  matchFound = false;
3671  }
3672  return matchFound;
3673 }
3674 
3675 
3676 // Calculate distance to boundary.
3678 {
3679  // Get geometry.
3680  art::ServiceHandle<geo::Geometry> geom;
3681 
3682  double d1 = pos.X(); // Distance to right side (wires).
3683  double d2 = 2.*geom->DetHalfWidth() - pos.X(); // Distance to left side (cathode).
3684  double d3 = pos.Y() + geom->DetHalfHeight(); // Distance to bottom.
3685  double d4 = geom->DetHalfHeight() - pos.Y(); // Distance to top.
3686  double d5 = pos.Z(); // Distance to front.
3687  double d6 = geom->DetLength() - pos.Z(); // Distance to back.
3688 
3689  double result = std::min(std::min(std::min(std::min(std::min(d1, d2), d3), d4), d5), d6);
3690  return result;
3691 }
3692 
3693 
3694 // Length of reconstructed track, trajectory by trajectory.
3695 double sbnd::AnalysisTree::length(const recob::Track& track)
3696 {
3697  return track.Length();
3698 }
3699 
3700 
3701 // Length of MC particle, trajectory by trajectory.
3702 double sbnd::AnalysisTree::length(const simb::MCParticle& part, TVector3& start, TVector3& end)
3703 {
3704  // Get geometry.
3705  art::ServiceHandle<geo::Geometry> geom;
3706 
3707  // Get active volume boundary.
3708  double xmin = -2.0 * geom->DetHalfWidth() - 1e-8;
3709  double xmax = 2.0 * geom->DetHalfWidth() + 1e-8;
3710  double ymin = -geom->DetHalfHeight() -1e-8;
3711  double ymax = geom->DetHalfHeight() + 1e-8;
3712  double zmin = 0. -1e-8;
3713  double zmax = geom->DetLength() + 1e-8;
3714 
3715  // Get number traj points
3716  int n = part.NumberTrajectoryPoints();
3717  if( n <= 1 ) return 0.;
3718 
3719  double L = 0.;
3720  bool first = true;
3721 
3722  // Loop over points (start with 2nd)
3723  for(int i = 1; i < n; ++i) {
3724 
3725  TVector3 p1(part.Vx(i),part.Vy(i),part.Vz(i));
3726 
3727  if( p1.X() >= xmin && p1.X() <= xmax
3728  && p1.Y() >= ymin && p1.Y() <= ymax
3729  && p1.Z() >= zmin && p1.Z() <= zmax ) {
3730 
3731  TVector3 p0(part.Vx(i-1),part.Vy(i-1),part.Vz(i-1));
3732 
3733  if(first) start = p1;
3734  else L += (p1-p0).Mag();
3735  first = false;
3736  end = p1;
3737  }
3738  }
3739 
3740  return L;
3741 }
3742 
3743 
3744 namespace sbnd{
3745 
3746  DEFINE_ART_MODULE(AnalysisTree)
3747 
3748 }
3749 
3750 #endif
bool fSaveGenieInfo
whether to extract and save CRY particle data
TrackDataStruct(size_t maxTracks)
Creates a tracker data structure allowing up to maxTracks tracks.
Little helper functor class to create or reset branches in a tree.
double std(const std::vector< short > &wf, const double ped_mean, size_t start, size_t nsample)
Definition: UtilFunc.cxx:42
bool hasVertexInfo() const
Returns whether we have Vertex data.
Int_t mcevts_truth
! The number of MCNeutrinos there is currently room for
double VertexMomentum() const
void CreateData(bool bClearData=false)
Creates the structure for the tree data; optionally initializes it.
static void BuildPFParticleMap(const PFParticleVector &particleVector, PFParticleMap &particleMap)
Build particle maps for reconstructed particles.
BEGIN_PROLOG true icarus_rawdigitfilter FilterTools FilterPlane1 Plane
void CheckTree(std::string caller) const
Helper function: throws if no tree is available.
int TrueParticleIDFromTotalTrueEnergy(detinfo::DetectorClocksData const &clockData, const std::vector< art::Ptr< recob::Hit > > &hits, bool rollup_unsaved_ids=1)
void SetShowerAddresses()
Sets the addresses of all the tree branches, creating the missing ones.
double GetMomentumMultiScatterChi2(art::Ptr< recob::Track > const &trk, const bool checkValidPoints=false)
Implementation of the Projection Matching Algorithm.
Int_t no_primaries
! how many particles there is currently room for
size_t GetMaxGEANTparticles() const
Returns the number of GEANT particles for which memory is allocated.
BEGIN_PROLOG could also be cerr
bool hasGeantInfo() const
Returns whether we have Geant data.
void SetShowerAddresses(TTree *pTree, std::string showerLabel, bool saveHierarchyInfo)
void CheckData(std::string caller) const
Helper function: throws if no data structure is available.
enum geo::_plane_proj View_t
Enumerate the possible plane projections.
double bdist(const recob::Track::Point_t &pos)
Planes which measure V.
Definition: geo_types.h:130
const TrackDataStruct & GetTrackerData(size_t iTracker) const
void SetTrackers(size_t nTrackers)
Allocates data structures for the given number of trackers (no Clear())
std::vector< bool > fSaveHierarchyInfo
whether to extract and save Slice information
void analyze(const art::Event &evt)
read access to event
Declaration of signal hit object.
void ResizeMCNeutrino(int nNeutrinos)
Resize the data structure for MCNeutrino particles.
constexpr unsigned short kMaxVertices
BEGIN_PROLOG or score(default)}sbnd_crttrackmatchingalg_crID
bool fSaveCaloCosmics
save calorimetry information for cosmics
bool fSaveTrackInfo
whether to extract and save Hit information
size_t NumberTrajectoryPoints() const
Various functions related to the presence and the number of (valid) points.
bool fSaveShowerInfo
whether to extract and save Track information
Vector_t VertexDirection() const
bool fSaveVertexInfo
whether to extract and save Shower information
double length(const recob::Track &track)
AuxDetMCData_t< Float_t > entryT
Entry T position of particle into AuxDet.
static constexpr bool
Definition of basic raw digits.
AuxDetMCData_t< Float_t > exitT
Exit T position of particle out of AuxDet.
AuxDetMCData_t< Float_t > exitPx
Exit x momentum of particle out of AuxDet.
std::map< std::string, float > PropertiesMap
process_name use argoneut_mc_hitfinder track
Creates a simple ROOT tree with tracking and calorimetry information.
size_t GetMaxTrackers() const
Returns the number of trackers for which memory is allocated.
process_name hit
Definition: cheaterreco.fcl:51
float fValue
Result of Particle ID algorithm/test.
Definition: ParticleID.h:28
void SetShowerAddresses(TTree *pTree, std::string showerLabel, bool saveHierarchyInfo)
Connect this object with a tree.
bool TrackIdToMCTruth(Int_t const trkID, art::Ptr< simb::MCTruth > &mctruth)
TrackData_t< Int_t > trkisprimary
If SaveHierarchyInfo is true, there are additional variables:
isCosmics(false)
bool hasSliceInfo() const
Returns whether we have Slice data.
void SetAddresses(TTree *pTree, const std::vector< std::string > &trackers, std::string showerLabel, const std::vector< std::string > &vertexLabels, bool isCosmics, const std::vector< bool > &saveHierarchyInfo, bool saveShowerHierarchyInfo)
Connect this object with a tree.
AnalysisTreeDataStruct(size_t nTrackers=0)
Constructor; clears all fields.
bool hasGenieInfo() const
Returns whether we have Genie data.
std::map< int, art::Ptr< recob::PFParticle > > PFParticleMap
SubRunData_t SubRunData
subrun data collected at begin of subrun
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
bool fSaveShowerHierarchyInfo
if the user wants to access the showers with their hierarchy
ShowerData_t< Int_t > shwisprimary
If SaveHierarchyInfo is true, there are additional variables:
AnalysisTreeDataStruct::SubRunData_t SubRunData
bool hasHitInfo() const
Returns whether we have Hit data.
IDparameter< geo::PlaneID > PlaneID
Member type of validated geo::PlaneID parameter.
AuxDetMCData_t< Float_t > exitPz
Exit z momentum of particle out of AuxDet.
process_name pandoraGausCryo1 vertexChargeCryo1 vertexStubCryo1 xmin
std::string fAlgName
&lt; determined particle ID
Definition: ParticleID.h:23
bool DoesHitHaveSimChannel(std::vector< const sim::SimChannel * > chans, art::Ptr< recob::Hit > const &hit)
while getopts h
Collection of particles crossing one auxiliary detector cell.
auto vector(Vector const &v)
Returns a manipulator which will print the specified array.
Definition: DumpUtils.h:265
Planes which measure U.
Definition: geo_types.h:129
void SetBits(unsigned int setbits, bool unset=false)
Sets the specified bits.
kVariableType fVariableType
Variable type enum: defined in ParticleID_VariableTypeEnums.h. Set to kNotSet by default.
Definition: ParticleID.h:24
BEGIN_PROLOG V
bool fSaveSliceInfo
whether to extract and save Vertex information
object containing MC truth information necessary for making RawDigits and doing back tracking ...
bool HitTruthId(detinfo::DetectorClocksData const &clockData, art::Ptr< recob::Hit > const &hit, Int_t &mcid)
A wrapper to a C array (needed to embed an array into a vector)
double Length(size_t p=0) const
Access to various track properties.
void CreateTree(bool bClearData=false)
Create the output tree and the data structures, if needed.
IDparameter< geo::WireID > WireID
Member type of validated geo::WireID parameter.
art::ServiceHandle< cheat::ParticleInventoryService > pi_serv
fSaveShowerHierarchyInfo(pset.get< bool >("SaveShowerHierarchyInfo", false))
std::vector< art::Ptr< recob::PFParticle > > PFParticleVector
void SetAddresses()
Sets the addresses of all the tree branches, creating the missing ones.
bool fSaveGeantInfo
whether to extract and save Genie information
void SetAddresses(TTree *pTree, std::string vertexLabel, bool saveHierarchyInfo)
Point_t const & Vertex() const
virtual ~AnalysisTree()
auto end(FixedBins< T, C > const &) noexcept
Definition: FixedBins.h:585
AuxDetMCData_t< Float_t > exitY
Exit Y position of particle out of AuxDet.
AuxDetMCData_t< Float_t > exitX
Exit X position of particle out of AuxDet.
fSaveCaloCosmics(pset.get< bool >("SaveCaloCosmics", false))
constexpr int kMaxShowers
void ClearLocalData()
Clear all fields if this object (not the tracker algorithm data)
AuxDetMCData_t< Float_t > entryY
Entry Y position of particle into AuxDet.
const Cut kCosmicRay
void HitsPurity(detinfo::DetectorClocksData const &clockData, std::vector< art::Ptr< recob::Hit > > const &hits, Int_t &trackid, Float_t &purity, double &maxe)
void fill(const art::PtrVector< recob::Hit > &hits, int only_plane)
bool hasShowerInfo() const
Returns whether we have Shower data.
int TrueParticleIDFromTotalRecoHits(detinfo::DetectorClocksData const &clockData, const std::vector< art::Ptr< recob::Hit > > &hits, bool rollup_unsaved_ids=1)
void beginSubRun(const art::SubRun &sr)
Declaration of cluster object.
AuxDetMCData_t< Float_t > entryZ
Entry Z position of particle into AuxDet.
bool fUseBuffer
whether to use a permanent buffer (faster, huge memory)
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
void operator()(std::string name, void *address, std::string leaflist)
Create a branch if it does not exist, and set its address.
Provides recob::Track data product.
void ResizeGEANT(int nParticles)
Resize the data strutcure for GEANT particles.
void DestroyData()
Destroy the local buffers (existing branches will point to invalid address!)
art::ServiceHandle< cheat::BackTrackerService > bt_serv
ShowerDataStruct(size_t maxShowers)
Creates a shower data structure allowing up to maxShowers showers.
auto begin(FixedBins< T, C > const &) noexcept
Definition: FixedBins.h:573
bool hasTrackInfo() const
Returns whether we have Track data.
AuxDetMCData_t< Float_t > exitPy
Exit y momentum of particle out of AuxDet.
void SetVertices(size_t nTrackers)
Allocates data structures for the given number of trackers (no Clear())
size_t GetMaxHits() const
Returns the number of hits for which memory is allocated.
size_t GetNTrackers() const
Returns the number of trackers configured.
bool fSaveHitInfo
whether to extract and save Geant information
bool hasCryInfo() const
Returns whether we have Cry data.
Contains all timing reference information for the detector.
Vector_t EndDirection() const
auto operator[](size_t index) -> decltype(*array)
Array interface.
MC truth information to make RawDigits and do back tracking.
AuxDetMCData_t< Float_t > CombinedEnergyDep
Sum energy of all particles with this trackID (+ID or -ID) in AuxDet.
process_name largeant stream1 can override from command line with o or output physics producers generator N
void ResizeCry(int nPrimaries)
Resize the data strutcure for Cry primaries.
tracking::Point_t Point_t
object containing MC truth information necessary for making RawDigits and doing back tracking ...
do i e
bool fSaveAuxDetInfo
whether to extract and save auxiliary detector data
Point_t const & End() const
stream1 can override from command line with o or output services user sbnd
then echo fcl name
int TrueParticleIDFromTotalRecoCharge(detinfo::DetectorClocksData const &clockData, const std::vector< art::Ptr< recob::Hit > > &hits, bool rollup_unsaved_ids=1)
temporary value
Planes which measure W (third view for Bo, MicroBooNE, etc).
Definition: geo_types.h:131
float fG4minE
Energy threshold to save g4 particle info.
art::ServiceHandle< art::TFileService > tfs
TCEvent evt
Definition: DataStructs.cxx:8
size_t GetMaxGeniePrimaries() const
Returns the number of GENIE primaries for which memory is allocated.
AuxDetMCData_t< Short_t > AuxDetID
Which AuxDet this particle went through.
std::vector< UShort_t > NAuxDets
Number of AuxDets crossed by this particle.
double GetMomentumMultiScatterLLHD(art::Ptr< recob::Track > const &trk)
std::vector< BoxedArray< T[kNplanes][kMaxTrackHits][3]>> HitCoordData_t
std::vector< BoxedArray< T[kMaxAuxDets]>> AuxDetMCData_t
helper function for LArPandoraInterface producer module
void ResizeGenie(int nPrimaries)
Resize the data strutcure for Genie primaries.
void SetAddresses(TTree *pTree, std::string tracker, bool isCosmics, bool saveHierarchyInfo)
void HitTruth(detinfo::DetectorClocksData const &clockData, art::Ptr< recob::Hit > const &hit, Int_t &truthid, Float_t &frac, Float_t &energy, Float_t &numElectrons)
fG4minE(pset.get< float >("G4minE", 0.01))
physics associatedGroupsWithLeft p1
size_t GetNTrackers() const
Returns the number of trackers for which data structures are allocated.
BEGIN_PROLOG don t mess with this pandoraTrackGausCryoW true
art framework interface to geometry description
BEGIN_PROLOG could also be cout
static bool IsFinalState(const PFParticleMap &particleMap, const art::Ptr< recob::PFParticle > daughterParticle)
Determine whether a particle has been reconstructed as a final-state particle.
Track from a non-cascading particle.A recob::Track consists of a recob::TrackTrajectory, plus additional members relevant for a &quot;fitted&quot; track:
constexpr Point origin()
Returns a origin position with a point of the specified type.
Definition: geo_vectors.h:227
AuxDetMCData_t< Float_t > entryX
Entry X position of particle into AuxDet.
double GetTrackMomentum(double trkrange, int pdg) const
VertexDataStruct(size_t maxVertices)
Creates a vertex data structure allowing up to maxVertices vertices.
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
bool hasAuxDetector() const
Returns whether we have auxiliary detector data.
AuxDetMCData_t< Float_t > exitZ
Exit Z position of particle out of AuxDet.