From 725a4c220316b2ae604b58a2eab097d2aa5c7926 Mon Sep 17 00:00:00 2001 From: Dave Casper <dcasper@uci.edu> Date: Thu, 8 Mar 2018 08:16:08 -0800 Subject: [PATCH] Add method to return global maximum of density, and a histogram to test it Former-commit-id: c776e396b639144bc6ce359ed2aa6d70e3d2d50b --- .../IVertexTrackDensityEstimator.h | 6 ++- .../GaussianTrackDensity.h | 20 +++++++++ .../GaussianDensityTestAlg_jobOptions.py | 3 +- .../src/GaussianDensityTestAlg.cxx | 25 +++++++---- .../src/GaussianDensityTestAlg.h | 1 + .../src/GaussianTrackDensity.cxx | 41 +++++++++++++++++-- 6 files changed, 83 insertions(+), 13 deletions(-) diff --git a/Tracking/TrkVertexFitter/TrkVertexFitterInterfaces/TrkVertexFitterInterfaces/IVertexTrackDensityEstimator.h b/Tracking/TrkVertexFitter/TrkVertexFitterInterfaces/TrkVertexFitterInterfaces/IVertexTrackDensityEstimator.h index f6d60e480cb..09e109b66d7 100755 --- a/Tracking/TrkVertexFitter/TrkVertexFitterInterfaces/TrkVertexFitterInterfaces/IVertexTrackDensityEstimator.h +++ b/Tracking/TrkVertexFitter/TrkVertexFitterInterfaces/TrkVertexFitterInterfaces/IVertexTrackDensityEstimator.h @@ -44,7 +44,6 @@ namespace Trk */ static const InterfaceID& interfaceID() { return IID_IVertexTrackDensityEstimator; }; - /** * Adds a list of tracks, whose impact parameters will contribute to the density function. */ @@ -77,6 +76,11 @@ namespace Trk */ virtual void trackDensity(double z, double& density, double& firstDerivative, double& secondDerivative) const = 0; + /* + * Find position of global maximum for density function + */ + virtual double globalMaximum() const = 0; + /** * Resets the internal state of the tool, forgetting all tracks previously added. */ diff --git a/Tracking/TrkVertexFitter/TrkVertexSeedFinderUtils/TrkVertexSeedFinderUtils/GaussianTrackDensity.h b/Tracking/TrkVertexFitter/TrkVertexSeedFinderUtils/TrkVertexSeedFinderUtils/GaussianTrackDensity.h index 1bb7c927b7f..9d64a2d92bf 100644 --- a/Tracking/TrkVertexFitter/TrkVertexSeedFinderUtils/TrkVertexSeedFinderUtils/GaussianTrackDensity.h +++ b/Tracking/TrkVertexFitter/TrkVertexSeedFinderUtils/TrkVertexSeedFinderUtils/GaussianTrackDensity.h @@ -72,6 +72,11 @@ namespace Trk */ virtual void trackDensity(double z, double& density, double& firstDerivative, double& secondDerivativec) const; + /** + * Find location of global maximum for density function + */ + virtual double globalMaximum() const; + /** * Resets the internal state of the tool, forgetting all tracks previously added. */ @@ -139,6 +144,13 @@ namespace Trk GaussianTrackDensity::pred_entry_by_min >::const_iterator upperMapIterator; private: + inline void updateMaximum(double trialZ, double trialValue, double& maxZ, double& maxValue) const + { if (trialValue > maxValue) { maxZ = trialZ; maxValue = trialValue; } } + + + inline double stepSize(double y, double dy, double ddy) const + { return ( m_gaussStep ? 1/(dy/y-ddy/dy) : -dy/ddy ); } + // Cache for track information trackMap m_trackMap; @@ -152,11 +164,19 @@ namespace Trk "MaxD0Significance", 3.5, "Maximum radial impact parameter significance to use track" }; + + // Tracks within this many sigma(z) are added to weight; increasing cut trades CPU efficiency for improved smoothness in tails Gaudi::Property<double> m_z0MaxSignificance { this, "MaxZ0Significance", 12.0, "Maximum longitudinal impact parameter significance to include track in weight"}; + // Assumed shape of density function near peak; Gaussian (true) or parabolic (false) + Gaudi::Property<bool> m_gaussStep { this, + "GaussianStep", + true, + "Peak search: True means assume Gaussian behavior, False means Newton/parabolic" }; + }; } #endif diff --git a/Tracking/TrkVertexFitter/TrkVertexSeedFinderUtils/share/GaussianDensityTestAlg_jobOptions.py b/Tracking/TrkVertexFitter/TrkVertexSeedFinderUtils/share/GaussianDensityTestAlg_jobOptions.py index 6784f0b8c1e..553052c06c2 100644 --- a/Tracking/TrkVertexFitter/TrkVertexSeedFinderUtils/share/GaussianDensityTestAlg_jobOptions.py +++ b/Tracking/TrkVertexFitter/TrkVertexSeedFinderUtils/share/GaussianDensityTestAlg_jobOptions.py @@ -7,7 +7,8 @@ import AthenaPython.ConfigLib as apcl cfg = apcl.AutoCfg(name = 'InDetRecExampleAutoConfig', input_files=athenaCommonFlags.FilesInput()) cfg.configure_job() -theApp.EvtMax = 1 +theApp.EvtMax = -1 +#athenaCommonFlags.SkipEvents = 1 svcMgr += CfgMgr.THistSvc() svcMgr.THistSvc.Output = [ "file1 DATAFILE='gaussianDensity.root' OPT='RECREATE'" ] diff --git a/Tracking/TrkVertexFitter/TrkVertexSeedFinderUtils/src/GaussianDensityTestAlg.cxx b/Tracking/TrkVertexFitter/TrkVertexSeedFinderUtils/src/GaussianDensityTestAlg.cxx index d6481036388..f7940784e21 100644 --- a/Tracking/TrkVertexFitter/TrkVertexSeedFinderUtils/src/GaussianDensityTestAlg.cxx +++ b/Tracking/TrkVertexFitter/TrkVertexSeedFinderUtils/src/GaussianDensityTestAlg.cxx @@ -65,10 +65,12 @@ StatusCode GaussianDensityTestAlg::initialize() m_h_density = new TH1F("Density", "Density", 800, -200.0, 200.0); m_h_truthDensity = new TH1F("Truth", "Truth", 800, -200.0, 200.0); m_h_truthVertices = new TH1F("TruthVertices", "TruthVertices", 800, -200.0, 200.0); + m_h_modeCheck = new TH1F("ModeOffset", "ModeOffset", 100, -10.0, 10.0); CHECK( m_iTHistSvc->regHist("/file1/h/density", m_h_density) ); CHECK( m_iTHistSvc->regHist("/file1/h/truth", m_h_truthDensity) ); CHECK( m_iTHistSvc->regHist("/file1/h/truthvertices", m_h_truthVertices) ); + CHECK( m_iTHistSvc->regHist("/file1/h/modeoffset", m_h_modeCheck) ); return StatusCode::SUCCESS; } @@ -96,17 +98,17 @@ StatusCode GaussianDensityTestAlg::execute() m_estimator->reset(); m_estimator->addTracks(perigeeList); - for (int i = 0; i < 800; i++) - { - double z = -200.0 + 0.25 + i*0.5; - double density = m_estimator->trackDensity(z); - m_h_density->Fill((float) z, (float) density); - } + // for (int i = 0; i < 800; i++) + // { + // double z = -200.0 + 0.25 + i*0.5; + // double density = m_estimator->trackDensity(z); + // m_h_density->Fill((float) z, (float) density); + // } ATH_MSG_VERBOSE("Analyzing MC truth"); std::vector<Amg::Vector3D> truth; ATH_CHECK( findTruth(trackVector, truth) ); ATH_MSG_VERBOSE("Filling truth vertex histogram"); - for (auto& v : truth) m_h_truthVertices->Fill( v[2] ); + //for (auto& v : truth) m_h_truthVertices->Fill( v[2] ); return StatusCode::SUCCESS; @@ -165,6 +167,9 @@ void GaussianDensityTestAlg::selectTracks(const xAOD::TrackParticleContainer* tr /////////////////////////////////////////////////////////////////// StatusCode GaussianDensityTestAlg::findTruth(const std::vector<Trk::ITrackLink*>& trackVector, std::vector<Amg::Vector3D>& truth) const { + double modeClosestDistance = std::numeric_limits<double>::max(); + double mode = m_estimator->globalMaximum(); + xAOD::TrackParticle::ConstAccessor<ElementLink<xAOD::TruthParticleContainer> > truthParticleAssoc("truthParticleLink"); SG::ReadHandle<xAOD::TruthEventContainer> signalEvents(m_truthEventsKey); @@ -201,7 +206,7 @@ void GaussianDensityTestAlg::selectTracks(const xAOD::TrackParticleContainer* tr nGoodTracks++; const Trk::Perigee* perigee = dynamic_cast<const Trk::Perigee*>(trk->parameters()); if (perigee == nullptr) ATH_MSG_ERROR("Invalid Perigee"); - m_h_truthDensity->Fill(vLink->z()); + //m_h_truthDensity->Fill(vLink->z()); ATH_MSG_VERBOSE("Filled truth density histogram"); } break; @@ -217,6 +222,7 @@ void GaussianDensityTestAlg::selectTracks(const xAOD::TrackParticleContainer* tr if (nGoodTracks >= m_truthVertexTracks) { truth.push_back(vTruth); + modeClosestDistance = std::min(modeClosestDistance, mode - vTruth[2]); } } } @@ -275,6 +281,7 @@ void GaussianDensityTestAlg::selectTracks(const xAOD::TrackParticleContainer* tr if (nGoodTracks >= m_truthVertexTracks) { truth.push_back(vTruth); + modeClosestDistance = std::min(modeClosestDistance, mode - vTruth[2]); } } } @@ -282,6 +289,8 @@ void GaussianDensityTestAlg::selectTracks(const xAOD::TrackParticleContainer* tr { ATH_MSG_WARNING("No TruthPileupEventContainer found"); } + + m_h_modeCheck->Fill( modeClosestDistance ); return StatusCode::SUCCESS; } diff --git a/Tracking/TrkVertexFitter/TrkVertexSeedFinderUtils/src/GaussianDensityTestAlg.h b/Tracking/TrkVertexFitter/TrkVertexSeedFinderUtils/src/GaussianDensityTestAlg.h index 605f64fe7ce..2ef16e3ff4c 100644 --- a/Tracking/TrkVertexFitter/TrkVertexSeedFinderUtils/src/GaussianDensityTestAlg.h +++ b/Tracking/TrkVertexFitter/TrkVertexSeedFinderUtils/src/GaussianDensityTestAlg.h @@ -133,6 +133,7 @@ class GaussianDensityTestAlg TH1* m_h_density; TH1* m_h_truthDensity; TH1* m_h_truthVertices; + TH1* m_h_modeCheck; }; // class } // namespace diff --git a/Tracking/TrkVertexFitter/TrkVertexSeedFinderUtils/src/GaussianTrackDensity.cxx b/Tracking/TrkVertexFitter/TrkVertexSeedFinderUtils/src/GaussianTrackDensity.cxx index cdc4c70dce3..0d7f3e3bfdb 100644 --- a/Tracking/TrkVertexFitter/TrkVertexSeedFinderUtils/src/GaussianTrackDensity.cxx +++ b/Tracking/TrkVertexFitter/TrkVertexSeedFinderUtils/src/GaussianTrackDensity.cxx @@ -61,14 +61,49 @@ namespace Trk if (firstLoop->second.lowerBound > z || finalLoop->second.upperBound < z) return sum; for (auto itrk = firstLoop; itrk != finalLoop && itrk != m_trackMap.end(); itrk++) { - //ATH_MSG_DEBUG("@z=" << z << " adding contrib from z0=" << itrk->first.parameters()[Trk::z0] << - // "c_0, c_1, c2 = " << itrk->second.c_0 << " " << itrk->second.c_1 << " " << - // itrk->second.c_2 << " arg=" << (itrk->second.c_0+z*(itrk->second.c_1 + z*itrk->second.c_2))); sum += exp(itrk->second.c_0+z*(itrk->second.c_1 + z*itrk->second.c_2)); } return sum; } + double GaussianTrackDensity::globalMaximum() const + { + // strategy: + // the global maximum must be somewhere near a track... + // since we can calculate the first and second derivatives, at each point we can determine + // a) whether the function is curved up (minimum) or down (maximum) + // b) the distance to nearest maximum, assuming either Newton (parabolic) or Gaussian local behavior + // + // For each track where the second derivative is negative, find step to nearest maximum + // Take that step, and then do one final refinement + // The largest density encountered in this procedure (after checking all tracks) is considered the maximum + // + double maximumPosition = 0.0; + double maximumDensity = 0.0; + + for (const auto& entry : m_trackMap) + { + double trialZ = entry.first.parameters()[Trk::z0]; + double density = 0.0; + double slope = 0.0; + double curvature = 0.0; + trackDensity( trialZ, density, slope, curvature ); + if ( curvature >= 0.0 || density <= 0.0 ) continue; + updateMaximum( trialZ, density, maximumPosition, maximumDensity ); + trialZ += stepSize( density, slope, curvature ); + trackDensity( trialZ, density, slope, curvature ); + if ( curvature >= 0.0 || density <= 0.0 ) continue; + updateMaximum( trialZ, density, maximumPosition, maximumDensity ); + trialZ += stepSize( density, slope, curvature ); + trackDensity( trialZ, density, slope, curvature ); + if ( curvature >= 0.0 || density <= 0.0) continue; + updateMaximum( trialZ, density, maximumPosition, maximumDensity ); + } + if ( maximumDensity <= 0 ) ATH_MSG_WARNING("Global maximum at density of 0; track map contains " << + m_trackMap.size() << " tracks"); + return maximumPosition; + } + void GaussianTrackDensity::addTracks(const std::vector<const Track*>& vectorTrk) { std::vector<const TrackParameters*> perigeeList; -- GitLab