ATLAS Offline Software
Loading...
Searching...
No Matches
EvtPhotosEngine.cxx
Go to the documentation of this file.
1
2/***********************************************************************
3* Copyright 1998-2024 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
22#include "EvtGen_i/EvtGenExternal/EvtPhotosEngine.hh"
23
24#include "EvtGenBase/EvtPDL.hh"
25#include "EvtGenBase/EvtPhotonParticle.hh"
26#include "EvtGenBase/EvtRandom.hh"
27#include "EvtGenBase/EvtReport.hh"
28#include "EvtGenBase/EvtVector4R.hh"
29
32
33#include <iostream>
34#include <sstream>
35#include <vector>
36
37using std::endl;
38
39EvtPhotosEngine::EvtPhotosEngine( const std::string& photonType, bool useEvtGenRandom ) :
40 m_photonType(photonType),
41 m_gammaId(EvtId( -1, -1 )),
42 m_gammaPDG(22), // default photon pdg integer
43 m_mPhoton(0.0)
44{
45
46 EvtGenReport( EVTGEN_INFO, "EvtGen" ) << "Setting up PHOTOS." << endl;
47
48 if ( useEvtGenRandom == true ) {
49 EvtGenReport( EVTGEN_INFO, "EvtGen" )
50 << "Using EvtGen random number engine also for Photos++" << endl;
51
52 Photospp::Photos::setRandomGenerator( EvtRandom::Flat );
53 }
54
55 Photospp::Photos::initialize();
56
57 // Increase the maximum possible value of the interference weight
58 Photospp::Photos::maxWtInterference(
59 64.0 ); // 2^n, where n = number of charges (+,-)
60 Photospp::Photos::setInterference( true );
61 Photospp::Photos::setExponentiation( true ); // Sets the infrared cutoff at 1e-7
62 // Reset the minimum photon energy, if required, in units of half of the decaying particle mass.
63 // This must be done after exponentiation! Keep the cut at 1e-7, i.e. 0.1 keV at the 1 GeV scale,
64 // which is appropriate for B decays
65 Photospp::Photos::setInfraredCutOff( 1.0e-7 );
66
67 m_initialised = false;
68}
69
70void EvtPhotosEngine::initialise()
71{
72 if ( m_initialised == false ) {
73 m_gammaId = EvtPDL::getId( m_photonType );
74
75 if ( m_gammaId == EvtId( -1, -1 ) ) {
76 EvtGenReport( EVTGEN_INFO, "EvtGen" )
77 << "Error in EvtPhotosEngine. Do not recognise the photon type "
78 << m_photonType << ". Setting this to \"gamma\". " << endl;
79 m_gammaId = EvtPDL::getId( "gamma" );
80 }
81
82 m_gammaPDG = EvtPDL::getStdHep( m_gammaId );
83 m_mPhoton = EvtPDL::getMeanMass( m_gammaId );
84
85 m_initialised = true;
86 }
87}
88
89bool EvtPhotosEngine::doDecay( EvtParticle* theMother )
90{
91 if ( m_initialised == false ) {
92 this->initialise();
93 }
94
95 if ( theMother == 0 ) {
96 return false;
97 }
98
99 // Create a dummy HepMC GenEvent containing a single vertex, with the mother
100 // assigned as the incoming particle and its daughters as outgoing particles.
101 // We then pass this event to Photos for processing.
102 // It will return a modified version of the event, updating the momentum of
103 // the original particles and will contain any new photon particles.
104 // We add these extra photons to the mother particle daughter list.
105
106 // Skip running Photos if the particle has no daughters, since we can't add FSR.
107 // Also skip Photos if the particle has too many daughters (>= 10) to avoid a problem
108 // with a hard coded upper limit in the PHOENE subroutine.
109 int nDaug( theMother->getNDaug() );
110 if ( nDaug == 0 || nDaug >= 10 ) {
111 return false;
112 }
113
114 // Create the dummy event.
115 auto theEvent = std::make_unique<GenEvent>( Units::GEV, Units::MM );
116
117 // Create the decay "vertex".
118 GenVertexPtr theVertex = newGenVertexPtr();
119 theEvent->add_vertex( theVertex );
120
121 // Add the mother particle as the incoming particle to the vertex.
122 GenParticlePtr hepMCMother = this->createGenParticle( theMother, true );
123 theVertex->add_particle_in( std::move(hepMCMother) );
124
125 // Find all daughter particles and assign them as outgoing particles to the vertex.
126 // Keep track of the number of photons already in the decay (e.g. we may have B -> K* gamma)
127 int iDaug( 0 ), nGamma( 0 );
128 for ( iDaug = 0; iDaug < nDaug; iDaug++ ) {
129 EvtParticle* theDaughter = theMother->getDaug( iDaug );
130 GenParticlePtr hepMCDaughter = this->createGenParticle( theDaughter,
131 false );
132 theVertex->add_particle_out( std::move(hepMCDaughter) );
133
134 if ( theDaughter ) {
135 int daugId = theDaughter->getPDGId();
136 if ( daugId == m_gammaPDG ) {
137 nGamma++;
138 }
139 }
140 }
141
142 // Now pass the event to Photos for processing
143 // Create a Photos event object
144 Photospp::PhotosHepMC3Event photosEvent( theEvent.get() );
145
146 // Run the Photos algorithm
147 photosEvent.process();
148
149 // Find the number of (outgoing) photons in the event
150 int nPhotons = this->getNumberOfPhotons( theVertex );
151
152 // See if Photos has created additional photons. If not, do nothing extra
153 int nDiffPhotons = nPhotons - nGamma;
154 int iLoop( 0 );
155
156 if ( nDiffPhotons > 0 ) {
157 // We have extra particles from Photos; these would have been appended
158 // to the outgoing particle list
159
160 // Get the iterator of outgoing particles for this vertex
161 for ( auto outParticle : theVertex->particles_out() ) {
162
163 // Get the three-momentum Photos result for this particle, and the PDG id
164 double px( 0.0 ), py( 0.0 ), pz( 0.0 );
165 int pdgId( 0 );
166
167 if ( outParticle != 0 ) {
168 FourVector HepMCP4 = outParticle->momentum();
169 px = HepMCP4.px();
170 py = HepMCP4.py();
171 pz = HepMCP4.pz();
172 pdgId = outParticle->pdg_id();
173 }
174
175 // Create an empty 4-momentum vector for the new/modified daughters
176 EvtVector4R newP4;
177
178 if ( iLoop < nDaug ) {
179 // Original daughters
180 EvtParticle* daugParticle = theMother->getDaug( iLoop );
181 if ( daugParticle != 0 ) {
182 // Keep the original particle mass, but set the three-momentum
183 // according to what Photos has modified. However, this will
184 // violate energy conservation (from what Photos has provided).
185 double mass = daugParticle->mass();
186 double energy = sqrt( mass * mass + px * px + py * py +
187 pz * pz );
188 newP4.set( energy, px, py, pz );
189 // Set the new four-momentum (FSR applied)
190 daugParticle->setP4WithFSR( newP4 );
191 }
192
193 } else if ( pdgId == m_gammaPDG ) {
194 // Extra photon particle. Setup the four-momentum object
195 double energy = sqrt( m_mPhoton * m_mPhoton + px * px + py * py +
196 pz * pz );
197 newP4.set( energy, px, py, pz );
198
199 // Create a new photon particle and add it to the list of daughters
200 EvtPhotonParticle* gamma = new EvtPhotonParticle();
201 gamma->init( m_gammaId, newP4 );
202 // Set the pre-FSR photon momentum to zero
203 gamma->setFSRP4toZero();
204 // Let the mother know about this new photon
205 gamma->addDaug( theMother );
206 // Set its particle attribute to specify it is a FSR photon
207 gamma->setAttribute( "FSR", 1 ); // it is a FSR photon
208 gamma->setAttribute( "ISR", 0 ); // it is not an ISR photon
209 }
210
211 // Increment the loop counter for detecting additional photon particles
212 iLoop++;
213 }
214 }
215
216 // Cleanup
217 theEvent->clear();
218
219 return true;
220}
221
222GenParticlePtr EvtPhotosEngine::createGenParticle( EvtParticle* theParticle,
223 bool incoming )
224{
225 // Method to create an HepMC::GenParticle version of the given EvtParticle.
226 if ( theParticle == 0 ) {
227 return 0;
228 }
229
230 // Get the 4-momentum (E, px, py, pz) for the EvtParticle
231 EvtVector4R p4( 0.0, 0.0, 0.0, 0.0 );
232
233 if ( incoming == true ) {
234 p4 = theParticle->getP4Restframe();
235 } else {
236 p4 = theParticle->getP4();
237 }
238
239 // Convert this to the HepMC 4-momentum
240 double E = p4.get( 0 );
241 double px = p4.get( 1 );
242 double py = p4.get( 2 );
243 double pz = p4.get( 3 );
244
245 FourVector hepMC_p4( px, py, pz, E );
246
247 int PDGInt = EvtPDL::getStdHep( theParticle->getId() );
248
249 // Set the status flag for the particle. This is required, otherwise Photos++
250 // will crash from out-of-bounds array index problems.
251 int status = Photospp::PhotosParticle::HISTORY;
252 if ( incoming == false ) {
253 status = Photospp::PhotosParticle::STABLE;
254 }
255
256 GenParticlePtr genParticle = newGenParticlePtr( hepMC_p4, PDGInt, status );
257
258 return genParticle;
259}
260
261int EvtPhotosEngine::getNumberOfPhotons( const GenVertexPtr theVertex ) const
262{
263 // Find the number of photons from the outgoing particle list
264
265 if ( !theVertex ) {
266 return 0;
267 }
268
269 int nPhotons( 0 );
270
271 // Get the iterator of outgoing particles for this vertex
272 for ( auto outParticle : theVertex->particles_out() ) {
273 // Get the PDG id
274 int pdgId( 0 );
275 if ( outParticle != 0 ) {
276 pdgId = outParticle->pdg_id();
277 }
278
279 // Keep track of how many photons there are
280 if ( pdgId == m_gammaPDG ) {
281 nPhotons++;
282 }
283 }
284
285 return nPhotons;
286}
287
HepMC3::FourVector FourVector
GenParticlePtr newGenParticlePtr(const HepMC3::FourVector &mom=HepMC3::FourVector::ZERO_VECTOR(), int pid=0, int status=0)
Definition GenParticle.h:21
HepMC3::GenParticlePtr GenParticlePtr
Definition GenParticle.h:19
GenVertexPtr newGenVertexPtr(const HepMC3::FourVector &pos=HepMC3::FourVector::ZERO_VECTOR(), const int i=0)
Definition GenVertex.h:25
HepMC3::GenVertexPtr GenVertexPtr
Definition GenVertex.h:23
status
Definition merge.py:16