9#include <top/reconstruction_cpp/YScanner.h>
10#include <top/reconstruction_cpp/func.h>
11#include <top/geometry/TOPGeometryPar.h>
12#include <framework/logging/Logger.h>
30 if (sol_dx.
step == 0) B2ERROR(
"TOP::YScanner::Derivatives: step (dx) is zero");
31 if (sol_de.
step == 0) B2ERROR(
"TOP::YScanner::Derivatives: step (de) is zero");
32 if (sol_dL.
step == 0) B2ERROR(
"TOP::YScanner::Derivatives: step (dL) is zero");
54 B2FATAL(
"TOP::YScanner: N must be > 1");
63 for (
size_t k = 0; k <
m_prism.unfoldedWindows.size(); k++) {
64 const auto& win =
m_prism.unfoldedWindows[k];
66 projection.
sy = win.sy;
67 projection.
sz = win.sz;
68 projection.
y0 = win.y0 + win.ny * dz;
69 projection.
z0 = win.z0 + win.nz * dz;
77 const auto* geo = topgp->getGeometry();
78 auto qe = geo->getNominalQE();
79 qe.applyFilterTransmission(geo->getWavelengthFilter());
84 B2FATAL(
"TOP::YScanner: quantum efficiency found zero for all wavelengths");
89 const auto& tdc = geo->getNominalTDC();
90 for (
unsigned i = 0; i < N; i++) {
93 double effi = qe.getEfficiency(lambda) * tdc.getEfficiency();
104 double p = entry.y * (1 - 1 / pow(topgp->getPhaseIndex(e), 2));
118 double reflectivity =
m_bars.front().reflectivity;
160 if (beta * topgp->getPhaseIndex(
m_meanE0) < 1)
return;
165 if (area == 0)
return;
173 const double radLength = 12.3;
174 double thetaScat = 13.6e-3 / beta / momentum *
sqrt(length / 2 / radLength);
176 double n = topgp->getPhaseIndex(
m_meanE);
178 B2ERROR(
"TOP::YScanner::prepare: beta * n < 1 ==> must be a bug!");
181 double dndE = topgp->getPhaseIndexDerivative(
m_meanE);
182 double dEdTheta = n *
sqrt(pow(beta * n, 2) - 1) / dndE;
205 double p = std::max(entry.y * (1 - 1 / pow(beta * topgp->getPhaseIndex(e), 2)), 0.0);
206 double ee = entry.xsq;
212 if (s == 0)
return 0;
227 B2ERROR(
"TOP::YScanner:setQuasyEnergyDistribution: unexpectedly large size of the std::map found, map cleared");
234 if (quasyEnergyDistribution.entries.empty()) {
235 std::vector<double> gaus;
236 for (
int i = 0; i <= ng; i++) {
237 double x = step * i / sigma;
238 gaus.push_back(exp(-0.5 * x * x));
244 const double* gausTable = gaus.data();
246 for (
int k = -ng; k < N + ng; k++) {
248 const int iMin = std::max(-ng, k - N + 1);
249 const int iMax = std::min(ng, k);
253 for (
int i = iMin; i <= iMax; i++) {
254 double p = gausTable[std::abs(i)] * entries[k - i].y;
255 double e = entries[k - i].x;
264 quasyEnergyDistribution.entries.push_back(
TableEntry(s, se, see));
267 for (
auto& entry : quasyEnergyDistribution.entries) entry.y /= sum;
278 if (D.dyB_de == 0)
return;
286 double dely = (std::abs(D.dyB_dL) *
m_length + std::abs(D.dyB_dx) * pixDx) / 2;
287 double y1 = yB - dely;
288 double y2 = yB + dely;
290 y1 += D.dyB_de * (minE -
m_meanE);
291 y2 += D.dyB_de * (maxE -
m_meanE);
293 y1 += D.dyB_de * (maxE -
m_meanE);
294 y2 += D.dyB_de * (minE -
m_meanE);
296 double B =
m_bars.front().B;
301 scan(col, yB, dydz, D, j1, j2);
304 merge(col, dydz, j1, j2);
315 const double barB =
m_bars.front().B;
317 std::map<int, EnergyMask*> masks;
318 for (
unsigned row = 0; row < numRows; row++) {
324 std::vector<PixelProjection> projections[2];
326 for (
size_t k = 0; k < numWindows; k++) {
328 if (proj[0].Dy > 0) projections[0].push_back(proj[0]);
329 proj[1].yc = -proj[1].yc;
330 if (proj[1].Dy > 0) projections[1].push_back(proj[1]);
332 if (projections[0].empty() and projections[1].empty())
continue;
334 for (
unsigned k = 0; k < 2; k++) {
335 std::sort(projections[k].begin(), projections[k].end());
336 for (
auto& projection : projections[k]) {
338 auto& mask = masks[iDy];
340 double Dy = projection.Dy;
344 projection.mask = mask;
349 double wid_old = 1000;
351 for (
int j = j1; j < j2; j++) {
352 double ybar = j * barB - yB;
353 for (
const auto& projection : projections[std::abs(j) % 2]) {
354 double Ecp = (ybar + projection.yc) / D.dyB_de +
m_meanE;
355 double wid = projection.mask->getFullWidth();
356 if (std::abs(Ecp - Ecp_old) > (wid + wid_old) / 2 and
m_results.back().sum > 0) {
368 for (
auto& result :
m_results) result.set();
370 for (
const auto& mask : masks) {
371 if (mask.second)
delete mask.second;
380 int Nodd = j2 - j1 - Neven;
384 const double barB =
m_bars.front().B;
386 for (
unsigned row = 0; row < numRows; row++) {
395 for (
size_t k = 0; k < numWindows; k++) {
397 if (proj[0].Dy > 0) Dy0 += proj[0].Dy;
398 if (proj[1].Dy > 0) Dy1 += proj[1].Dy;
400 if (Dy0 == 0 and Dy1 == 0)
continue;
402 double Dy = (Dy0 * Neven + Dy1 * Nodd) / (Neven + Nodd);
404 result.sum = Dy / barB;
414 const auto& mask = energyMask->
getMask();
420 double m = energyMask->
getMask(
E - Ecp);
423 double s = entry.y * m;
425 result.e0 += entry.x * s;
426 result.sigsq += entry.xsq * s;
438 int M = mask.size() - 1;
439 int i1 = std::max(i0 - M, 0);
440 int i2 = std::min(i0 + M - 1, N);
441 for (
int i = i1; i <= i2; i++) {
443 double m = mask[std::abs(i - i0)] * (1 - fract) + mask[std::abs(i - i0 + 1)] * fract;
444 double s = entry.y * m;
446 result.e0 += entry.x * s;
447 result.sigsq += entry.xsq * s;
A mask for energy masking.
const std::vector< double > & getMask() const
Returns discrete mask (note: only half of the mask is stored)
Pixel relative efficiencies of a single module.
Pixel masks of a single module.
Pixel positions and dimensions in module local frame.
@ c_Unified
single bar with average width and thickness
@ c_SemiLinear
semi-linear approximation
RaytracerBase(int moduleID, EGeometry geometry=c_Unified, EOptics optics=c_SemiLinear)
Constructor.
Prism m_prism
prism geometry data
std::vector< BarSegment > m_bars
geometry data of bar segments
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].
double m_cosTotal
cosine of total reflection angle
void prepare(double momentum, double beta, double length) const
Prepare for the PDF expansion in y for a given track mass hypothesis.
Table m_energyDistribution
photon energy distribution
static unsigned s_maxTabulatedPower
maximal power of the surface reflectivity that is tabulated
PixelEfficiencies m_pixelEfficiencies
pixel relative efficiencies
double m_beta
particle beta
bool m_scanDone
true if scan performed, false if reflections just merged
Table m_efficiency
nominal photon detection efficiencies (PDE)
double m_meanE
mean photon energy
static int s_maxReflections
maximal number of reflections to perform scan
double m_rmsE
r.m.s of photon energy
std::vector< double > m_surfaceReflectivities
bar surface reflectivity to the power of the index; filled on demand, never cleared
bool m_aboveThreshold
true if beta is above the Cerenkov threshold
void projectPixel(double yc, double size, int k, double dydz, PixelProjection proj[2]) const
Calculates projections of a pixel to prism entrance window (going down-stream the photon).
void merge(unsigned col, double dydz, int j1, int j2) const
Performs expansion by merging all reflections.
void scan(unsigned col, double yB, double dydz, const Derivatives &D, int j1, int j2) const
Performs expansion w/ the scan over reflections.
double tabulateSurfaceReflectivity(unsigned n) const
Extends the table of surface reflectivity powers up to n and returns the value.
double m_meanE0
mean photon energy for beta = 1
double m_momentum
particle momentum magnitude
Table * m_quasyEnergyDistribution
a pointer to the element in m_quasyEnergyDistributions
PixelMasks m_pixelMasks
pixel masks
void setQuasyEnergyDistribution(double sigma) const
Sets photon energy distribution convoluted with a normalized Gaussian.
void integrate(const EnergyMask *energyMask, double Ecp, Result &result) const
Integrates quasy energy distribution multiplied with energy mask.
void expand(unsigned col, double yB, double dydz, const Derivatives &D, int Ny, bool doScan) const
Performs the PDF expansion in y for a given pixel column using scan or merge methods.
YScanner(int moduleID, unsigned N=64)
Class constructor.
std::map< int, Table > m_quasyEnergyDistributions
photon energy distributions convoluted with Gaussian of different widths
std::vector< WindowProjection > m_windowProjections
pixel projection constants of unfolded prism exit windows
double setEnergyDistribution(double beta) const
Sets photon energy distribution and mean photon energy according to nominal PDE and particle beta.
double m_length
length of particle trajectory inside quartz
double m_rmsE0
r.m.s of photon energy for beta = 1
std::vector< Result > m_results
results of PDF expansion in y
double m_prismZR
z of the prism-bar joint (copy of m_prism.zR)
PixelPositions m_pixelPositions
positions and sizes of pixels
void clear() const
Clear mutable variables.
double m_numPhotons
number of photons per Cerenkov azimuthal angle per track length
double m_halfBarThickness
half thickness of the bar at prism entrance
double m_sigmaAlpha
surface roughness parameter in photon energy units
double sqrt(double a)
sqrt for double
int getNumOfEven(int j1, int j2)
Returns number of even numbers in the range given by arguments.
long lround(double x)
Rounds to the nearest integer, halfway cases away from zero.
Abstract base class for different kinds of events.
Solution of inverse ray-tracing.
double step
step for numerical derivative calculation
static double dyB_d(const InverseRaytracer::Solution &sol0, const InverseRaytracer::Solution &sol1)
Calculates the derivative of unfolded y coordinate at prism entrance.
static double dLen_d(const InverseRaytracer::Solution &sol0, const InverseRaytracer::Solution &sol1)
Calculates the derivative of propagation length.
double dFic_de
Cerenkov azimuthal angle over photon energy.
double dLen_de
propagation length over photon energy
Derivatives()
Default constructor.
double dFic_dx
Cerenkov azimuthal angle over photon detection coordinate x.
double dFic_dL
Cerenkov azimuthal angle over running parameter of particle trajectory.
double dLen_dL
propagation length over running parameter of particle trajectory
double dyB_de
unfolded y coordinate at prism entrance over photon energy
double dLen_dx
propagation length over photon detection coordinate x
double dyB_dL
unfolded y coordinate at prism entrance over running parameter of particle trajectory
double dyB_dx
unfolded y coordinate at prism entrance over photon detection coordinate x
static double dFic_d(const InverseRaytracer::Solution &sol0, const InverseRaytracer::Solution &sol1)
Calculates the derivative of Cerenkov azimuthal angle.
Down-stream projection of a pixel to prism entrance window w/ a clip on bar exit thickness.
Geometry-only quantities needed to project a pixel to a given unfolded prism exit window.
double sz
window surface direction in z
double z0
z of the window origin, displaced to the prism entrance plane
bool evenReflection
true if the window has the same orientation as the true one
double sy
window surface direction in y
double y0
y of the window origin, displaced to the prism entrance plane