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