Hall-D Software  alpha
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
DAnalysisUtilities.cc
Go to the documentation of this file.
1 #ifdef VTRACE
2 #include "vt_user.h"
3 #endif
4 
5 #include "DAnalysisUtilities.h"
7 
8 DAnalysisUtilities::DAnalysisUtilities(JEventLoop* locEventLoop)
9 {
10  DEBUG_LEVEL=0;
11  gPARMS->SetDefaultParameter("DAnalysisUtilities:DEBUG_LEVEL",DEBUG_LEVEL);
12 
13  locEventLoop->GetSingle(dPIDAlgorithm);
14 
15  dTargetZCenter = 65.0;
16  // Get Target parameters from XML
17  DApplication *locApplication = dynamic_cast<DApplication*> (locEventLoop->GetJApplication());
18  DGeometry *locGeometry = locApplication ? locApplication->GetDGeometry(locEventLoop->GetJEvent().GetRunNumber()) : NULL;
19  locGeometry->GetTargetZ(dTargetZCenter);
20 
21  //Get magnetic field map
22  dMagneticFieldMap = locApplication->GetBfield(locEventLoop->GetJEvent().GetRunNumber());
23  dIsNoFieldFlag = (dynamic_cast<const DMagneticFieldMapNoField*>(dMagneticFieldMap) != NULL);
24 
25  //For "Unused" tracks/showers
26  //BEWARE: IF THIS IS CHANGED, CHANGE IN THE BLUEPRINT FACTORY AND THE EVENT WRITER ALSO!!
27  dTrackSelectionTag = "PreSelect";
28  dShowerSelectionTag = "PreSelect";
29  gPARMS->SetDefaultParameter("COMBO:TRACK_SELECT_TAG", dTrackSelectionTag);
30  gPARMS->SetDefaultParameter("COMBO:SHOWER_SELECT_TAG", dShowerSelectionTag);
31 }
32 
33 bool DAnalysisUtilities::Check_IsBDTSignalEvent(JEventLoop* locEventLoop, const DReaction* locReaction, bool locExclusiveMatchFlag, bool locIncludeDecayingToReactionFlag) const
34 {
35 #ifdef VTRACE
36  VT_TRACER("DAnalysisUtilities::Check_IsBDTSignalEvent()");
37 #endif
38 
39  //IF DREACTION HAS A MISSING UNKNOWN PARTICLE, MUST USE locExclusiveMatchFlag = false
40 
41  //if locIncludeDecayingToReactionFlag = true, will test whether the thrown reaction could decay to the DReaction
42  //Note that resonances, phi's, and omega's are automatically decayed
43  //e.g. if DReaction or thrown is g, p -> pi+, pi-, omega, p; will instead treat it as g, p -> 2pi+, 2pi-, pi0, p (or whatever the omega decay products are)
44  //e.g. g, p -> pi+, pi0, K0, Lambda can decay to g, p -> 2pi+, 2pi-, pi0, p
45  //if locIncludeDecayingToReactionFlag = true, then it would be included as "Signal," if false, then background
46  //locIncludeDecayingToReactionFlag should be true UNLESS you are explicitly checking all possible reactions that could decay to your channel in your BDT
47  //e.g. could kinfit to g, p -> pi+, pi0, K0, Lambda and include it as a BDT variable
48 
49  if(dParticleComboCreator == nullptr) //Can't create in constructor: infinite recursion
50  dParticleComboCreator = new DParticleComboCreator(locEventLoop, nullptr, nullptr, nullptr);
51  DReaction_factory_Thrown* dThrownReactionFactory = static_cast<DReaction_factory_Thrown*>(locEventLoop->GetFactory("DReaction", "Thrown"));
52 
53  vector<const DReaction*> locThrownReactions;
54  locEventLoop->Get(locThrownReactions, "Thrown");
55  if(locThrownReactions.empty())
56  return false;
57  auto locActualThrownReaction = locThrownReactions[0];
58 
59  //Replace omega & phi in DReaction with their decay products
60  size_t locStepIndex = 0;
61  vector<DReactionStep> locNewReactionSteps;
62  const DReaction* locCurrentReaction = locReaction;
63  DReaction locNewReaction("Interim"); //if needed
64 
65  do
66  {
67  const DReactionStep* locReactionStep = locCurrentReaction->Get_ReactionStep(locStepIndex);
68  Particle_t locInitialPID = locReactionStep->Get_InitialPID();
69  if((locInitialPID != omega) && (locInitialPID != phiMeson))
70  {
71  ++locStepIndex;
72  continue;
73  }
74 
75  //is decaying phi or omega, replace it with its decay products
76  auto locDecayProducts = locReactionStep->Get_FinalPIDs();
77 
78  //find the production step
79  for(size_t loc_i = 0; loc_i < locStepIndex; ++loc_i)
80  {
81  const DReactionStep* locProductionStep = locCurrentReaction->Get_ReactionStep(loc_i);
82  auto locPIDs = locProductionStep->Get_FinalPIDs();
83 
84  //search for the decaying particle. when found, replace it with its decay products
85  bool locFoundFlag = false;
86  for(size_t loc_j = 0; loc_j < locPIDs.size(); ++loc_j)
87  {
88  Particle_t locFinalStatePID = locPIDs[loc_j];
89  if(locFinalStatePID != locInitialPID)
90  continue;
91  locPIDs.erase(locPIDs.begin() + loc_j);
92  locPIDs.insert(locPIDs.begin(), locDecayProducts.begin(), locDecayProducts.end());
93  locFoundFlag = true;
94  break;
95  }
96  if(!locFoundFlag)
97  continue;
98 
99  //make a new reaction step
100  DReactionStep locNewReactionStep;
101  locNewReactionStep.Set_InitialParticleID(locProductionStep->Get_InitialPID());
102  locNewReactionStep.Set_TargetParticleID(locProductionStep->Get_TargetPID());
103  int locMissingParticleIndex = locProductionStep->Get_MissingParticleIndex();
104  for(int loc_j = 0; loc_j < int(locPIDs.size()); ++loc_j)
105  locNewReactionStep.Add_FinalParticleID(locPIDs[loc_j], (loc_j == locMissingParticleIndex));
106  locNewReactionSteps.push_back(locNewReactionStep);
107 
108  //make a new reaction
109  DReaction locReactionBuild("Build");
110  locReactionBuild.Clear_ReactionSteps();
111  for(size_t loc_j = 0; loc_j < locCurrentReaction->Get_NumReactionSteps(); ++loc_j)
112  {
113  if(loc_j == loc_i)
114  locReactionBuild.Add_ReactionStep(&locNewReactionSteps.back());
115  else if(loc_j == locStepIndex)
116  continue;
117  else
118  locReactionBuild.Add_ReactionStep(locCurrentReaction->Get_ReactionStep(loc_j));
119  }
120  locNewReaction = locReactionBuild;
121  locCurrentReaction = &locNewReaction;
122  break;
123  }
124  }
125  while(locStepIndex < locCurrentReaction->Get_NumReactionSteps());
126 
127  //Get thrown steps
128  deque<pair<const DMCThrown*, deque<const DMCThrown*> > > locThrownSteps;
129  Get_ThrownParticleSteps(locEventLoop, locThrownSteps);
130 
131  if(locThrownSteps.size() == 1) //nothing to replace: it either works or it doesn't
132  return Check_ThrownsMatchReaction(locEventLoop, locCurrentReaction, locExclusiveMatchFlag);
133 
134  //build maps of counts of the thrown & DReaction decaying particles
135  map<Particle_t, size_t> locNumDecayingParticles_Thrown;
136  for(size_t loc_i = 0; loc_i < locThrownSteps.size(); ++loc_i)
137  {
138  if(locThrownSteps[loc_i].first == NULL)
139  continue; //beam particle
140  Particle_t locPID = locThrownSteps[loc_i].first->PID();
141  if(locNumDecayingParticles_Thrown.find(locPID) == locNumDecayingParticles_Thrown.end())
142  locNumDecayingParticles_Thrown[locPID] = 1;
143  else
144  ++locNumDecayingParticles_Thrown[locPID];
145  }
146 
147  map<Particle_t, size_t> locNumDecayingParticles_Reaction;
148  for(size_t loc_i = 0; loc_i < locCurrentReaction->Get_NumReactionSteps(); ++loc_i)
149  {
150  Particle_t locPID = locCurrentReaction->Get_ReactionStep(loc_i)->Get_InitialPID();
151  if(locPID == Gamma)
152  continue; //beam particle
153  if(locNumDecayingParticles_Reaction.find(locPID) == locNumDecayingParticles_Reaction.end())
154  locNumDecayingParticles_Reaction[locPID] = 1;
155  else
156  ++locNumDecayingParticles_Reaction[locPID];
157  }
158 
159  //if there is a particle type in the DReaction that is not present in the thrown, it's gonna fail no matter what: check now
160  map<Particle_t, size_t>::iterator locIterator = locNumDecayingParticles_Reaction.begin();
161  for(; locIterator != locNumDecayingParticles_Reaction.end(); ++locIterator)
162  {
163  Particle_t locPID = locIterator->first;
164  if(locNumDecayingParticles_Thrown.find(locPID) == locNumDecayingParticles_Thrown.end())
165  return false;
166  }
167 
168  //loop through thrown steps: replace phi's, omega's with their decay products
169  //also replace particles not in the DReaction with their decay products IF locIncludeDecayingToReactionFlag = true
170  locStepIndex = 1;
171  do
172  {
173  pair<const DMCThrown*, deque<const DMCThrown*> > locStepPair = locThrownSteps[locStepIndex];
174 
175  //check to see if the thrown decaying particle is present in the dreaction
176  const DMCThrown* locThrownParent = locStepPair.first;
177  Particle_t locInitialPID = locThrownParent->PID();
178  bool locInitialPIDFoundFlag = (locNumDecayingParticles_Reaction.find(locInitialPID) != locNumDecayingParticles_Reaction.end());
179 
180  //if it was not found, the only way it can be a match is if the decay products ARE in the reaction step: decay it in place
181  //also: omega and phi have non-negligible width: cannot constrain their peaks in kinfit or BDT: replace with their decay products
182  if(((!locInitialPIDFoundFlag) && locIncludeDecayingToReactionFlag) || (locInitialPID == omega) || (locInitialPID == phiMeson))
183  {
184  Replace_DecayingParticleWithProducts(locThrownSteps, locStepIndex);
185  if(locNumDecayingParticles_Thrown[locInitialPID] == 1)
186  locNumDecayingParticles_Thrown.erase(locInitialPID);
187  else
188  --locNumDecayingParticles_Thrown[locInitialPID];
189  }
190  else
191  ++locStepIndex;
192  }
193  while(locStepIndex < locThrownSteps.size());
194 
195  if(!locIncludeDecayingToReactionFlag)
196  {
197  //don't try decaying thrown particles: compare as-is
198  DReaction* locThrownReaction = dThrownReactionFactory->Build_ThrownReaction(locEventLoop, locThrownSteps);
199  auto locThrownCombo = dParticleComboCreator->Build_ThrownCombo(locEventLoop, locThrownReaction, locThrownSteps);
200  bool locCheckResult = Check_ThrownsMatchReaction(locActualThrownReaction, locThrownCombo, locCurrentReaction, locExclusiveMatchFlag);
201 
203  dThrownReactionFactory->Recycle_Reaction(locThrownReaction);
204  return locCheckResult;
205  }
206 
207  //at this point, #-steps are final. If exclusive, bail if they don't match
208  if(locExclusiveMatchFlag)
209  {
210  if(locReaction->Get_NumReactionSteps() != locThrownSteps.size())
211  return false;
212  }
213 
214  //ok, if there are still an unequal # of parents for a given PID between thrown & DReaction (i.e. both #'s are non-zero):
215  //it's too confusing to figure out which should be replaced by their decay products and which shouldn't
216  //so, try all possibilities, and see if any of them match.
217 
218  //build PIDs-to-replace vectors //easiest to manipulate a 1D vector
219  vector<Particle_t> locPIDVector;
220  vector<int> locResumeAtIndex;
221  for(locIterator = locNumDecayingParticles_Reaction.begin(); locIterator != locNumDecayingParticles_Reaction.end(); ++locIterator)
222  {
223  Particle_t locPID = locIterator->first;
224  size_t locNumThrown = locNumDecayingParticles_Thrown[locPID];
225  if(locNumThrown < locIterator->second)
226  return false; //thrown doesn't match
227  if(locNumThrown == locIterator->second)
228  continue; //all is well
229  for(size_t loc_i = 0; loc_i < locNumThrown - locIterator->second; ++loc_i)
230  {
231  locPIDVector.push_back(locPID);
232  locResumeAtIndex.push_back(0);
233  }
234  }
235 
236  //if no additional replacements to make: check it
237  if(locPIDVector.empty())
238  {
239  DReaction* locThrownReaction = dThrownReactionFactory->Build_ThrownReaction(locEventLoop, locThrownSteps);
240  auto locThrownCombo = dParticleComboCreator->Build_ThrownCombo(locEventLoop, locThrownReaction, locThrownSteps);
241  bool locCheckResult = Check_ThrownsMatchReaction(locActualThrownReaction, locThrownCombo, locCurrentReaction, locExclusiveMatchFlag);
242 
244  dThrownReactionFactory->Recycle_Reaction(locThrownReaction);
245  return locCheckResult;
246  }
247 
248  //loop through, making all combos of particles, (almost) just like in DParticleComboBlueprint_factory
249  //unlike that factory, the below may try a given combo twice: too hard to code against it though
250  //for a given PID, hard to compare current locResumeAtIndex to previous ones, since the thrown steps are continually replaced
251  deque<int> locDecayReplacementIndices;
252  int locParticleIndex = 0;
253  //below: contains "locThrownSteps" after each replacement
254  //1st deque index is replacement index,
255  deque<deque<pair<const DMCThrown*, deque<const DMCThrown*> > > > locReplacementThrownSteps(1, locThrownSteps);
256  do
257  {
258  if(locParticleIndex == -1)
259  break; //no success
260 
261  deque<pair<const DMCThrown*, deque<const DMCThrown*> > > locCurrentThrownSteps = locReplacementThrownSteps.back();
262  if(locParticleIndex == int(locPIDVector.size()))
263  {
264  //combo defined: try it
265  DReaction* locThrownReaction = dThrownReactionFactory->Build_ThrownReaction(locEventLoop, locCurrentThrownSteps);
266  auto locThrownCombo = dParticleComboCreator->Build_ThrownCombo(locEventLoop, locThrownReaction, locCurrentThrownSteps);
267  bool locCheckResult = Check_ThrownsMatchReaction(locActualThrownReaction, locThrownCombo, locCurrentReaction, locExclusiveMatchFlag);
268 
270  dThrownReactionFactory->Recycle_Reaction(locThrownReaction);
271 
272  if(locCheckResult)
273  return true; //it worked!
274  locReplacementThrownSteps.pop_back();
275  --locParticleIndex;
276  continue;
277  }
278 
279  Particle_t locPID = locPIDVector[locParticleIndex];
280  //find the next instance of this step & replace it
281  bool locFoundFlag = false;
282  for(size_t loc_i = locResumeAtIndex[locParticleIndex]; loc_i < locCurrentThrownSteps.size(); ++loc_i)
283  {
284  if(locCurrentThrownSteps[loc_i].first == NULL)
285  continue;
286  Particle_t locInitialPID = locCurrentThrownSteps[loc_i].first->PID();
287  if(locInitialPID != locPID)
288  continue;
289  locFoundFlag = true;
290 
291  Replace_DecayingParticleWithProducts(locCurrentThrownSteps, loc_i);
292  locReplacementThrownSteps.push_back(locCurrentThrownSteps);
293  locResumeAtIndex[locParticleIndex] = loc_i + 1;
294 
295  break;
296  }
297 
298  if(locFoundFlag)
299  ++locParticleIndex;
300  else
301  {
302  locResumeAtIndex[locParticleIndex] = 0;
303  locReplacementThrownSteps.pop_back();
304  --locParticleIndex;
305  }
306  }
307  while(true);
308 
309  return false;
310 }
311 
312 void DAnalysisUtilities::Replace_DecayingParticleWithProducts(deque<pair<const DMCThrown*, deque<const DMCThrown*> > >& locThrownSteps, size_t locStepIndex) const
313 {
314  if(locStepIndex >= locThrownSteps.size())
315  return;
316 
317  //find the step where this particle is produced at
318  int locInitialParticleDecayFromStepIndex = -1;
319  const DMCThrown* locThrownParent = locThrownSteps[locStepIndex].first;
320  if(locThrownParent == NULL)
321  return;
322 
323  for(size_t loc_j = 0; loc_j < locStepIndex; ++loc_j)
324  {
325  for(size_t loc_k = 0; loc_k < locThrownSteps[loc_j].second.size(); ++loc_k)
326  {
327  if(locThrownParent != locThrownSteps[loc_j].second[loc_k])
328  continue;
329  locInitialParticleDecayFromStepIndex = loc_j;
330  break;
331  }
332  if(locInitialParticleDecayFromStepIndex != -1)
333  break;
334  }
335 
336  if(locInitialParticleDecayFromStepIndex == -1)
337  {
338  cout << "ERROR: SOMETHING IS WRONG WITH DAnalysisUtilities::Replace_DecayingParticleWithProducts(). ABORTING." << endl;
339  abort();
340  }
341 
342  //insert the decay products where the production occured
343  deque<const DMCThrown*>& locProductionStepFinalParticles = locThrownSteps[locInitialParticleDecayFromStepIndex].second;
344  deque<const DMCThrown*>& locDecayStepFinalParticles = locThrownSteps[locStepIndex].second;
345  for(size_t loc_j = 0; loc_j < locProductionStepFinalParticles.size(); ++loc_j)
346  {
347  if(locProductionStepFinalParticles[loc_j] != locThrownParent)
348  continue;
349  locProductionStepFinalParticles.erase(locProductionStepFinalParticles.begin() + loc_j);
350  locProductionStepFinalParticles.insert(locProductionStepFinalParticles.end(), locDecayStepFinalParticles.begin(), locDecayStepFinalParticles.end());
351  break;
352  }
353 
354  locThrownSteps.erase(locThrownSteps.begin() + locStepIndex);
355 }
356 
357 bool DAnalysisUtilities::Check_ThrownsMatchReaction(JEventLoop* locEventLoop, const DReaction* locReaction, bool locExclusiveMatchFlag) const
358 {
359  //IF DREACTION HAS A MISSING UNKNOWN PARTICLE, MUST USE locExclusiveMatchFlag = false
360 
361  //note, if you decay a final state particle (e.g. k+, pi+) in your input DReaction*, a match will NOT be found: the thrown reaction/combo is truncated
362  //if locExclusiveMatchFlag = false, then allow the input DReaction to be a subset of the thrown
363  if(dParticleComboCreator == nullptr) //Can't create in constructor: infinite recursion
364  dParticleComboCreator = new DParticleComboCreator(locEventLoop, nullptr, nullptr, nullptr);
365  auto locThrownCombo = dParticleComboCreator->Build_ThrownCombo(locEventLoop);
366 
367  vector<const DReaction*> locReactions;
368  locEventLoop->Get(locReactions, "Thrown");
369  if(locReactions.empty())
370  return false;
371 
372  auto locResult = Check_ThrownsMatchReaction(locReactions[0], locThrownCombo, locReaction, locExclusiveMatchFlag);
374  return locResult;
375 }
376 
377 bool DAnalysisUtilities::Check_ThrownsMatchReaction(const DReaction* locThrownReaction, const DParticleCombo* locThrownCombo, const DReaction* locReaction, bool locExclusiveMatchFlag) const
378 {
379 #ifdef VTRACE
380  VT_TRACER("DAnalysisUtilities::Check_ThrownsMatchReaction()");
381 #endif
382 
383  //IF DREACTION HAS A MISSING UNKNOWN PARTICLE, MUST USE locExclusiveMatchFlag = false
384 
385  //note, if you decay a final state particle (e.g. k+, pi+) in your input DReaction*, a match will NOT be found: the thrown reaction/combo is truncated
386  //if locExclusiveMatchFlag = false, then allow the input DReaction to be a subset of the thrown
387 
388  if(locThrownCombo == NULL)
389  return false;
390  if(locExclusiveMatchFlag)
391  {
392  if(locReaction->Get_NumReactionSteps() != locThrownCombo->Get_NumParticleComboSteps())
393  return false;
394  }
395 
396  //build map of InitialParticleDecayFromStepIndex's for input reaction: assume that if it matters, the user wanted them in the input order
397  map<size_t, int> locReactionInitialParticleDecayFromStepIndexMap; //first is step index (of locReaction) where particle is initial, second is where is final state particle
398  for(size_t loc_i = 0; loc_i < locReaction->Get_NumReactionSteps(); ++loc_i)
399  {
400  const DReactionStep* locReactionStep = locReaction->Get_ReactionStep(loc_i);
401  if(loc_i == 0)
402  {
403  if(locReactionStep->Get_InitialPID() == Gamma)
404  locReactionInitialParticleDecayFromStepIndexMap[0] = -1;
405  }
406  //loop over final state particles, and if decaying, find the step they are a parent in
407  for(size_t loc_j = 0; loc_j < locReactionStep->Get_NumFinalPIDs(); ++loc_j)
408  {
409  Particle_t locFinalStatePID = locReactionStep->Get_FinalPID(loc_j);
410  //see if this pid is a parent in a future step
411  for(size_t loc_k = loc_i; loc_k < locReaction->Get_NumReactionSteps(); ++loc_k)
412  {
413  if(locReaction->Get_ReactionStep(loc_k)->Get_InitialPID() != locFinalStatePID)
414  continue;
415  if(locReactionInitialParticleDecayFromStepIndexMap.find(loc_k) != locReactionInitialParticleDecayFromStepIndexMap.end())
416  continue; //this step already accounted for
417  locReactionInitialParticleDecayFromStepIndexMap[loc_k] = loc_i;
418  break;
419  }
420  }
421  }
422 
423  //since throwns are more organized, loop through those and back-check to dreaction
424  set<size_t> locMatchedInputStepIndices; //step indices in input locReaction that are already matched-to
425  map<int, int> locStepMatching; //locReaction map to thrown step map
426  map<int, int> locReverseStepMatching; //thrown map to locReaction step map
427  for(size_t loc_i = 0; loc_i < locThrownCombo->Get_NumParticleComboSteps(); ++loc_i)
428  {
429  int locInitialParticleDecayFromStepIndex = DAnalysis::Get_InitialParticleDecayFromIndices(locThrownReaction, loc_i).first;
430 
431  //find where to start the search for this step in locReaction
432  size_t locStartSearchIndex = 0; //locReaction could be a subset of the total; start at the beginning unless ...:
433  if(locReverseStepMatching.find(locInitialParticleDecayFromStepIndex) != locReverseStepMatching.end())
434  locStartSearchIndex = locReverseStepMatching[locInitialParticleDecayFromStepIndex] + 1; //parent step was matched, start search for this one after it
435 
436  //loop through locReaction and try to find this thrown step
437  bool locMatchFoundFlag = false;
438  int locPossibleMatchIndex = -1;
439  for(size_t loc_j = locStartSearchIndex; loc_j < locReaction->Get_NumReactionSteps(); ++loc_j)
440  {
441  const DReactionStep* locReactionStep = locReaction->Get_ReactionStep(loc_j);
442  if(locMatchedInputStepIndices.find(loc_j) != locMatchedInputStepIndices.end())
443  continue; //this step was already accounted for
444 
445  //when not exact match: allow user step to have a missing unknown particle
446  if(!DAnalysis::Check_ChannelEquality(locThrownReaction->Get_ReactionStep(loc_i), locReactionStep, false, !locExclusiveMatchFlag))
447  continue; //particles aren't the same
448 
449  //ok, now check to make sure that the parent particle in this step was produced the same way in both thrown & locReaction
450  if(locReactionInitialParticleDecayFromStepIndexMap.find(loc_j) == locReactionInitialParticleDecayFromStepIndexMap.end())
451  {
452  //this (loc_j) parent particle's production step wasn't listed in the locReaction: locReaction is probably a subset of the total
453  //a match is possible but not certain: (e.g. locReaction is pi0, eta -> pi0, pi0 and this step (loc_i) is a pi0)
454  locPossibleMatchIndex = loc_j;
455  continue; //keep searching in case a different one should be used instead //will use this if another isn't found
456  }
457 
458  int locReactionInitialParticleDecayFromStepIndex = locReactionInitialParticleDecayFromStepIndexMap[loc_j];
459  if(locReactionInitialParticleDecayFromStepIndex != -1) //locReaction is not beam particle
460  {
461  if(locStepMatching.find(locReactionInitialParticleDecayFromStepIndex) == locStepMatching.end())
462  continue; //the step in locReaction where this (loc_j) parent particle was produced was not mapped to the thrown steps yet: this is not the step we want
463  int locReactionInitialParticleDecayFromStepIndexMappedBackToThrown = locStepMatching[locReactionInitialParticleDecayFromStepIndex];
464  if(locInitialParticleDecayFromStepIndex != locReactionInitialParticleDecayFromStepIndexMappedBackToThrown)
465  continue; //the decaying parent particle in this step (loc_j) comes from a different step in thrown (locInitialParticleDecayFromStepIndex)/reaction: continue
466  }
467  else if(locInitialParticleDecayFromStepIndex != -1)
468  continue; //reaction is beam but thrown is not beam
469 
470  //finally, a match! register it
471  locMatchedInputStepIndices.insert(loc_j);
472  locStepMatching[loc_j] = loc_i;
473  locReverseStepMatching[loc_i] = loc_j;
474  locMatchFoundFlag = true;
475  break;
476  }
477 
478  if((!locMatchFoundFlag) && (locPossibleMatchIndex != -1))
479  {
480  //need to use the possible match
481  locMatchedInputStepIndices.insert(locPossibleMatchIndex);
482  locStepMatching[locPossibleMatchIndex] = loc_i;
483  locReverseStepMatching[loc_i] = locPossibleMatchIndex;
484  locMatchFoundFlag = true;
485  }
486  if(locExclusiveMatchFlag && (!locMatchFoundFlag))
487  return false; //needed an exact match and it wasn't found: bail
488  }
489  if(locExclusiveMatchFlag)
490  return true;
491 
492  //locReaction could be a subset of thrown: check if all locReaction steps found
493  for(size_t loc_i = 0; loc_i < locReaction->Get_NumReactionSteps(); ++loc_i)
494  {
495  if(locMatchedInputStepIndices.find(loc_i) == locMatchedInputStepIndices.end())
496  return false; //one of the input steps wasn't matched: abort!
497  }
498 
499  return true;
500 }
501 
502 void DAnalysisUtilities::Get_UnusedChargedTracks(JEventLoop* locEventLoop, const DParticleCombo* locParticleCombo, vector<const DChargedTrack*>& locUnusedChargedTracks) const
503 {
504  locUnusedChargedTracks.clear();
505  locEventLoop->Get(locUnusedChargedTracks, "Combo");
506  std::sort(locUnusedChargedTracks.begin(), locUnusedChargedTracks.end());
507 
508  auto locChargedSourceObjects = locParticleCombo->Get_FinalParticle_SourceObjects(d_Charged);
509  for(size_t loc_i = 0; loc_i < locChargedSourceObjects.size(); ++loc_i)
510  {
511  for(auto locIterator = locUnusedChargedTracks.begin(); locIterator != locUnusedChargedTracks.end();)
512  {
513  if(locChargedSourceObjects[loc_i] != *locIterator)
514  ++locIterator; //not-used (yet)
515  else
516  locIterator = locUnusedChargedTracks.erase(locIterator); //used
517  }
518  }
519 }
520 
521 void DAnalysisUtilities::Get_UnusedTimeBasedTracks(JEventLoop* locEventLoop, const DParticleCombo* locParticleCombo, vector<const DTrackTimeBased*>& locUnusedTimeBasedTracks) const
522 {
523  locUnusedTimeBasedTracks.clear();
524  locEventLoop->Get(locUnusedTimeBasedTracks);
525 
526  vector<const DTrackTimeBased*> locComboTimeBasedTracks;
527  locEventLoop->Get(locComboTimeBasedTracks, "Combo");
528  locUnusedTimeBasedTracks.insert(locUnusedTimeBasedTracks.end(), locComboTimeBasedTracks.begin(), locComboTimeBasedTracks.end());
529 
530  auto locChargedSourceObjects = locParticleCombo->Get_FinalParticle_SourceObjects(d_Charged);
531  for(size_t loc_i = 0; loc_i < locChargedSourceObjects.size(); ++loc_i)
532  {
533  //only need the candidate id: same for all hypotheses for a given track
534  auto locChargedTrack = static_cast<const DChargedTrack*>(locChargedSourceObjects[loc_i]);
535  for(auto locIterator = locUnusedTimeBasedTracks.begin(); locIterator != locUnusedTimeBasedTracks.end();)
536  {
537  if(locChargedTrack->candidateid != (*locIterator)->candidateid)
538  ++locIterator; //not-used (yet)
539  else
540  locIterator = locUnusedTimeBasedTracks.erase(locIterator); //used
541  }
542  }
543 }
544 
545 void DAnalysisUtilities::Get_UnusedWireBasedTracks(JEventLoop* locEventLoop, const DParticleCombo* locParticleCombo, vector<const DTrackWireBased*>& locUnusedWireBasedTracks) const
546 {
547  locUnusedWireBasedTracks.clear();
548  locEventLoop->Get(locUnusedWireBasedTracks);
549 
550  auto locChargedSourceObjects = locParticleCombo->Get_FinalParticle_SourceObjects(d_Charged);
551  for(size_t loc_i = 0; loc_i < locChargedSourceObjects.size(); ++loc_i)
552  {
553  //only need the candidate id: same for all hypotheses for a given track
554  auto locChargedTrack = static_cast<const DChargedTrack*>(locChargedSourceObjects[loc_i]);
555  for(auto locIterator = locUnusedWireBasedTracks.begin(); locIterator != locUnusedWireBasedTracks.end();)
556  {
557  if(locChargedTrack->candidateid != (*locIterator)->candidateid)
558  ++locIterator; //not-used (yet)
559  else
560  locIterator = locUnusedWireBasedTracks.erase(locIterator); //used
561  }
562  }
563 }
564 
565 void DAnalysisUtilities::Get_UnusedTrackCandidates(JEventLoop* locEventLoop, const DParticleCombo* locParticleCombo, vector<const DTrackCandidate*>& locUnusedTrackCandidates) const
566 {
567  locUnusedTrackCandidates.clear();
568  locEventLoop->Get(locUnusedTrackCandidates);
569 
570  auto locChargedSourceObjects = locParticleCombo->Get_FinalParticle_SourceObjects(d_Charged);
571  set<unsigned int> locUsedCandidateIndices;
572  for(size_t loc_i = 0; loc_i < locChargedSourceObjects.size(); ++loc_i)
573  {
574  //only need the candidate id: same for all hypotheses for a given track
575  auto locChargedTrack = static_cast<const DChargedTrack*>(locChargedSourceObjects[loc_i]);
576  locUsedCandidateIndices.insert(locChargedTrack->candidateid - 1); //id = index + 1
577  }
578 
579  for(int loc_i = locUnusedTrackCandidates.size() - 1; loc_i >= 0; --loc_i)
580  {
581  if(locUsedCandidateIndices.find(loc_i) != locUsedCandidateIndices.end())
582  locUnusedTrackCandidates.erase(locUnusedTrackCandidates.begin() + loc_i);
583  }
584 }
585 
586 void DAnalysisUtilities::Get_UnusedNeutralShowers(JEventLoop* locEventLoop, const DParticleCombo* locParticleCombo, vector<const DNeutralShower*>& locUnusedNeutralShowers) const
587 {
588  locUnusedNeutralShowers.clear();
589  locEventLoop->Get(locUnusedNeutralShowers, dShowerSelectionTag.c_str());
590 
591  auto locNeutralSourceObjects = locParticleCombo->Get_FinalParticle_SourceObjects(d_Neutral);
592  for(size_t loc_i = 0; loc_i < locNeutralSourceObjects.size(); ++loc_i)
593  {
594  auto locNeutralShower = static_cast<const DNeutralShower*>(locNeutralSourceObjects[loc_i]);
595  for(auto locIterator = locUnusedNeutralShowers.begin(); locIterator != locUnusedNeutralShowers.end();)
596  {
597  if(locNeutralShower != *locIterator)
598  ++locIterator;
599  else
600  locIterator = locUnusedNeutralShowers.erase(locIterator);
601  }
602  }
603 }
604 
605 void DAnalysisUtilities::Get_UnusedNeutralParticles(JEventLoop* locEventLoop, const DParticleCombo* locParticleCombo, vector<const DNeutralParticle*>& locUnusedNeutralParticles) const
606 {
607  locUnusedNeutralParticles.clear();
608  locEventLoop->Get(locUnusedNeutralParticles, dShowerSelectionTag.c_str());
609 
610  auto locNeutralSourceObjects = locParticleCombo->Get_FinalParticle_SourceObjects(d_Neutral);
611  for(size_t loc_i = 0; loc_i < locNeutralSourceObjects.size(); ++loc_i)
612  {
613  auto locNeutralShower = static_cast<const DNeutralShower*>(locNeutralSourceObjects[loc_i]);
614  for(auto locIterator = locUnusedNeutralParticles.begin(); locIterator != locUnusedNeutralParticles.end();)
615  {
616  if(locNeutralShower != (*locIterator)->dNeutralShower)
617  ++locIterator;
618  else
619  locIterator = locUnusedNeutralParticles.erase(locIterator);
620  }
621  }
622 }
623 
624 void DAnalysisUtilities::Get_ThrownParticleSteps(JEventLoop* locEventLoop, deque<pair<const DMCThrown*, deque<const DMCThrown*> > >& locThrownSteps) const
625 {
626  vector<const DMCThrown*> locMCThrowns;
627  locEventLoop->Get(locMCThrowns);
628 
629  map<size_t, const DMCThrown*> locIDMap; //size_t is the myid
630  for(size_t loc_i = 0; loc_i < locMCThrowns.size(); ++loc_i)
631  locIDMap[locMCThrowns[loc_i]->myid] = locMCThrowns[loc_i];
632 
633  locThrownSteps.clear();
634  if(locMCThrowns.empty())
635  return;
636  locThrownSteps.push_back(pair<const DMCThrown*, deque<const DMCThrown*> >(NULL, deque<const DMCThrown*>() ) );
637 
638  for(size_t loc_i = 0; loc_i < locMCThrowns.size(); ++loc_i)
639  {
640  if(IsResonance(locMCThrowns[loc_i]->PID()))
641  continue; //don't include resonances in DReaction!!
642 
643  if(locMCThrowns[loc_i]->PID() == Unknown)
644  continue; //could be some weird pythia "resonance" like a diquark: just ignore them all
645 
646  //initial checks of parent id
647  int locParentID = locMCThrowns[loc_i]->parentid;
648  if(locParentID == 0) //photoproduced
649  {
650  locThrownSteps[0].second.push_back(locMCThrowns[loc_i]);
651  continue;
652  }
653  if(locIDMap.find(locParentID) == locIDMap.end()) //produced from a particle that was not saved: spurious, don't save (e.g. product of BCAL shower)
654  continue;
655 
656  //initial checks of parent pid
657  Particle_t locParentPID = locIDMap[locParentID]->PID();
658  bool locDoneFlag = false;
659  while(((locParentPID == Unknown) || IsResonance(locParentPID)) && (!locDoneFlag))
660  {
661  //intermediate particle, continue towards the source
662  locParentID = locIDMap[locParentID]->parentid; //parent's parent
663  if(locParentID == 0) //photoproduced
664  {
665  locThrownSteps[0].second.push_back(locMCThrowns[loc_i]);
666  locDoneFlag = true;
667  }
668  else if(locIDMap.find(locParentID) == locIDMap.end()) //produced from a particle that was not saved: spurious, don't save (e.g. product of BCAL shower)
669  locDoneFlag = true;
670  else
671  locParentPID = locIDMap[locParentID]->PID();
672  }
673 
674  if(Is_FinalStateParticle(locParentPID) == 1)
675  continue; //e.g. parent is a final state particle (e.g. this is a neutrino from a pion decay)
676 
677  //check to see if the parent is already listed as a decaying particle //if so, add it to that step
678  bool locListedAsDecayingFlag = false;
679  for(size_t loc_j = 1; loc_j < locThrownSteps.size(); ++loc_j)
680  {
681  if(locThrownSteps[loc_j].first->myid != locParentID)
682  continue;
683  locThrownSteps[loc_j].second.push_back(locMCThrowns[loc_i]);
684  locListedAsDecayingFlag = true;
685  break;
686  }
687  if(locListedAsDecayingFlag)
688  continue;
689 
690  //would add a new decay step, but first make sure that its parent is a decay product of a previous step
691  //if the parent was not saved as a product, it may have been a decay product of a final state particle: don't save
692  const DMCThrown* locThrownParent = locIDMap[locParentID];
693  bool locFoundFlag = false;
694  for(size_t loc_j = 0; loc_j < locThrownSteps.size(); ++loc_j)
695  {
696  for(size_t loc_k = 0; loc_k < locThrownSteps[loc_j].second.size(); ++loc_k)
697  {
698  if(locThrownSteps[loc_j].second[loc_k] != locThrownParent)
699  continue;
700  locFoundFlag = true;
701  break;
702  }
703  if(locFoundFlag)
704  break;
705  }
706  if(!locFoundFlag)
707  continue;
708 
709  //else add a new decay step and add this particle to it
710  locThrownSteps.push_back(pair<const DMCThrown*, deque<const DMCThrown*> >(locThrownParent, deque<const DMCThrown*>(1, locMCThrowns[loc_i]) ));
711  }
712 
713 /*
714 cout << "THROWN STEPS: " << endl;
715 for(size_t loc_i = 0; loc_i < locThrownSteps.size(); ++loc_i)
716 {
717  cout << ((loc_i == 0) ? 0 : locThrownSteps[loc_i].first->myid) << ": ";
718  for(size_t loc_j = 0; loc_j < locThrownSteps[loc_i].second.size(); ++loc_j)
719  cout << locThrownSteps[loc_i].second[loc_j]->myid << ", ";
720  cout << endl;
721 }
722 */
723 }
724 
725 bool DAnalysisUtilities::Are_ThrownPIDsSameAsDesired(JEventLoop* locEventLoop, const deque<Particle_t>& locDesiredPIDs, Particle_t locMissingPID) const
726 {
727  vector<const DMCThrown*> locMCThrowns;
728  locEventLoop->Get(locMCThrowns, "FinalState");
729  deque<Particle_t> locDesiredPIDs_Copy = locDesiredPIDs;
730 
731  bool locMissingPIDMatchedFlag = false;
732  for(size_t loc_i = 0; loc_i < locMCThrowns.size(); ++loc_i)
733  {
734  Particle_t locPID = (Particle_t)(locMCThrowns[loc_i]->type);
735 
736  if((!locMissingPIDMatchedFlag) && (locMissingPID == locPID))
737  {
738  //matched missing
739  locMissingPIDMatchedFlag = true;
740  continue;
741  }
742 
743  bool locPIDFoundFlag = false;
744  for(deque<Particle_t>::iterator locIterator = locDesiredPIDs_Copy.begin(); locIterator != locDesiredPIDs_Copy.end(); ++locIterator)
745  {
746  if(*locIterator != locPID)
747  continue;
748  locDesiredPIDs_Copy.erase(locIterator);
749  locPIDFoundFlag = true;
750  break;
751  }
752  if(!locPIDFoundFlag)
753  return false;
754  }
755 
756  return (locDesiredPIDs_Copy.empty());
757 }
758 
759 DLorentzVector DAnalysisUtilities::Calc_MissingP4(const DReaction* locReaction, const DParticleCombo* locParticleCombo, bool locUseKinFitDataFlag) const
760 {
761  set<pair<const JObject*, unsigned int> > locSourceObjects;
762  return Calc_MissingP4(locReaction, locParticleCombo, 0, -1, set<size_t>(), locSourceObjects, locUseKinFitDataFlag);
763 }
764 
765 DLorentzVector DAnalysisUtilities::Calc_MissingP4(const DReaction* locReaction, const DParticleCombo* locParticleCombo, set<pair<const JObject*, unsigned int> >& locSourceObjects, bool locUseKinFitDataFlag) const
766 {
767  return Calc_MissingP4(locReaction, locParticleCombo, 0, -1, set<size_t>(), locSourceObjects, locUseKinFitDataFlag);
768 }
769 
770 DLorentzVector DAnalysisUtilities::Calc_MissingP4(const DReaction* locReaction, const DParticleCombo* locParticleCombo, size_t locStepIndex, int locUpToStepIndex, set<size_t> locUpThroughIndices, bool locUseKinFitDataFlag) const
771 {
772  set<pair<const JObject*, unsigned int> > locSourceObjects;
773  return Calc_MissingP4(locReaction, locParticleCombo, locStepIndex, locUpToStepIndex, locUpThroughIndices, locSourceObjects, locUseKinFitDataFlag);
774 }
775 
776 DLorentzVector DAnalysisUtilities::Calc_MissingP4(const DReaction* locReaction, const DParticleCombo* locParticleCombo, size_t locStepIndex, int locUpToStepIndex, set<size_t> locUpThroughIndices, set<pair<const JObject*, unsigned int> >& locSourceObjects, bool locUseKinFitDataFlag) const
777 {
778  //NOTE: this routine assumes that the p4 of a charged decaying particle with a detached vertex is the same at both vertices!
779  //assumes missing particle is not the beam particle
780  if(locUseKinFitDataFlag && (locParticleCombo->Get_KinFitResults() == NULL))
781  return Calc_MissingP4(locReaction, locParticleCombo, locStepIndex, locUpToStepIndex, locUpThroughIndices, locSourceObjects, false); //kinematic fit failed
782 
783  DLorentzVector locMissingP4;
784  const DParticleComboStep* locParticleComboStep = locParticleCombo->Get_ParticleComboStep(locStepIndex);
785  auto locReactionStep = locReaction->Get_ReactionStep(locStepIndex);
786 
787  const DKinematicData* locKinematicData = NULL;
788  if(locStepIndex == 0)
789  {
790  //initial particle
791  locKinematicData = locParticleComboStep->Get_InitialParticle_Measured();
792  locSourceObjects.insert(pair<const JObject*, unsigned int>(locKinematicData, abs(PDGtype(locKinematicData->PID())))); //want to use source objects for comparing
793  if(locUseKinFitDataFlag) //kinfit
794  locKinematicData = locParticleComboStep->Get_InitialParticle();
795  locMissingP4 += locKinematicData->lorentzMomentum();
796  }
797 
798  //target particle
799  Particle_t locPID = locReactionStep->Get_TargetPID();
800  if(locPID != Unknown)
801  {
802  double locMass = ParticleMass(locPID);
803  locMissingP4 += DLorentzVector(DVector3(0.0, 0.0, 0.0), locMass);
804  }
805 
806  auto locParticles = locUseKinFitDataFlag ? locParticleComboStep->Get_FinalParticles() : locParticleComboStep->Get_FinalParticles_Measured();
807  for(size_t loc_j = 0; loc_j < locParticles.size(); ++loc_j)
808  {
809  if(int(loc_j) == locReactionStep->Get_MissingParticleIndex())
810  continue; //exclude missing particle
811  if((int(locStepIndex) == locUpToStepIndex) && (locUpThroughIndices.find(loc_j) == locUpThroughIndices.end()))
812  continue; //skip it: don't want to include it
813 
814  int locDecayStepIndex = DAnalysis::Get_DecayStepIndex(locReaction, locStepIndex, loc_j);
815  if(locDecayStepIndex > 0) //decaying-particle
816  {
817  //why plus? because the minus-signs are already applied during the call below
818  locMissingP4 += Calc_MissingP4(locReaction, locParticleCombo, locDecayStepIndex, locUpToStepIndex, locUpThroughIndices, locSourceObjects, locUseKinFitDataFlag); //p4 returned is already < 0
819  }
820  else //detected
821  {
822  Particle_t locPID = locReactionStep->Get_FinalPID(loc_j);
823  auto locDetectedP4 = locParticles[loc_j]->lorentzMomentum();
824  locMissingP4 -= locDetectedP4;
825  locSourceObjects.insert(pair<const JObject*, unsigned int>(locParticleComboStep->Get_FinalParticle_SourceObject(loc_j), abs(PDGtype(locPID))));
826  }
827  }
828 
829  return locMissingP4;
830 }
831 
832 TMatrixFSym DAnalysisUtilities::Calc_MissingP3Covariance(const DReaction* locReaction, const DParticleCombo* locParticleCombo) const
833 {
834  //uses measured data!
835  return Calc_MissingP3Covariance(locReaction, locParticleCombo, 0, -1, set<size_t>());
836 }
837 
838 TMatrixFSym DAnalysisUtilities::Calc_MissingP3Covariance(const DReaction* locReaction, const DParticleCombo* locParticleCombo, size_t locStepIndex, int locUpToStepIndex, set<size_t> locUpThroughIndices) const
839 {
840  //uses measured data!
841 
842  //NOTE: this routine assumes that the p4 of a charged decaying particle with a detached vertex is the same at both vertices!
843  //assumes missing particle is not the beam particle
844 
845  //missing covariance is just sum of covariance matrices of all particles used in the calculation
846  //because errors are uncorrelated: this doesn't work on kinfit data: just use kinfit matrix from missing particle then
847  const DParticleComboStep* locParticleComboStep = locParticleCombo->Get_ParticleComboStep(locStepIndex);
848  auto locReactionStep = locReaction->Get_ReactionStep(locStepIndex);
849  TMatrixFSym locMissingCovarianceMatrix(3);
850  locMissingCovarianceMatrix.Zero();
851 
852  const DKinematicData* locKinematicData = NULL;
853  if(locStepIndex == 0)
854  {
855  //initial particle
856  locKinematicData = locParticleComboStep->Get_InitialParticle_Measured();
857  TMatrixFSym locParticleCovarianceMatrix = *(locKinematicData->errorMatrix().get());
858  locParticleCovarianceMatrix.ResizeTo(3, 3);
859  locMissingCovarianceMatrix += locParticleCovarianceMatrix;
860  }
861 
862  auto locParticles = locParticleComboStep->Get_FinalParticles_Measured();
863  for(size_t loc_j = 0; loc_j < locParticles.size(); ++loc_j)
864  {
865  if(int(loc_j) == locReactionStep->Get_MissingParticleIndex())
866  continue; //exclude missing particle
867  if((int(locStepIndex) == locUpToStepIndex) && (locUpThroughIndices.find(loc_j) == locUpThroughIndices.end()))
868  continue; //skip it: don't want to include it
869 
870  int locDecayStepIndex = DAnalysis::Get_DecayStepIndex(locReaction, locStepIndex, loc_j);
871  if(locDecayStepIndex > 0) //decaying-particle
872  locMissingCovarianceMatrix += Calc_MissingP3Covariance(locReaction, locParticleCombo, locDecayStepIndex, locUpToStepIndex, locUpThroughIndices);
873  else //detected
874  {
875  TMatrixFSym locParticleCovarianceMatrix = *(locParticles[loc_j]->errorMatrix().get());
876  locParticleCovarianceMatrix.ResizeTo(3, 3);
877  locMissingCovarianceMatrix += locParticleCovarianceMatrix;
878  }
879  }
880 
881  return locMissingCovarianceMatrix;
882 }
883 
884 DLorentzVector DAnalysisUtilities::Calc_FinalStateP4(const DReaction* locReaction, const DParticleCombo* locParticleCombo, size_t locStepIndex, bool locUseKinFitDataFlag) const
885 {
886  set<pair<const JObject*, unsigned int> > locSourceObjects;
887  return Calc_FinalStateP4(locReaction, locParticleCombo, locStepIndex, set<size_t>(), locSourceObjects, locUseKinFitDataFlag);
888 }
889 
890 DLorentzVector DAnalysisUtilities::Calc_FinalStateP4(const DReaction* locReaction, const DParticleCombo* locParticleCombo, size_t locStepIndex, set<pair<const JObject*, unsigned int> >& locSourceObjects, bool locUseKinFitDataFlag) const
891 {
892  return Calc_FinalStateP4(locReaction, locParticleCombo, locStepIndex, set<size_t>(), locSourceObjects, locUseKinFitDataFlag);
893 }
894 
895 DLorentzVector DAnalysisUtilities::Calc_FinalStateP4(const DReaction* locReaction, const DParticleCombo* locParticleCombo, size_t locStepIndex, set<size_t> locToIncludeIndices, bool locUseKinFitDataFlag) const
896 {
897  set<pair<const JObject*, unsigned int> > locSourceObjects;
898  return Calc_FinalStateP4(locReaction, locParticleCombo, locStepIndex, locToIncludeIndices, locSourceObjects, locUseKinFitDataFlag);
899 }
900 
901 DLorentzVector DAnalysisUtilities::Calc_FinalStateP4(const DReaction* locReaction, const DParticleCombo* locParticleCombo, size_t locStepIndex, set<size_t> locToIncludeIndices, set<pair<const JObject*, unsigned int> >& locSourceObjects, bool locUseKinFitDataFlag) const
902 {
903  if(locUseKinFitDataFlag && (locParticleCombo->Get_KinFitResults() == NULL))
904  return Calc_FinalStateP4(locReaction, locParticleCombo, locStepIndex, locToIncludeIndices, locSourceObjects, false); //kinematic fit failed
905 
906  DLorentzVector locFinalStateP4;
907  const DParticleComboStep* locParticleComboStep = locParticleCombo->Get_ParticleComboStep(locStepIndex);
908  if(locParticleComboStep == NULL)
909  return (DLorentzVector());
910  auto locReactionStep = locReaction->Get_ReactionStep(locStepIndex);
911 
912  auto locParticles = locUseKinFitDataFlag ? locParticleComboStep->Get_FinalParticles() : locParticleComboStep->Get_FinalParticles_Measured();
913 
914  //subtract rescattering target if any!!
915  if(locStepIndex != 0)
916  {
917  Particle_t locPID = locReactionStep->Get_TargetPID();
918  if(locPID != Unknown)
919  locFinalStateP4 -= DLorentzVector(DVector3(0.0, 0.0, 0.0), ParticleMass(locPID));
920  }
921 
922  bool locDoSubsetFlag = !locToIncludeIndices.empty();
923  for(size_t loc_i = 0; loc_i < locParticles.size(); ++loc_i)
924  {
925  if(locDoSubsetFlag && (locToIncludeIndices.find(loc_i) == locToIncludeIndices.end()))
926  continue; //skip it: don't want to include it
927 
928  if(locReactionStep->Get_MissingParticleIndex() == int(loc_i))
929  return (DLorentzVector()); //bad!
930 
931  int locDecayStepIndex = DAnalysis::Get_DecayStepIndex(locReaction, locStepIndex, loc_i);
932  if(locDecayStepIndex >= 0) //decaying particle
933  {
934  //measured results, or not constrained by kinfit (either non-fixed mass or excluded from kinfit)
935  if((!locUseKinFitDataFlag) || (!IsFixedMass(locReactionStep->Get_FinalPID(loc_i))))
936  locFinalStateP4 += Calc_FinalStateP4(locReaction, locParticleCombo, locDecayStepIndex, set<size_t>(), locSourceObjects, locUseKinFitDataFlag);
937  else //want kinfit results, and decaying particle p4 is constrained by kinfit
938  {
939  locFinalStateP4 += locParticles[loc_i]->lorentzMomentum();
940  //still need source objects of decay products! dive down anyway, but ignore p4 result
941  Calc_FinalStateP4(locReaction, locParticleCombo, locDecayStepIndex, set<size_t>(), locSourceObjects, locUseKinFitDataFlag);
942  }
943  }
944  else //detected particle
945  {
946  locFinalStateP4 += locParticles[loc_i]->lorentzMomentum();
947  locSourceObjects.insert(pair<const JObject*, unsigned int>(locParticleComboStep->Get_FinalParticle_SourceObject(loc_i), abs(PDGtype(locParticles[loc_i]->PID()))));
948  }
949  }
950  return locFinalStateP4;
951 }
952 
953 double DAnalysisUtilities::Calc_Energy_UnusedShowers(JEventLoop* locEventLoop, const DParticleCombo* locParticleCombo) const
954 {
955  DVector3 locVertex(0.0, 0.0, dTargetZCenter);
956  const DEventRFBunch* locEventRFBunch = locParticleCombo->Get_EventRFBunch();
957  double locRFTime = (locEventRFBunch != NULL) ? locEventRFBunch->dTime : numeric_limits<double>::quiet_NaN();
958 
959  vector<const DNeutralShower*> locUnusedNeutralShowers;
960  Get_UnusedNeutralShowers(locEventLoop, locParticleCombo, locUnusedNeutralShowers);
961 
962  double locEnergy_UnusedShowers = 0.;
963  for(size_t loc_i = 0; loc_i < locUnusedNeutralShowers.size(); ++loc_i) {
964  const DNeutralShower* locUnusedNeutralShower = locUnusedNeutralShowers[loc_i];
965 
966  // requirements on unused showers
967  double locFlightTime = (locUnusedNeutralShower->dSpacetimeVertex.Vect() - locVertex).Mag()/SPEED_OF_LIGHT;
968  double locDeltaT = locUnusedNeutralShower->dSpacetimeVertex.T() - locFlightTime - locRFTime;
969  double locDetectorTheta = (locUnusedNeutralShower->dSpacetimeVertex.Vect()-locVertex).Theta()*180./TMath::Pi();
970  if(locDetectorTheta < 2.0 || fabs(locDeltaT) > 4.)
971  continue;
972 
973  locEnergy_UnusedShowers += locUnusedNeutralShower->dEnergy;
974  }
975 
976  return locEnergy_UnusedShowers;
977 }
978 
979 int DAnalysisUtilities::Calc_Momentum_UnusedTracks(JEventLoop* locEventLoop, const DParticleCombo* locParticleCombo, double &locSumPMag_UnusedTracks, TVector3 &locSumP3_UnusedTracks) const
980 {
981  vector<const DChargedTrack*> locUnusedChargedTracks;
982  Get_UnusedChargedTracks(locEventLoop, locParticleCombo, locUnusedChargedTracks);
983 
984  for(size_t loc_i = 0; loc_i < locUnusedChargedTracks.size(); ++loc_i) {
985  const DChargedTrack* locUnusedChargedTrack = locUnusedChargedTracks[loc_i];
986  const DChargedTrackHypothesis *locUnusedChargedTrackHypothesis = locUnusedChargedTrack->Get_BestTrackingFOM();
987 
988  locSumPMag_UnusedTracks += locUnusedChargedTrackHypothesis->pmag();
989  locSumP3_UnusedTracks += locUnusedChargedTrackHypothesis->momentum();
990  }
991 
992  return (int)locUnusedChargedTracks.size();
993 }
994 
995 double DAnalysisUtilities::Calc_DOCAToVertex(const DKinematicData* locKinematicData, const DVector3& locVertex) const
996 {
997  DVector3 locPOCA;
998  return Calc_DOCAToVertex(locKinematicData, locVertex, locPOCA);
999 }
1000 
1001 double DAnalysisUtilities::Calc_DOCAToVertex(const DKinematicData* locKinematicData, const DVector3& locVertex, DVector3& locPOCA) const
1002 {
1003  DVector3 locUnitDir = (1.0/locKinematicData->momentum().Mag())*locKinematicData->momentum();
1004  DVector3 locPosition = locKinematicData->position();
1005  return Calc_DOCAToVertex(locUnitDir, locPosition, locVertex, locPOCA);
1006 }
1007 
1008 double DAnalysisUtilities::Calc_DOCAToVertex(const DKinFitParticle* locKinFitParticle, const DVector3& locVertex) const
1009 {
1010  DVector3 locPOCA;
1011  return Calc_DOCAToVertex(locKinFitParticle, locVertex, locPOCA);
1012 }
1013 
1014 double DAnalysisUtilities::Calc_DOCAToVertex(const DKinFitParticle* locKinFitParticle, const DVector3& locVertex, DVector3& locPOCA) const
1015 {
1016  DVector3 locUnitDir(locKinFitParticle->Get_Momentum().Unit().X(),locKinFitParticle->Get_Momentum().Unit().Y(),locKinFitParticle->Get_Momentum().Unit().Z());
1017  DVector3 locPosition(locKinFitParticle->Get_Position().X(),locKinFitParticle->Get_Position().Y(),locKinFitParticle->Get_Position().Z());
1018  return Calc_DOCAToVertex(locUnitDir, locPosition, locVertex, locPOCA);
1019 }
1020 
1021 double DAnalysisUtilities::Calc_DOCAToVertex(const DVector3& locUnitDir, const DVector3& locPosition, const DVector3& locVertex) const
1022 {
1023  DVector3 locPOCA1, locPOCA2;
1024  return Calc_DOCA(locUnitDir, locUnitDir, locPosition, locVertex, locPOCA1, locPOCA2);
1025 }
1026 
1027 double DAnalysisUtilities::Calc_DOCAToVertex(const DVector3& locUnitDir, const DVector3& locPosition, const DVector3& locVertex, DVector3& locPOCA) const
1028 {
1029  DVector3 locPOCA2;
1030  return Calc_DOCA(locUnitDir, locUnitDir, locPosition, locVertex, locPOCA, locPOCA2);
1031 }
1032 
1033 double DAnalysisUtilities::Calc_DOCAVertex(const DKinFitParticle* locKinFitParticle1, const DKinFitParticle* locKinFitParticle2, DVector3& locDOCAVertex) const
1034 {
1035  DVector3 locPOCA1, locPOCA2;
1036  double locDOCA;
1037  // Try to use helical approximation if B!=0
1038  if (dIsNoFieldFlag==false && Calc_DOCA(locKinFitParticle1,locKinFitParticle2,
1039  locPOCA1,locPOCA2,locDOCA)==NOERROR){
1040  locDOCAVertex=0.5*(locPOCA1+locPOCA2);
1041  return locDOCA;
1042  }
1043 
1044  // Use straight line approximation
1045  DVector3 locUnitDir1(locKinFitParticle1->Get_Momentum().Unit().X(),locKinFitParticle1->Get_Momentum().Unit().Y(),locKinFitParticle1->Get_Momentum().Unit().Z());
1046  DVector3 locUnitDir2(locKinFitParticle2->Get_Momentum().Unit().X(),locKinFitParticle2->Get_Momentum().Unit().Y(),locKinFitParticle2->Get_Momentum().Unit().Z());
1047  DVector3 locVertex1(locKinFitParticle1->Get_Position().X(),locKinFitParticle1->Get_Position().Y(),locKinFitParticle1->Get_Position().Z());
1048  DVector3 locVertex2(locKinFitParticle2->Get_Position().X(),locKinFitParticle2->Get_Position().Y(),locKinFitParticle2->Get_Position().Z());
1049  return Calc_DOCAVertex(locUnitDir1, locUnitDir2, locVertex1, locVertex2, locDOCAVertex);
1050 }
1051 
1052 double DAnalysisUtilities::Calc_DOCAVertex(const DKinematicData* locKinematicData1, const DKinematicData* locKinematicData2, DVector3& locDOCAVertex) const
1053 {
1054  DVector3 locPOCA1, locPOCA2;
1055  double locDOCA;
1056  // Try to use helical approximation if B!=0
1057  if (dIsNoFieldFlag==false && Calc_DOCA(locKinematicData1,locKinematicData2,
1058  locPOCA1,locPOCA2,locDOCA)==NOERROR){
1059  locDOCAVertex=0.5*(locPOCA1+locPOCA2);
1060  return locDOCA;
1061  }
1062 
1063  // Use straight line approximation
1064  DVector3 locUnitDir1 = (1.0/locKinematicData1->momentum().Mag())*locKinematicData1->momentum();
1065  DVector3 locUnitDir2 = (1.0/locKinematicData2->momentum().Mag())*locKinematicData2->momentum();
1066  DVector3 locVertex1 = locKinematicData1->position();
1067  DVector3 locVertex2 = locKinematicData2->position();
1068  return Calc_DOCAVertex(locUnitDir1, locUnitDir2, locVertex1, locVertex2, locDOCAVertex);
1069 }
1070 
1071 double DAnalysisUtilities::Calc_DOCAVertex(const DVector3 &locUnitDir1, const DVector3 &locUnitDir2, const DVector3 &locVertex1, const DVector3 &locVertex2, DVector3& locDOCAVertex) const
1072 {
1073  DVector3 locPOCA1, locPOCA2;
1074  double locDOCA = Calc_DOCA(locUnitDir1, locUnitDir2, locVertex1, locVertex2, locPOCA1, locPOCA2);
1075  locDOCAVertex = 0.5*(locPOCA1 + locPOCA2);
1076  return locDOCA;
1077 }
1078 
1079 double DAnalysisUtilities::Calc_DOCA(const DKinFitParticle* locKinFitParticle1, const DKinFitParticle* locKinFitParticle2) const
1080 {
1081  DVector3 locPOCA1, locPOCA2;
1082  return Calc_DOCA(locKinFitParticle1, locKinFitParticle2, locPOCA1, locPOCA2);
1083 }
1084 
1085 double DAnalysisUtilities::Calc_DOCA(const DKinematicData* locKinematicData1, const DKinematicData* locKinematicData2) const
1086 {
1087  DVector3 locPOCA1, locPOCA2;
1088  return Calc_DOCA(locKinematicData1, locKinematicData2, locPOCA1, locPOCA2);
1089 }
1090 
1091 double DAnalysisUtilities::Calc_DOCA(const DKinFitParticle* locKinFitParticle1, const DKinFitParticle* locKinFitParticle2, DVector3 &locPOCA1, DVector3 &locPOCA2) const
1092 {
1093  DVector3 locUnitDir1(locKinFitParticle1->Get_Momentum().Unit().X(),locKinFitParticle1->Get_Momentum().Unit().Y(),locKinFitParticle1->Get_Momentum().Unit().Z());
1094  DVector3 locUnitDir2(locKinFitParticle2->Get_Momentum().Unit().X(),locKinFitParticle2->Get_Momentum().Unit().Y(),locKinFitParticle2->Get_Momentum().Unit().Z());
1095  DVector3 locVertex1(locKinFitParticle1->Get_Position().X(),locKinFitParticle1->Get_Position().Y(),locKinFitParticle1->Get_Position().Z());
1096  DVector3 locVertex2(locKinFitParticle2->Get_Position().X(),locKinFitParticle2->Get_Position().Y(),locKinFitParticle2->Get_Position().Z());
1097  return Calc_DOCA(locUnitDir1, locUnitDir2, locVertex1, locVertex2, locPOCA1, locPOCA2);
1098 }
1099 
1100 double DAnalysisUtilities::Calc_DOCA(const DKinematicData* locKinematicData1, const DKinematicData* locKinematicData2, DVector3 &locPOCA1, DVector3 &locPOCA2) const
1101 {
1102  DVector3 locUnitDir1 = (1.0/locKinematicData1->momentum().Mag())*locKinematicData1->momentum();
1103  DVector3 locUnitDir2 = (1.0/locKinematicData2->momentum().Mag())*locKinematicData2->momentum();
1104  DVector3 locVertex1 = locKinematicData1->position();
1105  DVector3 locVertex2 = locKinematicData2->position();
1106  return Calc_DOCA(locUnitDir1, locUnitDir2, locVertex1, locVertex2, locPOCA1, locPOCA2);
1107 }
1108 
1109 double DAnalysisUtilities::Calc_DOCA(const DVector3 &locUnitDir1, const DVector3 &locUnitDir2, const DVector3 &locVertex1, const DVector3 &locVertex2) const
1110 {
1111  DVector3 locPOCA1, locPOCA2;
1112  return Calc_DOCA(locUnitDir1, locUnitDir2, locVertex1, locVertex2, locPOCA1, locPOCA2);
1113 }
1114 
1115 double DAnalysisUtilities::Calc_DOCA(const DVector3 &locUnitDir1, const DVector3 &locUnitDir2, const DVector3 &locVertex1, const DVector3 &locVertex2, DVector3 &locPOCA1, DVector3 &locPOCA2) const
1116 {
1117  //originated from code by Jorn Langheinrich
1118  //you can use this function to find the DOCA to a fixed point by calling this function with locUnitDir1 and 2 parallel, and the fixed vertex as locVertex2
1119  double locUnitDot = locUnitDir1.Dot(locUnitDir2);
1120  double locDenominator = locUnitDot*locUnitDot - 1.0; // scalar product of directions
1121  double locDistVertToInterDOCA1 = 0.0, locDistVertToInterDOCA2 = 0.0; //distance from vertex to DOCA point
1122 
1123  if(fabs(locDenominator) < 1.0e-15) //parallel
1124  {
1125  locDistVertToInterDOCA1 = (locVertex2 - locVertex1).Dot(locUnitDir2)/locUnitDot; //the opposite
1126  locDistVertToInterDOCA2 = (locVertex1 - locVertex2).Dot(locUnitDir1)/locUnitDot;
1127  }
1128  else
1129  {
1130  double locA = (locVertex1 - locVertex2).Dot(locUnitDir1);
1131  double locB = (locVertex1 - locVertex2).Dot(locUnitDir2);
1132  locDistVertToInterDOCA1 = (locA - locUnitDot*locB)/locDenominator;
1133  locDistVertToInterDOCA2 = (locUnitDot*locA - locB)/locDenominator;
1134  }
1135 
1136  locPOCA1 = locVertex1 + locDistVertToInterDOCA1*locUnitDir1; //intersection point of DOCA line and track 1
1137  locPOCA2 = locVertex2 + locDistVertToInterDOCA2*locUnitDir2; //intersection point of DOCA line and track 2
1138  return (locPOCA1 - locPOCA2).Mag();
1139 }
1140 
1141 // Routine for steering the code that uses a small arc length approximation to
1142 // a helical trajectory to find the doca between two tracks curving in the
1143 // magnetic field.
1144 jerror_t
1146  const DKinFitParticle* locKinFitParticle2,
1147  DVector3 &pos1_out,DVector3 &pos2_out,
1148  double &doca) const{
1149  // Charges for the two input tracks
1150  double q1=locKinFitParticle1->Get_Charge();
1151  double q2=locKinFitParticle2->Get_Charge();
1152 
1153  // position info from the two input tracks
1154  DVector3 pos1_in=locKinFitParticle1->Get_Position();
1155  DVector3 pos2_in=locKinFitParticle2->Get_Position();
1156 
1157  // momentum info from the two input tracks
1158  DVector3 mom1_in=locKinFitParticle1->Get_Momentum();
1159  DVector3 mom2_in=locKinFitParticle2->Get_Momentum();
1160 
1161  return Calc_DOCA(q1,q2,pos1_in,pos2_in,mom1_in,mom2_in,pos1_out,pos2_out,
1162  doca);
1163 }
1164 
1165 // Routine for steering the code that uses a small arc length approximation to
1166 // a helical trajectory to find the doca between two tracks curving in the
1167 // magnetic field.
1168 jerror_t DAnalysisUtilities::Calc_DOCA(const DKinematicData* kinematicData1,
1169  const DKinematicData* kinematicData2,
1170  DVector3 &pos1_out,DVector3 &pos2_out,
1171  double &doca
1172  ) const {
1173  // Charges for the two input tracks
1174  double q1=kinematicData1->charge();
1175  double q2=kinematicData2->charge();
1176 
1177  // position info from the two input tracks
1178  DVector3 pos1_in=kinematicData1->position();
1179  DVector3 pos2_in=kinematicData2->position();
1180 
1181  // momentum info from the two input tracks
1182  DVector3 mom1_in=kinematicData1->momentum();
1183  DVector3 mom2_in=kinematicData2->momentum();
1184 
1185  return Calc_DOCA(q1,q2,pos1_in,pos2_in,mom1_in,mom2_in,pos1_out,pos2_out,
1186  doca);
1187 }
1188 
1189 // Use a small arc length approximation to a helical trajectory to find the
1190 // doca between two tracks curving in the magnetic field.
1191 jerror_t DAnalysisUtilities::Calc_DOCA(double q1,double q2,
1192  const DVector3 &pos1_in,
1193  const DVector3 &pos2_in,
1194  const DVector3 &mom1_in,
1195  const DVector3 &mom2_in,
1196  DVector3 &pos1_out,DVector3 &pos2_out,
1197  double &doca
1198  ) const {
1199  DVector3 avg_pos=0.5*(pos1_in+pos2_in);
1200  DVector3 diff_pos=pos1_in-pos2_in;
1201  double B=fabs(dMagneticFieldMap->GetBz(avg_pos.x(),avg_pos.y(),avg_pos.z()));
1202  double kap1=-0.003*B*q1/(2.*mom1_in.Perp());
1203  double kap2=-0.003*B*q2/(2.*mom2_in.Perp());
1204  double dx=diff_pos.x(),dy=diff_pos.y(),dz=diff_pos.z();
1205  double tan1=tan(M_PI_2-mom1_in.Theta());
1206  double tan1sq=tan1*tan1;
1207  double phi1=mom1_in.Phi();
1208  double cos1=cos(phi1),sin1=sin(phi1);
1209  double cos1sq=cos1*cos1,sin1sq=sin1*sin1;
1210  double tan2=tan(M_PI_2-mom2_in.Theta());
1211  double tan2sq=tan2*tan2;
1212  double phi2=mom2_in.Phi();
1213  double cos2=cos(phi2),sin2=sin(phi2);
1214  double cos2sq=cos2*cos2,sin2sq=sin2*sin2;
1215  double dx_sq=dx*dx,dy_sq=dy*dy;
1216  double cos2sin1_minus_cos1sin2=cos2*sin1 - cos1*sin2;
1217 
1218  double B1=pow(2*dx*kap2*sin1sq*sin2 - 2*dx*kap1*sin1*sin2sq - sin1sq*sin2sq
1219  + tan1sq + 2*dx*kap2*sin2*tan1sq - 2*dx*kap1*sin1*tan2sq
1220  - 2*sin1*sin2*(2*dx_sq*kap1*kap2 + tan1*tan2)
1221  + sin1sq*(1 + tan2sq) + cos1sq*(-2*cos2*dy*kap2
1222  + 4*dx*kap2*sin2 + sin2sq
1223  + tan2sq)
1224  + 2*cos2*(-2*dy*kap2*sin1sq + dy*kap1*sin1*sin2
1225  - dy*kap2*tan1sq + sin1*(2*dx*dy*kap1*kap2
1226  - dz*kap2*tan1
1227  + dz*kap1*tan2))
1228  + 2*cos1*(cos2sq*dy*kap1 + dy*kap2*sin1*sin2 + dy*kap1*tan2sq
1229  + sin2*(2*dx*dy*kap1*kap2 + dz*kap2*tan1
1230  - dz*kap1*tan2)
1231  - cos2*(2*dy_sq*kap1*kap2 + dx*kap2*sin1
1232  + dx*kap1*sin2 + sin1*sin2 + tan1*tan2)),2)
1233  + 8*(cos2sin1_minus_cos1sin2)*(cos1*kap1*(cos2 - 2*dy*kap2)
1234  + kap2*(-1 + 2*dx*kap1*sin1 - tan1sq)
1235  + kap1*(sin1*sin2 + tan1*tan2))*
1236  (2*cos2*dy_sq*kap2*sin1 + cos2*dx*sin1*sin2 - dz*tan1
1237  - 2*dx*dz*kap2*sin2*tan1 + dz*sin1*sin2*tan2 + cos2*dx*tan1*tan2
1238  + dy*(-2*dx*kap2*sin1*sin2 + sin1*sin2sq + 2*cos2*dz*kap2*tan1
1239  + sin2*tan1*tan2 - sin1*(1 + tan2sq))
1240  + cos1*(cos2*(2*dx*dy*kap2 + dy*sin2 + dz*tan2)
1241  - dx*(2*dx*kap2*sin2 + sin2sq + tan2sq)));
1242  if (B1<0.){
1243  doca=9.9e9;
1244  return VALUE_OUT_OF_RANGE;
1245  }
1246 
1247  double B2=pow(2*dx*kap2*sin1sq*sin2 - 2*dx*kap1*sin1*sin2sq - sin1sq*sin2sq
1248  + tan1sq + 2*dx*kap2*sin2*tan1sq - 2*dx*kap1*sin1*tan2sq
1249  - 2*sin1*sin2*(2*dx_sq*kap1*kap2 + tan1*tan2)
1250  + sin1sq*(1 + tan2sq) + cos1sq*(-2*cos2*dy*kap2
1251  + 4*dx*kap2*sin2 + sin2sq
1252  + tan2sq)
1253  + 2*cos2*(-2*dy*kap2*sin1sq + dy*kap1*sin1*sin2 -dy*kap2*tan1sq
1254  + sin1*(2*dx*dy*kap1*kap2 - dz*kap2*tan1
1255  + dz*kap1*tan2))
1256  + 2*cos1*(cos2sq*dy*kap1 + dy*kap2*sin1*sin2 + dy*kap1*tan2sq
1257  + sin2*(2*dx*dy*kap1*kap2 + dz*kap2*tan1
1258  - dz*kap1*tan2)
1259  - cos2*(2*dy_sq*kap1*kap2 + dx*kap2*sin1
1260  + dx*kap1*sin2 + sin1*sin2 + tan1*tan2)),2)
1261  + 8*(cos2sin1_minus_cos1sin2)*(cos1*kap1*(cos2 - 2*dy*kap2)
1262  + kap2*(-1 + 2*dx*kap1*sin1 - tan1sq)
1263  + kap1*(sin1*sin2 + tan1*tan2))
1264  * (2*cos2*dy_sq*kap2*sin1 + cos2*dx*sin1*sin2 - dz*tan1
1265  - 2*dx*dz*kap2*sin2*tan1 + dz*sin1*sin2*tan2 + cos2*dx*tan1*tan2
1266  + dy*(-2*dx*kap2*sin1*sin2 + sin1*sin2sq + 2*cos2*dz*kap2*tan1
1267  + sin2*tan1*tan2 - sin1*(1 + tan2sq))
1268  + cos1*(cos2*(2*dx*dy*kap2 + dy*sin2 + dz*tan2)
1269  - dx*(2*dx*kap2*sin2 + sin2sq + tan2sq)));
1270  if (B2<0){
1271  doca=9.9e9;
1272  return VALUE_OUT_OF_RANGE;
1273  }
1274 
1275  double A1=2*cos1*cos2sq*dy*kap1 - 2*cos1sq*cos2*dy*kap2
1276  - 4*cos1*cos2*dy_sq*kap1*kap2 - 2*cos1*cos2*dx*kap2*sin1
1277  + 4*cos2*dx*dy*kap1*kap2*sin1 + cos2sq*sin1sq - 4*cos2*dy*kap2*sin1sq
1278  - 2*cos1*cos2*dx*kap1*sin2 + 4*cos1sq*dx*kap2*sin2
1279  + 4*cos1*dx*dy*kap1*kap2*sin2 - 2*cos1*cos2*sin1*sin2
1280  + 2*cos2*dy*kap1*sin1*sin2 + 2*cos1*dy*kap2*sin1*sin2
1281  - 4*dx_sq*kap1*kap2*sin1*sin2 + 2*dx*kap2*sin1sq*sin2 + cos1sq*sin2sq
1282  - 2*dx*kap1*sin1*sin2sq - 2*cos2*dz*kap2*sin1*tan1
1283  + 2*cos1*dz*kap2*sin2*tan1 + cos2sq*tan1sq - 2*cos2*dy*kap2*tan1sq
1284  + 2*dx*kap2*sin2*tan1sq + sin2sq*tan1sq + 2*cos2*dz*kap1*sin1*tan2
1285  - 2*cos1*dz*kap1*sin2*tan2 - 2*cos1*cos2*tan1*tan2 - 2*sin1*sin2*tan1*tan2
1286  + cos1sq*tan2sq + 2*cos1*dy*kap1*tan2sq - 2*dx*kap1*sin1*tan2sq
1287  + sin1sq*tan2sq;
1288  double C1=-4.*(cos2sin1_minus_cos1sin2)
1289  *(cos1*kap1*(cos2 - 2*dy*kap2) + kap2*(-1 + 2*dx*kap1*sin1 - tan1sq)
1290  + kap1*(sin1*sin2 + tan1*tan2));
1291 
1292  double A2=2*cos1*cos2sq*dy*kap1 - 2*cos1sq*cos2*dy*kap2
1293  - 4*cos1*cos2*dy_sq*kap1*kap2 - 4*cos2sq*dx*kap1*sin1
1294  + 2*cos1*cos2*dx*kap2*sin1 + 4*cos2*dx*dy*kap1*kap2*sin1 + cos2sq*sin1sq
1295  + 2*cos1*cos2*dx*kap1*sin2 + 4*cos1*dx*dy*kap1*kap2*sin2
1296  - 2*cos1*cos2*sin1*sin2 - 2*cos2*dy*kap1*sin1*sin2
1297  - 2*cos1*dy*kap2*sin1*sin2 - 4*dx_sq*kap1*kap2*sin1*sin2
1298  + 2*dx*kap2*sin1sq*sin2 + cos1sq*sin2sq + 4*cos1*dy*kap1*sin2sq
1299  - 2*dx*kap1*sin1*sin2sq + 2*cos2*dz*kap2*sin1*tan1
1300  - 2*cos1*dz*kap2*sin2*tan1 + cos2sq*tan1sq - 2*cos2*dy*kap2*tan1sq
1301  + 2*dx*kap2*sin2*tan1sq + sin2sq*tan1sq - 2*cos2*dz*kap1*sin1*tan2
1302  + 2*cos1*dz*kap1*sin2*tan2 - 2*cos1*cos2*tan1*tan2 - 2*sin1*sin2*tan1*tan2
1303  + cos1sq*tan2sq + 2*cos1*dy*kap1*tan2sq - 2*dx*kap1*sin1*tan2sq
1304  + sin1sq*tan2sq;
1305  double C2=4.*(cos2sin1_minus_cos1sin2)
1306  *(kap2*(cos1*cos2 + sin1*sin2 + tan1*tan2)
1307  + kap1*(-1 + 2*cos2*dy*kap2 - 2*dx*kap2*sin2 - tan2sq));
1308 
1309  // Arc lengths to doca points
1310  double s1_minus=(A1-sqrt(B1))/C1;
1311  double s2_minus=(A2-sqrt(B2))/C2;
1312  double s1_plus=(A1+sqrt(B1))/C1;
1313  double s2_plus=(A2+sqrt(B2))/C2;
1314 
1315  // Position components
1316  double x1=pos1_in.x();
1317  double y1=pos1_in.y();
1318  double z1=pos1_in.z();
1319  double x2=pos2_in.x();
1320  double y2=pos2_in.y();
1321  double z2=pos2_in.z();
1322 
1323  // Use solution corresponding to the smaller arc lengths
1324  if (fabs(s1_minus+s2_minus)<fabs(s1_plus+s2_plus)){
1325  pos1_out.SetXYZ(x1+cos1*s1_minus,y1+sin1*s1_minus,z1+tan1*s1_minus);
1326  pos2_out.SetXYZ(x2+cos2*s2_minus,y2+sin2*s2_minus,z2+tan2*s2_minus);
1327  }
1328  else{
1329  pos1_out.SetXYZ(x1+cos1*s1_plus,y1+sin1*s1_plus,z1+tan1*s1_plus);
1330  pos2_out.SetXYZ(x2+cos2*s2_plus,y2+sin2*s2_plus,z2+tan2*s2_plus);
1331  }
1332 
1333  doca=(pos1_out-pos2_out).Mag();
1334 
1335  if (DEBUG_LEVEL>0){
1336  DVector3 myvertex=0.5*(pos1_out+pos2_out);
1337  printf("Vertex position (x,y,z)=(%3.2f, %3.2f, %3.2f)\n",myvertex.x(),
1338  myvertex.y(),myvertex.z());
1339  }
1340 
1341  return NOERROR;
1342 }
1343 
1344 
1345 
1346 double DAnalysisUtilities::Calc_CrudeTime(const vector<const DKinematicData*>& locParticles, const DVector3& locCommonVertex) const
1347 {
1348  //crudely propagate the track times to the common vertex and return the average track time
1349  DVector3 locPOCA;
1350  DVector3 locDeltaVertex;
1351  DVector3 locMomentum;
1352  double locAverageTime = 0.0;
1353  for(size_t loc_i = 0; loc_i < locParticles.size(); ++loc_i)
1354  {
1355  Calc_DOCAToVertex(locParticles[loc_i], locCommonVertex, locPOCA);
1356  locDeltaVertex = locPOCA - locParticles[loc_i]->position();
1357  locMomentum = locParticles[loc_i]->momentum();
1358  double locTime = locParticles[loc_i]->time() + locDeltaVertex.Dot(locMomentum)*locParticles[loc_i]->energy()/(29.9792458*locMomentum.Mag2());
1359  locAverageTime += locTime;
1360  }
1361  return locAverageTime/(double(locParticles.size()));
1362 }
1363 
1364 double DAnalysisUtilities::Calc_CrudeTime(const vector<DKinFitParticle*>& locParticles, const DVector3& locCommonVertex) const
1365 {
1366  //crudely propagate the track times to the common vertex and return the average track time
1367  DVector3 locPOCA;
1368  DVector3 locDeltaVertex;
1369  double locAverageTime = 0.0;
1370  for(size_t loc_i = 0; loc_i < locParticles.size(); ++loc_i)
1371  {
1372  double locTime = 0.0;
1373  double locE = locParticles[loc_i]->Get_ShowerEnergy();
1374  if((locParticles[loc_i]->Get_Charge() == 0) && (locE > 0.0))
1375  {
1376  double locMass = locParticles[loc_i]->Get_Mass();
1377  double locPMag = sqrt(locE*locE - locMass*locMass);
1378  DVector3 locPosition = locParticles[loc_i]->Get_Position();
1379  DVector3 locDPosition(locPosition.X(), locPosition.Y(), locPosition.Z());
1380  DVector3 locDeltaVertex = locDPosition - locCommonVertex;
1381  locTime = locParticles[loc_i]->Get_Time() + locDeltaVertex.Mag()*locE/(29.9792458*locPMag);
1382  }
1383  else
1384  {
1385  Calc_DOCAToVertex(locParticles[loc_i], locCommonVertex, locPOCA);
1386  locDeltaVertex = locPOCA - DVector3(locParticles[loc_i]->Get_Position().X(),locParticles[loc_i]->Get_Position().Y(),locParticles[loc_i]->Get_Position().Z());
1387  DVector3 locMomentum(locParticles[loc_i]->Get_Momentum().X(),locParticles[loc_i]->Get_Momentum().Y(),locParticles[loc_i]->Get_Momentum().Z());
1388  locTime = locParticles[loc_i]->Get_Time() + locDeltaVertex.Dot(locMomentum)*locParticles[loc_i]->Get_Energy()/(29.9792458*locMomentum.Mag2());
1389  }
1390  locAverageTime += locTime;
1391  }
1392  return locAverageTime/(double(locParticles.size()));
1393 }
1394 
1395 DVector3 DAnalysisUtilities::Calc_CrudeVertex(const vector<const DTrackTimeBased*>& locParticles) const
1396 {
1397  //assumes tracks are straight lines
1398  //uses the midpoint of the smallest DOCA line
1399  DVector3 locVertex(0.0, 0.0, dTargetZCenter);
1400 
1401  if(locParticles.size() == 0)
1402  return locVertex;
1403  if(locParticles.size() == 1)
1404  return locParticles[0]->position();
1405 
1406  double locDOCA, locSmallestDOCA;
1407  DVector3 locTempVertex;
1408 
1409  locSmallestDOCA = 9.9E9;
1410  for(int loc_j = 0; loc_j < (int(locParticles.size()) - 1); ++loc_j)
1411  {
1412  for(size_t loc_k = loc_j + 1; loc_k < locParticles.size(); ++loc_k)
1413  {
1414  locDOCA = Calc_DOCAVertex(locParticles[loc_j], locParticles[loc_k], locTempVertex);
1415 
1416  if(locDOCA < locSmallestDOCA)
1417  {
1418  locSmallestDOCA = locDOCA;
1419  locVertex = locTempVertex;
1420  }
1421  }
1422  }
1423  return locVertex;
1424 }
1425 
1426 DVector3 DAnalysisUtilities::Calc_CrudeVertex(const vector<const DChargedTrackHypothesis*>& locParticles) const
1427 {
1428  //assumes tracks are straight lines
1429  //uses the midpoint of the smallest DOCA line
1430  DVector3 locVertex(0.0, 0.0, dTargetZCenter);
1431 
1432  if(locParticles.size() == 0)
1433  return locVertex;
1434  if(locParticles.size() == 1)
1435  return locParticles[0]->position();
1436 
1437  double locDOCA, locSmallestDOCA;
1438  DVector3 locTempVertex;
1439 
1440  locSmallestDOCA = 9.9E9;
1441  for(int loc_j = 0; loc_j < (int(locParticles.size()) - 1); ++loc_j)
1442  {
1443  for(size_t loc_k = loc_j + 1; loc_k < locParticles.size(); ++loc_k)
1444  {
1445  locDOCA = Calc_DOCAVertex(locParticles[loc_j], locParticles[loc_k], locTempVertex);
1446  if(locDOCA < locSmallestDOCA)
1447  {
1448  locSmallestDOCA = locDOCA;
1449  locVertex = locTempVertex;
1450  }
1451  }
1452  }
1453  return locVertex;
1454 }
1455 
1456 DVector3 DAnalysisUtilities::Calc_CrudeVertex(const vector<const DKinematicData*>& locParticles) const
1457 {
1458  //assumes tracks are straight lines
1459  //uses the midpoint of the smallest DOCA line
1460  DVector3 locVertex(0.0, 0.0, dTargetZCenter);
1461 
1462  if(locParticles.size() == 0)
1463  return locVertex;
1464  if(locParticles.size() == 1)
1465  return locParticles[0]->position();
1466 
1467  double locDOCA, locSmallestDOCA;
1468  DVector3 locTempVertex;
1469 
1470  locSmallestDOCA = 9.9E9;
1471  for(int loc_j = 0; loc_j < (int(locParticles.size()) - 1); ++loc_j)
1472  {
1473  for(size_t loc_k = loc_j + 1; loc_k < locParticles.size(); ++loc_k)
1474  {
1475  locDOCA = Calc_DOCAVertex(locParticles[loc_j], locParticles[loc_k], locTempVertex);
1476  if(locDOCA < locSmallestDOCA)
1477  {
1478  locSmallestDOCA = locDOCA;
1479  locVertex = locTempVertex;
1480  }
1481  }
1482  }
1483  return locVertex;
1484 }
1485 
1486 DVector3 DAnalysisUtilities::Calc_CrudeVertex(const vector<shared_ptr<DKinFitParticle>>& locParticles) const
1487 {
1488  //assumes tracks are straight lines
1489  //uses the midpoint of the smallest DOCA line
1490  DVector3 locVertex(0.0, 0.0, dTargetZCenter);
1491 
1492  if(locParticles.size() == 0)
1493  return locVertex;
1494 
1495  if(locParticles.size() == 1)
1496  return DVector3(locParticles[0]->Get_Position().X(), locParticles[0]->Get_Position().Y(), locParticles[0]->Get_Position().Z());
1497 
1498  double locDOCA, locSmallestDOCA;
1499  DVector3 locTempVertex;
1500 
1501  locSmallestDOCA = 9.9E9;
1502  for(int loc_j = 0; loc_j < (int(locParticles.size()) - 1); ++loc_j)
1503  {
1504  for(size_t loc_k = loc_j + 1; loc_k < locParticles.size(); ++loc_k)
1505  {
1506  locDOCA = Calc_DOCAVertex(locParticles[loc_j].get(), locParticles[loc_k].get(), locTempVertex);
1507  if(locDOCA < locSmallestDOCA)
1508  {
1509  locSmallestDOCA = locDOCA;
1510  locVertex = locTempVertex;
1511  }
1512  }
1513  }
1514  return locVertex;
1515 }
1516 
1517 set<set<size_t> > DAnalysisUtilities::Build_IndexCombos(const DReactionStep* locReactionStep, deque<Particle_t> locToIncludePIDs) const
1518 {
1519  //if locToIncludePIDs is empty, will return one set with all (except missing)
1520  set<set<size_t> > locCombos;
1521 
1522  auto locReactionStepPIDs = locReactionStep->Get_FinalPIDs();
1523  int locMissingParticleIndex = locReactionStep->Get_MissingParticleIndex();
1524 
1525  if(locToIncludePIDs.empty())
1526  {
1527  set<size_t> locCombo;
1528  for(size_t loc_i = 0; loc_i < locReactionStepPIDs.size(); ++loc_i)
1529  {
1530  if(int(loc_i) == locMissingParticleIndex)
1531  continue;
1532  locCombo.insert(loc_i);
1533  }
1534  locCombos.insert(locCombo);
1535  return locCombos;
1536  }
1537 
1538  //deque indices corresponds to locToIncludePIDs, and each set is what could pass for it
1539  deque<deque<size_t> > locPossibilities(locToIncludePIDs.size(), deque<size_t>());
1540  deque<int> locResumeAtIndices(locToIncludePIDs.size(), 0);
1541 
1542  //build possibilities: loop over reaction PIDs
1543  for(size_t loc_i = 0; loc_i < locReactionStepPIDs.size(); ++loc_i)
1544  {
1545  if(int(loc_i) == locMissingParticleIndex)
1546  continue;
1547  Particle_t locPID = locReactionStepPIDs[loc_i];
1548 
1549  //register where this is a valid option: loop over to-include PIDs
1550  for(size_t loc_j = 0; loc_j < locToIncludePIDs.size(); ++loc_j)
1551  {
1552  if(locToIncludePIDs[loc_j] == locPID)
1553  locPossibilities[loc_j].push_back(loc_i);
1554  }
1555  }
1556 
1557  //build combos
1558  int locParticleIndex = 0;
1559  deque<size_t> locComboDeque;
1560  while(true)
1561  {
1562  if(locParticleIndex == int(locPossibilities.size())) //end of combo: save it
1563  {
1564  set<size_t> locComboSet; //convert set to deque
1565  for(size_t loc_i = 0; loc_i < locComboDeque.size(); ++loc_i)
1566  locComboSet.insert(locComboDeque[loc_i]);
1567  locCombos.insert(locComboSet); //saved
1568 
1569  if(!Handle_Decursion(locParticleIndex, locComboDeque, locResumeAtIndices, locPossibilities))
1570  break;
1571  continue;
1572  }
1573 
1574  int& locResumeAtIndex = locResumeAtIndices[locParticleIndex];
1575 
1576  //if two identical pids: locResumeAtIndex must always be >= the previous locResumeAtIndex (prevents duplicates) e.g. g, p -> p, pi0, pi0
1577  //search for same pid previously in this step
1578  Particle_t locToIncludePID = locToIncludePIDs[locParticleIndex];
1579  for(int loc_i = locParticleIndex - 1; loc_i >= 0; --loc_i)
1580  {
1581  if(locToIncludePIDs[loc_i] == locToIncludePID)
1582  {
1583  if(locResumeAtIndex < locResumeAtIndices[loc_i])
1584  locResumeAtIndex = locResumeAtIndices[loc_i];
1585  break; //dupe type in step: resume-at advanced to next
1586  }
1587  }
1588 
1589  if(locResumeAtIndex >= int(locPossibilities[locParticleIndex].size()))
1590  {
1591  if(!Handle_Decursion(locParticleIndex, locComboDeque, locResumeAtIndices, locPossibilities))
1592  break;
1593  continue;
1594  }
1595 
1596  // pid found
1597  locComboDeque.push_back(locPossibilities[locParticleIndex][locResumeAtIndex]);
1598  ++locResumeAtIndex;
1599  ++locParticleIndex;
1600  }
1601 
1602  return locCombos;
1603 }
1604 
1605 bool DAnalysisUtilities::Handle_Decursion(int& locParticleIndex, deque<size_t>& locComboDeque, deque<int>& locResumeAtIndices, deque<deque<size_t> >& locPossibilities) const
1606 {
1607  do
1608  {
1609  if(locParticleIndex < int(locResumeAtIndices.size())) //else just saved a combo
1610  locResumeAtIndices[locParticleIndex] = 0; //finding this particle failed: reset
1611 
1612  --locParticleIndex; //go to previous particle
1613  if(locParticleIndex < 0)
1614  return false; //end of particles: end of finding all combos
1615 
1616  locComboDeque.pop_back(); //reset this index
1617  }
1618  while(locResumeAtIndices[locParticleIndex] == int(locPossibilities[locParticleIndex].size()));
1619 
1620  return true;
1621 }
1622 
1623 //The POCA cannot technically be solved analytically, but we can approximate it pretty accurately
1624  //First, propagate the track to somewhere very close to the true POCA
1625  //Then, the equation can be solved by substituting cos(x) = 1, sin(x) = x
1626 double DAnalysisUtilities::Propagate_Track(int locCharge, const DVector3& locPropagateToPoint, DLorentzVector& locMeasuredX4, DLorentzVector& locMeasuredP4, TMatrixFSym* locCovarianceMatrix) const
1627 {
1628  //ASSUMES THAT THE B-FIELD IS IN THE +Z DIRECTION!!!!!!!!!!!!!!!
1629  double locDistance = (locMeasuredX4.Vect() - locPropagateToPoint).Mag();
1630  if(!Get_IsBFieldNearBeamline() || (locCharge == 0) || (locDistance < dMinDistanceForStraightTrack))
1631  {
1632  //use simpler methods
1633  DVector3 locPOCA;
1634  auto locP3 = locMeasuredP4.Vect();
1635  Calc_DOCAToVertex(locP3.Unit(), locMeasuredX4.Vect(), locPropagateToPoint, locPOCA);
1636  locMeasuredX4.SetVect(locPOCA);
1637  auto locDistanceVector = locPOCA - locMeasuredX4.Vect();
1638  //negative: if you had to propagate the track forwards, that means the path length is LESS than what you thought it was
1639  auto locDeltaPathLength = (locP3.Dot(locDistanceVector) > 0.0) ? -1.0*locDistanceVector.Mag() : locDistanceVector.Mag();
1640  locMeasuredX4.SetT(locMeasuredX4.T() - locDeltaPathLength/(locMeasuredP4.Beta()*SPEED_OF_LIGHT)); //v = s/t, t = s/v = s/(beta*c) = s*E/(p*c) =
1641  return locDeltaPathLength;
1642  }
1643 
1644  //propagate the track to the same z as the vertex (if pz != 0)
1645  double locTotalDeltaPathLength = 0.0;
1646  DLorentzVector locTempPropagatedPosition = locMeasuredX4;
1647  DLorentzVector locTempPropagatedMomentum = locMeasuredP4;
1648  if(fabs(locMeasuredP4.Pz()) > 0.0)
1649  {
1650  locTotalDeltaPathLength += (locPropagateToPoint.Z() - locMeasuredX4.Z())*locMeasuredP4.P()/locMeasuredP4.Pz(); //s = (z - z0)*p/p0z
1651  Propagate_Track(locTotalDeltaPathLength, locCharge, locTempPropagatedPosition, locTempPropagatedMomentum, NULL);
1652  }
1653 
1654  //now, step along the track until we get close to the POCA
1655  locTotalDeltaPathLength += Calc_PathLength_Step(locCharge, locPropagateToPoint, locTempPropagatedPosition, locTempPropagatedMomentum);
1656 
1657  //now, the path length is very close to accurate. get the rest of the way there
1658  locTotalDeltaPathLength += Calc_PathLength_FineGrained(locCharge, locPropagateToPoint, locTempPropagatedPosition.Vect(), locTempPropagatedMomentum.Vect());
1659 
1660  //Finally, propagate the track the given distance and return
1661 //cout << "FINAL: xyz, distance = " << locMeasuredX4.X() << ", " << locMeasuredX4.Y() << ", " << locMeasuredX4.Z() << ", " << locTotalDeltaPathLength << endl;
1662  Propagate_Track(locTotalDeltaPathLength, locCharge, locMeasuredX4, locMeasuredP4, locCovarianceMatrix);
1663 
1664  //negative: if you had to propagate the track forwards, that means the path length is LESS than what you thought it was
1665  return -1.0*locTotalDeltaPathLength;
1666 }
1667 
1668 double DAnalysisUtilities::Calc_PathLength_Step(int locCharge, const DVector3& locPropagateToPoint, DLorentzVector& locMeasuredX4, DLorentzVector& locMeasuredP4) const
1669 {
1670  //now, step slowly along the track (in path length), trying to get closer to the POCA
1671  //for the final calculation to work, rho*s must be small: cos(rho*s) -> 1
1672  DVector3 locBField = Get_BField(locPropagateToPoint);
1673  double locA = -0.00299792458*(double(locCharge))*locBField.Mag();
1674 
1675  double locPMag = locMeasuredP4.P();
1676  double locPathLengthOneRotation = 2.0*TMath::Pi()*locPMag/locA;
1677  double locStepDistance = locPathLengthOneRotation/12.0; //30 degrees //e.g. for 90 degree tracks
1678 
1679  //guard against long steps in z (e.g. for 2 degree tracks)
1680  double locStepDeltaZ = locMeasuredP4.Pz()*locStepDistance/locPMag;
1681  double locTargetDeltaZ = 1.0;
1682  if(fabs(locStepDeltaZ) > 5.0)
1683  locStepDistance = locTargetDeltaZ*locPMag/locMeasuredP4.Pz();
1684 
1685  //First, try stepping in +pvec direction
1686  double locStepDirection = 1.0;
1687  double locTotalDeltaPathLength = 0.0;
1688  double locDeltaX3 = (locMeasuredX4.Vect() - locPropagateToPoint).Mag();
1689  double locRhoS = locStepDistance*locA/locPMag;
1690  double locRhoSCutOff = 0.1;
1691  while(locRhoS > locRhoSCutOff) //at this point, cos(rho*s) = 0.995: close enough
1692  {
1693  double locDeltaPathLength = locStepDirection*locStepDistance;
1694  locTotalDeltaPathLength += locDeltaPathLength;
1695 //cout << "STEP LOOP: xyz, distance = " << locMeasuredX4.X() << ", " << locMeasuredX4.Y() << ", " << locMeasuredX4.Z() << ", " << locDeltaPathLength << endl;
1696  Propagate_Track(locDeltaPathLength, locCharge, locMeasuredX4, locMeasuredP4, NULL);
1697 
1698  double locNewDeltaX3 = (locMeasuredX4.Vect() - locPropagateToPoint).Mag();
1699  bool locGettingCloserFlag = (locNewDeltaX3 < locDeltaX3);
1700  locDeltaX3 = locNewDeltaX3;
1701 
1702  if(locGettingCloserFlag)
1703  continue; //stepping in correct direction, can still try to get closer
1704 
1705  //are now farther away than before: reverse direction, decrease step size
1706  locStepDirection *= -1.0;
1707  locStepDistance /= 2.0;
1708  locRhoS = locStepDistance*locA/locPMag;
1709 
1710  //if about to break, revert to older, better position
1711  if(locRhoS < locRhoSCutOff)
1712  {
1713  locTotalDeltaPathLength -= locDeltaPathLength;
1714  Propagate_Track(-1.0*locDeltaPathLength, locCharge, locMeasuredX4, locMeasuredP4, NULL);
1715  }
1716  }
1717 
1718  return locTotalDeltaPathLength;
1719 }
1720 
1721 double DAnalysisUtilities::Calc_PathLength_FineGrained(int locCharge, const DVector3& locPropagateToPoint, DVector3 locMeasuredPosition, DVector3 locMeasuredMomentum) const
1722 {
1723  //ASSUMES B-FIELD IS IN +Z DIRECTION!!
1724 
1725  //distance = sqrt((delta-x)^2 + (delta-y)^2 + (delta-z)^2)
1726  //find the delta-path-length s that minimizes the distance equation
1727  //take derivative of the distance equation, set = 0
1728 
1729  //Mathematica yields: F*(B*s + C) + D*cos(rho*s) + E*sin(rho*s) = 0
1730  //(where BCDEF are various, non-s-dependent terms)
1731  //This is unsolvable analytically. However, we know that s is small, since we're almost there
1732 
1733  //So, substitute cos(x) = 1, sin(x) = x:
1734  //F*(B*s + C) + D + E*rho*s = 0
1735  //Solving gives: s = - (F*C + D) / (F*B + E*rho)
1736  //Note that B = F
1737 
1738  DVector3 locBField = Get_BField(locMeasuredPosition);
1739  double locA = -0.00299792458*(double(locCharge))*locBField.Mag();
1740  double locPMag = locMeasuredMomentum.Mag();
1741  double locRho = locA/locPMag;
1742 
1743  DVector3 locDeltaX3 = locMeasuredPosition - locPropagateToPoint;
1744  double locF = locMeasuredMomentum.Pz()/locPMag;
1745  double locC = locDeltaX3.Z();
1746  double locD = locRho*(locMeasuredMomentum.Px()*locDeltaX3.X() + locMeasuredMomentum.Py()*locDeltaX3.Y())/locA;
1747  double locPerpPSq = locMeasuredMomentum.Px()*locMeasuredMomentum.Px() + locMeasuredMomentum.Py()*locMeasuredMomentum.Py();
1748  double locE = locRho*(locPerpPSq/locA - locMeasuredMomentum.Py()*locDeltaX3.X() + locMeasuredMomentum.Px()*locDeltaX3.Y())/locA;
1749  return -1.0*(locF*locC + locD)/(locF*locF + locE*locRho);
1750 }
1751 
1752 void DAnalysisUtilities::Propagate_Track(double locDeltaPathLength, int locCharge, DLorentzVector& locX4, DLorentzVector& locP4, TMatrixFSym* locCovarianceMatrix) const
1753 {
1754  //ASSUMES THAT THE B-FIELD IS IN THE +Z DIRECTION!!!!!!!!!!!!!!!
1755 
1756  DVector3 locBField = Get_BField(locX4.Vect());
1757  if(!(locBField.Mag() > 0.0))
1758  return;
1759  DVector3 locH = locBField.Unit();
1760  double locA = -0.00299792458*(double(locCharge))*locBField.Mag();
1761 
1762  double locPMag = locP4.P();
1763  double locRhoS = locDeltaPathLength*locA/locPMag;
1764 
1765  DLorentzVector locDeltaX4; //x - x0
1766  locDeltaX4.SetX(locP4.Px()*sin(locRhoS)/locA - locP4.Py()*(1.0 - cos(locRhoS))/locA);
1767  locDeltaX4.SetY(locP4.Py()*sin(locRhoS)/locA + locP4.Px()*(1.0 - cos(locRhoS))/locA);
1768  locDeltaX4.SetZ(locP4.Pz()*locDeltaPathLength/locPMag);
1769  locDeltaX4.SetT(locDeltaPathLength/(locP4.Beta()*SPEED_OF_LIGHT)); //v = s/t, t = s/v = s/(beta*c) = s*E/(p*c) =
1770  locX4 += locDeltaX4;
1771 
1772  if(locCovarianceMatrix == NULL)
1773  {
1774  locP4.SetVect(locP4.Vect() - locDeltaX4.Vect().Cross(locA*locH));
1775  return; //don't update error matrix
1776  }
1777 
1778  //transform(i, j) = di/dj, i = new, j = old //pxyz, xyz, t
1779  TMatrixF locTransformMatrix(7, 7);
1780  locTransformMatrix.Zero();
1781 
1782  double locPCubed = locPMag*locPMag*locPMag;
1783  double locSOverP3 = locDeltaPathLength/locPCubed;
1784 
1785  double locSOverP3_PxPx = locSOverP3*locP4.Px()*locP4.Px();
1786  double locSOverP3_PxPy = locSOverP3*locP4.Px()*locP4.Py();
1787  double locSOverP3_PxPz = locSOverP3*locP4.Px()*locP4.Pz();
1788 
1789  double locSOverP3_PyPy = locSOverP3*locP4.Py()*locP4.Py();
1790  double locSOverP3_PyPz = locSOverP3*locP4.Py()*locP4.Pz();
1791  double locSOverP3_PzPz = locSOverP3*locP4.Pz()*locP4.Pz();
1792 
1793  //dpx
1794  locTransformMatrix(0, 0) = (1.0 + locA*locSOverP3_PxPy)*cos(locRhoS) + locA*locSOverP3_PxPx*sin(locRhoS);
1795  locTransformMatrix(0, 1) = (-1.0 + locA*locSOverP3_PxPy)*sin(locRhoS) + locA*locSOverP3_PyPy*cos(locRhoS);
1796  locTransformMatrix(0, 2) = locA*locSOverP3_PyPz*cos(locRhoS) + locA*locSOverP3_PxPz*sin(locRhoS);
1797 
1798  //dpy
1799  locTransformMatrix(1, 0) = -1.0*locA*locSOverP3_PxPx*cos(locRhoS) + (1.0 + locA*locSOverP3_PxPy)*sin(locRhoS);
1800  locTransformMatrix(1, 1) = (1.0 - locA*locSOverP3_PxPy)*cos(locRhoS) + locA*locSOverP3_PyPy*sin(locRhoS);
1801  locTransformMatrix(1, 2) = locA*locSOverP3_PyPz*sin(locRhoS) - locA*locSOverP3_PxPz*cos(locRhoS);
1802 
1803  //dpz
1804  locTransformMatrix(2, 2) = 1.0;
1805 
1806  //dx
1807  locTransformMatrix(3, 0) = (1.0/locA + locSOverP3_PxPy)*sin(locRhoS) - locSOverP3_PxPx*cos(locRhoS);
1808  locTransformMatrix(3, 1) = -1.0/locA + (1.0/locA - locSOverP3_PxPy)*cos(locRhoS) + locSOverP3_PyPy*sin(locRhoS);
1809  locTransformMatrix(3, 2) = locSOverP3_PyPz*sin(locRhoS) - locSOverP3_PxPz*cos(locRhoS);
1810  locTransformMatrix(3, 3) = 1.0;
1811 
1812  //dy
1813  locTransformMatrix(4, 0) = 1.0/locA - (1.0/locA + locSOverP3_PxPy)*cos(locRhoS) + locSOverP3_PxPx*sin(locRhoS);
1814  locTransformMatrix(4, 1) = (1.0/locA - locSOverP3_PxPy)*sin(locRhoS) - locSOverP3_PyPy*cos(locRhoS);
1815  locTransformMatrix(4, 2) = -1.0*locSOverP3_PyPz*cos(locRhoS) - locSOverP3_PxPz*sin(locRhoS);
1816  locTransformMatrix(4, 4) = 1.0;
1817 
1818  //dz
1819  locTransformMatrix(5, 0) = -1.0*locSOverP3_PxPz;
1820  locTransformMatrix(5, 1) = -1.0*locSOverP3_PyPz;
1821  locTransformMatrix(5, 2) = locDeltaPathLength/locPMag - locSOverP3_PzPz;
1822  locTransformMatrix(5, 5) = 1.0;
1823 
1824  //dt
1825  locTransformMatrix(6, 0) = -1.0*locP4.M2()*locSOverP3*locP4.Px()/(SPEED_OF_LIGHT*locP4.E());
1826  locTransformMatrix(6, 1) = -1.0*locP4.M2()*locSOverP3*locP4.Py()/(SPEED_OF_LIGHT*locP4.E());
1827  locTransformMatrix(6, 2) = -1.0*locP4.M2()*locSOverP3*locP4.Pz()/(SPEED_OF_LIGHT*locP4.E());
1828  locTransformMatrix(6, 6) = 1.0;
1829 
1830  //transform!!
1831  locCovarianceMatrix->Similarity(locTransformMatrix);
1832 
1833  //update p3 //must do at the end!!
1834  locP4.SetVect(locP4.Vect() - locDeltaX4.Vect().Cross(locA*locH));
1835 }
vector< const DKinematicData * > Get_FinalParticles_Measured(void) const
vector< const JObject * > Get_FinalParticle_SourceObjects(Charge_t locCharge=d_AllCharges) const
char Get_Charge(void) const
void Add_ReactionStep(const DReactionStep *locReactionStep)
Definition: DReaction.h:48
#define SPEED_OF_LIGHT
int Calc_Momentum_UnusedTracks(JEventLoop *locEventLoop, const DParticleCombo *locParticleCombo, double &locSumPMag_UnusedTracks, TVector3 &locSumP3_UnusedTracks) const
pair< int, int > Get_InitialParticleDecayFromIndices(const DReaction *locReaction, int locStepIndex)
Definition: DReaction.cc:93
size_t Get_NumParticleComboSteps(void) const
bool Check_ChannelEquality(const DReaction *lhs, const DReaction *rhs, bool locSameOrderFlag=true, bool locRightSubsetOfLeftFlag=false)
Definition: DReaction.h:185
double pmag(void) const
TVector3 DVector3
Definition: DVector3.h:14
DAnalysisUtilities(JEventLoop *loop)
void Get_UnusedTimeBasedTracks(JEventLoop *locEventLoop, const DParticleCombo *locParticleCombo, vector< const DTrackTimeBased * > &locUnusedTimeBasedTracks) const
static unsigned short int IsResonance(Particle_t p)
Definition: particleType.h:802
const DChargedTrackHypothesis * Get_BestTrackingFOM(void) const
Definition: DChargedTrack.h:86
DMagneticFieldMap * GetBfield(unsigned int run_number=1)
bool Get_IsBFieldNearBeamline(void) const
const DVector3 & position(void) const
bool Check_IsBDTSignalEvent(JEventLoop *locEventLoop, const DReaction *locReaction, bool locExclusiveMatchFlag, bool locIncludeDecayingToReactionFlag) const
const DParticleCombo * Build_ThrownCombo(JEventLoop *locEventLoop)
void Clear_ReactionSteps(void)
Definition: DReaction.h:49
Particle_t Get_TargetPID(void) const
Definition: DReactionStep.h:83
double Calc_Energy_UnusedShowers(JEventLoop *locEventLoop, const DParticleCombo *locParticleCombo) const
set< set< size_t > > Build_IndexCombos(const DReactionStep *locReactionStep, deque< Particle_t > locToIncludePIDs) const
double Calc_DOCAToVertex(const DVector3 &locUnitDir, const DVector3 &locPosition, const DVector3 &locVertex) const
const DKinematicData * Get_InitialParticle_Measured(void) const
TLorentzVector DLorentzVector
const DEventRFBunch * Get_EventRFBunch(void) const
void Recycle_Reaction(DReaction *locReaction)
static int PDGtype(Particle_t p)
#define X(str)
Definition: hddm-c.cpp:83
double Calc_DOCAVertex(const DVector3 &locUnitDir1, const DVector3 &locUnitDir2, const DVector3 &locVertex1, const DVector3 &locVertex2, DVector3 &locDOCAPoint) const
DVector3 Get_BField(const DVector3 &locPosition) const
double Calc_DOCA(const DVector3 &locUnitDir1, const DVector3 &locUnitDir2, const DVector3 &locVertex1, const DVector3 &locVertex2) const
bool Handle_Decursion(int &locParticleIndex, deque< size_t > &locComboDeque, deque< int > &locResumeAtIndices, deque< deque< size_t > > &locPossibilities) const
DLorentzVector dSpacetimeVertex
DLorentzVector Calc_FinalStateP4(const DReaction *locReaction, const DParticleCombo *locParticleCombo, size_t locStepIndex, bool locUseKinFitDataFlag) const
TEllipse * e
void Replace_DecayingParticleWithProducts(deque< pair< const DMCThrown *, deque< const DMCThrown * > > > &locThrownSteps, size_t locStepIndex) const
Particle_t Get_InitialPID(void) const
Definition: DReactionStep.h:81
void Get_UnusedChargedTracks(JEventLoop *locEventLoop, const DParticleCombo *locParticleCombo, vector< const DChargedTrack * > &locUnusedChargedTracks) const
void Get_UnusedTrackCandidates(JEventLoop *locEventLoop, const DParticleCombo *locParticleCombo, vector< const DTrackCandidate * > &locUnusedTrackCandidates) const
void Add_FinalParticleID(Particle_t locPID, bool locIsMissingFlag=false)
DVector3 Calc_CrudeVertex(const vector< const DKinematicData * > &locParticles) const
DLorentzVector Calc_MissingP4(const DReaction *locReaction, const DParticleCombo *locParticleCombo, bool locUseKinFitDataFlag) const
DGeometry * GetDGeometry(unsigned int run_number)
double Calc_PathLength_FineGrained(int locCharge, const DVector3 &locPropagateToPoint, DVector3 locMeasuredPosition, DVector3 locMeasuredMomentum) const
double Calc_CrudeTime(const vector< const DKinematicData * > &locParticles, const DVector3 &locCommonVertex) const
static unsigned short int IsFixedMass(Particle_t p)
Definition: particleType.h:743
vector< const DKinematicData * > Get_FinalParticles(void) const
Particle_t Get_FinalPID(size_t locIndex) const
Definition: DReactionStep.h:87
bool Are_ThrownPIDsSameAsDesired(JEventLoop *locEventLoop, const deque< Particle_t > &locDesiredPIDs, Particle_t locMissingPID=Unknown) const
void Get_UnusedWireBasedTracks(JEventLoop *locEventLoop, const DParticleCombo *locParticleCombo, vector< const DTrackWireBased * > &locUnusedWireBasedTracks) const
static int Is_FinalStateParticle(Particle_t locPID)
double charge(void) const
int Get_MissingParticleIndex(void) const
Definition: DReactionStep.h:93
void Get_ThrownParticleSteps(JEventLoop *locEventLoop, deque< pair< const DMCThrown *, deque< const DMCThrown * > > > &locThrownSteps) const
DLorentzVector lorentzMomentum(void) const
static double ParticleMass(Particle_t p)
double sqrt(double)
const JObject * Get_FinalParticle_SourceObject(size_t locFinalParticleIndex) const
virtual double GetBz(double x, double y, double z) const =0
double sin(double)
const DKinematicData * Get_InitialParticle(void) const
size_t Get_NumFinalPIDs(void) const
Definition: DReactionStep.h:89
void Set_InitialParticleID(Particle_t locPID, bool locIsMissingFlag=false)
DParticleComboCreator * dParticleComboCreator
const DVector3 & momentum(void) const
vector< Particle_t > Get_FinalPIDs(bool locIncludeMissingFlag=true, Charge_t locCharge=d_AllCharges, bool locIncludeDuplicatesFlag=true) const
double Propagate_Track(int locCharge, const DVector3 &locPropagateToPoint, DLorentzVector &locMeasuredX4, DLorentzVector &locMeasuredP4, TMatrixFSym *locCovarianceMatrix) const
DReaction * Build_ThrownReaction(JEventLoop *locEventLoop, deque< pair< const DMCThrown *, deque< const DMCThrown * > > > &locThrownSteps)
const DReactionStep * Get_ReactionStep(size_t locStepIndex) const
Definition: DReaction.h:84
void Get_UnusedNeutralParticles(JEventLoop *locEventLoop, const DParticleCombo *locParticleCombo, vector< const DNeutralParticle * > &locUnusedNeutralParticles) const
int Get_DecayStepIndex(const DReaction *locReaction, size_t locStepIndex, size_t locParticleIndex)
Definition: DReaction.cc:135
const DKinFitResults * Get_KinFitResults(void) const
TVector3 Get_Position(void) const
void Get_UnusedNeutralShowers(JEventLoop *locEventLoop, const DParticleCombo *locParticleCombo, vector< const DNeutralShower * > &locUnusedNeutralShowers) const
shared_ptr< const TMatrixFSym > errorMatrix(void) const
bool Check_ThrownsMatchReaction(JEventLoop *locEventLoop, const DReaction *locReaction, bool locExclusiveMatchFlag) const
const DParticleComboStep * Get_ParticleComboStep(size_t locStepIndex) const
size_t Get_NumReactionSteps(void) const
Definition: DReaction.h:83
const DMagneticFieldMap * dMagneticFieldMap
printf("string=%s", string)
const DParticleID * dPIDAlgorithm
void Set_TargetParticleID(Particle_t locPID)
Definition: DReactionStep.h:76
bool GetTargetZ(double &z_target) const
z-location of center of target
Definition: DGeometry.cc:1933
Particle_t PID(void) const
TVector3 Get_Momentum(void) const
double Calc_PathLength_Step(int locCharge, const DVector3 &locPropagateToPoint, DLorentzVector &locMeasuredX4, DLorentzVector &locMeasuredP4) const
TMatrixFSym Calc_MissingP3Covariance(const DReaction *locReaction, const DParticleCombo *locParticleCombo) const
Particle_t
Definition: particleType.h:12