Hall-D Software  alpha
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
DSourceComboTimeHandler.cc
Go to the documentation of this file.
4 
5 /*************************************************** CHARGED TRACK TIMING CUTS *************************************************
6 *
7 * Charged time cuts are dependent on combo vertex, especially for low-theta tracks.
8 * Wherever the combo vertex is, the track won't pass through it until after the kinfit, so do "final" PID cuts at the end
9 *
10 * Once we have a vertex for the combo, compute POCA to the vertex and do pre-kinfit time cuts there.
11 * This will be pretty accurate, except for slow-single-track channels at low-theta, for which there's nothing you can do anyway.
12 *
13 * We don't want to wait until we have a combo vertex to do some PID timing cuts, but unfortunately we have to.
14 * Since computing neutral timing every 10cm, we can try to do the same for charged tracks as well, but this doesn't work.
15 *
16 * The maximum error associated with this is:
17 *
18 * delta_t = t_prop_track - t_beam
19 * delta_delta_t = delta_t_actual - delta_t_guess
20 * delta_delta_t = (t_prop_track_actual - t_beam_actual) - (t_prop_track_guess - t_beam_guess)
21 * delta_delta_t = (t_prop_track_actual - t_prop_track_guess) - (t_beam_actual - t_beam_guess)
22 *
23 * t_prop_track = t_track - path_track/(beta_track*c)
24 * delta_delta_t = ((t_track - path_track_actual/(beta_track*c)) - (t_track - path_track_guess/(beta_track*c))) - (t_beam_actual - t_beam_guess)
25 * delta_delta_t = (path_track_guess - path_track_actual)/(beta_track*c) - (t_beam_actual - t_beam_guess)
26 *
27 * t_beam = t_RF_targcenter + (vertz - targz)/c
28 * delta_delta_t = (path_track_guess - path_track_actual)/(beta_track*c) - ((t_RF_targcenter + (vertz_actual - targz)/c) - (t_RF_targcenter + (vertz_guess - targz)/c))
29 * delta_delta_t = (path_track_guess - path_track_actual)/(beta_track*c) + (vertz_guess - vertz_actual)/c
30 *
31 * define z_error = vertz_actual - vertz_guess
32 * delta_delta_t = (path_track_guess - path_track_actual)/(beta_track*c) - z_error/c
33 *
34 * From here, assume track is straight over the distance z_error/2:
35 *
36 * FCAL:
37 * path_track_guess = path_z_guess/cos(theta)
38 * path_track_actual = path_z_actual/cos(theta), path_z_actual = path_z_guess - z_error
39 * path_track_guess - path_track_actual = path_z_guess/cos(theta) - (path_z_guess - z_error)/cos(theta) = z_error/cos(theta)
40 * delta_delta_t = z_error/(cos(theta)*beta_track*c) - z_error/c
41 * delta_delta_t = (z_error/c) * [1/(cos(theta)*beta_track) - 1]
42 *
43 * BCAL:
44 * path_track_guess = path_r/sin(theta)
45 * path_track_actual = sqrt(path_z_actual*path_z_actual + path_r*path_r)
46 * path_z_actual = path_z_guess - z_error
47 * path_z_guess = path_r/tan(theta)
48 * path_z_actual = path_r/tan(theta) - z_error
49 * path_track_actual = sqrt((path_r/tan(theta) - z_error)^2 + path_r*path_r)
50 * path_track_actual = path_r*sqrt((1/tan(theta) - z_error/path_r)^2 + 1)
51 * delta_delta_t = path_r*(1/sin(theta) - sqrt((1/tan(theta) - z_error/path_r)^2 + 1))/(beta_track*c) - z_error/c
52 *
53 * These errors are too large:
54 * For slow tracks the errors are huge, and for fast tracks the errors are small.
55 * However, for fast tracks the timing isn't good enough to tell one PID from another anyway.
56 * So this does not gain much.
57 *
58 * Instead, charged track timing cuts cannot be placed until the vertex position is found.
59 *
60 * If it's a detached vertex, it may have been reconstructed at the wrong point.
61 * If we assume a maximum error of 10cm in z on the vertex location, then the delta_t uncertainty is ~2ns for the relevant kinematics (from above eqs)
62 * Therefore, for these charged particles, the cut will be 2ns wider in both directions, and tighter cuts should be placed after the kinfit.
63 *
64 *******************************************************************************************************************************/
65 
66 /**************************************************** PHOTON-RF DELTA-T CUTS ***************************************************
67 *
68 * We would also like to place photon timing cuts in advance as well (these narrow down the possible RF bunch).
69 * However, these also depend on the vertex position.
70 *
71 * The error on the delta-t (delta_delta_t) is derived in a separate section below. The result is:
72 * All: delta_delta_t = dr*[1/sin(theta) - sqrt(1 + (1/tan(theta) - z_error/dr)^2)]/c - z_error/c
73 * BCAL: delta_delta_t = 65*[1/sin(theta) - sqrt(1 + (1/tan(theta) - z_error/65)^2)]/c - z_error/c
74 * FCAL: delta_delta_t = (~650 - z_error)*[1/cos(theta) - sqrt(tan^2(theta) + (1 - z_error/(~650 - z_error))^2)]/c - z_error/c
75 *
76 * For the FCAL, at a z_error of 30cm (center of target + detached-z), the maximum error in delta_delta_t is 22ps
77 * At a z_error of 5cm, delta_delta_t is 3.5ps
78 *
79 * For the BCAL (dr = 65cm), at a z_error of 30cm (center of target + detached-z), the maximum error in delta_delta_t is 1.8ns (at 140 degrees)
80 * For a z_error of 5cm, delta_delta_t is 300ps
81 *
82 * So, since we are evaluating the photons at z-vertex steps of 10cm anyway (for invariant mass), do the same for the photons.
83 * Then, when performing delta-t cuts, increase the width of the cut by the max time error.
84 * This error is strongly theta-dependent, so we can calculate the max error on a shower-by-shower basis using the above equations.
85 *
86 * Because we are comboing as channel-independent as possible, when doing a photon combo we don't know if it's at a detached vertex or not.
87 * So, we must also include a max timing offset when doing time cuts (to select RF bunches) due for detached vertices.
88 * This time offset is also derived below
89 *
90 *******************************************************************************************************************************/
91 
92 /*********************************************** PHOTON-RF DELTA-T CUT DERIVATION **********************************************
93 *
94 * The error on the photon time difference (delta_delta_t) can be found as:
95 * delta_t = t_prop_shower - t_beam
96 * delta_delta_t = delta_t_actual - delta_t_guess
97 * delta_delta_t = (t_prop_shower_actual - t_beam_actual) - (t_prop_shower_guess - t_beam_guess)
98 * delta_delta_t = (t_prop_shower_actual - t_prop_shower_guess) - (t_beam_actual - t_beam_guess)
99 *
100 * t_prop_shower = t_shower - path_shower/c
101 * delta_delta_t = ((t_shower - path_shower_actual/c) - (t_shower - path_shower_guess/c)) - (t_beam_actual - t_beam_guess)
102 * delta_delta_t = (path_shower_guess - path_shower_actual)/c - (t_beam_actual - t_beam_guess)
103 *
104 * t_beam = t_RF_targcenter + (vertz - targz)/c
105 * delta_delta_t = (path_shower_guess - path_shower_actual)/c - ((t_RF_targcenter + (vertz_actual - targz)/c) - (t_RF_targcenter + (vertz_guess - targz)/c))
106 * delta_delta_t = [path_shower_guess - path_shower_actual - vertz_actual + vertz_guess]/c
107 *
108 * define z_error = vertz_actual - vertz_guess
109 * delta_delta_t = [path_shower_guess - path_shower_actual - z_error]/c
110 *
111 * path_shower_guess = shower_pos.Perp()/sin(theta)
112 * path_shower_actual = sqrt(shower_pos.Perp()^2 + path_z_shower_actual^2)
113 *
114 * path_z_shower_actual = shower_z - vertz_actual, vertz_actual = z_error + vertz_guess
115 * path_z_shower_actual = shower_z - (z_error + vertz_guess)
116 * path_z_shower_guess = shower_z - vertz_guess
117 * path_z_shower_actual = path_z_shower_guess - z_error
118 * So, path_shower_actual = sqrt(shower_pos.Perp()^2 + (path_z_shower_guess - z_error)^2)
119 *
120 * path_z_shower_guess = shower_pos.Perp()/tan(theta)
121 * So, path_shower_actual = sqrt(shower_pos.Perp()^2 + (shower_pos.Perp()/tan(theta) - z_error)^2)
122 *
123 * Using dr for shower_pos.Perp() and reducing gives:
124 * path_shower_actual = dr*sqrt(1 + (1/tan(theta) - z_error/dr)^2)
125 * and path_shower_guess = dr/sin(theta)
126 *
127 * So: delta_delta_t = dr*[1/sin(theta) - sqrt(1 + (1/tan(theta) - z_error/dr)^2)]/c - z_error/c
128 *
129 * For the FCAL, dr = dz*tan(theta), dz = 650 - z_error (approx 650)
130 * So: delta_delta_t = (650 - z_error)*[1/cos(theta) - sqrt(tan^2(theta) + (1 - z_error/(650 - z_error))^2)]/c - z_error/c
131 *
132 * For the FCAL, the delta_delta_t is at most 23ps when the z_error is 30cm (center of target + detached vertex) (12 degrees)
133 * Therefore, the z_error is irrelevant: Just choose the center of the target and increase the width of the delta_t cut as needed.
134 *
135 * However, for the BCAL the time error is rather large (largest at large angles (e.g. 140 degrees))
136 * Even with a z_error of 5cm, the delta_delta_t is 300ps. Therefore use 10-cm-wide vertex-z bins and increase the delta_t cut width as needed.
137 *
138 * Now, for the max time offset due to detached vertices:
139 * Worst case: Xi- -> Lambda -> pi0, n: ~30cm, say avg beta = 1/3 (beta can't be too small or ~30cm distance not likely!)
140 * max_time_offset = delta_t_neutral - delta_t_rf
141 * delta_t_neutral = delta_x/(beta*c) = 30/(30*1/3) = 3 ns
142 * delta_t_rf = delta_x/(beta*c) = 30/(1*30) = 1ns
143 * max_time_offset = 3ns - 1ns = 2ns
144 *
145 * And, due to the uncertainty in the position of the detached vertices:
146 * Assume 10cm (as is for charged tracks).
147 * Can use above error functions to increase width of cut. Will want to cut tighter after kinfit.
148 *
149 *******************************************************************************************************************************/
150 
151 //What about particles with unknown vertices? They shouldn't vote (unless those are the only particles), but still need to do a PID cut
152 
153 //Charged tracks:
154 //If vertex is known, can select RF bunch and apply final (only) cut and fill hists:
155 //If vertex is unknown, do PID cuts at end (after beam selection) using the best vertex available: NEED A NEW FUNCTION
156 
157 //Photons:
158 //Initially, without vertex: Hist/cut separately (as unknown)
159 //If vertex is known, can select RF bunch and apply final (only) cut and fill hists:
160 //If vertex is unknown, do PID cuts at end (after beam selection) using the best vertex available: NEED A NEW FUNCTION
161 
162 namespace DAnalysis
163 {
164 
166 {
167  //DEFAULT TIME CUT FUNCTION
169  //DEFINE FUNCTIONS STRINGS FOR PARTICLES/SYSTEMS THAT ARE NOT THE DEFAULT HERE (in dPIDTimingCuts_TF1FunctionString)
170 
171  //DEFINE DEFAULT CUT VALUES //CUTS ARE SYMMETRIC!!
172 
173  //Photon
176 
177  //Unknown: initial RF selection for photons (at beginning of event, prior to vertex) //can be separate cut function
179 
180  //Electrons
184 
185  //Other Leptons
189 
190  //Pions
195 
196  //Kaons
201 
202  //Protons
207 
208 //COMPARE:
209  // Timing Cuts: Start counter
210  // Start counter is special case: Since next to the target, and lower timing resolution, cannot separate PIDs
211  // However, we can separate out-of-time backgrounds from the event (e.g. e+/-, or ghost tracks)
212  // But, we have to be careful: If a lot of hits in the SC, we may accidentally choose the wrong SC hit
213  // This is especially true for low-theta tracks: phi not well defined.
214  // So, this cut will only be applied IF no other PID timing information is available, AND if ONLY 1 ST hit matched to the track in space
215  for(auto& locPIDPair : dPIDTimingCuts_TF1Params)
216  {
217  if(ParticleCharge(locPIDPair.first) != 0)
218  locPIDPair.second[SYS_START] = {2.5};
219  }
220 }
221 
223 {
224  //PARAM EXAMPLES:
225  //COMBO_TIMECUT:14_32=0.75 //Cut protons (14) in the FCAL (32) at +/- 0.75
226  //COMBO_TIMECUT:9_8_FUNC="[0] + [1]*x" //Cut pi-'s (9) in the TOF (8) according to the functional form: +/- ([0] + [1]*p), where p is track momentum
227  //COMBO_TIMECUT:9_8=1.5_0.001 //Set the parameters for the pi- cut function above
228 
229  map<string, string> locParameterMap; //parameter key - filter, value
230  gPARMS->GetParameters(locParameterMap, "COMBO_TIMECUT:"); //gets all parameters with this filter at the beginning of the key
231  for(auto locParamPair : locParameterMap)
232  {
233  if(dDebugLevel)
234  cout << "param pair: " << locParamPair.first << ", " << locParamPair.second << endl;
235 
236  //Figure out which particle was specified
237  auto locUnderscoreIndex = locParamPair.first.find('_');
238  auto locParticleString = locParamPair.first.substr(0, locUnderscoreIndex);
239  istringstream locPIDtream(locParticleString);
240  int locPIDInt;
241  locPIDtream >> locPIDInt;
242  if(locPIDtream.fail())
243  continue;
244  Particle_t locPID = (Particle_t)locPIDInt;
245 
246  //Figure out which detector was specified
247  auto locFuncIndex = locParamPair.first.find("_FUNC");
248  auto locDetectorString = locParamPair.first.substr(locUnderscoreIndex + 1, locFuncIndex);
249  istringstream locDetectorStream(locDetectorString);
250  int locSystemInt;
251  locDetectorStream >> locSystemInt;
252  if(locDetectorStream.fail())
253  continue;
254  DetectorSystem_t locSystem = (DetectorSystem_t)locSystemInt;
255 
256  if(dDebugLevel)
257  cout << "time cut: pid, detector = " << locPID << ", " << locSystem << endl;
258 
259  //get the parameter, with hack so that don't get warning message about no default
260  string locKeyValue;
261  string locFullParamName = string("COMBO_TIMECUT:") + locParamPair.first; //have to add back on the filter
262  gPARMS->SetDefaultParameter(locFullParamName, locKeyValue);
263 
264  //If functional form, save it and continue
265  if(locFuncIndex != string::npos)
266  {
267  dPIDTimingCuts_TF1FunctionString[locPID][locSystem] = locKeyValue;
268  continue;
269  }
270 
271  //is cut parameters: extract and save
272  //CUT PARAMETERS SHOULD BE SEPARATED BY SPACES
273  dPIDTimingCuts_TF1Params[locPID][locSystem].clear(); //get rid of previous cut values
274  while(true)
275  {
276  locUnderscoreIndex = locKeyValue.find('_');
277  auto locValueString = locKeyValue.substr(0, locUnderscoreIndex);
278 
279  istringstream locValuetream(locValueString);
280  double locParameter;
281  locValuetream >> locParameter;
282  if(locValuetream.fail())
283  continue; //must be for a different use
284  if(dDebugLevel)
285  cout << "param: " << locParameter << endl;
286 
287  //save locParameter and truncate locKeyValue (or break if done)
288  dPIDTimingCuts_TF1Params[locPID][locSystem].push_back(locParameter);
289  if(locUnderscoreIndex == string::npos)
290  break;
291  locKeyValue = locKeyValue.substr(locUnderscoreIndex + 1);
292  }
293  }
294 }
295 
297 {
298  //No idea why this lock is necessary, but it crashes without it. Stupid ROOT.
299  japp->RootWriteLock(); //ACQUIRE ROOT LOCK!!
300 
301  for(auto& locPIDPair : dPIDTimingCuts_TF1Params)
302  {
303  auto& locSystemMap = locPIDPair.second;
304  for(auto& locSystemPair : locSystemMap)
305  {
306  auto& locParamVector = locSystemPair.second;
307  if(locParamVector.empty())
308  continue; //should never happen
309 
310  //Get cut string
311  auto locCutFuncString = dDefaultTimeCutFunctionString; //default if nothing special specified
312  if(dPIDTimingCuts_TF1FunctionString.find(locPIDPair.first) != dPIDTimingCuts_TF1FunctionString.end())
313  {
314  auto locSystemStringMap = dPIDTimingCuts_TF1FunctionString[locPIDPair.first];
315  if(locSystemStringMap.find(locSystemPair.first) != locSystemStringMap.end())
316  locCutFuncString = locSystemStringMap[locSystemPair.first];
317  }
318 
319  //Create TF1, Set cut values
320  //These functions can have the same name because we are no longer adding them to the global ROOT list of functions
321  auto locFunc = new TF1("df_TimeCut", locCutFuncString.c_str(), 0.0, 12.0);
322  if(dPrintCutFlag)
323  jout << "Time Cut PID, System, func form, params: " << ParticleType(locPIDPair.first) << ", " << SystemName(locSystemPair.first) << ", " << locCutFuncString;
324  dPIDTimingCuts[locPIDPair.first][locSystemPair.first] = locFunc;
325  for(size_t loc_i = 0; loc_i < locParamVector.size(); ++loc_i)
326  {
327  locFunc->SetParameter(loc_i, locParamVector[loc_i]);
328  if(dPrintCutFlag)
329  jout << ", " << locParamVector[loc_i];
330  }
331  if(dPrintCutFlag)
332  jout << endl;
333 
334  //Reserve space for saving to-histogram quantities
335  dSelectedRFDeltaTs[locPIDPair.first][locSystemPair.first].reserve(1000);
336  }
337  }
339 
340  japp->RootUnLock(); //RELEASE ROOT LOCK!!
341 }
342 
343 DSourceComboTimeHandler::DSourceComboTimeHandler(JEventLoop* locEventLoop, DSourceComboer* locSourceComboer, const DSourceComboVertexer* locSourceComboVertexer) :
344  dSourceComboer(locSourceComboer), dSourceComboVertexer(locSourceComboVertexer)
345 {
346  gPARMS->SetDefaultParameter("COMBO:DEBUG_LEVEL", dDebugLevel);
347  gPARMS->SetDefaultParameter("COMBO:PRINT_CUTS", dPrintCutFlag);
348 
349  //Setup cuts
353 
354  if(locEventLoop == nullptr)
355  return; //only interested in querying cuts
356 
357  //UTILITIES
358  locEventLoop->GetSingle(dAnalysisUtilities);
359 
360  //GET THE GEOMETRY
361  DApplication* locApplication = dynamic_cast<DApplication*>(locEventLoop->GetJApplication());
362  DGeometry* locGeometry = locApplication->GetDGeometry(locEventLoop->GetJEvent().GetRunNumber());
363 
364  //TARGET INFORMATION
365  double locTargetCenterZ = 65.0;
366  locGeometry->GetTargetZ(locTargetCenterZ);
367  dTargetCenter.SetXYZ(0.0, 0.0, locTargetCenterZ);
368  double locTargetLength;
369  locGeometry->GetTargetLength(locTargetLength);
370 
371  //INITIALIZE PHOTON VERTEX-Z EVALUATION BINNING
372  //MAKE SURE THAT THE CENTER OF THE TARGET IS THE CENTER OF A BIN
373  //this is a little convoluted (and can probably be calculated without loops ...), but it ensures the above
374  dPhotonVertexZBinWidth = 10.0;
375  size_t locN = 0;
376  double locTargetUpstreamZ = dTargetCenter.Z() - locTargetLength/2.0;
377  double locTargetDownstreamZ = dTargetCenter.Z() + locTargetLength/2.0;
378  do
379  {
380  ++locN;
381  dPhotonVertexZRangeLow = dTargetCenter.Z() - (double(locN) - 0.5)*dPhotonVertexZBinWidth;
382  }
383  while(dPhotonVertexZRangeLow + dPhotonVertexZBinWidth > locTargetUpstreamZ);
384  while(dPhotonVertexZRangeLow + locN*dPhotonVertexZBinWidth <= locTargetDownstreamZ)
385  ++locN;
386  dNumPhotonVertexZBins = locN + size_t(ceil(20.0/dPhotonVertexZBinWidth) + 0.001); //20 more cm (two extra bins), for detached vertices
387 
388  //print zbins
389  if(dDebugLevel > 0)
390  {
391  cout << "VertexZ Bin Edges: ";
392  for(decltype(dNumPhotonVertexZBins) locZBin = 0; locZBin <= dNumPhotonVertexZBins; ++locZBin)
393  cout << dPhotonVertexZRangeLow + locZBin*dPhotonVertexZBinWidth << ", ";
394  cout << endl;
395  }
396 
397  //Init shower maps
402  for(decltype(dNumPhotonVertexZBins) locZBin = 0; locZBin < dNumPhotonVertexZBins; ++locZBin)
403  {
404  dShowerRFBunches[locZBin] = {};
405  dShowersByBeamBunchByZBin[locZBin] = {};
406  }
407 
408  //BEAM BUNCH PERIOD
409  vector<double> locBeamPeriodVector;
410  locEventLoop->GetCalib("PHOTON_BEAM/RF/beam_period", locBeamPeriodVector);
411  dBeamBunchPeriod = locBeamPeriodVector[0];
412 
413  //Look for troublesome channels: those with photons being produced from a detached vertex
414  //If any, adjust dMaxDecayTimeOffset accordingly
415  auto locReactions = DAnalysis::Get_Reactions(locEventLoop);
416  for(auto& locReaction : locReactions)
417  {
418  for(size_t loc_i = 1; loc_i < locReaction->Get_NumReactionSteps(); ++loc_i)
419  {
420  auto locStep = locReaction->Get_ReactionStep(loc_i);
421  auto locPID = locStep->Get_InitialPID();
422  if(!IsDetachedVertex(locPID))
423  continue;
424  auto locChainPIDs = DAnalysis::Get_ChainPIDs(locReaction, loc_i, -1, {}, true, true);
425  if(std::find(locChainPIDs.begin(), locChainPIDs.end(), Gamma) == locChainPIDs.end())
426  continue;
427  if((locPID == XiMinus) || (locPID == OmegaMinus) || (locPID == Xi0))
428  dMaxDecayTimeOffset = 2.0; //if 2x or 3x strange quarks, increase distance
429  else if(dMaxDecayTimeOffset < 1.9)
430  dMaxDecayTimeOffset = 1.0;
431  }
432  }
433 
434  vector<DetectorSystem_t> locTimingSystems_Charged {SYS_TOF, SYS_BCAL, SYS_FCAL, SYS_START};
435  vector<DetectorSystem_t> locTimingSystems_Neutral {SYS_BCAL, SYS_FCAL};
436  vector<Particle_t> locPIDs {Unknown, Gamma, Electron, Positron, MuonPlus, MuonMinus, PiPlus, PiMinus, KPlus, KMinus, Proton, AntiProton};
437 
438  //CREATE HISTOGRAMS
439  japp->RootWriteLock(); //to prevent undefined behavior due to directory changes, etc.
440  {
441  //get and change to the base (file/global) directory
442  TDirectory* locCurrentDir = gDirectory;
443 
444  string locDirName = "Independent";
445  TDirectoryFile* locDirectoryFile = static_cast<TDirectoryFile*>(gDirectory->GetDirectory(locDirName.c_str()));
446  if(locDirectoryFile == NULL)
447  locDirectoryFile = new TDirectoryFile(locDirName.c_str(), locDirName.c_str());
448  locDirectoryFile->cd();
449 
450  locDirName = "Combo_Construction";
451  locDirectoryFile = static_cast<TDirectoryFile*>(gDirectory->GetDirectory(locDirName.c_str()));
452  if(locDirectoryFile == NULL)
453  locDirectoryFile = new TDirectoryFile(locDirName.c_str(), locDirName.c_str());
454  locDirectoryFile->cd();
455 
456  locDirName = "PID";
457  locDirectoryFile = static_cast<TDirectoryFile*>(gDirectory->GetDirectory(locDirName.c_str()));
458  if(locDirectoryFile == NULL)
459  locDirectoryFile = new TDirectoryFile(locDirName.c_str(), locDirName.c_str());
460  locDirectoryFile->cd();
461 
462  for(auto locPID : locPIDs)
463  {
464  auto locPIDString = string((locPID != Unknown) ? ParticleType(locPID) : "Photons_PreVertex");
465 
466  locDirName = locPIDString;
467  locDirectoryFile = static_cast<TDirectoryFile*>(gDirectory->GetDirectory(locDirName.c_str()));
468  if(locDirectoryFile == NULL)
469  locDirectoryFile = new TDirectoryFile(locDirName.c_str(), locDirName.c_str());
470  locDirectoryFile->cd();
471 
472  auto& locTimingSystems = (ParticleCharge(locPID) == 0) ? locTimingSystems_Neutral : locTimingSystems_Charged;
473  for(auto locSystem : locTimingSystems)
474  {
475  if(locPID != Gamma)
476  {
477  auto locHistName = string("All_RFDeltaTVsP_") + string(SystemName(locSystem));
478  auto locHist = gDirectory->Get(locHistName.c_str());
479  if(locHist == nullptr)
480  {
481  auto locHistTitle = string((locPID != Unknown) ? ParticleName_ROOT(locPID) : "Photons_PreVertex");
482  locHistTitle += string(" Candidates, ") + string(SystemName(locSystem)) + string(";p (GeV/c);#Deltat_{Particle - All RFs}");
483  dHistMap_RFDeltaTVsP_AllRFs[locPID][locSystem] = new TH2I(locHistName.c_str(), locHistTitle.c_str(), 400, 0.0, 12.0, 1400, -7.0, 7.0);
484  }
485  else
486  dHistMap_RFDeltaTVsP_AllRFs[locPID][locSystem] = static_cast<TH2*>(locHist);
487  }
488  if(locPID == Unknown)
489  continue;
490 
491  auto locHistName = string("Best_RFDeltaTVsP_") + string(SystemName(locSystem));
492  auto locHist = gDirectory->Get(locHistName.c_str());
493  if(locHist == nullptr)
494  {
495  auto locHistTitle = string((locPID != Unknown) ? ParticleName_ROOT(locPID) : "Photons_PreVertex");
496  locHistTitle += string(" Candidates, ") + string(SystemName(locSystem)) + string(";p (GeV/c);#Deltat_{Particle - Best RF}");
497  dHistMap_RFDeltaTVsP_BestRF[locPID][locSystem] = new TH2I(locHistName.c_str(), locHistTitle.c_str(), 400, 0.0, 12.0, 1400, -7.0, 7.0);
498  }
499  else
500  dHistMap_RFDeltaTVsP_BestRF[locPID][locSystem] = static_cast<TH2*>(locHist);
501  }
502  gDirectory->cd("..");
503  }
504 
505  gDirectory->cd("..");
506 
507  //Beam-RF delta-t
508  string locHistName = "BeamRFDeltaTVsBeamE";
509  auto locHist = gDirectory->Get(locHistName.c_str());
510  if(locHist == nullptr)
511  dHist_BeamRFDeltaTVsBeamE = new TH2I(locHistName.c_str(), ";Beam Energy;#Deltat_{Beam - RF}", 400, 0.0, 12.0, 3600, -18.0, 18.0);
512  else
513  dHist_BeamRFDeltaTVsBeamE = static_cast<TH2*>(locHist);
514 
515  locCurrentDir->cd();
516  }
517  japp->RootUnLock(); //unlock
518 }
519 
520 void DSourceComboTimeHandler::Setup(const vector<const DNeutralShower*>& locNeutralShowers, const DEventRFBunch* locInitialEventRFBunch, const DDetectorMatches* locDetectorMatches)
521 {
522  //Precompute a few things for the neutral showers, before comboing
523  //Even if it turns out some of this isn't technically needed,
524  //it's still faster than doing a check to see if this has been done or not for every single photon-combo request
525 
526  //GET RF BUNCH
527  dInitialEventRFBunch = locInitialEventRFBunch;
528  dDetectorMatches = locDetectorMatches;
529 
530  //ARRANGE NEUTRAL SHOWERS
531  //also, save to unknown-z, unknown-rf (all showers)
532  vector<const DNeutralShower*> locBCALShowers, locFCALShowers;
533  auto locUnknownZBin = DSourceComboInfo::Get_VertexZIndex_Unknown();
534  for(const auto& locShower : locNeutralShowers)
535  {
536  auto& locContainer = (locShower->dDetectorSystem == SYS_BCAL) ? locBCALShowers : locFCALShowers;
537  locContainer.push_back(locShower);
538  }
539 
540  //CALCULATE KINEMATICS
541  //FCAL: at target center
543  for(const auto& locShower : locFCALShowers)
544  dPhotonKinematics[locFCALZBin].emplace(locShower, Create_KinematicData_Photon(locShower, dTargetCenter));
545 
546  //BCAL: in vertex-z bins
547  for(size_t loc_i = 0; loc_i < dNumPhotonVertexZBins; ++loc_i)
548  {
549  DVector3 locBinCenter(0.0, 0.0, Get_PhotonVertexZBinCenter(loc_i));
550  for(const auto& locShower : locBCALShowers)
551  dPhotonKinematics[loc_i].emplace(locShower, Create_KinematicData_Photon(locShower, locBinCenter));
552  }
553 
554  //DETERMINE WHICH RF BUNCHES ARE VALID
555  //FCAL: at target center
556  for(const auto& locShower : locFCALShowers)
557  Calc_PhotonBeamBunchShifts(locShower, dPhotonKinematics[locFCALZBin][locShower], dInitialEventRFBunch->dTime, locFCALZBin);
558 
559  //BCAL + FCAL: in vertex-z bins
560  for(size_t loc_i = 0; loc_i < dNumPhotonVertexZBins; ++loc_i)
561  {
562  //propagate RF time to vertex position
563  double locPropagatedRFTime = dInitialEventRFBunch->dTime + (Get_PhotonVertexZBinCenter(loc_i) - dTargetCenter.Z())/SPEED_OF_LIGHT;
564  for(const auto& locShower : locBCALShowers)
565  Calc_PhotonBeamBunchShifts(locShower, dPhotonKinematics[loc_i][locShower], locPropagatedRFTime, loc_i);
566  }
567 
568  //sort the by-bunch-by-zbin shower vectors (will do unions later), and remove duplicate BCAL entries in the z-unknown vector
569  for(auto& locZBinPair : dShowersByBeamBunchByZBin) //loop over z-bins
570  {
571  for(auto& locRFShowerPair : locZBinPair.second)
572  {
573  auto& locShowerVector = locRFShowerPair.second;
574  std::sort(locShowerVector.begin(), locShowerVector.end());
575  if(locZBinPair.first == locUnknownZBin) //remove dupe entries
576  locShowerVector.erase(std::unique(locShowerVector.begin(), locShowerVector.end()), locShowerVector.end());
577  }
578  }
579 
580  if(dDebugLevel >= 20)
581  {
582  cout << "SHOWER RF BUNCHES:" << endl;
583  for(const auto& locZBinPair : dShowerRFBunches) //loop over z-bins
584  {
585  for(const auto& locShowerPair : locZBinPair.second) //loop over particles
586  {
587  cout << "z-bin, pointer, system, bunches: " << int(locZBinPair.first) << ", " << locShowerPair.first << ", " << SystemName(static_cast<const DNeutralShower*>(locShowerPair.first)->dDetectorSystem) << ", ";
588  for(const auto& locBunch : locShowerPair.second)
589  cout << locBunch << ", ";
590  cout << endl;
591  }
592  }
593  cout << "SHOWERS BY BEAM BUNCH BY ZBIN:" << endl;
594  for(const auto& locZBinPair : dShowersByBeamBunchByZBin) //loop over z-bins
595  {
596  for(const auto& locBunchPair : locZBinPair.second) //loop over bunches
597  {
598  cout << "z-bin, bunch, showers: " << int(locZBinPair.first) << ", ";
599  if(locBunchPair.first.empty())
600  cout << "ANY, ";
601  else
602  cout << locBunchPair.first.front() << ", ";
603  for(const auto& locShower : locBunchPair.second)
604  cout << locShower << ", ";
605  cout << endl;
606  }
607  }
608  }
609 }
610 
611 void DSourceComboTimeHandler::Calc_PhotonBeamBunchShifts(const DNeutralShower* locNeutralShower, shared_ptr<const DKinematicData>& locKinematicData, double locRFTime, signed char locZBin)
612 {
613  //get delta-t cut
614  auto locSystem = locNeutralShower->dDetectorSystem;
615  auto locDeltaTCut = dPIDTimingCuts[Gamma][locSystem]->Eval(locNeutralShower->dEnergy) + Calc_MaxDeltaTError(locNeutralShower, locKinematicData->momentum().Theta());
616 
617  //do loop over possible #-RF-shifts
618  auto locVertexTime = locKinematicData->time();
619  if(dDebugLevel >= 10)
620  cout << "eval time shifts for shower, system, zbin: " << locNeutralShower << ", " << SystemName(locSystem) << ", " << int(locZBin) << endl;
621  auto locRFShifts = Calc_BeamBunchShifts(locVertexTime, locRFTime, locDeltaTCut, true, Unknown, locSystem, locNeutralShower->dEnergy);
622 
623  auto locJObject = static_cast<const JObject*>(locNeutralShower);
624  if(locSystem == SYS_FCAL)
625  {
626  //FCAL is valid for every z-bin
627  for(auto& locZBinPair : dShowerRFBunches) //loop over z-bins
628  {
629  locZBinPair.second.emplace(locJObject, locRFShifts); //save bunches for each shower
630  for(const auto& locNumShifts : locRFShifts) //save showers by bunch
631  dShowersByBeamBunchByZBin[locZBinPair.first][{locNumShifts}].push_back(locJObject);
632  dShowersByBeamBunchByZBin[locZBinPair.first][{}].push_back(locJObject); //save showers by bunch: any bunch (empty vector)
633  }
634  }
635  else //BCAL: Save to this z-bin & unknown
636  {
637  dShowerRFBunches[locZBin].emplace(locJObject, locRFShifts);
638  dShowerRFBunches[DSourceComboInfo::Get_VertexZIndex_Unknown()].emplace(locJObject, locRFShifts); //will dupe over z's
639  for(const auto& locNumShifts : locRFShifts)
640  {
641  dShowersByBeamBunchByZBin[locZBin][{locNumShifts}].push_back(locJObject);
642  dShowersByBeamBunchByZBin[DSourceComboInfo::Get_VertexZIndex_Unknown()][{locNumShifts}].push_back(locJObject); //will dupe over z's
643  }
644  dShowersByBeamBunchByZBin[DSourceComboInfo::Get_VertexZIndex_Unknown()][{}].push_back(locJObject); //will dupe over z's
645  dShowersByBeamBunchByZBin[locZBin][{}].push_back(locJObject);
646  }
647 }
648 
649 vector<int> DSourceComboTimeHandler::Calc_BeamBunchShifts(double locVertexTime, double locOrigRFBunchPropagatedTime, double locDeltaTCut, bool locIncludeDecayTimeOffset, Particle_t locPID, DetectorSystem_t locSystem, double locP)
650 {
651  if(dDebugLevel >= 10)
652  cout << "DSourceComboTimeHandler::Calc_BeamBunchShifts(): PID, system, period, orig rf time, particle vertex time, orig prop rf time, delta-t cut, include offset: " << locPID << ", " << SystemName(locSystem) << ", " << dBeamBunchPeriod << ", " << dInitialEventRFBunch->dTime << ", " << locVertexTime << ", " << locOrigRFBunchPropagatedTime << ", " << locDeltaTCut << ", " << locIncludeDecayTimeOffset << endl;
653  auto locOrigNumShifts = Calc_RFBunchShift(locOrigRFBunchPropagatedTime, locVertexTime); //get best shift
654  vector<int> locRFShifts;
655 
656  //if this particle is a decay product, the decaying particle may have been moving slowly across a large distance
657  //if so, we must correct for this delta-t before making a comparison
658  //if we know the distance, we can just correct the inputs to this function and it's not an issue
659  //but when evaluating photons before comboing, we obviously don't know the distance
660  //so, that means that we have to asymmetrically widen the cut:
661  //since delta_t = t_particle - t_rf, and this uncertainty acts as an increase to the t_rf (or a decrease to t_particle), we must have a larger delta_t cut on the HIGH side
662  //e.g. a cut at +/- 1ns becomes -1ns to 3ns
663  //this applies to both BCAL & FCAL photons
664  //this is only done at the beginning when picking valid RF bunches for all showers
665  auto locMinDeltaT = -1.0*locDeltaTCut;
666  auto locMaxDeltaT = locIncludeDecayTimeOffset ? locDeltaTCut + dMaxDecayTimeOffset : locDeltaTCut;
667 
668  //start with best-shift, then loop up until fails cut
669  auto locNumShifts = locOrigNumShifts;
670  auto locDeltaT = locVertexTime - (locOrigRFBunchPropagatedTime + locNumShifts*dBeamBunchPeriod);
671  if(dDebugLevel >= 20)
672  cout << "num shifts, delta-t = " << locNumShifts << ", " << locDeltaT << endl;
673  dAllRFDeltaTs[locPID][locSystem].push_back(std::make_pair(locP, locDeltaT));
674  while(((locDeltaT >= locMinDeltaT) && (locDeltaT < locMaxDeltaT)) || (locOrigNumShifts == locNumShifts)) //extra condition for histogramming purposes only
675  {
676  if((locDeltaT >= locMinDeltaT) && (locDeltaT < locMaxDeltaT))
677  {
678  if(dDebugLevel >= 10)
679  cout << "save shift: " << locNumShifts << endl;
680  locRFShifts.push_back(locNumShifts);
681  }
682  ++locNumShifts;
683  locDeltaT = locVertexTime - (locOrigRFBunchPropagatedTime + locNumShifts*dBeamBunchPeriod);
684  if(dDebugLevel >= 20)
685  cout << "num shifts, delta-t = " << locNumShifts << ", " << locDeltaT << endl;
686  dAllRFDeltaTs[locPID][locSystem].push_back(std::make_pair(locP, locDeltaT));
687  }
688 
689  //now loop down in n-shifts
690  locNumShifts = locOrigNumShifts - 1;
691  locDeltaT = locVertexTime - (locOrigRFBunchPropagatedTime + locNumShifts*dBeamBunchPeriod);
692  if(dDebugLevel >= 20)
693  cout << "num shifts, delta-t = " << locNumShifts << ", " << locDeltaT << endl;
694  dAllRFDeltaTs[locPID][locSystem].push_back(std::make_pair(locP, locDeltaT));
695  while((locDeltaT >= locMinDeltaT) && (locDeltaT < locMaxDeltaT))
696  {
697  if(dDebugLevel >= 10)
698  cout << "save shift: " << locNumShifts << endl;
699  locRFShifts.push_back(locNumShifts);
700  --locNumShifts;
701  locDeltaT = locVertexTime - (locOrigRFBunchPropagatedTime + locNumShifts*dBeamBunchPeriod);
702  if(dDebugLevel >= 20)
703  cout << "num shifts, delta-t = " << locNumShifts << ", " << locDeltaT << endl;
704  dAllRFDeltaTs[locPID][locSystem].push_back(std::make_pair(locP, locDeltaT));
705  }
706 
707  std::sort(locRFShifts.begin(), locRFShifts.end());
708  return locRFShifts;
709 }
710 
711 double DSourceComboTimeHandler::Calc_MaxDeltaTError(const DNeutralShower* locNeutralShower, double locTheta, double locZError) const
712 {
713  if(locNeutralShower->dDetectorSystem == SYS_BCAL)
714  {
715  auto locR = locNeutralShower->dSpacetimeVertex.Vect().Perp();
716  auto locPathError = locR*(1.0/sin(locTheta) - sqrt(1.0 + pow(1.0/tan(locTheta) - locZError/locR, 2.0))) - locZError;
717  return fabs(locPathError)/SPEED_OF_LIGHT;
718  }
719 
720  //FCAL
721  double locDeltaZ = locNeutralShower->dSpacetimeVertex.Z() - dTargetCenter.Z();
722  double locMaxZError = dTargetLength/2.0 + 15.0; //center of target + detached vertex
723  //delta_delta_t = (650 - z_error)*[1/cos(theta) - sqrt(tan^2(theta) + (1 - z_error/(650 - z_error))^2)]/c - z_error/c
724  double locPathErrorTerm = 1.0/cos(locTheta) - sqrt(pow(tan(locTheta), 2.0) + pow(1.0 - locMaxZError/(locDeltaZ - locMaxZError), 2.0));
725  double locPathError = (locDeltaZ - locMaxZError)*locPathErrorTerm - locMaxZError;
726  return fabs(locPathError)/SPEED_OF_LIGHT;
727 }
728 
729 bool DSourceComboTimeHandler::Select_RFBunches_Charged(const DReactionVertexInfo* locReactionVertexInfo, const DSourceCombo* locReactionChargedCombo, vector<int>& locValidRFBunches)
730 {
731  if(dDebugLevel >= 10)
732  cout << "DSourceComboTimeHandler::Select_RFBunches_Charged()" << endl;
733  auto locRFIterator = dChargedComboRFBunches.find(locReactionChargedCombo);
734  if(locRFIterator != dChargedComboRFBunches.end())
735  {
736  locValidRFBunches = locRFIterator->second.second; //already computed, return results!!
737  if(dDebugLevel >= 10)
738  cout << "Previously done, passed flag, # valid bunches = " << locRFIterator->second.first << ", " << locValidRFBunches.size() << endl;
739  return locRFIterator->second.first;
740  }
741 
742  //All charged tracks that are at a known vertex position vote, even those not at the primary vertex
743  //loop over vertices, get all charged particles at that vertex, utilize that + time offset
744  //Applying the RF time cuts is effectively applying PID timing cuts
745 
746  //loop over vertices
747  auto locOnlyTrackFlag = (locReactionChargedCombo->Get_SourceParticles(true, d_Charged).size() == 1);
748  locValidRFBunches.clear();
749  auto locPrimaryVertexZ = dSourceComboVertexer->Get_PrimaryVertex(locReactionVertexInfo, locReactionChargedCombo, nullptr).Z();
750  auto locIsPrimaryProductionVertex = locReactionVertexInfo->Get_StepVertexInfo(0)->Get_ProductionVertexFlag();
751 
752  for(const auto& locStepVertexInfo : locReactionVertexInfo->Get_StepVertexInfos())
753  {
754  if(dDebugLevel >= 20)
755  cout << "step: " << locStepVertexInfo->Get_StepIndices().front() << endl;
756 
757  auto locIsProductionVertex = locStepVertexInfo->Get_ProductionVertexFlag();
758  auto locVertexPrimaryCombo = dSourceComboer->Get_VertexPrimaryCombo(locReactionChargedCombo, locStepVertexInfo);
759  if(dDebugLevel >= 20)
760  {
761  cout << "PRIMARY VERTEX COMBO:" << endl;
762  DAnalysis::Print_SourceCombo(locVertexPrimaryCombo);
763  }
765  continue; //vertex position indeterminate at this stage: don't include these tracks
766 
767  //get combo, vertex position, and time offset from RF bunch
768  auto locIsCombo2ndVertex = locStepVertexInfo->Get_FullConstrainParticles(false, d_FinalState, d_Charged, false).empty();
769  auto locVertex = dSourceComboVertexer->Get_Vertex_NoBeam(locIsProductionVertex, locVertexPrimaryCombo, locIsCombo2ndVertex);
770  if(!dSourceComboVertexer->Get_IsTimeOffsetKnown(locIsPrimaryProductionVertex, locReactionChargedCombo, locVertexPrimaryCombo, nullptr))
771  continue; //not from this vertex
772  auto locTimeOffset = dSourceComboVertexer->Get_TimeOffset(locIsPrimaryProductionVertex, locReactionChargedCombo, locVertexPrimaryCombo, nullptr);
773 
774  auto locPropagatedRFTime = Calc_PropagatedRFTime(locPrimaryVertexZ, 0, locTimeOffset);
775 // auto locPropagatedRFTime = Calc_PropagatedRFTime(locVertex.Z(), 0, 0.0); //COMPARE:
776  if(dDebugLevel >= 20)
777  cout << "primary vertex z, targ z, init rf time, time offset, prop time = " << locPrimaryVertexZ << ", " << dTargetCenter.Z() << ", " << dInitialEventRFBunch->dTime << ", " << locTimeOffset << ", " << locPropagatedRFTime << endl;
778 
779  //loop over charged particles
780  auto locChargedParticles = DAnalysis::Get_SourceParticles_ThisVertex(locVertexPrimaryCombo);
781  for(const auto& locParticlePair : locChargedParticles)
782  {
783  auto locChargedHypo = static_cast<const DChargedTrack*>(locParticlePair.second)->Get_Hypothesis(locParticlePair.first);
784  vector<int> locParticleRFBunches;
785  if(!Get_RFBunches_ChargedTrack(locChargedHypo, locIsProductionVertex, locVertexPrimaryCombo, locIsCombo2ndVertex, locVertex, locPropagatedRFTime, locOnlyTrackFlag, !locIsProductionVertex, locParticleRFBunches))
786  {
787  if(dDebugLevel >= 10)
788  cout << "pid, has no timing info = " << locChargedHypo->PID() << endl;
789  continue;
790  }
791  if(dDebugLevel >= 10)
792  cout << "pid, # valid bunches = " << locChargedHypo->PID() << ", " << locParticleRFBunches.size() << endl;
793 
794  if(locParticleRFBunches.empty())
795  {
796  dChargedComboRFBunches.emplace(locReactionChargedCombo, std::make_pair(false, vector<int>{}));
797  return false;
798  }
799 
800  locValidRFBunches = Get_CommonRFBunches(locValidRFBunches, locParticleRFBunches);
801  if(dDebugLevel >= 10)
802  cout << "#common bunches = " << locValidRFBunches.size() << endl;
803  if(locValidRFBunches.empty())
804  {
805  dChargedComboRFBunches.emplace(locReactionChargedCombo, std::make_pair(false, vector<int>{}));
806  return false;
807  }
808  }
809  }
810 
811  dChargedComboRFBunches.emplace(locReactionChargedCombo, std::make_pair(true, locValidRFBunches));
812  if(dDebugLevel >= 10)
813  cout << "# valid bunches = " << locValidRFBunches.size() << endl;
814  return true;
815 }
816 
817 bool DSourceComboTimeHandler::Select_RFBunches_PhotonVertices(const DReactionVertexInfo* locReactionVertexInfo, const DSourceCombo* locReactionFullCombo, vector<int>& locValidRFBunches)
818 {
819  if(dDebugLevel > 0)
820  cout << "Select_RFBunches_PhotonVertices()" << endl;
821 
822  //also, do PID cuts of photons at charged vertices while we're at it
823  auto locRFIterator = dPhotonVertexRFBunches.find(locReactionFullCombo);
824  if(locRFIterator != dPhotonVertexRFBunches.end())
825  {
826  locValidRFBunches = locRFIterator->second.second; //already computed, return results!!
827  return locRFIterator->second.first;
828  }
829 
830  //loop over vertices
831  auto locIsPrimaryProductionVertex = locReactionVertexInfo->Get_StepVertexInfo(0)->Get_ProductionVertexFlag();
832  auto locOnlyTrackFlag = (locReactionFullCombo->Get_SourceParticles(true, d_Charged).size() == 1);
833  auto locPrimaryVertexZ = dSourceComboVertexer->Get_PrimaryVertex(locReactionVertexInfo, locReactionFullCombo, nullptr).Z();
834  for(const auto& locStepVertexInfo : locReactionVertexInfo->Get_StepVertexInfos())
835  {
836  if(locStepVertexInfo->Get_DanglingVertexFlag())
837  continue;
838 
839  auto locIsProductionVertex = locStepVertexInfo->Get_ProductionVertexFlag();
840  bool locVertexDeterminableWithCharged = dSourceComboVertexer->Get_VertexDeterminableWithCharged(locStepVertexInfo);
841 
842  auto locVertexPrimaryFullCombo = dSourceComboer->Get_VertexPrimaryCombo(locReactionFullCombo, locStepVertexInfo);
843  if(!dSourceComboVertexer->Get_IsVertexKnown_NoBeam(locIsProductionVertex, locVertexPrimaryFullCombo, false))
844  continue; //vertex not found yet
845 
846  //get combo, vertex position, and time offset from RF bunch
847  auto locVertex = dSourceComboVertexer->Get_Vertex_NoBeam(locIsProductionVertex, locVertexPrimaryFullCombo, false);
848  auto locVertexZBin = dSourceComboVertexer->Get_VertexZBin_NoBeam(locIsProductionVertex, locVertexPrimaryFullCombo, false);
849  if(!dSourceComboVertexer->Get_IsTimeOffsetKnown(locIsPrimaryProductionVertex, locReactionFullCombo, locVertexPrimaryFullCombo, nullptr))
850  continue; //not from this vertex
851  auto locTimeOffset = dSourceComboVertexer->Get_TimeOffset(locIsPrimaryProductionVertex, locReactionFullCombo, locVertexPrimaryFullCombo, nullptr);
852 
853  auto locPropagatedRFTime = Calc_PropagatedRFTime(locPrimaryVertexZ, 0, locTimeOffset);
854 // auto locPropagatedRFTime = Calc_PropagatedRFTime(locVertex.Z(), 0, 0.0); //COMPARE:
855 
856  //loop over particles at this vertex: BCAL photons & charged tracks get to vote (FCAL photons already voted, but faster)
857  auto locSourceParticles = DAnalysis::Get_SourceParticles_ThisVertex(locVertexPrimaryFullCombo);
858  for(const auto& locParticlePair : locSourceParticles)
859  {
860  auto locPID = locParticlePair.first;
861  vector<int> locParticleRFBunches;
862  if(ParticleCharge(locPID) == 0)
863  {
864  if(ParticleMass(locPID) > 0.0)
865  continue; //massive neutral, can't vote
866  auto locNeutralShower = static_cast<const DNeutralShower*>(locParticlePair.second);
867  auto locSystem = locNeutralShower->dDetectorSystem;
868 
869  //if vertex is known, but is outside of the range of our photon kinematics: so we must select rf bunches manually
870  if(locVertexZBin == DSourceComboInfo::Get_VertexZIndex_OutOfRange())
871  {
872  auto locDeltaTCut = dPIDTimingCuts[Gamma][locSystem]->Eval(locNeutralShower->dEnergy);
873  auto locVertexTime = Calc_Photon_Kinematics(locNeutralShower, locVertex).second;
874  locParticleRFBunches = Calc_BeamBunchShifts(locVertexTime, locPropagatedRFTime, locDeltaTCut, false, Gamma, locSystem, locNeutralShower->dEnergy);
875  if(dDebugLevel >= 10)
876  cout << "post-cut: pid, zbin, #bunches, #valid bunches = " << locPID << ", " << int(locVertexZBin) << ", " << locParticleRFBunches.size() << ", " << locValidRFBunches.size() << endl;
877  }
878  else
879  {
880  locParticleRFBunches = dShowerRFBunches[locVertexZBin][locParticlePair.second];
881  if(dDebugLevel >= 10)
882  cout << "pre-cut: pointer, system, energy, pid, zbin, #bunches, #valid bunches = " << locParticlePair.second << ", " << locSystem << ", " << locNeutralShower->dEnergy << ", " << locPID << ", " << int(locVertexZBin) << ", " << locParticleRFBunches.size() << ", " << locValidRFBunches.size() << endl;
883 
884  //Do PID cut
885  auto PhotonCutter = [&](int locRFBunch) -> bool {return !Cut_PhotonPID(locNeutralShower, locVertex, locPropagatedRFTime + locRFBunch*dBeamBunchPeriod, false, !locIsProductionVertex);};
886  locParticleRFBunches.erase(std::remove_if(locParticleRFBunches.begin(), locParticleRFBunches.end(), PhotonCutter), locParticleRFBunches.end());
887  if(dDebugLevel >= 10)
888  cout << "post-cut: pid, zbin, #bunches = " << locPID << ", " << int(locVertexZBin) << ", " << locParticleRFBunches.size() << endl;
889  }
890  }
891  else if(locVertexDeterminableWithCharged) //charged, previously cut
892  continue;
893  else //charged, a new vertex: do PID cuts
894  {
895  auto locChargedHypo = static_cast<const DChargedTrack*>(locParticlePair.second)->Get_Hypothesis(locParticlePair.first);
896  if(!Get_RFBunches_ChargedTrack(locChargedHypo, locIsProductionVertex, locVertexPrimaryFullCombo, false, locVertex, locPropagatedRFTime, locOnlyTrackFlag, !locIsProductionVertex, locParticleRFBunches))
897  {
898  if(dDebugLevel >= 10)
899  cout << "pid, has no timing info = " << locChargedHypo->PID() << endl;
900  continue;
901  }
902  }
903 
904  if(locParticleRFBunches.empty())
905  {
906  dPhotonVertexRFBunches.emplace(locReactionFullCombo, std::make_pair(false, vector<int>{}));
907  return false;
908  }
909  if(locValidRFBunches.empty())
910  {
911  locValidRFBunches = locParticleRFBunches;
912  continue;
913  }
914 
915  //get common rf bunches
916  locValidRFBunches = Get_CommonRFBunches(locValidRFBunches, locParticleRFBunches);
917  if(dDebugLevel >= 10)
918  cout << "#common bunches = " << locValidRFBunches.size() << endl;
919  if(locValidRFBunches.empty())
920  {
921  dPhotonVertexRFBunches.emplace(locReactionFullCombo, std::make_pair(false, vector<int>{}));
922  return false;
923  }
924  }
925  }
926 
927  dPhotonVertexRFBunches.emplace(locReactionFullCombo, std::make_pair(true, locValidRFBunches));
928  return true;
929 }
930 
931 bool DSourceComboTimeHandler::Select_RFBunches_AllVerticesUnknown(const DReactionVertexInfo* locReactionVertexInfo, const DSourceCombo* locReactionFullCombo, Charge_t locCharge, vector<int>& locValidRFBunches)
932 {
933  if(dDebugLevel > 0)
934  cout << "DSourceComboTimeHandler::Select_RFBunches_AllVerticesUnknown()" << endl;
935 
936  //this function is called to select RF bunches if every vertex is unknown
937  auto locRFIterator = dUnknownVertexRFBunches.find(locReactionFullCombo);
938  if(locRFIterator != dUnknownVertexRFBunches.end())
939  {
940  locValidRFBunches = locRFIterator->second.second; //already computed, return results!!
941  return locRFIterator->second.first;
942  }
943 
944  locValidRFBunches.clear();
945 
946  //get and loop over all particles
947  auto locSourceParticles = locReactionFullCombo->Get_SourceParticles(true, locCharge);
948  auto locVertexZBin = Get_VertexZBin_TargetCenter();
949  auto locOnlyTrackFlag = (locReactionFullCombo->Get_SourceParticles(true, d_Charged).size() == 1);
950  for(const auto& locParticlePair : locSourceParticles)
951  {
952  auto locPID = locParticlePair.first;
953  vector<int> locParticleRFBunches;
954  if(ParticleCharge(locPID) == 0)
955  {
956  if(ParticleMass(locPID) > 0.0)
957  continue; //massive neutral, can't vote
958  auto locNeutralShower = static_cast<const DNeutralShower*>(locParticlePair.second);
959  locParticleRFBunches = dShowerRFBunches[locVertexZBin][locParticlePair.second];
960  if(dDebugLevel >= 10)
961  cout << "pre-cut: pid, #bunches, #valid bunches = " << locPID << ", " << locParticleRFBunches.size() << ", " << locValidRFBunches.size() << endl;
962 
963  //Do PID cut
964  auto PhotonCutter = [&](int locRFBunch) -> bool {return !Cut_PhotonPID(locNeutralShower, dTargetCenter, dInitialEventRFBunch->dTime + locRFBunch*dBeamBunchPeriod, true, false);};
965  locParticleRFBunches.erase(std::remove_if(locParticleRFBunches.begin(), locParticleRFBunches.end(), PhotonCutter), locParticleRFBunches.end());
966  if(dDebugLevel >= 10)
967  cout << "post-cut: pid, #bunches, #valid bunches = " << locPID << ", " << locParticleRFBunches.size() << ", " << locValidRFBunches.size() << endl;
968  }
969  else //charged, a new vertex: do PID cuts
970  {
971  auto locChargedHypo = static_cast<const DChargedTrack*>(locParticlePair.second)->Get_Hypothesis(locParticlePair.first);
972  auto locVertex = locChargedHypo->position();
973  auto locPropagatedRFTime = dInitialEventRFBunch->dTime + (locVertex.Z() - dTargetCenter.Z())/SPEED_OF_LIGHT;
974  if(!Get_RFBunches_ChargedTrack(locChargedHypo, true, nullptr, false, locVertex, locPropagatedRFTime, locOnlyTrackFlag, false, locParticleRFBunches))
975  {
976  if(dDebugLevel >= 10)
977  cout << "pid, has no timing info = " << locChargedHypo->PID() << endl;
978  continue;
979  }
980  if(dDebugLevel >= 10)
981  cout << "pid, # valid bunches = " << locChargedHypo->PID() << ", " << locParticleRFBunches.size() << endl;
982  }
983 
984  if(locParticleRFBunches.empty())
985  {
986  dUnknownVertexRFBunches.emplace(locReactionFullCombo, std::make_pair(false, vector<int>{}));
987  return false;
988  }
989  if(locValidRFBunches.empty())
990  {
991  locValidRFBunches = locParticleRFBunches;
992  continue;
993  }
994 
995  //get common rf bunches
996  locValidRFBunches = Get_CommonRFBunches(locValidRFBunches, locParticleRFBunches);
997  if(dDebugLevel >= 10)
998  cout << "#common bunches = " << locValidRFBunches.size() << endl;
999  if(locValidRFBunches.empty())
1000  {
1001  dUnknownVertexRFBunches.emplace(locReactionFullCombo, std::make_pair(false, vector<int>{}));
1002  return false;
1003  }
1004  }
1005 
1006  if(dDebugLevel >= 10)
1007  cout << "# valid bunches = " << locValidRFBunches.size() << endl;
1008  dUnknownVertexRFBunches.emplace(locReactionFullCombo, std::make_pair(true, locValidRFBunches));
1009  return true;
1010 }
1011 
1012 int DSourceComboTimeHandler::Select_RFBunch_Full(const DReactionVertexInfo* locReactionVertexInfo, const DSourceCombo* locReactionFullCombo, const vector<int>& locRFBunches)
1013 {
1014  //The prior functions narrowed down the possible RF bunches. This function actually selects the RF bunch.
1015 
1016  if(dDebugLevel >= 10)
1017  cout << "DSourceComboTimeHandler::Select_RFBunch_Full()" << endl;
1018 
1019  auto locRFIterator = dFullComboRFBunches.find(locReactionFullCombo);
1020  if(locRFIterator != dFullComboRFBunches.end())
1021  {
1022  if(dDebugLevel >= 10)
1023  cout << "bunch previously determined: " << locRFIterator->second << endl;
1024  return locRFIterator->second; //already computed, return results!!
1025  }
1026 
1027  //note: even if there's only 1 bunch, we still want to histogram: proceed with the function
1028  if(locRFBunches.empty())
1029  return 0; //no information, hope that the default was correct //only detected particles are massive neutrals: e.g. g, p -> K_L, (p)
1030 
1031  //initialize chisq's
1032  unordered_map<int, double> locChiSqByRFBunch;
1033  for(const auto& locRFBunch : locRFBunches)
1034  locChiSqByRFBunch.emplace(locRFBunch, 0.0);
1035 
1036  //voting:
1037  //first use only particles at vertices that have been determined
1038  //then use charged particles at their POCAs to the beamline
1039  //then use photons at the target center
1040  bool locVotedFlag = false;
1041 
1042  //loop over vertices, using only particles at the vertices that have been determined
1043  auto locPrimaryVertexZ = dSourceComboVertexer->Get_PrimaryVertex(locReactionVertexInfo, locReactionFullCombo, nullptr).Z();
1044  auto locIsPrimaryProductionVertex = locReactionVertexInfo->Get_StepVertexInfo(0)->Get_ProductionVertexFlag();
1045  if(dDebugLevel >= 10)
1046  cout << "primary vertex z: " << locPrimaryVertexZ << endl;
1047  map<int, map<Particle_t, map<DetectorSystem_t, vector<pair<float, float>>>>> locRFDeltaTsForHisting; //first float is p, 2nd is delta-t //PID Unknown: photons prior to vertex selection
1048  for(const auto& locStepVertexInfo : locReactionVertexInfo->Get_StepVertexInfos())
1049  {
1050  if(dDebugLevel >= 10)
1051  cout << "Step: " << locStepVertexInfo->Get_StepIndices().front() << endl;
1052 
1053  if(locStepVertexInfo->Get_DanglingVertexFlag())
1054  continue; //unknown position!
1055 
1056  auto locIsProductionVertex = locStepVertexInfo->Get_ProductionVertexFlag();
1057  auto locVertexPrimaryFullCombo = dSourceComboer->Get_VertexPrimaryCombo(locReactionFullCombo, locStepVertexInfo);
1059  continue; //vertex position indeterminate at this stage: don't include these particles
1060 
1061  //get combo, vertex position, and time offset from RF bunch
1062  auto locVertex = dSourceComboVertexer->Get_Vertex_NoBeam(locIsProductionVertex, locVertexPrimaryFullCombo, false);
1063  if(!dSourceComboVertexer->Get_IsTimeOffsetKnown(locIsPrimaryProductionVertex, locReactionFullCombo, locVertexPrimaryFullCombo, nullptr))
1064  continue; //not from this vertex
1065  auto locTimeOffset = dSourceComboVertexer->Get_TimeOffset(locIsPrimaryProductionVertex, locReactionFullCombo, locVertexPrimaryFullCombo, nullptr);
1066  auto locParticles = DAnalysis::Get_SourceParticles_ThisVertex(locVertexPrimaryFullCombo);
1067  if(dDebugLevel >= 10)
1068  cout << "this vertex z, time offset: " << locVertex.Z() << ", " << locTimeOffset << endl;
1069 
1070  for(const auto& locRFBunch : locRFBunches)
1071  {
1072  //propagate rf time to vertex and add time offset (faster to just do it here rather than for each particle)
1073  auto locPropagatedRFTime = Calc_PropagatedRFTime(locPrimaryVertexZ, locRFBunch, locTimeOffset);
1074  if(dDebugLevel >= 10)
1075  cout << "bunch, propagated time: " << locRFBunch << ", " << locPropagatedRFTime << endl;
1076 
1077  //loop over all particles
1078  for(const auto& locParticlePair : locParticles)
1079  {
1080  auto locPID = locParticlePair.first;
1081  if((ParticleCharge(locPID) == 0) && (ParticleMass(locPID) > 0.0))
1082  continue; //ignore massive neutrals: timing defines their momentum, cannot be used
1083 
1084  locVotedFlag = true;
1085  if(ParticleCharge(locPID) == 0)
1086  {
1087  auto locNeutralShower = static_cast<const DNeutralShower*>(locParticlePair.second);
1088  auto locRFDeltaTPair = Calc_RFDeltaTChiSq(locNeutralShower, locVertex, locPropagatedRFTime);
1089  locChiSqByRFBunch[locRFBunch] += locRFDeltaTPair.second;
1090  locRFDeltaTsForHisting[locRFBunch][locPID][locNeutralShower->dDetectorSystem].emplace_back(locNeutralShower->dEnergy, locRFDeltaTPair.first);
1091  }
1092  else //charged
1093  {
1094  auto locChargedHypo = static_cast<const DChargedTrack*>(locParticlePair.second)->Get_Hypothesis(locParticlePair.first);
1095 
1096  //get the timing at the POCA to the vertex (computed previously!)
1097  auto locPOCAPair = std::make_pair(locChargedHypo, dSourceComboVertexer->Get_ConstrainingParticles_NoBeam(locIsProductionVertex, locVertexPrimaryFullCombo, false));
1098  auto locVertexTime = dChargedParticlePOCAToVertexX4.find(locPOCAPair)->second.T();
1099  auto locRFDeltaTPair = Calc_RFDeltaTChiSq(locChargedHypo, locVertexTime, locPropagatedRFTime);
1100  locChiSqByRFBunch[locRFBunch] += locRFDeltaTPair.second;
1101  locRFDeltaTsForHisting[locRFBunch][locPID][locChargedHypo->t1_detector()].emplace_back(locChargedHypo->momentum().Mag(), locRFDeltaTPair.first);
1102  }
1103  }
1104  if(dDebugLevel >= 10)
1105  cout << "bunch, total delta-t chisq = " << locRFBunch << ", " << locChiSqByRFBunch[locRFBunch] << endl;
1106  }
1107 
1108  }
1109 
1110  //if not voted yet, use charged particles at their POCAs to the beamline, else use photons at the target center
1111  if(!locVotedFlag)
1112  {
1113  if(!Compute_RFChiSqs_UnknownVertices(locReactionFullCombo, d_Charged, locRFBunches, locChiSqByRFBunch, locRFDeltaTsForHisting))
1114  Compute_RFChiSqs_UnknownVertices(locReactionFullCombo, d_Neutral, locRFBunches, locChiSqByRFBunch, locRFDeltaTsForHisting);
1115  }
1116 
1117  //ok, total chisq's are computed, pick the one that is the best!
1118  auto Compare_RFChiSqs = [](const pair<int, double>& lhs, const pair<int, double>& rhs) -> bool {return lhs.second < rhs.second;};
1119  auto locRFBunch = std::max_element(locChiSqByRFBunch.begin(), locChiSqByRFBunch.end(), Compare_RFChiSqs)->first;
1120 
1121  if(dDebugLevel >= 10)
1122  cout << "chosen bunch: " << locRFBunch << endl;
1123 
1124  //propagate chosen bunch timing into hist staging vector
1125  for(auto& locPIDPair : locRFDeltaTsForHisting[locRFBunch])
1126  {
1127  for(auto& locSystemPair : locPIDPair.second)
1128  {
1129  auto& locSaveToVector = dSelectedRFDeltaTs[locPIDPair.first][locSystemPair.first];
1130  auto& locMoveFromVector = locSystemPair.second;
1131  std::move(locMoveFromVector.begin(), locMoveFromVector.end(), std::back_inserter(locSaveToVector));
1132  }
1133  }
1134 
1135  //save it and return
1136  dFullComboRFBunches.emplace(locReactionFullCombo, locRFBunch);
1137  return locRFBunch;
1138 }
1139 
1140 void DSourceComboTimeHandler::Vote_OldMethod(const DSourceCombo* locReactionFullCombo, vector<int>& locValidRFBunches)
1141 {
1142  map<int, pair<size_t, double>> locOldMethodVoting; //double: sum(delta-t^2)
1143  auto locVertex = dSourceComboVertexer->Get_Vertex_NoBeam(true, locReactionFullCombo, false);
1144 
1145  if(dDebugLevel >= 20)
1146  cout << "Vote_OldMethod()" << endl;
1147 
1148  //assume all delta-t cuts <= 2ns
1149  auto locParticles = locReactionFullCombo->Get_SourceParticles(true);
1150 
1151  //loop over all particles
1152  for(const auto& locParticlePair : locParticles)
1153  {
1154  auto locPID = locParticlePair.first;
1155  if((ParticleCharge(locPID) == 0) && (ParticleMass(locPID) > 0.0))
1156  continue; //ignore massive neutrals: timing defines their momentum, cannot be used
1157 
1158  vector<int> locParticleRFBunches;
1159  double locVertexTime = 0.0, locPropagatedRFTime = 0.0;
1160  if(ParticleCharge(locPID) == 0)
1161  {
1162  auto locNeutralShower = static_cast<const DNeutralShower*>(locParticlePair.second);
1163  locVertexTime = Calc_Photon_Kinematics(locNeutralShower, locVertex).second;
1164  locPropagatedRFTime = dInitialEventRFBunch->dTime + (locVertex.Z() - dTargetCenter.Z())/SPEED_OF_LIGHT;
1165  locParticleRFBunches = Calc_BeamBunchShifts(locVertexTime, locPropagatedRFTime, 0.5*dBeamBunchPeriod, false, Gamma, locNeutralShower->dDetectorSystem, locNeutralShower->dEnergy);
1166  }
1167  else //charged
1168  {
1169  auto locHypothesis = static_cast<const DChargedTrack*>(locParticlePair.second)->Get_Hypothesis(locParticlePair.first);
1170  auto locP = locHypothesis->momentum().Mag();
1171  if(locHypothesis->t1_detector() == SYS_NULL)
1172  continue;
1173 
1174  //OLD SYSTEM PREFERENCE ORDER FOR SELECTING BUNCHES: TOF/SC/BCAL/FCAL
1175  locVertexTime = locHypothesis->time();
1176  locPropagatedRFTime = dInitialEventRFBunch->dTime + (locHypothesis->position().Z() - dTargetCenter.Z())/SPEED_OF_LIGHT;
1177  if((locHypothesis->t1_detector() != SYS_TOF) && (locHypothesis->Get_SCHitMatchParams() != nullptr))
1178  {
1179  //MUST CUT ON SC TIME TOO!!!
1180  locVertexTime = locHypothesis->Get_SCHitMatchParams()->dHitTime - locHypothesis->Get_SCHitMatchParams()->dFlightTime;
1181  locParticleRFBunches = Calc_BeamBunchShifts(locVertexTime, locPropagatedRFTime, 0.5*dBeamBunchPeriod, false, locPID, SYS_START, locP);
1182  }
1183  else
1184  locParticleRFBunches = Calc_BeamBunchShifts(locVertexTime, locPropagatedRFTime, 0.5*dBeamBunchPeriod, false, locPID, locHypothesis->t1_detector(), locP);
1185  if(dDebugLevel >= 20)
1186  {
1187  cout << "OldMethod: PID, t1, sc, position, prop-rf-time, vertex-time, #bunches, bunches: " << locHypothesis->PID() << ", " << locHypothesis->t1_detector() << ", " << locHypothesis->Get_SCHitMatchParams() << ", " << locHypothesis->position().Z() << ", " << locPropagatedRFTime << ", " << locVertexTime << ", " << locParticleRFBunches.size();
1188  for(auto& locBunch : locParticleRFBunches)
1189  cout << ", " << locBunch;
1190  cout << endl;
1191  }
1192  }
1193 
1194  for(auto& locRFBunch : locParticleRFBunches)
1195  {
1196  double locDeltaT = locVertexTime - (locPropagatedRFTime + dBeamBunchPeriod*locRFBunch);
1197  auto locIterator = locOldMethodVoting.find(locRFBunch);
1198  if(locIterator == locOldMethodVoting.end())
1199  locOldMethodVoting.emplace(locRFBunch, pair<size_t, double>(1, locDeltaT*locDeltaT));
1200  else
1201  {
1202  ++(locIterator->second.first);
1203  locIterator->second.second += locDeltaT*locDeltaT;
1204  }
1205  }
1206  }
1207 
1208  int locChosenBunch = 0;
1209  size_t locMostVotes = 0;
1210  double locBestDeltaTSq = 9999999.9;
1211  for(auto& locVotes : locOldMethodVoting)
1212  {
1213  if(dDebugLevel >= 20)
1214  cout << "bunch, #votes: " << locVotes.first << ", " << locVotes.second.first << endl;
1215  if(locVotes.second.first > locMostVotes)
1216  {
1217  locChosenBunch = locVotes.first;
1218  locMostVotes = locVotes.second.first;
1219  locBestDeltaTSq = locVotes.second.second;
1220  }
1221  else if(locVotes.second.first == locMostVotes)
1222  {
1223  if(locVotes.second.second < locBestDeltaTSq)
1224  {
1225  locChosenBunch = locVotes.first;
1226  locBestDeltaTSq = locVotes.second.second;
1227  }
1228  }
1229  }
1230  if(dDebugLevel >= 20)
1231  cout << "chosen bunch = " << locChosenBunch << endl;
1232 
1233  vector<int> locBestVector{locChosenBunch};
1234  if(locValidRFBunches.empty())
1235  {
1236  locValidRFBunches = locBestVector;
1237  return;
1238  }
1239  vector<int> locCommonRFBunches = {}; //if charged or massive neutrals, ignore (they don't choose at this stage)
1240  std::set_intersection(locBestVector.begin(), locBestVector.end(), locValidRFBunches.begin(), locValidRFBunches.end(), std::back_inserter(locCommonRFBunches));
1241  locValidRFBunches = locCommonRFBunches;
1242 }
1243 
1244 bool DSourceComboTimeHandler::Compute_RFChiSqs_UnknownVertices(const DSourceCombo* locReactionFullCombo, Charge_t locCharge, const vector<int>& locRFBunches, unordered_map<int, double>& locChiSqByRFBunch, map<int, map<Particle_t, map<DetectorSystem_t, vector<pair<float, float>>>>>& locRFDeltaTsForHisting)
1245 {
1246  //get and loop over all particles
1247  auto locSourceParticles = locReactionFullCombo->Get_SourceParticles(true, locCharge);
1248  bool locVotedFlag = false;
1249  for(const auto& locRFBunch : locRFBunches)
1250  {
1251  //loop over all particles
1252  for(const auto& locParticlePair : locSourceParticles)
1253  {
1254  auto locPID = locParticlePair.first;
1255  if((ParticleCharge(locPID) == 0) && (ParticleMass(locPID) > 0.0))
1256  continue; //ignore massive neutrals: timing defines their momentum, cannot be used
1257 
1258  locVotedFlag = true;
1259  if(ParticleCharge(locPID) == 0)
1260  {
1261  auto locNeutralShower = static_cast<const DNeutralShower*>(locParticlePair.second);
1262  auto locPropagatedRFTime = Calc_PropagatedRFTime(dTargetCenter.Z(), locRFBunch, 0.0);
1263  auto locRFDeltaTPair = Calc_RFDeltaTChiSq(locNeutralShower, dTargetCenter, locPropagatedRFTime);
1264  locChiSqByRFBunch[locRFBunch] += locRFDeltaTPair.second;
1265  locRFDeltaTsForHisting[locRFBunch][locPID][locNeutralShower->dDetectorSystem].emplace_back(locNeutralShower->dEnergy, locRFDeltaTPair.first);
1266  }
1267  else //charged
1268  {
1269  auto locChargedHypo = static_cast<const DChargedTrack*>(locParticlePair.second)->Get_Hypothesis(locParticlePair.first);
1270  auto locPropagatedRFTime = Calc_PropagatedRFTime(locChargedHypo->position().Z(), locRFBunch, 0.0);
1271  auto locRFDeltaTPair = Calc_RFDeltaTChiSq(locChargedHypo, locChargedHypo->time(), locPropagatedRFTime);
1272  locChiSqByRFBunch[locRFBunch] += locRFDeltaTPair.second;
1273  locRFDeltaTsForHisting[locRFBunch][locPID][locChargedHypo->t1_detector()].emplace_back(locChargedHypo->momentum().Mag(), locRFDeltaTPair.first);
1274  }
1275  }
1276  if(dDebugLevel >= 10)
1277  cout << "bunch, total delta-t chisq = " << locRFBunch << ", " << locChiSqByRFBunch[locRFBunch] << endl;
1278  }
1279  return locVotedFlag;
1280 }
1281 
1282 bool DSourceComboTimeHandler::Cut_Timing_MissingMassVertices(const DReactionVertexInfo* locReactionVertexInfo, const DSourceCombo* locReactionFullCombo, const DKinematicData* locBeamParticle, int locRFBunch)
1283 {
1284  if(dDebugLevel >= 10)
1285  cout << "DSourceComboTimeHandler::Cut_Timing_MissingMassVertices()" << endl;
1286 
1287  //Also cuts those at dangling vertices
1288 
1289  //All charged tracks vote, even those not at the primary vertex
1290  //loop over vertices, get all charged particles at that vertex, utilize that + time offset
1291  auto locPrimaryVertexZ = dSourceComboVertexer->Get_PrimaryVertex(locReactionVertexInfo, locReactionFullCombo, locBeamParticle).Z();
1292 
1293  //loop over vertices
1294  for(const auto& locStepVertexInfo : locReactionVertexInfo->Get_StepVertexInfos())
1295  {
1296  if(dDebugLevel >= 10)
1297  cout << "Step: " << locStepVertexInfo->Get_StepIndices().front() << ", dangling-flag = " << locStepVertexInfo->Get_DanglingVertexFlag() << endl;
1298 
1299  if(dDebugLevel >= 10)
1300  cout << "determinable flags: " << dSourceComboVertexer->Get_VertexDeterminableWithCharged(locStepVertexInfo) << ", " << dSourceComboVertexer->Get_VertexDeterminableWithPhotons(locStepVertexInfo) << endl;
1302  continue; //these have already been cut!
1304  continue; //these have already been cut!
1305 
1306  //get combo, vertex position, and time offset from RF bunch
1307  auto locIsProductionVertex = locStepVertexInfo->Get_ProductionVertexFlag();
1308  auto locVertexPrimaryFullCombo = dSourceComboer->Get_VertexPrimaryCombo(locReactionFullCombo, locStepVertexInfo);
1309 
1310  //get vertex position and time offset
1311  auto locVertex = dSourceComboVertexer->Get_Vertex(locStepVertexInfo, locReactionFullCombo, locBeamParticle, false);
1312  auto locTimeOffset = dSourceComboVertexer->Get_TimeOffset(locReactionVertexInfo, locStepVertexInfo, locReactionFullCombo, locBeamParticle);
1313  auto locPropagatedRFTime = Calc_PropagatedRFTime(locPrimaryVertexZ, locRFBunch, locTimeOffset);
1314 // auto locPropagatedRFTime = Calc_PropagatedRFTime(locVertex.Z(), locRFBunch, 0.0); //COMPARE:
1315 
1316  //loop over particles at this vertex: BCAL photons & charged tracks will get cut (FCAL photons already voted!)
1317  auto locSourceParticles = DAnalysis::Get_SourceParticles_ThisVertex(locVertexPrimaryFullCombo);
1318  for(const auto& locParticlePair : locSourceParticles)
1319  {
1320  auto locPID = locParticlePair.first;
1321  if(ParticleCharge(locPID) == 0)
1322  {
1323  if(ParticleMass(locPID) > 0.0)
1324  continue; //massive neutral, can't vote
1325  auto locNeutralShower = static_cast<const DNeutralShower*>(locParticlePair.second);
1326 
1327  //Do PID cut
1328  if(!Cut_PhotonPID(locNeutralShower, locVertex, locPropagatedRFTime, false, !locIsProductionVertex))
1329  return false;
1330  }
1331  else //charged
1332  {
1333  auto locChargedHypo = static_cast<const DChargedTrack*>(locParticlePair.second)->Get_Hypothesis(locParticlePair.first);
1334  if(!Cut_TrackPID(locChargedHypo, locIsProductionVertex, locReactionFullCombo, locVertexPrimaryFullCombo, locBeamParticle, false, locVertex, locPropagatedRFTime, !locIsProductionVertex))
1335  return false;
1336  }
1337  }
1338  }
1339 
1340  return true;
1341 }
1342 
1344 {
1345  japp->WriteLock("DSourceComboTimeHandler");
1346  {
1347  for(auto& locDeltaTPair : dBeamRFDeltaTs)
1348  dHist_BeamRFDeltaTVsBeamE->Fill(locDeltaTPair.first, locDeltaTPair.second);
1349 
1350  for(auto& locPIDPair : dSelectedRFDeltaTs)
1351  {
1352  auto locPIDIterator = dHistMap_RFDeltaTVsP_BestRF.find(locPIDPair.first);
1353  if(locPIDIterator == dHistMap_RFDeltaTVsP_BestRF.end())
1354  continue;
1355  for(auto& locSystemPair : locPIDPair.second)
1356  {
1357  auto locSystemIterator = locPIDIterator->second.find(locSystemPair.first);
1358  if(locSystemIterator == locPIDIterator->second.end())
1359  continue;
1360 
1361  auto& locBestHist = locSystemIterator->second;
1362  for(auto& locVectorPair : locSystemPair.second) //best vector
1363  locBestHist->Fill(locVectorPair.first, locVectorPair.second);
1364  }
1365  }
1366 
1367  for(auto& locPIDPair : dAllRFDeltaTs)
1368  {
1369  auto locPIDIterator = dHistMap_RFDeltaTVsP_AllRFs.find(locPIDPair.first);
1370  if(locPIDIterator == dHistMap_RFDeltaTVsP_AllRFs.end())
1371  continue;
1372  for(auto& locSystemPair : locPIDPair.second)
1373  {
1374  auto locSystemIterator = locPIDIterator->second.find(locSystemPair.first);
1375  if(locSystemIterator == locPIDIterator->second.end())
1376  continue;
1377 
1378  auto& locAllHist = locSystemIterator->second;
1379  for(auto& locVectorPair : locSystemPair.second) //best vector
1380  locAllHist->Fill(locVectorPair.first, locVectorPair.second);
1381  }
1382  }
1383  }
1384  japp->Unlock("DSourceComboTimeHandler");
1385 
1386  //Reset for next event
1387  decltype(dBeamRFDeltaTs)().swap(dBeamRFDeltaTs);
1388  for(auto& locPIDPair : dSelectedRFDeltaTs)
1389  {
1390  for(auto& locSystemPair : locPIDPair.second)
1391  decltype(locSystemPair.second)().swap(locSystemPair.second);
1392  }
1393  for(auto& locPIDPair : dAllRFDeltaTs)
1394  {
1395  for(auto& locSystemPair : locPIDPair.second)
1396  decltype(locSystemPair.second)().swap(locSystemPair.second);
1397  }
1398 }
1399 
1400 bool DSourceComboTimeHandler::Get_RFBunches_ChargedTrack(const DChargedTrackHypothesis* locHypothesis, bool locIsProductionVertex, const DSourceCombo* locVertexPrimaryCombo, bool locIsCombo2ndVertex, DVector3 locVertex, double locPropagatedRFTime, bool locOnlyTrackFlag, bool locDetachedVertex, vector<int>& locRFBunches)
1401 {
1402  locRFBunches.clear();
1403  auto locPID = locHypothesis->PID();
1404  auto locSystem = locHypothesis->t1_detector();
1405  if(locSystem == SYS_NULL)
1406  return false; //no timing info
1407 
1408  //COMPARE: NOT Comparison-to-old mode
1409  if((locSystem == SYS_START) && !locOnlyTrackFlag)
1410  {
1411  //special case: only cut if only matched to 1 ST hit
1412  vector<shared_ptr<const DSCHitMatchParams>> locSCMatchParams;
1413  dDetectorMatches->Get_SCMatchParams(locHypothesis->Get_TrackTimeBased(), locSCMatchParams);
1414  if(locSCMatchParams.size() > 1)
1415  return false; //don't cut on timing! can't tell for sure!
1416  }
1417 
1418  auto locX4 = Get_ChargedPOCAToVertexX4(locHypothesis, locIsProductionVertex, nullptr, locVertexPrimaryCombo, nullptr, locIsCombo2ndVertex, locVertex);
1419  auto locVertexTime = locX4.T();
1420 
1421  auto locP = locHypothesis->momentum().Mag();
1422  auto locCutFunc = Get_TimeCutFunction(locPID, locSystem);
1423  auto locDeltaTCut = (locCutFunc != nullptr) ? locCutFunc->Eval(locP) : 3.0; //if null will return false, but still use for histogramming
1424  if(locDetachedVertex) //not in COMPARE mode
1425  locDeltaTCut += dChargedDecayProductTimeUncertainty;
1426 
1427  if(false) //COMPARE: Comparison-to-old mode
1428  {
1429  locVertexTime = locHypothesis->time();
1430  locPropagatedRFTime += (locHypothesis->position().Z() - locVertex.Z())/SPEED_OF_LIGHT;
1431  if(dDebugLevel >= 20)
1432  cout << "charged track z, new track vert time, new prop rf time: " << locHypothesis->position().Z() << ", " << locVertexTime << ", " << locPropagatedRFTime << endl;
1433  }
1434 
1435  locRFBunches = Calc_BeamBunchShifts(locVertexTime, locPropagatedRFTime, locDeltaTCut, false, locPID, locSystem, locP);
1436  return (locCutFunc != nullptr);
1437 }
1438 
1439 //evaluate timing at the POCA to the vertex
1440 DLorentzVector DSourceComboTimeHandler::Get_ChargedPOCAToVertexX4(const DChargedTrackHypothesis* locHypothesis, bool locIsProductionVertex, const DSourceCombo* locReactionFullCombo, const DSourceCombo* locVertexPrimaryCombo, const DKinematicData* locBeamPhoton, bool locIsCombo2ndVertex, DVector3 locVertex)
1441 {
1442  auto locX4(locHypothesis->x4());
1443  if(locVertexPrimaryCombo == nullptr)
1444  return locX4;
1445 
1446  auto locP4(locHypothesis->lorentzMomentum());
1447  auto locPOCAPair = std::make_pair(locHypothesis, dSourceComboVertexer->Get_ConstrainingParticles(locIsProductionVertex, locReactionFullCombo, locVertexPrimaryCombo, locBeamPhoton, locIsCombo2ndVertex));
1448  auto locPOCAIterator = dChargedParticlePOCAToVertexX4.find(locPOCAPair);
1449  if(locPOCAIterator != dChargedParticlePOCAToVertexX4.end())
1450  return locPOCAIterator->second;
1451 
1452  //do the propagation
1453  dAnalysisUtilities->Propagate_Track(locHypothesis->charge(), locVertex, locX4, locP4, nullptr);
1454  dChargedParticlePOCAToVertexX4.emplace(locPOCAPair, locX4); //save results so we don't have to do it again
1455  return locX4;
1456 }
1457 
1458 bool DSourceComboTimeHandler::Cut_PhotonPID(const DNeutralShower* locNeutralShower, const DVector3& locVertex, double locPropagatedRFTime, bool locTargetCenterFlag, bool locDetachedVertex)
1459 {
1460  //get delta-t cut
1461  auto locSystem = locNeutralShower->dDetectorSystem;
1462  auto locPID = locTargetCenterFlag ? Unknown : Gamma;
1463  auto locCutFunc = Get_TimeCutFunction(locPID, locSystem);
1464  if(locCutFunc == nullptr)
1465  return true;
1466 
1467  auto locKinematicsPair = Calc_Photon_Kinematics(locNeutralShower, locVertex);
1468 
1469  auto locDeltaTCut = locCutFunc->Eval(locNeutralShower->dEnergy);
1470  if(locDetachedVertex) //not in COMPARE mode
1471  locDeltaTCut += Calc_MaxDeltaTError(locNeutralShower, locKinematicsPair.first.Theta(), dDetachedPathLengthUncertainty);
1472 
1473  //do cut
1474  auto locDeltaT = locKinematicsPair.second - locPropagatedRFTime;
1475  if(dDebugLevel >= 10)
1476  cout << "photon pid cut: pointer, system, vertex-z, photon t, rf t, delta_t, cut-delta-t, result = " << locNeutralShower << ", " << locSystem << ", " << locVertex.Z() << ", " << locKinematicsPair.second << ", " << locPropagatedRFTime << ", " << locDeltaT << ", " << locDeltaTCut << ", " << (fabs(locDeltaT) <= locDeltaTCut) << endl;
1477  if(locTargetCenterFlag) //only histogram if vertex is unknown: if vertex is known, it is histed elsewhere
1478  dSelectedRFDeltaTs[locPID][locSystem].emplace_back(locNeutralShower->dEnergy, locDeltaT);
1479  return (fabs(locDeltaT) <= locDeltaTCut);
1480 }
1481 
1482 bool DSourceComboTimeHandler::Cut_TrackPID(const DChargedTrackHypothesis* locHypothesis, bool locIsProductionVertex, const DSourceCombo* locFullReactionCombo, const DSourceCombo* locVertexPrimaryCombo, const DKinematicData* locBeamPhoton, bool locIsCombo2ndVertex, DVector3 locVertex, double locPropagatedRFTime, bool locDetachedVertex)
1483 {
1484  //get delta-t cut
1485  auto locPID = locHypothesis->PID();
1486  auto locSystem = locHypothesis->t1_detector();
1487  auto locCutFunc = Get_TimeCutFunction(locPID, locSystem);
1488  if(locCutFunc == nullptr)
1489  return true;
1490 
1491  auto locP = locHypothesis->momentum().Mag();
1492  auto locDeltaTCut = locCutFunc->Eval(locP);
1493  if(locDetachedVertex) //not in COMPARE mode
1494  locDeltaTCut += dChargedDecayProductTimeUncertainty;
1495 
1496  //COMPARE: NOT Comparison-to-old mode
1497  if(locSystem == SYS_START) //can't be only track if it's a detached vertex (which is the only way this function is called)
1498  {
1499  //special case: only cut if only matched to 1 ST hit
1500  vector<shared_ptr<const DSCHitMatchParams>> locSCMatchParams;
1501  dDetectorMatches->Get_SCMatchParams(locHypothesis->Get_TrackTimeBased(), locSCMatchParams);
1502  if(locSCMatchParams.size() > 1)
1503  return true; //don't cut on timing! can't tell for sure!
1504  }
1505 
1506  auto locX4 = Get_ChargedPOCAToVertexX4(locHypothesis, locIsProductionVertex, locFullReactionCombo, locVertexPrimaryCombo, locBeamPhoton, locIsCombo2ndVertex, locVertex);
1507  auto locDeltaT = locX4.T() - locPropagatedRFTime;
1508 
1509  if(false) //COMPARE: Comparison-to-old mode
1510  {
1511  auto locVertexTime = locHypothesis->time();
1512  locPropagatedRFTime += (locHypothesis->position().Z() - locVertex.Z())/SPEED_OF_LIGHT;
1513  locDeltaT = locVertexTime - locPropagatedRFTime;
1514  if(dDebugLevel >= 20)
1515  cout << "charged track z, new track vert time, new prop rf time: " << locHypothesis->position().Z() << ", " << locVertexTime << ", " << locPropagatedRFTime << endl;
1516  }
1517 
1518  //do cut
1519  if(dDebugLevel >= 10)
1520  cout << "track pid cut: pid, pointer, system, vertex-z, track t, rf t, delta_t, cut-delta-t, result = " << locPID << ", " << locHypothesis << ", " << locSystem << ", " << locVertex.Z() << ", " << locX4.T() << ", " << locPropagatedRFTime << ", " << locDeltaT << ", " << locDeltaTCut << ", " << (fabs(locDeltaT) <= locDeltaTCut) << endl;
1521  dSelectedRFDeltaTs[locPID][locSystem].emplace_back(locP, locDeltaT);
1522  return (fabs(locDeltaT) <= locDeltaTCut);
1523 }
1524 
1525 }
1526 
bool Compute_RFChiSqs_UnknownVertices(const DSourceCombo *locReactionFullCombo, Charge_t locCharge, const vector< int > &locRFBunches, unordered_map< int, double > &locChiSqByRFBunch, map< int, map< Particle_t, map< DetectorSystem_t, vector< pair< float, float >>>>> &locRFDeltaTsForHisting)
bool Select_RFBunches_PhotonVertices(const DReactionVertexInfo *locReactionVertexInfo, const DSourceCombo *locReactionFullCombo, vector< int > &locValidRFBunches)
bool Get_VertexDeterminableWithPhotons(const DReactionStepVertexInfo *locStepVertexInfo) const
unordered_map< const DSourceCombo *, pair< bool, vector< int > > > dUnknownVertexRFBunches
signed char Get_VertexZBin_NoBeam(bool locIsProductionVertex, const DSourceCombo *locPrimaryVertexCombo, bool locIsCombo2ndVertex) const
int Select_RFBunch_Full(const DReactionVertexInfo *locReactionVertexInfo, const DSourceCombo *locReactionFullCombo, const vector< int > &locRFBunches)
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
vector< int > Get_CommonRFBunches(const vector< int > &locRFBunches1, const JObject *locObject, signed char locVertexZBin) const
#define SPEED_OF_LIGHT
void Setup(const vector< const DNeutralShower * > &locNeutralShowers, const DEventRFBunch *locInitialEventRFBunch, const DDetectorMatches *locDetectorMatches)
bool Get_RFBunches_ChargedTrack(const DChargedTrackHypothesis *locHypothesis, bool locIsProductionVertex, const DSourceCombo *locVertexPrimaryCombo, bool locIsCombo2ndVertex, DVector3 locVertex, double locPropagatedRFTime, bool locOnlyTrackFlag, bool locDetachedVertex, vector< int > &locRFBunches)
bool Get_SCMatchParams(const DTrackingData *locTrack, vector< shared_ptr< const DSCHitMatchParams > > &locMatchParams) const
TVector3 DVector3
Definition: DVector3.h:14
Definition: GlueX.h:16
DLorentzVector Get_ChargedPOCAToVertexX4(const DChargedTrackHypothesis *locHypothesis, bool locIsProductionVertex, const DSourceCombo *locReactionFullCombo, const DSourceCombo *locVertexPrimaryCombo, const DKinematicData *locBeamPhoton, bool locIsCombo2ndVertex, DVector3 locVertex)
double Calc_MaxDeltaTError(const DNeutralShower *locNeutralShower, double locTheta) const
vector< const DReaction * > Get_Reactions(JEventLoop *locEventLoop)
Definition: DReaction.cc:218
map< pair< const DKinematicData *, vector< const DKinematicData * > >, DLorentzVector > dChargedParticlePOCAToVertexX4
const DReactionStepVertexInfo * Get_StepVertexInfo(size_t locStepIndex) const
char string[256]
pair< double, double > Calc_RFDeltaTChiSq(const DNeutralShower *locNeutralShower, const TVector3 &locVertex, double locPropagatedRFTime) const
const DVector3 & position(void) const
vector< const DKinematicData * > Get_ConstrainingParticles_NoBeam(bool locIsProductionVertex, const DSourceCombo *locVertexCombo, bool locIsCombo2ndVertex) const
map< Particle_t, map< DetectorSystem_t, vector< pair< float, float > > > > dAllRFDeltaTs
const DTrackTimeBased * Get_TrackTimeBased(void) const
bool Get_VertexDeterminableWithCharged(const DReactionStepVertexInfo *locStepVertexInfo) const
static signed char Get_VertexZIndex_OutOfRange(void)
Definition: DSourceCombo.h:80
unordered_map< signed char, unordered_map< const JObject *, vector< int > > > dShowerRFBunches
static unsigned short int IsDetachedVertex(Particle_t p)
Definition: particleType.h:817
static char * ParticleType(Particle_t p)
Definition: particleType.h:142
shared_ptr< const DKinematicData > Create_KinematicData_Photon(const DNeutralShower *locNeutralShower, const DVector3 &locVertex) const
DVector3 Get_Vertex(bool locIsProductionVertex, const DSourceCombo *locReactionCombo, const DSourceCombo *locVertexCombo, const DKinematicData *locBeamParticle, bool locIsCombo2ndVertex) const
bool Cut_PhotonPID(const DNeutralShower *locNeutralShower, const DVector3 &locVertex, double locPropagatedRFTime, bool locTargetCenterFlag, bool locDetachedVertex)
DLorentzVector x4(void) const
DetectorSystem_t
Definition: GlueX.h:15
int Calc_RFBunchShift(double locTimeToStepTo) 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
map< Particle_t, map< DetectorSystem_t, TH2 * > > dHistMap_RFDeltaTVsP_AllRFs
static int ParticleCharge(Particle_t p)
Charge_t
static signed char Get_VertexZIndex_ZIndependent(void)
Definition: DSourceCombo.h:81
Definition: GlueX.h:19
map< Particle_t, map< DetectorSystem_t, vector< pair< float, float > > > > dSelectedRFDeltaTs
map< Particle_t, map< DetectorSystem_t, vector< double > > > dPIDTimingCuts_TF1Params
JApplication * japp
vector< Particle_t > Get_ChainPIDs(const DReaction *locReaction, size_t locStepIndex, int locUpToStepIndex, vector< Particle_t > locUpThroughPIDs, bool locExpandDecayingFlag, bool locExcludeMissingFlag)
Definition: DReaction.cc:162
DetectorSystem_t dDetectorSystem
DLorentzVector dSpacetimeVertex
pair< DVector3, double > Calc_Photon_Kinematics(const DNeutralShower *locNeutralShower, const DVector3 &locVertex) const
double time(void) const
vector< pair< Particle_t, const JObject * > > Get_SourceParticles(bool locEntireChainFlag=false, Charge_t locCharge=d_AllCharges) const
Definition: DSourceCombo.h:290
void Vote_OldMethod(const DSourceCombo *locReactionFullCombo, vector< int > &locValidRFBunches)
bool Get_IsTimeOffsetKnown(bool locIsPrimaryProductionVertex, const DSourceCombo *locReactionCombo, const DSourceCombo *locVertexCombo, const DKinematicData *locBeamParticle) const
Definition: GlueX.h:20
void Calc_PhotonBeamBunchShifts(const DNeutralShower *locNeutralShower, shared_ptr< const DKinematicData > &locKinematicData, double locRFTime, signed char locZBin)
DGeometry * GetDGeometry(unsigned int run_number)
Definition: GlueX.h:22
bool Cut_Timing_MissingMassVertices(const DReactionVertexInfo *locReactionVertexInfo, const DSourceCombo *locReactionFullCombo, const DKinematicData *locBeamParticle, int locRFBunch)
bool Cut_TrackPID(const DChargedTrackHypothesis *locHypothesis, bool locIsProductionVertex, const DSourceCombo *locFullReactionCombo, const DSourceCombo *locVertexPrimaryCombo, const DKinematicData *locBeamPhoton, bool locIsCombo2ndVertex, DVector3 locVertex, double locPropagatedRFTime, bool locDetachedVertex)
TH2D * locHist
double charge(void) const
bool Select_RFBunches_Charged(const DReactionVertexInfo *locReactionVertexInfo, const DSourceCombo *locChargedCombo, vector< int > &locValidRFBunches)
const char * SystemName(DetectorSystem_t sys)
Definition: GlueX.h:38
bool Select_RFBunches_AllVerticesUnknown(const DReactionVertexInfo *locReactionVertexInfo, const DSourceCombo *locReactionFullCombo, Charge_t locCharge, vector< int > &locValidRFBunches)
DLorentzVector lorentzMomentum(void) const
map< Particle_t, map< DetectorSystem_t, string > > dPIDTimingCuts_TF1FunctionString
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
TF1 * Get_TimeCutFunction(Particle_t locPID, DetectorSystem_t locSystem) const
double sin(double)
vector< const DKinematicData * > Get_ConstrainingParticles(bool locIsProductionVertex, const DSourceCombo *locReactionCombo, const DSourceCombo *locVertexCombo, const DKinematicData *locBeamParticle, bool locIsCombo2ndVertex) const
const DVector3 & momentum(void) const
double Propagate_Track(int locCharge, const DVector3 &locPropagateToPoint, DLorentzVector &locMeasuredX4, DLorentzVector &locMeasuredP4, TMatrixFSym *locCovarianceMatrix) const
map< Particle_t, map< DetectorSystem_t, TF1 * > > dPIDTimingCuts
unordered_map< signed char, DPhotonShowersByBeamBunch > dShowersByBeamBunchByZBin
unordered_map< const DSourceCombo *, pair< bool, vector< int > > > dPhotonVertexRFBunches
vector< pair< Particle_t, const JObject * > > Get_SourceParticles_ThisVertex(const DSourceCombo *locSourceCombo, Charge_t locCharge=d_AllCharges)
Definition: DSourceCombo.h:396
DVector3 Get_Vertex_NoBeam(bool locIsProductionVertex, const DSourceCombo *locVertexCombo, bool locIsCombo2ndVertex) const
bool Get_IsVertexKnown_NoBeam(bool locIsProductionVertex, const DSourceCombo *locVertexCombo, bool locIsCombo2ndVertex) const
const DSourceComboVertexer * dSourceComboVertexer
unordered_map< const DSourceCombo *, pair< bool, vector< int > > > dChargedComboRFBunches
unordered_map< const DSourceCombo *, int > dFullComboRFBunches
vector< int > Calc_BeamBunchShifts(double locVertexTime, double locOrigRFBunchPropagatedTime, double locDeltaTCut, bool locIncludeDecayTimeOffset, Particle_t locPID, DetectorSystem_t locSystem, double locP)
bool GetTargetLength(double &target_length) const
z-location of center of target
Definition: DGeometry.cc:1972
DetectorSystem_t t1_detector(void) const
bool GetTargetZ(double &z_target) const
z-location of center of target
Definition: DGeometry.cc:1933
double Calc_PropagatedRFTime(double locPrimaryVertexZ, int locNumRFBunchShifts, double locDetachedVertexTimeOffset) const
Particle_t PID(void) const
const DAnalysisUtilities * dAnalysisUtilities
vector< pair< float, float > > dBeamRFDeltaTs
map< Particle_t, map< DetectorSystem_t, TH2 * > > dHistMap_RFDeltaTVsP_BestRF
void Print_SourceCombo(const DSourceCombo *locCombo, unsigned char locNumTabs=0)
Definition: DSourceCombo.h:346
Particle_t
Definition: particleType.h:12