10 #include <top/modules/OpticalGun/OpticalGunModule.h>
11 #include <top/geometry/TOPGeometryPar.h>
15 #include <framework/datastore/StoreArray.h>
18 #include <framework/gearbox/Unit.h>
19 #include <framework/logging/Logger.h>
24 #include <TRotation.h>
51 setDescription(
"Source of optical photons");
52 setPropertyFlags(c_ParallelProcessingCertified);
55 addParam(
"x", m_x,
"position in x [cm]", 0.0);
56 addParam(
"y", m_y,
"position in y [cm]", 0.0);
57 addParam(
"z", m_z,
"position in z [cm]", 0.0);
58 addParam(
"diameter", m_diameter,
"source diameter [cm]", 0.0);
59 addParam(
"minAlpha", m_minAlpha,
"source minimum emission angle [deg]. ", 0.0);
60 addParam(
"maxAlpha", m_maxAlpha,
"source maximum emission angle [deg]. ", 30.);
61 addParam(
"na", m_na,
"source numerical aperture. It is used only by the Gaussian distribution", 0.50);
62 addParam(
"angularDistribution", m_angularDistribution,
63 "source angular distribution: uniform, Lambertian, an arbitrary TFormula, or Gaussian (only one to use na and ignore m_minAlpha dn m_maxAlpha). If you are writing a TFormula, assume the angles are measured in degrees. The conversion to rad is done internally.",
65 addParam(
"wavelength", m_wavelength,
"wavelength of photons [nm]", 405.0);
66 addParam(
"phi", m_phi,
"first rotation angle (around z) [deg]", 0.0);
67 addParam(
"theta", m_theta,
"second rotation angle (around x) [deg]", 0.0);
68 addParam(
"psi", m_psi,
"third rotation angle (around z) [deg]", 0.0);
69 addParam(
"startTime", m_startTime,
70 "start time [ns]. If TOPCalPulseGenerator is in path this is relative to the first cal pulse", 0.0);
71 addParam(
"pulseWidth", m_pulseWidth,
"pulse duration (Gaussian sigma) [ns]", 0.0);
72 addParam(
"numPhotons", m_numPhotons,
73 "average number of photons per pulse, if positive, otherwise exactly one",
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, otherwise Belle II frame assumed",
78 addParam(
"slitDX", m_slitDX,
"slit size in x [cm], if positive, otherwise full open",
80 addParam(
"slitDY", m_slitDY,
"slit size in y [cm], if positive, otherwise full open",
82 addParam(
"slitX0", m_slitX0,
"slit x-offset in respect to source [cm] ", 0.0);
83 addParam(
"slitY0", m_slitY0,
"slit y-offset in respect to source [cm] ", 0.0);
84 addParam(
"slitZ", m_slitZ,
"slit distance to source [cm], if > 0.01, otherwise none",
88 OpticalGunModule::~OpticalGunModule()
90 if (m_customDistribution)
delete m_customDistribution;
93 void OpticalGunModule::initialize()
96 m_MCParticles.registerInDataStore();
97 m_simCalPulses.isOptional();
100 if (m_wavelength < 150 or m_wavelength > 1000)
101 B2FATAL(
"Wavelength does not correspond to optical photons.");
102 if (m_na < 0 or m_na > 1)
103 B2FATAL(
"Numerical aperture must be between 0 and 1.");
105 B2FATAL(
"Minimum emission angle must be positive");
107 B2FATAL(
"Maximum emission angle must be positive");
108 if (m_minAlpha >= m_maxAlpha)
109 B2FATAL(
"Minimum emission angle msut me smaller than the maximum emission angle");
112 if (m_angularDistribution ==
string(
"uniform") or
113 m_angularDistribution ==
string(
"Lambertian") or
114 m_angularDistribution ==
string(
"Gaussian"))
115 B2INFO(
"Using the pre-defined angular distribution " << m_angularDistribution);
117 B2INFO(m_angularDistribution <<
" is not a pre-defined distribution. Checking if it's a valid, positively-defined TFormula.");
118 TFormula testFormula(
"testFormula", m_angularDistribution.c_str());
119 int result = testFormula.Compile();
121 B2FATAL(m_angularDistribution <<
" is not a valid angular distribution keyword, or it's a TFormula that does not compile.");
123 double testPoint = m_minAlpha;
124 while (testPoint < m_maxAlpha) {
125 double value = testFormula.Eval(testPoint * Unit::deg);
127 B2FATAL(
"The formula " << m_angularDistribution <<
" is not positively defined in the test point " << testPoint <<
" deg (value = "
131 testPoint += (m_maxAlpha - m_minAlpha) / 100.;
133 m_customDistribution =
new TF1(
"m_customDistribution", m_angularDistribution.c_str(), m_minAlpha * Unit::deg,
134 m_maxAlpha * Unit::deg);
140 m_cosMinAlpha = cos(m_minAlpha * Unit::deg);
141 m_cosMaxAlpha = cos(m_maxAlpha * Unit::deg);
142 m_energy = TOPGeometryPar::c_hc / m_wavelength * Unit::eV;
148 const auto* geo = TOPGeometryPar::Instance()->getGeometry();
149 int Nbars = geo->getNumModules();
150 if (Nbars == 0) B2ERROR(
"TOP bars are not defined");
151 if (m_slotID < 0 or m_slotID > Nbars) {
152 B2ERROR(
"barID = " << m_slotID <<
" : not a valid ID");
155 barY0 = geo->getModule(m_slotID).getRadius();
156 barZ0 = geo->getModule(m_slotID).getZc();
157 barPhi = geo->getModule(m_slotID).getPhi() - M_PI / 2;
160 m_translate.SetXYZ(m_x, m_y + barY0, m_z + barZ0);
161 m_rotate.RotateXEulerAngles(m_phi * Unit::deg,
164 m_rotateBar.RotateZ(barPhi);
168 void OpticalGunModule::beginRun()
172 void OpticalGunModule::event()
177 if (m_numPhotons > 0) numPhotons = gRandom->Poisson(m_numPhotons);
180 double startTime = m_startTime;
181 if (m_simCalPulses.getEntries() > 0) {
182 startTime += m_simCalPulses[0]->getTime();
186 for (
int i = 0; i < numPhotons; i++) {
191 x = m_diameter * (gRandom->Rndm() - 0.5);
192 y = m_diameter * (gRandom->Rndm() - 0.5);
193 }
while (x * x + y * y > m_diameter * m_diameter / 4.0);
194 TVector3 point(x, y, 0);
198 if (m_angularDistribution ==
string(
"uniform")) {
199 direction = getDirectionUniform();
200 }
else if (m_angularDistribution ==
string(
"Lambertian")) {
201 direction = getDirectionLambertian();
202 }
else if (m_angularDistribution ==
string(
"Gaussian")) {
203 direction = getDirectionGaussian();
205 direction = getDirectionCustom();
207 TVector3 momentum = m_energy * direction;
210 if (!isInsideSlit(point, direction))
continue;
213 double alphaPol = 2.0 * M_PI * gRandom->Rndm();
214 TVector3 polarization(cos(alphaPol), sin(alphaPol), 0);
215 polarization.RotateUz(direction);
218 double emissionTime = gRandom->Gaus(startTime, m_pulseWidth);
221 momentum.Transform(m_rotate);
222 polarization.Transform(m_rotate);
223 point.Transform(m_rotate);
224 point += m_translate;
226 momentum.Transform(m_rotateBar);
227 polarization.Transform(m_rotateBar);
228 point.Transform(m_rotateBar);
232 auto* part = m_MCParticles.appendNew();
235 part->setStatus(MCParticle::c_PrimaryParticle);
236 part->addStatus(MCParticle::c_StableInGenerator);
237 part->setProductionVertex(point);
238 part->setProductionTime(emissionTime);
239 part->setMomentum(momentum);
240 part->setEnergy(m_energy);
241 part->setDecayVertex(polarization);
247 void OpticalGunModule::endRun()
251 void OpticalGunModule::terminate()
255 void OpticalGunModule::printModuleParams()
const
259 bool OpticalGunModule::isInsideSlit(
const TVector3& point,
260 const TVector3& direction)
const
262 if (m_slitZ < 0.01)
return true;
263 if (direction.Z() < 1.0e-6)
return false;
265 double pathLength = (m_slitZ - point.Z()) / direction.Z();
267 double x = point.X() + pathLength * direction.X();
268 if (abs(x - m_slitX0) > m_slitDX / 2.0)
return false;
271 double y = point.Y() + pathLength * direction.Y();
272 if (abs(y - m_slitY0) > m_slitDY / 2.0)
return false;
278 TVector3 OpticalGunModule::getDirectionGaussian()
const
286 x = gRandom->Gaus(0., asin(m_na) / 2.45);
287 y = gRandom->Gaus(0., asin(m_na) / 2.45);
288 z = 1. - x * x - y * y;
290 return TVector3(x, y, sqrt(z));
293 TVector3 OpticalGunModule::getDirectionUniform()
const
295 double cosTheta = (m_cosMinAlpha - m_cosMaxAlpha) * gRandom->Rndm() + m_cosMaxAlpha;
296 double sinTheta = sqrt(1.0 - cosTheta * cosTheta);
297 double phi = 2.0 * M_PI * gRandom->Rndm();
298 return TVector3(cos(phi) * sinTheta, sin(phi) * sinTheta, cosTheta);
301 TVector3 OpticalGunModule::getDirectionLambertian()
const
303 double cosTheta = sqrt((m_cosMinAlpha * m_cosMinAlpha - m_cosMaxAlpha * m_cosMaxAlpha) * gRandom->Rndm() +
304 m_cosMaxAlpha * m_cosMaxAlpha);
305 double sinTheta = sqrt(1.0 - cosTheta * cosTheta);
306 double phi = 2.0 * M_PI * gRandom->Rndm();
307 return TVector3(cos(phi) * sinTheta, sin(phi) * sinTheta, cosTheta);
310 TVector3 OpticalGunModule::getDirectionCustom()
const
312 double alpha = m_customDistribution->GetRandom();
313 double phi = 2.0 * M_PI * gRandom->Rndm();
314 return TVector3(cos(phi) * sin(alpha), sin(phi) * sin(alpha), cos(alpha));
Source of optical photons for the simulation of the TOP laser system.
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Abstract base class for different kinds of events.