8 #include <tracking/modules/mcMatcher/MCRecoTracksMatcherModule.h>
11 #include <framework/datastore/StoreArray.h>
13 #include <framework/gearbox/Const.h>
15 #include <tracking/dataobjects/RecoTrack.h>
16 #include <mdst/dataobjects/MCParticle.h>
19 #include <pxd/dataobjects/PXDCluster.h>
20 #include <svd/dataobjects/SVDCluster.h>
21 #include <cdc/dataobjects/CDCHit.h>
25 #include <Eigen/Dense>
33 #ifdef __INTEL_COMPILER
34 #pragma warning disable 177
45 struct iter_pair_range : std::pair<Iter, Iter> {
46 explicit iter_pair_range(std::pair<Iter, Iter>
const& x)
47 : std::pair<Iter, Iter>(x)
63 return begin() == end();
68 inline iter_pair_range<Iter> as_range(std::pair<Iter, Iter>
const& x)
70 return iter_pair_range<Iter>(x);
75 using RecoTrackId = int;
76 struct WeightedRecoTrackId {
77 operator int()
const {
return id; }
82 using DetHitIdPair = std::pair<DetId, HitId>;
84 struct CompDetHitIdPair {
85 bool operator()(
const std::pair<DetId, HitId>& lhs,
86 const std::pair<std::pair<DetId, HitId>, WeightedRecoTrackId>& rhs)
88 return lhs < rhs.first;
91 bool operator()(
const std::pair<std::pair<DetId, HitId>, WeightedRecoTrackId>& lhs,
92 const std::pair<DetId, HitId>& rhs)
94 return lhs.first < rhs;
99 template <
class AMapOrSet>
100 void fillIDsFromStoreArray(AMapOrSet& recoTrackID_by_hitID,
103 RecoTrackId recoTrackId = -1;
104 for (
const RecoTrack& recoTrack : storedRecoTracks) {
106 std::vector<std::pair<DetHitIdPair, WeightedRecoTrackId> > hitIDsInTrack;
107 double totalWeight = 0;
109 const OriginTrackFinder c_MCTrackFinderAuxiliaryHit =
110 OriginTrackFinder::c_MCTrackFinderAuxiliaryHit;
113 OriginTrackFinder originFinder = recoTrack.getFoundByTrackFinder(cdcHit);
114 double weight = originFinder == c_MCTrackFinderAuxiliaryHit ? 0 : 1;
115 totalWeight += weight;
116 hitIDsInTrack.push_back({{Const::CDC, cdcHit->getArrayIndex()}, {recoTrackId, weight}});
119 OriginTrackFinder originFinder = recoTrack.getFoundByTrackFinder(svdHit);
120 double weight = originFinder == c_MCTrackFinderAuxiliaryHit ? 0 : 1;
121 totalWeight += weight;
122 hitIDsInTrack.push_back({{Const::SVD, svdHit->getArrayIndex()}, {recoTrackId, weight}});
125 OriginTrackFinder originFinder = recoTrack.getFoundByTrackFinder(pxdHit);
126 double weight = originFinder == c_MCTrackFinderAuxiliaryHit ? 0 : 1;
127 totalWeight += weight;
128 hitIDsInTrack.push_back({{Const::PXD, pxdHit->getArrayIndex()}, {recoTrackId, weight}});
132 if (totalWeight == 0) {
133 for (std::pair<DetHitIdPair, WeightedRecoTrackId>& recoTrack_for_hitID : hitIDsInTrack) {
134 recoTrack_for_hitID.second.weight = 1;
139 typename AMapOrSet::iterator itInsertHint = recoTrackID_by_hitID.end();
140 for (std::pair<DetHitIdPair, WeightedRecoTrackId>& recoTrack_for_hitID : hitIDsInTrack) {
141 itInsertHint = recoTrackID_by_hitID.insert(itInsertHint, recoTrack_for_hitID);
150 setDescription(
"This module compares reconstructed tracks generated by some pattern recognition "
151 "algorithm for PXD, SVD and/or CDC to ideal Monte Carlo tracks and performs a "
152 "matching from the former to the underlying MCParticles.");
158 addParam(
"prRecoTracksStoreArrayName",
160 "Name of the collection containing the tracks as generate a patter recognition algorithm to be evaluated ",
163 addParam(
"mcRecoTracksStoreArrayName",
165 "Name of the collection containing the reference tracks as generate by a Monte-Carlo-Tracker (e.g. MCTrackFinder)",
166 std::string(
"MCGFTrackCands"));
171 "Set true if PXDHits or PXDClusters should be used in the matching in case they are present",
176 "Set true if SVDHits or SVDClusters should be used in the matching in case they are present",
181 "Set true if CDCHits should be used in the matching in case they are present",
186 "Set true if only the axial CDCHits should be used",
191 "Minimal purity of a PRTrack to be considered matchable to a MCTrack. "
192 "This number encodes how many correct hits are minimally need to compensate for a false hits. "
193 "The default 2.0 / 3.0 suggests that for each background hit can be compensated by two correct hits.",
198 "Minimal efficiency of a MCTrack to be considered matchable to a PRTrack. "
199 "This number encodes which fraction of the true hits must at least be in the reconstructed track. "
200 "The default 0.05 suggests that at least 5% of the true hits should have been picked up.",
263 B2DEBUG(100,
"Skipping MC Track Matcher as there are no MC Particles registered in the DataStore.");
267 B2DEBUG(100,
"########## MCRecoTracksMatcherModule ############");
274 int nMCRecoTracks = mcRecoTracks.
getEntries();
275 int nPRRecoTracks = prRecoTracks.
getEntries();
277 B2DEBUG(100,
"Number patter recognition tracks is " << nPRRecoTracks);
278 B2DEBUG(100,
"Number Monte-Carlo tracks is " << nMCRecoTracks);
280 if (not nMCRecoTracks or not nPRRecoTracks) {
288 std::multimap<DetHitIdPair, WeightedRecoTrackId > mcId_by_hitId;
289 fillIDsFromStoreArray(mcId_by_hitId, mcRecoTracks);
296 std::set<std::pair<DetHitIdPair, WeightedRecoTrackId>> prId_by_hitId;
297 fillIDsFromStoreArray(prId_by_hitId, prRecoTracks);
302 std::map<DetId, int> nHits_by_detId;
309 nHits_by_detId[Const::PXD] = nHits;
318 nHits_by_detId[Const::SVD] = nHits;
326 nHits_by_detId[Const::CDC] = cdcHits.
getEntries();
334 Eigen::MatrixXd confusionMatrix = Eigen::MatrixXd::Zero(nPRRecoTracks, nMCRecoTracks + 1);
335 Eigen::MatrixXd weightedConfusionMatrix = Eigen::MatrixXd::Zero(nPRRecoTracks, nMCRecoTracks + 1);
339 Eigen::RowVectorXd totalNDF_by_mcId = Eigen::RowVectorXd::Zero(nMCRecoTracks + 1);
340 Eigen::RowVectorXd totalWeight_by_mcId = Eigen::RowVectorXd::Zero(nMCRecoTracks + 1);
344 Eigen::VectorXd totalNDF_by_prId = Eigen::VectorXd::Zero(nPRRecoTracks);
347 const int mcBkgId = nMCRecoTracks;
351 for (
const std::pair<const DetId, NDF>& detId_nHits_pair : nHits_by_detId) {
353 DetId detId = detId_nHits_pair.first;
354 int nHits = detId_nHits_pair.second;
357 for (HitId hitId = 0; hitId < nHits; ++hitId) {
358 DetHitIdPair detId_hitId_pair(detId, hitId);
362 const CDCHit* cdcHit = cdcHits[hitId];
370 const auto mcIds_for_detId_hitId_pair =
371 as_range(mcId_by_hitId.equal_range(detId_hitId_pair));
374 const auto prIds_for_detId_hitId_pair =
375 as_range(std::equal_range(prId_by_hitId.begin(),
378 CompDetHitIdPair()));
382 if (mcIds_for_detId_hitId_pair.empty()) {
385 RecoTrackId mcId = mcBkgId;
387 totalNDF_by_mcId(mcId) += ndfForOneHit;
388 totalWeight_by_mcId(mcId) += ndfForOneHit * mcWeight;
390 for (
const auto& detId_hitId_pair_and_mcId : mcIds_for_detId_hitId_pair) {
391 WeightedRecoTrackId mcId = detId_hitId_pair_and_mcId.second;
392 double mcWeight = mcId.weight;
393 totalNDF_by_mcId(mcId) += ndfForOneHit;
394 totalWeight_by_mcId(mcId) += ndfForOneHit * mcWeight;
400 for (
const auto& detId_hitId_pair_and_prId : prIds_for_detId_hitId_pair) {
401 RecoTrackId prId = detId_hitId_pair_and_prId.second;
402 totalNDF_by_prId(prId) += ndfForOneHit;
406 for (
const auto& detId_hitId_pair_and_prId : prIds_for_detId_hitId_pair) {
407 RecoTrackId prId = detId_hitId_pair_and_prId.second;
408 if (mcIds_for_detId_hitId_pair.empty()) {
409 RecoTrackId mcId = mcBkgId;
411 confusionMatrix(prId, mcId) += ndfForOneHit;
412 weightedConfusionMatrix(prId, mcId) += ndfForOneHit * mcWeight;
414 for (
const auto& detId_hitId_pair_and_mcId : mcIds_for_detId_hitId_pair) {
415 WeightedRecoTrackId mcId = detId_hitId_pair_and_mcId.second;
416 double mcWeight = mcId.weight;
417 confusionMatrix(prId, mcId) += ndfForOneHit;
418 weightedConfusionMatrix(prId, mcId) += ndfForOneHit * mcWeight;
425 B2DEBUG(200,
"Confusion matrix of the event : " << std::endl << confusionMatrix);
426 B2DEBUG(200,
"Weighted confusion matrix of the event : " << std::endl << weightedConfusionMatrix);
428 B2DEBUG(200,
"totalNDF_by_mcId : " << std::endl << totalNDF_by_mcId);
429 B2DEBUG(200,
"totalWeight_by_mcId : " << std::endl << totalWeight_by_mcId);
431 B2DEBUG(200,
"totalNDF_by_prId : " << std::endl << totalNDF_by_prId);
433 Eigen::MatrixXd purityMatrix = confusionMatrix.array().colwise() / totalNDF_by_prId.array();
434 Eigen::MatrixXd efficiencyMatrix = confusionMatrix.array().rowwise() / totalNDF_by_mcId.array();
435 Eigen::MatrixXd weightedEfficiencyMatrix = weightedConfusionMatrix.array().rowwise() / totalWeight_by_mcId.array();
437 B2DEBUG(100,
"Purities");
438 B2DEBUG(100, purityMatrix);
440 B2DEBUG(100,
"Efficiencies");
441 B2DEBUG(100, efficiencyMatrix);
443 B2DEBUG(100,
"Weighted efficiencies");
444 B2DEBUG(100, weightedEfficiencyMatrix);
448 using Efficiency = float;
449 using Purity = float;
451 struct MostWeightEfficientPRId {
453 Efficiency weightedEfficiency;
455 Efficiency efficiency;
457 std::vector<MostWeightEfficientPRId> mostWeightEfficientPRId_by_mcId(nMCRecoTracks);
458 for (RecoTrackId mcId = 0; mcId < nMCRecoTracks; ++mcId) {
459 Eigen::VectorXd efficiencyCol = efficiencyMatrix.col(mcId);
460 Eigen::VectorXd weightedEfficiencyCol = weightedEfficiencyMatrix.col(mcId);
462 RecoTrackId bestPrId = 0;
463 Efficiency bestWeightedEfficiency = weightedEfficiencyCol(0);
464 Efficiency bestEfficiency = efficiencyCol(0);
465 Purity bestPurity = purityMatrix.row(0)(mcId);
469 bestWeightedEfficiency = 0;
473 for (RecoTrackId prId = 1; prId < nPRRecoTracks; ++prId) {
474 Eigen::RowVectorXd purityRow = purityMatrix.row(prId);
476 Efficiency currentWeightedEfficiency = weightedEfficiencyCol(prId);
477 Efficiency currentEfficiency = efficiencyCol(prId);
478 Purity currentPurity = purityRow(mcId);
482 currentWeightedEfficiency = 0;
485 if (std::tie(currentWeightedEfficiency, currentEfficiency, currentPurity) >
486 std::tie(bestWeightedEfficiency, bestEfficiency, bestPurity)) {
488 bestEfficiency = currentEfficiency;
489 bestWeightedEfficiency = currentWeightedEfficiency;
490 bestPurity = currentPurity;
494 bestWeightedEfficiency = weightedEfficiencyCol(bestPrId);
495 bestEfficiency = efficiencyCol(bestPrId);
496 mostWeightEfficientPRId_by_mcId[mcId] = {bestPrId, bestWeightedEfficiency, bestEfficiency};
501 struct MostPureMCId {
506 std::vector<MostPureMCId> mostPureMCId_by_prId(nPRRecoTracks);
507 for (
int prId = 0; prId < nPRRecoTracks; ++prId) {
508 Eigen::RowVectorXd purityRow = purityMatrix.row(prId);
511 Purity highestPurity = purityRow.maxCoeff(&mcId);
513 mostPureMCId_by_prId[prId] = {mcId, highestPurity};
519 RecoTrackId mcId = -1;
520 B2DEBUG(200,
"MCTrack to highest weighted efficiency PRTrack relation");
521 for (
const auto& mostWeightEfficientPRId_for_mcId : mostWeightEfficientPRId_by_mcId) {
523 const Efficiency& weightedEfficiency = mostWeightEfficientPRId_for_mcId.weightedEfficiency;
524 const RecoTrackId& prId = mostWeightEfficientPRId_for_mcId.id;
526 "mcId : " << mcId <<
" -> prId : " << prId <<
" with weighted efficiency "
527 << weightedEfficiency);
534 RecoTrackId prId = -1;
535 B2DEBUG(200,
"PRTrack to highest purity MCTrack relation");
536 for (
const auto& mostPureMCId_for_prId : mostPureMCId_by_prId) {
538 const RecoTrackId& mcId = mostPureMCId_for_prId.id;
539 const Purity& purity = mostPureMCId_for_prId.purity;
540 B2DEBUG(200,
"prId : " << prId <<
" -> mcId : " << mcId <<
" with purity " << purity);
545 int nMatched{}, nBackground{}, nClones{}, nGhost{};
551 for (RecoTrackId prId = 0; prId < nPRRecoTracks; ++prId) {
552 RecoTrack* prRecoTrack = prRecoTracks[prId];
554 const MostPureMCId& mostPureMCId = mostPureMCId_by_prId[prId];
556 const RecoTrackId& mcId = mostPureMCId.id;
557 const Purity& purity = mostPureMCId.purity;
563 B2DEBUG(100,
"Stored PRTrack " << prId <<
" as ghost because of too low purity");
568 if (mcId == mcBkgId) {
571 B2DEBUG(100,
"Stored PRTrack " << prId <<
" as background because of too low purity.");
581 RecoTrack* mcRecoTrack = mcRecoTracks[mcId];
583 B2ASSERT(
"No relation from MCRecoTrack to MCParticle.", mcParticle);
585 const MostWeightEfficientPRId& mostWeightEfficientPRId_for_mcId =
586 mostWeightEfficientPRId_by_mcId[mcId];
588 const RecoTrackId& mostWeightEfficientPRId = mostWeightEfficientPRId_for_mcId.id;
589 const Efficiency& weightedEfficiency = mostWeightEfficientPRId_for_mcId.weightedEfficiency;
596 if (prId == mostWeightEfficientPRId) {
604 B2DEBUG(100,
"Stored PRTrack " << prId <<
" as matched.");
605 B2DEBUG(100,
"MC Match prId " << prId <<
" to mcPartId " << mcParticle->
getArrayIndex());
606 B2DEBUG(100,
"Purity rel: prId " << prId <<
" -> mcId " << mcId <<
" : " << purity);
617 B2DEBUG(100,
"Stored PRTrack " << prId <<
" as ghost because of too low efficiency.");
631 B2DEBUG(100,
"Stored PRTrack " << prId <<
" as clone.");
632 B2DEBUG(100,
"MC Match prId " << prId <<
" to mcPartId " << mcParticle->
getArrayIndex());
633 B2DEBUG(100,
"Purity rel: prId " << prId <<
" -> mcId " << mcId <<
" : " << -purity);
637 B2DEBUG(100,
"Number of matches " << nMatched);
638 B2DEBUG(100,
"Number of clones " << nClones);
639 B2DEBUG(100,
"Number of bkg " << nBackground);
640 B2DEBUG(100,
"Number of ghost " << nGhost);
644 for (RecoTrackId mcId = 0; mcId < nMCRecoTracks; ++mcId) {
645 RecoTrack* mcRecoTrack = mcRecoTracks[mcId];
648 const MostWeightEfficientPRId& mostWeightEfficiencyPRId = mostWeightEfficientPRId_by_mcId[mcId];
650 const RecoTrackId& prId = mostWeightEfficiencyPRId.id;
651 const Efficiency& weightedEfficiency = mostWeightEfficiencyPRId.weightedEfficiency;
654 B2ASSERT(
"Index of pattern recognition tracks out of range.", prId < nPRRecoTracks and prId >= 0);
656 RecoTrack* prRecoTrack = prRecoTracks[prId];
658 const MostPureMCId& mostPureMCId_for_prId = mostPureMCId_by_prId[prId];
659 const RecoTrackId& mostPureMCId = mostPureMCId_for_prId.id;
662 if (mcId == mostPureMCId and
668 B2DEBUG(100,
"Efficiency rel: mcId " << mcId <<
" -> prId " << prId <<
" : " << weightedEfficiency);
676 bool isMergedMCRecoTrack =
681 if (isMergedMCRecoTrack) {
682 mcRecoTrack->
addRelationTo(prRecoTrack, -weightedEfficiency);
684 B2DEBUG(100,
"Efficiency rel: mcId " << mcId <<
" -> prId " << prId <<
" : " << -weightedEfficiency);
691 B2DEBUG(100,
"mcId " << mcId <<
" is missing. No relation created.");
692 B2DEBUG(100,
"is Primary" << mcRecoTracks[mcId]->getRelatedTo<MCParticle>()->isPrimaryParticle());
693 B2DEBUG(100,
"best prId " << prId <<
" with purity " << mostPureMCId_for_prId.purity <<
" -> " << mostPureMCId);
694 B2DEBUG(100,
"MC Total ndf " << totalNDF_by_mcId[mcId]);
695 B2DEBUG(100,
"MC Total weight" << totalWeight_by_mcId[mcId]);
696 B2DEBUG(100,
"MC Overlap ndf\n " << confusionMatrix.col(mcId).transpose());
697 B2DEBUG(100,
"MC Overlap weight\n " << weightedConfusionMatrix.col(mcId).transpose());
698 B2DEBUG(100,
"MC Efficiencies for the track\n" << efficiencyMatrix.col(mcId).transpose());
699 B2DEBUG(100,
"MC Weighted efficiencies for the track\n" << weightedEfficiencyMatrix.col(mcId).transpose());
702 B2DEBUG(100,
"########## End MCRecoTracksMatcherModule ############");
Class containing the result of the unpacker in raw data and the result of the digitizer in simulation...
unsigned short getISuperLayer() const
Getter for iSuperLayer.
EDetector
Enum for identifying the detector components (detector and subdetector).
A Class to store the Monte Carlo particle information.
int getArrayIndex() const
Get 0-based index of the particle in the corresponding MCParticle list.
double m_param_minimalPurity
Parameter : Minimal purity of a PRTrack to be considered matchable to a MCTrack.
double m_param_minimalEfficiency
Parameter : Minimal efficiency for a MCTrack to be considered matchable to a PRTrack.
void initialize() final
Signal the beginning of the event processing.
int NDF
Descriptive type defintion for a number of degrees of freedom.
bool m_mcParticlesPresent
Flag to indicated whether the Monte Carlo track are on the DataStore.
bool m_param_useSVDHits
Parameter : Switch whether SVDHits should be used in the matching.
MCRecoTracksMatcherModule()
Constructor setting up the parameter.
std::string m_param_prRecoTracksStoreArrayName
Parameter : RecoTracks store array name from the patter recognition.
void event() final
Process the event.
bool m_param_useOnlyAxialCDCHits
Parameter : Switch whether only axial CDCHits should be used.
bool m_param_usePXDHits
Parameter : Switch whether PXDHits should be used in the matching.
std::string m_param_mcRecoTracksStoreArrayName
Parameter : RecoTracks store array name from the mc recognition.
std::map< int, NDF > m_ndf_by_detId
Map storing the standard number degrees of freedom for a single hit by detector */.
bool m_param_useCDCHits
Parameter : Switch whether CDCHits should be used in the matching.
void setDescription(const std::string &description)
Sets the description of the module.
void setPropertyFlags(unsigned int propertyFlags)
Sets the flags for the module properties.
@ c_ParallelProcessingCertified
This module can be run in parallel processing mode safely (All I/O must be done through the data stor...
The PXD Cluster class This class stores all information about reconstructed PXD clusters The position...
This is the Reconstruction Event-Data Model Track.
void setMatchingStatus(MatchingStatus matchingStatus)
Set the matching status (used by the TrackMatcher module)
MatchingStatus getMatchingStatus() const
Return the matching status set by the TrackMatcher module.
void addRelationTo(const RelationsInterface< BASE > *object, float weight=1.0, const std::string &namedRelation="") const
Add a relation from this object to another object (with caching).
T * getRelated(const std::string &name="", const std::string &namedRelation="") const
Get the object to or from which this object has a relation.
The SVD Cluster class This class stores all information about reconstructed SVD clusters.
bool isRequired(const std::string &name="")
Ensure this array/object has been registered previously.
bool isOptional(const std::string &name="")
Tell the DataStore about an optional input.
const std::string & getName() const
Return name under which the object is saved in the DataStore.
Accessor to arrays stored in the data store.
int getEntries() const
Get the number of objects in the array.
bool registerRelationTo(const StoreArray< TO > &toArray, DataStore::EDurability durability=DataStore::c_Event, DataStore::EStoreFlags storeFlags=DataStore::c_WriteOut, const std::string &namedRelation="") const
Register a relation to the given StoreArray.
void addParam(const std::string &name, T ¶mVariable, const std::string &description, const T &defaultValue)
Adds a new parameter to the module.
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Abstract base class for different kinds of events.