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