CMS 3D CMS Logo

JetMatchingMGFastJet.cc
Go to the documentation of this file.
3 #include <iomanip>
9 
10 #include <boost/algorithm/string/trim.hpp>
11 
12 namespace gen {
13 
14  extern "C" {
15 
16 #define PARAMLEN 20
17  namespace {
18  struct Param {
19  Param(const std::string &str) {
20  int len = std::min(PARAMLEN, (int)str.length());
21  std::memcpy(value, str.c_str(), len);
22  std::memset(value + len, ' ', PARAMLEN - len);
23  }
24 
25  char value[PARAMLEN];
26  };
27  } // namespace
28 
29  extern struct UPPRIV {
30  int lnhin, lnhout;
31  int mscal, ievnt;
32  int ickkw, iscale;
33  } uppriv_;
34 
35  extern struct MEMAIN {
38  int mektsc, nexcres, excres[30];
39  int nqmatch, excproc, iexcproc[1000], iexcval[1000];
40  bool nosingrad, jetprocs;
41  } memain_;
42 
43  extern struct OUTTREE { int flag; } outtree_;
44  }
45 
46  template <typename T>
48  std::istringstream ss(value);
49  T result;
50  ss >> result;
51  return result;
52  }
53 
54  template <>
57  if (!result.empty() && result[0] == '\'')
58  result = result.substr(1);
59  if (!result.empty() && result[result.length() - 1] == '\'')
60  result.resize(result.length() - 1);
61  return result;
62  }
63 
64  template <>
66  std::string value(value_);
67  std::transform(value.begin(), value.end(), value.begin(), (int (*)(int))std::toupper);
68  return value == "T" || value == "Y" || value == "True" || value == "1" || value == ".TRUE.";
69  }
70 
71  template <typename T>
72  T JetMatchingMGFastJet::getParameter(const std::map<std::string, std::string> &params,
73  const std::string &var,
74  const T &defValue) {
75  std::map<std::string, std::string>::const_iterator pos = params.find(var);
76  if (pos == params.end())
77  return defValue;
78  return parseParameter<T>(pos->second);
79  }
80 
81  template <typename T>
82  T JetMatchingMGFastJet::getParameter(const std::string &var, const T &defValue) const {
83  return getParameter(mgParams, var, defValue);
84  }
85 
86  static std::map<std::string, std::string> parseHeader(const std::vector<std::string> &header) {
87  std::map<std::string, std::string> params;
88 
89  for (std::vector<std::string>::const_iterator iter = header.begin(); iter != header.end(); ++iter) {
90  std::string line = *iter;
91  if (line.empty() || line[0] == '#')
92  continue;
93 
94  std::string::size_type pos = line.find('!');
95  if (pos != std::string::npos)
96  line.resize(pos);
97 
98  pos = line.find('=');
99  if (pos == std::string::npos)
100  continue;
101 
102  std::string var = boost::algorithm::trim_copy(line.substr(pos + 1));
103  std::string value = boost::algorithm::trim_copy(line.substr(0, pos));
104 
105  params[var] = value;
106  }
107 
108  return params;
109  }
110 
111  template <typename T>
112  void JetMatchingMGFastJet::updateOrDie(const std::map<std::string, std::string> &params,
113  T &param,
114  const std::string &name) {
115  if (param < 0) {
116  param = getParameter(params, name, param);
117  }
118  if (param < 0)
119  throw cms::Exception("Generator|PartonShowerVeto") << "The MGParamCMS header does not specify the jet "
120  "matching parameter \""
121  << name
122  << "\", but it "
123  "is requested by the CMSSW configuration."
124  << std::endl;
125  }
126 
128  : JetMatching(params), runInitialized(false), fJetFinder(nullptr), fIsInit(false) {
129  std::string mode = params.getParameter<std::string>("mode");
130  if (mode == "inclusive") {
131  soup = false;
132  exclusive = false;
133  } else if (mode == "exclusive") {
134  soup = false;
135  exclusive = true;
136  } else if (mode == "auto")
137  soup = true;
138  else
139  throw cms::Exception("Generator|LHEInterface") << "MGFastJet jet matching scheme requires \"mode\" "
140  "parameter to be set to either \"inclusive\", "
141  "\"exclusive\" or \"auto\"."
142  << std::endl;
143 
144  memain_.etcjet = 0.;
145  memain_.rclmax = 0.0;
146  memain_.clfact = 0.0;
147  memain_.ktsche = 0.0;
148  memain_.etaclmax = params.getParameter<double>("MEMAIN_etaclmax");
149  memain_.qcut = params.getParameter<double>("MEMAIN_qcut");
150  memain_.minjets = params.getParameter<int>("MEMAIN_minjets");
151  memain_.maxjets = params.getParameter<int>("MEMAIN_maxjets");
152  memain_.showerkt = params.getParameter<double>("MEMAIN_showerkt");
153  memain_.nqmatch = params.getParameter<int>("MEMAIN_nqmatch");
154  outtree_.flag = params.getParameter<int>("outTree_flag");
155  std::string list_excres = params.getParameter<std::string>("MEMAIN_excres");
156  std::vector<std::string> elems;
157  std::stringstream ss(list_excres);
159  int index = 0;
160  while (std::getline(ss, item, ',')) {
161  elems.push_back(item);
162  memain_.excres[index] = std::atoi(item.c_str());
163  index++;
164  }
166 
167  fDJROutFlag = params.getParameter<int>("outTree_flag");
168  }
169 
171 
173  if (fIsInit)
174  return true;
175 
176  //
178  // doMerge = true;
179  qCut = memain_.qcut; //
181  clFact = 1.; // Default value
182  // NOTE: ME2pythia seems to default to 1.5 - need to check !!!
183  // in general, needs to read key ALPSFACT from LHE file - fix CMSSW code !!!
186 
188 
189  coneRadius = 1.0;
190  jetAlgoPower = 1; // this is the kT algorithm !!!
191 
192  // Matching procedure
193  //
194  qCutSq = pow(qCut, 2);
195  // this should be something like memaev_.iexc
196  fExcLocal = true;
197 
198  // If not merging, then done (?????)
199  //
200  // if (!doMerge) return true;
201 
202  // Initialise chosen jet algorithm.
203  //
204  fJetFinder = new fastjet::JetDefinition(fastjet::kt_algorithm, coneRadius);
205  fClusJets.clear();
206  fPtSortedJets.clear();
207 
208  fIsInit = true;
209 
210  return true;
211  }
212 
214  if (!runInitialized)
215  throw cms::Exception("Generator|PartonShowerVeto") << "Run not initialized in JetMatchingMGFastJet" << std::endl;
216 
217  for (int i = 0; i < 3; i++) {
218  typeIdx[i].clear();
219  }
220 
221  // Sort original process final state into light/heavy jets and 'other'.
222  // Criteria:
223  // 1 <= ID <= 5 and massless, or ID == 21 --> light jet (typeIdx[0])
224  // 4 <= ID <= 6 and massive --> heavy jet (typeIdx[1])
225  // All else --> other (typeIdx[2])
226  //
227  const lhef::HEPEUP &hepeup = *lhee->getHEPEUP();
228  int idx = 2;
229  for (int i = 0; i < hepeup.NUP; i++) {
230  if (hepeup.ISTUP[i] < 0)
231  continue;
232  if (hepeup.MOTHUP[i].first != 1 && hepeup.MOTHUP[i].second != 2)
233  continue; // this way we skip entries that come
234  // from resonance decays;
235  // we only take those that descent
236  // directly from "incoming partons"
237  idx = 2;
238  if (hepeup.IDUP[i] == ID_GLUON || (std::abs(hepeup.IDUP[i]) <= nQmatch)) // light jet
239  // light jet
240  idx = 0;
241  else if (std::abs(hepeup.IDUP[i]) > nQmatch && std::abs(hepeup.IDUP[i]) <= ID_TOP) // heavy jet
242  idx = 1;
243  // Store
244  typeIdx[idx].push_back(i);
245  }
246 
247  // NOTE: In principle, I should use exclusive, inclusive, or soup !!!
248  // should be like this:
249  if (soup) {
250  int NPartons = typeIdx[0].size();
251  fExcLocal = (NPartons < nJetMax);
252  } else
254 
255  return;
256  }
257 
259  if (fIsInit)
260  return;
261 
262  // read MGFastJet run card
263 
264  std::map<std::string, std::string> parameters;
265 
266  std::vector<std::string> header = runInfo->findHeader("MGRunCard");
267  if (header.empty())
268  throw cms::Exception("Generator|PartonShowerVeto") << "In order to use MGFastJet jet matching, "
269  "the input file has to contain the corresponding "
270  "MadGraph headers."
271  << std::endl;
272 
274 
275  // set variables in common block
276 
277  std::vector<Param> params;
278  std::vector<Param> values;
279  for (std::map<std::string, std::string>::const_iterator iter = mgParams.begin(); iter != mgParams.end(); ++iter) {
280  params.push_back(" " + iter->first);
281  values.push_back(iter->second);
282  }
283 
284  // set MG matching parameters
285 
286  uppriv_.ickkw = getParameter<int>("ickkw", 0);
287  memain_.mektsc = getParameter<int>("ktscheme", 0);
288 
289  header = runInfo->findHeader("MGParamCMS");
290 
291  std::map<std::string, std::string> mgInfoCMS = parseHeader(header);
292 
293  for (std::map<std::string, std::string>::const_iterator iter = mgInfoCMS.begin(); iter != mgInfoCMS.end(); ++iter) {
294  std::cout << "mgInfoCMS: " << iter->first << " " << iter->second << std::endl;
295  }
296 
297  updateOrDie(mgInfoCMS, memain_.etaclmax, "etaclmax");
298  updateOrDie(mgInfoCMS, memain_.qcut, "qcut");
299  updateOrDie(mgInfoCMS, memain_.minjets, "minjets");
300  updateOrDie(mgInfoCMS, memain_.maxjets, "maxjets");
301  updateOrDie(mgInfoCMS, memain_.showerkt, "showerkt");
302  updateOrDie(mgInfoCMS, memain_.nqmatch, "nqmatch");
303 
304  runInitialized = true;
305 
306  initAfterBeams();
307 
308  fIsInit = true;
309 
310  return;
311  }
312 
313  int JetMatchingMGFastJet::match(const lhef::LHEEvent *partonLevel, const std::vector<fastjet::PseudoJet> *jetInput) {
314  // Number of hard partons
315  //
316  int NPartons = typeIdx[0].size();
317 
318  fClusJets.clear();
319  fPtSortedJets.clear();
320 
321  int ClusSeqNJets = 0;
322 
323  fastjet::ClusterSequence ClusSequence(*jetInput, *fJetFinder);
324 
325  if (fExcLocal) {
326  fClusJets = ClusSequence.exclusive_jets(qCutSq);
327  } else {
328  fClusJets = ClusSequence.inclusive_jets(qCut);
329  }
330 
331  ClusSeqNJets = fClusJets.size();
332 
333  if (ClusSeqNJets < NPartons)
334  return LESS_JETS;
335 
336  double localQcutSq = qCutSq;
337 
338  if (fExcLocal) // exclusive
339  {
340  if (ClusSeqNJets > NPartons)
341  return MORE_JETS;
342  } else // inclusive
343  {
344  fPtSortedJets = fastjet::sorted_by_pt(*jetInput);
345  localQcutSq = std::max(qCutSq, fPtSortedJets[0].pt2());
346  fClusJets = ClusSequence.exclusive_jets(NPartons); // override
347  ClusSeqNJets = NPartons;
348  }
349 
350  if (clFact != 0)
351  localQcutSq *= pow(clFact, 2);
352 
353  std::vector<fastjet::PseudoJet> MatchingInput;
354 
355  std::vector<bool> jetAssigned;
356  jetAssigned.assign(fClusJets.size(), false);
357 
358  int counter = 0;
359 
360  const lhef::HEPEUP &hepeup = *partonLevel->getHEPEUP();
361 
362  while (counter < NPartons) {
363  MatchingInput.clear();
364 
365  for (int i = 0; i < ClusSeqNJets; i++) {
366  if (jetAssigned[i])
367  continue;
368  if (i == NPartons)
369  break;
370  //
371  // this looks "awkward" but this way we do NOT pass in cluster_hist_index
372  // which would actually indicate position in "history" of the "master" ClusSeq
373  //
374  fastjet::PseudoJet exjet = fClusJets[i];
375  MatchingInput.push_back(fastjet::PseudoJet(exjet.px(), exjet.py(), exjet.pz(), exjet.e()));
376  MatchingInput.back().set_user_index(i);
377  }
378 
379  int idx = typeIdx[0][counter];
380  MatchingInput.push_back(
381  fastjet::PseudoJet(hepeup.PUP[idx][0], hepeup.PUP[idx][1], hepeup.PUP[idx][2], hepeup.PUP[idx][3]));
382 
383  //
384  // in principle, one can use ClusterSequence::n_particles()
385  //
386  int NBefore = MatchingInput.size();
387 
388  // Create new clustering object - which includes the 1st clustering run !!!
389  // NOTE-1: it better be a new object for each try, or history will be "too crowded".
390  // NOTE-2: when created, the it ALWAYS makes at least 1 clustering step, so in most
391  // cases at least 1 new jet object will be added; although in some cases
392  // no jet is added, if the system doesn't cluster to anything (for example,
393  // input jet(s) and parton(s) are going opposite directions)
394  //
395  fastjet::ClusterSequence ClusSeq(MatchingInput, *fJetFinder);
396 
397  const std::vector<fastjet::PseudoJet> &output = ClusSeq.jets();
398  int NClusJets = output.size() - NBefore;
399 
400  //
401  // JVY - I think this is the right idea:
402  // at least 1 (one) new jet needs to be added
403  // however, need to double check details and refine, especially for inclusive mode
404  //
405  //
406  if (NClusJets < 1) {
407  return UNMATCHED_PARTON;
408  }
409  //
410  // very unlikely case but let's do it just to be safe
411  //
412  if (NClusJets >= NBefore) {
413  return MORE_JETS;
414  }
415 
416  // Now browse history and see how close the clustering distance
417  //
418  // NOTE: Remember, there maybe more than one new jet in the list (for example,
419  // for process=2,3,...);
420  // in this case we take the ** first ** one that satisfies the distance/cut,
421  // which is ** typically ** also the best one
422  //
423  bool matched = false;
424  const std::vector<fastjet::ClusterSequence::history_element> &history = ClusSeq.history();
425 
426  // for ( unsigned int i=nBefore; i<history.size(); i++ )
427  for (unsigned int i = NBefore; i < output.size(); i++) {
428  int hidx = output[i].cluster_sequence_history_index();
429  double dNext = history[hidx].dij;
430  if (dNext < localQcutSq) {
431  //
432  // the way we form input, parent1 is always jet, and parent2 can be any,
433  // but if it's a good match/cluster, it should point at the parton
434  //
435  int parent1 = history[hidx].parent1;
436  int parent2 = history[hidx].parent2;
437  if (parent1 < 0 || parent2 < 0)
438  break; // bad cluster, no match
439  //
440  // pull up jet's "global" index
441  //
442  int pidx = MatchingInput[parent1].user_index();
443  jetAssigned[pidx] = true;
444  matched = true;
445  break;
446  }
447  }
448  if (!matched) {
449  return UNMATCHED_PARTON;
450  }
451 
452  counter++;
453  }
454 
455  // Now save some info for DJR analysis (if requested).
456  // This mimics what is done in ME2pythia.f
457  // Basically, NJets and matching scale for these 4 cases:
458  // 1->0, 2->1, 3->2, and 4->3
459  //
460  if (fDJROutFlag > 0) {
461  std::vector<double> MergingScale;
462  MergingScale.clear();
463  for (int nj = 0; nj < 4; nj++) {
464  double dmscale2 = ClusSequence.exclusive_dmerge(nj);
465  double dmscale = sqrt(dmscale2);
466  MergingScale.push_back(dmscale);
467  }
468  fDJROutput.open("events.tree", std::ios_base::app);
469  double dNJets = (double)NPartons;
470  fDJROutput << " " << dNJets << " " << MergingScale[0] << " " << MergingScale[1] << " " << MergingScale[2] << " "
471  << MergingScale[3] << std::endl;
472  fDJROutput.close();
473  }
474 
475  return NONE;
476  }
477 
478 } // namespace gen
struct gen::OUTTREE outtree_
struct gen::MEMAIN memain_
fastjet::JetDefinition * fJetFinder
JetMatchingMGFastJet(const edm::ParameterSet &params)
double getJetEtaMax() const override
static T getParameter(const std::map< std::string, std::string > &params, const std::string &var, const T &defValue=T())
static void updateOrDie(const std::map< std::string, std::string > &params, T &param, const std::string &name)
uint16_t size_type
#define PARAMLEN
void beforeHadronisation(const lhef::LHEEvent *) override
int match(const lhef::LHEEvent *partonLevel, const std::vector< fastjet::PseudoJet > *jetInput) override
T sqrt(T t)
Definition: SSEVec.h:19
std::vector< FiveVector > PUP
Definition: LesHouches.h:246
Abs< T >::type abs(const T &t)
Definition: Abs.h:22
std::vector< int > ISTUP
Definition: LesHouches.h:228
Definition: value.py:1
std::vector< std::pair< int, int > > MOTHUP
Definition: LesHouches.h:234
static std::map< std::string, std::string > parseHeader(const std::vector< std::string > &header)
std::vector< int > IDUP
Definition: LesHouches.h:223
std::vector< fastjet::PseudoJet > fClusJets
static T parseParameter(const std::string &value)
std::vector< fastjet::PseudoJet > fPtSortedJets
std::map< std::string, std::string > mgParams
const HEPEUP * getHEPEUP() const
Definition: LHEEvent.h:38
void init(const lhef::LHERunInfo *runInfo) override
static std::atomic< unsigned int > counter
#define str(s)
long double T
Power< A, B >::type pow(const A &a, const B &b)
Definition: Power.h:29
struct gen::UPPRIV uppriv_
std::vector< int > typeIdx[3]
unsigned transform(const HcalDetId &id, unsigned transformCode)