ATLAS Offline Software
Loading...
Searching...
No Matches
GenEventBeamEffectBooster.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration
3*/
4
5// class header include
7
8// Athena includes
10#include "CLHEP/Random/RandGaussZiggurat.h"
11
12// CLHEP includes
13#include "CLHEP/Vector/LorentzVector.h"
14#include "CLHEP/Units/PhysicalConstants.h"
15
16// HepMC includes
17#include "AtlasHepMC/GenEvent.h"
19
20namespace Simulation
21{
24 const std::string& n,
25 const IInterface* p )
26 : base_class(t,n,p)
27 {
28 }
29
30
33 {
34 ATH_MSG_VERBOSE("Initializing ...");
35 // prepare the RandonNumber generation
36 ATH_CHECK(m_rndGenSvc.retrieve());
37 m_randomEngine = m_rndGenSvc->getEngine(this, m_randomEngineName); //FIXME
38 if (!m_randomEngine) {
39 ATH_MSG_ERROR("Could not get random number engine from RandomNumberService. Abort.");
40 return StatusCode::FAILURE;
41 }
42 return StatusCode::SUCCESS;
43 }
44
45
48 {
49 ATH_MSG_VERBOSE("Finalizing ...");
50 return StatusCode::SUCCESS;
51 }
52
54 {
55 // Refresh properties retrieved from the BeamCondSvc here if
56 // necessary. It may be more thread-safe to retrieve them directly
57 // from the BeamCondSvc during initializeGenEvent though?
58
59 // m_sigma_px_b1 = 20.E-6; // angular divergence in x of beam 1 [rad]
60 // m_sigma_px_b2 = 21.E-6; // angular divergence in x of beam 2 [rad]
61 // m_sigma_py_b1 = 22.E-6; // angular divergence in y of beam 1 [rad]
62 // m_sigma_py_b2 = 23.E-6; // angular divergence in y of beam 2 [rad]
63 // // Crossing angles, note the convention here is taken from online https://atlas-dcs.cern.ch/index.php?page=LHC_INS::INS_BPM
64 // m_xing_x_b1 = 19.E-6; // half-crossing in x for beam 1 at IP1, i.e. angle between beam 1 and z-axis
65 // m_xing_x_b2 = 1.E-6; // half-crossing in x for beam 2 at IP1, i.e. angle between beam 2 and z-axis
66 // m_xing_y_b1 = 150.E-6; // half-crossing in y for beam 1 at IP1, i.e. angle between beam 1 and z-axis
67 // m_xing_y_b2 = -152.E-6; // half-crossing in y for beam 2 at IP1, i.e. angle between beam 2 and z-axis
68 // m_dE = 1.1E-4; // Delta_E/E theoretical value
69 // m_pbeam1 = 3500.0E3; /// @todo Get from a service
70 // m_pbeam2 = 3500.0E3; /// @todo Get from a service
71 // m_beam1ParticleMass = CLHEP::proton_mass_c2;
72 // m_beam2ParticleMass = CLHEP::proton_mass_c2;
73
74 return StatusCode::SUCCESS;
75 }
76
77 StatusCode GenEventBeamEffectBooster::initializeGenEvent(CLHEP::HepLorentzRotation& transform, const EventContext& ctx) const
78 {
79 // Reset the transformation
80 transform = CLHEP::HepLorentzRotation(); //TODO drop this
81
82 // Prepare the random engine
83 m_randomEngine->setSeed( name(), ctx );
84 CLHEP::HepRandomEngine* randomEngine(m_randomEngine->getEngine(ctx));
85
86 // Create beam 1 and 2 momenta, including divergence and crossing-angle effects
87 const double px1 = m_pbeam1 * CLHEP::RandGaussZiggurat::shoot(randomEngine, m_xing_x_b2, m_sigma_px_b2);
88 const double py1 = m_pbeam1 * CLHEP::RandGaussZiggurat::shoot(randomEngine, m_xing_y_b2, m_sigma_py_b2);
89 const double pz1 = CLHEP::RandGaussZiggurat::shoot(randomEngine, sqrt(m_pbeam1*m_pbeam1 - px1*px1 - py1*py1), m_dE);
90 const double e1 = sqrt(px1*px1 + py1*py1 + pz1*pz1 + m_beam1ParticleMass*m_beam1ParticleMass);
91 CLHEP::HepLorentzVector pp1(px1, py1, pz1, e1);
92
93 const double px2 = -m_pbeam2 * CLHEP::RandGaussZiggurat::shoot(randomEngine, m_xing_x_b1, m_sigma_px_b1); // crossing angle & divergence
94 const double py2 = -m_pbeam2 * CLHEP::RandGaussZiggurat::shoot(randomEngine, m_xing_y_b1, m_sigma_py_b1);
95 const double pz2 = CLHEP::RandGaussZiggurat::shoot(randomEngine, -sqrt(m_pbeam2*m_pbeam2 - px2*px2 - py2*py2), m_dE); // longitudinal component in + direction energy smeared
96 const double e2 = sqrt(px2*px2 + py2*py2 + pz2*pz2 + m_beam2ParticleMass*m_beam2ParticleMass);
97 CLHEP::HepLorentzVector pp2(px2, py2, pz2, e2);
98
99 // Now set-up rotation-boost matrix
100 const CLHEP::HepLorentzVector psum = pp1 + pp2;
101 const CLHEP::HepLorentzVector& dir = pp1;
102 // Boost psum back on the direction of dir, adapted from bstback & fromCMframe PYTHIA8, credit to T.Sjostrand
103 const double betaX = -psum.x() / psum.t();
104 const double betaY = -psum.y() / psum.t();
105 const double betaZ = -psum.z() / psum.t();
106 const double beta2 = betaX*betaX + betaY*betaY + betaZ*betaZ;
107 const double gamma = 1. / sqrt(1. - beta2);
108 const double prod1 = betaX * dir.x() + betaY * dir.y() + betaZ * dir.z();
109 const double prod2 = gamma * (gamma * prod1 / (1. + gamma) + dir.t());
110 // Get the angle of rotation
111 const CLHEP::HepLorentzVector back(dir.x() + prod2 * betaX,
112 dir.y() + prod2 * betaY,
113 dir.z() + prod2 * betaZ,
114 gamma * (dir.t() + prod1));
115 const double thback = back.theta();
116 const double phback = back.phi();
117 // Setting up two rotation matrices, via 3x3 rep. rather than even more messy EulerAngles
118 const double sph = sin(phback), cph = cos(phback), sth = sin(thback), cth = cos(thback);
119 const CLHEP::HepRotation rot1(CLHEP::HepRep3x3(cph, sph, 0.0, -sph, cph, 0.0, 0.0, 0.0, 1.0));
120 const CLHEP::HepRotation rot2(CLHEP::HepRep3x3(cth*cph, -sph, sth*cph, cth*sph, cph, sth*sph, -sth, 0.0, cth));
121 const CLHEP::HepBoost bst(psum.px()/psum.e(), psum.py()/psum.e(), psum.pz()/psum.e());
122 // Combine the two rotations and the boost; matrix multiplication order matters
123 const CLHEP::HepRotation rot = rot2*rot1;
125 transform.set(rot,bst);
126 }
127 else {
128 if(m_applyBoost) {
129 transform.set(bst);
130 }
132 transform.set(rot);
133 }
134 }
135 return StatusCode::SUCCESS;
136 }
137
139 StatusCode GenEventBeamEffectBooster::manipulate(HepMC::GenEvent& ge, const EventContext& ctx) const
140 {
141 // Obtain the transformation
142 CLHEP::HepLorentzRotation transform = CLHEP::HepLorentzRotation();
143 ATH_CHECK( initializeGenEvent(transform, ctx) );
144
145 for( auto particleIter: ge) {
146 this->boostParticle(particleIter, transform);
147 }
148 return StatusCode::SUCCESS;
149 }
150
152 const CLHEP::HepLorentzRotation& transform) const
153 {
154 // Apply the same transformation for EVERY HepMC::GenParticle
155 const HepMC::FourVector &mom = p->momentum();
156 CLHEP::HepLorentzVector hv(mom.px(), mom.py(), mom.pz(), mom.e()); //TODO check units
157 ATH_MSG_VERBOSE("BEAMBOOST initial momentum " << hv );
158 hv.transform(transform);
159 ATH_MSG_VERBOSE("BEAMBOOST transformed momentum " << hv);
160 p->set_momentum(HepMC::FourVector(hv.px(),hv.py(),hv.pz(),hv.e())); //TODO check units
161 }
162
163}
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_VERBOSE(x)
StatusCode manipulate(HepMC::GenEvent &ge, const EventContext &ctx) const override final
modifies the given GenEvent
GenEventBeamEffectBooster(const std::string &t, const std::string &n, const IInterface *p)
Constructor with parameters.
StatusCode finalize() override final
Athena algtool's Hooks.
StatusCode initializeGenEvent(CLHEP::HepLorentzRotation &transform, const EventContext &ctx) const
calculate the transformations that we want to apply to the particles in the current GenEvent
StatusCode initialize() override final
Athena algtool's Hooks.
void boostParticle(HepMC::GenParticlePtr &p, const CLHEP::HepLorentzRotation &transform) const
apply boost to individual GenParticles
Gaudi::Property< std::string > m_randomEngineName
Name of the random number stream.
GenParticle * GenParticlePtr
Definition GenParticle.h:37