diff --git a/CalibPPS/TimingCalibration/interface/TimingCalibrationStruct.h b/CalibPPS/TimingCalibration/interface/TimingCalibrationStruct.h new file mode 100644 index 0000000000000..2d847dcdfe6f4 --- /dev/null +++ b/CalibPPS/TimingCalibration/interface/TimingCalibrationStruct.h @@ -0,0 +1,17 @@ +#ifndef CalibPPS_TimingCalibration_TimingCalibrationStruct_h +#define CalibPPS_TimingCalibration_TimingCalibrationStruct_h + +#include "DQMServices/Core/interface/DQMStore.h" +#include + +struct TimingCalibrationHistograms { +public: + TimingCalibrationHistograms() = default; + + using MonitorMap = std::unordered_map; + + MonitorMap leadingTime, toT; + MonitorMap leadingTimeVsToT; +}; + +#endif diff --git a/CalibPPS/TimingCalibration/plugins/BuildFile.xml b/CalibPPS/TimingCalibration/plugins/BuildFile.xml new file mode 100644 index 0000000000000..b67b7d23683d5 --- /dev/null +++ b/CalibPPS/TimingCalibration/plugins/BuildFile.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/CalibPPS/TimingCalibration/plugins/PPSTimingCalibrationPCLHarvester.cc b/CalibPPS/TimingCalibration/plugins/PPSTimingCalibrationPCLHarvester.cc new file mode 100644 index 0000000000000..9e2a43cdbb3fd --- /dev/null +++ b/CalibPPS/TimingCalibration/plugins/PPSTimingCalibrationPCLHarvester.cc @@ -0,0 +1,160 @@ +/**************************************************************************** + * + * This is a part of PPS offline software. + * Authors: + * Edoardo Bossini + * Piotr Maciej Cwiklicki + * Laurent Forthomme + * + ****************************************************************************/ + +#include "DQMServices/Core/interface/DQMEDHarvester.h" + +#include "FWCore/Framework/interface/Frameworkfwd.h" +#include "FWCore/Framework/interface/MakerMacros.h" +#include "FWCore/Framework/interface/ESHandle.h" +#include "FWCore/Framework/interface/EventSetup.h" +#include "FWCore/ParameterSet/interface/ParameterSet.h" +#include "FWCore/ServiceRegistry/interface/Service.h" + +#include "Geometry/VeryForwardGeometryBuilder/interface/CTPPSGeometry.h" +#include "Geometry/Records/interface/VeryForwardRealGeometryRecord.h" + +#include "CalibPPS/TimingCalibration/interface/TimingCalibrationStruct.h" +#include "CondCore/DBOutputService/interface/PoolDBOutputService.h" + +#include "DataFormats/CTPPSDetId/interface/CTPPSDiamondDetId.h" +#include "CondFormats/PPSObjects/interface/PPSTimingCalibration.h" + +//------------------------------------------------------------------------------ + +class PPSTimingCalibrationPCLHarvester : public DQMEDHarvester { +public: + PPSTimingCalibrationPCLHarvester(const edm::ParameterSet&); + void beginRun(const edm::Run&, const edm::EventSetup&) override; + + static void fillDescriptions(edm::ConfigurationDescriptions&); + +private: + void dqmEndJob(DQMStore::IBooker&, DQMStore::IGetter&) override; + edm::ESGetToken geomEsToken_; + std::vector detids_; + const std::string dqmDir_; + const std::string formula_; + const unsigned int min_entries_; + TF1 interp_; +}; + +//------------------------------------------------------------------------------ + +PPSTimingCalibrationPCLHarvester::PPSTimingCalibrationPCLHarvester(const edm::ParameterSet& iConfig) + : geomEsToken_(esConsumes()), + dqmDir_(iConfig.getParameter("dqmDir")), + formula_(iConfig.getParameter("formula")), + min_entries_(iConfig.getParameter("minEntries")), + interp_("interp", formula_.c_str(), 10.5, 25.) { + // first ensure DB output service is available + edm::Service poolDbService; + if (!poolDbService.isAvailable()) + throw cms::Exception("PPSTimingCalibrationPCLHarvester") << "PoolDBService required"; + + // constrain the min/max fit values + interp_.SetParLimits(1, 9., 15.); + interp_.SetParLimits(2, 0.2, 2.5); +} + +//------------------------------------------------------------------------------ + +void PPSTimingCalibrationPCLHarvester::beginRun(const edm::Run& iRun, const edm::EventSetup& iSetup) { + const auto& geom = iSetup.getData(geomEsToken_); + for (auto it = geom.beginSensor(); it != geom.endSensor(); ++it) { + if (!CTPPSDiamondDetId::check(it->first)) + continue; + const CTPPSDiamondDetId detid(it->first); + if (detid.station() == 1) // for the time being, only compute for this station (run 2 diamond) + detids_.emplace_back(detid); + } +} + +//------------------------------------------------------------------------------ + +void PPSTimingCalibrationPCLHarvester::dqmEndJob(DQMStore::IBooker& iBooker, DQMStore::IGetter& iGetter) { + // book the parameters containers + PPSTimingCalibration::ParametersMap calib_params; + PPSTimingCalibration::TimingMap calib_time; + + iGetter.cd(); + iGetter.setCurrentFolder(dqmDir_); + + // compute the fit parameters for all monitored channels + TimingCalibrationHistograms hists; + std::string ch_name; + for (const auto& detid : detids_) { + detid.channelName(ch_name); + const auto chid = detid.rawId(); + const PPSTimingCalibration::Key key{ + (int)detid.arm(), (int)detid.station(), (int)detid.plane(), (int)detid.channel()}; + hists.leadingTime[chid] = iGetter.get("t_" + ch_name); + if (hists.leadingTime[chid] == nullptr) { + edm::LogInfo("PPSTimingCalibrationPCLHarvester:dqmEndJob") + << "Failed to retrieve leading time monitor for channel (" << detid << ")."; + continue; + } + hists.toT[chid] = iGetter.get("tot_" + ch_name); + if (hists.toT[chid] == nullptr) { + edm::LogInfo("PPSTimingCalibrationPCLHarvester:dqmEndJob") + << "Failed to retrieve time over threshold monitor for channel (" << detid << ")."; + continue; + } + hists.leadingTimeVsToT[chid] = iGetter.get("tvstot_" + ch_name); + if (hists.leadingTimeVsToT[chid] == nullptr) { + edm::LogInfo("PPSTimingCalibrationPCLHarvester:dqmEndJob") + << "Failed to retrieve leading time vs. time over threshold monitor for channel (" << detid << ")."; + continue; + } + if (min_entries_ > 0 && hists.leadingTimeVsToT[chid]->getEntries() < min_entries_) { + edm::LogWarning("PPSTimingCalibrationPCLHarvester:dqmEndJob") + << "Not enough entries for channel (" << detid << "): " << hists.leadingTimeVsToT[chid]->getEntries() << " < " + << min_entries_ << ". Skipping calibration."; + continue; + } + const double upper_tot_range = hists.toT[chid]->getMean() + 2.5; + { // scope for x-profile + std::unique_ptr prof(hists.leadingTimeVsToT[chid]->getTH2D()->ProfileX("_prof_x", 1, -1)); + interp_.SetParameters(hists.leadingTime[chid]->getRMS(), + hists.toT[chid]->getMean(), + 0.8, + hists.leadingTime[chid]->getMean() - hists.leadingTime[chid]->getRMS()); + const auto& res = prof->Fit(&interp_, "B+", "", 10.4, upper_tot_range); + if ((bool)res) { + calib_params[key] = { + interp_.GetParameter(0), interp_.GetParameter(1), interp_.GetParameter(2), interp_.GetParameter(3)}; + calib_time[key] = std::make_pair(0.1, 0.); // hardcoded resolution/offset placeholder for the time being + // can possibly do something with interp_.GetChiSquare() in the near future + } else + edm::LogWarning("PPSTimingCalibrationPCLHarvester:dqmEndJob") + << "Fit did not converge for channel (" << detid << ")."; + } + } + + // fill the DB object record + PPSTimingCalibration calib(formula_, calib_params, calib_time); + + // write the object + edm::Service poolDbService; + poolDbService->writeOne(&calib, poolDbService->currentTime(), "PPSTimingCalibrationRcd"); +} + +//------------------------------------------------------------------------------ + +void PPSTimingCalibrationPCLHarvester::fillDescriptions(edm::ConfigurationDescriptions& descriptions) { + edm::ParameterSetDescription desc; + desc.add("dqmDir", "AlCaReco/PPSTimingCalibrationPCL") + ->setComment("input path for the various DQM plots"); + desc.add("formula", "[0]/(exp((x-[1])/[2])+1)+[3]") + ->setComment("interpolation formula for the time walk component"); + desc.add("minEntries", 100)->setComment("minimal number of hits to extract calibration"); + descriptions.addWithDefaultLabel(desc); +} + +DEFINE_FWK_MODULE(PPSTimingCalibrationPCLHarvester); diff --git a/CalibPPS/TimingCalibration/plugins/PPSTimingCalibrationPCLWorker.cc b/CalibPPS/TimingCalibration/plugins/PPSTimingCalibrationPCLWorker.cc new file mode 100644 index 0000000000000..cc3b74c3a970f --- /dev/null +++ b/CalibPPS/TimingCalibration/plugins/PPSTimingCalibrationPCLWorker.cc @@ -0,0 +1,126 @@ +/**************************************************************************** + * + * This is a part of PPS offline software. + * Authors: + * Edoardo Bossini + * Piotr Maciej Cwiklicki + * Laurent Forthomme + * + ****************************************************************************/ + +#include "DQMServices/Core/interface/DQMGlobalEDAnalyzer.h" +#include "DQMServices/Core/interface/DQMStore.h" + +#include "FWCore/Framework/interface/Frameworkfwd.h" +#include "FWCore/Framework/interface/MakerMacros.h" +#include "FWCore/Framework/interface/Event.h" +#include "FWCore/ParameterSet/interface/ParameterSet.h" + +#include "Geometry/VeryForwardGeometryBuilder/interface/CTPPSGeometry.h" +#include "Geometry/Records/interface/VeryForwardRealGeometryRecord.h" + +#include "DataFormats/Common/interface/DetSetVector.h" +#include "DataFormats/CTPPSDetId/interface/CTPPSDiamondDetId.h" +#include "DataFormats/CTPPSReco/interface/CTPPSDiamondRecHit.h" + +#include "CalibPPS/TimingCalibration/interface/TimingCalibrationStruct.h" + +//------------------------------------------------------------------------------ + +class PPSTimingCalibrationPCLWorker : public DQMGlobalEDAnalyzer { +public: + explicit PPSTimingCalibrationPCLWorker(const edm::ParameterSet&); + + void dqmAnalyze(const edm::Event&, const edm::EventSetup&, const TimingCalibrationHistograms&) const override; + + static void fillDescriptions(edm::ConfigurationDescriptions&); + +private: + void bookHistograms(DQMStore::IBooker&, + const edm::Run&, + const edm::EventSetup&, + TimingCalibrationHistograms&) const override; + + edm::EDGetTokenT> diamondRecHitToken_; + edm::ESGetToken geomEsToken_; + + const std::string dqmDir_; +}; + +//------------------------------------------------------------------------------ + +PPSTimingCalibrationPCLWorker::PPSTimingCalibrationPCLWorker(const edm::ParameterSet& iConfig) + : diamondRecHitToken_( + consumes>(iConfig.getParameter("diamondRecHitTag"))), + geomEsToken_(esConsumes()), + dqmDir_(iConfig.getParameter("dqmDir")) {} + +//------------------------------------------------------------------------------ + +void PPSTimingCalibrationPCLWorker::bookHistograms(DQMStore::IBooker& iBooker, + const edm::Run& iRun, + const edm::EventSetup& iSetup, + TimingCalibrationHistograms& iHists) const { + iBooker.cd(); + iBooker.setCurrentFolder(dqmDir_); + std::string ch_name; + + const auto& geom = iSetup.getData(geomEsToken_); + for (auto it = geom.beginSensor(); it != geom.endSensor(); ++it) { + if (!CTPPSDiamondDetId::check(it->first)) + continue; + const CTPPSDiamondDetId detid(it->first); + if (detid.station() != 1) + continue; + detid.channelName(ch_name); + iHists.leadingTime[detid.rawId()] = iBooker.book1D("t_" + ch_name, ch_name + ";t (ns);Entries", 1200, -60., 60.); + iHists.toT[detid.rawId()] = iBooker.book1D("tot_" + ch_name, ch_name + ";ToT (ns);Entries", 100, -20., 20.); + iHists.leadingTimeVsToT[detid.rawId()] = + iBooker.book2D("tvstot_" + ch_name, ch_name + ";ToT (ns);t (ns)", 240, 0., 60., 450, -20., 25.); + } +} + +//------------------------------------------------------------------------------ + +void PPSTimingCalibrationPCLWorker::dqmAnalyze(const edm::Event& iEvent, + const edm::EventSetup& iSetup, + const TimingCalibrationHistograms& iHists) const { + // then extract the rechits information for later processing + edm::Handle> dsv_rechits; + iEvent.getByToken(diamondRecHitToken_, dsv_rechits); + // ensure timing detectors rechits are found in the event content + if (dsv_rechits->empty()) { + edm::LogWarning("PPSTimingCalibrationPCLWorker:dqmAnalyze") << "No rechits retrieved from the event content."; + return; + } + for (const auto& ds_rechits : *dsv_rechits) { + const CTPPSDiamondDetId detid(ds_rechits.detId()); + if (iHists.leadingTimeVsToT.count(detid.rawId()) == 0) { + edm::LogWarning("PPSTimingCalibrationPCLWorker:dqmAnalyze") + << "Pad with detId=" << detid << " is not set to be monitored."; + continue; + } + for (const auto& rechit : ds_rechits) { + // skip invalid rechits + if (rechit.time() == 0. || rechit.toT() < 0.) + continue; + iHists.leadingTime.at(detid.rawId())->Fill(rechit.time()); + iHists.toT.at(detid.rawId())->Fill(rechit.toT()); + iHists.leadingTimeVsToT.at(detid.rawId())->Fill(rechit.toT(), rechit.time()); + } + } +} + +//------------------------------------------------------------------------------ + +void PPSTimingCalibrationPCLWorker::fillDescriptions(edm::ConfigurationDescriptions& descriptions) { + edm::ParameterSetDescription desc; + desc.add("diamondRecHitTag", edm::InputTag("ctppsDiamondUncalibRecHits")) + ->setComment("input tag for the PPS diamond detectors rechits"); + desc.add("dqmDir", "AlCaReco/PPSTimingCalibrationPCL") + ->setComment("output path for the various DQM plots"); + + descriptions.addWithDefaultLabel(desc); +} + +DEFINE_FWK_MODULE(PPSTimingCalibrationPCLWorker); diff --git a/CalibPPS/TimingCalibration/python/ALCARECOPPSCalTrackBasedSel_Output_cff.py b/CalibPPS/TimingCalibration/python/ALCARECOPPSCalTrackBasedSel_Output_cff.py new file mode 100644 index 0000000000000..1415b8c708f01 --- /dev/null +++ b/CalibPPS/TimingCalibration/python/ALCARECOPPSCalTrackBasedSel_Output_cff.py @@ -0,0 +1,15 @@ +import FWCore.ParameterSet.Config as cms + +OutALCARECOPPSCalTrackBasedSel_noDrop = cms.PSet( + SelectEvents = cms.untracked.PSet( + SelectEvents = cms.vstring('pathALCARECOPPSCalTrackBasedSel') + ), + outputCommands = cms.untracked.vstring( + 'keep *_ALCARECOPPSCalTrackBasedSel_*_*', + 'keep *_ctppsDiamondRawToDigi_*_*' + # will be updated to add the spatial alignment required collections + ) +) + +OutALCARECOPPSCalTrackBasedSel = OutALCARECOPPSCalTrackBasedSel_noDrop.clone() +OutALCARECOPPSCalTrackBasedSel.outputCommands.insert(0, 'drop *') diff --git a/CalibPPS/TimingCalibration/python/ALCARECOPPSCalTrackBasedSel_cff.py b/CalibPPS/TimingCalibration/python/ALCARECOPPSCalTrackBasedSel_cff.py new file mode 100644 index 0000000000000..27ad42bb7d8db --- /dev/null +++ b/CalibPPS/TimingCalibration/python/ALCARECOPPSCalTrackBasedSel_cff.py @@ -0,0 +1,48 @@ +import FWCore.ParameterSet.Config as cms + +# define the HLT base path +from HLTrigger.HLTfilters.hltHighLevel_cfi import hltHighLevel as _hlt +ALCARECOPPSCalTrackBasedSelHLT = _hlt.clone( + andOr = True, + HLTPaths = ['HLT_ZeroBias_v*'], + #eventSetupPathKey = 'SiStripCalZeroBias', # in case we have a proper base key + throw = False +) + +# perform basic PPS reconstruction +from EventFilter.CTPPSRawToDigi.ctppsRawToDigi_cff import * +from RecoPPS.Configuration.recoCTPPS_cff import * + +# select events passing the filter on pixel tracks +from HLTrigger.special.hltPPSPerPotTrackFilter_cfi import hltPPSPerPotTrackFilter as _filter +hltPPSPerPotTrackFilter = _filter.clone( + pixelFilter = cms.VPSet( + cms.PSet( # sector 45, near pot + detid = cms.uint32(2022703104), + minTracks = cms.int32(1), + maxTracks = cms.int32(6), + ), + cms.PSet( # sector 45, far pot + detid = cms.uint32(2023227392), + minTracks = cms.int32(1), + maxTracks = cms.int32(6), + ), + cms.PSet( # sector 56, near pot + detid = cms.uint32(2039480320), + minTracks = cms.int32(1), + maxTracks = cms.int32(6), + ), + cms.PSet( # sector 56, far pot + detid = cms.uint32(2040004608), + minTracks = cms.int32(1), + maxTracks = cms.int32(6), + ), + ) +) + +seqALCARECOPPSCalTrackBasedSel = cms.Sequence( + ctppsRawToDigi * + recoCTPPS * + ALCARECOPPSCalTrackBasedSelHLT * + hltPPSPerPotTrackFilter +) diff --git a/CalibPPS/TimingCalibration/python/ALCARECOPPSTimingCalib_Output_cff.py b/CalibPPS/TimingCalibration/python/ALCARECOPPSTimingCalib_Output_cff.py new file mode 100644 index 0000000000000..149971c7e47c4 --- /dev/null +++ b/CalibPPS/TimingCalibration/python/ALCARECOPPSTimingCalib_Output_cff.py @@ -0,0 +1,13 @@ +import FWCore.ParameterSet.Config as cms + +OutALCARECOPPSTimingCalib_noDrop = cms.PSet( + SelectEvents = cms.untracked.PSet( + SelectEvents = cms.vstring('pathALCARECOPPSTimingCalib') + ), + outputCommands = cms.untracked.vstring( + 'keep *_MEtoEDMConvertPPSTimingCalib_*_*', + ) +) + +OutALCARECOPPSTimingCalib = OutALCARECOPPSTimingCalib_noDrop.clone() +OutALCARECOPPSTimingCalib.outputCommands.insert(0, 'drop *') diff --git a/CalibPPS/TimingCalibration/python/ALCARECOPPSTimingCalib_cff.py b/CalibPPS/TimingCalibration/python/ALCARECOPPSTimingCalib_cff.py new file mode 100644 index 0000000000000..45ec0ab492e4c --- /dev/null +++ b/CalibPPS/TimingCalibration/python/ALCARECOPPSTimingCalib_cff.py @@ -0,0 +1,28 @@ +import FWCore.ParameterSet.Config as cms + +from RecoPPS.Configuration.recoCTPPS_cff import ctppsDiamondRecHits as _ctppsDiamondRecHits +from CalibPPS.TimingCalibration.ppsTimingCalibrationPCLWorker_cfi import ppsTimingCalibrationPCLWorker + +MEtoEDMConvertPPSTimingCalib = cms.EDProducer('MEtoEDMConverter', + Name = cms.untracked.string('MEtoEDMConverter'), + Verbosity = cms.untracked.int32(0), + Frequency = cms.untracked.int32(50), + MEPathToSave = cms.untracked.string('AlCaReco/PPSTimingCalibrationPCL'), + deleteAfterCopy = cms.untracked.bool(True), +) + +# calibrated rechits/tracks +ctppsDiamondUncalibRecHits = _ctppsDiamondRecHits.clone( + applyCalibration = False +) +# this task will be updated to include tracking based on the last +# calibration values to extract per-channel timing precision estimation +recoDiamondUncalibLocalReconstructionTask = cms.Task( + ctppsDiamondUncalibRecHits, +) + +taskALCARECOPPSTimingCalib = cms.Task( + recoDiamondUncalibLocalReconstructionTask, + ppsTimingCalibrationPCLWorker, + MEtoEDMConvertPPSTimingCalib +) diff --git a/CalibPPS/TimingCalibration/python/PPSTimingCalibrationHarvester_cff.py b/CalibPPS/TimingCalibration/python/PPSTimingCalibrationHarvester_cff.py new file mode 100644 index 0000000000000..5fcabfa63217e --- /dev/null +++ b/CalibPPS/TimingCalibration/python/PPSTimingCalibrationHarvester_cff.py @@ -0,0 +1,4 @@ +import FWCore.ParameterSet.Config as cms + +from Geometry.VeryForwardGeometry.geometryRPFromDB_cfi import * +from CalibPPS.TimingCalibration.ppsTimingCalibrationPCLHarvester_cfi import * diff --git a/Configuration/AlCa/python/autoPCL.py b/Configuration/AlCa/python/autoPCL.py index d5fdbdfe42f9f..e2825741730a0 100644 --- a/Configuration/AlCa/python/autoPCL.py +++ b/Configuration/AlCa/python/autoPCL.py @@ -7,5 +7,6 @@ 'PromptCalibProdEcalPedestals': 'EcalPedestals', 'PromptCalibProdSiStripGainsAAG' : 'SiStripGainsAAG', 'PromptCalibProdLumiPCC': 'LumiPCC', - 'PromptCalibProdSiPixel' : 'SiPixelQuality' + 'PromptCalibProdSiPixel' : 'SiPixelQuality', + 'PromptCalibProdPPS' : 'PPSTimingCalibration' } diff --git a/Configuration/EventContent/python/AlCaRecoOutput_cff.py b/Configuration/EventContent/python/AlCaRecoOutput_cff.py index f9e64e4508cae..9543fc6261692 100644 --- a/Configuration/EventContent/python/AlCaRecoOutput_cff.py +++ b/Configuration/EventContent/python/AlCaRecoOutput_cff.py @@ -47,7 +47,7 @@ from Calibration.TkAlCaRecoProducers.ALCARECOSiStripCalZeroBias_Output_cff import * # AlCaReco for SiPixel Bad Component using ZeroBias events from CalibTracker.SiPixelQuality.ALCARECOSiPixelCalZeroBias_Output_cff import * -# AlCaReco for tracker calibration using Cosmics events +# AlCaReco for tracker calibration using Cosmics events from Calibration.TkAlCaRecoProducers.ALCARECOSiStripCalCosmics_Output_cff import * from Calibration.TkAlCaRecoProducers.ALCARECOSiPixelCalCosmics_Output_cff import * @@ -134,6 +134,12 @@ from CalibMuon.DTCalibration.ALCARECODtCalibHI_Output_cff import * from CalibMuon.DTCalibration.ALCARECODtCalibCosmics_Output_cff import * +############################################################### +# PPS calibration +############################################################### +from CalibPPS.TimingCalibration.ALCARECOPPSCalTrackBasedSel_Output_cff import * +from CalibPPS.TimingCalibration.ALCARECOPPSTimingCalib_Output_cff import * + ############################################################### # stream for prompt-calibration @ Tier0 ############################################################### diff --git a/Configuration/PyReleaseValidation/python/relval_production.py b/Configuration/PyReleaseValidation/python/relval_production.py index fb193b7855ac9..a7bbc199faf7d 100644 --- a/Configuration/PyReleaseValidation/python/relval_production.py +++ b/Configuration/PyReleaseValidation/python/relval_production.py @@ -25,6 +25,7 @@ workflows[1040] = ['',['RunZeroBias2017F','TIER0RAWSIPIXELCAL','ALCASPLITSIPIXELCAL','ALCAHARVDSIPIXELCAL']] workflows[1040.1] = ['',['RunExpressPhy2017F','TIER0EXPSIPIXELCAL','ALCASPLITSIPIXELCAL','ALCAHARVDSIPIXELCAL']] +workflows[1041] = ['',['RunExpressPhy2017F','TIER0EXPPPSCAL','ALCASPLITPPSCAL','ALCAHARVDPPSCAL']] ## MC production test #workflows[1100] = [ '',[]] diff --git a/Configuration/PyReleaseValidation/python/relval_steps.py b/Configuration/PyReleaseValidation/python/relval_steps.py index 97235248c83b6..ecf3314da7c5f 100644 --- a/Configuration/PyReleaseValidation/python/relval_steps.py +++ b/Configuration/PyReleaseValidation/python/relval_steps.py @@ -710,7 +710,7 @@ def identitySim(wf): # FIXME: replace with AODSIM (more appropriate) steps['TTbar_13_reminiaod2017UL_INPUT']={'INPUT':InputInfo(dataSet='/RelValTTbar_13/CMSSW_10_6_4-PUpmx25ns_106X_mc2017_realistic_v6_rsb-v1/GEN-SIM-RECO',label='rmaod',location='STD')} steps['TTbar_13_reminiaod2018UL_INPUT']={'INPUT':InputInfo(dataSet='/RelValProdTTbar_13_pmx25ns/CMSSW_10_6_4-PUpmx25ns_106X_upgrade2018_realistic_v9-v1/AODSIM',label='rmaod',location='STD')} -# INPUT command for reminiAOD wfs on PbPb relval inputs +# INPUT command for reminiAOD wfs on PbPb relval inputs steps['HydjetQ_reminiaodPbPb2018_INPUT']={'INPUT':InputInfo(dataSet='/RelValHydjetQ_B12_5020GeV_2018_ppReco/CMSSW_10_3_3-PU_103X_upgrade2018_realistic_HI_v11-v1/GEN-SIM-RECO',label='rmaod',location='STD')} #input for a NANOAOD from MINIAOD workflow @@ -2068,6 +2068,16 @@ def lhegensim2018ml(fragment,howMuch): '--eventcontent':'ALCARECO', } +steps['TIER0EXPPPSCAL']={'-s':'RAW2DIGI,L1Reco,ALCAPRODUCER:PPSCalTrackBasedSel,ENDJOB', + '--process':'ALCARECO', + '--scenario': 'pp', + '--era':'Run2_2017', + '--conditions':'auto:run2_data', + '--data': '', + '--datatier':'ALCARECO', + '--eventcontent':'ALCARECO', + } + steps['ALCASPLITHPBS']={'-s':'ALCAOUTPUT:TkAlMinBias,ALCA:PromptCalibProdBeamSpotHP+PromptCalibProdBeamSpotHPLowPU', '--scenario':'pp', '--data':'', @@ -2089,6 +2099,16 @@ def lhegensim2018ml(fragment,howMuch): #'--filein':'file:step2.root' } +steps['ALCASPLITPPSCAL']={'-s':'ALCAOUTPUT:PPSCalTrackBasedSel,ALCA:PPSTimingCalib', + '--scenario':'pp', + '--data':'', + '--era':'Run2_2017', + '--datatier':'ALCARECO', + '--eventcontent':'ALCARECO', + '--conditions':'auto:run2_data', + '--triggerResultsProcess':'RECO', + } + steps['ALCAHARVDHPBS']={'-s':'ALCAHARVEST:%s'%(autoPCL['PromptCalibProdBeamSpotHP']), #'--conditions':'auto:run2_data_promptlike', '--conditions':'auto:run3_data_express', # to replaced with line above once run2_data_promptlike will contain DropBoxMetadata @@ -2121,6 +2141,13 @@ def lhegensim2018ml(fragment,howMuch): '--data':'', '--filein':'file:PromptCalibProdSiPixel.root'} +steps['ALCAHARVDPPSCAL']={'-s':'ALCAHARVEST:%s'%(autoPCL['PromptCalibProdPPS']), + '--conditions':'auto:run3_data_express', + '--scenario':'pp', + '--data':'', + '--era':'Run2_2017', + '--filein':'file:PPSTimingCalib.root'} + steps['RECOCOSD']=merge([{'--scenario':'cosmics', '-s':'RAW2DIGI,L1Reco,RECO,DQM', '--datatier':'RECO,DQMIO', # no miniAOD for cosmics diff --git a/Configuration/StandardSequences/python/AlCaHarvesting_cff.py b/Configuration/StandardSequences/python/AlCaHarvesting_cff.py index c35d814d4948d..41604bb588ed0 100644 --- a/Configuration/StandardSequences/python/AlCaHarvesting_cff.py +++ b/Configuration/StandardSequences/python/AlCaHarvesting_cff.py @@ -10,6 +10,7 @@ from Calibration.LumiAlCaRecoProducers.AlcaLumiPCCHarvester_cff import * from CalibTracker.SiPixelQuality.SiPixelStatusHarvester_cfi import * from CalibTracker.SiPixelQuality.DQMEventInfoSiPixelQuality_cff import * +from CalibPPS.TimingCalibration.PPSTimingCalibrationHarvester_cff import * from Calibration.TkAlCaRecoProducers.PCLMetadataWriter_cfi import * @@ -213,6 +214,15 @@ ) ALCAHARVESTSiPixelQuality_dbOutput.extend(dbOutput_ext) +# -------------------------------------------------------------------------------------- +# PPS calibration +ALCAHARVESTPPSTimingCalibration = ppsTimingCalibrationPCLHarvester.clone() +ALCAHARVESTPPSTimingCalibration_metadata = cms.PSet(record = cms.untracked.string('PPSTimingCalibrationRcd')) +ALCAHARVESTPPSTimingCalibration_dbOutput = cms.PSet(record = cms.string('PPSTimingCalibrationRcd'), + tag = cms.string('PPSDiamondTimingCalibration_pcl'), + timetype = cms.untracked.string('lumiid') + ) + # define all the paths BeamSpotByRun = cms.Path(ALCAHARVESTBeamSpotByRun) BeamSpotByLumi = cms.Path(ALCAHARVESTBeamSpotByLumi) @@ -227,6 +237,7 @@ SiStripGainsAAG = cms.Path(ALCAHARVESTSiStripGainsAAG) LumiPCC = cms.Path(ALCAHARVESTLumiPCC) SiPixelQuality = cms.Path(dqmEnvSiPixelQuality+ALCAHARVESTSiPixelQuality)#+siPixelPhase1DQMHarvester) +PPSTimingCalibration = cms.Path(ALCAHARVESTPPSTimingCalibration) ALCAHARVESTDQMSaveAndMetadataWriter = cms.Path(dqmSaver+pclMetadataWriter) diff --git a/Configuration/StandardSequences/python/AlCaRecoStreams_cff.py b/Configuration/StandardSequences/python/AlCaRecoStreams_cff.py index 00806b7280dda..c33eed099c55f 100644 --- a/Configuration/StandardSequences/python/AlCaRecoStreams_cff.py +++ b/Configuration/StandardSequences/python/AlCaRecoStreams_cff.py @@ -45,7 +45,7 @@ from Calibration.TkAlCaRecoProducers.ALCARECOSiStripCalZeroBias_cff import * # AlCaReco for SiPixel Bad Components using ZeroBias events in ExpressPhysics stream from CalibTracker.SiPixelQuality.ALCARECOSiPixelCalZeroBias_cff import * -# AlCaReco for tracker calibration using Cosmics events +# AlCaReco for tracker calibration using Cosmics events from Calibration.TkAlCaRecoProducers.ALCARECOSiStripCalCosmics_cff import * ############################################################### @@ -117,6 +117,12 @@ ############################################################### from CalibMuon.RPCCalibration.ALCARECORpcCalHLT_cff import * +############################################################### +# PPS calibration +############################################################### +# Timing calibration +from CalibPPS.TimingCalibration.ALCARECOPPSCalTrackBasedSel_cff import * +from CalibPPS.TimingCalibration.ALCARECOPPSTimingCalib_cff import * ############################################################### # nonbeam alcas @@ -178,6 +184,8 @@ pathALCARECOAlCaPCCZeroBiasFromRECO = cms.Path(seqALCARECOAlCaPCCZeroBiasFromRECO) pathALCARECOAlCaPCCRandomFromRECO = cms.Path(seqALCARECOAlCaPCCRandomFromRECO) +pathALCARECOPPSCalTrackBasedSel = cms.Path(seqALCARECOPPSCalTrackBasedSel) + #### ECAL pathALCARECOEcalCalZElectron = cms.Path(seqALCARECOEcalCalZElectron) pathALCARECOEcalCalZSCElectron = cms.Path(seqALCARECOEcalCalZSCElectron) @@ -213,6 +221,7 @@ pathALCARECOMuAlOverlaps = cms.Path(seqALCARECOMuAlOverlaps) pathALCARECOMuAlOverlapsGeneralTracks = cms.Path(seqALCARECOMuAlOverlapsGeneralTracks) pathALCARECORpcCalHLT = cms.Path(seqALCARECORpcCalHLT) +pathALCARECOPPSTimingCalib = cms.Path(taskALCARECOPPSTimingCalib) pathALCARECOTkAlBeamHalo = cms.Path(seqALCARECOTkAlBeamHalo*ALCARECOTkAlBeamHaloDQM) pathALCARECOMuAlBeamHaloOverlaps = cms.Path(seqALCARECOMuAlBeamHaloOverlaps) pathALCARECOMuAlBeamHalo = cms.Path(seqALCARECOMuAlBeamHalo) @@ -441,6 +450,15 @@ dataTier = cms.untracked.string('ALCARECO') ) +ALCARECOStreamPPSCalTrackBasedSel = cms.FilteredStream( + responsible = 'Laurent Forthomme', + name = 'PPSCalTrackBasedSel', + paths = (pathALCARECOPPSCalTrackBasedSel), + content = OutALCARECOPPSCalTrackBasedSel.outputCommands, + selectEvents = OutALCARECOPPSCalTrackBasedSel.SelectEvents, + dataTier = cms.untracked.string('ALCARECO') + ) + ALCARECOStreamEcalCalZElectron = cms.FilteredStream( responsible = 'Shervin Nourbakhsh', name = 'EcalCalZElectron', @@ -773,6 +791,14 @@ dataTier = cms.untracked.string('ALCARECO') ) +ALCARECOStreamPPSTimingCalib = cms.FilteredStream( + responsible = 'Laurent Forthomme', + name = 'PPSTimingCalib', + paths = (pathALCARECOPPSTimingCalib), + content = OutALCARECOPPSTimingCalib.outputCommands, + selectEvents = OutALCARECOPPSTimingCalib.SelectEvents, + dataTier = cms.untracked.string('ALCARECO') + ) ALCARECOStreamPromptCalibProd = cms.FilteredStream( responsible = 'Gianluca Cerminara', diff --git a/HLTrigger/special/plugins/HLTPPSPerPotTrackFilter.cc b/HLTrigger/special/plugins/HLTPPSPerPotTrackFilter.cc new file mode 100644 index 0000000000000..2eef587335a49 --- /dev/null +++ b/HLTrigger/special/plugins/HLTPPSPerPotTrackFilter.cc @@ -0,0 +1,192 @@ +// Laurent Forthomme +// lforthom@cern.ch +// 2020-02-17 +// +// HLT filter module to select events with tracks in the PPS detector +// + +#include "FWCore/Framework/interface/global/EDFilter.h" +#include "FWCore/Framework/interface/Event.h" +#include "FWCore/Framework/interface/EventSetup.h" +#include "FWCore/ParameterSet/interface/ParameterSet.h" +#include "FWCore/ParameterSet/interface/ConfigurationDescriptions.h" +#include "FWCore/MessageLogger/interface/MessageLogger.h" +#include "FWCore/Utilities/interface/InputTag.h" + +#include "DataFormats/Common/interface/Ref.h" +#include "DataFormats/Common/interface/Handle.h" +#include "DataFormats/Common/interface/DetSet.h" +#include "DataFormats/Common/interface/DetSetVector.h" + +#include "DataFormats/HLTReco/interface/TriggerTypeDefs.h" +#include "DataFormats/HLTReco/interface/TriggerFilterObjectWithRefs.h" + +#include "DataFormats/CTPPSDetId/interface/CTPPSPixelDetId.h" + +#include "DataFormats/CTPPSReco/interface/CTPPSPixelLocalTrack.h" // pixel +#include "DataFormats/CTPPSReco/interface/TotemRPLocalTrack.h" // strip +#include "DataFormats/CTPPSReco/interface/CTPPSDiamondLocalTrack.h" // diamond + +#include + +class HLTPPSPerPotTrackFilter : public edm::global::EDFilter<> { +public: + explicit HLTPPSPerPotTrackFilter(const edm::ParameterSet&); + ~HLTPPSPerPotTrackFilter() override = default; + + static void fillDescriptions(edm::ConfigurationDescriptions&); + bool filter(edm::StreamID, edm::Event&, const edm::EventSetup&) const override; + +private: + edm::EDGetTokenT> pixelLocalTrackToken_; + edm::EDGetTokenT> stripLocalTrackToken_; + edm::EDGetTokenT> diamondLocalTrackToken_; + + struct PerPotFilter { + int minTracks; + int maxTracks; + }; + std::unordered_map pixel_filter_; + std::unordered_map strip_filter_; + std::unordered_map diam_filter_; + + // Helper tool to count valid tracks + static constexpr auto valid_trks_ = [](const auto& trk) { return trk.isValid(); }; +}; + +void HLTPPSPerPotTrackFilter::fillDescriptions(edm::ConfigurationDescriptions& descriptions) { + edm::ParameterSetDescription desc; + + desc.add("pixelLocalTrackInputTag", edm::InputTag("ctppsPixelLocalTracks")) + ->setComment("input tag of the pixel local track collection"); + desc.add("stripLocalTrackInputTag", edm::InputTag("totemRPLocalTrackFitter")) + ->setComment("input tag of the strip local track collection"); + desc.add("diamondLocalTrackInputTag", edm::InputTag("ctppsDiamondLocalTracks")) + ->setComment("input tag of the diamond local track collection"); + + edm::ParameterSetDescription filterValid; + filterValid.add("detid", 0)->setComment("station/pot raw DetId"); + filterValid.add("minTracks", -1)->setComment("minimum number of tracks in pot"); + filterValid.add("maxTracks", -1)->setComment("maximum number of tracks in pot"); + + std::vector vPixelDefault; + auto& near_pix45 = vPixelDefault.emplace_back(); + near_pix45.addParameter("detid", CTPPSPixelDetId(0, 2, 2)); // arm-station-rp + near_pix45.addParameter("minTracks", 2); + near_pix45.addParameter("maxTracks", -1); + auto& far_pix45 = vPixelDefault.emplace_back(); + far_pix45.addParameter("detid", CTPPSPixelDetId(0, 2, 3)); // arm-station-rp + far_pix45.addParameter("minTracks", 2); + far_pix45.addParameter("maxTracks", -1); + auto& near_pix56 = vPixelDefault.emplace_back(); + near_pix56.addParameter("detid", CTPPSPixelDetId(1, 2, 2)); // arm-station-rp + near_pix56.addParameter("minTracks", 2); + near_pix56.addParameter("maxTracks", -1); + auto& far_pix56 = vPixelDefault.emplace_back(); + far_pix56.addParameter("detid", CTPPSPixelDetId(1, 2, 3)); // arm-station-rp + far_pix56.addParameter("minTracks", 2); + far_pix56.addParameter("maxTracks", -1); + desc.addVPSet("pixelFilter", filterValid, vPixelDefault); + + std::vector vStripDefault; + desc.addVPSet("stripFilter", filterValid, vStripDefault); + + std::vector vDiamDefault; + desc.addVPSet("diamondFilter", filterValid, vDiamDefault); + + desc.add("triggerType", trigger::TriggerTrack); + + descriptions.add("hltPPSPerPotTrackFilter", desc); +} + +HLTPPSPerPotTrackFilter::HLTPPSPerPotTrackFilter(const edm::ParameterSet& iConfig) { + // First define pixels (2017+) selection + const auto& pixelVPset = iConfig.getParameter>("pixelFilter"); + if (!pixelVPset.empty()) { + pixelLocalTrackToken_ = consumes>( + iConfig.getParameter("pixelLocalTrackInputTag")); + for (const auto& pset : pixelVPset) + pixel_filter_[pset.getParameter("detid")] = + PerPotFilter{pset.getParameter("minTracks"), pset.getParameter("maxTracks")}; + } + // Then define strips (2016-17) selection + const auto& stripVPset = iConfig.getParameter>("stripFilter"); + if (!stripVPset.empty()) { + stripLocalTrackToken_ = + consumes>(iConfig.getParameter("stripLocalTrackInputTag")); + for (const auto& pset : stripVPset) + strip_filter_[pset.getParameter("detid")] = + PerPotFilter{pset.getParameter("minTracks"), pset.getParameter("maxTracks")}; + } + // Finally define diamond (2016+) selection + const auto& diamVPset = iConfig.getParameter>("diamondFilter"); + if (!diamVPset.empty()) { + diamondLocalTrackToken_ = consumes>( + iConfig.getParameter("diamondLocalTrackInputTag")); + for (const auto& pset : diamVPset) + diam_filter_[pset.getParameter("detid")] = + PerPotFilter{pset.getParameter("minTracks"), pset.getParameter("maxTracks")}; + } +} + +bool HLTPPSPerPotTrackFilter::filter(edm::StreamID, edm::Event& iEvent, const edm::EventSetup& iSetup) const { + // First filter on pixels + if (!pixel_filter_.empty()) { + edm::Handle> pixelTracks; + iEvent.getByToken(pixelLocalTrackToken_, pixelTracks); + + for (const auto& rpv : *pixelTracks) { + if (pixel_filter_.count(rpv.id) == 0) + continue; + const auto& fltr = pixel_filter_.at(rpv.id); + + const auto ntrks = std::count_if(rpv.begin(), rpv.end(), valid_trks_); + if (fltr.minTracks > 0 && ntrks < fltr.minTracks) + return false; + if (fltr.maxTracks > 0 && ntrks > fltr.maxTracks) + return false; + } + } + + // Then filter on strips + if (!strip_filter_.empty()) { + edm::Handle> stripTracks; + iEvent.getByToken(stripLocalTrackToken_, stripTracks); + + for (const auto& rpv : *stripTracks) { + if (strip_filter_.count(rpv.id) == 0) + continue; + const auto& fltr = strip_filter_.at(rpv.id); + + const auto ntrks = std::count_if(rpv.begin(), rpv.end(), valid_trks_); + if (fltr.minTracks > 0 && ntrks < fltr.minTracks) + return false; + if (fltr.maxTracks > 0 && ntrks > fltr.maxTracks) + return false; + } + } + + // Finally filter on diamond + if (!diam_filter_.empty()) { + edm::Handle> diamondTracks; + iEvent.getByToken(diamondLocalTrackToken_, diamondTracks); + + for (const auto& rpv : *diamondTracks) { + if (diam_filter_.count(rpv.id) == 0) + continue; + const auto& fltr = diam_filter_.at(rpv.id); + + const auto ntrks = std::count_if(rpv.begin(), rpv.end(), valid_trks_); + if (fltr.minTracks > 0 && ntrks < fltr.minTracks) + return false; + if (fltr.maxTracks > 0 && ntrks > fltr.maxTracks) + return false; + } + } + + return true; +} + +// define as a framework module +#include "FWCore/Framework/interface/MakerMacros.h" +DEFINE_FWK_MODULE(HLTPPSPerPotTrackFilter);