forked from uboone/xsec_analyzer
-
Notifications
You must be signed in to change notification settings - Fork 2
/
analyzer.C
1758 lines (1372 loc) · 63.3 KB
/
analyzer.C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
// Analysis macro for use in the CCNp0pi single transverse variable analysis
// Designed for use with the PeLEE group's "searchingfornues" ntuples
//
// Updated 22 April 2023
// Steven Gardiner <gardiner@fnal.gov>
// Standard library includes
#include <cmath>
#include <iostream>
#include <map>
#include <memory>
#include <string>
#include <vector>
// ROOT includes
#include "TChain.h"
#include "TFile.h"
#include "TParameter.h"
#include "TTree.h"
#include "TVector3.h"
// STV analysis includes
#include "EventCategory.hh"
#include "FiducialVolume.hh"
#include "TreeUtils.hh"
// Helper function that avoids NaNs when taking square roots of negative
// numbers
double real_sqrt( double x ) {
if ( x < 0. ) return 0.;
else return std::sqrt( x );
}
// Helper function that returns true if a given PDG code represents a meson or
// antimeson. Otherwise returns false. Based on points 10, 12, and 13 of the
// Particle Data Group's "Monte Carlo Particle Numbering Scheme"
// (2019 revision).
bool is_meson_or_antimeson( int pdg_code ) {
// Ignore differences between mesons and antimesons for this test. Mesons
// will have positive PDG codes, while antimesons will have negative ones.
int abs_pdg = std::abs( pdg_code );
// Meson PDG codes have no more than seven digits. Seven-digit
// codes beginning with "99" are reserved for generator-specific
// particles
if ( abs_pdg >= 9900000 ) return false;
// Mesons have a value of zero for $n_{q1}$, the thousands digit
int thousands_digit = ( abs_pdg / 1000 ) % 10;
if ( thousands_digit != 0 ) return false;
// They also have a nonzero value for $n_{q2}$, the hundreds digit
int hundreds_digit = ( abs_pdg / 100 ) % 10;
if ( hundreds_digit == 0 ) return false;
// Reserved codes for Standard Model parton distribution functions
if ( abs_pdg >= 901 && abs_pdg <= 930 ) return false;
// Reggeon and pomeron
if ( abs_pdg == 110 || abs_pdg == 990 ) return false;
// Reserved codes for GEANT tracking purposes
if ( abs_pdg == 998 || abs_pdg == 999 ) return false;
// Reserved code for generator-specific pseudoparticles
if ( abs_pdg == 100 ) return false;
// If we've passed all of the tests above, then the particle is a meson
return true;
}
// A few helpful dummy constants
constexpr float BOGUS = 9999.;
constexpr int BOGUS_INT = 9999;
constexpr int BOGUS_INDEX = -1;
constexpr float LOW_FLOAT = -1e30;
constexpr float DEFAULT_WEIGHT = 1.;
// Integer representation of CC versus NC for the ccnc branch
constexpr int CHARGED_CURRENT = 0;
constexpr int NEUTRAL_CURRENT = 1;
// Useful PDG codes
constexpr int ELECTRON_NEUTRINO = 12;
constexpr int MUON = 13;
constexpr int MUON_NEUTRINO = 14;
constexpr int TAU_NEUTRINO = 16;
constexpr int PROTON = 2212;
constexpr int PI_ZERO = 111;
constexpr int PI_PLUS = 211;
// Values of parameters to use in analysis cuts
constexpr float DEFAULT_PROTON_PID_CUT = 0.2;
constexpr float LEAD_P_MIN_MOM_CUT = 0.250; // GeV/c
constexpr float LEAD_P_MAX_MOM_CUT = 1.; // GeV/c
constexpr float MUON_P_MIN_MOM_CUT = 0.100; // GeV/c
constexpr float MUON_P_MAX_MOM_CUT = 1.200; // GeV/c
constexpr float CHARGED_PI_MOM_CUT = 0.; // GeV/c
constexpr float MUON_MOM_QUALITY_CUT = 0.25; // fractional difference
constexpr float TOPO_SCORE_CUT = 0.1;
constexpr float COSMIC_IP_CUT = 10.; // cm
constexpr float MUON_TRACK_SCORE_CUT = 0.8;
constexpr float MUON_VTX_DISTANCE_CUT = 4.; // cm
constexpr float MUON_LENGTH_CUT = 10.; // cm
constexpr float MUON_PID_CUT = 0.2;
constexpr float TRACK_SCORE_CUT = 0.5;
// Function that defines the track-length-dependent proton PID cut
double proton_pid_cut( double track_length ) {
double cut = DEFAULT_PROTON_PID_CUT;
// Piecewise cut removed 27 June 2021
//// All track length values are in cm
//if ( track_length >= 0. && track_length <= 10.5 ) {
// cut = -0.0034219305*std::pow( track_length, 2 );
// cut += 0.018436866*track_length + 0.062718401;
//}
//else if ( track_length > 10.5 && track_length <= 33.1776508 ) {
// cut = 0.014153245*( track_length - 10.5 ) - 0.12096235;
//}
return cut;
}
// Boundaries of the proton containment volume (used in reco only) in cm
double PCV_X_MIN = 10.;
double PCV_X_MAX = 246.35;
double PCV_Y_MIN = -106.5;
double PCV_Y_MAX = 106.5;
double PCV_Z_MIN = 10.;
double PCV_Z_MAX = 1026.8;
// Mass values from GENIE v3.0.6
constexpr double TARGET_MASS = 37.215526; // 40Ar, GeV
constexpr double NEUTRON_MASS = 0.93956541; // GeV
constexpr double PROTON_MASS = 0.93827208; // GeV
constexpr double MUON_MASS = 0.10565837; // GeV
constexpr double PI_PLUS_MASS = 0.13957000; // GeV
// This binding energy value is used in GENIE v3.0.6
//constexpr double BINDING_ENERGY = 0.0295; // 40Ar, GeV
// This value is the shell-occupancy-weighted mean of the $E_{\alpha}$ values
// listed for 40Ar in Table II of arXiv:1609.03530. MINERvA uses an identical
// procedure for 12C to obtain the binding energy value of 27.13 MeV, which is
// adopted in their STV analysis described in arXiv:1910.08658.
constexpr double BINDING_ENERGY = 0.02478; // 40Ar, GeV
// Class used to hold information from the searchingfornues TTree branches and
// process it for our analysis
class AnalysisEvent {
public:
AnalysisEvent() {}
~AnalysisEvent() {}
EventCategory categorize_event();
void apply_selection();
void apply_numu_CC_selection();
void find_muon_candidate();
void find_lead_p_candidate();
void compute_observables();
void compute_mc_truth_observables();
// Event scores needed for numu CC selection
float topological_score_ = BOGUS;
float cosmic_impact_parameter_ = BOGUS;
// Backtracked purity and completeness of hits (MC only)
float nu_completeness_from_pfp_ = BOGUS;
float nu_purity_from_pfp_ = BOGUS;
// Reco PDG code of the neutrino candidate
int nu_pdg_ = BOGUS_INT;
// Number of neutrino slices identified by the SliceID. Allowed values
// are zero or one.
int nslice_ = BOGUS_INT;
// Reco neutrino vertex coordinates (cm). Space charge corrections have
// been applied for these.
float nu_vx_ = BOGUS;
float nu_vy_ = BOGUS;
float nu_vz_ = BOGUS;
// Reconstructed object counts
int num_pf_particles_ = BOGUS_INT;
int num_tracks_ = BOGUS_INT;
int num_showers_ = BOGUS_INT;
// PFParticle properties
MyPointer< std::vector<unsigned int> > pfp_generation_;
MyPointer< std::vector<unsigned int> > pfp_trk_daughters_count_;
MyPointer< std::vector<unsigned int> > pfp_shr_daughters_count_;
MyPointer< std::vector<float> > pfp_track_score_;
// Reco PDG code assigned by Pandora
MyPointer< std::vector<int> > pfp_reco_pdg_;
// Total number of wire plane hits associated with each PFParticle
MyPointer< std::vector<int> > pfp_hits_;
// Number of hits on the three individual planes
// (Y is the collection plane)
MyPointer< std::vector<int> > pfp_hitsU_;
MyPointer< std::vector<int> > pfp_hitsV_;
MyPointer< std::vector<int> > pfp_hitsY_;
// True PDG code found using the backtracker
MyPointer< std::vector<int> > pfp_true_pdg_;
// True 4-momentum components found using the backtracker
MyPointer< std::vector<float> > pfp_true_E_;
MyPointer< std::vector<float> > pfp_true_px_;
MyPointer< std::vector<float> > pfp_true_py_;
MyPointer< std::vector<float> > pfp_true_pz_;
// Shower properties
MyPointer< std::vector<unsigned long> > shower_pfp_id_;
MyPointer< std::vector<float> > shower_startx_;
MyPointer< std::vector<float> > shower_starty_;
MyPointer< std::vector<float> > shower_startz_;
MyPointer< std::vector<float> > shower_start_distance_;
// Track properties
MyPointer< std::vector<unsigned long> > track_pfp_id_;
MyPointer< std::vector<float> > track_length_;
MyPointer< std::vector<float> > track_startx_;
MyPointer< std::vector<float> > track_starty_;
MyPointer< std::vector<float> > track_startz_;
MyPointer< std::vector<float> > track_start_distance_;
MyPointer< std::vector<float> > track_endx_;
MyPointer< std::vector<float> > track_endy_;
MyPointer< std::vector<float> > track_endz_;
MyPointer< std::vector<float> > track_dirx_;
MyPointer< std::vector<float> > track_diry_;
MyPointer< std::vector<float> > track_dirz_;
// Proton *kinetic* energy using range-based momentum reconstruction
MyPointer< std::vector<float> > track_kinetic_energy_p_;
MyPointer< std::vector<float> > track_range_mom_mu_;
MyPointer< std::vector<float> > track_mcs_mom_mu_;
MyPointer< std::vector<float> > track_chi2_proton_;
// Log-likelihood ratio particle ID information
// Product of muon/proton log-likelihood ratios from all wire three planes
MyPointer< std::vector<float> > track_llr_pid_;
// Individual wire plane muon/proton log-likelihood ratios
MyPointer< std::vector<float> > track_llr_pid_U_;
MyPointer< std::vector<float> > track_llr_pid_V_;
MyPointer< std::vector<float> > track_llr_pid_Y_;
// Rescaled overall PID score (all three planes) that lies
// on the interval [-1, 1]
MyPointer< std::vector<float> > track_llr_pid_score_;
// True neutrino PDG code
int mc_nu_pdg_ = BOGUS_INT;
// True neutrino vertex coordinates (cm)
float mc_nu_vx_ = BOGUS;
float mc_nu_vy_ = BOGUS;
float mc_nu_vz_ = BOGUS;
// True neutrino 4-momentum
float mc_nu_energy_ = BOGUS;
// Whether the event is CC (0) or NC (1)
int mc_nu_ccnc_ = false;
// Interaction mode (QE, MEC, etc.)
int mc_nu_interaction_type_ = BOGUS_INT;
// Final-state particle PDG codes and energies (post-FSIs)
MyPointer< std::vector<int> > mc_nu_daughter_pdg_;
MyPointer< std::vector<float> > mc_nu_daughter_energy_;
MyPointer< std::vector<float> > mc_nu_daughter_px_;
MyPointer< std::vector<float> > mc_nu_daughter_py_;
MyPointer< std::vector<float> > mc_nu_daughter_pz_;
// General systematic weights
MyPointer< std::map< std::string, std::vector<double> > > mc_weights_map_;
// Map of pointers used to set output branch addresses for the elements
// of the weights map. Hacky, but it works.
// TODO: revisit this to make something more elegant
std::map< std::string, std::vector<double>* > mc_weights_ptr_map_;
// GENIE weights
float spline_weight_ = DEFAULT_WEIGHT;
float tuned_cv_weight_ = DEFAULT_WEIGHT;
// Signal definition requirements
bool is_mc_ = false;
bool mc_neutrino_is_numu_ = false;
bool mc_vertex_in_FV_ = false;
bool mc_muon_in_mom_range_ = false;
bool mc_lead_p_in_mom_range_ = false;
bool mc_no_fs_mesons_ = false;
// Intersection of all of these requirements
bool mc_is_signal_ = false;
// Extra flags for looking specifically at final-state pions
bool mc_no_fs_pi0_ = false;
bool mc_no_charged_pi_above_threshold_ = false;
EventCategory category_ = kUnknown;
// **** Reco selection requirements ****
// Whether the event passed the numu CC selection (a subset of the cuts
// used for the full analysis)
bool sel_nu_mu_cc_ = false;
// Whether the reconstructed neutrino vertex lies within the fiducial
// volume
bool sel_reco_vertex_in_FV_ = false;
// Whether the event passed the topological score cut
bool sel_topo_cut_passed_ = false;
// Whether the event passed the cosmic impact parameter cut
bool sel_cosmic_ip_cut_passed_ = false;
// Whether the start points for all PFParticles lie within the
// proton containment volume
bool sel_pfp_starts_in_PCV_ = false;
// True if a generation == 2 muon candidate was identified
bool sel_has_muon_candidate_ = false;
// Whether the end point of the muon candidate track is contained
// in the "containment volume"
bool sel_muon_contained_ = false;
// Whether the muon candidate has MCS- and range-based reco momenta
// that agree within a given tolerance
bool sel_muon_quality_ok_ = false;
// Whether the muon candidate has a reco momentum above threshold
bool sel_muon_passed_mom_cuts_ = false;
// False if at least one generation == 2 shower was reconstructed
bool sel_no_reco_showers_ = false;
// Whether at least one generation == 2 reco track exists that is not the
// muon candidate
bool sel_has_p_candidate_ = false;
// Whether all proton candidates (i.e., all tracks which are not the muon
// candidate) pass the proton PID cut or not
bool sel_passed_proton_pid_cut_ = false;
// Whether all proton candidates have track end coordinates that lie within
// the "containment volume"
bool sel_protons_contained_ = false;
// Whether the leading proton candidate has a range-based reco momentum
// above LEAD_P_MIN_MOM_CUT and below LEAD_P_MAX_MOM_CUT
bool sel_lead_p_passed_mom_cuts_ = false;
// Intersection of all of the above requirements
bool sel_CCNp0pi_ = false;
// Muon and leading proton candidate indices (BOGUS_INDEX if not present)
// in the reco track arrays
int muon_candidate_idx_ = BOGUS_INDEX;
int lead_p_candidate_idx_ = BOGUS_INDEX;
// ** Reconstructed observables **
// 3-momenta
MyPointer< TVector3 > p3_mu_;
MyPointer< TVector3 > p3_lead_p_;
// Reconstructed 3-momenta for all proton candidates,
// ordered from highest to lowest by magnitude
MyPointer< std::vector<TVector3> > p3_p_vec_;
// Reco STVs and other variables of interest
float delta_pT_ = BOGUS;
float delta_phiT_ = BOGUS;
float delta_alphaT_ = BOGUS;
float delta_pL_ = BOGUS;
float pn_ = BOGUS;
float delta_pTx_ = BOGUS;
float delta_pTy_ = BOGUS;
float theta_mu_p_ = BOGUS;
// ** MC truth observables **
// These are loaded for signal events whenever we have MC information
// to use
// 3-momenta
MyPointer< TVector3 > mc_p3_mu_;
MyPointer< TVector3 > mc_p3_lead_p_;
// True 3-momenta for all true MC protons, ordered from highest to lowest
// by magnitude
MyPointer< std::vector<TVector3> > mc_p3_p_vec_;
// MC truth STVs and other variables of interest
float mc_delta_pT_ = BOGUS;
float mc_delta_phiT_ = BOGUS;
float mc_delta_alphaT_ = BOGUS;
float mc_delta_pL_ = BOGUS;
float mc_pn_ = BOGUS;
float mc_delta_pTx_ = BOGUS;
float mc_delta_pTy_ = BOGUS;
float mc_theta_mu_p_ = BOGUS;
bool reco_vertex_inside_FV() {
return point_inside_FV( nu_vx_, nu_vy_, nu_vz_ );
}
bool mc_vertex_inside_FV() {
return point_inside_FV( mc_nu_vx_, mc_nu_vy_, mc_nu_vz_ );
}
bool in_proton_containment_vol( float x, float y, float z ) {
bool x_inside_PCV = ( PCV_X_MIN < x ) && ( x < PCV_X_MAX );
bool y_inside_PCV = ( PCV_Y_MIN < y ) && ( y < PCV_Y_MAX );
bool z_inside_PCV = ( PCV_Z_MIN < z ) && ( z < PCV_Z_MAX );
return ( x_inside_PCV && y_inside_PCV && z_inside_PCV );
}
};
// Helper function to set branch addresses for reading information
// from the Event TTree
void set_event_branch_addresses(TTree& etree, AnalysisEvent& ev)
{
// Reco PDG code of primary PFParticle in slice (i.e., the neutrino
// candidate)
etree.SetBranchAddress( "slpdg", &ev.nu_pdg_ );
// Number of neutrino slices identified by the SliceID. Allowed values
// are zero or one.
etree.SetBranchAddress( "nslice", &ev.nslice_ );
// Topological score
etree.SetBranchAddress( "topological_score", &ev.topological_score_ );
etree.SetBranchAddress( "CosmicIP", &ev.cosmic_impact_parameter_ );
//etree.SetBranchAddress( "CosmicIPAll3D", &ev.CosmicIPAll3D_ );
// Reconstructed neutrino vertex position (with corrections for
// space charge applied)
etree.SetBranchAddress( "reco_nu_vtx_sce_x", &ev.nu_vx_ );
etree.SetBranchAddress( "reco_nu_vtx_sce_y", &ev.nu_vy_ );
etree.SetBranchAddress( "reco_nu_vtx_sce_z", &ev.nu_vz_ );
// Reconstructed object counts
etree.SetBranchAddress( "n_pfps", &ev.num_pf_particles_ );
etree.SetBranchAddress( "n_tracks", &ev.num_tracks_ );
etree.SetBranchAddress( "n_showers", &ev.num_showers_ );
// PFParticle properties
set_object_input_branch_address( etree, "pfp_generation_v",
ev.pfp_generation_ );
set_object_input_branch_address( etree, "pfp_trk_daughters_v",
ev.pfp_trk_daughters_count_ );
set_object_input_branch_address( etree, "pfp_shr_daughters_v",
ev.pfp_shr_daughters_count_ );
set_object_input_branch_address( etree, "trk_score_v", ev.pfp_track_score_ );
set_object_input_branch_address( etree, "pfpdg", ev.pfp_reco_pdg_ );
set_object_input_branch_address( etree, "pfnhits", ev.pfp_hits_ );
set_object_input_branch_address( etree, "pfnplanehits_U", ev.pfp_hitsU_ );
set_object_input_branch_address( etree, "pfnplanehits_V", ev.pfp_hitsV_ );
set_object_input_branch_address( etree, "pfnplanehits_Y", ev.pfp_hitsY_ );
// Backtracked PFParticle properties
set_object_input_branch_address( etree, "backtracked_pdg", ev.pfp_true_pdg_ );
set_object_input_branch_address( etree, "backtracked_e", ev.pfp_true_E_ );
set_object_input_branch_address( etree, "backtracked_px", ev.pfp_true_px_ );
set_object_input_branch_address( etree, "backtracked_py", ev.pfp_true_py_ );
set_object_input_branch_address( etree, "backtracked_pz", ev.pfp_true_pz_ );
// Shower properties
// These are excluded from some ntuples to ensure blindness for the LEE
// analyses. We will skip them when not available.
bool has_shower_branches = ( etree.GetBranch("shr_pfp_id_v") != nullptr );
if ( has_shower_branches ) {
set_object_input_branch_address( etree, "shr_pfp_id_v", ev.shower_pfp_id_ );
set_object_input_branch_address( etree, "shr_start_x_v", ev.shower_startx_ );
set_object_input_branch_address( etree, "shr_start_y_v", ev.shower_starty_ );
set_object_input_branch_address( etree, "shr_start_z_v", ev.shower_startz_ );
// Shower start distance from reco neutrino vertex (pre-calculated for
// convenience)
set_object_input_branch_address( etree, "shr_dist_v",
ev.shower_start_distance_ );
}
else {
// When the shower information is not available, delete the owned vectors
// to signal that the associated branches should not be written to the
// output TTree
ev.shower_pfp_id_.reset( nullptr );
ev.shower_startx_.reset( nullptr );
ev.shower_starty_.reset( nullptr );
ev.shower_startz_.reset( nullptr );
ev.shower_start_distance_.reset( nullptr );
}
// Track properties
set_object_input_branch_address( etree, "trk_pfp_id_v", ev.track_pfp_id_ );
set_object_input_branch_address( etree, "trk_len_v", ev.track_length_ );
set_object_input_branch_address( etree, "trk_sce_start_x_v", ev.track_startx_ );
set_object_input_branch_address( etree, "trk_sce_start_y_v", ev.track_starty_ );
set_object_input_branch_address( etree, "trk_sce_start_z_v", ev.track_startz_ );
// Track start distance from reco neutrino vertex (pre-calculated for
// convenience)
set_object_input_branch_address( etree, "trk_distance_v",
ev.track_start_distance_ );
set_object_input_branch_address( etree, "trk_sce_end_x_v", ev.track_endx_ );
set_object_input_branch_address( etree, "trk_sce_end_y_v", ev.track_endy_ );
set_object_input_branch_address( etree, "trk_sce_end_z_v", ev.track_endz_ );
set_object_input_branch_address( etree, "trk_dir_x_v", ev.track_dirx_ );
set_object_input_branch_address( etree, "trk_dir_y_v", ev.track_diry_ );
set_object_input_branch_address( etree, "trk_dir_z_v", ev.track_dirz_ );
set_object_input_branch_address( etree, "trk_energy_proton_v",
ev.track_kinetic_energy_p_ );
set_object_input_branch_address( etree, "trk_range_muon_mom_v",
ev.track_range_mom_mu_ );
set_object_input_branch_address( etree, "trk_mcs_muon_mom_v",
ev.track_mcs_mom_mu_ );
// Some ntuples exclude the old proton chi^2 PID score. Only include it
// in the output if this branch is available.
bool has_chipr = ( etree.GetBranch("trk_pid_chipr_v") != nullptr );
if ( has_chipr ) {
set_object_input_branch_address( etree, "trk_pid_chipr_v",
ev.track_chi2_proton_ );
}
else {
ev.track_chi2_proton_.reset( nullptr );
}
// Log-likelihood-based particle ID information
set_object_input_branch_address( etree, "trk_llr_pid_v", ev.track_llr_pid_ );
set_object_input_branch_address( etree, "trk_llr_pid_u_v",
ev.track_llr_pid_U_ );
set_object_input_branch_address( etree, "trk_llr_pid_v_v",
ev.track_llr_pid_V_ );
set_object_input_branch_address( etree, "trk_llr_pid_y_v",
ev.track_llr_pid_Y_ );
set_object_input_branch_address( etree, "trk_llr_pid_score_v",
ev.track_llr_pid_score_ );
// MC truth information for the neutrino
etree.SetBranchAddress( "nu_pdg", &ev.mc_nu_pdg_ );
etree.SetBranchAddress( "true_nu_vtx_x", &ev.mc_nu_vx_ );
etree.SetBranchAddress( "true_nu_vtx_y", &ev.mc_nu_vy_ );
etree.SetBranchAddress( "true_nu_vtx_z", &ev.mc_nu_vz_ );
etree.SetBranchAddress( "nu_e", &ev.mc_nu_energy_ );
etree.SetBranchAddress( "ccnc", &ev.mc_nu_ccnc_ );
etree.SetBranchAddress( "interaction", &ev.mc_nu_interaction_type_ );
// MC truth information for the final-state primary particles
set_object_input_branch_address( etree, "mc_pdg", ev.mc_nu_daughter_pdg_ );
set_object_input_branch_address( etree, "mc_E", ev.mc_nu_daughter_energy_ );
set_object_input_branch_address( etree, "mc_px", ev.mc_nu_daughter_px_ );
set_object_input_branch_address( etree, "mc_py", ev.mc_nu_daughter_py_ );
set_object_input_branch_address( etree, "mc_pz", ev.mc_nu_daughter_pz_ );
// GENIE and other systematic variation weights
bool has_genie_mc_weights = ( etree.GetBranch("weightSpline") != nullptr );
if ( has_genie_mc_weights ) {
etree.SetBranchAddress( "weightSpline", &ev.spline_weight_ );
etree.SetBranchAddress( "weightTune", &ev.tuned_cv_weight_ );
}
bool has_weight_map = ( etree.GetBranch("weights") != nullptr );
if ( has_weight_map ) {
set_object_input_branch_address( etree, "weights", ev.mc_weights_map_ );
}
else {
ev.mc_weights_map_.reset( nullptr );
}
// Purity and completeness of the backtracked hits in the neutrino slice
bool has_pfp_backtracked_purity = ( etree.GetBranch("nu_purity_from_pfp")
!= nullptr );
if ( has_pfp_backtracked_purity ) {
etree.SetBranchAddress( "nu_completeness_from_pfp",
&ev.nu_completeness_from_pfp_ );
etree.SetBranchAddress( "nu_purity_from_pfp", &ev.nu_purity_from_pfp_ );
}
}
// Helper function to set branch addresses for the output TTree
void set_event_output_branch_addresses(TTree& out_tree, AnalysisEvent& ev,
bool create = false)
{
// Signal definition flags
set_output_branch_address( out_tree, "is_mc", &ev.is_mc_, create, "is_mc/O" );
set_output_branch_address( out_tree, "mc_neutrino_is_numu",
&ev.mc_neutrino_is_numu_, create, "mc_neutrino_is_numu/O" );
set_output_branch_address( out_tree, "mc_vertex_in_FV",
&ev.mc_vertex_in_FV_, create, "mc_vertex_in_FV/O" );
set_output_branch_address( out_tree, "mc_muon_in_mom_range",
&ev.mc_muon_in_mom_range_, create, "mc_muon_in_mom_range/O" );
set_output_branch_address( out_tree, "mc_lead_p_in_mom_range",
&ev.mc_lead_p_in_mom_range_, create, "mc_lead_p_in_mom_range/O" );
set_output_branch_address( out_tree, "mc_no_fs_pi0",
&ev.mc_no_fs_pi0_, create, "mc_no_fs_pi0/O" );
set_output_branch_address( out_tree, "mc_no_charged_pi_above_threshold",
&ev.mc_no_charged_pi_above_threshold_, create,
"mc_no_charged_pi_above_threshold/O" );
set_output_branch_address( out_tree, "mc_no_fs_mesons",
&ev.mc_no_fs_mesons_, create, "mc_no_fs_mesons/O" );
set_output_branch_address( out_tree, "mc_is_signal",
&ev.mc_is_signal_, create, "mc_is_signal/O" );
// MC event category
set_output_branch_address( out_tree, "category",
&ev.category_, create, "category/I" );
// Event weights
set_output_branch_address( out_tree, "spline_weight",
&ev.spline_weight_, create, "spline_weight/F" );
set_output_branch_address( out_tree, "tuned_cv_weight",
&ev.tuned_cv_weight_, create, "tuned_cv_weight/F" );
// If MC weights are available, prepare to store them in the output TTree
if ( ev.mc_weights_map_ ) {
// Make separate branches for the various sets of systematic variation
// weights in the map
for ( auto& pair : *ev.mc_weights_map_ ) {
// Prepend "weight_" to the name of the vector of weights in the map
std::string weight_branch_name = "weight_" + pair.first;
// Store a pointer to the vector of weights (needed to set the branch
// address properly) in the temporary map of pointers
ev.mc_weights_ptr_map_[ weight_branch_name ] = &pair.second;
// Set the branch address for this vector of weights
set_object_output_branch_address< std::vector<double> >( out_tree,
weight_branch_name, ev.mc_weights_ptr_map_.at(weight_branch_name),
create );
}
}
// Backtracked neutrino purity and completeness
set_output_branch_address( out_tree, "nu_completeness_from_pfp",
&ev.nu_completeness_from_pfp_, create, "nu_completeness_from_pfp/F" );
set_output_branch_address( out_tree, "nu_purity_from_pfp",
&ev.nu_purity_from_pfp_, create, "nu_purity_from_pfp/F" );
// Number of neutrino slices identified by the SliceID
set_output_branch_address( out_tree, "nslice", &ev.nslice_, create,
"nslice/I" );
// CCNp0pi selection criteria
set_output_branch_address( out_tree, "sel_nu_mu_cc", &ev.sel_nu_mu_cc_,
create, "sel_nu_mu_cc/O" );
set_output_branch_address( out_tree, "sel_reco_vertex_in_FV",
&ev.sel_reco_vertex_in_FV_, create, "sel_reco_vertex_in_FV/O" );
set_output_branch_address( out_tree, "sel_topo_cut_passed",
&ev.sel_topo_cut_passed_, create, "sel_topo_cut_passed/O" );
set_output_branch_address( out_tree, "sel_cosmic_ip_cut_passed",
&ev.sel_cosmic_ip_cut_passed_, create, "sel_cosmic_ip_cut_passed/O" );
set_output_branch_address( out_tree, "sel_pfp_starts_in_PCV",
&ev.sel_pfp_starts_in_PCV_, create, "sel_pfp_starts_in_PCV/O" );
set_output_branch_address( out_tree, "sel_no_reco_showers",
&ev.sel_no_reco_showers_, create, "sel_no_reco_showers/O" );
set_output_branch_address( out_tree, "sel_has_muon_candidate",
&ev.sel_has_muon_candidate_, create,
"sel_has_muon_candidate/O" );
set_output_branch_address( out_tree, "sel_muon_contained",
&ev.sel_muon_contained_, create, "sel_muon_contained/O" );
set_output_branch_address( out_tree, "sel_muon_passed_mom_cuts",
&ev.sel_muon_passed_mom_cuts_, create, "sel_muon_passed_mom_cuts/O" );
set_output_branch_address( out_tree, "sel_muon_quality_ok",
&ev.sel_muon_quality_ok_, create, "sel_muon_quality_ok/O" );
set_output_branch_address( out_tree, "sel_has_p_candidate",
&ev.sel_has_p_candidate_, create, "sel_has_p_candidate/O" );
set_output_branch_address( out_tree, "sel_passed_proton_pid_cut",
&ev.sel_passed_proton_pid_cut_, create, "sel_passed_proton_pid_cut/O" );
set_output_branch_address( out_tree, "sel_protons_contained",
&ev.sel_protons_contained_, create, "sel_protons_contained/O" );
set_output_branch_address( out_tree, "sel_lead_p_passed_mom_cuts",
&ev.sel_lead_p_passed_mom_cuts_, create, "sel_lead_p_passed_mom_cuts/O" );
set_output_branch_address( out_tree, "sel_CCNp0pi",
&ev.sel_CCNp0pi_, create, "sel_CCNp0pi/O" );
// Index for the muon candidate in the vectors of PFParticles
set_output_branch_address( out_tree, "muon_candidate_idx",
&ev.muon_candidate_idx_, create, "muon_candidate_idx/I" );
// Index for the leading proton candidate in the vectors of PFParticles
set_output_branch_address( out_tree, "lead_p_candidate_idx",
&ev.lead_p_candidate_idx_, create, "lead_p_candidate_idx/I" );
// Reco 3-momenta (muon, leading proton)
set_object_output_branch_address< TVector3 >( out_tree,
"p3_mu", ev.p3_mu_, create );
set_object_output_branch_address< TVector3 >( out_tree,
"p3_lead_p", ev.p3_lead_p_, create );
// Reco 3-momenta (all proton candidates, ordered from highest to lowest
// magnitude)
set_object_output_branch_address< std::vector<TVector3> >( out_tree,
"p3_p_vec", ev.p3_p_vec_, create );
// True 3-momenta (muon, leading proton)
set_object_output_branch_address< TVector3 >( out_tree,
"mc_p3_mu", ev.mc_p3_mu_, create );
set_object_output_branch_address< TVector3 >( out_tree,
"mc_p3_lead_p", ev.mc_p3_lead_p_, create );
// True 3-momenta (all protons, ordered from highest to lowest magnitude)
set_object_output_branch_address< std::vector<TVector3> >( out_tree,
"mc_p3_p_vec", ev.mc_p3_p_vec_, create );
// Reco STVs
set_output_branch_address( out_tree, "delta_pT",
&ev.delta_pT_, create, "delta_pT/F" );
set_output_branch_address( out_tree, "delta_phiT",
&ev.delta_phiT_, create, "delta_phiT/F" );
set_output_branch_address( out_tree, "delta_alphaT",
&ev.delta_alphaT_, create, "delta_alphaT/F" );
set_output_branch_address( out_tree, "delta_pL",
&ev.delta_pL_, create, "delta_pL/F" );
set_output_branch_address( out_tree, "pn",
&ev.pn_, create, "pn/F" );
set_output_branch_address( out_tree, "delta_pTx",
&ev.delta_pTx_, create, "delta_pTx/F" );
set_output_branch_address( out_tree, "delta_pTy",
&ev.delta_pTy_, create, "delta_pTy/F" );
set_output_branch_address( out_tree, "theta_mu_p",
&ev.theta_mu_p_, create, "theta_mu_p/F" );
// MC STVs (only filled for signal events)
set_output_branch_address( out_tree, "mc_delta_pT",
&ev.mc_delta_pT_, create, "mc_delta_pT/F" );
set_output_branch_address( out_tree, "mc_delta_phiT",
&ev.mc_delta_phiT_, create, "mc_delta_phiT/F" );
set_output_branch_address( out_tree, "mc_delta_alphaT",
&ev.mc_delta_alphaT_, create, "mc_delta_alphaT/F" );
set_output_branch_address( out_tree, "mc_delta_pL",
&ev.mc_delta_pL_, create, "mc_delta_pL/F" );
set_output_branch_address( out_tree, "mc_pn",
&ev.mc_pn_, create, "mc_pn/F" );
set_output_branch_address( out_tree, "mc_delta_pTx",
&ev.mc_delta_pTx_, create, "mc_delta_pTx/F" );
set_output_branch_address( out_tree, "mc_delta_pTy",
&ev.mc_delta_pTy_, create, "mc_delta_pTy/F" );
set_output_branch_address( out_tree, "mc_theta_mu_p",
&ev.mc_theta_mu_p_, create, "mc_theta_mu_p/F" );
// *** Branches copied directly from the input ***
// Cosmic rejection parameters for numu CC inclusive selection
set_output_branch_address( out_tree, "topological_score",
&ev.topological_score_, create, "topological_score/F" );
set_output_branch_address( out_tree, "CosmicIP",
&ev.cosmic_impact_parameter_, create, "CosmicIP/F" );
// Reconstructed neutrino vertex position
set_output_branch_address( out_tree, "reco_nu_vtx_sce_x",
&ev.nu_vx_, create, "reco_nu_vtx_sce_x/F" );
set_output_branch_address( out_tree, "reco_nu_vtx_sce_y",
&ev.nu_vy_, create, "reco_nu_vtx_sce_y/F" );
set_output_branch_address( out_tree, "reco_nu_vtx_sce_z",
&ev.nu_vz_, create, "reco_nu_vtx_sce_z/F" );
// MC truth information for the neutrino
set_output_branch_address( out_tree, "mc_nu_pdg", &ev.mc_nu_pdg_,
create, "mc_nu_pdg/I" );
set_output_branch_address( out_tree, "mc_nu_vtx_x", &ev.mc_nu_vx_,
create, "mc_nu_vtx_x/F" );
set_output_branch_address( out_tree, "mc_nu_vtx_y", &ev.mc_nu_vy_,
create, "mc_nu_vtx_y/F" );
set_output_branch_address( out_tree, "mc_nu_vtx_z", &ev.mc_nu_vz_,
create, "mc_nu_vtx_z/F" );
set_output_branch_address( out_tree, "mc_nu_energy", &ev.mc_nu_energy_,
create, "mc_nu_energy/F" );
set_output_branch_address( out_tree, "mc_ccnc", &ev.mc_nu_ccnc_,
create, "mc_ccnc/I" );
set_output_branch_address( out_tree, "mc_interaction",
&ev.mc_nu_interaction_type_, create, "mc_interaction/I" );
// PFParticle properties
set_object_output_branch_address< std::vector<unsigned int> >( out_tree,
"pfp_generation_v", ev.pfp_generation_, create );
set_object_output_branch_address< std::vector<unsigned int> >( out_tree,
"pfp_trk_daughters_v", ev.pfp_trk_daughters_count_, create );
set_object_output_branch_address< std::vector<unsigned int> >( out_tree,
"pfp_shr_daughters_v", ev.pfp_shr_daughters_count_, create );
set_object_output_branch_address< std::vector<float> >( out_tree,
"trk_score_v", ev.pfp_track_score_, create );
set_object_output_branch_address< std::vector<int> >( out_tree,
"pfpdg", ev.pfp_reco_pdg_, create );
set_object_output_branch_address< std::vector<int> >( out_tree,
"pfnhits", ev.pfp_hits_, create );
set_object_output_branch_address< std::vector<int> >( out_tree,
"pfnplanehits_U", ev.pfp_hitsU_, create );
set_object_output_branch_address< std::vector<int> >( out_tree,
"pfnplanehits_V", ev.pfp_hitsV_, create );
set_object_output_branch_address< std::vector<int> >( out_tree,
"pfnplanehits_Y", ev.pfp_hitsY_, create );
// Backtracked PFParticle properties
set_object_output_branch_address< std::vector<int> >( out_tree,
"backtracked_pdg", ev.pfp_true_pdg_, create );
set_object_output_branch_address< std::vector<float> >( out_tree,
"backtracked_e", ev.pfp_true_E_, create );
set_object_output_branch_address< std::vector<float> >( out_tree,
"backtracked_px", ev.pfp_true_px_, create );
set_object_output_branch_address< std::vector<float> >( out_tree,
"backtracked_py", ev.pfp_true_py_, create );
set_object_output_branch_address< std::vector<float> >( out_tree,
"backtracked_pz", ev.pfp_true_pz_, create );
// Shower properties
// For some ntuples, reconstructed shower information is excluded.
// In such cases, skip writing these branches to the output TTree.
if ( ev.shower_startx_ ) {
set_object_output_branch_address< std::vector<float> >( out_tree,
"shr_start_x_v", ev.shower_startx_, create );
set_object_output_branch_address< std::vector<float> >( out_tree,
"shr_start_y_v", ev.shower_starty_, create );
set_object_output_branch_address< std::vector<float> >( out_tree,
"shr_start_z_v", ev.shower_startz_, create );
// Shower start distance from reco neutrino vertex (pre-calculated for
// convenience)
set_object_output_branch_address< std::vector<float> >( out_tree,
"shr_dist_v", ev.shower_start_distance_, create );
}
// Track properties
set_object_output_branch_address< std::vector<float> >( out_tree,
"trk_len_v", ev.track_length_, create );
set_object_output_branch_address< std::vector<float> >( out_tree,
"trk_sce_start_x_v", ev.track_startx_, create );
set_object_output_branch_address< std::vector<float> >( out_tree,
"trk_sce_start_y_v", ev.track_starty_, create );
set_object_output_branch_address< std::vector<float> >( out_tree,
"trk_sce_start_z_v", ev.track_startz_, create );
// Track start distance from reco neutrino vertex (pre-calculated for
// convenience)
set_object_output_branch_address< std::vector<float> >( out_tree,
"trk_distance_v", ev.track_start_distance_, create );
set_object_output_branch_address< std::vector<float> >( out_tree,
"trk_sce_end_x_v", ev.track_endx_, create );
set_object_output_branch_address< std::vector<float> >( out_tree,
"trk_sce_end_y_v", ev.track_endy_, create );
set_object_output_branch_address< std::vector<float> >( out_tree,
"trk_sce_end_z_v", ev.track_endz_, create );
set_object_output_branch_address< std::vector<float> >( out_tree,
"trk_dir_x_v", ev.track_dirx_, create );
set_object_output_branch_address< std::vector<float> >( out_tree,
"trk_dir_y_v", ev.track_diry_, create );
set_object_output_branch_address< std::vector<float> >( out_tree,
"trk_dir_z_v", ev.track_dirz_, create );
set_object_output_branch_address< std::vector<float> >( out_tree,
"trk_energy_proton_v", ev.track_kinetic_energy_p_, create );
set_object_output_branch_address< std::vector<float> >( out_tree,
"trk_range_muon_mom_v", ev.track_range_mom_mu_, create );
set_object_output_branch_address< std::vector<float> >( out_tree,
"trk_mcs_muon_mom_v", ev.track_mcs_mom_mu_, create );
// Some ntuples exclude the old chi^2 proton PID score. Only include it in
// the output if it is available.
if ( ev.track_chi2_proton_ ) {
set_object_output_branch_address< std::vector<float> >( out_tree,
"trk_pid_chipr_v", ev.track_chi2_proton_, create );
}
// Log-likelihood-based particle ID information
set_object_output_branch_address< std::vector<float> >( out_tree,
"trk_llr_pid_v", ev.track_llr_pid_, create );
set_object_output_branch_address< std::vector<float> >( out_tree,
"trk_llr_pid_u_v", ev.track_llr_pid_U_, create );
set_object_output_branch_address< std::vector<float> >( out_tree,
"trk_llr_pid_v_v", ev.track_llr_pid_V_, create );
set_object_output_branch_address< std::vector<float> >( out_tree,
"trk_llr_pid_y_v", ev.track_llr_pid_Y_, create );
set_object_output_branch_address< std::vector<float> >( out_tree,
"trk_llr_pid_score_v", ev.track_llr_pid_score_, create );
// MC truth information for the final-state primary particles
set_object_output_branch_address< std::vector<int> >( out_tree, "mc_pdg",
ev.mc_nu_daughter_pdg_, create );
set_object_output_branch_address< std::vector<float> >( out_tree, "mc_E",
ev.mc_nu_daughter_energy_, create );
set_object_output_branch_address< std::vector<float> >( out_tree, "mc_px",
ev.mc_nu_daughter_px_, create );
set_object_output_branch_address< std::vector<float> >( out_tree, "mc_py",
ev.mc_nu_daughter_py_, create );
set_object_output_branch_address< std::vector<float> >( out_tree, "mc_pz",
ev.mc_nu_daughter_pz_, create );