inline double get_random(AIDA::IHistogram1D& a_histo, const std::vector<double>& a_integral) { //same logic as CERN-ROOT/TH1.cxx/GetRandom(). double r = rflat_shoot(); int xbins = a_histo.axis().bins(); int ibin = binary_search(xbins,a_integral.data(),r); double x = a_histo.axis().binLowerEdge(ibin); if(r>a_integral[ibin]) { x += a_histo.axis().binWidth(ibin)* (r-a_integral[ibin])/(a_integral[ibin+1]-a_integral[ibin]); } return x; }
inline bool get_integral(AIDA::IHistogram1D& a_histo, std::vector<double>& a_integral) { a_integral.clear(); a_integral.push_back(0); int xbins = a_histo.axis().bins(); for(int index=0;index<xbins;index++) { double h = a_histo.binHeight(index); a_integral.push_back(h+a_integral.back()); } // normalize integral to 1 : double w = a_integral.back(); if(w==0) return false; std::vector<double>::iterator it; for(it=a_integral.begin();it!=a_integral.end();++it){ *it /= w; } return true; }
void EUTelProcessorTrackAnalysis::initialiseResidualVsPositionHistograms(){ int NBinX; double MinX; double MaxX; int NBinY; double MinY; double MaxY; double MinZ; double MaxZ; std::string _histoInfoFileName="histoInfo.xml"; auto_ptr<EUTelHistogramManager> histoMgr( new EUTelHistogramManager( _histoInfoFileName )); EUTelHistogramInfo * histoInfo; bool isHistoManagerAvailable; try { isHistoManagerAvailable = histoMgr->init( ); } catch ( ios::failure& e ) { streamlog_out( ERROR5 ) << "I/O problem with " << _histoInfoFileName << "\n" << "Continuing without histogram manager using default settings" << endl; isHistoManagerAvailable = false; } catch ( ParseException& e ) { streamlog_out( ERROR5 ) << e.what( ) << "\n" << "Continuing without histogram manager using default settings" << endl; isHistoManagerAvailable = false; } std::stringstream sstm; std::string residGblFitHistName; std::string histTitle; for (size_t i = 0; i < _sensorIDs.size() ; ++i){ /////////////////////////////////////////////////////////////////////////////XY residual plots with position sstm << "ResidualX" << _sensorIDs.at(i); residGblFitHistName = sstm.str(); sstm.str(std::string()); sstm << "ResidualsX. Plane " << _sensorIDs.at(i) << ";X direction; Y direction"; histTitle = sstm.str(); sstm.str(std::string("")); histoInfo = histoMgr->getHistogramInfo(residGblFitHistName); NBinX = ( isHistoManagerAvailable && histoInfo ) ? histoInfo->_xBin : 40; MinX = ( isHistoManagerAvailable && histoInfo ) ? histoInfo->_xMin :-10 ; MaxX = ( isHistoManagerAvailable && histoInfo ) ? histoInfo->_xMax : 10; NBinY = ( isHistoManagerAvailable && histoInfo ) ? histoInfo->_yBin : 20; MinY = ( isHistoManagerAvailable && histoInfo ) ? histoInfo->_yMin : -5; MaxY = ( isHistoManagerAvailable && histoInfo ) ? histoInfo->_yMax : 5; MinZ = ( isHistoManagerAvailable && histoInfo ) ? histoInfo->_zMin : -20; MaxZ = ( isHistoManagerAvailable && histoInfo ) ? histoInfo->_zMax : 20; AIDA::IProfile2D * residGblFitX = marlin::AIDAProcessor::histogramFactory(this)->createProfile2D(residGblFitHistName, NBinX, MinX, MaxX, NBinY, MinY, MaxY, MinZ,MaxZ); if (residGblFitX) { residGblFitX->setTitle(histTitle); _mapFromSensorIDToHistogramX.insert(std::make_pair(_sensorIDs.at(i), residGblFitX)); } else { streamlog_out(ERROR2) << "Problem booking the " << (residGblFitHistName) << std::endl; streamlog_out(ERROR2) << "Very likely a problem with path name. Switching off histogramming and continue w/o" << std::endl; } sstm.str(std::string("")); } for(size_t i = 0; i < _sensorIDs.size() ; ++i){ sstm << "ResidualY" << _sensorIDs.at(i); residGblFitHistName = sstm.str(); sstm.str(std::string()); sstm << "ResidualsY. Plane " << _sensorIDs.at(i) << ";X direction; Y direction"; histTitle = sstm.str(); sstm.str(std::string("")); histoInfo = histoMgr->getHistogramInfo(residGblFitHistName); NBinX = ( isHistoManagerAvailable && histoInfo ) ? histoInfo->_xBin : 40;//every 500 micron there is a bin MinX = ( isHistoManagerAvailable && histoInfo ) ? histoInfo->_xMin :-10 ; MaxX = ( isHistoManagerAvailable && histoInfo ) ? histoInfo->_xMax : 10; NBinY = ( isHistoManagerAvailable && histoInfo ) ? histoInfo->_yBin : 20;//every 500 micron there is a bin MinY = ( isHistoManagerAvailable && histoInfo ) ? histoInfo->_yMin : -5; MaxY = ( isHistoManagerAvailable && histoInfo ) ? histoInfo->_yMax : 5; MinZ = ( isHistoManagerAvailable && histoInfo ) ? histoInfo->_zMin : -20; MaxZ = ( isHistoManagerAvailable && histoInfo ) ? histoInfo->_zMax : 20; AIDA::IProfile2D * residGblFitY = marlin::AIDAProcessor::histogramFactory(this)->createProfile2D(residGblFitHistName, NBinX, MinX, MaxX, NBinY, MinY, MaxY, MinZ,MaxZ); if (residGblFitY) { residGblFitY->setTitle(histTitle); _mapFromSensorIDToHistogramY.insert(std::make_pair(_sensorIDs.at(i), residGblFitY)); } else { streamlog_out(ERROR2) << "Problem booking the " << (residGblFitHistName) << std::endl; streamlog_out(ERROR2) << "Very likely a problem with path name. Switching off histogramming and continue w/o" << std::endl; } sstm.str(std::string("")); } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////The incidence angles for each plane for(size_t i = 0; i < _sensorIDs.size() ; ++i){ sstm << "IncidenceXZ" << _sensorIDs.at(i); residGblFitHistName = sstm.str(); sstm.str(std::string()); sstm << "Incidence local Tx (XZ plane). Plane " << _sensorIDs.at(i); histTitle = sstm.str(); sstm.str(std::string("")); histoInfo = histoMgr->getHistogramInfo(residGblFitHistName); NBinX = ( isHistoManagerAvailable && histoInfo ) ? histoInfo->_xBin : 40000; MinX = ( isHistoManagerAvailable && histoInfo ) ? histoInfo->_xMin :-0.05 ; MaxX = ( isHistoManagerAvailable && histoInfo ) ? histoInfo->_xMax : 0.005; AIDA::IHistogram1D * incidenceGblFitXZ = marlin::AIDAProcessor::histogramFactory(this)->createHistogram1D(residGblFitHistName, NBinX, MinX, MaxX); if (incidenceGblFitXZ){ incidenceGblFitXZ->setTitle(histTitle); _mapFromSensorIDToKinkXZ.insert(std::make_pair(_sensorIDs.at(i), incidenceGblFitXZ)); } else { streamlog_out(ERROR2) << "Problem booking the " << (residGblFitHistName) << std::endl; streamlog_out(ERROR2) << "Very likely a problem with path name. Switching off histogramming and continue w/o" << std::endl; } sstm.str(std::string("")); } for(size_t i = 0; i < _sensorIDs.size() ; ++i){ sstm << "IncidenceYZ" << _sensorIDs.at(i); residGblFitHistName = sstm.str(); sstm.str(std::string()); sstm << "Incidence local Ty (YZ plane). Plane " << _sensorIDs.at(i); histTitle = sstm.str(); sstm.str(std::string("")); histoInfo = histoMgr->getHistogramInfo(residGblFitHistName); NBinX = ( isHistoManagerAvailable && histoInfo ) ? histoInfo->_xBin : 40; MinX = ( isHistoManagerAvailable && histoInfo ) ? histoInfo->_xMin :-0.001 ; MaxX = ( isHistoManagerAvailable && histoInfo ) ? histoInfo->_xMax : 0.001; AIDA::IHistogram1D * incidenceGblFitYZ = marlin::AIDAProcessor::histogramFactory(this)->createHistogram1D(residGblFitHistName, NBinX, MinX, MaxX); if (incidenceGblFitYZ) { incidenceGblFitYZ->setTitle(histTitle); _mapFromSensorIDToKinkYZ.insert(std::make_pair(_sensorIDs.at(i), incidenceGblFitYZ)); } else { streamlog_out(ERROR2) << "Problem booking the " << (residGblFitHistName) << std::endl; streamlog_out(ERROR2) << "Very likely a problem with path name. Switching off histogramming and continue w/o" << std::endl; } sstm.str(std::string("")); } /////////////////////////////////////////////////////////////////////////////////////// }
int main(int argc,char* argv[]) { AIDA::IAnalysisFactory* af = AIDA_createAnalysisFactory(); if(!af) return EXIT_FAILURE; AIDA::ITreeFactory* trf = af->createTreeFactory(); if(!trf) return EXIT_FAILURE; AIDA::ITree* tree = trf->create(); delete trf; if(!tree) return EXIT_FAILURE; AIDA::IHistogramFactory* hf = af->createHistogramFactory(*tree); if(!hf) return EXIT_FAILURE; AIDA::IHistogram1D* h1d = hf->createHistogram1D("master 1d","master 1d",50,-3,3); AIDA::IHistogram1D* hr = hf->createHistogram1D("random","random",50,-3,3); delete hf; if(!h1d) return EXIT_FAILURE; if(!hr) return EXIT_FAILURE; { // fill the "master" histogram with a gaussian centered at zero, and a rms of one for (int i=0; i<1000000; i++) { h1d->fill(rgauss_shoot()); } } { // fill the "random" histogram with values sampled from the "master" std::vector<double> integral; if(!get_integral(*h1d,integral)) return EXIT_FAILURE; for (int i=0; i<1000000; i++) { hr->fill(get_random(*h1d,integral)); } } AIDA::IPlotterFactory* pf = af->createPlotterFactory(argc,argv); if(pf) { AIDA::IPlotter* plotter = pf->create(); delete pf; if(plotter) { plotter->createRegions(1,2,0); plotter->region(0)->plot(*h1d); plotter->region(1)->plot(*hr); plotter->show(); plotter->interact(); delete plotter; } } else { // Printing some statistical values of the "master" histogram std::cout << "Master :" << std::endl; std::cout << "Title : " << h1d->title() << std::endl; std::cout << "Entries: " << h1d->entries() << std::endl; std::cout << "Mean : " << h1d->mean() << std::endl; std::cout << "RMS : " << h1d->rms() << std::endl; std::cout << "========" << std::endl; // ... and the same for the "randomly sampled" histogram std::cout << "Sampled:" << std::endl; std::cout << "Title : " << hr->title() << std::endl; std::cout << "Entries: " << hr->entries() << std::endl; std::cout << "Mean : " << hr->mean() << std::endl; std::cout << "RMS : " << hr->rms() << std::endl; } delete af; std::cout << "That's it !" << std::endl; return EXIT_SUCCESS; }
StatusCode TrackVertexMonitor::execute() { LHCb::RecVertex::Range pvcontainer = get<LHCb::RecVertex::Range>(m_pvContainerName) ; LHCb::Track::Range alltracks = get<LHCb::Track::Range>( m_trackContainerName ); TrackTypePredicate isLong( LHCb::Track::Long ) ; TrackFlagPredicate isBackward( LHCb::Track::Backward ) ; TrackFlagPredicate isForward( LHCb::Track::Backward,false ) ; // lists needed // - primary vertices // - all tracks // - long tracks // - backward tracks // for now I'll just create the track lists from the Best container typedef std::vector<const LHCb::Track*> TrackVector ; // number of primary vertices plot(pvcontainer.size(),"NumPrimaryVertices",-0.5,10.5,11) ; BOOST_FOREACH( const LHCb::RecVertex* pv, pvcontainer ) { TrackVector tracks = myconvert(pv->tracks()) ; TrackVector forwardtracks = myselect(tracks,isForward) ; TrackVector backwardtracks = myselect(tracks,isBackward) ; TrackVector longtracks = myselect(tracks,isLong) ; // number of tracks per primary vertex plot( tracks.size(), "NumTracksPerPV",-0.5,99.5,50) ; // number of long tracks per primary vertex plot( longtracks.size(), "NumLongTracksPerPV",-0.5,99.5,50) ; // number of backward tracks per primary vertex plot( backwardtracks.size(), "NumBackTracksPerPV",-0.5,99.5,50) ; // chisquare plot( pv->chi2() / pv->nDoF(), "PV chisquare per dof",0.,3.,150) ; // position with crap hack for vertices at exactly 0 if(std::abs(pv->position().x()) > 0.00001 && std::abs(pv->position().y()) > 0.00001 ){ //info() << "pvx " << pv->position().x() << endmsg; plot( pv->position().x(), "PV x position",-m_rpvmax,m_rpvmax) ; plot( pv->position().y(), "PV y position",-m_rpvmax,m_rpvmax) ; plot( pv->position().z(), "PV z position", m_zpvmin,m_zpvmax) ; plot( pv->position().z(), "PV z position (wide)", m_zpvmin_wide,m_zpvmax_wide) ; } if( std::abs( pv->position().y() ) < m_rpvmax ) profile1D( pv->position().z(), pv->position().y(),"PV y versus z",m_zpvmin,m_zpvmax,m_nprbins) ; if( std::abs( pv->position().x() ) < m_rpvmax ) profile1D( pv->position().z(), pv->position().x(),"PV x versus z",m_zpvmin,m_zpvmax,m_nprbins) ; // refit the primary vertex with only the long tracks if(longtracks.size()>=2) { LHCb::RecVertex* longvertex = m_vertexer->fit( longtracks ) ; if(longvertex) plot( longvertex->chi2() / longvertex->nDoF(), "PV long chisquare per dof",0,10) ; delete longvertex ; } // now split the primary vertex in left and right tracks TrackVector lefttracks = myselect(tracks,TrackVeloSidePredicate(+1)) ; TrackVector righttracks = myselect(tracks,TrackVeloSidePredicate(-1)) ; if( lefttracks.size() >= 2 && righttracks.size() >= 2 ) { // fit two vertices LHCb::RecVertex* leftvertex = m_vertexer->fit( lefttracks ) ; if( leftvertex ) { plot( leftvertex->position().x(), "PV left x",-m_rpvmax,m_rpvmax) ; plot( leftvertex->position().y(), "PV left y",-m_rpvmax,m_rpvmax) ; plot( leftvertex->position().z(), "PV left z", m_zpvmin,m_zpvmax) ; if( leftSensor ) { plot( -(leftSensor->globalToVeloHalfBox(leftvertex->position())).x(), "PV left-Left half x",-m_rpvmax/2,m_rpvmax/2) ; plot( -(leftSensor->globalToVeloHalfBox(leftvertex->position())).y(), "PV left-Left half y",-m_rpvmax/2,m_rpvmax/2) ; } } LHCb::RecVertex* rightvertex = m_vertexer->fit( righttracks ) ; if( rightvertex) { plot( rightvertex->position().x(), "PV right x",-m_rpvmax,m_rpvmax) ; plot( rightvertex->position().y(), "PV right y",-m_rpvmax,m_rpvmax) ; plot( rightvertex->position().z(), "PV right z", m_zpvmin,m_zpvmax) ; if( rightSensor ) { plot( -(rightSensor->globalToVeloHalfBox(rightvertex->position())).x(), "PV right-Right half x",-m_rpvmax/2,m_rpvmax/2) ; plot( -(rightSensor->globalToVeloHalfBox(rightvertex->position())).y(), "PV right-Right half y",-m_rpvmax/2,m_rpvmax/2) ; } } if( leftvertex && rightvertex) { // draw the difference Gaudi::XYZVector dx = leftvertex->position() - rightvertex->position() ; plot( dx.x(), "PV left-right delta x",-0.1,0.1) ; plot( dx.y(), "PV left-right delta y",-0.1,0.1) ; plot( dx.z(), "PV left-right delta z",-1,1) ; if( std::abs( dx.y() ) < m_ipmaxprof ) profile1D( pv->position().z(), dx.y(),"PV left-right delta y versus z",m_zpvmin,m_zpvmax,m_nprbins) ; if( std::abs( dx.x() ) < m_ipmaxprof ) profile1D( pv->position().z(), dx.x(),"PV left-right delta x versus z",m_zpvmin,m_zpvmax,m_nprbins) ; // draw the pull of the difference Gaudi::SymMatrix3x3 cov = leftvertex->covMatrix() + rightvertex->covMatrix() ; plot( dx.x()/std::sqrt(cov(0,0)), "PV left-right delta x pull",-5,5) ; plot( dx.y()/std::sqrt(cov(1,1)), "PV left-right delta y pull",-5,5) ; plot( dx.z()/std::sqrt(cov(2,2)), "PV left-right delta z pull",-5,5) ; // draw the chisquares plot( leftvertex->chi2() / leftvertex->nDoF(), "PV left chisquare per dof",0,10) ; plot( rightvertex->chi2() / rightvertex->nDoF(), "PV right chisquare per dof",0,10) ; } delete leftvertex ; delete rightvertex ; } if( forwardtracks.size() >= 2 && backwardtracks.size() >= 2 ) { // fit two vertices LHCb::RecVertex* forwardvertex = m_vertexer->fit( forwardtracks ) ; LHCb::RecVertex* backwardvertex = m_vertexer->fit( backwardtracks ) ; if( forwardvertex && backwardvertex) { Gaudi::XYZVector dx = forwardvertex->position() - backwardvertex->position() ; // draw the difference plot( dx.x(), "PV forward-backward delta x",-m_ipmax,m_ipmax) ; plot( dx.y(), "PV forward-backward delta y",-m_ipmax,m_ipmax) ; plot( dx.z(), "PV forward-backward delta z",-m_dzmax,m_dzmax) ; if( std::abs( dx.y() ) < m_ipmaxprof ) profile1D( pv->position().z(), dx.y(),"PV forward-backward delta y versus z",m_zpvmin,m_zpvmax,m_nprbins) ; if( std::abs( dx.x() ) < m_ipmaxprof ) profile1D( pv->position().z(), dx.x(),"PV forward-backward delta x versus z",m_zpvmin,m_zpvmax,m_nprbins) ; // draw the pull of the difference Gaudi::SymMatrix3x3 cov = forwardvertex->covMatrix() + backwardvertex->covMatrix() ; plot( dx.x()/std::sqrt(cov(0,0)), "PV forward-backward delta x pull",-5,5) ; plot( dx.y()/std::sqrt(cov(1,1)), "PV forward-backward delta y pull",-5,5) ; plot( dx.z()/std::sqrt(cov(2,2)), "PV forward-backward delta z pull",-5,5) ; // draw the chisquares plot( forwardvertex->chi2() / forwardvertex->nDoF(), "PV forward chisquare/dof",0,10) ; plot( backwardvertex->chi2() / backwardvertex->nDoF(), "PV backward chisquare/dof",0,10) ; } delete forwardvertex ; delete backwardvertex ; } // for events with a single vertex, do something with IP of // highest momentum track, as function of phi and eta. if( pvcontainer.size()==1 && tracks.size()>=10 ) { // now get all good long tracks from the best container: TrackVector goodlongtracks ; BOOST_FOREACH( const LHCb::Track* tr, alltracks ) if( isLong(tr) && tr->chi2PerDoF()<m_maxLongTrackChisqPerDof && tr->p()>m_minLongTrackMomentum) goodlongtracks.push_back( tr ) ; BOOST_FOREACH( const LHCb::Track* tr, goodlongtracks ) { const LHCb::State& firststate = tr->firstState() ; double dz = pv->position().z() - firststate.z() ; double dx = firststate.x() + dz * firststate.tx() - pv->position().x() ; double dy = firststate.y() + dz * firststate.ty() - pv->position().y() ; Gaudi::XYZVector p3 = firststate.momentum() ; m_trackXIP->fill( dx ) ; m_trackYIP->fill( dy ) ; // apply a cut for the profiles if( std::abs(dx) < m_ipmaxprof && std::abs(dy) < m_ipmaxprof ) { double phi = p3.phi() ; double eta = p3.eta() ; m_trackXIPVsEta->fill(eta,dx) ; m_trackXIPVsPhi->fill(phi,dx) ; m_trackYIPVsEta->fill(eta,dy) ; m_trackYIPVsPhi->fill(phi,dy) ; } } if( goodlongtracks.size()>=2 ) { using namespace boost::lambda; std::sort(goodlongtracks.begin(), goodlongtracks.end(), bind(&LHCb::State::pt,bind(&LHCb::Track::firstState,*_1)) < bind(&LHCb::State::pt,bind(&LHCb::Track::firstState,*_2)) ) ; const LHCb::Track* firsttrack = goodlongtracks.back() ; goodlongtracks.pop_back() ; // now pick a 2nd track that makes the highest possible invariant mass with this one double highestmass2(0) ; const LHCb::Track* secondtrack(0) ; Gaudi::XYZVector firstp3 = firsttrack->firstState().momentum() ; for( TrackVector::const_iterator it = goodlongtracks.begin(); it != goodlongtracks.end(); ++it) { Gaudi::XYZVector p3 = (*it)->firstState().momentum() ; double mass2= p3.r() * firstp3.r() - p3.Dot( firstp3 ) ; if(secondtrack==0 || highestmass2 < mass2 ) { highestmass2 = mass2 ; secondtrack = *it ; } } // recompute the vertex without these tracks TrackVector::iterator newend = tracks.end() ; newend = std::remove(tracks.begin(),newend,firsttrack) ; newend = std::remove(tracks.begin(),newend,secondtrack) ; tracks.erase(newend,tracks.end()) ; LHCb::RecVertex* restvertex = m_vertexer->fit( tracks ) ; if( restvertex && firsttrack->nStates()!=0 ) { const LHCb::State& firststate = firsttrack->firstState() ; double dz = restvertex->position().z() - firststate.z() ; double dx = firststate.x() + dz * firststate.tx() - restvertex->position().x() ; double dy = firststate.y() + dz * firststate.ty() - restvertex->position().y() ; double nt = std::sqrt( firststate.tx()*firststate.tx() + firststate.ty()*firststate.ty() ) ; // transverse and longitudinal impact parameter double iptrans = (dx * firststate.ty() - dy * firststate.tx())/nt ; double iplong = (dx * firststate.tx() + dy * firststate.ty())/nt ; Gaudi::XYZVector p3 = firststate.momentum() ; double phi = p3.phi() ; double eta = p3.eta() ; m_fastTrackTransverseIP->fill(iptrans ) ; m_fastTrackLongitudinalIP->fill(iplong ) ; m_fastTrackXIP->fill( dx ) ; m_fastTrackYIP->fill( dy ) ; // apply a cut for the profiles if( std::abs(iptrans) < m_ipmaxprof && std::abs(iplong) < m_ipmaxprof ) { m_fastTrackTransverseIPVsEta->fill(eta,iptrans) ; m_fastTrackTransverseIPVsPhi->fill(phi,iptrans) ; m_fastTrackLongitudinalIPVsEta->fill(eta,iplong) ; m_fastTrackLongitudinalIPVsPhi->fill(phi,iplong) ; } if( std::abs(dx) < m_ipmaxprof && std::abs(dy) < m_ipmaxprof ) { m_fastTrackXIPVsEta->fill(eta,dx) ; m_fastTrackXIPVsPhi->fill(phi,dx) ; m_fastTrackYIPVsEta->fill(eta,dy) ; m_fastTrackYIPVsPhi->fill(phi,dy) ; } // The two-track cuts we only make for relatively heavy objects double mass = std::sqrt(highestmass2) ; m_twoprongMass->fill(mass / Gaudi::Units::GeV ) ; if( mass > 1*Gaudi::Units::GeV ) { // compute doca of two tracks Gaudi::XYZVector dx3 = firsttrack->firstState().position() - secondtrack->firstState().position() ; Gaudi::XYZVector n3 = firsttrack->firstState().slopes().Cross( secondtrack->firstState().slopes() ) ; double doca = dx3.Dot(n3) / n3.R() ; m_twoprongDoca->fill(doca) ; if( std::abs(doca) < m_twoprongDoca->axis().upperEdge() ) { m_twoprongDocaVsEta->fill(firstp3.eta(),doca) ; m_twoprongDocaVsPhi->fill(firstp3.phi(),doca) ; } // the easiest way to compute the pull is with a vertex fit LHCb::TwoProngVertex* twoprong = m_vertexer->fit(firsttrack->firstState(),secondtrack->firstState()) ; if(twoprong) { double pc = twoprong->p3().R() ; m_twoprongMomentum->fill( pc / Gaudi::Units::GeV ) ; m_twoprongDocaPull->fill(std::sqrt(twoprong->chi2()) * (doca>0 ? 1 : -1)) ; double chi2, decaylength,decaylengtherr ; m_vertexer->computeDecayLength( *twoprong, *restvertex, chi2, decaylength,decaylengtherr ) ; m_twoprongDecaylength->fill( decaylength ) ; m_twoprongDecaylengthSignificance->fill( decaylength/decaylengtherr ) ; m_twoprongIPChisquare->fill( chi2 / 2 ) ; m_twoprongCTau->fill( decaylength * mass / pc ) ; m_twoprongTau->fill( decaylength * mass / (pc * Gaudi::Units::c_light * Gaudi::Units::picosecond) ) ; delete twoprong ; } } } delete restvertex ; } }