diff --git a/CommonTools/RecoAlgos/BuildFile.xml b/CommonTools/RecoAlgos/BuildFile.xml index 7b909dccf91f7..1a72dbde78522 100644 --- a/CommonTools/RecoAlgos/BuildFile.xml +++ b/CommonTools/RecoAlgos/BuildFile.xml @@ -10,6 +10,7 @@ + diff --git a/CommonTools/RecoAlgos/python/tofPID_cfi.py b/CommonTools/RecoAlgos/python/tofPID_cfi.py deleted file mode 100644 index 1ad87f5802848..0000000000000 --- a/CommonTools/RecoAlgos/python/tofPID_cfi.py +++ /dev/null @@ -1,4 +0,0 @@ -import FWCore.ParameterSet.Config as cms - -from CommonTools.RecoAlgos.tofPIDProducer_cfi import tofPIDProducer -tofPID = tofPIDProducer.clone() diff --git a/PhysicsTools/PatAlgos/plugins/PATPackedCandidateProducer.cc b/PhysicsTools/PatAlgos/plugins/PATPackedCandidateProducer.cc index ba54267085429..4f525b2021547 100644 --- a/PhysicsTools/PatAlgos/plugins/PATPackedCandidateProducer.cc +++ b/PhysicsTools/PatAlgos/plugins/PATPackedCandidateProducer.cc @@ -103,6 +103,9 @@ namespace pat { const bool storeHcalDepthEndcapOnly_; const bool storeTiming_; + const bool timeFromValueMap_; + const edm::EDGetTokenT> t0Map_; + const edm::EDGetTokenT> t0ErrMap_; // for debugging float calcDxy(float dx, float dy, float phi) const { return -dx * std::sin(phi) + dy * std::cos(phi); } @@ -143,7 +146,13 @@ pat::PATPackedCandidateProducer::PATPackedCandidateProducer(const edm::Parameter covariancePackingSchemas_(iConfig.getParameter>("covariancePackingSchemas")), pfCandidateTypesForHcalDepth_(iConfig.getParameter>("pfCandidateTypesForHcalDepth")), storeHcalDepthEndcapOnly_(iConfig.getParameter("storeHcalDepthEndcapOnly")), - storeTiming_(iConfig.getParameter("storeTiming")) { + storeTiming_(iConfig.getParameter("storeTiming")), + timeFromValueMap_(!iConfig.getParameter("timeMap").encode().empty() && + !iConfig.getParameter("timeMapErr").encode().empty()), + t0Map_(timeFromValueMap_ ? consumes>(iConfig.getParameter("timeMap")) + : edm::EDGetTokenT>()), + t0ErrMap_(timeFromValueMap_ ? consumes>(iConfig.getParameter("timeMapErr")) + : edm::EDGetTokenT>()) { std::vector sv_tags = iConfig.getParameter>("secondaryVerticesForWhiteList"); for (auto itag : sv_tags) { @@ -219,6 +228,13 @@ void pat::PATPackedCandidateProducer::produce(edm::StreamID, edm::Event &iEvent, } } + edm::Handle> t0Map; + edm::Handle> t0ErrMap; + if (timeFromValueMap_) { + iEvent.getByToken(t0Map_, t0Map); + iEvent.getByToken(t0ErrMap_, t0ErrMap); + } + edm::Handle PVs; iEvent.getByToken(PVs_, PVs); reco::VertexRef PV(PVs.id()); @@ -425,8 +441,18 @@ void pat::PATPackedCandidateProducer::produce(edm::StreamID, edm::Event &iEvent, mappingPuppi[((*puppiCandsMap)[pkref]).key()] = ic; } - if (storeTiming_ && cand.isTimeValid()) { - outPtrP->back().setTime(cand.time(), cand.timeError()); + if (storeTiming_) { + if (timeFromValueMap_) { + if (cand.trackRef().isNonnull()) { + auto t0 = (*t0Map)[cand.trackRef()]; + auto t0Err = (*t0ErrMap)[cand.trackRef()]; + outPtrP->back().setTime(t0, t0Err); + } + } else { + if (cand.isTimeValid()) { + outPtrP->back().setTime(cand.time(), cand.timeError()); + } + } } mapping[ic] = ic; // trivial at the moment! diff --git a/PhysicsTools/PatAlgos/python/slimming/packedPFCandidates_cfi.py b/PhysicsTools/PatAlgos/python/slimming/packedPFCandidates_cfi.py index 98905cce1dda9..d94780c03c7d5 100644 --- a/PhysicsTools/PatAlgos/python/slimming/packedPFCandidates_cfi.py +++ b/PhysicsTools/PatAlgos/python/slimming/packedPFCandidates_cfi.py @@ -22,7 +22,9 @@ covariancePackingSchemas = cms.vint32(8,264,520,776,0), # more accurate schema +0.6kb/ev pfCandidateTypesForHcalDepth = cms.vint32(), storeHcalDepthEndcapOnly = cms.bool(False), # switch to store info only for endcap - storeTiming = cms.bool(False) + storeTiming = cms.bool(False), + timeMap = cms.InputTag(""), + timeMapErr = cms.InputTag("") ) from Configuration.Eras.Modifier_phase1Pixel_cff import phase1Pixel diff --git a/RecoMTD/Configuration/python/RecoMTD_EventContent_cff.py b/RecoMTD/Configuration/python/RecoMTD_EventContent_cff.py index 713c9121baeb6..b1ab3192818c1 100644 --- a/RecoMTD/Configuration/python/RecoMTD_EventContent_cff.py +++ b/RecoMTD/Configuration/python/RecoMTD_EventContent_cff.py @@ -3,7 +3,8 @@ #AOD RecoMTDAOD = cms.PSet( outputCommands = cms.untracked.vstring( - 'keep *_trackExtenderWithMTD_*_*' + 'keep *_trackExtenderWithMTD_*_*', + 'keep *_mtdTrackQualityMVA_*_*' ) ) diff --git a/RecoMTD/Configuration/python/RecoMTD_cff.py b/RecoMTD/Configuration/python/RecoMTD_cff.py index af93cfa9a92d9..783b54dd2cd3e 100644 --- a/RecoMTD/Configuration/python/RecoMTD_cff.py +++ b/RecoMTD/Configuration/python/RecoMTD_cff.py @@ -1,6 +1,7 @@ import FWCore.ParameterSet.Config as cms from RecoMTD.TrackExtender.trackExtenderWithMTD_cfi import * +from RecoMTD.TimingIDTools.mtdTrackQualityMVA_cfi import * -fastTimingGlobalRecoTask = cms.Task(trackExtenderWithMTD) +fastTimingGlobalRecoTask = cms.Task(trackExtenderWithMTD,mtdTrackQualityMVA) fastTimingGlobalReco = cms.Sequence(fastTimingGlobalRecoTask) diff --git a/RecoMTD/TimingIDTools/BuildFile.xml b/RecoMTD/TimingIDTools/BuildFile.xml new file mode 100644 index 0000000000000..1041c0307883c --- /dev/null +++ b/RecoMTD/TimingIDTools/BuildFile.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/RecoMTD/TimingIDTools/interface/MTDTrackQualityMVA.h b/RecoMTD/TimingIDTools/interface/MTDTrackQualityMVA.h new file mode 100644 index 0000000000000..46d9191906c8d --- /dev/null +++ b/RecoMTD/TimingIDTools/interface/MTDTrackQualityMVA.h @@ -0,0 +1,54 @@ +#ifndef RECOMTD_TIMINGIDTOOLS_MTDTRACKQUALITYMVA +#define RECOMTD_TIMINGIDTOOLS_MTDTRACKQUALITYMVA + +#include "DataFormats/VertexReco/interface/Vertex.h" +#include "DataFormats/VertexReco/interface/VertexFwd.h" +#include "DataFormats/TrackReco/interface/Track.h" +#include "DataFormats/TrackReco/interface/TrackFwd.h" +#include "DataFormats/Common/interface/ValueMap.h" + +#include "CommonTools/MVAUtils/interface/TMVAEvaluator.h" + +#define MTDTRACKQUALITYMVA_VARS(MTDBDTVAR) \ + MTDBDTVAR(pt) \ + MTDBDTVAR(eta) \ + MTDBDTVAR(phi) \ + MTDBDTVAR(chi2) \ + MTDBDTVAR(ndof) \ + MTDBDTVAR(numberOfValidHits) \ + MTDBDTVAR(numberOfValidPixelBarrelHits) \ + MTDBDTVAR(numberOfValidPixelEndcapHits) \ + MTDBDTVAR(btlMatchChi2) \ + MTDBDTVAR(btlMatchTimeChi2) \ + MTDBDTVAR(etlMatchChi2) \ + MTDBDTVAR(etlMatchTimeChi2) \ + MTDBDTVAR(mtdt) \ + MTDBDTVAR(path_len) + +#define MTDBDTVAR_ENUM(ENUM) ENUM, +#define MTDBDTVAR_STRING(STRING) #STRING, + +class MTDTrackQualityMVA { +public: + //---ctors--- + MTDTrackQualityMVA(std::string weights_file); + + enum class VarID { MTDTRACKQUALITYMVA_VARS(MTDBDTVAR_ENUM) }; + + //---getters--- + // 4D + float operator()(const reco::TrackRef& trk, + const reco::TrackRef& ext_trk, + const edm::ValueMap& btl_chi2s, + const edm::ValueMap& btl_time_chi2s, + const edm::ValueMap& etl_chi2s, + const edm::ValueMap& etl_time_chi2s, + const edm::ValueMap& tmtds, + const edm::ValueMap& trk_lengths) const; + +private: + std::vector vars_, spec_vars_; + std::unique_ptr mva_; +}; + +#endif diff --git a/RecoMTD/TimingIDTools/plugins/BuildFile.xml b/RecoMTD/TimingIDTools/plugins/BuildFile.xml new file mode 100644 index 0000000000000..7dec4bf73e281 --- /dev/null +++ b/RecoMTD/TimingIDTools/plugins/BuildFile.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/RecoMTD/TimingIDTools/plugins/MTDTrackQualityMVAProducer.cc b/RecoMTD/TimingIDTools/plugins/MTDTrackQualityMVAProducer.cc new file mode 100644 index 0000000000000..37152256f1a9e --- /dev/null +++ b/RecoMTD/TimingIDTools/plugins/MTDTrackQualityMVAProducer.cc @@ -0,0 +1,140 @@ +#include "FWCore/Framework/interface/Frameworkfwd.h" +#include "FWCore/Framework/interface/stream/EDProducer.h" +#include "FWCore/Framework/interface/Event.h" +#include "FWCore/Framework/interface/EventSetup.h" +#include "FWCore/Framework/interface/ESHandle.h" +#include "FWCore/ParameterSet/interface/ParameterSet.h" +#include "FWCore/ParameterSet/interface/ConfigurationDescriptions.h" + +#include "DataFormats/VertexReco/interface/VertexFwd.h" +#include "DataFormats/TrackReco/interface/TrackFwd.h" +#include "DataFormats/Common/interface/ValueMap.h" +#include "DataFormats/BeamSpot/interface/BeamSpot.h" +#include "DataFormats/TrackReco/interface/Track.h" +#include "DataFormats/VertexReco/interface/Vertex.h" + +#include "RecoMTD/TimingIDTools/interface/MTDTrackQualityMVA.h" + +using namespace std; +using namespace edm; + +class MTDTrackQualityMVAProducer : public edm::stream::EDProducer<> { +public: + MTDTrackQualityMVAProducer(const ParameterSet& pset); + + static void fillDescriptions(edm::ConfigurationDescriptions& descriptions); + + template + void fillValueMap(edm::Event& iEvent, + const edm::Handle& handle, + const std::vector& vec, + const std::string& name) const; + + void produce(edm::Event& ev, const edm::EventSetup& es) final; + +private: + static constexpr char mvaName[] = "mtdQualMVA"; + + edm::EDGetTokenT tracksToken_; + edm::EDGetTokenT tracksMTDToken_; + + edm::EDGetTokenT> btlMatchChi2Token_; + edm::EDGetTokenT> btlMatchTimeChi2Token_; + edm::EDGetTokenT> etlMatchChi2Token_; + edm::EDGetTokenT> etlMatchTimeChi2Token_; + edm::EDGetTokenT> mtdTimeToken_; + edm::EDGetTokenT> pathLengthToken_; + edm::EDGetTokenT> trackAssocToken_; + + MTDTrackQualityMVA mva_; +}; + +MTDTrackQualityMVAProducer::MTDTrackQualityMVAProducer(const ParameterSet& iConfig) + : tracksToken_(consumes(iConfig.getParameter("tracksSrc"))), + tracksMTDToken_(consumes(iConfig.getParameter("tracksMTDSrc"))), + btlMatchChi2Token_(consumes>(iConfig.getParameter("btlMatchChi2Src"))), + btlMatchTimeChi2Token_( + consumes>(iConfig.getParameter("btlMatchTimeChi2Src"))), + etlMatchChi2Token_(consumes>(iConfig.getParameter("etlMatchChi2Src"))), + etlMatchTimeChi2Token_( + consumes>(iConfig.getParameter("etlMatchTimeChi2Src"))), + mtdTimeToken_(consumes>(iConfig.getParameter("mtdTimeSrc"))), + pathLengthToken_(consumes>(iConfig.getParameter("pathLengthSrc"))), + trackAssocToken_(consumes>(iConfig.getParameter("trackAssocSrc"))), + mva_(iConfig.getParameter("qualityBDT_weights_file").fullPath()) { + produces>(mvaName); +} + +// Configuration descriptions +void MTDTrackQualityMVAProducer::fillDescriptions(edm::ConfigurationDescriptions& descriptions) { + edm::ParameterSetDescription desc; + desc.add("tracksSrc", edm::InputTag("generalTracks"))->setComment("Input tracks collection"); + desc.add("tracksMTDSrc", edm::InputTag("trackExtenderWithMTD")) + ->setComment("Input tracks collection for MTD extended tracks"); + desc.add("btlMatchChi2Src", edm::InputTag("trackExtenderWithMTD", "btlMatchChi2")) + ->setComment("BTL Chi2 Matching value Map"); + desc.add("btlMatchTimeChi2Src", edm::InputTag("trackExtenderWithMTD", "btlMatchTimeChi2")) + ->setComment("BTL Chi2 Matching value Map"); + desc.add("etlMatchChi2Src", edm::InputTag("trackExtenderWithMTD", "etlMatchChi2")) + ->setComment("ETL Chi2 Matching value Map"); + desc.add("etlMatchTimeChi2Src", edm::InputTag("trackExtenderWithMTD", "etlMatchTimeChi2")) + ->setComment("ETL Chi2 Matching value Map"); + desc.add("mtdTimeSrc", edm::InputTag("trackExtenderWithMTD", "tmtd")) + ->setComment("MTD TIme value Map"); + desc.add("pathLengthSrc", edm::InputTag("trackExtenderWithMTD", "pathLength")) + ->setComment("MTD PathLength value Map"); + desc.add("trackAssocSrc", edm::InputTag("trackExtenderWithMTD", "generalTrackassoc")) + ->setComment("Association between General and MTD Extended tracks"); + desc.add("qualityBDT_weights_file", + edm::FileInPath("RecoMTD/TimingIDTools/data/clf4D_MTDquality_bo.xml")) + ->setComment("Track MTD quality BDT weights"); + descriptions.add("mtdTrackQualityMVAProducer", desc); +} + +template +void MTDTrackQualityMVAProducer::fillValueMap(edm::Event& iEvent, + const edm::Handle& handle, + const std::vector& vec, + const std::string& name) const { + auto out = std::make_unique>(); + typename edm::ValueMap::Filler filler(*out); + filler.insert(handle, vec.begin(), vec.end()); + filler.fill(); + iEvent.put(std::move(out), name); +} + +void MTDTrackQualityMVAProducer::produce(edm::Event& ev, const edm::EventSetup& es) { + edm::Handle tracksH; + ev.getByToken(tracksToken_, tracksH); + const auto& tracks = *tracksH; + + edm::Handle tracksMTDH; + ev.getByToken(tracksMTDToken_, tracksMTDH); + + const auto& btlMatchChi2 = ev.get(btlMatchChi2Token_); + const auto& btlMatchTimeChi2 = ev.get(btlMatchTimeChi2Token_); + const auto& etlMatchChi2 = ev.get(etlMatchChi2Token_); + const auto& etlMatchTimeChi2 = ev.get(etlMatchTimeChi2Token_); + const auto& pathLength = ev.get(pathLengthToken_); + const auto& trackAssoc = ev.get(trackAssocToken_); + const auto& mtdTime = ev.get(mtdTimeToken_); + + std::vector mvaOutRaw; + + //Loop over tracks collection + for (unsigned int itrack = 0; itrack < tracks.size(); ++itrack) { + const reco::TrackRef trackref(tracksH, itrack); + if (trackAssoc[trackref] == -1) + mvaOutRaw.push_back(-1.); + else { + const reco::TrackRef mtdTrackref = reco::TrackRef(tracksMTDH, trackAssoc[trackref]); + mvaOutRaw.push_back(mva_( + trackref, mtdTrackref, btlMatchChi2, btlMatchTimeChi2, etlMatchChi2, etlMatchTimeChi2, mtdTime, pathLength)); + } + } + fillValueMap(ev, tracksH, mvaOutRaw, mvaName); +} + +//define this as a plug-in +#include +DEFINE_FWK_MODULE(MTDTrackQualityMVAProducer); diff --git a/CommonTools/RecoAlgos/plugins/TOFPIDProducer.cc b/RecoMTD/TimingIDTools/plugins/TOFPIDProducer.cc similarity index 97% rename from CommonTools/RecoAlgos/plugins/TOFPIDProducer.cc rename to RecoMTD/TimingIDTools/plugins/TOFPIDProducer.cc index ad844b4b91398..014a761157120 100644 --- a/CommonTools/RecoAlgos/plugins/TOFPIDProducer.cc +++ b/RecoMTD/TimingIDTools/plugins/TOFPIDProducer.cc @@ -53,6 +53,7 @@ class TOFPIDProducer : public edm::stream::EDProducer<> { double maxDz_; double maxDtSignificance_; double minProbHeavy_; + double fixedT0Error_; }; TOFPIDProducer::TOFPIDProducer(const ParameterSet& iConfig) @@ -67,7 +68,8 @@ TOFPIDProducer::TOFPIDProducer(const ParameterSet& iConfig) vtxMaxSigmaT_(iConfig.getParameter("vtxMaxSigmaT")), maxDz_(iConfig.getParameter("maxDz")), maxDtSignificance_(iConfig.getParameter("maxDtSignificance")), - minProbHeavy_(iConfig.getParameter("minProbHeavy")) { + minProbHeavy_(iConfig.getParameter("minProbHeavy")), + fixedT0Error_(iConfig.getParameter("fixedT0Error")) { produces>(t0Name); produces>(sigmat0Name); produces>(t0safeName); @@ -93,7 +95,7 @@ void TOFPIDProducer::fillDescriptions(edm::ConfigurationDescriptions& descriptio ->setComment("Input ValueMap for track path lengh from beamline to MTD"); desc.add("pSrc", edm::InputTag("trackExtenderWithMTD:generalTrackp")) ->setComment("Input ValueMap for track momentum magnitude (normally from refit with MTD hits)"); - desc.add("vtxsSrc", edm::InputTag("unsortedOfflinePrimaryVertices4DnoPID")) + desc.add("vtxsSrc", edm::InputTag("unsortedOfflinePrimaryVertices4DwithPID")) ->setComment("Input primary vertex collection"); desc.add("vtxMaxSigmaT", 0.025) ->setComment("Maximum primary vertex time uncertainty for use in particle id [ns]"); @@ -104,6 +106,7 @@ void TOFPIDProducer::fillDescriptions(edm::ConfigurationDescriptions& descriptio "Maximum distance in time (normalized by uncertainty) for track-primary vertex association for particle id"); desc.add("minProbHeavy", 0.75) ->setComment("Minimum probability for a particle to be a kaon or proton before reassigning the timestamp"); + desc.add("fixedT0Error", 0.)->setComment("Use a fixed T0 uncertainty [ns]"); descriptions.add("tofPIDProducer", desc); } @@ -174,7 +177,7 @@ void TOFPIDProducer::produce(edm::Event& ev, const edm::EventSetup& es) { float t0 = t0In[trackref]; float t0safe = t0; float sigmat0safe = sigmat0In[trackref]; - float sigmatmtd = sigmatmtdIn[trackref]; + float sigmatmtd = (sigmatmtdIn[trackref] > 0. && fixedT0Error_ > 0.) ? fixedT0Error_ : sigmatmtdIn[trackref]; float sigmat0 = sigmatmtd; float prob_pi = -1.; diff --git a/RecoMTD/TimingIDTools/python/mtdTrackQualityMVA_cfi.py b/RecoMTD/TimingIDTools/python/mtdTrackQualityMVA_cfi.py new file mode 100644 index 0000000000000..0e5dc0f1782a6 --- /dev/null +++ b/RecoMTD/TimingIDTools/python/mtdTrackQualityMVA_cfi.py @@ -0,0 +1,5 @@ +import FWCore.ParameterSet.Config as cms + +from RecoMTD.TimingIDTools.mtdTrackQualityMVAProducer_cfi import * + +mtdTrackQualityMVA = mtdTrackQualityMVAProducer.clone() diff --git a/RecoMTD/TimingIDTools/src/MTDTrackQualityMVA.cc b/RecoMTD/TimingIDTools/src/MTDTrackQualityMVA.cc new file mode 100644 index 0000000000000..26f7255cb7741 --- /dev/null +++ b/RecoMTD/TimingIDTools/src/MTDTrackQualityMVA.cc @@ -0,0 +1,53 @@ +#include "RecoMTD/TimingIDTools/interface/MTDTrackQualityMVA.h" + +MTDTrackQualityMVA::MTDTrackQualityMVA(std::string weights_file) { + std::string options("!Color:Silent"); + std::string method("BDT"); + + std::string vars_array[] = {MTDTRACKQUALITYMVA_VARS(MTDBDTVAR_STRING)}; + int nvars = sizeof(vars_array) / sizeof(vars_array[0]); + vars_.assign(vars_array, vars_array + nvars); + + mva_ = std::make_unique(); + mva_->initialize(options, method, weights_file, vars_, spec_vars_, true, false); //use GBR, GradBoost +} + +float MTDTrackQualityMVA::operator()(const reco::TrackRef& trk, + const reco::TrackRef& ext_trk, + const edm::ValueMap& btl_chi2s, + const edm::ValueMap& btl_time_chi2s, + const edm::ValueMap& etl_chi2s, + const edm::ValueMap& etl_time_chi2s, + const edm::ValueMap& tmtds, + const edm::ValueMap& trk_lengths) const { + const auto& pattern = ext_trk->hitPattern(); + + std::map vars; + + //---training performed only above 0.5 GeV + constexpr float minPtForMVA = 0.5; + if (trk->pt() < minPtForMVA) + return -1; + + //---training performed only for tracks with MTD hits + if (tmtds[ext_trk] > 0) { + vars.emplace(vars_[int(VarID::pt)], trk->pt()); + vars.emplace(vars_[int(VarID::eta)], trk->eta()); + vars.emplace(vars_[int(VarID::phi)], trk->phi()); + vars.emplace(vars_[int(VarID::chi2)], trk->chi2()); + vars.emplace(vars_[int(VarID::ndof)], trk->ndof()); + vars.emplace(vars_[int(VarID::numberOfValidHits)], trk->numberOfValidHits()); + vars.emplace(vars_[int(VarID::numberOfValidPixelBarrelHits)], pattern.numberOfValidPixelBarrelHits()); + vars.emplace(vars_[int(VarID::numberOfValidPixelEndcapHits)], pattern.numberOfValidPixelEndcapHits()); + vars.emplace(vars_[int(VarID::btlMatchChi2)], btl_chi2s.contains(ext_trk.id()) ? btl_chi2s[ext_trk] : -1); + vars.emplace(vars_[int(VarID::btlMatchTimeChi2)], + btl_time_chi2s.contains(ext_trk.id()) ? btl_time_chi2s[ext_trk] : -1); + vars.emplace(vars_[int(VarID::etlMatchChi2)], etl_chi2s.contains(ext_trk.id()) ? etl_chi2s[ext_trk] : -1); + vars.emplace(vars_[int(VarID::etlMatchTimeChi2)], + etl_time_chi2s.contains(ext_trk.id()) ? etl_time_chi2s[ext_trk] : -1); + vars.emplace(vars_[int(VarID::mtdt)], tmtds[ext_trk]); + vars.emplace(vars_[int(VarID::path_len)], trk_lengths[ext_trk]); + return 1. / (1 + sqrt(2 / (1 + mva_->evaluate(vars, false)) - 1)); //return values between 0-1 (probability) + } else + return -1; +} diff --git a/RecoMTD/TrackExtender/plugins/TrackExtenderWithMTD.cc b/RecoMTD/TrackExtender/plugins/TrackExtenderWithMTD.cc index 57db3308f0056..1d44982ca2825 100644 --- a/RecoMTD/TrackExtender/plugins/TrackExtenderWithMTD.cc +++ b/RecoMTD/TrackExtender/plugins/TrackExtenderWithMTD.cc @@ -50,12 +50,164 @@ #include "FWCore/ParameterSet/interface/ConfigurationDescriptions.h" #include "FWCore/ParameterSet/interface/ParameterSetDescription.h" + +#include "DataFormats/Math/interface/GeantUnits.h" +#include "DataFormats/Math/interface/LorentzVector.h" #include "CLHEP/Units/GlobalPhysicalConstants.h" -#include "CLHEP/Units/GlobalSystemOfUnits.h" + +#include "DataFormats/VertexReco/interface/VertexFwd.h" +#include "DataFormats/VertexReco/interface/Vertex.h" using namespace std; using namespace edm; +using namespace reco; + +namespace { + class MTDHitMatchingInfo { + public: + MTDHitMatchingInfo() { + hit = nullptr; + estChi2 = std::numeric_limits::max(); + timeChi2 = std::numeric_limits::max(); + } + + //Operator used to sort the hits while performing the matching step at the MTD + inline bool operator<(const MTDHitMatchingInfo& m2) const { + //only for good matching in time use estChi2, otherwise use mostly time compatibility + constexpr double chi2_cut = 10.; + constexpr double low_weight = 3.; + constexpr double high_weight = 8.; + if (timeChi2 < chi2_cut && m2.timeChi2 < chi2_cut) + return chi2(low_weight) < m2.chi2(low_weight); + else + return chi2(high_weight) < m2.chi2(high_weight); + } + + inline double chi2(double timeWeight = 1.) const { return estChi2 + timeWeight * timeChi2; } + + const MTDTrackingRecHit* hit; + double estChi2; + double timeChi2; + }; + + struct TrackTofPidInfo { + double tmtd; + double tmtderror; + double pathlength; + + double betaerror; + + double dt; + double dterror; + double dtchi2; + + double dt_best; + double dterror_best; + double dtchi2_best; + + double gammasq_pi; + double beta_pi; + double dt_pi; + + double gammasq_k; + double beta_k; + double dt_k; + + double gammasq_p; + double beta_p; + double dt_p; + + double prob_pi; + double prob_k; + double prob_p; + }; + + const TrackTofPidInfo computeTrackTofPidInfo(double magp2, + double length, + double t_mtd, + double t_mtderr, + double t_vtx, + double t_vtx_err, + bool addPIDError = true) { + constexpr double m_pi = 0.13957018; + constexpr double m_pi_inv2 = 1.0 / m_pi / m_pi; + constexpr double m_k = 0.493677; + constexpr double m_k_inv2 = 1.0 / m_k / m_k; + constexpr double m_p = 0.9382720813; + constexpr double m_p_inv2 = 1.0 / m_p / m_p; + constexpr double c_cm_ns = geant_units::operators::convertMmToCm(CLHEP::c_light); // [mm/ns] -> [cm/ns] + constexpr double c_inv = 1.0 / c_cm_ns; + + TrackTofPidInfo tofpid; + + tofpid.tmtd = t_mtd; + tofpid.tmtderror = t_mtderr; + tofpid.pathlength = length; + + tofpid.gammasq_pi = 1. + magp2 * m_pi_inv2; + tofpid.beta_pi = std::sqrt(1. - 1. / tofpid.gammasq_pi); + tofpid.dt_pi = tofpid.pathlength / tofpid.beta_pi * c_inv; + + tofpid.gammasq_k = 1. + magp2 * m_k_inv2; + tofpid.beta_k = std::sqrt(1. - 1. / tofpid.gammasq_k); + tofpid.dt_k = tofpid.pathlength / tofpid.beta_k * c_inv; + + tofpid.gammasq_p = 1. + magp2 * m_p_inv2; + tofpid.beta_p = std::sqrt(1. - 1. / tofpid.gammasq_p); + tofpid.dt_p = tofpid.pathlength / tofpid.beta_p * c_inv; + + tofpid.dt = tofpid.tmtd - tofpid.dt_pi - t_vtx; //assume by default the pi hypothesis + tofpid.dterror = sqrt(tofpid.tmtderror * tofpid.tmtderror + t_vtx_err * t_vtx_err); + tofpid.betaerror = 0; + if (addPIDError) { + tofpid.dterror = + sqrt(tofpid.dterror * tofpid.dterror + (tofpid.dt_p - tofpid.dt_pi) * (tofpid.dt_p - tofpid.dt_pi)); + tofpid.betaerror = tofpid.beta_p - tofpid.beta_pi; + } + + tofpid.dtchi2 = (tofpid.dt * tofpid.dt) / (tofpid.dterror * tofpid.dterror); + + tofpid.dt_best = tofpid.dt; + tofpid.dterror_best = tofpid.dterror; + tofpid.dtchi2_best = tofpid.dtchi2; + + tofpid.prob_pi = -1.; + tofpid.prob_k = -1.; + tofpid.prob_p = -1.; + + if (!addPIDError) { + //*TODO* deal with heavier nucleons and/or BSM case here? + double chi2_pi = tofpid.dtchi2; + double chi2_k = + (tofpid.tmtd - tofpid.dt_k - t_vtx) * (tofpid.tmtd - tofpid.dt_k - t_vtx) / (tofpid.dterror * tofpid.dterror); + double chi2_p = + (tofpid.tmtd - tofpid.dt_p - t_vtx) * (tofpid.tmtd - tofpid.dt_p - t_vtx) / (tofpid.dterror * tofpid.dterror); + + double rawprob_pi = exp(-0.5 * chi2_pi); + double rawprob_k = exp(-0.5 * chi2_k); + double rawprob_p = exp(-0.5 * chi2_p); + double normprob = 1. / (rawprob_pi + rawprob_k + rawprob_p); + + tofpid.prob_pi = rawprob_pi * normprob; + tofpid.prob_k = rawprob_k * normprob; + tofpid.prob_p = rawprob_p * normprob; + + double prob_heavy = 1. - tofpid.prob_pi; + constexpr double heavy_threshold = 0.75; + if (prob_heavy > heavy_threshold) { + if (chi2_k < chi2_p) { + tofpid.dt_best = (tofpid.tmtd - tofpid.dt_k - t_vtx); + tofpid.dtchi2_best = chi2_k; + } else { + tofpid.dt_best = (tofpid.tmtd - tofpid.dt_p - t_vtx); + tofpid.dtchi2_best = chi2_p; + } + } + } + return tofpid; + } +} // namespace template class TrackExtenderWithMTDT : public edm::stream::EDProducer<> { public: @@ -65,23 +217,44 @@ class TrackExtenderWithMTDT : public edm::stream::EDProducer<> { TrackExtenderWithMTDT(const ParameterSet& pset); template - void fillValueMap(edm::Event& iEvent, const H& handle, const std::vector& vec, const std::string& name) const; + void fillValueMap(edm::Event& iEvent, const H& handle, const std::vector& vec, const edm::EDPutToken& token) const; void produce(edm::Event& ev, const edm::EventSetup& es) final; static void fillDescriptions(edm::ConfigurationDescriptions& descriptions); TransientTrackingRecHit::ConstRecHitContainer tryBTLLayers(const TrackType&, + const Trajectory& traj, const MTDTrackingDetSetVector&, const MTDDetLayerGeometry*, const MagneticField* field, - const Propagator* prop) const; + const Propagator* prop, + const reco::BeamSpot& bs, + const double vtxTime, + const bool matchVertex, + MTDHitMatchingInfo& bestHit) const; TransientTrackingRecHit::ConstRecHitContainer tryETLLayers(const TrackType&, + const Trajectory& traj, const MTDTrackingDetSetVector&, const MTDDetLayerGeometry*, const MagneticField* field, - const Propagator* prop) const; + const Propagator* prop, + const reco::BeamSpot& bs, + const double vtxTime, + const bool matchVertex, + MTDHitMatchingInfo& bestHit) const; + + void fillMatchingHits(const DetLayer*, + const TrajectoryStateOnSurface&, + const Trajectory&, + const MTDTrackingDetSetVector&, + const Propagator*, + const reco::BeamSpot&, + const double&, + const bool, + TransientTrackingRecHit::ConstRecHitContainer&, + MTDHitMatchingInfo&) const; RefitDirection::GeometricalDirection checkRecHitsOrdering( TransientTrackingRecHit::ConstRecHitContainer const& recHits) const { @@ -116,20 +289,29 @@ class TrackExtenderWithMTDT : public edm::stream::EDProducer<> { string dumpLayer(const DetLayer* layer) const; private: - static constexpr char pathLengthName[] = "pathLength"; - static constexpr char tmtdName[] = "tmtd"; - static constexpr char sigmatmtdName[] = "sigmatmtd"; - static constexpr char pOrigTrkName[] = "generalTrackp"; - static constexpr char betaOrigTrkName[] = "generalTrackBeta"; - static constexpr char t0OrigTrkName[] = "generalTrackt0"; - static constexpr char sigmat0OrigTrkName[] = "generalTracksigmat0"; - static constexpr char pathLengthOrigTrkName[] = "generalTrackPathLength"; - static constexpr char tmtdOrigTrkName[] = "generalTracktmtd"; - static constexpr char sigmatmtdOrigTrkName[] = "generalTracksigmatmtd"; + edm::EDPutToken btlMatchChi2Token; + edm::EDPutToken etlMatchChi2Token; + edm::EDPutToken btlMatchTimeChi2Token; + edm::EDPutToken etlMatchTimeChi2Token; + edm::EDPutToken pathLengthToken; + edm::EDPutToken tmtdToken; + edm::EDPutToken sigmatmtdToken; + edm::EDPutToken pOrigTrkToken; + edm::EDPutToken betaOrigTrkToken; + edm::EDPutToken t0OrigTrkToken; + edm::EDPutToken sigmat0OrigTrkToken; + edm::EDPutToken pathLengthOrigTrkToken; + edm::EDPutToken tmtdOrigTrkToken; + edm::EDPutToken sigmatmtdOrigTrkToken; + edm::EDPutToken assocOrigTrkToken; edm::EDGetTokenT tracksToken_; edm::EDGetTokenT hitsToken_; edm::EDGetTokenT bsToken_; + edm::EDGetTokenT genVtxPositionToken_; + edm::EDGetTokenT genVtxTimeToken_; + edm::EDGetTokenT vtxToken_; + const bool updateTraj_, updateExtra_, updatePattern_; const std::string mtdRecHitBuilder_, propagator_, transientTrackBuilder_; std::unique_ptr theEstimator; @@ -138,6 +320,18 @@ class TrackExtenderWithMTDT : public edm::stream::EDProducer<> { edm::ESHandle hitbuilder; edm::ESHandle gtg; edm::ESHandle prop; + + const float estMaxChi2_; + const float estMaxNSigma_; + const float btlChi2Cut_; + const float btlTimeChi2Cut_; + const float etlChi2Cut_; + const float etlTimeChi2Cut_; + + const bool useVertex_; + const bool useSimVertex_; + const float dzCut_; + const float bsTimeSpread_; }; template @@ -150,23 +344,43 @@ TrackExtenderWithMTDT::TrackExtenderWithMTDT(const ParameterSet updatePattern_(iConfig.getParameter("updateTrackHitPattern")), mtdRecHitBuilder_(iConfig.getParameter("MTDRecHitBuilder")), propagator_(iConfig.getParameter("Propagator")), - transientTrackBuilder_(iConfig.getParameter("TransientTrackBuilder")) { - constexpr float maxChi2 = 500.; - constexpr float nSigma = 10.; - theEstimator = std::make_unique(maxChi2, nSigma); + transientTrackBuilder_(iConfig.getParameter("TransientTrackBuilder")), + estMaxChi2_(iConfig.getParameter("estimatorMaxChi2")), + estMaxNSigma_(iConfig.getParameter("estimatorMaxNSigma")), + btlChi2Cut_(iConfig.getParameter("btlChi2Cut")), + btlTimeChi2Cut_(iConfig.getParameter("btlTimeChi2Cut")), + etlChi2Cut_(iConfig.getParameter("etlChi2Cut")), + etlTimeChi2Cut_(iConfig.getParameter("etlTimeChi2Cut")), + useVertex_(iConfig.getParameter("useVertex")), + useSimVertex_(iConfig.getParameter("useSimVertex")), + dzCut_(iConfig.getParameter("dZCut")), + bsTimeSpread_(iConfig.getParameter("bsTimeSpread")) { + if (useVertex_) { + if (useSimVertex_) { + genVtxPositionToken_ = consumes(iConfig.getParameter("genVtxPositionSrc")); + genVtxTimeToken_ = consumes(iConfig.getParameter("genVtxTimeSrc")); + } else + vtxToken_ = consumes(iConfig.getParameter("vtxSrc")); + } + theEstimator = std::make_unique(estMaxChi2_, estMaxNSigma_); theTransformer = std::make_unique(iConfig.getParameterSet("TrackTransformer")); - produces>(pathLengthName); - produces>(tmtdName); - produces>(sigmatmtdName); - produces>(pOrigTrkName); - produces>(betaOrigTrkName); - produces>(t0OrigTrkName); - produces>(sigmat0OrigTrkName); - produces>(pathLengthOrigTrkName); - produces>(tmtdOrigTrkName); - produces>(sigmatmtdOrigTrkName); + btlMatchChi2Token = produces>("btlMatchChi2"); + etlMatchChi2Token = produces>("etlMatchChi2"); + btlMatchTimeChi2Token = produces>("btlMatchTimeChi2"); + etlMatchTimeChi2Token = produces>("etlMatchTimeChi2"); + pathLengthToken = produces>("pathLength"); + tmtdToken = produces>("tmtd"); + sigmatmtdToken = produces>("sigmatmtd"); + pOrigTrkToken = produces>("generalTrackp"); + betaOrigTrkToken = produces>("generalTrackBeta"); + t0OrigTrkToken = produces>("generalTrackt0"); + sigmat0OrigTrkToken = produces>("generalTracksigmat0"); + pathLengthOrigTrkToken = produces>("generalTrackPathLength"); + tmtdOrigTrkToken = produces>("generalTracktmtd"); + sigmatmtdOrigTrkToken = produces>("generalTracksigmatmtd"); + assocOrigTrkToken = produces>("generalTrackassoc"); produces>(); produces(); @@ -179,6 +393,9 @@ void TrackExtenderWithMTDT::fillDescriptions(edm::Configuration desc.add("tracksSrc", edm::InputTag("generalTracks")); desc.add("hitsSrc", edm::InputTag("mtdTrackingRecHits")); desc.add("beamSpotSrc", edm::InputTag("offlineBeamSpot")); + desc.add("genVtxPositionSrc", edm::InputTag("genParticles:xyz0")); + desc.add("genVtxTimeSrc", edm::InputTag("genParticles:t0")); + desc.add("vtxSrc", edm::InputTag("offlinePrimaryVertices4D")); desc.add("updateTrackTrajectory", true); desc.add("updateTrackExtra", true); desc.add("updateTrackHitPattern", true); @@ -196,6 +413,16 @@ void TrackExtenderWithMTDT::fillDescriptions(edm::Configuration "MuonRecHitBuilder", "MTDRecHitBuilder"); desc.add("TrackTransformer", transDesc); + desc.add("estimatorMaxChi2", 500.); + desc.add("estimatorMaxNSigma", 10.); + desc.add("btlChi2Cut", 50.); + desc.add("btlTimeChi2Cut", 10.); + desc.add("etlChi2Cut", 50.); + desc.add("etlTimeChi2Cut", 10.); + desc.add("useVertex", false); + desc.add("useSimVertex", false); + desc.add("dZCut", 0.1); + desc.add("bsTimeSpread", 0.2); descriptions.add("trackExtenderWithMTDBase", desc); } @@ -204,12 +431,12 @@ template void TrackExtenderWithMTDT::fillValueMap(edm::Event& iEvent, const H& handle, const std::vector& vec, - const std::string& name) const { + const edm::EDPutToken& token) const { auto out = std::make_unique>(); typename edm::ValueMap::Filler filler(*out); filler.insert(handle, vec.begin(), vec.end()); filler.fill(); - iEvent.put(std::move(out), name); + iEvent.put(token, std::move(out)); } template @@ -244,6 +471,10 @@ void TrackExtenderWithMTDT::produce(edm::Event& ev, const edm:: auto extras = std::make_unique(); auto outhits = std::make_unique>(); + std::vector btlMatchChi2; + std::vector etlMatchChi2; + std::vector btlMatchTimeChi2; + std::vector etlMatchTimeChi2; std::vector pathLengthsRaw; std::vector tmtdRaw; std::vector sigmatmtdRaw; @@ -254,6 +485,7 @@ void TrackExtenderWithMTDT::produce(edm::Event& ev, const edm:: std::vector pathLengthsOrigTrkRaw; std::vector tmtdOrigTrkRaw; std::vector sigmatmtdOrigTrkRaw; + std::vector assocOrigTrkRaw; edm::Handle tracksH; ev.getByToken(tracksToken_, tracksH); @@ -267,21 +499,78 @@ void TrackExtenderWithMTDT::produce(edm::Event& ev, const edm:: ev.getByToken(bsToken_, bsH); const auto& bs = *bsH; + const Vertex* pv = nullptr; + if (useVertex_ && !useSimVertex_) { + edm::Handle vtxH; + ev.getByToken(vtxToken_, vtxH); + if (vtxH.product()->size() > 0) + pv = &(vtxH.product()->at(0)); + } + + std::unique_ptr genPV(nullptr); + if (useVertex_ && useSimVertex_) { + const auto& genVtxPositionHandle = ev.getHandle(genVtxPositionToken_); + const auto& genVtxTimeHandle = ev.getHandle(genVtxTimeToken_); + genPV = std::make_unique( + genVtxPositionHandle->x(), genVtxPositionHandle->y(), genVtxPositionHandle->z(), *(genVtxTimeHandle)); + } + + double vtxTime = 0.; + if (useVertex_) { + if (useSimVertex_ && genPV) { + vtxTime = genPV->t(); + } else if (pv) + vtxTime = pv->t(); //already in ns + } + std::vector track_indices; unsigned itrack = 0; + for (const auto& track : tracks) { + double trackVtxTime = 0.; + if (useVertex_) { + double dz; + if (useSimVertex_) + dz = std::abs(track.dz(math::XYZPoint(*genPV))); + else + dz = std::abs(track.dz(pv->position())); + + if (dz < dzCut_) + trackVtxTime = vtxTime; + } + reco::TransientTrack ttrack(track, magfield.product(), gtg); const auto& trajs = theTransformer->transform(track); auto thits = theTransformer->getTransientRecHits(ttrack); - TransientTrackingRecHit::ConstRecHitContainer mtdthits; - const auto& btlhits = tryBTLLayers(track, hits, geo.product(), magfield.product(), prop.product()); - mtdthits.insert(mtdthits.end(), btlhits.begin(), btlhits.end()); - - // in the future this should include an intermediate refit before propagating to the ETL - // for now it is ok - const auto& etlhits = tryETLLayers(track, hits, geo.product(), magfield.product(), prop.product()); - mtdthits.insert(mtdthits.end(), etlhits.begin(), etlhits.end()); + MTDHitMatchingInfo mBTL, mETL; + if (!trajs.empty()) { + const auto& btlhits = tryBTLLayers(track, + trajs.front(), + hits, + geo.product(), + magfield.product(), + prop.product(), + bs, + trackVtxTime, + trackVtxTime != 0., + mBTL); + mtdthits.insert(mtdthits.end(), btlhits.begin(), btlhits.end()); + + // in the future this should include an intermediate refit before propagating to the ETL + // for now it is ok + const auto& etlhits = tryETLLayers(track, + trajs.front(), + hits, + geo.product(), + magfield.product(), + prop.product(), + bs, + trackVtxTime, + trackVtxTime != 0., + mETL); + mtdthits.insert(mtdthits.end(), etlhits.begin(), etlhits.end()); + } auto ordering = checkRecHitsOrdering(thits); if (ordering == RefitDirection::insideOut) { @@ -291,15 +580,25 @@ void TrackExtenderWithMTDT::produce(edm::Event& ev, const edm:: mtdthits.insert(mtdthits.end(), thits.begin(), thits.end()); thits.swap(mtdthits); } + const auto& trajwithmtd = theTransformer->transform(ttrack, thits); float pMap = 0.f, betaMap = 0.f, t0Map = 0.f, sigmat0Map = -1.f, pathLengthMap = -1.f, tmtdMap = 0.f, sigmatmtdMap = -1.f; + int iMap = -1; for (const auto& trj : trajwithmtd) { const auto& thetrj = (updateTraj_ ? trj : trajs.front()); float pathLength = 0.f, tmtd = 0.f, sigmatmtd = -1.f; - reco::Track result = buildTrack( - track, thetrj, trj, bs, magfield.product(), prop.product(), !mtdthits.empty(), pathLength, tmtd, sigmatmtd); + reco::Track result = buildTrack(track, + thetrj, + trj, + bs, + magfield.product(), + prop.product(), + !trajwithmtd.empty() && !mtdthits.empty(), + pathLength, + tmtd, + sigmatmtd); if (result.ndof() >= 0) { /// setup the track extras reco::TrackExtra::TrajParams trajParams; @@ -316,6 +615,10 @@ void TrackExtenderWithMTDT::produce(edm::Event& ev, const edm:: extras->back().setTrajParams(trajParams, chi2s); //create the track output->push_back(result); + btlMatchChi2.push_back(mBTL.hit ? mBTL.estChi2 : -1); + etlMatchChi2.push_back(mETL.hit ? mETL.estChi2 : -1); + btlMatchTimeChi2.push_back(mBTL.hit ? mBTL.timeChi2 : -1); + etlMatchTimeChi2.push_back(mETL.hit ? mETL.timeChi2 : -1); pathLengthsRaw.push_back(pathLength); tmtdRaw.push_back(tmtd); sigmatmtdRaw.push_back(sigmatmtd); @@ -323,6 +626,7 @@ void TrackExtenderWithMTDT::produce(edm::Event& ev, const edm:: tmtdMap = tmtd; sigmatmtdMap = sigmatmtd; auto& backtrack = output->back(); + iMap = output->size() - 1; pMap = backtrack.p(); betaMap = backtrack.beta(); t0Map = backtrack.t0(); @@ -332,8 +636,11 @@ void TrackExtenderWithMTDT::produce(edm::Event& ev, const edm:: for (unsigned ihit = hitsstart; ihit < hitsend; ++ihit) { backtrack.appendHitPattern((*outhits)[ihit], ttopo); } + } else { + LogTrace("TrackExtenderWithMTD") << "Error in the MTD track refitting. This should not happen"; } } + pOrigTrkRaw.push_back(pMap); betaOrigTrkRaw.push_back(betaMap); t0OrigTrkRaw.push_back(t0Map); @@ -341,6 +648,7 @@ void TrackExtenderWithMTDT::produce(edm::Event& ev, const edm:: pathLengthsOrigTrkRaw.push_back(pathLengthMap); tmtdOrigTrkRaw.push_back(tmtdMap); sigmatmtdOrigTrkRaw.push_back(sigmatmtdMap); + assocOrigTrkRaw.push_back(iMap); ++itrack; } @@ -348,48 +656,155 @@ void TrackExtenderWithMTDT::produce(edm::Event& ev, const edm:: ev.put(std::move(extras)); ev.put(std::move(outhits)); - fillValueMap(ev, outTrksHandle, pathLengthsRaw, pathLengthName); - fillValueMap(ev, outTrksHandle, tmtdRaw, tmtdName); - fillValueMap(ev, outTrksHandle, sigmatmtdRaw, sigmatmtdName); - fillValueMap(ev, tracksH, pOrigTrkRaw, pOrigTrkName); - fillValueMap(ev, tracksH, betaOrigTrkRaw, betaOrigTrkName); - fillValueMap(ev, tracksH, t0OrigTrkRaw, t0OrigTrkName); - fillValueMap(ev, tracksH, sigmat0OrigTrkRaw, sigmat0OrigTrkName); - fillValueMap(ev, tracksH, pathLengthsOrigTrkRaw, pathLengthOrigTrkName); - fillValueMap(ev, tracksH, tmtdOrigTrkRaw, tmtdOrigTrkName); - fillValueMap(ev, tracksH, sigmatmtdOrigTrkRaw, sigmatmtdOrigTrkName); + fillValueMap(ev, outTrksHandle, btlMatchChi2, btlMatchChi2Token); + fillValueMap(ev, outTrksHandle, etlMatchChi2, etlMatchChi2Token); + fillValueMap(ev, outTrksHandle, btlMatchTimeChi2, btlMatchTimeChi2Token); + fillValueMap(ev, outTrksHandle, etlMatchTimeChi2, etlMatchTimeChi2Token); + fillValueMap(ev, outTrksHandle, pathLengthsRaw, pathLengthToken); + fillValueMap(ev, outTrksHandle, tmtdRaw, tmtdToken); + fillValueMap(ev, outTrksHandle, sigmatmtdRaw, sigmatmtdToken); + fillValueMap(ev, tracksH, pOrigTrkRaw, pOrigTrkToken); + fillValueMap(ev, tracksH, betaOrigTrkRaw, betaOrigTrkToken); + fillValueMap(ev, tracksH, t0OrigTrkRaw, t0OrigTrkToken); + fillValueMap(ev, tracksH, sigmat0OrigTrkRaw, sigmat0OrigTrkToken); + fillValueMap(ev, tracksH, pathLengthsOrigTrkRaw, pathLengthOrigTrkToken); + fillValueMap(ev, tracksH, tmtdOrigTrkRaw, tmtdOrigTrkToken); + fillValueMap(ev, tracksH, sigmatmtdOrigTrkRaw, sigmatmtdOrigTrkToken); + fillValueMap(ev, tracksH, assocOrigTrkRaw, assocOrigTrkToken); } namespace { bool cmp_for_detset(const unsigned one, const unsigned two) { return one < two; }; + bool getTrajectoryStateClosestToBeamLine(const Trajectory& traj, + const reco::BeamSpot& bs, + const Propagator* thePropagator, + TrajectoryStateClosestToBeamLine& tscbl) { + // get the state closest to the beamline + TrajectoryStateOnSurface stateForProjectionToBeamLineOnSurface = + traj.closestMeasurement(GlobalPoint(bs.x0(), bs.y0(), bs.z0())).updatedState(); + + if (!stateForProjectionToBeamLineOnSurface.isValid()) { + edm::LogError("CannotPropagateToBeamLine") << "the state on the closest measurement isnot valid. skipping track."; + return false; + } + + const FreeTrajectoryState& stateForProjectionToBeamLine = *stateForProjectionToBeamLineOnSurface.freeState(); + + TSCBLBuilderWithPropagator tscblBuilder(*thePropagator); + tscbl = tscblBuilder(stateForProjectionToBeamLine, bs); + + return tscbl.isValid(); + } + + bool trackPathLength(const Trajectory& traj, + const reco::BeamSpot& bs, + const Propagator* thePropagator, + double& pathlength) { + pathlength = 0.; + + TrajectoryStateClosestToBeamLine tscbl; + bool tscbl_status = getTrajectoryStateClosestToBeamLine(traj, bs, thePropagator, tscbl); + + if (!tscbl_status) + return false; + + bool validpropagation = true; + double pathlength1 = 0.; + double pathlength2 = 0.; + + //add pathlength layer by layer + for (auto it = traj.measurements().begin(); it != traj.measurements().end() - 1; ++it) { + const auto& propresult = thePropagator->propagateWithPath(it->updatedState(), (it + 1)->updatedState().surface()); + double layerpathlength = std::abs(propresult.second); + if (layerpathlength == 0.) { + validpropagation = false; + } + pathlength1 += layerpathlength; + } + + //add distance from bs to first measurement + if (traj.direction() == alongMomentum) { + const auto& propresult2 = + thePropagator->propagateWithPath(tscbl.trackStateAtPCA(), traj.firstMeasurement().updatedState().surface()); + pathlength2 = propresult2.second; + if (pathlength2 == 0.) { + validpropagation = false; + } + pathlength = pathlength1 + pathlength2; + } else { + const auto& propresult2 = + thePropagator->propagateWithPath(tscbl.trackStateAtPCA(), traj.lastMeasurement().updatedState().surface()); + pathlength2 = propresult2.second; + if (pathlength2 == 0.) { + validpropagation = false; + } + pathlength = pathlength1 + pathlength2; + } + + return validpropagation; + } + void find_hits_in_dets(const MTDTrackingDetSetVector& hits, + const Trajectory& traj, const DetLayer* layer, const TrajectoryStateOnSurface& tsos, + const double vtxTime, + const reco::BeamSpot& bs, + const float bsTimeSpread, const Propagator* prop, - const MeasurementEstimator& theEstimator, - const TransientTrackingRecHitBuilder& hitbuilder, - TransientTrackingRecHit::ConstRecHitContainer& output) { - pair comp = layer->compatible(tsos, *prop, theEstimator); + const std::unique_ptr& theEstimator, + bool useVtxConstraint, + std::set& out) { + TrajectoryStateClosestToBeamLine tscbl; + bool tscbl_status = getTrajectoryStateClosestToBeamLine(traj, bs, prop, tscbl); + + if (!tscbl_status) + return; + + GlobalVector p = tscbl.trackStateAtPCA().momentum(); + + double pathlength; + trackPathLength(traj, bs, prop, pathlength); + + pair comp = layer->compatible(tsos, *prop, *theEstimator); if (comp.first) { - vector compDets = layer->compatibleDets(tsos, *prop, theEstimator); + vector compDets = layer->compatibleDets(tsos, *prop, *theEstimator); if (!compDets.empty()) { - MTDTrackingRecHit* best = nullptr; - double best_chi2 = std::numeric_limits::max(); for (const auto& detWithState : compDets) { auto range = hits.equal_range(detWithState.first->geographicalId(), cmp_for_detset); for (auto detitr = range.first; detitr != range.second; ++detitr) { for (auto itr = detitr->begin(); itr != detitr->end(); ++itr) { - auto est = theEstimator.estimate(detWithState.second, *itr); - if (est.first && est.second < best_chi2) { // just take the best chi2 - best = &(*itr); - best_chi2 = est.second; - } + auto est = theEstimator->estimate(detWithState.second, *itr); + auto pl = prop->propagateWithPath(tsos, detWithState.second.surface()); + + if (!est.first || std::abs(pl.second) == 0.) + continue; + + double tot_pl = pathlength + std::abs(pl.second); + double t_vtx = useVtxConstraint ? vtxTime : 0.; + + constexpr double vtx_res = 0.008; + double t_vtx_err = useVtxConstraint ? vtx_res : bsTimeSpread; + + constexpr double t_res_manual = 0.035; + + TrackTofPidInfo tof = computeTrackTofPidInfo(p.mag2(), + tot_pl, + itr->time(), + t_res_manual, //put hit error by hand for the moment + t_vtx, + t_vtx_err, //put vtx error by hand for the moment + false); + MTDHitMatchingInfo mi; + mi.hit = &(*itr); + mi.estChi2 = est.second; + mi.timeChi2 = tof.dtchi2_best; //use the chi2 for the best matching hypothesis + + out.insert(mi); } } } - if (best) - output.push_back(hitbuilder.build(best)); } } } @@ -398,47 +813,121 @@ namespace { template TransientTrackingRecHit::ConstRecHitContainer TrackExtenderWithMTDT::tryBTLLayers( const TrackType& track, + const Trajectory& traj, const MTDTrackingDetSetVector& hits, const MTDDetLayerGeometry* geo, const MagneticField* field, - const Propagator* prop) const { - TransientTrackingRecHit::ConstRecHitContainer output; + const Propagator* prop, + const reco::BeamSpot& bs, + const double vtxTime, + const bool matchVertex, + MTDHitMatchingInfo& bestHit) const { const vector& layers = geo->allBTLLayers(); + auto tTrack = builder->build(track); + // get the outermost trajectory point on the track + TrajectoryStateOnSurface tsos = tTrack.outermostMeasurementState(); - for (const DetLayer* ilay : layers) { - // get the outermost trajectory point on the track - TrajectoryStateOnSurface tsos = tTrack.outermostMeasurementState(); - find_hits_in_dets(hits, ilay, tsos, prop, *theEstimator, *hitbuilder, output); - } + TransientTrackingRecHit::ConstRecHitContainer output; + bestHit = MTDHitMatchingInfo(); + for (const DetLayer* ilay : layers) + fillMatchingHits(ilay, tsos, traj, hits, prop, bs, vtxTime, matchVertex, output, bestHit); return output; } template TransientTrackingRecHit::ConstRecHitContainer TrackExtenderWithMTDT::tryETLLayers( const TrackType& track, + const Trajectory& traj, const MTDTrackingDetSetVector& hits, const MTDDetLayerGeometry* geo, const MagneticField* field, - const Propagator* prop) const { - TransientTrackingRecHit::ConstRecHitContainer output; + const Propagator* prop, + const reco::BeamSpot& bs, + const double vtxTime, + const bool matchVertex, + MTDHitMatchingInfo& bestHit) const { const vector& layers = geo->allETLLayers(); auto tTrack = builder->build(track); + // get the outermost trajectory point on the track + TrajectoryStateOnSurface tsos = tTrack.outermostMeasurementState(); + TransientTrackingRecHit::ConstRecHitContainer output; + bestHit = MTDHitMatchingInfo(); for (const DetLayer* ilay : layers) { const BoundDisk& disk = static_cast(ilay)->specificSurface(); const double diskZ = disk.position().z(); - // get the outermost trajectory point on the track - TrajectoryStateOnSurface tsos = tTrack.outermostMeasurementState(); if (tsos.globalPosition().z() * diskZ < 0) continue; // only propagate to the disk that's on the same side - find_hits_in_dets(hits, ilay, tsos, prop, *theEstimator, *hitbuilder, output); + + fillMatchingHits(ilay, tsos, traj, hits, prop, bs, vtxTime, matchVertex, output, bestHit); } return output; } +template +void TrackExtenderWithMTDT::fillMatchingHits(const DetLayer* ilay, + const TrajectoryStateOnSurface& tsos, + const Trajectory& traj, + const MTDTrackingDetSetVector& hits, + const Propagator* prop, + const reco::BeamSpot& bs, + const double& vtxTime, + const bool matchVertex, + TransientTrackingRecHit::ConstRecHitContainer& output, + MTDHitMatchingInfo& bestHit) const { + std::set hitsInLayer; + bool hitMatched = false; + + using namespace std::placeholders; + auto find_hits = std::bind(find_hits_in_dets, + hits, + traj, + ilay, + tsos, + _1, + bs, + bsTimeSpread_, + prop, + std::ref(theEstimator), + _2, + std::ref(hitsInLayer)); + + if (useVertex_ && matchVertex) + find_hits(vtxTime, true); + else + find_hits(0, false); + + //just take the first hit because the hits are sorted on their matching quality + if (!hitsInLayer.empty()) { + //check hits to pass minimum quality matching requirements + if (hitsInLayer.begin()->estChi2 < etlChi2Cut_ && hitsInLayer.begin()->timeChi2 < etlTimeChi2Cut_) { + hitMatched = true; + output.push_back(hitbuilder->build(hitsInLayer.begin()->hit)); + if (*(hitsInLayer.begin()) < bestHit) + bestHit = *(hitsInLayer.begin()); + } + } + + if (useVertex_ && matchVertex && !hitMatched) { + //try a second search with beamspot hypothesis + hitsInLayer.clear(); + find_hits(0, false); + if (!hitsInLayer.empty()) { + if (hitsInLayer.begin()->timeChi2 < etlTimeChi2Cut_) { + if (hitsInLayer.begin()->estChi2 < etlChi2Cut_) { + hitMatched = true; + output.push_back(hitbuilder->build(hitsInLayer.begin()->hit)); + if ((*hitsInLayer.begin()) < bestHit) + bestHit = *(hitsInLayer.begin()); + } + } + } + } +} + //below is unfortunately ripped from other places but //since track producer doesn't know about MTD we have to do this template @@ -452,30 +941,11 @@ reco::Track TrackExtenderWithMTDT::buildTrack(const reco::Track float& pathLengthOut, float& tmtdOut, float& sigmatmtdOut) const { - // get the state closest to the beamline - TrajectoryStateOnSurface stateForProjectionToBeamLineOnSurface = - traj.closestMeasurement(GlobalPoint(bs.x0(), bs.y0(), bs.z0())).updatedState(); - - if - UNLIKELY(!stateForProjectionToBeamLineOnSurface.isValid()) { - edm::LogError("CannotPropagateToBeamLine") << "the state on the closest measurement isnot valid. skipping track."; - return reco::Track(); - } - - constexpr double m_pi = 0.13957018; - constexpr double m_pi_inv2 = 1.0 / m_pi / m_pi; - constexpr double m_p = 0.9382720813; - constexpr double m_p_inv2 = 1.0 / m_p / m_p; - constexpr double c_cm_ns = CLHEP::c_light * CLHEP::ns / CLHEP::cm; //[cm/ns] - constexpr double c_inv = 1.0 / c_cm_ns; - - const FreeTrajectoryState& stateForProjectionToBeamLine = *stateForProjectionToBeamLineOnSurface.freeState(); + TrajectoryStateClosestToBeamLine tscbl; + bool tsbcl_status = getTrajectoryStateClosestToBeamLine(traj, bs, thePropagator, tscbl); - TSCBLBuilderWithPropagator tscblBuilder(*thePropagator); - TrajectoryStateClosestToBeamLine tscbl = tscblBuilder(stateForProjectionToBeamLine, bs); - - if - UNLIKELY(!tscbl.isValid()) { return reco::Track(); } + if (!tsbcl_status) + return reco::Track(); GlobalPoint v = tscbl.trackStateAtPCA().position(); math::XYZPoint pos(v.x(), v.y(), v.z()); @@ -494,83 +964,35 @@ reco::Track TrackExtenderWithMTDT::buildTrack(const reco::Track //compute path length for time backpropagation, using first MTD hit for the momentum if (hasMTD) { - bool validpropagation = true; - double pathlength = 0.; - double pathlength1 = 0.; - double pathlength2 = 0.; - for (auto it = trajWithMtd.measurements().begin(); it != trajWithMtd.measurements().end() - 1; ++it) { - const auto& propresult = thePropagator->propagateWithPath(it->updatedState(), (it + 1)->updatedState().surface()); - double layerpathlength = std::abs(propresult.second); - if (layerpathlength == 0.) { - validpropagation = false; - } - pathlength1 += layerpathlength; - } - + double pathlength; + bool validpropagation = trackPathLength(trajWithMtd, bs, thePropagator, pathlength); double thit = 0.; double thiterror = -1.; bool validmtd = false; - if (trajWithMtd.direction() == alongMomentum) { - for (auto it = trajWithMtd.measurements().begin(); it != trajWithMtd.measurements().end(); ++it) { - bool ismtd = it->recHit()->geographicalId().det() == DetId::Forward && - ForwardSubdetector(it->recHit()->geographicalId().subdetId()) == FastTime; - if (ismtd) { - const auto& propresult2 = thePropagator->propagateWithPath( - tscbl.trackStateAtPCA(), trajWithMtd.firstMeasurement().updatedState().surface()); - pathlength2 = propresult2.second; - if (pathlength2 == 0.) { - validpropagation = false; - } - pathlength = pathlength1 + pathlength2; - const MTDTrackingRecHit* mtdhit = static_cast(it->recHit()->hit()); - thit = mtdhit->time(); - thiterror = mtdhit->timeError(); - validmtd = true; - break; - } - } - } else { - for (auto it = trajWithMtd.measurements().rbegin(); it != trajWithMtd.measurements().rend(); ++it) { - bool ismtd = it->recHit()->geographicalId().det() == DetId::Forward && - ForwardSubdetector(it->recHit()->geographicalId().subdetId()) == FastTime; - if (ismtd) { - const auto& propresult2 = thePropagator->propagateWithPath( - tscbl.trackStateAtPCA(), trajWithMtd.lastMeasurement().updatedState().surface()); - pathlength2 = propresult2.second; - if (pathlength2 == 0.) { - validpropagation = false; - } - pathlength = pathlength1 + pathlength2; - const MTDTrackingRecHit* mtdhit = static_cast(it->recHit()->hit()); - thit = mtdhit->time(); - thiterror = mtdhit->timeError(); - validmtd = true; - break; - } + + //need to better handle the cases with >1 hit in MTD + for (auto const& hit : trajWithMtd.measurements()) { + bool ismtd = hit.recHit()->geographicalId().det() == DetId::Forward && + ForwardSubdetector(hit.recHit()->geographicalId().subdetId()) == FastTime; + if (ismtd) { + const MTDTrackingRecHit* mtdhit = static_cast(hit.recHit()->hit()); + thit = mtdhit->time(); + thiterror = mtdhit->timeError(); + validmtd = true; + break; } } if (validmtd && validpropagation) { - double magp2 = p.mag2(); - - double gammasq_pi = 1. + magp2 * m_pi_inv2; - double beta_pi = std::sqrt(1. - 1. / gammasq_pi); - double dt_pi = pathlength / beta_pi * c_inv; - - double gammasq_p = 1. + magp2 * m_p_inv2; - double beta_p = std::sqrt(1. - 1. / gammasq_p); - double dt_p = pathlength / beta_p * c_inv; - - double dterror = dt_p - dt_pi; - double betaerror = beta_p - beta_pi; - + //here add the PID uncertainty for later use in the 1st step of 4D vtx reconstruction + TrackTofPidInfo tofInfo = computeTrackTofPidInfo(p.mag2(), pathlength, thit, thiterror, 0., 0., true); pathLengthOut = pathlength; // set path length if we've got a timing hit tmtdOut = thit; sigmatmtdOut = thiterror; - t0 = thit - dt_pi; - covt0t0 = thiterror * thiterror + dterror * dterror; - betaOut = beta_pi; - covbetabeta = betaerror * betaerror; + t0 = tofInfo.dt; + covt0t0 = tofInfo.dterror * tofInfo.dterror; + betaOut = tofInfo.beta_pi; + covbetabeta = tofInfo.betaerror * tofInfo.betaerror; } } diff --git a/RecoVertex/Configuration/python/RecoVertex_cff.py b/RecoVertex/Configuration/python/RecoVertex_cff.py index 70ae5d8cc0d11..429d720de76c8 100644 --- a/RecoVertex/Configuration/python/RecoVertex_cff.py +++ b/RecoVertex/Configuration/python/RecoVertex_cff.py @@ -46,6 +46,7 @@ offlinePrimaryVertices4DwithPID , offlinePrimaryVertices4DwithPIDWithBS, tofPID, + tofPID4DnoPID, unsortedOfflinePrimaryVertices4D, trackWithVertexRefSelectorBeforeSorting4D, trackRefsForJetsBeforeSorting4D, @@ -70,6 +71,7 @@ offlinePrimaryVertices4DnoPID , offlinePrimaryVertices4DnoPIDWithBS, tofPID, + tofPID4DnoPID, ) from Configuration.Eras.Modifier_phase2_timing_cff import phase2_timing @@ -82,3 +84,4 @@ phase2_timing_layer.toReplaceWith(offlinePrimaryVertices4DWithBS, offlinePrimaryVertices4DwithPIDWithBS.clone()) phase2_timing_layer.toModify(offlinePrimaryVertices4D, vertices = "unsortedOfflinePrimaryVertices4D", particles = "trackRefsForJetsBeforeSorting4D") phase2_timing_layer.toModify(offlinePrimaryVertices4DWithBS, vertices = "unsortedOfflinePrimaryVertices4D:WithBS", particles = "trackRefsForJetsBeforeSorting4D") + diff --git a/RecoVertex/Configuration/python/RecoVertex_phase2_timing_cff.py b/RecoVertex/Configuration/python/RecoVertex_phase2_timing_cff.py index f84fe747cba37..b39ee5438bf4a 100644 --- a/RecoVertex/Configuration/python/RecoVertex_phase2_timing_cff.py +++ b/RecoVertex/Configuration/python/RecoVertex_phase2_timing_cff.py @@ -31,8 +31,8 @@ trackTimeResoTag="trackExtenderWithMTD:generalTracksigmat0") offlinePrimaryVertices4DnoPIDWithBS=offlinePrimaryVertices4DnoPID.clone(vertices="unsortedOfflinePrimaryVertices4DnoPID:WithBS") -unsortedOfflinePrimaryVertices4DwithPID = unsortedOfflinePrimaryVertices4D.clone(TrackTimesLabel = "tofPID:t0safe", - TrackTimeResosLabel = "tofPID:sigmat0safe", +unsortedOfflinePrimaryVertices4DwithPID = unsortedOfflinePrimaryVertices4D.clone(TrackTimesLabel = "tofPID4DnoPID:t0safe", + TrackTimeResosLabel = "tofPID4DnoPID:sigmat0safe", ) trackWithVertexRefSelectorBeforeSorting4DwithPID = trackWithVertexRefSelector.clone(vertexTag="unsortedOfflinePrimaryVertices4DwithPID", ptMax=9e99, @@ -40,11 +40,18 @@ trackRefsForJetsBeforeSorting4DwithPID = trackRefsForJets.clone(src="trackWithVertexRefSelectorBeforeSorting4DwithPID") offlinePrimaryVertices4DwithPID=offlinePrimaryVertices4D.clone(vertices="unsortedOfflinePrimaryVertices4DwithPID", particles="trackRefsForJetsBeforeSorting4DwithPID", - trackTimeTag="tofPID:t0safe", - trackTimeResoTag="tofPID:sigmat0safe") + trackTimeTag="tofPID4DnoPID:t0safe", + trackTimeResoTag="tofPID4DnoPID:sigmat0safe") offlinePrimaryVertices4DwithPIDWithBS=offlinePrimaryVertices4DwithPID.clone(vertices="unsortedOfflinePrimaryVertices4DwithPID:WithBS") from SimTracker.TrackerHitAssociation.tpClusterProducer_cfi import tpClusterProducer from SimTracker.TrackAssociatorProducers.quickTrackAssociatorByHits_cfi import quickTrackAssociatorByHits from SimTracker.TrackAssociation.trackTimeValueMapProducer_cfi import trackTimeValueMapProducer -from CommonTools.RecoAlgos.tofPID_cfi import tofPID +from RecoMTD.TimingIDTools.tofPIDProducer_cfi import tofPIDProducer + +tofPID4DnoPID=tofPIDProducer.clone(vtxsSrc='unsortedOfflinePrimaryVertices4DnoPID') +tofPID=tofPIDProducer.clone() + +from Configuration.Eras.Modifier_phase2_timing_layer_cff import phase2_timing_layer +phase2_timing_layer.toModify(tofPID, vtxsSrc='unsortedOfflinePrimaryVertices4D') +