CMS 3D CMS Logo

 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
JetMatchingPy8Internal.cc
Go to the documentation of this file.
2 
3 using namespace Pythia8;
4 
5 //==========================================================================
6 
7 // Main implementation of JetMatching class.
8 // This may be split out to a separate C++ file if desired,
9 // but currently included here for ease of use.
10 
11 //--------------------------------------------------------------------------
12 
13 // Constants to be changed for debug printout or extra checks.
14 const bool JetMatching::MATCHINGDEBUG = false;
15 const bool JetMatching::MATCHINGCHECK = false;
16 
17 //--------------------------------------------------------------------------
18 
19 // Early parton level veto (before beam remnants and resonance showers)
20 
22 
23  // 1) Sort the original incoming process. After this step is performed,
24  // the following assignments have been made:
25  // eventProcessOrig - the original incoming process
26  // eventProcess - the final-state of the incoming process with
27  // resonance decays removed (and resonances
28  // themselves now with positive status code)
29  // typeIdx[0/1/2] - Indices into 'eventProcess' of
30  // light jets/heavy jets/other
31  // typeSet[0/1/2] - Indices into 'event' of light jets/heavy jets/other
32  // workEvent - partons from the hardest subsystem + ISR + FSR only
33  sortIncomingProcess(event);
34 
35  // For the shower-kT scheme, do not perform any veto here, as any vetoing
36  // will already have taken place in doVetoStep.
37  if ( doShowerKt ) return false;
38 
39  // Debug printout.
40  if (MATCHINGDEBUG) {
41  // Begin
42  cout << endl << "-------- Begin Madgraph Debug --------" << endl;
43  // Original incoming process
44  cout << endl << "Original incoming process:";
45  eventProcessOrig.list();
46  // Final-state of original incoming process
47  cout << endl << "Final-state incoming process:";
48  eventProcess.list();
49  // List categories of sorted particles
50  for (size_t i = 0; i < typeIdx[0].size(); i++)
51  cout << ((i == 0) ? "Light jets: " : ", ") << setw(3) << typeIdx[0][i];
52  if( typeIdx[0].size()== 0 )
53  cout << "Light jets: None";
54 
55  for (size_t i = 0; i < typeIdx[1].size(); i++)
56  cout << ((i == 0) ? "\nHeavy jets: " : ", ") << setw(3) << typeIdx[1][i];
57  for (size_t i = 0; i < typeIdx[2].size(); i++)
58  cout << ((i == 0) ? "\nOther: " : ", ") << setw(3) << typeIdx[2][i];
59  // Full event at this stage
60  cout << endl << endl << "Event:";
61  event.list();
62  // Work event (partons from hardest subsystem + ISR + FSR)
63  cout << endl << "Work event:";
64  workEvent.list();
65  }
66 
67  // 2) Light/heavy jets: iType = 0 (light jets), 1 (heavy jets)
68  int iTypeEnd = (typeIdx[1].empty()) ? 1 : 2;
69  for (int iType = 0; iType < iTypeEnd; iType++) {
70 
71  // 2a) Find particles which will be passed from the jet algorithm.
72  // Input from 'workEvent' and output in 'workEventJet'.
73  jetAlgorithmInput(event, iType);
74 
75  // Debug printout.
76  if (MATCHINGDEBUG) {
77  // Jet algorithm event
78  cout << endl << "Jet algorithm event (iType = " << iType << "):";
79  workEventJet.list();
80  }
81 
82  // 2b) Run jet algorithm on 'workEventJet'.
83  // Output is stored in jetMomenta.
84  runJetAlgorithm();
85 
86  // 2c) Match partons to jets and decide if veto is necessary
87  if (matchPartonsToJets(iType) == true) {
88  // Debug printout.
89  if (MATCHINGDEBUG) {
90  cout << endl << "Event vetoed" << endl
91  << "---------- End MLM Debug ----------" << endl;
92  }
93  return true;
94  }
95  }
96 
97  // Debug printout.
98  if (MATCHINGDEBUG) {
99  cout << endl << "Event accepted" << endl
100  << "---------- End MLM Debug ----------" << endl;
101  }
102 
103  // If we reached here, then no veto
104  return false;
105 
106 }
107 
108 //==========================================================================
109 
110 // Main implementation of Alpgen UserHooks class.
111 // This may be split out to a separate C++ file if desired,
112 // but currently included here for ease of use.
113 
114 //--------------------------------------------------------------------------
115 
116 // Constants: could be changed here if desired, but normally should not.
117 // These are of technical nature, as described for each.
118 
119 // The energy of ghost particles. For technical reasons, this cannot be
120 // set arbitrarily low, see 'Particle::TINY' in 'Event.cc' for details.
121 const double JetMatchingAlpgen::GHOSTENERGY = 1e-15;
122 
123 // A zero threshold value for double comparisons.
124 const double JetMatchingAlpgen::ZEROTHRESHOLD = 1e-10;
125 
126 //--------------------------------------------------------------------------
127 
128 // Function to sort typeIdx vectors into descending eT/pT order.
129 // Uses a selection sort, as number of partons generally small
130 // and so efficiency not a worry.
131 
132 void JetMatchingAlpgen::sortTypeIdx(vector < int > &vecIn) {
133  for (size_t i = 0; i < vecIn.size(); i++) {
134  size_t jMax = i;
135  double vMax = (jetAlgorithm == 1) ?
136  eventProcess[vecIn[i]].eT() :
137  eventProcess[vecIn[i]].pT();
138  for (size_t j = i + 1; j < vecIn.size(); j++) {
139  double vNow = (jetAlgorithm == 1)
140  ? eventProcess[vecIn[j]].eT() : eventProcess[vecIn[j]].pT();
141  if (vNow > vMax) {
142  vMax = vNow;
143  jMax = j;
144  }
145  }
146  if (jMax != i) swap(vecIn[i], vecIn[jMax]);
147  }
148 }
149 
150 //--------------------------------------------------------------------------
151 
152 // Initialisation routine automatically called from Pythia::init().
153 // Setup all parts needed for the merging.
154 
156 
157  // Read in parameters
158  doMerge = settingsPtr->flag("JetMatching:merge");
159  jetAlgorithm = settingsPtr->mode("JetMatching:jetAlgorithm");
160  nJet = settingsPtr->mode("JetMatching:nJet");
161  nJetMax = settingsPtr->mode("JetMatching:nJetMax");
162  eTjetMin = settingsPtr->parm("JetMatching:eTjetMin");
163  coneRadius = settingsPtr->parm("JetMatching:coneRadius");
164  etaJetMax = settingsPtr->parm("JetMatching:etaJetMax");
165 
166  // Use etaJetMax + coneRadius in input to jet algorithms
167  etaJetMaxAlgo = etaJetMax + coneRadius;
168 
169  // CellJet specific
170  nEta = settingsPtr->mode("JetMatching:nEta");
171  nPhi = settingsPtr->mode("JetMatching:nPhi");
172  eTseed = settingsPtr->parm("JetMatching:eTseed");
173  eTthreshold = settingsPtr->parm("JetMatching:eTthreshold");
174 
175  // SlowJet specific
176  slowJetPower = settingsPtr->mode("JetMatching:slowJetPower");
177  coneMatchLight = settingsPtr->parm("JetMatching:coneMatchLight");
178  coneRadiusHeavy = settingsPtr->parm("JetMatching:coneRadiusHeavy");
179  if (coneRadiusHeavy < 0.) coneRadiusHeavy = coneRadius;
180  coneMatchHeavy = settingsPtr->parm("JetMatching:coneMatchHeavy");
181 
182  // Matching procedure
183  jetAllow = settingsPtr->mode("JetMatching:jetAllow");
184  jetMatch = settingsPtr->mode("JetMatching:jetMatch");
185  exclusiveMode = settingsPtr->mode("JetMatching:exclusive");
186 
187  // If not merging, then done
188  if (!doMerge) return true;
189 
190  // Exclusive mode; if set to 2, then set based on nJet/nJetMax
191  if (exclusiveMode == 2) {
192 
193  // No nJet or nJetMax, so default to exclusive mode
194  if (nJet < 0 || nJetMax < 0) {
195  infoPtr->errorMsg("Warning in JetMatchingAlpgen:init: "
196  "missing jet multiplicity information; running in exclusive mode");
197  exclusive = true;
198 
199  // Inclusive if nJet == nJetMax, exclusive otherwise
200  } else {
201  exclusive = (nJet == nJetMax) ? false : true;
202  }
203 
204  // Otherwise, just set as given
205  } else {
206  exclusive = (exclusiveMode == 0) ? false : true;
207  }
208 
209  // Initialise chosen jet algorithm. CellJet.
210  if (jetAlgorithm == 1) {
211 
212  // Extra options for CellJet. nSel = 1 means that all final-state
213  // particles are taken and we retain control of what to select.
214  // smear/resolution/upperCut are not used and are set to default values.
215  int nSel = 2, smear = 0;
216  double resolution = 0.5, upperCut = 2.;
217  cellJet = new CellJet(etaJetMaxAlgo, nEta, nPhi, nSel,
218  smear, resolution, upperCut, eTthreshold);
219 
220  // SlowJet
221  } else if (jetAlgorithm == 2) {
222  slowJet = new SlowJet(slowJetPower, coneRadius, eTjetMin, etaJetMaxAlgo);
223  }
224 
225  // Check the jetMatch parameter; option 2 only works with SlowJet
226  if (jetAlgorithm == 1 && jetMatch == 2) {
227  infoPtr->errorMsg("Warning in JetMatchingAlpgen:init: "
228  "jetMatch = 2 only valid with SlowJet algorithm. "
229  "Reverting to jetMatch = 1");
230  jetMatch = 1;
231  }
232 
233  // Setup local event records
234  eventProcessOrig.init("(eventProcessOrig)", particleDataPtr);
235  eventProcess.init("(eventProcess)", particleDataPtr);
236  workEventJet.init("(workEventJet)", particleDataPtr);
237 
238  // Print information
239  string jetStr = (jetAlgorithm == 1) ? "CellJet" :
240  (slowJetPower == -1) ? "anti-kT" :
241  (slowJetPower == 0) ? "C/A" :
242  (slowJetPower == 1) ? "kT" : "unknown";
243  string modeStr = (exclusive) ? "exclusive" : "inclusive";
244  stringstream nJetStr, nJetMaxStr;
245  if (nJet >= 0) nJetStr << nJet; else nJetStr << "unknown";
246  if (nJetMax >= 0) nJetMaxStr << nJetMax; else nJetMaxStr << "unknown";
247  cout << endl
248  << " *------- MLM matching parameters -------*" << endl
249  << " | nJet | " << setw(14)
250  << nJetStr.str() << " |" << endl
251  << " | nJetMax | " << setw(14)
252  << nJetMaxStr.str() << " |" << endl
253  << " | Jet algorithm | " << setw(14)
254  << jetStr << " |" << endl
255  << " | eTjetMin | " << setw(14)
256  << eTjetMin << " |" << endl
257  << " | coneRadius | " << setw(14)
258  << coneRadius << " |" << endl
259  << " | etaJetMax | " << setw(14)
260  << etaJetMax << " |" << endl
261  << " | jetAllow | " << setw(14)
262  << jetAllow << " |" << endl
263  << " | jetMatch | " << setw(14)
264  << jetMatch << " |" << endl
265  << " | coneMatchLight | " << setw(14)
266  << coneMatchLight << " |" << endl
267  << " | coneRadiusHeavy | " << setw(14)
268  << coneRadiusHeavy << " |" << endl
269  << " | coneMatchHeavy | " << setw(14)
270  << coneMatchHeavy << " |" << endl
271  << " | Mode | " << setw(14)
272  << modeStr << " |" << endl
273  << " *-----------------------------------------*" << endl;
274 
275  return true;
276 }
277 
278 //--------------------------------------------------------------------------
279 
280 // Step (1): sort the incoming particles
281 
283 
284  // Remove resonance decays from original process and keep only final
285  // state. Resonances will have positive status code after this step.
286  omitResonanceDecays(eventProcessOrig, true);
287  eventProcess = workEvent;
288 
289  // Sort original process final state into light/heavy jets and 'other'.
290  // Criteria:
291  // 1 <= ID <= 5 and massless, or ID == 21 --> light jet (typeIdx[0])
292  // 4 <= ID <= 6 and massive --> heavy jet (typeIdx[1])
293  // All else --> other (typeIdx[2])
294  // Note that 'typeIdx' stores indices into 'eventProcess' (after resonance
295  // decays are omitted), while 'typeSet' stores indices into the original
296  // process record, 'eventProcessOrig', but these indices are also valid
297  // in 'event'.
298  for (int i = 0; i < 3; i++) {
299  typeIdx[i].clear();
300  typeSet[i].clear();
301  }
302  for (int i = 0; i < eventProcess.size(); i++) {
303  // Ignore nonfinal and default to 'other'
304  if (!eventProcess[i].isFinal()) continue;
305  int idx = 2;
306 
307  // Light jets
308  if (eventProcess[i].id() == ID_GLUON
309  || (eventProcess[i].idAbs() <= ID_BOT
310  && abs(eventProcess[i].m()) < ZEROTHRESHOLD)) idx = 0;
311 
312  // Heavy jets
313  else if (eventProcess[i].idAbs() >= ID_CHARM
314  && eventProcess[i].idAbs() <= ID_TOP) idx = 1;
315 
316  // Store
317  typeIdx[idx].push_back(i);
318  typeSet[idx].insert(eventProcess[i].daughter1());
319  }
320 
321  // Extract partons from hardest subsystem + ISR + FSR only into
322  // workEvent. Note no resonance showers or MPIs.
323  subEvent(event);
324 }
325 
326 //--------------------------------------------------------------------------
327 
328 // Step (2a): pick which particles to pass to the jet algorithm
329 
330 void JetMatchingAlpgen::jetAlgorithmInput(const Event &event, int iType) {
331 
332  // Take input from 'workEvent' and put output in 'workEventJet'
333  workEventJet = workEvent;
334 
335  // Loop over particles and decide what to pass to the jet algorithm
336  for (int i = 0; i < workEventJet.size(); ++i) {
337  if (!workEventJet[i].isFinal()) continue;
338 
339  // jetAllow option to disallow certain particle types
340  if (jetAllow == 1) {
341 
342  // Original AG+Py6 algorithm explicitly excludes tops,
343  // leptons and photons.
344  int id = workEventJet[i].idAbs();
345  if ( (id >= ID_LEPMIN && id <= ID_LEPMAX) || id == ID_TOP
346  || id == ID_PHOTON) {
347  workEventJet[i].statusNeg();
348  continue;
349  }
350  }
351 
352  // Get the index of this particle in original event
353  int idx = workEventJet[i].daughter1();
354 
355  // Start with particle idx, and afterwards track mothers
356  while (true) {
357 
358  // Light jets
359  if (iType == 0) {
360 
361  // Do not include if originates from heavy jet or 'other'
362  if (typeSet[1].find(idx) != typeSet[1].end() ||
363  typeSet[2].find(idx) != typeSet[2].end()) {
364  workEventJet[i].statusNeg();
365  break;
366  }
367 
368  // Made it to start of event record so done
369  if (idx == 0) break;
370  // Otherwise next mother and continue
371  idx = event[idx].mother1();
372 
373  // Heavy jets
374  } else if (iType == 1) {
375 
376  // Only include if originates from heavy jet
377  if (typeSet[1].find(idx) != typeSet[1].end()) break;
378 
379  // Made it to start of event record with no heavy jet mother,
380  // so DO NOT include particle
381  if (idx == 0) {
382  workEventJet[i].statusNeg();
383  break;
384  }
385 
386  // Otherwise next mother and continue
387  idx = event[idx].mother1();
388 
389  } // if (iType)
390  } // while (true)
391  } // for (i)
392 
393  // For jetMatch = 2, insert ghost particles corresponding to
394  // each hard parton in the original process
395  if (jetMatch == 2) {
396  for (int i = 0; i < int(typeIdx[iType].size()); i++) {
397  // Get y/phi of the parton
398  Vec4 pIn = eventProcess[typeIdx[iType][i]].p();
399  double y = pIn.rap();
400  double phi = pIn.phi();
401 
402  // Create a ghost particle and add to the workEventJet
403  double e = GHOSTENERGY;
404  double e2y = exp(2. * y);
405  double pz = e * (e2y - 1.) / (e2y + 1.);
406  double pt = sqrt(e*e - pz*pz);
407  double px = pt * cos(phi);
408  double py = pt * sin(phi);
409  workEventJet.append( ID_GLUON, 99, 0, 0, 0, 0, 0, 0, px, py, pz, e);
410 
411  // Extra check on reconstructed y/phi values. If many warnings
412  // of this type, GHOSTENERGY may be set too low.
413  if (MATCHINGCHECK) {
414  int lastIdx = workEventJet.size() - 1;
415  if (abs(y - workEventJet[lastIdx].y()) > ZEROTHRESHOLD ||
416  abs(phi - workEventJet[lastIdx].phi()) > ZEROTHRESHOLD)
417  infoPtr->errorMsg("Warning in JetMatchingAlpgen:jetAlgorithmInput: "
418  "ghost particle y/phi mismatch");
419  }
420 
421  } // for (i)
422  } // if (jetMatch == 2)
423 }
424 
425 //--------------------------------------------------------------------------
426 
427 // Step (2b): run jet algorithm and provide common output
428 
430 
431  // Run the jet clustering algorithm
432  if (jetAlgorithm == 1)
433  cellJet->analyze(workEventJet, eTjetMin, coneRadius, eTseed);
434  else
435  slowJet->analyze(workEventJet);
436 
437  // Extract four-momenta of jets with |eta| < etaJetMax and
438  // put into jetMomenta. Note that this is done backwards as
439  // jets are removed with SlowJet.
440  jetMomenta.clear();
441  int iJet = (jetAlgorithm == 1) ? cellJet->size() - 1:
442  slowJet->sizeJet() - 1;
443  for (int i = iJet; i > -1; i--) {
444  Vec4 jetMom = (jetAlgorithm == 1) ? cellJet->pMassive(i) :
445  slowJet->p(i);
446  double eta = jetMom.eta();
447 
448  if (abs(eta) > etaJetMax) {
449  if (jetAlgorithm == 2) slowJet->removeJet(i);
450  continue;
451  }
452  jetMomenta.push_back(jetMom);
453  }
454 
455  // Reverse jetMomenta to restore eT/pT ordering
456  reverse(jetMomenta.begin(), jetMomenta.end());
457 }
458 
459 //--------------------------------------------------------------------------
460 
461 // Step (2c): veto decision (returning true vetoes the event)
462 
464 
465  // Use two different routines for light/heavy jets as
466  // different veto conditions and for clarity
467  if (iType == 0) return (matchPartonsToJetsLight() > 0);
468  else return (matchPartonsToJetsHeavy() > 0);
469 }
470 
471 //--------------------------------------------------------------------------
472 
473 // Step(2c): light jets
474 // Return codes are given indicating the reason for a veto.
475 // Although not currently used, they are a useful debugging tool:
476 // 0 = no veto
477 // 1 = veto as number of jets less than number of partons
478 // 2 = veto as exclusive mode and number of jets greater than
479 // number of partons
480 // 3 = veto as inclusive mode and there would be an extra jet
481 // that is harder than any matched soft jet
482 // 4 = veto as there is a parton which does not match a jet
483 
485 
486  // Always veto if number of jets is less than original number of jets
487  if (jetMomenta.size() < typeIdx[0].size()) return LESS_JETS;
488  // Veto if in exclusive mode and number of jets bigger than original
489  if (exclusive && jetMomenta.size() > typeIdx[0].size()) return MORE_JETS;
490 
491  // Sort partons by eT/pT
492  sortTypeIdx(typeIdx[0]);
493 
494  // Number of hard partons
495  int nParton = typeIdx[0].size();
496 
497  // Keep track of which jets have been assigned a hard parton
498  vector < bool > jetAssigned;
499  jetAssigned.assign(jetMomenta.size(), false);
500 
501  // Jet matching procedure: (1) deltaR between partons and jets
502  if (jetMatch == 1) {
503 
504  // Loop over light hard partons and get 4-momentum
505  for (int i = 0; i < nParton; i++) {
506  Vec4 p1 = eventProcess[typeIdx[0][i]].p();
507 
508  // Track which jet has the minimal dR measure with this parton
509  int jMin = -1;
510  double dRmin = 0.;
511 
512  // Loop over all jets (skipping those already assigned).
513  for (int j = 0; j < int(jetMomenta.size()); j++) {
514  if (jetAssigned[j]) continue;
515 
516  // DeltaR between parton/jet and store if minimum
517  double dR = (jetAlgorithm == 1)
518  ? REtaPhi(p1, jetMomenta[j]) : RRapPhi(p1, jetMomenta[j]);
519  if (jMin < 0 || dR < dRmin) {
520  dRmin = dR;
521  jMin = j;
522  }
523  } // for (j)
524 
525  // Check for jet-parton match
526  if (jMin >= 0 && dRmin < coneRadius * coneMatchLight) {
527 
528  // If the matched jet is not one of the nParton hardest jets,
529  // the extra left over jet would be harder than some of the
530  // matched jets. This is disallowed, so veto.
531  if (jMin >= nParton) return HARD_JET;
532 
533  // Mark jet as assigned.
534  jetAssigned[jMin] = true;
535 
536  // If no match, then event will be vetoed in all cases
537  } else return UNMATCHED_PARTON;
538 
539  } // for (i)
540 
541  // Jet matching procedure: (2) ghost particles in SlowJet
542  } else {
543 
544  // Loop over added 'ghost' particles and find if assigned to a jet
545  for (int i = workEventJet.size() - nParton;
546  i < workEventJet.size(); i++) {
547  int jMin = slowJet->jetAssignment(i);
548 
549  // Veto if:
550  // 1) not one of nParton hardest jets
551  // 2) not assigned to a jet
552  // 3) jet has already been assigned
553  if (jMin >= nParton) return HARD_JET;
554  if (jMin < 0 || jetAssigned[jMin]) return UNMATCHED_PARTON;
555 
556  // Mark jet as assigned
557  jetAssigned[jMin] = true;
558 
559  } // for (i)
560  } // if (jetMatch)
561 
562  // Minimal eT/pT (CellJet/SlowJet) of matched light jets. Needed
563  // later for heavy jet vetos in inclusive mode.
564  if (nParton > 0)
565  eTpTlightMin = (jetAlgorithm == 1) ? jetMomenta[nParton - 1].eT()
566  : jetMomenta[nParton - 1].pT();
567  else
568  eTpTlightMin = -1.;
569 
570  // No veto
571  return NONE;
572 }
573 
574 //--------------------------------------------------------------------------
575 
576 // Step(2c): heavy jets
577 // Return codes are given indicating the reason for a veto.
578 // Although not currently used, they are a useful debugging tool:
579 // 0 = no veto as there are no extra jets present
580 // 1 = veto as in exclusive mode and extra jets present
581 // 2 = veto as in inclusive mode and extra jets were harder
582 // than any matched light jet
583 
585 
586  // If there are no extra jets, then accept
587  if (jetMomenta.empty()) return NONE;
588 
589  // Number of hard partons
590  int nParton = typeIdx[1].size();
591 
592  // Remove jets that are close to heavy quarks
593  set < int > removeJets;
594 
595  // Jet matching procedure: (1) deltaR between partons and jets
596  if (jetMatch == 1) {
597 
598  // Loop over heavy hard partons and get 4-momentum
599  for (int i = 0; i < nParton; i++) {
600  Vec4 p1 = eventProcess[typeIdx[1][i]].p();
601 
602  // Loop over all jets, find dR and mark for removal if match
603  for (int j = 0; j < int(jetMomenta.size()); j++) {
604  double dR = (jetAlgorithm == 1) ?
605  REtaPhi(p1, jetMomenta[j]) : RRapPhi(p1, jetMomenta[j]);
606  if (dR < coneRadiusHeavy * coneMatchHeavy)
607  removeJets.insert(j);
608 
609  } // for (j)
610  } // for (i)
611 
612  // Jet matching procedure: (2) ghost particles in SlowJet
613  } else {
614 
615  // Loop over added 'ghost' particles and if assigned to a jet
616  // then mark this jet for removal
617  for (int i = workEventJet.size() - nParton;
618  i < workEventJet.size(); i++) {
619  int jMin = slowJet->jetAssignment(i);
620  if (jMin >= 0) removeJets.insert(jMin);
621  }
622 
623  }
624 
625  // Remove jets (backwards order to not disturb indices)
626  for (set < int >::reverse_iterator it = removeJets.rbegin();
627  it != removeJets.rend(); it++)
628  jetMomenta.erase(jetMomenta.begin() + *it);
629 
630  // Handle case if there are still extra jets
631  if (!jetMomenta.empty()) {
632 
633  // Exclusive mode, so immediate veto
634  if (exclusive) return MORE_JETS;
635 
636  // Inclusive mode; extra jets must be softer than any matched light jet
637  else if (eTpTlightMin >= 0.)
638  for (size_t j = 0; j < jetMomenta.size(); j++) {
639  // CellJet uses eT, SlowJet uses pT
640  if ( (jetAlgorithm == 1 && jetMomenta[j].eT() > eTpTlightMin) ||
641  (jetAlgorithm == 2 && jetMomenta[j].pT() > eTpTlightMin) )
642  return HARD_JET;
643  }
644 
645  } // if (!jetMomenta.empty())
646 
647  // No extra jets were present so no veto
648  return NONE;
649 }
650 
651 //==========================================================================
652 
653 // Main implementation of Madgraph UserHooks class.
654 // This may be split out to a separate C++ file if desired,
655 // but currently included here for ease of use.
656 
657 //--------------------------------------------------------------------------
658 
659 // Initialisation routine automatically called from Pythia::init().
660 // Setup all parts needed for the merging.
661 
663 
664  // Read in Madgraph specific configuration variables
665  bool setMad = settingsPtr->flag("JetMatching:setMad");
666 
667  // If Madgraph parameters are present, then parse in MadgraphPar object
668  MadgraphPar par(infoPtr);
669  string parStr = infoPtr->header("MGRunCard");
670  if (!parStr.empty()) {
671  par.parse(parStr);
672  par.printParams();
673  }
674 
675  // Set Madgraph merging parameters from the file if requested
676  if (setMad) {
677  if ( par.haveParam("xqcut") && par.haveParam("maxjetflavor")
678  && par.haveParam("alpsfact") && par.haveParam("ickkw") ) {
679  settingsPtr->flag("JetMatching:merge", par.getParam("ickkw"));
680  settingsPtr->parm("JetMatching:qCut", par.getParam("xqcut"));
681  settingsPtr->mode("JetMatching:nQmatch",
682  par.getParamAsInt("maxjetflavor"));
683  settingsPtr->parm("JetMatching:clFact",
684  clFact = par.getParam("alpsfact"));
685  if (par.getParamAsInt("ickkw") == 0)
686  infoPtr->errorMsg("Error in JetMatchingMadgraph:init: "
687  "Madgraph file parameters are not set for merging");
688 
689  // Warn if setMad requested, but one or more parameters not present
690  } else {
691  infoPtr->errorMsg("Warning in JetMatchingMadgraph:init: "
692  "Madgraph merging parameters not found");
693  if (!par.haveParam("xqcut")) infoPtr->errorMsg("Warning in "
694  "JetMatchingMadgraph:init: No xqcut");
695  if (!par.haveParam("ickkw")) infoPtr->errorMsg("Warning in "
696  "JetMatchingMadgraph:init: No ickkw");
697  if (!par.haveParam("maxjetflavor")) infoPtr->errorMsg("Warning in "
698  "JetMatchingMadgraph:init: No maxjetflavor");
699  if (!par.haveParam("alpsfact")) infoPtr->errorMsg("Warning in "
700  "JetMatchingMadgraph:init: No alpsfact");
701  }
702  }
703 
704  // Read in FxFx matching parameters
705  doFxFx = settingsPtr->flag("JetMatching:doFxFx");
706  nPartonsNow = settingsPtr->mode("JetMatching:nPartonsNow");
707  qCutME = settingsPtr->parm("JetMatching:qCutME");
708  qCutMESq = pow(qCutME,2);
709 
710  // Read in Madgraph merging parameters
711  doMerge = settingsPtr->flag("JetMatching:merge");
712  doShowerKt = settingsPtr->flag("JetMatching:doShowerKt");
713  qCut = settingsPtr->parm("JetMatching:qCut");
714  nQmatch = settingsPtr->mode("JetMatching:nQmatch");
715  clFact = settingsPtr->parm("JetMatching:clFact");
716 
717  // Read in jet algorithm parameters
718  jetAlgorithm = settingsPtr->mode("JetMatching:jetAlgorithm");
719  nJetMax = settingsPtr->mode("JetMatching:nJetMax");
720  eTjetMin = settingsPtr->parm("JetMatching:eTjetMin");
721  coneRadius = settingsPtr->parm("JetMatching:coneRadius");
722  etaJetMax = settingsPtr->parm("JetMatching:etaJetMax");
723  slowJetPower = settingsPtr->mode("JetMatching:slowJetPower");
724 
725  // Matching procedure
726  jetAllow = settingsPtr->mode("JetMatching:jetAllow");
727  exclusiveMode = settingsPtr->mode("JetMatching:exclusive");
728  qCutSq = pow(qCut,2);
729  etaJetMaxAlgo = etaJetMax;
730 
731  // If not merging, then done
732  if (!doMerge) return true;
733 
734  // Exclusive mode; if set to 2, then set based on nJet/nJetMax
735  if (exclusiveMode == 2) {
736 
737  // No nJet or nJetMax, so default to exclusive mode
738  if (nJetMax < 0) {
739  infoPtr->errorMsg("Warning in JetMatchingMadgraph:init: "
740  "missing jet multiplicity information; running in exclusive mode");
741  exclusiveMode = 1;
742  }
743  }
744 
745  // Initialise chosen jet algorithm.
746  // Currently, this only supports the kT-algorithm in SlowJet.
747  // Use the QCD distance measure by default.
748  jetAlgorithm = 2;
749  slowJetPower = 1;
750  slowJet = new SlowJet(slowJetPower, coneRadius, eTjetMin,
751  etaJetMaxAlgo, 2, 2, NULL, false);
752 
753  // For FxFx, also initialise jet algorithm to define matrix element jets.
754  // Currently, this only supports the kT-algorithm in SlowJet.
755  // Use the QCD distance measure by default.
756  slowJetHard = new SlowJet(slowJetPower, coneRadius, qCutME,
757  etaJetMaxAlgo, 2, 2, NULL, false);
758 
759  // To access the DJR's
760  slowJetDJR = new SlowJet(slowJetPower, coneRadius, 0.0/*qCutME*/,
761  etaJetMaxAlgo, 2, 2, NULL, false);
762 
763  // Setup local event records
764  eventProcessOrig.init("(eventProcessOrig)", particleDataPtr);
765  eventProcess.init("(eventProcess)", particleDataPtr);
766  workEventJet.init("(workEventJet)", particleDataPtr);
767 
768  // Print information
769  string jetStr = (jetAlgorithm == 1) ? "CellJet" :
770  (slowJetPower == -1) ? "anti-kT" :
771  (slowJetPower == 0) ? "C/A" :
772  (slowJetPower == 1) ? "kT" : "unknown";
773  string modeStr = (exclusiveMode) ? "exclusive" : "inclusive";
774  cout << endl
775  << " *----- Madgraph matching parameters -----*" << endl
776  << " | qCut | " << setw(14)
777  << qCut << " |" << endl
778  << " | nQmatch | " << setw(14)
779  << nQmatch << " |" << endl
780  << " | clFact | " << setw(14)
781  << clFact << " |" << endl
782  << " | Jet algorithm | " << setw(14)
783  << jetStr << " |" << endl
784  << " | eTjetMin | " << setw(14)
785  << eTjetMin << " |" << endl
786  << " | etaJetMax | " << setw(14)
787  << etaJetMax << " |" << endl
788  << " | jetAllow | " << setw(14)
789  << jetAllow << " |" << endl
790  << " | Mode | " << setw(14)
791  << modeStr << " |" << endl
792  << " *-----------------------------------------*" << endl;
793 
794  return true;
795 }
796 
797 //--------------------------------------------------------------------------
798 
799 bool JetMatchingMadgraph::doVetoStep(int iPos, int nISR, int nFSR,
800  const Event& event) {
801 
802  // Do not perform any veto if not in the Shower-kT scheme.
803  if ( !doShowerKt ) return false;
804 
805  // Default to no veto in case the hard input matrix element already has too
806  // many partons (same as in Pythia6).
807  if ( int(typeIdx[0].size()) > nJetMax ) return false;
808 
809  // Do nothing for emissions after the first one.
810  if ( nISR + nFSR > 1 ) return false;
811 
812  // Do nothing in resonance decay showers.
813  if (iPos == 5) return false;
814 
815  // Clear the event of MPI systems and resonace decay products. Store trimmed
816  // event in workEvent.
817  sortIncomingProcess(event);
818 
819  // Get (kinematical) pT of first emission
820  double pTfirst = 0.;
821  for (int i = 0; i < workEvent.size(); i++){
822  // Since this event only contains one emission, this test is enough
823  // to isolate this emission.
824  if ( workEvent[i].isFinal()
825  && (workEvent[i].statusAbs()==43 || workEvent[i].statusAbs()==51)) {
826  // Only check partons originating from QCD splittings.
827  int iPos = 1;
828  bool QCDemission = true;
829  while ( workEvent[iPos].statusAbs() > 23 ) {
830  if ( workEvent[iPos].id() == 22 || workEvent[iPos].id() == 23
831  || workEvent[iPos].idAbs() == 24){
832  QCDemission = false;
833  break;
834  }
835  iPos = workEvent[iPos].mother1();
836  }
837  // Get kinematical pT.
838  if (QCDemission) {
839  pTfirst = workEvent[i].pT();
840  break;
841  }
842  }
843  }
844 
845  // Check veto.
846  if ( doShowerKtVeto(pTfirst) ) return true;
847 
848  // No veto if come this far.
849  return false;
850 
851 }
852 
853 //--------------------------------------------------------------------------
854 
856 
857  // Only check veto in the shower-kT scheme.
858  if ( !doShowerKt ) return false;
859 
860  // Reset veto code
861  bool doVeto = false;
862 
863  // Find the (kinematical) pT of the softest (light) parton in the hard
864  // process.
865  int nParton = typeIdx[0].size();
866  double pTminME=1e10;
867  for ( int i = 0; i < nParton; ++i)
868  pTminME = min(pTminME,eventProcess[typeIdx[0][i]].pT());
869 
870  // Veto if the softest hard process parton is below Qcut.
871  if ( nParton > 0 && pow(pTminME,2) < qCutSq ) doVeto = true;
872 
873  // For non-highest multiplicity, veto if the hardest emission is harder
874  // than Qcut.
875  if ( exclusive && pow(pTfirst,2) > qCutSq ) {
876  doVeto = true;
877  // For highest multiplicity sample, veto if the hardest emission is harder
878  // than the hard process parton.
879  } else if ( !exclusive && nParton > 0 && pTfirst > pTminME ) {
880  doVeto = true;
881  }
882 
883  // Return veto
884  return doVeto;
885 
886 }
887 
888 //--------------------------------------------------------------------------
889 
890 // Step (1): sort the incoming particles
891 
893 
894  // Remove resonance decays from original process and keep only final
895  // state. Resonances will have positive status code after this step.
896  omitResonanceDecays(eventProcessOrig, true);
897 
898  ClearDJR();
899  ClearnME();
900 
901  // For FxFx, pre-cluster partons in the event into jets.
902  if (doFxFx) {
903 
904  // Get final state partons
905  eventProcess.clear();
906  workEventJet.clear();
907  for( int i=0; i < workEvent.size(); ++i) {
908  // Original AG+Py6 algorithm explicitly excludes tops,
909  // leptons and photons.
910  int id = workEvent[i].idAbs();
911  if ((id >= ID_LEPMIN && id <= ID_LEPMAX) || id == ID_TOP
912  || id == ID_PHOTON || id == 23 || id == 24 || id == 25) {
913  eventProcess.append(workEvent[i]);
914  } else {
915  workEventJet.append(workEvent[i]);
916  }
917  }
918 
919  // Initialize SlowJetHard jet algorithm with current working event
920  if (!slowJetHard->setup(workEventJet) ) {
921  infoPtr->errorMsg("Warning in JetMatchingMadgraph:sortIncomingProcess"
922  ": the SlowJet algorithm failed on setup");
923  return;
924  }
925 
926  // Get matrix element cut scale.
927  double localQcutSq = qCutMESq;
928  // Cluster in steps to find all hadronic jets at the scale qCutME
929  while ( slowJetHard->sizeAll() - slowJetHard->sizeJet() > 0 ) {
930  // Done if next step is above qCut
931  if( slowJetHard->dNext() > localQcutSq ) break;
932  // Done if we're at or below the number of partons in the Born state.
933  if( slowJetHard->sizeAll()-slowJetHard->sizeJet() <= nPartonsNow) break;
934  slowJetHard->doStep();
935  }
936 
937  // Construct a master copy of the event containing only the
938  // hardest nPartonsNow hadronic clusters. While constructing the event,
939  // the parton type (ID_GLUON) and status (98,99) are arbitrary.
940  int nJets = slowJetHard->sizeJet();
941  int nClus = slowJetHard->sizeAll();
942  int nNow = 0;
943  for (int i = nJets; i < nClus; ++i) {
944  vector<int> parts;
945  if (i < nClus-nJets) parts = slowJetHard->clusConstituents(i);
946  else parts = slowJetHard->constituents(nClus-nJets-i);
947  int flavour = ID_GLUON;
948  for(int j=0; j < int(parts.size()); ++j)
949  if (workEventJet[parts[j]].id() == ID_BOT)
950  flavour = ID_BOT;
951  eventProcess.append( flavour, 98,
952  workEventJet[parts.back()].mother1(),
953  workEventJet[parts.back()].mother2(),
954  workEventJet[parts.back()].daughter1(),
955  workEventJet[parts.back()].daughter2(),
956  0, 0, slowJetHard->p(i).px(), slowJetHard->p(i).py(),
957  slowJetHard->p(i).pz(), slowJetHard->p(i).e() );
958  nNow++;
959  }
960 
961  // Done. Clean-up
962  workEventJet.clear();
963 
964  // For MLM matching, simply take hard process state from workEvent,
965  // without any preclustering.
966  } else {
967  eventProcess = workEvent;
968  }
969 
970  // Sort original process final state into light/heavy jets and 'other'.
971  // Criteria:
972  // 1 <= ID <= nQmatch, or ID == 21 --> light jet (typeIdx[0])
973  // nQMatch < ID --> heavy jet (typeIdx[1])
974  // All else --> other (typeIdx[2])
975  // Note that 'typeIdx' stores indices into 'eventProcess' (after resonance
976  // decays are omitted), while 'typeSet' stores indices into the original
977  // process record, 'eventProcessOrig', but these indices are also valid
978  // in 'event'.
979  for (int i = 0; i < 3; i++) {
980  typeIdx[i].clear();
981  typeSet[i].clear();
982  origTypeIdx[i].clear();
983  }
984  for (int i = 0; i < eventProcess.size(); i++) {
985  // Ignore non-final state and default to 'other'
986  if (!eventProcess[i].isFinal()) continue;
987  int idx = 2;
988  int orig_idx = 2;
989 
990  // Light jets: all gluons and quarks with id less than or equal to nQmatch
991  if (eventProcess[i].id() == ID_GLUON
992  || (eventProcess[i].idAbs() <= nQmatch) ) {
993  orig_idx = 0;
994  // Crucial point: MG puts the scale of a non-QCD particle to eCM. For
995  // such particles, we should keep the default "2"
996  if ( eventProcess[i].scale() < 1.999*sqrt(infoPtr->eA()*infoPtr->eB()) )
997  idx = 0;
998  }
999 
1000  // Heavy jets: all quarks with id greater than nQmatch
1001  else if (eventProcess[i].idAbs() > nQmatch
1002  && eventProcess[i].idAbs() <= ID_TOP) {
1003  idx = 1;
1004  orig_idx = 1;
1005 
1006  } else {
1007  idx = 2;
1008  orig_idx = 2;
1009  }
1010 
1011  // Store
1012  typeIdx[idx].push_back(i);
1013  typeSet[idx].insert(eventProcess[i].daughter1());
1014  origTypeIdx[orig_idx].push_back(i);
1015  }
1016 
1017  // Exclusive mode; if set to 2, then set based on nJet/nJetMax
1018  if (exclusiveMode == 2) {
1019 
1020  // Inclusive if nJet == nJetMax, exclusive otherwise
1021  int nParton = origTypeIdx[0].size();
1022  exclusive = (nParton == nJetMax) ? false : true;
1023 
1024  // Otherwise, just set as given
1025  } else {
1026  exclusive = (exclusiveMode == 0) ? false : true;
1027  }
1028 
1029  // Extract partons from hardest subsystem + ISR + FSR only into
1030  // workEvent. Note no resonance showers or MPIs.
1031  subEvent(event);
1032 }
1033 
1034 //--------------------------------------------------------------------------
1035 
1036 // Step (2a): pick which particles to pass to the jet algorithm
1037 
1038 void JetMatchingMadgraph::jetAlgorithmInput(const Event &event, int iType) {
1039 
1040  // Take input from 'workEvent' and put output in 'workEventJet'
1041  workEventJet = workEvent;
1042 
1043  // Loop over particles and decide what to pass to the jet algorithm
1044  for (int i = 0; i < workEventJet.size(); ++i) {
1045  if (!workEventJet[i].isFinal()) continue;
1046 
1047  // jetAllow option to disallow certain particle types
1048  if (jetAllow == 1) {
1049 
1050  // Original AG+Py6 algorithm explicitly excludes tops,
1051  // leptons and photons.
1052  int id = workEventJet[i].idAbs();
1053  if ((id >= ID_LEPMIN && id <= ID_LEPMAX) || id == ID_TOP
1054  || id == ID_PHOTON || (id > nQmatch && id!=21)) {
1055  workEventJet[i].statusNeg();
1056  continue;
1057  }
1058  }
1059 
1060  // Get the index of this particle in original event
1061  int idx = workEventJet[i].daughter1();
1062 
1063  // Start with particle idx, and afterwards track mothers
1064  while (true) {
1065 
1066  // Light jets
1067  if (iType == 0) {
1068 
1069  // Do not include if originates from heavy jet or 'other'
1070  if (typeSet[1].find(idx) != typeSet[1].end() ||
1071  typeSet[2].find(idx) != typeSet[2].end()) {
1072  workEventJet[i].statusNeg();
1073  break;
1074  }
1075 
1076  // Made it to start of event record so done
1077  if (idx == 0) break;
1078  // Otherwise next mother and continue
1079  idx = event[idx].mother1();
1080 
1081  // Heavy jets
1082  } else if (iType == 1) {
1083 
1084  // Only include if originates from heavy jet
1085  if (typeSet[1].find(idx) != typeSet[1].end()) break;
1086 
1087  // Made it to start of event record with no heavy jet mother,
1088  // so DO NOT include particle
1089  if (idx == 0) {
1090  workEventJet[i].statusNeg();
1091  break;
1092  }
1093 
1094  // Otherwise next mother and continue
1095  idx = event[idx].mother1();
1096 
1097  } // if (iType)
1098  } // while (true)
1099  } // for (i)
1100 }
1101 
1102 //--------------------------------------------------------------------------
1103 
1104 // Step (2b): run jet algorithm and provide common output
1105 // This does nothing, because the jet algorithm is run several times
1106 // in the matching algorithm.
1107 
1109 
1110 //--------------------------------------------------------------------------
1111 
1112 // Step (2c): veto decision (returning true vetoes the event)
1113 
1115 
1116  // Use two different routines for light/heavy jets as
1117  // different veto conditions and for clarity
1118  if (iType == 0) {
1119  SetDJR(workEventJet);
1120  SetnME();
1121  return (matchPartonsToJetsLight() > 0);
1122  }
1123  else return (matchPartonsToJetsHeavy() > 0);
1124 }
1125 
1126 //--------------------------------------------------------------------------
1127 
1128 // Step(2c): light jets
1129 // Return codes are given indicating the reason for a veto.
1130 // Although not currently used, they are a useful debugging tool:
1131 // 0 = no veto
1132 // 1 = veto as number of jets less than number of partons
1133 // 2 = veto as exclusive mode and number of jets greater than
1134 // number of partons
1135 // 3 = veto as inclusive mode and there would be an extra jet
1136 // that is harder than any matched soft jet
1137 // 4 = veto as there is a parton which does not match a jet
1138 
1140 
1141  // Count the number of hard partons
1142  int nParton = typeIdx[0].size();
1143  if((int)origTypeIdx[0].size()>nJetMax)return 1;
1144 
1145  // Initialize SlowJet with current working event
1146  if (!slowJet->setup(workEventJet) ) {
1147  infoPtr->errorMsg("Warning in JetMatchingMadgraph:matchPartonsToJets"
1148  "Light: the SlowJet algorithm failed on setup");
1149  return NONE;
1150  }
1151  double localQcutSq = qCutSq;
1152  double dOld = 0.0;
1153  // Cluster in steps to find all hadronic jets at the scale qCut
1154  while ( slowJet->sizeAll() - slowJet->sizeJet() > 0 ) {
1155  if( slowJet->dNext() > localQcutSq ) break;
1156  dOld = slowJet->dNext();
1157  slowJet->doStep();
1158  }
1159  int nJets = slowJet->sizeJet();
1160  int nClus = slowJet->sizeAll();
1161 
1162  // Debug printout.
1163  if (MATCHINGDEBUG) slowJet->list(true);
1164 
1165  // Count of the number of hadronic jets in SlowJet accounting
1166  int nCLjets = nClus - nJets;
1167  // Get number of partons. Different for MLM and FxFx schemes.
1168  int nRequested = (doFxFx) ? nPartonsNow : nParton;
1169 
1170  // Veto event if too few hadronic jets
1171  if ( nCLjets < nRequested ) return LESS_JETS;
1172 
1173  // In exclusive mode, do not allow more hadronic jets than partons
1174  if ( exclusive && !doFxFx ) {
1175  if ( nCLjets > nRequested ) return MORE_JETS;
1176  } else {
1177 
1178  // For FxFx, in the non-highest multipicity, all jets need to matched to
1179  // partons. For nCLjets > nRequested, this is not possible. Hence, we can
1180  // veto here already.
1181  if ( doFxFx && nRequested < nJetMax && nCLjets > nRequested )
1182  return MORE_JETS;
1183 
1184  // Now continue in inclusive mode.
1185  // In inclusive mode, there can be more hadronic jets than partons,
1186  // provided that all partons are properly matched to hadronic jets.
1187  // Start by setting up the jet algorithm.
1188  if (!slowJet->setup(workEventJet) ) {
1189  infoPtr->errorMsg("Warning in JetMatchingMadgraph:matchPartonsToJets"
1190  "Light: the SlowJet algorithm failed on setup");
1191  return NONE;
1192  }
1193 
1194  // For FxFx, continue clustering as long as the jet separation is above
1195  // qCut.
1196  if (doFxFx) {
1197  while ( slowJet->sizeAll() - slowJet->sizeJet() > 0 ) {
1198  if( slowJet->dNext() > localQcutSq ) break;
1199  slowJet->doStep();
1200  }
1201  // For MLM, cluster into hadronic jets until there are the same number as
1202  // partons.
1203  } else {
1204  while ( slowJet->sizeAll() - slowJet->sizeJet() > nParton )
1205  slowJet->doStep();
1206  }
1207 
1208  // Sort partons in pT. Update local qCut value.
1209  // Hadronic jets are already sorted in pT.
1210  localQcutSq = dOld;
1211  if ( clFact >= 0. && nParton > 0 ) {
1212  vector<double> partonPt;
1213  for (int i = 0; i < nParton; ++i)
1214  partonPt.push_back( eventProcess[typeIdx[0][i]].pT2() );
1215  sort( partonPt.begin(), partonPt.end());
1216  localQcutSq = max( qCutSq, partonPt[0]);
1217  }
1218  nJets = slowJet->sizeJet();
1219  nClus = slowJet->sizeAll();
1220  }
1221  // Update scale if clustering factor is non-zero
1222  if ( clFact != 0. ) localQcutSq *= pow2(clFact);
1223 
1224  Event tempEvent;
1225  tempEvent.init( "(tempEvent)", particleDataPtr);
1226  int nPass = 0;
1227  double pTminEstimate = -1.;
1228  // Construct a master copy of the event containing only the
1229  // hardest nParton hadronic clusters. While constructing the event,
1230  // the parton type (ID_GLUON) and status (98,99) are arbitrary.
1231  for (int i = nJets; i < nClus; ++i) {
1232  tempEvent.append( ID_GLUON, 98, 0, 0, 0, 0, 0, 0, slowJet->p(i).px(),
1233  slowJet->p(i).py(), slowJet->p(i).pz(), slowJet->p(i).e() );
1234  ++nPass;
1235  pTminEstimate = max( pTminEstimate, slowJet->pT(i));
1236  if(nPass == nRequested) break;
1237  }
1238 
1239  int tempSize = tempEvent.size();
1240  // This keeps track of which hadronic jets are matched to parton
1241  vector<bool> jetAssigned;
1242  jetAssigned.assign( tempSize, false);
1243 
1244  // This keeps track of which partons are matched to which hadronic
1245  // jets.
1246  vector< vector<bool> > partonMatchesJet;
1247  for (int i=0; i < nParton; ++i )
1248  partonMatchesJet.push_back( vector<bool>(tempEvent.size(),false) );
1249 
1250  // Begin matching.
1251  // Do jet matching for FxFx.
1252  // Make sure that the nPartonsNow hardest hadronic jets are matched to any
1253  // of the nPartonsNow (+1) partons. This matching is done by attaching a jet
1254  // from the list of unmatched hadronic jets, and appending a jet from the
1255  // list of partonic jets, one at a time. The partonic jet will be clustered
1256  // with the hadronic jet or the beam if the distance measure is below the
1257  // cut. The hadronic jet is matched once this happens. Otherwise, another
1258  // partonic jet is tried. When a hadronic jet is matched to a partonic jet,
1259  // it is removed from the list of unmatched hadronic jets. This process
1260  // continues until the nPartonsNow hardest hadronic jets are matched to
1261  // partonic jets, or it is not possible to make a match for a hadronic jet.
1262  int iNow = 0;
1263  while ( doFxFx && iNow < tempSize ) {
1264 
1265  // Check if this shower jet matches any partonic jet.
1266  Event tempEventJet;
1267  tempEventJet.init("(tempEventJet)", particleDataPtr);
1268  for (int i=0; i < nParton; ++i ) {
1269 
1271  //for (int j=0; j < tempSize; ++j )
1272  // if ( partonMatchesJet[i][j]) continue;
1273 
1274  // Attach a single hadronic jet.
1275  tempEventJet.clear();
1276  tempEventJet.append( ID_GLUON, 98, 0, 0, 0, 0, 0, 0,
1277  tempEvent[iNow].px(), tempEvent[iNow].py(),
1278  tempEvent[iNow].pz(), tempEvent[iNow].e() );
1279  // Attach the current parton.
1280  Vec4 pIn = eventProcess[typeIdx[0][i]].p();
1281  tempEventJet.append( ID_GLUON, 99, 0, 0, 0, 0, 0, 0,
1282  pIn.px(), pIn.py(), pIn.pz(), pIn.e() );
1283 
1284  // Setup jet algorithm.
1285  if ( !slowJet->setup(tempEventJet) ) {
1286  infoPtr->errorMsg("Warning in JetMatchingMadgraph:matchPartonsToJets"
1287  "Light: the SlowJet algorithm failed on setup");
1288  return NONE;
1289  }
1290 
1291  // These are the conditions for the hadronic jet to match the parton
1292  // at the local qCut scale
1293  if ( slowJet->iNext() == tempEventJet.size() - 1
1294  && slowJet->jNext() > -1 && slowJet->dNext() < localQcutSq ) {
1295  jetAssigned[iNow] = true;
1296  partonMatchesJet[i][iNow] = true;
1297  }
1298 
1299  } // End loop over hard partons.
1300 
1301  // Veto if the jet could not be assigned to any parton.
1302  if ( !jetAssigned[iNow] ) return UNMATCHED_PARTON;
1303 
1304  // Continue;
1305  ++iNow;
1306  }
1307 
1308  // Do jet matching for MLM.
1309  // Take the list of unmatched hadronic jets and append a parton, one at
1310  // a time. The parton will be clustered with the "closest" hadronic jet
1311  // or the beam if the distance measure is below the cut. When a hadronic
1312  // jet is matched to a parton, it is removed from the list of unmatched
1313  // hadronic jets. This process continues until all hadronic jets are
1314  // matched to partons or it is not possible to make a match.
1315  iNow = 0;
1316  while (!doFxFx && iNow < nParton ) {
1317  Event tempEventJet;
1318  tempEventJet.init("(tempEventJet)", particleDataPtr);
1319  for (int i = 0; i < tempSize; ++i) {
1320  if (jetAssigned[i]) continue;
1321  Vec4 pIn = tempEvent[i].p();
1322  // Append unmatched hadronic jets
1323  tempEventJet.append( ID_GLUON, 98, 0, 0, 0, 0, 0, 0,
1324  pIn.px(), pIn.py(), pIn.pz(), pIn.e() );
1325  }
1326 
1327  Vec4 pIn = eventProcess[typeIdx[0][iNow]].p();
1328  // Append the current parton
1329  tempEventJet.append( ID_GLUON, 99, 0, 0, 0, 0, 0, 0,
1330  pIn.px(), pIn.py(), pIn.pz(), pIn.e() );
1331  if ( !slowJet->setup(tempEventJet) ) {
1332  infoPtr->errorMsg("Warning in JetMatchingMadgraph:matchPartonsToJets"
1333  "Light: the SlowJet algorithm failed on setup");
1334  return NONE;
1335  }
1336  // These are the conditions for the hadronic jet to match the parton
1337  // at the local qCut scale
1338  if ( slowJet->iNext() == tempEventJet.size() - 1
1339  && slowJet->jNext() > -1 && slowJet->dNext() < localQcutSq ) {
1340  int iKnt = -1;
1341  for (int i = 0; i != tempSize; ++i) {
1342  if (jetAssigned[i]) continue;
1343  ++iKnt;
1344  // Identify the hadronic jet that matches the parton
1345  if (iKnt == slowJet->jNext() ) jetAssigned[i] = true;
1346  }
1347  } else {
1348  return UNMATCHED_PARTON;
1349  }
1350  ++iNow;
1351  }
1352 
1353  // Minimal eT/pT (CellJet/SlowJet) of matched light jets.
1354  // Needed later for heavy jet vetos in inclusive mode.
1355  // This information is not used currently.
1356  if (nParton > 0 && pTminEstimate > 0) eTpTlightMin = pTminEstimate;
1357  else eTpTlightMin = -1.;
1358 
1359  //SetDJR(workEventJet);
1360  //SetnME();
1361  // No veto
1362  //std::cout<<"No VETO"<<std::endl;
1363  return NONE;
1364 }
1365 
1366 //--------------------------------------------------------------------------
1367 
1368 // Step(2c): heavy jets
1369 // Return codes are given indicating the reason for a veto.
1370 // Although not currently used, they are a useful debugging tool:
1371 // 0 = no veto as there are no extra jets present
1372 // 1 = veto as in exclusive mode and extra jets present
1373 // 2 = veto as in inclusive mode and extra jets were harder
1374 // than any matched light jet
1375 
1377 
1378  // Currently, heavy jets are unmatched
1379  // If there are no extra jets, then accept
1380  if (jetMomenta.empty()) return NONE;
1381 
1382  // No extra jets were present so no veto
1383  return NONE;
1384 }
1385 
1386 //==========================================================================
void swap(ora::Record &rh, ora::Record &lh)
Definition: Record.h:70
int i
Definition: DBlmapReader.cc:9
int getParamAsInt(const string &paramIn)
void jetAlgorithmInput(const Pythia8::Event &, int)
void jetAlgorithmInput(const Pythia8::Event &, int)
ExtVec< T, 4 > Vec4
Definition: ExtVec.h:23
void printParams()
bool haveParam(const string &paramIn)
Sin< T >::type sin(const T &t)
Definition: Sin.h:22
#define NULL
Definition: scimark2.h:8
T eta() const
void find(edm::Handle< EcalRecHitCollection > &hits, DetId thisDet, std::vector< EcalRecHitCollection::const_iterator > &hit, bool debug=false)
Definition: FindCaloHit.cc:7
void sortTypeIdx(vector< int > &vecIn)
const T & max(const T &a, const T &b)
T sqrt(T t)
Definition: SSEVec.h:48
bool doShowerKtVeto(double pTfirst)
Cos< T >::type cos(const T &t)
Definition: Cos.h:22
void sortIncomingProcess(const Pythia8::Event &)
Abs< T >::type abs(const T &t)
Definition: Abs.h:22
int j
Definition: DBlmapReader.cc:9
#define end
Definition: vmac.h:37
How EventSelector::AcceptEvent() decides whether to accept an event for output otherwise it is excluding the probing of A single or multiple positive and the trigger will pass if any such matching triggers are PASS or EXCEPTION[A criterion thatmatches no triggers at all is detected and causes a throw.] A single negative with an expectation of appropriate bit checking in the decision and the trigger will pass if any such matching triggers are FAIL or EXCEPTION A wildcarded negative criterion that matches more than one trigger in the trigger but the state exists so we define the behavior If all triggers are the negative crieriion will lead to accepting the event(this again matches the behavior of"!*"before the partial wildcard feature was incorporated).The per-event"cost"of each negative criterion with multiple relevant triggers is about the same as!*was in the past
bool doVetoStep(int, int, int, const Pythia8::Event &)
double getParam(const string &paramIn)
tuple idx
DEBUGGING if hasattr(process,&quot;trackMonIterativeTracking2012&quot;): print &quot;trackMonIterativeTracking2012 D...
static const double ZEROTHRESHOLD
void sortIncomingProcess(const Pythia8::Event &)
double p1[4]
Definition: TauolaWrapper.h:89
static const bool MATCHINGCHECK
tuple cout
Definition: gather_cfg.py:121
bool doVetoPartonLevelEarly(const Pythia8::Event &event)
int flavour(const Candidate &part)
Definition: pdgIdUtils.h:31
static const bool MATCHINGDEBUG
tuple size
Write out results.
Power< A, B >::type pow(const A &a, const B &b)
Definition: Power.h:40
static const double GHOSTENERGY
bool parse(const string paramStr)
Definition: DDAxes.h:10