CMS 3D CMS Logo

 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
ParticleReplacerZtautau.cc
Go to the documentation of this file.
2 
5 
8 
10 
12 #include "HepPDT/ParticleDataTable.hh"
13 
14 #include "HepMC/IO_HEPEVT.h"
15 
17 #include "TauAnalysis/MCEmbeddingTools/interface/extraPythia.h" // needed for call_pyexec
18 
20 
23 
24 #include <Math/VectorUtil.h>
25 #include <TMath.h>
26 #include <TVector3.h>
27 
28 #include <stack>
29 #include <queue>
30 #include <vector>
31 
32 const double tauMass = 1.77690;
33 const double muonMass = 0.105658369;
34 const double electronMass = 0.00051099893; // GeV
35 const double protonMass = 0.938272;
36 
37 const double nomMassW = 80.398;
38 const double breitWignerWidthW = 2.141;
39 const double nomMassZ = 91.1876;
40 const double breitWignerWidthZ = 2.4952;
41 
43 
44 typedef std::vector<reco::Particle> ParticleCollection;
45 
47  : ParticleReplacerBase(cfg),
48  generatorMode_(cfg.getParameter<std::string>("generatorMode")),
49  beamEnergy_(cfg.getParameter<double>("beamEnergy")),
50  tauola_(gen::TauolaInterface::getInstance()),
51  applyMuonRadiationCorrection_(false),
52  muonRadiationAlgo_(0),
53  pythia_(cfg)
54 {
55  tauola_->setPSet(cfg.getParameter<edm::ParameterSet>("TauolaOptions"));
56  maxNumberOfAttempts_ = ( cfg.exists("maxNumberOfAttempts") ) ?
57  cfg.getParameter<int>("maxNumberOfAttempts") : 10000;
58 
59  // transformationMode =
60  // 0 - no transformation
61  // 1 - mumu -> tautau
62  // 2 - mumu -> ee
63  // 3 - mumu -> taunu
64  // 4 - munu -> taunu
65  transformationMode_ = ( cfg.exists("transformationMode") ) ?
66  cfg.getParameter<int>("transformationMode") : 1;
67  if ( verbosity_ ) {
68  edm::LogInfo("Replacer") << "generatorMode = " << generatorMode_ << "\n";
69  edm::LogInfo("Replacer") << "transformationMode = " << transformationMode_ << "\n";
70  }
71 
72  motherParticleID_ = ( cfg.exists("motherParticleID") ) ?
73  cfg.getParameter<int>("motherParticleID") : 23;
74 
75  // require generator level visible tau decay products to exceed given transverse momentum.
76  // The purpose of this flag is make maximal use of the available Zmumu events statistics
77  // by not generating tau-paisr which will fail the visible Pt cuts applied on reconstruction level in physics analyses.
78  //
79  // NOTE: the thresholds specified by configuration parameter 'minVisibleTransverseMomentum' need to be a few GeV lower
80  // than the cuts applied on reconstruction level in physics analyses,
81  // to account for resolution effects
82  //
83  if ( cfg.exists("minVisibleTransverseMomentum") ) {
84  std::string minVisibleTransverseMomentumLine = cfg.getParameter<std::string>("minVisibleTransverseMomentum");
85  const char* startptr = minVisibleTransverseMomentumLine.c_str();
86  char* endptr;
87  double d = strtod(startptr, &endptr);
88  if ( *endptr == '\0' && endptr != startptr ) {
89  // fallback for backwards compatibility:
90  // if it's a single number then use this as a threshold for both particles
91  MinVisPtCut cutLeg1;
92  cutLeg1.type_ = MinVisPtCut::kTAU;
93  cutLeg1.threshold_ = d;
94  cutLeg1.index_ = 0;
95  MinVisPtCut cutLeg2;
96  cutLeg2.type_ = MinVisPtCut::kTAU;
97  cutLeg2.threshold_ = d;
98  cutLeg2.index_ = 1;
99  MinVisPtCutCombination minVisPtCut;
100  minVisPtCut.cut_string_ = minVisibleTransverseMomentumLine;
101  minVisPtCut.cuts_.push_back(cutLeg1);
102  minVisPtCut.cuts_.push_back(cutLeg2);
103  minVisPtCuts_.push_back(minVisPtCut);
104  } else {
105  // string has new format:
106  // parse the minVisibleTransverseMomentum string
107  for ( std::string::size_type prev = 0, pos = 0; prev < minVisibleTransverseMomentumLine.length(); prev = pos + 1) {
108  pos = minVisibleTransverseMomentumLine.find(';', prev);
109  if ( pos == std::string::npos ) pos = minVisibleTransverseMomentumLine.length();
110 
111  std::string sub = minVisibleTransverseMomentumLine.substr(prev, pos - prev);
112  MinVisPtCutCombination minVisPtCut;
113  minVisPtCut.cut_string_ = minVisibleTransverseMomentumLine;
114  const char* sub_c = sub.c_str();
115  while (*sub_c != '\0' ) {
116  const char* sep = std::strchr(sub_c, '_');
117  if ( sep == NULL ) throw cms::Exception("Configuration")
118  << "Minimum transverse parameter string must contain an underscore to separate type from Pt threshold !!\n";
119  std::string type(sub_c, sep);
120 
122  if ( type == "elec1" ) { cut.type_ = MinVisPtCut::kELEC; cut.index_ = 0; }
123  else if ( type == "mu1" ) { cut.type_ = MinVisPtCut::kMU; cut.index_ = 0; }
124  else if ( type == "had1" ) { cut.type_ = MinVisPtCut::kHAD; cut.index_ = 0; }
125  else if ( type == "tau1" ) { cut.type_ = MinVisPtCut::kTAU; cut.index_ = 0; }
126  else if ( type == "elec2" ) { cut.type_ = MinVisPtCut::kELEC; cut.index_ = 1; }
127  else if ( type == "mu2" ) { cut.type_ = MinVisPtCut::kMU; cut.index_ = 1; }
128  else if ( type == "had2" ) { cut.type_ = MinVisPtCut::kHAD; cut.index_ = 1; }
129  else if ( type == "tau2" ) { cut.type_ = MinVisPtCut::kTAU; cut.index_ = 1; }
130  else throw cms::Exception("Configuration")
131  << "'" << type << "' is not a valid type. Allowed values are { elec1, mu1, had1, tau1, elec2, mu2, had2, tau2 } !!\n";
132 
133  char* endptr;
134  cut.threshold_ = strtod(sep + 1, &endptr);
135  if ( endptr == sep + 1 ) throw cms::Exception("Configuration")
136  << "No Pt threshold given !!\n";
137 
138  std::cout << "Adding vis. Pt cut: index = " << cut.index_ << ", type = " << cut.type_ << ", threshold = " << cut.threshold_ << std::endl;
139  minVisPtCut.cuts_.push_back(cut);
140  sub_c = endptr;
141  }
142  minVisPtCuts_.push_back(minVisPtCut);
143  }
144  }
145  }
146 
147  rfRotationAngle_ = cfg.getParameter<double>("rfRotationAngle")*TMath::Pi()/180.;
148 
150  if ( !rng.isAvailable() )
151  throw cms::Exception("Configuration")
152  << "The RandomNumberProducer module requires the RandomNumberGeneratorService\n"
153  << "which appears to be absent. Please add that service to your configuration\n"
154  << "or remove the modules that require it.\n";
155 
156  // this is a global variable defined in GeneratorInterface/ExternalDecays/src/ExternalDecayDriver.cc
157  decayRandomEngine = &rng->getEngine();
158 
159  std::string applyMuonRadiationCorrection_string = cfg.getParameter<std::string>("applyMuonRadiationCorrection");
160  if ( applyMuonRadiationCorrection_string != "" ) {
161  edm::ParameterSet cfgMuonRadiationAlgo;
162  cfgMuonRadiationAlgo.addParameter<double>("beamEnergy", beamEnergy_);
163  cfgMuonRadiationAlgo.addParameter<std::string>("mode", applyMuonRadiationCorrection_string);
164  cfgMuonRadiationAlgo.addParameter<int>("verbosity", 0);
165  edm::ParameterSet cfgPhotosOptions;
166  cfgMuonRadiationAlgo.addParameter<edm::ParameterSet>("PhotosOptions", cfgPhotosOptions);
167  edm::ParameterSet cfgPythiaParameters = cfg.getParameter<edm::ParameterSet>("PythiaParameters");
168  cfgMuonRadiationAlgo.addParameter<edm::ParameterSet>("PythiaParameters", cfgPythiaParameters);
169  muonRadiationAlgo_ = new GenMuonRadiationAlgorithm(cfgMuonRadiationAlgo);
171  }
172 }
173 
175 {
176  delete muonRadiationAlgo_;
177 }
178 
180 {
181  producer->call_produces<ParticleCollection>("muonsBeforeRad");
182  producer->call_produces<ParticleCollection>("muonsAfterRad");
183 }
184 
186 {
187  gen::Pythia6Service::InstanceWrapper pythia6InstanceGuard(&pythia_);
189 }
190 
191 namespace
192 {
193  double square(double x)
194  {
195  return x*x;
196  }
197 
198  bool matchesGenParticle(const HepMC::GenParticle* genParticle1, const HepMC::GenParticle* genParticle2)
199  {
200  if ( genParticle1->pdg_id() == genParticle2->pdg_id() &&
201  TMath::Abs(genParticle1->momentum().e() - genParticle2->momentum().e()) < (1.e-3*(genParticle1->momentum().e() + genParticle2->momentum().e())) &&
202  reco::deltaR(genParticle1->momentum(), genParticle2->momentum()) < 1.e-3 )
203  return true;
204  else
205  return false;
206  }
207 
208  bool matchesGenVertex(const HepMC::GenVertex* genVertex1, const HepMC::GenVertex* genVertex2, bool checkIncomingParticles, bool checkOutgoingParticles)
209  {
210  // require that vertex positions match
211  if ( !(TMath::Abs(genVertex1->position().x() - genVertex2->position().x()) < 1.e-3 &&
212  TMath::Abs(genVertex1->position().y() - genVertex2->position().y()) < 1.e-3 &&
213  TMath::Abs(genVertex1->position().z() - genVertex2->position().z()) < 1.e-3) ) return false;
214 
215  // require that "incoming" particles match
216  if ( checkIncomingParticles ) {
217  for ( HepMC::GenVertex::particles_in_const_iterator genParticle1 = genVertex1->particles_in_const_begin();
218  genParticle1 != genVertex1->particles_in_const_end(); ++genParticle1 ) {
219  bool isMatched = false;
220  for ( HepMC::GenVertex::particles_in_const_iterator genParticle2 = genVertex2->particles_in_const_begin();
221  genParticle2 != genVertex2->particles_in_const_end() && !isMatched; ++genParticle2 ) {
222  isMatched |= matchesGenParticle(*genParticle1, *genParticle2);
223  }
224  if ( !isMatched ) return false;
225  }
226  }
227 
228  // require that "outgoing" particles match
229  if ( checkOutgoingParticles ) {
230  for ( HepMC::GenVertex::particles_out_const_iterator genParticle1 = genVertex1->particles_out_const_begin();
231  genParticle1 != genVertex1->particles_out_const_end(); ++genParticle1 ) {
232  bool isMatched = false;
233  for ( HepMC::GenVertex::particles_out_const_iterator genParticle2 = genVertex2->particles_out_const_begin();
234  genParticle2 != genVertex2->particles_out_const_end() && !isMatched; ++genParticle2 ) {
235  isMatched |= matchesGenParticle(*genParticle1, *genParticle2);
236  }
237  if ( !isMatched ) return false;
238  }
239  }
240 
241  return true;
242  }
243 }
244 
245 std::auto_ptr<HepMC::GenEvent> ParticleReplacerZtautau::produce(const std::vector<reco::Particle>& muons, const reco::Vertex* evtVtx, const HepMC::GenEvent* genEvt, MCParticleReplacer* producer)
246 {
247  if ( evtVtx != 0 ) throw cms::Exception("Configuration")
248  << "ParticleReplacerZtautau does NOT support using primary vertex as the origin for taus !!\n";
249 
250  std::auto_ptr<ParticleCollection> muonsBeforeRad(new ParticleCollection());
251  std::auto_ptr<ParticleCollection> muonsAfterRad(new ParticleCollection());
252 
253 //--- transform the muons to the desired gen. particles
254  std::vector<reco::Particle> embedParticles;
255  if ( transformationMode_ <= 2 ) { // mumu -> ll (Z -> Z boson, l = { e, mu, tau })
256 
257  if ( muons.size() != 2 ) {
258  edm::LogError ("Replacer")
259  << "The decay mode Z->ll requires exactly two muons --> returning empty HepMC event !!" << std::endl;
260  return std::auto_ptr<HepMC::GenEvent>(0);
261  }
262 
263  switch ( transformationMode_ ) {
264  case 0: // mumu -> mumu
267  break;
268  case 1: // mumu -> tautau
271  break;
272  case 2: // mumu -> ee
275  break;
276  default:
277  assert(0);
278  }
281 
282  const reco::Particle& muon1 = muons.at(0);
283  const reco::Particle& muon2 = muons.at(1);
284  reco::Particle embedLepton1(muon1.charge(), muon1.p4(), muon1.vertex(), muon1.pdgId(), 0, true);
285  reco::Particle embedLepton2(muon2.charge(), muon2.p4(), muon2.vertex(), muon2.pdgId(), 0, true);
286  if ( targetParticle1AbsPdgID_ != 13 ) {
287  transformMuMu2LepLep(&embedLepton1, &embedLepton2);
288  }
289  embedParticles.push_back(embedLepton1);
290  embedParticles.push_back(embedLepton2);
291  } else if ( transformationMode_ == 3 ) { // mumu -> taunu (Z -> W boson)
292 
293  if ( muons.size() != 2 ) {
294  edm::LogError ("Replacer")
295  << "The decay mode W->taunu requires exactly two muons --> returning empty HepMC event !!" << std::endl;
296  return std::auto_ptr<HepMC::GenEvent>(0);
297  }
298 
303 
304  const reco::Particle& muon1 = muons.at(0);
305  const reco::Particle& muon2 = muons.at(1);
306  reco::Particle embedTau(muon1.charge(), muon1.p4(), muon1.vertex(), muon1.pdgId(), 0, true);
307  reco::Particle embedNu(muon2.charge(), muon2.p4(), muon2.vertex(), muon2.pdgId(), 0, true);
308  transformMuMu2TauNu(&embedTau, &embedNu);
309  embedParticles.push_back(embedTau);
310  embedParticles.push_back(embedNu);
311  } else if ( transformationMode_ == 4 ) { // munu -> taunu (W -> W boson)
312 
313  if ( muons.size() != 2 ) {
314  edm::LogError ("Replacer")
315  << "The decay mode W->taunu requires exactly two gen. leptons --> returning empty HepMC event !!" << std::endl;
316  return std::auto_ptr<HepMC::GenEvent>(0);
317  }
318 
323 
324  const reco::Particle& muon = muons.at(0);
325  double embedLeptonEn = sqrt(square(muon.px()) + square(muon.py()) + square(muon.pz()) + square(targetParticle1Mass_));
326  reco::Candidate::LorentzVector embedTauP4(muon.px(), muon.py(), muon.pz(), embedLeptonEn);
327  reco::Particle embedTau(muon.charge(), embedTauP4, muon.vertex(), targetParticle1AbsPdgID_*muon.pdgId()/std::abs(muon.pdgId()), 0, true);
328  embedTau.setStatus(1);
329  embedParticles.push_back(embedTau);
330  const reco::Particle& nu = muons.at(1);
331  reco::Particle embedNu(0, nu.p4(), nu.vertex(), -targetParticle2AbsPdgID_*muon.pdgId()/std::abs(muon.pdgId()), 0, true);
332  embedNu.setStatus(1);
333  embedParticles.push_back(embedNu);
334  }
335 
336  if ( embedParticles.size() != 2 ){
337  edm::LogError ("Replacer")
338  << "The creation of gen. particles failed somehow --> returning empty HepMC event !!" << std::endl;
339  return std::auto_ptr<HepMC::GenEvent>(0);
340  }
341 
342  HepMC::GenEvent* genEvt_output = 0;
343 
344  HepMC::GenVertex* genVtx_output = new HepMC::GenVertex();
345 
346  HepMC::GenVertex* ppCollisionVtx = 0;
347 
348  std::vector<reco::Candidate::LorentzVector> auxPhotonP4s;
349 
350 //--- prepare the output HepMC event
351  if ( genEvt ) { // embed gen. leptons into existing HepMC event
352  genEvt_output = new HepMC::GenEvent(*genEvt);
353 
354  for ( HepMC::GenEvent::vertex_iterator genVtx = genEvt_output->vertices_begin();
355  genVtx != genEvt_output->vertices_end(); ++genVtx ) {
356 
357  if ( (*genVtx)->particles_out_size() <= 0 || (*genVtx)->particles_in_size() <= 0 ) continue;
358 
359  bool foundMuon1 = false;
360  bool foundMuon2 = false;
361  bool foundZ = false;
362  for ( HepMC::GenVertex::particles_out_const_iterator genParticle = (*genVtx)->particles_out_const_begin();
363  genParticle != (*genVtx)->particles_out_const_end(); ++genParticle ) {
364  if ( (*genParticle)->pdg_id() == 13 ) foundMuon1 = true;
365  if ( (*genParticle)->pdg_id() == -13 ) foundMuon2 = true;
366  if ( (*genParticle)->pdg_id() == 23 ) foundZ = true;
367  }
368 
369  int motherPdgId = (*(*genVtx)->particles_in_const_begin())->pdg_id();
370 
371  if ( ((*genVtx)->particles_out_size() == 2 &&
372  (*genVtx)->particles_in_size() > 0 &&
373  motherPdgId == 23 &&
374  foundMuon1 &&
375  foundMuon2 ) ||
376  ((*genVtx)->particles_out_size() > 2 &&
377  (*genVtx)->particles_in_size() > 0 &&
378  motherPdgId == 23 &&
379  foundMuon1 &&
380  foundMuon2 &&
381  foundZ ) ) {
382  genVtx_output = (*genVtx);
383  }
384  }
385 
386  cleanEvent(genEvt_output, genVtx_output);
387 
388  // prevent a decay of existing particles
389  // (the decay of existing particles is a bug in the PythiaInterface which should be fixed in newer versions) <-- to be CHECKed (*)
390  for ( HepMC::GenEvent::particle_iterator genParticle = genEvt_output->particles_begin();
391  genParticle != genEvt_output->particles_end(); ++genParticle ) {
392  (*genParticle)->set_status(0);
393  }
394 
395  for ( std::vector<reco::Particle>::const_iterator embedParticle = embedParticles.begin();
396  embedParticle != embedParticles.end(); ++embedParticle ) {
398  reco::Candidate::LorentzVector sumOtherParticlesP4(0.,0.,0.,0.);
399  for ( std::vector<reco::Particle>::const_iterator otherParticle = embedParticles.begin();
400  otherParticle != embedParticles.end(); ++otherParticle ) {
401  if ( deltaR(otherParticle->p4(), embedParticle->p4()) > 1.e-3 ) sumOtherParticlesP4 += otherParticle->p4();
402  }
403  int errorFlag = 0;
404  reco::Candidate::LorentzVector muonFSR = muonRadiationAlgo_->compFSR(embedParticle->p4(), embedParticle->charge(), sumOtherParticlesP4, errorFlag);
405  double embedParticlePx_corrected = embedParticle->px() + muonFSR.px();
406  double embedParticlePy_corrected = embedParticle->py() + muonFSR.py();
407  double embedParticlePz_corrected = embedParticle->pz() + muonFSR.pz();
408  double embedParticleEn_corrected = sqrt(square(embedParticlePx_corrected) + square(embedParticlePy_corrected) + square(embedParticlePz_corrected) + square(embedParticle->mass()));
409  reco::Candidate::LorentzVector embedParticleP4_corrected(embedParticlePx_corrected, embedParticlePy_corrected, embedParticlePz_corrected, embedParticleEn_corrected);
410  genVtx_output->add_particle_out(new HepMC::GenParticle((HepMC::FourVector)embedParticleP4_corrected, embedParticle->pdgId(), 1, HepMC::Flow(), HepMC::Polarization(0,0)));
411  // CV: add photon of energy matching muon FSR correction
412  // in opposite eta, phi direction to preserve transverse momentum balance
413  auxPhotonP4s.push_back(reco::Candidate::LorentzVector(-muonFSR.px(), -muonFSR.py(), -muonFSR.pz(), sqrt(square(muonFSR.px()) + square(muonFSR.py()) + square(muonFSR.pz()))));
414  // CV: assume pp collision vertex to be simply the first vertex;
415  // should not really matter as long as pointer is not null...
416  ppCollisionVtx = (*genEvt_output->vertices_begin());
417  assert(ppCollisionVtx);
418 
419  muonsBeforeRad->push_back(reco::Particle(embedParticle->charge(), embedParticle->p4(), embedParticle->vertex(), embedParticle->pdgId()));
420  muonsAfterRad->push_back(reco::Particle(embedParticle->charge(), embedParticleP4_corrected, embedParticle->vertex(), embedParticle->pdgId()));
421  } else {
422  genVtx_output->add_particle_out(new HepMC::GenParticle((HepMC::FourVector)embedParticle->p4(), embedParticle->pdgId(), 1, HepMC::Flow(), HepMC::Polarization(0,0)));
423  }
424  }
425  } else { // embed gen. leptons into new (empty) HepMC event
426  reco::Particle::LorentzVector genMotherP4;
427  double ppCollisionPosX = 0.;
428  double ppCollisionPosY = 0.;
429  double ppCollisionPosZ = 0.;
430  int idx = 0;
431  for ( std::vector<reco::Particle>::const_iterator embedParticle = embedParticles.begin();
432  embedParticle != embedParticles.end(); ++embedParticle ) {
433  //std::cout << "embedParticle #" << idx << ": Pt = " << embedParticle->pt() << ","
434  // << " eta = " << embedParticle->eta() << ", phi = " << embedParticle->phi() << ", mass = " << embedParticle->mass() << std::endl;
435  //std::cout << "(production vertex: x = " << embedParticle->vertex().x() << ", y = " << embedParticle->vertex().y() << ", z = " << embedParticle->vertex().z() << ")" << std::endl;
436  genMotherP4 += embedParticle->p4();
437  const reco::Particle::Point& embedParticleVertex = embedParticle->vertex();
438  ppCollisionPosX += embedParticleVertex.x();
439  ppCollisionPosY += embedParticleVertex.y();
440  ppCollisionPosZ += embedParticleVertex.z();
441  ++idx;
442  }
443 
444  int numEmbedParticles = embedParticles.size();
445  if ( numEmbedParticles > 0 ) {
446  ppCollisionPosX /= numEmbedParticles;
447  ppCollisionPosY /= numEmbedParticles;
448  ppCollisionPosZ /= numEmbedParticles;
449  }
450 
451  ppCollisionVtx = new HepMC::GenVertex(HepMC::FourVector(ppCollisionPosX*10., ppCollisionPosY*10., ppCollisionPosZ*10., 0.)); // convert from cm to mm
452  double protonEn = beamEnergy_;
453  double protonPz = sqrt(square(protonEn) - square(protonMass));
454  ppCollisionVtx->add_particle_in(new HepMC::GenParticle(HepMC::FourVector(0., 0., +protonPz, protonEn), 2212, 3));
455  ppCollisionVtx->add_particle_in(new HepMC::GenParticle(HepMC::FourVector(0., 0., -protonPz, protonEn), 2212, 3));
456 
457  HepMC::GenVertex* genMotherDecayVtx = new HepMC::GenVertex(HepMC::FourVector(ppCollisionPosX*10., ppCollisionPosY*10., ppCollisionPosZ*10., 0.)); // Z decays immediately
458  HepMC::GenParticle* genMother = new HepMC::GenParticle((HepMC::FourVector)genMotherP4, motherParticleID_, (generatorMode_ == "Pythia" ? 3 : 2), HepMC::Flow(), HepMC::Polarization(0,0));
459  if ( transformationMode_ == 3 ) {
460  int chargedLepPdgId = embedParticles.begin()->pdgId(); // first daughter particle is charged lepton always
461  int motherPdgId = -24*chargedLepPdgId/std::abs(chargedLepPdgId);
462  genMother->set_pdg_id(motherPdgId);
463  }
464 
465  ppCollisionVtx->add_particle_out(genMother);
466 
467  genMotherDecayVtx->add_particle_in(genMother);
468  for ( std::vector<reco::Particle>::const_iterator embedParticle = embedParticles.begin();
469  embedParticle != embedParticles.end(); ++embedParticle ) {
471  reco::Candidate::LorentzVector sumOtherParticlesP4(0.,0.,0.,0.);
472  for ( std::vector<reco::Particle>::const_iterator otherParticle = embedParticles.begin();
473  otherParticle != embedParticles.end(); ++otherParticle ) {
474  if ( deltaR(otherParticle->p4(), embedParticle->p4()) > 1.e-3 ) sumOtherParticlesP4 += otherParticle->p4();
475  }
476  //std::cout << "embedParticle:"
477  // << " En = " << embedParticle->energy() << ","
478  // << " Px = " << embedParticle->px() << ","
479  // << " Py = " << embedParticle->py() << ","
480  // << " Pz = " << embedParticle->pz() << std::endl;
481  int errorFlag = 0;
482  reco::Candidate::LorentzVector muonFSR = muonRadiationAlgo_->compFSR(embedParticle->p4(), embedParticle->charge(), sumOtherParticlesP4, errorFlag);
483  //std::cout << "muonFSR:"
484  // << " En = " << muonFSR.E() << ","
485  // << " Px = " << muonFSR.px() << ","
486  // << " Py = " << muonFSR.py() << ","
487  // << " Pz = " << muonFSR.pz() << std::endl;
488  double embedParticlePx_corrected = embedParticle->px() + muonFSR.px();
489  double embedParticlePy_corrected = embedParticle->py() + muonFSR.py();
490  double embedParticlePz_corrected = embedParticle->pz() + muonFSR.pz();
491  double embedParticleEn_corrected = sqrt(square(embedParticlePx_corrected) + square(embedParticlePy_corrected) + square(embedParticlePz_corrected) + square(embedParticle->mass()));
492  reco::Candidate::LorentzVector embedParticleP4_corrected(embedParticlePx_corrected, embedParticlePy_corrected, embedParticlePz_corrected, embedParticleEn_corrected);
493  //std::cout << "embedParticle (corrected):"
494  // << " En = " << embedParticleP4_corrected.E() << ","
495  // << " Px = " << embedParticleP4_corrected.px() << ","
496  // << " Py = " << embedParticleP4_corrected.py() << ","
497  // << " Pz = " << embedParticleP4_corrected.pz() << std::endl;
498  genMotherDecayVtx->add_particle_out(new HepMC::GenParticle((HepMC::FourVector)embedParticleP4_corrected, embedParticle->pdgId(), 1, HepMC::Flow(), HepMC::Polarization(0,0)));
499  // CV: add photon of energy matching muon FSR correction
500  // in opposite eta, phi direction to preserve transverse momentum balance
501  auxPhotonP4s.push_back(reco::Candidate::LorentzVector(-muonFSR.px(), -muonFSR.py(), -muonFSR.pz(), sqrt(square(muonFSR.px()) + square(muonFSR.py()) + square(muonFSR.pz()))));
502 
503  muonsBeforeRad->push_back(reco::Particle(embedParticle->charge(), embedParticleP4_corrected, embedParticle->vertex(), embedParticle->pdgId()));
504  muonsAfterRad->push_back(reco::Particle(embedParticle->charge(), embedParticle->p4(), embedParticle->vertex(), embedParticle->pdgId()));
505  } else {
506  genMotherDecayVtx->add_particle_out(new HepMC::GenParticle((HepMC::FourVector)embedParticle->p4(), embedParticle->pdgId(), 1, HepMC::Flow(), HepMC::Polarization(0,0)));
507  }
508  }
509 
510  genEvt_output = new HepMC::GenEvent();
511  genEvt_output->add_vertex(ppCollisionVtx);
512  genEvt_output->add_vertex(genMotherDecayVtx);
513 
514  repairBarcodes(genEvt_output);
515  }
516 
517 //--- compute probability to pass visible Pt cuts
518  HepMC::GenEvent* passedEvt_output = 0;
519 
520  unsigned int numEvents_tried = 0;
521  unsigned int numEvents_passed = 0;
522 
523  int verbosity_backup = verbosity_;
524 
525  HepMC::IO_HEPEVT conv;
526  for ( int iTrial = 0; iTrial < maxNumberOfAttempts_; ++iTrial ) {
527  HepMC::GenEvent* tempEvt = new HepMC::GenEvent(*genEvt_output);
528  ++numEvents_tried;
529  if ( generatorMode_ == "Pythia" ) { // Pythia
530  throw cms::Exception("Configuration")
531  << "Pythia is currently not supported !!\n";
532  } else if ( generatorMode_ == "Tauola" ) { // TAUOLA
533  conv.write_event(tempEvt);
534  HepMC::GenEvent* decayEvt = tauola_->decay(tempEvt);
535  // This code only works if decay() modifies the event inplace. This seems
536  // to have changed between CMSSW_5_3_X and CMSSW_7_0_0
537  // (possible with the introduction of tauola++?), so make sure this
538  // assumption is correct:
539  assert(decayEvt == tempEvt);
540  }
541 
542  bool passesVisPtCuts = testEvent(tempEvt);
543  if ( passesVisPtCuts ) {
544  if ( !passedEvt_output ) passedEvt_output = tempEvt; // store first HepMC event passing visible Pt cuts in output file
545  else delete tempEvt;
546  ++numEvents_passed;
547  verbosity_ = 0;
548  } else {
549  delete tempEvt;
550  }
551  }
552 
553  tried_ = numEvents_tried;
554  passed_ = numEvents_passed;
555  verbosity_ = verbosity_backup;
556 
557  if ( !passedEvt_output ) {
558  edm::LogError ("Replacer")
559  << "Failed to create an event which satisfies the visible Pt cuts !!" << std::endl;
560  int idx = 0;
561  for ( std::vector<reco::Particle>::const_iterator muon = muons.begin();
562  muon != muons.end(); ++muon ) {
563  std::cout << " muon #" << idx << " (charge = " << muon->charge() << "): Pt = " << muon->pt() << ", eta = " << muon->eta() << ", phi = " << muon->phi() << std::endl;
564  ++idx;
565  }
566  return std::auto_ptr<HepMC::GenEvent>(0);
567  }
568 
569  // use PYTHIA to decay unstable hadrons (e.g. pi0 -> gamma gamma)
570  //std::cout << "before pi0 -> gamma gamma decays:" << std::endl;
571  //passedEvt_output->print(std::cout);
572 
573  conv.write_event(passedEvt_output);
574 
575  gen::Pythia6Service::InstanceWrapper pythia6InstanceGuard(&pythia_);
576 
577  // convert hepevt -> pythia
578  call_pyhepc(2);
579 
580  // call PYTHIA
581  call_pyexec();
582 
583  // convert pythia -> hepevt
584  call_pyhepc(1);
585 
586  HepMC::GenEvent* passedEvt_pythia = conv.read_next_event();
587  //std::cout << "PYTHIA output:" << std::endl;
588  //passedEvt_pythia->print(std::cout);
589 
590  // CV: back and forth conversion between HepMC and PYTHIA causes
591  // pp -> Z vertex to get corrupted for some reason;
592  // do **not** take HepMC::GenEvent from PYTHIA,
593  // but add decays of unstable particles to original HepMC::GenEvent
594  for ( HepMC::GenEvent::vertex_const_iterator genVertex_pythia = passedEvt_pythia->vertices_begin();
595  genVertex_pythia != passedEvt_pythia->vertices_end(); ++genVertex_pythia ) {
596  bool isDecayVertex = ((*genVertex_pythia)->particles_in_size() >= 1 && (*genVertex_pythia)->particles_out_size() >= 2);
597  for ( HepMC::GenEvent::vertex_const_iterator genVertex_output = passedEvt_output->vertices_begin();
598  genVertex_output != passedEvt_output->vertices_end(); ++genVertex_output ) {
599  if ( matchesGenVertex(*genVertex_output, *genVertex_pythia, true, false) ) isDecayVertex = false;
600  }
601  if ( !isDecayVertex ) continue;
602 
603  // create new vertex
604  //std::cout << "creating decay vertex: barcode = " << (*genVertex_pythia)->barcode() << std::endl;
605  HepMC::GenVertex* genVertex_output = new HepMC::GenVertex((*genVertex_pythia)->position());
606 
607  // associate "incoming" particles to new vertex
608  for ( HepMC::GenVertex::particles_in_const_iterator genParticle_pythia = (*genVertex_pythia)->particles_in_const_begin();
609  genParticle_pythia != (*genVertex_pythia)->particles_in_const_end(); ++genParticle_pythia ) {
610  for ( HepMC::GenEvent::particle_iterator genParticle_output = passedEvt_output->particles_begin();
611  genParticle_output != passedEvt_output->particles_end(); ++genParticle_output ) {
612  if ( matchesGenParticle(*genParticle_output, *genParticle_pythia) ) {
613  //std::cout << " adding 'incoming' particle: barcode = " << (*genParticle_output)->barcode() << std::endl;
614  genVertex_output->add_particle_in(*genParticle_output);
615  // flag "incoming" particle to be unstable
616  (*genParticle_output)->set_status(2);
617  }
618  }
619  }
620 
621  // create "outgoing" particles and associate them to new vertex
622  for ( HepMC::GenVertex::particles_out_const_iterator genParticle_pythia = (*genVertex_pythia)->particles_out_const_begin();
623  genParticle_pythia != (*genVertex_pythia)->particles_out_const_end(); ++genParticle_pythia ) {
624  HepMC::GenParticle* genParticle_output = new HepMC::GenParticle(
625  (*genParticle_pythia)->momentum(),
626  (*genParticle_pythia)->pdg_id(),
627  (*genParticle_pythia)->status(),
628  (*genParticle_pythia)->flow(),
629  (*genParticle_pythia)->polarization());
630  genParticle_output->suggest_barcode((*genParticle_pythia)->barcode());
631  //std::cout << " adding 'outgoing' particle: barcode = " << genParticle_output->barcode() << std::endl;
632  genVertex_output->add_particle_out(genParticle_output);
633  }
634 
635  //std::cout << "adding decay vertex: barcode = " << genVertex_output->barcode() << std::endl;
636  passedEvt_output->add_vertex(genVertex_output);
637 
638  // CV: add auxiliary photons correcting transverse momentum balance
639  // in case corrections for muon --> muon + gamma radiation are applied
640  // after TAUOLA has run, in order not to confuse TAUOLA (polarization)
642  for ( std::vector<reco::Candidate::LorentzVector>::const_iterator auxPhotonP4 = auxPhotonP4s.begin();
643  auxPhotonP4 != auxPhotonP4s.end(); ++auxPhotonP4 ) {
644  ppCollisionVtx->add_particle_out(new HepMC::GenParticle((HepMC::FourVector)*auxPhotonP4, 22, 1, HepMC::Flow(), HepMC::Polarization(0,0)));
645  }
646  }
647  }
648  delete passedEvt_pythia;
649 
650  //std::cout << "after pi0 -> gamma gamma decays:" << std::endl;
651  //passedEvt_output->print(std::cout);
652 
653  // undo the "hack" (*):
654  // recover the particle status codes
655  if ( genEvt ) {
656  for ( HepMC::GenEvent::particle_iterator genParticle = passedEvt_output->particles_begin();
657  genParticle != passedEvt_output->particles_end(); ++genParticle ) {
658  if ( (*genParticle)->end_vertex() ) (*genParticle)->set_status(2);
659  else (*genParticle)->set_status(1);
660  }
661  }
662 
663  // check that transverse momentum of embedded Z -> tautau matches
664  // transverse momentum of replaced di-muon system
665  reco::Candidate::LorentzVector sumMuonP4_replaced(0.,0.,0.,0.);
666  for ( std::vector<reco::Particle>::const_iterator muon = muons.begin();
667  muon != muons.end(); ++muon ) {
668  sumMuonP4_replaced += muon->p4();
669  }
670  reco::Candidate::LorentzVector sumMuonP4_embedded(0.,0.,0.,0.);
671  if ( genEvt ) {
672  for ( HepMC::GenEvent::particle_iterator genParticle = passedEvt_output->particles_begin();
673  genParticle != passedEvt_output->particles_end(); ++genParticle ) {
674  if ( (*genParticle)->status() != 1 ) continue;
675  if ( abs((*genParticle)->pdg_id()) == 12 || abs((*genParticle)->pdg_id()) == 14 || abs((*genParticle)->pdg_id()) == 16 ) continue;
676  sumMuonP4_embedded += reco::Candidate::LorentzVector((*genParticle)->momentum().px(), (*genParticle)->momentum().py(), (*genParticle)->momentum().pz(), (*genParticle)->momentum().e());
677  }
678  }
679  if ( (sumMuonP4_embedded.pt() - sumMuonP4_replaced.pt()) > (1.e-3*sumMuonP4_replaced.pt()) ) {
680  edm::LogWarning ("<MCEmbeddingValidationAnalyzer::analyze>")
681  << "Transverse momentum of embedded tau leptons = " << sumMuonP4_embedded.pt()
682  << " differs from transverse momentum of replaced muons = " << sumMuonP4_replaced.pt() << " !!" << std::endl;
683  }
684 
685  std::auto_ptr<HepMC::GenEvent> passedEvt_output_ptr(passedEvt_output);
686  if ( verbosity_ ) {
687  passedEvt_output_ptr->print(std::cout);
688  std::cout << " numEvents: tried = " << numEvents_tried << ", passed = " << numEvents_passed << std::endl;
689  }
690 
691  delete genVtx_output;
692  delete genEvt_output;
693 
694  producer->call_put(muonsBeforeRad, "muonsBeforeRad");
695  producer->call_put(muonsAfterRad, "muonsAfterRad");
696 
697  return passedEvt_output_ptr;
698 }
699 
701 {
702  if ( !tauola_isInitialized_ ) {
703  std::cout << "<ParticleReplacerZtautau::beginRun>: Initializing TAUOLA interface." << std::endl;
704  tauola_->init(es);
705  tauola_isInitialized_ = true;
706  }
707 }
708 
710 {
711  tauola_->statistics();
712 }
713 
715 {
716  //if ( verbosity_ ) std::cout << "<ParticleReplacerZtautau::testEvent>:" << std::endl;
717 
718  if ( minVisPtCuts_.empty() ) return true; // no visible Pt cuts applied
719 
720  std::vector<double> muonPts;
721  std::vector<double> electronPts;
722  std::vector<double> tauJetPts;
723  std::vector<double> tauPts;
724 
725  int genParticleIdx = 0;
726  for ( HepMC::GenEvent::particle_iterator genParticle = genEvt->particles_begin();
727  genParticle != genEvt->particles_end(); ++genParticle ) {
728  if ( abs((*genParticle)->pdg_id()) == 15 && (*genParticle)->end_vertex() ) {
730  std::queue<const HepMC::GenParticle*> decayProducts;
731  decayProducts.push(*genParticle);
732  enum { kELEC, kMU, kHAD };
733  int type = kHAD;
734  int decayProductIdx = 0;
735  while ( !decayProducts.empty() && decayProductIdx < 100 ) { // CV: protection against entering infinite loop in case of corrupt particle relations
736  const HepMC::GenParticle* decayProduct = decayProducts.front();
737  if ( verbosity_ ) {
738  std::cout << "decayProduct #" << (decayProductIdx + 1) << " (pdgId = " << decayProduct->pdg_id() << "):"
739  << " Pt = " << decayProduct->momentum().perp() << ", eta = " << decayProduct->momentum().eta() << ", phi = " << decayProduct->momentum().phi()
740  << std::endl;
741  }
742  decayProducts.pop();
743  if ( !decayProduct->end_vertex() ) { // stable decay product
744  int absPdgId = abs(decayProduct->pdg_id());
745  if ( !(absPdgId == 12 || absPdgId == 14 || absPdgId == 16) ) visP4 += (reco::Candidate::LorentzVector)decayProduct->momentum();
746  if ( absPdgId == 11 ) type = kELEC;
747  if ( absPdgId == 13 ) type = kMU;
748  } else { // decay product decays further...
749  HepMC::GenVertex* decayVtx = decayProduct->end_vertex();
750  for ( HepMC::GenVertex::particles_out_const_iterator daughter = decayVtx->particles_out_const_begin();
751  daughter != decayVtx->particles_out_const_end(); ++daughter ) {
752  decayProducts.push(*daughter);
753  }
754  }
755  ++decayProductIdx;
756  }
757 
758  double visPt = visP4.pt();
759  tauPts.push_back(visPt);
760  if ( type == kMU ) muonPts.push_back(visPt);
761  else if ( type == kELEC ) electronPts.push_back(visPt);
762  else if ( type == kHAD ) tauJetPts.push_back(visPt);
763  if ( verbosity_ ) {
764  std::string type_string = "";
765  if ( type == kMU ) type_string = "mu";
766  else if ( type == kELEC ) type_string = "elec";
767  else if ( type == kHAD ) type_string = "had";
768  std::cout << "visLeg #" << (genParticleIdx + 1) << " (type = " << type_string << "):"
769  << " Pt = " << visP4.pt() << ", eta = " << visP4.eta() << ", phi = " << visP4.phi()
770  << " (X = " << (visP4.energy()/(*genParticle)->momentum().e()) << ")" << std::endl;
771  }
772  ++genParticleIdx;
773  }
774  }
775 
776  std::sort(tauPts.begin(), tauPts.end(), std::greater<double>());
777  std::sort(electronPts.begin(), electronPts.end(), std::greater<double>());
778  std::sort(muonPts.begin(), muonPts.end(), std::greater<double>());
779  std::sort(tauJetPts.begin(), tauJetPts.end(), std::greater<double>());
780 
781  // check if visible decay products pass Pt cuts
782  //
783  // NOTE: return value = True if leg1 > threshold[i] && leg2 > threshold[i] for **any** path i
784  // (e.g. (leg1Pt > 10 && leg2Pt > 20) || (leg1Pt > 20 && leg2Pt > 10), consistent with logic used by HLT)
785  //
786  for ( std::vector<MinVisPtCutCombination>::const_iterator minVisPtCut = minVisPtCuts_.begin();
787  minVisPtCut != minVisPtCuts_.end(); ++minVisPtCut ) {
788  //if ( verbosity_ ) minVisPtCut->print(std::cout);
789 
790  bool passesMinVisCut = true;
791 
792  for ( std::vector<MinVisPtCut>::const_iterator cut = minVisPtCut->cuts_.begin();
793  cut != minVisPtCut->cuts_.end(); ++cut ) {
794  std::vector<double>* collection = 0;
795  switch ( cut->type_ ) {
796  case MinVisPtCut::kELEC:
797  collection = &electronPts;
798  break;
799  case MinVisPtCut::kMU:
800  collection = &muonPts;
801  break;
802  case MinVisPtCut::kHAD:
803  collection = &tauJetPts;
804  break;
805  case MinVisPtCut::kTAU:
806  collection = &tauPts;
807  break;
808  }
809  assert(collection);
810 
811  // j-th tau decay product fails visible Pt cut
812  if ( cut->index_ >= collection->size() || (*collection)[cut->index_] < cut->threshold_ ) {
813  passesMinVisCut = false;
814  break;
815  }
816  }
817 
818  // all tau decay products satisfy visible Pt cuts for i-th path
819  //if ( verbosity_ ) std::cout << "passes vis. Pt cuts = " << passesMinVisCut << std::endl;
820  if ( passesMinVisCut ) return true;
821  }
822 
823  // visible Pt cuts failed for all paths
824  return false;
825 }
826 
827 void ParticleReplacerZtautau::cleanEvent(HepMC::GenEvent* genEvt, HepMC::GenVertex* genVtx)
828 {
829  std::stack<HepMC::GenParticle*> genParticles_to_delete;
830 
831  std::stack<HepMC::GenVertex*> genVertices_to_process;
832  std::stack<HepMC::GenVertex*> genVertices_to_delete;
833 
834  for ( HepMC::GenVertex::particles_out_const_iterator genParticle = genVtx->particles_out_const_begin();
835  genParticle != genVtx->particles_out_const_end(); ++genParticle ) {
836  genParticles_to_delete.push(*genParticle);
837  if ( (*genParticle)->end_vertex() ) genVertices_to_process.push((*genParticle)->end_vertex());
838  }
839 
840  while ( !genVertices_to_process.empty() ) {
841  HepMC::GenVertex* tempVtx = genVertices_to_process.top();
842  if ( tempVtx->particles_out_size() > 0 ) {
843  for ( HepMC::GenVertex::particles_out_const_iterator genParticle = tempVtx->particles_out_const_begin();
844  genParticle != tempVtx->particles_out_const_end(); ++genParticle ) {
845  if ( (*genParticle)->end_vertex() ) genVertices_to_process.push((*genParticle)->end_vertex());
846  }
847  delete tempVtx;
848  }
849  genVertices_to_delete.push(tempVtx);
850  genVertices_to_process.pop();
851  }
852 
853  while ( !genVertices_to_delete.empty() ) {
854  genEvt->remove_vertex(genVertices_to_delete.top());
855  genVertices_to_delete.pop();
856  }
857 
858  while ( !genParticles_to_delete.empty() ) {
859  delete genVtx->remove_particle(genParticles_to_delete.top());
860  genParticles_to_delete.pop();
861  }
862 
863  repairBarcodes(genEvt);
864 }
865 
866 namespace
867 {
869  {
870  TVector3 p3(p4.px(), p4.py(), p4.pz());
871  p3.Rotate(angle, TVector3(axis.x(), axis.y(), axis.z()).Unit());
872  reco::Particle::LorentzVector p4_rotated(p3.Px(), p3.Py(), p3.Pz(), p4.energy());
873  assert(TMath::Abs(p3.Mag() - p4.P()) < (1.e-3*p4.P()));
874  return p4_rotated;
875  }
876 
877  void print(const std::string& label, const reco::Particle::LorentzVector& p4, const reco::Particle::LorentzVector* p4_ref = 0)
878  {
879  std::cout << label << ": En = " << p4.E() << ", Pt = " << p4.pt() << " (Px = " << p4.px() << ", Py = " << p4.py() << "),"
880  << " theta = " << p4.theta() << " (eta = " << p4.eta() << "), phi = " << p4.phi() << ", mass = " << p4.mass();
881  if ( p4_ref ) {
882  double angle = TMath::ACos((p4.px()*p4_ref->px() + p4.py()*p4_ref->py() + p4.pz()*p4_ref->pz())/(p4.P()*p4_ref->P()));
883  std::cout << " (angle wrt. ref = " << angle << ")";
884  }
885  std::cout << std::endl;
886  }
887 }
888 
890 {
891 //--- transform a muon pair into an electron/tau pair,
892 // taking into account the difference between muon and electron/tau mass
893 
894  reco::Particle::LorentzVector muon1P4_lab = muon1->p4();
895  reco::Particle::LorentzVector muon2P4_lab = muon2->p4();
896  reco::Particle::LorentzVector zP4_lab = muon1P4_lab + muon2P4_lab;
897 
898  ROOT::Math::Boost boost_to_rf(zP4_lab.BoostToCM());
899  ROOT::Math::Boost boost_to_lab(boost_to_rf.Inverse());
900 
901  reco::Particle::LorentzVector zP4_rf = boost_to_rf(zP4_lab);
902 
903  reco::Particle::LorentzVector muon1P4_rf = boost_to_rf(muon1P4_lab);
904  reco::Particle::LorentzVector muon2P4_rf = boost_to_rf(muon2P4_lab);
905 
906  if ( verbosity_ ) {
907  std::cout << "before rotation:" << std::endl;
908  print("muon1(lab)", muon1P4_lab, &zP4_lab);
909  print("muon2(lab)", muon2P4_lab, &zP4_lab);
910  print("Z(lab)", zP4_lab);
911  print("muon1(rf)", muon1P4_rf, &zP4_lab);
912  print("muon2(rf)", muon2P4_rf, &zP4_lab);
913  print("Z(rf)", zP4_rf);
914  }
915 
916  if ( rfRotationAngle_ != 0. ) {
917  double rfRotationAngle_value = rfRotationAngle_;
918  if ( rfRotationAngle_ == -1. ) {
919  double u = decayRandomEngine->flat();
920  rfRotationAngle_value = 2.*TMath::Pi()*u;
921  }
922 
923  muon1P4_rf = rotate(muon1P4_rf, zP4_lab, rfRotationAngle_value);
924  muon2P4_rf = rotate(muon2P4_rf, zP4_lab, rfRotationAngle_value);
925  }
926 
927  double muon1P_rf2 = square(muon1P4_rf.px()) + square(muon1P4_rf.py()) + square(muon1P4_rf.pz());
928  double lep1Mass2 = square(targetParticle1Mass_);
929  double lep1En_rf = 0.5*zP4_rf.E();
930  double lep1P_rf2 = square(lep1En_rf) - lep1Mass2;
931  if ( lep1P_rf2 < 0. ) lep1P_rf2 = 0.;
932  float scaleFactor1 = sqrt(lep1P_rf2/muon1P_rf2);
934  scaleFactor1*muon1P4_rf.px(), scaleFactor1*muon1P4_rf.py(), scaleFactor1*muon1P4_rf.pz(), lep1En_rf);
935 
936  double muon2P_rf2 = square(muon2P4_rf.px()) + square(muon2P4_rf.py()) + square(muon2P4_rf.pz());
937  double lep2Mass2 = square(targetParticle2Mass_);
938  double lep2En_rf = 0.5*zP4_rf.E();
939  double lep2P_rf2 = square(lep2En_rf) - lep2Mass2;
940  if ( lep2P_rf2 < 0. ) lep2P_rf2 = 0.;
941  float scaleFactor2 = sqrt(lep2P_rf2/muon2P_rf2);
943  scaleFactor2*muon2P4_rf.px(), scaleFactor2*muon2P4_rf.py(), scaleFactor2*muon2P4_rf.pz(), lep2En_rf);
944 
945  reco::Particle::LorentzVector lep1P4_lab = boost_to_lab(lep1P4_rf);
946  reco::Particle::LorentzVector lep2P4_lab = boost_to_lab(lep2P4_rf);
947 
948  if ( verbosity_ ) {
949  std::cout << "after rotation:" << std::endl;
950  print("lep1(rf)", muon1P4_rf, &zP4_lab);
951  print("lep2(rf)", muon2P4_rf, &zP4_lab);
952  reco::Particle::LorentzVector lep1p2_lab = lep1P4_lab + lep2P4_lab;
953  print("lep1(lab)", lep1P4_lab, &zP4_lab);
954  print("lep2(lab)", lep2P4_lab, &zP4_lab);
955  print("lep1+2(lab)", lep1p2_lab);
956  }
957 
958  // perform additional checks:
959  // the following tests guarantee a deviation of less than 0.1%
960  // for the following values of the original muons and the embedded electrons/taus in terms of:
961  // - invariant mass
962  // - transverse momentum
963  if ( !(fabs(zP4_lab.mass() - (lep1P4_lab + lep2P4_lab).mass()) < (1.e-3*zP4_lab.mass()) &&
964  fabs(zP4_lab.pt() - (lep1P4_lab + lep2P4_lab).pt()) < (1.e-3*zP4_lab.pt())) )
965  edm::LogError ("ParticleReplacerZtautau")
966  << "The kinematics of muons and embedded electrons/taus differ by more than 0.1%:" << std::endl
967  << " mass(muon1 + muon2) = " << zP4_lab.mass() << ", mass(lep1 + lep2) = " << (lep1P4_lab + lep2P4_lab).mass() << std::endl
968  << " Pt(muon1 + muon2) = " << zP4_lab.pt() << ", Pt(lep1 + lep2) = " << (lep1P4_lab + lep2P4_lab).pt() << " --> please CHECK !!" << std::endl;
969 
970  muon1->setP4(lep1P4_lab);
971  muon2->setP4(lep2P4_lab);
972 
973  muon1->setPdgId(targetParticle1AbsPdgID_*muon1->pdgId()/abs(muon1->pdgId()));
974  muon2->setPdgId(targetParticle2AbsPdgID_*muon2->pdgId()/abs(muon2->pdgId()));
975 
976  muon1->setStatus(1);
977  muon2->setStatus(1);
978 
979  return;
980 }
981 
983 {
984 //--- transform a muon pair into tau + nu (replacing a Z by W boson)
985 
986  reco::Particle::LorentzVector muon1P4_lab = muon1->p4();
987  reco::Particle::LorentzVector muon2P4_lab = muon2->p4();
988  reco::Particle::LorentzVector zP4_lab = muon1P4_lab + muon2P4_lab;
989 
990  ROOT::Math::Boost boost_to_rf(zP4_lab.BoostToCM());
991  ROOT::Math::Boost boost_to_lab(boost_to_rf.Inverse());
992 
993  reco::Particle::LorentzVector zP4_rf = boost_to_rf(zP4_lab);
994 
995  double wMass = (zP4_rf.mass() - nomMassZ)*(breitWignerWidthW/breitWignerWidthZ) + nomMassW;
996 
997  reco::Particle::LorentzVector muon1P4_rf = boost_to_rf(muon1P4_lab);
998  reco::Particle::LorentzVector muon2P4_rf = boost_to_rf(muon2P4_lab);
999 
1000  double muon1P_rf2 = square(muon1P4_rf.px()) + square(muon1P4_rf.py()) + square(muon1P4_rf.pz());
1001  double tauMass2 = square(targetParticle1Mass_);
1002  double tauEn_rf = 0.5*zP4_rf.E();
1003  double tauP_rf2 = square(tauEn_rf) - tauMass2;
1004  if ( tauP_rf2 < 0. ) tauP_rf2 = 0.;
1005  float scaleFactor1 = sqrt(tauP_rf2/muon1P_rf2)*(wMass/zP4_rf.mass());
1007  scaleFactor1*muon1P4_rf.px(), scaleFactor1*muon1P4_rf.py(), scaleFactor1*muon1P4_rf.pz(), tauEn_rf);
1008 
1009  double muon2P_rf2 = square(muon2P4_rf.px()) + square(muon2P4_rf.py()) + square(muon2P4_rf.pz());
1010  double nuMass2 = square(targetParticle2Mass_);
1011  assert(nuMass2 < 1.e-4);
1012  double nuEn_rf = 0.5*zP4_rf.E();
1013  double nuP_rf2 = square(nuEn_rf) - nuMass2;
1014  if ( nuP_rf2 < 0. ) nuP_rf2 = 0.;
1015  float scaleFactor2 = sqrt(nuP_rf2/muon2P_rf2)*(wMass/zP4_rf.mass());
1017  scaleFactor2*muon2P4_rf.px(), scaleFactor2*muon2P4_rf.py(), scaleFactor2*muon2P4_rf.pz(), nuEn_rf);
1018 
1019  reco::Particle::LorentzVector tauP4_lab = boost_to_lab(tauP4_rf);
1020  reco::Particle::LorentzVector nuP4_lab = boost_to_lab(nuP4_rf);
1021 
1022  // perform additional checks:
1023  // the following tests guarantee a deviation of less than 0.1%
1024  // for the following values of the original muons and the embedded electrons/taus in terms of:
1025  // - theta
1026  // - phi
1027  if ( !(std::abs(zP4_lab.theta() - (tauP4_lab + nuP4_lab).theta())/zP4_lab.theta() < 1.e-3 &&
1028  std::abs(zP4_lab.phi() - (tauP4_lab + nuP4_lab).phi())/zP4_lab.phi() < 1.e-3) )
1029  edm::LogError ("Replacer")
1030  << "The kinematics of muons and embedded tau/neutrino differ by more than 0.1%:" << std::endl
1031  << " mass(muon1 + muon2) = " << zP4_lab.mass() << ", mass(lep1 + lep2) = " << (tauP4_lab + nuP4_lab).mass() << std::endl
1032  << " Pt(muon1 + muon2) = " << zP4_lab.pt() << ", Pt(lep1 + lep2) = " << (tauP4_lab + nuP4_lab).pt() << " --> please CHECK !!" << std::endl;
1033 
1034  muon1->setP4(tauP4_lab);
1035  muon2->setP4(nuP4_lab);
1036 
1037  muon1->setPdgId(targetParticle1AbsPdgID_*muon1->pdgId()/abs(muon1->pdgId()));
1038  muon2->setPdgId(targetParticle2AbsPdgID_*muon2->pdgId()/abs(muon2->pdgId()));
1039 
1040  muon1->setStatus(1);
1041  muon2->setStatus(1);
1042 
1043  return;
1044 }
1045 
1047 
double px() const
x coordinate of momentum vector
Definition: Particle.cc:140
const double Pi
type
Definition: HCALResponse.h:21
T getParameter(std::string const &) const
virtual void beginRun(edm::Run &, const edm::EventSetup &)
std::vector< MinVisPtCutCombination > minVisPtCuts_
void setP4(const LorentzVector &p4)
set 4-momentum
Definition: Particle.cc:182
HepMC::GenEvent * decay(HepMC::GenEvent *)
static HepMC::IO_HEPEVT conv
virtual std::auto_ptr< HepMC::GenEvent > produce(const std::vector< reco::Particle > &, const reco::Vertex *=0, const HepMC::GenEvent *=0, MCParticleReplacer *=0)
virtual void declareExtraProducts(MCParticleReplacer *)
std::string print(const Track &, edm::Verbosity=edm::Concise)
Track print utility.
Definition: print.cc:8
const double protonMass
Definition: V0Fitter.cc:40
void call_pyexec()
Definition: extraPythia.cc:3
void setPSet(const edm::ParameterSet &)
Geom::Theta< T > theta() const
bool exists(std::string const &parameterName) const
checks if a parameter exists
const LorentzVector & p4() const
four-momentum Lorentz vector
Definition: Particle.cc:86
#define NULL
Definition: scimark2.h:8
const double muonMass
void cleanEvent(HepMC::GenEvent *, HepMC::GenVertex *)
uint16_t size_type
void transformMuMu2TauNu(reco::Particle *, reco::Particle *)
const double tauMass
void call_put(T &product, const std::string &instanceName)
T sqrt(T t)
Definition: SSEVec.h:48
double p4[4]
Definition: TauolaWrapper.h:92
bool testEvent(HepMC::GenEvent *)
void addParameter(std::string const &name, T const &value)
Definition: ParameterSet.h:142
bool isAvailable() const
Definition: Service.h:46
math::XYZPoint Point
point in the space
Definition: Particle.h:31
Abs< T >::type abs(const T &t)
Definition: Abs.h:22
auto deltaR(const T1 &t1, const T2 &t2) -> decltype(t1.eta())
Definition: deltaR.h:30
bool isMatched(TrackingRecHit const &hit)
const double nomMassW
const Point & vertex() const
vertex position
Definition: Particle.cc:226
virtual CLHEP::HepRandomEngine & getEngine() const =0
Use this to get the random number engine, this is the only function most users should call...
void call_produces(const std::string &instanceName)
const double breitWignerWidthW
double deltaR(double eta1, double eta2, double phi1, double phi2)
Definition: TreeUtility.cc:17
ParticleReplacerZtautau(const edm::ParameterSet &)
reco::Candidate::LorentzVector compFSR(const reco::Candidate::LorentzVector &, int, const reco::Candidate::LorentzVector &, int &)
tuple idx
DEBUGGING if hasattr(process,&quot;trackMonIterativeTracking2012&quot;): print &quot;trackMonIterativeTracking2012 D...
double pz() const
z coordinate of momentum vector
Definition: Particle.cc:150
int pdgId() const
PDG identifier.
Definition: Particle.cc:246
const double nomMassZ
def rotate
Definition: svgfig.py:704
const double electronMass
math::XYZTLorentzVector LorentzVector
Lorentz vector.
Definition: Candidate.h:41
void repairBarcodes(HepMC::GenEvent *)
void transformMuMu2LepLep(reco::Particle *, reco::Particle *)
tuple muons
Definition: patZpeak.py:38
gen::TauolaInterface * tauola_
void tauola_(int *, int *)
void setPdgId(int pdgId)
Definition: Particle.cc:250
double square(const double a)
tuple cout
Definition: gather_cfg.py:121
void init(const edm::EventSetup &)
#define DEFINE_EDM_PLUGIN(factory, type, name)
VertexRefVector::iterator vertex_iterator
iterator over a vector of references to Vertex objects in the same collection
Definition: VertexFwd.h:19
volatile std::atomic< bool > shutdown_flag false
Definition: DDAxes.h:10
CLHEP::HepRandomEngine * decayRandomEngine
double py() const
y coordinate of momentum vector
Definition: Particle.cc:145
void setStatus(int status)
set status word
Definition: Particle.cc:258
int charge() const
electric charge
Definition: Particle.cc:70
math::XYZTLorentzVector LorentzVector
Lorentz vector.
Definition: Particle.h:27
const double breitWignerWidthZ
GenMuonRadiationAlgorithm * muonRadiationAlgo_
Definition: Run.h:41
std::vector< reco::Particle > ParticleCollection
double p3[4]
Definition: TauolaWrapper.h:91
T angle(T x1, T y1, T z1, T x2, T y2, T z2)
Definition: angle.h:11
Definition: DDAxes.h:10