Bug Summary

File:/home/sdobbs/work/clang/halld_recon/src/libraries/ANALYSIS/DSourceComboer.cc
Warning:line 2061, column 3
Called C++ object pointer is null

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -main-file-name DSourceComboer.cc -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /w/halld-scifs17exp/home/sdobbs/clang/llvm-project/install/lib/clang/12.0.0 -D HAVE_CCDB -D HAVE_RCDB -D HAVE_EVIO -D HAVE_TMVA=1 -D RCDB_MYSQL=1 -D RCDB_SQLITE=1 -D SQLITE_USE_LEGACY_STRUCT=ON -I .Linux_CentOS7.7-x86_64-gcc4.8.5/libraries/ANALYSIS -I libraries/ANALYSIS -I . -I libraries -I libraries/include -I /w/halld-scifs17exp/home/sdobbs/clang/halld_recon/Linux_CentOS7.7-x86_64-gcc4.8.5/include -I external/xstream/include -I /usr/include/tirpc -I /group/halld/Software/builds/Linux_CentOS7.7-x86_64-gcc4.8.5/root/root-6.08.06/include -I /w/halld-scifs17exp/halld2/home/sdobbs/Software/jana/jana_0.8.2/Linux_CentOS7.7-x86_64-gcc4.8.5/include -I /group/halld/Software/builds/Linux_CentOS7.7-x86_64-gcc4.8.5/ccdb/ccdb_1.06.06/include -I /group/halld/Software/builds/Linux_CentOS7.7-x86_64-gcc4.8.5/rcdb/rcdb_0.06.00/cpp/include -I /usr/include/mysql -I /group/halld/Software/builds/Linux_CentOS7.7-x86_64-gcc4.8.5/sqlitecpp/SQLiteCpp-2.2.0^bs130/include -I /group/halld/Software/builds/Linux_CentOS7.7-x86_64-gcc4.8.5/sqlite/sqlite-3.13.0^bs130/include -I /group/halld/Software/builds/Linux_CentOS7.7-x86_64-gcc4.8.5/hdds/hdds-4.9.0/Linux_CentOS7.7-x86_64-gcc4.8.5/src -I /group/halld/Software/builds/Linux_CentOS7.7-x86_64-gcc4.8.5/xerces-c/xerces-c-3.1.4/include -I /group/halld/Software/builds/Linux_CentOS7.7-x86_64-gcc4.8.5/evio/evio-4.4.6/Linux-x86_64/include -internal-isystem /usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../include/c++/4.8.5 -internal-isystem /usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../include/c++/4.8.5/x86_64-redhat-linux -internal-isystem /usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../include/c++/4.8.5/backward -internal-isystem /usr/local/include -internal-isystem /w/halld-scifs17exp/home/sdobbs/clang/llvm-project/install/lib/clang/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -std=c++11 -fdeprecated-macro -fdebug-compilation-dir /home/sdobbs/work/clang/halld_recon/src -ferror-limit 19 -fgnuc-version=4.2.1 -fcxx-exceptions -fexceptions -vectorize-loops -vectorize-slp -analyzer-output=html -faddrsig -o /tmp/scan-build-2021-01-21-110224-160369-1 -x c++ libraries/ANALYSIS/DSourceComboer.cc

libraries/ANALYSIS/DSourceComboer.cc

1#include "ANALYSIS/DSourceComboer.h"
2#include "ANALYSIS/DSourceComboVertexer.h"
3#include "ANALYSIS/DSourceComboTimeHandler.h"
4
5//Abandon all hope, ye who enter here.
6//Seriously, it will take you at LEAST a month to understand this.
7//If you really want to see what's going on, run with -PCOMBO:DEBUG_LEVEL=5000 and prepare to embrace the pain
8
9namespace DAnalysis
10{
11
12/*
13FAQ:
14Q) If an event has the minimum # tracks, how can it fail to create combos for that event?
15A) It may be that one of the tracks failed cuts for the PIDs that you need, but passed for others. Thus the total #tracks is OK.
16 Then, say you need 1 pi+ & 1 proton, and you detected 2 tracks. The other track may have passed dE/dx cuts for both proton & pi+, so it registers as both.
17 Also, one track could have both a positively & negatively charged hypothesis, and thus would count for both charges.
18
19FAQ:
20Q) How can tracks have t1_detector() == SYS_NULL? I thought the PreSelect cuts were supposed to remove those?
21A) Not exactly. If ANY of the hypos for a track has at least one hit in any detector, ALL hypos are saved.
22
23FAQ:
24Q) How can I speed this up?
25A) You can try reducing the #z-bins by increasing their widths. However, much sure you also increase the uncertainty on the timing & invariant-mass cuts for photons as well.
26*/
27
28/****************************************************** COMBOING STRATEGY ******************************************************
29*
30* Creating all possible combos can be very time- and memory-intensive if not done properly.
31* For example, consider a 4pi0 analysis and 20 (N) reconstructed showers (it happens).
32* If you make all possible pairs of photons (for pi0's), you get 19 + 18 + 17 + ... 1 = (N - 1)*N/2 = 190 pi0 combos.
33* Now, consider that you have 4 pi0s: On the order of 190^4/16: On the order of a 80 million combos (although less once you guard against photon reuse)
34*
35* So, we must do everything we can to reduce the # of possible combos in ADVANCE of actually attempting to make them.
36* And, we have to make sure we don't do anything twice (e.g. two different users have 4pi0s in their channel).
37* The key to this being efficient (besides splitting the BCAL photons into vertex-z bins and placing timing cuts) is combo re-use.
38*
39* For example, suppose a channel needs 3 pi0s.
40* First this will build all combos for 1 pi0, then all combos for 2 pi0s, then 3. Placing mass cuts along the way.
41* The results after each of these steps is saved. That way, if someone then requests 2 pi0s, we merely have to return the results from the previous work.
42* Also, if someone later requests 4pi0s, then we just take the 3pi0 results and expand them by 1 pi0.
43* Or, if someone requests p3pi, we take the 1 pi0 combos and combine them with a proton, pi+, and pi-. Etc., etc.
44*
45* For more details on how this is done, see the comments in the Create_SourceCombos_Unknown function
46* But ultimately, this results in a clusterfuck of recursive calls.
47* Also, because of how the combo-info classes are structured (decaying PID NOT a member), you have be extremely careful not to get into an infinite loop.
48* So, modify this code at your own peril. Just try not to take the rest of the collaboration down with you.
49*
50* Now, technically, when we construct combos for a (e.g.) pi0, we are saving 2 different results:
51* The combos of 2 photons, and which of those combos survive the pi0 mass cut.
52* That way, if later someone wants to build an eta, all we have to do is take 2-photon combos and place eta mass cuts.
53*
54* Combos are created on-demand, used immediately, and once they are cut the memory is recycled for the next combo in that event.
55*
56*
57* The BCAL photons are evaluated in different vertex-z bins for calculating their kinematics (momentum & timing).
58* This is because their kinematics have a strong dependence on vertex-z, while the FCAL showers do not (see above derivations).
59* Whereas the FCAL photons have only a small dependence, so their kinematics are regardless of vertex-z.
60* For more discussion the above, see the derivations in the DSourceComboTimeHandler and DSourceComboP4Handler classes.
61*
62*
63*
64*
65*
66* Note that combos are constructed separately for different beam bunches.
67* This is because photons only survive their timing cuts for certain beam bunches.
68* Comboing only within a given beam bunch reduces the #photons we need to combo, and is thus faster.
69*
70* When comboing, first all of the FCAL showers alone are used to build the requested combos.
71* Then, the BCAL showers surviving the timing cuts within the input vertex-z bin are used to build the requested combos.
72* Finally, combos are created using a mix of these BCAL & FCAL showers.
73* The results from this comboing is saved for all cases, that way they can be easily retrieved and combined as needed for similar requests.
74*
75*
76*******************************************************************************************************************************/
77
78/****************************************************** DESIGN MOTIVATION ******************************************************
79*
80*
81*
82* 1) Re-use comboing results between DReactions.
83* If working on each DReaction individually, it is difficult (takes time & memory) to figure out what has already been done, and what to share
84* So instead, first break down the DReactions to their combo-building components, and share those components.
85* Then build combos out of the components, and distribute the results for each DReaction.
86*
87* 2) Reduce the time spent trying combos that we can know in advance won't work.
88* We can do this by placing cuts IMMEDIATELY on:
89* a) Time difference between charged tracks
90* b) Time difference between photons and possible RF bunches (discussed more below).
91* c) Invariant mass cuts for various decaying particles (e.g. pi0, eta, omega, phi, lambda, etc.)
92* Also, when building combos of charged tracks, we could only loop over PIDs of the right type, rather than all hypotheses
93*
94* 3) The only way to do both 1) and 2) is to make the loose time & mass cuts reaction-independent.
95* Users can always specify reaction-dependent tighter cuts later, but they cannot specify looser ones.
96* However, these cuts should be tweakable on the command line in case someone wants to change them.
97*
98*******************************************************************************************************************************/
99
100
101/*****
102 * COMBOING PHOTONS AND RF BUNCHES
103 *
104 * So, this is tricky.
105 * Start out by allowing ALL beam bunches, regardless of what the charged tracks want.
106 * Then, as each photon is chosen, reduce the set of possible photons to choose next: only those that agree on at least one RF bunch
107 * As combos are made, the valid RF bunches are saved along with the combo
108 * That way, as combos are combined with other combos/particles, we make sure that only valid possibilities are chosen.
109 *
110 * We can't start with those only valid for the charged tracks because:
111 * When we generate combos for a given info, we want to generate ALL combos at once.
112 * E.g. some charged tracks may want pi0s with beam bunch = 1, but another group might want pi0s with bunch 1 OR 2.
113 * Dealing with the overlap is a nightmare. This avoids the problem entirely.
114 *
115 * BEWARE: Massive-neutral-particle momentum depends on the RF bunch. So a cut on the invariant mass with a neutron is effectively a cut on the RF bunches
116 * Suppose: Sigma+ -> pi+ n
117 * You first generate combos for -> pi+ n, and save them for the use X -> pi+, n
118 * We then re-use the combos for the use Sigma+ -> pi+ n
119 * But then a cut on the Sigma+ mass reduces the #valid RF bunches. So now we need a new combo!
120 * We could decouple the RF bunches from the combo: e.g. save in map from combo_use -> rf bunches
121 * However, this would result in many duplicate entries: e.g. X -> 2g, pi0 -> 2g, eta -> 2g, etc.
122 * Users choosing final-state neutrons or KLongs is pretty rare compared to everything else: we are better off just creating new combos
123 *
124 * BEWARE: Massive-neutral-particle momentum depends on the RF bunch. So a cut on the invariant mass with a neutron is effectively a cut on the RF bunches.
125 * So we can't actually vote on RF bunches until we choose our massive-neutral particles!!!
126 */
127
128
129void DSourceComboer::Define_DefaultCuts(void)
130{
131//COMPARE:
132 //DEFINE DEFAULT dE/dx CUTS
133 //CDC Proton
134 ddEdxCuts_TF1FunctionStrings[Proton][SYS_CDC].first = "exp(-1.0*[0]*x + [1]) + [2]"; //low bound
135 ddEdxCuts_TF1Params[Proton][SYS_CDC].first = {4.0, 2.25, 1.0};
136 ddEdxCuts_TF1FunctionStrings[Proton][SYS_CDC].second = "[0]"; //high bound
137 ddEdxCuts_TF1Params[Proton][SYS_CDC].second = {9.9E9};
138
139 //CDC Pi+
140 ddEdxCuts_TF1FunctionStrings[PiPlus][SYS_CDC].first = "[0]"; //low bound
141 ddEdxCuts_TF1Params[PiPlus][SYS_CDC].first = {-9.9E9};
142 ddEdxCuts_TF1FunctionStrings[PiPlus][SYS_CDC].second = "exp(-1.0*[0]*x + [1]) + [2]"; //high bound
143 ddEdxCuts_TF1Params[PiPlus][SYS_CDC].second = {7.0, 3.0, 6.2};
144
145 //CDC K+
146 ddEdxCuts_TF1FunctionStrings[KPlus][SYS_CDC].first = "[0]"; //low bound
147 ddEdxCuts_TF1Params[KPlus][SYS_CDC].first = {-9.9E9};
148 ddEdxCuts_TF1FunctionStrings[KPlus][SYS_CDC].second = "exp(-1.0*[0]*x + [1]) + [2]"; //high bound
149 ddEdxCuts_TF1Params[KPlus][SYS_CDC].second = {7.0, 3.0, 6.2};
150
151 //CDC e-
152 ddEdxCuts_TF1FunctionStrings[Electron][SYS_CDC].first = "[0]"; //low bound
153 ddEdxCuts_TF1Params[Electron][SYS_CDC].first = {-9.9E9};
154 ddEdxCuts_TF1FunctionStrings[Electron][SYS_CDC].second = "[0]"; //high bound
155 ddEdxCuts_TF1Params[Electron][SYS_CDC].second = {5.5};
156
157 //CDC mu+
158 ddEdxCuts_TF1FunctionStrings[MuonPlus][SYS_CDC].first = "[0]"; //low bound
159 ddEdxCuts_TF1Params[MuonPlus][SYS_CDC].first = {-9.9E9};
160 ddEdxCuts_TF1FunctionStrings[MuonPlus][SYS_CDC].second = "exp(-1.0*[0]*x + [1]) + [2]"; //high bound
161 ddEdxCuts_TF1Params[MuonPlus][SYS_CDC].second = {7.0, 3.0, 6.2};
162
163 //pbar
164 ddEdxCuts_TF1FunctionStrings.emplace(AntiProton, ddEdxCuts_TF1FunctionStrings[Proton]);
165 ddEdxCuts_TF1Params.emplace(AntiProton, ddEdxCuts_TF1Params[Proton]);
166
167 //Pi-
168 ddEdxCuts_TF1FunctionStrings.emplace(PiMinus, ddEdxCuts_TF1FunctionStrings[PiPlus]);
169 ddEdxCuts_TF1Params.emplace(PiMinus, ddEdxCuts_TF1Params[PiPlus]);
170
171 //K-
172 ddEdxCuts_TF1FunctionStrings.emplace(KMinus, ddEdxCuts_TF1FunctionStrings[KPlus]);
173 ddEdxCuts_TF1Params.emplace(KMinus, ddEdxCuts_TF1Params[KPlus]);
174
175 //e+
176 ddEdxCuts_TF1FunctionStrings.emplace(Positron, ddEdxCuts_TF1FunctionStrings[Electron]);
177 ddEdxCuts_TF1Params.emplace(Positron, ddEdxCuts_TF1Params[Electron]);
178
179 //mu-
180 ddEdxCuts_TF1FunctionStrings.emplace(MuonMinus, ddEdxCuts_TF1FunctionStrings[MuonPlus]);
181 ddEdxCuts_TF1Params.emplace(MuonMinus, ddEdxCuts_TF1Params[MuonPlus]);
182
183
184 //DEFINE DEFAULT E/p CUTS //vs p, cut away everything below if electron/positron, everything above if else
185 //e- FCAL
186 dEOverPCuts_TF1FunctionStrings[Electron][SYS_FCAL] = "[0]";
187 dEOverPCuts_TF1Params[Electron][SYS_FCAL] = {0.7};
188
189 //e- BCAL
190 dEOverPCuts_TF1FunctionStrings[Electron][SYS_BCAL] = "[0]";
191 dEOverPCuts_TF1Params[Electron][SYS_BCAL] = {0.7};
192
193 //e+
194 dEOverPCuts_TF1FunctionStrings.emplace(Positron, dEOverPCuts_TF1FunctionStrings[Electron]);
195 dEOverPCuts_TF1Params.emplace(Positron, dEOverPCuts_TF1Params[Electron]);
196
197 //mu- FCAL
198 dEOverPCuts_TF1FunctionStrings[MuonMinus][SYS_FCAL] = "[0]";
199 dEOverPCuts_TF1Params[MuonMinus][SYS_FCAL] = {0.2};
200
201 //mu- BCAL
202 dEOverPCuts_TF1FunctionStrings[MuonMinus][SYS_BCAL] = "[0]";
203 dEOverPCuts_TF1Params[MuonMinus][SYS_BCAL] = {0.45};
204
205 //mu+
206 dEOverPCuts_TF1FunctionStrings.emplace(MuonPlus, dEOverPCuts_TF1FunctionStrings[MuonMinus]);
207 dEOverPCuts_TF1Params.emplace(MuonPlus, dEOverPCuts_TF1Params[MuonMinus]);
208
209 //DEFINE DEFAULT beta CUTS, for neutrons cut everything above
210 //n FCAL
211 dBetaCuts_TF1FunctionStrings[Neutron][SYS_FCAL] = "[0]";
212 dBetaCuts_TF1Params[Neutron][SYS_FCAL] = {0.9};
213
214 //n BCAL
215 dBetaCuts_TF1FunctionStrings[Neutron][SYS_BCAL] = "[0]";
216 dBetaCuts_TF1Params[Neutron][SYS_BCAL] = {0.9};
217
218
219
220}
221
222void DSourceComboer::Get_CommandLineCuts_dEdx(void)
223{
224 //PARAM EXAMPLES:
225 //COMBO_DEDXCUT:Low_14_1=0.75_0.5_1.0 //Cut protons (14) in the CDC (1) with the following parameters for the low-side cut
226 //COMBO_DEDXCUT:High_9_256_FUNC="[0] + [1]*x" //Cut pi-'s (9) in the SC (256) according to the functional form for the high-side cut //x = track momentum
227
228 map<string, string> locParameterMap; //parameter key - filter, value
229 gPARMS->GetParameters(locParameterMap, "COMBO_DEDXCUT:"); //gets all parameters with this filter at the beginning of the key
230 for(auto locParamPair : locParameterMap)
231 {
232 if(dDebugLevel)
233 cout << "param pair: " << locParamPair.first << ", " << locParamPair.second << endl;
234
235 //High or low cut?
236 auto locFirstUnderscoreIndex = locParamPair.first.find('_');
237 auto locSideString = locParamPair.first.substr(0, locFirstUnderscoreIndex);
238 auto locHighSideFlag = (locSideString == "Low") ? false : true;
239
240 //Figure out which particle was specified
241 auto locSecondUnderscoreIndex = locParamPair.first.find('_', locFirstUnderscoreIndex + 1);
242 auto locParticleString = locParamPair.first.substr(locFirstUnderscoreIndex + 1, locSecondUnderscoreIndex);
243 istringstream locPIDtream(locParticleString);
244 int locPIDInt;
245 locPIDtream >> locPIDInt;
246 if(locPIDtream.fail())
247 continue;
248 Particle_t locPID = (Particle_t)locPIDInt;
249
250 //Figure out which detector was specified
251 auto locFuncIndex = locParamPair.first.find("_FUNC");
252 auto locDetectorString = locParamPair.first.substr(locSecondUnderscoreIndex + 1, locFuncIndex);
253 istringstream locDetectorStream(locDetectorString);
254 int locSystemInt;
255 locDetectorStream >> locSystemInt;
256 if(locDetectorStream.fail())
257 continue;
258 DetectorSystem_t locSystem = (DetectorSystem_t)locSystemInt;
259
260 if(dDebugLevel)
261 cout << "dE/dx cut: pid, detector, high-side flag = " << locPID << ", " << locSystem << ", " << locHighSideFlag << endl;
262
263 //get the parameter, with hack so that don't get warning message about no default
264 string locKeyValue;
265 string locFullParamName = string("COMBO_DEDXCUT:") + locParamPair.first; //have to add back on the filter
266 gPARMS->SetDefaultParameter(locFullParamName, locKeyValue);
267
268 //If functional form, save it and continue
269 if(locFuncIndex != string::npos)
270 {
271 if(!locHighSideFlag)
272 ddEdxCuts_TF1FunctionStrings[locPID][locSystem].first = locKeyValue;
273 else
274 ddEdxCuts_TF1FunctionStrings[locPID][locSystem].second = locKeyValue;
275 continue;
276 }
277
278 //is cut parameters: extract and save
279 //CUT PARAMETERS SHOULD BE SEPARATED BY SPACES
280 //get rid of previous cut values
281 if(!locHighSideFlag)
282 ddEdxCuts_TF1Params[locPID][locSystem].first.clear();
283 else
284 ddEdxCuts_TF1Params[locPID][locSystem].second.clear();
285 while(true)
286 {
287 auto locUnderscoreIndex = locKeyValue.find('_');
288 auto locValueString = locKeyValue.substr(0, locUnderscoreIndex);
289
290 istringstream locValuetream(locValueString);
291 double locParameter;
292 locValuetream >> locParameter;
293 if(locValuetream.fail())
294 continue; //must be for a different use
295 if(dDebugLevel)
296 cout << "param: " << locParameter << endl;
297
298 //save locParameter and truncate locKeyValue (or break if done)
299 if(!locHighSideFlag)
300 ddEdxCuts_TF1Params[locPID][locSystem].first.push_back(locParameter);
301 else
302 ddEdxCuts_TF1Params[locPID][locSystem].second.push_back(locParameter);
303 if(locUnderscoreIndex == string::npos)
304 break;
305 locKeyValue = locKeyValue.substr(locUnderscoreIndex + 1);
306 }
307 }
308}
309
310void DSourceComboer::Get_CommandLineCuts_EOverP(void)
311{
312 //PARAM EXAMPLES:
313 //COMBO_EOVERP:14_32_FUNC="[0] + [1]*x" //Cut protons (14) in the FCAL (32) according to the functional form //x = track momentum
314 //COMBO_EOVERP:14_32=0.75_0.5 //Cut protons (14) in the FCAL (32) with the following parameters
315
316 map<string, string> locParameterMap; //parameter key - filter, value
317 gPARMS->GetParameters(locParameterMap, "COMBO_EOVERP:"); //gets all parameters with this filter at the beginning of the key
318 for(auto locParamPair : locParameterMap)
319 {
320 if(dDebugLevel)
321 cout << "param pair: " << locParamPair.first << ", " << locParamPair.second << endl;
322
323 //Figure out which particle was specified
324 auto locUnderscoreIndex = locParamPair.first.find('_');
325 auto locParticleString = locParamPair.first.substr(0, locUnderscoreIndex);
326 istringstream locPIDtream(locParticleString);
327 int locPIDInt;
328 locPIDtream >> locPIDInt;
329 if(locPIDtream.fail())
330 continue;
331 Particle_t locPID = (Particle_t)locPIDInt;
332
333 //Figure out which detector was specified
334 auto locFuncIndex = locParamPair.first.find("_FUNC");
335 auto locDetectorString = locParamPair.first.substr(locUnderscoreIndex + 1, locFuncIndex);
336 istringstream locDetectorStream(locDetectorString);
337 int locSystemInt;
338 locDetectorStream >> locSystemInt;
339 if(locDetectorStream.fail())
340 continue;
341 DetectorSystem_t locSystem = (DetectorSystem_t)locSystemInt;
342
343 if(dDebugLevel)
344 cout << "E/p cut: pid, detector = " << locPID << ", " << locSystem << endl;
345
346 //get the parameter, with hack so that don't get warning message about no default
347 string locKeyValue;
348 string locFullParamName = string("COMBO_EOVERP:") + locParamPair.first; //have to add back on the filter
349 gPARMS->SetDefaultParameter(locFullParamName, locKeyValue);
350
351 //If functional form, save it and continue
352 if(locFuncIndex != string::npos)
353 {
354 dEOverPCuts_TF1FunctionStrings[locPID][locSystem] = locKeyValue;
355 continue;
356 }
357
358 //is cut parameters: extract and save
359 //CUT PARAMETERS SHOULD BE SEPARATED BY SPACES
360 dEOverPCuts_TF1Params[locPID][locSystem].clear(); //get rid of previous cut values
361 while(true)
362 {
363 auto locUnderscoreIndex = locKeyValue.find('_');
364 auto locValueString = locKeyValue.substr(0, locUnderscoreIndex);
365
366 istringstream locValuetream(locValueString);
367 double locParameter;
368 locValuetream >> locParameter;
369 if(locValuetream.fail())
370 continue; //must be for a different use
371 if(dDebugLevel)
372 cout << "param: " << locParameter << endl;
373
374 //save locParameter and truncate locKeyValue (or break if done)
375 dEOverPCuts_TF1Params[locPID][locSystem].push_back(locParameter);
376 if(locUnderscoreIndex == string::npos)
377 break;
378 locKeyValue = locKeyValue.substr(locUnderscoreIndex + 1);
379 }
380 }
381}
382
383void DSourceComboer::Get_CommandLineCuts_Beta(void)
384{
385 //PARAM EXAMPLES:
386 //COMBO_BETA:13_32_FUNC="[0] + [1]*x" //Cut neutrons (13) in the FCAL (32) according to the functional form //x = track momentum
387 //COMBO_BETA:13_32=0.75_0.5 //Cut protons (13) in the FCAL (32) with the following parameters
388
389 map<string, string> locParameterMap; //parameter key - filter, value
390 gPARMS->GetParameters(locParameterMap, "COMBO_BETA:"); //gets all parameters with this filter at the beginning of the key
391 for(auto locParamPair : locParameterMap)
392 {
393 if(dDebugLevel)
394 cout << "param pair: " << locParamPair.first << ", " << locParamPair.second << endl;
395
396 //Figure out which particle was specified
397 auto locUnderscoreIndex = locParamPair.first.find('_');
398 auto locParticleString = locParamPair.first.substr(0, locUnderscoreIndex);
399 istringstream locPIDtream(locParticleString);
400 int locPIDInt;
401 locPIDtream >> locPIDInt;
402 if(locPIDtream.fail())
403 continue;
404 Particle_t locPID = (Particle_t)locPIDInt;
405
406 //Figure out which detector was specified
407 auto locFuncIndex = locParamPair.first.find("_FUNC");
408 auto locDetectorString = locParamPair.first.substr(locUnderscoreIndex + 1, locFuncIndex);
409 istringstream locDetectorStream(locDetectorString);
410 int locSystemInt;
411 locDetectorStream >> locSystemInt;
412 if(locDetectorStream.fail())
413 continue;
414 DetectorSystem_t locSystem = (DetectorSystem_t)locSystemInt;
415
416 if(dDebugLevel)
417 cout << "Beta cut: pid, detector = " << locPID << ", " << locSystem << endl;
418
419 //get the parameter, with hack so that don't get warning message about no default
420 string locKeyValue;
421 string locFullParamName = string("COMBO_BETA:") + locParamPair.first; //have to add back on the filter
422 gPARMS->SetDefaultParameter(locFullParamName, locKeyValue);
423
424 //If functional form, save it and continue
425 if(locFuncIndex != string::npos)
426 {
427 dBetaCuts_TF1FunctionStrings[locPID][locSystem] = locKeyValue;
428 continue;
429 }
430
431 //is cut parameters: extract and save
432 //CUT PARAMETERS SHOULD BE SEPARATED BY SPACES
433 dBetaCuts_TF1Params[locPID][locSystem].clear(); //get rid of previous cut values
434 while(true)
435 {
436 auto locUnderscoreIndex = locKeyValue.find('_');
437 auto locValueString = locKeyValue.substr(0, locUnderscoreIndex);
438
439 istringstream locValuetream(locValueString);
440 double locParameter;
441 locValuetream >> locParameter;
442 if(locValuetream.fail())
443 continue; //must be for a different use
444 if(dDebugLevel)
445 cout << "param: " << locParameter << endl;
446
447 //save locParameter and truncate locKeyValue (or break if done)
448 dBetaCuts_TF1Params[locPID][locSystem].push_back(locParameter);
449 if(locUnderscoreIndex == string::npos)
450 break;
451 locKeyValue = locKeyValue.substr(locUnderscoreIndex + 1);
452 }
453 }
454}
455
456void DSourceComboer::Create_CutFunctions(void)
457{
458 //No idea why this lock is necessary, but it crashes without it. Stupid ROOT.
459 japp->RootWriteLock(); //ACQUIRE ROOT LOCK!!
460
461 //dE/dx
462 for(auto& locPIDPair : ddEdxCuts_TF1Params)
463 {
464 auto& locSystemMap = locPIDPair.second;
465 for(auto& locSystemPair : locSystemMap)
466 {
467 auto& locParamsPair = locSystemPair.second;
468 auto& locParamVector_Low = locParamsPair.first;
469 auto& locParamVector_High = locParamsPair.second;
470 if(locParamVector_Low.empty() || locParamVector_High.empty())
471 continue;
472
473 //Get cut strings
474 if(ddEdxCuts_TF1FunctionStrings.find(locPIDPair.first) == ddEdxCuts_TF1FunctionStrings.end())
475 continue;
476 auto locSystemStringMap = ddEdxCuts_TF1FunctionStrings[locPIDPair.first];
477 if(locSystemStringMap.find(locSystemPair.first) == locSystemStringMap.end())
478 continue;
479 auto locCutFuncString_Low = locSystemStringMap[locSystemPair.first].first;
480 auto locCutFuncString_High = locSystemStringMap[locSystemPair.first].second;
481
482 //Create TF1 low-side, Set cut values
483 auto locFunc_Low = new TF1("df_dEdxCut_Low", locCutFuncString_Low.c_str(), 0.0, 12.0);
484 if(dPrintCutFlag)
485 jout << "dE/dx Cut PID, System, low-side func form, params: " << ParticleType(locPIDPair.first) << ", " << SystemName(locSystemPair.first) << ", " << locCutFuncString_Low;
486 ddEdxCutMap[locPIDPair.first][locSystemPair.first].first = locFunc_Low;
487 for(size_t loc_i = 0; loc_i < locParamVector_Low.size(); ++loc_i)
488 {
489 locFunc_Low->SetParameter(loc_i, locParamVector_Low[loc_i]);
490 if(dPrintCutFlag)
491 jout << ", " << locParamVector_Low[loc_i];
492 }
493 if(dPrintCutFlag)
494 jout << endl;
495
496 //Create TF1 high-side, Set cut values
497 auto locFunc_High = new TF1("df_dEdxCut_High", locCutFuncString_High.c_str(), 0.0, 12.0);
498 if(dPrintCutFlag)
499 jout << "dE/dx Cut PID, System, High-side func form, params: " << ParticleType(locPIDPair.first) << ", " << SystemName(locSystemPair.first) << ", " << locCutFuncString_High;
500 ddEdxCutMap[locPIDPair.first][locSystemPair.first].second = locFunc_High;
501 for(size_t loc_i = 0; loc_i < locParamVector_High.size(); ++loc_i)
502 {
503 locFunc_High->SetParameter(loc_i, locParamVector_High[loc_i]);
504 if(dPrintCutFlag)
505 jout << ", " << locParamVector_High[loc_i];
506 }
507 if(dPrintCutFlag)
508 jout << endl;
509 }
510 }
511
512 //E/p
513 for(auto& locPIDPair : dEOverPCuts_TF1Params)
514 {
515 auto& locSystemMap = locPIDPair.second;
516 for(auto& locSystemPair : locSystemMap)
517 {
518 auto& locParamVector = locSystemPair.second;
519
520 //Get cut strings
521 if(dEOverPCuts_TF1FunctionStrings.find(locPIDPair.first) == dEOverPCuts_TF1FunctionStrings.end())
522 continue;
523 auto locSystemStringMap = dEOverPCuts_TF1FunctionStrings[locPIDPair.first];
524 if(locSystemStringMap.find(locSystemPair.first) == locSystemStringMap.end())
525 continue;
526 auto locCutFuncString = locSystemStringMap[locSystemPair.first];
527
528 //Create TF1, Set cut values
529 auto locFunc = new TF1("df_EOverPCut", locCutFuncString.c_str(), 0.0, 12.0);
530 if(dPrintCutFlag)
531 jout << "E/p Cut PID, System, func form, params: " << ParticleType(locPIDPair.first) << ", " << SystemName(locSystemPair.first) << ", " << locCutFuncString;
532 dEOverPCutMap[locPIDPair.first][locSystemPair.first] = locFunc;
533 for(size_t loc_i = 0; loc_i < locParamVector.size(); ++loc_i)
534 {
535 locFunc->SetParameter(loc_i, locParamVector[loc_i]);
536 if(dPrintCutFlag)
537 jout << ", " << locParamVector[loc_i];
538 }
539 if(dPrintCutFlag)
540 jout << endl;
541 }
542 }
543
544 //Beta
545 for(auto& locPIDPair : dBetaCuts_TF1Params)
546 {
547 auto& locSystemMap = locPIDPair.second;
548 for(auto& locSystemPair : locSystemMap)
549 {
550 auto& locParamVector = locSystemPair.second;
551
552 //Get cut strings
553 if(dBetaCuts_TF1FunctionStrings.find(locPIDPair.first) == dBetaCuts_TF1FunctionStrings.end())
554 continue;
555 auto locSystemStringMap = dBetaCuts_TF1FunctionStrings[locPIDPair.first];
556 if(locSystemStringMap.find(locSystemPair.first) == locSystemStringMap.end())
557 continue;
558 auto locCutFuncString = locSystemStringMap[locSystemPair.first];
559
560 //Create TF1, Set cut values
561 auto locFunc = new TF1("df_BetaCut", locCutFuncString.c_str(), 0.0, 12.0);
562 if(dPrintCutFlag)
563 jout << "Beta Cut PID, System, func form, params: " << ParticleType(locPIDPair.first) << ", " << SystemName(locSystemPair.first) << ", " << locCutFuncString;
564 dBetaCutMap[locPIDPair.first][locSystemPair.first] = locFunc;
565 for(size_t loc_i = 0; loc_i < locParamVector.size(); ++loc_i)
566 {
567 locFunc->SetParameter(loc_i, locParamVector[loc_i]);
568 if(dPrintCutFlag)
569 jout << ", " << locParamVector[loc_i];
570 }
571 if(dPrintCutFlag)
572 jout << endl;
573 }
574 }
575
576 japp->RootUnLock(); //RELEASE ROOT LOCK!!
577}
578
579/********************************************************************* CONSTRUCTOR **********************************************************************/
580
581void DSourceComboer::Set_RunDependent_Data(JEventLoop *locEventLoop)
582{
583 // Set member data
584 //GET THE GEOMETRY
585 DApplication* locApplication = dynamic_cast<DApplication*>(locEventLoop->GetJApplication());
586 DGeometry* locGeometry = locApplication->GetDGeometry(locEventLoop->GetJEvent().GetRunNumber());
587
588 //TARGET INFORMATION
589 double locTargetCenterZ = 65.0;
590 locGeometry->GetTargetZ(locTargetCenterZ);
591 dTargetCenter.SetXYZ(0.0, 0.0, locTargetCenterZ);
592
593 // Update linked objects
594 dSourceComboP4Handler->Set_RunDependent_Data(locEventLoop);
595 dSourceComboVertexer->Set_RunDependent_Data(locEventLoop);
596 dSourceComboTimeHandler->Set_RunDependent_Data(locEventLoop);
597 dParticleComboCreator->Set_RunDependent_Data(locEventLoop);
598}
599
600DSourceComboer::DSourceComboer(JEventLoop* locEventLoop)
601{
602 dResourcePool_SourceCombo.Set_ControlParams(100, 50, 1000, 20000, 0);
603 dResourcePool_SourceComboVector.Set_ControlParams(10, 5, 200, 1200, 0);
604 dCreatedCombos.reserve(100000);
605 dCreatedComboVectors.reserve(1000);
606
607 //Get preselect tag, debug level
608 gPARMS->SetDefaultParameter("COMBO:SHOWER_SELECT_TAG", dShowerSelectionTag);
609 gPARMS->SetDefaultParameter("COMBO:DEBUG_LEVEL", dDebugLevel);
610 gPARMS->SetDefaultParameter("COMBO:PRINT_CUTS", dPrintCutFlag);
611 gPARMS->SetDefaultParameter("COMBO:MAX_NEUTRALS", dMaxNumNeutrals);
612
613
614 //SETUP CUTS
615 Define_DefaultCuts();
616 Get_CommandLineCuts_dEdx();
617 Get_CommandLineCuts_EOverP();
618 Get_CommandLineCuts_Beta();
619 Create_CutFunctions();
620
621 //GET THE REACTIONS
622 auto locReactions = DAnalysis::Get_Reactions(locEventLoop);
623
624 //CREATE DSourceComboINFO'S
625 vector<const DReactionVertexInfo*> locVertexInfos;
626 locEventLoop->Get(locVertexInfos);
627 for(const auto& locVertexInfo : locVertexInfos)
628 Create_SourceComboInfos(locVertexInfo);
629
630 //TRANSFER INFOS FROM SET TO VECTOR
631 dSourceComboInfos.reserve(dSourceComboInfoSet.size());
632 std::copy(dSourceComboInfoSet.begin(), dSourceComboInfoSet.end(), std::back_inserter(dSourceComboInfos));
633 dSourceComboInfoSet.clear(); //free up the memory
634
635 //CREATE HANDLERS
636 dSourceComboP4Handler = new DSourceComboP4Handler(this);
637 dSourceComboVertexer = new DSourceComboVertexer(locEventLoop, this, dSourceComboP4Handler);
638 dSourceComboTimeHandler = new DSourceComboTimeHandler(locEventLoop, this, dSourceComboVertexer);
639 dSourceComboP4Handler->Set_SourceComboTimeHandler(dSourceComboTimeHandler);
640 dSourceComboP4Handler->Set_SourceComboVertexer(dSourceComboVertexer);
641 dSourceComboVertexer->Set_SourceComboTimeHandler(dSourceComboTimeHandler);
642 dParticleComboCreator = new DParticleComboCreator(locEventLoop, this, dSourceComboTimeHandler, dSourceComboVertexer);
643
644 Set_RunDependent_Data(locEventLoop);
645
646 //save rf bunch cuts
647 if(gPARMS->Exists("COMBO:NUM_PLUSMINUS_RF_BUNCHES"))
648 {
649 size_t locNumPlusMinusRFBunches;
650 gPARMS->GetParameter("COMBO:NUM_PLUSMINUS_RF_BUNCHES", locNumPlusMinusRFBunches);
651 for(const auto& locReaction : locReactions)
652 dRFBunchCutsByReaction.emplace(locReaction, locNumPlusMinusRFBunches);
653 }
654 else //by reaction
655 {
656 for(const auto& locReaction : locReactions)
657 {
658 auto locNumBunches = locReaction->Get_NumPlusMinusRFBunches();
659 pair<bool, double> locMaxPhotonRFDeltaT = locReaction->Get_MaxPhotonRFDeltaT(); //DEPRECATED!!!
660 if(locMaxPhotonRFDeltaT.first)
661 locNumBunches = size_t(locMaxPhotonRFDeltaT.second/dSourceComboTimeHandler->Get_BeamBunchPeriod() - 0.499999999);
662 dRFBunchCutsByReaction.emplace(locReaction, locNumBunches);
663 }
664 }
665
666 //save max bunch cuts
667 for(const auto& locVertexInfo : locVertexInfos)
668 {
669 dMaxRFBunchCuts.emplace(locVertexInfo, 0);
670 for(const auto& locReaction : locVertexInfo->Get_Reactions())
671 {
672 if(dRFBunchCutsByReaction[locReaction] > dMaxRFBunchCuts[locVertexInfo])
673 dMaxRFBunchCuts[locVertexInfo] = dRFBunchCutsByReaction[locReaction];
674 }
675 }
676
677 //Make sure this matches DConstructionStage!!!
678 vector<string> locBuildStages_Event = {"Input", "Min # Particles", "Max # Particles", "In Skim", "Charged Combos", "Charged RF Bunch", "Full Combos", "Neutral RF Bunch",
679 "No-Vertex RF Bunch", "Heavy-Neutral IM", "Beam Combos", "MM/Dangling-Vertex Timing", "MM/Dangling-Vertex IM Cuts", "Accurate-Photon IM", "Reaction Beam-RF Cuts", "Missing Mass"};
680 vector<string> locBuildStages_Combo{"In Skim Events"}; //has same bin content as "In Skim"
681 locBuildStages_Combo.insert(locBuildStages_Combo.end(), locBuildStages_Event.begin() + 4, locBuildStages_Event.end());
682
683 //initialize success tracking
684 for(auto locReaction : locReactions)
685 {
686 for(auto locStage = static_cast<DConstructionStageType>(DConstructionStage::Min_Particles); locStage <= static_cast<DConstructionStageType>(DConstructionStage::Missing_Mass); ++locStage)
687 dNumCombosSurvivedStageTracker[locReaction][static_cast<DConstructionStage>(locStage)] = 0;
688 }
689
690 //Setup hists
691 japp->RootWriteLock(); //ACQUIRE ROOT LOCK!!
692 {
693 vector<DetectorSystem_t> locdEdxSystems {SYS_CDC, SYS_FDC, SYS_START, SYS_TOF};
694 vector<Particle_t> locPIDs {Electron, Positron, MuonPlus, MuonMinus, PiPlus, PiMinus, KPlus, KMinus, Proton, AntiProton};
695 vector<DetectorSystem_t> locEOverPSystems {SYS_BCAL, SYS_FCAL};
696
697 //get and change to the base (file/global) directory
698 TDirectory* locCurrentDir = gDirectory(TDirectory::CurrentDirectory());
699
700 string locDirName = "Independent";
701 TDirectoryFile* locDirectoryFile = static_cast<TDirectoryFile*>(gDirectory(TDirectory::CurrentDirectory())->GetDirectory(locDirName.c_str()));
702 if(locDirectoryFile == NULL__null)
703 locDirectoryFile = new TDirectoryFile(locDirName.c_str(), locDirName.c_str());
704 locDirectoryFile->cd();
705
706 locDirName = "Combo_Construction";
707 locDirectoryFile = static_cast<TDirectoryFile*>(gDirectory(TDirectory::CurrentDirectory())->GetDirectory(locDirName.c_str()));
708 if(locDirectoryFile == NULL__null)
709 locDirectoryFile = new TDirectoryFile(locDirName.c_str(), locDirName.c_str());
710 locDirectoryFile->cd();
711
712 locDirName = "PID";
713 locDirectoryFile = static_cast<TDirectoryFile*>(gDirectory(TDirectory::CurrentDirectory())->GetDirectory(locDirName.c_str()));
714 if(locDirectoryFile == NULL__null)
715 locDirectoryFile = new TDirectoryFile(locDirName.c_str(), locDirName.c_str());
716 locDirectoryFile->cd();
717
718 for(auto& locPID : locPIDs)
719 {
720 locDirName = ParticleType(locPID);
721 locDirectoryFile = static_cast<TDirectoryFile*>(gDirectory(TDirectory::CurrentDirectory())->GetDirectory(locDirName.c_str()));
722 if(locDirectoryFile == NULL__null)
723 locDirectoryFile = new TDirectoryFile(locDirName.c_str(), locDirName.c_str());
724 locDirectoryFile->cd();
725
726 for(auto& locSystem : locdEdxSystems)
727 {
728 string locHistName = string("dEdxVsP_") + string(SystemName(locSystem));
729 auto locHist = gDirectory(TDirectory::CurrentDirectory())->Get(locHistName.c_str());
730 if(locHist == nullptr)
731 {
732 string locUnits = ((locSystem == SYS_CDC) || (locSystem == SYS_FDC)) ? "(keV/cm)" : "(MeV/cm)";
733 string locHistTitle = ParticleName_ROOT(locPID) + string(", ") + string(SystemName(locSystem)) + string(";p (GeV/c);dE/dX ") + locUnits;
734 dHistMap_dEdx[locPID][locSystem] = new TH2I(locHistName.c_str(), locHistTitle.c_str(), 400, 0.0, 12.0, 400, 0.0, 25.0);
735 }
736 else
737 dHistMap_dEdx[locPID][locSystem] = static_cast<TH2*>(locHist);
738 }
739
740 for(auto& locSystem : locEOverPSystems)
741 {
742 string locHistName = string("EOverP_") + string(SystemName(locSystem));
743 auto locHist = gDirectory(TDirectory::CurrentDirectory())->Get(locHistName.c_str());
744 if(locHist == nullptr)
745 {
746 string locHistTitle = ParticleName_ROOT(locPID) + string(", ") + string(SystemName(locSystem)) + string(";p (GeV/c);E_{Shower}/p_{Track} (c)");
747 dHistMap_EOverP[locPID][locSystem] = new TH2I(locHistName.c_str(), locHistTitle.c_str(), 400, 0.0, 12.0, 400, 0.0, 4.0);
748 }
749 else
750 dHistMap_EOverP[locPID][locSystem] = static_cast<TH2*>(locHist);
751 }
752 gDirectory(TDirectory::CurrentDirectory())->cd("..");
753 }
754 locCurrentDir->cd();
755
756 //construction stage tracking
757 for(auto locReaction : locReactions)
758 {
759 string locReactionName = locReaction->Get_ReactionName();
760
761 locDirName = locReactionName;
762 locDirectoryFile = static_cast<TDirectoryFile*>(gDirectory(TDirectory::CurrentDirectory())->GetDirectory(locDirName.c_str()));
763 if(locDirectoryFile == NULL__null)
764 locDirectoryFile = new TDirectoryFile(locDirName.c_str(), locDirName.c_str());
765 locDirectoryFile->cd();
766
767 string locHistName = "ComboConstruction_NumEventsSurvived";
768 auto locHist = gDirectory(TDirectory::CurrentDirectory())->Get(locHistName.c_str());
769 if(locHist == nullptr)
770 {
771 string locHistTitle = locReactionName + string(";;# Events Survived Stage");
772 dNumEventsSurvivedStageMap[locReaction] = new TH1D(locHistName.c_str(), locHistTitle.c_str(), locBuildStages_Event.size(), -0.5, locBuildStages_Event.size() - 0.5);
773 for(size_t loc_i = 0; loc_i < locBuildStages_Event.size(); ++loc_i)
774 dNumEventsSurvivedStageMap[locReaction]->GetXaxis()->SetBinLabel(loc_i + 1, locBuildStages_Event[loc_i].c_str());
775 }
776 else
777 dNumEventsSurvivedStageMap[locReaction] = static_cast<TH1*>(locHist);
778
779 locHistName = "ComboConstruction_NumCombosSurvived";
780 locHist = gDirectory(TDirectory::CurrentDirectory())->Get(locHistName.c_str());
781 if(locHist == nullptr)
782 {
783 string locHistTitle = locReactionName + string(";;# Combos Survived Stage");
784 dNumCombosSurvivedStageMap[locReaction] = new TH1D(locHistName.c_str(), locHistTitle.c_str(), locBuildStages_Combo.size(), -0.5, locBuildStages_Combo.size() - 0.5);
785 for(size_t loc_i = 0; loc_i < locBuildStages_Combo.size(); ++loc_i)
786 dNumCombosSurvivedStageMap[locReaction]->GetXaxis()->SetBinLabel(loc_i + 1, locBuildStages_Combo[loc_i].c_str());
787 }
788 else
789 dNumCombosSurvivedStageMap[locReaction] = static_cast<TH1*>(locHist);
790
791 locHistName = "ComboConstruction_NumCombosSurvived2D";
792 locHist = gDirectory(TDirectory::CurrentDirectory())->Get(locHistName.c_str());
793 if(locHist == nullptr)
794 {
795 string locHistTitle = locReactionName + string(";;# Combos Survived Stage");
796 dNumCombosSurvivedStage2DMap[locReaction] = new TH2D(locHistName.c_str(), locHistTitle.c_str(), locBuildStages_Combo.size(), -0.5, locBuildStages_Combo.size() - 0.5, 1000, 0, 1000);
797 for(size_t loc_i = 0; loc_i < locBuildStages_Combo.size(); ++loc_i)
798 dNumCombosSurvivedStage2DMap[locReaction]->GetXaxis()->SetBinLabel(loc_i + 1, locBuildStages_Combo[loc_i].c_str());
799 }
800 else
801 dNumCombosSurvivedStage2DMap[locReaction] = static_cast<TH2*>(locHist);
802
803 gDirectory(TDirectory::CurrentDirectory())->cd("..");
804 }
805 locCurrentDir->cd();
806 }
807 japp->RootUnLock(); //RELEASE ROOT LOCK!!
808}
809
810void DSourceComboer::Fill_SurvivalHistograms(void)
811{
812 auto locNumPreComboStages = 3; //"In Skim" will be first for #combos
813 japp->WriteLock("DSourceComboer_Survival");
814 {
815 for(auto& locReactionPair : dNumCombosSurvivedStageTracker)
816 {
817 auto& locReaction = locReactionPair.first;
818 for(auto& locStagePair : locReactionPair.second)
819 {
820 auto locNumCombos = locStagePair.second;
821 if(locNumCombos == 0)
822 break;
823
824 auto locStageIndex = static_cast<std::underlying_type<DConstructionStage>::type>(locStagePair.first);
825 dNumEventsSurvivedStageMap[locReaction]->Fill(locStageIndex);
826 if(locStageIndex < locNumPreComboStages)
827 continue;
828
829 //fill combo hists
830 auto locBin = locStageIndex - locNumPreComboStages + 1;
831 auto locBinContent = dNumCombosSurvivedStageMap[locReaction]->GetBinContent(locBin) + locNumCombos;
832 dNumCombosSurvivedStageMap[locReaction]->SetBinContent(locBin, locBinContent);
833
834 if(dNumCombosSurvivedStage2DMap[locReaction]->GetYaxis()->FindBin(locNumCombos) <= dNumCombosSurvivedStage2DMap[locReaction]->GetNbinsY())
835 dNumCombosSurvivedStage2DMap[locReaction]->Fill(locBin, locNumCombos);
836 }
837 }
838 }
839 japp->Unlock("DSourceComboer_Survival");
840
841 //Reset for next event
842 for(auto& locReactionPair : dNumCombosSurvivedStageTracker)
843 {
844 for(auto& locStagePair : locReactionPair.second)
845 locStagePair.second = 0;
846 }
847}
848
849/******************************************************************* CREATE DSOURCOMBOINFO'S ********************************************************************/
850
851void DSourceComboer::Create_SourceComboInfos(const DReactionVertexInfo* locReactionVertexInfo)
852{
853 //FULL combo use: Segregate each step into (up to) 3 combos: a fully charged, a fully neutral, and a mixed
854 //that way we will combo each separately before combining them horizontally: maximum re-use, especially of time-intensive neutral comboing
855 //However, an exception: if a any-# of a single neutral PID (e.g. pi0, n, or g), promote it to the level where the charged/neutral/mixed are combined
856 //Charged is similar, but not the same: if a single DECAYING-to-charged particle, promote it as well
857 //Not so for a single detected charged particle though: We want to keep charged separate because that's what defines the vertices: Easier lookup
858
859 /*
860 * suppose reaction is 0) g, p -> omega, p
861 * 1) omega -> 3pi
862 * 2) pi0 -> 2g
863 *
864 * It will have uses/infos like:
865 * 0: X -> A, 1 (mixed + charged)
866 * A: X -> p (charged)
867 * 1: omega -> B, 2 (mixed)
868 * B: X -> pi+, pi- (charged)
869 * 2: pi0 -> 2g (neutral)
870 */
871
872 /*
873 * suppose reaction is 0) g, p -> K0, Sigma+
874 * 1) K0 -> 3pi
875 * 2) pi0 -> 2g
876 * 3) Sigma+ -> pi+, n
877 *
878 * It will have uses/infos like:
879 * 0: X -> A, 1, 3 (mixed -> charged, mixed, mixed)
880 * A: X -> p (charged)
881 * 1: K0 -> B, 2 (mixed -> charged, neutral)
882 * B: X -> pi+, pi- (charged)
883 * 2: pi0 -> 2g (neutral)
884 * 3: Sigma+ -> C, n (mixed -> charged, n)
885 * C: X -> pi+ (charged)
886 */
887
888 if(dDebugLevel > 0)
889 cout << "CREATING DSourceComboInfo OBJECTS FOR DREACTION " << locReactionVertexInfo->Get_Reaction()->Get_ReactionName() << endl;
890
891 //We will register what steps these combos are created for
892 map<size_t, DSourceComboUse> locStepComboUseMap; //size_t = step index
893
894 //loop over steps in reverse order
895 auto locReaction = locReactionVertexInfo->Get_Reaction();
896 auto locReactionSteps = locReaction->Get_ReactionSteps();
897 for(auto locStepIterator = locReactionSteps.rbegin(); locStepIterator != locReactionSteps.rend(); ++locStepIterator)
898 {
899 auto locStep = *locStepIterator;
900 auto locStepIndex = locReaction->Get_NumReactionSteps() - std::distance(locReactionSteps.rbegin(), locStepIterator) - 1;
901 if(dDebugLevel >= 5)
902 cout << "Step index " << locStepIndex << endl;
903
904 //create combo uses for all charged, all neutral, then for any mixed decays
905 map<Particle_t, unsigned char> locChargedParticleMap = Build_ParticleMap(locReaction, locStepIndex, d_Charged);
906 map<Particle_t, unsigned char> locNeutralParticleMap = Build_ParticleMap(locReaction, locStepIndex, d_Neutral);
907
908 //get combo infos for final-state decaying particles //if not present, ignore parent
909 auto locFinalStateDecayingComboUsesPair = Get_FinalStateDecayingComboUses(locReaction, locStepIndex, locStepComboUseMap);
910 auto locIncludeParentFlag = locFinalStateDecayingComboUsesPair.first;
911 auto& locFurtherDecays = locFinalStateDecayingComboUsesPair.second;
912
913 //split up further-decays into all-charged, all-neutral, and mixed
914 map<DSourceComboUse, unsigned char> locFurtherDecays_Charged, locFurtherDecays_Neutral, locFurtherDecays_Mixed;
915 for(const auto& locDecayPair : locFurtherDecays)
916 {
917 auto locChargeContent = dComboInfoChargeContent[std::get<2>(locDecayPair.first)];
918 if(locChargeContent == d_Charged)
919 locFurtherDecays_Charged.emplace(locDecayPair);
920 else if(locChargeContent == d_Neutral)
921 locFurtherDecays_Neutral.emplace(locDecayPair);
922 else
923 locFurtherDecays_Mixed.emplace(locDecayPair);
924 }
925
926 //exclude parent if production
927 if((locStepIndex == 0) && DAnalysis::Get_IsFirstStepBeam(locReaction)) //decay
928 locIncludeParentFlag = false;
929
930 //create combo uses for each case
931 auto locInitPID = locIncludeParentFlag ? locStep->Get_InitialPID() : Unknown;
932 bool locNoChargedFlag = (locChargedParticleMap.empty() && locFurtherDecays_Charged.empty());
933 bool locNoNeutralFlag = (locNeutralParticleMap.empty() && locFurtherDecays_Neutral.empty());
934
935 //determine if we need to subtract a target particle when calculating the invariant mass (e.g. rescattering)
936 auto locTargetToInclude = (locStepIndex != 0) ? locStep->Get_TargetPID() : Unknown;
937
938 //determine if there is a missing decay product, such that we can't do invariant mass cuts
939 bool locMissingDecayProductFlag = false;
940 if((locStepIndex != 0) || !DAnalysis::Get_IsFirstStepBeam(locReaction)) //decay
941 locMissingDecayProductFlag = DAnalysis::Check_IfMissingDecayProduct(locReaction, locStepIndex);
942
943 if(dDebugLevel >= 5)
944 cout << "locIncludeParentFlag, init pid, missing-product flag, to-include target pid: " << locIncludeParentFlag << ", " << locInitPID << ", " << locMissingDecayProductFlag << ", " << locTargetToInclude << endl;
945
946 //default to unknown use
947 DSourceComboUse locPrimaryComboUse(Unknown, DSourceComboInfo::Get_VertexZIndex_ZIndependent(), nullptr, false, Unknown);
948 if(locNoChargedFlag && locNoNeutralFlag) //only mixed
949 locPrimaryComboUse = Make_ComboUse(locInitPID, {}, locFurtherDecays_Mixed, locMissingDecayProductFlag, locTargetToInclude);
950 else if(locNoNeutralFlag && locFurtherDecays_Mixed.empty()) //only charged
951 locPrimaryComboUse = Make_ComboUse(locInitPID, locChargedParticleMap, locFurtherDecays_Charged, locMissingDecayProductFlag, locTargetToInclude);
952 else if(locNoChargedFlag && locFurtherDecays_Mixed.empty()) //only neutral
953 locPrimaryComboUse = Make_ComboUse(locInitPID, locNeutralParticleMap, locFurtherDecays_Neutral, locMissingDecayProductFlag, locTargetToInclude);
954 else //some combination
955 {
956 auto locFurtherDecays_All = locFurtherDecays_Mixed;
957 map<Particle_t, unsigned char> locParticleMap_All = {};
958 //create a combo for each charged group, with init pid = unknown
959 if(!locNoChargedFlag)
960 {
961 //if lone Charged decaying particle, promote to be parallel with mixed
962 if(locChargedParticleMap.empty() && (locFurtherDecays_Charged.size() == 1) && (locFurtherDecays_Charged.begin()->second == 1))
963 locFurtherDecays_All.emplace(locFurtherDecays_Charged.begin()->first, 1);
964 else //multiple Charged decaying particles, group together separately (own use)
965 {
966 auto locComboUse_Charged = Make_ComboUse(Unknown, locChargedParticleMap, locFurtherDecays_Charged, false, Unknown);
967 locFurtherDecays_All.emplace(locComboUse_Charged, 1);
968 }
969 }
970 if(!locNoNeutralFlag)
971 {
972 //if lone neutral PID, promote to be parallel with mixed
973 if(locNeutralParticleMap.empty() && (locFurtherDecays_Neutral.size() == 1))
974 locFurtherDecays_All.emplace(locFurtherDecays_Neutral.begin()->first, locFurtherDecays_Neutral.begin()->second); //decaying
975 else if(locFurtherDecays_Neutral.empty() && (locNeutralParticleMap.size() == 1))
976 locParticleMap_All.emplace(locNeutralParticleMap.begin()->first, locNeutralParticleMap.begin()->second); //detected
977 else //multiple neutral particles, group together separately (own use)
978 {
979 auto locComboUse_Neutral = Make_ComboUse(Unknown, locNeutralParticleMap, locFurtherDecays_Neutral, false, Unknown);
980 locFurtherDecays_All.emplace(locComboUse_Neutral, 1);
981 }
982 }
983
984 locPrimaryComboUse = Make_ComboUse(locInitPID, locParticleMap_All, locFurtherDecays_All, locMissingDecayProductFlag, locTargetToInclude);
985 }
986
987 locStepComboUseMap.emplace(locStepIndex, locPrimaryComboUse);
988 }
989
990 //Register the results!!
991 for(const auto& locStepVertexInfo : locReactionVertexInfo->Get_StepVertexInfos())
992 dSourceComboUseReactionMap.emplace(locStepVertexInfo, locStepComboUseMap[locStepVertexInfo->Get_StepIndices().front()]);
993 for(const auto& locUseStepPair : locStepComboUseMap)
994 dSourceComboInfoStepMap.emplace(std::make_pair(locReactionVertexInfo->Get_StepVertexInfo(locUseStepPair.first), locUseStepPair.second), locUseStepPair.first);
995 for(auto locTempReaction : locReactionVertexInfo->Get_Reactions())
996 dSourceComboUseReactionStepMap.emplace(locTempReaction, locStepComboUseMap);
997
998 if(dDebugLevel > 0)
999 cout << "DSourceComboInfo OBJECTS CREATED" << endl;
1000}
1001
1002pair<bool, map<DSourceComboUse, unsigned char>> DSourceComboer::Get_FinalStateDecayingComboUses(const DReaction* locReaction, size_t locStepIndex, const map<size_t, DSourceComboUse>& locStepComboUseMap) const
1003{
1004 //get combo infos for final-state decaying particles //if one is not present, ignore parent
1005 auto locIncludeParentFlag = true; //unless changed below
1006 map<DSourceComboUse, unsigned char> locFurtherDecays;
1007 auto locStep = locReaction->Get_ReactionStep(locStepIndex);
1008 for(size_t loc_i = 0; loc_i < locStep->Get_NumFinalPIDs(); ++loc_i)
1009 {
1010 int locDecayStepIndex = DAnalysis::Get_DecayStepIndex(locReaction, locStepIndex, loc_i);
1011 if(locDecayStepIndex < 0)
1012 continue;
1013
1014 auto locUseIterator = locStepComboUseMap.find(size_t(locDecayStepIndex));
1015 if(locUseIterator == locStepComboUseMap.end())
1016 locIncludeParentFlag = false;
1017 else
1018 {
1019 //save decay
1020 auto& locSourceComboUse = locUseIterator->second;
1021 auto locDecayIterator = locFurtherDecays.find(locSourceComboUse);
1022 if(locDecayIterator == locFurtherDecays.end())
1023 locFurtherDecays.emplace(locSourceComboUse, 1);
1024 else
1025 ++(locDecayIterator->second);
1026 }
1027 }
1028
1029 return std::make_pair(locIncludeParentFlag, locFurtherDecays);
1030}
1031
1032map<Particle_t, unsigned char> DSourceComboer::Build_ParticleMap(const DReaction* locReaction, size_t locStepIndex, Charge_t locCharge) const
1033{
1034 //build map of charged particles
1035 map<Particle_t, unsigned char> locNumParticles;
1036 auto locParticles = locReaction->Get_FinalPIDs(locStepIndex, false, false, locCharge, true); //no missing or decaying, include duplicates
1037 for(const auto& locPID : locParticles)
1038 {
1039 auto locPIDIterator = locNumParticles.find(locPID);
1040 if(locPIDIterator != locNumParticles.end())
1041 ++(locPIDIterator->second);
1042 else
1043 locNumParticles.emplace(locPID, 1);
1044 }
1045
1046 return locNumParticles;
1047}
1048
1049DSourceComboUse DSourceComboer::Make_ComboUse(Particle_t locInitPID, const map<Particle_t, unsigned char>& locNumParticles, const map<DSourceComboUse, unsigned char>& locFurtherDecays, bool locMissingDecayProductFlag, Particle_t locTargetToInclude)
1050{
1051 //convert locFurtherDecays map to a vector
1052 vector<pair<DSourceComboUse, unsigned char>> locDecayVector;
1053 locDecayVector.reserve(locFurtherDecays.size());
1054 std::copy(locFurtherDecays.begin(), locFurtherDecays.end(), std::back_inserter(locDecayVector));
1055
1056 //convert locNumParticles map to a vector
1057 vector<pair<Particle_t, unsigned char>> locParticleVector;
1058 locParticleVector.reserve(locNumParticles.size());
1059 std::copy(locNumParticles.begin(), locNumParticles.end(), std::back_inserter(locParticleVector));
1060
1061 //make or get the combo info
1062 auto locComboInfo = MakeOrGet_SourceComboInfo(locParticleVector, locDecayVector, 0);
1063 auto locComboUse = DSourceComboUse(locInitPID, DSourceComboInfo::Get_VertexZIndex_ZIndependent(), locComboInfo, locMissingDecayProductFlag, locTargetToInclude);
1064 if(dDebugLevel >= 5)
1065 {
1066 cout << "CREATED COMBO USE:" << endl;
1067 DAnalysis::Print_SourceComboUse(locComboUse);
1068 }
1069 return locComboUse;
1070}
1071
1072const DSourceComboInfo* DSourceComboer::MakeOrGet_SourceComboInfo(const vector<pair<Particle_t, unsigned char>>& locNumParticles, const vector<pair<DSourceComboUse, unsigned char>>& locFurtherDecays, unsigned char locNumTabs)
1073{
1074 //to be called (indirectly) by constructor: during the stage when primarily making
1075 //create the object on the stack
1076 DSourceComboInfo locSearchForInfo(locNumParticles, locFurtherDecays);
1077
1078 //then search through the set to retrieve the pointer to the corresponding object if it already exists
1079 auto locInfoIterator = dSourceComboInfoSet.find(&locSearchForInfo);
1080 if(locInfoIterator != dSourceComboInfoSet.end())
1081 return *locInfoIterator; //it exists: return it
1082
1083 //doesn't exist, make it and insert it into the sorted vector in the correct spot
1084 auto locComboInfo = new DSourceComboInfo(locNumParticles, locFurtherDecays);
1085 dSourceComboInfoSet.insert(locComboInfo);
1086 dComboInfoChargeContent.emplace(locComboInfo, DAnalysis::Get_ChargeContent(locComboInfo));
1087 if(dDebugLevel >= 5)
1088 {
1089 for(decltype(locNumTabs) locTabNum = 0; locTabNum < locNumTabs; ++locTabNum) cout << "\t";
1090 cout << "CREATED COMBO INFO:" << endl;
1091 DAnalysis::Print_SourceComboInfo(locComboInfo, locNumTabs);
1092 for(decltype(locNumTabs) locTabNum = 0; locTabNum < locNumTabs; ++locTabNum) cout << "\t";
1093 cout << "charge content = " << dComboInfoChargeContent[locComboInfo] << endl;
1094 }
1095 if(DAnalysis::Get_HasMassiveNeutrals(locComboInfo))
1096 dComboInfosWithMassiveNeutrals.insert(locComboInfo);
1097 if(DAnalysis::Get_HasPhotons(locComboInfo))
1098 dComboInfosWithPhotons.insert(locComboInfo);
1099 return locComboInfo;
1100}
1101
1102const DSourceComboInfo* DSourceComboer::GetOrMake_SourceComboInfo(const vector<pair<Particle_t, unsigned char>>& locNumParticles, const vector<pair<DSourceComboUse, unsigned char>>& locFurtherDecays, unsigned char locNumTabs)
1103{
1104 //to be called when making combos: during the stage when primarily getting
1105 //create the object on the stack
1106 DSourceComboInfo locSearchForInfo(locNumParticles, locFurtherDecays);
1107
1108 //then search through the vector to retrieve the pointer to the corresponding object if it already exists
1109 auto locIteratorPair = std::equal_range(dSourceComboInfos.begin(), dSourceComboInfos.end(), &locSearchForInfo, DCompare_SourceComboInfos());
1110 if(locIteratorPair.first != locIteratorPair.second)
1111 return *(locIteratorPair.first); //it exists: return it
1112
1113 //doesn't exist, make it and insert it into the sorted vector in the correct spot
1114 auto locComboInfo = new DSourceComboInfo(locNumParticles, locFurtherDecays);
1115 dSourceComboInfos.emplace(locIteratorPair.first, locComboInfo);
1116 dComboInfoChargeContent.emplace(locComboInfo, DAnalysis::Get_ChargeContent(locComboInfo));
1117 if(dDebugLevel >= 5)
1118 {
1119 for(decltype(locNumTabs) locTabNum = 0; locTabNum < locNumTabs; ++locTabNum) cout << "\t";
1120 cout << "CREATED COMBO INFO:" << endl;
1121 DAnalysis::Print_SourceComboInfo(locComboInfo, locNumTabs);
1122 for(decltype(locNumTabs) locTabNum = 0; locTabNum < locNumTabs; ++locTabNum) cout << "\t";
1123 cout << "charge content = " << dComboInfoChargeContent[locComboInfo] << endl;
1124 }
1125 if(DAnalysis::Get_HasMassiveNeutrals(locComboInfo))
1126 dComboInfosWithMassiveNeutrals.insert(locComboInfo);
1127 if(DAnalysis::Get_HasPhotons(locComboInfo))
1128 dComboInfosWithPhotons.insert(locComboInfo);
1129 return locComboInfo;
1130}
1131
1132DSourceComboUse DSourceComboer::Create_ZDependentSourceComboUses(const DReactionVertexInfo* locReactionVertexInfo, const DSourceCombo* locReactionChargedCombo)
1133{
1134 //this creates new uses, with the specific vertex-z bins needed
1135 //note that the use can have a different structure from the charged!! (although not likely)
1136 //E.g. if something crazy like 2 KShorts -> 3pi, each at a different vertex-z bin, then they will no longer be grouped together vertically (separate uses: horizontally instead)
1137
1138 //see if they've already been created. if so, just return it.
1139 auto locVertexZBins = dSourceComboVertexer->Get_VertexZBins(locReactionVertexInfo, locReactionChargedCombo, nullptr, true);
1140 auto locCreationPair = std::make_pair(locReactionVertexInfo, locVertexZBins);
1141 auto locUseIterator = dSourceComboUseVertexZMap.find(locCreationPair);
1142 if(locUseIterator != dSourceComboUseVertexZMap.end())
1143 return locUseIterator->second; //already created! we are done
1144
1145 auto locReaction = locReactionVertexInfo->Get_Reaction();
1146
1147 //loop over vertex infos in reverse-step order
1148 unordered_map<size_t, DSourceComboUse> locCreatedUseMap; //size_t: step index
1149 auto locStepVertexInfos = DAnalysis::Get_StepVertexInfos_ReverseOrderByStep(locReactionVertexInfo);
1150 for(const auto& locStepVertexInfo : locStepVertexInfos)
1151 {
1152 //for this vertex, get the vertex z bin
1153 auto locVertexZBin = (locReactionChargedCombo != nullptr) ? dSourceComboVertexer->Get_VertexZBin(locStepVertexInfo, locReactionChargedCombo, nullptr, true) : dSourceComboTimeHandler->Get_VertexZBin_TargetCenter();
1154 if(dDebugLevel >= 20)
1155 cout << "step, vertex z-bin = " << locStepVertexInfo->Get_StepIndices().front() << ", " << locVertexZBin << endl;
1156
1157 //loop over the steps at this vertex z bin, in reverse order
1158 auto locStepIndices = locStepVertexInfo->Get_StepIndices();
1159 for(auto locStepIterator = locStepIndices.rbegin(); locStepIterator != locStepIndices.rend(); ++locStepIterator)
1160 {
1161 auto locStepIndex = *locStepIterator;
1162 auto locStepOrigUse = dSourceComboUseReactionStepMap[locReaction][locStepIndex];
1163
1164 //build new use for the further decays, setting the vertex z-bins
1165 auto locNewComboUse = Build_NewZDependentUse(locReaction, locStepIndex, locVertexZBin, locStepOrigUse, locCreatedUseMap);
1166 locCreatedUseMap.emplace(locStepIndex, locNewComboUse);
1167 }
1168 }
1169
1170 dSourceComboUseVertexZMap.emplace(locCreationPair, locCreatedUseMap[0]);
1171 return locCreatedUseMap[0];
1172}
1173
1174DSourceComboUse DSourceComboer::Build_NewZDependentUse(const DReaction* locReaction, size_t locStepIndex, signed char locVertexZBin, const DSourceComboUse& locOrigUse, const unordered_map<size_t, DSourceComboUse>& locCreatedUseMap)
1175{
1176 //each step can be broken up into combo infos with a depth of 2 (grouping charges separately)
1177 auto locStep = locReaction->Get_ReactionStep(locStepIndex);
1178 auto locOrigInfo = std::get<2>(locOrigUse);
1179 if(dComboInfoChargeContent[locOrigInfo] == d_Charged)
1180 {
1181 dZDependentUseToIndependentMap.emplace(locOrigUse, locOrigUse);
1182 return locOrigUse; //no need to change!: no neutrals anyway
1183 }
1184
1185 map<DSourceComboUse, unsigned char> locNewFurtherDecays;
1186 auto locOrigFurtherDecays = locOrigInfo->Get_FurtherDecays();
1187 for(const auto& locDecayPair : locOrigFurtherDecays)
1188 {
1189 const auto& locOrigDecayUse = locDecayPair.first;
1190 auto locDecayPID = std::get<0>(locOrigDecayUse);
1191 if(locDecayPID != Unknown)
1192 {
1193 //these decays are represented by other steps, and have already been saved
1194 for(unsigned char locInstance = 1; locInstance <= locDecayPair.second; ++locInstance)
1195 {
1196 auto locParticleIndex = DAnalysis::Get_ParticleIndex(locStep, locDecayPID, locInstance);
1197 auto locDecayStepIndex = DAnalysis::Get_DecayStepIndex(locReaction, locStepIndex, locParticleIndex);
1198 const auto& locSavedDecayUse = locCreatedUseMap.find(locDecayStepIndex)->second; //is same as locOrigDecayUse, except different zbins along chain
1199
1200 //save the use for this decay
1201 auto locUseIterator = locNewFurtherDecays.find(locSavedDecayUse);
1202 if(locUseIterator != locNewFurtherDecays.end())
1203 ++(locUseIterator->second);
1204 else
1205 locNewFurtherDecays.emplace(locSavedDecayUse, 1);
1206 }
1207 }
1208 else //is unknown (and guaranteed to be size 1 since has unknown parent)
1209 {
1210 //must dig down, but only one level: their decays must terminate at new steps (or end)
1211 auto locNewComboUse = Build_NewZDependentUse(locReaction, locStepIndex, locVertexZBin, locOrigDecayUse, locCreatedUseMap);
1212 //save the use for this decay
1213 auto locUseIterator = locNewFurtherDecays.find(locNewComboUse);
1214 if(locUseIterator != locNewFurtherDecays.end())
1215 ++(locUseIterator->second);
1216 else
1217 locNewFurtherDecays.emplace(locNewComboUse, 1);
1218 }
1219 }
1220
1221 //build and save new info, use, and return
1222 vector<pair<DSourceComboUse, unsigned char>> locFurtherDecayVector;
1223 locFurtherDecayVector.reserve(locNewFurtherDecays.size());
1224 std::copy(locNewFurtherDecays.begin(), locNewFurtherDecays.end(), std::back_inserter(locFurtherDecayVector));
1225 auto locNewComboInfo = locNewFurtherDecays.empty() ? locOrigInfo : GetOrMake_SourceComboInfo(locOrigInfo->Get_NumParticles(), locFurtherDecayVector, 0);
1226
1227 DSourceComboUse locNewComboUse(std::get<0>(locOrigUse), locVertexZBin, locNewComboInfo, std::get<3>(locOrigUse), std::get<4>(locOrigUse));
1228 if(dDebugLevel >= 30)
1229 {
1230 cout << "NEW Z-DEPENDENT USE:" << endl;
1231 Print_SourceComboUse(locNewComboUse);
1232 cout << "FROM ORIG USE:" << endl;
1233 Print_SourceComboUse(locOrigUse);
1234 }
1235 dZDependentUseToIndependentMap.emplace(locNewComboUse, locOrigUse);
1236 return locNewComboUse;
1237}
1238
1239/********************************************************************** SETUP FOR NEW EVENT ***********************************************************************/
1240
1241void DSourceComboer::Reset_NewEvent(JEventLoop* locEventLoop)
1242{
1243 //check if it's actually a new event
1244 auto locEventNumber = locEventLoop->GetJEvent().GetEventNumber();
1245 if(locEventNumber == dEventNumber) {
1246 jout << "WARNING: Calling DSourceComboer::Reset_NewEvent() with repeated run number: " << locEventNumber << endl;
1247 return; //nope
1248 }
1249 dEventNumber = locEventNumber;
1250 if(dDebugLevel >= 5) //for the last event
1251 {
1252 cout << "Total # of Combos Allocated (All threads): " << dResourcePool_SourceCombo.Get_NumObjectsAllThreads() << endl;
1253 cout << "Total # of Combo Vectors Allocated (All threads): " << dResourcePool_SourceComboVector.Get_NumObjectsAllThreads() << endl;
1254 Print_NumCombosByUse();
1255 }
1256
1257 Fill_SurvivalHistograms();
1258
1259 /************************************************************* RECYCLE AND RESET **************************************************************/
1260
1261 //RECYCLE COMBO & VECTOR POINTERS
1262 //be careful! don't recycle combos with a use pid != unknown, because they are just copies! not unique pointers!
1263
1264 //HANDLERS AND VERTEXERS
1265 dSourceComboP4Handler->Reset();
1266 dSourceComboTimeHandler->Reset();
1267 dSourceComboVertexer->Reset();
1268 dParticleComboCreator->Reset();
1269
1270 //PARTICLES
1271 dNumChargedTracks = 0;
1272 dTracksByPID.clear();
1273 dTracksByCharge.clear();
1274 dShowersByBeamBunchByZBin.clear();
1275 dNeutralHadronShowers.clear();
1276
1277 //RECYCLE THE DSOURCECOMBO OBJECTS
1278 dResourcePool_SourceCombo.Recycle(dCreatedCombos);
1279 decltype(dCreatedCombos)().swap(dCreatedCombos); //should have been reset anyway, but just in case
1280 Recycle_Vectors();
1281
1282 //COMBOING RESULTS:
1283 dSourceCombosByUse_Charged.clear(); //BEWARE, CONTAINS VECTORS
1284 dMixedCombosByUseByChargedCombo.clear(); //BEWARE, CONTAINS VECTORS
1285 dSourceCombosByBeamBunchByUse.clear();
1286 dVertexPrimaryComboMap.clear();
1287 dValidRFBunches_ByCombo.clear();
1288 dNPhotonsToComboMap.clear();
1289
1290 //COMBOING RESUME/SEARCH-AFTER TRACKING
1291 dResumeSearchAfterIndices_Particles.clear();
1292 dResumeSearchAfterIndices_Combos.clear();
1293
1294 /************************************************************ SETUP FOR NEW EVENT *************************************************************/
1295
1296 //GET JANA OBJECTS
1297 vector<const DNeutralShower*> locNeutralShowers;
1298 locEventLoop->Get(locNeutralShowers, dShowerSelectionTag.c_str());
1299
1300 vector<const DChargedTrack*> locChargedTracks;
1301 locEventLoop->Get(locChargedTracks, "Combo");
1302
1303 vector<const DBeamPhoton*> locBeamPhotons;
1304 locEventLoop->Get(locBeamPhotons);
1305
1306 const DEventRFBunch* locInitialRFBunch = nullptr;
1307 locEventLoop->GetSingle(locInitialRFBunch);
1308
1309 const DDetectorMatches* locDetectorMatches = nullptr;
1310 locEventLoop->GetSingle(locDetectorMatches, "Combo");
1311
1312 //COMPARE:
1313 const DVertex* locVertex = nullptr;
1314 locEventLoop->GetSingle(locVertex);
1315 dSourceComboVertexer->Set_Vertex(locVertex);
1316
1317 vector<const DESSkimData*> locESSkimDataVector;
1318 locEventLoop->Get(locESSkimDataVector);
1319 dESSkimData = locESSkimDataVector.empty() ? NULL__null : locESSkimDataVector[0];
1320
1321 //SETUP NEUTRAL SHOWERS
1322 dSourceComboTimeHandler->Setup(locNeutralShowers, locInitialRFBunch, locDetectorMatches);
1323 dSourceComboP4Handler->Set_PhotonKinematics(dSourceComboTimeHandler->Get_PhotonKinematics());
1324 dShowersByBeamBunchByZBin = dSourceComboTimeHandler->Get_ShowersByBeamBunchByZBin();
1325 for(auto& locZBinPair : dShowersByBeamBunchByZBin)
1326 {
1327 auto& locShowerByBunchMap = locZBinPair.second;
1328 if(dDebugLevel >= 20)
1329 cout << "Register zbin: " << int(locZBinPair.first) << endl;
1330 for(auto& locBunchPair : locShowerByBunchMap)
1331 Build_ParticleIndices(Gamma, locBunchPair.first, locBunchPair.second, locZBinPair.first);
1332 }
1333
1334 // handle showers from neutral hadrons differently to allow for different selections to be applied
1335 vector<const DNeutralShower*> locNeutralHadronShowers;
1336 locEventLoop->Get(locNeutralHadronShowers, dHadronShowerSelectionTag.c_str());
1337
1338 for(auto &locHadronShower : locNeutralHadronShowers) {
1339 dNeutralHadronShowers.push_back(static_cast<const JObject*>(locHadronShower));
1340 }
1341
1342 //SETUP BEAM PARTICLES
1343 dSourceComboTimeHandler->Set_BeamParticles(locBeamPhotons);
1344
1345 //SETUP TRACKS
1346 dNumChargedTracks = locChargedTracks.size();
1347 for(const auto& locChargedTrack : locChargedTracks)
1348 {
1349 for(const auto& locChargedHypo : locChargedTrack->dChargedTrackHypotheses)
1350 {
1351 if(dDebugLevel >= 5)
1352 cout << "track, hypo, pid, t1 system = " << locChargedTrack << ", " << locChargedHypo << ", " << locChargedHypo->PID() << ", " << locChargedHypo->t1_detector() << endl;
1353 if(!Cut_dEdxAndEOverP(locChargedHypo))
1354 continue;
1355 if(dDebugLevel >= 5)
1356 cout << "passed cuts, register" << endl;
1357 dTracksByPID[locChargedHypo->PID()].push_back(locChargedTrack);
1358 dTracksByCharge[ParticleCharge(locChargedHypo->PID()) > 0].push_back(locChargedTrack); //will insert duplicates
1359 }
1360 }
1361
1362 //sort by pid & create indices
1363 for(auto& locPIDPair : dTracksByPID)
1364 {
1365 std::sort(locPIDPair.second.begin(), locPIDPair.second.end());
1366 Build_ParticleIndices(locPIDPair.first, {}, locPIDPair.second, DSourceComboInfo::Get_VertexZIndex_ZIndependent());
1367 }
1368 //sort & remove duplicates in tracks-by-charge
1369 for(auto& locChargePair : dTracksByCharge)
1370 {
1371 auto& locVector = locChargePair.second;
1372 std::sort(locVector.begin(), locVector.end());
1373 locVector.erase(std::unique(locVector.begin(), locVector.end()), locVector.end()); //remove duplicates
1374 }
1375
1376 if(dDebugLevel > 0)
1377 {
1378 cout << "TRACKS BY PID:" << endl;
1379 for(const auto& locPIDPair : dTracksByPID)
1380 {
1381 cout << "PID, pointers: " << locPIDPair.first << ", ";
1382 for(const auto& locTrack : locPIDPair.second)
1383 cout << locTrack << ", ";
1384 cout << endl;
1385 }
1386 cout << "TRACKS BY CHARGE:" << endl;
1387 for(const auto& locChargePair : dTracksByCharge)
1388 {
1389 cout << "charge, pointers: " << (locChargePair.first ? 1 : -1) << ", ";
1390 for(const auto& locTrack : locChargePair.second)
1391 cout << locTrack << ", ";
1392 cout << endl;
1393 }
1394 }
1395
1396 //Fill histograms
1397 Fill_CutHistograms();
1398}
1399
1400bool DSourceComboer::Cut_dEdxAndEOverP(const DChargedTrackHypothesis* locChargedTrackHypothesis)
1401{
1402 auto locPID = locChargedTrackHypothesis->PID();
1403 auto locTrackTimeBased = locChargedTrackHypothesis->Get_TrackTimeBased();
1404 auto locP = locTrackTimeBased->momentum().Mag();
1405 bool locPassedCutFlag = true;
1406
1407 //CDC dE/dx
1408//cout << "PID, p, dedx, #hits = " << locPID << ", " << locP << ", " << locTrackTimeBased->ddEdx_CDC*1.0E6 << ", " << locTrackTimeBased->dNumHitsUsedFordEdx_CDC << endl;
1409 if(locTrackTimeBased->dNumHitsUsedFordEdx_CDC > 0)
1410 {
1411 auto locdEdx = locTrackTimeBased->ddEdx_CDC_amp*1.0E6;
1412 if(!Cut_dEdx(locPID, SYS_CDC, locP, locdEdx))
1413 locPassedCutFlag = false;
1414 }
1415 else if((locPID == KPlus) || (locPID == KMinus))
1416// if((locPID == KPlus) || (locPID == KMinus)) //COMPARE: use this instead
1417 {
1418 auto locSystem = locChargedTrackHypothesis->t1_detector();
1419 if((locSystem == SYS_START) || (locSystem == SYS_NULL))
1420 return false; //kaons are rare, and no PID information to find them (swamped with background): just cut these away
1421 }
1422
1423 //FDC dE/dx
1424 if(locTrackTimeBased->dNumHitsUsedFordEdx_FDC > 0)
1425 {
1426 auto locdEdx = locTrackTimeBased->ddEdx_FDC*1.0E6;
1427 if(!Cut_dEdx(locPID, SYS_FDC, locP, locdEdx))
1428 locPassedCutFlag = false;
1429 }
1430
1431 //SC dE/dx
1432 auto locSCHitMatchParams = locChargedTrackHypothesis->Get_SCHitMatchParams();
1433 if(locSCHitMatchParams != nullptr)
1434 {
1435 auto locdEdx = locSCHitMatchParams->dEdx*1.0E3;
1436 if(!Cut_dEdx(locPID, SYS_START, locP, locdEdx))
1437 locPassedCutFlag = false;
1438 }
1439
1440 //TOF dE/dx
1441 auto locTOFHitMatchParams = locChargedTrackHypothesis->Get_TOFHitMatchParams();
1442 if(locTOFHitMatchParams != nullptr)
1443 {
1444 auto locdEdx = locTOFHitMatchParams->dEdx*1.0E3;
1445 if(!Cut_dEdx(locPID, SYS_TOF, locP, locdEdx))
1446 locPassedCutFlag = false;
1447 }
1448
1449 //BCAL E/p
1450 auto locBCALShowerMatchParams = locChargedTrackHypothesis->Get_BCALShowerMatchParams();
1451 if(locBCALShowerMatchParams != nullptr)
1452 {
1453 const DBCALShower* locBCALShower = locBCALShowerMatchParams->dBCALShower;
1454 double locEOverP = locBCALShower->E/locP;
1455 if(!Cut_EOverP(locPID, SYS_BCAL, locP, locEOverP))
1456 locPassedCutFlag = false;
1457 }
1458
1459 //FCAL E/p
1460 auto locFCALShowerMatchParams = locChargedTrackHypothesis->Get_FCALShowerMatchParams();
1461 if(locFCALShowerMatchParams != nullptr)
1462 {
1463 const DFCALShower* locFCALShower = locFCALShowerMatchParams->dFCALShower;
1464 double locEOverP = locFCALShower->getEnergy()/locP;
1465 if(!Cut_EOverP(locPID, SYS_FCAL, locP, locEOverP))
1466 locPassedCutFlag = false;
1467 }
1468
1469 return locPassedCutFlag;
1470}
1471
1472bool DSourceComboer::Cut_Beta(const DNeutralParticleHypothesis* locNeutralParticleHypothesis)
1473{
1474 auto locPID = locNeutralParticleHypothesis->PID();
1475 auto locBeta = locNeutralParticleHypothesis->measuredBeta();
1476 auto locP = locNeutralParticleHypothesis->momentum().Mag();
1477 bool locPassedCutFlag = true;
1478 //cout << "PID " << locPID << " Momentum " << locP << endl;
1479
1480 //BCAL beta
1481 auto locDetectorSystem = locNeutralParticleHypothesis->t1_detector();
1482 if(!Cut_Beta(locPID, locDetectorSystem, locP, locBeta))
1483 locPassedCutFlag = false;
1484
1485 return locPassedCutFlag;
1486}
1487
1488void DSourceComboer::Fill_CutHistograms(void)
1489{
1490 japp->WriteLock("DSourceComboer_Cuts");
1491 {
1492 for(auto& locPIDPair : dHistMap_dEdx)
1493 {
1494 for(auto& locSystemPair : locPIDPair.second)
1495 {
1496 auto& locHist = locSystemPair.second;
1497 auto& locVector = ddEdxValueMap[locPIDPair.first][locSystemPair.first];
1498 for(auto& locVectorPair : locVector)
1499 locHist->Fill(locVectorPair.first, locVectorPair.second);
1500 }
1501 }
1502 for(auto& locPIDPair : dHistMap_EOverP)
1503 {
1504 for(auto& locSystemPair : locPIDPair.second)
1505 {
1506 auto& locHist = locSystemPair.second;
1507 auto& locVector = dEOverPValueMap[locPIDPair.first][locSystemPair.first];
1508 for(auto& locVectorPair : locVector)
1509 locHist->Fill(locVectorPair.first, locVectorPair.second);
1510 }
1511 }
1512 }
1513 japp->Unlock("DSourceComboer_Cuts");
1514
1515 //Reset for next event
1516 for(auto& locPIDPair : ddEdxValueMap)
1517 {
1518 for(auto& locSystemPair : locPIDPair.second)
1519 decltype(locSystemPair.second)().swap(locSystemPair.second);
1520 }
1521 for(auto& locPIDPair : dEOverPValueMap)
1522 {
1523 for(auto& locSystemPair : locPIDPair.second)
1524 decltype(locSystemPair.second)().swap(locSystemPair.second);
1525 }
1526}
1527
1528/********************************************************************* CREATE DSOURCOMBO'S **********************************************************************/
1529
1530DCombosByReaction DSourceComboer::Build_ParticleCombos(const DReactionVertexInfo* locReactionVertexInfo)
1531{
1532 //This builds the combos and creates DParticleCombo & DParticleComboSteps (doing whatever is necessary)
1533 if(dDebugLevel > 0)
1
Assuming field 'dDebugLevel' is <= 0
2
Taking false branch
1534 cout << "CREATING DSourceCombo's FOR DREACTION " << locReactionVertexInfo->Get_Reaction()->Get_ReactionName() << endl;
1535
1536 //Initialize results to be returned
1537 DCombosByReaction locOutputComboMap;
1538 auto locReactions = locReactionVertexInfo->Get_Reactions();
1539 for(auto locReaction : locReactions)
1540 {
1541 locOutputComboMap[locReaction] = {};
1542 dNumCombosSurvivedStageTracker[locReaction][DConstructionStage::Input] = 1; //is really #events
1543 }
1544
1545 if(!Check_Reactions(locReactions))
3
Taking false branch
1546 {
1547 if(dDebugLevel > 0)
1548 {
1549 cout << "FINISHED COMBOING:" << endl;
1550 for(auto locComboPair : locOutputComboMap)
1551 cout << "event#, reaction, #combos = " << dEventNumber << ", " << locComboPair.first->Get_ReactionName() << ", " << locComboPair.second.size() << endl;
1552 }
1553 return locOutputComboMap; //no combos!
1554 }
1555
1556 /******************************************************** COMBOING STEPS *******************************************************
1557 *
1558 * CHARGED STAGE:
1559 *
1560 * OK, we start with charged tracks, because we can't do much with neutrals until we know the vertex to compute the kinematics.
1561 * So, we create our combos, skipping all neutral particles, but filling in all charged tracks.
1562 *
1563 * If mass cuts are needed (e.g. Lambda -> p, pi-), we first create combos of "-> p, pi-", saving them for the USE "X -> p, pi-"
1564 * We then place the invariant mass cut, and those that pass get copied and saved for the USE "Lambda -> p, pi-"
1565 * Thus, storing the decay PID separately from the combo means we can reuse the combo without creating new objects in this case.
1566 *
1567 * Once we have our charged track combos, we can find (most of) the vertices (will discuss exceptions below).
1568 * Once we have the vertices, we can compute the time offsets between the vertices (the amount of time a decaying particle took to decay).
1569 * And we can then place timing cuts on the charged tracks to select which beam bunches are possible.
1570 * Now, you might be thinking that we can cut on the timing of the charged tracks BEFORE we find the vertices, but in some cases we can't.
1571 * For a discussion on this, see the comments in DSourceComboTimeHandler.
1572 *
1573 *
1574 *
1575 * MIXED STAGE: GENERAL
1576 *
1577 * OK, now let's combo some neutrals.
1578 * First, we combo all of the neutrals that are needed with each other, and THEN we combo them with charged tracks.
1579 * (This is how the DSourceComboInfo objects were constructed).
1580 * This is because pi0 comboing will take the longest, and we want to make sure it is done largely independent of any charged tracks.
1581 *
1582 *
1583 * MIXED STAGE: VERTEX-Z
1584 * Now, as discussed earlier, showers can be broken up into z-dependent and z-independent varieties.
1585 * Z-Independent: FCAL photons
1586 * Z-Dependent: BCAL showers or FCAL massive neutrals
1587 * However, since
1588 * Again, for details, see the comments in DSourceComboTimeHandler and DSourceComboP4Handler.
1589 *
1590 * Now, since the z-independent combos can be reused for any vertex-z, they are created first.
1591 * Then, the z-dependent combos are created, and combined with the z-independent ones.
1592 * To do this, it turns out it's easier to just try to create combos with ALL showers, and then skip creating the ones we've already created.
1593 *
1594 * While building combos, mass cuts are placed along the way, EXCEPT on combos with massive neutral particles.
1595 * This is because the exact vertex position is needed to get an accurate massive-neutral momentum.
1596 * While comboing, we want the results to be as re-usable as possible, that's why we use vertex-z bins.
1597 * But vertex-z bins are not sufficient for this, so we will cut on invariant masses with massive neutrals later.
1598 *
1599 *******************************************************************************************************************************/
1600
1601 //MUST BEWARE DUPLICATE COMBOS
1602 //let's say a combo of charged tracks has 2 valid RF bunches
1603 //and we need to combo 2 pi0s with them
1604 //and the shower timing cuts are loose enough that all 4 showers satisfy both RF bunches
1605 //if we combo the 2 rf bunches separately: WE HAVE DUPLICATE COMBOS
1606 //and doing the duplicate check AFTER the fact takes FOREVER
1607 //therefore, we must take the neutral showers for the 2 rfs, COMBINE THEM, and then COMBO AS A UNIT
1608
1609 //get step vertex infos (sorted in dependency order)
1610 auto locStepVertexInfos = locReactionVertexInfo->Get_StepVertexInfos();
1611 auto locPrimaryStepVertexInfo = locReactionVertexInfo->Get_StepVertexInfo(0);
1612 auto locPrimaryComboUse = dSourceComboUseReactionMap[locPrimaryStepVertexInfo];
1613 auto locPrimaryComboInfo = std::get<2>(locPrimaryComboUse);
1614
1615 //handle special case of no charged tracks
1616 if(dDebugLevel > 0)
4
Assuming field 'dDebugLevel' is <= 0
5
Taking false branch
1617 cout << "Combo charge content: " << dComboInfoChargeContent[std::get<2>(locPrimaryComboUse)] << " (charged/neutral are " << d_Charged << "/" << d_Neutral << ")" << endl;
1618 if(dComboInfoChargeContent[std::get<2>(locPrimaryComboUse)] == d_Neutral)
6
Assuming the condition is false
7
Taking false branch
1619 {
1620 if(dDebugLevel > 0)
1621 cout << "No charged tracks." << endl;
1622 for(auto& locReaction : locReactions)
1623 {
1624 dNumCombosSurvivedStageTracker[locReaction][DConstructionStage::Charged_Combos] = 1; //is really #-events
1625 dNumCombosSurvivedStageTracker[locReaction][DConstructionStage::Charged_RFBunch] = 1; //is really #-events
1626 }
1627 Combo_WithNeutralsAndBeam(locReactions, locReactionVertexInfo, locPrimaryComboUse, nullptr, {}, locOutputComboMap);
1628
1629 if(dDebugLevel > 0)
1630 {
1631 cout << "FINISHED COMBOING:" << endl;
1632 for(auto locComboPair : locOutputComboMap)
1633 cout << "event#, reaction, #combos = " << dEventNumber << ", " << locComboPair.first->Get_ReactionName() << ", " << locComboPair.second.size() << endl;
1634 }
1635 return locOutputComboMap;
1636 }
1637
1638 //Build vertex combos (returns those for the primary vertex, others are stored)
1639 Create_SourceCombos(locPrimaryComboUse, d_ChargedStage, nullptr, 0);
8
Calling 'DSourceComboer::Create_SourceCombos'
1640 const auto& locReactionChargedCombos = *(Get_CombosSoFar(d_ChargedStage, d_Charged, nullptr)[locPrimaryComboUse]);
1641 for(auto& locReaction : locReactions)
1642 dNumCombosSurvivedStageTracker[locReaction][DConstructionStage::Charged_Combos] = locReactionChargedCombos.size();
1643
1644 if(dDebugLevel > 0)
1645 {
1646 cout << "Charged combos built: " << locReactionChargedCombos.size() << endl;
1647 if(locReactionChargedCombos.empty())
1648 cout << "no combos for event: " << dEventNumber << endl;
1649 }
1650
1651 //loop over primary vertex combos //each contains decay combos except when dangling
1652 for(const auto& locReactionChargedCombo : locReactionChargedCombos)
1653 {
1654 //Calc all the vertex positions and time offsets for the vertices for these combos (where possible without beam energy)
1655 dSourceComboVertexer->Calc_VertexTimeOffsets_WithCharged(locReactionVertexInfo, locReactionChargedCombo);
1656
1657 //For the charged tracks, apply timing cuts to determine which RF bunches are possible
1658 vector<int> locBeamBunches_Charged;
1659 if(!dSourceComboTimeHandler->Select_RFBunches_Charged(locReactionVertexInfo, locReactionChargedCombo, locBeamBunches_Charged))
1660 continue; //failed PID timing cuts!
1661 for(auto& locReaction : locReactions)
1662 ++(dNumCombosSurvivedStageTracker[locReaction][DConstructionStage::Charged_RFBunch]);
1663
1664 //Special case of FULLY charged
1665 auto locChargeContent = dComboInfoChargeContent[locPrimaryComboInfo];
1666 if(locChargeContent == d_Charged)
1667 {
1668 if(dDebugLevel > 0)
1669 cout << "Fully charged." << endl;
1670
1671 if(false) //COMPARE: Comparison-to-old mode
1672 {
1673 dSourceComboTimeHandler->Vote_OldMethod(locReactionChargedCombo, locBeamBunches_Charged);
1674 if(locBeamBunches_Charged.empty())
1675 continue;
1676 }
1677
1678 //Select final RF bunch
1679 auto locRFBunch = dSourceComboTimeHandler->Select_RFBunch_Full(locReactionVertexInfo, locReactionChargedCombo, locBeamBunches_Charged);
1680 if(dDebugLevel > 0)
1681 cout << "Selected rf bunch." << endl;
1682
1683 for(auto& locReaction : locReactions)
1684 {
1685 ++(dNumCombosSurvivedStageTracker[locReaction][DConstructionStage::Full_Combos]);
1686 ++(dNumCombosSurvivedStageTracker[locReaction][DConstructionStage::Neutral_RFBunch]);
1687 ++(dNumCombosSurvivedStageTracker[locReaction][DConstructionStage::NoVertex_RFBunch]);
1688 ++(dNumCombosSurvivedStageTracker[locReaction][DConstructionStage::HeavyNeutral_IM]);
1689 }
1690
1691 //combo with beam and save results!!! (if no beam needed, just saves and returns)
1692 Combo_WithBeam(locReactions, locReactionVertexInfo, locPrimaryComboUse, locReactionChargedCombo, locRFBunch, locOutputComboMap);
1693 continue;
1694 }
1695
1696 //Combo with neutrals and beam
1697 Combo_WithNeutralsAndBeam(locReactions, locReactionVertexInfo, locPrimaryComboUse, locReactionChargedCombo, locBeamBunches_Charged, locOutputComboMap);
1698 }
1699
1700 if(dDebugLevel > 0)
1701 {
1702 cout << "FINISHED COMBOING:" << endl;
1703 for(auto locComboPair : locOutputComboMap)
1704 cout << "event#, reaction, #combos = " << dEventNumber << ", " << locComboPair.first->Get_ReactionName() << ", " << locComboPair.second.size() << endl;
1705 }
1706
1707 return locOutputComboMap;
1708}
1709
1710void DSourceComboer::Combo_WithNeutralsAndBeam(const vector<const DReaction*>& locReactions, const DReactionVertexInfo* locReactionVertexInfo, const DSourceComboUse& locPrimaryComboUse, const DSourceCombo* locReactionChargedCombo, const vector<int>& locBeamBunches_Charged, DCombosByReaction& locOutputComboMap)
1711{
1712 if(dDebugLevel > 0)
1713 {
1714 auto locNumDetectedShowers = dShowersByBeamBunchByZBin[DSourceComboInfo::Get_VertexZIndex_Unknown()][{}].size();
1715 auto locNumFCALShowers = dShowersByBeamBunchByZBin[DSourceComboInfo::Get_VertexZIndex_ZIndependent()][{}].size(); // Includes ComCal showers
1716 cout << endl << "Comboing neutrals, z-independent, #FCAL/BCAL showers: " << locNumFCALShowers << "/" << locNumDetectedShowers - locNumFCALShowers << endl;
1717 }
1718
1719 if(dDebugLevel >= 5)
1720 {
1721 cout << "charged combo, vertex zbins: " << locReactionChargedCombo;
1722 auto locVertexZBins = dSourceComboVertexer->Get_VertexZBins(locReactionVertexInfo, locReactionChargedCombo, nullptr, true);
1723 for(auto& locZBin : locVertexZBins)
1724 cout << ", " << int(locZBin);
1725 cout << endl;
1726 }
1727 //if there is a vertex zbin that is out of range, and we need photons: don't allow: will blow up memory due to no invariant mass cuts
1728 for(auto& locStepVertexInfo : locReactionVertexInfo->Get_StepVertexInfos())
1729 {
1730 auto locZBin = dSourceComboVertexer->Get_VertexZBin(locStepVertexInfo, locReactionChargedCombo, nullptr, true);
1731 if(locZBin != DSourceComboInfo::Get_VertexZIndex_OutOfRange())
1732 continue;
1733 if(!locStepVertexInfo->Get_OnlyConstrainTimeParticles().empty())
1734 {
1735 if(dDebugLevel > 0)
1736 cout << "Combo has photons at a vertex that is out of range: don't combo." << endl;
1737 return; //has photons, don't combo
1738 }
1739 }
1740
1741 //Create full source-particle combos (including neutrals): First using only FCAL showers, then using all showers
1742 Create_SourceCombos(locPrimaryComboUse, d_MixedStage_ZIndependent, locReactionChargedCombo, 0);
1743 auto locZDependentComboUse = Create_ZDependentSourceComboUses(locReactionVertexInfo, locReactionChargedCombo);
1744 if(dDebugLevel > 0)
1745 cout << endl << "Comboing neutrals, z-dependent." << endl;
1746 Create_SourceCombos(locZDependentComboUse, d_MixedStage, locReactionChargedCombo, 0);
1747
1748 //Then, get the full combos, but only those that satisfy the charged RF bunches
1749 vector<int> locComboRFBunches = locBeamBunches_Charged;
1750 //However, if there are no photons (only massive neutrals), then all of the combos have been saved with RF bunches = {} (empty set)
1751 if(!Get_HasPhotons(std::get<2>(locPrimaryComboUse)))
1752 locComboRFBunches.clear();
1753 const auto& locReactionFullCombos = Get_CombosForComboing(locZDependentComboUse, d_MixedStage, locComboRFBunches, locReactionChargedCombo);
1754 if(dDebugLevel > 0)
1755 cout << endl << "Neutral combos created, # with the charged RF bunches: " << locReactionFullCombos.size() << endl;
1756 for(auto& locReaction : locReactions)
1757 dNumCombosSurvivedStageTracker[locReaction][DConstructionStage::Full_Combos] += locReactionFullCombos.size();
1758
1759 if((dDebugLevel > 0) || (dDebugLevel == -1))
1760 Check_ForDuplicates(locReactionFullCombos);
1761
1762 //loop over full combos
1763 for(const auto& locReactionFullCombo : locReactionFullCombos)
1764 {
1765 //get common RF bunches between charged & neutral
1766 auto locNeutralRFBunches = dValidRFBunches_ByCombo[std::make_pair(locReactionFullCombo, DSourceComboInfo::Get_VertexZIndex_ZIndependent())];
1767 auto locValidRFBunches = dSourceComboTimeHandler->Get_CommonRFBunches(locBeamBunches_Charged, locNeutralRFBunches);
1768 if(dDebugLevel > 0)
1769 cout << "#charged bunches, #neutral, #common = " << locBeamBunches_Charged.size() << ", " << locNeutralRFBunches.size() << ", " << locValidRFBunches.size() << endl;
1770 if(locValidRFBunches.empty() && (!locNeutralRFBunches.empty() || !locBeamBunches_Charged.empty()))
1771 continue; //fail RF bunch cut
1772
1773 //if not fully neutral (at least one vertex position is known), do the below
1774 if(locReactionChargedCombo != nullptr)
1775 {
1776 //Calculate vertex positions & time offsets using photons
1777 //not likely to have any effect, but it's necessary sometimes (but rarely)
1778 //E.g. g, p -> K0, Sigma+ K0 -> 3pi: The selected pi0 photons could help define the production vertex
1779 dSourceComboVertexer->Calc_VertexTimeOffsets_WithPhotons(locReactionVertexInfo, locReactionChargedCombo, locReactionFullCombo);
1780
1781 //Now further select rf bunches, using tracks at the vertices we just found, and BCAL photon showers at any vertex
1782 //this also does PID cuts of photons at charged vertices while we're at it
1783 if(!dSourceComboTimeHandler->Select_RFBunches_PhotonVertices(locReactionVertexInfo, locReactionFullCombo, locValidRFBunches))
1784 {
1785 if(dDebugLevel > 0)
1786 cout << "Failed photon/photon-vertex PID timing cuts" << endl;
1787 continue; //failed PID timing cuts!
1788 }
1789 for(auto& locReaction : locReactions)
1790 ++(dNumCombosSurvivedStageTracker[locReaction][DConstructionStage::Neutral_RFBunch]);
1791
1792 //if no valid RF bunches, but still haven't cut: none of the charged tracks are at known vertices: select RF bunches with charged only
1793 if(locValidRFBunches.empty()) //e.g. g, p -> K0, Sigma+ K0 -> pi+, (pi-)
1794 {
1795 if(!dSourceComboTimeHandler->Select_RFBunches_AllVerticesUnknown(locReactionVertexInfo, locReactionFullCombo, d_Charged, locValidRFBunches))
1796 continue; //failed PID timing cuts!
1797 }
1798 for(auto& locReaction : locReactions)
1799 ++(dNumCombosSurvivedStageTracker[locReaction][DConstructionStage::NoVertex_RFBunch]);
1800 }
1801 else //fully neutral, so no known vertices, target center was chosen as vertex for comboing showers //e.g. g, p -> pi0, (p)
1802 {
1803 //we will never have a vertex, so do PID cuts for ALL photons using target center to select possible RF bunches
1804 if(!dSourceComboTimeHandler->Select_RFBunches_AllVerticesUnknown(locReactionVertexInfo, locReactionFullCombo, d_Neutral, locValidRFBunches))
1805 continue; //failed PID timing cuts!
1806 for(auto& locReaction : locReactions)
1807 ++(dNumCombosSurvivedStageTracker[locReaction][DConstructionStage::NoVertex_RFBunch]);
1808 }
1809
1810 if(false) //COMPARE: Comparison-to-old mode
1811 {
1812 dSourceComboTimeHandler->Vote_OldMethod(locReactionFullCombo, locValidRFBunches);
1813 if(locValidRFBunches.empty())
1814 continue;
1815 }
1816
1817 //Place mass cuts on massive neutrals: Effectively narrows down RF bunches
1818 //do 2 things at once (where vertex is known) (hence the really long function name):
1819 //calc & cut invariant mass: when massive neutral present
1820 //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)
1821 if(!dSourceComboP4Handler->Cut_InvariantMass_HasMassiveNeutral_OrPhotonVertex(locReactionVertexInfo, locReactionFullCombo, locValidRFBunches))
1822 continue; //failed cut!
1823 for(auto& locReaction : locReactions)
1824 ++(dNumCombosSurvivedStageTracker[locReaction][DConstructionStage::HeavyNeutral_IM]);
1825
1826 //Select final RF bunch //this is not a cut: at least one has passed all cuts (check by the Get_CombosForComboing function & the mass cuts)
1827 auto locRFBunch = dSourceComboTimeHandler->Select_RFBunch_Full(locReactionVertexInfo, locReactionFullCombo, locValidRFBunches);
1828
1829 //combo with beam and save results!!! (if no beam needed, just saves and returns)
1830 Combo_WithBeam(locReactions, locReactionVertexInfo, locZDependentComboUse, locReactionFullCombo, locRFBunch, locOutputComboMap);
1831 }
1832}
1833
1834void DSourceComboer::Combo_WithBeam(const vector<const DReaction*>& locReactions, const DReactionVertexInfo* locReactionVertexInfo, const DSourceComboUse& locReactionFullComboUse, const DSourceCombo* locReactionFullCombo, int locRFBunch, DCombosByReaction& locOutputComboMap)
1835{
1836 if(dDebugLevel > 0)
1837 cout << endl << "Comboing beam." << endl;
1838
1839 //if no beam then we are done!
1840 if(!locReactionVertexInfo->Get_StepVertexInfo(0)->Get_ProductionVertexFlag())
1841 {
1842 if(dDebugLevel > 0)
1843 cout << "No beam particles, we are done!" << endl;
1844
1845 //place invariant mass cuts using accurate photon kinematics
1846 auto locPassMassCutFlag = dSourceComboP4Handler->Cut_InvariantMass_AccuratePhotonKinematics(locReactionVertexInfo, locReactionFullCombo, nullptr, locRFBunch);
1847 for(const auto& locReaction : locReactions)
1848 {
1849 ++(dNumCombosSurvivedStageTracker[locReaction][DConstructionStage::Beam_Combos]);
1850 ++(dNumCombosSurvivedStageTracker[locReaction][DConstructionStage::MMVertex_Timing]);
1851 ++(dNumCombosSurvivedStageTracker[locReaction][DConstructionStage::MMVertex_IMCuts]);
1852 if(!locPassMassCutFlag)
1853 continue; //FAILED MASS CUTS!
1854
1855 ++(dNumCombosSurvivedStageTracker[locReaction][DConstructionStage::AccuratePhoton_IM]);
1856 ++(dNumCombosSurvivedStageTracker[locReaction][DConstructionStage::Reaction_BeamRFCuts]);
1857 ++(dNumCombosSurvivedStageTracker[locReaction][DConstructionStage::Missing_Mass]);
1858 locOutputComboMap[locReaction].push_back(dParticleComboCreator->Build_ParticleCombo(locReactionVertexInfo, locReactionFullCombo, nullptr, locRFBunch, locReaction->Get_KinFitType()));
1859 }
1860 return;
1861 }
1862
1863 //Select beam particles
1864 if (abs(locRFBunch) > 2000000000)
1865 return; // proximity to INT_MAX can cause infinite loops, certainly no valid beam particle
1866
1867 auto locBeamParticles = dSourceComboTimeHandler->Get_BeamParticlesByRFBunch(locRFBunch, dMaxRFBunchCuts[locReactionVertexInfo]);
1868 if(dDebugLevel > 0)
1869 cout << "rf bunch, max #rf bunches, #beams = " << locRFBunch << ", " << dMaxRFBunchCuts[locReactionVertexInfo] << ", " << locBeamParticles.size() << endl;
1870 if(locBeamParticles.empty())
1871 return; //no valid beam particles!!
1872 for(const auto& locReaction : locReactions)
1873 dNumCombosSurvivedStageTracker[locReaction][DConstructionStage::Beam_Combos] += locBeamParticles.size();
1874
1875 //loop over beam particles
1876 for(const auto& locBeamParticle : locBeamParticles)
1877 {
1878 //Calculate remaining vertex positions (that needed to be done via missing mass)
1879 dSourceComboVertexer->Calc_VertexTimeOffsets_WithBeam(locReactionVertexInfo, locReactionFullComboUse, locReactionFullCombo, locBeamParticle);
1880
1881 //placing timing cuts on the particles at these vertices
1882 if(!dSourceComboTimeHandler->Cut_Timing_MissingMassVertices(locReactionVertexInfo, locReactionFullCombo, locBeamParticle, locRFBunch))
1883 continue; //FAILED TIME CUTS!
1884 for(const auto& locReaction : locReactions)
1885 ++(dNumCombosSurvivedStageTracker[locReaction][DConstructionStage::MMVertex_Timing]);
1886
1887 //place invariant mass cuts on the particles at these vertices (if they had z-dependent neutral showers (BCAL or massive))
1888 if(!dSourceComboP4Handler->Cut_InvariantMass_MissingMassVertex(locReactionVertexInfo, locReactionFullCombo, locBeamParticle, locRFBunch))
1889 continue; //FAILED MASS CUTS!
1890 for(const auto& locReaction : locReactions)
1891 ++(dNumCombosSurvivedStageTracker[locReaction][DConstructionStage::MMVertex_IMCuts]);
1892
1893 //place invariant mass cuts using accurate photon kinematics
1894 if(!dSourceComboP4Handler->Cut_InvariantMass_AccuratePhotonKinematics(locReactionVertexInfo, locReactionFullCombo, locBeamParticle, locRFBunch))
1895 continue; //FAILED MASS CUTS!
1896 for(const auto& locReaction : locReactions)
1897 ++(dNumCombosSurvivedStageTracker[locReaction][DConstructionStage::AccuratePhoton_IM]);
1898
1899 //loop over reactions: cut on rf-bunch shift for each reaction, cut on missing mass^2, then save the results
1900 auto locBeamRFBunch = dSourceComboTimeHandler->Calc_RFBunchShift(locBeamParticle->time());
1901 size_t locDeltaRFBunch = abs(locRFBunch - locBeamRFBunch);
1902 for(const auto& locReaction : locReactions)
1903 {
1904 if(dDebugLevel > 0)
1905 cout<< "beam rf bunch, delta rf bunch, reaction, max for reaction = " << locBeamRFBunch << ", " << locDeltaRFBunch << ", " << locReaction->Get_ReactionName() << ", " << dRFBunchCutsByReaction[locReaction] << endl;
1906 if(locDeltaRFBunch > dRFBunchCutsByReaction[locReaction])
1907 continue; //FAILED RF BUNCH CUT
1908 ++(dNumCombosSurvivedStageTracker[locReaction][DConstructionStage::Reaction_BeamRFCuts]);
1909
1910 if(!dSourceComboP4Handler->Cut_MissingMassSquared(locReaction, locReactionVertexInfo, locReactionFullComboUse, locReactionFullCombo, locBeamParticle, locRFBunch))
1911 continue; //FAILED MISSING MASS^2 CUT!
1912 ++(dNumCombosSurvivedStageTracker[locReaction][DConstructionStage::Missing_Mass]);
1913
1914 //build particle combo & save
1915 locOutputComboMap[locReaction].push_back(dParticleComboCreator->Build_ParticleCombo(locReactionVertexInfo, locReactionFullCombo, locBeamParticle, locRFBunch, locReaction->Get_KinFitType()));
1916 if(dDebugLevel >= 10)
1917 {
1918 cout << "Created particle combo, beam energy, combo contents = " << locBeamParticle->energy() << endl;
1919 DAnalysis::Print_SourceCombo(locReactionFullCombo);
1920 }
1921 }
1922 }
1923}
1924
1925/**************************************************************** BUILD SOURCE COMBOS - GENERAL *****************************************************************/
1926
1927/*
1928 * suppose reaction is 0) g, p -> omega, p
1929 * 1) omega -> 3pi
1930 * 2) pi0 -> 2g
1931 *
1932 * It will have uses/infos like:
1933 * 0: X -> 1, A (mixed + charged) (both are listed as further decays)
1934 * A: X -> p (charged)
1935 * 1: omega -> B, 2 (mixed) (both are listed as further decays)
1936 * B: X -> pi+, pi- (charged)
1937 * 2: pi0 -> 2g (neutral)
1938 *
1939 * The purpose of passing through the charged combo:
1940 * 1) To retrieve the correct charged combo when comboing it to neutrals to create mixed
1941 * 2) To save the mixed comboing results in a way that they can be reused
1942 *
1943 * The charged combos will be:
1944 * 0: X -> A, 1 //presiding = 0, withnow = A
1945 * A: X -> p //both = nullptr
1946 * 1: omega -> B, 2 //presiding = 1, withnow = B
1947 * B: X -> pi+, pi- //both = nullptr
1948 * 2: pi0 -> 2g //both = nullptr
1949 *
1950 * suppose reaction is 0) g, p -> K0, Sigma+
1951 * 1) K0 -> 3pi
1952 * 2) pi0 -> 2g
1953 * 3) Sigma+ -> pi+, n
1954 *
1955 * It will have uses/infos like:
1956 * 0: X -> A, 1, 3 (mixed -> charged, mixed, mixed) //presiding = 0, withnow = A
1957 * A: X -> p (charged) //both = nullptr
1958 * 1: K0 -> B, 2 (mixed -> charged, neutral) //presiding = 1, withnow = B
1959 * B: X -> pi+, pi- (charged) //both = nullptr
1960 * 2: pi0 -> 2g (neutral) //both = nullptr
1961 * 3: Sigma+ -> C, n (mixed -> charged, n) //presiding = 3, withnow = C
1962 * C: X -> pi+ (charged) //both = nullptr
1963 */
1964
1965void DSourceComboer::Create_SourceCombos(const DSourceComboUse& locComboUseToCreate, ComboingStage_t locComboingStage, const DSourceCombo* locChargedCombo_Presiding, unsigned char locNumTabs)
1966{
1967 if(dDebugLevel > 0)
9
Assuming field 'dDebugLevel' is <= 0
10
Taking false branch
1968 {
1969 cout << endl;
1970 for(decltype(locNumTabs) locTabNum = 0; locTabNum < locNumTabs; ++locTabNum) cout << "\t";
1971 cout << "Creating source combos: Stage, presiding charged combo: " << locComboingStage << ", " << locChargedCombo_Presiding << endl;
1972 for(decltype(locNumTabs) locTabNum = 0; locTabNum < locNumTabs; ++locTabNum) cout << "\t";
1973 cout << "PRESIDING COMBO:" << endl;
1974 DAnalysis::Print_SourceCombo(locChargedCombo_Presiding, locNumTabs);
1975 for(decltype(locNumTabs) locTabNum = 0; locTabNum < locNumTabs; ++locTabNum) cout << "\t";
1976 cout << "USE TO CREATE:" << endl;
1977 DAnalysis::Print_SourceComboUse(locComboUseToCreate, locNumTabs);
1978 }
1979
1980 //if on mixed stage, it is impossible for this function to be called with a fully-charged use (already exists!!)
1981 const auto& locDecayPID = std::get<0>(locComboUseToCreate);
1982 const auto& locVertexZBin = std::get<1>(locComboUseToCreate);
1983 const auto& locSourceComboInfo = std::get<2>(locComboUseToCreate);
1984 const auto& locMissingDecayProductFlag = std::get<3>(locComboUseToCreate);
1985
1986 //Get combos so far
1987 auto& locSourceCombosByUseSoFar = Get_CombosSoFar(locComboingStage, dComboInfoChargeContent[locSourceComboInfo], locChargedCombo_Presiding);
1988 if(locSourceCombosByUseSoFar.find(locComboUseToCreate) != locSourceCombosByUseSoFar.end())
11
Assuming the condition is false
12
Taking false branch
1989 {
1990 if(dDebugLevel > 0)
1991 cout << "Already created!" << endl;
1992 return; //we're done!
1993 }
1994
1995 //we will create these combos for an "Unknown" decay (i.e. no decay, just a direct grouping) (unless already created!)
1996 //then, when we return from this function, we can cut on the invariant mass of the system for any decay we might need it for
1997 DSourceComboUse locUnknownComboUse(Unknown, locVertexZBin, locSourceComboInfo, false, Unknown);
1998 if(locSourceCombosByUseSoFar.find(locUnknownComboUse) == locSourceCombosByUseSoFar.end())
13
Assuming the condition is false
14
Taking false branch
1999 Create_SourceCombos_Unknown(locUnknownComboUse, locComboingStage, locChargedCombo_Presiding, locNumTabs);
2000
2001 if(dDebugLevel > 0)
15
Assuming field 'dDebugLevel' is <= 0
16
Taking false branch
2002 {
2003 for(decltype(locNumTabs) locTabNum = 0; locTabNum < locNumTabs; ++locTabNum) cout << "\t";
2004 cout << "Combos with unknown parent created, desired decay pid = " << locDecayPID << endl;
2005 }
2006
2007 //if all we want is a direct grouping (unknown), then the combos have already been made: return
2008 if(locDecayPID == Unknown)
17
Assuming 'locDecayPID' is not equal to Unknown
18
Taking false branch
2009 return;
2010
2011 //get the combos that we just created
2012 auto locInfoChargeContent = dComboInfoChargeContent[locSourceComboInfo];
2013 auto locSourceCombos = locSourceCombosByUseSoFar[locUnknownComboUse];
2014
2015 if((locComboingStage
18.1
'locComboingStage' is equal to d_ChargedStage
18.1
'locComboingStage' is equal to d_ChargedStage
18.1
'locComboingStage' is equal to d_ChargedStage
== d_ChargedStage) && (locInfoChargeContent != d_Charged))
19
Assuming 'locInfoChargeContent' is equal to d_Charged
20
Taking false branch
2016 {
2017 //don't cut yet! we don't have the neutrals! just copy results and return
2018 if(dDebugLevel > 0)
2019 {
2020 for(decltype(locNumTabs) locTabNum = 0; locTabNum < locNumTabs; ++locTabNum) cout << "\t";
2021 cout << "On charged stage, need neutrals: done for now" << endl;
2022 }
2023 locSourceCombosByUseSoFar.emplace(locComboUseToCreate, locSourceCombos);
2024
2025 //Set the resume indices
2026 Build_ComboResumeIndices(locComboUseToCreate, locComboingStage, locChargedCombo_Presiding);
2027 return;
2028 }
2029
2030 if(locMissingDecayProductFlag)
21
Assuming 'locMissingDecayProductFlag' is false
22
Taking false branch
2031 {
2032 //Don't cut! just copy results and return
2033 if(dDebugLevel > 0)
2034 {
2035 for(decltype(locNumTabs) locTabNum = 0; locTabNum < locNumTabs; ++locTabNum) cout << "\t";
2036 cout << "Missing decay product: No invariant mass cut." << endl;
2037 }
2038 locSourceCombosByUseSoFar.emplace(locComboUseToCreate, locSourceCombos);
2039
2040 //Set the resume indices
2041 Build_ComboResumeIndices(locComboUseToCreate, locComboingStage, locChargedCombo_Presiding);
2042 return;
2043 }
2044
2045 //get combos by beam bunch
2046 auto* locSourceCombosByBeamBunchByUse = (locComboingStage
22.1
'locComboingStage' is equal to d_ChargedStage
22.1
'locComboingStage' is equal to d_ChargedStage
22.1
'locComboingStage' is equal to d_ChargedStage
!= d_ChargedStage) ? &(Get_SourceCombosByBeamBunchByUse(locInfoChargeContent, locChargedCombo_Presiding)) : nullptr;
23
'?' condition is false
24
'locSourceCombosByBeamBunchByUse' initialized to a null pointer value
2047
2048 //cannot place an invariant mass cut on massive neutrals yet, because:
2049 //vertex position must first be defined
2050 //although we probably HAVE the vertex position, if it's a fully neutral combo, we don't want to use it:
2051 //results are stored in vertex-z-bins and independent of charged combo: if we cut, we won't be able to reuse the results (because we need PRECISE position, not just a z-bin)
2052 //if it is a mixed combo with known vertex, we can conceivably cut, but there aren't too many of those: Just put off the cuts until later
2053 if(Get_HasMassiveNeutrals(locSourceComboInfo))
25
Calling 'DSourceComboer::Get_HasMassiveNeutrals'
31
Returning from 'DSourceComboer::Get_HasMassiveNeutrals'
32
Taking true branch
2054 {
2055 if(dDebugLevel > 0)
33
Assuming field 'dDebugLevel' is <= 0
34
Taking false branch
2056 {
2057 for(decltype(locNumTabs) locTabNum = 0; locTabNum < locNumTabs; ++locTabNum) cout << "\t";
2058 cout << "Massive neutrals, done for now" << endl;
2059 }
2060 locSourceCombosByUseSoFar.emplace(locComboUseToCreate, locSourceCombos);
2061 (*locSourceCombosByBeamBunchByUse)[locComboUseToCreate] = (*locSourceCombosByBeamBunchByUse)[locUnknownComboUse];
35
Called C++ object pointer is null
2062
2063 //Set the resume indices
2064 Build_ComboResumeIndices(locComboUseToCreate, locComboingStage, locChargedCombo_Presiding);
2065 return;
2066 }
2067
2068 //if on the all-showers stage, first copy over ALL fcal-only results
2069 locSourceCombosByUseSoFar.emplace(locComboUseToCreate, Get_SourceComboVectorResource());
2070 if(locComboingStage == d_MixedStage)
2071 Copy_ZIndependentMixedResults(locComboUseToCreate, locChargedCombo_Presiding);
2072
2073 if(locSourceCombos->empty())
2074 return; //nothing to create
2075
2076 if((locComboingStage == d_MixedStage) && (locVertexZBin == DSourceComboInfo::Get_VertexZIndex_Unknown()))
2077 {
2078 //we need a zbin for BCAL showers, but it is unknown: can't cut yet!
2079 //However, the FCAL ones were already cut during the z-independent stage, and have already been saved
2080 //so, just copy over the bcal results from the unknown use
2081 for(auto& locCombo : *locSourceCombos)
2082 {
2083 if(!locCombo->Get_IsComboingZIndependent()) //bcal only
2084 locSourceCombosByUseSoFar[locComboUseToCreate]->push_back(locCombo);
2085 }
2086
2087 //Copy over the combos-by-beam-bunch
2088 auto& locUnknownBothCombosByBeamBunch = (*locSourceCombosByBeamBunchByUse)[locUnknownComboUse];
2089 for(const auto& locComboBeamBunchPair : locUnknownBothCombosByBeamBunch)
2090 {
2091 if(locComboBeamBunchPair.first.size() > 1)
2092 continue; //don't copy the overlap ones: they are not complete & need to be filled on the fly
2093 for(const auto& locCombo : locComboBeamBunchPair.second)
2094 {
2095 if(!locCombo->Get_IsComboingZIndependent()) //bcal only
2096 (*locSourceCombosByBeamBunchByUse)[locComboUseToCreate][locComboBeamBunchPair.first].push_back(locCombo);
2097 }
2098 }
2099
2100 //Set the resume indices
2101 Build_ComboResumeIndices(locComboUseToCreate, locComboingStage, locChargedCombo_Presiding);
2102 return;
2103 }
2104
2105 //place an invariant mass cut & save the results
2106 auto locTargetPIDToSubtract = std::get<4>(locComboUseToCreate);
2107 for(const auto& locSourceCombo : *locSourceCombos)
2108 {
2109 //If on all-showers stage, and combo is fcal-only, don't save (combo already created!!)
2110 if((locComboingStage == d_MixedStage) && locSourceCombo->Get_IsComboingZIndependent())
2111 continue; //this combo has already passed the cut & been saved: during the FCAL-only stage
2112 if(!dSourceComboP4Handler->Cut_InvariantMass_NoMassiveNeutrals(locSourceCombo, locDecayPID, locTargetPIDToSubtract, dTargetCenter, locVertexZBin, false))
2113 continue; //vertex not used if accurate-flag is false: can be anything (target center)
2114
2115 //save the results
2116 locSourceCombosByUseSoFar[locComboUseToCreate]->push_back(locSourceCombo);
2117 if(locComboingStage == d_ChargedStage)
2118 continue;
2119
2120 //register beam bunches
2121 const auto& locBeamBunches = dValidRFBunches_ByCombo[std::make_pair(locSourceCombo, locVertexZBin)];
2122 Register_ValidRFBunches(locComboUseToCreate, locSourceCombo, locBeamBunches, locComboingStage, locChargedCombo_Presiding);
2123 }
2124
2125 //Set the resume indices
2126 Build_ComboResumeIndices(locComboUseToCreate, locComboingStage, locChargedCombo_Presiding);
2127}
2128
2129void DSourceComboer::Create_SourceCombos_Unknown(const DSourceComboUse& locComboUseToCreate, ComboingStage_t locComboingStage, const DSourceCombo* locChargedCombo_Presiding, unsigned char locNumTabs)
2130{
2131 /****************************************************** COMBOING PARTICLES *****************************************************
2132 *
2133 * First combo VERTICALLY, and then HORIZONTALLY
2134 * What does this mean?
2135 * Vertically: Make combos of size N of each PID needed (e.g. 3 pi0s)
2136 * Horizontally: Make combos of different PIDs (e.g. 2pi0, pi+, pi-, p)
2137 *
2138 * Why start with vertical comboing?
2139 * because the thing that takes the most time is when someone decides to analyze (e.g.) 2pi0, 3pi0, then 3pi0 eta, 3pi0 something else, 4pi0, etc.
2140 * we want to make the Npi0 combos as needed, then reuse the Npi0s when making combos of other types
2141 * thus we want to build vertically (pi0s together, then etas together), and THEN horizontally (combine pi0s & etas, etc)
2142 * plus, when building vertically, it's easier to keep track of things since the PID / decay-parent is the same
2143 *
2144 * Build all possible combos for all NEEDED GROUPINGS for each of the FURTHER DECAYS (if not done already)
2145 * this becomes a series of recursive calls
2146 * e.g. if need 3 pi0s, call for 2pi0s, which calls for 1pi0, which calls for 2g
2147 * then do the actual pi0 groupings on the return
2148 *
2149 * Note, if we combo vertically (e.g. 3pi0s, 2pi+'s, etc.), they are created with a use that is strictly that content.
2150 * Then, when we combo them horizontally, they are promoted out of the vertical combo, at the same level as everything else in the new horizontal combo.
2151 * This reduces the depth-complexity of the combos.
2152 *
2153 *******************************************************************************************************************************/
2154
2155 if(dDebugLevel > 0)
2156 {
2157 cout << endl;
2158 for(decltype(locNumTabs) locTabNum = 0; locTabNum < locNumTabs; ++locTabNum) cout << "\t";
2159 cout << "Create_SourceCombos_Unknown: Stage, presiding charged combo, use to create = " << locComboingStage << ", " << locChargedCombo_Presiding << endl;
2160 for(decltype(locNumTabs) locTabNum = 0; locTabNum < locNumTabs; ++locTabNum) cout << "\t";
2161 cout << "PRESIDING COMBO:" << endl;
2162 DAnalysis::Print_SourceCombo(locChargedCombo_Presiding, locNumTabs);
2163 for(decltype(locNumTabs) locTabNum = 0; locTabNum < locNumTabs; ++locTabNum) cout << "\t";
2164 cout << "USE TO CREATE:" << endl;
2165 DAnalysis::Print_SourceComboUse(locComboUseToCreate, locNumTabs);
2166 }
2167
2168 //get use info, combos
2169 auto locComboInfoToCreate = std::get<2>(locComboUseToCreate);
2170 auto locChargeContent = dComboInfoChargeContent[locComboInfoToCreate];
2171 auto& locSourceCombosByUseSoFar = Get_CombosSoFar(locComboingStage, locChargeContent, locChargedCombo_Presiding);
2172
2173 Combo_Vertically_AllDecays(locComboUseToCreate, locComboingStage, locChargedCombo_Presiding, locNumTabs);
2174 if(locSourceCombosByUseSoFar.find(locComboUseToCreate) != locSourceCombosByUseSoFar.end())
2175 {
2176 if(dDebugLevel > 0)
2177 cout << "We're done!" << endl;
2178 return; //we're done!
2179 }
2180
2181 if((locComboingStage == d_ChargedStage) || (locChargeContent == d_Neutral))
2182 {
2183 Combo_Vertically_AllParticles(locComboUseToCreate, locComboingStage, locNumTabs); //no such thing as a "mixed" particle
2184 if(locSourceCombosByUseSoFar.find(locComboUseToCreate) != locSourceCombosByUseSoFar.end())
2185 {
2186 if(dDebugLevel > 0)
2187 cout << "We're done!" << endl;
2188 return; //we're done!
2189 }
2190 }
2191
2192 //OK, now build horizontally!! //group particles with different PIDs
2193 Combo_Horizontally_All(locComboUseToCreate, locComboingStage, locChargedCombo_Presiding, locNumTabs);
2194}
2195
2196/************************************************************** BUILD PHOTON COMBOS - VERTICALLY ****************************************************************/
2197
2198void DSourceComboer::Combo_Vertically_AllDecays(const DSourceComboUse& locComboUseToCreate, ComboingStage_t locComboingStage, const DSourceCombo* locChargedCombo_Presiding, unsigned char locNumTabs)
2199{
2200 if(dDebugLevel >= 5)
2201 {
2202 cout << endl;
2203 for(decltype(locNumTabs) locTabNum = 0; locTabNum < locNumTabs; ++locTabNum) cout << "\t";
2204 cout << "Combo_Vertically_AllDecays: Stage, presiding charged combo = " << locComboingStage << ", " << locChargedCombo_Presiding << endl;
2205 for(decltype(locNumTabs) locTabNum = 0; locTabNum < locNumTabs; ++locTabNum) cout << "\t";
2206 cout << "PRESIDING COMBO:" << endl;
2207 DAnalysis::Print_SourceCombo(locChargedCombo_Presiding, locNumTabs);
2208 for(decltype(locNumTabs) locTabNum = 0; locTabNum < locNumTabs; ++locTabNum) cout << "\t";
2209 cout << "USE TO CREATE:" << endl;
2210 DAnalysis::Print_SourceComboUse(locComboUseToCreate, locNumTabs);
2211 }
2212
2213 //get combo use contents
2214 auto locComboInfo = std::get<2>(locComboUseToCreate);
2215 auto locVertexZBin = std::get<1>(locComboUseToCreate);
2216 auto locNumParticlesNeeded = locComboInfo->Get_NumParticles();
2217 auto locFurtherDecays = locComboInfo->Get_FurtherDecays();
2218
2219 //for each further decay map entry (e.g. pi0, 3), this is a collection of the uses representing those groupings //e.g. Unknown -> 3pi0
2220 for(const auto& locFurtherDecayPair : locFurtherDecays)
2221 {
2222 auto& locSourceComboDecayUse = locFurtherDecayPair.first; //e.g. pi0, -> 2g
2223 auto& locNumDecaysNeeded = locFurtherDecayPair.second; //N of the above decay (e.g. pi0s)
2224 auto locSourceComboDecayInfo = std::get<2>(locSourceComboDecayUse);
2225 auto locDecayChargeContent = dComboInfoChargeContent[locSourceComboDecayInfo];
2226
2227 if((locComboingStage == d_ChargedStage) && (locDecayChargeContent == d_Neutral))
2228 continue; //skip for now!!
2229 //if on a mixed stage, and the to-build combo info is fully charged, skip it: it's already been done
2230 if((locComboingStage != d_ChargedStage) && (locDecayChargeContent == d_Charged))
2231 continue;
2232
2233 if(locNumDecaysNeeded == 1)
2234 {
2235 //must dive down to get the next charged combo
2236 //building for the first time: the first one (later ones will be grabbed when building these combos vertically (in Combo_Vertically_NDecays))
2237 auto locChargedCombo_NextPresiding = Get_NextChargedCombo(locChargedCombo_Presiding, locSourceComboDecayUse, locComboingStage, true, 1);
2238 auto& locSourceCombosByUseSoFar = Get_CombosSoFar(locComboingStage, locDecayChargeContent, locChargedCombo_NextPresiding);
2239
2240 //build the decay combo directly
2241 if(locSourceCombosByUseSoFar.find(locSourceComboDecayUse) == locSourceCombosByUseSoFar.end()) //if not done already!
2242 {
2243 //must return to top-level combo function to build this decay, as this may have any structure
2244 Create_SourceCombos(locSourceComboDecayUse, locComboingStage, locChargedCombo_NextPresiding, locNumTabs + 1);
2245 }
2246 else if(dDebugLevel > 0)
2247 cout << "This decay already created!" << endl;
2248
2249 continue; //no actual comboing needs to be done with this just yet, will do so in horizontal stage
2250 }
2251
2252 //OK, so we need a grouping of N > 1 decays (e.g. pi0s)
2253 //so, let's create a use of Unknown -> N pi0s (e.g.)
2254 //if we can just utilize the use from the input combo-info, then we will. if not, we'll make a new one
2255 auto locNeededGroupingUse = locComboUseToCreate;
2256 if((locFurtherDecays.size() > 1) || !locNumParticlesNeeded.empty()) //if true: can't use the input
2257 {
2258 auto locGroupingComboInfo = GetOrMake_SourceComboInfo({}, {std::make_pair(locSourceComboDecayUse, locNumDecaysNeeded)}, locNumTabs); // -> N pi0s (e.g.)
2259 locNeededGroupingUse = std::make_tuple(Unknown, locVertexZBin, locGroupingComboInfo, false, Unknown); // Unknown -> Npi0s (e.g.)
2260 }
2261
2262 // Now, see whether the combos for this grouping have already been done
2263 auto& locSourceCombosByUseSoFar = Get_CombosSoFar(locComboingStage, locDecayChargeContent, locChargedCombo_Presiding);
2264 if(locSourceCombosByUseSoFar.find(locNeededGroupingUse) != locSourceCombosByUseSoFar.end())
2265 {
2266 if(dDebugLevel > 0)
2267 cout << "This decay already created!" << endl;
2268 continue; //it's already done!!
2269 }
2270
2271 //it's not already done. darn it.
2272 //build an info and a use for a direct grouping of N - 1 decays //e.g. 2pi0s
2273 auto locNMinus1ComboUse = locSourceComboDecayUse; //initialize (is valid if #needed == 2, otherwise will create it)
2274 if(locNumDecaysNeeded > 2)
2275 {
2276 auto locNMinus1Info = GetOrMake_SourceComboInfo({}, {std::make_pair(locSourceComboDecayUse, locNumDecaysNeeded - 1)}, locNumTabs); // 0 detected particles, N - 1 pi0s (e.g.)
2277 locNMinus1ComboUse = std::make_tuple(Unknown, locVertexZBin, locNMinus1Info, false, Unknown); // Unknown -> N - 1 pi0s (e.g.)
2278 }
2279
2280 // Now, see whether the combos for the direct N - 1 grouping have already been done. If not, create them
2281 if(locNumDecaysNeeded == 2) //(so N - 1 = 1)
2282 {
2283 auto locChargedCombo_NextPresiding = Get_NextChargedCombo(locChargedCombo_Presiding, locSourceComboDecayUse, locComboingStage, true, 1);
2284 locSourceCombosByUseSoFar = Get_CombosSoFar(locComboingStage, locDecayChargeContent, locChargedCombo_NextPresiding);
2285 if(locSourceCombosByUseSoFar.find(locNMinus1ComboUse) == locSourceCombosByUseSoFar.end())
2286 Create_SourceCombos(locNMinus1ComboUse, locComboingStage, locChargedCombo_NextPresiding, locNumTabs + 1);
2287 }
2288 else
2289 {
2290 //if not done yet, no need to go to top-level combo function since just N - 1: can re-call this one
2291 if(locSourceCombosByUseSoFar.find(locNMinus1ComboUse) == locSourceCombosByUseSoFar.end())
2292 Combo_Vertically_AllDecays(locNMinus1ComboUse, locComboingStage, locChargedCombo_Presiding, locNumTabs + 1);
2293 }
2294
2295 //Finally, we can actually DO the grouping, between the N - 1 combos and the one-off combos
2296 Combo_Vertically_NDecays(locNeededGroupingUse, locNMinus1ComboUse, locSourceComboDecayUse, locComboingStage, locChargedCombo_Presiding, locNumTabs);
2297 }
2298}
2299
2300void DSourceComboer::Combo_Vertically_NDecays(const DSourceComboUse& locComboUseToCreate, const DSourceComboUse& locNMinus1ComboUse, const DSourceComboUse& locSourceComboDecayUse, ComboingStage_t locComboingStage, const DSourceCombo* locChargedCombo_Presiding, unsigned char locNumTabs)
2301{
2302 if(dDebugLevel >= 5)
2303 {
2304 cout << endl;
2305 for(decltype(locNumTabs) locTabNum = 0; locTabNum < locNumTabs; ++locTabNum) cout << "\t";
2306 cout << "Combo_Vertically_NDecays: Stage, presiding charged combo = " << locComboingStage << ", " << locChargedCombo_Presiding << endl;
2307 for(decltype(locNumTabs) locTabNum = 0; locTabNum < locNumTabs; ++locTabNum) cout << "\t";
2308 cout << "PRESIDING COMBO:" << endl;
2309 DAnalysis::Print_SourceCombo(locChargedCombo_Presiding, locNumTabs);
2310 for(decltype(locNumTabs) locTabNum = 0; locTabNum < locNumTabs; ++locTabNum) cout << "\t";
2311 cout << "USE TO CREATE:" << endl;
2312 DAnalysis::Print_SourceComboUse(locComboUseToCreate, locNumTabs);
2313 for(decltype(locNumTabs) locTabNum = 0; locTabNum < locNumTabs; ++locTabNum) cout << "\t";
2314 cout << "N - 1 USE:" << endl;
2315 DAnalysis::Print_SourceComboUse(locNMinus1ComboUse, locNumTabs);
2316 for(decltype(locNumTabs) locTabNum = 0; locTabNum < locNumTabs; ++locTabNum) cout << "\t";
2317 cout << "SINGLE USE:" << endl;
2318 DAnalysis::Print_SourceComboUse(locSourceComboDecayUse, locNumTabs);
2319 }
2320
2321 auto locNIs2Flag = (locNMinus1ComboUse == locSourceComboDecayUse); //true if need exactly 2 decaying particles
2322
2323 //Get combos so far
2324 auto locComboInfoToCreate = std::get<2>(locComboUseToCreate);
2325 auto locChargeContent = dComboInfoChargeContent[locComboInfoToCreate];
2326 auto& locSourceCombosByUseSoFar = Get_CombosSoFar(locComboingStage, locChargeContent, locChargedCombo_Presiding);
2327
2328 //e.g. we are grouping 1 pi0 with N - 1 pi0s to make a combo of N pi0s
2329 //so, let's get the combos for (e.g.) 1 pi0 and for N - 1 pi0s
2330 const auto& locCombos_NMinus1 = *locSourceCombosByUseSoFar[locNMinus1ComboUse]; //Combos are a vector of (e.g.): -> N - 1 pi0s
2331
2332 //if on the all-showers stage, first copy over ALL fcal-only results
2333 locSourceCombosByUseSoFar.emplace(locComboUseToCreate, Get_SourceComboVectorResource());
2334 if(locComboingStage == d_MixedStage)
2335 Copy_ZIndependentMixedResults(locComboUseToCreate, locChargedCombo_Presiding);
2336
2337 if(dDebugLevel >= 20)
2338 cout << "n-1 size: " << locCombos_NMinus1.size() << endl;
2339 if(locCombos_NMinus1.empty())
2340 return; //nothing to create
2341
2342 //if comboing N mixed combos (locComboUseToCreate) (which are thus all used in the same step), do this:
2343 //locChargedCombo_WithNow corresponds to N mixed combos
2344 auto locZIndependentDecayUse = Get_ZIndependentUse(locSourceComboDecayUse);
2345 auto locInstanceUse = locCombos_NMinus1.front()->Get_IsComboingZIndependent() ? locZIndependentDecayUse : locSourceComboDecayUse;
2346 auto locFirstNMinus1FurtherDecayCombos = locCombos_NMinus1.front()->Get_FurtherDecayCombos();
2347 size_t locInstance = 2; //changed below if needed
2348 if(!locNIs2Flag)
2349 {
2350 auto locIteratorPair = std::equal_range(locFirstNMinus1FurtherDecayCombos.begin(), locFirstNMinus1FurtherDecayCombos.end(), locInstanceUse, DSourceCombo::DCompare_FurtherDecays());
2351 locInstance = (*locIteratorPair.first).second.size() + 1; //numbering starts with 1, not 0
2352 }
2353 auto locPreviousPresidingCombo = Get_NextChargedCombo(locChargedCombo_Presiding, locSourceComboDecayUse, locComboingStage, true, locInstance);
2354 auto locChargedCombo_WithPrevious = Get_ChargedCombo_WithNow(locPreviousPresidingCombo, locComboInfoToCreate, locComboingStage);
2355
2356 if(dDebugLevel >= 20)
2357 cout << "instance = " << locInstance << ", combos: presiding, previous-presiding, with-previous: " << locChargedCombo_Presiding << ", " << locPreviousPresidingCombo << ", " << locChargedCombo_WithPrevious << endl;
2358
2359 //now, for each combo of N - 1 (e.g.) pi0s, see which of the single-decay combos are a valid grouping
2360 //valid grouping:
2361 //TEST 1: If (e.g.) pi0s have names "A", "B", "C", don't include the grouping "ABA", and don't include "ACB" if we already have "ABC"
2362 //TEST 2: Also, don't re-use a shower we've already used (e.g. if A & C each contain the same photon, don't group them together)
2363 //Technically, if we pass Test 2 we automatically pass Test 1.
2364 //However, validating for Test 1 is much faster, as discussed below.
2365 auto& locComboResultsVector = *(locSourceCombosByUseSoFar[locComboUseToCreate]);
2366 for(const auto& locCombo_NMinus1 : locCombos_NMinus1)
2367 {
2368 //loop over potential combos to add to the group, creating a new combo for each valid (non-duplicate) grouping
2369 //however, we don't have to loop over all of the combos!!
2370
2371 //first of all, get the potential combos that satisfy the RF bunches for the N - 1 combo
2372 const auto& locValidRFBunches_NMinus1 = dValidRFBunches_ByCombo[std::make_pair(locCombo_NMinus1, std::get<1>(locNMinus1ComboUse))];
2373 const auto& locDecayCombos_1 = Get_CombosForComboing(locSourceComboDecayUse, locComboingStage, locValidRFBunches_NMinus1, locPreviousPresidingCombo);
2374 if(dDebugLevel >= 20)
2375 cout << "decay combos vector address, size: " << &locDecayCombos_1 << ", " << locDecayCombos_1.size() << endl;
2376 if(dDebugLevel >= 100)
2377 {
2378 cout << "Vector combos: ";
2379 for(auto& locCombo : locDecayCombos_1)
2380 cout << locCombo << ", ";
2381 cout << endl;
2382 }
2383
2384 //now, note that all of the combos are stored in the order in which they were created (e.g. A, B, C, D)
2385 //so (e.g.), groupings of 2 will be created and saved in the order: AB, AC, AD, BC, BD, CD
2386 //above, on the B-loop, we start the search at "C," not at A, because this was already tested on an earlier pass
2387 //therefore, start the search one AFTER the LAST (e.g. -> 2 photon) combo of the N - 1 group
2388 //this will guarantee we pass "TEST 1" without ever checking
2389
2390 //actually, we already saved the iterator to the first (e.g.) pi0 to test when we saved the N - 1 combo, so just retrieve it
2391 auto locNMinus1ComboDecayUse = locCombo_NMinus1->Get_IsComboingZIndependent() ? locZIndependentDecayUse : locSourceComboDecayUse;
2392 auto locNMinus1FurtherDecayCombos = locCombo_NMinus1->Get_FurtherDecayCombos();
2393 auto locNMinus1LastCombo = locCombo_NMinus1;
2394 if(!locNIs2Flag)
2395 {
2396 auto locIteratorPair = std::equal_range(locNMinus1FurtherDecayCombos.begin(), locNMinus1FurtherDecayCombos.end(), locNMinus1ComboDecayUse, DSourceCombo::DCompare_FurtherDecays());
2397 locNMinus1LastCombo = (*locIteratorPair.first).second.back();
2398 }
2399
2400 auto locComboSearchIndex = Get_ResumeAtIndex_Combos(locSourceComboDecayUse, locNMinus1LastCombo, locValidRFBunches_NMinus1, locComboingStage);
2401 if(dDebugLevel >= 20)
2402 cout << "n-1 last combo, begin search index = : " << locNMinus1LastCombo << ", " << locComboSearchIndex << endl;
2403 if(locComboSearchIndex == locDecayCombos_1.size())
2404 continue; //e.g. this combo is "AD" and there are only 4 reconstructed combos (ABCD): no potential matches! move on to the next N - 1 combo
2405
2406 //before we loop, first get all of the showers used to make the N - 1 grouping, and sort it so that we can quickly search it
2407 auto locUsedParticles_NMinus1 = DAnalysis::Get_SourceParticles(locCombo_NMinus1->Get_SourceParticles(true)); //true: entire chain
2408 std::sort(locUsedParticles_NMinus1.begin(), locUsedParticles_NMinus1.end()); //must sort, because when retrieving entire chain is unsorted
2409
2410 //this function will do our "TEST 2"
2411 auto Search_Duplicates = [&locUsedParticles_NMinus1](const JObject* locParticle) -> bool
2412 {return std::binary_search(locUsedParticles_NMinus1.begin(), locUsedParticles_NMinus1.end(), locParticle);};
2413
2414 auto locIsZIndependent_NMinus1 = locCombo_NMinus1->Get_IsComboingZIndependent();
2415
2416 //now loop over the potential combos
2417 for(; locComboSearchIndex != locDecayCombos_1.size(); ++locComboSearchIndex)
2418 {
2419 const auto locDecayCombo_1 = locDecayCombos_1[locComboSearchIndex];
2420
2421 //If on all-showers stage, and combo is fcal-only, don't save (combo already created!!)
2422 auto locIsZIndependent = locIsZIndependent_NMinus1 && locDecayCombo_1->Get_IsComboingZIndependent();
2423 if((locComboingStage == d_MixedStage) && locIsZIndependent)
2424 continue; //this combo has already been created (assuming it was valid): during the FCAL-only stage
2425
2426 //conduct "TEST 2" search: search the N - 1 shower vector to see if any of the showers in this combo are duplicated
2427 auto locUsedParticles_1 = DAnalysis::Get_SourceParticles(locDecayCombo_1->Get_SourceParticles(true)); //true: entire chain
2428 if(std::any_of(locUsedParticles_1.begin(), locUsedParticles_1.end(), Search_Duplicates))
2429 continue; //at least one photon was a duplicate, this combo won't work
2430
2431 //no duplicates: this combo is unique. build a new combo!
2432
2433 //See which RF bunches match up //guaranteed to be at least one, due to selection in Get_ParticlesForComboing() function
2434 auto locValidRFBunches = dSourceComboTimeHandler->Get_CommonRFBunches(locValidRFBunches_NMinus1, dValidRFBunches_ByCombo[std::make_pair(locDecayCombo_1, std::get<1>(locSourceComboDecayUse))]);
2435
2436 //Combine the decay combos
2437 vector<const DSourceCombo*> locAllDecayCombos;
2438 if(locNIs2Flag) //N = 2 Two identical combos (e.g. 2 of pi0 -> 2g)
2439 locAllDecayCombos = {locCombo_NMinus1, locDecayCombo_1};
2440 else //combine a combo of N - 1 (e.g. pi0) decays to this new one
2441 {
2442 auto locIteratorPair = std::equal_range(locNMinus1FurtherDecayCombos.begin(), locNMinus1FurtherDecayCombos.end(), locNMinus1ComboDecayUse, DSourceCombo::DCompare_FurtherDecays());
2443 locAllDecayCombos = (*locIteratorPair.first).second;
2444 locAllDecayCombos.push_back(locDecayCombo_1);
2445 }
2446
2447 //then create the new combo
2448 DSourceCombosByUse_Small locFurtherDecayCombos = {std::make_pair(locSourceComboDecayUse, locAllDecayCombos)}; //arguments (e.g.): (pi0, -> 2g), N combos of: -> 2g
2449 auto locCombo = Get_SourceComboResource();
2450 locCombo->Set_Members({}, locFurtherDecayCombos, locIsZIndependent); // 1 combo of N (e.g.) pi0s
2451 if(dDebugLevel >= 10)
2452 {
2453 for(decltype(locNumTabs) locTabNum = 0; locTabNum < locNumTabs; ++locTabNum) cout << "\t";
2454 cout << "CREATED COMBO:" << endl;
2455 DAnalysis::Print_SourceCombo(locCombo, locNumTabs);
2456 }
2457
2458 //save it!
2459 locComboResultsVector.push_back(locCombo);
2460 Register_ValidRFBunches(locComboUseToCreate, locCombo, locValidRFBunches, locComboingStage, locChargedCombo_Presiding);
2461 }
2462 }
2463 if((dDebugLevel > 0) || (dDebugLevel == -1))
2464 Check_ForDuplicates(locComboResultsVector);
2465
2466 //Set the resume indices
2467 Build_ComboResumeIndices(locComboUseToCreate, locComboingStage, locChargedCombo_Presiding);
2468 if(dDebugLevel >= 5)
2469 {
2470 for(decltype(locNumTabs) locTabNum = 0; locTabNum < locNumTabs; ++locTabNum) cout << "\t";
2471 cout << "Combo_Vertically_NDecays: NUM SOURCE COMBOS CREATED: " << locComboResultsVector.size() << endl;
2472 }
2473}
2474
2475void DSourceComboer::Combo_Vertically_AllParticles(const DSourceComboUse& locComboUseToCreate, ComboingStage_t locComboingStage, unsigned char locNumTabs)
2476{
2477 if(dDebugLevel >= 5)
2478 {
2479 cout << endl;
2480 for(decltype(locNumTabs) locTabNum = 0; locTabNum < locNumTabs; ++locTabNum) cout << "\t";
2481 cout << "Combo_Vertically_AllParticles: Stage = " << locComboingStage << endl;
2482 for(decltype(locNumTabs) locTabNum = 0; locTabNum < locNumTabs; ++locTabNum) cout << "\t";
2483 cout << "USE TO CREATE:" << endl;
2484 DAnalysis::Print_SourceComboUse(locComboUseToCreate, locNumTabs);
2485 }
2486
2487 //get combo use contents
2488 auto locVertexZBin = std::get<1>(locComboUseToCreate);
2489 auto locNumParticlesNeeded = std::get<2>(locComboUseToCreate)->Get_NumParticles();
2490 auto locFurtherDecays = std::get<2>(locComboUseToCreate)->Get_FurtherDecays();
2491
2492 //Get combos so far //guaranteed not to be mixed
2493 auto& locSourceCombosByUseSoFar = Get_CombosSoFar(locComboingStage, d_Neutral); //if not neutral then is on charged stage: argument doesn't matter
2494
2495 //for each further decay map entry (e.g. pi0, 3), this is a collection of the uses representing those groupings //e.g. Unknown -> 3pi0
2496 for(const auto& locParticlePair : locNumParticlesNeeded)
2497 {
2498 //get PID information
2499 auto& locPID = locParticlePair.first; //e.g. pi0, -> 2g
2500 auto& locNumPIDNeeded = locParticlePair.second; //N of the above decay (e.g. pi0s)
2501
2502 if(locNumPIDNeeded == 1)
2503 continue; //nothing to do vertically; we will combo this horizontally later
2504
2505 if((locComboingStage == d_ChargedStage) && (ParticleCharge(locPID) == 0))
2506 continue; //skip for now!!
2507 if((locComboingStage != d_ChargedStage) && (ParticleCharge(locPID) != 0))
2508 continue; //already done!
2509
2510 //OK, so we need a grouping of N > 1 particles with the same PID (e.g. g's)
2511 //so, let's create a use of Unknown -> N g's (e.g.)
2512 //if we can just utilize the use from the input combo-info, then we will. if not, we'll make a new one
2513 DSourceComboUse locNeededGroupingUse = locComboUseToCreate;
2514 if((locNumParticlesNeeded.size() > 1) || !locFurtherDecays.empty()) //if true: can't use the input
2515 {
2516 auto locGroupingComboInfo = GetOrMake_SourceComboInfo({std::make_pair(locPID, locNumPIDNeeded)}, {}, locNumTabs); // -> N g's (e.g.)
2517 locNeededGroupingUse = std::make_tuple(Unknown, locVertexZBin, locGroupingComboInfo, false, Unknown); // Unknown -> N g's (e.g.)
2518 }
2519
2520 //See whether the combos for this grouping have already been done
2521 if(locSourceCombosByUseSoFar.find(locNeededGroupingUse) != locSourceCombosByUseSoFar.end())
2522 {
2523 if(dDebugLevel > 0)
2524 cout << "This group already created!" << endl;
2525 continue; //it's already done!!
2526 }
2527
2528 //it's not already done. darn it.
2529 //if it's a direct combo of 2 particles, just make it and continue
2530 if(locNumPIDNeeded == 2)
2531 {
2532 Combo_Vertically_NParticles(locNeededGroupingUse, DSourceComboUse(), locComboingStage, locNumTabs);
2533 continue;
2534 }
2535
2536 //build an info and a use for a direct grouping of N - 1 particles //e.g. 3 g's
2537 auto locNMinus1Info = GetOrMake_SourceComboInfo({std::make_pair(locPID, locNumPIDNeeded - 1)}, {}, locNumTabs); // N - 1 g's (e.g.), no decaying particles
2538 DSourceComboUse locNMinus1ComboUse(Unknown, locVertexZBin, locNMinus1Info, false, Unknown); // Unknown -> N - 1 g's (e.g.)
2539
2540 // Now, see whether the combos for the direct N - 1 grouping have already been done. If not, create them
2541 if(locSourceCombosByUseSoFar.find(locNMinus1ComboUse) == locSourceCombosByUseSoFar.end())
2542 Combo_Vertically_AllParticles(locNMinus1ComboUse, locComboingStage, locNumTabs + 1); //no need to go to top-level combo function since just N - 1: can re-call this one
2543
2544 //Finally, we can actually DO the grouping, between the N - 1 particles and one more particle
2545 Combo_Vertically_NParticles(locNeededGroupingUse, locNMinus1ComboUse, locComboingStage, locNumTabs);
2546 }
2547}
2548
2549void DSourceComboer::Combo_Vertically_NParticles(const DSourceComboUse& locComboUseToCreate, const DSourceComboUse& locNMinus1ComboUse, ComboingStage_t locComboingStage, unsigned char locNumTabs)
2550{
2551 if(dDebugLevel >= 5)
2552 {
2553 cout << endl;
2554 for(decltype(locNumTabs) locTabNum = 0; locTabNum < locNumTabs; ++locTabNum) cout << "\t";
2555 cout << "Combo_Vertically_NParticles: Stage = " << locComboingStage << endl;
2556 for(decltype(locNumTabs) locTabNum = 0; locTabNum < locNumTabs; ++locTabNum) cout << "\t";
2557 cout << "USE TO CREATE:" << endl;
2558 DAnalysis::Print_SourceComboUse(locComboUseToCreate, locNumTabs);
2559 for(decltype(locNumTabs) locTabNum = 0; locTabNum < locNumTabs; ++locTabNum) cout << "\t";
2560 cout << "N - 1 USE:" << endl;
2561 DAnalysis::Print_SourceComboUse(locNMinus1ComboUse, locNumTabs);
2562 }
2563
2564 //either: combining two particles with the same PID to create a new combo, or combining a combo of N particles (with the same PID) with one more particle
2565 auto locComboInfo = std::get<2>(locComboUseToCreate);
2566 auto locParticlePair = locComboInfo->Get_NumParticles().back(); //is guaranteed to be size 1
2567 auto locPID = locParticlePair.first;
2568 auto locNumParticles = locParticlePair.second;
2569 auto locVertexZBin = std::get<1>(locComboUseToCreate);
2570
2571 //Get combos so far //guaranteed not to be mixed
2572 auto& locSourceCombosByUseSoFar = Get_CombosSoFar(locComboingStage, d_Neutral); //if not neutral then is on charged stage: argument doesn't matter
2573
2574 //check if comboing massive neutrals: comboing results are independent of z-bin: see if this has already been done for a different (non-z-independent) zbin
2575 if((ParticleCharge(locPID) == 0) && (ParticleMass(locPID) > 0.0) && (locComboingStage == d_MixedStage))
2576 {
2577 //if so, just copy the results into this zbin!
2578 //note that this can only the case for comboing particles, not comboing combos: decays contain uses, which have the zbin specified
2579 for(signed char locZBin = 0; locZBin < (signed char)dSourceComboTimeHandler->Get_NumVertexZBins(); ++locZBin)
2580 {
2581 if(locZBin == locVertexZBin)
2582 continue;
2583 auto locZBinUse = DSourceComboUse{Unknown, locZBin, locComboInfo, false, Unknown};
2584 if(locSourceCombosByUseSoFar.find(locZBinUse) == locSourceCombosByUseSoFar.end())
2585 continue;
2586
2587 //just copy the results!
2588 locSourceCombosByUseSoFar[locComboUseToCreate] = locSourceCombosByUseSoFar[locZBinUse];
2589 auto& locSourceCombosByBeamBunchByUse = Get_SourceCombosByBeamBunchByUse(dComboInfoChargeContent[locComboInfo], nullptr);
2590 locSourceCombosByBeamBunchByUse.emplace(locComboUseToCreate, locSourceCombosByBeamBunchByUse[locZBinUse]);
2591
2592 //Set the resume indices
2593 Build_ComboResumeIndices(locComboUseToCreate, locComboingStage, nullptr);
2594 if(dDebugLevel >= 5)
2595 {
2596 for(decltype(locNumTabs) locTabNum = 0; locTabNum < locNumTabs; ++locTabNum) cout << "\t";
2597 cout << "Combo_Vertically_NParticles: NUM SOURCE COMBOS CREATED: " << locSourceCombosByUseSoFar[locComboUseToCreate]->size() << endl;
2598 }
2599 return;
2600 }
2601 }
2602
2603 //if on the all-showers stage, first copy over ALL fcal-only results
2604 locSourceCombosByUseSoFar.emplace(locComboUseToCreate, Get_SourceComboVectorResource());
2605 if(locComboingStage == d_MixedStage)
2606 Copy_ZIndependentMixedResults(locComboUseToCreate, nullptr);
2607
2608 if(locNumParticles == 2)
2609 {
2610 //Get particles for comboing
2611 const auto& locParticles = Get_ParticlesForComboing(locPID, locComboingStage, {}, locVertexZBin);
2612 if(locParticles.size() < 2)
2613 return; //not enough to create combos
2614
2615 auto locLastIteratorToCheck = std::prev(locParticles.end());
2616 for(auto locFirstIterator = locParticles.begin(); locFirstIterator != locLastIteratorToCheck; ++locFirstIterator)
2617 {
2618 auto locRFBunches_First = (locPID == Gamma) ? dSourceComboTimeHandler->Get_ValidRFBunches(*locFirstIterator, locVertexZBin) : vector<int>{};
2619 for(auto locSecondIterator = std::next(locFirstIterator); locSecondIterator != locParticles.end(); ++locSecondIterator)
2620 {
2621 auto locIsZIndependent = (locComboingStage == d_MixedStage_ZIndependent) || (Get_IsComboingZIndependent(*locFirstIterator, locPID) && Get_IsComboingZIndependent(*locSecondIterator, locPID));
2622 if((locComboingStage == d_MixedStage) && locIsZIndependent)
2623 continue; //this combo has already been created (assuming it was valid): during the FCAL-only stage
2624
2625 //See which RF bunches match up, if any //if charged or massive neutrals, ignore (they don't choose at this stage)
2626 auto locValidRFBunches = (locPID != Gamma) ? vector<int>{} : dSourceComboTimeHandler->Get_CommonRFBunches(locRFBunches_First, *locSecondIterator, locVertexZBin);
2627 if((locPID == Gamma) && locValidRFBunches.empty())
2628 continue;
2629
2630 //check if this combo is unique!
2631 //it will not be unique if: comboing photons, on mixed stage, and this combo has already been created for a different zbin
2632 //if so, don't duplicate memory
2633 //note that this can only the case for comboing particles, not comboing combos: decays contain uses, which have the zbin specified
2634 vector<const JObject*> locPhotons;
2635 if((locPID == Gamma) && (locComboingStage == d_MixedStage))
2636 {
2637 locPhotons = {*locFirstIterator, *locSecondIterator};
2638 auto locIterator = dNPhotonsToComboMap.find(locPhotons);
2639 if(locIterator != dNPhotonsToComboMap.end()) //if true, already exists, copy it and continue;
2640 {
2641 auto locCombo = locIterator->second;
2642 locSourceCombosByUseSoFar[locComboUseToCreate]->push_back(locCombo);
2643 if(dDebugLevel >= 15)
2644 {
2645 for(decltype(locNumTabs) locTabNum = 0; locTabNum < locNumTabs; ++locTabNum) cout << "\t";
2646 cout << "COPIED COMBO:" << endl;
2647 DAnalysis::Print_SourceCombo(locCombo, locNumTabs);
2648 }
2649 Register_ValidRFBunches(locComboUseToCreate, locCombo, locValidRFBunches, locComboingStage, nullptr);
2650 continue;
2651 }
2652 }
2653
2654 auto locCombo = Get_SourceComboResource();
2655 locCombo->Set_Members({std::make_pair(locPID, *locFirstIterator), std::make_pair(locPID, *locSecondIterator)}, {}, locIsZIndependent);
2656 locSourceCombosByUseSoFar[locComboUseToCreate]->push_back(locCombo); //save it //in creation order
2657 if(locPID == Gamma)
2658 dNPhotonsToComboMap.emplace(locPhotons, locCombo);
2659 if(dDebugLevel >= 10)
2660 {
2661 for(decltype(locNumTabs) locTabNum = 0; locTabNum < locNumTabs; ++locTabNum) cout << "\t";
2662 cout << "CREATED COMBO:" << endl;
2663 DAnalysis::Print_SourceCombo(locCombo, locNumTabs);
2664 }
2665
2666 Register_ValidRFBunches(locComboUseToCreate, locCombo, locValidRFBunches, locComboingStage, nullptr);
2667 }
2668 }
2669 if((dDebugLevel > 0) || (dDebugLevel == -1))
2670 Check_ForDuplicates(*(locSourceCombosByUseSoFar[locComboUseToCreate]));
2671
2672 //Set the resume indices
2673 Build_ComboResumeIndices(locComboUseToCreate, locComboingStage, nullptr);
2674 if(dDebugLevel >= 5)
2675 {
2676 for(decltype(locNumTabs) locTabNum = 0; locTabNum < locNumTabs; ++locTabNum) cout << "\t";
2677 cout << "Combo_Vertically_NParticles: NUM SOURCE COMBOS CREATED: " << locSourceCombosByUseSoFar[locComboUseToCreate]->size() << endl;
2678 }
2679 return;
2680 }
2681
2682 //create combo of N same-PID-particles by adding one particle to previously-created combos of N - 1 same-PID-particles
2683 const auto& locCombos_NMinus1 = *locSourceCombosByUseSoFar[locNMinus1ComboUse]; //Each combo contains a vector of N - 1 same-PID-particles
2684 for(const auto& locCombo_NMinus1 : locCombos_NMinus1)
2685 {
2686 //Get particles for comboing
2687 const auto& locValidRFBunches_NMinus1 = dValidRFBunches_ByCombo[std::make_pair(locCombo_NMinus1, std::get<1>(locNMinus1ComboUse))];
2688 const auto& locParticles = Get_ParticlesForComboing(locPID, locComboingStage, locValidRFBunches_NMinus1, locVertexZBin);
2689
2690 //retrieve where to begin the search
2691 auto locLastParticleInCombo = locCombo_NMinus1->Get_SourceParticles(false).back().second;
2692 auto locParticleSearchIndex = Get_ResumeAtIndex_Particles(locPID, locLastParticleInCombo, locValidRFBunches_NMinus1, locVertexZBin);
2693 if(dDebugLevel >= 20)
2694 cout << "particle index, #particles = " << locParticleSearchIndex << ", " << locParticles.size() << endl;
2695 if(locParticleSearchIndex == locParticles.size())
2696 continue; //e.g. this combo is "AD" and there are only 4 reconstructed combos (ABCD): no potential matches! move on to the next N - 1 combo
2697
2698 auto locIsZIndependent_NMinus1 = locCombo_NMinus1->Get_IsComboingZIndependent();
2699
2700 for(; locParticleSearchIndex < locParticles.size(); ++locParticleSearchIndex)
2701 {
2702 auto& locParticle = locParticles[locParticleSearchIndex];
2703 auto locIsZIndependent = (locComboingStage == d_MixedStage_ZIndependent) || (locIsZIndependent_NMinus1 && Get_IsComboingZIndependent(locParticle, locPID));
2704 if((locComboingStage == d_MixedStage) && locIsZIndependent)
2705 continue; //this combo has already been created (assuming it was valid): during the FCAL-only stage
2706
2707 //See which RF bunches match up //guaranteed to be at least one, due to selection in Get_ParticlesForComboing() function
2708 //if charged or massive neutrals, ignore (they don't choose at this stage)
2709 auto locValidRFBunches = (locPID != Gamma) ? vector<int>{} : dSourceComboTimeHandler->Get_CommonRFBunches(locValidRFBunches_NMinus1, locParticle, locVertexZBin);
2710
2711 auto locComboParticlePairs = locCombo_NMinus1->Get_SourceParticles();
2712
2713 //check if this combo is unique!
2714 //it will not be unique if: comboing photons, on mixed stage, and this combo has already been created for a different zbin
2715 //if so, don't duplicate memory
2716 //note that this can only the case for comboing particles, not comboing combos: decays contain uses, which have the zbin specified
2717 vector<const JObject*> locPhotons;
2718 if((locPID == Gamma) && (locComboingStage == d_MixedStage))
2719 {
2720 auto GetParticle = [](const pair<Particle_t, const JObject*>& locPair) -> const JObject* {return locPair.second;};
2721 std::transform(locComboParticlePairs.begin(), locComboParticlePairs.end(), std::back_inserter(locPhotons), GetParticle);
2722 locPhotons.push_back(locParticle);
2723 auto locIterator = dNPhotonsToComboMap.find(locPhotons);
2724 if(locIterator != dNPhotonsToComboMap.end()) //if true, already exists, save it and continue;
2725 {
2726 auto locCombo = locIterator->second;
2727 locSourceCombosByUseSoFar[locComboUseToCreate]->push_back(locCombo);
2728 if(dDebugLevel >= 15)
2729 {
2730 for(decltype(locNumTabs) locTabNum = 0; locTabNum < locNumTabs; ++locTabNum) cout << "\t";
2731 cout << "COPIED COMBO:" << endl;
2732 DAnalysis::Print_SourceCombo(locCombo, locNumTabs);
2733 }
2734 Register_ValidRFBunches(locComboUseToCreate, locCombo, locValidRFBunches, locComboingStage, nullptr);
2735 continue;
2736 }
2737 }
2738
2739 locComboParticlePairs.emplace_back(locPID, locParticle);
2740 auto locCombo = Get_SourceComboResource();
2741 locCombo->Set_Members(locComboParticlePairs, {}, locIsZIndependent);
2742 locSourceCombosByUseSoFar[locComboUseToCreate]->push_back(locCombo); //save it //in creation order
2743 if(locPID == Gamma)
2744 dNPhotonsToComboMap.emplace(locPhotons, locCombo);
2745 if(dDebugLevel >= 10)
2746 {
2747 for(decltype(locNumTabs) locTabNum = 0; locTabNum < locNumTabs; ++locTabNum) cout << "\t";
2748 cout << "CREATED COMBO:" << endl;
2749 DAnalysis::Print_SourceCombo(locCombo, locNumTabs);
2750 }
2751
2752 Register_ValidRFBunches(locComboUseToCreate, locCombo, locValidRFBunches, locComboingStage, nullptr);
2753 }
2754 }
2755 if((dDebugLevel > 0) || (dDebugLevel == -1))
2756 Check_ForDuplicates(*(locSourceCombosByUseSoFar[locComboUseToCreate]));
2757
2758 //Set the resume indices
2759 Build_ComboResumeIndices(locComboUseToCreate, locComboingStage, nullptr);
2760 if(dDebugLevel >= 5)
2761 {
2762 cout << "Combo_Vertically_NParticles: NUM SOURCE COMBOS CREATED: " << locSourceCombosByUseSoFar[locComboUseToCreate]->size() << endl;
2763 for(decltype(locNumTabs) locTabNum = 0; locTabNum < locNumTabs; ++locTabNum) cout << "\t";
2764 }
2765}
2766
2767/************************************************************* BUILD PHOTON COMBOS - HORIZONTALLY ***************************************************************/
2768
2769void DSourceComboer::Combo_Horizontally_All(const DSourceComboUse& locComboUseToCreate, ComboingStage_t locComboingStage, const DSourceCombo* locChargedCombo_Presiding, unsigned char locNumTabs)
2770{
2771 if(dDebugLevel >= 5)
2772 {
2773 cout << endl;
2774 for(decltype(locNumTabs) locTabNum = 0; locTabNum < locNumTabs; ++locTabNum) cout << "\t";
2775 cout << "Combo_Horizontally_All: Stage, presiding charged combo = " << locComboingStage << ", " << locChargedCombo_Presiding << endl;
2776 for(decltype(locNumTabs) locTabNum = 0; locTabNum < locNumTabs; ++locTabNum) cout << "\t";
2777 cout << "PRESIDING COMBO:" << endl;
2778 DAnalysis::Print_SourceCombo(locChargedCombo_Presiding, locNumTabs);
2779 for(decltype(locNumTabs) locTabNum = 0; locTabNum < locNumTabs; ++locTabNum) cout << "\t";
2780 cout << "USE TO CREATE:" << endl;
2781 DAnalysis::Print_SourceComboUse(locComboUseToCreate, locNumTabs);
2782 }
2783
2784 //get combo use contents
2785 auto locVertexZBin = std::get<1>(locComboUseToCreate);
2786 const auto& locComboInfoToCreate = std::get<2>(locComboUseToCreate);
2787 auto locNumParticlesNeeded = locComboInfoToCreate->Get_NumParticles();
2788 auto locFurtherDecays = locComboInfoToCreate->Get_FurtherDecays();
2789
2790 //first handle special cases:
2791 if(locNumParticlesNeeded.empty() && (locFurtherDecays.size() == 1))
2792 {
2793 Create_Combo_OneDecay(locComboUseToCreate, locComboingStage, locChargedCombo_Presiding, locNumTabs);
2794 return;
2795 }
2796 if(locFurtherDecays.empty() && (locNumParticlesNeeded.size() == 1))
2797 {
2798 //we just need N (e.g.) photons together
2799 auto& locParticlePair = locNumParticlesNeeded.front();
2800 if(locParticlePair.second > 1)
2801 return; //already done when comboing vertically!!
2802
2803 //not much of a combo if there's only 1, is it? //e.g. 1 charged track at a vertex
2804 if((locComboingStage == d_ChargedStage) && (ParticleCharge(locParticlePair.first) == 0))
2805 return; //skip for now!!
2806
2807 Create_Combo_OneParticle(locComboUseToCreate, locComboingStage, locNumTabs);
2808 return;
2809 }
2810
2811 //see if there is another combo that already exists that is a subset of what we requested
2812 //e.g. if we need a charged combo, a neutral combo, and a mixed: search for:
2813 //charged + neutral (no mixed)
2814 //charged + mixed (no neutral)
2815 //neutral + mixed (no charged)
2816 //e.g. if we need 2pi0s, one omega, and 1g: search for:
2817 //2pi0s, one omega: if exists, just combo that with 1g
2818 //2pi0s, one photon: if exists, just combo with one omega
2819 //etc.
2820
2821 DSourceComboUse locComboUse_SubsetToBuild(Unknown, locVertexZBin, nullptr, false, Unknown);
2822 DSourceComboUse locComboUse_SubsetToAdd(Unknown, locVertexZBin, nullptr, false, Unknown);
2823 auto locChargedCombo_SubsetToBuildPresiding = locChargedCombo_Presiding;
2824
2825 //First test the case: 1 set of particles, 1 decay
2826 bool locMissingSubsetIsDecayFlag = true; //set false if otherwise
2827 if((locFurtherDecays.size() == 1) && (locNumParticlesNeeded.size() == 1))
2828 {
2829 if(dDebugLevel >= 5)
2830 cout << "1 decay, 1 type of particle needed" << endl;
2831
2832 //build the particles first, then we'll add the decay horizontally
2833 //unless the particles are fully neutral and we're on the charged stage: then we'll do the decay first
2834 if((locComboingStage == d_ChargedStage) && (ParticleCharge(locNumParticlesNeeded[0].first) == 0))
2835 {
2836 if(dDebugLevel >= 5)
2837 cout << "build decay first" << endl;
2838 auto locAllBut1ComboUse = locFurtherDecays[0].first; //do decay first
2839 locMissingSubsetIsDecayFlag = false;
2840
2841 //Get combos so far
2842 auto locAllBut1ComboInfo = std::get<2>(locAllBut1ComboUse);
2843 auto locChargedCombo_NextPresiding = Get_NextChargedCombo(locChargedCombo_Presiding, locAllBut1ComboUse, locComboingStage, true, 1);
2844 auto& locSourceCombosByUseSoFar = Get_CombosSoFar(locComboingStage, dComboInfoChargeContent[locAllBut1ComboInfo], locChargedCombo_NextPresiding);
2845
2846 // Now, see whether the combos for this grouping have already been done
2847 if(locSourceCombosByUseSoFar.find(locAllBut1ComboUse) == locSourceCombosByUseSoFar.end()) //if true: not yet
2848 locComboUse_SubsetToBuild = locAllBut1ComboUse; //will build below before the end of the function
2849 else //yes, it's already been done!
2850 {
2851 //and, since we are in the charged stage and the remaining particles are neutral, we are done for now
2852 //just copy the all-but-1 as the desired combos
2853 auto& locAllBut1Combos = locSourceCombosByUseSoFar[locAllBut1ComboUse];
2854 locSourceCombosByUseSoFar.emplace(locComboUseToCreate, locAllBut1Combos);
2855 //Set the resume indices
2856 Build_ComboResumeIndices(locComboUseToCreate, locComboingStage, locChargedCombo_NextPresiding);
2857 return;
2858 }
2859 }
2860 else //particles first
2861 {
2862 if(dDebugLevel >= 5)
2863 cout << "build particles first" << endl;
2864
2865 auto locAllBut1ComboInfo = GetOrMake_SourceComboInfo(locNumParticlesNeeded, {}, locNumTabs);
2866 auto locAllBut1ZBin = (Get_ChargeContent(locAllBut1ComboInfo) != d_Charged) ? locVertexZBin : DSourceComboInfo::Get_VertexZIndex_ZIndependent();
2867 DSourceComboUse locAllBut1ComboUse{Unknown, locAllBut1ZBin, locAllBut1ComboInfo, false, Unknown}; //Unknown -> particles
2868
2869 //Get combos so far //not mixed charge: with-now is nullptr
2870 auto& locSourceCombosByUseSoFar = Get_CombosSoFar(locComboingStage, dComboInfoChargeContent[locAllBut1ComboInfo], nullptr);
2871
2872 //if we can directly build the to-add decay use, then we will (only 1 combo requested)
2873 //else we must build a new use first, and then promote the to-add use when comboing horizontally
2874 auto locToAddComboInfo = (locFurtherDecays[0].second == 1) ? std::get<2>(locFurtherDecays[0].first) : GetOrMake_SourceComboInfo({}, {std::make_pair(locFurtherDecays[0].first, locFurtherDecays[0].second)}, locNumTabs);
2875 auto locToAddChargeContent = dComboInfoChargeContent[locToAddComboInfo];
2876 auto locToAddZBin = (locToAddChargeContent != d_Charged) ? locVertexZBin : DSourceComboInfo::Get_VertexZIndex_ZIndependent();
2877 auto locToAddComboUse = (locFurtherDecays[0].second == 1) ? locFurtherDecays[0].first : DSourceComboUse{Unknown, locToAddZBin, locToAddComboInfo, false, Unknown};
2878
2879 // Now, see whether the combos for this grouping have already been done
2880 if(locSourceCombosByUseSoFar.find(locAllBut1ComboUse) == locSourceCombosByUseSoFar.end()) //if true: not yet
2881 {
2882 locComboUse_SubsetToBuild = locAllBut1ComboUse; //will build below before the end of the function
2883 locComboUse_SubsetToAdd = locToAddComboUse;
2884 locChargedCombo_SubsetToBuildPresiding = nullptr; //not needed when building particles
2885 }
2886 else //yes, it's already been done!
2887 {
2888 //just combo the All-but-1 combos to those from this decay and save the results
2889 Combo_Horizontally_AddCombo(locComboUseToCreate, locAllBut1ComboUse, locToAddComboUse, locComboingStage, locChargedCombo_Presiding, false, locNumTabs);
2890 return;
2891 }
2892 }
2893 }
2894 else //at least 2 of one type (decays / particles) needed:
2895 {
2896 //for each further decay map entry (e.g. pi0, 3), this is a collection of the uses representing those groupings //e.g. Unknown -> 3pi0
2897 //decays are sorted by: mixed-charge first, then fully-neutral, then fully-charged
2898 //within a charge: loop from heaviest-mass to least (most likely to be missing)
2899 for(auto locDecayIterator = locFurtherDecays.begin(); locDecayIterator != locFurtherDecays.end(); ++locDecayIterator)
2900 {
2901 if(locFurtherDecays.size() == 1)
2902 break; //will work with the particles instead
2903 if(dDebugLevel >= 5)
2904 cout << "2+ decays: try to build subsets with a decay missing" << endl;
2905
2906 //build a DSourceComboUse with everything EXCEPT this set of decays, and see if it already exists
2907 //build the further-decays, removing this decay
2908 auto locFurtherDecaysToSearchFor = locFurtherDecays;
2909 const auto& locSourceComboUse_ThisDecay = locDecayIterator->first;
2910 locFurtherDecaysToSearchFor.erase(locFurtherDecaysToSearchFor.begin() + std::distance(locFurtherDecays.begin(), locDecayIterator));
2911
2912 //if we can directly build the further-decays-to-search-for use, then we will (e.g. only one use & only 1 combo requested)
2913 //else we must build a new use first, and then expand the all-but-1 when comboing horizontally
2914 auto locAllBut1ComboInfo = std::get<2>((*locFurtherDecaysToSearchFor.begin()).first); //changed below if needed
2915
2916 //if we can directly build the to-add decay use, then we will (only 1 combo requested)
2917 //else we must build a new use first, and then promote the to-add use when comboing horizontally
2918 auto locToAddComboInfo = (locDecayIterator->second == 1) ? std::get<2>(locSourceComboUse_ThisDecay) : GetOrMake_SourceComboInfo({}, {std::make_pair(locSourceComboUse_ThisDecay, locDecayIterator->second)}, locNumTabs);
2919 auto locToAddChargeContent = dComboInfoChargeContent[locToAddComboInfo];
2920 auto locToAddZBin = (locToAddChargeContent != d_Charged) ? locVertexZBin : DSourceComboInfo::Get_VertexZIndex_ZIndependent();
2921 auto locToAddComboUse = (locDecayIterator->second == 1) ? locSourceComboUse_ThisDecay : DSourceComboUse{Unknown, locToAddZBin, locToAddComboInfo, false, Unknown};
2922
2923 //guard against special cases for the all-but-1 combo use //must be after check on whether all-but-1 is charged (it itself is special case)
2924 auto locAllBut1ComboUse = DSourceComboUse{Unknown, locVertexZBin, locAllBut1ComboInfo, false, Unknown}; //may change below
2925 auto locChargedCombo_PresidingToUse = locChargedCombo_Presiding; //may change below
2926 if((locFurtherDecaysToSearchFor.size() > 1) || !locNumParticlesNeeded.empty())
2927 {
2928 locAllBut1ComboInfo = GetOrMake_SourceComboInfo(locNumParticlesNeeded, locFurtherDecaysToSearchFor, locNumTabs);
2929 auto locAllBut1ZBin = (Get_ChargeContent(locAllBut1ComboInfo) != d_Charged) ? locVertexZBin : DSourceComboInfo::Get_VertexZIndex_ZIndependent();
2930 locAllBut1ComboUse = DSourceComboUse{Unknown, locAllBut1ZBin, locAllBut1ComboInfo, false, Unknown};
2931 }
2932 else if((locFurtherDecaysToSearchFor.size() == 1) && (locFurtherDecaysToSearchFor[0].second > 1))
2933 {
2934 locAllBut1ComboInfo = GetOrMake_SourceComboInfo({}, {std::make_pair(locSourceComboUse_ThisDecay, locDecayIterator->second)}, locNumTabs);
2935 auto locAllBut1ZBin = (Get_ChargeContent(locAllBut1ComboInfo) != d_Charged) ? locVertexZBin : DSourceComboInfo::Get_VertexZIndex_ZIndependent();
2936 locAllBut1ComboUse = DSourceComboUse{Unknown, locAllBut1ZBin, locAllBut1ComboInfo, false, Unknown};
2937 }
2938 else if(locFurtherDecaysToSearchFor.size() == 1)
2939 {
2940 locAllBut1ComboUse = (*locFurtherDecaysToSearchFor.begin()).first;
2941 locChargedCombo_PresidingToUse = Get_NextChargedCombo(locChargedCombo_Presiding, locAllBut1ComboUse, locComboingStage, true, 1);
2942 }
2943
2944 if(dDebugLevel >= 20)
2945 {
2946 for(decltype(locNumTabs) locTabNum = 0; locTabNum < locNumTabs; ++locTabNum) cout << "\t";
2947 cout << "Comboing decays together. All-But-1 Use:" << endl;
2948 DAnalysis::Print_SourceComboUse(locAllBut1ComboUse, locNumTabs);
2949 for(decltype(locNumTabs) locTabNum = 0; locTabNum < locNumTabs; ++locTabNum) cout << "\t";
2950 cout << "Comboing decays together. To-Add Use:" << endl;
2951 DAnalysis::Print_SourceComboUse(locToAddComboUse, locNumTabs);
2952 }
2953
2954 //if on charged stage and in this loop, at least one decay must be charged
2955 //(if fully neutral wouldn't be trying to build, and if comboing with neutral the charged are represented by the decay e.g. X -> pi+, pi-, p ... etc.)
2956 //we will guard against the case of to-add == neutral in Combo_Horizontally_AddDecay()
2957 //here, we guard against the case of all-but-1 == neutral
2958 auto locAllBut1ChargeContent = dComboInfoChargeContent[locAllBut1ComboInfo];
2959 if((locComboingStage == d_ChargedStage) && (locAllBut1ChargeContent == d_Neutral))
2960 {
2961 //just copy the to-add (which is either charged or mixed) as the desired combos
2962 auto& locSourceCombosByUseSoFar = Get_CombosSoFar(locComboingStage, locToAddChargeContent);
2963 auto& locToAddCombos = locSourceCombosByUseSoFar[locToAddComboUse];
2964 locSourceCombosByUseSoFar.emplace(locComboUseToCreate, locToAddCombos);
2965 if(dDebugLevel > 0)
2966 cout << "Save for later!" << endl;
2967
2968 //Set the resume indices
2969 Build_ComboResumeIndices(locComboUseToCreate, locComboingStage, nullptr);
2970 return;
2971 }
2972
2973 if((locComboingStage != d_ChargedStage) && (locAllBut1ChargeContent == d_Charged))
2974 {
2975 //yes, it's already been done!
2976 //just combo the All-but-1 combos to those from this decay and return the results
2977 //don't promote particles or expand all-but-1: create new combo ABOVE all-but-1, that will contain all-but-1 and to-add side-by-side
2978 Combo_Horizontally_AddDecay(locComboUseToCreate, locAllBut1ComboUse, locToAddComboUse, locComboingStage, locChargedCombo_Presiding, false, locNumTabs);
2979 return;
2980 }
2981
2982 //Get combos so far
2983 auto& locSourceCombosByUseSoFar = Get_CombosSoFar(locComboingStage, locAllBut1ChargeContent, locChargedCombo_PresidingToUse);
2984
2985 // Now, see whether the combos for this grouping have already been done
2986 if(locSourceCombosByUseSoFar.find(locAllBut1ComboUse) == locSourceCombosByUseSoFar.end()) //if true: not yet
2987 {
2988 //if on the first one (heaviest mass), save this subset in case we need to create it (if nothing else already done)
2989 if(locDecayIterator == locFurtherDecays.begin())
2990 {
2991 locComboUse_SubsetToBuild = locAllBut1ComboUse;
2992 locChargedCombo_SubsetToBuildPresiding = locChargedCombo_PresidingToUse;
2993 locComboUse_SubsetToAdd = locToAddComboUse;
2994 }
2995 continue; // try the next decay
2996 }
2997
2998 //yes, it's already been done!
2999 //just combo the All-but-1 combos to those from this decay and save the results
3000 auto locExpandAllBut1Flag = Get_ExpandAllBut1Flag(locComboingStage, locAllBut1ComboUse, Get_ChargeContent(std::get<2>(locToAddComboUse)));
3001 Combo_Horizontally_AddDecay(locComboUseToCreate, locAllBut1ComboUse, locToAddComboUse, locComboingStage, locChargedCombo_Presiding, locExpandAllBut1Flag, locNumTabs);
3002 return;
3003 }
3004
3005 //ok, none of the subsets without a decay has yet been created. let's try subsets without detected particles
3006 if((locComboingStage == d_ChargedStage) || (dComboInfoChargeContent[locComboInfoToCreate] == d_Neutral)) //no loose particles when mixing charged & neutral
3007 {
3008 if(dDebugLevel >= 5)
3009 cout << "try to build subsets with some detected particles missing" << endl;
3010 for(auto locParticleIterator = locNumParticlesNeeded.begin(); locParticleIterator != locNumParticlesNeeded.end(); ++locParticleIterator)
3011 {
3012 //build a DSourceComboUse with everything EXCEPT this set of particles, and see if it already exists
3013 //combo the particle horizontally, removing this PID
3014 auto locNumParticlesToSearchFor = locNumParticlesNeeded;
3015 const auto& locParticlePair = *locParticleIterator;
3016 locNumParticlesToSearchFor.erase(locNumParticlesToSearchFor.begin() + std::distance(locNumParticlesNeeded.begin(), locParticleIterator));
3017 if(dDebugLevel >= 5)
3018 cout << "particle pair: " << locParticlePair.first << ", " << int(locParticlePair.second) << endl;
3019
3020 //build the DSourceComboUse
3021 auto locAllBut1ComboInfo = GetOrMake_SourceComboInfo(locNumParticlesToSearchFor, locFurtherDecays, locNumTabs);
3022 if((locComboingStage == d_ChargedStage) && (dComboInfoChargeContent[locAllBut1ComboInfo] == d_Neutral))
3023 continue; //this won't be done yet!
3024 auto locChargedContentAllBut1 = Get_ChargeContent(locAllBut1ComboInfo);
3025 auto locAllBut1ZBin = (locChargedContentAllBut1 != d_Charged) ? locVertexZBin : DSourceComboInfo::Get_VertexZIndex_ZIndependent();
3026 DSourceComboUse locAllBut1ComboUse(Unknown, locAllBut1ZBin, locAllBut1ComboInfo, false, Unknown); // Unknown -> everything but these particles
3027
3028 //Get combos so far
3029 auto locChargedCombo_PresidingToUse = locChargedCombo_Presiding;
3030 if(locFurtherDecays.empty() && (locNumParticlesToSearchFor.size() == 1))
3031 locChargedCombo_PresidingToUse = Get_NextChargedCombo(locChargedCombo_Presiding, locAllBut1ComboUse, locComboingStage, true, 1);
3032 auto& locSourceCombosByUseSoFar = Get_CombosSoFar(locComboingStage, locChargedContentAllBut1, locChargedCombo_PresidingToUse); //if not neutral then is on charged stage: argument doesn't matter
3033
3034 // Now, see whether the combos for this grouping have already been done
3035 if(locSourceCombosByUseSoFar.find(locAllBut1ComboUse) == locSourceCombosByUseSoFar.end()) //if true: not yet
3036 {
3037 //if on the first one and there's no decays, save this subset in case we need to create it (if nothing else already done)
3038 if((locParticleIterator == locNumParticlesNeeded.begin()) && (locFurtherDecays.size() < 2))
3039 {
3040 locComboUse_SubsetToBuild = locAllBut1ComboUse;
3041 locChargedCombo_SubsetToBuildPresiding = locChargedCombo_PresidingToUse;
3042 locMissingSubsetIsDecayFlag = false;
3043 }
3044 continue; // try the next PID
3045 }
3046
3047 //yes, it's already been done!
3048 //just combo the All-but-1 combos to those from this particle and return the results
3049 bool locExpandAllBut1Flag = false; //changed if following conditions hold
3050 if(std::get<0>(locAllBut1ComboUse) == Unknown) //check other conditions
3051 locExpandAllBut1Flag = (locAllBut1ComboInfo->Get_NumParticles().size() + locAllBut1ComboInfo->Get_FurtherDecays().size()) > 1; //true: has already been comboed horizontally once
3052 Combo_Horizontally_AddParticles(locComboUseToCreate, locAllBut1ComboUse, locParticlePair, locComboingStage, locChargedCombo_Presiding, locExpandAllBut1Flag, locNumTabs);
3053 return;
3054 }
3055 }
3056 }
3057
3058 //none of the possible immediate subsets have been created
3059 //therefore, create one of them (the one without the heaviest particle), and then do the remaining combo
3060 if(dDebugLevel >= 5)
3061 cout << "build subset: dive down" << endl;
3062 Create_SourceCombos(locComboUse_SubsetToBuild, locComboingStage, locChargedCombo_SubsetToBuildPresiding, locNumTabs + 1); //this may be something we want to combo vertically: go back to (unknown) mother function
3063
3064 //do the final combo!
3065 if(locMissingSubsetIsDecayFlag) //subset was missing a decay PID
3066 {
3067 if(dDebugLevel >= 5)
3068 cout << "do final add: add decay" << endl;
3069 auto locExpandAllBut1Flag = Get_ExpandAllBut1Flag(locComboingStage, locComboUse_SubsetToBuild, Get_ChargeContent(std::get<2>(locComboUse_SubsetToAdd)));
3070 Combo_Horizontally_AddDecay(locComboUseToCreate, locComboUse_SubsetToBuild, locComboUse_SubsetToAdd, locComboingStage, locChargedCombo_Presiding, locExpandAllBut1Flag, locNumTabs);
3071 }
3072 else //subset was missing a detected PID
3073 {
3074 if(dDebugLevel >= 5)
3075 cout << "do final add: add particles" << endl;
3076 auto locToAddChargeContent = (ParticleCharge(locNumParticlesNeeded.front().first) == 0) ? d_Neutral : d_Charged;
3077 auto locExpandAllBut1Flag = Get_ExpandAllBut1Flag(locComboingStage, locComboUse_SubsetToBuild, locToAddChargeContent);
3078 Combo_Horizontally_AddParticles(locComboUseToCreate, locComboUse_SubsetToBuild, locNumParticlesNeeded.front(), locComboingStage, locChargedCombo_Presiding, locExpandAllBut1Flag, locNumTabs);
3079 }
3080}
3081
3082bool DSourceComboer::Get_ExpandAllBut1Flag(ComboingStage_t locComboingStage, const DSourceComboUse& locAllBut1ComboUse, Charge_t locToAddChargeContent)
3083{
3084 if(std::get<0>(locAllBut1ComboUse) != Unknown)
3085 return false;
3086
3087 auto locAllBut1ComboInfo = std::get<2>(locAllBut1ComboUse);
3088 auto locAllBut1ChargeContent = Get_ChargeContent(locAllBut1ComboInfo);
3089
3090 //special case: if one is charged and the other is not: do not expand: must be side-by-side
3091 if((locAllBut1ChargeContent == d_Charged) != (locToAddChargeContent == d_Charged))
3092 return false;
3093 //don't expand if all-but-1 is mixed and merely contains a promoted charged combo
3094 if((locComboingStage == d_ChargedStage) && (locAllBut1ChargeContent == d_AllCharges))
3095 {
3096 size_t locNumNeutralUses = locAllBut1ComboInfo->Get_NumParticles().size();
3097 size_t locNumNonNeutralUses = 0;
3098 for(auto& locAllBut1DecayPair : locAllBut1ComboInfo->Get_FurtherDecays())
3099 {
3100 if(dComboInfoChargeContent[std::get<2>(locAllBut1DecayPair.first)] == d_Neutral)
3101 ++locNumNeutralUses;
3102 else
3103 ++locNumNonNeutralUses;
3104 }
3105 if((locNumNeutralUses >= 1) && (locNumNonNeutralUses == 1))
3106 return false; //merely a promoted charged combo
3107 }
3108
3109 auto locExpandAllBut1Flag = ((locAllBut1ComboInfo->Get_NumParticles().size() + locAllBut1ComboInfo->Get_FurtherDecays().size()) > 1); //if true: has already been comboed horizontally once
3110 //special case: if only content is a single decay use, but > 1 combo of that use
3111 if(!locExpandAllBut1Flag && locAllBut1ComboInfo->Get_NumParticles().empty() && (locAllBut1ComboInfo->Get_FurtherDecays()[0].second > 1)) //
3112 locExpandAllBut1Flag = true;
3113 return locExpandAllBut1Flag;
3114}
3115
3116void DSourceComboer::Combo_Horizontally_AddDecay(const DSourceComboUse& locComboUseToCreate, const DSourceComboUse& locComboUseAllBut1, const DSourceComboUse& locComboUseToAdd, ComboingStage_t locComboingStage, const DSourceCombo* locChargedCombo_Presiding, bool locExpandAllBut1Flag, unsigned char locNumTabs)
3117{
3118 auto locChargeContentUseToAdd = Get_ChargeContent(std::get<2>(locComboUseToAdd));
3119 if((locComboingStage == d_ChargedStage) && (locChargeContentUseToAdd == d_Neutral))
3120 {
3121 //this won't be done yet! just copy the all-but-1 as the desired combos
3122 auto& locSourceCombosByUseSoFar = Get_CombosSoFar(locComboingStage, d_Charged);
3123 auto& locAllBut1Combos = locSourceCombosByUseSoFar[locComboUseAllBut1];
3124 locSourceCombosByUseSoFar.emplace(locComboUseToCreate, locAllBut1Combos);
3125 if(dDebugLevel > 0)
3126 cout << "Save for later!" << endl;
3127
3128 //Set the resume indices
3129 Build_ComboResumeIndices(locComboUseToCreate, locComboingStage, nullptr);
3130 return;
3131 }
3132
3133 //create the combos for the use-to-add if they haven't been created yet
3134 auto locChargedCombo_NextPresiding = Get_NextChargedCombo(locChargedCombo_Presiding, locComboUseToAdd, locComboingStage, true, 1);
3135 auto& locSourceCombosByUseSoFar = Get_CombosSoFar(locComboingStage, locChargeContentUseToAdd, locChargedCombo_NextPresiding);
3136 if(locSourceCombosByUseSoFar.find(locComboUseToAdd) == locSourceCombosByUseSoFar.end()) //if true: not yet
3137 Create_SourceCombos(locComboUseToAdd, locComboingStage, locChargedCombo_Presiding, locNumTabs + 1); //this may be something we want to combo vertically: go back to (unknown) mother function
3138
3139 //combo it horizontally with the rest
3140 Combo_Horizontally_AddCombo(locComboUseToCreate, locComboUseAllBut1, locComboUseToAdd, locComboingStage, locChargedCombo_Presiding, locExpandAllBut1Flag, locNumTabs);
3141}
3142
3143void DSourceComboer::Combo_Horizontally_AddParticles(const DSourceComboUse& locComboUseToCreate, const DSourceComboUse& locComboUseAllBut1, const pair<Particle_t, unsigned char>& locParticlePairToAdd, ComboingStage_t locComboingStage, const DSourceCombo* locChargedCombo_Presiding, bool locExpandAllBut1Flag, unsigned char locNumTabs)
3144{
3145 if((locComboingStage == d_ChargedStage) && (ParticleCharge(locParticlePairToAdd.first) == 0))
3146 {
3147 //this won't be done yet! just copy the all-but-1 as the desired combos
3148 auto& locSourceCombosByUseSoFar = Get_CombosSoFar(locComboingStage, d_Charged);
3149 auto& locAllBut1Combos = locSourceCombosByUseSoFar[locComboUseAllBut1];
3150 locSourceCombosByUseSoFar.emplace(locComboUseToCreate, locAllBut1Combos);
3151 if(dDebugLevel > 0)
3152 cout << "Save for later!" << endl;
3153
3154 //Set the resume indices
3155 Build_ComboResumeIndices(locComboUseToCreate, locComboingStage, nullptr);
3156 return;
3157 }
3158 if(locParticlePairToAdd.second > 1)
3159 {
3160 //create a combo use for X -> N particles of this type
3161 auto locSourceInfoToAdd = GetOrMake_SourceComboInfo({locParticlePairToAdd}, {}, locNumTabs);
3162 auto locChargeContentUseToAdd = Get_ChargeContent(locSourceInfoToAdd);
3163 auto locToAddZBin = (locChargeContentUseToAdd != d_Charged) ? std::get<1>(locComboUseToCreate) : DSourceComboInfo::Get_VertexZIndex_ZIndependent();
3164 DSourceComboUse locComboUseToAdd(Unknown, locToAddZBin, locSourceInfoToAdd, false, Unknown);
3165
3166 //create the combos for the use-to-add if they haven't been created yet
3167 auto locChargedCombo_NextPresiding = Get_NextChargedCombo(locChargedCombo_Presiding, locComboUseToAdd, locComboingStage, true, 1);
3168 auto& locSourceCombosByUseSoFar = Get_CombosSoFar(locComboingStage, locChargeContentUseToAdd, locChargedCombo_NextPresiding);
3169 if(locSourceCombosByUseSoFar.find(locComboUseToAdd) == locSourceCombosByUseSoFar.end()) //if true: not yet
3170 Create_SourceCombos(locComboUseToAdd, locComboingStage, locChargedCombo_Presiding, locNumTabs + 1); //this may be something we want to combo vertically: go back to (unknown) mother function
3171
3172 //combo it horizontally with the rest
3173 Combo_Horizontally_AddCombo(locComboUseToCreate, locComboUseAllBut1, locComboUseToAdd, locComboingStage, locChargedCombo_Presiding, locExpandAllBut1Flag, locNumTabs);
3174 }
3175 else
3176 Combo_Horizontally_AddParticle(locComboUseToCreate, locComboUseAllBut1, locParticlePairToAdd.first, locComboingStage, locChargedCombo_Presiding, locNumTabs);
3177}
3178
3179void DSourceComboer::Create_Combo_OneParticle(const DSourceComboUse& locComboUseToCreate, ComboingStage_t locComboingStage, unsigned char locNumTabs)
3180{
3181 if(dDebugLevel >= 5)
3182 {
3183 cout << endl;
3184 for(decltype(locNumTabs) locTabNum = 0; locTabNum < locNumTabs; ++locTabNum) cout << "\t";
3185 cout << "Create_Combo_OneParticle: Stage = " << locComboingStage << endl;
3186 for(decltype(locNumTabs) locTabNum = 0; locTabNum < locNumTabs; ++locTabNum) cout << "\t";
3187 cout << "USE TO CREATE:" << endl;
3188 DAnalysis::Print_SourceComboUse(locComboUseToCreate, locNumTabs);
3189 }
3190
3191 //not much of a combo if there's only 1, is it? //e.g. 1 charged track at a vertex
3192
3193 //Get combos so far
3194 auto& locSourceCombosByUseSoFar = Get_CombosSoFar(locComboingStage, d_Neutral); //if not neutral then is on charged stage: argument doesn't matter
3195
3196 //get combo use contents
3197 auto locVertexZBin = std::get<1>(locComboUseToCreate);
3198 auto locComboInfo = std::get<2>(locComboUseToCreate);
3199 auto locParticlePair = locComboInfo->Get_NumParticles().front();
3200 auto locPID = locParticlePair.first;
3201
3202 //check if comboing massive neutrals: comboing results are independent of z-bin: see if this has already been done for a different (non-z-independent) zbin
3203 if((ParticleCharge(locPID) == 0) && (ParticleMass(locPID) > 0.0) && (locComboingStage == d_MixedStage))
3204 {
3205 //if so, just copy the results into this zbin!
3206 //note that this is only the case for comboing particles, not comboing combos: decays contain uses, which have the zbin specified
3207 for(signed char locZBin = 0; locZBin < (signed char)dSourceComboTimeHandler->Get_NumVertexZBins(); ++locZBin)
3208 {
3209 if(locZBin == locVertexZBin)
3210 continue;
3211 auto locZBinUse = DSourceComboUse{Unknown, locZBin, locComboInfo, false, Unknown};
3212 if(locSourceCombosByUseSoFar.find(locZBinUse) == locSourceCombosByUseSoFar.end())
3213 continue;
3214
3215 //just copy the results!
3216 locSourceCombosByUseSoFar[locComboUseToCreate] = locSourceCombosByUseSoFar[locZBinUse];
3217 auto& locSourceCombosByBeamBunchByUse = Get_SourceCombosByBeamBunchByUse(dComboInfoChargeContent[locComboInfo], nullptr);
3218 locSourceCombosByBeamBunchByUse.emplace(locComboUseToCreate, locSourceCombosByBeamBunchByUse[locZBinUse]);
3219
3220 //Set the resume indices
3221 Build_ComboResumeIndices(locComboUseToCreate, locComboingStage, nullptr);
3222 if(dDebugLevel >= 5)
3223 {
3224 for(decltype(locNumTabs) locTabNum = 0; locTabNum < locNumTabs; ++locTabNum) cout << "\t";
3225 cout << "Create_Combo_OneParticle: NUM SOURCE COMBOS CREATED: " << locSourceCombosByUseSoFar[locComboUseToCreate]->size() << endl;
3226 }
3227 return;
3228 }
3229 }
3230
3231 //if on the mixed stage, must be doing all neutrals: first copy over ALL fcal-only results
3232 locSourceCombosByUseSoFar.emplace(locComboUseToCreate, Get_SourceComboVectorResource());
3233 if(locComboingStage == d_MixedStage)
3234 Copy_ZIndependentMixedResults(locComboUseToCreate, nullptr);
3235
3236 //Get particles for comboing
3237 const auto& locParticles = Get_ParticlesForComboing(locPID, locComboingStage, {}, locVertexZBin);
3238 for(const auto& locParticle : locParticles)
3239 {
3240 auto locIsZIndependent = Get_IsComboingZIndependent(locParticle, locPID);
3241 if((locComboingStage == d_MixedStage) && locIsZIndependent)
3242 continue; //this combo has already been created (assuming it was valid): during the FCAL-only stage
3243
3244 //check if this combo is unique!
3245 //it will not be unique if: comboing photons, on mixed stage, and this combo has already been created for a different zbin
3246 //if so, don't duplicate memory
3247 //note that this can only the case for comboing particles, not comboing combos: decays contain uses, which have the zbin specified
3248 if((locPID == Gamma) && (locComboingStage == d_MixedStage))
3249 {
3250 auto locIterator = dNPhotonsToComboMap.find({locParticle});
3251 if(locIterator != dNPhotonsToComboMap.end()) //if true, already exists, save it and continue;
3252 {
3253 auto locCombo = locIterator->second;
3254 locSourceCombosByUseSoFar[locComboUseToCreate]->push_back(locCombo);
3255 if(dDebugLevel >= 15)
3256 {
3257 for(decltype(locNumTabs) locTabNum = 0; locTabNum < locNumTabs; ++locTabNum) cout << "\t";
3258 cout << "COPIED COMBO:" << endl;
3259 DAnalysis::Print_SourceCombo(locCombo, locNumTabs);
3260 }
3261 continue;
3262 }
3263 }
3264
3265 auto locCombo = Get_SourceComboResource();
3266 locCombo->Set_Members({std::make_pair(locPID, locParticle)}, {}, locIsZIndependent);
3267 if(locPID == Gamma)
3268 dNPhotonsToComboMap.emplace(vector<const JObject*>{locParticle}, locCombo);
3269 if(dDebugLevel >= 10)
3270 {
3271 for(decltype(locNumTabs) locTabNum = 0; locTabNum < locNumTabs; ++locTabNum) cout << "\t";
3272 cout << "CREATED COMBO:" << endl;
3273 DAnalysis::Print_SourceCombo(locCombo, locNumTabs);
3274 /*
3275 if(locPID == Neutron) {
3276 // TEMP
3277 for(decltype(locNumTabs) locTabNum = 0; locTabNum < locNumTabs; ++locTabNum) cout << "\t";
3278 cout << " Neutron energy = " ;
3279 auto locNeutralShower = dynamic_cast<const DNeutralShower *>(locParticle);
3280 if( locNeutralShower == nullptr )
3281 cout << "FAILED" << endl;
3282 else
3283 cout << locNeutralShower->dEnergy << endl;
3284 }
3285 */
3286 }
3287
3288 locSourceCombosByUseSoFar[locComboUseToCreate]->push_back(locCombo); //save it //in creation order
3289 if(locPID == Gamma)
3290 Register_ValidRFBunches(locComboUseToCreate, locCombo, dSourceComboTimeHandler->Get_ValidRFBunches(locParticle, locVertexZBin), locComboingStage, nullptr);
3291 else
3292 Register_ValidRFBunches(locComboUseToCreate, locCombo, {}, locComboingStage, nullptr);
3293 }
3294 if((dDebugLevel > 0) || (dDebugLevel == -1))
3295 Check_ForDuplicates(*(locSourceCombosByUseSoFar[locComboUseToCreate]));
3296
3297 //Set the resume indices
3298 Build_ComboResumeIndices(locComboUseToCreate, locComboingStage, nullptr);
3299 if(dDebugLevel >= 5)
3300 {
3301 for(decltype(locNumTabs) locTabNum = 0; locTabNum < locNumTabs; ++locTabNum) cout << "\t";
3302 cout << "Create_Combo_OneParticle: NUM SOURCE COMBOS CREATED: " << locSourceCombosByUseSoFar[locComboUseToCreate]->size() << endl;
3303 }
3304}
3305
3306void DSourceComboer::Create_Combo_OneDecay(const DSourceComboUse& locComboUseToCreate, ComboingStage_t locComboingStage, const DSourceCombo* locChargedCombo_Presiding, unsigned char locNumTabs)
3307{
3308 //here you're literally just promoting something you created earlier. e.g. creating a X -> Lambda combo
3309 //this can happen if your channel is something like g, p -> (K+), Lambda
3310 if(dDebugLevel >= 5)
3311 {
3312 cout << endl;
3313 for(decltype(locNumTabs) locTabNum = 0; locTabNum < locNumTabs; ++locTabNum) cout << "\t";
3314 cout << "Create_Combo_OneDecay: Stage = " << locComboingStage << endl;
3315 for(decltype(locNumTabs) locTabNum = 0; locTabNum < locNumTabs; ++locTabNum) cout << "\t";
3316 cout << "USE TO CREATE:" << endl;
3317 DAnalysis::Print_SourceComboUse(locComboUseToCreate, locNumTabs);
3318 }
3319
3320 auto locComboInfoToCreate = std::get<2>(locComboUseToCreate);
3321
3322 auto locFurtherDecays = locComboInfoToCreate->Get_FurtherDecays();
3323 auto& locDecayUse = locFurtherDecays[0].first;
3324 auto locChargedCombo_PreviousPresiding = Get_NextChargedCombo(locChargedCombo_Presiding, locDecayUse, locComboingStage, true, 1);
3325
3326 //if on the all-showers stage, first copy over ALL fcal-only results
3327 auto& locSourceCombosByUseSoFar = Get_CombosSoFar(locComboingStage, dComboInfoChargeContent[locComboInfoToCreate], locChargedCombo_PreviousPresiding);
3328 auto& locSourceCombosByUseToSaveTo = Get_CombosSoFar(locComboingStage, dComboInfoChargeContent[locComboInfoToCreate], locChargedCombo_Presiding);
3329 locSourceCombosByUseToSaveTo.emplace(locComboUseToCreate, Get_SourceComboVectorResource());
3330
3331 if(locComboingStage == d_MixedStage)
3332 Copy_ZIndependentMixedResults(locComboUseToCreate, locChargedCombo_Presiding);
3333
3334 //The decay itself has already been created (when comboing vertically)
3335 auto& locDecayCombos = locSourceCombosByUseSoFar[locDecayUse];
3336 for(auto locDecayCombo : *locDecayCombos)
3337 {
3338 auto locIsZIndependent = locDecayCombo->Get_IsComboingZIndependent();
3339 if((locComboingStage == d_MixedStage) && locIsZIndependent)
3340 continue; //this combo has already been created (assuming it was valid): during the FCAL-only stage
3341
3342 auto& locValidRFBunches = dValidRFBunches_ByCombo[std::make_pair(locDecayCombo, std::get<1>(locDecayUse))];
3343
3344 //create new combo!
3345 auto locCombo = Get_SourceComboResource();
3346 locCombo->Set_Members({}, {std::make_pair(locDecayUse, vector<const DSourceCombo*>{locDecayCombo})}, locIsZIndependent);
3347
3348 //save it!
3349 locSourceCombosByUseToSaveTo[locComboUseToCreate]->push_back(locCombo);
3350 Register_ValidRFBunches(locComboUseToCreate, locCombo, locValidRFBunches, locComboingStage, locChargedCombo_Presiding);
3351 }
3352
3353 //Set the resume indices
3354 Build_ComboResumeIndices(locComboUseToCreate, locComboingStage, locChargedCombo_Presiding);
3355 if(dDebugLevel >= 5)
3356 {
3357 for(decltype(locNumTabs) locTabNum = 0; locTabNum < locNumTabs; ++locTabNum) cout << "\t";
3358 cout << "Create_Combo_OneDecay: NUM SOURCE COMBOS CREATED: " << locSourceCombosByUseToSaveTo[locComboUseToCreate]->size() << endl;
3359 }
3360}
3361
3362void DSourceComboer::Combo_Horizontally_AddCombo(const DSourceComboUse& locComboUseToCreate, const DSourceComboUse& locAllBut1ComboUse, const DSourceComboUse& locSourceComboUseToAdd, ComboingStage_t locComboingStage, const DSourceCombo* locChargedCombo_Presiding, bool locExpandAllBut1Flag, unsigned char locNumTabs)
3363{
3364 if(dDebugLevel >= 5)
3365 {
3366 cout << endl;
3367 for(decltype(locNumTabs) locTabNum = 0; locTabNum < locNumTabs; ++locTabNum) cout << "\t";
3368 cout << "Combo_Horizontally_AddCombo: Stage, presiding charged combo = " << locComboingStage << ", " << locChargedCombo_Presiding << endl;
3369 for(decltype(locNumTabs) locTabNum = 0; locTabNum < locNumTabs; ++locTabNum) cout << "\t";
3370 cout << "PRESIDING COMBO:" << endl;
3371 DAnalysis::Print_SourceCombo(locChargedCombo_Presiding, locNumTabs);
3372 for(decltype(locNumTabs) locTabNum = 0; locTabNum < locNumTabs; ++locTabNum) cout << "\t";
3373 cout << "USE TO CREATE:" << endl;
3374 DAnalysis::Print_SourceComboUse(locComboUseToCreate, locNumTabs);
3375 for(decltype(locNumTabs) locTabNum = 0; locTabNum < locNumTabs; ++locTabNum) cout << "\t";
3376 cout << "All-But-1 USE:" << endl;
3377 DAnalysis::Print_SourceComboUse(locAllBut1ComboUse, locNumTabs);
3378 for(decltype(locNumTabs) locTabNum = 0; locTabNum < locNumTabs; ++locTabNum) cout << "\t";
3379 cout << "USE TO ADD:" << endl;
3380 DAnalysis::Print_SourceComboUse(locSourceComboUseToAdd, locNumTabs);
3381 }
3382
3383 //e.g. we are grouping N pi0s and M photons (> 1) with L etas (>= 1), etc. to make combos
3384 //so, let's get the combos for the main grouping
3385
3386 //Get combos so far
3387 auto locComboInfo_AllBut1 = std::get<2>(locAllBut1ComboUse);
3388 auto locComboInfoToCreate = std::get<2>(locComboUseToCreate);
3389 auto locChargeContent_AllBut1 = dComboInfoChargeContent[locComboInfo_AllBut1];
3390 auto locChargedCombo_WithNow = Get_ChargedCombo_WithNow(locChargedCombo_Presiding, locComboInfoToCreate, locComboingStage);
3391//cout << "save to: stage, charge, withnow = " << locComboingStage << ", " << dComboInfoChargeContent[locComboInfoToCreate] << ", " << locChargedCombo_WithNow << endl;
3392 auto& locSourceCombosByUseToSaveTo = Get_CombosSoFar(locComboingStage, dComboInfoChargeContent[locComboInfoToCreate], locChargedCombo_Presiding);
3393
3394 bool locGetFromSoFarFlag = (locComboingStage == d_ChargedStage) || (locChargeContent_AllBut1 != d_Charged);
3395 auto locChargedCombo_PresidingAllBut1 = locChargedCombo_Presiding;
3396 if((locComboInfo_AllBut1->Get_FurtherDecays().size() == 1) && locComboInfo_AllBut1->Get_NumParticles().empty())
3397 locChargedCombo_PresidingAllBut1 = Get_NextChargedCombo(locChargedCombo_Presiding, locAllBut1ComboUse, locComboingStage, true, 1);
3398 auto& locSourceCombosByUseAllBut1 = Get_CombosSoFar(locComboingStage, locChargeContent_AllBut1, locChargedCombo_PresidingAllBut1);
3399
3400 vector<const DSourceCombo*> locChargedComboVector = {locChargedCombo_WithNow}; //ugh
3401 auto locCombos_AllBut1 = locGetFromSoFarFlag ? locSourceCombosByUseAllBut1[locAllBut1ComboUse] : &locChargedComboVector; //Combos are a vector of (e.g.): -> N pi0s
3402
3403 auto locChargeContent_ToAdd = dComboInfoChargeContent[std::get<2>(locSourceComboUseToAdd)];
3404 if((locComboingStage == d_ChargedStage) && (locChargeContent_ToAdd == d_Neutral))
3405 {
3406 //can't add neutrals, so we are already done! just copy the results to the new vector
3407 locSourceCombosByUseToSaveTo.emplace(locComboUseToCreate, locCombos_AllBut1);
3408 //Set the resume indices
3409 Build_ComboResumeIndices(locComboUseToCreate, locComboingStage, nullptr);
3410 if(dDebugLevel > 0)
3411 cout << "Save for later!" << endl;
3412 return;
3413 }
3414
3415 //if on the all-showers stage, first copy over ALL fcal-only results
3416 locSourceCombosByUseToSaveTo.emplace(locComboUseToCreate, Get_SourceComboVectorResource());
3417 if(locComboingStage == d_MixedStage)
3418 Copy_ZIndependentMixedResults(locComboUseToCreate, locChargedCombo_Presiding);
3419
3420 if(locCombos_AllBut1->empty())
3421 return; //nothing to do
3422
3423 auto locDecayPID_UseToAdd = std::get<0>(locSourceComboUseToAdd);
3424 auto locComboInfo_UseToAdd = std::get<2>(locSourceComboUseToAdd);
3425
3426 //determine whether we should promote the contents of the combos we are combining up to the new combo (else set combo as decay of new combo)
3427 auto locComboInfo_UseToCreate = std::get<2>(locComboUseToCreate);
3428 DSourceComboUse locNonNeutralUse{Unknown, 0, nullptr, false, Unknown};
3429 bool locPromoteToAddFlag = Get_PromoteFlag(locComboingStage, locDecayPID_UseToAdd, locComboInfo_UseToCreate, locComboInfo_UseToAdd, locNonNeutralUse); //is ignored if charged
3430 bool locPromoteAllBut1Flag = Get_PromoteFlag(locComboingStage, std::get<0>(locAllBut1ComboUse), locComboInfo_UseToCreate, locComboInfo_AllBut1, locNonNeutralUse);
3431 if(dDebugLevel >= 20)
3432 cout << "flags: expand all-but-1, promote to-add, promote all-but-1: " << locExpandAllBut1Flag << ", " << locPromoteToAddFlag << ", " << locPromoteAllBut1Flag << endl;
3433
3434 //check if on mixed stage but comboing to charged
3435 if((locComboingStage != d_ChargedStage) && (locChargeContent_ToAdd == d_Charged))
3436 {
3437 //only one valid option for to-add: locChargedCombo_WithNow: create all combos immediately
3438 for(const auto& locCombo_AllBut1 : *locCombos_AllBut1)
3439 {
3440 auto locIsZIndependent = locCombo_AllBut1->Get_IsComboingZIndependent();
3441 if((locComboingStage == d_MixedStage) && locIsZIndependent)
3442 continue; //this combo has already been created (assuming it was valid): during the FCAL-only stage
3443
3444 //get the valid RF bunches (those for the all-but-1, because we are comboing with charged which is "all")
3445 const auto& locValidRFBunches = dValidRFBunches_ByCombo[std::make_pair(locCombo_AllBut1, std::get<1>(locAllBut1ComboUse))];
3446
3447 //create new combo!
3448 auto locCombo = Get_SourceComboResource();
3449
3450 //get contents of the all-but-1 so that we can add to them
3451 auto locFurtherDecayCombos_AllBut1 = locCombo_AllBut1->Get_FurtherDecayCombos(); //the all-but-1 combo contents by use
3452 auto locComboParticles_AllBut1 = locCombo_AllBut1->Get_SourceParticles();
3453
3454 if(locExpandAllBut1Flag)
3455 {
3456 locFurtherDecayCombos_AllBut1.emplace_back(locSourceComboUseToAdd, vector<const DSourceCombo*>{locChargedCombo_WithNow});
3457 locCombo->Set_Members(locComboParticles_AllBut1, locFurtherDecayCombos_AllBut1, locIsZIndependent); // create combo with all PIDs
3458 }
3459 else
3460 {
3461 if(locPromoteAllBut1Flag)
3462 {
3463 //promote contents of all-but-1 above the to-add level
3464 //so, really, use the all-but-1 as the basis, and put the to-add as a another decay in the all-but-1
3465 locFurtherDecayCombos_AllBut1.emplace_back(locSourceComboUseToAdd, vector<const DSourceCombo*>{locChargedCombo_WithNow});
3466 locCombo->Set_Members(locComboParticles_AllBut1, locFurtherDecayCombos_AllBut1, locIsZIndependent);
3467 }
3468 else //no promotions: side by side in a new combo
3469 {
3470 DSourceCombosByUse_Small locFurtherDecayCombos_Needed;
3471 locFurtherDecayCombos_Needed.emplace_back(locAllBut1ComboUse, vector<const DSourceCombo*>{locCombo_AllBut1});
3472 locFurtherDecayCombos_Needed.emplace_back(locSourceComboUseToAdd, vector<const DSourceCombo*>{locChargedCombo_WithNow});
3473 locCombo->Set_Members({}, locFurtherDecayCombos_Needed, locIsZIndependent); // create combo with all PIDs
3474 }
3475 }
3476 if(dDebugLevel >= 10)
3477 {
3478 for(decltype(locNumTabs) locTabNum = 0; locTabNum < locNumTabs; ++locTabNum) cout << "\t";
3479 cout << "CREATED COMBO:" << endl;
3480 DAnalysis::Print_SourceCombo(locCombo, locNumTabs);
3481 }
3482
3483 //save it!
3484 locSourceCombosByUseToSaveTo[locComboUseToCreate]->push_back(locCombo);
3485 Register_ValidRFBunches(locComboUseToCreate, locCombo, locValidRFBunches, locComboingStage, locChargedCombo_Presiding);
3486 }
3487 if((dDebugLevel > 0) || (dDebugLevel == -1))
3488 Check_ForDuplicates(*(locSourceCombosByUseToSaveTo[locComboUseToCreate]));
3489
3490 //Set the resume indices
3491 Build_ComboResumeIndices(locComboUseToCreate, locComboingStage, locChargedCombo_Presiding);
3492 if(dDebugLevel >= 5)
3493 {
3494 for(decltype(locNumTabs) locTabNum = 0; locTabNum < locNumTabs; ++locTabNum) cout << "\t";
3495 cout << "Combo_Horizontally_AddCombo: NUM SOURCE COMBOS CREATED: " << locSourceCombosByUseToSaveTo[locComboUseToCreate]->size() << endl;
3496 }
3497 return;
3498 }
3499
3500 //get the previous charged combo (if needed)
3501 auto locNextPresidingCombo = Get_NextChargedCombo(locChargedCombo_Presiding, locSourceComboUseToAdd, locComboingStage, true, 1);
3502 auto locChargedCombo_WithPrevious = Get_ChargedCombo_WithNow(locNextPresidingCombo, std::get<2>(locSourceComboUseToAdd), locComboingStage);
3503 if(dDebugLevel >= 20)
3504 cout << "combos: presiding, next-presiding, with-previous: " << locChargedCombo_Presiding << ", " << locNextPresidingCombo << ", " << locChargedCombo_WithPrevious << endl;
3505
3506 //now, for each combo of all-but-1-PIDs, see which of the to-add combos we can group to it
3507 //valid grouping: Don't re-use a shower we've already used
3508 for(const auto& locCombo_AllBut1 : *locCombos_AllBut1)
3509 {
3510 //first of all, get the potential combos that satisfy the RF bunches for the all-but-1 combo
3511 const auto& locValidRFBunches_AllBut1 = dValidRFBunches_ByCombo[std::make_pair(locCombo_AllBut1, std::get<1>(locAllBut1ComboUse))];
3512 const auto& locDecayCombos_ToAdd = Get_CombosForComboing(locSourceComboUseToAdd, locComboingStage, locValidRFBunches_AllBut1, locNextPresidingCombo);
3513
3514 //before we loop, first get all of the showers used to make the all-but-1 grouping, and sort it so that we can quickly search it
3515 auto locUsedParticles_AllBut1 = DAnalysis::Get_SourceParticles(locCombo_AllBut1->Get_SourceParticles(true)); //true: entire chain
3516 std::sort(locUsedParticles_AllBut1.begin(), locUsedParticles_AllBut1.end()); //must sort, because when retrieving entire chain is unsorted
3517
3518 //this function will do our validity test
3519 auto Search_Duplicates = [&locUsedParticles_AllBut1](const JObject* locParticle) -> bool
3520 {return std::binary_search(locUsedParticles_AllBut1.begin(), locUsedParticles_AllBut1.end(), locParticle);};
3521
3522 auto locIsZIndependent_AllBut1 = locCombo_AllBut1->Get_IsComboingZIndependent();
3523
3524 //loop over potential combos to add to the group, creating a new combo for each valid (non-duplicate) grouping
3525 for(const auto& locDecayCombo_ToAdd : locDecayCombos_ToAdd)
3526 {
3527 auto locIsZIndependent = (locIsZIndependent_AllBut1 && locDecayCombo_ToAdd->Get_IsComboingZIndependent());
3528 if((locComboingStage == d_MixedStage) && locIsZIndependent)
3529 continue; //this combo has already been created (assuming it was valid): during the FCAL-only stage
3530
3531 //search the all-but-1 shower vector to see if any of the showers in this combo are duplicated
3532 auto locUsedParticles_ToAdd = DAnalysis::Get_SourceParticles(locDecayCombo_ToAdd->Get_SourceParticles(true)); //true: entire chain
3533
3534 //conduct search
3535 if(std::any_of(locUsedParticles_ToAdd.begin(), locUsedParticles_ToAdd.end(), Search_Duplicates))
3536 continue; //at least one photon was a duplicate, this combo won't work
3537
3538 //no duplicates: this combo is unique. build a new combo
3539
3540 //See which RF bunches match up //guaranteed to be at least one, due to selection in Get_CombosForComboing() function
3541 vector<int> locValidRFBunches = {}; //if charged or massive neutrals, ignore (they don't choose at this stage)
3542 if(locComboingStage != d_ChargedStage)
3543 locValidRFBunches = dSourceComboTimeHandler->Get_CommonRFBunches(locValidRFBunches_AllBut1, dValidRFBunches_ByCombo[std::make_pair(locDecayCombo_ToAdd, std::get<1>(locSourceComboUseToAdd))]);
3544
3545 //create new combo!
3546 auto locCombo = Get_SourceComboResource();
3547
3548 //get contents of the all-but-1 so that we can add to them
3549 auto locFurtherDecayCombos_AllBut1 = locCombo_AllBut1->Get_FurtherDecayCombos(); //the all-but-1 combo contents by use
3550 auto locComboParticles_AllBut1 = locCombo_AllBut1->Get_SourceParticles(false);
3551 if(locExpandAllBut1Flag)
3552 {
3553 if(locPromoteToAddFlag)
3554 {
3555 //promote all contents of to-add to the all-but-1 level
3556 auto locUsedParticlePairs_ToAdd = locDecayCombo_ToAdd->Get_SourceParticles(false);
3557 locComboParticles_AllBut1.insert(locComboParticles_AllBut1.end(), locUsedParticlePairs_ToAdd.begin(), locUsedParticlePairs_ToAdd.end());
3558 auto locFurtherDecayCombos_ToAdd = locDecayCombo_ToAdd->Get_FurtherDecayCombos();
3559 locFurtherDecayCombos_AllBut1.insert(locFurtherDecayCombos_AllBut1.end(), locFurtherDecayCombos_ToAdd.begin(), locFurtherDecayCombos_ToAdd.end());
3560 }
3561 else
3562 locFurtherDecayCombos_AllBut1.emplace_back(locSourceComboUseToAdd, vector<const DSourceCombo*>{locDecayCombo_ToAdd});
3563 locCombo->Set_Members(locComboParticles_AllBut1, locFurtherDecayCombos_AllBut1, locIsZIndependent); // create combo with all PIDs
3564 }
3565 else //side by side in a new combo
3566 {
3567 auto locComboParticlePairs_ToAdd = locDecayCombo_ToAdd->Get_SourceParticles(false);
3568 auto locFurtherDecayCombos_ToAdd = locDecayCombo_ToAdd->Get_FurtherDecayCombos();
3569 if(locPromoteAllBut1Flag && locPromoteToAddFlag)
3570 {
3571 //union of particles & decays from each
3572 //so, use the all-but-1 as a basis, and merge the to-add content in at the same level
3573 locFurtherDecayCombos_AllBut1.insert(locFurtherDecayCombos_AllBut1.end(), locFurtherDecayCombos_ToAdd.begin(), locFurtherDecayCombos_ToAdd.end());
3574 locComboParticles_AllBut1.insert(locComboParticles_AllBut1.end(), locComboParticlePairs_ToAdd.begin(), locComboParticlePairs_ToAdd.end());
3575 locCombo->Set_Members(locComboParticles_AllBut1, locFurtherDecayCombos_AllBut1, locIsZIndependent);
3576 }
3577 else if(locPromoteAllBut1Flag)
3578 {
3579 //promote contents of all-but-1 above the to-add level
3580 //so, really, use the all-but-1 as the basis, and put the to-add as a another decay in the all-but-1
3581 locFurtherDecayCombos_AllBut1.emplace_back(locSourceComboUseToAdd, vector<const DSourceCombo*>{locDecayCombo_ToAdd});
3582 locCombo->Set_Members(locComboParticles_AllBut1, locFurtherDecayCombos_AllBut1, locIsZIndependent);
3583 }
3584 else if(locPromoteToAddFlag)
3585 {
3586 //promote contents of to-add above the all-but-1 level
3587 //so, really, use the to-add as the basis, and put the all-but-1 as a another decay in the to-add
3588 //if non-neutral-use info is not nullptr, then the all-but-1 is a charged combo that has been promoted: keep the combo, but change the use
3589 auto locAllBut1UseToUse = (std::get<2>(locNonNeutralUse) == nullptr) ? locAllBut1ComboUse : locNonNeutralUse;
3590 locFurtherDecayCombos_ToAdd.emplace_back(locAllBut1UseToUse, vector<const DSourceCombo*>{locCombo_AllBut1});
3591 locCombo->Set_Members(locComboParticlePairs_ToAdd, locFurtherDecayCombos_ToAdd, locIsZIndependent);
3592 }
3593 else //promote nothing
3594 {
3595 DSourceCombosByUse_Small locFurtherDecayCombos_Needed;
3596 //if non-neutral-use info is not nullptr, then the all-but-1 is a charged combo that has been promoted: keep the combo, but change the use
3597 auto locAllBut1UseToUse = (std::get<2>(locNonNeutralUse) == nullptr) ? locAllBut1ComboUse : locNonNeutralUse;
3598 locFurtherDecayCombos_Needed.emplace_back(locAllBut1UseToUse, vector<const DSourceCombo*>{locCombo_AllBut1});
3599 locFurtherDecayCombos_Needed.emplace_back(locSourceComboUseToAdd, vector<const DSourceCombo*>{locDecayCombo_ToAdd});
3600 locCombo->Set_Members({}, locFurtherDecayCombos_Needed, locIsZIndependent);
3601 }
3602 }
3603 if(dDebugLevel >= 10)
3604 {
3605 for(decltype(locNumTabs) locTabNum = 0; locTabNum < locNumTabs; ++locTabNum) cout << "\t";
3606 cout << "CREATED COMBO:" << endl;
3607 DAnalysis::Print_SourceCombo(locCombo, locNumTabs);
3608 }
3609
3610 //save it! //in creation order!
3611 locSourceCombosByUseToSaveTo[locComboUseToCreate]->push_back(locCombo);
3612 Register_ValidRFBunches(locComboUseToCreate, locCombo, locValidRFBunches, locComboingStage, locChargedCombo_Presiding);
3613 }
3614 }
3615 if((dDebugLevel > 0) || (dDebugLevel == -1))
3616 Check_ForDuplicates(*(locSourceCombosByUseToSaveTo[locComboUseToCreate]));
3617
3618 //Set the resume indices
3619 Build_ComboResumeIndices(locComboUseToCreate, locComboingStage, locChargedCombo_Presiding);
3620 if(dDebugLevel >= 5)
3621 {
3622 for(decltype(locNumTabs) locTabNum = 0; locTabNum < locNumTabs; ++locTabNum) cout << "\t";
3623 cout << "Combo_Horizontally_AddCombo: NUM SOURCE COMBOS CREATED: " << locSourceCombosByUseToSaveTo[locComboUseToCreate]->size() << endl;
3624 }
3625}
3626
3627void DSourceComboer::Combo_Horizontally_AddParticle(const DSourceComboUse& locComboUseToCreate, const DSourceComboUse& locAllBut1ComboUse, Particle_t locPID, ComboingStage_t locComboingStage, const DSourceCombo* locChargedCombo_Presiding, unsigned char locNumTabs)
3628{
3629 if(dDebugLevel >= 5)
3630 {
3631 cout << endl;
3632 for(decltype(locNumTabs) locTabNum = 0; locTabNum < locNumTabs; ++locTabNum) cout << "\t";
3633 cout << "Combo_Horizontally_AddParticle: Stage, PID-to-add, presiding charged combo = " << locComboingStage << ", " << locPID << ", " << locChargedCombo_Presiding << endl;
3634 for(decltype(locNumTabs) locTabNum = 0; locTabNum < locNumTabs; ++locTabNum) cout << "\t";
3635 cout << "PRESIDING COMBO:" << endl;
3636 DAnalysis::Print_SourceCombo(locChargedCombo_Presiding, locNumTabs);
3637 for(decltype(locNumTabs) locTabNum = 0; locTabNum < locNumTabs; ++locTabNum) cout << "\t";
3638 cout << "USE TO CREATE:" << endl;
3639 DAnalysis::Print_SourceComboUse(locComboUseToCreate, locNumTabs);
3640 for(decltype(locNumTabs) locTabNum = 0; locTabNum < locNumTabs; ++locTabNum) cout << "\t";
3641 cout << "All-But-1 USE:" << endl;
3642 DAnalysis::Print_SourceComboUse(locAllBut1ComboUse, locNumTabs);
3643 }
3644
3645 //Get combos so far
3646 auto locComboInfo_AllBut1 = std::get<2>(locAllBut1ComboUse);
3647 auto locChargeContent_AllBut1 = dComboInfoChargeContent[locComboInfo_AllBut1];
3648 auto locComboInfoToCreate = std::get<2>(locAllBut1ComboUse);
3649 auto locChargedCombo_WithNow = Get_ChargedCombo_WithNow(locChargedCombo_Presiding, locComboInfoToCreate, locComboingStage);
3650 auto locChargedCombo_PresidingAllBut1 = locChargedCombo_Presiding;
3651 if((locComboInfo_AllBut1->Get_FurtherDecays().size() == 1) && locComboInfo_AllBut1->Get_NumParticles().empty())
3652 locChargedCombo_PresidingAllBut1 = Get_NextChargedCombo(locChargedCombo_Presiding, locAllBut1ComboUse, locComboingStage, true, 1);
3653 auto& locSourceCombosByUseSoFar = Get_CombosSoFar(locComboingStage, locChargeContent_AllBut1, locChargedCombo_PresidingAllBut1);
3654
3655 //e.g. we are grouping a whole bunch of particles and decays with a lone particle to make new combos
3656 auto& locSourceCombosByUseToSaveTo = Get_CombosSoFar(locComboingStage, dComboInfoChargeContent[locComboInfoToCreate], locChargedCombo_Presiding);
3657
3658 vector<const DSourceCombo*> locChargedComboVector = {locChargedCombo_WithNow}; //ugh
3659 bool locGetFromSoFarFlag = (locComboingStage == d_ChargedStage) || (locChargeContent_AllBut1 != d_Charged);
3660 auto locCombos_AllBut1 = locGetFromSoFarFlag ? locSourceCombosByUseSoFar[locAllBut1ComboUse] : &locChargedComboVector; //Combos are a vector of (e.g.): -> N pi0s
3661
3662 if((locComboingStage == d_ChargedStage) && (ParticleCharge(locPID) == 0))
3663 {
3664 //can't add neutrals, so we are already done! just copy the results to the new vector
3665 locSourceCombosByUseToSaveTo[locComboUseToCreate] = locCombos_AllBut1;
3666 //Set the resume indices
3667 Build_ComboResumeIndices(locComboUseToCreate, locComboingStage, nullptr);
3668 if(dDebugLevel > 0)
3669 cout << "Save for later!" << endl;
3670 return;
3671 }
3672
3673 //if on the all-showers stage, first copy over ALL fcal-only results
3674 locSourceCombosByUseToSaveTo.emplace(locComboUseToCreate, Get_SourceComboVectorResource());
3675 if(locComboingStage == d_MixedStage)
3676 Copy_ZIndependentMixedResults(locComboUseToCreate, nullptr);
3677
3678 auto locVertexZBin = std::get<1>(locComboUseToCreate);
3679
3680 //loop over the combos
3681 for(const auto& locCombo_AllBut1 : *locCombos_AllBut1)
3682 {
3683 //now, for each combo of all-but-1-PIDs, see which of the particles can group to it
3684 //valid grouping: Don't re-use a particle we've already used
3685
3686 //before we loop, first get all of the particles of the given PID used to make the all-but-1 grouping, and sort it so that we can quickly search it
3687 auto locUsedParticlePairs_AllBut1 = locCombo_AllBut1->Get_SourceParticles(true);
3688
3689 auto locUsedParticles_AllBut1 = DAnalysis::Get_SourceParticles(locUsedParticlePairs_AllBut1, ParticleCharge(locPID)); //true: entire chain
3690 std::sort(locUsedParticles_AllBut1.begin(), locUsedParticles_AllBut1.end()); //necessary: may be out of order due to comboing of different decays
3691
3692 //also, pre-get the further decays & FCAL-only flag, as we'll need them to build new combos
3693 auto locFurtherDecays = locCombo_AllBut1->Get_FurtherDecayCombos(); //the all-but-1 combo contents by use
3694 auto locIsZIndependent_AllBut1 = locCombo_AllBut1->Get_IsComboingZIndependent();
3695
3696 //Get potential particles for comboing
3697 const auto& locValidRFBunches_AllBut1 = dValidRFBunches_ByCombo[std::make_pair(locCombo_AllBut1, std::get<1>(locAllBut1ComboUse))];
3698 const auto& locParticles = Get_ParticlesForComboing(locPID, locComboingStage, locValidRFBunches_AllBut1, locVertexZBin);
3699
3700 //loop over potential showers to add to the group, creating a new combo for each valid (non-duplicate) grouping
3701 for(const auto& locParticle : locParticles)
3702 {
3703 auto locIsZIndependent = (locComboingStage == d_MixedStage_ZIndependent) || (locIsZIndependent_AllBut1 && Get_IsComboingZIndependent(locParticle, locPID));
3704 if((locComboingStage == d_MixedStage) && locIsZIndependent)
3705 continue; //this combo has already been created (assuming it was valid): during the FCAL-only stage
3706
3707 //conduct search
3708 if(std::binary_search(locUsedParticles_AllBut1.begin(), locUsedParticles_AllBut1.end(), locParticle))
3709 continue; //this particle has already been used, this combo won't work
3710
3711 //See which RF bunches match up //guaranteed to be at least one, due to selection in Get_ParticlesForComboing() function
3712 //if charged or massive neutrals, ignore (they don't choose at this stage)
3713 vector<int> locValidRFBunches = (locPID != Gamma) ? locValidRFBunches_AllBut1 : dSourceComboTimeHandler->Get_CommonRFBunches(locValidRFBunches_AllBut1, locParticle, locVertexZBin);
3714
3715 //no duplicates: this combo is unique. build a new combo
3716 auto locComboParticles = locCombo_AllBut1->Get_SourceParticles(false);
3717 locComboParticles.emplace_back(locPID, locParticle);
3718 auto locCombo = Get_SourceComboResource();
3719 locCombo->Set_Members(locComboParticles, locFurtherDecays, locIsZIndependent); // create combo with all PIDs
3720 if(dDebugLevel >= 10)
3721 {
3722 for(decltype(locNumTabs) locTabNum = 0; locTabNum < locNumTabs; ++locTabNum) cout << "\t";
3723 cout << "CREATED COMBO:" << endl;
3724 DAnalysis::Print_SourceCombo(locCombo, locNumTabs);
3725 }
3726
3727 //save it! //in creation order!
3728 locSourceCombosByUseToSaveTo[locComboUseToCreate]->push_back(locCombo);
3729 Register_ValidRFBunches(locComboUseToCreate, locCombo, locValidRFBunches, locComboingStage, locChargedCombo_Presiding);
3730 }
3731 }
3732 if((dDebugLevel > 0) || (dDebugLevel == -1))
3733 Check_ForDuplicates(*(locSourceCombosByUseToSaveTo[locComboUseToCreate]));
3734
3735 //Set the resume indices
3736 Build_ComboResumeIndices(locComboUseToCreate, locComboingStage, locChargedCombo_Presiding);
3737 if(dDebugLevel >= 5)
3738 {
3739 for(decltype(locNumTabs) locTabNum = 0; locTabNum < locNumTabs; ++locTabNum) cout << "\t";
3740 cout << "Combo_Horizontally_AddParticle: NUM SOURCE COMBOS CREATED: " << locSourceCombosByUseToSaveTo[locComboUseToCreate]->size() << endl;
3741 }
3742}
3743
3744/***************************************************************** PARTICLE UTILITY FUNCTIONS *****************************************************************/
3745
3746const vector<const JObject*>& DSourceComboer::Get_ParticlesForComboing(Particle_t locPID, ComboingStage_t locComboingStage, const vector<int>& locBeamBunches, signed char locVertexZBin)
3747{
3748 //find all particles that have an overlapping beam bunch with the input
3749
3750 //SPECIAL CASES FOR NEUTRALS:
3751 //massive neutral: all showers
3752 //unknown RF: All showers
3753 //unknown vertex, known RF: from each zbin, all showers that were valid for that rf bunch (already setup)
3754
3755 if(ParticleCharge(locPID) != 0) //charged tracks
3756 return dTracksByPID[locPID]; //rf bunch & vertex-z are irrelevant
3757 else if(locPID != Gamma) { //massive neutrals
3758 //return dShowersByBeamBunchByZBin[DSourceComboInfo::Get_VertexZIndex_Unknown()][{}]; //all neutrals: cannot do PID at all, and cannot do mass cuts until a specific vertex is chosen, so vertex-z doesn't matter
3759 // massive neutral particles could be any showers, so we keep a list which can have different selections applied
3760 return dNeutralHadronShowers;
3761 }
3762
3763 if(locComboingStage == d_MixedStage_ZIndependent) //fcal
3764 {
3765 locVertexZBin = DSourceComboInfo::Get_VertexZIndex_ZIndependent();
3766 auto locGroupBunchIterator = dShowersByBeamBunchByZBin[locVertexZBin].find(locBeamBunches);
3767 if(locGroupBunchIterator != dShowersByBeamBunchByZBin[locVertexZBin].end())
3768 return locGroupBunchIterator->second;
3769 return Get_ShowersByBeamBunch(locBeamBunches, dShowersByBeamBunchByZBin[locVertexZBin], locVertexZBin);
3770 }
3771
3772 if(locBeamBunches.empty())
3773 return dShowersByBeamBunchByZBin[DSourceComboInfo::Get_VertexZIndex_Unknown()][{}]; //all showers, regardless of vertex-z
3774
3775 auto locGroupBunchIterator = dShowersByBeamBunchByZBin[locVertexZBin].find(locBeamBunches);
3776 if(locGroupBunchIterator != dShowersByBeamBunchByZBin[locVertexZBin].end())
3777 return locGroupBunchIterator->second;
3778 return Get_ShowersByBeamBunch(locBeamBunches, dShowersByBeamBunchByZBin[locVertexZBin], locVertexZBin);
3779}
3780
3781const vector<const JObject*>& DSourceComboer::Get_ShowersByBeamBunch(const vector<int>& locBeamBunches, DPhotonShowersByBeamBunch& locShowersByBunch, signed char locVertexZBin)
3782{
3783 if(locBeamBunches.empty())
3784 return locShowersByBunch[{}];
3785
3786 //find all particles that have an overlapping beam bunch with the input
3787 //this won't happen often (max probably tens of times each event), so we can be a little inefficient
3788 vector<int> locBunchesSoFar = {*locBeamBunches.begin()};
3789 for(auto locBunchIterator = std::next(locBeamBunches.begin()); locBunchIterator != locBeamBunches.end(); ++locBunchIterator)
3790 {
3791 const auto& locComboShowers = locShowersByBunch[locBunchesSoFar];
3792 const auto& locBunchShowers = locShowersByBunch[{*locBunchIterator}];
3793
3794 locBunchesSoFar.push_back(*locBunchIterator);
3795 if(locShowersByBunch.find(locBunchesSoFar) != locShowersByBunch.end())
3796 continue; //this subset already created and indexed
3797
3798 if(locBunchShowers.empty())
3799 {
3800 locShowersByBunch.emplace(locBunchesSoFar, locComboShowers);
3801 Build_ParticleIndices(Gamma, locBeamBunches, locShowersByBunch[locBunchesSoFar], locVertexZBin);
3802 continue;
3803 }
3804
3805 //merge and move-emplace
3806 vector<const JObject*> locMergeResult;
3807 locMergeResult.reserve(locComboShowers.size() + locBunchShowers.size());
3808 std::set_union(locComboShowers.begin(), locComboShowers.end(), locBunchShowers.begin(), locBunchShowers.end(), std::back_inserter(locMergeResult));
3809 locShowersByBunch.emplace(locBunchesSoFar, std::move(locMergeResult));
3810 Build_ParticleIndices(Gamma, locBunchesSoFar, locShowersByBunch[locBunchesSoFar], locVertexZBin);
3811 }
3812 return locShowersByBunch[locBeamBunches];
3813}
3814
3815/******************************************************************* COMBO UTILITY FUNCTIONS ******************************************************************/
3816
3817void DSourceComboer::Register_ValidRFBunches(const DSourceComboUse& locSourceComboUse, const DSourceCombo* locSourceCombo, const vector<int>& locRFBunches, ComboingStage_t locComboingStage, const DSourceCombo* locChargedCombo_Presiding)
3818{
3819 //search and register
3820 auto locComboInfo = std::get<2>(locSourceComboUse);
3821 dValidRFBunches_ByCombo.emplace(std::make_pair(locSourceCombo, std::get<1>(locSourceComboUse)), locRFBunches);
3822
3823 //also, register for each individual bunch: so that we can get valid combos for some input rf bunches later
3824 if(locComboingStage != d_ChargedStage)
3825 {
3826 auto& locSourceCombosByBeamBunchByUse = Get_SourceCombosByBeamBunchByUse(dComboInfoChargeContent[locComboInfo], locChargedCombo_Presiding);
3827 auto& locCombosByBeamBunch = locSourceCombosByBeamBunchByUse[locSourceComboUse];
3828 for(const auto& locBeamBunch : locRFBunches)
3829 locCombosByBeamBunch[{locBeamBunch}].push_back(locSourceCombo);
3830 }
3831}
3832
3833void DSourceComboer::Build_ComboResumeIndices(const DSourceComboUse& locSourceComboUse, ComboingStage_t locComboingStage, const DSourceCombo* locChargedCombo_Presiding)
3834{
3835 auto locComboInfo = std::get<2>(locSourceComboUse);
3836
3837 auto& locComboVector = *(Get_CombosSoFar(locComboingStage, dComboInfoChargeContent[locComboInfo], locChargedCombo_Presiding)[locSourceComboUse]);
3838 std::sort(locComboVector.begin(), locComboVector.end());
3839 Build_ComboIndices(locSourceComboUse, {}, locComboVector, locComboingStage);
3840
3841 //register for each individual bunch: so that we can get valid combos for some input rf bunches later
3842 if(locComboingStage != d_ChargedStage)
3843 {
3844 auto& locSourceCombosByBeamBunchByUse = Get_SourceCombosByBeamBunchByUse(dComboInfoChargeContent[locComboInfo], locChargedCombo_Presiding);
3845 auto& locCombosByBeamBunch = locSourceCombosByBeamBunchByUse[locSourceComboUse];
3846 for(auto& locRFPair : locCombosByBeamBunch)
3847 {
3848 std::sort(locRFPair.second.begin(), locRFPair.second.end());
3849 Build_ComboIndices(locSourceComboUse, locRFPair.first, locRFPair.second, locComboingStage);
3850 }
3851 }
3852}
3853
3854const vector<const DSourceCombo*>& DSourceComboer::Get_CombosForComboing(const DSourceComboUse& locComboUse, ComboingStage_t locComboingStage, const vector<int>& locBeamBunches, const DSourceCombo* locChargedCombo_PresidingPrevious)
3855{
3856 if(dDebugLevel >= 20)
3857 {
3858 cout << "Get_CombosForComboing: stage, #bunches, charged combo, bunches " << locComboingStage << ", " << locBeamBunches.size() << ", " << locChargedCombo_PresidingPrevious << ", ";
3859 for(auto& locBunch : locBeamBunches)
3860 cout << locBunch << ", ";
3861 cout << endl;
3862 cout << "GET-COMBOS USE:" << endl;
3863 Print_SourceComboUse(locComboUse);
3864 }
3865
3866 //THE INPUT locChargedCombo MUST BE:
3867 //Whatever charged combo PREVIOUSLY presided when creating the combos you're trying to get
3868 //find all combos for the given use that have an overlapping beam bunch with the input
3869 auto locChargeContent = dComboInfoChargeContent[std::get<2>(locComboUse)];
3870 if(locBeamBunches.empty() || (locChargeContent == d_Charged)) //e.g. fully charged, or a combo of 2 KLongs (RF bunches not saved for massive neutrals)
3871 return *((Get_CombosSoFar(locComboingStage, locChargeContent, locChargedCombo_PresidingPrevious))[locComboUse]);
3872
3873 auto& locSourceCombosByBeamBunchByUse = Get_SourceCombosByBeamBunchByUse(locChargeContent, locChargedCombo_PresidingPrevious);
3874 auto locGroupBunchIterator = locSourceCombosByBeamBunchByUse[locComboUse].find(locBeamBunches);
3875 if(locGroupBunchIterator != locSourceCombosByBeamBunchByUse[locComboUse].end())
3876 return locGroupBunchIterator->second;
3877
3878 return Get_CombosByBeamBunch(locComboUse, locSourceCombosByBeamBunchByUse[locComboUse], locBeamBunches, locComboingStage);
3879}
3880
3881const vector<const DSourceCombo*>& DSourceComboer::Get_CombosByBeamBunch(const DSourceComboUse& locComboUse, DCombosByBeamBunch& locCombosByBunch, const vector<int>& locBeamBunches, ComboingStage_t locComboingStage)
3882{
3883 if(dDebugLevel >= 20)
3884 {
3885 cout << "Get_CombosByBeamBunch: stage, # bunches, bunches: " << locComboingStage << ", " << locBeamBunches.size() << ", ";
3886 for(auto& locBunch : locBeamBunches)
3887 cout << locBunch << ", ";
3888 cout << endl;
3889 }
3890 if(locBeamBunches.empty())
3891 {
3892 Build_ComboIndices(locComboUse, locBeamBunches, locCombosByBunch[locBeamBunches], locComboingStage);
3893 return locCombosByBunch[{}];
3894 }
3895
3896 //find all combos for the given use that have an overlapping beam bunch with the input
3897 //this shouldn't be called very many times per event, so we can be a little inefficient
3898 vector<int> locBunchesSoFar = {*locBeamBunches.begin()}; //0
3899 for(auto locBunchIterator = std::next(locBeamBunches.begin()); locBunchIterator != locBeamBunches.end(); ++locBunchIterator)
3900 {
3901 //get vectors and sort them: sort needed for union below
3902 auto& locCombosSoFar = locCombosByBunch[locBunchesSoFar]; //{0}
3903 auto& locBunchCombos = locCombosByBunch[{*locBunchIterator}]; //{1}
3904
3905 locBunchesSoFar.push_back(*locBunchIterator); //{0, 1}
3906 if(locCombosByBunch.find(locBunchesSoFar) != locCombosByBunch.end())
3907 continue; //this subset already created and indexed
3908
3909 if(locBunchCombos.empty())
3910 {
3911 locCombosByBunch.emplace(locBunchesSoFar, locCombosSoFar);
3912 Build_ComboIndices(locComboUse, locBeamBunches, locCombosByBunch[locBunchesSoFar], locComboingStage);
3913 continue;
3914 }
3915
3916 //merge and move-emplace
3917 vector<const DSourceCombo*> locMergeResult;
3918 locMergeResult.reserve(locCombosSoFar.size() + locBunchCombos.size());
3919 std::set_union(locCombosSoFar.begin(), locCombosSoFar.end(), locBunchCombos.begin(), locBunchCombos.end(), std::back_inserter(locMergeResult));
3920 locCombosByBunch.emplace(locBunchesSoFar, std::move(locMergeResult)); //when building for 0, 1, 2 this replaces 0,1
3921 Build_ComboIndices(locComboUse, locBunchesSoFar, locCombosByBunch[locBunchesSoFar], locComboingStage);
3922 }
3923
3924 return locCombosByBunch[locBeamBunches];
3925}
3926
3927void DSourceComboer::Copy_ZIndependentMixedResults(const DSourceComboUse& locComboUseToCreate, const DSourceCombo* locChargedCombo_Presiding)
3928{
3929 //Copy the results from the FCAL-only stage through to the both stage (that way we don't have to repeat them)
3930
3931 //THE INPUT locChargedCombo MUST BE:
3932 //Whatever charged combo you are about to combo horizontally with to make this new, mixed combo
3933
3934 //Get combos so far
3935 auto locChargeContent = dComboInfoChargeContent[std::get<2>(locComboUseToCreate)];
3936 auto& locSourceCombosByUseSoFar = Get_CombosSoFar(d_MixedStage_ZIndependent, locChargeContent, locChargedCombo_Presiding);
3937
3938 //Get FCAL results
3939 auto locComboUseFCAL = Get_ZIndependentUse(locComboUseToCreate);
3940 if(dDebugLevel >= 20)
3941 {
3942 cout << "FCAL USE: " << endl;
3943 Print_SourceComboUse(locComboUseFCAL);
3944 }
3945 if(locSourceCombosByUseSoFar.find(locComboUseFCAL) == locSourceCombosByUseSoFar.end())
3946 return; //no results to copy, just return
3947 const auto& locFCALComboVector = *(locSourceCombosByUseSoFar[locComboUseFCAL]);
3948 if(dDebugLevel >= 20)
3949 cout << "copying " << locFCALComboVector.size() << " from the fcal vector" << endl;
3950 if(locFCALComboVector.empty())
3951 return;
3952
3953 //Copy over the combos
3954 auto& locBothComboVector = *(locSourceCombosByUseSoFar[locComboUseToCreate]);
3955 locBothComboVector.reserve(locFCALComboVector.size() + dInitialComboVectorCapacity);
3956 locBothComboVector.assign(locFCALComboVector.begin(), locFCALComboVector.end());
3957
3958 //Copy over the combos-by-beam-bunch
3959 auto& locSourceCombosByBeamBunchByUse = Get_SourceCombosByBeamBunchByUse(locChargeContent, locChargedCombo_Presiding);
3960 const auto& locCombosByBeamBunch = locSourceCombosByBeamBunchByUse[locComboUseFCAL];
3961 for(const auto& locComboBeamBunchPair : locCombosByBeamBunch)
3962 {
3963 if(locComboBeamBunchPair.first.size() == 1) //don't copy the overlap ones: they are not complete & need to be filled on the fly
3964 locSourceCombosByBeamBunchByUse[locComboUseToCreate].emplace(locComboBeamBunchPair);
3965 }
3966}
3967
3968const DSourceCombo* DSourceComboer::Get_VertexPrimaryCombo(const DSourceCombo* locReactionCombo, const DReactionStepVertexInfo* locStepVertexInfo)
3969{
3970 //if it's the production vertex, just return the input
3971 if(locStepVertexInfo->Get_ProductionVertexFlag())
3972 return locReactionCombo;
3973
3974 //see if it's already been determined before: if so, just return it
3975 auto locCreationPair = std::make_pair(locReactionCombo, locStepVertexInfo);
3976 auto locIterator = dVertexPrimaryComboMap.find(locCreationPair);
3977 if(locIterator != dVertexPrimaryComboMap.end())
3978 return locIterator->second;
3979
3980 //find it
3981 auto locReaction = locStepVertexInfo->Get_Reaction();
3982 auto locDesiredStepIndex = locStepVertexInfo->Get_StepIndices().front();
3983 auto locVertexPrimaryCombo = Get_StepSourceCombo(locReaction, locDesiredStepIndex, locReactionCombo, 0);
3984
3985 //save it and return it
3986 dVertexPrimaryComboMap.emplace(locCreationPair, locVertexPrimaryCombo);
3987 return locVertexPrimaryCombo;
3988}
3989
3990const DSourceCombo* DSourceComboer::Get_VertexPrimaryCombo(const DSourceCombo* locReactionCombo, const DReactionStepVertexInfo* locStepVertexInfo) const
3991{
3992 //if it's the production vertex, just return the input
3993 if(locStepVertexInfo->Get_ProductionVertexFlag())
3994 return locReactionCombo;
3995
3996 //see if it's already been determined before: if so, just return it
3997 auto locCreationPair = std::make_pair(locReactionCombo, locStepVertexInfo);
3998 auto locIterator = dVertexPrimaryComboMap.find(locCreationPair);
3999 if(locIterator != dVertexPrimaryComboMap.end())
4000 return locIterator->second;
4001
4002 //find it
4003 auto locReaction = locStepVertexInfo->Get_Reaction();
4004 auto locDesiredStepIndex = locStepVertexInfo->Get_StepIndices().front();
4005 auto locVertexPrimaryCombo = Get_StepSourceCombo(locReaction, locDesiredStepIndex, locReactionCombo, 0);
4006
4007 //return it
4008 return locVertexPrimaryCombo;
4009}
4010
4011const DSourceCombo* DSourceComboer::Get_StepSourceCombo(const DReaction* locReaction, size_t locDesiredStepIndex, const DSourceCombo* locVertexPrimaryCombo, size_t locVertexPrimaryStepIndex) const
4012{
4013 if(dDebugLevel >= 100)
4014 cout << "reaction, desired step index, current step index: " << locReaction->Get_ReactionName() << ", " << locDesiredStepIndex << ", " << locVertexPrimaryStepIndex << endl;
4015 if(locDesiredStepIndex == locVertexPrimaryStepIndex)
4016 return locVertexPrimaryCombo;
4017
4018 //Get the list of steps we need to traverse //particle pair: step index, particle instance index
4019 vector<pair<size_t, int>> locParticleIndices = {std::make_pair(locDesiredStepIndex, DReactionStep::Get_ParticleIndex_Initial())};
4020 while(locParticleIndices.back().first != locVertexPrimaryStepIndex)
4021 {
4022 auto locParticlePair = DAnalysis::Get_InitialParticleDecayFromIndices(locReaction, locParticleIndices.back().first);
4023 if(dDebugLevel >= 100)
4024 cout << "decay from pair: " << locParticlePair.first << ", " << locParticlePair.second << endl;
4025 auto locStep = locReaction->Get_ReactionStep(locParticlePair.first);
4026 auto locInstanceIndex = DAnalysis::Get_ParticleInstanceIndex(locStep, locParticlePair.second);
4027 locParticleIndices.emplace_back(locParticlePair.first, locInstanceIndex);
4028 if(dDebugLevel >= 100)
4029 cout << "save indices: " << locParticlePair.first << ", " << locInstanceIndex << endl;
4030 }
4031
4032 //start from back of locParticleIndices, searching
4033 while(true)
4034 {
4035 auto locNextStep = locParticleIndices[locParticleIndices.size() - 2].first;
4036 auto locInstanceIndexToFind = locParticleIndices.back().second;
4037 const auto& locUseToFind = dSourceComboUseReactionStepMap.find(locReaction)->second.find(locNextStep)->second;
4038 if(dDebugLevel >= 100)
4039 cout << "next step, instance to find, use to find: " << locNextStep << ", " << locInstanceIndexToFind << endl;
4040 if(dDebugLevel >= 100)
4041 Print_SourceComboUse(locUseToFind);
4042 locVertexPrimaryCombo = Find_Combo_AtThisStep(locVertexPrimaryCombo, locUseToFind, locInstanceIndexToFind);
4043 if(dDebugLevel >= 100)
4044 cout << "pointer = " << locVertexPrimaryCombo << endl;
4045 if(locVertexPrimaryCombo == nullptr)
4046 return nullptr; //e.g. entirely neutral step when input is charged
4047 if(locNextStep == locDesiredStepIndex)
4048 return locVertexPrimaryCombo;
4049 locParticleIndices.pop_back();
4050 }
4051
4052 return nullptr;
4053}
4054
4055const DSourceCombo* DSourceComboer::Find_Combo_AtThisStep(const DSourceCombo* locSourceCombo, DSourceComboUse locUseToFind, size_t locDecayInstanceIndex) const
4056{
4057 //ignores z-bin when comparing
4058 //if z-dependent, go to z-independent use
4059 if(std::get<1>(locUseToFind) != DSourceComboInfo::Get_VertexZIndex_ZIndependent())
4060 locUseToFind = dZDependentUseToIndependentMap.find(locUseToFind)->second;
4061 if(dDebugLevel >= 100)
4062 {
4063 cout << "Find_Combo_AtThisStep: USE TO FIND:" << endl;
4064 DAnalysis::Print_SourceComboUse(locUseToFind);
4065 }
4066 for(const auto& locDecayPair : locSourceCombo->Get_FurtherDecayCombos())
4067 {
4068 //if z-dependent, go to z-independent
4069 auto locDecayUse = locDecayPair.first;
4070 if(std::get<1>(locDecayUse) != DSourceComboInfo::Get_VertexZIndex_ZIndependent())
4071 locDecayUse = dZDependentUseToIndependentMap.find(locDecayUse)->second;
4072 if(dDebugLevel >= 100)
4073 {
4074 cout << "USE TO CHECK:" << endl;
4075 DAnalysis::Print_SourceComboUse(locDecayUse);
4076 }
4077
4078 if(locDecayUse == locUseToFind) //good, do stuff
4079 return locDecayPair.second[locDecayInstanceIndex];
4080 if(std::get<0>(locDecayUse) != Unknown)
4081 continue; //is another step!
4082
4083 //vector of combos is guaranteed to be size 1, and it's guaranteed that none of ITS further decays are unknown
4084 auto locComboToSearch = locDecayPair.second[0];
4085 if(dDebugLevel >= 100)
4086 cout << "#to-check decay uses: " << locComboToSearch->Get_FurtherDecayCombos().size() << endl;
4087 for(const auto& locNestedDecayPair : locComboToSearch->Get_FurtherDecayCombos())
4088 {
4089 //if z-dependent, go to z-independent
4090 auto locNestedDecayUse = locNestedDecayPair.first;
4091 if(std::get<1>(locNestedDecayUse) != DSourceComboInfo::Get_VertexZIndex_ZIndependent())
4092 locNestedDecayUse = dZDependentUseToIndependentMap.find(locNestedDecayUse)->second;
4093 if(dDebugLevel >= 100)
4094 {
4095 cout << "NESTED USE TO CHECK:" << endl;
4096 DAnalysis::Print_SourceComboUse(locNestedDecayUse);
4097 }
4098 if(locNestedDecayUse == locUseToFind) //good, do stuff
4099 return locNestedDecayPair.second[locDecayInstanceIndex];
4100 }
4101 }
4102
4103 //Not found: Either invalid request, OR the input is a fully-charged combo being used for a Use that contains neutrals (created during charged-only stage): Return the input, it is already what you want
4104 return locSourceCombo;
4105}
4106
4107pair<DSourceComboUse, size_t> DSourceComboer::Get_StepSourceComboUse(const DReaction* locReaction, size_t locDesiredStepIndex, DSourceComboUse locVertexPrimaryComboUse, size_t locVertexPrimaryStepIndex) const
4108{
4109 //size_t: combo instance
4110 if(dDebugLevel >= 100)
4111 cout << "reaction, desired step index, current step index: " << locReaction->Get_ReactionName() << ", " << locDesiredStepIndex << ", " << locVertexPrimaryStepIndex << endl;
4112 if(locDesiredStepIndex == locVertexPrimaryStepIndex)
4113 return std::make_pair(locVertexPrimaryComboUse, size_t(1));
4114
4115 //Get the list of steps we need to traverse //particle pair: step index, particle instance index
4116 vector<pair<size_t, int>> locParticleIndices = {std::make_pair(locDesiredStepIndex, DReactionStep::Get_ParticleIndex_Initial())};
4117 while(locParticleIndices.back().first != locVertexPrimaryStepIndex)
4118 {
4119 auto locParticlePair = DAnalysis::Get_InitialParticleDecayFromIndices(locReaction, locParticleIndices.back().first);
4120 if(dDebugLevel >= 100)
4121 cout << "decay from pair: " << locParticlePair.first << ", " << locParticlePair.second << endl;
4122 auto locStep = locReaction->Get_ReactionStep(locParticlePair.first);
4123 auto locInstanceIndex = DAnalysis::Get_ParticleInstanceIndex(locStep, locParticlePair.second);
4124 locParticleIndices.emplace_back(locParticlePair.first, locInstanceIndex);
4125 if(dDebugLevel >= 100)
4126 cout << "save indices: " << locParticlePair.first << ", " << locInstanceIndex << endl;
4127 }
4128
4129 //start from back of locParticleIndices, searching
4130 while(true)
4131 {
4132 auto locNextStep = locParticleIndices[locParticleIndices.size() - 2].first;
4133 auto locInstanceIndexToFind = locParticleIndices.back().second;
4134 const auto& locUseToFind = dSourceComboUseReactionStepMap.find(locReaction)->second.find(locNextStep)->second;
4135 if(dDebugLevel >= 100)
4136 cout << "next step, instance to find, use to find: " << locNextStep << ", " << locInstanceIndexToFind << endl;
4137 if(dDebugLevel >= 100)
4138 Print_SourceComboUse(locUseToFind);
4139 locVertexPrimaryComboUse = Find_ZDependentUse_AtThisStep(locVertexPrimaryComboUse, locUseToFind, locInstanceIndexToFind);
4140 if(std::get<2>(locVertexPrimaryComboUse) == nullptr)
4141 return std::make_pair(locVertexPrimaryComboUse, size_t(locInstanceIndexToFind + 1)); //e.g. entirely neutral step when input is charged
4142 if(locNextStep == locDesiredStepIndex)
4143 return std::make_pair(locVertexPrimaryComboUse, size_t(locInstanceIndexToFind + 1));
4144 locParticleIndices.pop_back();
4145 }
4146 return std::make_pair(DSourceComboUse(Unknown, 0, nullptr, 0, Unknown), size_t(1));
4147}
4148
4149DSourceComboUse DSourceComboer::Find_ZDependentUse_AtThisStep(const DSourceComboUse& locSourceComboUse, DSourceComboUse locUseToFind, size_t locDecayInstanceIndex) const
4150{
4151 //ignores z-bin when comparing
4152 //if z-dependent, go to z-independent use
4153 if(std::get<1>(locUseToFind) != DSourceComboInfo::Get_VertexZIndex_ZIndependent())
4154 locUseToFind = dZDependentUseToIndependentMap.find(locUseToFind)->second;
4155 if(dDebugLevel >= 100)
4156 {
4157 cout << "Find_Combo_AtThisStep: USE TO FIND:" << endl;
4158 DAnalysis::Print_SourceComboUse(locUseToFind);
4159 }
4160 for(const auto& locDecayPair : std::get<2>(locSourceComboUse)->Get_FurtherDecays())
4161 {
4162 //if z-dependent, go to z-independent
4163 auto locDecayUse = locDecayPair.first;
4164 auto locZIndependentDecayUse = locDecayUse;
4165 if(std::get<1>(locDecayUse) != DSourceComboInfo::Get_VertexZIndex_ZIndependent())
4166 locZIndependentDecayUse = dZDependentUseToIndependentMap.find(locDecayUse)->second;
4167 if(dDebugLevel >= 100)
4168 {
4169 cout << "USE TO CHECK:" << endl;
4170 DAnalysis::Print_SourceComboUse(locDecayUse);
4171 }
4172
4173 if(locZIndependentDecayUse == locUseToFind) //good, do stuff
4174 return locDecayUse;
4175 if(std::get<0>(locDecayUse) != Unknown)
4176 continue; //is another step!
4177
4178 //check other uses at this step (further depth guaranteed to be only 1)
4179 if(dDebugLevel >= 100)
4180 cout << "#to-check decay uses: " << std::get<2>(locDecayUse)->Get_FurtherDecays().size() << endl;
4181 for(const auto& locNestedDecayPair : std::get<2>(locDecayUse)->Get_FurtherDecays())
4182 {
4183 //if z-dependent, go to z-independent
4184 auto locNestedDecayUse = locNestedDecayPair.first;
4185 auto locZIndependentNestedDecayUse = locNestedDecayUse;
4186 if(std::get<1>(locNestedDecayUse) != DSourceComboInfo::Get_VertexZIndex_ZIndependent())
4187 locZIndependentNestedDecayUse = dZDependentUseToIndependentMap.find(locNestedDecayUse)->second;
4188 if(dDebugLevel >= 100)
4189 {
4190 cout << "NESTED USE TO CHECK:" << endl;
4191 DAnalysis::Print_SourceComboUse(locZIndependentNestedDecayUse);
4192 }
4193 if(locZIndependentNestedDecayUse == locUseToFind) //good, do stuff
4194 return locNestedDecayUse;
4195 }
4196 }
4197
4198 //Not found: Either invalid request, OR the input is a fully-charged combo being used for a Use that contains neutrals (created during charged-only stage): Return the input, it is already what you want
4199 return DSourceComboUse(Unknown, 0, nullptr, 0, Unknown);
4200}
4201/*
4202 * For K0, Sigma+, p the full combos will be:
4203 * 0: X -> A, 1, 3 (mixed -> charged, mixed, mixed)
4204 * A: X -> p (charged)
4205 * 1: K0 -> B, 2 (mixed -> charged, neutral)
4206 * B: X -> pi+, pi- (charged)
4207 * 2: pi0 -> 2g (neutral)
4208 * 3: Sigma+ -> C, n (mixed -> charged, n)
4209 * C: X -> pi+ (charged)
4210 *
4211 * For XXX, the charged combos will be:
4212 * 0: X -> A, B, C
4213 * A: X -> p
4214 * B: X -> pi+, pi-
4215 * C: X -> pi+
4216 *
4217 * For XXX, the presiding/withnow combos will be:
4218 * 0: X -> A, 1, 3 (mixed -> charged, mixed, mixed) //presiding = 0, withnow = A
4219 * A: X -> p (charged) //both = nullptr
4220 * 1: K0 -> B, 2 (mixed -> charged, neutral) //presiding = 0, withnow = B
4221 * B: X -> pi+, pi- (charged) //both = nullptr
4222 * 2: pi0 -> 2g (neutral) //both = nullptr
4223 * 3: Sigma+ -> C, n (mixed -> charged, n) //presiding = 0, withnow = C
4224 * C: X -> pi+ (charged) //both = nullptr
4225 *
4226*/
4227
4228const DSourceCombo* DSourceComboer::Get_ChargedCombo_WithNow(const DSourceCombo* locChargedCombo_Presiding, const DSourceComboInfo* locToCreateComboInfo, ComboingStage_t locComboingStage) const
4229{
4230 if(locChargedCombo_Presiding == nullptr)
4231 return nullptr;
4232
4233 //find the charged use what use we want
4234 DSourceComboUse locWithNowComboUse{Unknown, 0, nullptr, false, Unknown};
4235 for(const auto& locDecayComboPair : locToCreateComboInfo->Get_FurtherDecays())
4236 {
4237 if(Get_ChargeContent(std::get<2>(locDecayComboPair.first)) != d_Charged)
4238 continue;
4239 locWithNowComboUse = locDecayComboPair.first;
4240 break;
4241 }
4242
4243 if(std::get<2>(locWithNowComboUse) == nullptr)
4244 {
4245 if(dDebugLevel >= 20)
4246 cout << "CHARGED COMBO WITH NOW: Same as presiding." << endl;
4247 return locChargedCombo_Presiding; //the info we are trying to create will use the presiding itself
4248 }
4249 return Get_NextChargedCombo(locChargedCombo_Presiding, locWithNowComboUse, locComboingStage, false, 0);
4250}
4251
4252const DSourceCombo* DSourceComboer::Get_NextChargedCombo(const DSourceCombo* locChargedCombo_Presiding, const DSourceComboUse& locNextComboUse, ComboingStage_t locComboingStage, bool locGetPresidingFlag, size_t locInstance) const
4253{
4254 //locInstance starts from ONE!! (and is not used if locGetPresidingFlag = false (getting withnow))
4255 if(locComboingStage == d_ChargedStage)
4256 return nullptr;
4257 if(locChargedCombo_Presiding == nullptr)
4258 return nullptr;
4259 if(Get_ChargeContent(std::get<2>(locNextComboUse)) == d_Neutral)
4260 return nullptr; //not needed
4261
4262 auto locFurtherDecayCombos = locChargedCombo_Presiding->Get_FurtherDecayCombos();
4263
4264 auto locUseToFind = (locComboingStage == d_MixedStage_ZIndependent) ? locNextComboUse : dZDependentUseToIndependentMap.find(locNextComboUse)->second;
4265 auto locIteratorPair = std::equal_range(locFurtherDecayCombos.begin(), locFurtherDecayCombos.end(), locUseToFind, DSourceCombo::DCompare_FurtherDecays());
4266
4267 if(dDebugLevel >= 20)
4268 {
4269 cout << "Get_NextChargedCombo: get-presiding-flag, instance, stage, find result, use-to-find: " << locGetPresidingFlag << ", " << locInstance << ", " << locComboingStage << ", " << (locIteratorPair.first != locIteratorPair.second) << endl;
4270 DAnalysis::Print_SourceComboUse(locUseToFind);
4271 cout << "Presiding combo:" << endl;
4272 DAnalysis::Print_SourceCombo(locChargedCombo_Presiding);
4273 }
4274
4275 //check if the use you are looking for is a temporary (e.g. vertical grouping of 2KShorts when comboing horizontally)
4276 //or if the charged combos were supposed to be comboed with neutrals, but were instead promoted: no intermediary charged combo, just retuern current
4277 if(locIteratorPair.first == locIteratorPair.second)
4278 return locChargedCombo_Presiding; //temporary: the presiding is still the same!
4279
4280 //get the vector of potential charged combos
4281 auto locNextChargedComboVector = (*locIteratorPair.first).second;
4282 if(dDebugLevel >= 20)
4283 cout << "next charged combo vector size: = " << locNextChargedComboVector.size() << endl;
4284
4285 //if getting with-now, size is guaranteed to be 1, just get the first one
4286 if(!locGetPresidingFlag)
4287 {
4288 if(dDebugLevel >= 20)
4289 {
4290 cout << "CHARGED COMBO WITH NOW:" << endl;
4291 Print_SourceCombo(locNextChargedComboVector[0]);
4292 }
4293 return locNextChargedComboVector[0];
4294 }
4295
4296 //if on z-independent, don't need to do anything fancy, just return the requested instance
4297 if(locComboingStage == d_MixedStage_ZIndependent)
4298 return locNextChargedComboVector[locInstance - 1];
4299
4300 //there might be multiple combos (e.g. K0 decays), each at a different vertex-z
4301 //so, we must retrieve the N'th charged combo with the correct vertex-z bin
4302 size_t locCount = 0;
4303 auto locDesiredVertexZBin = std::get<1>(locNextComboUse);
4304 for(const auto& locNextPotentialCombo : locNextChargedComboVector)
4305 {
4306 //either locNextPotentialCombo is the primary combo of a detached vertex (and we need to check the zbin), or it's not (returns -1) and we don't
4307 if(IsDetachedVertex(std::get<0>(locUseToFind)))
4308 {
4309 auto locVertexChargeContent = DAnalysis::Get_ChargeContent_ThisVertex(std::get<2>(locUseToFind));
4310 auto locIsCombo2ndVertex = (locVertexChargeContent == d_Neutral);
4311 auto locIsVertexKnown = dSourceComboVertexer->Get_IsVertexKnown_NoBeam(false, locNextPotentialCombo, locIsCombo2ndVertex);
4312 auto locNextVertexZBin = dSourceComboVertexer->Get_VertexZBin_NoBeam(false, locNextPotentialCombo, locIsCombo2ndVertex); //defaults to center of target if not known
4313
4314 if(dDebugLevel >= 20)
4315 cout << "detached next potential combo, next zbin, desired zbin = " << locNextPotentialCombo << ", " << int(locNextVertexZBin) << ", " << int(locDesiredVertexZBin) << endl;
4316 //if desired = independent we don't care, or if unknown we don't need to check
4317 if(locIsVertexKnown && (locNextVertexZBin != locDesiredVertexZBin) && (locDesiredVertexZBin != DSourceComboInfo::Get_VertexZIndex_ZIndependent()))
4318 continue;
4319 }
4320 if(dDebugLevel >= 20)
4321 cout << "pre-count, instance = " << locCount << ", " << locInstance << endl;
4322 if(++locCount == locInstance)
4323 return locNextPotentialCombo;
4324 }
4325
4326 if(dDebugLevel >= 20)
4327 cout << "uh oh" << endl;
4328 return nullptr; //uh oh ...
4329}
4330
4331bool DSourceComboer::Get_PromoteFlag(ComboingStage_t locComboingStage, Particle_t locDecayPID_UseToCheck, const DSourceComboInfo* locComboInfo_UseToCreate, const DSourceComboInfo* locComboInfo_UseToCheck, DSourceComboUse& locNonNeutralUse) const
4332{
4333 locNonNeutralUse = DSourceComboUse{Unknown, 0, nullptr, false, Unknown};
4334 if(locDecayPID_UseToCheck != Unknown)
4335 return false;
4336
4337 auto locFurtherDecayInfo_UseToCheck = locComboInfo_UseToCheck->Get_FurtherDecays();
4338
4339 //don't promote if is mixed and merely contains a promoted charged combo
4340 if((locComboingStage == d_ChargedStage) && (Get_ChargeContent(locComboInfo_UseToCheck) == d_AllCharges))
4341 {
4342 size_t locNumNeutralUses = locComboInfo_UseToCheck->Get_NumParticles().size();
4343 size_t locNumNonNeutralUses = 0;
4344 for(auto& locAllBut1DecayPair : locFurtherDecayInfo_UseToCheck)
4345 {
4346 if(Get_ChargeContent(std::get<2>(locAllBut1DecayPair.first)) == d_Neutral)
4347 ++locNumNeutralUses;
4348 else
4349 {
4350 ++locNumNonNeutralUses;
4351 locNonNeutralUse = locAllBut1DecayPair.first;
4352 }
4353 }
4354 if((locNumNeutralUses >= 1) && (locNumNonNeutralUses == 1))
4355 return false; //merely a promoted charged combo
4356 locNonNeutralUse = DSourceComboUse{Unknown, 0, nullptr, false, Unknown}; //reset in case > 1
4357 }
4358
4359//we must: ungroup all-but-1 use: save the existing combo under the charged/mixed use & ditch the neutral decay uses
4360//in this case: it becomes a no-promote, but a different use
4361
4362 if(!locFurtherDecayInfo_UseToCheck.empty())
4363 {
4364 auto locFurtherDecayInfo_UseToCreate = locComboInfo_UseToCreate->Get_FurtherDecays();
4365 return std::binary_search(locFurtherDecayInfo_UseToCreate.begin(), locFurtherDecayInfo_UseToCreate.end(), locFurtherDecayInfo_UseToCheck.front(), DSourceComboInfo::DCompare_FurtherDecays());
4366 }
4367 else
4368 {
4369 auto locNumParticles_ToAdd = locComboInfo_UseToCheck->Get_NumParticles();
4370 auto locNumParticles_UseToCreate = locComboInfo_UseToCreate->Get_NumParticles();
4371 return std::binary_search(locNumParticles_UseToCreate.begin(), locNumParticles_UseToCreate.end(), locNumParticles_ToAdd.front(), DSourceComboInfo::DCompare_ParticlePairPIDs());
4372 }
4373}
4374
4375bool DSourceComboer::Check_Reactions(vector<const DReaction*>& locReactions)
4376{
4377 //All of the reactions in the vertex-info are guaranteed to have the same channel content
4378 //They just may differ in actions, or skims
4379 //So, we can check #particles for just one reaction, but must check skims for all reactions
4380 if(!Check_NumParticles(locReactions.front()))
4381 {
4382 if(dDebugLevel > 0)
4383 cout << "Not enough particles: No combos." << endl;
4384 return false;
4385 }
4386 for(auto& locReaction : locReactions)
4387 dNumCombosSurvivedStageTracker[locReaction][DConstructionStage::Min_Particles] = 1; //is really #-events
4388
4389 //Check Max neutrals
4390 auto locNumNeutralNeeded = locReactions.front()->Get_FinalPIDs(-1, false, false, d_Neutral, true).size(); //no missing, no decaying, include duplicates
4391 auto locNumDetectedShowers = dShowersByBeamBunchByZBin[DSourceComboInfo::Get_VertexZIndex_Unknown()][{}].size();
4392 if((locNumNeutralNeeded > 0) && (locNumDetectedShowers > dMaxNumNeutrals))
4393 {
4394 if(dDebugLevel > 0)
4395 cout << "Too many neutrals: No combos." << endl;
4396 return false;
4397 }
4398 //Check additional showers
4399 auto NumShower_Checker = [&](const DReaction* locReaction) -> bool
4400 {
4401 auto locCutPair = locReaction->Get_MaxExtraShowers();
4402 if(!locCutPair.first)
4403 return false;
4404 return ((locNumDetectedShowers - locNumNeutralNeeded) > locCutPair.second);
4405 };
4406 locReactions.erase(std::remove_if(locReactions.begin(), locReactions.end(), NumShower_Checker), locReactions.end());
4407 if(locReactions.empty())
4408 {
4409 if(dDebugLevel > 0)
4410 cout << "Too many showers (" << locNumDetectedShowers << "): No combos." << endl;
4411 return false;
4412 }
4413
4414 //Check Max charged tracks
4415 auto locNumTracksNeeded = locReactions.front()->Get_FinalPIDs(-1, false, false, d_Charged, true).size(); //no missing, no decaying, include duplicates
4416 auto NumExtra_Checker = [&](const DReaction* locReaction) -> bool
4417 {
4418 auto locCutPair = locReaction->Get_MaxExtraGoodTracks();
4419 if(!locCutPair.first)
4420 return false;
4421 return ((dNumChargedTracks - locNumTracksNeeded) > locCutPair.second);
4422 };
4423 locReactions.erase(std::remove_if(locReactions.begin(), locReactions.end(), NumExtra_Checker), locReactions.end());
4424 if(locReactions.empty())
4425 {
4426 if(dDebugLevel > 0)
4427 cout << "Too many tracks (" << dNumChargedTracks << "): No combos." << endl;
4428 return false;
4429 }
4430 for(auto& locReaction : locReactions)
4431 dNumCombosSurvivedStageTracker[locReaction][DConstructionStage::Max_Particles] = 1; //is really #-events
4432
4433 //Check skims
4434 auto Skim_Checker = [this](const DReaction* locReaction) -> bool{return !Check_Skims(locReaction);};
4435 locReactions.erase(std::remove_if(locReactions.begin(), locReactions.end(), Skim_Checker), locReactions.end());
4436 if(locReactions.empty())
4437 {
4438 if(dDebugLevel > 0)
4439 cout << "Event not in skim: No combos." << endl;
4440 return false;
4441 }
4442 for(auto& locReaction : locReactions)
4443 dNumCombosSurvivedStageTracker[locReaction][DConstructionStage::In_Skim] = 1; //is really #-events
4444
4445 return true;
4446}
4447
4448bool DSourceComboer::Check_NumParticles(const DReaction* locReaction)
4449{
4450 if(dDebugLevel > 0)
4451 cout << "Checking #particles" << endl;
4452
4453 //see if enough particles were detected to build this reaction
4454 auto locReactionPIDs = locReaction->Get_FinalPIDs(-1, false, false, d_AllCharges, true); //no missing, no decaying, include duplicates
4455 auto locPIDMap = DAnalysis::Convert_VectorToCountMap<Particle_t>(locReactionPIDs);
4456 size_t locNumPositiveNeeded = 0, locNumNegativeNeeded = 0, locNumNeutralNeeded = 0;
4457 for(const auto& locPIDPair : locPIDMap)
4458 {
4459 if(ParticleCharge(locPIDPair.first) > 0)
4460 locNumPositiveNeeded += locPIDPair.second;
4461 else if(ParticleCharge(locPIDPair.first) < 0)
4462 locNumNegativeNeeded += locPIDPair.second;
4463 else
4464 locNumNeutralNeeded += locPIDPair.second;
4465 }
4466 auto locNumDetectedShowers = dShowersByBeamBunchByZBin[DSourceComboInfo::Get_VertexZIndex_Unknown()][{}].size();
4467
4468 //check by charge
4469 if(dDebugLevel > 0)
4470 cout << "q+: Need " << locNumPositiveNeeded << ", Have " << dTracksByCharge[true].size() << endl;
4471 if(dTracksByCharge[true].size() < locNumPositiveNeeded)
4472 return false;
4473 if(dDebugLevel > 0)
4474 cout << "q-: Need " << locNumNegativeNeeded << ", Have " << dTracksByCharge[false].size() << endl;
4475 if(dTracksByCharge[false].size() < locNumNegativeNeeded)
4476 return false;
4477 if(dDebugLevel > 0)
4478 cout << "q+/-: Need " << locNumNegativeNeeded + locNumPositiveNeeded << ", Have " << dNumChargedTracks << endl;
4479 if(dNumChargedTracks < (locNumNegativeNeeded + locNumPositiveNeeded))
4480 return false;
4481 if(dDebugLevel > 0)
4482 cout << "q0: Need " << locNumNeutralNeeded << ", Have " << locNumDetectedShowers << ", Max allowed: " << dMaxNumNeutrals << endl;
4483 if(locNumDetectedShowers < locNumNeutralNeeded)
4484 return false;
4485
4486 for(const auto& locPIDPair : locPIDMap)
4487 {
4488 auto locNumParticlesForComboing = Get_ParticlesForComboing(locPIDPair.first, d_MixedStage).size();
4489 if(dDebugLevel > 0)
4490 cout << ParticleType(locPIDPair.first) << ": Need " << locPIDPair.second << ", Have " << locNumParticlesForComboing << endl;
4491 if(locNumParticlesForComboing < locPIDPair.second)
4492 return false;
4493 if(locPIDPair.first != Gamma)
4494 continue;
4495
4496 //check if these photons can even at least agree on a beam bunch, regardless of vertex position
4497 size_t locMaxNumPhotonsSameBunch = 0;
4498 for(const auto& locZBinPair : dShowersByBeamBunchByZBin) //loop over z-bins
4499 {
4500 for(const auto& locBunchPair : locZBinPair.second) //loop over bunches
4501 {
4502 if(locBunchPair.first.empty())
4503 continue;
4504 if(locBunchPair.second.size() > locMaxNumPhotonsSameBunch)
4505 locMaxNumPhotonsSameBunch = locBunchPair.second.size();
4506 }
4507 }
4508 if(dDebugLevel > 0)
4509 cout << ParticleType(locPIDPair.first) << ": Need " << locPIDPair.second << ", Have at most " << locMaxNumPhotonsSameBunch << " that agree on any beam bunch." << endl;
4510 if(locMaxNumPhotonsSameBunch < locPIDPair.second)
4511 return false;
4512 }
4513 return true;
4514}
4515
4516void DSourceComboer::Print_NumCombosByUse(void)
4517{
4518 cout << "Num combos by use (charged):" << endl;
4519 for(const auto& locCombosByUsePair : dSourceCombosByUse_Charged)
4520 {
4521 cout << locCombosByUsePair.second->size() << " of ";
4522 Print_SourceComboUse(locCombosByUsePair.first);
4523
4524 //save
4525 auto locIterator = dNumMixedCombosMap_Charged.find(locCombosByUsePair.first);
4526 if(locIterator == dNumMixedCombosMap_Charged.end())
4527 dNumMixedCombosMap_Charged.emplace(locCombosByUsePair.first, locCombosByUsePair.second->size());
4528 else
4529 locIterator->second += locCombosByUsePair.second->size();
4530 }
4531
4532 //get #mixed by use (must merge results for different charged combos)
4533 map<DSourceComboUse, size_t> locNumMixedCombosMap;
4534 for(const auto& locChargedComboPair : dMixedCombosByUseByChargedCombo)
4535 {
4536 const auto& locCombosByUseMap = locChargedComboPair.second;
4537 for(const auto& locCombosByUsePair : locCombosByUseMap)
4538 {
4539 auto locIterator = locNumMixedCombosMap.find(locCombosByUsePair.first);
4540 if(locIterator == locNumMixedCombosMap.end())
4541 locNumMixedCombosMap.emplace(locCombosByUsePair.first, locCombosByUsePair.second->size());
4542 else
4543 locIterator->second += locCombosByUsePair.second->size();
4544 }
4545 }
4546
4547 cout << "Num combos by use (neutral/mixed):" << endl;
4548 for(const auto& locNumCombosByUsePair : locNumMixedCombosMap)
4549 {
4550 cout << locNumCombosByUsePair.second << " of ";
4551 Print_SourceComboUse(locNumCombosByUsePair.first);
4552
4553 //save
4554 auto locIterator = dNumMixedCombosMap_Mixed.find(locNumCombosByUsePair.first);
4555 if(locIterator == dNumMixedCombosMap_Mixed.end())
4556 dNumMixedCombosMap_Mixed.emplace(locNumCombosByUsePair.first, locNumCombosByUsePair.second);
4557 else
4558 locIterator->second += locNumCombosByUsePair.second;
4559 }
4560}
4561
4562void DSourceComboer::Check_ForDuplicates(const vector<const DSourceCombo*>& locCombos) const
4563{
4564 //Check for dupes & reuses!
4565 if(std::any_of(locCombos.begin(), locCombos.end(), DSourceComboChecker_ReusedParticle()))
4566 {
4567 cout << "Re-used particles, event = " << dEventNumber << ". Aborting!" << endl;
4568 abort();
4569 }
4570 for(size_t loc_i = 0; loc_i < locCombos.size(); ++loc_i)
4571 {
4572 for(size_t loc_j = loc_i + 1; loc_j < locCombos.size(); ++loc_j)
4573 {
4574 if(!DAnalysis::Check_AreDuplicateCombos(locCombos[loc_i], locCombos[loc_j]))
4575 continue;
4576 cout << "Duplicate particles, event = " << dEventNumber << ". Aborting!" << endl;
4577 cout << "DUPE COMBO 1:" << endl;
4578 Print_SourceCombo(locCombos[loc_i]);
4579 cout << "DUPE COMBO 2:" << endl;
4580 Print_SourceCombo(locCombos[loc_j]);
4581 abort();
4582 }
4583 }
4584}
4585
4586} //end DAnalysis namespace

libraries/ANALYSIS/DSourceComboer.h

1#ifndef DSourceComboer_h
2#define DSourceComboer_h
3
4#include <map>
5#include <set>
6#include <vector>
7#include <memory>
8#include <unordered_map>
9#include <unordered_set>
10#include <cmath>
11#include <algorithm>
12#include <stack>
13
14#include "TF1.h"
15
16#include "JANA/JObject.h"
17#include "JANA/JEventLoop.h"
18
19#include "particleType.h"
20#include "SplitString.h"
21#include "DANA/DApplication.h"
22#include "HDGEOMETRY/DGeometry.h"
23#include "EVENTSTORE/DESSkimData.h"
24
25#include "PID/DNeutralShower.h"
26#include "PID/DKinematicData.h"
27#include "PID/DEventRFBunch.h"
28
29#include "ANALYSIS/DReaction.h"
30#include "ANALYSIS/DSourceCombo.h"
31#include "ANALYSIS/DReactionStepVertexInfo.h"
32#include "ANALYSIS/DReactionVertexInfo.h"
33#include "DResourcePool.h"
34
35#include "ANALYSIS/DSourceComboVertexer.h"
36#include "ANALYSIS/DSourceComboP4Handler.h"
37#include "ANALYSIS/DSourceComboTimeHandler.h"
38#include "ANALYSIS/DParticleComboCreator.h"
39
40
41#include "PID/DNeutralParticleHypothesis.h"
42
43
44using namespace std;
45using namespace jana;
46
47namespace DAnalysis
48{
49
50/****************************************************** DEFINE LAMBDAS, USING STATEMENTS *******************************************************/
51
52struct DCompare_SourceComboInfos{
53 bool operator()(const DSourceComboInfo* lhs, const DSourceComboInfo* rhs) const{return *lhs < *rhs;}
54};
55
56/********************************************************** DEFINE USING STATEMENTS ***********************************************************/
57
58//DEFINE USING STATEMENTS
59using DCombosByBeamBunch = map<vector<int>, vector<const DSourceCombo*>>;
60using DSourceCombosByBeamBunchByUse = map<DSourceComboUse, DCombosByBeamBunch>;
61//The DSourceCombosByUse_Large type uses a vector to pointer so that the combos can be easily copied and reused for another use
62//e.g. when you can't place a mass cut yet: 2 different uses, identical combos: far faster to just copy the pointer to the large vector
63using DSourceCombosByUse_Large = map<DSourceComboUse, vector<const DSourceCombo*>*>;
64using DCombosByReaction = unordered_map<const DReaction*, vector<const DParticleCombo*>>;
65
66/************************************************************** DEFINE CLASSES ***************************************************************/
67
68class DSourceComboer : public JObject
69{
70 enum ComboingStage_t
71 {
72 d_ChargedStage = 0,
73 d_MixedStage_ZIndependent,
74 d_MixedStage
75 };
76
77 enum class DConstructionStage
78 {
79 Input = 0,
80 Min_Particles,
81 Max_Particles,
82 In_Skim,
83 Charged_Combos,
84 Charged_RFBunch,
85 Full_Combos,
86 Neutral_RFBunch,
87 NoVertex_RFBunch,
88 HeavyNeutral_IM,
89 Beam_Combos,
90 MMVertex_Timing,
91 MMVertex_IMCuts,
92 AccuratePhoton_IM,
93 Reaction_BeamRFCuts,
94 Missing_Mass
95 };
96
97 using DConstructionStageType = std::underlying_type<DConstructionStage>::type;
98
99 public:
100
101 DSourceComboer(void) = delete;
102 DSourceComboer(JEventLoop* locEventLoop);
103 ~DSourceComboer(void);
104
105 //RESET
106 void Reset_NewEvent(JEventLoop* locEventLoop);
107
108 void Set_RunDependent_Data(JEventLoop *locEventLoop);
109
110 //BUILD COMBOS (what should be called from the outside to do all of the work)
111 DCombosByReaction Build_ParticleCombos(const DReactionVertexInfo* locReactionVertexInfo);
112
113 //Get combo characteristics
114 Charge_t Get_ChargeContent(const DSourceComboInfo* locSourceComboInfo) const{return dComboInfoChargeContent.find(locSourceComboInfo)->second;}
115 bool Get_HasMassiveNeutrals(const DSourceComboInfo* locSourceComboInfo) const{return (dComboInfosWithMassiveNeutrals.find(locSourceComboInfo) != dComboInfosWithMassiveNeutrals.end());}
26
Calling 'operator!=<const DAnalysis::DSourceComboInfo *, false>'
29
Returning from 'operator!=<const DAnalysis::DSourceComboInfo *, false>'
30
Returning the value 1, which participates in a condition later
116 bool Get_HasPhotons(const DSourceComboInfo* locSourceComboInfo) const{return (dComboInfosWithPhotons.find(locSourceComboInfo) != dComboInfosWithPhotons.end());}
117
118 //Combo utility functions
119 const DSourceCombo* Get_StepSourceCombo(const DReaction* locReaction, size_t locDesiredStepIndex, const DSourceCombo* locVertexPrimaryCombo, size_t locVertexPrimaryStepIndex = 0) const;
120 const DSourceCombo* Get_VertexPrimaryCombo(const DSourceCombo* locReactionCombo, const DReactionStepVertexInfo* locStepVertexInfo) const;
121 const DSourceCombo* Get_VertexPrimaryCombo(const DSourceCombo* locReactionCombo, const DReactionStepVertexInfo* locStepVertexInfo);
122 pair<DSourceComboUse, size_t> Get_StepSourceComboUse(const DReaction* locReaction, size_t locDesiredStepIndex, DSourceComboUse locVertexPrimaryComboUse, size_t locVertexPrimaryStepIndex) const;
123
124 //Get combo uses
125 DSourceComboUse Get_SourceComboUse(const DReactionStepVertexInfo* locStepVertexInfo) const{return dSourceComboUseReactionMap.find(locStepVertexInfo)->second;};
126 DSourceComboUse Get_SourceComboUse(const DReaction* locReaction, size_t locStepIndex) const{return dSourceComboUseReactionStepMap.find(locReaction)->second.find(locStepIndex)->second;};
127 DSourceComboUse Get_PrimaryComboUse(const DReactionVertexInfo* locReactionVertexInfo) const{return Get_SourceComboUse(locReactionVertexInfo->Get_StepVertexInfo(0));};
128
129 DParticleComboCreator* Get_ParticleComboCreator(void) const{return dParticleComboCreator;}
130 void Print_NumCombosByUse(void);
131
132 private:
133
134 /********************************************************** DECLARE MEMBER FUNCTIONS ***********************************************************/
135
136 //SETUP
137 void Define_DefaultCuts(void);
138 void Get_CommandLineCuts_dEdx(void);
139 void Get_CommandLineCuts_EOverP(void);
140 void Get_CommandLineCuts_Beta(void);
141 void Create_CutFunctions(void);
142 void Setup_NeutralShowers(JEventLoop* locEventLoop);
143 void Recycle_Vectors(void);
144
145 //INITIAL CHECKS
146 bool Check_Reactions(vector<const DReaction*>& locReactions);
147 bool Check_NumParticles(const DReaction* locReaction);
148 bool Check_Skims(const DReaction* locReaction) const;
149
150 //PARTICLE CUTS
151 bool Cut_dEdxAndEOverP(const DChargedTrackHypothesis* locHypo);
152 bool Cut_dEdx(Particle_t locPID, DetectorSystem_t locSystem, double locP, double locdEdx);
153 bool Cut_EOverP(Particle_t locPID, DetectorSystem_t locSystem, double locP, double locEOverP);
154 bool Cut_Beta(const DNeutralParticleHypothesis* locNeutralParticleHypothesis);
155 bool Cut_Beta(Particle_t locPID, DetectorSystem_t locSystem, double locP, double locBeta);
156 void Fill_CutHistograms(void);
157 void Fill_SurvivalHistograms(void);
158
159 //CREATE PHOTON COMBO INFOS & USES
160 void Create_SourceComboInfos(const DReactionVertexInfo* locReactionVertexInfo);
161 DSourceComboUse Create_ZDependentSourceComboUses(const DReactionVertexInfo* locReactionVertexInfo, const DSourceCombo* locReactionChargedCombo);
162 DSourceComboUse Build_NewZDependentUse(const DReaction* locReaction, size_t locStepIndex, signed char locVertexZBin, const DSourceComboUse& locOrigUse, const unordered_map<size_t, DSourceComboUse>& locCreatedUseMap);
163 DSourceComboUse Get_ZIndependentUse(const DSourceComboUse& locZDependentUse);
164 const DSourceComboInfo* Get_ZIndependentComboInfo(const DSourceComboInfo* locZDependentComboInfo);
165
166 //CREATE PHOTON COMBO INFOS & USES: UTILITY METHODS
167 map<Particle_t, unsigned char> Build_ParticleMap(const DReaction* locReaction, size_t locStepIndex, Charge_t locCharge) const;
168 pair<bool, map<DSourceComboUse, unsigned char>> Get_FinalStateDecayingComboUses(const DReaction* locReaction, size_t locStepIndex, const map<size_t, DSourceComboUse>& locStepComboUseMap) const;
169 DSourceComboUse Make_ComboUse(Particle_t locInitPID, const map<Particle_t, unsigned char>& locNumParticles, const map<DSourceComboUse, unsigned char>& locFurtherDecays, bool locMissingDecayProductFlag, Particle_t locTargetToInclude);
170 const DSourceComboInfo* MakeOrGet_SourceComboInfo(const vector<pair<Particle_t, unsigned char>>& locNumParticles, const vector<pair<DSourceComboUse, unsigned char>>& locFurtherDecays, unsigned char locNumTabs);
171 const DSourceComboInfo* GetOrMake_SourceComboInfo(const vector<pair<Particle_t, unsigned char>>& locNumParticles, const vector<pair<DSourceComboUse, unsigned char>>& locFurtherDecays, unsigned char locNumTabs);
172
173 //CREATE COMBOS
174 void Combo_WithNeutralsAndBeam(const vector<const DReaction*>& locReactions, const DReactionVertexInfo* locReactionVertexInfo, const DSourceComboUse& locPrimaryComboUse, const DSourceCombo* locReactionChargedCombo, const vector<int>& locBeamBunches_Charged, DCombosByReaction& locOutputComboMap);
175 void Combo_WithBeam(const vector<const DReaction*>& locReactions, const DReactionVertexInfo* locReactionVertexInfo, const DSourceComboUse& locReactionFullComboUse, const DSourceCombo* locReactionFullCombo, int locRFBunch, DCombosByReaction& locOutputComboMap);
176 const DParticleCombo* Build_ParticleCombo(const DReactionVertexInfo* locReactionVertexInfo, const DSourceCombo* locFullCombo, const DKinematicData* locBeamParticle);
177
178 //CREATE SOURCE COMBOS - GENERAL METHODS
179 void Create_SourceCombos(const DSourceComboUse& locComboUseToCreate, ComboingStage_t locComboingStage, const DSourceCombo* locChargedCombo_Presiding, unsigned char locNumTabs);
180 void Create_SourceCombos_Unknown(const DSourceComboUse& locComboUseToCreate, ComboingStage_t locComboingStage, const DSourceCombo* locChargedCombo_Presiding, unsigned char locNumTabs);
181
182 //COMBO VERTICALLY METHODS
183 //Note that vertical comboing always takes place at the same vertex-z
184 void Combo_Vertically_AllDecays(const DSourceComboUse& locComboUseToCreate, ComboingStage_t locComboingStage, const DSourceCombo* locChargedCombo_Presiding, unsigned char locNumTabs);
185 void Combo_Vertically_NDecays(const DSourceComboUse& locComboUseToCreate, const DSourceComboUse& locNMinus1ComboUse, const DSourceComboUse& locSourceComboDecayUse, ComboingStage_t locComboingStage, const DSourceCombo* locChargedCombo_Presiding, unsigned char locNumTabs);
186 void Combo_Vertically_AllParticles(const DSourceComboUse& locComboUseToCreate, ComboingStage_t locComboingStage, unsigned char locNumTabs);
187 void Combo_Vertically_NParticles(const DSourceComboUse& locComboUseToCreate, const DSourceComboUse& locNMinus1ComboUse, ComboingStage_t locComboingStage, unsigned char locNumTabs);
188
189 //COMBO HORIZONTALLY ORGANIZATION METHODS
190 void Combo_Horizontally_All(const DSourceComboUse& locComboUseToCreate, ComboingStage_t locComboingStage, const DSourceCombo* locChargedCombo_Presiding, unsigned char locNumTabs);
191 void Combo_Horizontally_AddDecay(const DSourceComboUse& locComboUseToCreate, const DSourceComboUse& locComboUseAllBut1, const DSourceComboUse& locComboUseToAdd, ComboingStage_t locComboingStage, const DSourceCombo* locChargedCombo_Presiding, bool locExpandAllBut1Flag, unsigned char locNumTabs);
192 void Combo_Horizontally_AddParticles(const DSourceComboUse& locComboUseToCreate, const DSourceComboUse& locComboUseAllBut1, const pair<Particle_t, unsigned char>& locParticlePairToAdd, ComboingStage_t locComboingStage, const DSourceCombo* locChargedCombo_Presiding, bool locExpandAllBut1Flag, unsigned char locNumTabs);
193
194 //COMBO HORIZONTALLY COMBOING METHODS
195 void Create_Combo_OneParticle(const DSourceComboUse& locComboUseToCreate, ComboingStage_t locComboingStage, unsigned char locNumTabs);
196 void Create_Combo_OneDecay(const DSourceComboUse& locComboUseToCreate, ComboingStage_t locComboingStage, const DSourceCombo* locChargedCombo_Presiding, unsigned char locNumTabs);
197 void Combo_Horizontally_AddCombo(const DSourceComboUse& locComboUseToCreate, const DSourceComboUse& locAllBut1ComboUse, const DSourceComboUse& locSourceComboUseToAdd, ComboingStage_t locComboingStage, const DSourceCombo* locChargedCombo_Presiding, bool locExpandAllBut1Flag, unsigned char locNumTabs);
198 void Combo_Horizontally_AddParticle(const DSourceComboUse& locComboUseToCreate, const DSourceComboUse& locAllBut1ComboUse, Particle_t locPID, ComboingStage_t locComboingStage, const DSourceCombo* locChargedCombo_Presiding, unsigned char locNumTabs);
199
200 //BUILD/RETRIEVE RESUME-AT ITERATORS
201 void Build_ParticleIndices(Particle_t locPID, const vector<int>& locBeamBunches, const vector<const JObject*>& locParticles, signed char locVertexZBin);
202 void Build_ComboIndices(const DSourceComboUse& locSourceComboUse, const vector<int>& locBeamBunches, const vector<const DSourceCombo*>& locCombos, ComboingStage_t locComboingStage);
203 size_t Get_ResumeAtIndex_Particles(Particle_t locPID, const JObject* locPreviousObject, vector<int> locBeamBunches, signed char locVertexZBin) const;
204 size_t Get_ResumeAtIndex_Combos(const DSourceComboUse& locSourceComboUse, const DSourceCombo* locPreviousCombo, const vector<int>& locBeamBunches, ComboingStage_t locComboingStage) const;
205
206 //GET POTENTIAL PARTICLES & COMBOS FOR COMBOING
207 const vector<const DSourceCombo*>& Get_CombosForComboing(const DSourceComboUse& locComboUse, ComboingStage_t locComboingStage, const vector<int>& locBeamBunches, const DSourceCombo* locChargedCombo_PresidingPrevious);
208 const vector<const DSourceCombo*>& Get_CombosByBeamBunch(const DSourceComboUse& locComboUse, DCombosByBeamBunch& locCombosByBunch, const vector<int>& locBeamBunches, ComboingStage_t locComboingStage);
209
210 //REGISTER VALID RF BUNCHES
211 void Register_ValidRFBunches(const DSourceComboUse& locSourceComboUse, const DSourceCombo* locSourceCombo, const vector<int>& locRFBunches, ComboingStage_t locComboingStage, const DSourceCombo* locChargedCombo_Presiding);
212 void Build_ComboResumeIndices(const DSourceComboUse& locSourceComboUse, ComboingStage_t locComboingStage, const DSourceCombo* locChargedCombo_Presiding);
213
214 //PARTICLE UTILITY FUNCTIONS
215 const vector<const JObject*>& Get_ParticlesForComboing(Particle_t locPID, ComboingStage_t locComboingStage, const vector<int>& locBeamBunches = {}, signed char locVertexZBin = 0);
216 const vector<const JObject*>& Get_ShowersByBeamBunch(const vector<int>& locBeamBunches, DPhotonShowersByBeamBunch& locShowersByBunch, signed char locVertexZBin);
217 shared_ptr<const DKinematicData> Create_KinematicData(const DNeutralShower* locNeutralShower, const DVector3& locVertex) const;
218 bool Get_IsComboingZIndependent(const JObject* locObject, Particle_t locPID) const;
219
220 //COMBO UTILITY FUNCTIONS
221 DSourceCombosByUse_Large& Get_CombosSoFar(ComboingStage_t locComboingStage, Charge_t locChargeContent_SearchForUse, const DSourceCombo* locChargedCombo = nullptr);
222 DSourceCombosByBeamBunchByUse& Get_SourceCombosByBeamBunchByUse(Charge_t locChargeContent_SearchForUse, const DSourceCombo* locChargedCombo = nullptr);
223 void Copy_ZIndependentMixedResults(const DSourceComboUse& locComboUseToCreate, const DSourceCombo* locChargedCombo_Presiding);
224 const DSourceCombo* Get_ChargedCombo_WithNow(const DSourceCombo* locChargedCombo_Presiding, const DSourceComboInfo* locToCreateComboInfo, ComboingStage_t locComboingStage) const;
225 const DSourceCombo* Get_NextChargedCombo(const DSourceCombo* locChargedCombo_Presiding, const DSourceComboUse& locNextComboUse, ComboingStage_t locComboingStage, bool locGetPresidingFlag, size_t locInstance) const;
226 bool Get_ExpandAllBut1Flag(ComboingStage_t locComboingStage, const DSourceComboUse& locAllBut1ComboUse, Charge_t locToAddChargeContent);
227 bool Get_PromoteFlag(ComboingStage_t locComboingStage, Particle_t locDecayPID_UseToCheck, const DSourceComboInfo* locComboInfo_UseToCreate, const DSourceComboInfo* locComboInfo_UseToCheck, DSourceComboUse& locNonNeutralUse) const;
228 const DSourceCombo* Find_Combo_AtThisStep(const DSourceCombo* locSourceCombo, DSourceComboUse locUseToFind, size_t locDecayInstanceIndex) const;
229 void Check_ForDuplicates(const vector<const DSourceCombo*>& locCombos) const;
230 DSourceComboUse Find_ZDependentUse_AtThisStep(const DSourceComboUse& locSourceComboUse, DSourceComboUse locUseToFind, size_t locDecayInstanceIndex) const;
231
232 //GET RESOURCES
233 DSourceCombo* Get_SourceComboResource(void);
234 vector<const DSourceCombo*>* Get_SourceComboVectorResource(void);
235
236 /************************************************************** DEFINE MEMBERS ***************************************************************/
237
238 //CONTROL INFORMATION
239 uint64_t dEventNumber = 0; //re-setup on new events
240 string dShowerSelectionTag = "PreSelect";
241 string dHadronShowerSelectionTag = "HadronPreSelect";
242 int dDebugLevel = 0;
243 bool dPrintCutFlag = false;
244
245 //EXPERIMENT INFORMATION
246 DVector3 dTargetCenter;
247
248 //RF BUNCH CUTS
249 pair<bool, size_t> dNumPlusMinusRFBunches = std::make_pair(false, 0); //by default use DReaction cut //only use this if set on command line
250 unordered_map<const DReaction*, size_t> dRFBunchCutsByReaction;
251 unordered_map<const DReactionVertexInfo*, size_t> dMaxRFBunchCuts;
252
253 //HANDLERS AND VERTEXERS
254 DSourceComboVertexer* dSourceComboVertexer;
255 DSourceComboP4Handler* dSourceComboP4Handler;
256 DSourceComboTimeHandler* dSourceComboTimeHandler;
257 DParticleComboCreator* dParticleComboCreator;
258
259 //SOURCE COMBO INFOS: CREATED ONCE DURING DSOURCECOMBOER OBJECT CONSTRUCTION
260 //with some exceptions (specific vertex-z, etc.)
261 //want to make sure we only have one of each type: suggests using a set
262 //however, after the first few events, almost all of these have already been created: vector has faster lookup time
263 //therefore, use the set when creating the objects during construction, but then move the results into the vector and keep it sorted
264 set<const DSourceComboInfo*, DCompare_SourceComboInfos> dSourceComboInfoSet;
265 vector<const DSourceComboInfo*> dSourceComboInfos;
266 unordered_map<const DSourceComboInfo*, Charge_t> dComboInfoChargeContent;
267 unordered_set<const DSourceComboInfo*> dComboInfosWithMassiveNeutrals;
268 unordered_set<const DSourceComboInfo*> dComboInfosWithPhotons;
269 //the rest
270 unordered_map<const DReactionStepVertexInfo*, DSourceComboUse> dSourceComboUseReactionMap; //primary combo info (nullptr if none)
271 //combo use -> step
272 map<pair<const DReactionStepVertexInfo*, DSourceComboUse>, size_t> dSourceComboInfoStepMap; //size_t: step index
273 //i need to go from step -> combo use
274 unordered_map<const DReaction*, map<size_t, DSourceComboUse>> dSourceComboUseReactionStepMap; //primary combo info (nullptr if none)
275 //with specific vertex-z's
276 map<pair<const DReactionVertexInfo*, vector<signed char>>, DSourceComboUse> dSourceComboUseVertexZMap;
277 map<DSourceComboUse, DSourceComboUse> dZDependentUseToIndependentMap; //from z-dependent -> z-independent
278
279 //SKIM INFORMATION
280 const DESSkimData* dESSkimData = nullptr;
281
282 //PARTICLES
283 size_t dMaxNumNeutrals = 20;
284 map<Particle_t, vector<const JObject*>> dTracksByPID;
285 size_t dNumChargedTracks;
286 map<bool, vector<const JObject*>> dTracksByCharge; //true/false: positive/negative
287 unordered_map<signed char, DPhotonShowersByBeamBunch> dShowersByBeamBunchByZBin; //char: zbin //for all showers: unknown z-bin, {} RF bunch
288 vector<const JObject*> dNeutralHadronShowers;
289
290 //SOURCE COMBOS //vector: z-bin //if attempted and all failed, DSourceCombosByUse_Large vector will be empty
291 size_t dInitialComboVectorCapacity = 100;
292 DSourceCombosByUse_Large dSourceCombosByUse_Charged;
293 unordered_map<const DSourceCombo*, DSourceCombosByUse_Large> dMixedCombosByUseByChargedCombo; //key: charged combo //value: contains mixed & neutral combos //neutral: key is nullptr
294 //also, sort by which beam bunches they are valid for: that way when comboing, we can retrieve only the combos that can possibly match the input RF bunches
295 unordered_map<const DSourceCombo*, DSourceCombosByBeamBunchByUse> dSourceCombosByBeamBunchByUse; //key: charged combo //value: contains mixed & neutral combos: key is nullptr
296 map<pair<const DSourceCombo*, const DReactionStepVertexInfo*>, const DSourceCombo*> dVertexPrimaryComboMap; //first combo: reaction primary combo (can be charged or full!)
297
298 //RESUME SEARCH ITERATORS
299 //e.g. if a DSourceCombo is -> 2pi0, and we want to use it as a basis for building a combo of 3pi0s,
300 //then this iterator points to the first pi0 in the DSourceCombosByUse_Large vector that we want to test
301 //that way we save a lot of time, since we don't have to look for it again
302 //they are useful when comboing VERTICALLY, but cannot be used when comboing HORIZONTALLY
303 //e.g. when comboing a pi0 (with photons = A, D) with a single photon, the photon could be B, C, or E+: no single spot to resume at
304 map<tuple<const JObject*, Particle_t, vector<int>, signed char>, size_t> dResumeSearchAfterIndices_Particles; //vector<int>: RF bunches (empty for all) //signed char: zbin
305 map<pair<const DSourceCombo*, DSourceComboUse>, map<vector<int>, size_t>> dResumeSearchAfterIndices_Combos; //char: zbin, size_t: index
306
307 //VALID RF BUNCHES BY COMBO
308 map<pair<const DSourceCombo*, signed char>, vector<int>> dValidRFBunches_ByCombo; //char: zbin
309
310 //RESOURCE POOLS
311 //Don't use these directly! Use the Get_*Resource functions instead!!
312 DResourcePool<DSourceCombo> dResourcePool_SourceCombo;
313 DResourcePool<vector<const DSourceCombo*>> dResourcePool_SourceComboVector;
314 //These are used to know what to recycle
315 vector<DSourceCombo*> dCreatedCombos;
316 vector<vector<const DSourceCombo*>*> dCreatedComboVectors;
317
318 //Combo/event tracking
319 map<const DReaction*, TH1*> dNumEventsSurvivedStageMap;
320 map<const DReaction*, TH1*> dNumCombosSurvivedStageMap;
321 map<const DReaction*, TH2*> dNumCombosSurvivedStage2DMap;
322 map<const DReaction*, map<DConstructionStage, size_t>> dNumCombosSurvivedStageTracker; //index is for event stages!!!
323 map<DSourceComboUse, size_t> dNumMixedCombosMap_Charged;
324 map<DSourceComboUse, size_t> dNumMixedCombosMap_Mixed;
325 map<vector<const JObject*>, const DSourceCombo*> dNPhotonsToComboMap; //vector contents are auto-sorted by how they're created
326
327 //dE/dx
328 map<Particle_t, map<DetectorSystem_t, pair<string, string>>> ddEdxCuts_TF1FunctionStrings; //pair: low bound, high bound
329 map<Particle_t, map<DetectorSystem_t, pair<vector<double>, vector<double>>>> ddEdxCuts_TF1Params; //pair: low bound, high bound
330 map<Particle_t, map<DetectorSystem_t, pair<TF1*, TF1*>>> ddEdxCutMap; //pair: first is lower bound, second is upper bound
331 map<Particle_t, map<DetectorSystem_t, vector<pair<double, double>>>> ddEdxValueMap; //pair: first is p, 2nd is dE/dx
332 map<Particle_t, map<DetectorSystem_t, TH2*>> dHistMap_dEdx;
333
334 //E/p
335 map<Particle_t, map<DetectorSystem_t, string>> dEOverPCuts_TF1FunctionStrings;
336 map<Particle_t, map<DetectorSystem_t, vector<double>>> dEOverPCuts_TF1Params;
337 map<Particle_t, map<DetectorSystem_t, TF1*>> dEOverPCutMap; //if lepton, select above function, else select below
338 map<Particle_t, map<DetectorSystem_t, vector<pair<double, double>>>> dEOverPValueMap; //pair: first is p, 2nd is E/p
339 map<Particle_t, map<DetectorSystem_t, TH2*>> dHistMap_EOverP;
340
341 //beta
342 map<Particle_t, map<DetectorSystem_t, string>> dBetaCuts_TF1FunctionStrings;
343 map<Particle_t, map<DetectorSystem_t, vector<double>>> dBetaCuts_TF1Params;
344 map<Particle_t, map<DetectorSystem_t, TF1*>> dBetaCutMap; //if lepton, select above function, else select below
345 map<Particle_t, map<DetectorSystem_t, vector<pair<double, double>>>> dBetaValueMap; //pair: first is p, 2nd is E/p
346 map<Particle_t, map<DetectorSystem_t, TH2*>> dHistMap_Beta;
347};
348
349/*********************************************************** INLINE MEMBER FUNCTION DEFINITIONS ************************************************************/
350
351
352inline DSourceCombo* DSourceComboer::Get_SourceComboResource(void)
353{
354 auto locCombo = dResourcePool_SourceCombo.Get_Resource();
355 dCreatedCombos.push_back(locCombo);
356 return locCombo;
357}
358
359inline void DSourceComboer::Recycle_Vectors(void)
360{
361 for(auto& locComboVector : dCreatedComboVectors)
362 {
363 vector<const DSourceCombo*> locTempCombo;
364 locTempCombo.reserve(dInitialComboVectorCapacity);
365 locTempCombo.swap(*locComboVector); //reduces capacity of combo vector to dInitialComboVectorCapacity
366 dResourcePool_SourceComboVector.Recycle(locComboVector);
367 }
368 decltype(dCreatedComboVectors)().swap(dCreatedComboVectors);
369}
370
371inline vector<const DSourceCombo*>* DSourceComboer::Get_SourceComboVectorResource(void)
372{
373 auto locComboVector = dResourcePool_SourceComboVector.Get_Resource();
374 locComboVector->clear();
375 locComboVector->reserve(dInitialComboVectorCapacity);
376 dCreatedComboVectors.push_back(locComboVector);
377 return locComboVector;
378}
379
380inline bool DSourceComboer::Check_Skims(const DReaction* locReaction) const
381{
382 if(dESSkimData == nullptr)
383 return true;
384
385 string locReactionSkimString = locReaction->Get_EventStoreSkims();
386 vector<string> locReactionSkimVector;
387 SplitString(locReactionSkimString, locReactionSkimVector, ",");
388 for(size_t loc_j = 0; loc_j < locReactionSkimVector.size(); ++loc_j)
389 {
390 if(!dESSkimData->Get_IsEventSkim(locReactionSkimVector[loc_j]))
391 return false;
392 }
393
394 return true;
395}
396
397inline DSourceComboUse DSourceComboer::Get_ZIndependentUse(const DSourceComboUse& locZDependentUse)
398{
399 auto locIterator = dZDependentUseToIndependentMap.find(locZDependentUse);
400 if(locIterator != dZDependentUseToIndependentMap.end())
401 return locIterator->second;
402
403 auto locZIndependentComboInfo = Get_ZIndependentComboInfo(std::get<2>(locZDependentUse));
404 DSourceComboUse locZIndependentUse(std::get<0>(locZDependentUse), DSourceComboInfo::Get_VertexZIndex_ZIndependent(), locZIndependentComboInfo, std::get<3>(locZDependentUse), std::get<4>(locZDependentUse));
405 dZDependentUseToIndependentMap.emplace(locZDependentUse, locZIndependentUse);
406 return locZIndependentUse;
407}
408
409inline const DSourceComboInfo* DSourceComboer::Get_ZIndependentComboInfo(const DSourceComboInfo* locZDependentComboInfo)
410{
411 vector<pair<DSourceComboUse, unsigned char>> locFurtherDecays_ZIndependent;
412 for(const auto& locDecayPair : locZDependentComboInfo->Get_FurtherDecays())
413 locFurtherDecays_ZIndependent.emplace_back(Get_ZIndependentUse(locDecayPair.first), locDecayPair.second);
414
415 return GetOrMake_SourceComboInfo(locZDependentComboInfo->Get_NumParticles(), locFurtherDecays_ZIndependent, 0);
416}
417
418inline void DSourceComboer::Build_ParticleIndices(Particle_t locPID, const vector<int>& locBeamBunches, const vector<const JObject*>& locParticles, signed char locVertexZBin)
419{
420 for(size_t loc_i = 0; loc_i < locParticles.size(); ++loc_i)
421 {
422 if(dDebugLevel >= 20)
423 {
424 cout << "build resume indices: vector address, locPID, particle, zbin, index, bunches: " << &locParticles << ", " << locPID << ", " << locParticles[loc_i] << ", " << int(locVertexZBin) << ", " << loc_i << ", ";
425 for(auto& locBunch : locBeamBunches)
426 cout << locBunch << ", ";
427 cout << endl;
428 }
429 dResumeSearchAfterIndices_Particles.emplace(std::make_tuple(locParticles[loc_i], locPID, locBeamBunches, locVertexZBin), loc_i);
430 }
431}
432
433inline void DSourceComboer::Build_ComboIndices(const DSourceComboUse& locSourceComboUse, const vector<int>& locBeamBunches, const vector<const DSourceCombo*>& locCombos, ComboingStage_t locComboingStage)
434{
435 for(size_t loc_i = 0; loc_i < locCombos.size(); ++loc_i)
436 {
437 if(dDebugLevel >= 20)
438 {
439 cout << "build resume indices: vector address, combo, decay pid, zbin, index, bunches: " << &locCombos << ", " << locCombos[loc_i] << ", " << std::get<0>(locSourceComboUse) << ", " << int(std::get<1>(locSourceComboUse)) << ", " << loc_i << ", ";
440 for(auto& locBunch : locBeamBunches)
441 cout << locBunch << ", ";
442 cout << endl;
443 }
444 dResumeSearchAfterIndices_Combos[std::make_pair(locCombos[loc_i], locSourceComboUse)].emplace(locBeamBunches, loc_i);
445 }
446}
447
448inline size_t DSourceComboer::Get_ResumeAtIndex_Particles(Particle_t locPID, const JObject* locPreviousObject, vector<int> locBeamBunches, signed char locVertexZBin) const
449{
450 if((ParticleCharge(locPID) == 0) && (ParticleMass(locPID) > 0.0))
451 {
452 locPID = Gamma;
453 locBeamBunches = {}; //need to get all showers
454 }
455 auto locParticleTuple = std::make_tuple(locPreviousObject, locPID, locBeamBunches, locVertexZBin);
456 if(dDebugLevel >= 20)
457 {
458 cout << "object, pid, zbin, bunches, find result, saved index: " << locPreviousObject << ", " << locPID << ", " << int(locVertexZBin) << ", ";
459 for(auto& locBunch : locBeamBunches)
460 cout << locBunch << ", ";
461 cout << (dResumeSearchAfterIndices_Particles.find(locParticleTuple) != dResumeSearchAfterIndices_Particles.end()) << ", " << dResumeSearchAfterIndices_Particles.find(locParticleTuple)->second + 1 << endl;
462 }
463 return dResumeSearchAfterIndices_Particles.find(locParticleTuple)->second + 1;
464}
465
466inline size_t DSourceComboer::Get_ResumeAtIndex_Combos(const DSourceComboUse& locSourceComboUse, const DSourceCombo* locPreviousCombo, const vector<int>& locBeamBunches, ComboingStage_t locComboingStage) const
467{
468 //Suppose you are comboing N pi0s together (let's say 3), and 6 different pi0 combos were reconstructed
469 //So, you choose the first pi0, then want to loop over the remaining ones
470 //To avoid duplication, you don't want to loop over ALL of the others, only the ones AFTER the first one
471 //So, the input is the last pi0 that you've chosen for your combo
472 //Then, just find the location where that pi0 is the possible-combos-vector (pi0 vector), and return that index + 1
473 auto locSearchPair = std::make_pair(locPreviousCombo, locSourceComboUse);
474 auto& locBunchIndexMap = dResumeSearchAfterIndices_Combos.find(locSearchPair)->second;
475 auto locSavedIndex = locBunchIndexMap.find(locBeamBunches)->second;
476 if(dDebugLevel >= 20)
477 {
478 cout << "Get_ResumeAtIndex_Combos: previous combo, bunches, saved index" << ", " << locPreviousCombo << ", ";
479 for(auto& locBunch : locBeamBunches)
480 cout << locBunch << ", ";
481 cout << locSavedIndex << endl;
482 }
483 return locSavedIndex + 1;
484}
485
486inline bool DSourceComboer::Get_IsComboingZIndependent(const JObject* locObject, Particle_t locPID) const
487{
488 //make this virtual!
489 if(ParticleCharge(locPID) != 0)
490 return true;
491
492 //actually, everything is z-dependent for massive neutrals.
493 //however the momentum is SO z-dependent, that we can't cut on it until the end when we have the final vertex, AFTER comboing
494 //a mere z-bin is not enough.
495 //So, as far as COMBOING is concerned, massive neutrals are Z-INDEPENDENT
496 if(ParticleMass(locPID) > 0.0)
497 return true;
498
499 auto locNeutralShower = static_cast<const DNeutralShower*>(locObject);
500 return (locNeutralShower->dDetectorSystem == SYS_FCAL || locNeutralShower->dDetectorSystem == SYS_CCAL);
501}
502
503inline DSourceCombosByUse_Large& DSourceComboer::Get_CombosSoFar(ComboingStage_t locComboingStage, Charge_t locChargeContent_SearchForUse, const DSourceCombo* locChargedCombo)
504{
505 //THE INPUT locChargedCombo MUST BE:
506 //If reading from: Whatever charged combo PREVIOUSLY presided over the creation of the combos you're trying to get
507 //If saving to (you are making a mixed): Whatever charged combo is presiding over what you are about to make
508
509 //NOTE: If on mixed stage, it is NOT valid to get fully-charged combos from here! In fact, what you want is probably the input combo!
510 if((locComboingStage == d_ChargedStage) || (locChargeContent_SearchForUse == d_Charged))
511 return dSourceCombosByUse_Charged;
512 else if(locChargeContent_SearchForUse == d_Neutral)
513 return dMixedCombosByUseByChargedCombo[nullptr]; //if fully neutral, then the charged combo doesn't matter: only matters for mixing charges
514 return dMixedCombosByUseByChargedCombo[locChargedCombo];
515}
516
517inline DSourceCombosByBeamBunchByUse& DSourceComboer::Get_SourceCombosByBeamBunchByUse(Charge_t locChargeContent_SearchForUse, const DSourceCombo* locChargedCombo)
518{
519//shouldn't ever be called if charged
520 //THE INPUT locChargedCombo MUST BE:
521 //If reading from: Whatever charged combo PREVIOUSLY presided over the creation of the combos you're trying to get
522 //If saving to (you are making a mixed): Whatever charged combo is presiding over what you are about to make
523 if(locChargeContent_SearchForUse == d_Neutral)
524 return dSourceCombosByBeamBunchByUse[nullptr];
525 return dSourceCombosByBeamBunchByUse[locChargedCombo];
526}
527
528inline bool DSourceComboer::Cut_dEdx(Particle_t locPID, DetectorSystem_t locSystem, double locP, double locdEdx)
529{
530 ddEdxValueMap[locPID][locSystem].emplace_back(locP, locdEdx);
531 if(ddEdxCutMap[locPID].find(locSystem) == ddEdxCutMap[locPID].end())
532 return true;
533
534 auto locCutPair = ddEdxCutMap[locPID][locSystem];
535//cout << "PID, p, dedx, cut value low/high, cut result: " << locPID << ", " << locP << ", " << locdEdx << ", " << locCutPair.first->Eval(locP) << ", " << locCutPair.second->Eval(locP) << ", " << ((locdEdx >= locCutPair.first->Eval(locP)) && (locdEdx <= locCutPair.second->Eval(locP))) << endl;
536 return ((locdEdx >= locCutPair.first->Eval(locP)) && (locdEdx <= locCutPair.second->Eval(locP)));
537}
538
539inline bool DSourceComboer::Cut_EOverP(Particle_t locPID, DetectorSystem_t locSystem, double locP, double locEOverP)
540{
541 dEOverPValueMap[locPID][locSystem].emplace_back(locP, locEOverP);
542 if(dEOverPCutMap[locPID].find(locSystem) == dEOverPCutMap[locPID].end())
543 return true;
544
545 auto locCutFunc = dEOverPCutMap[locPID][locSystem];
546 return (((locPID == Electron) || (locPID == Positron)) == (locEOverP >= locCutFunc->Eval(locP)));
547}
548
549inline bool DSourceComboer::Cut_Beta(Particle_t locPID, DetectorSystem_t locSystem, double locP, double locBeta)
550{
551 dBetaValueMap[locPID][locSystem].emplace_back(locP, locBeta);
552 if(dBetaCutMap[locPID].find(locSystem) == dBetaCutMap[locPID].end())
553 return true;
554
555 auto locCutFunc = dBetaCutMap[locPID][locSystem];
556 return ((locPID == Gamma) == (locBeta >= locCutFunc->Eval(locP)));
557}
558
559inline DSourceComboer::~DSourceComboer(void)
560{
561 //no need for a resource pool for these objects, as they will exist for the length of the program
562 Fill_SurvivalHistograms();
563 if(dDebugLevel >= 5)
564 {
565 Print_NumCombosByUse(); //for the final event
566
567 cout << "FINAL Num combos by use (charged):" << endl;
568 for(const auto& locNumCombosByUsePair : dNumMixedCombosMap_Charged)
569 {
570 cout << locNumCombosByUsePair.second << " of ";
571 Print_SourceComboUse(locNumCombosByUsePair.first);
572 }
573 cout << "FINAL Num combos by use (neutral/mixed):" << endl;
574 for(const auto& locNumCombosByUsePair : dNumMixedCombosMap_Mixed)
575 {
576 cout << locNumCombosByUsePair.second << " of ";
577 Print_SourceComboUse(locNumCombosByUsePair.first);
578 }
579
580 }
581 for(auto locComboInfo : dSourceComboInfos)
582 delete locComboInfo;
583 delete dSourceComboVertexer;
584 delete dSourceComboP4Handler;
585 delete dSourceComboTimeHandler;
586 delete dParticleComboCreator;
587}
588
589
590/*********************************************************** INLINE NAMESPACE-SCOPE FUNCTION DEFINITIONS ************************************************************/
591
592} //end DAnalysis namespace
593
594#endif // DSourceComboer_h

/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../include/c++/4.8.5/bits/hashtable_policy.h

1// Internal policy header for unordered_set and unordered_map -*- C++ -*-
2
3// Copyright (C) 2010-2013 Free Software Foundation, Inc.
4//
5// This file is part of the GNU ISO C++ Library. This library is free
6// software; you can redistribute it and/or modify it under the
7// terms of the GNU General Public License as published by the
8// Free Software Foundation; either version 3, or (at your option)
9// any later version.
10
11// This library is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14// GNU General Public License for more details.
15
16// Under Section 7 of GPL version 3, you are granted additional
17// permissions described in the GCC Runtime Library Exception, version
18// 3.1, as published by the Free Software Foundation.
19
20// You should have received a copy of the GNU General Public License and
21// a copy of the GCC Runtime Library Exception along with this program;
22// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
23// <http://www.gnu.org/licenses/>.
24
25/** @file bits/hashtable_policy.h
26 * This is an internal header file, included by other library headers.
27 * Do not attempt to use it directly.
28 * @headername{unordered_map,unordered_set}
29 */
30
31#ifndef _HASHTABLE_POLICY_H1
32#define _HASHTABLE_POLICY_H1 1
33
34namespace std _GLIBCXX_VISIBILITY(default)__attribute__ ((__visibility__ ("default")))
35{
36_GLIBCXX_BEGIN_NAMESPACE_VERSION
37
38 template<typename _Key, typename _Value, typename _Alloc,
39 typename _ExtractKey, typename _Equal,
40 typename _H1, typename _H2, typename _Hash,
41 typename _RehashPolicy, typename _Traits>
42 class _Hashtable;
43
44_GLIBCXX_END_NAMESPACE_VERSION
45
46namespace __detail
47{
48_GLIBCXX_BEGIN_NAMESPACE_VERSION
49
50 /**
51 * @defgroup hashtable-detail Base and Implementation Classes
52 * @ingroup unordered_associative_containers
53 * @{
54 */
55 template<typename _Key, typename _Value,
56 typename _ExtractKey, typename _Equal,
57 typename _H1, typename _H2, typename _Hash, typename _Traits>
58 struct _Hashtable_base;
59
60 // Helper function: return distance(first, last) for forward
61 // iterators, or 0 for input iterators.
62 template<class _Iterator>
63 inline typename std::iterator_traits<_Iterator>::difference_type
64 __distance_fw(_Iterator __first, _Iterator __last,
65 std::input_iterator_tag)
66 { return 0; }
67
68 template<class _Iterator>
69 inline typename std::iterator_traits<_Iterator>::difference_type
70 __distance_fw(_Iterator __first, _Iterator __last,
71 std::forward_iterator_tag)
72 { return std::distance(__first, __last); }
73
74 template<class _Iterator>
75 inline typename std::iterator_traits<_Iterator>::difference_type
76 __distance_fw(_Iterator __first, _Iterator __last)
77 {
78 typedef typename std::iterator_traits<_Iterator>::iterator_category _Tag;
79 return __distance_fw(__first, __last, _Tag());
80 }
81
82 // Helper type used to detect whether the hash functor is noexcept.
83 template <typename _Key, typename _Hash>
84 struct __is_noexcept_hash : std::integral_constant<bool,
85 noexcept(declval<const _Hash&>()(declval<const _Key&>()))>
86 { };
87
88 struct _Identity
89 {
90 template<typename _Tp>
91 _Tp&&
92 operator()(_Tp&& __x) const
93 { return std::forward<_Tp>(__x); }
94 };
95
96 struct _Select1st
97 {
98 template<typename _Tp>
99 auto
100 operator()(_Tp&& __x) const
101 -> decltype(std::get<0>(std::forward<_Tp>(__x)))
102 { return std::get<0>(std::forward<_Tp>(__x)); }
103 };
104
105 // Auxiliary types used for all instantiations of _Hashtable nodes
106 // and iterators.
107
108 /**
109 * struct _Hashtable_traits
110 *
111 * Important traits for hash tables.
112 *
113 * @tparam _Cache_hash_code Boolean value. True if the value of
114 * the hash function is stored along with the value. This is a
115 * time-space tradeoff. Storing it may improve lookup speed by
116 * reducing the number of times we need to call the _Equal
117 * function.
118 *
119 * @tparam _Constant_iterators Boolean value. True if iterator and
120 * const_iterator are both constant iterator types. This is true
121 * for unordered_set and unordered_multiset, false for
122 * unordered_map and unordered_multimap.
123 *
124 * @tparam _Unique_keys Boolean value. True if the return value
125 * of _Hashtable::count(k) is always at most one, false if it may
126 * be an arbitrary number. This is true for unordered_set and
127 * unordered_map, false for unordered_multiset and
128 * unordered_multimap.
129 */
130 template<bool _Cache_hash_code, bool _Constant_iterators, bool _Unique_keys>
131 struct _Hashtable_traits
132 {
133 template<bool _Cond>
134 using __bool_constant = integral_constant<bool, _Cond>;
135
136 using __hash_cached = __bool_constant<_Cache_hash_code>;
137 using __constant_iterators = __bool_constant<_Constant_iterators>;
138 using __unique_keys = __bool_constant<_Unique_keys>;
139 };
140
141 /**
142 * struct _Hash_node_base
143 *
144 * Nodes, used to wrap elements stored in the hash table. A policy
145 * template parameter of class template _Hashtable controls whether
146 * nodes also store a hash code. In some cases (e.g. strings) this
147 * may be a performance win.
148 */
149 struct _Hash_node_base
150 {
151 _Hash_node_base* _M_nxt;
152
153 _Hash_node_base() : _M_nxt() { }
154
155 _Hash_node_base(_Hash_node_base* __next) : _M_nxt(__next) { }
156 };
157
158 /**
159 * Primary template struct _Hash_node.
160 */
161 template<typename _Value, bool _Cache_hash_code>
162 struct _Hash_node;
163
164 /**
165 * Specialization for nodes with caches, struct _Hash_node.
166 *
167 * Base class is __detail::_Hash_node_base.
168 */
169 template<typename _Value>
170 struct _Hash_node<_Value, true> : _Hash_node_base
171 {
172 _Value _M_v;
173 std::size_t _M_hash_code;
174
175 template<typename... _Args>
176 _Hash_node(_Args&&... __args)
177 : _M_v(std::forward<_Args>(__args)...), _M_hash_code() { }
178
179 _Hash_node*
180 _M_next() const { return static_cast<_Hash_node*>(_M_nxt); }
181 };
182
183 /**
184 * Specialization for nodes without caches, struct _Hash_node.
185 *
186 * Base class is __detail::_Hash_node_base.
187 */
188 template<typename _Value>
189 struct _Hash_node<_Value, false> : _Hash_node_base
190 {
191 _Value _M_v;
192
193 template<typename... _Args>
194 _Hash_node(_Args&&... __args)
195 : _M_v(std::forward<_Args>(__args)...) { }
196
197 _Hash_node*
198 _M_next() const { return static_cast<_Hash_node*>(_M_nxt); }
199 };
200
201 /// Base class for node iterators.
202 template<typename _Value, bool _Cache_hash_code>
203 struct _Node_iterator_base
204 {
205 using __node_type = _Hash_node<_Value, _Cache_hash_code>;
206
207 __node_type* _M_cur;
208
209 _Node_iterator_base(__node_type* __p)
210 : _M_cur(__p) { }
211
212 void
213 _M_incr()
214 { _M_cur = _M_cur->_M_next(); }
215 };
216
217 template<typename _Value, bool _Cache_hash_code>
218 inline bool
219 operator==(const _Node_iterator_base<_Value, _Cache_hash_code>& __x,
220 const _Node_iterator_base<_Value, _Cache_hash_code >& __y)
221 { return __x._M_cur == __y._M_cur; }
222
223 template<typename _Value, bool _Cache_hash_code>
224 inline bool
225 operator!=(const _Node_iterator_base<_Value, _Cache_hash_code>& __x,
226 const _Node_iterator_base<_Value, _Cache_hash_code>& __y)
227 { return __x._M_cur != __y._M_cur; }
27
Assuming '__x._M_cur' is not equal to '__y._M_cur'
28
Returning the value 1, which participates in a condition later
228
229 /// Node iterators, used to iterate through all the hashtable.
230 template<typename _Value, bool __constant_iterators, bool __cache>
231 struct _Node_iterator
232 : public _Node_iterator_base<_Value, __cache>
233 {
234 private:
235 using __base_type = _Node_iterator_base<_Value, __cache>;
236 using __node_type = typename __base_type::__node_type;
237
238 public:
239 typedef _Value value_type;
240 typedef std::ptrdiff_t difference_type;
241 typedef std::forward_iterator_tag iterator_category;
242
243 using pointer = typename std::conditional<__constant_iterators,
244 const _Value*, _Value*>::type;
245
246 using reference = typename std::conditional<__constant_iterators,
247 const _Value&, _Value&>::type;
248
249 _Node_iterator()
250 : __base_type(0) { }
251
252 explicit
253 _Node_iterator(__node_type* __p)
254 : __base_type(__p) { }
255
256 reference
257 operator*() const
258 { return this->_M_cur->_M_v; }
259
260 pointer
261 operator->() const
262 { return std::__addressof(this->_M_cur->_M_v); }
263
264 _Node_iterator&
265 operator++()
266 {
267 this->_M_incr();
268 return *this;
269 }
270
271 _Node_iterator
272 operator++(int)
273 {
274 _Node_iterator __tmp(*this);
275 this->_M_incr();
276 return __tmp;
277 }
278 };
279
280 /// Node const_iterators, used to iterate through all the hashtable.
281 template<typename _Value, bool __constant_iterators, bool __cache>
282 struct _Node_const_iterator
283 : public _Node_iterator_base<_Value, __cache>
284 {
285 private:
286 using __base_type = _Node_iterator_base<_Value, __cache>;
287 using __node_type = typename __base_type::__node_type;
288
289 public:
290 typedef _Value value_type;
291 typedef std::ptrdiff_t difference_type;
292 typedef std::forward_iterator_tag iterator_category;
293
294 typedef const _Value* pointer;
295 typedef const _Value& reference;
296
297 _Node_const_iterator()
298 : __base_type(0) { }
299
300 explicit
301 _Node_const_iterator(__node_type* __p)
302 : __base_type(__p) { }
303
304 _Node_const_iterator(const _Node_iterator<_Value, __constant_iterators,
305 __cache>& __x)
306 : __base_type(__x._M_cur) { }
307
308 reference
309 operator*() const
310 { return this->_M_cur->_M_v; }
311
312 pointer
313 operator->() const
314 { return std::__addressof(this->_M_cur->_M_v); }
315
316 _Node_const_iterator&
317 operator++()
318 {
319 this->_M_incr();
320 return *this;
321 }
322
323 _Node_const_iterator
324 operator++(int)
325 {
326 _Node_const_iterator __tmp(*this);
327 this->_M_incr();
328 return __tmp;
329 }
330 };
331
332 // Many of class template _Hashtable's template parameters are policy
333 // classes. These are defaults for the policies.
334
335 /// Default range hashing function: use division to fold a large number
336 /// into the range [0, N).
337 struct _Mod_range_hashing
338 {
339 typedef std::size_t first_argument_type;
340 typedef std::size_t second_argument_type;
341 typedef std::size_t result_type;
342
343 result_type
344 operator()(first_argument_type __num, second_argument_type __den) const
345 { return __num % __den; }
346 };
347
348 /// Default ranged hash function H. In principle it should be a
349 /// function object composed from objects of type H1 and H2 such that
350 /// h(k, N) = h2(h1(k), N), but that would mean making extra copies of
351 /// h1 and h2. So instead we'll just use a tag to tell class template
352 /// hashtable to do that composition.
353 struct _Default_ranged_hash { };
354
355 /// Default value for rehash policy. Bucket size is (usually) the
356 /// smallest prime that keeps the load factor small enough.
357 struct _Prime_rehash_policy
358 {
359 _Prime_rehash_policy(float __z = 1.0)
360 : _M_max_load_factor(__z), _M_next_resize(0) { }
361
362 float
363 max_load_factor() const noexcept
364 { return _M_max_load_factor; }
365
366 // Return a bucket size no smaller than n.
367 std::size_t
368 _M_next_bkt(std::size_t __n) const;
369
370 // Return a bucket count appropriate for n elements
371 std::size_t
372 _M_bkt_for_elements(std::size_t __n) const
373 { return __builtin_ceil(__n / (long double)_M_max_load_factor); }
374
375 // __n_bkt is current bucket count, __n_elt is current element count,
376 // and __n_ins is number of elements to be inserted. Do we need to
377 // increase bucket count? If so, return make_pair(true, n), where n
378 // is the new bucket count. If not, return make_pair(false, 0).
379 std::pair<bool, std::size_t>
380 _M_need_rehash(std::size_t __n_bkt, std::size_t __n_elt,
381 std::size_t __n_ins) const;
382
383 typedef std::size_t _State;
384
385 _State
386 _M_state() const
387 { return _M_next_resize; }
388
389 void
390 _M_reset(_State __state)
391 { _M_next_resize = __state; }
392
393 enum { _S_n_primes = sizeof(unsigned long) != 8 ? 256 : 256 + 48 };
394
395 static const std::size_t _S_growth_factor = 2;
396
397 float _M_max_load_factor;
398 mutable std::size_t _M_next_resize;
399 };
400
401 // Base classes for std::_Hashtable. We define these base classes
402 // because in some cases we want to do different things depending on
403 // the value of a policy class. In some cases the policy class
404 // affects which member functions and nested typedefs are defined;
405 // we handle that by specializing base class templates. Several of
406 // the base class templates need to access other members of class
407 // template _Hashtable, so we use a variant of the "Curiously
408 // Recurring Template Pattern" (CRTP) technique.
409
410 /**
411 * Primary class template _Map_base.
412 *
413 * If the hashtable has a value type of the form pair<T1, T2> and a
414 * key extraction policy (_ExtractKey) that returns the first part
415 * of the pair, the hashtable gets a mapped_type typedef. If it
416 * satisfies those criteria and also has unique keys, then it also
417 * gets an operator[].
418 */
419 template<typename _Key, typename _Value, typename _Alloc,
420 typename _ExtractKey, typename _Equal,
421 typename _H1, typename _H2, typename _Hash,
422 typename _RehashPolicy, typename _Traits,
423 bool _Unique_keys = _Traits::__unique_keys::value>
424 struct _Map_base { };
425
426 /// Partial specialization, __unique_keys set to false.
427 template<typename _Key, typename _Pair, typename _Alloc, typename _Equal,
428 typename _H1, typename _H2, typename _Hash,
429 typename _RehashPolicy, typename _Traits>
430 struct _Map_base<_Key, _Pair, _Alloc, _Select1st, _Equal,
431 _H1, _H2, _Hash, _RehashPolicy, _Traits, false>
432 {
433 using mapped_type = typename std::tuple_element<1, _Pair>::type;
434 };
435
436 /// Partial specialization, __unique_keys set to true.
437 template<typename _Key, typename _Pair, typename _Alloc, typename _Equal,
438 typename _H1, typename _H2, typename _Hash,
439 typename _RehashPolicy, typename _Traits>
440 struct _Map_base<_Key, _Pair, _Alloc, _Select1st, _Equal,
441 _H1, _H2, _Hash, _RehashPolicy, _Traits, true>
442 {
443 private:
444 using __hashtable_base = __detail::_Hashtable_base<_Key, _Pair,
445 _Select1st,
446 _Equal, _H1, _H2, _Hash,
447 _Traits>;
448
449 using __hashtable = _Hashtable<_Key, _Pair, _Alloc,
450 _Select1st, _Equal,
451 _H1, _H2, _Hash, _RehashPolicy, _Traits>;
452
453 using __hash_code = typename __hashtable_base::__hash_code;
454 using __node_type = typename __hashtable_base::__node_type;
455
456 public:
457 using key_type = typename __hashtable_base::key_type;
458 using iterator = typename __hashtable_base::iterator;
459 using mapped_type = typename std::tuple_element<1, _Pair>::type;
460
461 mapped_type&
462 operator[](const key_type& __k);
463
464 mapped_type&
465 operator[](key_type&& __k);
466
467 // _GLIBCXX_RESOLVE_LIB_DEFECTS
468 // DR 761. unordered_map needs an at() member function.
469 mapped_type&
470 at(const key_type& __k);
471
472 const mapped_type&
473 at(const key_type& __k) const;
474 };
475
476 template<typename _Key, typename _Pair, typename _Alloc, typename _Equal,
477 typename _H1, typename _H2, typename _Hash,
478 typename _RehashPolicy, typename _Traits>
479 typename _Map_base<_Key, _Pair, _Alloc, _Select1st, _Equal,
480 _H1, _H2, _Hash, _RehashPolicy, _Traits, true>
481 ::mapped_type&
482 _Map_base<_Key, _Pair, _Alloc, _Select1st, _Equal,
483 _H1, _H2, _Hash, _RehashPolicy, _Traits, true>::
484 operator[](const key_type& __k)
485 {
486 __hashtable* __h = static_cast<__hashtable*>(this);
487 __hash_code __code = __h->_M_hash_code(__k);
488 std::size_t __n = __h->_M_bucket_index(__k, __code);
489 __node_type* __p = __h->_M_find_node(__n, __k, __code);
490
491 if (!__p)
492 {
493 __p = __h->_M_allocate_node(std::piecewise_construct,
494 std::tuple<const key_type&>(__k),
495 std::tuple<>());
496 return __h->_M_insert_unique_node(__n, __code, __p)->second;
497 }
498
499 return (__p->_M_v).second;
500 }
501
502 template<typename _Key, typename _Pair, typename _Alloc, typename _Equal,
503 typename _H1, typename _H2, typename _Hash,
504 typename _RehashPolicy, typename _Traits>
505 typename _Map_base<_Key, _Pair, _Alloc, _Select1st, _Equal,
506 _H1, _H2, _Hash, _RehashPolicy, _Traits, true>
507 ::mapped_type&
508 _Map_base<_Key, _Pair, _Alloc, _Select1st, _Equal,
509 _H1, _H2, _Hash, _RehashPolicy, _Traits, true>::
510 operator[](key_type&& __k)
511 {
512 __hashtable* __h = static_cast<__hashtable*>(this);
513 __hash_code __code = __h->_M_hash_code(__k);
514 std::size_t __n = __h->_M_bucket_index(__k, __code);
515 __node_type* __p = __h->_M_find_node(__n, __k, __code);
516
517 if (!__p)
518 {
519 __p = __h->_M_allocate_node(std::piecewise_construct,
520 std::forward_as_tuple(std::move(__k)),
521 std::tuple<>());
522 return __h->_M_insert_unique_node(__n, __code, __p)->second;
523 }
524
525 return (__p->_M_v).second;
526 }
527
528 template<typename _Key, typename _Pair, typename _Alloc, typename _Equal,
529 typename _H1, typename _H2, typename _Hash,
530 typename _RehashPolicy, typename _Traits>
531 typename _Map_base<_Key, _Pair, _Alloc, _Select1st, _Equal,
532 _H1, _H2, _Hash, _RehashPolicy, _Traits, true>
533 ::mapped_type&
534 _Map_base<_Key, _Pair, _Alloc, _Select1st, _Equal,
535 _H1, _H2, _Hash, _RehashPolicy, _Traits, true>::
536 at(const key_type& __k)
537 {
538 __hashtable* __h = static_cast<__hashtable*>(this);
539 __hash_code __code = __h->_M_hash_code(__k);
540 std::size_t __n = __h->_M_bucket_index(__k, __code);
541 __node_type* __p = __h->_M_find_node(__n, __k, __code);
542
543 if (!__p)
544 __throw_out_of_range(__N("_Map_base::at")("_Map_base::at"));
545 return (__p->_M_v).second;
546 }
547
548 template<typename _Key, typename _Pair, typename _Alloc, typename _Equal,
549 typename _H1, typename _H2, typename _Hash,
550 typename _RehashPolicy, typename _Traits>
551 const typename _Map_base<_Key, _Pair, _Alloc, _Select1st,
552 _Equal, _H1, _H2, _Hash, _RehashPolicy,
553 _Traits, true>::mapped_type&
554 _Map_base<_Key, _Pair, _Alloc, _Select1st, _Equal,
555 _H1, _H2, _Hash, _RehashPolicy, _Traits, true>::
556 at(const key_type& __k) const
557 {
558 const __hashtable* __h = static_cast<const __hashtable*>(this);
559 __hash_code __code = __h->_M_hash_code(__k);
560 std::size_t __n = __h->_M_bucket_index(__k, __code);
561 __node_type* __p = __h->_M_find_node(__n, __k, __code);
562
563 if (!__p)
564 __throw_out_of_range(__N("_Map_base::at")("_Map_base::at"));
565 return (__p->_M_v).second;
566 }
567
568 /**
569 * Primary class template _Insert_base.
570 *
571 * insert member functions appropriate to all _Hashtables.
572 */
573 template<typename _Key, typename _Value, typename _Alloc,
574 typename _ExtractKey, typename _Equal,
575 typename _H1, typename _H2, typename _Hash,
576 typename _RehashPolicy, typename _Traits>
577 struct _Insert_base
578 {
579 using __hashtable = _Hashtable<_Key, _Value, _Alloc, _ExtractKey,
580 _Equal, _H1, _H2, _Hash,
581 _RehashPolicy, _Traits>;
582
583 using __hashtable_base = _Hashtable_base<_Key, _Value, _ExtractKey,
584 _Equal, _H1, _H2, _Hash,
585 _Traits>;
586
587 using value_type = typename __hashtable_base::value_type;
588 using iterator = typename __hashtable_base::iterator;
589 using const_iterator = typename __hashtable_base::const_iterator;
590 using size_type = typename __hashtable_base::size_type;
591
592 using __unique_keys = typename __hashtable_base::__unique_keys;
593 using __ireturn_type = typename __hashtable_base::__ireturn_type;
594 using __iconv_type = typename __hashtable_base::__iconv_type;
595
596 __hashtable&
597 _M_conjure_hashtable()
598 { return *(static_cast<__hashtable*>(this)); }
599
600 __ireturn_type
601 insert(const value_type& __v)
602 {
603 __hashtable& __h = _M_conjure_hashtable();
604 return __h._M_insert(__v, __unique_keys());
605 }
606
607 iterator
608 insert(const_iterator, const value_type& __v)
609 { return __iconv_type()(insert(__v)); }
610
611 void
612 insert(initializer_list<value_type> __l)
613 { this->insert(__l.begin(), __l.end()); }
614
615 template<typename _InputIterator>
616 void
617 insert(_InputIterator __first, _InputIterator __last);
618 };
619
620 template<typename _Key, typename _Value, typename _Alloc,
621 typename _ExtractKey, typename _Equal,
622 typename _H1, typename _H2, typename _Hash,
623 typename _RehashPolicy, typename _Traits>
624 template<typename _InputIterator>
625 void
626 _Insert_base<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash,
627 _RehashPolicy, _Traits>::
628 insert(_InputIterator __first, _InputIterator __last)
629 {
630 using __rehash_type = typename __hashtable::__rehash_type;
631 using __rehash_state = typename __hashtable::__rehash_state;
632 using pair_type = std::pair<bool, std::size_t>;
633
634 size_type __n_elt = __detail::__distance_fw(__first, __last);
635
636 __hashtable& __h = _M_conjure_hashtable();
637 __rehash_type& __rehash = __h._M_rehash_policy;
638 const __rehash_state& __saved_state = __rehash._M_state();
639 pair_type __do_rehash = __rehash._M_need_rehash(__h._M_bucket_count,
640 __h._M_element_count,
641 __n_elt);
642
643 if (__do_rehash.first)
644 __h._M_rehash(__do_rehash.second, __saved_state);
645
646 for (; __first != __last; ++__first)
647 __h._M_insert(*__first, __unique_keys());
648 }
649
650 /**
651 * Primary class template _Insert.
652 *
653 * Select insert member functions appropriate to _Hashtable policy choices.
654 */
655 template<typename _Key, typename _Value, typename _Alloc,
656 typename _ExtractKey, typename _Equal,
657 typename _H1, typename _H2, typename _Hash,
658 typename _RehashPolicy, typename _Traits,
659 bool _Constant_iterators = _Traits::__constant_iterators::value,
660 bool _Unique_keys = _Traits::__unique_keys::value>
661 struct _Insert;
662
663 /// Specialization.
664 template<typename _Key, typename _Value, typename _Alloc,
665 typename _ExtractKey, typename _Equal,
666 typename _H1, typename _H2, typename _Hash,
667 typename _RehashPolicy, typename _Traits>
668 struct _Insert<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash,
669 _RehashPolicy, _Traits, true, true>
670 : public _Insert_base<_Key, _Value, _Alloc, _ExtractKey, _Equal,
671 _H1, _H2, _Hash, _RehashPolicy, _Traits>
672 {
673 using __base_type = _Insert_base<_Key, _Value, _Alloc, _ExtractKey,
674 _Equal, _H1, _H2, _Hash,
675 _RehashPolicy, _Traits>;
676 using value_type = typename __base_type::value_type;
677 using iterator = typename __base_type::iterator;
678 using const_iterator = typename __base_type::const_iterator;
679
680 using __unique_keys = typename __base_type::__unique_keys;
681 using __hashtable = typename __base_type::__hashtable;
682
683 using __base_type::insert;
684
685 std::pair<iterator, bool>
686 insert(value_type&& __v)
687 {
688 __hashtable& __h = this->_M_conjure_hashtable();
689 return __h._M_insert(std::move(__v), __unique_keys());
690 }
691
692 iterator
693 insert(const_iterator, value_type&& __v)
694 { return insert(std::move(__v)).first; }
695 };
696
697 /// Specialization.
698 template<typename _Key, typename _Value, typename _Alloc,
699 typename _ExtractKey, typename _Equal,
700 typename _H1, typename _H2, typename _Hash,
701 typename _RehashPolicy, typename _Traits>
702 struct _Insert<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash,
703 _RehashPolicy, _Traits, true, false>
704 : public _Insert_base<_Key, _Value, _Alloc, _ExtractKey, _Equal,
705 _H1, _H2, _Hash, _RehashPolicy, _Traits>
706 {
707 using __base_type = _Insert_base<_Key, _Value, _Alloc, _ExtractKey,
708 _Equal, _H1, _H2, _Hash,
709 _RehashPolicy, _Traits>;
710 using value_type = typename __base_type::value_type;
711 using iterator = typename __base_type::iterator;
712 using const_iterator = typename __base_type::const_iterator;
713
714 using __unique_keys = typename __base_type::__unique_keys;
715 using __hashtable = typename __base_type::__hashtable;
716
717 using __base_type::insert;
718
719 iterator
720 insert(value_type&& __v)
721 {
722 __hashtable& __h = this->_M_conjure_hashtable();
723 return __h._M_insert(std::move(__v), __unique_keys());
724 }
725
726 iterator
727 insert(const_iterator, value_type&& __v)
728 { return insert(std::move(__v)); }
729 };
730
731 /// Specialization.
732 template<typename _Key, typename _Value, typename _Alloc,
733 typename _ExtractKey, typename _Equal,
734 typename _H1, typename _H2, typename _Hash,
735 typename _RehashPolicy, typename _Traits, bool _Unique_keys>
736 struct _Insert<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash,
737 _RehashPolicy, _Traits, false, _Unique_keys>
738 : public _Insert_base<_Key, _Value, _Alloc, _ExtractKey, _Equal,
739 _H1, _H2, _Hash, _RehashPolicy, _Traits>
740 {
741 using __base_type = _Insert_base<_Key, _Value, _Alloc, _ExtractKey,
742 _Equal, _H1, _H2, _Hash,
743 _RehashPolicy, _Traits>;
744 using value_type = typename __base_type::value_type;
745 using iterator = typename __base_type::iterator;
746 using const_iterator = typename __base_type::const_iterator;
747
748 using __unique_keys = typename __base_type::__unique_keys;
749 using __hashtable = typename __base_type::__hashtable;
750 using __ireturn_type = typename __base_type::__ireturn_type;
751 using __iconv_type = typename __base_type::__iconv_type;
752
753 using __base_type::insert;
754
755 template<typename _Pair>
756 using __is_cons = std::is_constructible<value_type, _Pair&&>;
757
758 template<typename _Pair>
759 using _IFcons = std::enable_if<__is_cons<_Pair>::value>;
760
761 template<typename _Pair>
762 using _IFconsp = typename _IFcons<_Pair>::type;
763
764 template<typename _Pair, typename = _IFconsp<_Pair>>
765 __ireturn_type
766 insert(_Pair&& __v)
767 {
768 __hashtable& __h = this->_M_conjure_hashtable();
769 return __h._M_emplace(__unique_keys(), std::forward<_Pair>(__v));
770 }
771
772 template<typename _Pair, typename = _IFconsp<_Pair>>
773 iterator
774 insert(const_iterator, _Pair&& __v)
775 { return __iconv_type()(insert(std::forward<_Pair>(__v))); }
776 };
777
778 /**
779 * Primary class template _Rehash_base.
780 *
781 * Give hashtable the max_load_factor functions and reserve iff the
782 * rehash policy is _Prime_rehash_policy.
783 */
784 template<typename _Key, typename _Value, typename _Alloc,
785 typename _ExtractKey, typename _Equal,
786 typename _H1, typename _H2, typename _Hash,
787 typename _RehashPolicy, typename _Traits>
788 struct _Rehash_base;
789
790 /// Specialization.
791 template<typename _Key, typename _Value, typename _Alloc,
792 typename _ExtractKey, typename _Equal,
793 typename _H1, typename _H2, typename _Hash, typename _Traits>
794 struct _Rehash_base<_Key, _Value, _Alloc, _ExtractKey, _Equal,
795 _H1, _H2, _Hash, _Prime_rehash_policy, _Traits>
796 {
797 using __hashtable = _Hashtable<_Key, _Value, _Alloc, _ExtractKey,
798 _Equal, _H1, _H2, _Hash,
799 _Prime_rehash_policy, _Traits>;
800
801 float
802 max_load_factor() const noexcept
803 {
804 const __hashtable* __this = static_cast<const __hashtable*>(this);
805 return __this->__rehash_policy().max_load_factor();
806 }
807
808 void
809 max_load_factor(float __z)
810 {
811 __hashtable* __this = static_cast<__hashtable*>(this);
812 __this->__rehash_policy(_Prime_rehash_policy(__z));
813 }
814
815 void
816 reserve(std::size_t __n)
817 {
818 __hashtable* __this = static_cast<__hashtable*>(this);
819 __this->rehash(__builtin_ceil(__n / max_load_factor()));
820 }
821 };
822
823 /**
824 * Primary class template _Hashtable_ebo_helper.
825 *
826 * Helper class using EBO when it is not forbidden, type is not
827 * final, and when it worth it, type is empty.
828 */
829 template<int _Nm, typename _Tp,
830 bool __use_ebo = !__is_final(_Tp) && __is_empty(_Tp)>
831 struct _Hashtable_ebo_helper;
832
833 /// Specialization using EBO.
834 template<int _Nm, typename _Tp>
835 struct _Hashtable_ebo_helper<_Nm, _Tp, true>
836 : private _Tp
837 {
838 _Hashtable_ebo_helper() = default;
839
840 _Hashtable_ebo_helper(const _Tp& __tp) : _Tp(__tp)
841 { }
842
843 static const _Tp&
844 _S_cget(const _Hashtable_ebo_helper& __eboh)
845 { return static_cast<const _Tp&>(__eboh); }
846
847 static _Tp&
848 _S_get(_Hashtable_ebo_helper& __eboh)
849 { return static_cast<_Tp&>(__eboh); }
850 };
851
852 /// Specialization not using EBO.
853 template<int _Nm, typename _Tp>
854 struct _Hashtable_ebo_helper<_Nm, _Tp, false>
855 {
856 _Hashtable_ebo_helper() = default;
857
858 _Hashtable_ebo_helper(const _Tp& __tp) : _M_tp(__tp)
859 { }
860
861 static const _Tp&
862 _S_cget(const _Hashtable_ebo_helper& __eboh)
863 { return __eboh._M_tp; }
864
865 static _Tp&
866 _S_get(_Hashtable_ebo_helper& __eboh)
867 { return __eboh._M_tp; }
868
869 private:
870 _Tp _M_tp;
871 };
872
873 /**
874 * Primary class template _Local_iterator_base.
875 *
876 * Base class for local iterators, used to iterate within a bucket
877 * but not between buckets.
878 */
879 template<typename _Key, typename _Value, typename _ExtractKey,
880 typename _H1, typename _H2, typename _Hash,
881 bool __cache_hash_code>
882 struct _Local_iterator_base;
883
884 /**
885 * Primary class template _Hash_code_base.
886 *
887 * Encapsulates two policy issues that aren't quite orthogonal.
888 * (1) the difference between using a ranged hash function and using
889 * the combination of a hash function and a range-hashing function.
890 * In the former case we don't have such things as hash codes, so
891 * we have a dummy type as placeholder.
892 * (2) Whether or not we cache hash codes. Caching hash codes is
893 * meaningless if we have a ranged hash function.
894 *
895 * We also put the key extraction objects here, for convenience.
896 * Each specialization derives from one or more of the template
897 * parameters to benefit from Ebo. This is important as this type
898 * is inherited in some cases by the _Local_iterator_base type used
899 * to implement local_iterator and const_local_iterator. As with
900 * any iterator type we prefer to make it as small as possible.
901 *
902 * Primary template is unused except as a hook for specializations.
903 */
904 template<typename _Key, typename _Value, typename _ExtractKey,
905 typename _H1, typename _H2, typename _Hash,
906 bool __cache_hash_code>
907 struct _Hash_code_base;
908
909 /// Specialization: ranged hash function, no caching hash codes. H1
910 /// and H2 are provided but ignored. We define a dummy hash code type.
911 template<typename _Key, typename _Value, typename _ExtractKey,
912 typename _H1, typename _H2, typename _Hash>
913 struct _Hash_code_base<_Key, _Value, _ExtractKey, _H1, _H2, _Hash, false>
914 : private _Hashtable_ebo_helper<0, _ExtractKey>,
915 private _Hashtable_ebo_helper<1, _Hash>
916 {
917 private:
918 using __ebo_extract_key = _Hashtable_ebo_helper<0, _ExtractKey>;
919 using __ebo_hash = _Hashtable_ebo_helper<1, _Hash>;
920
921 protected:
922 typedef void* __hash_code;
923 typedef _Hash_node<_Value, false> __node_type;
924
925 // We need the default constructor for the local iterators.
926 _Hash_code_base() = default;
927
928 _Hash_code_base(const _ExtractKey& __ex, const _H1&, const _H2&,
929 const _Hash& __h)
930 : __ebo_extract_key(__ex), __ebo_hash(__h) { }
931
932 __hash_code
933 _M_hash_code(const _Key& __key) const
934 { return 0; }
935
936 std::size_t
937 _M_bucket_index(const _Key& __k, __hash_code, std::size_t __n) const
938 { return _M_ranged_hash()(__k, __n); }
939
940 std::size_t
941 _M_bucket_index(const __node_type* __p, std::size_t __n) const
942 { return _M_ranged_hash()(_M_extract()(__p->_M_v), __n); }
943
944 void
945 _M_store_code(__node_type*, __hash_code) const
946 { }
947
948 void
949 _M_copy_code(__node_type*, const __node_type*) const
950 { }
951
952 void
953 _M_swap(_Hash_code_base& __x)
954 {
955 std::swap(_M_extract(), __x._M_extract());
956 std::swap(_M_ranged_hash(), __x._M_ranged_hash());
957 }
958
959 const _ExtractKey&
960 _M_extract() const { return __ebo_extract_key::_S_cget(*this); }
961
962 _ExtractKey&
963 _M_extract() { return __ebo_extract_key::_S_get(*this); }
964
965 const _Hash&
966 _M_ranged_hash() const { return __ebo_hash::_S_cget(*this); }
967
968 _Hash&
969 _M_ranged_hash() { return __ebo_hash::_S_get(*this); }
970 };
971
972 // No specialization for ranged hash function while caching hash codes.
973 // That combination is meaningless, and trying to do it is an error.
974
975 /// Specialization: ranged hash function, cache hash codes. This
976 /// combination is meaningless, so we provide only a declaration
977 /// and no definition.
978 template<typename _Key, typename _Value, typename _ExtractKey,
979 typename _H1, typename _H2, typename _Hash>
980 struct _Hash_code_base<_Key, _Value, _ExtractKey, _H1, _H2, _Hash, true>;
981
982 /// Specialization: hash function and range-hashing function, no
983 /// caching of hash codes.
984 /// Provides typedef and accessor required by C++ 11.
985 template<typename _Key, typename _Value, typename _ExtractKey,
986 typename _H1, typename _H2>
987 struct _Hash_code_base<_Key, _Value, _ExtractKey, _H1, _H2,
988 _Default_ranged_hash, false>
989 : private _Hashtable_ebo_helper<0, _ExtractKey>,
990 private _Hashtable_ebo_helper<1, _H1>,
991 private _Hashtable_ebo_helper<2, _H2>
992 {
993 private:
994 using __ebo_extract_key = _Hashtable_ebo_helper<0, _ExtractKey>;
995 using __ebo_h1 = _Hashtable_ebo_helper<1, _H1>;
996 using __ebo_h2 = _Hashtable_ebo_helper<2, _H2>;
997
998 public:
999 typedef _H1 hasher;
1000
1001 hasher
1002 hash_function() const
1003 { return _M_h1(); }
1004
1005 protected:
1006 typedef std::size_t __hash_code;
1007 typedef _Hash_node<_Value, false> __node_type;
1008
1009 // We need the default constructor for the local iterators.
1010 _Hash_code_base() = default;
1011
1012 _Hash_code_base(const _ExtractKey& __ex,
1013 const _H1& __h1, const _H2& __h2,
1014 const _Default_ranged_hash&)
1015 : __ebo_extract_key(__ex), __ebo_h1(__h1), __ebo_h2(__h2) { }
1016
1017 __hash_code
1018 _M_hash_code(const _Key& __k) const
1019 { return _M_h1()(__k); }
1020
1021 std::size_t
1022 _M_bucket_index(const _Key&, __hash_code __c, std::size_t __n) const
1023 { return _M_h2()(__c, __n); }
1024
1025 std::size_t
1026 _M_bucket_index(const __node_type* __p,
1027 std::size_t __n) const
1028 { return _M_h2()(_M_h1()(_M_extract()(__p->_M_v)), __n); }
1029
1030 void
1031 _M_store_code(__node_type*, __hash_code) const
1032 { }
1033
1034 void
1035 _M_copy_code(__node_type*, const __node_type*) const
1036 { }
1037
1038 void
1039 _M_swap(_Hash_code_base& __x)
1040 {
1041 std::swap(_M_extract(), __x._M_extract());
1042 std::swap(_M_h1(), __x._M_h1());
1043 std::swap(_M_h2(), __x._M_h2());
1044 }
1045
1046 const _ExtractKey&
1047 _M_extract() const { return __ebo_extract_key::_S_cget(*this); }
1048
1049 _ExtractKey&
1050 _M_extract() { return __ebo_extract_key::_S_get(*this); }
1051
1052 const _H1&
1053 _M_h1() const { return __ebo_h1::_S_cget(*this); }
1054
1055 _H1&
1056 _M_h1() { return __ebo_h1::_S_get(*this); }
1057
1058 const _H2&
1059 _M_h2() const { return __ebo_h2::_S_cget(*this); }
1060
1061 _H2&
1062 _M_h2() { return __ebo_h2::_S_get(*this); }
1063 };
1064
1065 /// Specialization: hash function and range-hashing function,
1066 /// caching hash codes. H is provided but ignored. Provides
1067 /// typedef and accessor required by C++ 11.
1068 template<typename _Key, typename _Value, typename _ExtractKey,
1069 typename _H1, typename _H2>
1070 struct _Hash_code_base<_Key, _Value, _ExtractKey, _H1, _H2,
1071 _Default_ranged_hash, true>
1072 : private _Hashtable_ebo_helper<0, _ExtractKey>,
1073 private _Hashtable_ebo_helper<1, _H1>,
1074 private _Hashtable_ebo_helper<2, _H2>
1075 {
1076 private:
1077 // Gives access to _M_h2() to the local iterator implementation.
1078 friend struct _Local_iterator_base<_Key, _Value, _ExtractKey, _H1, _H2,
1079 _Default_ranged_hash, true>;
1080
1081 using __ebo_extract_key = _Hashtable_ebo_helper<0, _ExtractKey>;
1082 using __ebo_h1 = _Hashtable_ebo_helper<1, _H1>;
1083 using __ebo_h2 = _Hashtable_ebo_helper<2, _H2>;
1084
1085 public:
1086 typedef _H1 hasher;
1087
1088 hasher
1089 hash_function() const
1090 { return _M_h1(); }
1091
1092 protected:
1093 typedef std::size_t __hash_code;
1094 typedef _Hash_node<_Value, true> __node_type;
1095
1096 _Hash_code_base(const _ExtractKey& __ex,
1097 const _H1& __h1, const _H2& __h2,
1098 const _Default_ranged_hash&)
1099 : __ebo_extract_key(__ex), __ebo_h1(__h1), __ebo_h2(__h2) { }
1100
1101 __hash_code
1102 _M_hash_code(const _Key& __k) const
1103 { return _M_h1()(__k); }
1104
1105 std::size_t
1106 _M_bucket_index(const _Key&, __hash_code __c,
1107 std::size_t __n) const
1108 { return _M_h2()(__c, __n); }
1109
1110 std::size_t
1111 _M_bucket_index(const __node_type* __p, std::size_t __n) const
1112 { return _M_h2()(__p->_M_hash_code, __n); }
1113
1114 void
1115 _M_store_code(__node_type* __n, __hash_code __c) const
1116 { __n->_M_hash_code = __c; }
1117
1118 void
1119 _M_copy_code(__node_type* __to, const __node_type* __from) const
1120 { __to->_M_hash_code = __from->_M_hash_code; }
1121
1122 void
1123 _M_swap(_Hash_code_base& __x)
1124 {
1125 std::swap(_M_extract(), __x._M_extract());
1126 std::swap(_M_h1(), __x._M_h1());
1127 std::swap(_M_h2(), __x._M_h2());
1128 }
1129
1130 const _ExtractKey&
1131 _M_extract() const { return __ebo_extract_key::_S_cget(*this); }
1132
1133 _ExtractKey&
1134 _M_extract() { return __ebo_extract_key::_S_get(*this); }
1135
1136 const _H1&
1137 _M_h1() const { return __ebo_h1::_S_cget(*this); }
1138
1139 _H1&
1140 _M_h1() { return __ebo_h1::_S_get(*this); }
1141
1142 const _H2&
1143 _M_h2() const { return __ebo_h2::_S_cget(*this); }
1144
1145 _H2&
1146 _M_h2() { return __ebo_h2::_S_get(*this); }
1147 };
1148
1149 /**
1150 * Primary class template _Equal_helper.
1151 *
1152 */
1153 template <typename _Key, typename _Value, typename _ExtractKey,
1154 typename _Equal, typename _HashCodeType,
1155 bool __cache_hash_code>
1156 struct _Equal_helper;
1157
1158 /// Specialization.
1159 template<typename _Key, typename _Value, typename _ExtractKey,
1160 typename _Equal, typename _HashCodeType>
1161 struct _Equal_helper<_Key, _Value, _ExtractKey, _Equal, _HashCodeType, true>
1162 {
1163 static bool
1164 _S_equals(const _Equal& __eq, const _ExtractKey& __extract,
1165 const _Key& __k, _HashCodeType __c, _Hash_node<_Value, true>* __n)
1166 { return __c == __n->_M_hash_code && __eq(__k, __extract(__n->_M_v)); }
1167 };
1168
1169 /// Specialization.
1170 template<typename _Key, typename _Value, typename _ExtractKey,
1171 typename _Equal, typename _HashCodeType>
1172 struct _Equal_helper<_Key, _Value, _ExtractKey, _Equal, _HashCodeType, false>
1173 {
1174 static bool
1175 _S_equals(const _Equal& __eq, const _ExtractKey& __extract,
1176 const _Key& __k, _HashCodeType, _Hash_node<_Value, false>* __n)
1177 { return __eq(__k, __extract(__n->_M_v)); }
1178 };
1179
1180
1181 /// Specialization.
1182 template<typename _Key, typename _Value, typename _ExtractKey,
1183 typename _H1, typename _H2, typename _Hash>
1184 struct _Local_iterator_base<_Key, _Value, _ExtractKey,
1185 _H1, _H2, _Hash, true>
1186 : private _Hashtable_ebo_helper<0, _H2>
1187 {
1188 protected:
1189 using __base_type = _Hashtable_ebo_helper<0, _H2>;
1190 using __hash_code_base = _Hash_code_base<_Key, _Value, _ExtractKey,
1191 _H1, _H2, _Hash, true>;
1192
1193 public:
1194 _Local_iterator_base() = default;
1195 _Local_iterator_base(const __hash_code_base& __base,
1196 _Hash_node<_Value, true>* __p,
1197 std::size_t __bkt, std::size_t __bkt_count)
1198 : __base_type(__base._M_h2()),
1199 _M_cur(__p), _M_bucket(__bkt), _M_bucket_count(__bkt_count) { }
1200
1201 void
1202 _M_incr()
1203 {
1204 _M_cur = _M_cur->_M_next();
1205 if (_M_cur)
1206 {
1207 std::size_t __bkt
1208 = __base_type::_S_get(*this)(_M_cur->_M_hash_code,
1209 _M_bucket_count);
1210 if (__bkt != _M_bucket)
1211 _M_cur = nullptr;
1212 }
1213 }
1214
1215 _Hash_node<_Value, true>* _M_cur;
1216 std::size_t _M_bucket;
1217 std::size_t _M_bucket_count;
1218 };
1219
1220 /// Specialization.
1221 template<typename _Key, typename _Value, typename _ExtractKey,
1222 typename _H1, typename _H2, typename _Hash>
1223 struct _Local_iterator_base<_Key, _Value, _ExtractKey,
1224 _H1, _H2, _Hash, false>
1225 : private _Hash_code_base<_Key, _Value, _ExtractKey,
1226 _H1, _H2, _Hash, false>
1227 {
1228 protected:
1229 using __hash_code_base = _Hash_code_base<_Key, _Value, _ExtractKey,
1230 _H1, _H2, _Hash, false>;
1231
1232 public:
1233 _Local_iterator_base() = default;
1234 _Local_iterator_base(const __hash_code_base& __base,
1235 _Hash_node<_Value, false>* __p,
1236 std::size_t __bkt, std::size_t __bkt_count)
1237 : __hash_code_base(__base),
1238 _M_cur(__p), _M_bucket(__bkt), _M_bucket_count(__bkt_count) { }
1239
1240 void
1241 _M_incr()
1242 {
1243 _M_cur = _M_cur->_M_next();
1244 if (_M_cur)
1245 {
1246 std::size_t __bkt = this->_M_bucket_index(_M_cur, _M_bucket_count);
1247 if (__bkt != _M_bucket)
1248 _M_cur = nullptr;
1249 }
1250 }
1251
1252 _Hash_node<_Value, false>* _M_cur;
1253 std::size_t _M_bucket;
1254 std::size_t _M_bucket_count;
1255 };
1256
1257 template<typename _Key, typename _Value, typename _ExtractKey,
1258 typename _H1, typename _H2, typename _Hash, bool __cache>
1259 inline bool
1260 operator==(const _Local_iterator_base<_Key, _Value, _ExtractKey,
1261 _H1, _H2, _Hash, __cache>& __x,
1262 const _Local_iterator_base<_Key, _Value, _ExtractKey,
1263 _H1, _H2, _Hash, __cache>& __y)
1264 { return __x._M_cur == __y._M_cur; }
1265
1266 template<typename _Key, typename _Value, typename _ExtractKey,
1267 typename _H1, typename _H2, typename _Hash, bool __cache>
1268 inline bool
1269 operator!=(const _Local_iterator_base<_Key, _Value, _ExtractKey,
1270 _H1, _H2, _Hash, __cache>& __x,
1271 const _Local_iterator_base<_Key, _Value, _ExtractKey,
1272 _H1, _H2, _Hash, __cache>& __y)
1273 { return __x._M_cur != __y._M_cur; }
1274
1275 /// local iterators
1276 template<typename _Key, typename _Value, typename _ExtractKey,
1277 typename _H1, typename _H2, typename _Hash,
1278 bool __constant_iterators, bool __cache>
1279 struct _Local_iterator
1280 : public _Local_iterator_base<_Key, _Value, _ExtractKey,
1281 _H1, _H2, _Hash, __cache>
1282 {
1283 private:
1284 using __base_type = _Local_iterator_base<_Key, _Value, _ExtractKey,
1285 _H1, _H2, _Hash, __cache>;
1286 using __hash_code_base = typename __base_type::__hash_code_base;
1287 public:
1288 typedef _Value value_type;
1289 typedef typename std::conditional<__constant_iterators,
1290 const _Value*, _Value*>::type
1291 pointer;
1292 typedef typename std::conditional<__constant_iterators,
1293 const _Value&, _Value&>::type
1294 reference;
1295 typedef std::ptrdiff_t difference_type;
1296 typedef std::forward_iterator_tag iterator_category;
1297
1298 _Local_iterator() = default;
1299
1300 _Local_iterator(const __hash_code_base& __base,
1301 _Hash_node<_Value, __cache>* __p,
1302 std::size_t __bkt, std::size_t __bkt_count)
1303 : __base_type(__base, __p, __bkt, __bkt_count)
1304 { }
1305
1306 reference
1307 operator*() const
1308 { return this->_M_cur->_M_v; }
1309
1310 pointer
1311 operator->() const
1312 { return std::__addressof(this->_M_cur->_M_v); }
1313
1314 _Local_iterator&
1315 operator++()
1316 {
1317 this->_M_incr();
1318 return *this;
1319 }
1320
1321 _Local_iterator
1322 operator++(int)
1323 {
1324 _Local_iterator __tmp(*this);
1325 this->_M_incr();
1326 return __tmp;
1327 }
1328 };
1329
1330 /// local const_iterators
1331 template<typename _Key, typename _Value, typename _ExtractKey,
1332 typename _H1, typename _H2, typename _Hash,
1333 bool __constant_iterators, bool __cache>
1334 struct _Local_const_iterator
1335 : public _Local_iterator_base<_Key, _Value, _ExtractKey,
1336 _H1, _H2, _Hash, __cache>
1337 {
1338 private:
1339 using __base_type = _Local_iterator_base<_Key, _Value, _ExtractKey,
1340 _H1, _H2, _Hash, __cache>;
1341 using __hash_code_base = typename __base_type::__hash_code_base;
1342
1343 public:
1344 typedef _Value value_type;
1345 typedef const _Value* pointer;
1346 typedef const _Value& reference;
1347 typedef std::ptrdiff_t difference_type;
1348 typedef std::forward_iterator_tag iterator_category;
1349
1350 _Local_const_iterator() = default;
1351
1352 _Local_const_iterator(const __hash_code_base& __base,
1353 _Hash_node<_Value, __cache>* __p,
1354 std::size_t __bkt, std::size_t __bkt_count)
1355 : __base_type(__base, __p, __bkt, __bkt_count)
1356 { }
1357
1358 _Local_const_iterator(const _Local_iterator<_Key, _Value, _ExtractKey,
1359 _H1, _H2, _Hash,
1360 __constant_iterators,
1361 __cache>& __x)
1362 : __base_type(__x)
1363 { }
1364
1365 reference
1366 operator*() const
1367 { return this->_M_cur->_M_v; }
1368
1369 pointer
1370 operator->() const
1371 { return std::__addressof(this->_M_cur->_M_v); }
1372
1373 _Local_const_iterator&
1374 operator++()
1375 {
1376 this->_M_incr();
1377 return *this;
1378 }
1379
1380 _Local_const_iterator
1381 operator++(int)
1382 {
1383 _Local_const_iterator __tmp(*this);
1384 this->_M_incr();
1385 return __tmp;
1386 }
1387 };
1388
1389 /**
1390 * Primary class template _Hashtable_base.
1391 *
1392 * Helper class adding management of _Equal functor to
1393 * _Hash_code_base type.
1394 *
1395 * Base class templates are:
1396 * - __detail::_Hash_code_base
1397 * - __detail::_Hashtable_ebo_helper
1398 */
1399 template<typename _Key, typename _Value,
1400 typename _ExtractKey, typename _Equal,
1401 typename _H1, typename _H2, typename _Hash, typename _Traits>
1402 struct _Hashtable_base
1403 : public _Hash_code_base<_Key, _Value, _ExtractKey, _H1, _H2, _Hash,
1404 _Traits::__hash_cached::value>,
1405 private _Hashtable_ebo_helper<0, _Equal>
1406 {
1407 public:
1408 typedef _Key key_type;
1409 typedef _Value value_type;
1410 typedef _Equal key_equal;
1411 typedef std::size_t size_type;
1412 typedef std::ptrdiff_t difference_type;
1413
1414 using __traits_type = _Traits;
1415 using __hash_cached = typename __traits_type::__hash_cached;
1416 using __constant_iterators = typename __traits_type::__constant_iterators;
1417 using __unique_keys = typename __traits_type::__unique_keys;
1418
1419 using __hash_code_base = _Hash_code_base<_Key, _Value, _ExtractKey,
1420 _H1, _H2, _Hash,
1421 __hash_cached::value>;
1422
1423 using __hash_code = typename __hash_code_base::__hash_code;
1424 using __node_type = typename __hash_code_base::__node_type;
1425
1426 using iterator = __detail::_Node_iterator<value_type,
1427 __constant_iterators::value,
1428 __hash_cached::value>;
1429
1430 using const_iterator = __detail::_Node_const_iterator<value_type,
1431 __constant_iterators::value,
1432 __hash_cached::value>;
1433
1434 using local_iterator = __detail::_Local_iterator<key_type, value_type,
1435 _ExtractKey, _H1, _H2, _Hash,
1436 __constant_iterators::value,
1437 __hash_cached::value>;
1438
1439 using const_local_iterator = __detail::_Local_const_iterator<key_type,
1440 value_type,
1441 _ExtractKey, _H1, _H2, _Hash,
1442 __constant_iterators::value,
1443 __hash_cached::value>;
1444
1445 using __ireturn_type = typename std::conditional<__unique_keys::value,
1446 std::pair<iterator, bool>,
1447 iterator>::type;
1448
1449 using __iconv_type = typename std::conditional<__unique_keys::value,
1450 _Select1st, _Identity
1451 >::type;
1452 private:
1453 using _EqualEBO = _Hashtable_ebo_helper<0, _Equal>;
1454 using _EqualHelper = _Equal_helper<_Key, _Value, _ExtractKey, _Equal,
1455 __hash_code, __hash_cached::value>;
1456
1457 protected:
1458 using __node_base = __detail::_Hash_node_base;
1459 using __bucket_type = __node_base*;
1460
1461 _Hashtable_base(const _ExtractKey& __ex, const _H1& __h1, const _H2& __h2,
1462 const _Hash& __hash, const _Equal& __eq)
1463 : __hash_code_base(__ex, __h1, __h2, __hash), _EqualEBO(__eq)
1464 { }
1465
1466 bool
1467 _M_equals(const _Key& __k, __hash_code __c, __node_type* __n) const
1468 {
1469 return _EqualHelper::_S_equals(_M_eq(), this->_M_extract(),
1470 __k, __c, __n);
1471 }
1472
1473 void
1474 _M_swap(_Hashtable_base& __x)
1475 {
1476 __hash_code_base::_M_swap(__x);
1477 std::swap(_M_eq(), __x._M_eq());
1478 }
1479
1480 const _Equal&
1481 _M_eq() const { return _EqualEBO::_S_cget(*this); }
1482
1483 _Equal&
1484 _M_eq() { return _EqualEBO::_S_get(*this); }
1485 };
1486
1487 /**
1488 * struct _Equality_base.
1489 *
1490 * Common types and functions for class _Equality.
1491 */
1492 struct _Equality_base
1493 {
1494 protected:
1495 template<typename _Uiterator>
1496 static bool
1497 _S_is_permutation(_Uiterator, _Uiterator, _Uiterator);
1498 };
1499
1500 // See std::is_permutation in N3068.
1501 template<typename _Uiterator>
1502 bool
1503 _Equality_base::
1504 _S_is_permutation(_Uiterator __first1, _Uiterator __last1,
1505 _Uiterator __first2)
1506 {
1507 for (; __first1 != __last1; ++__first1, ++__first2)
1508 if (!(*__first1 == *__first2))
1509 break;
1510
1511 if (__first1 == __last1)
1512 return true;
1513
1514 _Uiterator __last2 = __first2;
1515 std::advance(__last2, std::distance(__first1, __last1));
1516
1517 for (_Uiterator __it1 = __first1; __it1 != __last1; ++__it1)
1518 {
1519 _Uiterator __tmp = __first1;
1520 while (__tmp != __it1 && !bool(*__tmp == *__it1))
1521 ++__tmp;
1522
1523 // We've seen this one before.
1524 if (__tmp != __it1)
1525 continue;
1526
1527 std::ptrdiff_t __n2 = 0;
1528 for (__tmp = __first2; __tmp != __last2; ++__tmp)
1529 if (*__tmp == *__it1)
1530 ++__n2;
1531
1532 if (!__n2)
1533 return false;
1534
1535 std::ptrdiff_t __n1 = 0;
1536 for (__tmp = __it1; __tmp != __last1; ++__tmp)
1537 if (*__tmp == *__it1)
1538 ++__n1;
1539
1540 if (__n1 != __n2)
1541 return false;
1542 }
1543 return true;
1544 }
1545
1546 /**
1547 * Primary class template _Equality.
1548 *
1549 * This is for implementing equality comparison for unordered
1550 * containers, per N3068, by John Lakos and Pablo Halpern.
1551 * Algorithmically, we follow closely the reference implementations
1552 * therein.
1553 */
1554 template<typename _Key, typename _Value, typename _Alloc,
1555 typename _ExtractKey, typename _Equal,
1556 typename _H1, typename _H2, typename _Hash,
1557 typename _RehashPolicy, typename _Traits,
1558 bool _Unique_keys = _Traits::__unique_keys::value>
1559 struct _Equality;
1560
1561 /// Specialization.
1562 template<typename _Key, typename _Value, typename _Alloc,
1563 typename _ExtractKey, typename _Equal,
1564 typename _H1, typename _H2, typename _Hash,
1565 typename _RehashPolicy, typename _Traits>
1566 struct _Equality<_Key, _Value, _Alloc, _ExtractKey, _Equal,
1567 _H1, _H2, _Hash, _RehashPolicy, _Traits, true>
1568 {
1569 using __hashtable = _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
1570 _H1, _H2, _Hash, _RehashPolicy, _Traits>;
1571
1572 bool
1573 _M_equal(const __hashtable&) const;
1574 };
1575
1576 template<typename _Key, typename _Value, typename _Alloc,
1577 typename _ExtractKey, typename _Equal,
1578 typename _H1, typename _H2, typename _Hash,
1579 typename _RehashPolicy, typename _Traits>
1580 bool
1581 _Equality<_Key, _Value, _Alloc, _ExtractKey, _Equal,
1582 _H1, _H2, _Hash, _RehashPolicy, _Traits, true>::
1583 _M_equal(const __hashtable& __other) const
1584 {
1585 const __hashtable* __this = static_cast<const __hashtable*>(this);
1586
1587 if (__this->size() != __other.size())
1588 return false;
1589
1590 for (auto __itx = __this->begin(); __itx != __this->end(); ++__itx)
1591 {
1592 const auto __ity = __other.find(_ExtractKey()(*__itx));
1593 if (__ity == __other.end() || !bool(*__ity == *__itx))
1594 return false;
1595 }
1596 return true;
1597 }
1598
1599 /// Specialization.
1600 template<typename _Key, typename _Value, typename _Alloc,
1601 typename _ExtractKey, typename _Equal,
1602 typename _H1, typename _H2, typename _Hash,
1603 typename _RehashPolicy, typename _Traits>
1604 struct _Equality<_Key, _Value, _Alloc, _ExtractKey, _Equal,
1605 _H1, _H2, _Hash, _RehashPolicy, _Traits, false>
1606 : public _Equality_base
1607 {
1608 using __hashtable = _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
1609 _H1, _H2, _Hash, _RehashPolicy, _Traits>;
1610
1611 bool
1612 _M_equal(const __hashtable&) const;
1613 };
1614
1615 template<typename _Key, typename _Value, typename _Alloc,
1616 typename _ExtractKey, typename _Equal,
1617 typename _H1, typename _H2, typename _Hash,
1618 typename _RehashPolicy, typename _Traits>
1619 bool
1620 _Equality<_Key, _Value, _Alloc, _ExtractKey, _Equal,
1621 _H1, _H2, _Hash, _RehashPolicy, _Traits, false>::
1622 _M_equal(const __hashtable& __other) const
1623 {
1624 const __hashtable* __this = static_cast<const __hashtable*>(this);
1625
1626 if (__this->size() != __other.size())
1627 return false;
1628
1629 for (auto __itx = __this->begin(); __itx != __this->end();)
1630 {
1631 const auto __xrange = __this->equal_range(_ExtractKey()(*__itx));
1632 const auto __yrange = __other.equal_range(_ExtractKey()(*__itx));
1633
1634 if (std::distance(__xrange.first, __xrange.second)
1635 != std::distance(__yrange.first, __yrange.second))
1636 return false;
1637
1638 if (!_S_is_permutation(__xrange.first, __xrange.second,
1639 __yrange.first))
1640 return false;
1641
1642 __itx = __xrange.second;
1643 }
1644 return true;
1645 }
1646
1647 /**
1648 * This type is to combine a _Hash_node_base instance with an allocator
1649 * instance through inheritance to benefit from EBO when possible.
1650 */
1651 template<typename _NodeAlloc>
1652 struct _Before_begin : public _NodeAlloc
1653 {
1654 _Hash_node_base _M_node;
1655
1656 _Before_begin(const _Before_begin&) = default;
1657 _Before_begin(_Before_begin&&) = default;
1658
1659 template<typename _Alloc>
1660 _Before_begin(_Alloc&& __a)
1661 : _NodeAlloc(std::forward<_Alloc>(__a))
1662 { }
1663 };
1664
1665 //@} hashtable-detail
1666_GLIBCXX_END_NAMESPACE_VERSION
1667} // namespace __detail
1668} // namespace std
1669
1670#endif // _HASHTABLE_POLICY_H