Hall-D Software  alpha
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
DSourceComboP4Handler.cc
Go to the documentation of this file.
3 
4 /*************************************************** PHOTON P4 RECONSTRUCTION **************************************************
5 *
6 * The exact photon momentum is unknown until its production vertex is known.
7 * However, that vertex is combo-dependent. We'd like to make cuts on the pi0 mass globally in advance, rather than on a combo-by-combo basis.
8 * This would be a huge savings in time and memory.
9 *
10 * The momentum of the hypotheses calculated in DNeutralParticle is based on the DVertex (class) position.
11 * This vertex is determined from all of the "good" charged tracks in the event, typically by doing a kinematic fit.
12 *
13 * However, there a several potential problems with using this vertex:
14 * 1) There may have been extra (junk, accidental) tracks reconstructed in the event. These will throw off the vertex position.
15 * And, if there are only 2 tracks, it can throw it off considerably.
16 * 2) The track position & momentum are different for each hypothesis, and it's not clear in advance which hypothesis should be used.
17 * 3) The photons may have come from a detached vertex, which can be 10+ cm downstream of the main vertex.
18 *
19 * So while the DVertex is OK for someone looking for a quick estimate, it should not be used in an actual analysis.
20 *
21 * Now, as we said before, the true photon momentum is combo-dependent, and we want to do loose mass cuts in a combo-independent way.
22 * So, we can compute all of the p4's at a specific vertex position (e.g. center of the target), rather than separately for each combo.
23 * But, how much of an impact will a given error in the vertex position have on the calculated 2-photon invariant mass?
24 *
25 * The calculation below determines that the maximum 2-photon-mass error occurs when both photons are at 45 degrees near the eta peak (less near pi0).
26 * Specifically: z_err = 5cm yields a mass error of ~20 MeV, 10cm -> ~40 MeV, 15cm -> ~60 MeV, etc.
27 *
28 * So, what is the maximum delta_m we can tolerate with our loose cuts?
29 * The idea is that the loose cuts should be wide enough around the signal peak to provide enough statistics for sideband subtraction.
30 * So, no matter what we choose, it won't affect the signal peak. But we also don't want to affect the sidebands too much.
31 * E.g. pi0 mass peak is from ~110 -> ~160 MeV, loose cut is 50 -> 220 MeV at the moment
32 * Therefore, you probably want to keep the maximum delta_m at around the 20 MeV level.
33 * This means that the max z_error should be about 5 cm
34 *
35 * Therefore, every 10 cm, from 5cm upstream of the target to 15 cm downstream of the target (detached vertex) (5 bins):
36 * Compute p4s at the centers of these vertex-z bins and do loose mass cuts
37 *
38 *******************************************************************************************************************************/
39 
40 /************************************************ 2-PHOTON MASS ERROR DERIVATION ***********************************************
41 *
42 * For this error estimate, consider the decay pi0 -> 2g (or eta -> 2g).
43 * The equation for the invariant mass squared of the 2 photons is:
44 * m^2 = (E1 + E2)^2 - (px1 + px2)^2 - (py1 + py2)^2 - (pz1 + pz2)^2
45 *
46 * The difference in mass squared due to the error is: (using "_g" prefix for guess and "_t" prefix for "true")
47 * delta(m^2) = m_g^2 - m^2_t
48 * delta(m^2) = (px1 + px2)^2_t + (py1 + py2)^2_t + (pz1 + pz2)^2_t - (px1 + px2)^2_g - (py1 + py2)^2_g - (pz1 + pz2)^2_g
49 *
50 * Simplifying, we will choose the 2 photons to have opposite phi's at 0 & 180 degrees
51 * Thus, py1 = py2 = 0 for guess & true momentum.
52 * delta(m^2) = (px1 + px2)^2_t + (pz1 + pz2)^2_t - (px1 + px2)^2_g - (pz1 + pz2)^2_g
53 * Also, px1_unit = -px2_unit, but we'll use this a little later.
54 *
55 * Now, assume that both photons have the same E & theta: Whatever the worst-case is, it will be the same for both photons.
56 * Since from before px1_unit = -px2_unit, Now px1_t = -px2_t and px1_g = -px2_g. Also, pz1_t = pz2_t = pz_t, & pz1_g = pz2_g = pz_g
57 * delta(m^2) = 4*pz_t^2 - 4*pz_g^2
58 *
59 * Now for photons, pz = E*dz/d, where d is the distance between the shower and the vertex, and dz is the z-component of d.
60 * Plugging this in gives:
61 * delta(m^2) = 4*E^2*[(dz_t/d_t)^2 - (dz_g/d_g)^2]
62 * Using dz_g/d_g = cos(theta_g) gives:
63 * delta(m^2) = 4*E^2*[(dz_t/d_t)^2 - cos^2(theta_g)]
64 *
65 * Now, m_g^2 = (E1 + E2)^2 - (px1 + px2)^2_g - (py1 + py2)^2_g - (pz1 + pz2)^2_g
66 * However, we've defined our photon guesses pretty narrowly: py = 0, px1 = -px2, pz1 = pz2, E1 = E2
67 * Thus, m_g^2 = (2E)^2 - (2pz_g)^2
68 * Plugging in pz_g = E*dz_g/d_g yields:
69 * Thus, m_g^2 = 4*E^2*[1 - (dz_g/d_g)^2]
70 * Using dz_g/d_g = cos(theta_g)
71 * Thus, m_g^2 = 4*E^2*sin^2(theta_g)
72 * Rearranging gives: 4*E^2 = m_g^2/sin^2(theta_g)
73 *
74 * Plugging the above into delta(m^2)
75 * delta(m^2) = m_g^2*[(dz_t/d_t)^2 - cos^2(theta_g)]/sin^2(theta_g)
76 *
77 * But, we want delta_m, not delta(m^2)
78 * delta_m = m_g - m_t, m_t = sqrt(m_g^2 - delta(m^2))
79 * delta_m = m_g - sqrt(m_g^2 - delta(m^2))
80 * delta_m = m_g - sqrt(m_g^2 - m_g^2*[(dz_t/d_t)^2 - cos^2(theta_g)]/sin^2(theta_g))
81 *
82 * Rearrange and cancel terms
83 * delta_m = m_g - m_g*sqrt(1 - [(dz_t/d_t)^2 - cos^2(theta_g)]/sin^2(theta_g))
84 * delta_m = m_g - m_g*sqrt([sin^2(theta_g) - (dz_t/d_t)^2 + cos^2(theta_g)]/sin^2(theta_g))
85 * delta_m = m_g - m_g*sqrt[1 - (dz_t/d_t)^2]/sin(theta_g)
86 * delta_m = m_g - m_g*sqrt[(d_t^2 - dz_t^2)/d_t^2]/sin(theta_g)
87 *
88 * Note that d_t^2 - dz_t^2 = dx^2 (since dy is zero)
89 * delta_m = m_g - m_g*sqrt[dx^2/d_t^2]/sin(theta_g)
90 * delta_m = m_g - m_g*dx/(d_t*sin(theta_g))
91 *
92 * Getting the true dz_t & d_t in terms of some z_error:
93 * d_t = sqrt(dx^2 + dz_t^2), dz_t = dz_g + z_error
94 * delta_m = m_g - m_g*dx/(sin(theta_g)*sqrt(dx^2 + (dz_g + z_error)^2))
95 * And dz_g = dx/tan(theta_g)
96 * delta_m = m_g - m_g*dx/(sin(theta_g)*sqrt(dx^2 + (dx/tan(theta_g) + z_error)^2))
97 * delta_m = m_g - m_g/(sin(theta_g)*sqrt(1 + (1/tan(theta_g) + z_error/dx)^2))
98 *
99 * For BCAL, dx = 65.
100 * For the FCAL, dx = dz*tan(theta), dz = 650 - z_error (approx 650):
101 * delta_m = m_g - m_g/(sin(theta_g)*sqrt(1 + (1 + z_error/(650 - z_error))^2/tan^2(theta_g)))
102 * delta_m = m_g - m_g/(cos(theta_g)*sqrt(tan^2(theta_g) + (1 + z_error/(650 - z_error))^2))
103 *
104 * delta_m Is larger at higher m_g, max at 45 degrees (and is thus small for FCAL)
105 * In fact, for the FCAL, delta_m is ~25 MeV for the eta mass when the z_error is 30cm (max: center of target + detached vertex)
106 * Therefore, if the center of the target is used, the error is negligible compared to the width of the mass cut.
107 *
108 * For the BCAL:
109 * With m_g near eta mass, z_error = 15: delta_m_max = ~60 MeV
110 * With m_g near eta mass, z_error = 10: delta_m_max = ~40 MeV
111 * With m_g near eta mass, z_error = 5: delta_m_max = ~20 MeV
112 * With m_g near eta mass, z_error = 3: delta_m_max = ~15 MeV
113 * With m_g near eta mass, z_error = 2: delta_m_max = ~9 MeV
114 * Instead of the above, you can of course plot the delta_m for real data, and get something similar
115 * So, choose a z_error of 5: compute at center of 10-cm-wide bins.
116 *
117 * OK, but what about eta -> 3pi0? Or Lambda -> pi0, n?
118 * eta -> 3pi0: Max error for a given pi0 is ~small, not bad when combined with 3 others: it's fine as long as cut is wide.
119 * pi0, n: Neutron is likely slow, similar to charged tracks: Error is much larger, cannot combo massive neutrals without exact vertex position
120 * Well, OK, we can COMBO them, but we can't place mass cuts.
121 *
122 *******************************************************************************************************************************/
123 
124 
125 namespace DAnalysis
126 {
127 
129 {
130  //INVARIANT MASS CUTS: MESONS
131  dInvariantMassCuts.emplace(Pi0, std::make_pair(0.08, 0.19));
132  dInvariantMassCuts.emplace(KShort, std::make_pair(0.3, 0.7));
133  dInvariantMassCuts.emplace(Eta, std::make_pair(0.35, 0.75));
134  dInvariantMassCuts.emplace(omega, std::make_pair(0.4, 1.2));
135  dInvariantMassCuts.emplace(EtaPrime, std::make_pair(0.6, 1.3));
136  dInvariantMassCuts.emplace(phiMeson, std::make_pair(0.8, 1.2));
137  dInvariantMassCuts.emplace(D0, std::make_pair(1.8, 1.92));
138  dInvariantMassCuts.emplace(AntiD0, std::make_pair(1.8, 1.92));
139 // dInvariantMassCuts.emplace(Jpsi, std::make_pair(2.7, 3.5));
140 
141  //INVARIANT MASS CUTS: BARYONS
142  dInvariantMassCuts.emplace(Lambda, std::make_pair(1.0, 1.2));
144  dInvariantMassCuts.emplace(Sigma0, std::make_pair(1.1, 1.3));
147  dInvariantMassCuts.emplace(XiMinus, std::make_pair(1.1, 1.5));
149  dInvariantMassCuts.emplace(OmegaMinus, std::make_pair(1.32, 2.22));
150  dInvariantMassCuts.emplace(Lambda_c, std::make_pair(2.0, 2.6));
151 
152 
153  //DEFAULT MISSING MASS SQUARED CUT FUNCTION
155  //DEFINE FUNCTIONS STRINGS FOR PARTICLES THAT ARE NOT THE DEFAULT HERE (in dMissingMassSquaredCuts_TF1FunctionStrings)
156 
157 
158  //DEFAULT MISSING MASS SQUARED CUT VALUES //vs p
159  //pair of vectors: params for low bound, high bound
160 
161  //Unknown: None missing
162  dMissingMassSquaredCuts_TF1Params[Unknown] = std::make_pair(vector<double>{-0.1}, vector<double>{0.1});
163 
164  //Photon
166 
167  //e+/-
168  dMissingMassSquaredCuts_TF1Params[Electron] = std::make_pair(vector<double>{-1.0}, vector<double>{1.0});
170 
171  //pi+/-/0
172  dMissingMassSquaredCuts_TF1Params[PiPlus] = std::make_pair(vector<double>{-1.0}, vector<double>{1.0});
175 
176  //K+/-/S/L
177  dMissingMassSquaredCuts_TF1Params[KPlus] = std::make_pair(vector<double>{-1.0}, vector<double>{2.0});
181 
182  //p/n
183  dMissingMassSquaredCuts_TF1Params[Proton] = std::make_pair(vector<double>{-0.5}, vector<double>{4.41});
185 
186 
187  //DEFAULT MISSING ENERGY CUT //Only applied if nothing is missing
190  dMissingEnergyCuts_TF1Params = std::make_pair(vector<double>{-3.0}, vector<double>{3.0}); //pair: low bound, high bound
191 }
192 
194 {
195  //PARAM EXAMPLES:
196 
197  //Cut missing mass squared of protons (14) from -0.7 to 3.7 (GeV/c^2)^2
198  //COMBO_MM2CUT:Low_14=-0.7
199  //COMBO_MM2CUT:High_14=3.7
200 
201  //Change the cut functions //is function of beam energy
202  //COMBO_MM2CUT:Low_14_FUNC="[0] + [1]*x"
203  //COMBO_MM2CUT:High_14_FUNC="[0] + [1]*x"
204 
205  //Cut missing mass squared of protons (14) with params matching above functional form (GeV/c^2)^2
206  //COMBO_MM2CUT:Low_14=-0.7_-0.001
207  //COMBO_MM2CUT:High_14=3.7_0.001
208 
209  map<string, string> locParameterMap; //parameter key - filter, value
210  gPARMS->GetParameters(locParameterMap, "COMBO_MM2CUT:"); //gets all parameters with this filter at the beginning of the key
211  for(auto locParamPair : locParameterMap)
212  {
213  if(dDebugLevel)
214  cout << "param pair: " << locParamPair.first << ", " << locParamPair.second << endl;
215 
216  //High or low cut?
217  auto locUnderscoreIndex = locParamPair.first.find('_');
218  auto locSideString = locParamPair.first.substr(0, locUnderscoreIndex);
219  auto locHighSideFlag = (locSideString == "Low") ? false : true;
220 
221  //Figure out which particle was specified
222  auto locFuncIndex = locParamPair.first.find("_FUNC");
223  auto locParticleString = locParamPair.first.substr(locUnderscoreIndex + 1, locFuncIndex);
224  istringstream locPIDtream(locParticleString);
225  int locPIDInt;
226  locPIDtream >> locPIDInt;
227  if(locPIDtream.fail())
228  continue;
229  Particle_t locPID = (Particle_t)locPIDInt;
230 
231  if(dDebugLevel)
232  cout << "mm2 cut: pid, side = " << locPID << ", " << locSideString << endl;
233 
234  //get the parameter, with hack so that don't get warning message about no default
235  string locKeyValue;
236  string locFullParamName = string("COMBO_MM2CUT:") + locParamPair.first; //have to add back on the filter
237  gPARMS->SetDefaultParameter(locFullParamName, locKeyValue);
238 
239  //If functional form, save it and continue
240  if(locFuncIndex != string::npos)
241  {
242  if(!locHighSideFlag)
243  dMissingMassSquaredCuts_TF1FunctionStrings[locPID].first = locKeyValue;
244  else
245  dMissingMassSquaredCuts_TF1FunctionStrings[locPID].second = locKeyValue;
246  continue;
247  }
248 
249  //is cut parameters: extract and save
250  //CUT PARAMETERS SHOULD BE SEPARATED BY SPACES
251  if(!locHighSideFlag)
252  dMissingMassSquaredCuts_TF1Params[locPID].first.clear(); //get rid of previous cut values
253  else
254  dMissingMassSquaredCuts_TF1Params[locPID].second.clear(); //get rid of previous cut values
255  while(true)
256  {
257  locUnderscoreIndex = locKeyValue.find('_');
258  auto locValueString = locKeyValue.substr(0, locUnderscoreIndex);
259 
260  istringstream locValuetream(locValueString);
261  double locParameter;
262  locValuetream >> locParameter;
263  if(locValuetream.fail())
264  continue; //must be for a different use
265  if(dDebugLevel)
266  cout << "param: " << locParameter << endl;
267 
268  //save locParameter and truncate locKeyValue (or break if done)
269  if(!locHighSideFlag)
270  dMissingMassSquaredCuts_TF1Params[locPID].first.push_back(locParameter);
271  else
272  dMissingMassSquaredCuts_TF1Params[locPID].second.push_back(locParameter);
273  if(locUnderscoreIndex == string::npos)
274  break;
275  locKeyValue = locKeyValue.substr(locUnderscoreIndex + 1);
276  }
277  }
278 }
279 
281 {
282  //PARAM EXAMPLES:
283 
284  //Cut invariant mass of pi0s (7) from 0.05 to 0.3 (GeV/c^2)
285  //COMBO_IMCUT:Low_7=0.05
286  //COMBO_IMCUT:High_7=0.3
287 
288  map<string, string> locParameterMap; //parameter key - filter, value
289  gPARMS->GetParameters(locParameterMap, "COMBO_IMCUT:"); //gets all parameters with this filter at the beginning of the key
290  for(auto locParamPair : locParameterMap)
291  {
292  if(dDebugLevel)
293  cout << "param pair: " << locParamPair.first << ", " << locParamPair.second << endl;
294 
295  //High or low cut?
296  auto locUnderscoreIndex = locParamPair.first.find('_');
297  auto locSideString = locParamPair.first.substr(0, locUnderscoreIndex);
298  auto locHighSideFlag = (locSideString == "Low") ? false : true;
299 
300  //Figure out which particle was specified
301  auto locParticleString = locParamPair.first.substr(locUnderscoreIndex + 1);
302  istringstream locPIDtream(locParticleString);
303  int locPIDInt;
304  locPIDtream >> locPIDInt;
305  if(locPIDtream.fail())
306  continue;
307  Particle_t locPID = (Particle_t)locPIDInt;
308 
309  if(dDebugLevel)
310  cout << "im cut: pid, side = " << locPID << ", " << locSideString << endl;
311 
312  //get the parameter, with hack so that don't get warning message about no default
313  string locKeyValue;
314  string locFullParamName = string("COMBO_IMCUT:") + locParamPair.first; //have to add back on the filter
315  gPARMS->SetDefaultParameter(locFullParamName, locKeyValue);
316 
317  //is cut parameter: extract and save
318  istringstream locValuetream(locKeyValue);
319  double locParameter;
320  locValuetream >> locParameter;
321  if(locValuetream.fail())
322  continue; //must be for a different use
323  if(dDebugLevel)
324  cout << "param: " << locParameter << endl;
325 
326  //save locParameter and truncate locKeyValue (or break if done)
327  if(!locHighSideFlag)
328  dInvariantMassCuts[locPID].first = locParameter;
329  else
330  dInvariantMassCuts[locPID].second = locParameter;
331  }
332 
333  //Print cuts
334  if(!dPrintCutFlag)
335  return;
336 
337  for(auto& locPIDPair : dInvariantMassCuts)
338  jout << "Invariant mass cut: pid, low cut, high cut = " << locPIDPair.first << ", " << locPIDPair.second.first << ", " << locPIDPair.second.second << endl;
339 }
340 
342 {
343  //PARAM EXAMPLES:
344 
345  //Cut missing energy (if none missing) from -0.7 to 3.7 (GeV)
346  //COMBO_MISSECUT:Low=-0.7
347  //COMBO_MISSECUT:High=3.7
348 
349  //Change the cut functions //is function of beam energy
350  //COMBO_MISSECUT:Low_FUNC="[0] + [1]*x"
351  //COMBO_MISSECUT:High_FUNC="[0] + [1]*x"
352 
353  //Cut missing energy (if none missing) with params matching above functional form (GeV/c^2)^2
354  //COMBO_MISSECUT:Low=-0.7_-0.001
355  //COMBO_MISSECUT:High=3.7_0.001
356 
357  map<string, string> locParameterMap; //parameter key - filter, value
358  gPARMS->GetParameters(locParameterMap, "COMBO_MISSECUT:"); //gets all parameters with this filter at the beginning of the key
359  for(auto locParamPair : locParameterMap)
360  {
361  if(dDebugLevel)
362  cout << "param pair: " << locParamPair.first << ", " << locParamPair.second << endl;
363 
364  //High or low cut?
365  auto locUnderscoreIndex = locParamPair.first.find('_');
366  auto locSideString = locParamPair.first.substr(0, locUnderscoreIndex);
367  auto locHighSideFlag = (locSideString == "Low") ? false : true;
368  if(dDebugLevel)
369  cout << "missE cut: side = " << locSideString << endl;
370 
371  //get the parameter, with hack so that don't get warning message about no default
372  string locKeyValue;
373  string locFullParamName = string("COMBO_MISSECUT:") + locParamPair.first; //have to add back on the filter
374  gPARMS->SetDefaultParameter(locFullParamName, locKeyValue);
375 
376  //If functional form, save it and continue
377  auto locFuncIndex = locParamPair.first.find("_FUNC");
378  if(locFuncIndex != string::npos)
379  {
380  if(!locHighSideFlag)
381  dMissingEnergyCuts_TF1FunctionStrings.first = locKeyValue;
382  else
383  dMissingEnergyCuts_TF1FunctionStrings.second = locKeyValue;
384  continue;
385  }
386 
387  //is cut parameters: extract and save
388  //CUT PARAMETERS SHOULD BE SEPARATED BY SPACES
389  if(!locHighSideFlag)
390  dMissingEnergyCuts_TF1Params.first.clear(); //get rid of previous cut values
391  else
392  dMissingEnergyCuts_TF1Params.second.clear(); //get rid of previous cut values
393  while(true)
394  {
395  locUnderscoreIndex = locKeyValue.find('_');
396  auto locValueString = locKeyValue.substr(0, locUnderscoreIndex);
397 
398  istringstream locValuetream(locValueString);
399  double locParameter;
400  locValuetream >> locParameter;
401  if(locValuetream.fail())
402  continue; //must be for a different use
403  if(dDebugLevel)
404  cout << "param: " << locParameter << endl;
405 
406  //save locParameter and truncate locKeyValue (or break if done)
407  if(!locHighSideFlag)
408  dMissingEnergyCuts_TF1Params.first.push_back(locParameter);
409  else
410  dMissingEnergyCuts_TF1Params.second.push_back(locParameter);
411  if(locUnderscoreIndex == string::npos)
412  break;
413  locKeyValue = locKeyValue.substr(locUnderscoreIndex + 1);
414  }
415  }
416 }
417 
419 {
420  //No idea why this lock is necessary, but it crashes without it. Stupid ROOT.
421  japp->RootWriteLock(); //ACQUIRE ROOT LOCK!!
422 
423  //Missing mass squared
424  for(auto& locPIDPair : dMissingMassSquaredCuts_TF1Params)
425  {
426  auto& locParamVector_Low = locPIDPair.second.first;
427  auto& locParamVector_High = locPIDPair.second.second;
428  if(locParamVector_Low.empty() || locParamVector_High.empty())
429  continue; //should never happen
430 
431  //Get cut strings
432  auto locCutFuncString_Low = dDefaultMissingMassSquaredCutFunctionString; //default if nothing special specified
433  auto locCutFuncString_High = dDefaultMissingMassSquaredCutFunctionString; //default if nothing special specified
435  {
436  locCutFuncString_Low = dMissingMassSquaredCuts_TF1FunctionStrings[locPIDPair.first].first;
437  locCutFuncString_High = dMissingMassSquaredCuts_TF1FunctionStrings[locPIDPair.first].second;
438  }
439 
440  //Create TF1, Set cut values
441  //These functions can have the same name because we are no longer adding them to the global ROOT list of functions
442 
443  //low-side
444  auto locFunc_Low = new TF1("df_MissingMassSquaredCut", locCutFuncString_Low.c_str(), 0.0, 12.0);
445  if(dPrintCutFlag)
446  jout << "Missing Mass Squared Cut, Low-side: PID, func form, params: " << ParticleType(locPIDPair.first) << ", " << locCutFuncString_Low;
447  for(size_t loc_i = 0; loc_i < locParamVector_Low.size(); ++loc_i)
448  {
449  locFunc_Low->SetParameter(loc_i, locParamVector_Low[loc_i]);
450  if(dPrintCutFlag)
451  jout << ", " << locParamVector_Low[loc_i];
452  }
453  if(dPrintCutFlag)
454  jout << endl;
455 
456  //High-side
457  auto locFunc_High = new TF1("df_MissingMassSquaredCut", locCutFuncString_High.c_str(), 0.0, 12.0);
458  if(dPrintCutFlag)
459  jout << "Missing Mass Squared Cut, High-side: PID, func form, params: " << ParticleType(locPIDPair.first) << ", " << locCutFuncString_High;
460  for(size_t loc_i = 0; loc_i < locParamVector_High.size(); ++loc_i)
461  {
462  locFunc_High->SetParameter(loc_i, locParamVector_High[loc_i]);
463  if(dPrintCutFlag)
464  jout << ", " << locParamVector_High[loc_i];
465  }
466  if(dPrintCutFlag)
467  jout << endl;
468 
469  dMissingMassSquaredCuts[locPIDPair.first] = std::make_pair(locFunc_Low, locFunc_High);
470  }
471 
472  //Missing beam energy
473  //Get cut strings
474  auto locCutFuncString_Low = dMissingEnergyCuts_TF1FunctionStrings.first; //default if nothing special specified
475  auto locCutFuncString_High = dMissingEnergyCuts_TF1FunctionStrings.second; //default if nothing special specified
476 
477  //low-side
478  auto locFunc_Low = new TF1("df_MissingBeamEnergyCut", locCutFuncString_Low.c_str(), 0.0, 12.0);
479  if(dPrintCutFlag)
480  jout << "Missing Energy Cut (none-missing only), Low-side: func form, params: " << locCutFuncString_Low;
481  for(size_t loc_i = 0; loc_i < dMissingEnergyCuts_TF1Params.first.size(); ++loc_i)
482  {
483  locFunc_Low->SetParameter(loc_i, dMissingEnergyCuts_TF1Params.first[loc_i]);
484  if(dPrintCutFlag)
485  jout << ", " << dMissingEnergyCuts_TF1Params.first[loc_i];
486  }
487  if(dPrintCutFlag)
488  jout << endl;
489 
490  //High-side
491  auto locFunc_High = new TF1("df_MissingBeamEnergyCut", locCutFuncString_High.c_str(), 0.0, 12.0);
492  if(dPrintCutFlag)
493  jout << "Missing Energy Cut (none-missing only), High-side: func form, params: " << locCutFuncString_High;
494  for(size_t loc_i = 0; loc_i < dMissingEnergyCuts_TF1Params.second.size(); ++loc_i)
495  {
496  locFunc_High->SetParameter(loc_i, dMissingEnergyCuts_TF1Params.second[loc_i]);
497  if(dPrintCutFlag)
498  jout << ", " << dMissingEnergyCuts_TF1Params.second[loc_i];
499  }
500  if(dPrintCutFlag)
501  jout << endl;
502 
503  dMissingECuts = std::make_pair(locFunc_Low, locFunc_High);
504 
505  japp->RootUnLock(); //RELEASE ROOT LOCK!!
506 }
507 
508 DSourceComboP4Handler::DSourceComboP4Handler(DSourceComboer* locSourceComboer, bool locCreateHistsFlag) : dSourceComboer(locSourceComboer)
509 {
510  gPARMS->SetDefaultParameter("COMBO:DEBUG_LEVEL", dDebugLevel);
511  gPARMS->SetDefaultParameter("COMBO:PRINT_CUTS", dPrintCutFlag);
512  gPARMS->SetDefaultParameter("COMBO:MAX_MASSIVE_NEUTRAL_BETA", dMaxMassiveNeutralBeta);
513 
519 
520  if(!locCreateHistsFlag)
521  return;
522 
523  //MISSING MASS CUTS & MASS HISTOGRAMS
524  japp->RootWriteLock(); //ACQUIRE ROOT LOCK!! //I have no idea why this is needed (for the cuts), but without it it crashes. Sigh.
525  {
526  //HISTOGRAMS
527  //get and change to the base (file/global) directory
528  TDirectory* locCurrentDir = gDirectory;
529 
530  string locDirName = "Independent";
531  TDirectoryFile* locDirectoryFile = static_cast<TDirectoryFile*>(gDirectory->GetDirectory(locDirName.c_str()));
532  if(locDirectoryFile == NULL)
533  locDirectoryFile = new TDirectoryFile(locDirName.c_str(), locDirName.c_str());
534  locDirectoryFile->cd();
535 
536  locDirName = "Combo_Construction";
537  locDirectoryFile = static_cast<TDirectoryFile*>(gDirectory->GetDirectory(locDirName.c_str()));
538  if(locDirectoryFile == NULL)
539  locDirectoryFile = new TDirectoryFile(locDirName.c_str(), locDirName.c_str());
540  locDirectoryFile->cd();
541 
542  locDirName = "Invariant_Mass";
543  locDirectoryFile = static_cast<TDirectoryFile*>(gDirectory->GetDirectory(locDirName.c_str()));
544  if(locDirectoryFile == NULL)
545  locDirectoryFile = new TDirectoryFile(locDirName.c_str(), locDirName.c_str());
546  locDirectoryFile->cd();
547 
548  //INVARIANT MASS HISTOGRAMS: 2GAMMA
549  {
550  string locHistName = "InvariantMass_2Gamma_BCAL";
551  auto locHist = gDirectory->Get(locHistName.c_str());
552  dHistMap_2GammaMass[SYS_BCAL] = (locHist != nullptr) ? static_cast<TH1*>(locHist) : new TH1I(locHistName.c_str(), ";BCAL 2#gamma Invariant Mass (GeV/c^{2})", 2000, 0.0, 2.0);
553 
554  locHistName = "InvariantMass_2Gamma_FCAL";
555  locHist = gDirectory->Get(locHistName.c_str());
556  dHistMap_2GammaMass[SYS_FCAL] = (locHist != nullptr) ? static_cast<TH1*>(locHist) : new TH1I(locHistName.c_str(), ";FCAL 2#gamma Invariant Mass (GeV/c^{2})", 2000, 0.0, 2.0);
557 
558  locHistName = "InvariantMass_2Gamma_BCALFCAL";
559  locHist = gDirectory->Get(locHistName.c_str());
560  dHistMap_2GammaMass[SYS_NULL] = (locHist != nullptr) ? static_cast<TH1*>(locHist) : new TH1I(locHistName.c_str(), ";BCAL/FCAL 2#gamma Invariant Mass (GeV/c^{2})", 2000, 0.0, 2.0);
561  }
562 
563  //INVARIANT MASS HISTOGRAMS: PIDS
564  for(const auto& locPIDPair : dInvariantMassCuts)
565  {
566  auto locPID = locPIDPair.first;
567  auto& locMassPair = locPIDPair.second;
568  string locHistName = string("InvariantMass_") + ParticleType(locPID);
569  auto locHist = gDirectory->Get(locHistName.c_str());
570  if(locHist == nullptr)
571  {
572  string locHistTitle = string("From All Decay Products;") + string(ParticleName_ROOT(locPID)) + string(" Invariant Mass (GeV/c^{2})");
573  auto locMinMass = locMassPair.first - 0.2;
574  if(locMinMass < 0.0)
575  locMinMass = 0.0;
576  auto locMaxMass = locMassPair.second + 0.2;
577  auto locNumBins = 1000.0*(locMaxMass - locMinMass);
578  dHistMap_InvariantMass[locPID] = new TH1I(locHistName.c_str(), locHistTitle.c_str(), locNumBins, locMinMass, locMaxMass);
579  }
580  else
581  dHistMap_InvariantMass[locPID] = static_cast<TH1*>(locHist);
582  }
583  gDirectory->cd("..");
584 
585  locDirName = "Missing_Mass";
586  locDirectoryFile = static_cast<TDirectoryFile*>(gDirectory->GetDirectory(locDirName.c_str()));
587  if(locDirectoryFile == NULL)
588  locDirectoryFile = new TDirectoryFile(locDirName.c_str(), locDirName.c_str());
589  locDirectoryFile->cd();
590 
591  //MISSING MASS HISTOGRAMS
592  for(const auto& locPIDPair : dMissingMassSquaredCuts)
593  {
594  auto locPID = locPIDPair.first;
595  auto& locMassPair = locPIDPair.second;
596  string locHistName = string("MissingMassVsBeamEnergy_") + ((locPID != Unknown) ? ParticleType(locPID) : "None");
597  auto locHist = gDirectory->Get(locHistName.c_str());
598  if(locHist == nullptr)
599  {
600  string locHistTitle = string("From All Production Mechanisms;Beam Energy (GeV);") + string((locPID != Unknown) ? ParticleName_ROOT(locPID) : "None") + string(" Missing Mass Squared (GeV/c^{2})^{2}");
601  auto locMinMass = locMassPair.first->Eval(12.0) - 0.2; //assume widest at highest energy
602  auto locMaxMass = locMassPair.second->Eval(12.0) + 0.2;
603  auto locNumBins = 1000.0*(locMaxMass - locMinMass);
604  dHistMap_MissingMassSquaredVsBeamEnergy[locPID] = new TH2I(locHistName.c_str(), locHistTitle.c_str(), 600, 0.0, 12.0, locNumBins, locMinMass, locMaxMass);
605  }
606  else
607  dHistMap_MissingMassSquaredVsBeamEnergy[locPID] = static_cast<TH2*>(locHist);
608  }
609 
610  //NONE MISSING, MISSING E:
611  {
612  string locHistName = "NoneMissing_MissingEVsBeamEnergy_PreMissMassSqCut";
613  auto locHist = gDirectory->Get(locHistName.c_str());
614  if(locHist == nullptr)
615  {
616  string locHistTitle = string("None Missing: From All Production Mechanisms;Beam Energy (GeV); Missing E (GeV)");
617  dHist_NoneMissing_MissingEVsBeamEnergy_PreMissMassSqCut = new TH2I(locHistName.c_str(), locHistTitle.c_str(), 600, 0.0, 12.0, 1200, -6.0, 6.0);
618  }
619  else
621 
622  locHistName = "NoneMissing_MissingEVsBeamEnergy_PostMissMassSqCut";
623  locHist = gDirectory->Get(locHistName.c_str());
624  if(locHist == nullptr)
625  {
626  string locHistTitle = string("None Missing: From All Production Mechanisms;Beam Energy (GeV); Missing E (GeV)");
627  dHist_NoneMissing_MissingEVsBeamEnergy_PostMissMassSqCut = new TH2I(locHistName.c_str(), locHistTitle.c_str(), 600, 0.0, 12.0, 1200, -6.0, 6.0);
628  }
629  else
631  }
632 
633  //NONE MISSING, MISSING PT:
634  {
635  string locHistName = "NoneMissing_MissingPtVsMissingE_PreMissMassSqCut";
636  auto locHist = gDirectory->Get(locHistName.c_str());
637  if(locHist == nullptr)
638  {
639  string locHistTitle = string("None Missing: From All Production Mechanisms; Missing E (GeV); Missing Transverse Momentum (GeV/c)");
640  dHist_NoneMissing_MissingPtVsMissingE_PreMissMassSqCut = new TH2I(locHistName.c_str(), locHistTitle.c_str(), 1200, -6.0, 6.0, 800, 0.0, 4.0);
641  }
642  else
644 
645  locHistName = "NoneMissing_MissingPtVsMissingE_PostMissMassSqCut";
646  locHist = gDirectory->Get(locHistName.c_str());
647  if(locHist == nullptr)
648  {
649  string locHistTitle = string("None Missing: From All Production Mechanisms; Missing E (GeV); Missing Transverse Momentum (GeV/c)");
650  dHist_NoneMissing_MissingPtVsMissingE_PostMissMassSqCut = new TH2I(locHistName.c_str(), locHistTitle.c_str(), 1200, -6.0, 6.0, 600, 0.0, 3.0);
651  }
652  else
654  }
655 
656  locCurrentDir->cd();
657  }
658  japp->RootUnLock(); //RELEASE ROOT LOCK!!
659 }
660 
661 DLorentzVector DSourceComboP4Handler::Get_P4_NotMassiveNeutral(Particle_t locPID, const JObject* locObject, const DVector3& locVertex, bool locAccuratePhotonsFlag) const
662 {
663  if(ParticleCharge(locPID) != 0)
664  return static_cast<const DChargedTrack*>(locObject)->Get_Hypothesis(locPID)->lorentzMomentum();
665 
666  //assume is photon!
667  auto locNeutralShower = static_cast<const DNeutralShower*>(locObject);
668  if(!locAccuratePhotonsFlag)
669  {
670  signed char locVertexZBin = DSourceComboInfo::Get_VertexZIndex_ZIndependent();
671  if(locNeutralShower->dDetectorSystem == SYS_BCAL)
672  locVertexZBin = dSourceComboTimeHandler->Get_PhotonVertexZBin(locVertex.Z());
673  if(locVertexZBin == DSourceComboInfo::Get_VertexZIndex_OutOfRange())
674  locVertexZBin = dSourceComboTimeHandler->Get_VertexZBin_TargetCenter(); //we need a zbin for BCAL showers, but it is unknown: we must pick something: center of target
675  auto& locKinematicData = dPhotonKinematics.find(locVertexZBin)->second.find(locNeutralShower)->second;
676  return locKinematicData->lorentzMomentum();
677  }
678 
679  //vertex is known: calculate exactly
680  auto locMomentum = locNeutralShower->dEnergy*((locNeutralShower->dSpacetimeVertex.Vect() - locVertex).Unit());
681  return DLorentzVector(locMomentum, locNeutralShower->dEnergy);
682 }
683 
684 DLorentzVector DSourceComboP4Handler::Calc_MassiveNeutralP4(const DNeutralShower* locNeutralShower, Particle_t locPID, const DVector3& locVertex, double locRFVertexTime) const
685 {
686  //locRFVertexTime: the RF time propagated to the vertex, through any decaying particles if necessary
687  auto locMass = ParticleMass(locPID);
688  auto locPath = locNeutralShower->dSpacetimeVertex.Vect() - locVertex;
689  auto locPathMag = locPath.Mag();
690  double locDeltaT = locNeutralShower->dSpacetimeVertex.T() - locRFVertexTime;
691 
692  double locBeta = locPathMag/(locDeltaT*29.9792458);
693  if(locBeta >= 1.0)
694  locBeta = dMaxMassiveNeutralBeta;
695  if(locBeta < 0.0)
696  locBeta = 0.0;
697 
698  auto locGamma = 1.0/sqrt(1.0 - locBeta*locBeta);
699  auto locPMag = locGamma*locBeta*locMass;
700  locPath.SetMag(locPMag); //is now the momentum!
701 
702  if(dDebugLevel >= 20)
703  cout << "Calc_MassiveNeutralP4: pid, mass, shower-z, vertex-z, path, shower t, rf t, delta-t, beta, pmag = " << locPID << ", " << locMass << ", " << locNeutralShower->dSpacetimeVertex.Vect().Z() << ", " << locVertex.Z() << ", " << locPathMag << ", " << locNeutralShower->dSpacetimeVertex.T() << ", " << locRFVertexTime << ", " << locDeltaT << ", " << locBeta << ", " << locPMag << endl;
704 
705  auto locEnergy = sqrt(locPMag*locPMag + locMass*locMass);
706  return DLorentzVector(locPath, locEnergy);
707 }
708 
709 DLorentzVector DSourceComboP4Handler::Calc_P4_NoMassiveNeutrals(const DSourceCombo* locReactionCombo, const DSourceCombo* locVertexCombo, const DVector3& locVertex, signed char locVertexZBin, const DKinematicData* locBeamParticle, const DSourceComboUse& locToExcludeUse, size_t locInstanceToExclude, bool locAccuratePhotonsFlag)
710 {
711  //locVertexZBin MUST be a separate argument, to signal special bins!!!
712  if(!locVertexCombo->Get_IsComboingZIndependent() && ((locVertexZBin == DSourceComboInfo::Get_VertexZIndex_Unknown()) || (locVertexZBin == DSourceComboInfo::Get_VertexZIndex_OutOfRange())))
713  locVertexZBin = dSourceComboTimeHandler->Get_VertexZBin_TargetCenter(); //we need a zbin for BCAL showers, but it is unknown: we must pick something: center of target
714 
715  auto locHasPhotons = !DAnalysis::Get_SourceParticles(locVertexCombo->Get_SourceParticles(true, d_Neutral), Gamma).empty();
716  auto locIterator = (locHasPhotons && locAccuratePhotonsFlag) ? dFinalStateP4ByCombo.end() : dFinalStateP4ByCombo.find(std::make_pair(locVertexCombo, locVertexZBin));
717  if(locIterator != dFinalStateP4ByCombo.end())
718  {
719  if(dDebugLevel >= 10)
720  cout << "Read Calc_P4_NoMassiveNeutrals: Combo " << locVertexCombo << " P4: " << locIterator->second.Px() << ", " << locIterator->second.Py() << ", " << locIterator->second.Pz() << ", " << locIterator->second.E() << endl;
721  return locIterator->second;
722  }
723 
724  //loop over particles
725  //vertex-z bin may be different for decay products! (detached vertex)
726  //save/retrieve masses by combo instead
727  DLorentzVector locTotalP4 = Calc_P4_SourceParticles(locVertexCombo, locVertex, 0.0, locAccuratePhotonsFlag);
728 
729  //loop over decays
730  auto locFurtherDecayCombos = locVertexCombo->Get_FurtherDecayCombos();
731  for(const auto& locCombosByUsePair : locFurtherDecayCombos)
732  {
733  auto locDetachedVertexFlag = IsDetachedVertex(std::get<0>(locCombosByUsePair.first));
734  auto locDecayVertexZBin = std::get<1>(locCombosByUsePair.first);
735  for(size_t loc_i = 0; loc_i < locCombosByUsePair.second.size(); ++loc_i)
736  {
737  const auto& locCombo = (locCombosByUsePair.second)[loc_i];
738  if((locCombosByUsePair.first == locToExcludeUse) && ((loc_i + 1) == locInstanceToExclude))
739  continue;
740  //2nd false: either during charged-only stage, and vertex doesn't matter, or on neutral stage, and is-2nd-combo-use flag is false: just use false
741  auto locIsVertexKnown = dSourceComboVertexer->Get_IsVertexKnown(false, locReactionCombo, locCombo, locBeamParticle, false); //1st false: will be detached if needed
742  auto locDecayVertex = (locDetachedVertexFlag && locIsVertexKnown) ? dSourceComboVertexer->Get_Vertex(false, locReactionCombo, locCombo, locBeamParticle, false) : locVertex;
743  locTotalP4 += Calc_P4_NoMassiveNeutrals(locReactionCombo, locCombo, locDecayVertex, locDecayVertexZBin, locBeamParticle, locToExcludeUse, locInstanceToExclude, locAccuratePhotonsFlag);
744  }
745 
746  //Subtract target p4 if necessary (e.g. Lambda, p -> p, p, pi-)
747  auto locTargetPIDToSubtract = std::get<4>(locCombosByUsePair.first);
748  if(locTargetPIDToSubtract != Unknown)
749  locTotalP4 -= DLorentzVector(TVector3(), ParticleMass(locTargetPIDToSubtract));
750  }
751 
752  //save the results and return
753  if(!locAccuratePhotonsFlag || !locHasPhotons)
754  dFinalStateP4ByCombo.emplace(std::make_pair(locVertexCombo, locVertexZBin), locTotalP4);
755 
756  if(!locAccuratePhotonsFlag)
757  {
758  auto locSourceParticles = locVertexCombo->Get_SourceParticles();
759  if((locSourceParticles.size() == 2) && (locSourceParticles[0].first == Gamma) && (locSourceParticles[1].first == Gamma))
760  {
761  auto locSystem1 = static_cast<const DNeutralShower*>(locSourceParticles[0].second)->dDetectorSystem;
762  auto locSystem2 = static_cast<const DNeutralShower*>(locSourceParticles[1].second)->dDetectorSystem;
763  auto locSystem = (locSystem1 != locSystem2) ? SYS_NULL : locSystem1;
764  d2GammaInvariantMasses[locSystem].push_back(locTotalP4.M());
765  }
766  }
767 
768  if(dDebugLevel >= 10)
769  cout << "Save Calc_P4_NoMassiveNeutrals: Combo " << locVertexCombo << " P4: " << locTotalP4.Px() << ", " << locTotalP4.Py() << ", " << locTotalP4.Pz() << ", " << locTotalP4.E() << endl;
770  return locTotalP4;
771 }
772 
773 DLorentzVector DSourceComboP4Handler::Calc_P4_SourceParticles(const DSourceCombo* locVertexCombo, const DVector3& locVertex, double locRFVertexTime, bool locAccuratePhotonsFlag)
774 {
775  //z-bin is kept separate from locVertex because it may indicate special values, or the vertex may not be known yet
776  DLorentzVector locTotalP4(0.0, 0.0, 0.0, 0.0);
777  auto locSourceParticles = locVertexCombo->Get_SourceParticles(false); //false: NOT the whole chain
778  for(const auto& locParticlePair : locSourceParticles)
779  {
780  auto locPID = locParticlePair.first;
781  if((ParticleCharge(locPID) == 0) && (ParticleMass(locPID) > 0.0))
782  {
783  auto locNeutralShower = static_cast<const DNeutralShower*>(locParticlePair.second);
784  auto locParticleP4 = Calc_MassiveNeutralP4(locNeutralShower, locPID, locVertex, locRFVertexTime);
785  if(dDebugLevel >= 20)
786  cout << "pid, pointer, pxyzE = " << locPID << ", " << locParticlePair.second << ", " << locParticleP4.Px() << ", " << locParticleP4.Py() << ", " << locParticleP4.Pz() << ", " << locParticleP4.E() << endl;
787  locTotalP4 += locParticleP4;
788  }
789  else
790  {
791  auto locParticleP4 = Get_P4_NotMassiveNeutral(locParticlePair.first, locParticlePair.second, locVertex, locAccuratePhotonsFlag);
792  if(dDebugLevel >= 20)
793  cout << "pid, pointer, pxyzE = " << locPID << ", " << locParticlePair.second << ", " << locParticleP4.Px() << ", " << locParticleP4.Py() << ", " << locParticleP4.Pz() << ", " << locParticleP4.E() << endl;
794  locTotalP4 += locParticleP4;
795  }
796  }
797 
798  if(dDebugLevel >= 10)
799  cout << "Calc_P4_SourceParticles: Combo " << locVertexCombo << " P4: " << locTotalP4.Px() << ", " << locTotalP4.Py() << ", " << locTotalP4.Pz() << ", " << locTotalP4.E() << endl;
800 
801  return locTotalP4;
802 }
803 
804 bool DSourceComboP4Handler::Calc_P4_Decay(bool locIsProductionVertex, bool locIsPrimaryProductionVertex, const DSourceCombo* locReactionFullCombo, const DSourceComboUse& locDecayUse, const DSourceCombo* locDecayCombo, DVector3 locVertex, double locTimeOffset, int locRFBunch, double locRFVertexTime, DLorentzVector& locDecayP4, const DKinematicData* locBeamParticle, const DSourceComboUse& locToExcludeUse, size_t locInstanceToExclude, bool locAccuratePhotonsFlag)
805 {
806  auto locDecayPID = std::get<0>(locDecayUse);
807  auto locDecayVertexZBin = std::get<1>(locDecayUse);
808  auto locHasMassiveNeutrals = dSourceComboer->Get_HasMassiveNeutrals(std::get<2>(locDecayUse));
809 
810  locDecayP4 = DLorentzVector(0.0, 0.0, 0.0, 0.0);
811  if(!IsDetachedVertex(locDecayPID))
812  {
813  if(!locHasMassiveNeutrals)
814  locDecayP4 = Calc_P4_NoMassiveNeutrals(locReactionFullCombo, locDecayCombo, locVertex, locDecayVertexZBin, locBeamParticle, locToExcludeUse, locInstanceToExclude, locAccuratePhotonsFlag);
815  else if(!Calc_P4_HasMassiveNeutrals(locIsProductionVertex, locIsPrimaryProductionVertex, locReactionFullCombo, locDecayCombo, locVertex, locTimeOffset, locRFBunch, locRFVertexTime, locToExcludeUse, locInstanceToExclude, locDecayP4, locBeamParticle, locAccuratePhotonsFlag))
816  return false;
817  if(dDebugLevel >= 10)
818  cout << "Calc_P4_Decay: Combo " << locDecayCombo << " P4: " << locDecayP4.Px() << ", " << locDecayP4.Py() << ", " << locDecayP4.Pz() << ", " << locDecayP4.E() << endl;
819  return true;
820  }
821 
822  //detached vertex!
823  if(!locHasMassiveNeutrals)
824  {
825  if(locAccuratePhotonsFlag)
826  {
827  auto locIsVertexKnown = dSourceComboVertexer->Get_IsVertexKnown(locIsProductionVertex, locReactionFullCombo, locDecayCombo, locBeamParticle, false); //1st false: will be detached if needed
828  locVertex = locIsVertexKnown ? dSourceComboVertexer->Get_Vertex(locIsProductionVertex, locReactionFullCombo, locDecayCombo, locBeamParticle, false) : locVertex;
829  }
830  else
831  locVertex.SetXYZ(0.0, 0.0, dSourceComboTimeHandler->Get_PhotonVertexZBinCenter(locDecayVertexZBin));
832  locDecayP4 = Calc_P4_NoMassiveNeutrals(locReactionFullCombo, locDecayCombo, locVertex, locDecayVertexZBin, locBeamParticle, locToExcludeUse, locInstanceToExclude, locAccuratePhotonsFlag);
833  }
834  else if(!locAccuratePhotonsFlag)
835  {
836  //p4 better have already been calculated: if not, it means it was uncalcable (e.g. vertex unknown)
837  auto locDecayP4LookupTuple = std::make_tuple(locIsProductionVertex, locReactionFullCombo, locDecayCombo, locRFBunch, locBeamParticle, locToExcludeUse, locInstanceToExclude);
838  auto locDecayIterator = dFinalStateP4ByCombo_HasMassiveNeutrals.find(locDecayP4LookupTuple);
839  if(locDecayIterator == dFinalStateP4ByCombo_HasMassiveNeutrals.end())
840  {
841  if(locBeamParticle == nullptr)
842  return false; //failed!
843 
844  //try without beam particle
845  locDecayP4LookupTuple = std::make_tuple(locIsProductionVertex, locReactionFullCombo, locDecayCombo, locRFBunch, (const DKinematicData*)nullptr, locToExcludeUse, locInstanceToExclude);
846  locDecayIterator = dFinalStateP4ByCombo_HasMassiveNeutrals.find(locDecayP4LookupTuple);
847  if(locDecayIterator == dFinalStateP4ByCombo_HasMassiveNeutrals.end())
848  return false; //failed!
849  }
850  locDecayP4 = locDecayIterator->second;
851  }
852  else //recalculate regardless
853  {
854  auto locIsVertexKnown = dSourceComboVertexer->Get_IsVertexKnown(false, locReactionFullCombo, locDecayCombo, locBeamParticle, false); //1st false: will be detached if needed
855  locVertex = locIsVertexKnown ? dSourceComboVertexer->Get_Vertex(false, locReactionFullCombo, locDecayCombo, locBeamParticle, false) : locVertex;
856  auto locIsTimeOffsetKnown = dSourceComboVertexer->Get_IsTimeOffsetKnown(locIsPrimaryProductionVertex, locReactionFullCombo, locDecayCombo, locBeamParticle);
857  locTimeOffset = locIsTimeOffsetKnown ? dSourceComboVertexer->Get_TimeOffset(locIsPrimaryProductionVertex, locReactionFullCombo, locDecayCombo, locBeamParticle) : locTimeOffset;
858 
859  auto locPrimaryVertex = dSourceComboVertexer->Get_Vertex(true, locReactionFullCombo, locReactionFullCombo, locBeamParticle, false);
860  locRFVertexTime = dSourceComboTimeHandler->Calc_PropagatedRFTime(locPrimaryVertex.Z(), locRFBunch, locTimeOffset);
861  if(!Calc_P4_HasMassiveNeutrals(false, locIsPrimaryProductionVertex, locReactionFullCombo, locDecayCombo, locVertex, locTimeOffset, locRFBunch, locRFVertexTime, locToExcludeUse, locInstanceToExclude, locDecayP4, locBeamParticle, locAccuratePhotonsFlag))
862  return false;
863  }
864 
865  if(dDebugLevel >= 10)
866  cout << "Calc_P4_Decay: Combo " << locDecayCombo << " P4: " << locDecayP4.Px() << ", " << locDecayP4.Py() << ", " << locDecayP4.Pz() << ", " << locDecayP4.E() << endl;
867  return true;
868 }
869 
870 bool DSourceComboP4Handler::Calc_P4_HasMassiveNeutrals(bool locIsProductionVertex, bool locIsPrimaryProductionVertex, const DSourceCombo* locReactionFullCombo, const DSourceCombo* locCurrentCombo, DVector3 locVertex, double locTimeOffset, int locRFBunch, double locRFVertexTime, const DSourceComboUse& locToExcludeUse, size_t locInstanceToExclude, DLorentzVector& locTotalP4, const DKinematicData* locBeamParticle, bool locAccuratePhotonsFlag)
871 {
872  auto locP4LookupTuple = std::make_tuple(locIsProductionVertex, locReactionFullCombo, locCurrentCombo, locRFBunch, locBeamParticle, locToExcludeUse, locInstanceToExclude);
873  auto locHasPhotons = !DAnalysis::Get_SourceParticles(locCurrentCombo->Get_SourceParticles(true, d_Neutral), Gamma).empty();
874 
875  if(!locHasPhotons || !locAccuratePhotonsFlag)
876  {
877  auto locIterator = dFinalStateP4ByCombo_HasMassiveNeutrals.find(locP4LookupTuple);
878  if(locIterator != dFinalStateP4ByCombo_HasMassiveNeutrals.end())
879  {
880  locTotalP4 = locIterator->second;
881  if(dDebugLevel >= 10)
882  cout << "Read Calc_P4_HasMassiveNeutrals: Combo " << locCurrentCombo << " P4: " << locTotalP4.Px() << ", " << locTotalP4.Py() << ", " << locTotalP4.Pz() << ", " << locTotalP4.E() << endl;
883  return true;
884  }
885  }
886 
887  //final state particles
888  locTotalP4 = DLorentzVector(0.0, 0.0, 0.0, 0.0);
889  auto locParticlesP4 = Calc_P4_SourceParticles(locCurrentCombo, locVertex, locRFVertexTime, locAccuratePhotonsFlag);
890  if(dDebugLevel >= 20)
891  cout << "combo, source total pxyzE = " << locCurrentCombo << ", " << locParticlesP4.Px() << ", " << locParticlesP4.Py() << ", " << locParticlesP4.Pz() << ", " << locParticlesP4.E() << endl;
892  locTotalP4 += locParticlesP4;
893 
894  //now loop over decays
895  auto locFurtherDecayCombos = locCurrentCombo->Get_FurtherDecayCombos();
896  for(const auto& locCombosByUsePair : locFurtherDecayCombos)
897  {
898  for(size_t loc_i = 0; loc_i < locCombosByUsePair.second.size(); ++loc_i)
899  {
900  const auto& locDecayCombo = (locCombosByUsePair.second)[loc_i];
901  if((locCombosByUsePair.first == locToExcludeUse) && ((loc_i + 1) == locInstanceToExclude))
902  continue;
903 
904  DLorentzVector locDecayP4;
905  if(!Calc_P4_Decay(locIsProductionVertex, locIsPrimaryProductionVertex, locReactionFullCombo, locCombosByUsePair.first, locDecayCombo, locVertex, locTimeOffset, locRFBunch, locRFVertexTime, locDecayP4, locBeamParticle, locToExcludeUse, locInstanceToExclude, locAccuratePhotonsFlag))
906  return false;
907  if(dDebugLevel >= 20)
908  cout << "combo, add decayp4 = " << locDecayCombo << ", " << locDecayP4.Px() << ", " << locDecayP4.Py() << ", " << locDecayP4.Pz() << ", " << locDecayP4.E() << endl;
909  locTotalP4 += locDecayP4;
910  }
911 
912  //Subtract target p4 if necessary (e.g. Lambda, p -> p, p, pi-)
913  auto locTargetPIDToSubtract = std::get<4>(locCombosByUsePair.first);
914  if(locTargetPIDToSubtract != Unknown)
915  locTotalP4 -= DLorentzVector(TVector3(), ParticleMass(locTargetPIDToSubtract));
916  }
917 
918  if(!locAccuratePhotonsFlag || !locHasPhotons)
919  dFinalStateP4ByCombo_HasMassiveNeutrals.emplace(locP4LookupTuple, locTotalP4);
920  if(dDebugLevel >= 10)
921  cout << "Save Calc_P4_HasMassiveNeutrals: Combo " << locCurrentCombo << " P4: " << locTotalP4.Px() << ", " << locTotalP4.Py() << ", " << locTotalP4.Pz() << ", " << locTotalP4.E() << endl;
922  return true;
923 }
924 
925 bool DSourceComboP4Handler::Get_InvariantMassCut(const DSourceCombo* locSourceCombo, Particle_t locDecayPID, bool locAccuratePhotonsFlag, pair<float, float>& locMinMaxMassCuts_GeV) const
926 {
927  auto locCutIterator = dInvariantMassCuts.find(locDecayPID);
928  if(locCutIterator == dInvariantMassCuts.end())
929  return false; //no cut to place!!
930  locMinMaxMassCuts_GeV = locCutIterator->second;
931 
932  if(locAccuratePhotonsFlag)
933  return true;
934 
935  auto locNumPhotons = DAnalysis::Get_SourceParticles(locSourceCombo->Get_SourceParticles(true, d_Neutral), Gamma).size();
936  if(locNumPhotons == 0)
937  return true;
938  auto locMassError = (locNumPhotons > 2) ? 0.5*double(locNumPhotons)*d2PhotonInvariantMassCutError : d2PhotonInvariantMassCutError;
939  locMinMaxMassCuts_GeV.first -= locMassError;
940  locMinMaxMassCuts_GeV.second += locMassError;
941  return true;
942 }
943 
944 bool DSourceComboP4Handler::Cut_InvariantMass_NoMassiveNeutrals(const DSourceCombo* locVertexCombo, Particle_t locDecayPID, Particle_t locTargetPIDToSubtract, const DVector3& locVertex, signed char locVertexZBin, bool locAccuratePhotonsFlag)
945 {
946  //Z-bin necessary to signal the special negative bins!!
947  //Don't call if it contains massive neutrals! Call the other cut function instead!!
948  pair<float, float> locMassCuts;
949  if(!Get_InvariantMassCut(locVertexCombo, locDecayPID, locAccuratePhotonsFlag, locMassCuts))
950  return true; //no cut to place!!
951 
952  if(!locVertexCombo->Get_IsComboingZIndependent() && (locVertexZBin == DSourceComboInfo::Get_VertexZIndex_Unknown()) && !locAccuratePhotonsFlag)
953  return true; //don't cut yet: will cut later when vertex known or accurate photons
954  auto locFinalStateP4 = Calc_P4_NoMassiveNeutrals(nullptr, locVertexCombo, locVertex, locVertexZBin, nullptr, DSourceComboUse(Unknown, 0, nullptr, false, Unknown), 1, locAccuratePhotonsFlag);
955 
956  //Subtract target p4 if necessary (e.g. Lambda, p -> p, p, pi-)
957  if(locTargetPIDToSubtract != Unknown)
958  locFinalStateP4 -= DLorentzVector(TVector3(), ParticleMass(locTargetPIDToSubtract));
959  auto locInvariantMass = locFinalStateP4.M();
960 
961  //save and cut
962  auto locCutResult = ((locInvariantMass >= locMassCuts.first) && (locInvariantMass <= locMassCuts.second));
963 
964  if(!locAccuratePhotonsFlag) //else has already been saved during inaccurate stage
965  {
966  auto locSaveTuple = std::make_tuple(locDecayPID, locVertexCombo);
967  if(dInvariantMassFilledSet.find(locSaveTuple) == dInvariantMassFilledSet.end())
968  {
969  if(dDebugLevel >= 20)
970  cout << "fill no-massive hist" << endl;
971  dInvariantMasses[locDecayPID].emplace_back(locInvariantMass);
972  dInvariantMassFilledSet.insert(locSaveTuple);
973  }
974  }
975  if(dDebugLevel >= 10)
976  cout << "accurate flag, decay pid, z, zbin, mass, cut min/max, pass flag: " << locAccuratePhotonsFlag << ", " << locDecayPID << ", " << locVertex.Z() << ", " << int(locVertexZBin) << ", " << locInvariantMass << ", " << locMassCuts.first << ", " << locMassCuts.second << ", " << locCutResult << endl;
977  return locCutResult;
978 }
979 
980 bool DSourceComboP4Handler::Cut_InvariantMass_HasMassiveNeutral(bool locIsProductionVertex, bool locIsPrimaryProductionVertex, const DSourceCombo* locReactionFullCombo, const DSourceCombo* locVertexCombo, Particle_t locDecayPID, Particle_t locTargetPIDToSubtract, double locPrimaryVertexZ, const DVector3& locVertex, double locTimeOffset, vector<int>& locValidRFBunches, const DKinematicData* locBeamParticle, bool locAccuratePhotonsFlag)
981 {
982  if(locValidRFBunches.empty())
983  return true; //massive neutral p4 not defined, can't cut
984 
985  pair<float, float> locMassCuts;
986  if(!Get_InvariantMassCut(locVertexCombo, locDecayPID, locAccuratePhotonsFlag, locMassCuts))
987  return true; //no cut to place!!
988 
989  auto locVertexZBin = dSourceComboTimeHandler->Get_PhotonVertexZBin(locVertex.Z());
990  if(!locVertexCombo->Get_IsComboingZIndependent() && (locVertexZBin == DSourceComboInfo::Get_VertexZIndex_Unknown()) && !locAccuratePhotonsFlag)
991  return true; //don't cut yet: will cut later when vertex known or accurate photons
992 
993  //function for calculating and cutting the invariant mass for each rf bunch
994  auto CalcAndCut_InvariantMass = [&](int locRFBunch) -> bool
995  {
996  auto locRFVertexTime = dSourceComboTimeHandler->Calc_PropagatedRFTime(locPrimaryVertexZ, locRFBunch, locTimeOffset);
997 
998  DLorentzVector locTotalP4(0.0, 0.0, 0.0, 0.0);
999  if(!Calc_P4_HasMassiveNeutrals(locIsProductionVertex, locIsPrimaryProductionVertex, locReactionFullCombo, locVertexCombo, locVertex, locTimeOffset, locRFBunch, locRFVertexTime, DSourceComboUse(Unknown, 0, nullptr, false, Unknown), 1, locTotalP4, locBeamParticle, locAccuratePhotonsFlag))
1000  return true; //can't cut it yet!
1001 
1002  //Subtract target p4 if necessary (e.g. Lambda, p -> p, p, pi-)
1003  if(locTargetPIDToSubtract != Unknown)
1004  locTotalP4 -= DLorentzVector(TVector3(), ParticleMass(locTargetPIDToSubtract));
1005 
1006  auto locInvariantMass = locTotalP4.M();
1007  auto locPassCutFlag = ((locInvariantMass > locMassCuts.first) && (locInvariantMass < locMassCuts.second));
1008  if(dDebugLevel >= 10)
1009  cout << "has-mass neutral: accurate flag, decay pid, z, mass, cut min/max, pass flag: " << locAccuratePhotonsFlag << ", " << locDecayPID << ", " << locVertex.Z() << ", " << locTotalP4.M() << ", " << locMassCuts.first << ", " << locMassCuts.second << ", " << locPassCutFlag << endl;
1010 
1011  //save and cut
1012  if(!locAccuratePhotonsFlag) //else has already been saved during inaccurate stage
1013  {
1014  auto locSaveTuple = std::make_tuple(locDecayPID, locIsProductionVertex, locReactionFullCombo, locVertexCombo, locRFBunch);
1016  {
1017  if(dDebugLevel >= 20)
1018  cout << "fill hist: massive neutrals" << endl;
1019  dInvariantMasses[locDecayPID].emplace_back(locInvariantMass);
1020  dInvariantMassFilledSet_MassiveNeutral.insert(locSaveTuple);
1021  }
1022  }
1023  return !locPassCutFlag; //because it's used in remove_if!!
1024  };
1025 
1026  //apply the function
1027  locValidRFBunches.erase(std::remove_if(locValidRFBunches.begin(), locValidRFBunches.end(), CalcAndCut_InvariantMass), locValidRFBunches.end());
1028  return !locValidRFBunches.empty();
1029 }
1030 
1031 bool DSourceComboP4Handler::Cut_InvariantMass_HasMassiveNeutral_OrPhotonVertex(const DReactionVertexInfo* locReactionVertexInfo, const DSourceCombo* locReactionFullCombo, vector<int>& locValidRFBunches)
1032 {
1033  //do 2 things at once (where vertex is known) (hence the really long function name):
1034  //calc & cut invariant mass: when massive neutral present
1035  //calc & cut invariant mass: when vertex-z was unknown with only charged tracks, but is known now, and contains BCAL photons (won't happen very often)
1036  if(dDebugLevel >= 10)
1037  cout << "Cut_InvariantMass_HasMassiveNeutral_OrPhotonVertex()" << endl;
1038  auto locPrimaryVertexZ = dSourceComboVertexer->Get_PrimaryVertex(locReactionVertexInfo, locReactionFullCombo, nullptr).Z();
1039  auto locIsPrimaryProductionVertex = locReactionVertexInfo->Get_StepVertexInfo(0)->Get_ProductionVertexFlag();
1040 
1041  //loop over vertices in reverse step order //dependency for calculating invariant mass
1042  auto locStepVertexInfos = DAnalysis::Get_StepVertexInfos_ReverseOrderByStep(locReactionVertexInfo);
1043  for(const auto& locStepVertexInfo : locReactionVertexInfo->Get_StepVertexInfos())
1044  {
1045  if(locStepVertexInfo->Get_DanglingVertexFlag())
1046  continue; //unknown position!
1047 
1048  //see if vertex position has been found yet
1049  auto locIsProductionVertex = locStepVertexInfo->Get_ProductionVertexFlag();
1050  auto locVertexPrimaryFullCombo = dSourceComboer->Get_VertexPrimaryCombo(locReactionFullCombo, locStepVertexInfo);
1051  if(!dSourceComboVertexer->Get_IsVertexKnown_NoBeam(locIsProductionVertex, locVertexPrimaryFullCombo, false))
1052  continue; //vertex not found yet!
1053 
1054  auto locVertexComboUse = dSourceComboer->Get_SourceComboUse(locStepVertexInfo);
1055  auto locHasMassiveNeutrals = dSourceComboer->Get_HasMassiveNeutrals(std::get<2>(locVertexComboUse));
1056 
1057  auto locVertexConstrainedByChargedFlag = dSourceComboVertexer->Get_VertexDeterminableWithCharged(locStepVertexInfo);
1058  if(dDebugLevel >= 10)
1059  cout << "determinable, has-flag: " << locVertexConstrainedByChargedFlag << ", " << locHasMassiveNeutrals << endl;
1060  if(locVertexConstrainedByChargedFlag && !locHasMassiveNeutrals)
1061  continue; //no massive neutrals, and vertex found with charged: mass cuts already placed
1062 
1063  if(locVertexPrimaryFullCombo->Get_IsComboingZIndependent() && !locHasMassiveNeutrals)
1064  continue; //nothing new (e.g. new vertex found with neutrals, but all of the neutrals in the combo are FCAL photons anyway: nothing to do
1065 
1066  //get vertex position and time offset
1067  auto locVertex = dSourceComboVertexer->Get_Vertex_NoBeam(locIsProductionVertex, locVertexPrimaryFullCombo, false);
1068  if(!dSourceComboVertexer->Get_IsTimeOffsetKnown(locIsPrimaryProductionVertex, locReactionFullCombo, locVertexPrimaryFullCombo, nullptr))
1069  continue; //not from this vertex
1070  auto locTimeOffset = dSourceComboVertexer->Get_TimeOffset(locIsPrimaryProductionVertex, locReactionFullCombo, locVertexPrimaryFullCombo, nullptr);
1071 
1072  //get all combos at this vertex, with their uses, in reverse dependency order
1073  vector<pair<DSourceComboUse, vector<const DSourceCombo*>>> locSourceCombosAndUses_ThisVertex = DAnalysis::Get_SourceCombosAndUses_ThisVertex(locVertexPrimaryFullCombo);
1074  locSourceCombosAndUses_ThisVertex.emplace(locSourceCombosAndUses_ThisVertex.begin(), locVertexComboUse, vector<const DSourceCombo*>{locVertexPrimaryFullCombo}); //not ideal ...
1075 
1076  //loop over combos & uses at this vertex in dependency order (in reverse)
1077  for(auto locIterator = locSourceCombosAndUses_ThisVertex.rbegin(); locIterator != locSourceCombosAndUses_ThisVertex.rend(); ++locIterator)
1078  {
1079  auto locDecayComboUse = locIterator->first;
1080  auto locDecayPID = std::get<0>(locDecayComboUse);
1081  if((locDecayPID == Unknown) || std::get<3>(locDecayComboUse))
1082  continue; //no mass cut to place!
1083 
1084  auto locDecayHasMassiveNeutrals = dSourceComboer->Get_HasMassiveNeutrals(std::get<2>(locDecayComboUse));
1085  auto locTargetPIDToSubtract = std::get<4>(locDecayComboUse);
1086 
1087  //loop over combos
1088  for(const auto& locDecayCombo : locIterator->second)
1089  {
1090  if(locDecayCombo->Get_IsComboingZIndependent() && !locDecayHasMassiveNeutrals)
1091  continue; //no massive neutrals, no BCAL showers: already cut!
1092  if(!Cut_InvariantMass_HasMassiveNeutral(locIsProductionVertex, locIsPrimaryProductionVertex, locReactionFullCombo, locDecayCombo, locDecayPID, locTargetPIDToSubtract, locPrimaryVertexZ, locVertex, locTimeOffset, locValidRFBunches, nullptr, false))
1093  return false; //failed mass cut for all possible rf bunches!
1094  }
1095  }
1096  }
1097 
1098  return true;
1099 }
1100 
1101 bool DSourceComboP4Handler::Cut_InvariantMass_MissingMassVertex(const DReactionVertexInfo* locReactionVertexInfo, const DSourceCombo* locReactionFullCombo, const DKinematicData* locBeamParticle, int locRFBunch)
1102 {
1103  //Also cuts for dangling vertices
1104 
1105  //calc & cut invariant mass: when vertex-z was unknown without the beam energy
1106  auto locPrimaryVertexZ = dSourceComboVertexer->Get_PrimaryVertex(locReactionVertexInfo, locReactionFullCombo, locBeamParticle).Z();
1107  auto locIsPrimaryProductionVertex = locReactionVertexInfo->Get_StepVertexInfo(0)->Get_ProductionVertexFlag();
1108 
1109  //loop over vertices in reverse step order //dependency for calculating invariant mass
1110  auto locStepVertexInfos = DAnalysis::Get_StepVertexInfos_ReverseOrderByStep(locReactionVertexInfo);
1111  for(const auto& locStepVertexInfo : locReactionVertexInfo->Get_StepVertexInfos())
1112  {
1113  auto locIsProductionVertex = locStepVertexInfo->Get_ProductionVertexFlag();
1114 
1115  auto locVertexComboUse = dSourceComboer->Get_SourceComboUse(locStepVertexInfo);
1116  auto locHasMassiveNeutrals = dSourceComboer->Get_HasMassiveNeutrals(std::get<2>(locVertexComboUse));
1117 
1119  continue; //vertex found with charged: mass cuts already placed
1120 
1121  auto locVertexPrimaryFullCombo = dSourceComboer->Get_VertexPrimaryCombo(locReactionFullCombo, locStepVertexInfo);
1123  continue; //vertex found with photons: mass cuts already placed
1124 
1125  if(locVertexPrimaryFullCombo->Get_IsComboingZIndependent() && !locHasMassiveNeutrals)
1126  continue; //nothing new (e.g. new vertex found with beam, but all of the neutrals in the combo are FCAL photons anyway: nothing to do
1127 
1128  //get vertex position and time offset
1129  auto locVertex = dSourceComboVertexer->Get_Vertex(locStepVertexInfo, locReactionFullCombo, locBeamParticle, false);
1130  auto locTimeOffset = dSourceComboVertexer->Get_TimeOffset(locReactionVertexInfo, locStepVertexInfo, locReactionFullCombo, locBeamParticle);
1131 
1132  //get all combos at this vertex, with their uses, in reverse dependency order
1133  vector<pair<DSourceComboUse, vector<const DSourceCombo*>>> locSourceCombosAndUses_ThisVertex = DAnalysis::Get_SourceCombosAndUses_ThisVertex(locVertexPrimaryFullCombo);
1134  locSourceCombosAndUses_ThisVertex.emplace(locSourceCombosAndUses_ThisVertex.begin(), locVertexComboUse, vector<const DSourceCombo*>{locVertexPrimaryFullCombo}); //not ideal ...
1135 
1136  //loop over combos & uses at this vertex in dependency order (in reverse)
1137  for(auto locIterator = locSourceCombosAndUses_ThisVertex.rbegin(); locIterator != locSourceCombosAndUses_ThisVertex.rend(); ++locIterator)
1138  {
1139  auto locDecayComboUse = locIterator->first;
1140  auto locDecayPID = std::get<0>(locDecayComboUse);
1141  if((locDecayPID == Unknown) || std::get<3>(locDecayComboUse))
1142  continue; //no mass cut to place!
1143 
1144  auto locDecayHasMassiveNeutrals = dSourceComboer->Get_HasMassiveNeutrals(std::get<2>(locDecayComboUse));
1145  auto locTargetPIDToSubtract = std::get<4>(locDecayComboUse);
1146 
1147  //loop over combos
1148  for(const auto& locDecayCombo : locIterator->second)
1149  {
1150  if(locDecayCombo->Get_IsComboingZIndependent() && !locDecayHasMassiveNeutrals)
1151  continue; //no massive neutrals, no BCAL showers: already cut!
1152  vector<int> locRFBunches{locRFBunch};
1153  if(!Cut_InvariantMass_HasMassiveNeutral(locIsProductionVertex, locIsPrimaryProductionVertex, locReactionFullCombo, locDecayCombo, locDecayPID, locTargetPIDToSubtract, locPrimaryVertexZ, locVertex, locTimeOffset, locRFBunches, nullptr, false))
1154  return false; //failed mass cut for all possible rf bunches!
1155  }
1156  }
1157  }
1158 
1159  return true;
1160 }
1161 
1162 bool DSourceComboP4Handler::Cut_MissingMassSquared(const DReaction* locReaction, const DReactionVertexInfo* locReactionVertexInfo, const DSourceComboUse& locReactionFullComboUse, const DSourceCombo* locReactionFullCombo, const DKinematicData* locBeamParticle, int locRFBunch)
1163 {
1164  if(dDebugLevel > 0)
1165  cout << "DSourceComboP4Handler::Cut_MissingMassSquared()" << endl;
1166  if(!DAnalysis::Get_IsFirstStepBeam(locReaction))
1167  return true; //nothing to do
1168 
1169  //compute missing p4
1170  //ASSUMES FIXED TARGET EXPERIMENT!
1171  auto locTargetPID = locReaction->Get_ReactionStep(0)->Get_TargetPID();
1172  auto locInitialStateP4 = locBeamParticle->lorentzMomentum() + DLorentzVector(0.0, 0.0, 0.0, ParticleMass(locTargetPID));
1173 
1174  //get num missing particles & exclusive steps
1175  auto locNumMissingParticles = locReaction->Get_MissingPIDs().size();
1176  size_t locNumInclusiveSteps = 0;
1177  for(auto locReactionStep : locReaction->Get_ReactionSteps())
1178  {
1179  if(locReactionStep->Get_IsInclusiveFlag())
1180  ++locNumInclusiveSteps;
1181  }
1182 
1183  //if nothing missing, overall missing mass squared
1184  if((locNumMissingParticles == 0) && (locNumInclusiveSteps == 0))
1185  {
1186  DLorentzVector locMissingP4;
1187  if(!Cut_MissingMassSquared(locReaction, locReactionVertexInfo, locReactionFullComboUse, locReactionFullCombo, Unknown, 0, -1, locInitialStateP4, locRFBunch, locBeamParticle, locMissingP4))
1188  return false;
1189  }
1190 
1191 //V2 compare, as long as no missing particles!!
1192 //return true;
1193 
1194  //loop over steps, looking for decaying & missing particles
1195  map<size_t, DLorentzVector> locDecayP4sByStep;
1196  for(size_t loc_i = 0; loc_i < locReaction->Get_NumReactionSteps(); ++loc_i)
1197  {
1198  if(loc_i > 0)
1199  {
1200  auto locP4Iterator = locDecayP4sByStep.find(loc_i);
1201  if(locP4Iterator == locDecayP4sByStep.end())
1202  continue; //must not be possible for whatever reason
1203  locInitialStateP4 = locP4Iterator->second;
1204  }
1205 
1206  auto locReactionStep = locReaction->Get_ReactionStep(loc_i);
1207  for(size_t loc_j = 0; loc_j < locReactionStep->Get_NumFinalPIDs(); ++loc_j)
1208  {
1209  auto locPID = locReactionStep->Get_FinalPID(loc_j);
1210  if(dDebugLevel >= 100)
1211  cout << "i, j, pid, missing index: " << loc_i << ", " << loc_j << ", " << locPID << ", " << locReactionStep->Get_MissingParticleIndex() << endl;
1212 
1213  //check if missing particle
1214  if(int(loc_j) == locReactionStep->Get_MissingParticleIndex())
1215  {
1216  if((locNumMissingParticles > 1) || (locNumInclusiveSteps > 0))
1217  continue;
1218  DLorentzVector locMissingP4;
1219  if(!Cut_MissingMassSquared(locReaction, locReactionVertexInfo, locReactionFullComboUse, locReactionFullCombo, locPID, loc_i, -1, locInitialStateP4, locRFBunch, locBeamParticle, locMissingP4))
1220  return false;
1221  }
1222 
1223  //check if decaying particle
1224  auto locDecayStepIndex = DAnalysis::Get_DecayStepIndex(locReaction, loc_i, loc_j);
1225  if(dDebugLevel >= 100)
1226  cout << "decay step index: " << locDecayStepIndex << endl;
1227  if(locDecayStepIndex <= 0)
1228  continue; //nope
1229 
1230  //nothing can be missing anywhere, except in it's decay products
1231  auto locMissingDecayProducts = DAnalysis::Get_MissingDecayProductIndices(locReaction, locDecayStepIndex);
1232  if(dDebugLevel >= 100)
1233  cout << "num missing total/decay: " << locNumMissingParticles << ", " << locMissingDecayProducts.size() << endl;
1234  if((locNumMissingParticles - locMissingDecayProducts.size()) > 0)
1235  continue; //nope
1236 
1237  //check inclusives, same thing
1238  size_t locNumInclusiveDecayProductSteps = 0;
1239  for(auto& locParticlePair : locMissingDecayProducts)
1240  {
1241  if(locParticlePair.second == DReactionStep::Get_ParticleIndex_Inclusive())
1242  ++locNumInclusiveDecayProductSteps;
1243  }
1244  if(dDebugLevel >= 100)
1245  cout << "num inclusives total/decay: " << locNumInclusiveSteps << ", " << locNumInclusiveDecayProductSteps << endl;
1246  if((locNumInclusiveSteps - locNumInclusiveDecayProductSteps) > 0)
1247  continue; //nope
1248 
1249  DLorentzVector locMissingP4;
1250  if(!Cut_MissingMassSquared(locReaction, locReactionVertexInfo, locReactionFullComboUse, locReactionFullCombo, locPID, loc_i, locDecayStepIndex, locInitialStateP4, locRFBunch, locBeamParticle, locMissingP4))
1251  return false;
1252  locDecayP4sByStep.emplace(locDecayStepIndex, locMissingP4);
1253  }
1254  }
1255 
1256  return true;
1257 }
1258 
1259 bool DSourceComboP4Handler::Cut_MissingMassSquared(const DReaction* locReaction, const DReactionVertexInfo* locReactionVertexInfo, const DSourceComboUse& locReactionFullComboUse, const DSourceCombo* locFullCombo, Particle_t locMissingPID, int locStepIndex, int locDecayStepIndex, const DLorentzVector& locInitialStateP4, int locRFBunch, const DKinematicData* locBeamParticle, DLorentzVector& locMissingP4)
1260 {
1261  auto locStepVertexInfo = locReactionVertexInfo->Get_StepVertexInfo(locStepIndex);
1262  auto locIsProductionVertex = locStepVertexInfo->Get_ProductionVertexFlag();
1263  auto locVertexPrimaryCombo = dSourceComboer->Get_VertexPrimaryCombo(locFullCombo, locStepVertexInfo);
1264  auto locSourceCombo = (locStepIndex == 0) ? locFullCombo : dSourceComboer->Get_StepSourceCombo(locReaction, locStepIndex, locVertexPrimaryCombo, locStepVertexInfo->Get_StepIndices().front());
1265  auto locBeamEnergy = locBeamParticle->lorentzMomentum().E();
1266  auto locPrimaryVertexZ = dSourceComboVertexer->Get_PrimaryVertex(locReactionVertexInfo, locFullCombo, locBeamParticle).Z();
1267 
1268  //get vertex position and time offset
1269  auto locVertex = dSourceComboVertexer->Get_Vertex(locStepVertexInfo, locFullCombo, locBeamParticle, false);
1270  auto locTimeOffset = dSourceComboVertexer->Get_TimeOffset(locReactionVertexInfo, locStepVertexInfo, locFullCombo, locBeamParticle);
1271  auto locRFVertexTime = dSourceComboTimeHandler->Calc_PropagatedRFTime(locPrimaryVertexZ, locRFBunch, locTimeOffset);
1272  auto locToExcludeUsePair = (locDecayStepIndex > 0) ? dSourceComboer->Get_StepSourceComboUse(locReaction, locDecayStepIndex, locReactionFullComboUse, 0) : std::make_pair(DSourceComboUse(Unknown, 0, nullptr, false, Unknown), size_t(1));
1273 
1274  //compute final-state p4
1275  DLorentzVector locFinalStateP4(0.0, 0.0, 0.0, 0.0);
1276  //it may not have massive neutrals, but this function is the worst-case (hardest, most-complete) scenario
1277  if(!Calc_P4_HasMassiveNeutrals(locIsProductionVertex, true, locFullCombo, locSourceCombo, locVertex, locTimeOffset, locRFBunch, locRFVertexTime, locToExcludeUsePair.first, locToExcludeUsePair.second, locFinalStateP4, locBeamParticle, true))
1278  {
1279  locMissingP4.SetE(0.0);
1280  return true; //failed to calculate somehow
1281  }
1282 
1283  locMissingP4 = locInitialStateP4 - locFinalStateP4;
1284  if(dDebugLevel >= 5)
1285  cout << "missing pid, pxyzE = " << locMissingPID << ", " << locMissingP4.Px() << ", " << locMissingP4.Py() << ", " << locMissingP4.Pz() << ", " << locMissingP4.E() << endl;
1286 
1287  pair<TF1*, TF1*> locCutPair;
1288  if(!Get_MissingMassSquaredCuts(locMissingPID, locCutPair))
1289  return true; //don't cut
1290 
1291  auto locMissingMassSquared_Min = locCutPair.first->Eval(locBeamEnergy);
1292  auto locMissingMassSquared_Max = locCutPair.second->Eval(locBeamEnergy);
1293  if(dDebugLevel >= 5)
1294  cout << "beam E, missing mass^2 min/max/measured = " << locBeamEnergy << ", " << locMissingMassSquared_Min << ", " << locMissingMassSquared_Max << ", " << locMissingP4.M2() << endl;
1295 
1296  //save and cut
1297  dMissingMassPairs[locMissingPID].emplace_back(locBeamEnergy, locMissingP4.M2());
1298  auto locPassCutFlag = ((locMissingP4.M2() >= locMissingMassSquared_Min) && (locMissingP4.M2() <= locMissingMassSquared_Max));
1299  if(locMissingPID == Unknown)
1300  {
1301  dMissingEVsBeamEnergy_PreMissMassSqCut.emplace_back(locBeamEnergy, locMissingP4.E());
1302  dMissingPtVsMissingE_PreMissMassSqCut.emplace_back(locMissingP4.E(), locMissingP4.Perp());
1303  if(locPassCutFlag)
1304  {
1305  if((dMissingECuts.first != nullptr) && (dMissingECuts.second != nullptr)) //cut missing E!!
1306  locPassCutFlag = ((locMissingP4.E() >= dMissingECuts.first->Eval(locBeamEnergy)) && (locMissingP4.E() <= dMissingECuts.second->Eval(locBeamEnergy)));
1307  dMissingEVsBeamEnergy_PostMissMassSqCut.emplace_back(locBeamEnergy, locMissingP4.E());
1308  dMissingPtVsMissingE_PostMissMassSqCut.emplace_back(locMissingP4.E(), locMissingP4.Perp());
1309  }
1310  }
1311 
1312  return locPassCutFlag;
1313 }
1314 
1315 bool DSourceComboP4Handler::Cut_InvariantMass_AccuratePhotonKinematics(const DReactionVertexInfo* locReactionVertexInfo, const DSourceCombo* locReactionFullCombo, const DKinematicData* locBeamParticle, int locRFBunch)
1316 {
1317  if(dDebugLevel >= 5)
1318  cout << "DSourceComboP4Handler::Cut_InvariantMass_AccuratePhotonKinematics()" << endl;
1319 
1320  if(DAnalysis::Get_SourceParticles(locReactionFullCombo->Get_SourceParticles(true, d_Neutral), Gamma).empty())
1321  return true; //nothing has changed!
1322 
1323  //if photons in combo, cut again using correct p4 (rather than estimated)
1324  auto locPrimaryVertexZ = dSourceComboVertexer->Get_PrimaryVertex(locReactionVertexInfo, locReactionFullCombo, nullptr).Z();
1325  auto locIsPrimaryProductionVertex = locReactionVertexInfo->Get_StepVertexInfo(0)->Get_ProductionVertexFlag();
1326 
1327  //loop over vertices in reverse step order //dependency for calculating invariant mass
1328  auto locStepVertexInfos = DAnalysis::Get_StepVertexInfos_ReverseOrderByStep(locReactionVertexInfo);
1329  for(const auto& locStepVertexInfo : locReactionVertexInfo->Get_StepVertexInfos())
1330  {
1331  auto locIsProductionVertex = locStepVertexInfo->Get_ProductionVertexFlag();
1332  auto locVertexPrimaryFullCombo = dSourceComboer->Get_VertexPrimaryCombo(locReactionFullCombo, locStepVertexInfo);
1333  if(DAnalysis::Get_SourceParticles(locVertexPrimaryFullCombo->Get_SourceParticles(true, d_Neutral), Gamma).empty())
1334  continue; //nothing has changed
1335 
1336  //get vertex position and time offset
1337  auto locVertex = dSourceComboVertexer->Get_Vertex(locStepVertexInfo, locReactionFullCombo, locBeamParticle, false);
1338  auto locTimeOffset = dSourceComboVertexer->Get_TimeOffset(locReactionVertexInfo, locStepVertexInfo, locReactionFullCombo, locBeamParticle);
1339 
1340  //get all combos at this vertex, with their uses, in reverse dependency order
1341  auto locVertexComboUse = dSourceComboer->Get_SourceComboUse(locStepVertexInfo);
1342  vector<pair<DSourceComboUse, vector<const DSourceCombo*>>> locSourceCombosAndUses_ThisVertex = DAnalysis::Get_SourceCombosAndUses_ThisVertex(locVertexPrimaryFullCombo);
1343  locSourceCombosAndUses_ThisVertex.emplace(locSourceCombosAndUses_ThisVertex.begin(), locVertexComboUse, vector<const DSourceCombo*>{locVertexPrimaryFullCombo}); //not ideal ...
1344 
1345  //loop over combos & uses at this vertex in dependency order (in reverse)
1346  for(auto locIterator = locSourceCombosAndUses_ThisVertex.rbegin(); locIterator != locSourceCombosAndUses_ThisVertex.rend(); ++locIterator)
1347  {
1348  auto locDecayComboUse = locIterator->first;
1349  auto locDecayPID = std::get<0>(locDecayComboUse);
1350  if((locDecayPID == Unknown) || std::get<3>(locDecayComboUse))
1351  continue; //no mass cut to place!
1352 
1353  auto locDecayHasMassiveNeutrals = dSourceComboer->Get_HasMassiveNeutrals(std::get<2>(locDecayComboUse));
1354  auto locTargetPIDToSubtract = std::get<4>(locDecayComboUse);
1355 
1356  //loop over combos
1357  for(const auto& locDecayCombo : locIterator->second)
1358  {
1359  if(DAnalysis::Get_SourceParticles(locDecayCombo->Get_SourceParticles(true, d_Neutral), Gamma).empty())
1360  continue; //nothing has changed
1361  if(locDecayHasMassiveNeutrals)
1362  {
1363  vector<int> locBeamBunches{locRFBunch};
1364  if(!Cut_InvariantMass_HasMassiveNeutral(locIsProductionVertex, locIsPrimaryProductionVertex, locReactionFullCombo, locDecayCombo, locDecayPID, locTargetPIDToSubtract, locPrimaryVertexZ, locVertex, locTimeOffset, locBeamBunches, locBeamParticle, true))
1365  return false;
1366  }
1367  else
1368  {
1369  if(!Cut_InvariantMass_NoMassiveNeutrals(locDecayCombo, locDecayPID, locTargetPIDToSubtract, locVertex, std::get<1>(locDecayComboUse), true))
1370  return false;
1371  }
1372  }
1373  }
1374  }
1375  return true;
1376 }
1377 
1379 {
1380  japp->WriteLock("DSourceComboP4Handler");
1381  {
1382  for(auto& locPIDPair : dInvariantMasses)
1383  {
1384  for(auto& locMass : locPIDPair.second)
1385  dHistMap_InvariantMass[locPIDPair.first]->Fill(locMass);
1386  }
1387  for(auto& locPIDPair : dMissingMassPairs)
1388  {
1389  for(auto& locMassPair : locPIDPair.second)
1390  dHistMap_MissingMassSquaredVsBeamEnergy[locPIDPair.first]->Fill(locMassPair.first, locMassPair.second);
1391  }
1392  for(auto& locSystemPair : d2GammaInvariantMasses)
1393  {
1394  for(auto& locMass : locSystemPair.second)
1395  dHistMap_2GammaMass[locSystemPair.first]->Fill(locMass);
1396  }
1397 
1398  for(auto& locMissingPair : dMissingEVsBeamEnergy_PreMissMassSqCut)
1399  dHist_NoneMissing_MissingEVsBeamEnergy_PreMissMassSqCut->Fill(locMissingPair.first, locMissingPair.second);
1400  for(auto& locMissingPair : dMissingEVsBeamEnergy_PostMissMassSqCut)
1401  dHist_NoneMissing_MissingEVsBeamEnergy_PostMissMassSqCut->Fill(locMissingPair.first, locMissingPair.second);
1402  for(auto& locMissingPair : dMissingPtVsMissingE_PreMissMassSqCut)
1403  dHist_NoneMissing_MissingPtVsMissingE_PreMissMassSqCut->Fill(locMissingPair.first, locMissingPair.second);
1404  for(auto& locMissingPair : dMissingPtVsMissingE_PostMissMassSqCut)
1405  dHist_NoneMissing_MissingPtVsMissingE_PostMissMassSqCut->Fill(locMissingPair.first, locMissingPair.second);
1406  }
1407  japp->Unlock("DSourceComboP4Handler");
1408 
1409  vector<pair<float, float>>().swap(dMissingEVsBeamEnergy_PreMissMassSqCut);
1410  vector<pair<float, float>>().swap(dMissingEVsBeamEnergy_PostMissMassSqCut);
1411  vector<pair<float, float>>().swap(dMissingPtVsMissingE_PreMissMassSqCut);
1412  vector<pair<float, float>>().swap(dMissingPtVsMissingE_PostMissMassSqCut);
1413 
1414  for(auto& locPIDPair : dInvariantMasses)
1415  decltype(locPIDPair.second)().swap(locPIDPair.second);
1416  for(auto& locPIDPair : dMissingMassPairs)
1417  decltype(locPIDPair.second)().swap(locPIDPair.second);
1418  for(auto& locSystemPair : d2GammaInvariantMasses)
1419  decltype(locSystemPair.second)().swap(locSystemPair.second);
1420 }
1421 
1422 } //end namespace
1423 
vector< pair< float, float > > dMissingPtVsMissingE_PostMissMassSqCut
DLorentzVector Get_P4_NotMassiveNeutral(Particle_t locPID, const JObject *locObject, const DVector3 &locVertex, bool locAccuratePhotonsFlag) const
bool Cut_InvariantMass_MissingMassVertex(const DReactionVertexInfo *locReactionVertexInfo, const DSourceCombo *locReactionFullCombo, const DKinematicData *locBeamParticle, int locRFBunch)
pair< DSourceComboUse, size_t > Get_StepSourceComboUse(const DReaction *locReaction, size_t locDesiredStepIndex, DSourceComboUse locVertexPrimaryComboUse, size_t locVertexPrimaryStepIndex) const
bool Get_IsFirstStepBeam(const DReaction *locReaction)
Definition: DReaction.h:178
vector< pair< DSourceComboUse, vector< const DSourceCombo * > > > Get_SourceCombosAndUses_ThisVertex(const DSourceCombo *locSourceCombo)
Definition: DSourceCombo.h:432
bool Get_VertexDeterminableWithPhotons(const DReactionStepVertexInfo *locStepVertexInfo) const
DPhotonKinematicsByZBin dPhotonKinematics
static char * ParticleName_ROOT(Particle_t p)
Definition: particleType.h:851
double Get_TimeOffset(bool locIsPrimaryProductionVertex, const DSourceCombo *locReactionCombo, const DSourceCombo *locVertexCombo, const DKinematicData *locBeamParticle) const
map< Particle_t, vector< pair< float, float > > > dMissingMassPairs
DSourceComboUse Get_SourceComboUse(const DReactionStepVertexInfo *locStepVertexInfo) const
bool Cut_InvariantMass_HasMassiveNeutral_OrPhotonVertex(const DReactionVertexInfo *locReactionVertexInfo, const DSourceCombo *locReactionFullCombo, vector< int > &locValidRFBunches)
bool Get_MissingMassSquaredCuts(Particle_t locPID, pair< TF1 *, TF1 * > &locMinMaxCuts_GeVSq) const
map< DetectorSystem_t, vector< float > > d2GammaInvariantMasses
map< Particle_t, pair< double, double > > dInvariantMassCuts
TVector3 DVector3
Definition: DVector3.h:14
Definition: GlueX.h:16
vector< pair< float, float > > dMissingEVsBeamEnergy_PreMissMassSqCut
map< Particle_t, vector< float > > dInvariantMasses
const DReactionStepVertexInfo * Get_StepVertexInfo(size_t locStepIndex) const
char string[256]
const DSourceComboVertexer * dSourceComboVertexer
map< Particle_t, pair< vector< double >, vector< double > > > dMissingMassSquaredCuts_TF1Params
bool Calc_P4_Decay(bool locIsProductionVertex, bool locIsPrimaryProductionVertex, const DSourceCombo *locReactionFullCombo, const DSourceComboUse &locDecayUse, const DSourceCombo *locDecayCombo, DVector3 locVertex, double locTimeOffset, int locRFBunch, double locRFVertexTime, DLorentzVector &locDecayP4, const DKinematicData *locBeamParticle, const DSourceComboUse &locToExcludeUse, size_t locInstanceToExclude, bool locAccuratePhotonsFlag)
const DSourceCombo * Get_StepSourceCombo(const DReaction *locReaction, size_t locDesiredStepIndex, const DSourceCombo *locVertexPrimaryCombo, size_t locVertexPrimaryStepIndex=0) const
Particle_t Get_TargetPID(void) const
Definition: DReactionStep.h:83
bool Get_VertexDeterminableWithCharged(const DReactionStepVertexInfo *locStepVertexInfo) const
static signed char Get_VertexZIndex_OutOfRange(void)
Definition: DSourceCombo.h:80
set< tuple< Particle_t, bool, const DSourceCombo *, const DSourceCombo *, int > > dInvariantMassFilledSet_MassiveNeutral
bool Cut_InvariantMass_NoMassiveNeutrals(const DSourceCombo *locVertexCombo, Particle_t locDecayPID, Particle_t locTargetPIDToSubtract, const DVector3 &locVertex, signed char locVertexZBin, bool locAccuratePhotonsFlag)
static unsigned short int IsDetachedVertex(Particle_t p)
Definition: particleType.h:817
static char * ParticleType(Particle_t p)
Definition: particleType.h:142
DVector3 Get_Vertex(bool locIsProductionVertex, const DSourceCombo *locReactionCombo, const DSourceCombo *locVertexCombo, const DKinematicData *locBeamParticle, bool locIsCombo2ndVertex) const
static signed char Get_VertexZIndex_Unknown(void)
Definition: DSourceCombo.h:82
TLorentzVector DLorentzVector
DVector3 Get_PrimaryVertex(const DReactionVertexInfo *locReactionVertexInfo, const DSourceCombo *locReactionCombo, const DKinematicData *locBeamParticle) const
double Get_PhotonVertexZBinCenter(signed char locVertexZBin) const
DLorentzVector Calc_MassiveNeutralP4(const DNeutralShower *locNeutralShower, Particle_t locPID, const DVector3 &locVertex, double locVertexTime) const
static int ParticleCharge(Particle_t p)
map< tuple< bool, const DSourceCombo *, const DSourceCombo *, int, const DKinematicData *, DSourceComboUse, size_t >, DLorentzVector > dFinalStateP4ByCombo_HasMassiveNeutrals
static signed char Get_VertexZIndex_ZIndependent(void)
Definition: DSourceCombo.h:81
Definition: GlueX.h:19
JApplication * japp
tuple< Particle_t, signed char, const DSourceComboInfo *, bool, Particle_t > DSourceComboUse
Definition: DSourceCombo.h:34
map< Particle_t, TH1 * > dHistMap_InvariantMass
bool Cut_InvariantMass_AccuratePhotonKinematics(const DReactionVertexInfo *locReactionVertexInfo, const DSourceCombo *locReactionFullCombo, const DKinematicData *locBeamParticle, int locRFBunch)
DLorentzVector dSpacetimeVertex
bool Calc_P4_HasMassiveNeutrals(bool locIsProductionVertex, bool locIsPrimaryProductionVertex, const DSourceCombo *locReactionFullCombo, const DSourceCombo *locCurrentCombo, DVector3 locVertex, double locTimeOffset, int locRFBunch, double locRFVertexTime, const DSourceComboUse &locToExcludeUse, size_t locInstanceToExclude, DLorentzVector &locTotalP4, const DKinematicData *locBeamParticle, bool locAccuratePhotonsFlag)
map< Particle_t, TH2 * > dHistMap_MissingMassSquaredVsBeamEnergy
vector< pair< Particle_t, const JObject * > > Get_SourceParticles(bool locEntireChainFlag=false, Charge_t locCharge=d_AllCharges) const
Definition: DSourceCombo.h:290
vector< pair< int, int > > Get_MissingDecayProductIndices(const DReaction *locReaction, size_t locStepIndex)
Definition: DReaction.h:239
bool Get_IsTimeOffsetKnown(bool locIsPrimaryProductionVertex, const DSourceCombo *locReactionCombo, const DSourceCombo *locVertexCombo, const DKinematicData *locBeamParticle) const
signed char Get_PhotonVertexZBin(double locVertexZ) const
map< Particle_t, pair< TF1 *, TF1 * > > dMissingMassSquaredCuts
bool Get_IsComboingZIndependent(void) const
Definition: DSourceCombo.h:177
Definition: GlueX.h:22
Particle_t Get_FinalPID(size_t locIndex) const
Definition: DReactionStep.h:87
vector< pair< float, float > > dMissingPtVsMissingE_PreMissMassSqCut
TH2D * locHist
static constexpr int Get_ParticleIndex_Inclusive(void)
vector< const JObject * > Get_SourceParticles(const vector< pair< Particle_t, const JObject * >> &locSourceParticles, Particle_t locPID=Unknown)
Definition: DSourceCombo.h:369
map< pair< const DSourceCombo *, signed char >, DLorentzVector > dFinalStateP4ByCombo
pair< string, string > dMissingEnergyCuts_TF1FunctionStrings
vector< Particle_t > Get_MissingPIDs(int locStepIndex=-1, Charge_t locCharge=d_AllCharges, bool locIncludeDuplicatesFlag=true) const
Definition: DReaction.cc:46
DLorentzVector lorentzMomentum(void) const
static double ParticleMass(Particle_t p)
vector< const DReactionStepVertexInfo * > Get_StepVertexInfos(void) const
double sqrt(double)
const DSourceCombo * Get_VertexPrimaryCombo(const DSourceCombo *locReactionCombo, const DReactionStepVertexInfo *locStepVertexInfo) const
pair< vector< double >, vector< double > > dMissingEnergyCuts_TF1Params
bool Get_InvariantMassCut(const DSourceCombo *locSourceCombo, Particle_t locDecayPID, bool locAccuratePhotonsFlag, pair< float, float > &locMinMaxMassCuts_GeV) const
vector< const DReactionStepVertexInfo * > Get_StepVertexInfos_ReverseOrderByStep(const DReactionVertexInfo *locReactionVertexInfo)
vector< pair< float, float > > dMissingEVsBeamEnergy_PostMissMassSqCut
map< Particle_t, pair< string, string > > dMissingMassSquaredCuts_TF1FunctionStrings
const DReactionStep * Get_ReactionStep(size_t locStepIndex) const
Definition: DReaction.h:84
DLorentzVector Calc_P4_SourceParticles(const DSourceCombo *locVertexCombo, const DVector3 &locVertex, double locRFVertexTime, bool locAccuratePhotonsFlag)
int Get_DecayStepIndex(const DReaction *locReaction, size_t locStepIndex, size_t locParticleIndex)
Definition: DReaction.cc:135
DVector3 Get_Vertex_NoBeam(bool locIsProductionVertex, const DSourceCombo *locVertexCombo, bool locIsCombo2ndVertex) const
bool Get_IsVertexKnown(bool locIsProductionVertex, const DSourceCombo *locReactionCombo, const DSourceCombo *locVertexCombo, const DKinematicData *locBeamParticle, bool locIsCombo2ndVertex) const
bool Get_IsVertexKnown_NoBeam(bool locIsProductionVertex, const DSourceCombo *locVertexCombo, bool locIsCombo2ndVertex) const
DSourceCombosByUse_Small Get_FurtherDecayCombos(void) const
Definition: DSourceCombo.h:176
vector< const DReactionStep * > Get_ReactionSteps(void) const
Definition: DReaction.h:85
const DSourceComboTimeHandler * dSourceComboTimeHandler
size_t Get_NumReactionSteps(void) const
Definition: DReaction.h:83
bool Cut_InvariantMass_HasMassiveNeutral(bool locIsProductionVertex, bool locIsPrimaryProductionVertex, const DSourceCombo *locReactionFullCombo, const DSourceCombo *locVertexCombo, Particle_t locDecayPID, Particle_t locTargetPIDToSubtract, double locPrimaryVertexZ, const DVector3 &locVertex, double locTimeOffset, vector< int > &locValidRFBunches, const DKinematicData *locBeamParticle, bool locAccuratePhotonsFlag)
set< tuple< Particle_t, const DSourceCombo * > > dInvariantMassFilledSet
map< DetectorSystem_t, TH1 * > dHistMap_2GammaMass
double Calc_PropagatedRFTime(double locPrimaryVertexZ, int locNumRFBunchShifts, double locDetachedVertexTimeOffset) const
bool Get_HasMassiveNeutrals(const DSourceComboInfo *locSourceComboInfo) const
DLorentzVector Calc_P4_NoMassiveNeutrals(const DSourceCombo *locReactionCombo, const DSourceCombo *locVertexCombo, const DVector3 &locVertex, signed char locVertexZBin, const DKinematicData *locBeamParticle, const DSourceComboUse &locToExcludeUse, size_t locInstanceToExclude, bool locAccuratePhotonsFlag)
bool Cut_MissingMassSquared(const DReaction *locReaction, const DReactionVertexInfo *locReactionVertexInfo, const DSourceComboUse &locReactionFullComboUse, const DSourceCombo *locReactionFullCombo, const DKinematicData *locBeamParticle, int locRFBunch)
Particle_t
Definition: particleType.h:12