Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-09-07 04:37:31

0001 #include <memory>  // unique_ptr
0002 #include "FWCore/Framework/interface/stream/EDProducer.h"
0003 #include "FWCore/ParameterSet/interface/ParameterSet.h"
0004 #include "FWCore/ParameterSet/interface/ConfigurationDescriptions.h"
0005 #include "FWCore/ParameterSet/interface/PluginDescription.h"
0006 #include "FWCore/MessageLogger/interface/MessageLogger.h"
0007 #include "FWCore/Utilities/interface/ESGetToken.h"
0008 #include "FWCore/Framework/interface/ESHandle.h"
0009 #include "FWCore/Framework/interface/Frameworkfwd.h"
0010 #include "FWCore/Framework/interface/MakerMacros.h"
0011 #include "FWCore/ParameterSet/interface/ParameterSetDescription.h"
0012 #include "FWCore/Framework/interface/ConsumesCollector.h"
0013 
0014 #include "DataFormats/CaloRecHit/interface/CaloCluster.h"
0015 #include "DataFormats/HGCalReco/interface/Common.h"
0016 #include "DataFormats/HGCalReco/interface/TICLLayerTile.h"
0017 #include "DataFormats/HGCalReco/interface/Trackster.h"
0018 #include "DataFormats/TrackReco/interface/Track.h"
0019 #include "DataFormats/MuonReco/interface/Muon.h"
0020 #include "DataFormats/GeometrySurface/interface/BoundDisk.h"
0021 #include "DataFormats/HGCalReco/interface/TICLCandidate.h"
0022 #include "DataFormats/TrackReco/interface/TrackFwd.h"
0023 #include "DataFormats/Math/interface/Vector3D.h"
0024 
0025 #include "RecoHGCal/TICL/interface/GlobalCache.h"
0026 
0027 #include "PhysicsTools/TensorFlow/interface/TfGraphRecord.h"
0028 #include "PhysicsTools/TensorFlow/interface/TensorFlow.h"
0029 #include "PhysicsTools/TensorFlow/interface/TfGraphDefWrapper.h"
0030 
0031 #include "RecoHGCal/TICL/plugins/LinkingAlgoBase.h"
0032 #include "RecoHGCal/TICL/plugins/LinkingAlgoFactory.h"
0033 #include "RecoHGCal/TICL/plugins/LinkingAlgoByDirectionGeometric.h"
0034 
0035 #include "RecoLocalCalo/HGCalRecAlgos/interface/RecHitTools.h"
0036 #include "PhysicsTools/TensorFlow/interface/TensorFlow.h"
0037 
0038 #include "TrackingTools/TrajectoryState/interface/TrajectoryStateTransform.h"
0039 #include "TrackingTools/GeomPropagators/interface/Propagator.h"
0040 #include "TrackingTools/Records/interface/TrackingComponentsRecord.h"
0041 
0042 #include "MagneticField/Engine/interface/MagneticField.h"
0043 #include "MagneticField/Records/interface/IdealMagneticFieldRecord.h"
0044 
0045 #include "Geometry/HGCalCommonData/interface/HGCalDDDConstants.h"
0046 #include "Geometry/Records/interface/IdealGeometryRecord.h"
0047 #include "Geometry/CommonDetUnit/interface/GeomDet.h"
0048 
0049 #include "TrackstersPCA.h"
0050 
0051 using namespace ticl;
0052 
0053 class TrackstersMergeProducer : public edm::stream::EDProducer<> {
0054 public:
0055   explicit TrackstersMergeProducer(const edm::ParameterSet &ps);
0056   ~TrackstersMergeProducer() override {}
0057   void produce(edm::Event &, const edm::EventSetup &) override;
0058   static void fillDescriptions(edm::ConfigurationDescriptions &descriptions);
0059 
0060   // static methods for handling the global cache
0061   static std::unique_ptr<TrackstersCache> initializeGlobalCache(const edm::ParameterSet &);
0062   static void globalEndJob(TrackstersCache *);
0063 
0064   void beginJob();
0065   void endJob();
0066 
0067   void beginRun(edm::Run const &iEvent, edm::EventSetup const &es) override;
0068 
0069 private:
0070   typedef ticl::Trackster::IterationIndex TracksterIterIndex;
0071   typedef ticl::Vector Vector;
0072 
0073   void fillTile(TICLTracksterTiles &, const std::vector<Trackster> &, TracksterIterIndex);
0074 
0075   void energyRegressionAndID(const std::vector<reco::CaloCluster> &layerClusters,
0076                              const tensorflow::Session *,
0077                              std::vector<Trackster> &result) const;
0078   void printTrackstersDebug(const std::vector<Trackster> &, const char *label) const;
0079   void assignTimeToCandidates(std::vector<TICLCandidate> &resultCandidates) const;
0080   void dumpTrackster(const Trackster &) const;
0081 
0082   std::unique_ptr<LinkingAlgoBase> linkingAlgo_;
0083 
0084   const edm::EDGetTokenT<std::vector<Trackster>> tracksters_clue3d_token_;
0085   const edm::EDGetTokenT<std::vector<reco::CaloCluster>> clusters_token_;
0086   const edm::EDGetTokenT<edm::ValueMap<std::pair<float, float>>> clustersTime_token_;
0087   const edm::EDGetTokenT<std::vector<reco::Track>> tracks_token_;
0088   edm::EDGetTokenT<edm::ValueMap<float>> tracks_time_token_;
0089   edm::EDGetTokenT<edm::ValueMap<float>> tracks_time_quality_token_;
0090   edm::EDGetTokenT<edm::ValueMap<float>> tracks_time_err_token_;
0091   const edm::EDGetTokenT<std::vector<reco::Muon>> muons_token_;
0092   const std::string tfDnnLabel_;
0093   const edm::ESGetToken<TfGraphDefWrapper, TfGraphRecord> tfDnnToken_;
0094   const tensorflow::Session *tfSession_;
0095 
0096   const edm::ESGetToken<CaloGeometry, CaloGeometryRecord> geometry_token_;
0097   const std::string detector_;
0098   const std::string propName_;
0099 
0100   const edm::ESGetToken<MagneticField, IdealMagneticFieldRecord> bfield_token_;
0101   const edm::ESGetToken<Propagator, TrackingComponentsRecord> propagator_token_;
0102   const bool optimiseAcrossTracksters_;
0103   const bool useMTDTiming_;
0104   const int eta_bin_window_;
0105   const int phi_bin_window_;
0106   const double pt_sigma_high_;
0107   const double pt_sigma_low_;
0108   const double halo_max_distance2_;
0109   const double track_min_pt_;
0110   const double track_min_eta_;
0111   const double track_max_eta_;
0112   const int track_max_missing_outerhits_;
0113   const double cosangle_align_;
0114   const double e_over_h_threshold_;
0115   const double pt_neutral_threshold_;
0116   const double resol_calo_offset_had_;
0117   const double resol_calo_scale_had_;
0118   const double resol_calo_offset_em_;
0119   const double resol_calo_scale_em_;
0120   const std::string eidInputName_;
0121   const std::string eidOutputNameEnergy_;
0122   const std::string eidOutputNameId_;
0123   const float eidMinClusterEnergy_;
0124   const int eidNLayers_;
0125   const int eidNClusters_;
0126   std::once_flag initializeGeometry_;
0127 
0128   const HGCalDDDConstants *hgcons_;
0129 
0130   std::unique_ptr<GeomDet> firstDisk_[2];
0131 
0132   tensorflow::Session *eidSession_;
0133   hgcal::RecHitTools rhtools_;
0134 
0135   static constexpr int eidNFeatures_ = 3;
0136 
0137   edm::ESGetToken<HGCalDDDConstants, IdealGeometryRecord> hdc_token_;
0138 };
0139 
0140 TrackstersMergeProducer::TrackstersMergeProducer(const edm::ParameterSet &ps)
0141     : tracksters_clue3d_token_(consumes<std::vector<Trackster>>(ps.getParameter<edm::InputTag>("trackstersclue3d"))),
0142       clusters_token_(consumes<std::vector<reco::CaloCluster>>(ps.getParameter<edm::InputTag>("layer_clusters"))),
0143       clustersTime_token_(
0144           consumes<edm::ValueMap<std::pair<float, float>>>(ps.getParameter<edm::InputTag>("layer_clustersTime"))),
0145       tracks_token_(consumes<std::vector<reco::Track>>(ps.getParameter<edm::InputTag>("tracks"))),
0146       muons_token_(consumes<std::vector<reco::Muon>>(ps.getParameter<edm::InputTag>("muons"))),
0147       tfDnnLabel_(ps.getParameter<std::string>("tfDnnLabel")),
0148       tfDnnToken_(esConsumes(edm::ESInputTag("", tfDnnLabel_))),
0149       tfSession_(nullptr),
0150       geometry_token_(esConsumes<CaloGeometry, CaloGeometryRecord, edm::Transition::BeginRun>()),
0151       detector_(ps.getParameter<std::string>("detector")),
0152       propName_(ps.getParameter<std::string>("propagator")),
0153       bfield_token_(esConsumes<MagneticField, IdealMagneticFieldRecord, edm::Transition::BeginRun>()),
0154       propagator_token_(
0155           esConsumes<Propagator, TrackingComponentsRecord, edm::Transition::BeginRun>(edm::ESInputTag("", propName_))),
0156       optimiseAcrossTracksters_(ps.getParameter<bool>("optimiseAcrossTracksters")),
0157       useMTDTiming_(ps.getParameter<bool>("useMTDTiming")),
0158       eta_bin_window_(ps.getParameter<int>("eta_bin_window")),
0159       phi_bin_window_(ps.getParameter<int>("phi_bin_window")),
0160       pt_sigma_high_(ps.getParameter<double>("pt_sigma_high")),
0161       pt_sigma_low_(ps.getParameter<double>("pt_sigma_low")),
0162       halo_max_distance2_(ps.getParameter<double>("halo_max_distance2")),
0163       track_min_pt_(ps.getParameter<double>("track_min_pt")),
0164       track_min_eta_(ps.getParameter<double>("track_min_eta")),
0165       track_max_eta_(ps.getParameter<double>("track_max_eta")),
0166       track_max_missing_outerhits_(ps.getParameter<int>("track_max_missing_outerhits")),
0167       cosangle_align_(ps.getParameter<double>("cosangle_align")),
0168       e_over_h_threshold_(ps.getParameter<double>("e_over_h_threshold")),
0169       pt_neutral_threshold_(ps.getParameter<double>("pt_neutral_threshold")),
0170       resol_calo_offset_had_(ps.getParameter<double>("resol_calo_offset_had")),
0171       resol_calo_scale_had_(ps.getParameter<double>("resol_calo_scale_had")),
0172       resol_calo_offset_em_(ps.getParameter<double>("resol_calo_offset_em")),
0173       resol_calo_scale_em_(ps.getParameter<double>("resol_calo_scale_em")),
0174       eidInputName_(ps.getParameter<std::string>("eid_input_name")),
0175       eidOutputNameEnergy_(ps.getParameter<std::string>("eid_output_name_energy")),
0176       eidOutputNameId_(ps.getParameter<std::string>("eid_output_name_id")),
0177       eidMinClusterEnergy_(ps.getParameter<double>("eid_min_cluster_energy")),
0178       eidNLayers_(ps.getParameter<int>("eid_n_layers")),
0179       eidNClusters_(ps.getParameter<int>("eid_n_clusters")),
0180       eidSession_(nullptr) {
0181   produces<std::vector<Trackster>>();
0182   produces<std::vector<TICLCandidate>>();
0183 
0184   if (useMTDTiming_) {
0185     tracks_time_token_ = consumes<edm::ValueMap<float>>(ps.getParameter<edm::InputTag>("tracksTime"));
0186     tracks_time_quality_token_ = consumes<edm::ValueMap<float>>(ps.getParameter<edm::InputTag>("tracksTimeQual"));
0187     tracks_time_err_token_ = consumes<edm::ValueMap<float>>(ps.getParameter<edm::InputTag>("tracksTimeErr"));
0188   }
0189 
0190   std::string detectorName_ = (detector_ == "HFNose") ? "HGCalHFNoseSensitive" : "HGCalEESensitive";
0191   hdc_token_ =
0192       esConsumes<HGCalDDDConstants, IdealGeometryRecord, edm::Transition::BeginRun>(edm::ESInputTag("", detectorName_));
0193 
0194   auto linkingPSet = ps.getParameter<edm::ParameterSet>("linkingPSet");
0195   auto algoType = linkingPSet.getParameter<std::string>("type");
0196   linkingAlgo_ = LinkingAlgoFactory::get()->create(algoType, linkingPSet);
0197 }
0198 
0199 void TrackstersMergeProducer::beginJob() {}
0200 
0201 void TrackstersMergeProducer::endJob() {}
0202 
0203 void TrackstersMergeProducer::beginRun(edm::Run const &iEvent, edm::EventSetup const &es) {
0204   edm::ESHandle<HGCalDDDConstants> hdc = es.getHandle(hdc_token_);
0205   hgcons_ = hdc.product();
0206 
0207   edm::ESHandle<CaloGeometry> geom = es.getHandle(geometry_token_);
0208   rhtools_.setGeometry(*geom);
0209 
0210   edm::ESHandle<MagneticField> bfield = es.getHandle(bfield_token_);
0211   edm::ESHandle<Propagator> propagator = es.getHandle(propagator_token_);
0212 
0213   linkingAlgo_->initialize(hgcons_, rhtools_, bfield, propagator);
0214 };
0215 
0216 void TrackstersMergeProducer::fillTile(TICLTracksterTiles &tracksterTile,
0217                                        const std::vector<Trackster> &tracksters,
0218                                        TracksterIterIndex tracksterIteration) {
0219   int tracksterId = 0;
0220   for (auto const &t : tracksters) {
0221     tracksterTile.fill(tracksterIteration, t.barycenter().eta(), t.barycenter().phi(), tracksterId);
0222     LogDebug("TrackstersMergeProducer") << "Adding tracksterId: " << tracksterId << " into bin [eta,phi]: [ "
0223                                         << tracksterTile[tracksterIteration].etaBin(t.barycenter().eta()) << ", "
0224                                         << tracksterTile[tracksterIteration].phiBin(t.barycenter().phi())
0225                                         << "] for iteration: " << tracksterIteration << std::endl;
0226 
0227     tracksterId++;
0228   }
0229 }
0230 
0231 void TrackstersMergeProducer::dumpTrackster(const Trackster &t) const {
0232   auto e_over_h = (t.raw_em_pt() / ((t.raw_pt() - t.raw_em_pt()) != 0. ? (t.raw_pt() - t.raw_em_pt()) : 1.));
0233   LogDebug("TrackstersMergeProducer")
0234       << "\nTrackster raw_pt: " << t.raw_pt() << " raw_em_pt: " << t.raw_em_pt() << " eoh: " << e_over_h
0235       << " barycenter: " << t.barycenter() << " eta,phi (baricenter): " << t.barycenter().eta() << ", "
0236       << t.barycenter().phi() << " eta,phi (eigen): " << t.eigenvectors(0).eta() << ", " << t.eigenvectors(0).phi()
0237       << " pt(eigen): " << std::sqrt(t.eigenvectors(0).Unit().perp2()) * t.raw_energy() << " seedID: " << t.seedID()
0238       << " seedIndex: " << t.seedIndex() << " size: " << t.vertices().size() << " average usage: "
0239       << (std::accumulate(std::begin(t.vertex_multiplicity()), std::end(t.vertex_multiplicity()), 0.) /
0240           (float)t.vertex_multiplicity().size())
0241       << " raw_energy: " << t.raw_energy() << " regressed energy: " << t.regressed_energy()
0242       << " probs(ga/e/mu/np/cp/nh/am/unk): ";
0243   for (auto const &p : t.id_probabilities()) {
0244     LogDebug("TrackstersMergeProducer") << std::fixed << p << " ";
0245   }
0246   LogDebug("TrackstersMergeProducer") << " sigmas: ";
0247   for (auto const &s : t.sigmas()) {
0248     LogDebug("TrackstersMergeProducer") << s << " ";
0249   }
0250   LogDebug("TrackstersMergeProducer") << std::endl;
0251 }
0252 
0253 void TrackstersMergeProducer::produce(edm::Event &evt, const edm::EventSetup &es) {
0254   auto resultTrackstersMerged = std::make_unique<std::vector<Trackster>>();
0255   auto resultCandidates = std::make_unique<std::vector<TICLCandidate>>();
0256   auto resultFromTracks = std::make_unique<std::vector<TICLCandidate>>();
0257   tfSession_ = es.getData(tfDnnToken_).getSession();
0258 
0259   edm::Handle<std::vector<Trackster>> trackstersclue3d_h;
0260   evt.getByToken(tracksters_clue3d_token_, trackstersclue3d_h);
0261 
0262   edm::Handle<std::vector<reco::Track>> track_h;
0263   evt.getByToken(tracks_token_, track_h);
0264   const auto &tracks = *track_h;
0265 
0266   const auto &layerClusters = evt.get(clusters_token_);
0267   const auto &layerClustersTimes = evt.get(clustersTime_token_);
0268   const auto &muons = evt.get(muons_token_);
0269   edm::Handle<edm::ValueMap<float>> trackTime_h;
0270   edm::Handle<edm::ValueMap<float>> trackTimeErr_h;
0271   edm::Handle<edm::ValueMap<float>> trackTimeQual_h;
0272   if (useMTDTiming_) {
0273     evt.getByToken(tracks_time_token_, trackTime_h);
0274     evt.getByToken(tracks_time_err_token_, trackTimeErr_h);
0275     evt.getByToken(tracks_time_quality_token_, trackTimeQual_h);
0276   }
0277 
0278   // Linking
0279   linkingAlgo_->linkTracksters(track_h,
0280                                trackTime_h,
0281                                trackTimeErr_h,
0282                                trackTimeQual_h,
0283                                muons,
0284                                trackstersclue3d_h,
0285                                useMTDTiming_,
0286                                *resultCandidates,
0287                                *resultFromTracks);
0288 
0289   // Print debug info
0290   LogDebug("TrackstersMergeProducer") << "Results from the linking step : " << std::endl
0291                                       << "No. of Tracks : " << tracks.size()
0292                                       << "  No. of Tracksters : " << (*trackstersclue3d_h).size() << std::endl
0293                                       << "(neutral candidates have track id -1)" << std::endl;
0294 
0295   std::vector<TICLCandidate> &candidates = *resultCandidates;
0296   for (const auto &cand : candidates) {
0297     auto track_ptr = cand.trackPtr();
0298     auto trackster_ptrs = cand.tracksters();
0299 
0300     auto track_idx = track_ptr.get() - (edm::Ptr<reco::Track>(track_h, 0)).get();
0301     track_idx = (track_ptr.isNull()) ? -1 : track_idx;
0302 #ifdef EDM_ML_DEBUG
0303     LogDebug("TrackstersMergeProducer") << "PDG ID " << cand.pdgId() << " charge " << cand.charge() << " p " << cand.p()
0304                                         << std::endl;
0305     LogDebug("TrackstersMergeProducer") << "track id (p) : " << track_idx << " ("
0306                                         << (track_ptr.isNull() ? -1 : track_ptr->p()) << ") "
0307                                         << " trackster ids (E) : ";
0308 #endif
0309 
0310     // Merge included tracksters
0311     ticl::Trackster outTrackster;
0312     outTrackster.setTrackIdx(track_idx);
0313     auto updated_size = 0;
0314     for (const auto &ts_ptr : trackster_ptrs) {
0315 #ifdef EDM_ML_DEBUG
0316       auto ts_idx = ts_ptr.get() - (edm::Ptr<ticl::Trackster>(trackstersclue3d_h, 0)).get();
0317       LogDebug("TrackstersMergeProducer") << ts_idx << " (" << ts_ptr->raw_energy() << ") ";
0318 #endif
0319 
0320       auto &thisTrackster = *ts_ptr;
0321       updated_size += thisTrackster.vertices().size();
0322       outTrackster.vertices().reserve(updated_size);
0323       outTrackster.vertex_multiplicity().reserve(updated_size);
0324       std::copy(std::begin(thisTrackster.vertices()),
0325                 std::end(thisTrackster.vertices()),
0326                 std::back_inserter(outTrackster.vertices()));
0327       std::copy(std::begin(thisTrackster.vertex_multiplicity()),
0328                 std::end(thisTrackster.vertex_multiplicity()),
0329                 std::back_inserter(outTrackster.vertex_multiplicity()));
0330     }
0331 
0332     LogDebug("TrackstersMergeProducer") << std::endl;
0333 
0334     // Find duplicate LCs
0335     auto &orig_vtx = outTrackster.vertices();
0336     auto vtx_sorted{orig_vtx};
0337     std::sort(std::begin(vtx_sorted), std::end(vtx_sorted));
0338     for (unsigned int iLC = 1; iLC < vtx_sorted.size(); ++iLC) {
0339       if (vtx_sorted[iLC] == vtx_sorted[iLC - 1]) {
0340         // Clean up duplicate LCs
0341         const auto lcIdx = vtx_sorted[iLC];
0342         const auto firstEl = std::find(orig_vtx.begin(), orig_vtx.end(), lcIdx);
0343         const auto firstPos = std::distance(std::begin(orig_vtx), firstEl);
0344         auto iDup = std::find(std::next(firstEl), orig_vtx.end(), lcIdx);
0345         while (iDup != orig_vtx.end()) {
0346           orig_vtx.erase(iDup);
0347           outTrackster.vertex_multiplicity().erase(outTrackster.vertex_multiplicity().begin() +
0348                                                    std::distance(std::begin(orig_vtx), iDup));
0349           outTrackster.vertex_multiplicity()[firstPos] -= 1;
0350           iDup = std::find(std::next(firstEl), orig_vtx.end(), lcIdx);
0351         };
0352       }
0353     }
0354 
0355     outTrackster.zeroProbabilities();
0356     if (!outTrackster.vertices().empty()) {
0357       resultTrackstersMerged->push_back(outTrackster);
0358     }
0359   }
0360 
0361   assignPCAtoTracksters(*resultTrackstersMerged,
0362                         layerClusters,
0363                         layerClustersTimes,
0364                         rhtools_.getPositionLayer(rhtools_.lastLayerEE()).z(),
0365                         rhtools_);
0366   energyRegressionAndID(layerClusters, tfSession_, *resultTrackstersMerged);
0367 
0368   //filling the TICLCandidates information
0369   assert(resultTrackstersMerged->size() == resultCandidates->size());
0370 
0371   auto isHad = [](const Trackster &tracksterMerge) {
0372     return tracksterMerge.id_probability(Trackster::ParticleType::photon) +
0373                tracksterMerge.id_probability(Trackster::ParticleType::electron) <
0374            0.5;
0375   };
0376   for (size_t i = 0; i < resultTrackstersMerged->size(); i++) {
0377     auto const &tm = (*resultTrackstersMerged)[i];
0378     auto &cand = (*resultCandidates)[i];
0379     //common properties
0380     cand.setIdProbabilities(tm.id_probabilities());
0381     //charged candidates
0382     if (!cand.trackPtr().isNull()) {
0383       auto pdgId = isHad(tm) ? 211 : 11;
0384       auto const &tk = cand.trackPtr().get();
0385       cand.setPdgId(pdgId * tk->charge());
0386       cand.setCharge(tk->charge());
0387       cand.setRawEnergy(tm.raw_energy());
0388       auto const &regrE = tm.regressed_energy();
0389       math::XYZTLorentzVector p4(regrE * tk->momentum().unit().x(),
0390                                  regrE * tk->momentum().unit().y(),
0391                                  regrE * tk->momentum().unit().z(),
0392                                  regrE);
0393       cand.setP4(p4);
0394     } else {  // neutral candidates
0395       auto pdgId = isHad(tm) ? 130 : 22;
0396       cand.setPdgId(pdgId);
0397       cand.setCharge(0);
0398       cand.setRawEnergy(tm.raw_energy());
0399       const float &regrE = tm.regressed_energy();
0400       math::XYZTLorentzVector p4(regrE * tm.barycenter().unit().x(),
0401                                  regrE * tm.barycenter().unit().y(),
0402                                  regrE * tm.barycenter().unit().z(),
0403                                  regrE);
0404       cand.setP4(p4);
0405     }
0406   }
0407   for (auto &cand : *resultFromTracks) {  //Tracks with no linked tracksters are promoted to charged hadron candidates
0408     auto const &tk = cand.trackPtr().get();
0409     cand.setPdgId(211 * tk->charge());
0410     cand.setCharge(tk->charge());
0411     const float energy = std::sqrt(tk->p() * tk->p() + ticl::mpion2);
0412     cand.setRawEnergy(energy);
0413     math::PtEtaPhiMLorentzVector p4Polar(tk->pt(), tk->eta(), tk->phi(), ticl::mpion);
0414     cand.setP4(p4Polar);
0415   }
0416   // Compute timing
0417   resultCandidates->insert(resultCandidates->end(), resultFromTracks->begin(), resultFromTracks->end());
0418   assignTimeToCandidates(*resultCandidates);
0419 
0420   evt.put(std::move(resultTrackstersMerged));
0421   evt.put(std::move(resultCandidates));
0422 }
0423 
0424 void TrackstersMergeProducer::energyRegressionAndID(const std::vector<reco::CaloCluster> &layerClusters,
0425                                                     const tensorflow::Session *eidSession,
0426                                                     std::vector<Trackster> &tracksters) const {
0427   // Energy regression and particle identification strategy:
0428   //
0429   // 1. Set default values for regressed energy and particle id for each trackster.
0430   // 2. Store indices of tracksters whose total sum of cluster energies is above the
0431   //    eidMinClusterEnergy_ (GeV) threshold. Inference is not applied for soft tracksters.
0432   // 3. When no trackster passes the selection, return.
0433   // 4. Create input and output tensors. The batch dimension is determined by the number of
0434   //    selected tracksters.
0435   // 5. Fill input tensors with layer cluster features. Per layer, clusters are ordered descending
0436   //    by energy. Given that tensor data is contiguous in memory, we can use pointer arithmetic to
0437   //    fill values, even with batching.
0438   // 6. Zero-fill features for empty clusters in each layer.
0439   // 7. Batched inference.
0440   // 8. Assign the regressed energy and id probabilities to each trackster.
0441   //
0442   // Indices used throughout this method:
0443   // i -> batch element / trackster
0444   // j -> layer
0445   // k -> cluster
0446   // l -> feature
0447 
0448   // do nothing when no trackster passes the selection (3)
0449   int batchSize = (int)tracksters.size();
0450   if (batchSize == 0) {
0451     return;
0452   }
0453 
0454   for (auto &t : tracksters) {
0455     t.setRegressedEnergy(0.f);
0456     t.zeroProbabilities();
0457   }
0458 
0459   // create input and output tensors (4)
0460   tensorflow::TensorShape shape({batchSize, eidNLayers_, eidNClusters_, eidNFeatures_});
0461   tensorflow::Tensor input(tensorflow::DT_FLOAT, shape);
0462   tensorflow::NamedTensorList inputList = {{eidInputName_, input}};
0463   static constexpr int inputDimension = 4;
0464 
0465   std::vector<tensorflow::Tensor> outputs;
0466   std::vector<std::string> outputNames;
0467   if (!eidOutputNameEnergy_.empty()) {
0468     outputNames.push_back(eidOutputNameEnergy_);
0469   }
0470   if (!eidOutputNameId_.empty()) {
0471     outputNames.push_back(eidOutputNameId_);
0472   }
0473 
0474   // fill input tensor (5)
0475   for (int i = 0; i < batchSize; i++) {
0476     const Trackster &trackster = tracksters[i];
0477 
0478     // per layer, we only consider the first eidNClusters_ clusters in terms of
0479     // energy, so in order to avoid creating large / nested structures to do
0480     // the sorting for an unknown number of total clusters, create a sorted
0481     // list of layer cluster indices to keep track of the filled clusters
0482     std::vector<int> clusterIndices(trackster.vertices().size());
0483     for (int k = 0; k < (int)trackster.vertices().size(); k++) {
0484       clusterIndices[k] = k;
0485     }
0486     sort(clusterIndices.begin(), clusterIndices.end(), [&layerClusters, &trackster](const int &a, const int &b) {
0487       return layerClusters[trackster.vertices(a)].energy() > layerClusters[trackster.vertices(b)].energy();
0488     });
0489 
0490     // keep track of the number of seen clusters per layer
0491     std::vector<int> seenClusters(eidNLayers_);
0492 
0493     // loop through clusters by descending energy
0494     for (const int &k : clusterIndices) {
0495       // get features per layer and cluster and store the values directly in the input tensor
0496       const reco::CaloCluster &cluster = layerClusters[trackster.vertices(k)];
0497       int j = rhtools_.getLayerWithOffset(cluster.hitsAndFractions()[0].first) - 1;
0498       if (j < eidNLayers_ && seenClusters[j] < eidNClusters_) {
0499         // get the pointer to the first feature value for the current batch, layer and cluster
0500         float *features = &input.tensor<float, inputDimension>()(i, j, seenClusters[j], 0);
0501 
0502         // fill features
0503         *(features++) = float(cluster.energy() / float(trackster.vertex_multiplicity(k)));
0504         *(features++) = float(std::abs(cluster.eta()));
0505         *(features) = float(cluster.phi());
0506 
0507         // increment seen clusters
0508         seenClusters[j]++;
0509       }
0510     }
0511 
0512     // zero-fill features of empty clusters in each layer (6)
0513     for (int j = 0; j < eidNLayers_; j++) {
0514       for (int k = seenClusters[j]; k < eidNClusters_; k++) {
0515         float *features = &input.tensor<float, inputDimension>()(i, j, k, 0);
0516         for (int l = 0; l < eidNFeatures_; l++) {
0517           *(features++) = 0.f;
0518         }
0519       }
0520     }
0521   }
0522 
0523   // run the inference (7)
0524   tensorflow::run(eidSession, inputList, outputNames, &outputs);
0525 
0526   // store regressed energy per trackster (8)
0527   if (!eidOutputNameEnergy_.empty()) {
0528     // get the pointer to the energy tensor, dimension is batch x 1
0529     float *energy = outputs[0].flat<float>().data();
0530 
0531     for (int i = 0; i < batchSize; ++i) {
0532       float regressedEnergy =
0533           tracksters[i].raw_energy() > eidMinClusterEnergy_ ? energy[i] : tracksters[i].raw_energy();
0534       tracksters[i].setRegressedEnergy(regressedEnergy);
0535     }
0536   }
0537 
0538   // store id probabilities per trackster (8)
0539   if (!eidOutputNameId_.empty()) {
0540     // get the pointer to the id probability tensor, dimension is batch x id_probabilities.size()
0541     int probsIdx = !eidOutputNameEnergy_.empty();
0542     float *probs = outputs[probsIdx].flat<float>().data();
0543     int probsNumber = tracksters[0].id_probabilities().size();
0544     for (int i = 0; i < batchSize; ++i) {
0545       tracksters[i].setProbabilities(&probs[i * probsNumber]);
0546     }
0547   }
0548 }
0549 
0550 void TrackstersMergeProducer::assignTimeToCandidates(std::vector<TICLCandidate> &resultCandidates) const {
0551   for (auto &cand : resultCandidates) {
0552     if (cand.tracksters().size() > 1) {  // For single-trackster candidates the timing is already set
0553       float time = 0.f;
0554       float invTimeErr = 0.f;
0555       for (const auto &tr : cand.tracksters()) {
0556         if (tr->timeError() > 0) {
0557           auto invTimeESq = pow(tr->timeError(), -2);
0558           time += tr->time() * invTimeESq;
0559           invTimeErr += invTimeESq;
0560         }
0561       }
0562       if (invTimeErr > 0) {
0563         cand.setTime(time / invTimeErr, sqrt(1.f / invTimeErr));
0564       }
0565     }
0566   }
0567 }
0568 
0569 void TrackstersMergeProducer::printTrackstersDebug(const std::vector<Trackster> &tracksters, const char *label) const {
0570 #ifdef EDM_ML_DEBUG
0571   int counter = 0;
0572   for (auto const &t : tracksters) {
0573     LogDebug("TrackstersMergeProducer")
0574         << counter++ << " TrackstersMergeProducer (" << label << ") obj barycenter: " << t.barycenter()
0575         << " eta,phi (baricenter): " << t.barycenter().eta() << ", " << t.barycenter().phi()
0576         << " eta,phi (eigen): " << t.eigenvectors(0).eta() << ", " << t.eigenvectors(0).phi()
0577         << " pt(eigen): " << std::sqrt(t.eigenvectors(0).Unit().perp2()) * t.raw_energy() << " seedID: " << t.seedID()
0578         << " seedIndex: " << t.seedIndex() << " size: " << t.vertices().size() << " average usage: "
0579         << (std::accumulate(std::begin(t.vertex_multiplicity()), std::end(t.vertex_multiplicity()), 0.) /
0580             (float)t.vertex_multiplicity().size())
0581         << " raw_energy: " << t.raw_energy() << " regressed energy: " << t.regressed_energy()
0582         << " probs(ga/e/mu/np/cp/nh/am/unk): ";
0583     for (auto const &p : t.id_probabilities()) {
0584       LogDebug("TrackstersMergeProducer") << std::fixed << p << " ";
0585     }
0586     LogDebug("TrackstersMergeProducer") << " sigmas: ";
0587     for (auto const &s : t.sigmas()) {
0588       LogDebug("TrackstersMergeProducer") << s << " ";
0589     }
0590     LogDebug("TrackstersMergeProducer") << std::endl;
0591   }
0592 #endif
0593 }
0594 
0595 void TrackstersMergeProducer::fillDescriptions(edm::ConfigurationDescriptions &descriptions) {
0596   edm::ParameterSetDescription desc;
0597 
0598   edm::ParameterSetDescription linkingDesc;
0599   linkingDesc.addNode(edm::PluginDescription<LinkingAlgoFactory>("type", "LinkingAlgoByDirectionGeometric", true));
0600   desc.add<edm::ParameterSetDescription>("linkingPSet", linkingDesc);
0601 
0602   desc.add<edm::InputTag>("trackstersclue3d", edm::InputTag("ticlTrackstersCLUE3DHigh"));
0603   desc.add<edm::InputTag>("layer_clusters", edm::InputTag("hgcalMergeLayerClusters"));
0604   desc.add<edm::InputTag>("layer_clustersTime", edm::InputTag("hgcalMergeLayerClusters", "timeLayerCluster"));
0605   desc.add<edm::InputTag>("tracks", edm::InputTag("generalTracks"));
0606   desc.add<edm::InputTag>("tracksTime", edm::InputTag("tofPID:t0"));
0607   desc.add<edm::InputTag>("tracksTimeQual", edm::InputTag("mtdTrackQualityMVA:mtdQualMVA"));
0608   desc.add<edm::InputTag>("tracksTimeErr", edm::InputTag("tofPID:sigmat0"));
0609   desc.add<edm::InputTag>("muons", edm::InputTag("muons1stStep"));
0610   desc.add<std::string>("detector", "HGCAL");
0611   desc.add<std::string>("propagator", "PropagatorWithMaterial");
0612   desc.add<bool>("optimiseAcrossTracksters", true);
0613   desc.add<bool>("useMTDTiming", true);
0614   desc.add<int>("eta_bin_window", 1);
0615   desc.add<int>("phi_bin_window", 1);
0616   desc.add<double>("pt_sigma_high", 2.);
0617   desc.add<double>("pt_sigma_low", 2.);
0618   desc.add<double>("halo_max_distance2", 4.);
0619   desc.add<double>("track_min_pt", 1.);
0620   desc.add<double>("track_min_eta", 1.48);
0621   desc.add<double>("track_max_eta", 3.);
0622   desc.add<int>("track_max_missing_outerhits", 5);
0623   desc.add<double>("cosangle_align", 0.9945);
0624   desc.add<double>("e_over_h_threshold", 1.);
0625   desc.add<double>("pt_neutral_threshold", 2.);
0626   desc.add<double>("resol_calo_offset_had", 1.5);
0627   desc.add<double>("resol_calo_scale_had", 0.15);
0628   desc.add<double>("resol_calo_offset_em", 1.5);
0629   desc.add<double>("resol_calo_scale_em", 0.15);
0630   desc.add<std::string>("tfDnnLabel", "tracksterSelectionTf");
0631   desc.add<std::string>("eid_input_name", "input");
0632   desc.add<std::string>("eid_output_name_energy", "output/regressed_energy");
0633   desc.add<std::string>("eid_output_name_id", "output/id_probabilities");
0634   desc.add<double>("eid_min_cluster_energy", 2.5);
0635   desc.add<int>("eid_n_layers", 50);
0636   desc.add<int>("eid_n_clusters", 10);
0637   descriptions.add("trackstersMergeProducer", desc);
0638 }
0639 
0640 DEFINE_FWK_MODULE(TrackstersMergeProducer);