Belle II Software development
OpticalGunModule.cc
1/**************************************************************************
2 * basf2 (Belle II Analysis Software Framework) *
3 * Author: The Belle II Collaboration *
4 * *
5 * See git log for contributors and copyright holders. *
6 * This file is licensed under LGPL-3.0, see LICENSE.md. *
7 **************************************************************************/
8
9// Own header.
10#include <top/modules/OpticalGun/OpticalGunModule.h>
11
12// TOP headers.
13#include <top/geometry/TOPGeometryPar.h>
14
15// framework aux
16#include <framework/gearbox/Unit.h>
17#include <framework/logging/Logger.h>
18
19// ROOT
20#include <TRandom.h>
21#include <Math/EulerAngles.h>
22#include <TFormula.h>
23#include <TF1.h>
24#include <top/reconstruction_cpp/func.h>
25
26using namespace std;
27using namespace ROOT::Math;
28
29namespace Belle2 {
34
35 using namespace TOP;
36
37 //-----------------------------------------------------------------
39 //-----------------------------------------------------------------
40
41 REG_MODULE(OpticalGun);
42
43 //-----------------------------------------------------------------
44 // Implementation
45 //-----------------------------------------------------------------
46
48 {
49 // set module description
50 setDescription("Source of optical photons");
52
53 // Add parameters
54 addParam("x", m_x, "position in x [cm]", 0.0);
55 addParam("y", m_y, "position in y [cm]", 0.0);
56 addParam("z", m_z, "position in z [cm]", 0.0);
57 addParam("diameter", m_diameter, "source diameter [cm]", 0.0);
58 addParam("minAlpha", m_minAlpha, "source minimum emission angle [deg]. ", 0.0);
59 addParam("maxAlpha", m_maxAlpha, "source maximum emission angle [deg]. ", 30.);
60 addParam("na", m_na, "source numerical aperture. It is used only by the Gaussian distribution", 0.50);
61 addParam("angularDistribution", m_angularDistribution,
62 "source angular distribution: uniform, Lambertian, an arbitrary TFormula, or Gaussian "
63 "(numerical aperture instead of minAlpha and maxAlpha). If you are writing a TFormula, "
64 "assume the angles are measured in degrees. The conversion to radians is done internally.",
65 string("Gaussian"));
66 addParam("wavelength", m_wavelength, "wavelength of photons [nm]", 405.0);
67 addParam("phi", m_phi, "first rotation angle (around z) [deg]", 0.0);
68 addParam("theta", m_theta, "second rotation angle (around x) [deg]", 0.0);
69 addParam("psi", m_psi, "third rotation angle (around z) [deg]", 0.0);
70 addParam("startTime", m_startTime,
71 "start time [ns]. If TOPCalPulseGenerator is in path this is relative to the first cal pulse", 0.0);
72 addParam("pulseWidth", m_pulseWidth, "pulse duration (Gaussian sigma) [ns]", 0.0);
73 addParam("numPhotons", m_numPhotons,
74 "average number of photons per pulse, if positive, otherwise exactly one", 0.0);
75 addParam("slotID", m_slotID,
76 "TOP slot ID (1-16): if valid, source position and rotation angles assumed to be given in a local bar frame, "
77 "otherwise Belle II frame is assumed", 0);
78 addParam("slitDX", m_slitDX, "slit size in x [cm], if positive, otherwise full open", 0.0);
79 addParam("slitDY", m_slitDY, "slit size in y [cm], if positive, otherwise full open", 0.0);
80 addParam("slitX0", m_slitX0, "slit x-offset in respect to source [cm] ", 0.0);
81 addParam("slitY0", m_slitY0, "slit y-offset in respect to source [cm] ", 0.0);
82 addParam("slitZ", m_slitZ, "slit distance to source [cm], if > 0.01, otherwise slit full open", 0.0);
83 }
84
86 {
87 // data store objects registration
88 m_MCParticles.registerInDataStore();
89 m_simCalPulses.isOptional();
90
91 // parameters check
93 B2FATAL("Wavelength does not correspond to optical photons.");
95 B2FATAL("Numerical aperture must be between 0 and 1.");
96 if (m_minAlpha < 0)
97 B2FATAL("Minimum emission angle must be positive");
98 if (m_maxAlpha < 0)
99 B2FATAL("Maximum emission angle must be positive");
100 if (m_minAlpha >= m_maxAlpha)
101 B2FATAL("Minimum emission angle must me smaller than the maximum emission angle");
102
103 if (m_angularDistribution == string("uniform") or
104 m_angularDistribution == string("Lambertian") or
105 m_angularDistribution == string("Gaussian"))
106 B2INFO("Using the pre-defined angular distribution " << m_angularDistribution);
107 else {
108 B2INFO(m_angularDistribution << " is not a pre-defined distribution. "
109 << "Checking if it's a valid, positively-defined TFormula.");
110 TFormula testFormula("testFormula", m_angularDistribution.c_str());
111 int result = testFormula.Compile();
112 if (result != 0) {
113 B2FATAL(m_angularDistribution << " TFormula does not compile.");
114 }
115 double testPoint = m_minAlpha; // let's test if the function is positive defined everywhere
116 while (testPoint < m_maxAlpha) {
117 double value = testFormula.Eval(testPoint * Unit::deg);
118 if (value < 0) {
119 B2FATAL("The formula " << m_angularDistribution << " is not positively defined at the test point "
120 << testPoint << " deg (value = " << value << ")");
121 }
122 testPoint += (m_maxAlpha - m_minAlpha) / 100.;
123 }
124 m_customDistribution = TF1("m_customDistribution", m_angularDistribution.c_str(), m_minAlpha * Unit::deg,
126 }
127
128 // set other private variables
132
133 EulerAngles ea(-m_phi * Unit::deg, -m_theta * Unit::deg, -m_psi * Unit::deg); // rotation of an object as in TRotation
134 m_transform = Transform3D(Rotation3D(ea), Translation3D(m_x, m_y, m_z)); // source positioning and elevation
135 if (m_slotID != 0) {
136 const auto* geo = TOPGeometryPar::Instance()->getGeometry();
137 if (not geo->isModuleIDValid(m_slotID)) B2FATAL("Slot ID is not valid");
138 const auto& T = geo->getModule(m_slotID).getTransformation(); // slot to BelleII
140 }
141
142 }
143
144
146 {
147 // generate number of photons
148 int numPhotons = 1;
149 if (m_numPhotons > 0) numPhotons = gRandom->Poisson(m_numPhotons);
150
151 // start time
152 double startTime = m_startTime;
153 if (m_simCalPulses.getEntries() > 0) { // TOPCalPulseGenerator in the path
154 startTime += m_simCalPulses[0]->getTime(); // set start time w.r.t cal pulse
155 }
156
157 // generate photons and store them to MCParticles
158 for (int i = 0; i < numPhotons; i++) {
159
160 // generate emission point
161 double x, y;
162 do {
163 x = m_diameter * (gRandom->Rndm() - 0.5);
164 y = m_diameter * (gRandom->Rndm() - 0.5);
165 } while (x * x + y * y > m_diameter * m_diameter / 4.0);
166 XYZPoint point(x, y, 0);
167
168 // generate direction
169 XYZVector direction;
170 if (m_angularDistribution == string("uniform")) {
171 direction = getDirectionUniform();
172 } else if (m_angularDistribution == string("Lambertian")) {
173 direction = getDirectionLambertian();
174 } else if (m_angularDistribution == string("Gaussian")) {
175 direction = getDirectionGaussian();
176 } else { // we already have tested the formula and initialized the TF1 in the initialize() method
177 direction = getDirectionCustom();
178 }
179 XYZVector momentum = m_energy * direction;
180
181 // check if photon passes the slit
182 if (not isInsideSlit(point, direction)) continue;
183
184 // generate polarization vector (unpolarized light source assumed)
185 double alphaPol = 2.0 * M_PI * gRandom->Rndm();
186 XYZVector polarization(cos(alphaPol), sin(alphaPol), 0);
187 func::rotateUz(polarization, direction);
188
189 // generate emission time
190 double emissionTime = gRandom->Gaus(startTime, m_pulseWidth);
191
192 // transform to Belle II frame
193 point = m_transform * point;
194 momentum = m_transform * momentum;
195 polarization = m_transform * polarization;
196
197 // store generated photon
198 auto* part = m_MCParticles.appendNew();
199 part->setPDG(0); // optical photon
200 part->setMass(0);
201 part->setStatus(MCParticle::c_PrimaryParticle);
202 part->addStatus(MCParticle::c_StableInGenerator);
203 part->setProductionVertex(static_cast<XYZVector>(point));
204 part->setProductionTime(emissionTime);
205 part->setMomentum(momentum);
206 part->setEnergy(m_energy);
207 part->setDecayVertex(polarization); // use this location temporary to pass photon polarization to FullSim
208 }
209
210 }
211
212
213 bool OpticalGunModule::isInsideSlit(const XYZPoint& point,
214 const XYZVector& direction) const
215 {
216 if (m_slitZ < 0.01) return true; // no screen with a slit is put in front of a source
217 if (direction.Z() < 1.0e-6) return false; // must fly toward the slit
218
219 double pathLength = (m_slitZ - point.Z()) / direction.Z();
220 if (m_slitDX > 0) {
221 double x = point.X() + pathLength * direction.X();
222 if (abs(x - m_slitX0) > m_slitDX / 2.0) return false;
223 }
224 if (m_slitDY > 0) {
225 double y = point.Y() + pathLength * direction.Y();
226 if (abs(y - m_slitY0) > m_slitDY / 2.0) return false;
227 }
228
229 return true;
230 }
231
233 {
234 // NA is defined as the aperture where the amplitude is 5% of that of the
235 // peak, which translates into 2.45 sigma for a gaussian distribution
236 double x = 0;
237 double y = 0;
238 double z = 0;
239 do {
240 x = gRandom->Gaus(0., asin(m_na) / 2.45);
241 y = gRandom->Gaus(0., asin(m_na) / 2.45);
242 z = 1. - x * x - y * y;
243 } while (z < 0);
244 return XYZVector(x, y, sqrt(z));
245 }
246
248 {
249 double cosTheta = (m_cosMinAlpha - m_cosMaxAlpha) * gRandom->Rndm() + m_cosMaxAlpha;
250 double sinTheta = sqrt(1.0 - cosTheta * cosTheta);
251 double phi = 2.0 * M_PI * gRandom->Rndm();
252 return XYZVector(cos(phi) * sinTheta, sin(phi) * sinTheta, cosTheta);
253 }
254
256 {
257 double cosTheta = sqrt((m_cosMinAlpha * m_cosMinAlpha - m_cosMaxAlpha * m_cosMaxAlpha) * gRandom->Rndm() +
259 double sinTheta = sqrt(1.0 - cosTheta * cosTheta);
260 double phi = 2.0 * M_PI * gRandom->Rndm();
261 return XYZVector(cos(phi) * sinTheta, sin(phi) * sinTheta, cosTheta);
262 }
263
265 {
266 double alpha = m_customDistribution.GetRandom();
267 double phi = 2.0 * M_PI * gRandom->Rndm();
268 return XYZVector(cos(phi) * sin(alpha), sin(phi) * sin(alpha), cos(alpha));
269 }
270
271
273} // end Belle2 namespace
274
@ c_PrimaryParticle
bit 0: Particle is primary particle.
Definition MCParticle.h:47
@ c_StableInGenerator
bit 1: Particle is stable, i.e., not decaying in the generator.
Definition MCParticle.h:49
void setDescription(const std::string &description)
Sets the description of the module.
Definition Module.cc:214
void setPropertyFlags(unsigned int propertyFlags)
Sets the flags for the module properties.
Definition Module.cc:208
Module()
Constructor.
Definition Module.cc:30
@ c_ParallelProcessingCertified
This module can be run in parallel processing mode safely (All I/O must be done through the data stor...
Definition Module.h:80
std::string m_angularDistribution
source angular distribution
double m_minAlpha
minimum emission angle
TF1 m_customDistribution
Custom angular distribution, that uses m_angularDistribution as formula.
double m_slitZ
slit distance from source
double m_cosMinAlpha
cos of m_minAlpha
StoreArray< TOPSimCalPulse > m_simCalPulses
simulated cal pulse collection
double m_slitDX
slit size in x
double m_wavelength
source wavelength [nm]
double m_cosMaxAlpha
cos of m_maxAlpha
double m_slitDY
slit size in y
double m_slitX0
slit x-offset in respect to source
double m_na
source numerical aperture.
double m_slitY0
slit y-offset in respect to source
double m_phi
first rotation angle (around z) [deg]
double m_x
source position in x
double m_theta
second rotation angle (around x) [deg]
double m_startTime
start time
double m_maxAlpha
maximum emission angle
double m_energy
photon energy (from wavelength)
double m_diameter
source diameter
double m_psi
third rotation angle (around z) [deg]
double m_z
source position in z
double m_y
source position in y
double m_pulseWidth
pulse duration (Gaussian sigma)
double m_numPhotons
average number of photons in a pulse
StoreArray< MCParticle > m_MCParticles
MC particles collection.
ROOT::Math::Transform3D m_transform
transformation to BelleII frame
const TOPGeometry * getGeometry() const
Returns pointer to geometry object using basf2 units.
static TOPGeometryPar * Instance()
Static method to obtain the pointer to its instance.
static const double c_hc
Planck constant times speed of light in [eV*nm].
static const double deg
degree to radians
Definition Unit.h:109
static const double eV
[electronvolt]
Definition Unit.h:112
void addParam(const std::string &name, T &paramVariable, const std::string &description, const T &defaultValue)
Adds a new parameter to the module.
Definition Module.h:559
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Definition Module.h:649
double sqrt(double a)
sqrt for double
Definition beamHelpers.h:28
ROOT::Math::XYZVector getDirectionGaussian() const
Return photon direction according to a projected 2D gaussian distribution based on numerical aperture...
ROOT::Math::XYZVector getDirectionUniform() const
Return photon direction according to a projected uniform distribution with opening angle alpha.
ROOT::Math::XYZVector getDirectionCustom() const
Return photon direction according to a custom angular distribution given by TFormula.
virtual void initialize() override
Initialize the Module.
virtual void event() override
Event processor.
bool isInsideSlit(const ROOT::Math::XYZPoint &point, const ROOT::Math::XYZVector &direction) const
Checks if photon passes the slit.
ROOT::Math::XYZVector getDirectionLambertian() const
Return photon direction according to a lambertian distribution with opening angle alpha.
void rotateUz(ROOT::Math::XYZVector &vec, const ROOT::Math::XYZVector &z_Axis)
Replacement for a function TVector3::RotateUz which is not implemented in GenVector classes.
Definition func.h:114
Abstract base class for different kinds of events.
STL namespace.