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