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