void kine_daughters(IlcEveTrack* parent, IlcStack* stack, Double_t min_pt, Double_t min_p, Bool_t pdg_col, Bool_t recurse) { TParticle *p = stack->Particle(parent->GetLabel()); if (p->GetNDaughters() > 0) { TEveTrackPropagator* rs = parent->GetPropagator(); for (int d=p->GetFirstDaughter(); d>0 && d<=p->GetLastDaughter(); ++d) { TParticle* dp = stack->Particle(d); if (dp->Pt() < min_pt && dp->P() < min_p) continue; IlcEveTrack* dtrack = new IlcEveTrack(dp, d, rs); char form[1000]; sprintf(form,"%s [%d]", dp->GetName(), d); dtrack->SetName(form); dtrack->SetStdTitle(); set_track_color(dtrack, pdg_col); gEve->AddElement(dtrack, parent); if (recurse) kine_daughters(dtrack, stack, min_pt, min_p, pdg_col, recurse); } } }
//________________________________________________________________________________ void StarMCHits::FinishEvent() { static const Double_t pEMax = 1 - 1.e-10; TDataSet *m_DataSet = StarMCHits::instance()->GetHitHolder(); if (! m_DataSet) return; St_g2t_event *g2t_event = new St_g2t_event("g2t_event",1); m_DataSet->Add(g2t_event); g2t_event_st event; memset (&event, 0, sizeof(g2t_event_st)); fEventNumber++; event.n_event = fEventNumber;//IHEAD(2) event.ge_rndm[0] = fSeed;//IHEAD(3) event.ge_rndm[1] = 0;//IHEAD(4) event.n_run = 1; event.n_track_eg_fs = StarVMCApplication::Instance()->GetStack()->GetNtrack(); event.n_track_prim = StarVMCApplication::Instance()->GetStack()->GetNprimary(); event.prim_vertex_p = 1; event.b_impact = 99; event.phi_impact = 0.5; g2t_event->AddAt(&event); Int_t NoVertex = 1; St_g2t_vertex *g2t_vertex = new St_g2t_vertex("g2t_vertex",NoVertex); m_DataSet->Add(g2t_vertex); g2t_vertex_st vertex; Int_t NTracks = StarVMCApplication::Instance()->GetStack()->GetNtrack(); St_g2t_track *g2t_track = new St_g2t_track ("g2t_track",NTracks); m_DataSet->Add(g2t_track); g2t_track_st track; StarMCParticle *particle = 0; Int_t iv = 0; TLorentzVector oldV(0,0,0,0); TLorentzVector newV(0,0,0,0); TLorentzVector devV(0,0,0,0); for (Int_t it = 0; it <NTracks; it++) { memset(&track, 0, sizeof(g2t_track_st)); particle = (StarMCParticle*) StarVMCApplication::Instance()->GetStack()->GetParticle(it); TParticle *part = (TParticle *) particle->GetParticle(); part->ProductionVertex(newV); devV = newV - oldV; if (iv == 0 || devV.Mag() > 1.e-7) { if (iv > 0) g2t_vertex->AddAt(&vertex); memset (&vertex, 0, sizeof(g2t_vertex_st)); iv++; vertex.id = iv ;// primary key vertex.event_p = 0 ;// pointer to event vertex.eg_label = 0 ;// generator label (0 if GEANT) vertex.eg_tof = 0 ;// vertex production time vertex.eg_proc = 0 ;// event generator mechanism memcpy(vertex.ge_volume," ",4); ;// GEANT volume name vertex.ge_medium = 0 ;// GEANT Medium vertex.ge_tof = 0 ;// GEANT vertex production time vertex.ge_proc = 0 ;// GEANT mechanism (0 if eg) vertex.ge_x[0] = newV.X() ;// GEANT vertex coordinate vertex.ge_x[1] = newV.Y() ; vertex.ge_x[2] = newV.Z() ; vertex.ge_tof = newV.T() ; vertex.n_parent = 0 ;// number of parent tracks vertex.parent_p = 0 ;// first parent track vertex.is_itrmd = 0 ;// flags intermediate vertex vertex.next_itrmd_p = 0 ;// next intermedate vertex vertex.next_prim_v_p= 0 ;// next primary vertex oldV = newV; } vertex.n_daughter++; track.id = it+1; track.eg_label = particle->GetIdGen(); track.eg_pid = part->GetPdgCode(); track.ge_pid = gMC->IdFromPDG(track.eg_pid); track.start_vertex_p = iv; track.p[0] = part->Px(); track.p[1] = part->Py(); track.p[2] = part->Pz(); track.ptot = part->P(); track.e = part->Energy(); track.charge = part->GetPDG()->Charge()/3; Double_t ratio = part->Pz()/part->Energy(); ratio = TMath::Min(1.-1e-10,TMath::Max(-1.+1e-10, ratio)); track.rapidity = TMath::ATanH(ratio); track.pt = part->Pt(); ratio = part->Pz()/part->P(); ratio = TMath::Min(pEMax,TMath::Max(-pEMax, ratio)); track.eta = TMath::ATanH(ratio); g2t_track->AddAt(&track); } g2t_vertex->AddAt(&vertex); }
Bool_t CheckESD(const char* gAliceFileName = "galice.root", const char* esdFileName = "AliESDs.root") { // check the content of the ESD // check values Int_t checkNGenLow = 1; Double_t checkEffLow = 0.5; Double_t checkEffSigma = 3; Double_t checkFakeHigh = 0.5; Double_t checkFakeSigma = 3; Double_t checkResPtInvHigh = 5; Double_t checkResPtInvSigma = 3; Double_t checkResPhiHigh = 10; Double_t checkResPhiSigma = 3; Double_t checkResThetaHigh = 10; Double_t checkResThetaSigma = 3; Double_t checkPIDEffLow = 0.5; Double_t checkPIDEffSigma = 3; Double_t checkResTOFHigh = 500; Double_t checkResTOFSigma = 3; Double_t checkPHOSNLow = 5; Double_t checkPHOSEnergyLow = 0.3; Double_t checkPHOSEnergyHigh = 1.0; Double_t checkEMCALNLow = 50; Double_t checkEMCALEnergyLow = 0.05; Double_t checkEMCALEnergyHigh = 1.0; Double_t checkMUONNLow = 1; Double_t checkMUONPtLow = 0.5; Double_t checkMUONPtHigh = 10.; Double_t cutPtV0 = 0.3; Double_t checkV0EffLow = 0.02; Double_t checkV0EffSigma = 3; Double_t cutPtCascade = 0.5; Double_t checkCascadeEffLow = 0.01; Double_t checkCascadeEffSigma = 3; // open run loader and load gAlice, kinematics and header AliRunLoader* runLoader = AliRunLoader::Open(gAliceFileName); if (!runLoader) { Error("CheckESD", "getting run loader from file %s failed", gAliceFileName); return kFALSE; } runLoader->LoadgAlice(); gAlice = runLoader->GetAliRun(); if (!gAlice) { Error("CheckESD", "no galice object found"); return kFALSE; } runLoader->LoadKinematics(); runLoader->LoadHeader(); // open the ESD file TFile* esdFile = TFile::Open(esdFileName); if (!esdFile || !esdFile->IsOpen()) { Error("CheckESD", "opening ESD file %s failed", esdFileName); return kFALSE; } AliESDEvent * esd = new AliESDEvent; TTree* tree = (TTree*) esdFile->Get("esdTree"); if (!tree) { Error("CheckESD", "no ESD tree found"); return kFALSE; } esd->ReadFromTree(tree); // efficiency and resolution histograms Int_t nBinsPt = 15; Float_t minPt = 0.1; Float_t maxPt = 3.1; TH1F* hGen = CreateHisto("hGen", "generated tracks", nBinsPt, minPt, maxPt, "p_{t} [GeV/c]", "N"); TH1F* hRec = CreateHisto("hRec", "reconstructed tracks", nBinsPt, minPt, maxPt, "p_{t} [GeV/c]", "N"); Int_t nGen = 0; Int_t nRec = 0; Int_t nFake = 0; TH1F* hResPtInv = CreateHisto("hResPtInv", "", 100, -10, 10, "(p_{t,rec}^{-1}-p_{t,sim}^{-1}) / p_{t,sim}^{-1} [%]", "N"); TH1F* hResPhi = CreateHisto("hResPhi", "", 100, -20, 20, "#phi_{rec}-#phi_{sim} [mrad]", "N"); TH1F* hResTheta = CreateHisto("hResTheta", "", 100, -20, 20, "#theta_{rec}-#theta_{sim} [mrad]", "N"); // PID Int_t partCode[AliPID::kSPECIES] = {kElectron, kMuonMinus, kPiPlus, kKPlus, kProton}; const char* partName[AliPID::kSPECIES+1] = {"electron", "muon", "pion", "kaon", "proton", "other"}; Double_t partFrac[AliPID::kSPECIES] = {0.01, 0.01, 0.85, 0.10, 0.05}; Int_t identified[AliPID::kSPECIES+1][AliPID::kSPECIES]; for (Int_t iGen = 0; iGen < AliPID::kSPECIES+1; iGen++) { for (Int_t iRec = 0; iRec < AliPID::kSPECIES; iRec++) { identified[iGen][iRec] = 0; } } Int_t nIdentified = 0; // dE/dx and TOF TH2F* hDEdxRight = new TH2F("hDEdxRight", "", 300, 0, 3, 100, 0, 400); hDEdxRight->SetStats(kFALSE); hDEdxRight->GetXaxis()->SetTitle("p [GeV/c]"); hDEdxRight->GetYaxis()->SetTitle("dE/dx_{TPC}"); hDEdxRight->SetMarkerStyle(kFullCircle); hDEdxRight->SetMarkerSize(0.4); TH2F* hDEdxWrong = new TH2F("hDEdxWrong", "", 300, 0, 3, 100, 0, 400); hDEdxWrong->SetStats(kFALSE); hDEdxWrong->GetXaxis()->SetTitle("p [GeV/c]"); hDEdxWrong->GetYaxis()->SetTitle("dE/dx_{TPC}"); hDEdxWrong->SetMarkerStyle(kFullCircle); hDEdxWrong->SetMarkerSize(0.4); hDEdxWrong->SetMarkerColor(kRed); TH1F* hResTOFRight = CreateHisto("hResTOFRight", "", 100, -1000, 1000, "t_{TOF}-t_{track} [ps]", "N"); TH1F* hResTOFWrong = CreateHisto("hResTOFWrong", "", 100, -1000, 1000, "t_{TOF}-t_{track} [ps]", "N"); hResTOFWrong->SetLineColor(kRed); // calorimeters TH1F* hEPHOS = CreateHisto("hEPHOS", "PHOS", 100, 0, 50, "E [GeV]", "N"); TH1F* hEEMCAL = CreateHisto("hEEMCAL", "EMCAL", 100, 0, 50, "E [GeV]", "N"); // muons TH1F* hPtMUON = CreateHisto("hPtMUON", "MUON", 100, 0, 20, "p_{t} [GeV/c]", "N"); // V0s and cascades TH1F* hMassK0 = CreateHisto("hMassK0", "K^{0}", 100, 0.4, 0.6, "M(#pi^{+}#pi^{-}) [GeV/c^{2}]", "N"); TH1F* hMassLambda = CreateHisto("hMassLambda", "#Lambda", 100, 1.0, 1.2, "M(p#pi^{-}) [GeV/c^{2}]", "N"); TH1F* hMassLambdaBar = CreateHisto("hMassLambdaBar", "#bar{#Lambda}", 100, 1.0, 1.2, "M(#bar{p}#pi^{+}) [GeV/c^{2}]", "N"); Int_t nGenV0s = 0; Int_t nRecV0s = 0; TH1F* hMassXi = CreateHisto("hMassXi", "#Xi", 100, 1.2, 1.5, "M(#Lambda#pi) [GeV/c^{2}]", "N"); TH1F* hMassOmega = CreateHisto("hMassOmega", "#Omega", 100, 1.5, 1.8, "M(#LambdaK) [GeV/c^{2}]", "N"); Int_t nGenCascades = 0; Int_t nRecCascades = 0; // loop over events for (Int_t iEvent = 0; iEvent < runLoader->GetNumberOfEvents(); iEvent++) { runLoader->GetEvent(iEvent); // select simulated primary particles, V0s and cascades AliStack* stack = runLoader->Stack(); Int_t nParticles = stack->GetNtrack(); TArrayF vertex(3); runLoader->GetHeader()->GenEventHeader()->PrimaryVertex(vertex); TObjArray selParticles; TObjArray selV0s; TObjArray selCascades; for (Int_t iParticle = 0; iParticle < nParticles; iParticle++) { TParticle* particle = stack->Particle(iParticle); if (!particle) continue; if (particle->Pt() < 0.001) continue; if (TMath::Abs(particle->Eta()) > 0.9) continue; TVector3 dVertex(particle->Vx() - vertex[0], particle->Vy() - vertex[1], particle->Vz() - vertex[2]); if (dVertex.Mag() > 0.0001) continue; switch (TMath::Abs(particle->GetPdgCode())) { case kElectron: case kMuonMinus: case kPiPlus: case kKPlus: case kProton: { if (particle->Pt() > minPt) { selParticles.Add(particle); nGen++; hGen->Fill(particle->Pt()); } break; } case kK0Short: case kLambda0: { if (particle->Pt() > cutPtV0) { nGenV0s++; selV0s.Add(particle); } break; } case kXiMinus: case kOmegaMinus: { if (particle->Pt() > cutPtCascade) { nGenCascades++; selCascades.Add(particle); } break; } default: break; } } // get the event summary data tree->GetEvent(iEvent); if (!esd) { Error("CheckESD", "no ESD object found for event %d", iEvent); return kFALSE; } // loop over tracks for (Int_t iTrack = 0; iTrack < esd->GetNumberOfTracks(); iTrack++) { AliESDtrack* track = esd->GetTrack(iTrack); // select tracks of selected particles Int_t label = TMath::Abs(track->GetLabel()); if (label > stack->GetNtrack()) continue; // background TParticle* particle = stack->Particle(label); if (!selParticles.Contains(particle)) continue; if ((track->GetStatus() & AliESDtrack::kITSrefit) == 0) continue; if (track->GetConstrainedChi2() > 1e9) continue; selParticles.Remove(particle); // don't count multiple tracks nRec++; hRec->Fill(particle->Pt()); if (track->GetLabel() < 0) nFake++; // resolutions hResPtInv->Fill(100. * (TMath::Abs(track->GetSigned1Pt()) - 1./particle->Pt()) * particle->Pt()); hResPhi->Fill(1000. * (track->Phi() - particle->Phi())); hResTheta->Fill(1000. * (track->Theta() - particle->Theta())); // PID if ((track->GetStatus() & AliESDtrack::kESDpid) == 0) continue; Int_t iGen = 5; for (Int_t i = 0; i < AliPID::kSPECIES; i++) { if (TMath::Abs(particle->GetPdgCode()) == partCode[i]) iGen = i; } Double_t probability[AliPID::kSPECIES]; track->GetESDpid(probability); Double_t pMax = 0; Int_t iRec = 0; for (Int_t i = 0; i < AliPID::kSPECIES; i++) { probability[i] *= partFrac[i]; if (probability[i] > pMax) { pMax = probability[i]; iRec = i; } } identified[iGen][iRec]++; if (iGen == iRec) nIdentified++; // dE/dx and TOF Double_t time[AliPID::kSPECIES]; track->GetIntegratedTimes(time); if (iGen == iRec) { hDEdxRight->Fill(particle->P(), track->GetTPCsignal()); if ((track->GetStatus() & AliESDtrack::kTOFpid) != 0) { hResTOFRight->Fill(track->GetTOFsignal() - time[iRec]); } } else { hDEdxWrong->Fill(particle->P(), track->GetTPCsignal()); if ((track->GetStatus() & AliESDtrack::kTOFpid) != 0) { hResTOFWrong->Fill(track->GetTOFsignal() - time[iRec]); } } } // loop over muon tracks { for (Int_t iTrack = 0; iTrack < esd->GetNumberOfMuonTracks(); iTrack++) { AliESDMuonTrack* muonTrack = esd->GetMuonTrack(iTrack); Double_t ptInv = TMath::Abs(muonTrack->GetInverseBendingMomentum()); if (ptInv > 0.001) { hPtMUON->Fill(1./ptInv); } } } // loop over V0s for (Int_t iV0 = 0; iV0 < esd->GetNumberOfV0s(); iV0++) { AliESDv0* v0 = esd->GetV0(iV0); if (v0->GetOnFlyStatus()) continue; v0->ChangeMassHypothesis(kK0Short); hMassK0->Fill(v0->GetEffMass()); v0->ChangeMassHypothesis(kLambda0); hMassLambda->Fill(v0->GetEffMass()); v0->ChangeMassHypothesis(kLambda0Bar); hMassLambdaBar->Fill(v0->GetEffMass()); Int_t negLabel = TMath::Abs(esd->GetTrack(v0->GetNindex())->GetLabel()); if (negLabel > stack->GetNtrack()) continue; // background Int_t negMother = stack->Particle(negLabel)->GetMother(0); if (negMother < 0) continue; Int_t posLabel = TMath::Abs(esd->GetTrack(v0->GetPindex())->GetLabel()); if (posLabel > stack->GetNtrack()) continue; // background Int_t posMother = stack->Particle(posLabel)->GetMother(0); if (negMother != posMother) continue; TParticle* particle = stack->Particle(negMother); if (!selV0s.Contains(particle)) continue; selV0s.Remove(particle); nRecV0s++; } // loop over Cascades for (Int_t iCascade = 0; iCascade < esd->GetNumberOfCascades(); iCascade++) { AliESDcascade* cascade = esd->GetCascade(iCascade); Double_t v0q; cascade->ChangeMassHypothesis(v0q,kXiMinus); hMassXi->Fill(cascade->GetEffMassXi()); cascade->ChangeMassHypothesis(v0q,kOmegaMinus); hMassOmega->Fill(cascade->GetEffMassXi()); Int_t negLabel = TMath::Abs(esd->GetTrack(cascade->GetNindex()) ->GetLabel()); if (negLabel > stack->GetNtrack()) continue; // background Int_t negMother = stack->Particle(negLabel)->GetMother(0); if (negMother < 0) continue; Int_t posLabel = TMath::Abs(esd->GetTrack(cascade->GetPindex()) ->GetLabel()); if (posLabel > stack->GetNtrack()) continue; // background Int_t posMother = stack->Particle(posLabel)->GetMother(0); if (negMother != posMother) continue; Int_t v0Mother = stack->Particle(negMother)->GetMother(0); if (v0Mother < 0) continue; Int_t bacLabel = TMath::Abs(esd->GetTrack(cascade->GetBindex()) ->GetLabel()); if (bacLabel > stack->GetNtrack()) continue; // background Int_t bacMother = stack->Particle(bacLabel)->GetMother(0); if (v0Mother != bacMother) continue; TParticle* particle = stack->Particle(v0Mother); if (!selCascades.Contains(particle)) continue; selCascades.Remove(particle); nRecCascades++; } // loop over the clusters { for (Int_t iCluster=0; iCluster<esd->GetNumberOfCaloClusters(); iCluster++) { AliESDCaloCluster * clust = esd->GetCaloCluster(iCluster); if (clust->IsPHOS()) hEPHOS->Fill(clust->E()); if (clust->IsEMCAL()) hEEMCAL->Fill(clust->E()); } } } // perform checks if (nGen < checkNGenLow) { Warning("CheckESD", "low number of generated particles: %d", Int_t(nGen)); } TH1F* hEff = CreateEffHisto(hGen, hRec); Info("CheckESD", "%d out of %d tracks reconstructed including %d " "fake tracks", nRec, nGen, nFake); if (nGen > 0) { // efficiency Double_t eff = nRec*1./nGen; Double_t effError = TMath::Sqrt(eff*(1.-eff) / nGen); Double_t fake = nFake*1./nGen; Double_t fakeError = TMath::Sqrt(fake*(1.-fake) / nGen); Info("CheckESD", "eff = (%.1f +- %.1f) %% fake = (%.1f +- %.1f) %%", 100.*eff, 100.*effError, 100.*fake, 100.*fakeError); if (eff < checkEffLow - checkEffSigma*effError) { Warning("CheckESD", "low efficiency: (%.1f +- %.1f) %%", 100.*eff, 100.*effError); } if (fake > checkFakeHigh + checkFakeSigma*fakeError) { Warning("CheckESD", "high fake: (%.1f +- %.1f) %%", 100.*fake, 100.*fakeError); } // resolutions Double_t res, resError; if (FitHisto(hResPtInv, res, resError)) { Info("CheckESD", "relative inverse pt resolution = (%.1f +- %.1f) %%", res, resError); if (res > checkResPtInvHigh + checkResPtInvSigma*resError) { Warning("CheckESD", "bad pt resolution: (%.1f +- %.1f) %%", res, resError); } } if (FitHisto(hResPhi, res, resError)) { Info("CheckESD", "phi resolution = (%.1f +- %.1f) mrad", res, resError); if (res > checkResPhiHigh + checkResPhiSigma*resError) { Warning("CheckESD", "bad phi resolution: (%.1f +- %.1f) mrad", res, resError); } } if (FitHisto(hResTheta, res, resError)) { Info("CheckESD", "theta resolution = (%.1f +- %.1f) mrad", res, resError); if (res > checkResThetaHigh + checkResThetaSigma*resError) { Warning("CheckESD", "bad theta resolution: (%.1f +- %.1f) mrad", res, resError); } } // PID if (nRec > 0) { Double_t eff = nIdentified*1./nRec; Double_t effError = TMath::Sqrt(eff*(1.-eff) / nRec); Info("CheckESD", "PID eff = (%.1f +- %.1f) %%", 100.*eff, 100.*effError); if (eff < checkPIDEffLow - checkPIDEffSigma*effError) { Warning("CheckESD", "low PID efficiency: (%.1f +- %.1f) %%", 100.*eff, 100.*effError); } } printf("%9s:", "gen\\rec"); for (Int_t iRec = 0; iRec < AliPID::kSPECIES; iRec++) { printf("%9s", partName[iRec]); } printf("\n"); for (Int_t iGen = 0; iGen < AliPID::kSPECIES+1; iGen++) { printf("%9s:", partName[iGen]); for (Int_t iRec = 0; iRec < AliPID::kSPECIES; iRec++) { printf("%9d", identified[iGen][iRec]); } printf("\n"); } if (FitHisto(hResTOFRight, res, resError)) { Info("CheckESD", "TOF resolution = (%.1f +- %.1f) ps", res, resError); if (res > checkResTOFHigh + checkResTOFSigma*resError) { Warning("CheckESD", "bad TOF resolution: (%.1f +- %.1f) ps", res, resError); } } // calorimeters if (hEPHOS->Integral() < checkPHOSNLow) { Warning("CheckESD", "low number of PHOS particles: %d", Int_t(hEPHOS->Integral())); } else { Double_t mean = hEPHOS->GetMean(); if (mean < checkPHOSEnergyLow) { Warning("CheckESD", "low mean PHOS energy: %.1f GeV", mean); } else if (mean > checkPHOSEnergyHigh) { Warning("CheckESD", "high mean PHOS energy: %.1f GeV", mean); } } if (hEEMCAL->Integral() < checkEMCALNLow) { Warning("CheckESD", "low number of EMCAL particles: %d", Int_t(hEEMCAL->Integral())); } else { Double_t mean = hEEMCAL->GetMean(); if (mean < checkEMCALEnergyLow) { Warning("CheckESD", "low mean EMCAL energy: %.1f GeV", mean); } else if (mean > checkEMCALEnergyHigh) { Warning("CheckESD", "high mean EMCAL energy: %.1f GeV", mean); } } // muons if (hPtMUON->Integral() < checkMUONNLow) { Warning("CheckESD", "low number of MUON particles: %d", Int_t(hPtMUON->Integral())); } else { Double_t mean = hPtMUON->GetMean(); if (mean < checkMUONPtLow) { Warning("CheckESD", "low mean MUON pt: %.1f GeV/c", mean); } else if (mean > checkMUONPtHigh) { Warning("CheckESD", "high mean MUON pt: %.1f GeV/c", mean); } } // V0s if (nGenV0s > 0) { Double_t eff = nRecV0s*1./nGenV0s; Double_t effError = TMath::Sqrt(eff*(1.-eff) / nGenV0s); if (effError == 0) effError = checkV0EffLow / TMath::Sqrt(1.*nGenV0s); Info("CheckESD", "V0 eff = (%.1f +- %.1f) %%", 100.*eff, 100.*effError); if (eff < checkV0EffLow - checkV0EffSigma*effError) { Warning("CheckESD", "low V0 efficiency: (%.1f +- %.1f) %%", 100.*eff, 100.*effError); } } // Cascades if (nGenCascades > 0) { Double_t eff = nRecCascades*1./nGenCascades; Double_t effError = TMath::Sqrt(eff*(1.-eff) / nGenCascades); if (effError == 0) effError = checkV0EffLow / TMath::Sqrt(1.*nGenCascades); Info("CheckESD", "Cascade eff = (%.1f +- %.1f) %%", 100.*eff, 100.*effError); if (eff < checkCascadeEffLow - checkCascadeEffSigma*effError) { Warning("CheckESD", "low Cascade efficiency: (%.1f +- %.1f) %%", 100.*eff, 100.*effError); } } } // draw the histograms if not in batch mode if (!gROOT->IsBatch()) { new TCanvas; hEff->DrawCopy(); new TCanvas; hResPtInv->DrawCopy("E"); new TCanvas; hResPhi->DrawCopy("E"); new TCanvas; hResTheta->DrawCopy("E"); new TCanvas; hDEdxRight->DrawCopy(); hDEdxWrong->DrawCopy("SAME"); new TCanvas; hResTOFRight->DrawCopy("E"); hResTOFWrong->DrawCopy("SAME"); new TCanvas; hEPHOS->DrawCopy("E"); new TCanvas; hEEMCAL->DrawCopy("E"); new TCanvas; hPtMUON->DrawCopy("E"); new TCanvas; hMassK0->DrawCopy("E"); new TCanvas; hMassLambda->DrawCopy("E"); new TCanvas; hMassLambdaBar->DrawCopy("E"); new TCanvas; hMassXi->DrawCopy("E"); new TCanvas; hMassOmega->DrawCopy("E"); } // write the output histograms to a file TFile* outputFile = TFile::Open("check.root", "recreate"); if (!outputFile || !outputFile->IsOpen()) { Error("CheckESD", "opening output file check.root failed"); return kFALSE; } hEff->Write(); hResPtInv->Write(); hResPhi->Write(); hResTheta->Write(); hDEdxRight->Write(); hDEdxWrong->Write(); hResTOFRight->Write(); hResTOFWrong->Write(); hEPHOS->Write(); hEEMCAL->Write(); hPtMUON->Write(); hMassK0->Write(); hMassLambda->Write(); hMassLambdaBar->Write(); hMassXi->Write(); hMassOmega->Write(); outputFile->Close(); delete outputFile; // clean up delete hGen; delete hRec; delete hEff; delete hResPtInv; delete hResPhi; delete hResTheta; delete hDEdxRight; delete hDEdxWrong; delete hResTOFRight; delete hResTOFWrong; delete hEPHOS; delete hEEMCAL; delete hPtMUON; delete hMassK0; delete hMassLambda; delete hMassLambdaBar; delete hMassXi; delete hMassOmega; delete esd; esdFile->Close(); delete esdFile; runLoader->UnloadHeader(); runLoader->UnloadKinematics(); delete runLoader; // result of check Info("CheckESD", "check of ESD was successfull"); return kTRUE; }
Int_t TOFquickanal(Int_t eventNumber = 0) { ///////////////////////////////////////////////////////////////////////// // This macro is a small example of a ROOT macro // illustrating how to read the output of GALICE // and fill some histograms concerning the TOF Hit Tree. // // Root > .L TOFquickanal.C //this loads the macro in memory // Root > TOFquickanal(); //by default process first event // Root > TOFquickanal(2); //process third event //Begin_Html /* <img src="picts/TOFquickanal.gif"> */ //End_Html // // Author: F. Pierella , Bologna University 12-04-2001 // Updated to the new I/O by: A. De Caro, C. Zampolli ///////////////////////////////////////////////////////////////////////// // Dynamically link some shared libs if (gClassTable->GetID("AliRun") < 0) { gROOT->LoadMacro("loadlibs.C"); loadlibs(); } Int_t rc = 0; AliRunLoader *rl =AliRunLoader::Open("galice.root",AliConfig::GetDefaultEventFolderName(),"update"); if (!rl) { cerr << "Can't load RunLoader from file!\n"; rc = 1; return rc; } rl->LoadgAlice(); gAlice=rl->GetAliRun(); if (!gAlice) { cerr << "<TOFquickanal> AliRun object not found on file \n"; rc = 2; return rc; } // Get the pointer to the TOF detector AliLoader *tofl = rl->GetLoader("TOFLoader"); AliTOF * tof = (AliTOF*) gAlice->GetDetector("TOF"); if (tof == 0x0 || tofl == 0x0) { cerr << "<TOFquickanal> Can not find TOF or TOFLoader\n"; rc = 3; return rc; } //=======> Create histograms //---> Time of Flight for Primary Particles (ns) TH1F *htofprim = new TH1F("htofprim","Time of Flight for Primary Particles",100,0.,100.); //--->Time of Flight for Secondary Particles (ns) TH1F *htofsec = new TH1F("htofsec","Time of Flight for Secondary Particles",100,0.,100.); //---> r (radius) coordinate of production in the ALICE frame for secondary particles that produce at // least one TOF-hit (cm) - cylindrical coordinate system assumed, primary plus secondary- TH1F *hradius = new TH1F("hradius","r (radius) coordinate at the production vertex for secondary particles with at least one TOF-Hit",50,0.,500.); //---> Momentum of primary particles that produce (at least) one TOF-hit when the hit // is produced (Gev/c) TH1F *htofmom = new TH1F("htofmom","Momentum of primary particles when the Hit is produced",50,0.,5.); //---> Momentum of primary particles that produce (at least) one TOF-hit at the production vertex // (Gev/c) TH1F *hprodmom = new TH1F("hprodmom","Momentum of primary particles (with at least one TOF hit) at the production ",50,0.,5.); //---> Theta of production for primary particles that produce (at least) one TOF-hit (deg) TH1F *hprodthe = new TH1F("hprodthe","Theta of primary particles (with at least one TOF hit) at the production ",90,0.,180.); //---> Phi of production for primary particles that produce (at least) one TOF-hit (deg) TH1F *hprodphi = new TH1F("hprodphi","Phi of primary particles (with at least one TOF hit) at the production ",180,-180.,180.); //---> z Coordinate of the TOF Hit (z beam axis) - primary plus secondary - (cm) TH1F *hzcoor = new TH1F("hzcoor","z Coordinate of the TOF Hit",800,-400.,400.); //---> Incidence Angle of the particle on the pad (or strip) (deg) - primary plus secondary - TH1F *hincangle = new TH1F("hincangle","Incidence Angle of the particle on the strip",90,0.,180.); printf ("Processing event %d \n", eventNumber); rl->GetEvent(eventNumber); // Get pointers to Alice detectors and Hits containers tofl->LoadHits(); TTree *TH = tofl->TreeH(); tof->SetTreeAddress(); if (!TH) { cout << "<TOFquickanal> No hit tree found" << endl; rc = 4; return rc; } // Import the Kine Tree for the event eventNumber in the file rl->LoadHeader(); rl->LoadKinematics(); //AliStack * stack = rl->Stack(); Int_t ntracks = TH->GetEntries(); cout<<" ntracks = "<<ntracks<<endl; AliTOFhitT0 *tofHit; // Start loop on tracks in the hits containers for (Int_t track=0; track<ntracks;track++) { tof->ResetHits(); TH->GetEvent(track); for(tofHit=(AliTOFhitT0*)tof->FirstHit(track); tofHit; tofHit=(AliTOFhitT0*)tof->NextHit()) { Float_t toflight = tofHit->GetTof(); toflight *= 1.E+09; // conversion from s to ns Double_t tofmom = tofHit->GetMom(); Int_t ipart = tofHit->Track(); TParticle *particle = gAlice->Particle(ipart); if (particle->GetFirstMother() < 0) { htofprim->Fill(toflight); htofmom->Fill(tofmom); } else { htofsec->Fill(toflight); } Double_t zcoor = tofHit->Z(); hzcoor->Fill(zcoor); Double_t incangle = tofHit->GetIncA(); hincangle->Fill(incangle); Double_t xcoor = particle->Vx(); Double_t ycoor = particle->Vy(); Double_t radius = TMath::Sqrt(xcoor*xcoor+ycoor*ycoor); if (particle->GetFirstMother() >= 0) hradius->Fill(radius); Double_t prodmom = particle->P(); if (prodmom!=0.) { Double_t dummy = (particle->Pz())/prodmom; Double_t prodthe = TMath::ACos(dummy); prodthe *= 57.29578; // conversion from rad to deg if (particle->GetFirstMother() < 0) hprodthe->Fill(prodthe); } // theta at production vertex if (particle->GetFirstMother() < 0) { hprodmom->Fill(prodmom); Double_t dummypx = particle->Px(); Double_t dummypy = particle->Py(); Double_t prodphi = TMath::ATan2(dummypy,dummypx); prodphi *= 57.29578; // conversion from rad to deg hprodphi->Fill(prodphi); } // phi at production vertex } // close loop on TOF-hits } // close loop on tracks in the hits containers //Create canvas, set the view range, show histograms TCanvas *c1 = new TCanvas("c1","Alice TOF hits quick analysis",400,10,600,700); c1->cd(); hprodmom->Draw(); TCanvas *c2 = new TCanvas("c2","Alice TOF hits quick analysis",400,10,600,700); c2->cd(); hprodthe->Draw(); TCanvas *c3 = new TCanvas("c3","Alice TOF hits quick analysis",400,10,600,700); c3->cd(); hprodphi->Draw(); TCanvas *c4 = new TCanvas("c4","Alice TOF hits quick analysis",400,10,600,700); c4->cd(); hzcoor->Draw(); TCanvas *c5 = new TCanvas("c5","Alice TOF hits quick analysis",400,10,600,700); c5->cd(); hradius->Draw(); TCanvas *c6 = new TCanvas("c6","Alice TOF hits quick analysis",400,10,600,700); c6->cd(); htofprim->Draw(); TCanvas *c7 = new TCanvas("c7","Alice TOF hits quick analysis",400,10,600,700); c7->cd(); htofsec->Draw(); TCanvas *c8 = new TCanvas("c8","Alice TOF hits quick analysis",400,10,600,700); c8->cd(); htofmom->Draw(); TCanvas *c9 = new TCanvas("c9","Alice TOF hits quick analysis",400,10,600,700); c9->cd(); hincangle->Draw(); //tofl->UnloadHits(); //rl->UnloadHeader(); //rl->UnloadgAlice(); //rl->UnloadKinematics(); return rc; }
int main(int argc, char* argv[]) { TApplication theApp(srcName.Data(), &argc, argv); //============================================================================= for (int i=0; i<argc; i++) cout << i << ", " << argv[i] << endl; //============================================================================= if (argc<5) return -1; TString sPath = argv[1]; if (sPath.IsNull()) return -1; TString sFile = argv[2]; if (sFile.IsNull()) return -1; TString sJetR = argv[3]; if (sJetR.IsNull()) return -1; TString sSjeR = argv[4]; if (sSjeR.IsNull()) return -1; //============================================================================= sPath.ReplaceAll("#", "/"); //============================================================================= double dJetR = -1.; if (sJetR=="JetR02") dJetR = 0.2; if (sJetR=="JetR03") dJetR = 0.3; if (sJetR=="JetR04") dJetR = 0.4; if (sJetR=="JetR05") dJetR = 0.5; if (dJetR<0.) return -1; cout << "Jet R = " << dJetR << endl; //============================================================================= double dSjeR = -1.; if (sSjeR=="SjeR01") dSjeR = 0.1; if (sSjeR=="SjeR02") dSjeR = 0.2; if (sSjeR=="SjeR03") dSjeR = 0.3; if (sSjeR=="SjeR04") dSjeR = 0.4; if (dSjeR<0.) return -1; cout << "Sub-jet R = " << dSjeR << endl; //============================================================================= const double dJetsPtMin = 0.001; const double dCutEtaMax = 1.6; const double dJetEtaMax = 1.; const double dJetAreaRef = TMath::Pi() * dJetR * dJetR; fastjet::GhostedAreaSpec areaSpc(dCutEtaMax); fastjet::JetDefinition jetsDef(fastjet::antikt_algorithm, dJetR, fastjet::BIpt_scheme, fastjet::Best); //fastjet::AreaDefinition areaDef(fastjet::active_area,areaSpc); fastjet::AreaDefinition areaDef(fastjet::active_area_explicit_ghosts,areaSpc); //fastjet::JetDefinition bkgsDef(fastjet::kt_algorithm, 0.2, fastjet::BIpt_scheme, fastjet::Best); //fastjet::AreaDefinition aBkgDef(fastjet::active_area_explicit_ghosts, areaSpc); fastjet::Selector selectJet = fastjet::SelectorAbsEtaMax(dJetEtaMax); //fastjet::Selector selectRho = fastjet::SelectorAbsEtaMax(dCutEtaMax-0.2); //fastjet::Selector selecHard = fastjet::SelectorNHardest(2); //fastjet::Selector selectBkg = selectRho * (!(selecHard)); //fastjet::JetMedianBackgroundEstimator bkgsEstimator(selectBkg, bkgsDef, aBkgDef); //fastjet::Subtractor bkgSubtractor(&bkgsEstimator); fastjet::JetDefinition subjDef(fastjet::antikt_algorithm, dSjeR, fastjet::BIpt_scheme, fastjet::Best); //============================================================================= std::vector<fastjet::PseudoJet> fjInput; //============================================================================= TList *list = new TList(); TH1D *hPtHat = new TH1D("hPtHat", "", 1000, 0., 1000.); TH1D *hJet = new TH1D("hJet", "", 1000, 0., 1000.); hJet->Sumw2(); list->Add(hJet); TH2D *hJetNsj = new TH2D("hJetNsj", "", 1000, 0., 1000., 101, -0.5, 100.5); hJetNsj->Sumw2(); list->Add(hJetNsj); TH2D *hJetIsj = new TH2D("hJetIsj", "", 1000, 0., 1000., 1000, 0., 1000.); hJetIsj->Sumw2(); list->Add(hJetIsj); TH2D *hJet1sj = new TH2D("hJet1sj", "", 1000, 0., 1000., 1000, 0., 1000.); hJet1sj->Sumw2(); list->Add(hJet1sj); TH2D *hJet2sj = new TH2D("hJet2sj", "", 1000, 0., 1000., 1000, 0., 1000.); hJet2sj->Sumw2(); list->Add(hJet2sj); TH2D *hJetDsj = new TH2D("hJetDsj", "", 1000, 0., 1000., 1000, 0., 1000.); hJetDsj->Sumw2(); list->Add(hJetDsj); TH2D *hJetIsz = new TH2D("hJetIsz", "", 1000, 0., 1000., 120, 0., 1.2); hJetIsz->Sumw2(); list->Add(hJetIsz); TH2D *hJet1sz = new TH2D("hJet1sz", "", 1000, 0., 1000., 120, 0., 1.2); hJet1sz->Sumw2(); list->Add(hJet1sz); TH2D *hJet2sz = new TH2D("hJet2sz", "", 1000, 0., 1000., 120, 0., 1.2); hJet2sz->Sumw2(); list->Add(hJet2sz); TH2D *hJetDsz = new TH2D("hJetDsz", "", 1000, 0., 1000., 120, 0., 1.2); hJetDsz->Sumw2(); list->Add(hJetDsz); //============================================================================= AliRunLoader *rl = AliRunLoader::Open(Form("%s/galice.root",sPath.Data())); if (!rl) return -1; if (rl->LoadHeader()) return -1; if (rl->LoadKinematics("READ")) return -1; //============================================================================= for (Int_t iEvent=0; iEvent<rl->GetNumberOfEvents(); iEvent++) { fjInput.resize(0); if (rl->GetEvent(iEvent)) continue; //============================================================================= AliStack *pStack = rl->Stack(); if (!pStack) continue; AliHeader *pHeader = rl->GetHeader(); if (!pHeader) continue; //============================================================================= AliGenPythiaEventHeader *pHeadPy = (AliGenPythiaEventHeader*)pHeader->GenEventHeader(); if (!pHeadPy) continue; hPtHat->Fill(pHeadPy->GetPtHard()); //============================================================================= for (Int_t i=0; i<pStack->GetNtrack(); i++) if (pStack->IsPhysicalPrimary(i)) { TParticle *pTrk = pStack->Particle(i); if (!pTrk) continue; if (TMath::Abs(pTrk->Eta())>dCutEtaMax) { pTrk = 0; continue; } // TParticlePDG *pPDG = pTrk->GetPDG(); if (!pPDG) { pTrk = 0; continue; } fjInput.push_back(fastjet::PseudoJet(pTrk->Px(), pTrk->Py(), pTrk->Pz(), pTrk->P())); // pPDG = 0; pTrk = 0; } //============================================================================= fastjet::ClusterSequenceArea clustSeq(fjInput, jetsDef, areaDef); std::vector<fastjet::PseudoJet> includJets = clustSeq.inclusive_jets(dJetsPtMin); // std::vector<fastjet::PseudoJet> subtedJets = bkgSubtractor(includJets); std::vector<fastjet::PseudoJet> selectJets = selectJet(includJets); // std::vector<fastjet::PseudoJet> sortedJets = fastjet::sorted_by_pt(selectJets); for (int j=0; j<selectJets.size(); j++) { double dJet = selectJets[j].pt(); hJet->Fill(dJet); //============================================================================= fastjet::Filter trimmer(subjDef, fastjet::SelectorPtFractionMin(0.)); fastjet::PseudoJet trimmdJet = trimmer(selectJets[j]); std::vector<fastjet::PseudoJet> trimmdSj = trimmdJet.pieces(); double nIsj = 0.; double d1sj = -1.; int k1sj = -1; double d2sj = -1.; int k2sj = -1; for (int i=0; i<trimmdSj.size(); i++) { double dIsj = trimmdSj[i].pt(); if (dIsj<0.001) continue; hJetIsj->Fill(dJet, dIsj); hJetIsz->Fill(dJet, dIsj/dJet); if (dIsj>d1sj) { d2sj = d1sj; k2sj = k1sj; d1sj = dIsj; k1sj = i; } else if (dIsj>d2sj) { d2sj = dIsj; k2sj = i; } nIsj += 1.; } hJetNsj->Fill(dJet, nIsj); if (d1sj>0.) { hJet1sj->Fill(dJet, d1sj); hJet1sz->Fill(dJet, d1sj/dJet); } if (d2sj>0.) { hJet2sj->Fill(dJet, d2sj); hJet2sz->Fill(dJet, d2sj/dJet); } if ((d1sj>0.) && (d2sj>0.)) { double dsj = d1sj - d2sj; double dsz = dsj / dJet; hJetDsj->Fill(dJet, dsj); hJetDsz->Fill(dJet, dsz); } } //============================================================================= pStack = 0; pHeadPy = 0; pHeader = 0; } //============================================================================= rl->UnloadgAlice(); rl->UnloadHeader(); rl->UnloadKinematics(); rl->RemoveEventFolder(); //============================================================================= TFile *file = TFile::Open(Form("%s/pyxsec_hists.root",sPath.Data()), "READ"); TList *lXsc = (TList*)file->Get("cFilterList"); file->Close(); TH1D *hWeightSum = (TH1D*)lXsc->FindObject("h1Trials"); hWeightSum->SetName("hWeightSum"); TProfile *hSigmaGen = (TProfile*)lXsc->FindObject("h1Xsec"); hSigmaGen->SetName("hSigmaGen"); //============================================================================= file = TFile::Open(Form("%s.root",sFile.Data()), "NEW"); hPtHat->Write(); hWeightSum->Write(); hSigmaGen->Write(); list->Write(); file->Close(); //============================================================================= cout << "DONE" << endl; //============================================================================= return 0; }
//_____________________________________________________________________________ void amsvmc_MCStack::PushTrack(Int_t toBeDone, Int_t parent, Int_t pdg, Double_t px, Double_t py, Double_t pz, Double_t e, Double_t vx, Double_t vy, Double_t vz, Double_t tof, Double_t polx, Double_t poly, Double_t polz, TMCProcess mech, Int_t& ntr, Double_t weight, Int_t is) { // cout<<"DEBUG in amsvmc_MCStack::PushTrack, about to call"<<endl; /// Create a new particle and push into stack; /// adds it to the particles array (fParticles) and if not done to the /// stack (fStack). /// Use TParticle::fMother[1] to store Track ID. /// \param toBeDone 1 if particles should go to tracking, 0 otherwise /// \param parent number of the parent track, -1 if track is primary /// \param pdg PDG encoding /// \param px particle momentum - x component [GeV/c] /// \param py particle momentum - y component [GeV/c] /// \param pz particle momentum - z component [GeV/c] /// \param e total energy [GeV] /// \param vx position - x component [cm] /// \param vy position - y component [cm] /// \param vz position - z component [cm] /// \param tof time of flight [s] /// \param polx polarization - x component /// \param poly polarization - y component /// \param polz polarization - z component /// \param mech creator process VMC code /// \param ntr track number (is filled by the stack /// \param weight particle weight /// \param is generation status code const Int_t kFirstDaughter=-1; const Int_t kLastDaughter=-1; TClonesArray& particlesRef = *fParticles; Int_t trackId = GetNtrack(); TParticle* particle = new(particlesRef[trackId]) TParticle(pdg, is, parent, trackId, kFirstDaughter, kLastDaughter, px, py, pz, e, vx, vy, vz, tof); particle->SetPolarisation(polx, poly, polz); particle->SetWeight(weight); particle->SetUniqueID(mech); if (parent<0) fNPrimary++; if (toBeDone && pdg!=50000050) { // cout<<"DEBUG: a track is pushed into fStack, "<<pdg<<", stack number increased to"<<GetNtrack()<<endl; // printf("momemtum: px= %f, py= %f,pz= %f; position:x=%f, y=%f,z=%f; Total momemtum: %f \n",px,py,pz,vx,vy,vz,particle->P()); fStack.push(particle); } if (toBeDone && pdg==50000050 ) { float p=particle->P(); //pow(px*px+py*py+pz*pz,0.5); bool vmc_richpmtcut=RICHDB::detcer(p); // cout<<"vmc_richpmtcut"<<vmc_richpmtcut<<endl; if(vmc_richpmtcut){ // cout<<"DEBUG: a Cerenkov photon is produced, "<<pdg<<", P ="<<p<<endl; // cout<<"DEBUG: a Cerenkov photon is pushed into fStack, "<<pdg<<", stack number increased to"<<GetNtrack()<<endl; // printf("momemtum: px= %f, py= %f,pz= %f; position:x=%f, y=%f,z=%f; tof: %f \n",px*10000,py*10000,pz*10000,vx,vy,vz,tof); fStack.push(particle); } } ntr = GetNtrack() - 1; // cout<<"DEBUG: in PushTracks:"<<endl; // cout<<"parent = "<<parent<<endl; // cout<<"trackID:"<<trackId<<endl; // cout<<"ntr="<<ntr<<endl; // cout<<"Particle is : "<< pdg<<endl; }
TEveTrackList* kine_tracks(Double_t min_pt, Double_t min_p, Bool_t pdg_col, Bool_t recurse, Bool_t use_track_refs) { IlcRunLoader* rl = IlcEveEventManager::AssertRunLoader(); rl->LoadKinematics(); IlcStack* stack = rl->Stack(); if (!stack) { Error("kine_tracks", "can not get kinematics."); return 0; } gEve->DisableRedraw(); TEveTrackList* cont = new TEveTrackList("Kine Tracks"); cont->SetMainColor(3); TEveTrackPropagator* trkProp = cont->GetPropagator(); kine_track_propagator_setup(trkProp); gEve->AddElement(cont); Int_t count = 0; Int_t Np = stack->GetNprimary(); for (Int_t i = 0; i < Np; ++i) { TParticle* p = stack->Particle(i); if (p->GetStatusCode() <= 1) { if (p->Pt() < min_pt && p->P() < min_p) continue; ++count; IlcEveTrack* track = new IlcEveTrack(p, i, trkProp); //PH The line below is replaced waiting for a fix in Root //PH which permits to use variable siza arguments in CINT //PH on some platforms (alphalinuxgcc, solariscc5, etc.) //PH track->SetName(Form("%s [%d]", p->GetName(), i)); char form[1000]; sprintf(form,"%s [%d]", p->GetName(), i); track->SetName(form); track->SetStdTitle(); Int_t ml = p->GetMother(0); if (ml != -1) { track->SetTitle(Form("%s\nMother label=%d\nMother Pdg=%d", track->GetElementTitle(), ml, stack->Particle(ml)->GetPdgCode())); } set_track_color(track, pdg_col); gEve->AddElement(track, cont); if (recurse) kine_daughters(track, stack, min_pt, min_p, pdg_col, recurse); } } // set path marks IlcEveKineTools kt; kt.SetDaughterPathMarks(cont, stack, recurse); if (use_track_refs && rl->LoadTrackRefs() == 0) { kt.SetTrackReferences(cont, rl->TreeTR(), recurse); trkProp->SetEditPathMarks(kTRUE); } kt.SortPathMarks(cont, recurse); //PH const Text_t* tooltip = Form("min pT=%.2lf, min P=%.2lf), N=%d", min_pt, min_p, count); char tooltip[1000]; sprintf(tooltip,"min pT=%.2lf, min P=%.2lf), N=%d", min_pt, min_p, count); cont->SetTitle(tooltip); // Not broadcasted automatically ... cont->MakeTracks(recurse); gEve->EnableRedraw(); gEve->Redraw3D(); return cont; }