Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-06-13 03:24:05

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   energyRegressionAndID(layerClusters, tfSession_, *resultTrackstersMerged);
0366 
0367   //filling the TICLCandidates information
0368   assert(resultTrackstersMerged->size() == resultCandidates->size());
0369 
0370   auto isHad = [](const Trackster &tracksterMerge) {
0371     return tracksterMerge.id_probability(Trackster::ParticleType::photon) +
0372                tracksterMerge.id_probability(Trackster::ParticleType::electron) <
0373            0.5;
0374   };
0375   for (size_t i = 0; i < resultTrackstersMerged->size(); i++) {
0376     auto const &tm = (*resultTrackstersMerged)[i];
0377     auto &cand = (*resultCandidates)[i];
0378     //common properties
0379     cand.setIdProbabilities(tm.id_probabilities());
0380     //charged candidates
0381     if (!cand.trackPtr().isNull()) {
0382       auto pdgId = isHad(tm) ? 211 : 11;
0383       auto const &tk = cand.trackPtr().get();
0384       cand.setPdgId(pdgId * tk->charge());
0385       cand.setCharge(tk->charge());
0386       cand.setRawEnergy(tm.raw_energy());
0387       auto const &regrE = tm.regressed_energy();
0388       math::XYZTLorentzVector p4(regrE * tk->momentum().unit().x(),
0389                                  regrE * tk->momentum().unit().y(),
0390                                  regrE * tk->momentum().unit().z(),
0391                                  regrE);
0392       cand.setP4(p4);
0393     } else {  // neutral candidates
0394       auto pdgId = isHad(tm) ? 130 : 22;
0395       cand.setPdgId(pdgId);
0396       cand.setCharge(0);
0397       cand.setRawEnergy(tm.raw_energy());
0398       const float &regrE = tm.regressed_energy();
0399       math::XYZTLorentzVector p4(regrE * tm.barycenter().unit().x(),
0400                                  regrE * tm.barycenter().unit().y(),
0401                                  regrE * tm.barycenter().unit().z(),
0402                                  regrE);
0403       cand.setP4(p4);
0404     }
0405   }
0406   for (auto &cand : *resultFromTracks) {  //Tracks with no linked tracksters are promoted to charged hadron candidates
0407     auto const &tk = cand.trackPtr().get();
0408     cand.setPdgId(211 * tk->charge());
0409     cand.setCharge(tk->charge());
0410     const float energy = std::sqrt(tk->p() * tk->p() + ticl::mpion2);
0411     cand.setRawEnergy(energy);
0412     math::PtEtaPhiMLorentzVector p4Polar(tk->pt(), tk->eta(), tk->phi(), ticl::mpion);
0413     cand.setP4(p4Polar);
0414   }
0415   // Compute timing
0416   resultCandidates->insert(resultCandidates->end(), resultFromTracks->begin(), resultFromTracks->end());
0417   assignTimeToCandidates(*resultCandidates);
0418 
0419   evt.put(std::move(resultTrackstersMerged));
0420   evt.put(std::move(resultCandidates));
0421 }
0422 
0423 void TrackstersMergeProducer::energyRegressionAndID(const std::vector<reco::CaloCluster> &layerClusters,
0424                                                     const tensorflow::Session *eidSession,
0425                                                     std::vector<Trackster> &tracksters) const {
0426   // Energy regression and particle identification strategy:
0427   //
0428   // 1. Set default values for regressed energy and particle id for each trackster.
0429   // 2. Store indices of tracksters whose total sum of cluster energies is above the
0430   //    eidMinClusterEnergy_ (GeV) threshold. Inference is not applied for soft tracksters.
0431   // 3. When no trackster passes the selection, return.
0432   // 4. Create input and output tensors. The batch dimension is determined by the number of
0433   //    selected tracksters.
0434   // 5. Fill input tensors with layer cluster features. Per layer, clusters are ordered descending
0435   //    by energy. Given that tensor data is contiguous in memory, we can use pointer arithmetic to
0436   //    fill values, even with batching.
0437   // 6. Zero-fill features for empty clusters in each layer.
0438   // 7. Batched inference.
0439   // 8. Assign the regressed energy and id probabilities to each trackster.
0440   //
0441   // Indices used throughout this method:
0442   // i -> batch element / trackster
0443   // j -> layer
0444   // k -> cluster
0445   // l -> feature
0446 
0447   // do nothing when no trackster passes the selection (3)
0448   int batchSize = (int)tracksters.size();
0449   if (batchSize == 0) {
0450     return;
0451   }
0452 
0453   for (auto &t : tracksters) {
0454     t.setRegressedEnergy(0.f);
0455     t.zeroProbabilities();
0456   }
0457 
0458   // create input and output tensors (4)
0459   tensorflow::TensorShape shape({batchSize, eidNLayers_, eidNClusters_, eidNFeatures_});
0460   tensorflow::Tensor input(tensorflow::DT_FLOAT, shape);
0461   tensorflow::NamedTensorList inputList = {{eidInputName_, input}};
0462   static constexpr int inputDimension = 4;
0463 
0464   std::vector<tensorflow::Tensor> outputs;
0465   std::vector<std::string> outputNames;
0466   if (!eidOutputNameEnergy_.empty()) {
0467     outputNames.push_back(eidOutputNameEnergy_);
0468   }
0469   if (!eidOutputNameId_.empty()) {
0470     outputNames.push_back(eidOutputNameId_);
0471   }
0472 
0473   // fill input tensor (5)
0474   for (int i = 0; i < batchSize; i++) {
0475     const Trackster &trackster = tracksters[i];
0476 
0477     // per layer, we only consider the first eidNClusters_ clusters in terms of
0478     // energy, so in order to avoid creating large / nested structures to do
0479     // the sorting for an unknown number of total clusters, create a sorted
0480     // list of layer cluster indices to keep track of the filled clusters
0481     std::vector<int> clusterIndices(trackster.vertices().size());
0482     for (int k = 0; k < (int)trackster.vertices().size(); k++) {
0483       clusterIndices[k] = k;
0484     }
0485     sort(clusterIndices.begin(), clusterIndices.end(), [&layerClusters, &trackster](const int &a, const int &b) {
0486       return layerClusters[trackster.vertices(a)].energy() > layerClusters[trackster.vertices(b)].energy();
0487     });
0488 
0489     // keep track of the number of seen clusters per layer
0490     std::vector<int> seenClusters(eidNLayers_);
0491 
0492     // loop through clusters by descending energy
0493     for (const int &k : clusterIndices) {
0494       // get features per layer and cluster and store the values directly in the input tensor
0495       const reco::CaloCluster &cluster = layerClusters[trackster.vertices(k)];
0496       int j = rhtools_.getLayerWithOffset(cluster.hitsAndFractions()[0].first) - 1;
0497       if (j < eidNLayers_ && seenClusters[j] < eidNClusters_) {
0498         // get the pointer to the first feature value for the current batch, layer and cluster
0499         float *features = &input.tensor<float, inputDimension>()(i, j, seenClusters[j], 0);
0500 
0501         // fill features
0502         *(features++) = float(cluster.energy() / float(trackster.vertex_multiplicity(k)));
0503         *(features++) = float(std::abs(cluster.eta()));
0504         *(features) = float(cluster.phi());
0505 
0506         // increment seen clusters
0507         seenClusters[j]++;
0508       }
0509     }
0510 
0511     // zero-fill features of empty clusters in each layer (6)
0512     for (int j = 0; j < eidNLayers_; j++) {
0513       for (int k = seenClusters[j]; k < eidNClusters_; k++) {
0514         float *features = &input.tensor<float, inputDimension>()(i, j, k, 0);
0515         for (int l = 0; l < eidNFeatures_; l++) {
0516           *(features++) = 0.f;
0517         }
0518       }
0519     }
0520   }
0521 
0522   // run the inference (7)
0523   tensorflow::run(eidSession, inputList, outputNames, &outputs);
0524 
0525   // store regressed energy per trackster (8)
0526   if (!eidOutputNameEnergy_.empty()) {
0527     // get the pointer to the energy tensor, dimension is batch x 1
0528     float *energy = outputs[0].flat<float>().data();
0529 
0530     for (int i = 0; i < batchSize; ++i) {
0531       float regressedEnergy =
0532           tracksters[i].raw_energy() > eidMinClusterEnergy_ ? energy[i] : tracksters[i].raw_energy();
0533       tracksters[i].setRegressedEnergy(regressedEnergy);
0534     }
0535   }
0536 
0537   // store id probabilities per trackster (8)
0538   if (!eidOutputNameId_.empty()) {
0539     // get the pointer to the id probability tensor, dimension is batch x id_probabilities.size()
0540     int probsIdx = !eidOutputNameEnergy_.empty();
0541     float *probs = outputs[probsIdx].flat<float>().data();
0542     int probsNumber = tracksters[0].id_probabilities().size();
0543     for (int i = 0; i < batchSize; ++i) {
0544       tracksters[i].setProbabilities(&probs[i * probsNumber]);
0545     }
0546   }
0547 }
0548 
0549 void TrackstersMergeProducer::assignTimeToCandidates(std::vector<TICLCandidate> &resultCandidates) const {
0550   for (auto &cand : resultCandidates) {
0551     if (cand.tracksters().size() > 1) {  // For single-trackster candidates the timing is already set
0552       float time = 0.f;
0553       float invTimeErr = 0.f;
0554       for (const auto &tr : cand.tracksters()) {
0555         if (tr->timeError() > 0) {
0556           auto invTimeESq = pow(tr->timeError(), -2);
0557           time += tr->time() * invTimeESq;
0558           invTimeErr += invTimeESq;
0559         }
0560       }
0561       if (invTimeErr > 0) {
0562         cand.setTime(time / invTimeErr, sqrt(1.f / invTimeErr));
0563       }
0564     }
0565   }
0566 }
0567 
0568 void TrackstersMergeProducer::printTrackstersDebug(const std::vector<Trackster> &tracksters, const char *label) const {
0569 #ifdef EDM_ML_DEBUG
0570   int counter = 0;
0571   for (auto const &t : tracksters) {
0572     LogDebug("TrackstersMergeProducer")
0573         << counter++ << " TrackstersMergeProducer (" << label << ") obj barycenter: " << t.barycenter()
0574         << " eta,phi (baricenter): " << t.barycenter().eta() << ", " << t.barycenter().phi()
0575         << " eta,phi (eigen): " << t.eigenvectors(0).eta() << ", " << t.eigenvectors(0).phi()
0576         << " pt(eigen): " << std::sqrt(t.eigenvectors(0).Unit().perp2()) * t.raw_energy() << " seedID: " << t.seedID()
0577         << " seedIndex: " << t.seedIndex() << " size: " << t.vertices().size() << " average usage: "
0578         << (std::accumulate(std::begin(t.vertex_multiplicity()), std::end(t.vertex_multiplicity()), 0.) /
0579             (float)t.vertex_multiplicity().size())
0580         << " raw_energy: " << t.raw_energy() << " regressed energy: " << t.regressed_energy()
0581         << " probs(ga/e/mu/np/cp/nh/am/unk): ";
0582     for (auto const &p : t.id_probabilities()) {
0583       LogDebug("TrackstersMergeProducer") << std::fixed << p << " ";
0584     }
0585     LogDebug("TrackstersMergeProducer") << " sigmas: ";
0586     for (auto const &s : t.sigmas()) {
0587       LogDebug("TrackstersMergeProducer") << s << " ";
0588     }
0589     LogDebug("TrackstersMergeProducer") << std::endl;
0590   }
0591 #endif
0592 }
0593 
0594 void TrackstersMergeProducer::fillDescriptions(edm::ConfigurationDescriptions &descriptions) {
0595   edm::ParameterSetDescription desc;
0596 
0597   edm::ParameterSetDescription linkingDesc;
0598   linkingDesc.addNode(edm::PluginDescription<LinkingAlgoFactory>("type", "LinkingAlgoByDirectionGeometric", true));
0599   desc.add<edm::ParameterSetDescription>("linkingPSet", linkingDesc);
0600 
0601   desc.add<edm::InputTag>("trackstersclue3d", edm::InputTag("ticlTrackstersCLUE3DHigh"));
0602   desc.add<edm::InputTag>("layer_clusters", edm::InputTag("hgcalMergeLayerClusters"));
0603   desc.add<edm::InputTag>("layer_clustersTime", edm::InputTag("hgcalMergeLayerClusters", "timeLayerCluster"));
0604   desc.add<edm::InputTag>("tracks", edm::InputTag("generalTracks"));
0605   desc.add<edm::InputTag>("tracksTime", edm::InputTag("tofPID:t0"));
0606   desc.add<edm::InputTag>("tracksTimeQual", edm::InputTag("mtdTrackQualityMVA:mtdQualMVA"));
0607   desc.add<edm::InputTag>("tracksTimeErr", edm::InputTag("tofPID:sigmat0"));
0608   desc.add<edm::InputTag>("muons", edm::InputTag("muons1stStep"));
0609   desc.add<std::string>("detector", "HGCAL");
0610   desc.add<std::string>("propagator", "PropagatorWithMaterial");
0611   desc.add<bool>("optimiseAcrossTracksters", true);
0612   desc.add<bool>("useMTDTiming", true);
0613   desc.add<int>("eta_bin_window", 1);
0614   desc.add<int>("phi_bin_window", 1);
0615   desc.add<double>("pt_sigma_high", 2.);
0616   desc.add<double>("pt_sigma_low", 2.);
0617   desc.add<double>("halo_max_distance2", 4.);
0618   desc.add<double>("track_min_pt", 1.);
0619   desc.add<double>("track_min_eta", 1.48);
0620   desc.add<double>("track_max_eta", 3.);
0621   desc.add<int>("track_max_missing_outerhits", 5);
0622   desc.add<double>("cosangle_align", 0.9945);
0623   desc.add<double>("e_over_h_threshold", 1.);
0624   desc.add<double>("pt_neutral_threshold", 2.);
0625   desc.add<double>("resol_calo_offset_had", 1.5);
0626   desc.add<double>("resol_calo_scale_had", 0.15);
0627   desc.add<double>("resol_calo_offset_em", 1.5);
0628   desc.add<double>("resol_calo_scale_em", 0.15);
0629   desc.add<std::string>("tfDnnLabel", "tracksterSelectionTf");
0630   desc.add<std::string>("eid_input_name", "input");
0631   desc.add<std::string>("eid_output_name_energy", "output/regressed_energy");
0632   desc.add<std::string>("eid_output_name_id", "output/id_probabilities");
0633   desc.add<double>("eid_min_cluster_energy", 2.5);
0634   desc.add<int>("eid_n_layers", 50);
0635   desc.add<int>("eid_n_clusters", 10);
0636   descriptions.add("trackstersMergeProducer", desc);
0637 }
0638 
0639 DEFINE_FWK_MODULE(TrackstersMergeProducer);