evtgen is hosted by Hepforge, IPPP Durham
EvtGen  2.0.0
Monte Carlo generator of particle decays, in particular the weak decays of heavy flavour particles such as B mesons.
EvtPhotosEngine.cpp
Go to the documentation of this file.
1 
2 /***********************************************************************
3 * Copyright 1998-2020 CERN for the benefit of the EvtGen authors *
4 * *
5 * This file is part of EvtGen. *
6 * *
7 * EvtGen is free software: you can redistribute it and/or modify *
8 * it under the terms of the GNU General Public License as published by *
9 * the Free Software Foundation, either version 3 of the License, or *
10 * (at your option) any later version. *
11 * *
12 * EvtGen is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU General Public License for more details. *
16 * *
17 * You should have received a copy of the GNU General Public License *
18 * along with EvtGen. If not, see <https://www.gnu.org/licenses/>. *
19 ***********************************************************************/
20 
21 #ifdef EVTGEN_PHOTOS
22 
24 
25 #include "EvtGenBase/EvtPDL.hh"
27 #include "EvtGenBase/EvtRandom.hh"
28 #include "EvtGenBase/EvtReport.hh"
30 
31 #include <iostream>
32 #include <sstream>
33 #include <vector>
34 
35 using std::endl;
36 
37 EvtPhotosEngine::EvtPhotosEngine( std::string photonType, bool useEvtGenRandom )
38 {
39  _photonType = photonType;
40  _gammaId = EvtId( -1, -1 );
41  _gammaPDG = 22; // default photon pdg integer
42  _mPhoton = 0.0;
43 
44  EvtGenReport( EVTGEN_INFO, "EvtGen" ) << "Setting up PHOTOS." << endl;
45 
46  if ( useEvtGenRandom == true ) {
47  EvtGenReport( EVTGEN_INFO, "EvtGen" )
48  << "Using EvtGen random number engine also for Photos++" << endl;
49 
50  Photospp::Photos::setRandomGenerator( EvtRandom::Flat );
51  }
52 
53  Photospp::Photos::initialize();
54 
55  // Increase the maximum possible value of the interference weight
56  Photospp::Photos::maxWtInterference(
57  64.0 ); // 2^n, where n = number of charges (+,-)
58  Photospp::Photos::setInterference( true );
59  Photospp::Photos::setExponentiation( true ); // Sets the infrared cutoff at 1e-7
60  // Reset the minimum photon energy, if required, in units of half of the decaying particle mass.
61  // This must be done after exponentiation! Keep the cut at 1e-7, i.e. 0.1 keV at the 1 GeV scale,
62  // which is appropriate for B decays
63  Photospp::Photos::setInfraredCutOff( 1.0e-7 );
64 
65  _initialised = false;
66 }
67 
68 void EvtPhotosEngine::initialise()
69 {
70  if ( _initialised == false ) {
71  _gammaId = EvtPDL::getId( _photonType );
72 
73  if ( _gammaId == EvtId( -1, -1 ) ) {
74  EvtGenReport( EVTGEN_INFO, "EvtGen" )
75  << "Error in EvtPhotosEngine. Do not recognise the photon type "
76  << _photonType << ". Setting this to \"gamma\". " << endl;
77  _gammaId = EvtPDL::getId( "gamma" );
78  }
79 
80  _gammaPDG = EvtPDL::getStdHep( _gammaId );
81  _mPhoton = EvtPDL::getMeanMass( _gammaId );
82 
83  _initialised = true;
84  }
85 }
86 
87 bool EvtPhotosEngine::doDecay( EvtParticle* theMother )
88 {
89  if ( _initialised == false ) {
90  this->initialise();
91  }
92 
93  if ( theMother == 0 ) {
94  return false;
95  }
96 
97  // Create a dummy HepMC GenEvent containing a single vertex, with the mother
98  // assigned as the incoming particle and its daughters as outgoing particles.
99  // We then pass this event to Photos for processing.
100  // It will return a modified version of the event, updating the momentum of
101  // the original particles and will contain any new photon particles.
102  // We add these extra photons to the mother particle daughter list.
103 
104  // Skip running Photos if the particle has no daughters, since we can't add FSR.
105  // Also skip Photos if the particle has too many daughters (>= 10) to avoid a problem
106  // with a hard coded upper limit in the PHOENE subroutine.
107  int nDaug( theMother->getNDaug() );
108  if ( nDaug == 0 || nDaug >= 10 ) {
109  return false;
110  }
111 
112  // Create the dummy event.
113  auto theEvent = std::make_unique<GenEvent>( Units::GEV, Units::MM );
114 
115  // Create the decay "vertex".
116  GenVertexPtr theVertex = newGenVertexPtr();
117  theEvent->add_vertex( theVertex );
118 
119  // Add the mother particle as the incoming particle to the vertex.
120  GenParticlePtr hepMCMother = this->createGenParticle( theMother, true );
121  theVertex->add_particle_in( hepMCMother );
122 
123  // Find all daughter particles and assign them as outgoing particles to the vertex.
124  // Keep track of the number of photons already in the decay (e.g. we may have B -> K* gamma)
125  int iDaug( 0 ), nGamma( 0 );
126  for ( iDaug = 0; iDaug < nDaug; iDaug++ ) {
127  EvtParticle* theDaughter = theMother->getDaug( iDaug );
128  GenParticlePtr hepMCDaughter = this->createGenParticle( theDaughter,
129  false );
130  theVertex->add_particle_out( hepMCDaughter );
131 
132  if ( theDaughter ) {
133  int daugId = theDaughter->getPDGId();
134  if ( daugId == _gammaPDG ) {
135  nGamma++;
136  }
137  }
138  }
139 
140  // Now pass the event to Photos for processing
141  // Create a Photos event object
142 #ifdef EVTGEN_HEPMC3
143  Photospp::PhotosHepMC3Event photosEvent( theEvent.get() );
144 #else
145  Photospp::PhotosHepMCEvent photosEvent( theEvent.get() );
146 #endif
147 
148  // Run the Photos algorithm
149  photosEvent.process();
150 
151  // Find the number of (outgoing) photons in the event
152  int nPhotons = this->getNumberOfPhotons( theVertex );
153 
154  // See if Photos has created additional photons. If not, do nothing extra
155  int nDiffPhotons = nPhotons - nGamma;
156  int iLoop( 0 );
157 
158  if ( nDiffPhotons > 0 ) {
159  // We have extra particles from Photos; these would have been appended
160  // to the outgoing particle list
161 
162  // Get the iterator of outgoing particles for this vertex
163 #ifdef EVTGEN_HEPMC3
164  for ( auto outParticle : theVertex->particles_out() ) {
165 #else
166  HepMC::GenVertex::particles_out_const_iterator outIter;
167  for ( outIter = theVertex->particles_out_const_begin();
168  outIter != theVertex->particles_out_const_end(); ++outIter ) {
169  // Get the next HepMC GenParticle
170  HepMC::GenParticle* outParticle = *outIter;
171 #endif
172 
173  // Get the three-momentum Photos result for this particle, and the PDG id
174  double px( 0.0 ), py( 0.0 ), pz( 0.0 );
175  int pdgId( 0 );
176 
177  if ( outParticle != 0 ) {
178  FourVector HepMCP4 = outParticle->momentum();
179  px = HepMCP4.px();
180  py = HepMCP4.py();
181  pz = HepMCP4.pz();
182  pdgId = outParticle->pdg_id();
183  }
184 
185  // Create an empty 4-momentum vector for the new/modified daughters
186  EvtVector4R newP4;
187 
188  if ( iLoop < nDaug ) {
189  // Original daughters
190  EvtParticle* daugParticle = theMother->getDaug( iLoop );
191  if ( daugParticle != 0 ) {
192  // Keep the original particle mass, but set the three-momentum
193  // according to what Photos has modified. However, this will
194  // violate energy conservation (from what Photos has provided).
195  double mass = daugParticle->mass();
196  double energy = sqrt( mass * mass + px * px + py * py +
197  pz * pz );
198  newP4.set( energy, px, py, pz );
199  // Set the new four-momentum (FSR applied)
200  daugParticle->setP4WithFSR( newP4 );
201  }
202 
203  } else if ( pdgId == _gammaPDG ) {
204  // Extra photon particle. Setup the four-momentum object
205  double energy = sqrt( _mPhoton * _mPhoton + px * px + py * py +
206  pz * pz );
207  newP4.set( energy, px, py, pz );
208 
209  // Create a new photon particle and add it to the list of daughters
210  EvtPhotonParticle* gamma = new EvtPhotonParticle();
211  gamma->init( _gammaId, newP4 );
212  // Set the pre-FSR photon momentum to zero
213  gamma->setFSRP4toZero();
214  // Let the mother know about this new photon
215  gamma->addDaug( theMother );
216  // Set its particle attribute to specify it is a FSR photon
217  gamma->setAttribute( "FSR", 1 ); // it is a FSR photon
218  gamma->setAttribute( "ISR", 0 ); // it is not an ISR photon
219  }
220 
221  // Increment the loop counter for detecting additional photon particles
222  iLoop++;
223  }
224  }
225 
226  // Cleanup
227  theEvent->clear();
228 
229  return true;
230 }
231 
232 GenParticlePtr EvtPhotosEngine::createGenParticle( EvtParticle* theParticle,
233  bool incoming )
234 {
235  // Method to create an HepMC::GenParticle version of the given EvtParticle.
236  if ( theParticle == 0 ) {
237  return 0;
238  }
239 
240  // Get the 4-momentum (E, px, py, pz) for the EvtParticle
241  EvtVector4R p4( 0.0, 0.0, 0.0, 0.0 );
242 
243  if ( incoming == true ) {
244  p4 = theParticle->getP4Restframe();
245  } else {
246  p4 = theParticle->getP4();
247  }
248 
249  // Convert this to the HepMC 4-momentum
250  double E = p4.get( 0 );
251  double px = p4.get( 1 );
252  double py = p4.get( 2 );
253  double pz = p4.get( 3 );
254 
255  FourVector hepMC_p4( px, py, pz, E );
256 
257  int PDGInt = EvtPDL::getStdHep( theParticle->getId() );
258 
259  // Set the status flag for the particle. This is required, otherwise Photos++
260  // will crash from out-of-bounds array index problems.
261  int status = Photospp::PhotosParticle::HISTORY;
262  if ( incoming == false ) {
263  status = Photospp::PhotosParticle::STABLE;
264  }
265 
266  GenParticlePtr genParticle = newGenParticlePtr( hepMC_p4, PDGInt, status );
267 
268  return genParticle;
269 }
270 
271 int EvtPhotosEngine::getNumberOfPhotons( const GenVertexPtr theVertex ) const
272 {
273  // Find the number of photons from the outgoing particle list
274 
275  if ( !theVertex ) {
276  return 0;
277  }
278 
279  int nPhotons( 0 );
280 
281  // Get the iterator of outgoing particles for this vertex
282 #ifdef EVTGEN_HEPMC3
283  for ( auto outParticle : theVertex->particles_out() ) {
284 #else
285  HepMC::GenVertex::particles_out_const_iterator outIter;
286  for ( outIter = theVertex->particles_out_const_begin();
287  outIter != theVertex->particles_out_const_end(); ++outIter ) {
288  // Get the next HepMC GenParticle
289  HepMC::GenParticle* outParticle = *outIter;
290 #endif
291 
292  // Get the PDG id
293  int pdgId( 0 );
294  if ( outParticle != 0 ) {
295  pdgId = outParticle->pdg_id();
296  }
297 
298  // Keep track of how many photons there are
299  if ( pdgId == _gammaPDG ) {
300  nPhotons++;
301  }
302  }
303 
304  return nPhotons;
305 }
306 
307 #endif
void setAttribute(std::string attName, int attValue)
Definition: EvtParticle.hh:418
void setFSRP4toZero()
Definition: EvtParticle.hh:275
HepMC::GenParticle * GenParticlePtr
std::ostream & EvtGenReport(EvtGenSeverity severity, const char *facility=0)
Definition: EvtReport.cpp:33
static double getMeanMass(EvtId i)
Definition: EvtPDL.cpp:314
EvtId getId() const
void set(int i, double d)
Definition: EvtVector4R.hh:167
HepMC::FourVector FourVector
GenVertexPtr newGenVertexPtr(const FourVector &pos=FourVector(0.0, 0.0, 0.0, 0.0))
Definition: EvtId.hh:27
size_t getNDaug() const
double get(int i) const
Definition: EvtVector4R.hh:162
void init(EvtId part_n, double e, double px, double py, double pz)
static double Flat()
Definition: EvtRandom.cpp:72
void addDaug(EvtParticle *node)
static EvtId getId(const std::string &name)
Definition: EvtPDL.cpp:287
void setP4WithFSR(const EvtVector4R &p4)
Definition: EvtParticle.hh:273
const EvtVector4R & getP4() const
HepMC::GenVertex * GenVertexPtr
double mass() const
int getPDGId() const
EvtParticle * getDaug(int i)
Definition: EvtParticle.cpp:91
EvtVector4R getP4Restframe() const
GenParticlePtr newGenParticlePtr(const FourVector &mom=FourVector(0.0, 0.0, 0.0, 0.0), int pid=0, int status=0)
static int getStdHep(EvtId id)
Definition: EvtPDL.cpp:362