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