Belle II Software development
ARICHReconstruction.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#include "arich/modules/arichReconstruction/ARICHReconstruction.h"
10#include "arich/dbobjects/ARICHGeometryConfig.h"
11#include "arich/modules/arichReconstruction/Utility.h"
12#include "arich/dataobjects/ARICHHit.h"
13#include "arich/dataobjects/ARICHTrack.h"
14#include "arich/dataobjects/ARICHPhoton.h"
15
16// DataStore
17#include <framework/datastore/StoreArray.h>
18
19// framework aux
20#include <framework/logging/Logger.h>
21#include <framework/gearbox/Const.h>
22#include <framework/geometry/VectorUtil.h>
23
24#include <cmath>
25#include <vector>
26#include <Math/Vector3D.h>
27#include <TRandom3.h>
28
29using namespace boost;
30
31namespace Belle2 {
37 using namespace arich;
38
40 m_arichgp(),
41 m_recPars(),
42 m_trackPosRes(0),
43 m_trackAngRes(0),
44 m_alignMirrors(true),
45 m_nAerogelLayers(0),
46 m_storePhot(storePhot)
47 {
48 for (unsigned i = 0; i < c_noOfHypotheses; i++) {p_mass[i] = 0;}
49 for (unsigned i = 0; i < c_noOfAerogels; i++) {
50 m_refractiveInd[i] = 0;
51 m_zaero[i] = 0;
52 m_thickness[i] = 0;
53 m_transmissionLen[i] = 0;
54 m_n0[i] = 0;
55 m_anorm[i] = ROOT::Math::XYZVector();
56 }
57
58 }
59
61 {
62
63 for (const auto& part : Const::chargedStableSet) {
64 p_mass[part.getIndex()] = part.getMass();
65 }
66
67 m_nAerogelLayers = m_arichgp->getAerogelPlane().getNLayers();
69 for (unsigned int i = 0; i < m_nAerogelLayers; i++) {
70 m_refractiveInd[i] = m_arichgp->getAerogelPlane().getLayerRefIndex(i + 1);
71 m_anorm[i] = ROOT::Math::XYZVector(0, 0, 1);
72 m_thickness[i] = m_arichgp->getAerogelPlane().getLayerThickness(i + 1);
73 if (i == 0) m_zaero[i] = m_arichgp->getAerogelPlane().getAerogelZPosition() + m_thickness[i];
74 else m_zaero[i] = m_zaero[i - 1] + m_thickness[i];
75
76 m_transmissionLen[i] = m_arichgp->getAerogelPlane().getLayerTrLength(i + 1) ; // aerogel transmission length;
77
78 // measured FOM; aeroMerit is number of detected photons for beam of beta=1 and perpedicular incidence to aerogel tile
79 // (corrected for geometrical acceptance). n0[i] is then calculated from
80 // aeroMerit[i]=n0[i]*sin2(thc)*transmissionLen[i] * (1 - exp(-thickness[i] / transmissionLen[i])
81 m_n0[i] = m_recPars->getAerogelFOM(i) / ((1. - 1. / m_refractiveInd[i] / m_refractiveInd[i]) * m_transmissionLen[i] * (1 - exp(
84 }
86 m_refractiveInd[m_nAerogelLayers + 1] = m_arichgp->getHAPDGeometry().getWinRefIndex();
87 m_zaero[m_nAerogelLayers ] = m_arichgp->getDetectorZPosition();
88 m_zaero[m_nAerogelLayers + 1] = m_zaero[m_nAerogelLayers] + m_arichgp->getHAPDGeometry().getWinThickness();
89
90 if (m_mirrAlign.hasChanged()) {
91 m_mirrorNorms.clear();
92 m_mirrorPoints.clear();
93 for (unsigned i = 1; i < m_arichgp->getMirrors().getNMirrors() + 1; i++) {
94 m_mirrorNorms.push_back(getMirrorNorm(i));
95 m_mirrorPoints.push_back(getMirrorPoint(i));
96 }
97 }
98
99 if (m_tileAlign) {
100 if (m_tileAlign.hasChanged()) {
101 for (int iTile = 1; iTile < 125; iTile++) {
102 m_tilePars[iTile - 1][0] = m_tileAlign->getAlignmentElement(iTile).getAlpha();
103 m_tilePars[iTile - 1][1] = m_tileAlign->getAlignmentElement(iTile).getBeta();
104 }
105 }
106 }
107 }
108
109
110 int ARICHReconstruction::InsideDetector(ROOT::Math::XYZVector a, int copyno)
111 {
112 if (copyno == -1) return 0;
113 ROOT::Math::XYVector origin;
114 origin.SetXY(m_arichgp->getDetectorPlane().getSlotR(copyno) * std::cos(m_arichgp->getDetectorPlane().getSlotPhi(copyno)),
115 m_arichgp->getDetectorPlane().getSlotR(copyno) * std::sin(m_arichgp->getDetectorPlane().getSlotPhi(copyno)));
116 ROOT::Math::XYVector a2(a);
117 double phi = m_arichgp->getDetectorPlane().getSlotPhi(copyno);
118 ROOT::Math::XYVector diff = a2 - origin;
119 diff.Rotate(-phi);
120 const double size = m_arichgp->getHAPDGeometry().getAPDSizeX();
121 if (fabs(diff.X()) < size / 2. && fabs(diff.Y()) < size / 2.) {
122 int chX, chY;
123 m_arichgp->getHAPDGeometry().getXYChannel(diff.X(), diff.Y(), chX, chY);
124 if (chX < 0 || chY < 0) return 0;
125 int asicChannel = m_chnMap->getAsicFromXY(chX, chY);
126 // eliminate un-active channels
127 if (asicChannel < 0 || !m_chnMask->isActive(copyno, asicChannel)) return 0;
128 return 1;
129 }
130 return 0;
131 }
132
133
135 {
136 double a = gRandom->Gaus(0, m_trackAngRes);
137 double b = gRandom->Gaus(0, m_trackAngRes);
138 ROOT::Math::XYZVector dirf(a, b, sqrt(1 - a * a - b * b));
139 double dx = gRandom->Gaus(0, m_trackPosRes);
140 double dy = gRandom->Gaus(0, m_trackPosRes);
141 ROOT::Math::XYZVector mod(dx, dy, 0);
142 ROOT::Math::XYZVector rpoint = arichTrack.getPosition() + mod;
143 ROOT::Math::XYZVector odir = arichTrack.getDirection();
144 double omomentum = arichTrack.getMomentum();
145 ROOT::Math::XYZVector rdir = TransformFromFixed(odir) * dirf; // global system
146 double rmomentum = omomentum;
147 arichTrack.setReconstructedValues(rpoint, ROOT::Math::XYZVector(rdir), rmomentum);
148 return 1;
149 }
150
151
152 ROOT::Math::XYZVector ARICHReconstruction::FastTracking(ROOT::Math::XYZVector dirf, ROOT::Math::XYZVector r,
153 double* refractiveInd, double* z, int n, int opt)
154 {
155 //
156 // Description:
157 // The method calculates the intersection of the cherenkov photon
158 // with the detector plane
159
160 // z[n+1]
161 // z[0] .. 1st aerogel exit
162 // z[n-1] .. 2nd aerogel exit
163
164 double angmir = 0; int section[2] = {0, 0};
165
166 unsigned tileID = m_arichgp->getAerogelPlane().getAerogelTileID(r.X(), r.Y());
167
168 if (tileID == 0 && opt == 1) return ROOT::Math::XYZVector();
169
170 int nmir = m_arichgp->getMirrors().getNMirrors();
171 if (nmir > 0) {
172 double dangle = 2 * M_PI / nmir;
173 angmir = m_arichgp->getMirrors().getStartAngle() - dangle / 2.;
174
175 double trkangle = r.Phi() - angmir;
176 if (trkangle < 0) trkangle += 2 * M_PI;
177 if (trkangle > 2 * M_PI) trkangle -= 2 * M_PI;
178
179 section[1] = int(trkangle / dangle) + 1;
180 }
181
182 bool reflok = false; bool refl = false;
183 double path = (z[0] - r.Z()) / dirf.Z();
184 r += dirf * path;
185 for (int a = 1; a <= n + 1 ; a++) {
186 double rind = refractiveInd[a] / refractiveInd[a - 1];
187 dirf = Refraction(dirf, rind);
188 if (dirf.R() == 0) return ROOT::Math::XYZVector();
189 path = (z[a] - r.Z()) / dirf.Z();
190 ROOT::Math::XYZVector r0 = r;
191 if (a == n && opt == 1) {
192 if (m_arichgp->getAerogelPlane().getAerogelTileID(r.X(), r.Y()) != tileID) return ROOT::Math::XYZVector();
193 }
194 r += dirf * path;
195 ROOT::Math::XYVector rxy(r);
196 // check for possible reflections
197 if (a != n || nmir == 0) continue;
198 double angle = rxy.Phi() - angmir;
199 if (angle < 0) angle += 2 * M_PI;
200 if (angle > 2 * M_PI) angle -= 2 * M_PI;
201 double dangle = 2 * M_PI / nmir;
202 section[0] = int(angle / dangle) + 1;
203 if (r.R() > (r - 2 * m_mirrorPoints[section[0] - 1]).R()) {
204 refl = true;
205 int nrefl = 2;
206 if (section[0] == section[1]) nrefl = 1;
207 for (int k = 0; k < nrefl; k++) {
208 if (!HitsMirror(r0, dirf, section[k])) continue;
209 ROOT::Math::XYZVector mirpoint = m_mirrorPoints[section[k] - 1];
210 ROOT::Math::XYZVector mirnorm = m_mirrorNorms[section[k] - 1];
211 double s = dirf.Dot(mirnorm);
212 double s1 = (mirpoint - r0).Dot(mirnorm);
213 r = r0 + s1 / s * dirf;
214 dirf = dirf - 2 * (dirf.Dot(mirnorm)) * mirnorm;
215 path = (z[a] - r.Z()) / dirf.Z();
216 r += dirf * path;
217 reflok = true;
218 break;
219 }
220 }
221 }
222
223 if (!reflok && refl) return ROOT::Math::XYZVector();
224 return r;
225 }
226
227 ROOT::Math::XYZVector ARICHReconstruction::HitVirtualPosition(const ROOT::Math::XYZVector& hitpos, int mirrorID)
228 {
229
230 if (mirrorID == 0) return hitpos;
231 ROOT::Math::XYZVector mirpoint = m_mirrorPoints[mirrorID - 1];
232 ROOT::Math::XYZVector mirnorm = m_mirrorNorms[mirrorID - 1];
233 return hitpos - 2 * ((hitpos - mirpoint).Dot(mirnorm)) * mirnorm;
234 }
235
236
237 bool ARICHReconstruction::HitsMirror(const ROOT::Math::XYZVector& pos, const ROOT::Math::XYZVector& dir, int mirrorID)
238 {
239
240 ROOT::Math::XYZVector mirnorm = m_mirrorNorms[mirrorID - 1];
241 ROOT::Math::XYZVector mirpoint = m_mirrorPoints[mirrorID - 1];
242 ROOT::Math::Rotation3D rot = TransformToFixed(mirnorm);
243 ROOT::Math::XYZVector dirTr = rot * dir;
244 if (dirTr.Z() < 0) return 0; // comes from outer side
245 ROOT::Math::XYZVector posTr = rot * (pos - mirpoint);
246 ROOT::Math::XYZVector pointOnMirr = posTr - (posTr.Z() / dirTr.Z()) * dirTr;
247 if (fabs(pointOnMirr.Y()) < m_arichgp->getMirrors().getPlateLength() / 2.
248 && fabs(pointOnMirr.X()) < m_arichgp->getMirrors().getPlateWidth() / 2.) return 1;
249
250 return 0;
251 }
252
253
254 int ARICHReconstruction::CherenkovPhoton(ROOT::Math::XYZVector r, ROOT::Math::XYZVector rh,
255 ROOT::Math::XYZVector& rf, ROOT::Math::XYZVector& dirf,
256 double* refractiveInd, double* z, int n, int mirrorID)
257 {
258 //
259 // Description:
260 // The method calculates the direction of the cherenkov photon
261 // and intersection with the aerogel exit point
262 //
263 // Called by: CerenkovAngle
264
265
266 // Arguments:
267 // Input:
268 // dir, r track position
269 // rh photon hit
270
271
272 // Output:
273 // rf aerogel exit from which the photon was emitted
274 // dirf photon direction in aerogel
275 static ROOT::Math::XYZVector norm(0, 0, 1); // detector plane normal vector
276
277 double dwin = m_arichgp->getHAPDGeometry().getWinThickness();
278 double refractiveInd0 = m_arichgp->getHAPDGeometry().getWinRefIndex();
279
280 // iteration is stopped when the difference of photon positions on first aerogel exit
281 // between two iterations is smaller than this value.
282 const double dmin = 0.0000001;
283 const int niter = 100; // maximal number of iterations
284 ROOT::Math::XYZVector dirw;
285 ROOT::Math::XYZVector rh1 = rh - dwin * norm;
286
287 std::vector <ROOT::Math::XYZVector > rf0(n + 2);
288 // rf0[0] .. track point
289 // rf0[1] 1. 1st aerogel exit
290 // rf0[n] n. aerogel exit ...
291 std::vector <ROOT::Math::XYZVector > dirf0(n + 2);
292 // dirf0[0] .. 1st aerogel direction
293 // dirf0[1] .. 2nd aerogel direction
294 // dirf0[n] .. direction after aerogels
295
296 // z[0] .. 1st aerogel exit
297 // z[n-1] .. 2nd aerogel exit
298 // z[n] .. detector position
299 // z[n+1] .. detector + window
300
301 rf0[0] = r;
302 rf0[1] = rf;
303
304 for (int iter = 0; iter < niter; iter++) {
305
306 // direction in the space between aerogels and detector
307 // *************************************
308 if (iter == 0) dirf0[n] = (rh1 - rf0[1]).Unit();
309 else dirf0[n] = (rh1 - rf0[n]).Unit();
310
311 // *************************************
312 // n-layers of aerogel // refractiveInd relative refractive index
313 for (int a = n - 1; a >= 0 ; a--) {
314 double rind = refractiveInd[a] / refractiveInd[a + 1];
315 dirf0[a] = Refraction(dirf0[a + 1], rind);
316 }
317
318 double path = (z[0] - r.Z()) / dirf0[0].Z();
319 double x1 = rf0[1].X();
320 double y1 = rf0[1].Y();
321 for (int a = 0; a < n ; a++) {
322 rf0[a + 1] = rf0[a] + dirf0[a] * path;
323 path = (z[a + 1] - rf0[a + 1].Z()) / dirf0[a + 1].Z();
324 }
325
326 Refraction(dirf0[n], norm, refractiveInd0, dirw);
327
328 // *************************************
329
330 path = dwin / (dirw.Dot(norm));
331 rh1 = rh - dirw * path;
332
333 double d2 = (rf0[1].X() - x1) * (rf0[1].X() - x1) + (rf0[1].Y() - y1) * (rf0[1].Y() - y1);
334
335 if ((d2 < dmin) && (iter)) {
336
337 // if mirror hypothesis check if reflection point lies on mirror plate
338 if (mirrorID) {
339 if (!HitsMirror(rf0[n], dirf0[n], mirrorID)) return -1;
340 }
341
342 rf = rf0[1];
343 dirf = dirf0[0];
344 return iter;
345 }
346 }
347 return -1;
348 }
349
351 ARICHLikelihood& arichLikelihood)
352 {
353
354 const unsigned int nPhotonHits = arichHits.getEntries(); // number of detected photons
355
356 if (m_nAerogelLayers + 1 > c_noOfAerogels) B2ERROR("ARICHReconstrucion: number of aerogel layers defined in the xml file exceeds "
357 << c_noOfAerogels);
358
359 double logL[c_noOfHypotheses] = {0.0};
360 double nSig_w_acc[c_noOfHypotheses][c_noOfAerogels] = { {0.0} }; // expected no. of signal photons, including geometrical acceptance
361 double nSig_wo_acc[c_noOfHypotheses][c_noOfAerogels][20] = { { {0.0} } }; // expected no. of signal photons, without geometrical acceptance, divided in 20 phi bins (used for PDF normalization)
362 double nSig_wo_accInt[c_noOfHypotheses][c_noOfAerogels] = { {0.0} }; // expected no. of signal photons, without geometrical acceptance, integrated over phi
363 double esigi[c_noOfHypotheses] = {0.0}; // expected number of signal photons in hit pixel
364 double thetaCh[c_noOfHypotheses][c_noOfAerogels] = { {0.0} }; // expected Cherenkov angle
365
366 // read some geometry parameters
367 double padSize = m_arichgp->getHAPDGeometry().getPadSize();
368 int nMirSeg = m_arichgp->getMirrors().getNMirrors();
369 double angmir = m_arichgp->getMirrors().getStartAngle();
370
371 // Detected photons in cherenkov ring (integrated over 0.1<theta<0.5)
372 int nDetPhotons = 0;
373
374 double ebgri[c_noOfHypotheses] = {0.0}; // number of expected background photons per pad
375 double nBgr[c_noOfHypotheses] = {0.0}; // total number of expected background photons (in 0.1-0.5 rad ring)
376
377 // reconstructed track direction
378 ROOT::Math::XYZVector edir = arichTrack.getDirection();
379 if (edir.Z() < 0) return 0;
380 double momentum = arichTrack.getMomentum();
381
382 double thcResolution = m_recPars->getThcResolution(momentum);
383 if (thcResolution < 0) thcResolution = 0.01; // happens for spurious tracks with 100 GeV momentum!
384
385 double wideGaussFract = (m_recPars->getParameters())[0];
386 double wideGaussSigma = (m_recPars->getParameters())[1];
387
388 unsigned tileID = m_arichgp->getAerogelPlane().getAerogelTileID(arichTrack.getPosition().X(), arichTrack.getPosition().Y());
389 double r = arichTrack.getPosition().Rho();
390 if (tileID > 0) correctEmissionPoint(tileID, r);
391
392 //------------------------------------------------------
393 // Calculate number of expected detected photons (emitted x geometrical acceptance).
394 // -----------------------------------------------------
395
396 float nphot_scaling = 20.; // number of photons to be traced is (expected number of emitted photons * nphot_scaling)
397 int nStep = 5; // number of steps in one aerogel layer
398
399 // loop over all particle hypotheses
400 for (int iHyp = 0; iHyp < c_noOfHypotheses; iHyp++) {
401
402 // absorption factor (scattering)
403 double abs = 1;
404
405 // loop over aerogel layers
406 for (int iAerogel = m_nAerogelLayers - 1; iAerogel >= 0; iAerogel--) {
407
408 thetaCh[iHyp][iAerogel] = ExpectedCherenkovAngle(momentum,
409 p_mass[iHyp],
410 m_refractiveInd[iAerogel]);
411
412 // track length in the radiator
413 double pathLengthRadiator = arichTrack.getDirection().Dot(m_anorm[iAerogel]);
414 if (pathLengthRadiator) pathLengthRadiator = m_thickness[iAerogel] / pathLengthRadiator;
415
416 // step length
417 double dxx = pathLengthRadiator / double(nStep);
418 // number of photons to be emitted per step (number of expected photons * nphot_scaling)
419 double nPhot = m_n0[iAerogel] * sin(thetaCh[iHyp][iAerogel]) * sin(thetaCh[iHyp][iAerogel]) * dxx * nphot_scaling;
420 ROOT::Math::XYZVector exit_point = getTrackPositionAtZ(arichTrack, m_zaero[iAerogel]);
421
422 // loop over emission point steps
423 for (int iepoint = 0; iepoint < nStep; iepoint++) {
424
425 ROOT::Math::XYZVector epoint = exit_point - (0.5 + iepoint) * dxx * edir;
426 abs *= exp(-dxx / m_transmissionLen[iAerogel]);
427 unsigned int genPhot = nPhot * abs; // number of photons to emit in current step, including scattering correction
428
429 // loop over emitted "photons"
430 for (unsigned int iPhoton = 0; iPhoton < genPhot; iPhoton++) {
431 double fi = 2 * M_PI * iPhoton / float(genPhot); // uniformly distributed in phi
432 ROOT::Math::XYZVector adirf = setThetaPhi(thetaCh[iHyp][iAerogel], fi); // photon direction in track system
433 adirf = TransformFromFixed(edir) * adirf; // photon direction in global system
434 int ifi = int (fi * 20 / 2. / M_PI); // phi bin
435 // track photon from emission point to the detector plane
436 ROOT::Math::XYZVector dposition = FastTracking(adirf, epoint, &m_refractiveInd[iAerogel], &m_zaero[iAerogel],
437 m_nAerogelLayers - iAerogel, 1);
438 if (dposition.R() > 1.0) {nSig_wo_acc[iHyp][iAerogel][ifi] += 1; nSig_wo_accInt[iHyp][iAerogel] += 1;}
439 else continue;
440 unsigned copyno = m_arichgp->getDetectorPlane().pointSlotID(dposition.X(), dposition.Y());
441 if (!copyno) continue;
442 // check if photon fell on photosensitive area
443 if (InsideDetector(dposition, copyno)) nSig_w_acc[iHyp][iAerogel] += 1;
444 }
445 }
446
447 // scale the obtained numbers
448 for (int ik = 0; ik < 20; ik++) {
449 nSig_wo_acc[iHyp][iAerogel][ik] /= nphot_scaling;
450 }
451 nSig_w_acc[iHyp][iAerogel] /= nphot_scaling;
452 nSig_wo_accInt[iHyp][iAerogel] /= nphot_scaling;
453 } // for (unsigned int iAerogel=0;iAerogel<m_nAerogelLayers;iAerogel++)
454
455 // sum up contribution from all aerogel layers
456 for (unsigned int iAerogel = 0; iAerogel < m_nAerogelLayers; iAerogel++) {
457 nSig_w_acc[iHyp][m_nAerogelLayers] += nSig_w_acc[iHyp][iAerogel];
458 nSig_wo_accInt[iHyp][m_nAerogelLayers] += nSig_wo_accInt[iHyp][iAerogel];
459
460 for (int ik = 0; ik < 20; ik++) {
461 nSig_wo_acc[iHyp][m_nAerogelLayers][ik] += nSig_wo_acc[iHyp][iAerogel][ik];
462 }
463 }
464
465 // get number of expected background photons in ring (integrated from 0.1 to 0.5 rad)
466 std::vector<double> bkgPars = {momentum / sqrt(p_mass[iHyp]*p_mass[iHyp] + momentum * momentum), double(arichTrack.hitsWindow())};
467 nBgr[iHyp] = m_recPars->getExpectedBackgroundHits(bkgPars);
468
469 } // for (int iHyp=0;iHyp < c_noOfHypotheses; iHyp++ )
470 //#####################################################
471
472 ROOT::Math::XYZVector track_at_detector = getTrackPositionAtZ(arichTrack, m_zaero[m_nAerogelLayers + 1]);
473
474 // the id numbers of mirrors from which the photons could possibly reflect are calculated
475 int mirrors[3];
476 mirrors[0] = 0; // for no reflection
477 int refl = 1;
478
479 // only if particle track on detector is at radius larger than 850mm (for now hardcoded)
480 // possible reflections are taken into account.
481 if (track_at_detector.Rho() > 85.0) {
482 double trackang = track_at_detector.Phi() - angmir;
483 if (trackang < 0) trackang += 2 * M_PI;
484 if (trackang > 2 * M_PI) trackang -= 2 * M_PI;
485 int section1 = int(trackang * nMirSeg / 2. / M_PI) + 1;
486 int section2 = section1 + 1;
487 if (section1 == nMirSeg) section2 = 1;
488 mirrors[1] = section1; mirrors[2] = section2;
489 refl = 3;
490 }
491
492 // loop over all detected photon hits
493
494 for (unsigned int iPhoton = 0; iPhoton < nPhotonHits; iPhoton++) {
495
496 ARICHHit* h = arichHits[iPhoton];
497 int modID = h->getModule();
498 int channel = h->getChannel();
499 ROOT::Math::XYZVector hitpos = m_arichgp->getMasterVolume().pointToLocal(h->getPosition());
500 bool bkgAdded = false;
501 int nfoo = nDetPhotons;
502 for (int iHyp = 0; iHyp < c_noOfHypotheses; iHyp++) { esigi[iHyp] = 0; ebgri[iHyp] = 0;}
503
504 bool reflOK = true; // remove window photons from reflected hypothesis
505
506 // loop over possible mirror reflections
507 for (int mirr = 0; mirr < refl; mirr++) {
508
509 if (!reflOK) break; // photon from window so break
510
511 // calculate fi_ch for a given track refl
512 ROOT::Math::XYZVector virthitpos = HitVirtualPosition(hitpos, mirrors[mirr]);
513
514 // if hit is more than 25cm from the track position on the detector plane, skip it.
515 // (not reconstructing hits with irrelevantly large Cherenkov angle)
516 if ((track_at_detector - virthitpos).R() > 25.0) continue;
517
518 double sigExpArr[c_noOfHypotheses] = {0.0}; // esigi for given mirror hypothesis only
519 double th_cer_all[c_noOfAerogels] = {0.0};
520 double fi_cer_all[c_noOfAerogels] = {0.0};
521
522 double weight[c_noOfHypotheses][c_noOfAerogels] = { {0.0} };
523 double weight_sum[c_noOfHypotheses] = {0.0};
524 int proc = 0;
525 double fi_cer_trk = 0.;
526
527 // loop over all aerogel layers
528 for (unsigned int iAerogel = 0; iAerogel < m_nAerogelLayers; iAerogel++) {
529
530 ROOT::Math::XYZVector initialrf = getTrackPositionAtZ(arichTrack, m_zaero[iAerogel]);
531 ROOT::Math::XYZVector epoint = getTrackMeanEmissionPosition(arichTrack, iAerogel);
532 ROOT::Math::XYZVector edirr = arichTrack.getDirection();
533 ROOT::Math::XYZVector photonDirection; // calculated photon direction
534
535 if (CherenkovPhoton(epoint, virthitpos, initialrf, photonDirection, &m_refractiveInd[iAerogel], &m_zaero[iAerogel],
536 m_nAerogelLayers - iAerogel, mirrors[mirr]) < 0) break;
537
538 ROOT::Math::XYZVector dirch = TransformToFixed(edirr) * photonDirection;
539 double fi_cer = dirch.Phi();
540 double th_cer = dirch.Theta();
541
542
543 th_cer_all[iAerogel] = th_cer;
544 fi_cer_all[iAerogel] = fi_cer;
545 auto deltaPhi = dirch.Phi() - edir.Phi();
546 if (deltaPhi > M_PI)
547 deltaPhi -= 2 * M_PI;
548 if (deltaPhi < -M_PI)
549 deltaPhi += 2 * M_PI;
550 fi_cer_trk = deltaPhi;
551
552 if (mirr == 0 && th_cer < 0.1) reflOK = false;
553 // skip photons with irrelevantly large/small Cherenkov angle
554 if (th_cer > 0.5 || th_cer < 0.1) continue;
555
556 // count photons with 0.1<thc<0.5
557 if (nfoo == nDetPhotons) nDetPhotons++;
558
559 if (fi_cer < 0) fi_cer += 2 * M_PI;
560 double fii = fi_cer;
561 if (mirr > 0) {
562 double fi_mir = m_mirrorNorms[mirrors[mirr] - 1].Phi();
563 fii = 2 * fi_mir - fi_cer - M_PI;
564 }
565
566
567 // loop over all particle hypotheses
568 for (int iHyp = 0; iHyp < c_noOfHypotheses; iHyp++) {
569
570 // track a photon from the mean emission point to the detector surface
571 ROOT::Math::XYZVector photonDirection1 = setThetaPhi(thetaCh[iHyp][iAerogel], fi_cer); // particle system
572 photonDirection1 = TransformFromFixed(edirr) * photonDirection1; // global system
573 int ifi = int (fi_cer * 20 / 2. / M_PI);
574 ROOT::Math::XYZVector detector_position;
575
576 detector_position = FastTracking(photonDirection1, epoint, &m_refractiveInd[iAerogel], &m_zaero[iAerogel],
577 m_nAerogelLayers - iAerogel, 0);
578
579 ROOT::Math::XYZVector meanr = detector_position - epoint;
580 double path = meanr.R();
581 meanr = meanr.Unit();
582
583 double meanpath = (m_recPars->getParameters())[2];
584 if (iAerogel == 1) meanpath = meanpath - m_thickness[iAerogel];
585
586 double detector_sigma = thcResolution * meanpath / meanr.Z();
587 double wide_sigma = wideGaussSigma * path / meanr.Z();
588 // calculate pad orientation and distance relative to that photon
589 double modphi = m_arichgp->getDetectorPlane().getSlotPhi(modID);
590
591 double pad_fi = fii - modphi;
592 double dx = (detector_position - hitpos).R();
593 double dr = (track_at_detector - detector_position).R();
594
595 if (dr > 0.01) {
596 double normalizacija = nSig_wo_acc[iHyp][iAerogel][ifi] * padSize / (0.1 * M_PI * dr * meanr.Z());
597 weight[iHyp][iAerogel] = normalizacija;
598 weight_sum[iHyp] += weight[iHyp][iAerogel];
599 double integralMain = SquareInt(padSize, pad_fi, dx, detector_sigma) / sqrt(2.);
600 double integralWide = SquareInt(padSize, pad_fi, dx, wide_sigma) / sqrt(2.);
601 // expected number of signal photons in each pixel
602 double exp = normalizacija * ((1 - wideGaussFract) * integralMain + wideGaussFract * integralWide);
603 esigi[iHyp] += exp;
604 sigExpArr[iHyp] += exp;
605 } // if (dr>0 && thetaCh[iHyp][iAerogel])
606
607 }// for (int iHyp=0;iHyp< c_noOfHypotheses; iHyp++)
608 if (iAerogel == m_nAerogelLayers - 1) proc = 1; // successfully processed for all layers
609 }// for (unsigned int iAerogel=0; iAerogel<m_nAerogelLayers;iAerogel++)
610
611 if (proc) {
612 // add background contribution if not yet (add only once)
613 if (!bkgAdded) {
614 for (int iHyp = 0; iHyp < c_noOfHypotheses; iHyp++) {
615 std::vector<double> pars = {momentum / sqrt(p_mass[iHyp]*p_mass[iHyp] + momentum * momentum), double(arichTrack.hitsWindow())};
616 ebgri[iHyp] += m_recPars->getBackgroundPerPad(th_cer_all[1], pars);
617 }
618 bkgAdded = true;
619 }
620 }
621 // create ARICHPhoton if desired
622 if (m_storePhot && th_cer_all[1] > 0 && th_cer_all[1] < 0.6) {
623 double n_cos_theta_ch[c_noOfHypotheses] = {0.0};
624 double phi_ch[c_noOfHypotheses] = {0.0};
625 for (int iHyp = 0; iHyp < c_noOfHypotheses; iHyp++) {
626 if (weight_sum[iHyp] > 0) {
627 for (unsigned int iAerogel = 0; iAerogel < m_nAerogelLayers; iAerogel++) {
628 double emission_prob = weight[iHyp][iAerogel] / weight_sum[iHyp];
629 n_cos_theta_ch[iHyp] += emission_prob * m_refractiveInd[iAerogel] * cos(th_cer_all[iAerogel]);
630 phi_ch[iHyp] += emission_prob * fi_cer_all[iAerogel];
631 }
632 //std::cout << iHyp << " " << n_cos_theta_ch[iHyp] << " " << phi_ch[iHyp] << std::endl;
633 } else {
634 n_cos_theta_ch[iHyp] = -99999.;
635 phi_ch[iHyp] = -99999.;
636 }
637 }
638 ARICHPhoton phot(iPhoton, th_cer_all[1], fi_cer_all[1], mirrors[mirr]); // th_cer of the first aerogel layer assumption is stored
639 phot.setBkgExp(ebgri); // store expected number of background hits
640 phot.setSigExp(sigExpArr); // store expected number of signal hits
641 phot.setPhiCerTrk(fi_cer_trk); // store phi angle in track coordinates
642 phot.setNCosThetaCh(n_cos_theta_ch); // store n cos(theta_th) for all particle hypotheses
643 phot.setPhiCh(phi_ch); // store phi_ch for all particle hypotheses
644 phot.setXY(hitpos.X(), hitpos.Y()); // store x-y hit position
645 phot.setModuleID(modID); // store module id
646 phot.setChannel(channel); // store channel
647 arichTrack.addPhoton(phot);
648 }
649
650
651 }// for (int mirr = 0; mirr < refl; mirr++)
652
653 //******************************************
654 // LIKELIHOOD construction
655 //*******************************************
656
657 for (int iHyp = 0; iHyp < c_noOfHypotheses; iHyp++) {
658 double expected = esigi[iHyp] + ebgri[iHyp];
659 if (bkgAdded) logL[iHyp] += expected + log(1 - exp(-expected));
660 }
661
662 } // for (unsigned int iPhoton=0; iPhoton< nPhotonHits; iPhoton++)
663
664 //*********************************************
665 // add constant term to the LIKELIHOOD function
666 //*********************************************
667 double exppho[c_noOfHypotheses] = {0.0};
668 for (int iHyp = 0; iHyp < c_noOfHypotheses; iHyp++) {
669 exppho[iHyp] = nSig_w_acc[iHyp][m_nAerogelLayers] * (1 - wideGaussFract) + wideGaussFract * 0.7 *
670 nSig_wo_accInt[iHyp][m_nAerogelLayers] + nBgr[iHyp];
671 logL[iHyp] -= exppho[iHyp];
672 if (std::isnan(logL[iHyp]) || std::isinf(logL[iHyp])) {
673 B2WARNING("ARICHReconstruction: log likelihood value infinite! Flat background hit probability is " << ebgri[iHyp] << "!");
674 logL[iHyp] = 0;
675 }
676 }
677
678 //******************************************
679 // store LikeliHOOD info
680 //******************************************
681
682 int flag = 1;
683 if ((thetaCh[0][0] > 0 || thetaCh[0][1] > 0) && nSig_w_acc[0][m_nAerogelLayers] == 0) flag = 0;
684
685 // set values of ARICHLikelihood
686 arichLikelihood.setValues(flag, logL, nDetPhotons, exppho);
687
688 return 1;
689 }
690
692 {
693 m_trackPosRes = pRes;
694 }
696 {
697 m_trackAngRes = aRes;
698 }
699
700 ROOT::Math::XYZVector ARICHReconstruction::getTrackMeanEmissionPosition(const ARICHTrack& track, int iAero)
701 {
702 // Emission length measured from aerogel exit
703
704 ROOT::Math::XYZVector dir = track.getDirection();
705 if (dir.Z() == 0) return ROOT::Math::XYZVector();
706 double d = m_thickness[iAero] / dir.Z() / m_transmissionLen[iAero];
707 double dmean = 1 - d / expm1(d);
708 //double dmean = -log((1 + exp(-d)) / 2.);
709 double mel = dmean * m_transmissionLen[iAero];
710
711 return (getTrackPositionAtZ(track, m_zaero[iAero]) - mel * dir);
712 }
713
714 ROOT::Math::XYZVector ARICHReconstruction::getTrackPositionAtZ(const ARICHTrack& track, double zout)
715 {
716 ROOT::Math::XYZVector dir = track.getDirection();
717 ROOT::Math::XYZVector pos = track.getPosition();
718 if (dir.Z() == 0) return ROOT::Math::XYZVector(0, 0, 0);
719 double path = (zout - pos.Z()) / dir.Z();
720 return pos + dir * path;
721 }
722
724 {
725 // transform track from Belle II to local ARICH frame
726 ROOT::Math::XYZVector locPos = m_arichgp->getMasterVolume().pointToLocal(arichTrack.getPosition());
727 ROOT::Math::XYZVector locDir = m_arichgp->getMasterVolume().momentumToLocal(arichTrack.getDirection());
728
729 // apply the alignment correction
730 if (align && m_alignp.isValid()) {
731 // apply global alignment correction
732 locPos = m_alignp->pointToLocal(locPos);
733 locDir = m_alignp->momentumToLocal(locDir);
734 }
735
736 // set parameters and return
737 // is it needed to extrapolate to z of aerogel in local frame?? tabun
738 arichTrack.setReconstructedValues(locPos, locDir, arichTrack.getMomentum());
739 return;
740 }
741
742
743 ROOT::Math::XYZVector ARICHReconstruction::getMirrorPoint(int mirrorID)
744 {
745
746 ROOT::Math::XYZVector mirpoint = m_arichgp->getMirrors().getPoint(mirrorID);
747 if (m_alignMirrors && m_mirrAlign.isValid()) mirpoint += m_mirrAlign->getAlignmentElement(mirrorID).getTranslation();
748 return mirpoint;
749
750 }
751
752 ROOT::Math::XYZVector ARICHReconstruction::getMirrorNorm(int mirrorID)
753 {
754 if (m_alignMirrors && m_mirrAlign.isValid()) {
755
756 ROOT::Math::XYZVector mirnorm = m_arichgp->getMirrors().getNormVector(mirrorID);
757
758 VectorUtil::setMagThetaPhi(mirnorm,
759 mirnorm.R(),
760 mirnorm.Theta() + m_mirrAlign->getAlignmentElement(mirrorID).getAlpha(),
761 mirnorm.Phi() + m_mirrAlign->getAlignmentElement(mirrorID).getBeta());
762
763 return mirnorm;
764
765 }
766 return m_arichgp->getMirrors().getNormVector(mirrorID);
767 }
768
770 {
771
772 double ang = m_tilePars[tileID - 1][0] + m_tilePars[tileID - 1][1] * r;
773 m_zaero[0] = m_arichgp->getAerogelPlane().getAerogelZPosition() + m_thickness[0] - ang * 50.;
774 m_zaero[1] = m_zaero[0] + m_thickness[1];
775
776 }
777
779}
double R
typedef autogenerated by FFTW
Datastore class that holds photon hits. Input to the reconstruction.
Definition: ARICHHit.h:23
This is a class to store ARICH likelihoods in the datastore.
void setValues(int flag, const double *logL, int detPhot, const double *expPhot)
Set values.
Struct for ARICH reconstructed photon (hit related to track) information.
Definition: ARICHPhoton.h:25
void setXY(float x, float y)
Set X-Y position of hit.
Definition: ARICHPhoton.h:64
void setBkgExp(const double *bkgExp)
Set expected background contribution.
Definition: ARICHPhoton.h:104
void setChannel(int chn)
set channel (asic) of hit
Definition: ARICHPhoton.h:81
void setNCosThetaCh(const double *n_cos_theta_ch)
Set n cos(theta_ch)
Definition: ARICHPhoton.h:117
void setModuleID(int modID)
Set id of hit module.
Definition: ARICHPhoton.h:73
void setPhiCh(const double *phi_ch)
Set phi_ch.
Definition: ARICHPhoton.h:130
void setPhiCerTrk(float phi)
Set hit phi angle in track coordinates.
Definition: ARICHPhoton.h:56
void setSigExp(const double *sigExp)
Set expected signal contribution.
Definition: ARICHPhoton.h:91
DBObjPtr< ARICHReconstructionPar > m_recPars
reconstruction parameters from the DB
std::vector< ROOT::Math::XYZVector > m_mirrorPoints
vector of points on all mirror plates
double m_zaero[c_noOfAerogels]
z-positions of aerogel layers
double p_mass[c_noOfHypotheses]
particle masses
double m_n0[c_noOfAerogels]
number of emitted photons per unit length
DBObjPtr< ARICHMirrorAlignment > m_mirrAlign
global alignment parameters from the DB
double m_transmissionLen[c_noOfAerogels]
transmission lengths of aerogel layers
bool m_alignMirrors
if set to true mirror alignment constants from DB are used
DBObjPtr< ARICHGeometryConfig > m_arichgp
geometry configuration parameters from the DB
std::vector< ROOT::Math::XYZVector > m_mirrorNorms
vector of normal vectors of all mirror plates
OptionalDBObjPtr< ARICHAeroTilesAlignment > m_tileAlign
alignment of aerogel tiles from DB
double m_trackAngRes
track direction resolution (from tracking)
ROOT::Math::XYZVector m_anorm[c_noOfAerogels]
normal vector of the aerogel plane
double m_refractiveInd[c_noOfAerogels]
refractive indices of aerogel layers
DBObjPtr< ARICHGlobalAlignment > m_alignp
global alignment parameters from the DB
unsigned int m_nAerogelLayers
number of aerogel layers
static const int c_noOfAerogels
Maximal number of aerogel layers to loop over.
double m_trackPosRes
track position resolution (from tracking)
static const int c_noOfHypotheses
Number of hypotheses to loop over.
DBObjPtr< ARICHChannelMapping > m_chnMap
map x,y channels to asic channels from the DB
int m_storePhot
set to 1 to store individual reconstructed photon information
double m_tilePars[124][2]
array of tile parameters
double m_thickness[c_noOfAerogels]
thicknesses of aerogel layers
Datastore class that holds position and momentum information of tracks that hit ARICH.
Definition: ARICHTrack.h:35
void setReconstructedValues(ROOT::Math::XYZVector r, ROOT::Math::XYZVector dir, double p)
Sets the reconstructed value of track parameters.
Definition: ARICHTrack.h:169
bool hitsWindow() const
Returns true if track hits HAPD window.
Definition: ARICHTrack.h:154
ROOT::Math::XYZVector getDirection() const
returns track direction vector
Definition: ARICHTrack.h:142
void addPhoton(ARICHPhoton photon)
Add ARICHPhoton to collection of photons.
Definition: ARICHTrack.h:183
ROOT::Math::XYZVector getPosition() const
returns track position vector
Definition: ARICHTrack.h:136
double getMomentum() const
returns track momentum
Definition: ARICHTrack.h:148
static const ParticleSet chargedStableSet
set of charged stable particles
Definition: Const.h:618
Accessor to arrays stored in the data store.
Definition: StoreArray.h:113
The Unit class.
Definition: Unit.h:40
void setTrackPositionResolution(double pRes)
Sets track position resolution (from tracking).
ROOT::Math::XYZVector FastTracking(ROOT::Math::XYZVector dirf, ROOT::Math::XYZVector r, double *refind, double *z, int n, int opt)
Calculates the intersection of the Cherenkov photon emitted from point "r" in "dirf" direction with t...
int CherenkovPhoton(ROOT::Math::XYZVector r, ROOT::Math::XYZVector rh, ROOT::Math::XYZVector &rf, ROOT::Math::XYZVector &dirf, double *refind, double *z, int n, int mirrorID=0)
Calculates the direction of photon emission.
int likelihood2(ARICHTrack &arichTrack, const StoreArray< ARICHHit > &arichHits, ARICHLikelihood &arichLikelihood)
Computes the value of identity likelihood function for different particle hypotheses.
void initialize()
Read geometry parameters from xml and initialize class members.
ROOT::Math::XYZVector HitVirtualPosition(const ROOT::Math::XYZVector &hitpos, int mirrorID)
Returns the hit virtual position, assuming that it was reflected from mirror.
void correctEmissionPoint(int tileID, double r)
Correct mean emission point z position.
ROOT::Math::XYZVector getMirrorNorm(int mirrorID)
Returns normal vector of the mirror plate with id mirrorID.
void setTrackAngleResolution(double aRes)
Sets track direction resolution (from tracking).
int InsideDetector(ROOT::Math::XYZVector a, int copyno)
Returns 1 if vector "a" lies on "copyno"-th detector active surface of detector and 0 else.
void transformTrackToLocal(ARICHTrack &arichTrack, bool align)
Transforms track parameters from global Belle2 to ARICH local frame.
bool HitsMirror(const ROOT::Math::XYZVector &pos, const ROOT::Math::XYZVector &dir, int mirrorID)
Returns true if photon at position pos with direction dir hits mirror plate with ID mirrorID.
ROOT::Math::XYZVector getTrackMeanEmissionPosition(const ARICHTrack &track, int iAero)
Returns mean emission position of Cherenkov photons from i-th aerogel layer.
ROOT::Math::XYZVector getMirrorPoint(int mirrorID)
Returns point on the mirror plate with id mirrorID.
ROOT::Math::XYZVector getTrackPositionAtZ(const ARICHTrack &track, double zout)
Returns track direction at point with z coordinate "zout" (assumes straight track).
ARICHReconstruction(int storePhotons=0)
Constructor.
int smearTrack(ARICHTrack &arichTrack)
Smears track parameters ("simulate" the uncertainties of tracking).
double sqrt(double a)
sqrt for double
Definition: beamHelpers.h:28
Abstract base class for different kinds of events.
record to be used to store ASIC info