@@ -243,6 +243,68 @@ o2::dataformats::GlobalFwdTrack refitGlobalMuonCov(TFwdTrack const& muon, TMFTTr
243243 return globalTrack;
244244}
245245
246+ template <typename TFullFwdTrack, typename TCollision>
247+ float getFwdChi2IP (const TFullFwdTrack& fwdtrack, const TCollision& collision, const float bz, const float zShift)
248+ {
249+ // this function returns imcompatibility of fwdtrack respect to a given PV.
250+ // fwdtracks are never PV contributors in ALICE.
251+ // chi2IP is defined as chi2^{PV}_{with fwdtrack} - chi2^{PV}_{without fwdtrack}. https://arxiv.org/abs/2604.11574
252+ // chi2IP cannot be used to decide the best fwdtrack-to-collision match or MFT-MCH match, because it gives biases toward small muon impact parameter.
253+ // chi2IP should be used only after the best fwdtrack-to-collision association and the best MFT-MCH match are defined.
254+
255+ o2::track::TrackParCovFwd trk = getTrackParCovFwdShift (fwdtrack, zShift, fwdtrack);
256+
257+ if (std::abs (bz) < 1e-12 ) {
258+ trk.propagateToZlinear (collision.posZ ());
259+ } else {
260+ trk.propagateToZhelix (collision.posZ (), bz);
261+ }
262+
263+ float x = trk.getX ();
264+ float y = trk.getY ();
265+ float phi = trk.getPhi ();
266+ float tgl = trk.getTanl ();
267+
268+ if (!std::isfinite (x) || !std::isfinite (y) || !std::isfinite (phi) || !std::isfinite (tgl) || std::abs (tgl) < 1e-8 ) {
269+ return -1 .f ;
270+ }
271+
272+ float dx = x - collision.posX ();
273+ float dy = y - collision.posY ();
274+
275+ // dx/dz and dy/dz for TrackParFwd.
276+ float tx = std::cos (phi) / tgl;
277+ float ty = std::sin (phi) / tgl;
278+
279+ const auto & ct = trk.getCovariances ();
280+
281+ float trkXX = ct (0 , 0 );
282+ float trkXY = ct (0 , 1 );
283+ float trkYY = ct (1 , 1 );
284+
285+ float pvXX = collision.covXX () - 2.0 * tx * collision.covXZ () + tx * tx * collision.covZZ ();
286+ float pvXY = collision.covXY () - ty * collision.covXZ () - tx * collision.covYZ () + tx * ty * collision.covZZ ();
287+ float pvYY = collision.covYY () - 2.0 * ty * collision.covYZ () + ty * ty * collision.covZZ ();
288+
289+ float sXX = trkXX + pvXX;
290+ float sXY = trkXY + pvXY;
291+ float sYY = trkYY + pvYY;
292+
293+ float det = sXX * sYY - sXY * sXY ;
294+
295+ if (!std::isfinite (det) || det <= 0.0 ) {
296+ return -1 .f ;
297+ }
298+
299+ float chi2 = (sYY * dx * dx - 2.0 * sXY * dx * dy + sXX * dy * dy) / det;
300+
301+ if (!std::isfinite (chi2) || chi2 < -1e-8 ) {
302+ return -1 .f ;
303+ }
304+
305+ return std::max (0 .f , chi2);
306+ }
307+
246308} // namespace fwdtrackutils
247309} // namespace o2::aod
248310
0 commit comments