CMS 3D CMS Logo

JetMatchingEWKFxFx.cc
Go to the documentation of this file.
1 // Implementation of the new JetMatching plugin
2 // author: Carlos Vico (U. Oviedo)
3 // taken from: https://amcatnlo.web.cern.ch/amcatnlo/JetMatching.h
4 
5 #include "JetMatchingEWKFxFx.h"
6 using namespace Pythia8;
7 
9 
11  // This method is automatically called by Pythia8::init
12  // and it can be used to change any of the parameter given
13  // in the fragment.
14 
15  // Initialise values for stored jet matching veto inputs.
16  pTfirstSave = -1.;
17  processSubsetSave.init("(eventProcess)", particleDataPtr);
18  workEventJetSave.init("(workEventJet)", particleDataPtr);
19 
20  // Read Madgraph specific configuration variables
21  bool setMad = settingsPtr->flag("JetMatching:setMad");
22 
23  // Parse in MadgraphPar object
24  MadgraphPar par;
25 
26  string parStr = infoPtr->header("MGRunCard");
27  if (!parStr.empty()) {
28  par.parse(parStr);
29  par.printParams();
30  }
31 
32  // Set Madgraph merging parameters from the file if requested
33  if (setMad) {
34  if (par.haveParam("xqcut") && par.haveParam("maxjetflavor") && par.haveParam("alpsfact") &&
35  par.haveParam("ickkw")) {
36  settingsPtr->flag("JetMatching:merge", par.getParam("ickkw"));
37  settingsPtr->parm("JetMatching:qCut", par.getParam("xqcut"));
38  settingsPtr->mode("JetMatching:nQmatch", par.getParamAsInt("maxjetflavor"));
39  settingsPtr->parm("JetMatching:clFact", clFact = par.getParam("alpsfact"));
40  if (par.getParamAsInt("ickkw") == 0)
41  errorMsg(
42  "Error in JetMatchingMadgraph:init: "
43  "Madgraph file parameters are not set for merging");
44 
45  // Warn if setMad requested, but one or more parameters not present
46  } else {
47  errorMsg(
48  "Warning in JetMatchingMadgraph:init: "
49  "Madgraph merging parameters not found");
50  if (!par.haveParam("xqcut"))
51  errorMsg(
52  "Warning in "
53  "JetMatchingMadgraph:init: No xqcut");
54  if (!par.haveParam("ickkw"))
55  errorMsg(
56  "Warning in "
57  "JetMatchingMadgraph:init: No ickkw");
58  if (!par.haveParam("maxjetflavor"))
59  errorMsg(
60  "Warning in "
61  "JetMatchingMadgraph:init: No maxjetflavor");
62  if (!par.haveParam("alpsfact"))
63  errorMsg(
64  "Warning in "
65  "JetMatchingMadgraph:init: No alpsfact");
66  }
67  }
68 
69  // Read in FxFx matching parameters
70  doFxFx = settingsPtr->flag("JetMatching:doFxFx");
71  nPartonsNow = settingsPtr->mode("JetMatching:nPartonsNow");
72  qCutME = settingsPtr->parm("JetMatching:qCutME");
73  qCutMESq = pow(qCutME, 2);
74 
75  // Read in Madgraph merging parameters
76  doMerge = settingsPtr->flag("JetMatching:merge");
77  doShowerKt = settingsPtr->flag("JetMatching:doShowerKt");
78  qCut = settingsPtr->parm("JetMatching:qCut");
79  nQmatch = settingsPtr->mode("JetMatching:nQmatch");
80  clFact = settingsPtr->parm("JetMatching:clFact");
81 
82  // Read in jet algorithm parameters
83  jetAlgorithm = settingsPtr->mode("JetMatching:jetAlgorithm");
84  nJetMax = settingsPtr->mode("JetMatching:nJetMax");
85  eTjetMin = settingsPtr->parm("JetMatching:eTjetMin");
86  coneRadius = settingsPtr->parm("JetMatching:coneRadius");
87  etaJetMax = settingsPtr->parm("JetMatching:etaJetMax");
88  slowJetPower = settingsPtr->mode("JetMatching:slowJetPower");
89 
90  // Matching procedure
91  jetAllow = settingsPtr->mode("JetMatching:jetAllow");
92  exclusiveMode = settingsPtr->mode("JetMatching:exclusive");
93  qCutSq = pow(qCut, 2);
94  etaJetMaxAlgo = etaJetMax;
95  //performVeto = true;
96 
97  // If not merging is applied, then we are done
98  if (!doMerge)
99  return true;
100 
101  // Exclusive mode; if set to 2, then set based on nJet/nJetMax
102  if (exclusiveMode == 2) {
103  // No nJet or nJetMax, so default to exclusive mode
104  if (nJetMax < 0) {
105  errorMsg(
106  "Warning in JetMatchingMadgraph:init: "
107  "missing jet multiplicity information; running in exclusive mode");
108  exclusiveMode = 1;
109  }
110  }
111 
112  // Initialise chosen jet algorithm.
113  // Currently, this only supports the kT-algorithm in SlowJet.
114  // Use the QCD distance measure by default.
115  jetAlgorithm = 2;
116 
117  slowJet = new SlowJet(slowJetPower, coneRadius, eTjetMin, etaJetMaxAlgo, 2, 2, nullptr, false);
118 
119  // For FxFx, also initialise jet algorithm to define matrix element jets.
120  slowJetHard = new SlowJet(slowJetPower, coneRadius, qCutME, etaJetMaxAlgo, 2, 2, nullptr, false);
121 
122  // To access the DJR's
123  slowJetDJR = new SlowJet(slowJetPower, coneRadius, qCutME, etaJetMaxAlgo, 2, 2, nullptr, false);
124 
125  // A special version of SlowJet to handle heavy and other partons
126  hjSlowJet = new HJSlowJet(slowJetPower, coneRadius, 0.0, 100.0, 1, 2, nullptr, false, true);
127 
128  // Setup local event records
129  eventProcessOrig.init("(eventProcessOrig)", particleDataPtr);
130  eventProcess.init("(eventProcess)", particleDataPtr);
131  workEventJet.init("(workEventJet)", particleDataPtr);
132 
133  // Print information
134  if (MATCHINGDEBUG) {
135  string jetStr = (jetAlgorithm == 1) ? "CellJet"
136  : (slowJetPower == -1) ? "anti-kT"
137  : (slowJetPower == 0) ? "C/A"
138  : (slowJetPower == 1) ? "kT"
139  : "unknown";
140  string modeStr = (exclusiveMode) ? "exclusive" : "inclusive";
141  cout << endl
142  << " *----- Madgraph matching parameters -----*" << endl
143  << " | qCut | " << setw(14) << qCut << " |" << endl
144  << " | nQmatch | " << setw(14) << nQmatch << " |" << endl
145  << " | clFact | " << setw(14) << clFact << " |" << endl
146  << " | Jet algorithm | " << setw(14) << jetStr << " |" << endl
147  << " | eTjetMin | " << setw(14) << eTjetMin << " |" << endl
148  << " | etaJetMax | " << setw(14) << etaJetMax << " |" << endl
149  << " | jetAllow | " << setw(14) << jetAllow << " |" << endl
150  << " | Mode | " << setw(14) << modeStr << " |" << endl
151  << " *-----------------------------------------*" << endl;
152  }
153  return true;
154 }
155 
157  // Sort event using the procedure required at parton level
158  sortIncomingProcess(event);
159 
160  // For the shower-kT scheme, do not perform any veto here, as any vetoing
161  // will already have taken place in doVetoStep.
162  if (doShowerKt)
163  return false;
164 
165  // Debug printout.
166  if (MATCHINGDEBUG) {
167  // Begin
168  cout << endl << "-------- Begin Madgraph Debug --------" << endl;
169  // Original incoming process
170  cout << endl << "Original incoming process:";
171  eventProcessOrig.list();
172  // Final-state of original incoming process
173  cout << endl << "Final-state incoming process:";
174  eventProcess.list();
175  // List categories of sorted particles
176  for (size_t i = 0; i < typeIdx[0].size(); i++)
177  cout << ((i == 0) ? "Light jets: " : ", ") << setw(3) << typeIdx[0][i];
178  if (typeIdx[0].empty())
179  cout << "Light jets: None";
180 
181  for (size_t i = 0; i < typeIdx[1].size(); i++)
182  cout << ((i == 0) ? "\nHeavy jets: " : ", ") << setw(3) << typeIdx[1][i];
183  for (size_t i = 0; i < typeIdx[2].size(); i++)
184  cout << ((i == 0) ? "\nOther: " : ", ") << setw(3) << typeIdx[2][i];
185  // Full event at this stage
186  cout << endl << endl << "Event:";
187  event.list();
188  // Work event (partons from hardest subsystem + ISR + FSR)
189  cout << endl << "Work event:";
190  workEvent.list();
191  }
192 
193  // 2) Light/heavy jets: iType = 0 (light jets), 1 (heavy jets)
194  int iTypeEnd = (typeIdx[2].empty()) ? 2 : 3;
195  for (int iType = 0; iType < iTypeEnd; iType++) {
196  // 2a) Find particles which will be passed from the jet algorithm.
197  // Input from 'workEvent' and output in 'workEventJet'.
198  jetAlgorithmInput(event, iType);
199 
200  // Debug printout.
201  if (MATCHINGDEBUG) {
202  // Jet algorithm event
203  cout << endl << "Jet algorithm event (iType = " << iType << "):";
204  workEventJet.list();
205  }
206 
207  // 2b) Run jet algorithm on 'workEventJet'.
208  // Output is stored in jetMomenta.
209  runJetAlgorithm();
210 
211  // 2c) Match partons to jets and decide if veto is necessary
212  if (matchPartonsToJets(iType) == true) {
213  // Debug printout.
214  if (MATCHINGDEBUG) {
215  cout << endl
216  << "Event vetoed"
217  << "---------- End MLM Debug ----------" << endl;
218  }
219  return true;
220  }
221  }
222 
223  // Debug printout.
224  if (MATCHINGDEBUG) {
225  cout << endl
226  << "Event accepted"
227  << "---------- End MLM Debug ----------" << endl;
228  }
229  // If we reached here, then no veto
230  return false;
231 }
232 
234  omitResonanceDecays(eventProcessOrig, true);
235  clearDJR();
236  clear_nMEpartons();
237 
238  // Step-FxFx-1: remove preclustering from FxFx
239  eventProcess = workEvent;
240 
241  for (int i = 0; i < 3; i++) {
242  typeIdx[i].clear();
243  typeSet[i].clear();
244  origTypeIdx[i].clear();
245  }
246 
247  for (int i = 0; i < eventProcess.size(); i++) {
248  // Ignore non-final state and default to 'other'
249  if (!eventProcess[i].isFinal())
250  continue;
251  int idx = -1;
252  int orig_idx = -1;
253 
254  // Light jets: all gluons and quarks with id less than or equal to nQmatch
255  if (eventProcess[i].isGluon() || (eventProcess[i].idAbs() <= nQmatch)) {
256  orig_idx = 0;
257  if (doFxFx) {
258  // Crucial point FxFx: MG5 puts the scale of a not-to-be-matched quark 1 MeV lower than scalup. For
259  // such particles, we should keep the default "2"
260  idx = (trunc(1000. * eventProcess[i].scale()) == trunc(1000. * infoPtr->scalup())) ? 0 : 2;
261  } else {
262  // Crucial point: MG puts the scale of a non-QCD particle to eCM. For
263  // such particles, we should keep the default "2"
264  idx = (eventProcess[i].scale() < 1.999 * sqrt(infoPtr->eA() * infoPtr->eB())) ? 0 : 2;
265  }
266  }
267 
268  // Heavy jets: all quarks with id greater than nQmatch
269  else if (eventProcess[i].idAbs() > nQmatch && eventProcess[i].idAbs() <= ID_TOP) {
270  idx = 1;
271  orig_idx = 1;
272  // Update to include non-SM colored particles
273  } else if (eventProcess[i].colType() != 0 && eventProcess[i].idAbs() > ID_TOP) {
274  idx = 1;
275  orig_idx = 1;
276  }
277  if (idx < 0)
278  continue;
279  // Store
280  typeIdx[idx].push_back(i);
281  typeSet[idx].insert(eventProcess[i].daughter1());
282  origTypeIdx[orig_idx].push_back(i);
283  }
284  // Exclusive mode; if set to 2, then set based on nJet/nJetMax
285  if (exclusiveMode == 2) {
286  // Inclusive if nJet == nJetMax, exclusive otherwise
287  int nParton = origTypeIdx[0].size();
288  exclusive = (nParton == nJetMax) ? false : true;
289 
290  // Otherwise, just set as given
291  } else {
292  exclusive = (exclusiveMode == 0) ? false : true;
293  }
294 
295  // Extract partons from hardest subsystem + ISR + FSR only into
296  // workEvent. Note no resonance showers or MPIs.
297  subEvent(event);
298 
299  // Store things that are necessary to perform the kT-MLM veto externally.
300  int nParton = typeIdx[0].size();
301  processSubsetSave.clear();
302  for (int i = 0; i < nParton; ++i)
303  processSubsetSave.append(eventProcess[typeIdx[0][i]]);
304 }
305 
307  eventProcessOrig = process;
308 
309  // Setup for veto if hard ME has too many partons.
310  // This is done to achieve consistency with the Pythia6 implementation.
311 
312  // Clear the event of MPI systems and resonace decay products. Store trimmed
313  // event in workEvent.
314  sortIncomingProcess(process);
315 
316  // Veto in case the hard input matrix element already has too many partons.
317  if (!doFxFx && int(typeIdx[0].size()) > nJetMax)
318  return true;
319  if (doFxFx && npNLO() < nJetMax && int(typeIdx[0].size()) > nJetMax)
320  return true;
321 
322  // Done
323  return false;
324 }
325 
326 void JetMatchingEWKFxFx::jetAlgorithmInput(const Event& event, int iType) {
327  // Take input from 'workEvent' and put output in 'workEventJet'
328  workEventJet = workEvent;
329 
330  // Loop over particles and decide what to pass to the jet algorithm
331  for (int i = 0; i < workEventJet.size(); ++i) {
332  if (!workEventJet[i].isFinal())
333  continue;
334 
335  // jetAllow option to disallow certain particle types
336  if (jetAllow == 1) {
337  // Remove all non-QCD partons from veto list
338  if (workEventJet[i].colType() == 0) {
339  workEventJet[i].statusNeg();
340  continue;
341  }
342  }
343  // Get the index of this particle in original event
344  int idx = workEventJet[i].daughter1();
345 
346  // Start with particle idx, and afterwards track mothers
347  while (true) {
348  // Light jets
349  if (iType == 0) {
350  // Do not include if originates from heavy jet or 'other'
351  if (typeSet[1].find(idx) != typeSet[1].end() || typeSet[2].find(idx) != typeSet[2].end()) {
352  workEventJet[i].statusNeg();
353  break;
354  }
355 
356  // Made it to start of event record so done
357  if (idx == 0)
358  break;
359  // Otherwise next mother and continue
360  idx = event[idx].mother1();
361 
362  // Heavy jets
363  } else if (iType == 1) {
364  // Only include if originates from heavy jet
365  if (typeSet[1].find(idx) != typeSet[1].end())
366  break;
367 
368  // Made it to start of event record with no heavy jet mother,
369  // so DO NOT include particle
370  if (idx == 0) {
371  workEventJet[i].statusNeg();
372  break;
373  }
374 
375  // Otherwise next mother and continue
376  idx = event[idx].mother1();
377 
378  // Other jets
379  } else if (iType == 2) {
380  // Only include if originates from other jet
381  if (typeSet[2].find(idx) != typeSet[2].end())
382  break;
383 
384  // Made it to start of event record with no heavy jet mother,
385  // so DO NOT include particle
386  if (idx == 0) {
387  workEventJet[i].statusNeg();
388  break;
389  }
390 
391  // Otherwise next mother and continue
392  idx = event[idx].mother1();
393  }
394  }
395  }
396 }
397 
399 
400 bool JetMatchingEWKFxFx::doVetoStep(int iPos, int nISR, int nFSR, const Event& event) {
401  // Do not perform any veto if not in the Shower-kT scheme.
402  if (!doShowerKt)
403  return false;
404 
405  // Do nothing for emissions after the first one.
406  if (nISR + nFSR > 1)
407  return false;
408 
409  // Do nothing in resonance decay showers.
410  if (iPos == 5)
411  return false;
412 
413  // Clear the event of MPI systems and resonace decay products. Store trimmed
414  // event in workEvent.
415  sortIncomingProcess(event);
416 
417  // Get (kinematical) pT of first emission
418  double pTfirst = 0.;
419 
420  // Get weak bosons, for later checks if the emission is a "QCD emission".
421  vector<int> weakBosons;
422  for (int i = 0; i < event.size(); i++) {
423  if (event[i].id() == 22 && event[i].id() == 23 && event[i].idAbs() == 24)
424  weakBosons.push_back(i);
425  }
426 
427  for (int i = workEvent.size() - 1; i > 0; --i) {
428  if (workEvent[i].isFinal() && workEvent[i].colType() != 0 &&
429  (workEvent[i].statusAbs() == 43 || workEvent[i].statusAbs() == 51)) {
430  // Check if any of the EW bosons are ancestors of this parton. This
431  // should never happen for the first non-resonance shower emission.
432  // Check just to be sure.
433  bool QCDemission = true;
434  // Get position of this parton in the actual event (workEvent does
435  // not contain right mother-daughter relations). Stored in daughters.
436  int iPosOld = workEvent[i].daughter1();
437  for (int j = 0; i < int(weakBosons.size()); ++i)
438  if (event[iPosOld].isAncestor(j)) {
439  QCDemission = false;
440  break;
441  }
442  // Done for a QCD emission.
443  if (QCDemission) {
444  pTfirst = workEvent[i].pT();
445  break;
446  }
447  }
448  }
449 
450  // Store things that are necessary to perform the shower-kT veto externally.
451  pTfirstSave = pTfirst;
452  // Done if only inputs for an external vetoing procedure should be stored.
453  //if (!performVeto) return false;
454 
455  // Check veto.
456  if (doShowerKtVeto(pTfirst))
457  return true;
458 
459  // No veto if come this far.
460  return false;
461 }
462 
463 void JetMatchingEWKFxFx::setDJR(const Event& event) {
464  // Clear members.
465  clearDJR();
466  vector<double> result;
467 
468  // Initialize SlowJetDJR jet algorithm with event
469  if (!slowJetDJR->setup(event)) {
470  errorMsg(
471  "Warning in JetMatchingMadgraph:setDJR"
472  ": the SlowJet algorithm failed on setup");
473  return;
474  }
475 
476  // Cluster in steps to find all hadronic jets
477  while (slowJetDJR->sizeAll() - slowJetDJR->sizeJet() > 0) {
478  // Save the next clustering scale.
479  result.push_back(sqrt(slowJetDJR->dNext()));
480  // Perform step.
481  slowJetDJR->doStep();
482  }
483 
484  // Save clustering scales in reserve order.
485  for (int i = int(result.size()) - 1; i >= 0; --i)
486  DJR.push_back(result[i]);
487 }
488 
490  // Use different routines for light/heavy/other jets as
491  // different veto conditions and for clarity
492  if (iType == 0) {
493  // Record the jet separations here, also if matchPartonsToJetsLight
494  // returns preemptively.
495  setDJR(workEventJet);
496  set_nMEpartons(origTypeIdx[0].size(), typeIdx[0].size());
497  // Perform jet matching.
498  return (matchPartonsToJetsLight() > 0);
499  } else if (iType == 1) {
500  return (matchPartonsToJetsHeavy() > 0);
501  } else {
502  return (matchPartonsToJetsOther() > 0);
503  }
504 }
505 
507  // Store things that are necessary to perform the kT-MLM veto externally.
508  workEventJetSave = workEventJet;
509  // Done if only inputs for an external vetoing procedure should be stored.
510  //if (!performVeto) return false;
511 
512  // Count the number of hard partons
513  int nParton = typeIdx[0].size();
514 
515  // Initialize SlowJet with current working event
516  if (!slowJet->setup(workEventJet)) {
517  errorMsg(
518  "Warning in JetMatchingMadgraph:matchPartonsToJets"
519  "Light: the SlowJet algorithm failed on setup");
520  return NONE;
521  }
522  double localQcutSq = qCutSq;
523  double dOld = 0.0;
524  // Cluster in steps to find all hadronic jets at the scale qCut
525  while (slowJet->sizeAll() - slowJet->sizeJet() > 0) {
526  if (slowJet->dNext() > localQcutSq)
527  break;
528  dOld = slowJet->dNext();
529  slowJet->doStep();
530  }
531  int nJets = slowJet->sizeJet();
532  int nClus = slowJet->sizeAll();
533 
534  // Debug printout.
535  if (MATCHINGDEBUG)
536  slowJet->list(true);
537 
538  // Count of the number of hadronic jets in SlowJet accounting
539  int nCLjets = nClus - nJets;
540  // Get number of partons. Different for MLM and FxFx schemes.
541  //int nRequested = (doFxFx) ? npNLO() : nParton;
542  //Step-FxFx-3: Change nRequested subtracting the typeIdx[2] partons
543  //Exclude the highest multiplicity sample in the case of real emissions and all typeIdx[2]
544  //npNLO=multiplicity,nJetMax=njmax(shower_card),typeIdx[2]="Weak" jets
545  int nRequested = (doFxFx && !(npNLO() == nJetMax && npNLO() == (int)(typeIdx[2].size() - 1)))
546  ? npNLO() - typeIdx[2].size()
547  : nParton;
548 
549  //Step-FxFx-4:For FxFx veto the real emissions that have only typeIdx=2 partons
550  //From Step-FxFx-3 they already have negative nRequested, so this step may not be necessary
551  //Exclude the highest multiplicity sample
552  if (doFxFx && npNLO() < nJetMax && !typeIdx[2].empty() && npNLO() == (int)(typeIdx[2].size() - 1)) {
553  return MORE_JETS;
554  }
555  //----------------
556  //Exclude all Weak Jets for matching
557  //if (doFxFx && typeIdx[2].size()>0) {
558  // return MORE_JETS;
559  //} // 2A
560  //keep only Weak Jets for matching
561  //if (doFxFx && typeIdx[2].size()==0) {
562  // return MORE_JETS;
563  //} // 2B
564  //keep only lowest multiplicity sample @0
565  //if (doFxFx && npNLO()==1) {
566  // return MORE_JETS;
567  //} // 2C
568  //keep only highest multiplicity sample @1
569  //if (doFxFx && npNLO()==0) {
570  // return MORE_JETS;
571  //} // 2D
572  //--------------
573  // Veto event if too few hadronic jets
574  if (nCLjets < nRequested)
575  return LESS_JETS;
576 
577  // In exclusive mode, do not allow more hadronic jets than partons
578  if (exclusive && !doFxFx) {
579  if (nCLjets > nRequested)
580  return MORE_JETS;
581  } else {
582  // For FxFx, in the non-highest multipicity, all jets need to matched to
583  // partons. For nCLjets > nRequested, this is not possible. Hence, we can
584  // veto here already.
585  // if ( doFxFx && nRequested < nJetMax && nCLjets > nRequested )
586  //Step-FxFx-5:Change the nRequested to npNLO() in the first condition
587  //Before in Step-FxFx-3 it was nRequested=npNLO() for FxFx
588  //This way we correctly select the non-highest multipicity regardless the nRequested
589  if (doFxFx && npNLO() < nJetMax && nCLjets > nRequested)
590  return MORE_JETS;
591 
592  // Now continue in inclusive mode.
593  // In inclusive mode, there can be more hadronic jets than partons,
594  // provided that all partons are properly matched to hadronic jets.
595  // Start by setting up the jet algorithm.
596  if (!slowJet->setup(workEventJet)) {
597  errorMsg(
598  "Warning in JetMatchingMadgraph:matchPartonsToJets"
599  "Light: the SlowJet algorithm failed on setup");
600  return NONE;
601  }
602 
603  // For FxFx, continue clustering as long as the jet separation is above
604  // qCut.
605  if (doFxFx) {
606  while (slowJet->sizeAll() - slowJet->sizeJet() > 0) {
607  if (slowJet->dNext() > localQcutSq)
608  break;
609  slowJet->doStep();
610  }
611  // For MLM, cluster into hadronic jets until there are the same number as
612  // partons.
613  } else {
614  while (slowJet->sizeAll() - slowJet->sizeJet() > nParton)
615  slowJet->doStep();
616  }
617 
618  // Sort partons in pT. Update local qCut value.
619  // Hadronic jets are already sorted in pT.
620  localQcutSq = dOld;
621  if (clFact >= 0. && nParton > 0) {
622  vector<double> partonPt;
623  partonPt.reserve(nParton);
624  for (int i = 0; i < nParton; ++i)
625  partonPt.push_back(eventProcess[typeIdx[0][i]].pT2());
626  sort(partonPt.begin(), partonPt.end());
627  localQcutSq = max(qCutSq, partonPt[0]);
628  }
629  nJets = slowJet->sizeJet();
630  nClus = slowJet->sizeAll();
631  }
632  // Update scale if clustering factor is non-zero
633  if (clFact != 0.)
634  localQcutSq *= pow2(clFact);
635 
636  Event tempEvent;
637  tempEvent.init("(tempEvent)", particleDataPtr);
638  int nPass = 0;
639  double pTminEstimate = -1.;
640  // Construct a master copy of the event containing only the
641  // hardest nParton hadronic clusters. While constructing the event,
642  // the parton type (ID_GLUON) and status (98,99) are arbitrary.
643  for (int i = nJets; i < nClus; ++i) {
644  tempEvent.append(
645  ID_GLUON, 98, 0, 0, 0, 0, 0, 0, slowJet->p(i).px(), slowJet->p(i).py(), slowJet->p(i).pz(), slowJet->p(i).e());
646  ++nPass;
647  pTminEstimate = max(pTminEstimate, slowJet->pT(i));
648  if (nPass == nRequested)
649  break;
650  }
651 
652  int tempSize = tempEvent.size();
653  // This keeps track of which hadronic jets are matched to parton
654  vector<bool> jetAssigned;
655  jetAssigned.assign(tempSize, false);
656 
657  // This keeps track of which partons are matched to which hadronic
658  // jets.
659  vector<vector<bool> > partonMatchesJet;
660  partonMatchesJet.reserve(nParton);
661  for (int i = 0; i < nParton; ++i)
662  partonMatchesJet.push_back(vector<bool>(tempEvent.size(), false));
663 
664  // Begin matching.
665  // Do jet matching for FxFx.
666  // Make sure that the nPartonsNow hardest hadronic jets are matched to any
667  // of the nPartonsNow (+1) partons. This matching is done by attaching a jet
668  // from the list of unmatched hadronic jets, and appending a jet from the
669  // list of partonic jets, one at a time. The partonic jet will be clustered
670  // with the hadronic jet or the beam if the distance measure is below the
671  // cut. The hadronic jet is matched once this happens. Otherwise, another
672  // partonic jet is tried. When a hadronic jet is matched to a partonic jet,
673  // it is removed from the list of unmatched hadronic jets. This process
674  // continues until the nPartonsNow hardest hadronic jets are matched to
675  // partonic jets, or it is not possible to make a match for a hadronic jet.
676  int iNow = 0;
677  int nMatched = 0;
678 
679  while (doFxFx && iNow < tempSize) {
680  // Check if this shower jet matches any partonic jet.
681  Event tempEventJet;
682  tempEventJet.init("(tempEventJet)", particleDataPtr);
683  for (int i = 0; i < nParton; ++i) {
685  //for (int j=0; j < tempSize; ++j )
686  // if ( partonMatchesJet[i][j]) continue;
687 
688  // Attach a single hadronic jet.
689  tempEventJet.clear();
690  tempEventJet.append(ID_GLUON,
691  98,
692  0,
693  0,
694  0,
695  0,
696  0,
697  0,
698  tempEvent[iNow].px(),
699  tempEvent[iNow].py(),
700  tempEvent[iNow].pz(),
701  tempEvent[iNow].e());
702  // Attach the current parton.
703  Vec4 pIn = eventProcess[typeIdx[0][i]].p();
704  tempEventJet.append(ID_GLUON, 99, 0, 0, 0, 0, 0, 0, pIn.px(), pIn.py(), pIn.pz(), pIn.e());
705 
706  // Setup jet algorithm.
707  if (!slowJet->setup(tempEventJet)) {
708  errorMsg(
709  "Warning in JetMatchingMadgraph:matchPartonsToJets"
710  "Light: the SlowJet algorithm failed on setup");
711  return NONE;
712  }
713  // These are the conditions for the hadronic jet to match the parton
714  // at the local qCut scale
715  if (slowJet->iNext() == tempEventJet.size() - 1 && slowJet->jNext() > -1 && slowJet->dNext() < localQcutSq) {
716  jetAssigned[iNow] = true;
717  partonMatchesJet[i][iNow] = true;
718  }
719  } // End loop over hard partons.
720 
721  // Veto if the jet could not be assigned to any parton.
722  if (jetAssigned[iNow])
723  nMatched++;
724 
725  // Continue;
726  ++iNow;
727  }
728  // Jet matching veto for FxFx
729  if (doFxFx) {
730  // if ( nRequested < nJetMax && nMatched != nRequested )
731  // return UNMATCHED_PARTON;
732  // if ( nRequested == nJetMax && nMatched < nRequested )
733  // return UNMATCHED_PARTON;
734  //Step-FxFx-6:Change the nRequested to npNLO() in the first condition (like in Step-FxFx-5)
735  //Before in Step-FxFx-3 it was nRequested=npNLO() for FxFx
736  //This way we correctly select the non-highest multipicity regardless the nRequested
737  if (npNLO() < nJetMax && nMatched != nRequested)
738  return UNMATCHED_PARTON;
739  if (npNLO() == nJetMax && nMatched < nRequested)
740  return UNMATCHED_PARTON;
741  }
742  // Do jet matching for MLM.
743  // Take the list of unmatched hadronic jets and append a parton, one at
744  // a time. The parton will be clustered with the "closest" hadronic jet
745  // or the beam if the distance measure is below the cut. When a hadronic
746  // jet is matched to a parton, it is removed from the list of unmatched
747  // hadronic jets. This process continues until all hadronic jets are
748  // matched to partons or it is not possible to make a match.
749  iNow = 0;
750  while (!doFxFx && iNow < nParton) {
751  Event tempEventJet;
752  tempEventJet.init("(tempEventJet)", particleDataPtr);
753  for (int i = 0; i < tempSize; ++i) {
754  if (jetAssigned[i])
755  continue;
756  Vec4 pIn = tempEvent[i].p();
757  // Append unmatched hadronic jets
758  tempEventJet.append(ID_GLUON, 98, 0, 0, 0, 0, 0, 0, pIn.px(), pIn.py(), pIn.pz(), pIn.e());
759  }
760 
761  Vec4 pIn = eventProcess[typeIdx[0][iNow]].p();
762  // Append the current parton
763  tempEventJet.append(ID_GLUON, 99, 0, 0, 0, 0, 0, 0, pIn.px(), pIn.py(), pIn.pz(), pIn.e());
764  if (!slowJet->setup(tempEventJet)) {
765  errorMsg(
766  "Warning in JetMatchingMadgraph:matchPartonsToJets"
767  "Light: the SlowJet algorithm failed on setup");
768  return NONE;
769  }
770  // These are the conditions for the hadronic jet to match the parton
771  // at the local qCut scale
772  if (slowJet->iNext() == tempEventJet.size() - 1 && slowJet->jNext() > -1 && slowJet->dNext() < localQcutSq) {
773  int iKnt = -1;
774  for (int i = 0; i != tempSize; ++i) {
775  if (jetAssigned[i])
776  continue;
777  ++iKnt;
778  // Identify the hadronic jet that matches the parton
779  if (iKnt == slowJet->jNext())
780  jetAssigned[i] = true;
781  }
782  } else {
783  return UNMATCHED_PARTON;
784  }
785  ++iNow;
786  }
787  // Minimal eT/pT (CellJet/SlowJet) of matched light jets.
788  // Needed later for heavy jet vetos in inclusive mode.
789  // This information is not used currently.
790  if (nParton > 0 && pTminEstimate > 0)
791  eTpTlightMin = pTminEstimate;
792  else
793  eTpTlightMin = -1.;
794 
795  // Record the jet separations.
796  setDJR(workEventJet);
797 
798  // No veto
799  return NONE;
800 }
801 
803  // Currently, heavy jets are unmatched
804  // If there are no extra jets, then accept
805  // jetMomenta is NEVER used by MadGraph and is always empty.
806  // This check does nothing.
807  // Rather, if there is any heavy flavor that is harder than
808  // what is present at the LHE level, then the event should
809  // be vetoed.
810 
811  // if (jetMomenta.empty()) return NONE;
812  // Count the number of hard partons
813  int nParton = typeIdx[1].size();
814 
815  Event tempEventJet(workEventJet);
816 
817  double scaleF(1.0);
818  // Rescale the heavy partons that are from the hard process to
819  // have pT=collider energy. Soft/collinear gluons will cluster
820  // onto them, leaving a remnant of hard emissions.
821  for (int i = 0; i < nParton; ++i) {
822  scaleF = eventProcessOrig[0].e() / workEventJet[typeIdx[1][i]].pT();
823  tempEventJet[typeIdx[1][i]].rescale5(scaleF);
824  }
825 
826  if (!hjSlowJet->setup(tempEventJet)) {
827  errorMsg(
828  "Warning in JetMatchingMadgraph:matchPartonsToJets"
829  "Heavy: the SlowJet algorithm failed on setup");
830  return NONE;
831  }
832 
833  while (hjSlowJet->sizeAll() - hjSlowJet->sizeJet() > 0) {
834  if (hjSlowJet->dNext() > qCutSq)
835  break;
836  hjSlowJet->doStep();
837  }
838 
839  int nCLjets(0);
840  // Count the number of clusters with pT>qCut. This includes the
841  // original hard partons plus any hard emissions.
842  for (int idx = 0; idx < hjSlowJet->sizeAll(); ++idx) {
843  if (hjSlowJet->pT(idx) > qCut)
844  nCLjets++;
845  }
846 
847  // Debug printout.
848  if (MATCHINGDEBUG)
849  hjSlowJet->list(true);
850 
851  // Count of the number of hadronic jets in SlowJet accounting
852  // int nCLjets = nClus - nJets;
853  // Get number of partons. Different for MLM and FxFx schemes.
854  int nRequested = nParton;
855 
856  // Veto event if too few hadronic jets
857  if (nCLjets < nRequested) {
858  if (MATCHINGDEBUG)
859  cout << "veto : hvy LESS_JETS " << endl;
860  if (MATCHINGDEBUG)
861  cout << "nCLjets = " << nCLjets << "; nRequest = " << nRequested << endl;
862  return LESS_JETS;
863  }
864 
865  // In exclusive mode, do not allow more hadronic jets than partons
866  if (exclusive) {
867  if (nCLjets > nRequested) {
868  if (MATCHINGDEBUG)
869  cout << "veto : excl hvy MORE_JETS " << endl;
870  return MORE_JETS;
871  }
872  }
873 
874  // No extra jets were present so no veto
875  return NONE;
876 }
877 
879  // Currently, heavy jets are unmatched
880  // If there are no extra jets, then accept
881  // jetMomenta is NEVER used by MadGraph and is always empty.
882  // This check does nothing.
883  // Rather, if there is any heavy flavor that is harder than
884  // what is present at the LHE level, then the event should
885  // be vetoed.
886 
887  // if (jetMomenta.empty()) return NONE;
888  // Count the number of hard partons
889  int nParton = typeIdx[2].size();
890 
891  Event tempEventJet(workEventJet);
892 
893  double scaleF(1.0);
894  // Rescale the heavy partons that are from the hard process to
895  // have pT=collider energy. Soft/collinear gluons will cluster
896  // onto them, leaving a remnant of hard emissions.
897  for (int i = 0; i < nParton; ++i) {
898  scaleF = eventProcessOrig[0].e() / workEventJet[typeIdx[2][i]].pT();
899  tempEventJet[typeIdx[2][i]].rescale5(scaleF);
900  }
901 
902  if (!hjSlowJet->setup(tempEventJet)) {
903  errorMsg(
904  "Warning in JetMatchingMadgraph:matchPartonsToJets"
905  "Heavy: the SlowJet algorithm failed on setup");
906  return NONE;
907  }
908 
909  while (hjSlowJet->sizeAll() - hjSlowJet->sizeJet() > 0) {
910  if (hjSlowJet->dNext() > qCutSq)
911  break;
912  hjSlowJet->doStep();
913  }
914 
915  int nCLjets(0);
916  // Count the number of clusters with pT>qCut. This includes the
917  // original hard partons plus any hard emissions.
918  for (int idx = 0; idx < hjSlowJet->sizeAll(); ++idx) {
919  if (hjSlowJet->pT(idx) > qCut)
920  nCLjets++;
921  }
922 
923  // Debug printout.
924  if (MATCHINGDEBUG)
925  hjSlowJet->list(true);
926 
927  // Count of the number of hadronic jets in SlowJet accounting
928  // int nCLjets = nClus - nJets;
929  // Get number of partons. Different for MLM and FxFx schemes.
930  int nRequested = nParton;
931 
932  // Veto event if too few hadronic jets
933  if (nCLjets < nRequested) {
934  if (MATCHINGDEBUG)
935  cout << "veto : other LESS_JETS " << endl;
936  if (MATCHINGDEBUG)
937  cout << "nCLjets = " << nCLjets << "; nRequest = " << nRequested << endl;
938  return LESS_JETS;
939  }
940 
941  // In exclusive mode, do not allow more hadronic jets than partons
942  if (exclusive) {
943  if (nCLjets > nRequested) {
944  if (MATCHINGDEBUG)
945  cout << "veto : excl other MORE_JETS" << endl;
946  return MORE_JETS;
947  }
948  }
949 
950  // No extra jets were present so no veto
951  return NONE;
952 }
953 
955  // Only check veto in the shower-kT scheme.
956  if (!doShowerKt)
957  return false;
958 
959  // Reset veto code
960  bool doVeto = false;
961 
962  // Find the (kinematical) pT of the softest (light) parton in the hard
963  // process.
964  int nParton = typeIdx[0].size();
965  double pTminME = 1e10;
966  for (int i = 0; i < nParton; ++i)
967  pTminME = min(pTminME, eventProcess[typeIdx[0][i]].pT());
968 
969  // Veto if the softest hard process parton is below Qcut.
970  if (nParton > 0 && pow(pTminME, 2) < qCutSq)
971  doVeto = true;
972 
973  // For non-highest multiplicity, veto if the hardest emission is harder
974  // than Qcut.
975  if (exclusive && pow(pTfirst, 2) > qCutSq) {
976  doVeto = true;
977  // For highest multiplicity sample, veto if the hardest emission is harder
978  // than the hard process parton.
979  } else if (!exclusive && nParton > 0 && pTfirst > pTminME) {
980  doVeto = true;
981  }
982 
983  // Return veto
984  return doVeto;
985 }
986 
987 // Function to get the current number of partons in the Born state, as
988 // read from LHE.
989 
991  string npIn = infoPtr->getEventAttribute("npNLO", true);
992  int np = !npIn.empty() ? std::atoi(npIn.c_str()) : -1;
993  if (np < 0) {
994  ;
995  } else
996  return np;
997  return nPartonsNow;
998 }
bool matchPartonsToJets(int) override
size
Write out results.
void jetAlgorithmInput(const Pythia8::Event &, int) override
bool doVetoPartonLevelEarly(const Pythia8::Event &event) override
int matchPartonsToJetsLight() override
constexpr int pow(int x)
Definition: conifer.h:24
bool doVetoStep(int, int, int, const Pythia8::Event &) override
void find(edm::Handle< EcalRecHitCollection > &hits, DetId thisDet, std::vector< EcalRecHitCollection::const_iterator > &hit, bool debug=false)
Definition: FindCaloHit.cc:19
bool isAncestor(ProcessHistory const &a, ProcessHistory const &b)
int np
Definition: AMPTWrapper.h:43
int matchPartonsToJetsHeavy() override
T sqrt(T t)
Definition: SSEVec.h:19
void runJetAlgorithm() override
bool doShowerKtVeto(double pTfirst)
ExtVec< T, 4 > Vec4
Definition: ExtVec.h:60
void sortIncomingProcess(const Pythia8::Event &) override
bool initAfterBeams() override
void setDJR(const Pythia8::Event &event)
JetMatchingEWKFxFx(const edm::ParameterSet &iConfig)
constexpr int pow2(int x)
Definition: conifer.h:28
Definition: TkAlStyle.h:43
bool doVetoProcessLevel(Pythia8::Event &event) override
Definition: event.py:1