diff --git a/DataFormats/ParticleFlowReco/interface/HGCalMultiCluster.h b/DataFormats/ParticleFlowReco/interface/HGCalMultiCluster.h index 15557770655a9..46b2818177396 100644 --- a/DataFormats/ParticleFlowReco/interface/HGCalMultiCluster.h +++ b/DataFormats/ParticleFlowReco/interface/HGCalMultiCluster.h @@ -31,5 +31,7 @@ namespace reco { private: edm::PtrVector myclusters; }; + + typedef std::vector HGCalMultiClusterCollection; } // namespace reco #endif diff --git a/SimCalorimetry/HGCalAssociatorProducers/interface/AssociatorTools.h b/SimCalorimetry/HGCalAssociatorProducers/interface/AssociatorTools.h index 5a0b2b04d0f1f..bacdee9bbb3cb 100644 --- a/SimCalorimetry/HGCalAssociatorProducers/interface/AssociatorTools.h +++ b/SimCalorimetry/HGCalAssociatorProducers/interface/AssociatorTools.h @@ -4,12 +4,14 @@ #include "SimDataFormats/CaloAnalysis/interface/CaloParticle.h" #include -void removeCPFromPU(const std::vector& caloParticles, std::vector& cPIndices) { +static void removeCPFromPU(const std::vector& caloParticles, + std::vector& cPIndices, + bool hardScatterOnly = true) { //Consider CaloParticles coming from the hard scatterer //excluding the PU contribution and save the indices. for (unsigned int cpId = 0; cpId < caloParticles.size(); ++cpId) { - if (caloParticles[cpId].g4Tracks()[0].eventId().event() != 0 or - caloParticles[cpId].g4Tracks()[0].eventId().bunchCrossing() != 0) { + if (hardScatterOnly && (caloParticles[cpId].g4Tracks()[0].eventId().event() != 0 or + caloParticles[cpId].g4Tracks()[0].eventId().bunchCrossing() != 0)) { LogDebug("HGCalValidator") << "Excluding CaloParticles from event: " << caloParticles[cpId].g4Tracks()[0].eventId().event() << " with BX: " << caloParticles[cpId].g4Tracks()[0].eventId().bunchCrossing() @@ -19,4 +21,5 @@ void removeCPFromPU(const std::vector& caloParticles, std::vector< cPIndices.emplace_back(cpId); } } + #endif diff --git a/SimCalorimetry/HGCalAssociatorProducers/plugins/LayerClusterAssociatorByEnergyScoreImpl.cc b/SimCalorimetry/HGCalAssociatorProducers/plugins/LayerClusterAssociatorByEnergyScoreImpl.cc index 2a63778286cef..39d61303997bd 100644 --- a/SimCalorimetry/HGCalAssociatorProducers/plugins/LayerClusterAssociatorByEnergyScoreImpl.cc +++ b/SimCalorimetry/HGCalAssociatorProducers/plugins/LayerClusterAssociatorByEnergyScoreImpl.cc @@ -28,7 +28,7 @@ hgcal::association LayerClusterAssociatorByEnergyScoreImpl::makeConnections( std::vector cPIndices; //Consider CaloParticles coming from the hard scatterer //excluding the PU contribution and save the indices. - removeCPFromPU(caloParticles, cPIndices); + removeCPFromPU(caloParticles, cPIndices, hardScatterOnly_); auto nCaloParticles = cPIndices.size(); // Initialize cPOnLayer. To be returned outside, since it contains the diff --git a/SimCalorimetry/HGCalAssociatorProducers/plugins/MCToCPAssociatorEDProducer.cc b/SimCalorimetry/HGCalAssociatorProducers/plugins/MCToCPAssociatorEDProducer.cc new file mode 100644 index 0000000000000..4cf5d8d3f79d8 --- /dev/null +++ b/SimCalorimetry/HGCalAssociatorProducers/plugins/MCToCPAssociatorEDProducer.cc @@ -0,0 +1,94 @@ +// +// Original Author: Leonardo Cristella +// Created: Tue Feb 2 10:52:11 CET 2021 +// +// + +// system include files +#include +#include + +// user include files +#include "FWCore/Framework/interface/global/EDProducer.h" + +#include "FWCore/Framework/interface/Event.h" +#include "FWCore/Framework/interface/MakerMacros.h" + +#include "FWCore/Framework/interface/ESHandle.h" + +#include "FWCore/ParameterSet/interface/ParameterSet.h" + +#include "SimDataFormats/Associations/interface/MultiClusterToCaloParticleAssociator.h" + +#include "FWCore/MessageLogger/interface/MessageLogger.h" +#include "SimDataFormats/CaloAnalysis/interface/CaloParticleFwd.h" +#include "DataFormats/ParticleFlowReco/interface/HGCalMultiCluster.h" + +#include "FWCore/Utilities/interface/EDGetToken.h" + +// +// class decleration +// + +class MCToCPAssociatorEDProducer : public edm::global::EDProducer<> { +public: + explicit MCToCPAssociatorEDProducer(const edm::ParameterSet &); + ~MCToCPAssociatorEDProducer() override; + +private: + void produce(edm::StreamID, edm::Event &, const edm::EventSetup &) const override; + + edm::EDGetTokenT CPCollectionToken_; + edm::EDGetTokenT MCCollectionToken_; + edm::EDGetTokenT associatorToken_; +}; + +MCToCPAssociatorEDProducer::MCToCPAssociatorEDProducer(const edm::ParameterSet &pset) { + produces(); + produces(); + + CPCollectionToken_ = consumes(pset.getParameter("label_cp")); + MCCollectionToken_ = consumes(pset.getParameter("label_mcl")); + associatorToken_ = + consumes(pset.getParameter("associator")); +} + +MCToCPAssociatorEDProducer::~MCToCPAssociatorEDProducer() {} + +// +// member functions +// + +// ------------ method called to produce the data ------------ +void MCToCPAssociatorEDProducer::produce(edm::StreamID, edm::Event &iEvent, const edm::EventSetup &iSetup) const { + using namespace edm; + + edm::Handle theAssociator; + iEvent.getByToken(associatorToken_, theAssociator); + + Handle CPCollection; + iEvent.getByToken(CPCollectionToken_, CPCollection); + + Handle MCCollection; + iEvent.getByToken(MCCollectionToken_, MCCollection); + + // associate MutiCluster and CP + LogTrace("AssociatorValidator") << "Calling associateRecoToSim method" + << "\n"; + hgcal::RecoToSimCollectionWithMultiClusters recSimColl = + theAssociator->associateRecoToSim(MCCollection, CPCollection); + + LogTrace("AssociatorValidator") << "Calling associateSimToReco method" + << "\n"; + hgcal::SimToRecoCollectionWithMultiClusters simRecColl = + theAssociator->associateSimToReco(MCCollection, CPCollection); + + auto rts = std::make_unique(recSimColl); + auto str = std::make_unique(simRecColl); + + iEvent.put(std::move(rts)); + iEvent.put(std::move(str)); +} + +// define this as a plug-in +DEFINE_FWK_MODULE(MCToCPAssociatorEDProducer); diff --git a/SimCalorimetry/HGCalAssociatorProducers/plugins/MultiClusterAssociatorByEnergyScoreImpl.cc b/SimCalorimetry/HGCalAssociatorProducers/plugins/MultiClusterAssociatorByEnergyScoreImpl.cc new file mode 100644 index 0000000000000..e1c22ec2aa925 --- /dev/null +++ b/SimCalorimetry/HGCalAssociatorProducers/plugins/MultiClusterAssociatorByEnergyScoreImpl.cc @@ -0,0 +1,529 @@ +// Original Author: Leonardo Cristella +// + +#include "MultiClusterAssociatorByEnergyScoreImpl.h" + +#include "FWCore/MessageLogger/interface/MessageLogger.h" +#include "SimDataFormats/CaloAnalysis/interface/CaloParticle.h" +#include "SimDataFormats/CaloAnalysis/interface/SimCluster.h" +#include "SimCalorimetry/HGCalAssociatorProducers/interface/AssociatorTools.h" + +MultiClusterAssociatorByEnergyScoreImpl::MultiClusterAssociatorByEnergyScoreImpl( + edm::EDProductGetter const& productGetter, + bool hardScatterOnly, + std::shared_ptr recHitTools, + const std::unordered_map*& hitMap) + : hardScatterOnly_(hardScatterOnly), recHitTools_(recHitTools), hitMap_(hitMap), productGetter_(&productGetter) { + layers_ = recHitTools_->lastLayerBH(); +} + +hgcal::association MultiClusterAssociatorByEnergyScoreImpl::makeConnections( + const edm::Handle& mCCH, const edm::Handle& cPCH) const { + // 1. Extract collections and filter CaloParticles, if required + const auto& mClusters = *mCCH.product(); + const auto& caloParticles = *cPCH.product(); + auto nMultiClusters = mClusters.size(); + //Consider CaloParticles coming from the hard scatterer, excluding the PU contribution. + std::vector cPIndices; + //Consider CaloParticles coming from the hard scatterer + //excluding the PU contribution and save the indices. + removeCPFromPU(caloParticles, cPIndices, false); + auto nCaloParticles = cPIndices.size(); + + std::vector cPSelectedIndices; + removeCPFromPU(caloParticles, cPSelectedIndices, true); + + //cPOnLayer[caloparticle][layer] + //This defines a "caloParticle on layer" concept. It is only filled in case + //that caloParticle has a reconstructed hit related via detid. So, a cPOnLayer[i][j] connects a + //specific caloParticle i in layer j with: + //1. the sum of all recHits energy times fraction of the relevant simHit in layer j related to that caloParticle i. + //2. the hits and fractions of that caloParticle i in layer j. + //3. the layer clusters with matched recHit id. + hgcal::caloParticleToMultiCluster cPOnLayer; + cPOnLayer.resize(nCaloParticles); + for (unsigned int i = 0; i < nCaloParticles; ++i) { + auto cpIndex = cPIndices[i]; + cPOnLayer[cpIndex].resize(layers_ * 2); + for (unsigned int j = 0; j < layers_ * 2; ++j) { + cPOnLayer[cpIndex][j].caloParticleId = cpIndex; + cPOnLayer[cpIndex][j].energy = 0.f; + cPOnLayer[cpIndex][j].hits_and_fractions.clear(); + } + } + + std::unordered_map> detIdToCaloParticleId_Map; + // Fill detIdToCaloParticleId_Map and update cPOnLayer + for (const auto& cpId : cPIndices) { + //take sim clusters + const SimClusterRefVector& simClusterRefVector = caloParticles[cpId].simClusters(); + //loop through sim clusters + for (const auto& it_sc : simClusterRefVector) { + const SimCluster& simCluster = (*(it_sc)); + const auto& hits_and_fractions = simCluster.hits_and_fractions(); + for (const auto& it_haf : hits_and_fractions) { + const auto hitid = (it_haf.first); + const auto cpLayerId = + recHitTools_->getLayerWithOffset(hitid) + layers_ * ((recHitTools_->zside(hitid) + 1) >> 1) - 1; + const auto itcheck = hitMap_->find(hitid); + if (itcheck != hitMap_->end()) { + //Since the current hit from sim cluster has a reconstructed hit with the same detid, + //make a map that will connect a detid with: + //1. the caloParticles that have a simcluster with sim hits in that cell via caloParticle id. + //2. the sum of all simHits fractions that contributes to that detid. + //So, keep in mind that in case of multiple caloParticles contributing in the same cell + //the fraction is the sum over all caloParticles. So, something like: + //detid: (caloParticle 1, sum of hits fractions in that detid over all cp) , (caloParticle 2, sum of hits fractions in that detid over all cp), (caloParticle 3, sum of hits fractions in that detid over all cp) ... + auto hit_find_it = detIdToCaloParticleId_Map.find(hitid); + if (hit_find_it == detIdToCaloParticleId_Map.end()) { + detIdToCaloParticleId_Map[hitid] = std::vector(); + detIdToCaloParticleId_Map[hitid].emplace_back(cpId, it_haf.second); + } else { + auto findHitIt = std::find(detIdToCaloParticleId_Map[hitid].begin(), + detIdToCaloParticleId_Map[hitid].end(), + hgcal::detIdInfoInCluster{cpId, it_haf.second}); + if (findHitIt != detIdToCaloParticleId_Map[hitid].end()) { + findHitIt->fraction += it_haf.second; + } else { + detIdToCaloParticleId_Map[hitid].emplace_back(cpId, it_haf.second); + } + } + const HGCRecHit* hit = itcheck->second; + //Since the current hit from sim cluster has a reconstructed hit with the same detid, + //fill the cPOnLayer[caloparticle][layer] object with energy (sum of all recHits energy times fraction + //of the relevant simHit) and keep the hit (detid and fraction) that contributed. + cPOnLayer[cpId][cpLayerId].energy += it_haf.second * hit->energy(); + // We need to compress the hits and fractions in order to have a + // reasonable score between CP and LC. Imagine, for example, that a + // CP has detID X used by 2 SimClusters with different fractions. If + // a single LC uses X with fraction 1 and is compared to the 2 + // contributions separately, it will be assigned a score != 0, which + // is wrong. + auto& haf = cPOnLayer[cpId][cpLayerId].hits_and_fractions; + auto found = std::find_if( + std::begin(haf), std::end(haf), [&hitid](const std::pair& v) { return v.first == hitid; }); + if (found != haf.end()) { + found->second += it_haf.second; + } else { + cPOnLayer[cpId][cpLayerId].hits_and_fractions.emplace_back(hitid, it_haf.second); + } + } + } // end of loop through simHits + } // end of loop through simclusters + } // end of loop through caloParticles + +#ifdef EDM_ML_DEBUG + LogDebug("MultiClusterAssociatorByEnergyScoreImpl") << "cPOnLayer INFO" << std::endl; + for (size_t cp = 0; cp < cPOnLayer.size(); ++cp) { + LogDebug("MultiClusterAssociatorByEnergyScoreImpl") << "For CaloParticle Idx: " << cp << " we have: " << std::endl; + for (size_t cpp = 0; cpp < cPOnLayer[cp].size(); ++cpp) { + LogDebug("MultiClusterAssociatorByEnergyScoreImpl") << " On Layer: " << cpp << " we have:" << std::endl; + LogDebug("MultiClusterAssociatorByEnergyScoreImpl") + << " CaloParticleIdx: " << cPOnLayer[cp][cpp].caloParticleId << std::endl; + LogDebug("MultiClusterAssociatorByEnergyScoreImpl") + << " Energy: " << cPOnLayer[cp][cpp].energy << std::endl; + double tot_energy = 0.; + for (auto const& haf : cPOnLayer[cp][cpp].hits_and_fractions) { + LogDebug("MultiClusterAssociatorByEnergyScoreImpl") + << " Hits/fraction/energy: " << (uint32_t)haf.first << "/" << haf.second << "/" + << haf.second * hitMap_->at(haf.first)->energy() << std::endl; + tot_energy += haf.second * hitMap_->at(haf.first)->energy(); + } + LogDebug("MultiClusterAssociatorByEnergyScoreImpl") << " Tot Sum haf: " << tot_energy << std::endl; + for (auto const& mc : cPOnLayer[cp][cpp].multiClusterIdToEnergyAndScore) { + LogDebug("MultiClusterAssociatorByEnergyScoreImpl") << " mcIdx/energy/score: " << mc.first << "/" + << mc.second.first << "/" << mc.second.second << std::endl; + } + } + } + + LogDebug("MultiClusterAssociatorByEnergyScoreImpl") << "detIdToCaloParticleId_Map INFO" << std::endl; + for (auto const& cp : detIdToCaloParticleId_Map) { + LogDebug("MultiClusterAssociatorByEnergyScoreImpl") + << "For detId: " << (uint32_t)cp.first + << " we have found the following connections with CaloParticles:" << std::endl; + for (auto const& cpp : cp.second) { + LogDebug("MultiClusterAssociatorByEnergyScoreImpl") + << " CaloParticle Id: " << cpp.clusterId << " with fraction: " << cpp.fraction + << " and energy: " << cpp.fraction * hitMap_->at(cp.first)->energy() << std::endl; + } + } +#endif + + // Fill detIdToMultiClusterId_Map and cpsInMultiCluster; update cPOnLayer + std::unordered_map> detIdToMultiClusterId_Map; + + // this contains the ids of the caloParticles contributing with at least one hit to the multiCluster and the reconstruction error + //cpsInMultiCluster[multicluster][CPids] + //Connects a multiCluster with all related caloParticles. + hgcal::multiClusterToCaloParticle cpsInMultiCluster; + cpsInMultiCluster.resize(nMultiClusters); + + //Loop through multiClusters + for (unsigned int mcId = 0; mcId < nMultiClusters; ++mcId) { + const auto& hits_and_fractions = mClusters[mcId].hitsAndFractions(); + if (!hits_and_fractions.empty()) { + std::unordered_map CPEnergyInMCL; + int maxCPId_byNumberOfHits = -1; + unsigned int maxCPNumberOfHitsInMCL = 0; + int maxCPId_byEnergy = -1; + float maxEnergySharedMCLandCP = 0.f; + float energyFractionOfMCLinCP = 0.f; + float energyFractionOfCPinMCL = 0.f; + + //In case of matched rechit-simhit, so matched + //caloparticle-layercluster-multicluster, we count and save the number of + //recHits related to the maximum energy CaloParticle out of all + //CaloParticles related to that layer cluster and multiCluster. + + std::unordered_map occurrencesCPinMCL; + unsigned int numberOfNoiseHitsInMCL = 0; + unsigned int numberOfHaloHitsInMCL = 0; + unsigned int numberOfHitsInMCL = 0; + + //number of hits related to that cluster + unsigned int numberOfHitsInLC = hits_and_fractions.size(); + numberOfHitsInMCL += numberOfHitsInLC; + std::unordered_map CPEnergyInLC; + + //hitsToCaloParticleId is a vector of ints, one for each recHit of the + //layer cluster under study. If negative, there is no simHit from any CaloParticle related. + //If positive, at least one CaloParticle has been found with matched simHit. + //In more detail: + // 1. hitsToCaloParticleId[hitId] = -3 + // TN: These represent Halo Cells(N) that have not been + // assigned to any CaloParticle (hence the T). + // 2. hitsToCaloParticleId[hitId] = -2 + // FN: There represent Halo Cells(N) that have been assigned + // to a CaloParticle (hence the F, since those should have not been marked as halo) + // 3. hitsToCaloParticleId[hitId] = -1 + // FP: These represent Real Cells(P) that have not been + // assigned to any CaloParticle (hence the F, since these are fakes) + // 4. hitsToCaloParticleId[hitId] >= 0 + // TP There represent Real Cells(P) that have been assigned + // to a CaloParticle (hence the T) + + std::vector hitsToCaloParticleId(numberOfHitsInLC); + //det id of the first hit just to make the lcLayerId variable + //which maps the layers in -z: 0->51 and in +z: 52->103 + const auto firstHitDetId = hits_and_fractions[0].first; + int lcLayerId = recHitTools_->getLayerWithOffset(firstHitDetId) + + layers_ * ((recHitTools_->zside(firstHitDetId) + 1) >> 1) - 1; + + //Loop though the hits of the layer cluster under study + for (unsigned int hitId = 0; hitId < numberOfHitsInLC; hitId++) { + const auto rh_detid = hits_and_fractions[hitId].first; + const auto rhFraction = hits_and_fractions[hitId].second; + + //Since the hit is belonging to the layer cluster, it must also be in the recHits map. + const auto itcheck = hitMap_->find(rh_detid); + const auto hit = itcheck->second; + + //Make a map that will connect a detid (that belongs to a recHit of the layer cluster under study, + //no need to save others) with: + //1. the layer clusters that have recHits in that detid + //2. the fraction of the recHit of each layer cluster that contributes to that detid. + //So, something like: + //detid: (layer cluster 1, hit fraction) , (layer cluster 2, hit fraction), (layer cluster 3, hit fraction) ... + //here comparing with the caloParticle map above + auto hit_find_in_LC = detIdToMultiClusterId_Map.find(rh_detid); + if (hit_find_in_LC == detIdToMultiClusterId_Map.end()) { + detIdToMultiClusterId_Map[rh_detid] = std::vector(); + } + detIdToMultiClusterId_Map[rh_detid].emplace_back(hgcal::detIdInfoInMultiCluster{mcId, mcId, rhFraction}); + + // Check whether the recHit of the layer cluster under study has a sim hit in the same cell + auto hit_find_in_CP = detIdToCaloParticleId_Map.find(rh_detid); + + // If the fraction is zero or the hit does not belong to any calo + // particle, set the caloParticleId for the hit to -1 and this will + // contribute to the number of noise hits + if (rhFraction == 0.) { // this could be a real hit that has been marked as halo + hitsToCaloParticleId[hitId] = -2; + numberOfHaloHitsInMCL++; + } + if (hit_find_in_CP == detIdToCaloParticleId_Map.end()) { + hitsToCaloParticleId[hitId] -= 1; + } else { + auto maxCPEnergyInLC = 0.f; + auto maxCPId = -1; + for (auto& h : hit_find_in_CP->second) { + auto shared_fraction = std::min(rhFraction, h.fraction); + //We are in the case where there are caloParticles with simHits connected via detid with the recHit under study + //So, from all layers clusters, find the recHits that are connected with a caloParticle and save/calculate the + //energy of that caloParticle as the sum over all recHits of the recHits energy weighted + //by the caloParticle's fraction related to that recHit. + CPEnergyInMCL[h.clusterId] += shared_fraction * hit->energy(); + //Same but for layer clusters for the cell association per layer + CPEnergyInLC[h.clusterId] += shared_fraction * hit->energy(); + //Here cPOnLayer[caloparticle][layer] described above is set + //Here for multiClusters with matched recHit, the CP fraction times hit energy is added and saved + cPOnLayer[h.clusterId][lcLayerId].multiClusterIdToEnergyAndScore[mcId].first += + shared_fraction * hit->energy(); + cPOnLayer[h.clusterId][lcLayerId].multiClusterIdToEnergyAndScore[mcId].second = FLT_MAX; + //cpsInMultiCluster[multicluster][CPids] + //Connects a multiCluster with all related caloParticles + cpsInMultiCluster[mcId].emplace_back(h.clusterId, FLT_MAX); + //From all CaloParticles related to a layer cluster, we save id and energy of the caloParticle + //that after simhit-rechit matching in layer has the maximum energy. + if (shared_fraction > maxCPEnergyInLC) { + //energy is used only here. cpid is saved for multiClusters + maxCPEnergyInLC = CPEnergyInLC[h.clusterId]; + maxCPId = h.clusterId; + } + } + //Keep in mind here maxCPId could be zero. So, below ask for negative not including zero to count noise. + hitsToCaloParticleId[hitId] = maxCPId; + } + + } //end of loop through recHits of the layer cluster. + + //Loop through all recHits to count how many of them are noise and how many are matched. + //In case of matched rechit-simhit, we count and save the number of recHits related to the maximum energy CaloParticle. + for (auto c : hitsToCaloParticleId) { + if (c < 0) { + numberOfNoiseHitsInMCL++; + } else { + occurrencesCPinMCL[c]++; + } + } + + //Below from all maximum energy CaloParticles, we save the one with the largest amount + //of related recHits. + for (auto& c : occurrencesCPinMCL) { + if (c.second > maxCPNumberOfHitsInMCL) { + maxCPId_byNumberOfHits = c.first; + maxCPNumberOfHitsInMCL = c.second; + } + } + + //Find the CaloParticle that has the maximum energy shared with the multiCluster under study. + for (auto& c : CPEnergyInMCL) { + if (c.second > maxEnergySharedMCLandCP) { + maxCPId_byEnergy = c.first; + maxEnergySharedMCLandCP = c.second; + } + } + //The energy of the CaloParticle that found to have the maximum energy shared with the multiCluster under study. + float totalCPEnergyFromLayerCP = 0.f; + if (maxCPId_byEnergy >= 0) { + //Loop through all layers + for (unsigned int j = 0; j < layers_ * 2; ++j) { + totalCPEnergyFromLayerCP = totalCPEnergyFromLayerCP + cPOnLayer[maxCPId_byEnergy][j].energy; + } + energyFractionOfCPinMCL = maxEnergySharedMCLandCP / totalCPEnergyFromLayerCP; + if (mClusters[mcId].energy() > 0.f) { + energyFractionOfMCLinCP = maxEnergySharedMCLandCP / mClusters[mcId].energy(); + } + } + + LogDebug("MultiClusterAssociatorByEnergyScoreImpl") << std::setw(12) << "multiCluster" + << "\t" << std::setw(10) << "mulcl energy" + << "\t" << std::setw(5) << "nhits" + << "\t" << std::setw(12) << "noise hits" + << "\t" << std::setw(22) << "maxCPId_byNumberOfHits" + << "\t" << std::setw(8) << "nhitsCP" + << "\t" << std::setw(16) << "maxCPId_byEnergy" + << "\t" << std::setw(23) << "maxEnergySharedMCLandCP" + << "\t" << std::setw(22) << "totalCPEnergyFromAllLayerCP" + << "\t" << std::setw(22) << "energyFractionOfMCLinCP" + << "\t" << std::setw(25) << "energyFractionOfCPinMCL" + << "\t" << std::endl; + LogDebug("MultiClusterAssociatorByEnergyScoreImpl") + << std::setw(12) << mcId << "\t" << std::setw(10) << mClusters[mcId].energy() << "\t" << std::setw(5) + << numberOfHitsInMCL << "\t" << std::setw(12) << numberOfNoiseHitsInMCL << "\t" << std::setw(22) + << maxCPId_byNumberOfHits << "\t" << std::setw(8) << maxCPNumberOfHitsInMCL << "\t" << std::setw(16) + << maxCPId_byEnergy << "\t" << std::setw(23) << maxEnergySharedMCLandCP << "\t" << std::setw(22) + << totalCPEnergyFromLayerCP << "\t" << std::setw(22) << energyFractionOfMCLinCP << "\t" << std::setw(25) + << energyFractionOfCPinMCL << std::endl; + } + } // end of loop through multiClusters + + // Update cpsInMultiCluster; compute the score MultiCluster-to-CaloParticle, + // together with the returned AssociationMap + for (unsigned int mcId = 0; mcId < nMultiClusters; ++mcId) { + // find the unique caloParticles id contributing to the multilusters + std::sort(cpsInMultiCluster[mcId].begin(), cpsInMultiCluster[mcId].end()); + auto last = std::unique(cpsInMultiCluster[mcId].begin(), cpsInMultiCluster[mcId].end()); + cpsInMultiCluster[mcId].erase(last, cpsInMultiCluster[mcId].end()); + + const auto& hits_and_fractions = mClusters[mcId].hitsAndFractions(); + unsigned int numberOfHitsInLC = hits_and_fractions.size(); + if (numberOfHitsInLC > 0) { + if (mClusters[mcId].energy() == 0. && !cpsInMultiCluster[mcId].empty()) { + //Loop through all CaloParticles contributing to multiCluster mcId. + for (auto& cpPair : cpsInMultiCluster[mcId]) { + //In case of a multiCluster with zero energy but related CaloParticles the score is set to 1. + cpPair.second = 1.; + LogDebug("MultiClusterAssociatorByEnergyScoreImpl") + << "multiClusterId : \t " << mcId << "\t CP id : \t" << cpPair.first << "\t score \t " << cpPair.second + << "\n"; + } + continue; + } + + // Compute the correct normalization + float invMultiClusterEnergyWeight = 0.f; + for (auto const& haf : mClusters[mcId].hitsAndFractions()) { + invMultiClusterEnergyWeight += + (haf.second * hitMap_->at(haf.first)->energy()) * (haf.second * hitMap_->at(haf.first)->energy()); + } + invMultiClusterEnergyWeight = 1.f / invMultiClusterEnergyWeight; + + for (unsigned int i = 0; i < numberOfHitsInLC; ++i) { + DetId rh_detid = hits_and_fractions[i].first; + float rhFraction = hits_and_fractions[i].second; + + bool hitWithNoCP = (detIdToCaloParticleId_Map.find(rh_detid) == detIdToCaloParticleId_Map.end()); + + auto itcheck = hitMap_->find(rh_detid); + const HGCRecHit* hit = itcheck->second; + float hitEnergyWeight = hit->energy() * hit->energy(); + + for (auto& cpPair : cpsInMultiCluster[mcId]) { + unsigned int multiClusterId = cpPair.first; + float cpFraction = 0.f; + if (!hitWithNoCP) { + auto findHitIt = std::find(detIdToCaloParticleId_Map[rh_detid].begin(), + detIdToCaloParticleId_Map[rh_detid].end(), + hgcal::detIdInfoInCluster{multiClusterId, 0.f}); + if (findHitIt != detIdToCaloParticleId_Map[rh_detid].end()) + cpFraction = findHitIt->fraction; + } + if (cpPair.second == FLT_MAX) { + cpPair.second = 0.f; + } + cpPair.second += + (rhFraction - cpFraction) * (rhFraction - cpFraction) * hitEnergyWeight * invMultiClusterEnergyWeight; + } + } // End of loop over Hits within a MultiCluster +#ifdef EDM_ML_DEBUG + //In case of a multiCluster with some energy but none related CaloParticles print some info. + if (cpsInMultiCluster[mcId].empty()) + LogDebug("MultiClusterAssociatorByEnergyScoreImpl") << "multiCluster Id: \t" << mcId << "\tCP id:\t-1 " + << "\t score \t-1" + << "\n"; +#endif + } + } // End of loop over MultiClusters + + // Compute the CaloParticle-To-MultiCluster score + for (const auto& cpId : cPSelectedIndices) { + for (unsigned int layerId = 0; layerId < layers_ * 2; ++layerId) { + unsigned int CPNumberOfHits = cPOnLayer[cpId][layerId].hits_and_fractions.size(); + if (CPNumberOfHits == 0) + continue; +#ifdef EDM_ML_DEBUG + int mcWithMaxEnergyInCP = -1; + float maxEnergyMCLperlayerinCP = 0.f; + float CPenergy = cPOnLayer[cpId][layerId].energy; + float CPEnergyFractionInMCLperlayer = 0.f; + for (auto& mc : cPOnLayer[cpId][layerId].multiClusterIdToEnergyAndScore) { + if (mc.second.first > maxEnergyMCLperlayerinCP) { + maxEnergyMCLperlayerinCP = mc.second.first; + mcWithMaxEnergyInCP = mc.first; + } + } + if (CPenergy > 0.f) + CPEnergyFractionInMCLperlayer = maxEnergyMCLperlayerinCP / CPenergy; + + LogDebug("MultiClusterAssociatorByEnergyScoreImpl") + << std::setw(8) << "LayerId:\t" << std::setw(12) << "caloparticle\t" << std::setw(15) << "cp total energy\t" + << std::setw(15) << "cpEnergyOnLayer\t" << std::setw(14) << "CPNhitsOnLayer\t" << std::setw(18) + << "mcWithMaxEnergyInCP\t" << std::setw(15) << "maxEnergyMCLinCP\t" << std::setw(20) + << "CPEnergyFractionInMCL" + << "\n"; + LogDebug("MultiClusterAssociatorByEnergyScoreImpl") + << std::setw(8) << layerId << "\t" << std::setw(12) << cpId << "\t" << std::setw(15) + << caloParticles[cpId].energy() << "\t" << std::setw(15) << CPenergy << "\t" << std::setw(14) + << CPNumberOfHits << "\t" << std::setw(18) << mcWithMaxEnergyInCP << "\t" << std::setw(15) + << maxEnergyMCLperlayerinCP << "\t" << std::setw(20) << CPEnergyFractionInMCLperlayer << "\n"; +#endif + + for (unsigned int i = 0; i < CPNumberOfHits; ++i) { + auto& cp_hitDetId = cPOnLayer[cpId][layerId].hits_and_fractions[i].first; + auto& cpFraction = cPOnLayer[cpId][layerId].hits_and_fractions[i].second; + + bool hitWithNoMCL = false; + if (cpFraction == 0.f) + continue; //hopefully this should never happen + auto hit_find_in_MCL = detIdToMultiClusterId_Map.find(cp_hitDetId); + if (hit_find_in_MCL == detIdToMultiClusterId_Map.end()) + hitWithNoMCL = true; + auto itcheck = hitMap_->find(cp_hitDetId); + const HGCRecHit* hit = itcheck->second; + float hitEnergyWeight = hit->energy() * hit->energy(); + for (auto& mcPair : cPOnLayer[cpId][layerId].multiClusterIdToEnergyAndScore) { + unsigned int multiClusterId = mcPair.first; + float mcFraction = 0.f; + + if (!hitWithNoMCL) { + auto findHitIt = std::find(detIdToMultiClusterId_Map[cp_hitDetId].begin(), + detIdToMultiClusterId_Map[cp_hitDetId].end(), + hgcal::detIdInfoInMultiCluster{multiClusterId, 0, 0.f}); + if (findHitIt != detIdToMultiClusterId_Map[cp_hitDetId].end()) + mcFraction = findHitIt->fraction; + } + //Observe here that we do not divide as before by the layer cluster energy weight. We should sum first + //over all layers and divide with the total CP energy over all layers. + if (mcPair.second.second == FLT_MAX) { + mcPair.second.second = 0.f; + } + mcPair.second.second += (mcFraction - cpFraction) * (mcFraction - cpFraction) * hitEnergyWeight; +#ifdef EDM_ML_DEBUG + LogDebug("HGCalValidator") << "multiClusterId:\t" << multiClusterId << "\tmcfraction,cpfraction:\t" + << mcFraction << ", " << cpFraction << "\thitEnergyWeight:\t" << hitEnergyWeight + << "\tcurrent score numerator:\t" << mcPair.second.second << "\n"; +#endif + } // End of loop over MultiClusters linked to hits of this CaloParticle + } // End of loop over hits of CaloParticle on a Layer +#ifdef EDM_ML_DEBUG + if (cPOnLayer[cpId][layerId].multiClusterIdToEnergyAndScore.empty()) + LogDebug("HGCalValidator") << "CP Id: \t" << cpId << "\t MCL id:\t-1 " + << "\t layer \t " << layerId << " Sub score in \t -1" + << "\n"; + +#endif + } + } + return {cpsInMultiCluster, cPOnLayer}; +} + +hgcal::RecoToSimCollectionWithMultiClusters MultiClusterAssociatorByEnergyScoreImpl::associateRecoToSim( + const edm::Handle& mCCH, const edm::Handle& cPCH) const { + hgcal::RecoToSimCollectionWithMultiClusters returnValue(productGetter_); + const auto& links = makeConnections(mCCH, cPCH); + + const auto& cpsInMultiCluster = std::get<0>(links); + for (size_t mcId = 0; mcId < cpsInMultiCluster.size(); ++mcId) { + for (auto& cpPair : cpsInMultiCluster[mcId]) { + LogDebug("MultiClusterAssociatorByEnergyScoreImpl") + << "multiCluster Id: \t" << mcId << "\t CP id: \t" << cpPair.first << "\t score \t" << cpPair.second << "\n"; + // Fill AssociationMap + returnValue.insert(edm::Ref(mCCH, mcId), // Ref to MC + std::make_pair(edm::Ref(cPCH, cpPair.first), + cpPair.second) // Pair + ); + } + } + return returnValue; +} + +hgcal::SimToRecoCollectionWithMultiClusters MultiClusterAssociatorByEnergyScoreImpl::associateSimToReco( + const edm::Handle& mCCH, const edm::Handle& cPCH) const { + hgcal::SimToRecoCollectionWithMultiClusters returnValue(productGetter_); + const auto& links = makeConnections(mCCH, cPCH); + const auto& cPOnLayer = std::get<1>(links); + for (size_t cpId = 0; cpId < cPOnLayer.size(); ++cpId) { + for (size_t layerId = 0; layerId < cPOnLayer[cpId].size(); ++layerId) { + for (auto& mcPair : cPOnLayer[cpId][layerId].multiClusterIdToEnergyAndScore) { + returnValue.insert( + edm::Ref(cPCH, cpId), // Ref to CP + std::make_pair(edm::Ref(mCCH, mcPair.first), // Pair > + ); + } + } + } + return returnValue; +} diff --git a/SimCalorimetry/HGCalAssociatorProducers/plugins/MultiClusterAssociatorByEnergyScoreImpl.h b/SimCalorimetry/HGCalAssociatorProducers/plugins/MultiClusterAssociatorByEnergyScoreImpl.h new file mode 100644 index 0000000000000..c30f7190f0b0e --- /dev/null +++ b/SimCalorimetry/HGCalAssociatorProducers/plugins/MultiClusterAssociatorByEnergyScoreImpl.h @@ -0,0 +1,70 @@ +// Original Author: Leonardo Cristella + +#include +#include +#include +#include // shared_ptr + +#include "DataFormats/ForwardDetId/interface/HGCalDetId.h" +#include "DataFormats/HGCRecHit/interface/HGCRecHit.h" +#include "SimDataFormats/Associations/interface/MultiClusterToCaloParticleAssociator.h" +#include "RecoLocalCalo/HGCalRecAlgos/interface/RecHitTools.h" + +namespace edm { + class EDProductGetter; +} + +namespace hgcal { + struct detIdInfoInCluster { + bool operator==(const detIdInfoInCluster &o) const { return clusterId == o.clusterId; }; + long unsigned int clusterId; + float fraction; + detIdInfoInCluster(long unsigned int cId, float fr) { + clusterId = cId; + fraction = fr; + } + }; + + struct detIdInfoInMultiCluster { + bool operator==(const detIdInfoInMultiCluster &o) const { return multiclusterId == o.multiclusterId; }; + unsigned int multiclusterId; + long unsigned int clusterId; + float fraction; + }; + + struct caloParticleOnLayer { + unsigned int caloParticleId; + float energy = 0; + std::vector> hits_and_fractions; + std::unordered_map> multiClusterIdToEnergyAndScore; + }; + + typedef std::vector>> multiClusterToCaloParticle; + typedef std::vector> caloParticleToMultiCluster; + typedef std::tuple association; +} // namespace hgcal + +class MultiClusterAssociatorByEnergyScoreImpl : public hgcal::MultiClusterToCaloParticleAssociatorBaseImpl { +public: + explicit MultiClusterAssociatorByEnergyScoreImpl(edm::EDProductGetter const &, + bool, + std::shared_ptr, + const std::unordered_map *&); + + hgcal::RecoToSimCollectionWithMultiClusters associateRecoToSim( + const edm::Handle &mCCH, + const edm::Handle &cPCH) const override; + + hgcal::SimToRecoCollectionWithMultiClusters associateSimToReco( + const edm::Handle &mCCH, + const edm::Handle &cPCH) const override; + +private: + const bool hardScatterOnly_; + std::shared_ptr recHitTools_; + const std::unordered_map *hitMap_; + unsigned layers_; + edm::EDProductGetter const *productGetter_; + hgcal::association makeConnections(const edm::Handle &mCCH, + const edm::Handle &cPCH) const; +}; diff --git a/SimCalorimetry/HGCalAssociatorProducers/plugins/MultiClusterAssociatorByEnergyScoreProducer.cc b/SimCalorimetry/HGCalAssociatorProducers/plugins/MultiClusterAssociatorByEnergyScoreProducer.cc new file mode 100644 index 0000000000000..b0ffb0ce9f8b6 --- /dev/null +++ b/SimCalorimetry/HGCalAssociatorProducers/plugins/MultiClusterAssociatorByEnergyScoreProducer.cc @@ -0,0 +1,67 @@ +// Original author: Leonardo Cristella + +// user include files +#include "FWCore/Framework/interface/Frameworkfwd.h" +#include "FWCore/Framework/interface/global/EDProducer.h" + +#include "FWCore/Framework/interface/Event.h" +#include "FWCore/Framework/interface/MakerMacros.h" + +#include "FWCore/ParameterSet/interface/ParameterSet.h" +#include "FWCore/Utilities/interface/EDGetToken.h" +#include "FWCore/Utilities/interface/ESGetToken.h" + +#include "SimDataFormats/Associations/interface/MultiClusterToCaloParticleAssociator.h" +#include "MultiClusterAssociatorByEnergyScoreImpl.h" + +class MultiClusterAssociatorByEnergyScoreProducer : public edm::global::EDProducer<> { +public: + explicit MultiClusterAssociatorByEnergyScoreProducer(const edm::ParameterSet &); + ~MultiClusterAssociatorByEnergyScoreProducer() override; + + static void fillDescriptions(edm::ConfigurationDescriptions &descriptions); + +private: + void produce(edm::StreamID, edm::Event &, const edm::EventSetup &) const override; + edm::EDGetTokenT> hitMap_; + edm::ESGetToken caloGeometry_; + const bool hardScatterOnly_; + std::shared_ptr rhtools_; +}; + +MultiClusterAssociatorByEnergyScoreProducer::MultiClusterAssociatorByEnergyScoreProducer(const edm::ParameterSet &ps) + : hitMap_(consumes>(ps.getParameter("hitMapTag"))), + caloGeometry_(esConsumes()), + hardScatterOnly_(ps.getParameter("hardScatterOnly")) { + rhtools_.reset(new hgcal::RecHitTools()); + + // Register the product + produces(); +} + +MultiClusterAssociatorByEnergyScoreProducer::~MultiClusterAssociatorByEnergyScoreProducer() {} + +void MultiClusterAssociatorByEnergyScoreProducer::produce(edm::StreamID, + edm::Event &iEvent, + const edm::EventSetup &es) const { + edm::ESHandle geom = es.getHandle(caloGeometry_); + rhtools_->setGeometry(*geom); + + const std::unordered_map *hitMap = &iEvent.get(hitMap_); + + auto impl = std::make_unique( + iEvent.productGetter(), hardScatterOnly_, rhtools_, hitMap); + auto toPut = std::make_unique(std::move(impl)); + iEvent.put(std::move(toPut)); +} + +void MultiClusterAssociatorByEnergyScoreProducer::fillDescriptions(edm::ConfigurationDescriptions &cfg) { + edm::ParameterSetDescription desc; + desc.add("hitMapTag", edm::InputTag("hgcalRecHitMapProducer")); + desc.add("hardScatterOnly", true); + + cfg.add("multiClusterAssociatorByEnergyScore", desc); +} + +//define this as a plug-in +DEFINE_FWK_MODULE(MultiClusterAssociatorByEnergyScoreProducer); diff --git a/SimCalorimetry/HGCalAssociatorProducers/python/MCToCPAssociation_cfi.py b/SimCalorimetry/HGCalAssociatorProducers/python/MCToCPAssociation_cfi.py new file mode 100644 index 0000000000000..7e82345bfa585 --- /dev/null +++ b/SimCalorimetry/HGCalAssociatorProducers/python/MCToCPAssociation_cfi.py @@ -0,0 +1,12 @@ +import FWCore.ParameterSet.Config as cms + +multiClusterCaloParticleAssociation = cms.EDProducer("MCToCPAssociatorEDProducer", + associator = cms.InputTag('mcAssocByEnergyScoreProducer'), + label_cp = cms.InputTag("mix","MergedCaloTruth"), + label_mcl = cms.InputTag("ticlMultiClustersFromTrackstersMerge") +) + +from Configuration.ProcessModifiers.premix_stage2_cff import premix_stage2 +premix_stage2.toModify(multiClusterCaloParticleAssociation, + label_cp = "mixData:MergedCaloTruth" +) diff --git a/SimDataFormats/Associations/interface/MultiClusterToCaloParticleAssociator.h b/SimDataFormats/Associations/interface/MultiClusterToCaloParticleAssociator.h new file mode 100644 index 0000000000000..6e9979ace3814 --- /dev/null +++ b/SimDataFormats/Associations/interface/MultiClusterToCaloParticleAssociator.h @@ -0,0 +1,50 @@ +#ifndef SimDataFormats_Associations_MultiClusterToCaloParticleAssociator_h +#define SimDataFormats_Associations_MultiClusterToCaloParticleAssociator_h +// Original Author: Leonardo Cristella + +// system include files +#include + +// user include files + +#include "SimDataFormats/Associations/interface/MultiClusterToCaloParticleAssociatorBaseImpl.h" + +// forward declarations + +namespace hgcal { + + class MultiClusterToCaloParticleAssociator { + public: + MultiClusterToCaloParticleAssociator(std::unique_ptr); + MultiClusterToCaloParticleAssociator() = default; + MultiClusterToCaloParticleAssociator(MultiClusterToCaloParticleAssociator &&) = default; + MultiClusterToCaloParticleAssociator &operator=(MultiClusterToCaloParticleAssociator &&) = default; + ~MultiClusterToCaloParticleAssociator() = default; + + // ---------- const member functions --------------------- + /// Associate a MultiCluster to CaloParticles + hgcal::RecoToSimCollectionWithMultiClusters associateRecoToSim( + const edm::Handle &cCCH, + const edm::Handle &cPCH) const { + return m_impl->associateRecoToSim(cCCH, cPCH); + }; + + /// Associate a CaloParticle to MultiClusters + hgcal::SimToRecoCollectionWithMultiClusters associateSimToReco( + const edm::Handle &cCCH, + const edm::Handle &cPCH) const { + return m_impl->associateSimToReco(cCCH, cPCH); + } + + private: + MultiClusterToCaloParticleAssociator(const MultiClusterToCaloParticleAssociator &) = delete; // stop default + + const MultiClusterToCaloParticleAssociator &operator=(const MultiClusterToCaloParticleAssociator &) = + delete; // stop default + + // ---------- member data -------------------------------- + std::unique_ptr m_impl; + }; +} // namespace hgcal + +#endif diff --git a/SimDataFormats/Associations/interface/MultiClusterToCaloParticleAssociatorBaseImpl.h b/SimDataFormats/Associations/interface/MultiClusterToCaloParticleAssociatorBaseImpl.h new file mode 100644 index 0000000000000..6d21a51cea9f3 --- /dev/null +++ b/SimDataFormats/Associations/interface/MultiClusterToCaloParticleAssociatorBaseImpl.h @@ -0,0 +1,47 @@ +#ifndef SimDataFormats_Associations_MultiClusterToCaloParticleAssociatorBaseImpl_h +#define SimDataFormats_Associations_MultiClusterToCaloParticleAssociatorBaseImpl_h + +/** \class MultiClusterToCaloParticleAssociatorBaseImpl + * + * Base class for MultiClusterToCaloParticleAssociators. Methods take as input + * the handle of MultiClusters and the CaloParticle collections and return an + * AssociationMap (oneToManyWithQuality) + * + * \author Leonardo Cristella + */ + +#include "DataFormats/Common/interface/Handle.h" +#include "DataFormats/Common/interface/AssociationMap.h" +#include "DataFormats/ParticleFlowReco/interface/HGCalMultiCluster.h" + +#include "SimDataFormats/CaloAnalysis/interface/CaloParticleFwd.h" + +namespace hgcal { + + typedef edm::AssociationMap< + edm::OneToManyWithQualityGeneric>> + SimToRecoCollectionWithMultiClusters; + typedef edm::AssociationMap< + edm::OneToManyWithQualityGeneric> + RecoToSimCollectionWithMultiClusters; + + class MultiClusterToCaloParticleAssociatorBaseImpl { + public: + /// Constructor + MultiClusterToCaloParticleAssociatorBaseImpl(); + /// Destructor + virtual ~MultiClusterToCaloParticleAssociatorBaseImpl(); + + /// Associate a MultiCluster to CaloParticles + virtual hgcal::RecoToSimCollectionWithMultiClusters associateRecoToSim( + const edm::Handle &cCH, + const edm::Handle &cPCH) const; + + /// Associate a CaloParticle to MultiClusters + virtual hgcal::SimToRecoCollectionWithMultiClusters associateSimToReco( + const edm::Handle &cCH, + const edm::Handle &cPCH) const; + }; +} // namespace hgcal + +#endif diff --git a/SimDataFormats/Associations/src/MultiClusterToCaloParticleAssociator.cc b/SimDataFormats/Associations/src/MultiClusterToCaloParticleAssociator.cc new file mode 100644 index 0000000000000..5b13f8ef8a4ae --- /dev/null +++ b/SimDataFormats/Associations/src/MultiClusterToCaloParticleAssociator.cc @@ -0,0 +1,7 @@ +// Original Author: Leonardo Cristella + +#include "SimDataFormats/Associations/interface/MultiClusterToCaloParticleAssociator.h" + +hgcal::MultiClusterToCaloParticleAssociator::MultiClusterToCaloParticleAssociator( + std::unique_ptr ptr) + : m_impl(std::move(ptr)) {} diff --git a/SimDataFormats/Associations/src/MultiClusterToCaloParticleAssociatorBaseImpl.cc b/SimDataFormats/Associations/src/MultiClusterToCaloParticleAssociatorBaseImpl.cc new file mode 100644 index 0000000000000..3b9768beae315 --- /dev/null +++ b/SimDataFormats/Associations/src/MultiClusterToCaloParticleAssociatorBaseImpl.cc @@ -0,0 +1,21 @@ +// Original Author: Leonardo Cristella + +#include "SimDataFormats/Associations/interface/MultiClusterToCaloParticleAssociatorBaseImpl.h" + +namespace hgcal { + MultiClusterToCaloParticleAssociatorBaseImpl::MultiClusterToCaloParticleAssociatorBaseImpl(){}; + MultiClusterToCaloParticleAssociatorBaseImpl::~MultiClusterToCaloParticleAssociatorBaseImpl(){}; + + hgcal::RecoToSimCollectionWithMultiClusters MultiClusterToCaloParticleAssociatorBaseImpl::associateRecoToSim( + const edm::Handle &cCCH, + const edm::Handle &cPCH) const { + return hgcal::RecoToSimCollectionWithMultiClusters(); + } + + hgcal::SimToRecoCollectionWithMultiClusters MultiClusterToCaloParticleAssociatorBaseImpl::associateSimToReco( + const edm::Handle &cCCH, + const edm::Handle &cPCH) const { + return hgcal::SimToRecoCollectionWithMultiClusters(); + } + +} // namespace hgcal diff --git a/SimDataFormats/Associations/src/classes.h b/SimDataFormats/Associations/src/classes.h index 44f3be3a5a8f5..d327d03291380 100644 --- a/SimDataFormats/Associations/src/classes.h +++ b/SimDataFormats/Associations/src/classes.h @@ -9,6 +9,7 @@ #include "SimDataFormats/Associations/interface/LayerClusterToCaloParticleAssociator.h" #include "SimDataFormats/Associations/interface/LayerClusterToSimClusterAssociator.h" #include "SimDataFormats/Associations/interface/TracksterToSimClusterAssociator.h" +#include "SimDataFormats/Associations/interface/MultiClusterToCaloParticleAssociator.h" #include "SimDataFormats/Associations/interface/TTTrackTruthPair.h" namespace SimDataFormats_Associations { @@ -26,6 +27,8 @@ namespace SimDataFormats_Associations { edm::Wrapper dummy7; + edm::Wrapper dummy8; + reco::VertexSimToRecoCollection vstrc; reco::VertexSimToRecoCollection::const_iterator vstrci; edm::Wrapper wvstrc; diff --git a/SimDataFormats/Associations/src/classes_def.xml b/SimDataFormats/Associations/src/classes_def.xml index 8eec7db0ff36a..0e1edcd95fc26 100644 --- a/SimDataFormats/Associations/src/classes_def.xml +++ b/SimDataFormats/Associations/src/classes_def.xml @@ -18,6 +18,9 @@ + + + @@ -27,6 +30,7 @@ + @@ -41,6 +45,7 @@ + @@ -66,8 +71,21 @@ - - + + + + + + + + + + + + + + +