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