diff --git a/DQM/GEM/interface/GEMDQMEfficiencyCalculator.h b/DQM/GEM/interface/GEMDQMEfficiencyCalculator.h new file mode 100644 index 0000000000000..860a2389f303f --- /dev/null +++ b/DQM/GEM/interface/GEMDQMEfficiencyCalculator.h @@ -0,0 +1,34 @@ +#ifndef DQM_GEM_GEMDQMEfficiencyCalculator_h +#define DQM_GEM_GEMDQMEfficiencyCalculator_h + +/** GEMDQMEfficiencyCalculator + * + * \author Seungjin Yang + */ + +#include "DQMServices/Core/interface/DQMEDHarvester.h" +#include "DQMServices/Core/interface/DQMStore.h" + +#include +#include + +class GEMDQMEfficiencyCalculator { +public: + typedef dqm::harvesting::DQMStore DQMStore; + typedef dqm::harvesting::MonitorElement MonitorElement; + + GEMDQMEfficiencyCalculator(); + ~GEMDQMEfficiencyCalculator(); + + void drawEfficiency(DQMStore::IBooker&, DQMStore::IGetter&, const std::string&); + +private: + TProfile* computeEfficiency(const TH1F*, const TH1F*, const char*, const char*); + TH2F* computeEfficiency(const TH2F*, const TH2F*, const char*, const char*); + + const float kConfidenceLevel_ = 0.683; + const std::string kMatchedSuffix_ = "_matched"; + const std::string kLogCategory_ = "GEMDQMEfficiencyCalculator"; +}; + +#endif // DQM_GEM_GEMDQMEfficiencyCalculator_h diff --git a/DQM/GEM/plugins/GEMEffByGEMCSCSegmentClient.cc b/DQM/GEM/plugins/GEMEffByGEMCSCSegmentClient.cc new file mode 100644 index 0000000000000..68a6a0f0931f8 --- /dev/null +++ b/DQM/GEM/plugins/GEMEffByGEMCSCSegmentClient.cc @@ -0,0 +1,22 @@ +#include "DQM/GEM/plugins/GEMEffByGEMCSCSegmentClient.h" + +GEMEffByGEMCSCSegmentClient::GEMEffByGEMCSCSegmentClient(const edm::ParameterSet& parameter_set) + : kFolder_(parameter_set.getUntrackedParameter("folder")), + kLogCategory_(parameter_set.getUntrackedParameter("logCategory")) { + eff_calculator_ = std::make_unique(); +} + +void GEMEffByGEMCSCSegmentClient::fillDescriptions(edm::ConfigurationDescriptions& descriptions) { + edm::ParameterSetDescription desc; + desc.addUntracked("folder", "GEM/Efficiency/GEMCSCSegment"); + desc.addUntracked("logCategory", "GEMEffByGEMCSCSegmentClient"); + descriptions.addWithDefaultLabel(desc); +} + +void GEMEffByGEMCSCSegmentClient::dqmEndLuminosityBlock(DQMStore::IBooker& booker, + DQMStore::IGetter& getter, + edm::LuminosityBlock const&, + edm::EventSetup const&) { + eff_calculator_->drawEfficiency(booker, getter, kFolder_ + "/Efficiency"); + eff_calculator_->drawEfficiency(booker, getter, kFolder_ + "/Misc"); +} diff --git a/DQM/GEM/plugins/GEMEffByGEMCSCSegmentClient.h b/DQM/GEM/plugins/GEMEffByGEMCSCSegmentClient.h new file mode 100644 index 0000000000000..68deac8ea3b9d --- /dev/null +++ b/DQM/GEM/plugins/GEMEffByGEMCSCSegmentClient.h @@ -0,0 +1,39 @@ +#ifndef DQM_GEM_GEMEffByGEMCSCSegmentClient_h +#define DQM_GEM_GEMEffByGEMCSCSegmentClient_h + +/** \class GEMEffByGEMCSCSegmentClient + * + * `GEMEffByGEMCSCSegmentSource` measures the efficiency of GE11-L1(2) using GE11-L2(1) and ME11 as trigger detectors. + * See https://github.com/cms-sw/cmssw/blob/CMSSW_12_3_0_pre5/RecoLocalMuon/GEMCSCSegment/plugins/GEMCSCSegAlgoRR.cc + * + * \author Seungjin Yang + */ + +#include "DQMServices/Core/interface/DQMEDHarvester.h" +#include "DQMServices/Core/interface/DQMStore.h" +#include "FWCore/ParameterSet/interface/ParameterSet.h" +#include "FWCore/ParameterSet/interface/ConfigurationDescriptions.h" +#include "DQM/GEM/interface/GEMDQMEfficiencyCalculator.h" + +class GEMEffByGEMCSCSegmentClient : public DQMEDHarvester { +public: + GEMEffByGEMCSCSegmentClient(const edm::ParameterSet &); + ~GEMEffByGEMCSCSegmentClient() override{}; + static void fillDescriptions(edm::ConfigurationDescriptions &descriptions); + +protected: + void dqmEndLuminosityBlock(DQMStore::IBooker &, + DQMStore::IGetter &, + edm::LuminosityBlock const &, + edm::EventSetup const &) override; + + void dqmEndJob(DQMStore::IBooker &, DQMStore::IGetter &) override{}; + + // initialized in the constructor initializer list + const std::string kFolder_; + const std::string kLogCategory_; + + std::unique_ptr eff_calculator_; +}; + +#endif // DQM_GEM_GEMEffByGEMCSCSegmentClient_h diff --git a/DQM/GEM/plugins/GEMEffByGEMCSCSegmentSource.cc b/DQM/GEM/plugins/GEMEffByGEMCSCSegmentSource.cc new file mode 100644 index 0000000000000..bf64098d3fc2d --- /dev/null +++ b/DQM/GEM/plugins/GEMEffByGEMCSCSegmentSource.cc @@ -0,0 +1,339 @@ +#include "DQM/GEM/plugins/GEMEffByGEMCSCSegmentSource.h" + +#include "Validation/MuonGEMHits/interface/GEMValidationUtils.h" + +GEMEffByGEMCSCSegmentSource::GEMEffByGEMCSCSegmentSource(const edm::ParameterSet& parameter_set) + : GEMOfflineDQMBase(parameter_set), + kGEMTokenBeginRun_(esConsumes()), + kGEMCSCSegmentToken_( + consumes(parameter_set.getParameter("gemcscSegmentTag"))), + kMuonToken_(consumes(parameter_set.getParameter("muonTag"))), + kUseMuon_(parameter_set.getUntrackedParameter("useMuon")), + kMinCSCRecHits_(parameter_set.getUntrackedParameter("minCSCRecHits")), + kFolder_(parameter_set.getUntrackedParameter("folder")), + kLogCategory_(parameter_set.getUntrackedParameter("logCategory")) {} + +GEMEffByGEMCSCSegmentSource::~GEMEffByGEMCSCSegmentSource() {} + +void GEMEffByGEMCSCSegmentSource::fillDescriptions(edm::ConfigurationDescriptions& descriptions) { + edm::ParameterSetDescription desc; + desc.add("gemcscSegmentTag", edm::InputTag("gemcscSegments")); + desc.add("muonTag", edm::InputTag("muons")); + desc.addUntracked("useMuon", false); + desc.addUntracked("minCSCRecHits", 6u); + desc.addUntracked("folder", "GEM/Efficiency/GEMCSCSegment"); + desc.addUntracked("logCategory", "GEMEffByGEMCSCSegmentSource"); + descriptions.addWithDefaultLabel(desc); +} + +void GEMEffByGEMCSCSegmentSource::bookHistograms(DQMStore::IBooker& ibooker, + edm::Run const&, + edm::EventSetup const& setup) { + const edm::ESHandle& gem = setup.getHandle(kGEMTokenBeginRun_); + if (not gem.isValid()) { + edm::LogError(kLogCategory_) << "invalid GEMGeometry"; + return; + } + + bookEfficiencyChamber(ibooker, gem); + bookMisc(ibooker, gem); +} + +void GEMEffByGEMCSCSegmentSource::bookEfficiencyChamber(DQMStore::IBooker& ibooker, + const edm::ESHandle& gem) { + ibooker.setCurrentFolder(kFolder_ + "/Efficiency"); + + for (const GEMStation* station : gem->stations()) { + const int region_id = station->region(); + const int station_id = station->station(); + + if (station_id == 1) { + // GE11 + const std::vector superchambers = station->superChambers(); + if (not checkRefs(superchambers)) { + edm::LogError(kLogCategory_) << "failed to get a valid vector of GEMSuperChamber ptrs"; + return; + } + + const int num_chambers = superchambers.size(); + for (const GEMChamber* chamber : superchambers.at(0)->chambers()) { + const int layer_id = chamber->id().layer(); + + const TString name_suffix = GEMUtils::getSuffixName(region_id, station_id, layer_id); + const TString title_suffix = GEMUtils::getSuffixTitle(region_id, station_id, layer_id); + const GEMDetId key = getReStLaKey(chamber->id()); + + me_chamber_[key] = ibooker.book1D("chamber" + name_suffix, title_suffix, num_chambers, 0.5, num_chambers + 0.5); + me_chamber_[key]->setAxisTitle("Chamber", 1); + for (int binx = 1; binx <= num_chambers; binx++) { + me_chamber_[key]->setBinLabel(binx, std::to_string(binx), 1); + } + me_chamber_matched_[key] = bookNumerator1D(ibooker, me_chamber_[key]); + + if (kUseMuon_) { + me_muon_chamber_[key] = + ibooker.book1D("muon_chamber" + name_suffix, title_suffix, num_chambers, 0.5, num_chambers + 0.5); + me_muon_chamber_[key]->setAxisTitle("Chamber", 1); + for (int binx = 1; binx <= num_chambers; binx++) { + me_muon_chamber_[key]->setBinLabel(binx, std::to_string(binx), 1); + } + me_muon_chamber_matched_[key] = bookNumerator1D(ibooker, me_muon_chamber_[key]); + } + } // layer + + } else { + LogDebug(kLogCategory_) << "skip " << station->getName(); + continue; + } + } // station +} + +void GEMEffByGEMCSCSegmentSource::bookMisc(DQMStore::IBooker& ibooker, const edm::ESHandle& gem) { + ibooker.setCurrentFolder(kFolder_ + "/Misc"); + + for (const GEMStation* station : gem->stations()) { + const int region_id = station->region(); + const int station_id = station->station(); + + if (station_id == 1) { + // GE11 + const std::vector superchambers = station->superChambers(); + if (not checkRefs(superchambers)) { + edm::LogError(kLogCategory_) << "failed to get a valid vector of GEMSuperChamber ptrs"; + return; + } + + for (const GEMChamber* chamber : superchambers.at(0)->chambers()) { + const int layer_id = chamber->id().layer(); + + const TString name_suffix = GEMUtils::getSuffixName(region_id, station_id, layer_id); + const TString title_suffix = GEMUtils::getSuffixTitle(region_id, station_id, layer_id); + const GEMDetId key = getReStLaKey(chamber->id()); + + // num_csc_hits + me_num_csc_hits_[key] = ibooker.book1D("num_csc_hits" + name_suffix, title_suffix, 4, 2.5, 6.5); + me_num_csc_hits_[key]->setAxisTitle("Number of CSCRecHits", 1); + + me_num_csc_hits_matched_[key] = bookNumerator1D(ibooker, me_num_csc_hits_[key]); + + // reduced_chi2 + me_reduced_chi2_[key] = ibooker.book1D("reduced_chi2" + name_suffix, title_suffix, 30, 0, 3); + me_reduced_chi2_[key]->setAxisTitle("#chi^{2} / dof", 1); + + me_reduced_chi2_matched_[key] = bookNumerator1D(ibooker, me_reduced_chi2_[key]); + + // CSC chamber type + // https://github.com/cms-sw/cmssw/blob/CMSSW_12_3_0_pre5/DataFormats/MuonDetId/interface/CSCDetId.h#L187-L193 + me_csc_chamber_type_[key] = ibooker.book1D("csc_chamber_type" + name_suffix, title_suffix, 10, 0.5, 10.5); + me_csc_chamber_type_[key]->setAxisTitle("CSC chamber type", 1); + for (int chamber_type = 1; chamber_type <= 10; chamber_type++) { + const std::string label = CSCDetId::chamberName(chamber_type); + me_csc_chamber_type_[key]->setBinLabel(chamber_type, label, 1); + } + + me_csc_chamber_type_matched_[key] = bookNumerator1D(ibooker, me_csc_chamber_type_[key]); + + } // layer + + } else { + LogDebug(kLogCategory_) << "skip " << station->getName(); + continue; + } + } // region-station +} + +dqm::impl::MonitorElement* GEMEffByGEMCSCSegmentSource::bookNumerator1D(DQMStore::IBooker& ibooker, + MonitorElement* me) { + const std::string name = me->getName() + "_matched"; + TH1F* hist = dynamic_cast(me->getTH1F()->Clone(name.c_str())); + return ibooker.book1D(name, hist); +} + +void GEMEffByGEMCSCSegmentSource::analyze(const edm::Event& event, const edm::EventSetup& setup) { + ////////////////////////////////////////////////////////////////////////////// + // get data from Event & EventSetup + const GEMCSCSegmentCollection* gemcsc_segment_collection = nullptr; + if (const edm::Handle handle = event.getHandle(kGEMCSCSegmentToken_)) { + gemcsc_segment_collection = handle.product(); + + } else { + edm::LogError(kLogCategory_) << "invalid GEMCSCSegmentCollection"; + return; + } + + const reco::MuonCollection* muon_collection = nullptr; + if (kUseMuon_) { + if (const edm::Handle handle = event.getHandle(kMuonToken_)) { + muon_collection = handle.product(); + + } else { + edm::LogError(kLogCategory_) << "invalid reco::MuonCollection"; + return; + } + } + + ////////////////////////////////////////////////////////////////////////////// + // quick check + if (gemcsc_segment_collection->size() < 1) { + LogDebug(kLogCategory_) << "empty GEMCSCSegment"; + return; + } + + ////////////////////////////////////////////////////////////////////////////// + // + if (kUseMuon_) { + findMatchedME11Segments(muon_collection); + } + + ////////////////////////////////////////////////////////////////////////////// + // main loop + for (edm::OwnVector::const_iterator iter = gemcsc_segment_collection->begin(); + iter != gemcsc_segment_collection->end(); + iter++) { + const GEMCSCSegment& gemcsc_segment = *iter; + + const CSCDetId csc_id = gemcsc_segment.cscDetId(); + if (csc_id.isME11()) { + analyzeME11GE11Segment(gemcsc_segment); + + } else { + LogDebug(kLogCategory_) << "skip " << csc_id; + continue; + } + } // GEMCSCSegment +} + +void GEMEffByGEMCSCSegmentSource::analyzeME11GE11Segment(const GEMCSCSegment& gemcsc_segment) { + const GEMRecHit* ge11_hit_layer1 = nullptr; + const GEMRecHit* ge11_hit_layer2 = nullptr; + + const CSCDetId csc_id = gemcsc_segment.cscDetId(); + for (const GEMRecHit& gem_hit : gemcsc_segment.gemRecHits()) { + const GEMDetId gem_id = gem_hit.gemId(); + + if (not gem_id.isGE11()) { + edm::LogWarning(kLogCategory_) << "CSCSegment is in " << csc_id << " but GEMRecHit is in " << gem_id + << ". skip this GEMCSCSegment." + << "check if RecoLocalMuon/GEMCSCSegment/plugins/GEMCSCSegAlgoRR.cc has changed."; + return; + } + + const int layer = gem_id.layer(); + if (layer == 1) { + ge11_hit_layer1 = &gem_hit; + + } else if (layer == 2) { + ge11_hit_layer2 = &gem_hit; + + } else { + edm::LogError(kLogCategory_) << "isGE11 but got unexpected layer " << gem_id << ". skip this GEMCSCSegment."; + return; + } + } // GEMRecHit + + checkCoincidenceGE11(ge11_hit_layer1, ge11_hit_layer2, gemcsc_segment); + checkCoincidenceGE11(ge11_hit_layer2, ge11_hit_layer1, gemcsc_segment); +} + +void GEMEffByGEMCSCSegmentSource::checkCoincidenceGE11(const GEMRecHit* trigger_layer_hit, + const GEMRecHit* detection_layer_hit, + const GEMCSCSegment& gemcsc_segment) { + if (trigger_layer_hit == nullptr) { + LogDebug(kLogCategory_) << "trigger_layer_hit is nullptr"; + return; + } + + const GEMDetId trigger_layer_id = trigger_layer_hit->gemId(); + const int detection_layer = trigger_layer_id.layer() == 1 ? 2 : 1; + // detection layer key + // GEMDetId(int region, int ring, int station, int layer, int chamber, int ieta) + const GEMDetId key{trigger_layer_id.region(), 1, trigger_layer_id.station(), detection_layer, 0, 0}; + + const int chamber = trigger_layer_id.chamber(); + const bool is_matched = kUseMuon_ ? isME11SegmentMatched(gemcsc_segment.cscSegment()) : false; + + const int num_csc_hits = gemcsc_segment.cscRecHits().size(); + // TODO fillMEWithinLimits + const double reduced_chi2 = std::min(gemcsc_segment.chi2() / gemcsc_segment.degreesOfFreedom(), 2.9999); + const int csc_chamber_type = gemcsc_segment.cscDetId().iChamberType(); + + // TODO add a method + const bool is_good = gemcsc_segment.cscRecHits().size() >= kMinCSCRecHits_; + + fillME(me_num_csc_hits_, key, num_csc_hits); + fillME(me_reduced_chi2_, key, reduced_chi2); + fillME(me_csc_chamber_type_, key, csc_chamber_type); + if (detection_layer_hit) { + fillME(me_num_csc_hits_matched_, key, num_csc_hits); + fillME(me_reduced_chi2_matched_, key, reduced_chi2); + fillME(me_csc_chamber_type_matched_, key, csc_chamber_type); + } + + if (is_good) { + // twofold coincidence rate + fillME(me_chamber_, key, chamber); + if (is_matched) { + fillME(me_muon_chamber_, key, chamber); + } + + // threefold coincidence rate + if (detection_layer_hit) { + fillME(me_chamber_matched_, key, chamber); + if (is_matched) { + fillME(me_muon_chamber_matched_, key, chamber); + } + } + } +} + +void GEMEffByGEMCSCSegmentSource::findMatchedME11Segments(const reco::MuonCollection* muon_collection) { + matched_me11_segment_vector_.clear(); + for (unsigned int idx = 0; idx < muon_collection->size(); idx++) { + const reco::Muon& muon = muon_collection->at(idx); + + for (const reco::MuonChamberMatch& chamber_match : muon.matches()) { + if (chamber_match.detector() != MuonSubdetId::CSC) { + continue; + } + + const CSCDetId csc_id{chamber_match.id}; + if (not csc_id.isME11()) { + continue; + } + + for (const reco::MuonSegmentMatch& segment_match : chamber_match.segmentMatches) { + if (not segment_match.isMask(reco::MuonSegmentMatch::BestInStationByDR)) { + continue; + } + matched_me11_segment_vector_.push_back(segment_match.cscSegmentRef.get()); + } // MuonSegmentMatch + } // MuonChamberMatch + } // MuonCollection +} + +// TODO +bool GEMEffByGEMCSCSegmentSource::isME11SegmentMatched(const CSCSegment& csc_segment) { + bool found = false; + + const CSCDetId csc_id = csc_segment.cscDetId(); + if (not csc_id.isME11()) { + return false; + } + + for (const CSCSegment* matched_segment : matched_me11_segment_vector_) { + if (csc_id != matched_segment->cscDetId()) + continue; + if (csc_segment.localPosition().x() != matched_segment->localPosition().x()) + continue; + if (csc_segment.localPosition().y() != matched_segment->localPosition().y()) + continue; + if (csc_segment.localPosition().z() != matched_segment->localPosition().z()) + continue; + if (csc_segment.time() != matched_segment->time()) + continue; + + found = true; + } + + return found; +} diff --git a/DQM/GEM/plugins/GEMEffByGEMCSCSegmentSource.h b/DQM/GEM/plugins/GEMEffByGEMCSCSegmentSource.h new file mode 100644 index 0000000000000..64ca3d12d4d7c --- /dev/null +++ b/DQM/GEM/plugins/GEMEffByGEMCSCSegmentSource.h @@ -0,0 +1,69 @@ +#ifndef DQM_GEM_GEMEffByGEMCSCSegmentSource_h +#define DQM_GEM_GEMEffByGEMCSCSegmentSource_h + +/** \class GEMEffByGEMCSCSegmentSource + * + * `GEMEffByGEMCSCSegmentSource` measures the efficiency of GE11-L1(2) using GE11-L2(1) and ME11 as trigger detectors. + * See https://github.com/cms-sw/cmssw/blob/CMSSW_12_3_0_pre5/RecoLocalMuon/GEMCSCSegment/plugins/GEMCSCSegAlgoRR.cc + * + * \author Seungjin Yang + */ + +#include "DQM/GEM/interface/GEMOfflineDQMBase.h" + +#include "FWCore/Utilities/interface/EDGetToken.h" +#include "FWCore/Framework/interface/ESHandle.h" +#include "FWCore/ParameterSet/interface/ConfigurationDescriptions.h" + +#include "DataFormats/GEMRecHit/interface/GEMCSCSegmentCollection.h" +#include "DataFormats/MuonReco/interface/Muon.h" +#include "DataFormats/MuonReco/interface/MuonFwd.h" +#include "Geometry/Records/interface/MuonGeometryRecord.h" + +class GEMEffByGEMCSCSegmentSource : public GEMOfflineDQMBase { +public: + explicit GEMEffByGEMCSCSegmentSource(const edm::ParameterSet &); + ~GEMEffByGEMCSCSegmentSource() override; + static void fillDescriptions(edm::ConfigurationDescriptions &); + +private: + void bookHistograms(DQMStore::IBooker &, edm::Run const &, edm::EventSetup const &) override; + void analyze(const edm::Event &event, const edm::EventSetup &eventSetup) override; + + void bookEfficiencyChamber(DQMStore::IBooker &, const edm::ESHandle &); + void bookMisc(DQMStore::IBooker &, const edm::ESHandle &); + MonitorElement *bookNumerator1D(DQMStore::IBooker &, MonitorElement *); + + // ME11-GE11 segments + void analyzeME11GE11Segment(const GEMCSCSegment &); + void checkCoincidenceGE11(const GEMRecHit *, const GEMRecHit *, const GEMCSCSegment &); + void findMatchedME11Segments(const reco::MuonCollection *); + bool isME11SegmentMatched(const CSCSegment &); + + // const member data (mainly parameters) + const edm::ESGetToken kGEMTokenBeginRun_; + const edm::EDGetTokenT kGEMCSCSegmentToken_; + const edm::EDGetTokenT kMuonToken_; + const bool kUseMuon_; + const uint32_t kMinCSCRecHits_; + const std::string kFolder_; + const std::string kLogCategory_; + + // member data + std::vector matched_me11_segment_vector_; + + // MonitorElement + MEMap me_chamber_; // 1D, (region, station, layer) + MEMap me_chamber_matched_; + MEMap me_muon_chamber_; // 1D, (region, station, layer) + MEMap me_muon_chamber_matched_; + // misc + MEMap me_num_csc_hits_; + MEMap me_num_csc_hits_matched_; + MEMap me_reduced_chi2_; + MEMap me_reduced_chi2_matched_; + MEMap me_csc_chamber_type_; + MEMap me_csc_chamber_type_matched_; +}; + +#endif // DQM_GEM_GEMEffByGEMCSCSegmentSource_h diff --git a/DQM/GEM/plugins/SealModule.cc b/DQM/GEM/plugins/SealModule.cc index b8c53a493ffd1..f8d5cfd76c99f 100644 --- a/DQM/GEM/plugins/SealModule.cc +++ b/DQM/GEM/plugins/SealModule.cc @@ -3,6 +3,10 @@ #include "DQM/GEM/plugins/GEMEfficiencyAnalyzer.h" #include "DQM/GEM/plugins/GEMEfficiencyHarvester.h" +#include "DQM/GEM/plugins/GEMEffByGEMCSCSegmentSource.h" +#include "DQM/GEM/plugins/GEMEffByGEMCSCSegmentClient.h" DEFINE_FWK_MODULE(GEMEfficiencyAnalyzer); DEFINE_FWK_MODULE(GEMEfficiencyHarvester); +DEFINE_FWK_MODULE(GEMEffByGEMCSCSegmentSource); +DEFINE_FWK_MODULE(GEMEffByGEMCSCSegmentClient); diff --git a/DQM/GEM/python/gemEffByGEMCSCSegment_cff.py b/DQM/GEM/python/gemEffByGEMCSCSegment_cff.py new file mode 100644 index 0000000000000..83930e7baff96 --- /dev/null +++ b/DQM/GEM/python/gemEffByGEMCSCSegment_cff.py @@ -0,0 +1,9 @@ +import FWCore.ParameterSet.Config as cms + +from DQM.GEM.gemEffByGEMCSCSegmentSource_cfi import * +from DQM.GEM.gemEffByGEMCSCSegmentClient_cfi import * + +gemEffByGEMCSCSegment = cms.Sequence( + gemEffByGEMCSCSegmentSource * + gemEffByGEMCSCSegmentClient +) diff --git a/DQM/GEM/src/GEMDQMEfficiencyCalculator.cc b/DQM/GEM/src/GEMDQMEfficiencyCalculator.cc new file mode 100644 index 0000000000000..173ba8c1abc50 --- /dev/null +++ b/DQM/GEM/src/GEMDQMEfficiencyCalculator.cc @@ -0,0 +1,190 @@ +#include "DQM/GEM/interface/GEMDQMEfficiencyCalculator.h" + +#include "FWCore/MessageLogger/interface/MessageLogger.h" +#include "FWCore/Utilities/interface/isFinite.h" + +#include "TEfficiency.h" + +GEMDQMEfficiencyCalculator::GEMDQMEfficiencyCalculator() {} + +GEMDQMEfficiencyCalculator::~GEMDQMEfficiencyCalculator() {} + +// +TProfile* GEMDQMEfficiencyCalculator::computeEfficiency(const TH1F* passed, + const TH1F* total, + const char* name, + const char* title) { + if (not TEfficiency::CheckConsistency(*passed, *total)) { + edm::LogError(kLogCategory_) << "failed to pass TEfficiency::CheckConsistency. " << name; + return nullptr; + } + + const TAxis* total_x = total->GetXaxis(); + + TProfile* eff_profile = new TProfile(name, title, total_x->GetNbins(), total_x->GetXmin(), total_x->GetXmax()); + eff_profile->GetXaxis()->SetTitle(total_x->GetTitle()); + eff_profile->GetYaxis()->SetTitle("Efficiency"); + + for (int bin = 1; bin <= total->GetNbinsX(); bin++) { + const double num_passed = passed->GetBinContent(bin); + const double num_total = total->GetBinContent(bin); + + if (num_total < 1) { + eff_profile->SetBinEntries(bin, 0); + continue; + } + + const double efficiency = num_passed / num_total; + const double lower_boundary = TEfficiency::ClopperPearson(num_total, num_passed, kConfidenceLevel_, false); + const double upper_boundary = TEfficiency::ClopperPearson(num_total, num_passed, kConfidenceLevel_, true); + const double error = std::max(efficiency - lower_boundary, upper_boundary - efficiency); + // NOTE tprofile + const double profile_error = std::hypot(efficiency, error); + + eff_profile->SetBinContent(bin, efficiency); + eff_profile->SetBinError(bin, profile_error); + eff_profile->SetBinEntries(bin, 1); + } + + return eff_profile; +} + +// +TH2F* GEMDQMEfficiencyCalculator::computeEfficiency(const TH2F* passed, + const TH2F* total, + const char* name, + const char* title) { + if (not TEfficiency::CheckConsistency(*passed, *total)) { + edm::LogError(kLogCategory_) << "failed to pass TEfficiency::CheckConsistency. " << name; + return nullptr; + } + + TEfficiency eff(*passed, *total); + auto eff_hist = dynamic_cast(eff.CreateHistogram()); + eff_hist->SetName(name); + eff_hist->SetTitle(title); + + const TAxis* total_x = total->GetXaxis(); + TAxis* eff_hist_x = eff_hist->GetXaxis(); + eff_hist_x->SetTitle(total_x->GetTitle()); + for (int bin = 1; bin <= total->GetNbinsX(); bin++) { + const char* label = total_x->GetBinLabel(bin); + eff_hist_x->SetBinLabel(bin, label); + } + + const TAxis* total_y = total->GetYaxis(); + TAxis* eff_hist_y = eff_hist->GetYaxis(); + eff_hist_y->SetTitle(total_y->GetTitle()); + for (int bin = 1; bin <= total->GetNbinsY(); bin++) { + const char* label = total_y->GetBinLabel(bin); + eff_hist_y->SetBinLabel(bin, label); + } + + return eff_hist; +} + +void GEMDQMEfficiencyCalculator::drawEfficiency(DQMStore::IBooker& ibooker, + DQMStore::IGetter& igetter, + const std::string& folder) { + ibooker.setCurrentFolder(folder); + igetter.setCurrentFolder(folder); + + std::map > me_pairs; + + for (const std::string& name : igetter.getMEs()) { + const std::string fullpath = folder + "/" + name; + const MonitorElement* me = igetter.get(fullpath); + if (me == nullptr) { + edm::LogError(kLogCategory_) << "failed to get " << fullpath; + continue; + } + + const bool is_matched = name.find(kMatchedSuffix_) != std::string::npos; + + std::string key = name; + if (is_matched) + key.erase(key.find(kMatchedSuffix_), kMatchedSuffix_.length()); + + if (me_pairs.find(key) == me_pairs.end()) { + me_pairs[key] = {nullptr, nullptr}; + } + + if (is_matched) + me_pairs[key].first = me; + else + me_pairs[key].second = me; + } + + for (auto& [key, value] : me_pairs) { + const auto& [me_passed, me_total] = value; + if (me_passed == nullptr) { + LogDebug(kLogCategory_) << "numerator is missing. " << key; + continue; + } + + if (me_total == nullptr) { + LogDebug(kLogCategory_) << "denominator is missing. " << key; + continue; + } + + if (me_passed->kind() != me_total->kind()) { + edm::LogError(kLogCategory_) << "inconsistency between kinds of passed and total" << key; + continue; + } + + const std::string name = "eff_" + me_total->getName(); + const std::string title = me_passed->getTitle(); + + if (me_passed->kind() == MonitorElement::Kind::TH1F) { + TH1F* h_passed = me_passed->getTH1F(); + if (h_passed == nullptr) { + edm::LogError(kLogCategory_) << "failed to get TH1F from passed " << key; + continue; + } + // h_passed->Sumw2(); + + TH1F* h_total = me_total->getTH1F(); + if (h_total == nullptr) { + edm::LogError(kLogCategory_) << "failed to get TH1F from total" << key; + continue; + } + // h_total->Sumw2(); + + TProfile* eff = computeEfficiency(h_passed, h_total, name.c_str(), title.c_str()); + if (eff == nullptr) { + edm::LogError(kLogCategory_) << "failed to compute the efficiency " << key; + continue; + } + + ibooker.bookProfile(name, eff); + + } else if (me_passed->kind() == MonitorElement::Kind::TH2F) { + TH2F* h_passed = me_passed->getTH2F(); + if (h_passed == nullptr) { + edm::LogError(kLogCategory_) << "failed to get TH1F from passed " << key; + continue; + } + // h_passed->Sumw2(); + + TH2F* h_total = me_total->getTH2F(); + if (h_total == nullptr) { + edm::LogError(kLogCategory_) << "failed to get TH1F from total" << key; + continue; + } + // h_total->Sumw2(); + + TH2F* eff = computeEfficiency(h_passed, h_total, name.c_str(), title.c_str()); + if (eff == nullptr) { + edm::LogError(kLogCategory_) << "failed to compute the efficiency " << key; + continue; + } + + ibooker.book2D(name, eff); + + } else { + edm::LogError(kLogCategory_) << "not implemented"; + continue; + } + + } // me_pairs +} diff --git a/DQM/GEM/test/testGEMEffByGEMCSCSegment.py b/DQM/GEM/test/testGEMEffByGEMCSCSegment.py new file mode 100644 index 0000000000000..bfa95ce390a74 --- /dev/null +++ b/DQM/GEM/test/testGEMEffByGEMCSCSegment.py @@ -0,0 +1,77 @@ +import FWCore.ParameterSet.Config as cms + +from Configuration.Eras.Era_Run3_cff import Run3 +process = cms.Process('DQM', Run3) + +process.MessageLogger = cms.Service("MessageLogger", + statistics = cms.untracked.vstring(), + destinations = cms.untracked.vstring('cerr'), + cerr = cms.untracked.PSet( + threshold = cms.untracked.string('WARNING') + ) +) + +process.load("Configuration.StandardSequences.GeometryRecoDB_cff") +from Configuration.AlCa.GlobalTag import GlobalTag +process.GlobalTag = GlobalTag(None, 'auto:phase1_2021_cosmics', '') + +process.load("DQM.Integration.config.environment_cfi") +process.dqmEnv.subSystemFolder = "GEM" +process.dqmEnv.eventInfoFolder = "EventInfo" +process.dqmSaver.path = "" +process.dqmSaver.tag = "GEM" + +from FWCore.ParameterSet.VarParsing import VarParsing +options = VarParsing('analysis') +options.parseArguments() + +process.source = cms.Source("PoolSource", + fileNames = cms.untracked.vstring(options.inputFiles), + inputCommands = cms.untracked.vstring( + 'keep *', + ) +) + +process.maxEvents = cms.untracked.PSet( + input = cms.untracked.int32(options.maxEvents) +) + +process.load("EventFilter.GEMRawToDigi.muonGEMDigis_cfi") +process.load('RecoLocalMuon.GEMRecHit.gemRecHits_cfi') +process.load("Configuration.StandardSequences.RawToDigi_Data_cff") +process.load("Configuration.StandardSequences.Reconstruction_cff") +process.load('RecoLocalMuon.GEMCSCSegment.gemcscSegments_cfi') +process.load("DQM.GEM.gemEffByGEMCSCSegment_cff") + +process.muonGEMDigis.useDBEMap = True +process.muonGEMDigis.keepDAQStatus = True # DEFAULT + + +process.muonCSCDigis.InputObjects = "rawDataCollector" + +#-------------------------------------------------- +print("Running with run type = ", process.runType.getRunType()) +if (process.runType.getRunType() == process.runType.hi_run): + process.muonCSCDigis.InputObjects = "rawDataRepacker" + + +#################################### +process.path = cms.Path( + process.muonGEMDigis * + process.gemRecHits * + process.muonCSCDigis * + process.csc2DRecHits * + process.cscSegments * + process.gemcscSegments * + process.gemEffByGEMCSCSegment +) + +process.end_path = cms.EndPath( + process.dqmEnv + + process.dqmSaver +) + +process.schedule = cms.Schedule( + process.path, + process.end_path +) diff --git a/DQM/Integration/python/clients/gem_dqm_sourceclient-live_cfg.py b/DQM/Integration/python/clients/gem_dqm_sourceclient-live_cfg.py index f520d2b15c8db..47112a25b2cf6 100644 --- a/DQM/Integration/python/clients/gem_dqm_sourceclient-live_cfg.py +++ b/DQM/Integration/python/clients/gem_dqm_sourceclient-live_cfg.py @@ -6,18 +6,18 @@ unitTest = False if 'unitTest=True' in sys.argv: - unitTest=True + unitTest = True process.load('Configuration.StandardSequences.GeometryRecoDB_cff') process.load("DQM.Integration.config.FrontierCondition_GT_cfi") if unitTest: - process.load("DQM.Integration.config.unittestinputsource_cfi") - from DQM.Integration.config.unittestinputsource_cfi import options + process.load("DQM.Integration.config.unittestinputsource_cfi") + from DQM.Integration.config.unittestinputsource_cfi import options else: - process.load("DQM.Integration.config.inputsource_cfi") - from DQM.Integration.config.inputsource_cfi import options - + process.load("DQM.Integration.config.inputsource_cfi") + from DQM.Integration.config.inputsource_cfi import options + process.load("DQM.Integration.config.environment_cfi") process.dqmEnv.subSystemFolder = "GEM" process.dqmSaver.tag = "GEM" @@ -27,36 +27,53 @@ process.load("DQMServices.Components.DQMProvInfo_cfi") -process.load("EventFilter.GEMRawToDigi.muonGEMDigis_cfi") -process.load('RecoLocalMuon.GEMRecHit.gemRecHits_cfi') +process.load("Configuration.StandardSequences.RawToDigi_Data_cff") +process.load("Configuration.StandardSequences.Reconstruction_cff") +process.load('RecoLocalMuon.GEMCSCSegment.gemcscSegments_cfi') process.load("DQM.GEM.GEMDQM_cff") +process.load("DQM.GEM.gemEffByGEMCSCSegment_cff") - +process.muonCSCDigis.InputObjects = "rawDataCollector" if (process.runType.getRunType() == process.runType.hi_run): - process.muonGEMDigis.InputLabel = "rawDataRepacker" + process.muonGEMDigis.InputLabel = "rawDataRepacker" + process.muonCSCDigis.InputObjects = "rawDataRepacker" process.muonGEMDigis.useDBEMap = True process.muonGEMDigis.keepDAQStatus = True +# from csc_dqm_sourceclient-live_cfg.py +process.CSCGeometryESModule.useGangedStripsInME1a = False +process.idealForDigiCSCGeometry.useGangedStripsInME1a = False +process.CSCIndexerESProducer.AlgoName = "CSCIndexerPostls1" +process.CSCChannelMapperESProducer.AlgoName = "CSCChannelMapperPostls1" +process.csc2DRecHits.readBadChambers = False +process.csc2DRecHits.readBadChannels = False +process.csc2DRecHits.CSCUseGasGainCorrections = False + process.path = cms.Path( - process.muonGEMDigis * - process.gemRecHits * - process.GEMDQM + process.muonGEMDigis * + process.gemRecHits * + process.muonCSCDigis * + process.csc2DRecHits * + process.cscSegments * + process.gemcscSegments * + process.GEMDQM * + process.gemEffByGEMCSCSegment ) process.end_path = cms.EndPath( - process.dqmEnv + - process.dqmSaver + - process.dqmSaverPB + process.dqmEnv + + process.dqmSaver + + process.dqmSaverPB ) process.schedule = cms.Schedule( - process.path, - process.end_path + process.path, + process.end_path ) process.dqmProvInfo.runType = process.runType.getRunTypeName() from DQM.Integration.config.online_customizations_cfi import * -print("Final Source settings:", process.source) process = customise(process) +print("Final Source settings:", process.source)