Hall-D Software  alpha
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
mergeTrees.C
Go to the documentation of this file.
1 /*
2  * This script is designed to take a primary and secondary TTree produced
3  * by the ReactionFilter plugin and merge the chi-square and ndf of the
4  * secondary TTree into the primary.
5  *
6  * The TTrees should be similar such that some of the final state particles
7  * could be swapped with each other, i.e. K+, K-, p and Pi+, Pi-, p
8  *
9  * Author: Alex Barnes
10 */
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string>
14 #include <iostream>
15 #include <chrono>
16 #include <algorithm>
17 
18 #include "TFile.h"
19 #include "TTree.h"
20 #include "TObjArray.h"
21 #include "TBranch.h"
22 #include "TTreeReader.h"
23 #include "TTreeReaderValue.h"
24 #include "TTreeReaderArray.h"
25 
26 using namespace std;
27 using namespace chrono;
28 
29 vector<const char*> getBranches(TTree *tree)
30 {
31  vector<const char*> locVector;
32 
33  TObjArray *arr = tree->GetListOfBranches();
34 
35  for (int i = 0; i < arr->GetEntries(); ++i)
36  {
37  TBranch *b = (TBranch*)arr->At(i);
38  const char* b_name = b->GetName();
39 
40  // Get branches that vary between TTrees
41  if ( strstr( b_name, "__ChargedIndex" ) != NULL ||
42  strstr( b_name, "__NeutralIndex" ) != NULL )
43  {
44  locVector.push_back( b_name );
45  }
46  else
47  continue; // branch didn't match with anything that should be kept
48  }
49 
50  return locVector;
51 }
52 
53 bool searchMap( map<string, Int_t> p_map, string substring )
54 {
55  // This method searches a map to determine if it contains a final state particle matching the substring
56  bool isMatch = false;
57  for ( auto const &p_iter : p_map )
58  {
59  if ( p_iter.first.find(substring) != string::npos )
60  isMatch = true;
61  }
62 
63  return isMatch;
64 }
65 
66 bool compareMaps( map<string, Int_t> p_map, map<string, Int_t> s_map )
67 {
68 
69  bool isMatch = false;
70  int totalParticles = 0;
71  int matchedParticles = 0;
72 
73  // check that maps are the same size
74  if ( p_map.size() != s_map.size() )
75  return isMatch;
76 
77  // loop over the primary TTree's map of (branch name, track ID)
78  for ( auto const &p_iter : p_map )
79  {
80  totalParticles++;
81 
82  // loop over the secondary TTree's map of (branch name, track ID)
83  for ( auto const &s_iter : s_map )
84  {
85  // compare the trackIDs
86  if ( p_iter.second == s_iter.second )
87  matchedParticles++;
88  }
89  }
90 
91  isMatch = ( totalParticles == matchedParticles ) ? true : false;
92 
93  return isMatch;
94 
95 }
96 
97 void mergeTrees(const char* primaryFile, const char* primaryTree, const char* secondaryFile, const char* secondaryTree)
98 {
99  // For measuring performance
100  high_resolution_clock::time_point t1 = high_resolution_clock::now();
101 
102  TFile f_secondary(secondaryFile);
103  TTree *t_secondary = (TTree*)f_secondary.Get(secondaryTree);
104 
105  TFile f_orig(primaryFile);
106  TTree *t_orig = (TTree*)f_orig.Get(primaryTree);
107 
108  TFile f_primary("newtree.root", "recreate");
109  TTree *t_primary = (TTree*)t_orig->CloneTree();
110 
111  // Get branch information for each TTree
112  vector<const char*> branches_primary = getBranches(t_primary);
113  vector<const char*> branches_secondary = getBranches(t_secondary);
114 
115  // get reaction names and set up arrays for new branches
116  UInt_t initArraySize = 100;
117  Float_t new_chisq[initArraySize];
118  UInt_t new_ndf[initArraySize];
119  string p(primaryTree);
120  string primaryReactionName = p.substr(0, p.find("_"));
121  cout << "Primary reaction: " << primaryReactionName << endl;
122  string s(secondaryTree);
123  string secondaryReactionName = s.substr(0, s.find("_"));
124  cout << "Secondary reaction: " << secondaryReactionName << endl;
125 
126  // primary tree
127  TTreeReader primaryReader(t_primary);
128  cout << "added primary tree" << endl;
129  TTreeReaderArray<Float_t> chisq(primaryReader, "ChiSq_KinFit");
130  TTreeReaderArray<UInt_t> ndf(primaryReader, "NDF_KinFit");
131  TTreeReaderValue<UInt_t> run(primaryReader, "RunNumber");
132  TTreeReaderValue<ULong64_t> event(primaryReader, "EventNumber");
133  TTreeReaderArray<Int_t> ChargedHypoID(primaryReader, "ChargedHypo__TrackID");
134  TTreeReaderArray<Int_t> ChargedHypo__PID(primaryReader, "ChargedHypo__PID");
135  TTreeReaderArray<Int_t> NeutralHypoID(primaryReader, "NeutralHypo__NeutralID");
136  TTreeReaderArray<Int_t> beam_ID(primaryReader, "ComboBeam__BeamIndex");
137  // secondary tree
138  TTreeReader secondaryReader(t_secondary);
139  cout << "added secondary tree" << endl;
140  TTreeReaderArray<Float_t> secondary_chisq(secondaryReader, "ChiSq_KinFit");
141  TTreeReaderArray<UInt_t> secondary_ndf(secondaryReader, "NDF_KinFit");
142  TTreeReaderValue<UInt_t> secondary_run(secondaryReader, "RunNumber");
143  TTreeReaderValue<ULong64_t> secondary_event(secondaryReader, "EventNumber");
144  TTreeReaderArray<Int_t> secondary_ChargedHypoID(secondaryReader, "ChargedHypo__TrackID");
145  TTreeReaderArray<Int_t> secondary_ChargedHypo__PID(secondaryReader, "ChargedHypo__PID");
146  TTreeReaderArray<Int_t> secondary_NeutralHypoID(primaryReader, "NeutralHypo__NeutralID");
147  TTreeReaderArray<Int_t> secondary_beam_ID(secondaryReader, "ComboBeam__BeamIndex");
148 
149  // The only branches that will vary are the Int arrays
150  // Map for the Int array branches
151  map< const char*, TTreeReaderArray<Int_t> > primary_ReaderArray__Int;
152  map< const char*, TTreeReaderArray<Int_t> > secondary_ReaderArray__Int;
153 
154  // Create TTreeReaderArrays for the Int_t branches
155  for ( auto const& p_iter : branches_primary )
156  {
157  TTreeReaderArray<Int_t> a(primaryReader, p_iter);
158  auto P = make_pair( p_iter, a );
159  primary_ReaderArray__Int.insert(P);
160  }
161  for ( auto const& s_iter : branches_secondary )
162  {
163  TTreeReaderArray<Int_t> a(secondaryReader, s_iter);
164  auto P = make_pair( s_iter, a );
165  secondary_ReaderArray__Int.insert(P);
166  }
167  cout << "Added to maps" << endl;
168 
169  // Get sizes of each map
170  const int size_primary = (int)primary_ReaderArray__Int.size();
171  const int size_secondary = (int)secondary_ReaderArray__Int.size();
172  // Make arrays of the map keys
173  const char* keys_primary[ size_primary ];
174  const char* keys_secondary[ size_secondary ];
175  // Get keys and fill arrays
176  int count = 0;
177  for ( auto const& p_iter : primary_ReaderArray__Int )
178  {
179  keys_primary[count] = p_iter.first;
180  ++count;
181  }
182  count = 0;
183  for ( auto const& s_iter : secondary_ReaderArray__Int )
184  {
185  keys_secondary[count] = s_iter.first;
186  ++count;
187  }
188 
189  // Create branches for secondary chisq and NDF
190  string branchName("ChiSq_KinFit_");
191  branchName += secondaryReactionName;
192  TBranch *new_b_chisq = t_primary->Branch(branchName.c_str(), &new_chisq, (branchName + "[NumCombos]/F").c_str() );
193  branchName = "NDF_KinFit_";
194  branchName += secondaryReactionName;
195  TBranch *new_b_ndf = t_primary->Branch(branchName.c_str(), &new_ndf, (branchName + "[NumCombos]/i").c_str() );
196 
197  // Make std::map< EventNumber, entry > for secondary TTree
198  map< ULong64_t, Long64_t > map_event_secondary;
199  while (secondaryReader.Next() )
200  {
201  ULong64_t thisEvent = *secondary_event;
202  Long64_t thisEntry = secondaryReader.GetCurrentEntry();
203  map_event_secondary.insert( pair< ULong64_t, Long64_t >(thisEvent, thisEntry ) );
204  }
205 
206  // Find primary's EventNumber in secondary's TTree and get the desired information
207  while (primaryReader.Next() )
208  {
209  Long64_t pentry = primaryReader.GetCurrentEntry();
210  if ( pentry / 1000000 * 1000000 == pentry )
211  cout << pentry / 1000000 + 1 << " million events analyzed" << endl;
212 
213  // TTreeReader.SetEntry() won't work unless the TTreeReader is restarted to the 0th entry
214  secondaryReader.Restart();
215 
216  // Reset defaults for next event
217  for (UInt_t i = 0; i < initArraySize; ++i)
218  {
219  new_chisq[i] = -1.0;
220  new_ndf[i] = 1;
221  }
222 
223  UInt_t p_numCombos = primary_ReaderArray__Int.begin()->second.GetSize();
224 
225  // Need to put in safe guard in case event doesn't exist
226  if (map_event_secondary.find( *event ) == map_event_secondary.end() )
227  {
228  new_b_chisq->Fill();
229  new_b_ndf->Fill();
230  continue;
231  }
232  else
233  {
234  Long64_t entry = map_event_secondary.at( *event );
235  secondaryReader.SetEntry( entry );
236  }
237 
238  // Only get secondary number of combos if event exists in secondary TTree
239  UInt_t s_numCombos = secondary_ReaderArray__Int.begin()->second.GetSize();
240 
241  // Loop over primary combos
242  for (UInt_t i = 0; i < p_numCombos; ++i)
243  {
244  bool isMatched = false;
245 
246  // Get primary trackIDs
247  map<string, Int_t> primary_trackIDs;
248  map<string, Int_t> primary_neutralIDs;
249  for ( int i_keys = 0; i_keys < size_primary; ++i_keys )
250  {
251  Int_t track;
252  Int_t neutral;
253  const char* b_name = keys_primary[ i_keys ];
254  string s(b_name);
255  if ( strstr( b_name, "__ChargedIndex" ) != NULL )
256  {
257  track = ChargedHypoID[ primary_ReaderArray__Int.at( b_name )[i] ];
258  auto track_pair = make_pair( s, track );
259  primary_trackIDs.insert( track_pair );
260  }
261  else if ( strstr( b_name, "__NeutralIndex" ) != NULL )
262  {
263  neutral = NeutralHypoID[ primary_ReaderArray__Int.at( b_name )[i] ];
264  auto neutral_pair = make_pair( s, neutral );
265  primary_neutralIDs.insert( neutral_pair );
266  }
267  else continue;
268  }
269  Int_t beam = beam_ID[i];
270 
271  // Loop over the secondary combos
272  for (UInt_t j = 0; j < s_numCombos; ++j)
273  {
274  map<string, Int_t> secondary_trackIDs;
275  map<string, Int_t> secondary_neutralIDs;
276  for ( int j_keys = 0; j_keys < size_secondary; ++j_keys )
277  {
278  Int_t track;
279  Int_t neutral;
280  const char* b_name = keys_secondary[ j_keys ];
281  string s(b_name);
282  if ( strstr( b_name, "__ChargedIndex" ) != NULL )
283  {
284  track = secondary_ChargedHypoID[ secondary_ReaderArray__Int.at( b_name )[j] ];
285  auto track_pair = make_pair( s, track );
286  secondary_trackIDs.insert(track_pair);
287  }
288  else if ( strstr( b_name, "__NeutralIndex" ) != NULL )
289  {
290  neutral = secondary_NeutralHypoID[ secondary_ReaderArray__Int.at( b_name )[j] ];
291  auto neutral_pair = make_pair( s, neutral );
292  secondary_neutralIDs.insert( neutral_pair );
293  }
294  else continue;
295  }
296  Int_t secondary_beam = secondary_beam_ID[j];
297 
298  // check for the types of final state particles in the primary map
299  bool hasPlus = searchMap( primary_trackIDs, "Plus" );
300  bool hasMinus = searchMap( primary_trackIDs, "Minus" );
301  bool hasProton = searchMap( primary_trackIDs, "Proton" ); // finds both protons and antiprotons
302  bool hasPhoton = searchMap( primary_neutralIDs, "Photon" );
303 
304  // if the reaction does not contain a certain type of final state particle, set the match to true
305  // otherwise, find the correct match
306  bool chargedMatch = (hasPlus || hasMinus || hasProton) ? compareMaps( primary_trackIDs, secondary_trackIDs ) : true;
307  bool neutralMatch = hasPhoton ? compareMaps( primary_neutralIDs, secondary_neutralIDs ) : true;
308 
309  // match final state particle IDs
310  if ( !(chargedMatch && neutralMatch) )
311  continue;
312  // match beam ID
313  if (beam != secondary_beam)
314  continue;
315 
316  // grab secondary chisq, ndf information
317  new_chisq[i] = secondary_chisq[j];
318  new_ndf[i] = secondary_ndf[j];
319  isMatched = true;
320  }
321  }
322 
323  new_b_chisq->Fill();
324  new_b_ndf->Fill();
325 
326  }
327  t_primary->Write("", TObject::kOverwrite); // save only the new version of the tree
328 
329  // For measuring performance
330  high_resolution_clock::time_point t2 = high_resolution_clock::now();
331 
332  auto duration = duration_cast<microseconds>( t2 - t1 ).count();
333  cout << "The process took: " << duration << " microseconds" << endl;
334  cout << "The process took: " << duration*1E-6 << " seconds" << endl;
335  cout << "The process took: " << duration*1E-6/60. << " minutes" << endl;
336 
337 }
Definition: track.h:16
bool searchMap(map< string, Int_t > p_map, string substring)
Definition: mergeTrees.C:53
bool compareMaps(map< string, Int_t > p_map, map< string, Int_t > s_map)
Definition: mergeTrees.C:66
TLatex * t1
vector< const char * > getBranches(TTree *tree)
Definition: mergeTrees.C:29
void mergeTrees(const char *primaryFile, const char *primaryTree, const char *secondaryFile, const char *secondaryTree)
Definition: mergeTrees.C:97