Back to home page

sPhenix code displayed by LXR

 
 

    


File indexing completed on 2025-08-03 08:20:18

0001 /*
0002  * This file is part of KFParticle package
0003  * Copyright (C) 2007-2019 FIAS Frankfurt Institute for Advanced Studies
0004  *               2007-2019 Goethe University of Frankfurt
0005  *               2007-2019 Ivan Kisel <I.Kisel@compeng.uni-frankfurt.de>
0006  *               2007-2019 Maksym Zyzak
0007  *
0008  * KFParticle is free software: you can redistribute it and/or modify
0009  * it under the terms of the GNU General Public License as published by
0010  * the Free Software Foundation, either version 3 of the License, or
0011  * (at your option) any later version.
0012  *
0013  * KFParticle is distributed in the hope that it will be useful,
0014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0016  * GNU General Public License for more details.
0017  *
0018  * You should have received a copy of the GNU General Public License
0019  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
0020  */
0021 
0022 #ifdef DO_TPCCATRACKER_EFF_PERFORMANCE
0023 
0024 #include "KFTopoPerformance.h"
0025 
0026 #ifdef KFPWITHTRACKER
0027 #ifdef MAIN_DRAW
0028 #include "AliHLTTPCCADisplay.h"
0029 #endif //DRAW
0030 #include "AliHLTTPCCATracker.h"
0031 #include "AliHLTTPCCAPerformance.h"
0032 #endif
0033 
0034 #include "KFParticleTopoReconstructor.h"
0035 #include "KFParticleSIMD.h"
0036 #include "KFPHistogram/KFPHistogram.h"
0037 #include "TParticlePDG.h"
0038 #include "TDatabasePDG.h"
0039 
0040 #include "TMath.h"
0041 #include "TH1.h"
0042 #include "TH2.h"
0043 #include "TH3.h"
0044 #include "TProfile.h"
0045 #include "TProfile2D.h"
0046 
0047 #include <map>
0048 #include <algorithm>
0049 using std::sort;
0050 using std::vector;
0051 
0052 KFTopoPerformance::KFTopoPerformance():KFParticlePerformanceBase(),fTopoReconstructor(0),fPrimVertices(0), fMCTrackToMCPVMatch(0), 
0053   fPVPurity(0), fNCorrectPVTracks(0), fTrackMatch(0), vMCTracks(0), vMCParticles(0), fNeutralIndex(0), MCtoRParticleId(0), RtoMCParticleId(0), 
0054   MCtoRPVId(0), RtoMCPVId(0), fPrintEffFrequency(1), fCentralityBin(-1), fCentralityWeight(0.f)
0055 {
0056 }
0057 
0058 KFTopoPerformance::~KFTopoPerformance()
0059 {
0060 }
0061 
0062 #ifdef KFPWITHTRACKER
0063 void KFTopoPerformance::SetNewEvent(
0064                             const AliHLTTPCCAGBTracker * const tracker,
0065                             AliHLTResizableArray<AliHLTTPCCAHitLabel> *hitLabels,
0066                             AliHLTResizableArray<AliHLTTPCCAMCTrack> *mcTracks,
0067                             AliHLTResizableArray<AliHLTTPCCALocalMCPoint> *localMCPoints)
0068 {  
0069   vMCTracks.resize(mcTracks->Size());
0070   for(int iTr=0; iTr<vMCTracks.size(); iTr++)
0071   {
0072     for(int iP=0; iP<3; iP++)
0073       vMCTracks[iTr].SetPar(iP, (*mcTracks)[iTr].Par(iP));
0074     for(int iP=3; iP<6; iP++)
0075       vMCTracks[iTr].SetPar(iP, (*mcTracks)[iTr].Par(iP) * (*mcTracks)[iTr].P());
0076     vMCTracks[iTr].SetPar(6, (*mcTracks)[iTr].Par(6));
0077     
0078     vMCTracks[iTr].SetPDG( (*mcTracks)[iTr].PDG() );
0079     vMCTracks[iTr].SetMotherId( (*mcTracks)[iTr].MotherId() );
0080     vMCTracks[iTr].SetNMCPoints( (*mcTracks)[iTr].NMCPoints() );
0081   } 
0082 } // void KFTopoPerformance::SetNewEvent
0083 #endif
0084 
0085 void KFTopoPerformance::SetTopoReconstructor( const KFParticleTopoReconstructor * const TopoReconstructor)
0086 {  
0087   /** Sets a pointer to the external KFParticleTopoReconstructor object. */
0088   fTopoReconstructor = TopoReconstructor;
0089 } // void KFTopoPerformance::SetTopoReconstructor
0090 
0091 void KFTopoPerformance::CheckMCTracks()
0092 {
0093   /** Cleans Monte Carlo information on primary vertices, and refill it with the current event. */
0094   fMCTrackToMCPVMatch.clear();
0095   fPrimVertices.clear();
0096 
0097     // find prim vertex
0098   if (vMCTracks.size() <= 0) return;
0099   
0100   fMCTrackToMCPVMatch.resize(vMCTracks.size(),-1);
0101   
0102   vector<int> pvIndex;
0103   for(unsigned int iTr=0; iTr<vMCTracks.size(); iTr++)
0104   {
0105     KFMCTrack &mctr = vMCTracks[iTr];
0106     int motherID = mctr.MotherId();
0107     if(motherID <0 )
0108     {
0109       bool newPV = 1;
0110       for(unsigned int iPV=0; iPV<pvIndex.size(); iPV++)
0111       {
0112         if(motherID == pvIndex[iPV])
0113         {
0114           fPrimVertices[iPV].AddDaughterTrack(iTr);
0115           fMCTrackToMCPVMatch[iTr] = iPV;
0116           newPV = 0;
0117         }
0118       }
0119       if(newPV)
0120       {
0121         KFMCVertex primVertex;
0122         primVertex.SetX( mctr.X() );
0123         primVertex.SetY( mctr.Y() );
0124         primVertex.SetZ( mctr.Z() );
0125         primVertex.AddDaughterTrack(iTr);
0126         if(motherID == -1)
0127           primVertex.SetTriggerPV();
0128         fPrimVertices.push_back(primVertex);
0129         fMCTrackToMCPVMatch[iTr] = pvIndex.size();
0130         pvIndex.push_back(motherID);
0131       }
0132     }
0133   }
0134 } // void KFTopoPerformance::CheckMCTracks()
0135 
0136 void KFTopoPerformance::GetMCParticles()
0137 {
0138   /** Fills information on relations between Monte Carlo particles. */
0139 
0140   vMCParticles.clear();
0141   vMCParticles.reserve(vMCTracks.size());
0142   // all MC tracks are copied into KF MC Particles
0143   for(unsigned int iMC=0; iMC < vMCTracks.size(); iMC++)
0144   {
0145     KFMCTrack &mtra = vMCTracks[iMC];
0146     KFMCParticle part;
0147     part.SetMCTrackID( iMC );
0148     part.SetMotherId ( mtra.MotherId() );
0149     part.SetPDG      ( mtra.PDG() );
0150     vMCParticles.push_back( part );
0151   }
0152   // find relations between mother and daughter MC particles
0153   const int nMCParticles = vMCParticles.size();
0154   for (int iP = 0; iP < nMCParticles; iP++ ) {
0155     KFMCParticle &part = vMCParticles[iP];
0156     int motherId = part.GetMotherId();
0157     if(motherId < 0) continue;
0158     if(motherId >= nMCParticles)
0159     {
0160       std::cout << "ERROR!!!!!  KF Particle Performance: MC track mother Id is out of range." << std::endl;
0161       exit(1);
0162     }
0163     KFMCParticle &motherPart = vMCParticles[motherId];
0164     motherPart.AddDaughter(iP);
0165   }
0166   
0167   fNeutralIndex.clear();
0168   fNeutralIndex.resize(nMCParticles, -1);
0169   
0170   for(unsigned int iMC=0; iMC < vMCParticles.size(); iMC++)
0171   {
0172     KFMCParticle &part = vMCParticles[iMC];
0173     part.SetMCTrackID( iMC );
0174   }
0175   
0176   const int NmmPDG = 7;
0177   vector<int> mmMotherPDG(NmmPDG); //PDG for particles found by the missing mass method
0178   vector<int> mmChargedDaughterPDG(NmmPDG);
0179   vector<int> mmNeutralDaughterPDG(NmmPDG);
0180   vector<int> newMotherPDG(NmmPDG);
0181   vector<int> newNeutralPDG(NmmPDG);
0182   
0183   mmMotherPDG[ 0] = 3112; mmChargedDaughterPDG[ 0] =  211; mmNeutralDaughterPDG[ 0] = 2112;
0184   mmMotherPDG[ 1] = 3222; mmChargedDaughterPDG[ 1] =  211; mmNeutralDaughterPDG[ 1] = 2112;
0185   mmMotherPDG[ 2] = 3312; mmChargedDaughterPDG[ 2] =  211; mmNeutralDaughterPDG[ 2] = 3122;
0186   mmMotherPDG[ 3] = 3334; mmChargedDaughterPDG[ 3] =  211; mmNeutralDaughterPDG[ 3] = 3322;
0187   mmMotherPDG[ 4] =  321; mmChargedDaughterPDG[ 4] =  211; mmNeutralDaughterPDG[ 4] =  111;
0188   mmMotherPDG[ 5] = 3334; mmChargedDaughterPDG[ 5] =  321; mmNeutralDaughterPDG[ 5] = 3122;
0189   mmMotherPDG[ 6] = 3222; mmChargedDaughterPDG[ 6] = 2212; mmNeutralDaughterPDG[ 6] =  111;
0190   
0191   newMotherPDG[ 0] = 7003112; newNeutralPDG[ 0] = 7002112;
0192   newMotherPDG[ 1] = 7003222; newNeutralPDG[ 1] = 8002112;
0193   newMotherPDG[ 2] = 7003312; newNeutralPDG[ 2] = 7003122;
0194   newMotherPDG[ 3] = 7003334; newNeutralPDG[ 3] = 7003322;
0195   newMotherPDG[ 4] = 9000321; newNeutralPDG[ 4] = 9000111;
0196   newMotherPDG[ 5] = 8003334; newNeutralPDG[ 5] = 8003122;
0197   newMotherPDG[ 6] = 8003222; newNeutralPDG[ 6] = 8000111;
0198     
0199   //add neutrinos, if they are not saved
0200   for(int iMC=0; iMC<nMCParticles; iMC++)
0201   {
0202     if( abs(vMCParticles[iMC].GetPDG()) == 211 || abs(vMCParticles[iMC].GetPDG()) == 321 )
0203     {
0204       int muonIndex = -1;
0205       for(int iD=0; iD<vMCParticles[iMC].NDaughters(); iD++)
0206         if( abs(vMCParticles[vMCParticles[iMC].GetDaughterIds()[iD]].GetPDG()) == 13 )
0207           muonIndex = vMCParticles[iMC].GetDaughterIds()[iD];
0208 
0209       if(muonIndex > -1)
0210       {
0211         int newPDG = 0;
0212         if(vMCParticles[iMC].GetPDG() >0)
0213           newPDG = vMCParticles[iMC].GetPDG() + 7000000;
0214         else
0215           newPDG = vMCParticles[iMC].GetPDG() - 7000000;
0216         KFMCParticle motherPart = vMCParticles[iMC];
0217         KFMCTrack motherTrack = vMCTracks[motherPart.GetMCTrackID()];
0218         motherTrack.SetPDG(newPDG);
0219         motherTrack.SetNotReconstructed();
0220         int newMotherIndex = vMCTracks.size();
0221         motherPart.SetPDG(newPDG);
0222         motherPart.SetMCTrackID(newMotherIndex);
0223 
0224         const KFMCParticle& daughterPart = vMCParticles[muonIndex];
0225         const KFMCTrack& daughterTrack = vMCTracks[daughterPart.GetMCTrackID()];
0226 
0227         int neutrinoPDG = 7000014;
0228         if(vMCParticles[iMC].GetPDG() == -211) neutrinoPDG = -7000014;
0229         if(vMCParticles[iMC].GetPDG() ==  321) neutrinoPDG =  8000014;
0230         if(vMCParticles[iMC].GetPDG() == -321) neutrinoPDG = -8000014;
0231 
0232         int neutrinoIndex = vMCTracks.size()+1;
0233         vMCParticles[iMC].AddDaughter(neutrinoIndex);
0234         
0235         fNeutralIndex[iMC] = neutrinoIndex;
0236 
0237         KFMCParticle neutrinoPart;
0238         KFMCTrack neutrinoTrack;
0239         neutrinoTrack.SetX(daughterTrack.X());
0240         neutrinoTrack.SetY(daughterTrack.Y());
0241         neutrinoTrack.SetZ(daughterTrack.Z());
0242         neutrinoTrack.SetPx(motherTrack.Px() - daughterTrack.Px());
0243         neutrinoTrack.SetPy(motherTrack.Py() - daughterTrack.Py());
0244         neutrinoTrack.SetPz(motherTrack.Pz() - daughterTrack.Pz());
0245         neutrinoTrack.SetQP(0);
0246         neutrinoTrack.SetMotherId(newMotherIndex);
0247         neutrinoTrack.SetPDG(neutrinoPDG);
0248 
0249         motherPart.CleanDaughters();
0250         motherPart.AddDaughter(muonIndex);
0251         motherPart.AddDaughter(neutrinoIndex);
0252         motherPart.SetInitialParticleId(iMC);
0253         vMCTracks.push_back(motherTrack);
0254         vMCParticles.push_back(motherPart);
0255         fNeutralIndex.push_back(-1);
0256         
0257         neutrinoPart.SetMCTrackID(neutrinoIndex);
0258         neutrinoPart.SetMotherId(newMotherIndex);
0259         neutrinoPart.SetPDG(neutrinoPDG);
0260         neutrinoPart.AddDaughter(iMC);
0261         neutrinoPart.AddDaughter(muonIndex);
0262         vMCTracks.push_back(neutrinoTrack);
0263         vMCParticles.push_back(neutrinoPart);
0264         fNeutralIndex.push_back(-1);
0265         
0266         vMCParticles[iMC].SetAsReconstructable(4);
0267         vMCParticles[muonIndex].SetAsReconstructable(4);
0268       }
0269     }
0270     // add sigmas, omegas, xis ...
0271     if( vMCParticles[iMC].NDaughters() >= 2 && 
0272         (abs(vMCParticles[iMC].GetPDG()) == 3112 || 
0273          abs(vMCParticles[iMC].GetPDG()) == 3222 || 
0274          abs(vMCParticles[iMC].GetPDG()) == 3312 || 
0275          abs(vMCParticles[iMC].GetPDG()) == 3334 || 
0276          abs(vMCParticles[iMC].GetPDG()) ==  321) )
0277     {
0278       int neutralDaughterId = -1, chargedDaughterId = -1;
0279 
0280       int newPDG = 0;
0281       int neutralPDG = 0;
0282 
0283       for(int iPDG=0; iPDG<NmmPDG; iPDG++)
0284       {
0285         if(abs(vMCParticles[iMC].GetPDG()) == mmMotherPDG[iPDG])
0286         {
0287           bool isDaughter[2] = {0,0};
0288 
0289           vector<float> xDaughter;
0290           vector<float> yDaughter;
0291           vector<float> zDaughter;
0292           vector< vector<int> > nDaughtersAtPoint;
0293           
0294           for(int iMCDaughter=0; iMCDaughter<vMCParticles[iMC].NDaughters(); iMCDaughter++)
0295           {
0296             bool isNewDecayPoint = 1;
0297             
0298             for(unsigned int iPoint=0; iPoint<xDaughter.size(); iPoint++)
0299             {
0300               float dx = fabs(vMCTracks[vMCParticles[iMC].GetDaughterIds()[iMCDaughter]].X() - xDaughter[iPoint]);
0301               float dy = fabs(vMCTracks[vMCParticles[iMC].GetDaughterIds()[iMCDaughter]].Y() - yDaughter[iPoint]);
0302               float dz = fabs(vMCTracks[vMCParticles[iMC].GetDaughterIds()[iMCDaughter]].Z() - zDaughter[iPoint]);
0303               
0304               bool isSamePoint = (dx < 1.e-5 && dy < 1.e-5 && dz < 1.e-5);
0305               if(isSamePoint)
0306                 nDaughtersAtPoint[iPoint].push_back(iMCDaughter);
0307               
0308               isNewDecayPoint &= !isSamePoint;
0309             }
0310             
0311             if(isNewDecayPoint)
0312             {
0313               xDaughter.push_back(vMCTracks[vMCParticles[iMC].GetDaughterIds()[iMCDaughter]].X());
0314               yDaughter.push_back(vMCTracks[vMCParticles[iMC].GetDaughterIds()[iMCDaughter]].Y());
0315               zDaughter.push_back(vMCTracks[vMCParticles[iMC].GetDaughterIds()[iMCDaughter]].Z());
0316               vector<int> newPointIndex;
0317               newPointIndex.push_back(iMCDaughter);
0318               nDaughtersAtPoint.push_back(newPointIndex);
0319             }
0320           }
0321           
0322           for(unsigned int iPoint = 0; iPoint<nDaughtersAtPoint.size(); iPoint++)
0323           {
0324             if(nDaughtersAtPoint[iPoint].size() == 2)
0325             {
0326               for(unsigned int iDaughter=0; iDaughter<nDaughtersAtPoint[iPoint].size(); iDaughter++)
0327               {
0328                 int iMCDaughter = nDaughtersAtPoint[iPoint][iDaughter];
0329                 if(abs(vMCParticles[vMCParticles[iMC].GetDaughterIds()[iMCDaughter]].GetPDG()) == mmChargedDaughterPDG[iPDG])
0330                 {
0331                   isDaughter[0] = 1;
0332                   chargedDaughterId = vMCParticles[iMC].GetDaughterIds()[iMCDaughter];
0333                 }
0334                 if(abs(vMCParticles[vMCParticles[iMC].GetDaughterIds()[iMCDaughter]].GetPDG()) == mmNeutralDaughterPDG[iPDG])
0335                 {
0336                   isDaughter[1] = 1;
0337                   neutralDaughterId = vMCParticles[iMC].GetDaughterIds()[iMCDaughter];
0338                 }
0339               }
0340               
0341               if(isDaughter[0] && isDaughter[1])
0342               {
0343                 int signPDG = vMCParticles[iMC].GetPDG()/abs(vMCParticles[iMC].GetPDG());
0344                 newPDG     = signPDG * newMotherPDG[iPDG];
0345                 neutralPDG = signPDG * newNeutralPDG[iPDG];
0346               }
0347             }
0348           }
0349         }
0350       }
0351 
0352       if(newPDG != 0)
0353       {
0354         KFMCParticle motherPart = vMCParticles[iMC];
0355         KFMCTrack motherTrack = vMCTracks[motherPart.GetMCTrackID()];
0356         motherTrack.SetPDG(newPDG);
0357         motherTrack.SetNotReconstructed();
0358         int newMotherIndex = vMCTracks.size();
0359         motherPart.SetPDG(newPDG);
0360         motherPart.SetMCTrackID(newMotherIndex);
0361 
0362         int neutrinoIndex = vMCTracks.size()+1;
0363         fNeutralIndex[iMC] = neutrinoIndex;
0364         
0365         KFMCTrack neutralTrack = vMCTracks[neutralDaughterId];
0366         neutralTrack.SetMotherId(newMotherIndex);
0367         neutralTrack.SetPDG(neutralPDG);
0368 
0369         motherPart.CleanDaughters();
0370         motherPart.AddDaughter(chargedDaughterId);
0371         motherPart.AddDaughter(neutrinoIndex);
0372         motherPart.SetInitialParticleId(iMC);
0373         vMCTracks.push_back(motherTrack);
0374         vMCParticles.push_back(motherPart);
0375         fNeutralIndex.push_back(-1);
0376         
0377         KFMCParticle neutralPart;
0378         neutralPart.SetMCTrackID(neutrinoIndex);
0379         neutralPart.SetMotherId(newMotherIndex);
0380         neutralPart.SetPDG(neutralPDG);
0381         neutralPart.AddDaughter(iMC);
0382         neutralPart.AddDaughter(chargedDaughterId);
0383         vMCTracks.push_back(neutralTrack);
0384         vMCParticles.push_back(neutralPart);
0385         fNeutralIndex.push_back(-1);
0386         
0387         vMCParticles[iMC].SetAsReconstructable(4);
0388         vMCParticles[chargedDaughterId].SetAsReconstructable(4);
0389       }
0390     }
0391   }
0392   
0393   //clean Lambda c daughters
0394   for(unsigned int iMC=0; iMC < vMCParticles.size(); iMC++)
0395   {
0396     KFMCParticle &part = vMCParticles[iMC];
0397 
0398 //     if(abs(part.GetPDG()) == 4122)
0399     {
0400       //add daughters into one pool
0401       vector<int> newDaughters;
0402       for(unsigned int iD=0; iD<part.GetDaughterIds().size(); iD++)
0403       {
0404         KFMCParticle &d = vMCParticles[part.GetDaughterIds()[iD]];
0405         if( abs(d.GetPDG())==3224 || 
0406             abs(d.GetPDG())==3114 || 
0407             abs(d.GetPDG())==113  ||
0408             abs(d.GetPDG())==313  ||
0409             abs(d.GetPDG())==323  ||
0410             abs(d.GetPDG())==2224 ||
0411             abs(d.GetPDG())==2214 ||
0412             abs(d.GetPDG())==2114 ||
0413             abs(d.GetPDG())==1114
0414           )
0415         {
0416           for(unsigned int iDaughter=0; iDaughter<d.GetDaughterIds().size(); iDaughter++)
0417           {
0418             newDaughters.push_back(d.GetDaughterIds()[iDaughter]);
0419             vMCParticles[d.GetDaughterIds()[iDaughter]].SetMotherId(iMC);
0420           }
0421         }
0422         else
0423 //         if(d.GetDaughterIds().size() == 0 || abs(d.GetPDG())==310 || abs(d.GetPDG())==3122)
0424           newDaughters.push_back(part.GetDaughterIds()[iD]);
0425       }
0426       part.CleanDaughters();
0427       for(unsigned int iDaughter=0; iDaughter<newDaughters.size(); iDaughter++)
0428         part.AddDaughter(newDaughters[iDaughter]);
0429       
0430       //change PDG to separate channels
0431       int indexPDG = fParteff.GetParticleIndex(part.GetPDG());
0432       for(int iPDG=indexPDG; iPDG<indexPDG+10; iPDG++)
0433       {
0434         const int nDaughters = part.GetDaughterIds().size();
0435         
0436         if(int(fParteff.partDaughterPdg[iPDG].size()) != nDaughters)
0437           continue;
0438         
0439         vector<bool> isDaughterFound(nDaughters);
0440         vector<bool> isDaughterUsed(nDaughters);
0441         for(int iDMC=0; iDMC<nDaughters; iDMC++)
0442         {
0443           isDaughterFound[iDMC] = 0;
0444           isDaughterUsed[iDMC] = 0;
0445         }
0446         
0447         bool isCorrectPDG = 1;
0448         for(int iDMC=0; iDMC<nDaughters; iDMC++)
0449           for(int iD=0; iD<nDaughters; iD++)
0450           {
0451             if(isDaughterUsed[iD]) continue;
0452             if(vMCParticles[part.GetDaughterIds()[iD]].GetPDG() == fParteff.partDaughterPdg[iPDG][iDMC]) 
0453             {
0454               isDaughterUsed[iD] = 1;
0455               isDaughterFound[iDMC] = 1;
0456               break;
0457             }
0458           }
0459 
0460         for(int iDMC=0; iDMC<nDaughters; iDMC++)
0461           isCorrectPDG &= isDaughterFound[iDMC];
0462         
0463         if(isCorrectPDG)
0464         {
0465           part.SetPDG(fParteff.partPDG[iPDG]);
0466           break;
0467         }
0468       }
0469     }
0470   }
0471 }
0472 
0473 void KFTopoPerformance::FindReconstructableMCParticles()
0474 {
0475   /** Check each Monte Carlo particle if it can be reconstructed. */
0476   const unsigned int nMCParticles = vMCParticles.size();
0477 
0478   for ( unsigned int iP = 0; iP < nMCParticles; iP++ ) {
0479     KFMCParticle &part = vMCParticles[iP];
0480     CheckMCParticleIsReconstructable(part);
0481   }
0482 }
0483 
0484 void KFTopoPerformance::CheckMCParticleIsReconstructable(KFMCParticle &part)
0485 {
0486   /** Checks if the given Monte Carlo particle can be reconstructed. */
0487   if ( part.IsReconstructable(0) ) return;
0488   if ( vMCTracks[part.GetMCTrackID()].IsOutOfDetector() ) return;
0489   
0490   if( abs(part.GetPDG()) ==        211 ||
0491       abs(part.GetPDG()) ==       2212 ||
0492       abs(part.GetPDG()) ==        321 ||
0493       abs(part.GetPDG()) ==         13 ||
0494       abs(part.GetPDG()) ==       3112 ||
0495       abs(part.GetPDG()) ==       3222 ||
0496       abs(part.GetPDG()) ==       3312 ||
0497       abs(part.GetPDG()) ==       3334 )
0498   {
0499     int iMCTrack = part.GetMCTrackID();
0500     KFMCTrack &mcTrack = vMCTracks[iMCTrack];
0501 
0502     // reconstructable in 4pi is defined in GetMCParticles, when decay is found
0503     if(mcTrack.IsReconstructed())
0504       part.SetAsReconstructable(3);
0505   }
0506     // tracks
0507   if ( abs(part.GetPDG()) ==        211 ||
0508        abs(part.GetPDG()) ==       2212 ||
0509        abs(part.GetPDG()) ==        321 ||
0510        abs(part.GetPDG()) ==         11 ||
0511        abs(part.GetPDG()) ==         13 ||
0512        abs(part.GetPDG()) == 1000010020 ||
0513        abs(part.GetPDG()) == 1000010030 ||
0514        abs(part.GetPDG()) == 1000020030 ||
0515        abs(part.GetPDG()) == 1000020040 ||
0516        ( (part.GetPDG() == 22) && (vMCTracks[part.GetMCTrackID()].IsReconstructed()) ) )
0517   {
0518     int iMCTrack = part.GetMCTrackID();
0519     KFMCTrack &mcTrack = vMCTracks[iMCTrack];
0520 
0521     part.SetAsReconstructable(0);
0522 
0523     if(mcTrack.NMCPoints() >= 15)
0524       part.SetAsReconstructable(1);   
0525 //     if(mc.IsReconstructable())
0526 //       part.SetAsReconstructable2();
0527 
0528     if(mcTrack.IsReconstructed())
0529       part.SetAsReconstructable(2);
0530   }
0531     //  mother particles
0532   else
0533   {
0534     //Check if the particle is V0
0535     
0536     if(part.NDaughters() >= 2)
0537     {
0538       bool isPositiveDaughter[5] = {0,0,0,0,0};
0539       bool isNegativeDaughter[5] = {0,0,0,0,0};
0540       
0541       int nRecoDaughters[5] = {0,0,0,0,0};
0542       
0543       for(int iD=0; iD < part.NDaughters(); iD++)
0544       {
0545         KFMCParticle &daughter = vMCParticles[part.GetDaughterIds()[iD]];
0546         CheckMCParticleIsReconstructable(daughter);
0547         
0548         TParticlePDG* particlePDG = TDatabasePDG::Instance()->GetParticle(daughter.GetPDG());
0549         Double_t charge = (particlePDG) ? particlePDG->Charge()/3 : 0;
0550         
0551         for(int iEff=0; iEff<5; iEff++)
0552         {
0553           if(charge > 0)
0554             isPositiveDaughter[iEff] |= daughter.IsReconstructable(iEff);
0555           else
0556             isNegativeDaughter[iEff] |= daughter.IsReconstructable(iEff);
0557           
0558           if(daughter.IsReconstructable(iEff))
0559             nRecoDaughters[iEff]++;
0560         }
0561       }
0562       
0563 //       for(int iEff=0; iEff<3; iEff++)
0564 //         if(isPositiveDaughter[iEff] && isNegativeDaughter[iEff])
0565 //           part.SetAsReconstructableV0(iEff);
0566       for(int iEff=0; iEff<3; iEff++)
0567         if(nRecoDaughters[iEff] > 1)
0568           part.SetAsReconstructableV0(iEff);
0569     }
0570     
0571     for(int iPart=0; iPart<fParteff.nParticles; iPart++)
0572     {
0573       if(part.GetPDG() == fParteff.partPDG[iPart])
0574       {
0575         const unsigned int nDaughters = fParteff.partDaughterPdg[iPart].size();
0576         if( part.GetDaughterIds().size() != nDaughters ) return;
0577         vector<int> pdg(nDaughters);
0578 
0579         for(unsigned int iD=0; iD<nDaughters; iD++)
0580           pdg[iD] = vMCParticles[part.GetDaughterIds()[iD]].GetPDG();
0581 
0582         vector<bool> isDaughterFound(nDaughters);
0583         for(unsigned int iDMC=0; iDMC<nDaughters; iDMC++)
0584           isDaughterFound[iDMC] = 0;
0585 
0586         bool isReco = 1;
0587         for(unsigned int iDMC=0; iDMC<nDaughters; iDMC++)
0588           for(unsigned int iD=0; iD<nDaughters; iD++)
0589             if(pdg[iD] == fParteff.partDaughterPdg[iPart][iDMC]) isDaughterFound[iDMC] = 1;
0590 
0591         for(unsigned int iDMC=0; iDMC<nDaughters; iDMC++)
0592           isReco = isReco && isDaughterFound[iDMC];
0593 
0594         if(!isReco) return;
0595       }
0596     }
0597 
0598     const vector<int>& dIds = part.GetDaughterIds();
0599     const unsigned int nD = dIds.size();
0600     if(nD == 0) return; //TODO optimize for all species
0601     
0602     bool reco1 = 1;
0603     bool reco2 = 1;
0604     bool reco3 = 1;
0605     bool reco4 = 1;
0606     bool reco5 = 1;
0607       
0608     for ( unsigned int iD = 0; iD < nD && (reco1 || reco2 || reco3 || reco4 || reco5); iD++ ) {
0609       KFMCParticle &dp = vMCParticles[dIds[iD]];
0610       CheckMCParticleIsReconstructable(dp);
0611       reco1 &= dp.IsReconstructable(0);
0612       reco2 &= dp.IsReconstructable(1);
0613       reco3 &= dp.IsReconstructable(2);
0614       reco4 &= dp.IsReconstructable(3);
0615       reco5 &= dp.IsReconstructable(4);
0616     }
0617     
0618     if (reco1) part.SetAsReconstructable(0);
0619     if (reco2) part.SetAsReconstructable(1);
0620     if (reco3) part.SetAsReconstructable(2);
0621     int iParticle = fParteff.GetParticleIndex(part.GetPDG());
0622     if (reco4 && iParticle>=KFPartEfficiencies::fFirstMissingMassParticleIndex &&
0623                  iParticle<=KFPartEfficiencies::fLastMissingMassParticleIndex ) part.SetAsReconstructable(3);
0624     if (reco5 && iParticle>=KFPartEfficiencies::fFirstMissingMassParticleIndex &&
0625                  iParticle<=KFPartEfficiencies::fLastMissingMassParticleIndex ) part.SetAsReconstructable(4);
0626   }
0627 }
0628 
0629 
0630 void KFTopoPerformance::FindReconstructableMCVertices()
0631 {
0632   /** Checks which Monte Carlo primary vertices can be reconstructed. */
0633   const unsigned int nMCVertices = fPrimVertices.size();
0634 
0635   for ( unsigned int iV = 0; iV < nMCVertices; iV++ ) {
0636     KFMCVertex &vert = fPrimVertices[iV];
0637         
0638     int nReconstructableDaughters = 0;
0639     int nMCReconstructableDaughters = 0;
0640 
0641     for(int iP=0; iP<vert.NDaughterTracks(); iP++)
0642     {
0643       int idDaughter = vert.DaughterTrack(iP);
0644       KFMCParticle &part = vMCParticles[idDaughter];
0645       
0646       if(part.IsReconstructable(2)) nReconstructableDaughters++;
0647       if(part.IsReconstructable(1)) nMCReconstructableDaughters++;
0648     }
0649     
0650     if(nReconstructableDaughters >= 2) vert.SetReconstructable();
0651     else vert.SetUnReconstructable();
0652     
0653     if(nMCReconstructableDaughters >= 2) vert.SetMCReconstructable();
0654     else vert.SetMCUnReconstructable();
0655   }
0656 }
0657 
0658 void KFTopoPerformance::MatchParticles()
0659 {
0660   /** Matches Monte Carlo and reconstructed particles. */
0661   MCtoRParticleId.clear();
0662   RtoMCParticleId.clear();
0663   MCtoRParticleId.resize(vMCParticles.size());
0664   RtoMCParticleId.resize(fTopoReconstructor->GetParticles().size() );
0665 
0666   // match tracks ( particles which are direct copies of tracks )
0667   for( unsigned int iRP = 0; iRP < fTopoReconstructor->GetParticles().size(); iRP++ ) 
0668   {
0669     const KFParticle &rPart = fTopoReconstructor->GetParticles()[iRP];
0670 
0671     if (rPart.NDaughters() != 1) continue;
0672 
0673     const int rTrackId = rPart.DaughterIds()[0];
0674     const int mcTrackId = fTrackMatch[rTrackId];
0675 
0676     if(mcTrackId < 0) continue;
0677 
0678     KFMCParticle &mPart = vMCParticles[mcTrackId];
0679     if( mPart.GetPDG() == rPart.GetPDG() ) 
0680     {
0681       MCtoRParticleId[mcTrackId].ids.push_back(iRP);
0682       RtoMCParticleId[iRP].ids.push_back(mcTrackId);
0683     }
0684     else {
0685       MCtoRParticleId[mcTrackId].idsMI.push_back(iRP);
0686       RtoMCParticleId[iRP].idsMI.push_back(mcTrackId);
0687     }
0688   }
0689 
0690   // match created mother particles
0691   for( unsigned int iRP = 0; iRP < fTopoReconstructor->GetParticles().size(); iRP++ ) {
0692     const KFParticle &rPart = fTopoReconstructor->GetParticles()[iRP];
0693     const unsigned int NRDaughters = rPart.NDaughters();
0694     
0695     if (NRDaughters < 2) continue;
0696 
0697     bool isMissingMass = ((abs(rPart.GetPDG()) == 7000211)||(abs(rPart.GetPDG()) == 7000321)||(abs(rPart.GetPDG()) == 7003112) || (abs(rPart.GetPDG()) == 7003222)|| (abs(rPart.GetPDG()) == 7003312)|| (abs(rPart.GetPDG()) == 7003334)|| (abs(rPart.GetPDG()) == 9000321)|| (abs(rPart.GetPDG()) == 8003334)||(abs(rPart.GetPDG()) == 8003222));
0698     
0699     //missing mass method
0700     if ( (abs(rPart.GetPDG()) == 7000014 ) || (abs(rPart.GetPDG()) == 8000014 ) || (abs(rPart.GetPDG()) == 7002112 ) ||
0701          (abs(rPart.GetPDG()) == 8002112 ) || (abs(rPart.GetPDG()) == 7003122 ) || (abs(rPart.GetPDG()) == 7003322 ) ||
0702          (abs(rPart.GetPDG()) == 9000111 ) || (abs(rPart.GetPDG()) == 8003122 ) || (abs(rPart.GetPDG()) == 8000111 ) )
0703     {
0704       //During the reconstruction 1st daughter - mother particle, 2nd daughter - charged daughter
0705 
0706       int mcNeutralDaughterId = -1;
0707       const int recoMotherId = rPart.DaughterIds()[0];
0708       if ( !RtoMCParticleId[recoMotherId].IsMatched() ) continue;
0709 
0710       const int mcMotherId = RtoMCParticleId[recoMotherId].GetBestMatch();
0711       
0712       const int recoChargedDaughterId = rPart.DaughterIds()[1];
0713       if ( !RtoMCParticleId[recoChargedDaughterId].IsMatched() ) continue;
0714 
0715       const int mcChargedDaughterId = RtoMCParticleId[recoChargedDaughterId].GetBestMatch();
0716       const KFMCParticle& chargedDaughter = vMCParticles[mcChargedDaughterId];
0717 
0718       if(chargedDaughter.GetMotherId() != mcMotherId) continue;
0719       const KFMCParticle& mother = vMCParticles[mcMotherId];
0720 
0721       if(fNeutralIndex[mcMotherId] > -1)
0722         mcNeutralDaughterId = fNeutralIndex[mcMotherId];
0723 
0724       if(mcNeutralDaughterId > -1)
0725       {
0726         KFMCParticle &neutralDaughter = vMCParticles[mcNeutralDaughterId];
0727         
0728         int iParticle = fParteff.GetParticleIndex(rPart.GetPDG());
0729         
0730         bool allCorrectDaughters = mother.GetPDG()          == fParteff.partDaughterPdg[iParticle][0] &&
0731                                    chargedDaughter.GetPDG() == fParteff.partDaughterPdg[iParticle][1];
0732 
0733         if( neutralDaughter.GetPDG()     == rPart.GetPDG()     &&
0734             neutralDaughter.NDaughters() == rPart.NDaughters() &&
0735             allCorrectDaughters) {
0736           MCtoRParticleId[mcNeutralDaughterId].ids.push_back(iRP);
0737           RtoMCParticleId[iRP].ids.push_back(mcNeutralDaughterId);
0738         }
0739         else {
0740           MCtoRParticleId[mcNeutralDaughterId].idsMI.push_back(iRP);
0741           RtoMCParticleId[iRP].idsMI.push_back(mcNeutralDaughterId);
0742         }
0743       }
0744     }
0745     
0746     
0747     
0748     //normal decays
0749     else
0750     {
0751       unsigned int iD = 0;
0752       vector<int> mcDaughterIds;
0753       int mmId = -2; // MC id for rPart
0754       {
0755         const int rdId = rPart.DaughterIds()[iD];
0756         if ( !RtoMCParticleId[rdId].IsMatched() ) continue;
0757         const int mdId = RtoMCParticleId[rdId].GetBestMatch();
0758         mcDaughterIds.push_back(mdId);
0759         mmId = vMCParticles[mdId].GetMotherId();
0760       }
0761       
0762       iD++;
0763       for ( ; iD < NRDaughters; iD++ ) {
0764         const int rdId = rPart.DaughterIds()[iD];
0765         if ( !RtoMCParticleId[rdId].IsMatched() ) break;
0766         const int mdId = RtoMCParticleId[rdId].GetBestMatch();
0767         mcDaughterIds.push_back(mdId);
0768 
0769         if(isMissingMass)
0770         {
0771           const KFMCParticle &neutralDaughter = vMCParticles[mdId];
0772           if(mmId != vMCParticles[neutralDaughter.GetMotherId()].InitialParticleId()) break;
0773           mmId = neutralDaughter.GetMotherId();
0774         }
0775         
0776         if( !(isMissingMass) && (vMCParticles[mdId].GetMotherId() != mmId) ) break;
0777       }
0778       
0779       int nClones = 0;
0780       sort(mcDaughterIds.begin(), mcDaughterIds.end());
0781       for(unsigned int ie=1; ie<mcDaughterIds.size(); ie++)
0782       {
0783         if(mcDaughterIds[ie] == mcDaughterIds[ie-1])
0784           nClones++;
0785       }
0786 
0787       if(nClones > 0) continue;
0788       
0789       if ( iD == NRDaughters && mmId > -1 ) { // match is found and it is not primary vertex
0790         KFMCParticle &mmPart = vMCParticles[mmId];
0791         
0792         if( mmPart.GetPDG()     == rPart.GetPDG()     &&
0793             mmPart.NDaughters() == rPart.NDaughters() ) {
0794           MCtoRParticleId[mmId].ids.push_back(iRP);
0795           RtoMCParticleId[iRP].ids.push_back(mmId);        
0796         }
0797         else {
0798           MCtoRParticleId[mmId].idsMI.push_back(iRP);
0799           RtoMCParticleId[iRP].idsMI.push_back(mmId);
0800         }
0801       }
0802     }
0803   }
0804 }
0805 
0806 void KFTopoPerformance::MatchPV()
0807 {
0808   /** Matches Monte Carlo and reconstructed primary vertices. */
0809   MCtoRPVId.clear();
0810   RtoMCPVId.clear();
0811   MCtoRPVId.resize(fPrimVertices.size());
0812   RtoMCPVId.resize(fTopoReconstructor->NPrimaryVertices() );
0813 
0814   fPVPurity.clear();
0815   fPVPurity.resize(fTopoReconstructor->NPrimaryVertices(), 0.);
0816   fNCorrectPVTracks.clear();
0817   fNCorrectPVTracks.resize(fTopoReconstructor->NPrimaryVertices(), 0);
0818 
0819   for(int iE = 0; iE<4; iE++)
0820   {
0821     fPVTracksRate[iE].clear();
0822     fPVTracksRate[iE].resize(fTopoReconstructor->NPrimaryVertices(),0);
0823   }
0824   
0825   for( unsigned int iMCPV=0; iMCPV<fPrimVertices.size(); iMCPV++)
0826   {
0827     KFMCVertex &mcPV = fPrimVertices[iMCPV];
0828     int nReconstructedDaughters = 0;
0829     for(int iD=0; iD<mcPV.NDaughterTracks(); iD++)
0830       if(MCtoRParticleId[ mcPV.DaughterTrack(iD) ].IsMatched())
0831         nReconstructedDaughters++;
0832     
0833     mcPV.SetNReconstructedDaughters(nReconstructedDaughters);
0834   }
0835 
0836   for( int iPV = 0; iPV < fTopoReconstructor->NPrimaryVertices(); iPV++ ) {
0837 
0838     vector<int> &tracks = fTopoReconstructor->GetPVTrackIndexArray(iPV);
0839     
0840     int nPVTracks = tracks.size()>0 ? tracks.size() : -1;//tracks.size();
0841     
0842     vector<short int> nTracksFromMCPV(fPrimVertices.size() + vMCParticles.size(), 0);
0843     vector< vector<int> > mcIDs(fPrimVertices.size() + vMCParticles.size());
0844 
0845     int nGhostTracks = 0;
0846     int nTriggerTracks = 0;
0847     int nPileupTracks = 0;
0848     int nBGTracks = 0;
0849         
0850     for(int iRP=0; iRP < nPVTracks; iRP++)
0851     {
0852       const int rTrackId = tracks[iRP];
0853       if ( !RtoMCParticleId[rTrackId].IsMatched() )
0854       {
0855         nGhostTracks++;
0856         continue;
0857       }
0858             
0859       int iMCPart = RtoMCParticleId[rTrackId].GetBestMatch();
0860       KFMCParticle &mcPart = vMCParticles[iMCPart];
0861       int iMCTrack = mcPart.GetMCTrackID();
0862       KFMCTrack &mcTrack = vMCTracks[iMCTrack];
0863       
0864       int motherId = mcTrack.MotherId();
0865 
0866       if(motherId < 0) //real PV
0867       {
0868         if(motherId == -1)
0869           nTriggerTracks++;
0870         if(motherId < -1)
0871           nPileupTracks++;
0872         
0873         int iMCPV = fMCTrackToMCPVMatch[iMCTrack];
0874         if(iMCPV < 0)
0875         {
0876           std::cout << "Error!!!  iMCPV < 0" << std::endl;
0877           continue;
0878         }
0879       
0880         nTracksFromMCPV[iMCPV]++;
0881         mcIDs[iMCPV].push_back(iMCTrack);
0882       }
0883       else // pchysics background
0884       {        
0885         if(motherId >-1)
0886         {
0887           nBGTracks++;
0888 
0889           int iMCPV = motherId + fPrimVertices.size();
0890       
0891           nTracksFromMCPV[iMCPV]++;
0892           mcIDs[iMCPV].push_back(iMCTrack);
0893         }
0894       }
0895     }
0896     
0897 
0898 
0899     for(unsigned int iMCPV=0; iMCPV<nTracksFromMCPV.size(); iMCPV++)
0900     {
0901       int nClones = 0;
0902       sort(mcIDs[iMCPV].begin(), mcIDs[iMCPV].end());
0903       for(unsigned int ie=1; ie<mcIDs[iMCPV].size(); ie++)
0904       {
0905         if(mcIDs[iMCPV][ie] == mcIDs[iMCPV][ie-1])
0906           nClones++;
0907       }
0908       nTracksFromMCPV[iMCPV] = nTracksFromMCPV[iMCPV] - nClones;
0909       nPVTracks -= nClones;
0910     }
0911 
0912     // calculate rate of each type of tracks in reconstructed PV
0913     fPVTracksRate[0][iPV] = double(nGhostTracks)/double(nPVTracks);
0914     fPVTracksRate[1][iPV] = double(nTriggerTracks)/double(nPVTracks);
0915     fPVTracksRate[2][iPV] = double(nPileupTracks)/double(nPVTracks);
0916     fPVTracksRate[3][iPV] = double(nBGTracks)/double(nPVTracks);
0917 
0918     int iBestMCPV=-1;
0919     int nTracksBestMCPV = 1;
0920     for(unsigned int iMCPV=0; iMCPV<nTracksFromMCPV.size(); iMCPV++ )
0921     {
0922       if(nTracksFromMCPV[iMCPV] > nTracksBestMCPV )
0923       {
0924         nTracksBestMCPV = nTracksFromMCPV[iMCPV];
0925         iBestMCPV = iMCPV;
0926       }
0927     }
0928 
0929     if( (iBestMCPV > -1) && (iBestMCPV<int(fPrimVertices.size())) )
0930     {
0931       fNCorrectPVTracks[iPV] = nTracksFromMCPV[iBestMCPV];
0932     }
0933     else
0934       fNCorrectPVTracks[iPV] = 0;
0935     
0936     double purity = double(nTracksBestMCPV)/double(nPVTracks);
0937 
0938     fPVPurity[iPV] = purity;
0939 //     if(purity < 0.7) continue;
0940 
0941     if(iBestMCPV < 0) continue;
0942     
0943     if(iBestMCPV < int(fPrimVertices.size()))
0944     {
0945       fPrimVertices[iBestMCPV].SetReconstructed();
0946     
0947       MCtoRPVId[iBestMCPV].ids.push_back(iPV);
0948       RtoMCPVId[iPV].ids.push_back(iBestMCPV);
0949     }
0950     else
0951     {
0952       RtoMCPVId[iPV].idsMI.push_back(iBestMCPV);
0953     }
0954   }
0955 }
0956 
0957 void KFTopoPerformance::MatchTracks()
0958 {
0959   /** Runs reading of Monte Carlo particles and vertices, their matching, calculation of efficiency. */
0960 #ifdef KFPWITHTRACKER
0961   for(int iTr=0; iTr<vMCTracks.size(); iTr++)
0962   {
0963     if( (AliHLTTPCCAPerformance::Instance().GetSubPerformance("Global Performance")->GetMCData())[iTr].IsReconstructed() )
0964       vMCTracks[iTr].SetReconstructed();
0965   } 
0966   fTrackMatch.resize(AliHLTTPCCAPerformance::Instance().GetSubPerformance("Global Performance")->GetRecoData().size());
0967   for(int iTr=0; iTr<fTrackMatch.size(); iTr++)
0968   {
0969     const AliHLTTPCCAPerformanceRecoTrackData& matchInfo = (AliHLTTPCCAPerformance::Instance().GetSubPerformance("Global Performance")->GetRecoData())[iTr];
0970     if( matchInfo.IsGhost(PParameters::MinTrackPurity) || matchInfo.GetMCTrackId()<0  )
0971       fTrackMatch[iTr] = -1;
0972     else
0973       fTrackMatch[iTr] = matchInfo.GetMCTrackId();
0974   }
0975 #endif
0976 
0977   GetMCParticles();
0978   FindReconstructableMCParticles();
0979   MatchParticles();
0980   CalculateEfficiency();
0981   
0982   FindReconstructableMCVertices();
0983   MatchPV();
0984   CalculatePVEfficiency();
0985 } // void KFTopoPerformance::MatchTracks()
0986 
0987 void KFTopoPerformance::CalculateEfficiency()
0988 {
0989   /** Calculates reconstruction efficiency of short-lived particles. */
0990   KFPartEfficiencies partEff; // efficiencies for current event
0991 
0992   const int NRP = fTopoReconstructor->GetParticles().size();
0993   for ( int iP = 0; iP < NRP; ++iP ) {
0994 //    const CbmKFParticle &part = fPF->GetParticles()[iP];
0995     const KFParticle &part = fTopoReconstructor->GetParticles()[iP];
0996     const int pdg = part.GetPDG();
0997 
0998     const bool isBG = RtoMCParticleId[iP].idsMI.size() != 0;
0999     const bool isGhost = !RtoMCParticleId[iP].IsMatched();
1000 
1001     for(int iPart=0; iPart<fParteff.nParticles; iPart++)
1002       if ( pdg == fParteff.partPDG[iPart] )
1003         partEff.IncReco(isGhost, isBG, fParteff.partName[iPart].data());
1004     
1005     // Calculate the gost level for V0
1006     if(abs(pdg) == 310  /*||
1007        CAMath::Abs(pdg) == 3122 ||
1008        CAMath::Abs(pdg) == 421  ||
1009        CAMath::Abs(pdg) == 22 */)
1010     {
1011       partEff.IncReco(isGhost, 0, fParteff.partName[fParteff.nParticles - 1].data());
1012     }
1013   }
1014 
1015   const int NMP = vMCParticles.size();
1016   for ( int iP = 0; iP < NMP; ++iP ) {
1017     const KFMCParticle &part = vMCParticles[iP];
1018     const int pdg = part.GetPDG();
1019     const int mId = part.GetMotherId();
1020     
1021     vector<bool> isReco;
1022     vector<int> nClones;
1023 
1024     vector<int> iParticle;
1025     iParticle.push_back(fParteff.GetParticleIndex(pdg));
1026     vector< vector<bool> > isReconstructable;
1027     vector<bool> isRecPart;
1028 
1029     const std::map<int,bool>& decays = fTopoReconstructor->GetKFParticleFinder()->GetReconstructionList();
1030     if(!(decays.empty()) && (iParticle[0] < fParteff.fFirstStableParticleIndex || iParticle[0] > fParteff.fLastStableParticleIndex))
1031       if(decays.find(pdg) == decays.end()) continue;
1032         
1033     if( fParteff.GetParticleIndex(pdg)>=KFPartEfficiencies::fFirstMissingMassParticleIndex &&
1034         fParteff.GetParticleIndex(pdg)<=KFPartEfficiencies::fLastMissingMassParticleIndex )
1035     {
1036       isRecPart.push_back(part.IsReconstructable(4));
1037       isRecPart.push_back(part.IsReconstructable(1));
1038       isRecPart.push_back(part.IsReconstructable(3));
1039     }
1040     else
1041       for(int iEff = 0; iEff < 3; iEff++)
1042         isRecPart.push_back(part.IsReconstructable(iEff));
1043     
1044     isReconstructable.push_back(isRecPart);
1045     isReco.push_back( MCtoRParticleId[iP].ids.size() != 0 );
1046     nClones.push_back( MCtoRParticleId[iP].ids.size() - 1 );
1047     
1048     if(decays.empty() && (part.IsReconstructableV0(0) || part.IsReconstructableV0(1) || part.IsReconstructableV0(2)) )
1049     {
1050       iParticle.push_back(fParteff.nParticles - 1);
1051       vector<bool> isRecV0;
1052       for(int iEff = 0; iEff < 3; iEff++)
1053         isRecV0.push_back(part.IsReconstructableV0(iEff));
1054       isReconstructable.push_back(isRecV0);
1055       isReco.push_back( (MCtoRParticleId[iP].ids.size() != 0) || (MCtoRParticleId[iP].idsMI.size() != 0) );
1056       
1057       int nClonesV0 = MCtoRParticleId[iP].ids.size() + MCtoRParticleId[iP].idsMI.size() - 1;
1058       nClones.push_back( nClonesV0 );
1059     }
1060 
1061     {
1062       for(unsigned int iPType=0; iPType<iParticle.size(); iPType++)
1063       {
1064         int iPart = iParticle[iPType];
1065         if(iPart<0) continue;
1066           
1067         partEff.Inc(isReco[iPType], nClones[iPType], isReconstructable[iPType][0], isReconstructable[iPType][1], isReconstructable[iPType][2], fParteff.partName[iPart].data());
1068         if ( mId == -1 )
1069           partEff.Inc(isReco[iPType], nClones[iPType], isReconstructable[iPType][0], isReconstructable[iPType][1], isReconstructable[iPType][2], (fParteff.partName[iPart]+"_prim").data());
1070         else
1071           partEff.Inc(isReco[iPType], nClones[iPType], isReconstructable[iPType][0], isReconstructable[iPType][1], isReconstructable[iPType][2], (fParteff.partName[iPart]+"_sec").data());
1072         
1073         for(int iEff=0; iEff<3; iEff++)
1074         {
1075           if(!isReconstructable[iPType][iEff]) continue;
1076           
1077           int iMCTrack = part.GetMCTrackID();
1078           KFMCTrack &mcTrack = vMCTracks[iMCTrack];
1079           
1080           Double_t massMC = fParteff.partMass[iPart];
1081           Double_t E = sqrt(mcTrack.P()*mcTrack.P() + massMC*massMC);
1082           Double_t Y = 0.5*log((E + mcTrack.Pz())/(E - mcTrack.Pz()));
1083           Double_t Z = mcTrack.Z();
1084           Double_t R = -1, L=-1;
1085           Double_t Mt_mc = sqrt(mcTrack.Pt()*mcTrack.Pt()+massMC*massMC)-massMC;
1086           Double_t cT = -1.e10;
1087           Double_t decayLength = -1.e10;
1088           
1089           if(part.NDaughters() > 0)
1090           {
1091             int mcDaughterId = part.GetDaughterIds()[0];
1092             KFMCTrack &mcDaughter = vMCTracks[mcDaughterId];
1093             R = sqrt(mcDaughter.X()*mcDaughter.X() + mcDaughter.Y()*mcDaughter.Y());
1094             L = sqrt(mcDaughter.X()*mcDaughter.X() + mcDaughter.Y()*mcDaughter.Y());
1095             Z = mcDaughter.Z();
1096             
1097             if(mcTrack.MotherId() < 0)
1098             {
1099               KFParticle motherKFParticle;
1100               float decayPoint[3] = { mcDaughter.X(), mcDaughter.Y(), mcDaughter.Z() };
1101               for(int iP=0; iP<6; iP++)
1102                 motherKFParticle.Parameter(iP) = mcTrack.Par()[iP];
1103               
1104               float dsdr[6];
1105               double s = motherKFParticle.GetDStoPoint(decayPoint, dsdr);
1106               int jParticlePDG = fParteff.GetParticleIndex(mcTrack.PDG());      
1107               Double_t massMC = (jParticlePDG>=0) ? fParteff.partMass[jParticlePDG] :0.13957;
1108               
1109               cT = s*massMC;
1110               decayLength = s*mcTrack.P();
1111             }
1112           }
1113 
1114           if(fStoreMCHistograms)
1115           {
1116             hPartEfficiency[iPart][iEff][0]->Fill( mcTrack.P(), isReco[iPType] );
1117             hPartEfficiency[iPart][iEff][1]->Fill( mcTrack.Pt(), isReco[iPType] );
1118             hPartEfficiency[iPart][iEff][2]->Fill( Y, isReco[iPType] );
1119             hPartEfficiency[iPart][iEff][3]->Fill( Z, isReco[iPType] );
1120             if(cT > -1.e10)          hPartEfficiency[iPart][iEff][4]->Fill( cT, isReco[iPType] );
1121             if(decayLength > -1.e10) hPartEfficiency[iPart][iEff][5]->Fill( decayLength, isReco[iPType] );
1122             hPartEfficiency[iPart][iEff][3]->Fill( Z, isReco[iPType] );
1123             hPartEfficiency[iPart][iEff][6]->Fill( L, isReco[iPType] );
1124             hPartEfficiency[iPart][iEff][7]->Fill( R, isReco[iPType] );
1125             hPartEfficiency[iPart][iEff][8]->Fill( Mt_mc, isReco[iPType] );
1126             
1127             hPartEfficiency2D[iPart][iEff][0]->Fill( Y, mcTrack.Pt(), isReco[iPType] );
1128             hPartEfficiency2D[iPart][iEff][1]->Fill( Y, Mt_mc, isReco[iPType] );
1129           }
1130         }
1131       }
1132     }
1133   }
1134 
1135   fNEvents++;
1136 
1137   fParteff += partEff;
1138 
1139   partEff.CalcEff();
1140   fParteff.CalcEff();
1141 
1142   if(fNEvents%fPrintEffFrequency == 0)
1143   {
1144     std::cout << " ---- KF Particle finder --- " << std::endl;
1145     std::cout << "ACCUMULATED STAT    : " << fNEvents << " EVENTS "               << std::endl << std::endl;
1146     fParteff.PrintEff();
1147     std::cout<<std::endl;
1148   }
1149 }
1150 
1151 void KFTopoPerformance::CalculatePVEfficiency()
1152 {
1153   /** Calculates reconstruction efficiency of primary vertices. */
1154   KFPVEfficiencies pvEff; // efficiencies for current event
1155   KFPVEfficiencies pvEffMCReconstructable;
1156   int nTracks = 0;
1157   //calculate N reco tracks
1158   for( unsigned int iRP = 0; iRP < fTopoReconstructor->GetParticles().size(); iRP++ ) {
1159 //    CbmKFParticle &rPart = fTopoReconstructor->GetParticles()[iRP];
1160     const KFParticle &rPart = fTopoReconstructor->GetParticles()[iRP];
1161 
1162     if (rPart.NDaughters() != 1) continue;
1163     
1164     nTracks++;
1165   }
1166     
1167   const int NRecoPV = fTopoReconstructor->NPrimaryVertices();
1168   for ( int iP = 0; iP < NRecoPV; ++iP ) {
1169       
1170     const bool isBG = RtoMCPVId[iP].idsMI.size() != 0;
1171     const bool isGhost = !RtoMCPVId[iP].IsMatched();
1172 
1173     pvEff.IncReco(isGhost, isBG, "PV");
1174     pvEffMCReconstructable.IncReco(isGhost, isBG, "PV");
1175   }
1176 
1177   const int NMCPV = fPrimVertices.size();
1178   for ( int iV = 0; iV < NMCPV; ++iV ) {
1179     const KFMCVertex &pvMC = fPrimVertices[iV];
1180     if ( pvMC.IsReconstructable() ) 
1181     {
1182       const bool isReco = pvMC.IsReconstructed();
1183       const int nClones = MCtoRPVId[iV].ids.size() - 1;
1184 
1185         
1186       pvEff.Inc(isReco, nClones, "PV");
1187       if ( pvMC.IsTriggerPV() )
1188       {
1189         pvEff.Inc(isReco, nClones, "PVtrigger");
1190         hPVefficiency[0][0]->Fill( pvMC.NDaughterTracks(), isReco );
1191         hPVefficiency[0][1]->Fill( NMCPV, isReco );
1192         hPVefficiency[0][2]->Fill( vMCTracks.size(), isReco );
1193         hPVefficiency[0][3]->Fill( pvMC.NReconstructedDaughterTracks(), isReco );
1194         hPVefficiency[0][4]->Fill( NRecoPV, isReco );
1195         hPVefficiency[0][5]->Fill( nTracks, isReco );
1196       }
1197       else
1198       {
1199         pvEff.Inc(isReco, nClones, "PVpileup");
1200         hPVefficiency[1][0]->Fill( pvMC.NDaughterTracks(), isReco );
1201         hPVefficiency[1][1]->Fill( NMCPV, isReco );
1202         hPVefficiency[1][2]->Fill( vMCTracks.size(), isReco );
1203         hPVefficiency[1][3]->Fill( pvMC.NReconstructedDaughterTracks(), isReco );
1204         hPVefficiency[1][4]->Fill( NRecoPV, isReco );
1205         hPVefficiency[1][5]->Fill( nTracks, isReco );
1206       }
1207     }
1208     if ( pvMC.IsMCReconstructable() ) 
1209     {
1210       const bool isReco = pvMC.IsReconstructed();
1211       const int nClones = MCtoRPVId[iV].ids.size() - 1;
1212 
1213         
1214       pvEffMCReconstructable.Inc(isReco, nClones, "PV");
1215       if ( pvMC.IsTriggerPV() )
1216       {
1217         pvEffMCReconstructable.Inc(isReco, nClones, "PVtrigger");
1218         hPVefficiency[2][0]->Fill( pvMC.NDaughterTracks(), isReco );
1219         hPVefficiency[2][1]->Fill( NMCPV, isReco );
1220         hPVefficiency[2][2]->Fill( vMCTracks.size(), isReco );
1221         hPVefficiency[2][3]->Fill( pvMC.NReconstructedDaughterTracks(), isReco );
1222         hPVefficiency[2][4]->Fill( NRecoPV, isReco );
1223         hPVefficiency[2][5]->Fill( nTracks, isReco );
1224       }
1225       else
1226       {
1227         pvEffMCReconstructable.Inc(isReco, nClones, "PVpileup");
1228         hPVefficiency[3][0]->Fill( pvMC.NDaughterTracks(), isReco );
1229         hPVefficiency[3][1]->Fill( NMCPV, isReco );
1230         hPVefficiency[3][2]->Fill( vMCTracks.size(), isReco );
1231         hPVefficiency[3][3]->Fill( pvMC.NReconstructedDaughterTracks(), isReco );
1232         hPVefficiency[3][4]->Fill( NRecoPV, isReco );
1233         hPVefficiency[3][5]->Fill( nTracks, isReco );
1234       }
1235     }
1236   }
1237 
1238   fPVeff += pvEff;
1239   
1240   pvEff.CalcEff();
1241   fPVeff.CalcEff();
1242   
1243   fPVeffMCReconstructable += pvEffMCReconstructable;
1244   pvEffMCReconstructable.CalcEff();
1245   fPVeffMCReconstructable.CalcEff();
1246 
1247   if(fNEvents%fPrintEffFrequency == 0)
1248   {
1249     std::cout << " ---- KF PV finder --- " << std::endl;
1250     std::cout << "ACCUMULATED STAT    : " << fNEvents << " EVENTS "               << std::endl << std::endl;
1251     std::cout << "PV with at least 2 reconstructed tracks is reconstructable:" << std::endl;
1252     fPVeff.PrintEff();
1253     std::cout << std::endl;
1254     std::cout << "PV with at least 2 MC tracks with 15 MC points is reconstructable:" << std::endl;
1255     fPVeffMCReconstructable.PrintEff();
1256 
1257     std::cout<<std::endl;
1258   }
1259 }
1260 
1261 void KFTopoPerformance::FillParticleParameters(KFParticle& TempPart,
1262                                                int iParticle,
1263                                                int iP,
1264                                                int iPV,
1265                                                TH1F* histoParameters[nParametersSet][KFPartEfficiencies::nParticles][nHistoPartParam],
1266                                                TH2F* histoParameters2D[nParametersSet][KFPartEfficiencies::nParticles][nHistoPartParam2D],
1267                                                TH3F* histoParameters3D[1][KFPartEfficiencies::nParticles][nHistoPartParam3D],
1268                                                TH1F* histoFit[KFPartEfficiencies::nParticles][nFitQA],
1269                                                TH1F* histoFitDaughtersQA[KFPartEfficiencies::nParticles][nFitQA],
1270                                                TH1F* histoDSToParticleQA[KFPartEfficiencies::nParticles][nDSToParticleQA],
1271                                                vector<int>* multiplicities)
1272 {
1273   /** Fills provided histograms with the parameters of the given particle. */
1274   
1275   const std::map<int,bool>& decays = fTopoReconstructor->GetKFParticleFinder()->GetReconstructionList();
1276   if(!(decays.empty()) && (iParticle < fParteff.fFirstStableParticleIndex || iParticle > fParteff.fLastStableParticleIndex))
1277     if(decays.find(TempPart.GetPDG()) == decays.end()) return;
1278     
1279   float M, M_t, ErrM;
1280   float dL, ErrdL; // decay length
1281   float cT, ErrcT; // c*tau
1282   float P, ErrP;
1283   float Pt;
1284   float Rapidity;
1285   float Theta;
1286   float Phi;
1287   float X,Y,Z,R;
1288   float QtAlpha[2];
1289     
1290   TempPart.GetMass(M,ErrM);
1291   TempPart.GetMomentum(P,ErrP);
1292   Pt = TempPart.GetPt();
1293   Rapidity = TempPart.GetRapidity();
1294   
1295   KFParticle TempPartTopo = TempPart;
1296   TempPartTopo.SetProductionVertex(fTopoReconstructor->GetPrimVertex(0));
1297   TempPartTopo.GetDecayLength(dL,ErrdL);
1298   TempPartTopo.GetLifeTime(cT,ErrcT);
1299   
1300   float chi2 = TempPart.GetChi2();
1301   Int_t ndf = TempPart.GetNDF();
1302   float prob = TMath::Prob(chi2, ndf);//(TDHelper<float>::Chi2IProbability( ndf, chi2 ));
1303   Theta = TempPart.GetTheta();
1304   Phi = TempPart.GetPhi();
1305   X = TempPart.GetX();
1306   Y = TempPart.GetY();
1307   Z = TempPart.GetZ();
1308 #ifdef CBM
1309   if(Z>=1. && iParticle>=54 && iParticle<=64) return;
1310 #endif
1311   R = sqrt(X*X+Y*Y);
1312   M_t = sqrt(Pt*Pt+fParteff.GetMass(iParticle)*fParteff.GetMass(iParticle))-fParteff.GetMass(iParticle);
1313   
1314   KFParticleSIMD tempSIMDPart(TempPart);
1315   float_v l,dl;
1316   KFParticleSIMD pv(fTopoReconstructor->GetPrimVertex(iPV));
1317   tempSIMDPart.GetDistanceToVertexLine(pv, l, dl);
1318 #ifdef __ROOT__
1319   if( (l[0] > 0.2f || Pt < 0.f) && (abs( TempPart.GetPDG() ) ==   4122 ||
1320                                     abs( TempPart.GetPDG() ) == 104122 ||
1321                                     abs( TempPart.GetPDG() ) == 204122 ||
1322                                     abs( TempPart.GetPDG() ) == 304122 ||
1323                                     abs( TempPart.GetPDG() ) == 404122 || 
1324                                     abs( TempPart.GetPDG() ) == 504122 )  ) return;
1325   if( (l[0] > 0.2f || Pt < 0.f) && (abs( TempPart.GetPDG() ) == 421 ||
1326                                     abs( TempPart.GetPDG() ) == 420 ||
1327                                     abs( TempPart.GetPDG() ) == 425 ||
1328                                     abs( TempPart.GetPDG() ) == 426 ||
1329                                     abs( TempPart.GetPDG() ) == 427 ||
1330                                     abs( TempPart.GetPDG() ) == 429)  ) return;
1331   if( (l[0] > 0.4f || Pt < 0.f) && (abs( TempPart.GetPDG() ) ==    411 ||
1332                                     abs( TempPart.GetPDG() ) == 100411 ||
1333                                     abs( TempPart.GetPDG() ) == 200411 ||
1334                                     abs( TempPart.GetPDG() ) == 300411)  ) return;
1335   if( (l[0] > 0.2f || Pt < 0.f) && (abs( TempPart.GetPDG() ) ==    431 ||
1336                                     abs( TempPart.GetPDG() ) == 100431 ||
1337                                     abs( TempPart.GetPDG() ) == 200431 ||
1338                                     abs( TempPart.GetPDG() ) == 300431 ||
1339                                     abs( TempPart.GetPDG() ) == 400431)  ) return;
1340   
1341 //   if(Pt < 2. && (abs( TempPart.GetPDG() ) ==    443 ||
1342 //                  abs( TempPart.GetPDG() ) == 100443 ||
1343 //                  abs( TempPart.GetPDG() ) == 200443 ||
1344 //                  abs( TempPart.GetPDG() ) == 300443 ||
1345 //                  abs( TempPart.GetPDG() ) == 400443 ||
1346 //                  abs( TempPart.GetPDG() ) == 500443) ) return;
1347   
1348   if(Pt < 0.5f && (abs( TempPart.GetPDG() ) == 3000 ||
1349                    abs( TempPart.GetPDG() ) == 3001) ) return;
1350 #endif
1351   float parameters[17] = {M, P, Pt, Rapidity, dL, cT, chi2/ndf, prob, Theta, Phi, X, Y, Z, R, l[0], l[0]/dl[0], M_t };
1352 
1353   //for all particle-candidates
1354   for(int iParam=0; iParam<17; iParam++)
1355     histoParameters[0][iParticle][iParam]->Fill(parameters[iParam]);
1356 
1357   if(multiplicities)
1358     multiplicities[0][iParticle]++;
1359 
1360   histoParameters2D[0][iParticle][0]->Fill(Rapidity,Pt,1);
1361   histoParameters2D[0][iParticle][3]->Fill(Rapidity,M_t,1);
1362   
1363   const bool drawZR = IsCollectZRHistogram(iParticle);
1364   if(histoParameters2D[0][iParticle][1] && drawZR)
1365   {
1366     histoParameters2D[0][iParticle][1]->Fill(Z,R,1);
1367   }
1368 
1369   if(TempPart.NDaughters() == 2 && IsCollectArmenteros(iParticle))
1370   {
1371     int index1 = TempPart.DaughterIds()[0];
1372     int index2 = TempPart.DaughterIds()[1];
1373     if(index1 >= int(fTopoReconstructor->GetParticles().size()) || 
1374         index2 >= int(fTopoReconstructor->GetParticles().size()) || 
1375         index1 < 0 || index2 < 0 ) 
1376       return;
1377       
1378     KFParticle posDaughter, negDaughter;
1379     if(int(fTopoReconstructor->GetParticles()[index1].Q()) > 0)
1380     {
1381       posDaughter = fTopoReconstructor->GetParticles()[index1];
1382       negDaughter = fTopoReconstructor->GetParticles()[index2];
1383     }
1384     else
1385     {
1386       negDaughter = fTopoReconstructor->GetParticles()[index1];
1387       posDaughter = fTopoReconstructor->GetParticles()[index2];
1388     }
1389     float vertex[3] = {TempPart.GetX(), TempPart.GetY(), TempPart.GetZ()};
1390     posDaughter.TransportToPoint(vertex);
1391     negDaughter.TransportToPoint(vertex);
1392     KFParticle::GetArmenterosPodolanski(posDaughter, negDaughter, QtAlpha );
1393     
1394     histoParameters2D[0][iParticle][2]->Fill(QtAlpha[1],QtAlpha[0],1);
1395   }
1396     
1397   //Fill 3D histograms for multi differential analysis
1398   if( histoParameters3D && IsCollect3DHistogram(iParticle))
1399   {
1400     histoParameters3D[0][iParticle][0]->Fill(Rapidity,Pt,M,1);
1401     histoParameters3D[0][iParticle][1]->Fill(Rapidity,M_t,M,1);
1402     if(fCentralityBin>=0)
1403     {
1404       histoParameters3D[0][iParticle][2]->Fill(fCentralityBin, Pt, M, fCentralityWeight);
1405       histoParameters3D[0][iParticle][3]->Fill(fCentralityBin, Rapidity, M, fCentralityWeight);
1406       histoParameters3D[0][iParticle][4]->Fill(fCentralityBin, M_t, M, fCentralityWeight);
1407     }
1408     histoParameters3D[0][iParticle][5]->Fill(cT, Pt, M, 1);
1409   }
1410   
1411   //Fill histograms for the side bands analysis
1412   if(histoDSToParticleQA && IsCollect3DHistogram(iParticle))
1413   {
1414     if(fabs(fParteff.GetMass(iParticle)-M) < 3.f*fParteff.GetMassSigma(iParticle))//SignalReco
1415     {
1416       for(int iParam=0; iParam<17; iParam++)
1417         histoParameters[4][iParticle][iParam]->Fill(parameters[iParam]);
1418       
1419       if(multiplicities)
1420         multiplicities[4][iParticle]++;
1421 
1422       histoParameters2D[4][iParticle][0]->Fill(Rapidity,Pt,1);
1423       histoParameters2D[4][iParticle][3]->Fill(Rapidity,M_t,1);
1424       
1425       if(drawZR)
1426       {
1427         if(histoParameters2D[4][iParticle][1])
1428           histoParameters2D[4][iParticle][1]->Fill(Z,R,1);
1429         if(histoParameters2D[4][iParticle][2])
1430           histoParameters2D[4][iParticle][2]->Fill(QtAlpha[1],QtAlpha[0],1);
1431       }
1432     }
1433     
1434     if( fabs(fParteff.GetMass(iParticle)-M) > 3.f*fParteff.GetMassSigma(iParticle) &&
1435         fabs(fParteff.GetMass(iParticle)-M) <= 6.f*fParteff.GetMassSigma(iParticle) )//BGReco
1436     {
1437       for(int iParam=0; iParam<17; iParam++)
1438         histoParameters[5][iParticle][iParam]->Fill(parameters[iParam]);
1439       
1440       if(multiplicities)
1441         multiplicities[5][iParticle]++;
1442 
1443       histoParameters2D[5][iParticle][0]->Fill(Rapidity,Pt,1);
1444       histoParameters2D[5][iParticle][3]->Fill(Rapidity,M_t,1);
1445       
1446       if(drawZR)
1447       {
1448         if(histoParameters2D[5][iParticle][1])
1449           histoParameters2D[5][iParticle][1]->Fill(Z,R,1);
1450         if(histoParameters2D[5][iParticle][2])
1451           histoParameters2D[5][iParticle][2]->Fill(QtAlpha[1],QtAlpha[0],1);
1452       }
1453     }
1454   }
1455   
1456   if(!fStoreMCHistograms) return;
1457 
1458   int iSet = 1;
1459   if(!RtoMCParticleId[iP].IsMatchedWithPdg()) //background
1460   {
1461     if(!RtoMCParticleId[iP].IsMatched()) iSet = 3; // for ghost particles - combinatorial background
1462     else iSet = 2; // for physical background
1463   }
1464   
1465   //Check if PV association is correct
1466   if(!histoDSToParticleQA && iSet == 1)
1467   { 
1468     int iMCPart = RtoMCParticleId[iP].GetBestMatchWithPdg();
1469     KFMCParticle &mcPart = vMCParticles[iMCPart];
1470     int iMCTrack = mcPart.GetMCTrackID();
1471     KFMCTrack &mcTrack = vMCTracks[iMCTrack];
1472     int motherId = mcTrack.MotherId();
1473     bool isSecondaryParticle = motherId >= 0;
1474     
1475     if(iPV >=0)
1476     {
1477       if(isSecondaryParticle)
1478         iSet = 4;
1479       else 
1480       {
1481         int iMCPV = -1;
1482         if(RtoMCPVId[iPV].IsMatchedWithPdg())
1483           iMCPV = RtoMCPVId[iPV].GetBestMatch();
1484         
1485         int iMCPVFromParticle = fMCTrackToMCPVMatch[iMCTrack];
1486         if(iMCPV != iMCPVFromParticle)
1487           iSet = 4;
1488       }
1489     }
1490     else
1491     {
1492       if(!isSecondaryParticle)
1493         iSet = 4;
1494     }
1495   }
1496   
1497   //for signal particles
1498   for(int iParam=0; iParam<17; iParam++)
1499     histoParameters[iSet][iParticle][iParam]->Fill(parameters[iParam]);
1500     
1501   if(multiplicities)
1502     multiplicities[iSet][iParticle]++;
1503   
1504   histoParameters2D[iSet][iParticle][0]->Fill(Rapidity,Pt,1);
1505   if(drawZR)
1506   {
1507     if(histoParameters2D[iSet][iParticle][1])
1508       histoParameters2D[iSet][iParticle][1]->Fill(Z,R,1);
1509     if(histoParameters2D[iSet][iParticle][2])
1510       histoParameters2D[iSet][iParticle][2]->Fill(QtAlpha[1],QtAlpha[0],1);
1511   }
1512   histoParameters2D[iSet][iParticle][3]->Fill(Rapidity,M_t,1);
1513   
1514   if(iSet != 1) return;
1515   
1516   int iMCPart = RtoMCParticleId[iP].GetBestMatchWithPdg();
1517   KFMCParticle &mcPart = vMCParticles[iMCPart];
1518   // Fit quality of the mother particle
1519   if(histoFit)
1520   {
1521     int iMCTrack = mcPart.GetMCTrackID();
1522     KFMCTrack &mcTrack = vMCTracks[iMCTrack];
1523     int mcDaughterId = -1;
1524     if(iParticle >= fParteff.fFirstStableParticleIndex && iParticle <= fParteff.fLastStableParticleIndex)
1525       mcDaughterId = iMCTrack;
1526     else if(mcTrack.PDG() == 22 && TempPart.NDaughters() == 1)
1527       mcDaughterId = iMCTrack;
1528     else if(iParticle >= fParteff.fFirstMissingMassParticleIndex && iParticle <= fParteff.fLastMissingMassParticleIndex)
1529       mcDaughterId = mcPart.GetDaughterIds()[1]; //the charged daughter
1530     else
1531       mcDaughterId = mcPart.GetDaughterIds()[0];
1532     
1533     KFMCTrack &mcDaughter = vMCTracks[mcDaughterId];
1534     
1535     float mcX =  mcTrack.X();
1536     float mcY =  mcTrack.Y();
1537     float mcZ =  mcTrack.Z();
1538     if(histoDSToParticleQA || hPartParamPrimary == histoParameters)
1539     {
1540       mcX =  mcDaughter.X();
1541       mcY =  mcDaughter.Y();
1542       mcZ =  mcDaughter.Z();
1543     }
1544     const float mcPx = mcTrack.Par(3);
1545     const float mcPy = mcTrack.Par(4);
1546     const float mcPz = mcTrack.Par(5);
1547 
1548     float decayVtx[3] = { mcTrack.X(), mcTrack.Y(), mcTrack.Z() };
1549     float recParam[8] = { 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f };
1550     float errParam[8] = { 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f };
1551 
1552     for(int iPar=0; iPar<3; iPar++)
1553     {
1554       recParam[iPar] = TempPart.GetParameter(iPar);
1555       Double_t error = TempPart.GetCovariance(iPar,iPar);
1556       if(error < 0.) { error = 1.e20;}
1557       errParam[iPar] = TMath::Sqrt(error);
1558     }
1559     TempPart.TransportToPoint(decayVtx);
1560     for(int iPar=3; iPar<7; iPar++)
1561     {
1562       recParam[iPar] = TempPart.GetParameter(iPar);
1563       Double_t error = TempPart.GetCovariance(iPar,iPar);
1564       if(error < 0.) { error = 1.e20;}
1565       errParam[iPar] = TMath::Sqrt(error);
1566     }
1567 
1568     int jParticlePDG = fParteff.GetParticleIndex(mcTrack.PDG());      
1569     Double_t massMC = (jParticlePDG>=0) ? fParteff.partMass[jParticlePDG] :0.13957;
1570     
1571     Double_t Emc = sqrt(mcTrack.P()*mcTrack.P() + massMC*massMC);
1572     Double_t res[8] = {0}, 
1573               pull[8] = {0}, 
1574               mcParam[8] = { mcX, mcY, mcZ,
1575                             mcPx, mcPy, mcPz, Emc, massMC };
1576     for(int iPar=0; iPar < 7; iPar++ )
1577     {
1578       res[iPar]  = recParam[iPar] - mcParam[iPar];
1579       if(fabs(errParam[iPar]) > 1.e-20) pull[iPar] = res[iPar]/errParam[iPar];
1580     }
1581 
1582     res[7] = M - mcParam[7];
1583     if(fabs(ErrM) > 1.e-20) pull[7] = res[7]/ErrM;
1584 
1585     for(int iPar=0; iPar < 8; iPar++ )
1586     {
1587       histoFit[iParticle][iPar]->Fill(res[iPar]);
1588       histoFit[iParticle][iPar+8]->Fill(pull[iPar]);
1589     }
1590   }
1591   // Fit quality of daughters
1592   int daughterIndex[2] = {-1, -1};
1593   
1594   if(histoFitDaughtersQA)
1595   {
1596     for(int iD=0; iD<mcPart.NDaughters(); ++iD)
1597     {
1598       int mcDaughterId = mcPart.GetDaughterIds()[iD];
1599   //      if(!MCtoRParticleId[mcDaughterId].IsMatchedWithPdg()) continue;
1600       if(!MCtoRParticleId[mcDaughterId].IsMatched()) continue;
1601       KFMCTrack &mcTrack = vMCTracks[mcDaughterId];
1602   //      int recDaughterId = MCtoRParticleId[mcDaughterId].GetBestMatchWithPdg();
1603       int recDaughterId = MCtoRParticleId[mcDaughterId].GetBestMatch();
1604       KFParticle Daughter = fTopoReconstructor->GetParticles()[recDaughterId];
1605       Daughter.GetMass(M,ErrM);
1606 
1607       const float mcX =  mcTrack.X();
1608       const float mcY =  mcTrack.Y();
1609       const float mcZ =  mcTrack.Z();
1610       const float mcPx = mcTrack.Px();
1611       const float mcPy = mcTrack.Py();
1612       const float mcPz = mcTrack.Pz();
1613 
1614       float_v decayVtx[3] = {mcX, mcY, mcZ};
1615 
1616       KFParticleSIMD DaughterSIMD(Daughter);
1617       DaughterSIMD.TransportToPoint(decayVtx);
1618       
1619       int jParticlePDG = fParteff.GetParticleIndex(mcTrack.PDG());      
1620       Double_t massMC = (jParticlePDG>=0) ? fParteff.partMass[jParticlePDG] :0.13957;
1621       Double_t Emc = sqrt(mcTrack.P()*mcTrack.P() + massMC*massMC);
1622       
1623       Double_t res[8] = {0}, 
1624                 pull[8] = {0}, 
1625                 mcParam[8] = { mcX, mcY, mcZ,
1626                               mcPx, mcPy, mcPz, Emc, massMC };
1627       for(int iPar=0; iPar < 7; iPar++ )
1628       {
1629         Double_t error = DaughterSIMD.GetCovariance(iPar,iPar)[0];
1630         if(error < 0.) { error = 1.e20;}
1631         error = TMath::Sqrt(error);
1632         Double_t recoPar = DaughterSIMD.GetParameter(iPar)[0];
1633         res[iPar]  = recoPar - mcParam[iPar];
1634         if(fabs(error) > 1.e-20) pull[iPar] = res[iPar]/error;
1635       }
1636       res[7] = M - mcParam[7];
1637       if(fabs(ErrM) > 1.e-20) pull[7] = res[7]/ErrM;
1638 
1639       for(int iPar=0; iPar < 8; iPar++ )
1640       {
1641         histoFitDaughtersQA[iParticle][iPar]->Fill(res[iPar]);
1642         histoFitDaughtersQA[iParticle][iPar+8]->Fill(pull[iPar]);
1643       }
1644       
1645       //fill Histos for GetDStoParticle
1646       if(iD == 0)
1647         daughterIndex[0] = recDaughterId;
1648       if(iD == 1 && daughterIndex[0] > -1 && histoDSToParticleQA)
1649       {
1650         daughterIndex[1] = recDaughterId;
1651         KFParticle d1 = fTopoReconstructor->GetParticles()[daughterIndex[0]];
1652         KFParticle d2 = fTopoReconstructor->GetParticles()[daughterIndex[1]];
1653         
1654         KFParticleSIMD daughters[2] = {d2, d1};
1655         
1656         float_v dS[2] = {0.f, 0.f};
1657         float_v dsdr[4][6];
1658         for(int i1=0; i1<4; i1++)
1659           for(int i2=0; i2<6; i2++)
1660             dsdr[i1][i2] = 0.f;
1661           
1662         daughters[0].GetDStoParticle(daughters[1], dS, dsdr);
1663         float_v pD[2][8], cD[2][36], corrPD[2][36], corrCD[2][36];
1664         
1665         for(int iDR=0; iDR<2; iDR++)
1666         {
1667           for(int iPD = 0; iPD<8; iPD++)
1668           {
1669             pD[iDR][iPD] = 0;
1670             corrPD[iDR][iPD] = 0;
1671           }
1672           for(int iCD=0; iCD<36; iCD++)
1673           {
1674             cD[iDR][iCD] = 0;
1675             corrCD[iDR][iCD] = 0;
1676           }
1677         }
1678         
1679         float_v F[4][36];
1680         {
1681           for(int i1=0; i1<4; i1++)
1682             for(int i2=0; i2<36; i2++)
1683                 F[i1][i2] = 0;
1684         }
1685         daughters[0].Transport(dS[0], dsdr[0], pD[0], cD[0], dsdr[1], F[0], F[1]);
1686         daughters[1].Transport(dS[1], dsdr[3], pD[1], cD[1], dsdr[2], F[3], F[2]);
1687         
1688         daughters[0].MultQSQt( F[1], daughters[1].CovarianceMatrix(), corrCD[0], 6);
1689         daughters[0].MultQSQt( F[2], daughters[0].CovarianceMatrix(), corrCD[1], 6);
1690         for(int iDR=0; iDR<2; iDR++)
1691           for(int iC=0; iC<6; iC++)
1692             cD[iDR][iC] += corrCD[iDR][iC];
1693 
1694         for(int iDR=0; iDR<2; iDR++)
1695         {
1696           cD[iDR][1] = cD[iDR][2];
1697           cD[iDR][2] = cD[iDR][5];
1698           for(int iPar=0; iPar<3; iPar++)
1699           {
1700             res[iPar] = pD[iDR][iPar][0] - decayVtx[iPar][0];
1701             
1702             Double_t error = cD[iDR][iPar][0];
1703             if(error < 0.) { error = 1.e20;}
1704             error = sqrt(error);
1705             
1706             pull[iPar] = res[iPar] / error;
1707             
1708             histoDSToParticleQA[iParticle][iPar]->Fill(res[iPar]);
1709             histoDSToParticleQA[iParticle][iPar+3]->Fill(pull[iPar]);
1710           }
1711         }
1712         
1713         Double_t dXds = pD[0][0][0] - pD[1][0][0];
1714         Double_t dYds = pD[0][1][0] - pD[1][1][0];
1715         Double_t dZds = pD[0][2][0] - pD[1][2][0];
1716         
1717         Double_t dRds = sqrt(dXds*dXds + dYds*dYds + dZds*dZds);
1718         histoDSToParticleQA[iParticle][6]->Fill(dRds);
1719       }
1720     }
1721   }
1722 }
1723 
1724 void KFTopoPerformance::FillHistos()
1725 {
1726   /** Fills histograms with parameter  distributions and fit quality for all particle and primary vertex candidates. */
1727   vector<int> multiplicities[6];
1728   for(int iV=0; iV<6; iV++)
1729     multiplicities[iV].resize(KFPartEfficiencies::nParticles, 0);
1730   
1731   //fill histograms for found short-lived particles
1732   for(unsigned int iP=0; iP<fTopoReconstructor->GetParticles().size(); iP++)
1733   {
1734     int iParticle = fParteff.GetParticleIndex(fTopoReconstructor->GetParticles()[iP].GetPDG());
1735     if(iParticle < 0) continue;
1736     KFParticle TempPart = fTopoReconstructor->GetParticles()[iP];
1737     
1738     FillParticleParameters(TempPart,iParticle, iP, 0, hPartParam, hPartParam2D, hPartParam3D,
1739                            hFitQA, hFitDaughtersQA, hDSToParticleQA, multiplicities);
1740   }
1741   
1742   if(fStoreMCHistograms)
1743   {
1744     for(int iSet=0; iSet<KFParticleFinder::GetNSecondarySets(); iSet++)
1745     {
1746       const std::vector<KFParticle>& SecondaryCandidates = fTopoReconstructor->GetKFParticleFinder()->GetSecondaryCandidates()[iSet];
1747       for(unsigned int iP=0; iP<SecondaryCandidates.size(); iP++)
1748       {
1749         KFParticle TempPart = SecondaryCandidates[iP];
1750         int iParticle = fParteff.GetParticleIndex(TempPart.GetPDG());
1751         if(iParticle < 0) continue;
1752         
1753         const int id = TempPart.Id();
1754         FillParticleParameters(TempPart, iParticle, id, 0, hPartParamSecondaryMass, hPartParam2DSecondaryMass, 0);
1755         
1756         TempPart = fTopoReconstructor->GetParticles()[id];
1757         FillParticleParameters(TempPart, iParticle, id, 0, hPartParamSecondary, hPartParam2DSecondary, 0);
1758       }
1759     }
1760     
1761     for(int iSet=0; iSet<KFParticleFinder::GetNPrimarySets(); iSet++)
1762     {
1763       for(int iPV=0; iPV<fTopoReconstructor->NPrimaryVertices(); iPV++)
1764       {
1765         const std::vector<KFParticle>& PrimaryCandidates = fTopoReconstructor->GetKFParticleFinder()->GetPrimaryCandidates()[iSet][iPV];
1766         for(unsigned int iP=0; iP<PrimaryCandidates.size(); iP++)
1767         {
1768           KFParticle TempPart =  PrimaryCandidates[iP];
1769           int iParticle = fParteff.GetParticleIndex(TempPart.GetPDG());
1770           if(iParticle < 0) continue;
1771           
1772           const int id = TempPart.Id();
1773           FillParticleParameters(TempPart,iParticle, id, iPV, hPartParamPrimaryMass, hPartParam2DPrimaryMass, 0, hFitQAMassConstraint);
1774           
1775           TempPart = fTopoReconstructor->GetParticles()[id];
1776           FillParticleParameters(TempPart,iParticle, id, iPV, hPartParamPrimary, hPartParam2DPrimary, 0, hFitQANoConstraint);
1777         }
1778         
1779         const std::vector<KFParticle>& PrimaryCandidatesTopo = fTopoReconstructor->GetKFParticleFinder()->GetPrimaryTopoCandidates()[iSet][iPV];
1780         for(unsigned int iP=0; iP<PrimaryCandidatesTopo.size(); iP++)
1781         {
1782           KFParticle TempPart =  PrimaryCandidatesTopo[iP];
1783           int iParticle = fParteff.GetParticleIndex(TempPart.GetPDG());
1784           if(iParticle < 0) continue;
1785           
1786           FillParticleParameters(TempPart,iParticle, TempPart.Id(), iPV, hPartParamPrimaryTopo, hPartParam2DPrimaryTopo, 0, hFitQATopoConstraint);
1787         }
1788         
1789         const std::vector<KFParticle>& PrimaryCandidatesTopoMass = fTopoReconstructor->GetKFParticleFinder()->GetPrimaryTopoMassCandidates()[iSet][iPV];
1790         for(unsigned int iP=0; iP<PrimaryCandidatesTopoMass.size(); iP++)
1791         {
1792           KFParticle TempPart =  PrimaryCandidatesTopoMass[iP];
1793           int iParticle = fParteff.GetParticleIndex(TempPart.GetPDG());
1794           if(iParticle < 0) continue;
1795           
1796           FillParticleParameters(TempPart,iParticle, TempPart.Id(), iPV, hPartParamPrimaryTopoMass, hPartParam2DPrimaryTopoMass, 0, hFitQATopoMassConstraint);
1797         }
1798       }
1799     }
1800   }
1801   //fill histograms with ChiPrim for every particle
1802   for(unsigned int iP=0; iP<fTopoReconstructor->GetParticles().size(); iP++)
1803   {
1804     KFParticle TempPart = fTopoReconstructor->GetParticles()[iP];
1805     KFParticle vtx = fTopoReconstructor->GetPrimVertex(0);
1806     
1807     if(RtoMCParticleId[iP].IsMatched())
1808     {
1809       int iMCPV = vMCParticles[RtoMCParticleId[iP].GetBestMatch()].GetMotherId();
1810       if(iMCPV<0.)
1811       {
1812         iMCPV = -iMCPV - 1;
1813         if(MCtoRPVId[iMCPV].IsMatched())
1814         { 
1815           vtx = fTopoReconstructor->GetPrimVertex(MCtoRPVId[iMCPV].GetBestMatch());
1816         }  
1817       }
1818     }
1819 //     else
1820 //       KFParticle & vtx = fTopoReconstructor->GetPrimVertex(0);
1821     
1822     
1823     float chi2 = TempPart.GetDeviationFromVertex(vtx);
1824     int ndf = 2;
1825     
1826     hTrackParameters[KFPartEfficiencies::nParticles]->Fill(chi2);
1827     hTrackParameters[KFPartEfficiencies::nParticles+4]->Fill(TMath::Prob(chi2, ndf));
1828     
1829     if(!RtoMCParticleId[iP].IsMatched()) 
1830     {
1831       hTrackParameters[KFPartEfficiencies::nParticles+3]->Fill(chi2);
1832       hTrackParameters[KFPartEfficiencies::nParticles+7]->Fill(TMath::Prob(chi2, ndf));
1833       continue;
1834     }
1835     
1836     int iMCPart = RtoMCParticleId[iP].GetBestMatch();
1837     KFMCParticle &mcPart = vMCParticles[iMCPart];
1838     if(mcPart.GetMotherId() < 0)
1839     {
1840       hTrackParameters[KFPartEfficiencies::nParticles+1]->Fill(chi2 );
1841       hTrackParameters[KFPartEfficiencies::nParticles+5]->Fill(TMath::Prob(chi2, ndf));
1842     }
1843     else
1844     {
1845       hTrackParameters[KFPartEfficiencies::nParticles+2]->Fill(chi2 );
1846       hTrackParameters[KFPartEfficiencies::nParticles+6]->Fill(TMath::Prob(chi2, ndf));
1847     }    
1848     int iParticle = fParteff.GetParticleIndex(fTopoReconstructor->GetParticles()[iP].GetPDG());
1849     if(iParticle > -1 && iParticle<KFPartEfficiencies::nParticles)
1850       hTrackParameters[iParticle]->Fill(chi2 );
1851     
1852   }
1853   
1854   
1855   //fill histograms of the primary vertex quality
1856   for(int iPV = 0; iPV<fTopoReconstructor->NPrimaryVertices(); iPV++)
1857   {
1858     KFParticle & vtx = fTopoReconstructor->GetPrimVertex(iPV);
1859     vector<int> &tracks = fTopoReconstructor->GetPVTrackIndexArray(iPV);
1860 
1861     Double_t probPV = TMath::Prob(vtx.Chi2(), vtx.NDF());//(TDHelper<float>::Chi2IProbability( ndf, chi2 ));
1862     vector<Double_t> dzPV;
1863     if(RtoMCPVId[iPV].IsMatched())
1864     {
1865       int iCurrMCPV = RtoMCPVId[iPV].GetBestMatch();
1866       for(int iPV2 = iPV+1; iPV2 < fTopoReconstructor->NPrimaryVertices(); iPV2++)
1867       {
1868         if(!RtoMCPVId[iPV2].IsMatched()) continue;
1869         int iCurrMCPV2 = RtoMCPVId[iPV2].GetBestMatch();
1870         if(iCurrMCPV != iCurrMCPV2) continue;
1871         KFParticle & vtx2 = fTopoReconstructor->GetPrimVertex(iPV2);
1872         
1873         dzPV.push_back(fabs(vtx.Z() - vtx2.Z())); 
1874       }
1875     }
1876     
1877     hPVParam[ 0]->Fill(vtx.X());
1878     hPVParam[ 1]->Fill(vtx.Y());
1879     hPVParam[ 2]->Fill(vtx.Z());
1880     hPVParam[ 3]->Fill(sqrt(vtx.X()*vtx.X() + vtx.Y()*vtx.Y()));
1881     hPVParam[ 4]->Fill(tracks.size());    
1882     hPVParam[ 5]->Fill(vtx.Chi2());
1883     hPVParam[ 6]->Fill(vtx.NDF());
1884     hPVParam[ 7]->Fill(vtx.Chi2()/vtx.NDF());      
1885     hPVParam[ 8]->Fill(probPV);
1886     hPVParam[ 9]->Fill(fPVPurity[iPV]);
1887     hPVParam[10]->Fill(fPVTracksRate[0][iPV]);
1888     hPVParam[11]->Fill(fPVTracksRate[1][iPV]);
1889     hPVParam[12]->Fill(fPVTracksRate[2][iPV]);
1890     hPVParam[13]->Fill(fPVTracksRate[3][iPV]);
1891     for(unsigned int iZ=0; iZ<dzPV.size(); iZ++)
1892       hPVParam[14]->Fill(dzPV[iZ]);
1893 
1894     hPVParam2D[0]->Fill(vtx.X(),vtx.Y());
1895 
1896     
1897     if(!RtoMCPVId[iPV].IsMatchedWithPdg())
1898     {
1899       if(!RtoMCPVId[iPV].IsMatched())
1900       {
1901         hPVParamGhost[ 0]->Fill(vtx.X());
1902         hPVParamGhost[ 1]->Fill(vtx.Y());
1903         hPVParamGhost[ 2]->Fill(vtx.Z());
1904         hPVParamGhost[ 3]->Fill(sqrt(vtx.X()*vtx.X() + vtx.Y()*vtx.Y()));
1905         hPVParamGhost[ 4]->Fill(tracks.size());    
1906         hPVParamGhost[ 5]->Fill(vtx.Chi2());
1907         hPVParamGhost[ 6]->Fill(vtx.NDF());
1908         hPVParamGhost[ 7]->Fill(vtx.Chi2()/vtx.NDF());      
1909         hPVParamGhost[ 8]->Fill(probPV);
1910         hPVParamGhost[ 9]->Fill(fPVPurity[iPV]);
1911         hPVParamGhost[10]->Fill(fPVTracksRate[0][iPV]);
1912         hPVParamGhost[11]->Fill(fPVTracksRate[1][iPV]);
1913         hPVParamGhost[12]->Fill(fPVTracksRate[2][iPV]);
1914         hPVParamGhost[13]->Fill(fPVTracksRate[3][iPV]);
1915         for(unsigned int iZ=0; iZ<dzPV.size(); iZ++)
1916           hPVParamGhost[14]->Fill(dzPV[iZ]);
1917       }
1918       else
1919       {
1920         hPVParamBG[ 0]->Fill(vtx.X());
1921         hPVParamBG[ 1]->Fill(vtx.Y());
1922         hPVParamBG[ 2]->Fill(vtx.Z());
1923         hPVParamBG[ 3]->Fill(sqrt(vtx.X()*vtx.X() + vtx.Y()*vtx.Y()));
1924         hPVParamBG[ 4]->Fill(tracks.size());    
1925         hPVParamBG[ 5]->Fill(vtx.Chi2());
1926         hPVParamBG[ 6]->Fill(vtx.NDF());
1927         hPVParamBG[ 7]->Fill(vtx.Chi2()/vtx.NDF());      
1928         hPVParamBG[ 8]->Fill(probPV);
1929         hPVParamBG[ 9]->Fill(fPVPurity[iPV]);
1930         hPVParamBG[10]->Fill(fPVTracksRate[0][iPV]);
1931         hPVParamBG[11]->Fill(fPVTracksRate[1][iPV]);
1932         hPVParamBG[12]->Fill(fPVTracksRate[2][iPV]);
1933         hPVParamBG[13]->Fill(fPVTracksRate[3][iPV]);
1934         for(unsigned int iZ=0; iZ<dzPV.size(); iZ++)
1935           hPVParamBG[14]->Fill(dzPV[iZ]);
1936       }
1937       continue;
1938     }
1939     
1940     int iMCPV = RtoMCPVId[iPV].GetBestMatch();
1941     KFMCVertex &mcPV = fPrimVertices[iMCPV]; // primary vertex positions (currently only one vertex is implemented)
1942     
1943     int iPVType = 0;
1944     if(mcPV.IsTriggerPV())
1945     {
1946       hPVParamSignal[ 0]->Fill(vtx.X());
1947       hPVParamSignal[ 1]->Fill(vtx.Y());
1948       hPVParamSignal[ 2]->Fill(vtx.Z());
1949       hPVParamSignal[ 3]->Fill(sqrt(vtx.X()*vtx.X() + vtx.Y()*vtx.Y()));
1950       hPVParamSignal[ 4]->Fill(tracks.size());    
1951       hPVParamSignal[ 5]->Fill(vtx.Chi2());
1952       hPVParamSignal[ 6]->Fill(vtx.NDF());
1953       hPVParamSignal[ 7]->Fill(vtx.Chi2()/vtx.NDF());      
1954       hPVParamSignal[ 8]->Fill(probPV);
1955       hPVParamSignal[ 9]->Fill(fPVPurity[iPV]);
1956       hPVParamSignal[10]->Fill(fPVTracksRate[0][iPV]);
1957       hPVParamSignal[11]->Fill(fPVTracksRate[1][iPV]);
1958       hPVParamSignal[12]->Fill(fPVTracksRate[2][iPV]);
1959       hPVParamSignal[13]->Fill(fPVTracksRate[3][iPV]);
1960       for(unsigned int iZ=0; iZ<dzPV.size(); iZ++)
1961         hPVParamSignal[14]->Fill(dzPV[iZ]);
1962     }
1963     else
1964     {
1965       hPVParamPileup[ 0]->Fill(vtx.X());
1966       hPVParamPileup[ 1]->Fill(vtx.Y());
1967       hPVParamPileup[ 2]->Fill(vtx.Z());
1968       hPVParamPileup[ 3]->Fill(sqrt(vtx.X()*vtx.X() + vtx.Y()*vtx.Y()));
1969       hPVParamPileup[ 4]->Fill(tracks.size());    
1970       hPVParamPileup[ 5]->Fill(vtx.Chi2());
1971       hPVParamPileup[ 6]->Fill(vtx.NDF());
1972       hPVParamPileup[ 7]->Fill(vtx.Chi2()/vtx.NDF());      
1973       hPVParamPileup[ 8]->Fill(probPV);
1974       hPVParamPileup[ 9]->Fill(fPVPurity[iPV]);
1975       hPVParamPileup[10]->Fill(fPVTracksRate[0][iPV]);
1976       hPVParamPileup[11]->Fill(fPVTracksRate[1][iPV]);
1977       hPVParamPileup[12]->Fill(fPVTracksRate[2][iPV]);
1978       hPVParamPileup[13]->Fill(fPVTracksRate[3][iPV]);
1979       for(unsigned int iZ=0; iZ<dzPV.size(); iZ++)
1980         hPVParamPileup[14]->Fill(dzPV[iZ]);
1981       iPVType = 1;
1982     }
1983     //Find MC parameters of the primary vertex 
1984     float mcPVx[3]={mcPV.X(), mcPV.Y(), mcPV.Z()};
1985 
1986     float errPV[3] = {vtx.CovarianceMatrix()[0], vtx.CovarianceMatrix()[2], vtx.CovarianceMatrix()[5]};
1987     for(int iErr=0; iErr<3; iErr++)
1988       if(fabs(errPV[iErr]) < 1.e-8f) errPV[iErr] = 1.e8;
1989         
1990     float dRPVr[3] = {vtx.X()-mcPVx[0],
1991                       vtx.Y()-mcPVx[1],
1992                       vtx.Z()-mcPVx[2]};
1993     float dRPVp[3] = {static_cast<float>(dRPVr[0]/sqrt(errPV[0])),
1994                       static_cast<float>(dRPVr[1]/sqrt(errPV[1])),
1995                       static_cast<float>(dRPVr[2]/sqrt(errPV[2]))};
1996 
1997     for(unsigned int iHPV=0; iHPV<3; ++iHPV)
1998       hPVFitQa[iPVType][iHPV]->Fill(dRPVr[iHPV]);
1999     for(unsigned int iHPV=3; iHPV<6; ++iHPV)
2000       hPVFitQa[iPVType][iHPV]->Fill(dRPVp[iHPV-3]);
2001     
2002     for(unsigned int iHPV=0; iHPV<3; ++iHPV)
2003       hPVFitQa2D[iPVType][1][iHPV]->Fill(fNCorrectPVTracks[iPV],dRPVr[iHPV]);
2004     for(unsigned int iHPV=3; iHPV<6; ++iHPV)
2005       hPVFitQa2D[iPVType][1][iHPV]->Fill(fNCorrectPVTracks[iPV],dRPVp[iHPV-3]);
2006 
2007     for(unsigned int iHPV=0; iHPV<3; ++iHPV)
2008       hPVFitQa2D[iPVType][0][iHPV]->Fill(mcPV.NReconstructedDaughterTracks(),dRPVr[iHPV]);
2009     for(unsigned int iHPV=3; iHPV<6; ++iHPV)
2010       hPVFitQa2D[iPVType][0][iHPV]->Fill(mcPV.NReconstructedDaughterTracks(),dRPVp[iHPV-3]);
2011     
2012     hPVFitQa[iPVType][6]->Fill( double(mcPV.NReconstructedDaughterTracks() - fNCorrectPVTracks[iPV])/double(mcPV.NReconstructedDaughterTracks()) );
2013   }
2014   
2015   //fill histograms with quality of input tracks from PV
2016   for(unsigned int iP=0; iP<fTopoReconstructor->GetParticles().size(); iP++)
2017   {
2018     KFParticle TempPart = fTopoReconstructor->GetParticles()[iP];
2019     int nDaughters = TempPart.NDaughters();
2020     if(nDaughters > 1) continue; //use only tracks, not short lived particles
2021     
2022     if(!RtoMCParticleId[iP].IsMatchedWithPdg())  continue; //ghost
2023     
2024     int iMCPart = RtoMCParticleId[iP].GetBestMatchWithPdg();
2025     KFMCParticle &mcPart = vMCParticles[iMCPart];
2026 
2027     int iMCTrack = mcPart.GetMCTrackID();
2028     KFMCTrack &mcTrack = vMCTracks[iMCTrack];
2029     
2030     if( mcTrack.MotherId() > -1 ) continue; // select only PV tracks
2031     
2032     const float mcX =  mcTrack.X();
2033     const float mcY =  mcTrack.Y();
2034     const float mcZ =  mcTrack.Z();
2035     const float mcPx = mcTrack.Px();
2036     const float mcPy = mcTrack.Py();
2037     const float mcPz = mcTrack.Pz();
2038 
2039     float decayVtx[3] = {mcX, mcY, mcZ};
2040     TempPart.TransportToPoint(decayVtx);
2041 
2042 
2043     Double_t res[6] = {0}, 
2044              pull[6] = {0}, 
2045              mcParam[6] = { mcX, mcY, mcZ,
2046                             mcPx, mcPy, mcPz };
2047     for(int iPar=0; iPar < 6; iPar++ )
2048     {
2049       Double_t error = TempPart.GetCovariance(iPar,iPar);
2050       if(error < 0.) { error = 1.e20;}
2051       error = TMath::Sqrt(error);
2052       res[iPar]  = TempPart.GetParameter(iPar) - mcParam[iPar];
2053       if(fabs(error) > 1.e-20) pull[iPar] = res[iPar]/error;
2054       
2055       hFitPVTracksQA[iPar]->Fill(res[iPar]);
2056       hFitPVTracksQA[iPar+6]->Fill(pull[iPar]);
2057     }
2058   }
2059   
2060   if(fStoreMCHistograms)
2061   {
2062     for(int iV=0; iV<6; iV++)
2063       for(int iP=0; iP < KFPartEfficiencies::nParticles; iP++)
2064         if(hPartParam[iV][iP][17])
2065           hPartParam[iV][iP][17]->Fill(multiplicities[iV][iP]);
2066     FillMCHistos();
2067   }
2068   else
2069     for(int iP=0; iP < KFPartEfficiencies::nParticles; iP++)
2070       if(hPartParam[0][iP][17])
2071         hPartParam[0][iP][17]->Fill(multiplicities[0][iP]);  
2072 } // void KFTopoPerformance::FillHistos()
2073 
2074 void KFTopoPerformance::FillMCHistos()
2075 {
2076   /** Fills histograms of Monte Carlo particles. */
2077   for(unsigned int iMCTrack=0; iMCTrack<vMCTracks.size(); iMCTrack++)
2078   {
2079     int iPDG = fParteff.GetParticleIndex(vMCTracks[iMCTrack].PDG());
2080     if(iPDG < 0) continue;
2081     
2082     if(vMCTracks[iMCTrack].MotherId()>=0) continue;
2083     KFMCParticle &part = vMCParticles[iMCTrack];
2084        
2085     float M = fParteff.partMass[iPDG];
2086     float P = vMCTracks[iMCTrack].P();
2087     float Pt = vMCTracks[iMCTrack].Pt();
2088     float E = sqrt(M*M+P*P);
2089     float Rapidity = 0.5*log((E+vMCTracks[iMCTrack].Pz())/(E-vMCTracks[iMCTrack].Pz()));
2090     float M_t = sqrt(Pt*Pt+M*M)-M;
2091     
2092     float X;
2093     float Y;
2094     float Z;
2095     float R;
2096     
2097     if (part.NDaughters()>0)
2098     {
2099       X = vMCTracks[part.GetDaughterIds()[0]].X();
2100       Y = vMCTracks[part.GetDaughterIds()[0]].Y();
2101       Z = vMCTracks[part.GetDaughterIds()[0]].Z();
2102     }
2103     else
2104     {
2105       X = vMCTracks[iMCTrack].X();
2106       Y = vMCTracks[iMCTrack].Y();
2107       Z = vMCTracks[iMCTrack].Z();
2108     }
2109     R = sqrt(X*X+Y*Y);
2110     
2111     
2112     float parameters[17] = {M, P, Pt, Rapidity, 0, 0, 0, 0, 0, 0, X, Y, Z, R, 0, 0, M_t};
2113     //for all particle-candidates
2114     for(int iParam=0; iParam<17; iParam++)
2115       if(hPartParam[6][iPDG][iParam]) hPartParam[6][iPDG][iParam]->Fill(parameters[iParam]);
2116 
2117     if(hPartParam2D[6][iPDG][0]) hPartParam2D[6][iPDG][0]->Fill(Rapidity,Pt,1);
2118     if(hPartParam2D[6][iPDG][3]) hPartParam2D[6][iPDG][3]->Fill(Rapidity,M_t,1);
2119     
2120     if(IsCollectZRHistogram(iPDG))
2121       if(hPartParam2D[6][iPDG][1]) hPartParam2D[6][iPDG][1]->Fill(Z,R,1);
2122     
2123     if( part.IsReconstructable(2) && IsCollectArmenteros(iPDG))
2124     {
2125       int index1 = part.GetDaughterIds()[0];
2126       int index2 = part.GetDaughterIds()[1];
2127       KFMCTrack positive, negative;
2128       if(vMCTracks[index1].Par(6) > 0)
2129       {
2130         positive = vMCTracks[index1];
2131         negative = vMCTracks[index2];
2132       }
2133       else
2134       {
2135         negative = vMCTracks[index1];
2136         positive = vMCTracks[index2];
2137       }
2138 
2139       float alpha = 0., qt = 0.;
2140       float spx = positive.Px() + negative.Px();
2141       float spy = positive.Py() + negative.Py();
2142       float spz = positive.Pz() + negative.Pz();
2143       float sp  = sqrt(spx*spx + spy*spy + spz*spz);
2144       float pn, pln, plp;
2145       pn = sqrt(negative.Px()*negative.Px() + negative.Py()*negative.Py() + negative.Pz()*negative.Pz());
2146       pln  = (negative.Px()*spx+negative.Py()*spy+negative.Pz()*spz)/sp;
2147       plp  = (positive.Px()*spx+positive.Py()*spy+positive.Pz()*spz)/sp;
2148       float ptm  = (1.-((pln/pn)*(pln/pn)));
2149       qt= (ptm>=0.)?  pn*sqrt(ptm) :0;
2150       alpha = (plp-pln)/(plp+pln);
2151       
2152       if(hPartParam2D[6][iPDG][2]) hPartParam2D[6][iPDG][2]->Fill(alpha,qt,1);
2153     }  
2154   }
2155 }
2156 
2157 void KFTopoPerformance::AddV0Histos()
2158 {
2159   /** Copies histograms of K0s candidates to V0 folder. */
2160   int iV0 = fParteff.nParticles - 1;
2161   int iK0 = fParteff.GetParticleIndex(310);
2162   
2163   for(int iH=0; iH<nFitQA; iH++)
2164   {
2165     hFitDaughtersQA[iV0][iH]->Add(hFitDaughtersQA[iK0][iH]);
2166     hFitQA[iV0][iH]->Add(hFitQA[iK0][iH]);
2167   }
2168 
2169   for(int iV=0; iV<4; iV++)
2170     for(int iH=0; iH<nHistoPartParam; iH++)
2171       hPartParam[iV][iV0][iH]->Add(hPartParam[iV][iK0][iH]);
2172 }
2173 
2174 void KFTopoPerformance::FillHistos(const KFPHistogram* histograms)
2175 {
2176   /** Fill histograms with the histograms from the provided KFPHistogram object. */
2177   for(int iParticle=0; iParticle<KFPartEfficiencies::nParticles; iParticle++)
2178   {
2179     const int& nHistograms = histograms->GetHistogramSet(0).GetNHisto1D();
2180     for(int iHistogram=0; iHistogram<nHistograms; iHistogram++)
2181     {
2182       const KFPHistogram1D& histogram = histograms->GetHistogram(iParticle,iHistogram);
2183       for(int iBin=0; iBin<histogram.Size(); iBin++)
2184         hPartParam[0][iParticle][iHistogram]->SetBinContent( iBin, histogram.GetHistogram()[iBin] );
2185     }
2186   }
2187 }
2188 
2189 #endif //DO_TPCCATRACKER_EFF_PERFORMANCE