/
githubmirror
/
cmssw
Обзор
Документация
Войти
/
githubmirror
/
cmssw
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
DQMServices/Components/plugins/DQMGenericClient.cc
1 396 строк
50 KB
Gabriel Moreira
refactor: use smart pointer instead of raw pointer
10 дек 2025, 11:23
Не верифицирован
10 дек 2025, 11:23
17086f1
Код
Авторство
О чём код?
/* * Class:DQMGenericClient * * DQM histogram post processor * * * \author Junghwan Goh - SungKyunKwan University */ #include "FWCore/Framework/interface/MakerMacros.h" #include "FWCore/ParameterSet/interface/ParameterSet.h" #include "FWCore/ServiceRegistry/interface/Service.h" #include "FWCore/MessageLogger/interface/MessageLogger.h" #include "DQMServices/Core/interface/DQMEDHarvester.h" #include <TH1.h> #include <TH1F.h> #include <TH2F.h> #include <TClass.h> #include <TString.h> #include <TPRegexp.h> #include <TDirectory.h> #include <TEfficiency.h> #include <set> #include <cmath> #include <string> #include <vector> #include <climits> #include <boost/tokenizer.hpp> using namespace std; using namespace edm; class DQMGenericClient : public DQMEDHarvester { public: DQMGenericClient(const edm::ParameterSet& pset); ~DQMGenericClient() override {} void dqmEndLuminosityBlock(DQMStore::IBooker& ibooker, DQMStore::IGetter& igetter, const edm::LuminosityBlock& lumiSeg, const edm::EventSetup& c) override; void dqmEndRun(DQMStore::IBooker&, DQMStore::IGetter&, edm::Run const&, edm::EventSetup const&) override; void dqmEndJob(DQMStore::IBooker&, DQMStore::IGetter&) override {} enum class EfficType { none = 0, efficiency, fakerate, simpleratio }; enum class ResType { none = 0, fit, rms }; struct EfficOption { std::string name, title; std::string numerator, denominator; EfficType type; bool isProfile; }; struct ResolOption { std::string namePrefix, titlePrefix; std::string srcName; ResType type; bool isProfile; }; struct ProfileOption { std::string name, title; std::string srcName; }; struct NormOption { std::string name, normHistName; }; struct CDOption { std::string name; bool ascending; }; struct NoFlowOption { std::string name; }; void computeEfficiency(DQMStore::IBooker& ibooker, DQMStore::IGetter& igetter, const std::string& startDir, const std::string& efficMEName, const std::string& efficMETitle, const std::string& recoMEName, const std::string& simMEName, const EfficType type = EfficType::efficiency, const bool makeProfile = false); void computeResolution(DQMStore::IBooker& ibooker, DQMStore::IGetter& igetter, const std::string& startDir, const std::string& fitMEPrefix, const std::string& fitMETitlePrefix, const std::string& srcMEName, const ResType type = ResType::fit, const bool makeProfile = false); void computeProfile(DQMStore::IBooker& ibooker, DQMStore::IGetter& igetter, const std::string& startDir, const std::string& profileMEName, const std::string& profileMETitle, const std::string& srcMEName); void normalizeToEntries(DQMStore::IBooker& ibooker, DQMStore::IGetter& igetter, const std::string& startDir, const std::string& histName, const std::string& normHistName); void makeCumulativeDist(DQMStore::IBooker& ibooker, DQMStore::IGetter& igetter, const std::string& startDir, const std::string& cdName, bool ascending = true); void makeNoFlowDist(DQMStore::IBooker& ibooker, DQMStore::IGetter& igetter, const std::string& startDir, const std::string& cdName); void limitedFit(MonitorElement* srcME, MonitorElement* meanME, MonitorElement* sigmaME); private: TPRegexp metacharacters_; TPRegexp nonPerlWildcard_; unsigned int verbose_; bool runOnEndLumi_; bool runOnEndJob_; bool makeGlobalEffPlot_; bool isWildcardUsed_; bool resLimitedFit_; DQMStore* theDQM; std::vector<std::string> subDirs_; std::string outputFileName_; std::vector<EfficOption> efficOptions_; std::vector<ResolOption> resolOptions_; std::vector<ProfileOption> profileOptions_; std::vector<NormOption> normOptions_; std::vector<CDOption> cdOptions_; std::vector<NoFlowOption> noFlowOptions_; void generic_eff(TH1* denom, TH1* numer, MonitorElement* efficiencyHist, const EfficType type = EfficType::efficiency); void findAllSubdirectories(DQMStore::IBooker& ibooker, DQMStore::IGetter& igetter, std::string dir, std::set<std::string>* myList, const TString& pattern); void makeAllPlots(DQMStore::IBooker&, DQMStore::IGetter&); void removeMEIfBooked(const std::string& meName, DQMStore::IGetter& igetter); }; class FitSlicesYTool { public: typedef dqm::harvesting::MonitorElement MonitorElement; FitSlicesYTool(MonitorElement* me) { // ... create your hists TObjArray aSlices; TH2F* h = me->getTH2F(); TF1 fgaus("fgaus", "gaus", h->GetYaxis()->GetXmin(), h->GetYaxis()->GetXmax(), TF1::EAddToList::kNo); h->FitSlicesY(&fgaus, 0, -1, 0, "QNR SERIAL", &aSlices); string name(h->GetName()); h0_ = fetchSlice(aSlices, name + "_0"); h1_ = fetchSlice(aSlices, name + "_1"); h2_ = fetchSlice(aSlices, name + "_2"); h3_ = fetchSlice(aSlices, name + "_chi2"); } /// Fill the ME with the mean value of the gaussian fit in each slice void getFittedMean(MonitorElement* me) { if (!(h1_ && me)) throw cms::Exception("FitSlicesYTool") << "Pointer =0 : h1_=" << h1_ << " me=" << me; if (h1_->GetNbinsX() == me->getNbinsX()) { for (int bin = 0; bin != h1_->GetNbinsX(); bin++) { me->setBinContent(bin + 1, h1_->GetBinContent(bin + 1)); // me->setBinEntries(bin+1, 1.); } } else { throw cms::Exception("FitSlicesYTool") << "Different number of bins!"; } } /// Fill the ME with the sigma value of the gaussian fit in each slice void getFittedSigma(MonitorElement* me) { if (!(h2_ && me)) throw cms::Exception("FitSlicesYTool") << "Pointer =0 : h1_=" << h1_ << " me=" << me; if (h2_->GetNbinsX() == me->getNbinsX()) { for (int bin = 0; bin != h2_->GetNbinsX(); bin++) { me->setBinContent(bin + 1, h2_->GetBinContent(bin + 1)); // me->setBinEntries(bin+1, 1.); } } else { throw cms::Exception("FitSlicesYTool") << "Different number of bins!"; } } /// Fill the ME with the mean value (with error) of the gaussian fit in each slice void getFittedMeanWithError(MonitorElement* me) { if (!(h1_ && me)) throw cms::Exception("FitSlicesYTool") << "Pointer =0 : h1_=" << h1_ << " me=" << me; if (h1_->GetNbinsX() == me->getNbinsX()) { for (int bin = 0; bin != h1_->GetNbinsX(); bin++) { me->setBinContent(bin + 1, h1_->GetBinContent(bin + 1)); me->setBinError(bin + 1, h1_->GetBinError(bin + 1)); if (me->kind() == MonitorElement::Kind::TPROFILE) { me->setBinEntries(bin + 1, 1); } } } else { throw cms::Exception("FitSlicesYTool") << "Different number of bins!"; } } /// Fill the ME with the sigma value (with error) of the gaussian fit in each slice void getFittedSigmaWithError(MonitorElement* me) { if (!(h2_ && me)) throw cms::Exception("FitSlicesYTool") << "Pointer =0 : h1_=" << h1_ << " me=" << me; if (h2_->GetNbinsX() == me->getNbinsX()) { for (int bin = 0; bin != h2_->GetNbinsX(); bin++) { me->setBinContent(bin + 1, h2_->GetBinContent(bin + 1)); me->setBinError(bin + 1, h2_->GetBinError(bin + 1)); if (me->kind() == MonitorElement::Kind::TPROFILE) { me->setBinEntries(bin + 1, 1); } } } else { throw cms::Exception("FitSlicesYTool") << "Different number of bins!"; } } private: std::unique_ptr<TH1> h0_; std::unique_ptr<TH1> h1_; std::unique_ptr<TH1> h2_; std::unique_ptr<TH1> h3_; std::unique_ptr<TH1> fetchSlice(TObjArray& arr, const std::string& name) { auto* obj = (TH1*)arr.FindObject(name.c_str()); if (!obj) { throw cms::Exception("FitSlicesYTool") << "Cannot find slice histogram: " << name; } TH1* hnew = (TH1*)obj->Clone(); hnew->SetDirectory(nullptr); return std::unique_ptr<TH1>(hnew); } }; typedef DQMGenericClient::MonitorElement ME; DQMGenericClient::DQMGenericClient(const ParameterSet& pset) : metacharacters_("[\\^\\$\\.\\*\\+\\?\\|\\(\\)\\{\\}\\[\\]]"), nonPerlWildcard_("\\w\\*|^\\*") { typedef std::vector<edm::ParameterSet> VPSet; typedef std::vector<std::string> vstring; typedef boost::escaped_list_separator<char> elsc; elsc commonEscapes("\\", " \t", "\'"); verbose_ = pset.getUntrackedParameter<unsigned int>("verbose", 0); runOnEndLumi_ = pset.getUntrackedParameter<bool>("runOnEndLumi", false); runOnEndJob_ = pset.getUntrackedParameter<bool>("runOnEndJob", true); makeGlobalEffPlot_ = pset.getUntrackedParameter<bool>("makeGlobalEffienciesPlot", true); // Parse efficiency commands vstring effCmds = pset.getParameter<vstring>("efficiency"); for (vstring::const_iterator effCmd = effCmds.begin(); effCmd != effCmds.end(); ++effCmd) { if (effCmd->empty()) continue; boost::tokenizer<elsc> tokens(*effCmd, commonEscapes); vector<string> args; for (boost::tokenizer<elsc>::const_iterator iToken = tokens.begin(); iToken != tokens.end(); ++iToken) { if (iToken->empty()) continue; args.push_back(*iToken); } if (args.size() < 4) { LogInfo("DQMGenericClient") << "Wrong input to effCmds\n"; continue; } EfficOption opt; opt.name = args[0]; opt.title = args[1]; opt.numerator = args[2]; opt.denominator = args[3]; opt.isProfile = false; const string typeName = args.size() == 4 ? "eff" : args[4]; if (typeName == "eff") opt.type = EfficType::efficiency; else if (typeName == "fake") opt.type = EfficType::fakerate; else if (typeName == "simpleratio") opt.type = EfficType::simpleratio; else opt.type = EfficType::none; efficOptions_.push_back(opt); } VPSet efficSets = pset.getUntrackedParameter<VPSet>("efficiencySets", VPSet()); for (VPSet::const_iterator efficSet = efficSets.begin(); efficSet != efficSets.end(); ++efficSet) { EfficOption opt; opt.name = efficSet->getUntrackedParameter<string>("name"); opt.title = efficSet->getUntrackedParameter<string>("title"); opt.numerator = efficSet->getUntrackedParameter<string>("numerator"); opt.denominator = efficSet->getUntrackedParameter<string>("denominator"); opt.isProfile = false; const string typeName = efficSet->getUntrackedParameter<string>("typeName", "eff"); if (typeName == "eff") opt.type = EfficType::efficiency; else if (typeName == "fake") opt.type = EfficType::fakerate; else if (typeName == "simpleratio") opt.type = EfficType::simpleratio; else opt.type = EfficType::none; efficOptions_.push_back(opt); } // Parse efficiency profiles vstring effProfileCmds = pset.getUntrackedParameter<vstring>("efficiencyProfile", vstring()); for (vstring::const_iterator effProfileCmd = effProfileCmds.begin(); effProfileCmd != effProfileCmds.end(); ++effProfileCmd) { if (effProfileCmd->empty()) continue; boost::tokenizer<elsc> tokens(*effProfileCmd, commonEscapes); vector<string> args; for (boost::tokenizer<elsc>::const_iterator iToken = tokens.begin(); iToken != tokens.end(); ++iToken) { if (iToken->empty()) continue; args.push_back(*iToken); } if (args.size() < 4) { LogInfo("DQMGenericClient") << "Wrong input to effProfileCmds\n"; continue; } EfficOption opt; opt.name = args[0]; opt.title = args[1]; opt.numerator = args[2]; opt.denominator = args[3]; opt.isProfile = true; const string typeName = args.size() == 4 ? "eff" : args[4]; if (typeName == "eff") opt.type = EfficType::efficiency; else if (typeName == "fake") opt.type = EfficType::fakerate; else if (typeName == "simpleratio") opt.type = EfficType::simpleratio; else opt.type = EfficType::none; efficOptions_.push_back(opt); } VPSet effProfileSets = pset.getUntrackedParameter<VPSet>("efficiencyProfileSets", VPSet()); for (VPSet::const_iterator effProfileSet = effProfileSets.begin(); effProfileSet != effProfileSets.end(); ++effProfileSet) { EfficOption opt; opt.name = effProfileSet->getUntrackedParameter<string>("name"); opt.title = effProfileSet->getUntrackedParameter<string>("title"); opt.numerator = effProfileSet->getUntrackedParameter<string>("numerator"); opt.denominator = effProfileSet->getUntrackedParameter<string>("denominator"); opt.isProfile = true; const string typeName = effProfileSet->getUntrackedParameter<string>("typeName", "eff"); if (typeName == "eff") opt.type = EfficType::efficiency; else if (typeName == "fake") opt.type = EfficType::fakerate; else if (typeName == "simpleratio") opt.type = EfficType::simpleratio; else opt.type = EfficType::none; efficOptions_.push_back(opt); } // Parse resolution commands std::array<std::string, 2> optionNames = {{"resolution", "resolutionProfile"}}; for (auto& optName : optionNames) { vstring resCmds; if (optName.find("Profile") != std::string::npos) resCmds = pset.getUntrackedParameter<vstring>(optName, vstring()); else resCmds = pset.getParameter<vstring>(optName); for (vstring::const_iterator resCmd = resCmds.begin(); resCmd != resCmds.end(); ++resCmd) { if (resCmd->empty()) continue; boost::tokenizer<elsc> tokens(*resCmd, commonEscapes); vector<string> args; for (boost::tokenizer<elsc>::const_iterator iToken = tokens.begin(); iToken != tokens.end(); ++iToken) { if (iToken->empty()) continue; args.push_back(*iToken); } if (args.size() < 3) { LogInfo("DQMGenericClient") << "Wrong input to resCmds\n"; continue; } ResolOption opt; opt.namePrefix = args[0]; opt.titlePrefix = args[1]; opt.srcName = args[2]; opt.isProfile = (optName.find("Profile") != std::string::npos) ? true : false; std::string typeDefault = (optName.find("Profile") != std::string::npos) ? "rms" : "fit"; const string typeName = args.size() == 3 ? typeDefault : args[3]; if (typeName == "fit") opt.type = ResType::fit; else if (typeName == "rms") opt.type = ResType::rms; else opt.type = ResType::none; resolOptions_.push_back(opt); } } std::array<std::string, 2> optionSetNames = {{"resolutionProfileSets", "resolutionSets"}}; for (auto& optName : optionSetNames) { VPSet resSets = pset.getUntrackedParameter<VPSet>(optName, VPSet()); for (VPSet::const_iterator resSet = resSets.begin(); resSet != resSets.end(); ++resSet) { ResolOption opt; opt.namePrefix = resSet->getUntrackedParameter<string>("namePrefix"); opt.titlePrefix = resSet->getUntrackedParameter<string>("titlePrefix"); opt.srcName = resSet->getUntrackedParameter<string>("srcName"); std::string typeDefault = (optName.find("Profile") != std::string::npos) ? "rms" : "fit"; const string typeName = resSet->getUntrackedParameter<string>("typeName", typeDefault); if (typeName == "fit") opt.type = ResType::fit; else if (typeName == "rms") opt.type = ResType::rms; else opt.type = ResType::none; opt.isProfile = (optName.find("Profile") != std::string::npos) ? true : false; resolOptions_.push_back(opt); } } // Parse profiles vstring profileCmds = pset.getUntrackedParameter<vstring>("profile", vstring()); for (const auto& profileCmd : profileCmds) { boost::tokenizer<elsc> tokens(profileCmd, commonEscapes); vector<string> args; for (boost::tokenizer<elsc>::const_iterator iToken = tokens.begin(); iToken != tokens.end(); ++iToken) { if (iToken->empty()) continue; args.push_back(*iToken); } if (args.size() != 3) { LogInfo("DQMGenericClient") << "Wrong input to profileCmds\n"; continue; } ProfileOption opt; opt.name = args[0]; opt.title = args[1]; opt.srcName = args[2]; profileOptions_.push_back(opt); } VPSet profileSets = pset.getUntrackedParameter<VPSet>("profileSets", VPSet()); for (const auto& profileSet : profileSets) { ProfileOption opt; opt.name = profileSet.getUntrackedParameter<string>("name"); opt.title = profileSet.getUntrackedParameter<string>("title"); opt.srcName = profileSet.getUntrackedParameter<string>("srcName"); profileOptions_.push_back(opt); } // Parse Normalization commands vstring normCmds = pset.getUntrackedParameter<vstring>("normalization", vstring()); for (vstring::const_iterator normCmd = normCmds.begin(); normCmd != normCmds.end(); ++normCmd) { if (normCmd->empty()) continue; boost::tokenizer<elsc> tokens(*normCmd, commonEscapes); vector<string> args; for (boost::tokenizer<elsc>::const_iterator iToken = tokens.begin(); iToken != tokens.end(); ++iToken) { if (iToken->empty()) continue; args.push_back(*iToken); } if (args.empty() or args.size() > 2) { LogInfo("DQMGenericClient") << "Wrong input to normCmds\n"; continue; } NormOption opt; opt.name = args[0]; opt.normHistName = args.size() == 2 ? args[1] : args[0]; normOptions_.push_back(opt); } VPSet normSets = pset.getUntrackedParameter<VPSet>("normalizationSets", VPSet()); for (VPSet::const_iterator normSet = normSets.begin(); normSet != normSets.end(); ++normSet) { NormOption opt; opt.name = normSet->getUntrackedParameter<string>("name"); opt.normHistName = normSet->getUntrackedParameter<string>("normalizedTo", opt.name); normOptions_.push_back(opt); } // Cumulative distributions vstring cdCmds = pset.getUntrackedParameter<vstring>("cumulativeDists", vstring()); for (vstring::const_iterator cdCmd = cdCmds.begin(); cdCmd != cdCmds.end(); ++cdCmd) { if (cdCmd->empty()) continue; boost::tokenizer<elsc> tokens(*cdCmd, commonEscapes); vector<string> args; for (boost::tokenizer<elsc>::const_iterator iToken = tokens.begin(); iToken != tokens.end(); ++iToken) { if (iToken->empty()) continue; args.push_back(*iToken); } if (args.empty() || args.size() > 2) { LogInfo("DQMGenericClient") << "Wrong input to cdCmds\n"; continue; } CDOption opt; opt.name = args[0]; opt.ascending = args.size() == 2 ? (args[1] != "descending") : true; cdOptions_.push_back(opt); } VPSet cdSets = pset.getUntrackedParameter<VPSet>("cumulativeDistSets", VPSet()); for (VPSet::const_iterator cdSet = cdSets.begin(); cdSet != cdSets.end(); ++cdSet) { CDOption opt; opt.name = cdSet->getUntrackedParameter<string>("name"); opt.ascending = cdSet->getUntrackedParameter<bool>("ascending", true); cdOptions_.push_back(opt); } // move under/overflows to first/last bins vstring noFlowCmds = pset.getUntrackedParameter<vstring>("noFlowDists", vstring()); for (vstring::const_iterator noFlowCmd = noFlowCmds.begin(); noFlowCmd != noFlowCmds.end(); ++noFlowCmd) { if (noFlowCmd->empty()) continue; boost::tokenizer<elsc> tokens(*noFlowCmd, commonEscapes); vector<string> args; for (boost::tokenizer<elsc>::const_iterator iToken = tokens.begin(); iToken != tokens.end(); ++iToken) { if (iToken->empty()) continue; args.push_back(*iToken); } if (args.empty() || args.size() > 2) { LogInfo("DQMGenericClient") << "Wrong input to noFlowCmds\n"; continue; } NoFlowOption opt; opt.name = args[0]; noFlowOptions_.push_back(opt); } VPSet noFlowSets = pset.getUntrackedParameter<VPSet>("noFlowDistSets", VPSet()); for (VPSet::const_iterator noFlowSet = noFlowSets.begin(); noFlowSet != noFlowSets.end(); ++noFlowSet) { NoFlowOption opt; opt.name = noFlowSet->getUntrackedParameter<string>("name"); noFlowOptions_.push_back(opt); } outputFileName_ = pset.getUntrackedParameter<string>("outputFileName", ""); subDirs_ = pset.getUntrackedParameter<vstring>("subDirs"); resLimitedFit_ = pset.getUntrackedParameter<bool>("resolutionLimitedFit", false); isWildcardUsed_ = false; } void DQMGenericClient::dqmEndLuminosityBlock(DQMStore::IBooker& ibooker, DQMStore::IGetter& igetter, const edm::LuminosityBlock& lumiSeg, const edm::EventSetup& c) { if (runOnEndLumi_) { makeAllPlots(ibooker, igetter); } } void DQMGenericClient::dqmEndRun(DQMStore::IBooker& ibooker, DQMStore::IGetter& igetter, edm::Run const&, edm::EventSetup const&) { // Create new MEs in endRun, even though we are requested to do it in endJob. // This gives the QTests a chance to run, before summaries are created in // endJob. The negative side effect is that we cannot run the GenericClient // for plots produced in Harvesting, but that seems rather rare. // // It is important that this is still save in the presence of multiple runs, // first because in multi-run harvesting, we accumulate statistics over all // runs and have full statistics at the endRun of the last run, and second, // because we set the efficiencyFlag so any further aggregation should produce // correct results. Also, all operations should be idempotent; running them // more than once does no harm. // needed to access the DQMStore::save method theDQM = nullptr; theDQM = Service<DQMStore>().operator->(); if (runOnEndJob_) { makeAllPlots(ibooker, igetter); } if (!outputFileName_.empty()) theDQM->save(outputFileName_); } void DQMGenericClient::makeAllPlots(DQMStore::IBooker& ibooker, DQMStore::IGetter& igetter) { typedef vector<string> vstring; // Process wildcard in the sub-directory set<string> subDirSet; for (vstring::const_iterator iSubDir = subDirs_.begin(); iSubDir != subDirs_.end(); ++iSubDir) { string subDir = *iSubDir; if (subDir[subDir.size() - 1] == '/') subDir.erase(subDir.size() - 1); if (TString(subDir).Contains(metacharacters_)) { isWildcardUsed_ = true; const string::size_type shiftPos = subDir.rfind('/'); const string searchPath = subDir.substr(0, shiftPos); const string pattern = subDir.substr(shiftPos + 1, subDir.length()); //std::cout << "\n\n\n\nLooking for all subdirs of " << subDir << std::endl; findAllSubdirectories(ibooker, igetter, searchPath, &subDirSet, pattern); } else { subDirSet.insert(subDir); } } for (set<string>::const_iterator iSubDir = subDirSet.begin(); iSubDir != subDirSet.end(); ++iSubDir) { const string& dirName = *iSubDir; // First normalize, then move under/overflows, then make // cumulative, and only then efficiency This allows to use the // cumulative distributions for efficiency calculation for (vector<NormOption>::const_iterator normOption = normOptions_.begin(); normOption != normOptions_.end(); ++normOption) { normalizeToEntries(ibooker, igetter, dirName, normOption->name, normOption->normHistName); } for (vector<NoFlowOption>::const_iterator noFlowOption = noFlowOptions_.begin(); noFlowOption != noFlowOptions_.end(); ++noFlowOption) { makeNoFlowDist(ibooker, igetter, dirName, noFlowOption->name); } for (vector<CDOption>::const_iterator cdOption = cdOptions_.begin(); cdOption != cdOptions_.end(); ++cdOption) { makeCumulativeDist(ibooker, igetter, dirName, cdOption->name, cdOption->ascending); } for (vector<EfficOption>::const_iterator efficOption = efficOptions_.begin(); efficOption != efficOptions_.end(); ++efficOption) { computeEfficiency(ibooker, igetter, dirName, efficOption->name, efficOption->title, efficOption->numerator, efficOption->denominator, efficOption->type, efficOption->isProfile); } if (makeGlobalEffPlot_) { ME* globalEfficME = igetter.get(dirName + "/globalEfficiencies"); if (globalEfficME) globalEfficME->getTH1F()->LabelsDeflate("X"); } for (vector<ResolOption>::const_iterator resolOption = resolOptions_.begin(); resolOption != resolOptions_.end(); ++resolOption) { computeResolution(ibooker, igetter, dirName, resolOption->namePrefix, resolOption->titlePrefix, resolOption->srcName, resolOption->type, resolOption->isProfile); } for (const auto& profileOption : profileOptions_) { computeProfile(ibooker, igetter, dirName, profileOption.name, profileOption.title, profileOption.srcName); } } } void DQMGenericClient::computeEfficiency(DQMStore::IBooker& ibooker, DQMStore::IGetter& igetter, const string& startDir, const string& efficMEName, const string& efficMETitle, const string& recoMEName, const string& simMEName, const EfficType type, const bool makeProfile) { if (!igetter.dirExists(startDir)) { if (verbose_ >= 2 || (verbose_ == 1 && !isWildcardUsed_)) { LogInfo("DQMGenericClient") << "computeEfficiency() : " << "Cannot find sub-directory " << startDir << endl; } return; } ibooker.cd(); ME* simME = igetter.get(startDir + "/" + simMEName); ME* recoME = igetter.get(startDir + "/" + recoMEName); if (!simME) { if (verbose_ >= 2 || (verbose_ == 1 && !isWildcardUsed_)) { LogInfo("DQMGenericClient") << "computeEfficiency() : " << "No sim-ME '" << simMEName << "' found\n"; } return; } if (!recoME) { if (verbose_ >= 2 || (verbose_ == 1 && !isWildcardUsed_)) { LogInfo("DQMGenericClient") << "computeEfficiency() : " << "No reco-ME '" << recoMEName << "' found\n"; } return; } // Treat everything as the base class, TH1 TH1* hSim = simME->getTH1(); TH1* hReco = recoME->getTH1(); if (!hSim || !hReco) { if (verbose_ >= 2 || (verbose_ == 1 && !isWildcardUsed_)) { LogInfo("DQMGenericClient") << "computeEfficiency() : " << "Cannot create TH1 from ME\n"; } return; } string efficDir = startDir; string newEfficMEName = efficMEName; string::size_type shiftPos; if (string::npos != (shiftPos = efficMEName.rfind('/'))) { efficDir += "/" + efficMEName.substr(0, shiftPos); newEfficMEName.erase(0, shiftPos + 1); } ibooker.setCurrentFolder(efficDir); if (makeProfile) { TProfile* efficHist = (hReco->GetXaxis()->GetXbins()->GetSize() == 0) ? new TProfile(newEfficMEName.c_str(), efficMETitle.c_str(), hReco->GetXaxis()->GetNbins(), hReco->GetXaxis()->GetXmin(), hReco->GetXaxis()->GetXmax()) : new TProfile(newEfficMEName.c_str(), efficMETitle.c_str(), hReco->GetXaxis()->GetNbins(), hReco->GetXaxis()->GetXbins()->GetArray()); efficHist->GetXaxis()->SetTitle(hSim->GetXaxis()->GetTitle()); efficHist->GetYaxis()->SetTitle(hSim->GetYaxis()->GetTitle()); for (int i = 1; i <= hReco->GetNbinsX(); i++) { const double nReco = hReco->GetBinContent(i); const double nSim = hSim->GetBinContent(i); if (!std::string(hSim->GetXaxis()->GetBinLabel(i)).empty()) efficHist->GetXaxis()->SetBinLabel(i, hSim->GetXaxis()->GetBinLabel(i)); if (nSim == 0 or nReco < 0 or nReco > nSim) continue; const double effVal = nReco / nSim; const double errLo = TEfficiency::ClopperPearson(nSim, nReco, 0.683, false); const double errUp = TEfficiency::ClopperPearson(nSim, nReco, 0.683, true); const double errVal = (effVal - errLo > errUp - effVal) ? effVal - errLo : errUp - effVal; efficHist->SetBinContent(i, effVal); efficHist->SetBinEntries(i, 1); efficHist->SetBinError(i, std::hypot(effVal, errVal)); } ME* efficMe = ibooker.bookProfile(newEfficMEName, efficHist); efficMe->setEfficiencyFlag(); delete efficHist; } else { TH1* efficHist = (TH1*)hSim->Clone(newEfficMEName.c_str()); efficHist->SetTitle(efficMETitle.c_str()); // Here is where you have trouble --- you need // to understand what type of hist you have. ME* efficME = nullptr; // Parse the class name // This works, but there might be a better way TClass* myHistClass = efficHist->IsA(); TString histClassName = myHistClass->GetName(); if (histClassName == "TH1F") { efficME = ibooker.book1D(newEfficMEName, (TH1F*)efficHist); } else if (histClassName == "TH2F") { efficME = ibooker.book2D(newEfficMEName, (TH2F*)efficHist); } else if (histClassName == "TH3F") { efficME = ibooker.book3D(newEfficMEName, (TH3F*)efficHist); } delete efficHist; if (!efficME) { LogInfo("DQMGenericClient") << "computeEfficiency() : " << "Cannot book effic-ME from the DQM\n"; return; } // Update: 2009-9-16 slaunwhj // call the most generic efficiency function // works up to 3-d histograms generic_eff(hSim, hReco, efficME, type); // const int nBin = efficME->getNbinsX(); // for(int bin = 0; bin <= nBin; ++bin) { // const float nSim = simME ->getBinContent(bin); // const float nReco = recoME->getBinContent(bin); // float eff =0; // if (type=="fake")eff = nSim ? 1-nReco/nSim : 0.; // else eff= nSim ? nReco/nSim : 0.; // const float err = nSim && eff <= 1 ? sqrt(eff*(1-eff)/nSim) : 0.; // efficME->setBinContent(bin, eff); // efficME->setBinError(bin, err); // } efficME->setEntries(simME->getEntries()); } // Global efficiency if (makeGlobalEffPlot_) { ME* globalEfficME = igetter.get(efficDir + "/globalEfficiencies"); if (!globalEfficME) globalEfficME = ibooker.book1D("globalEfficiencies", "Global efficiencies", 1, 0, 1); if (!globalEfficME) { LogInfo("DQMGenericClient") << "computeEfficiency() : " << "Cannot book globalEffic-ME from the DQM\n"; return; } globalEfficME->setEfficiencyFlag(); TH1F* hGlobalEffic = globalEfficME->getTH1F(); if (!hGlobalEffic) { LogInfo("DQMGenericClient") << "computeEfficiency() : " << "Cannot create TH1F from ME, globalEfficME\n"; return; } const float nSimAll = hSim->GetEntries(); const float nRecoAll = hReco->GetEntries(); float efficAll = 0; if (type == EfficType::efficiency || type == EfficType::simpleratio) efficAll = nSimAll ? nRecoAll / nSimAll : 0; else if (type == EfficType::fakerate) efficAll = nSimAll ? 1 - nRecoAll / nSimAll : 0; float errorAll = 0; if (type == EfficType::simpleratio) { if (nSimAll) { const float x = nRecoAll / nSimAll; errorAll = std::sqrt(1.f / nSimAll * x * (1 + x)); } } else errorAll = nSimAll && efficAll < 1 ? sqrt(efficAll * (1 - efficAll) / nSimAll) : 0; const int iBin = hGlobalEffic->Fill(newEfficMEName.c_str(), 0); hGlobalEffic->SetBinContent(iBin, efficAll); hGlobalEffic->SetBinError(iBin, errorAll); } } void DQMGenericClient::computeResolution(DQMStore::IBooker& ibooker, DQMStore::IGetter& igetter, const string& startDir, const string& namePrefix, const string& titlePrefix, const std::string& srcName, const ResType type, const bool makeProfile) { if (!igetter.dirExists(startDir)) { if (verbose_ >= 2 || (verbose_ == 1 && !isWildcardUsed_)) { LogInfo("DQMGenericClient") << "computeResolution() : " << "Cannot find sub-directory " << startDir << endl; } return; } ibooker.cd(); ME* srcME = igetter.get(startDir + "/" + srcName); if (!srcME) { if (verbose_ >= 2 || (verbose_ == 1 && !isWildcardUsed_)) { LogInfo("DQMGenericClient") << "computeResolution() : " << "No source ME '" << srcName << "' found\n"; } return; } TH2F* hSrc = srcME->getTH2F(); if (!hSrc) { if (verbose_ >= 2 || (verbose_ == 1 && !isWildcardUsed_)) { LogInfo("DQMGenericClient") << "computeResolution() : " << "Cannot create TH2F from source-ME\n"; } return; } const int nBin = hSrc->GetNbinsX(); string newDir = startDir; string newPrefix = namePrefix; string::size_type shiftPos; if (string::npos != (shiftPos = namePrefix.rfind('/'))) { newDir += "/" + namePrefix.substr(0, shiftPos); newPrefix.erase(0, shiftPos + 1); } ibooker.setCurrentFolder(newDir); float* lowedgesfloats = new float[nBin + 1]; if (makeProfile) { TProfile* meanHist; TProfile* sigmaHist; if (hSrc->GetXaxis()->GetXbins()->GetSize()) { for (int j = 0; j < nBin + 1; ++j) lowedgesfloats[j] = (float)hSrc->GetXaxis()->GetXbins()->GetAt(j); meanHist = new TProfile((newPrefix + "_Mean").c_str(), (titlePrefix + " Mean").c_str(), nBin, lowedgesfloats); sigmaHist = new TProfile((newPrefix + "_Sigma").c_str(), (titlePrefix + " Sigma").c_str(), nBin, lowedgesfloats); } else { meanHist = new TProfile((newPrefix + "_Mean").c_str(), (titlePrefix + " Mean").c_str(), hSrc->GetXaxis()->GetNbins(), hSrc->GetXaxis()->GetXmin(), hSrc->GetXaxis()->GetXmax()); sigmaHist = new TProfile((newPrefix + "_Sigma").c_str(), (titlePrefix + " Sigma").c_str(), hSrc->GetXaxis()->GetNbins(), hSrc->GetXaxis()->GetXmin(), hSrc->GetXaxis()->GetXmax()); } ME* meanME = ibooker.bookProfile((newPrefix + "_Mean").c_str(), meanHist); ME* sigmaME = ibooker.bookProfile((newPrefix + "_Sigma").c_str(), sigmaHist); if (meanME && sigmaME) { meanME->setEfficiencyFlag(); sigmaME->setEfficiencyFlag(); if (type == ResType::fit) { if (!resLimitedFit_) { FitSlicesYTool fitTool(srcME); fitTool.getFittedMeanWithError(meanME); fitTool.getFittedSigmaWithError(sigmaME); } else { limitedFit(srcME, meanME, sigmaME); } } if (type == ResType::rms) { for (int i = 1; i <= nBin; i++) { TH1* histoY = hSrc->ProjectionY(" ", i, i, "e"); if (histoY->GetEntries() > 0) { meanME->setBinContent(i, histoY->GetMean() * histoY->GetEntries()); meanME->setBinError(i, histoY->GetMeanError()); meanME->setBinEntries(i, histoY->GetEntries()); sigmaME->setBinContent(i, histoY->GetRMS() * histoY->GetEntries()); sigmaME->setBinError(i, histoY->GetRMSError()); sigmaME->setBinEntries(i, histoY->GetEntries()); } } } } } else { ME* meanME; ME* sigmaME; if (hSrc->GetXaxis()->GetXbins()->GetSize()) { for (int j = 0; j < nBin + 1; ++j) lowedgesfloats[j] = (float)hSrc->GetXaxis()->GetXbins()->GetAt(j); meanME = ibooker.book1D(newPrefix + "_Mean", titlePrefix + " Mean", nBin, lowedgesfloats); sigmaME = ibooker.book1D(newPrefix + "_Sigma", titlePrefix + " Sigma", nBin, lowedgesfloats); } else { meanME = ibooker.book1D( newPrefix + "_Mean", titlePrefix + " Mean", nBin, hSrc->GetXaxis()->GetXmin(), hSrc->GetXaxis()->GetXmax()); sigmaME = ibooker.book1D( newPrefix + "_Sigma", titlePrefix + " Sigma", nBin, hSrc->GetXaxis()->GetXmin(), hSrc->GetXaxis()->GetXmax()); } if (meanME && sigmaME) { meanME->setEfficiencyFlag(); sigmaME->setEfficiencyFlag(); if (type == ResType::fit) { if (!resLimitedFit_) { FitSlicesYTool fitTool(srcME); fitTool.getFittedMeanWithError(meanME); fitTool.getFittedSigmaWithError(sigmaME); //// fitTool.getFittedChisqWithError(chi2ME); // N/A } else { limitedFit(srcME, meanME, sigmaME); } } else if (type == ResType::rms) { for (int i = 1; i <= nBin; i++) { TH1* histoY = hSrc->ProjectionY(" ", i, i, "e"); if (histoY->GetEntries() > 0) { meanME->setBinContent(i, histoY->GetMean()); meanME->setBinError(i, histoY->GetMeanError()); sigmaME->setBinContent(i, histoY->GetRMS()); sigmaME->setBinError(i, histoY->GetRMSError()); } } } } } delete[] lowedgesfloats; } void DQMGenericClient::computeProfile(DQMStore::IBooker& ibooker, DQMStore::IGetter& igetter, const std::string& startDir, const std::string& profileMEName, const std::string& profileMETitle, const std::string& srcMEName) { if (!igetter.dirExists(startDir)) { if (verbose_ >= 2 || (verbose_ == 1 && !isWildcardUsed_)) { LogInfo("DQMGenericClient") << "computeProfile() : " << "Cannot find sub-directory " << startDir << endl; } return; } ibooker.cd(); ME* srcME = igetter.get(startDir + "/" + srcMEName); if (!srcME) { if (verbose_ >= 2 || (verbose_ == 1 && !isWildcardUsed_)) { LogInfo("DQMGenericClient") << "computeProfile() : " << "No source ME '" << srcMEName << "' found\n"; } return; } TH2F* hSrc = srcME->getTH2F(); if (!hSrc) { if (verbose_ >= 2 || (verbose_ == 1 && !isWildcardUsed_)) { LogInfo("DQMGenericClient") << "computeProfile() : " << "Cannot create TH2F from source-ME\n"; } return; } string profileDir = startDir; string newProfileMEName = profileMEName; string::size_type shiftPos; if (string::npos != (shiftPos = profileMEName.rfind('/'))) { profileDir += "/" + profileMEName.substr(0, shiftPos); newProfileMEName.erase(0, shiftPos + 1); } ibooker.setCurrentFolder(profileDir); std::unique_ptr<TProfile> profile(hSrc->ProfileX()); // We own the pointer profile->SetTitle(profileMETitle.c_str()); ibooker.bookProfile(profileMEName, profile.get()); // ibooker makes a copy } void DQMGenericClient::normalizeToEntries(DQMStore::IBooker& ibooker, DQMStore::IGetter& igetter, const std::string& startDir, const std::string& histName, const std::string& normHistName) { if (!igetter.dirExists(startDir)) { if (verbose_ >= 2 || (verbose_ == 1 && !isWildcardUsed_)) { LogInfo("DQMGenericClient") << "normalizeToEntries() : " << "Cannot find sub-directory " << startDir << endl; } return; } ibooker.cd(); ME* element = igetter.get(startDir + "/" + histName); ME* normME = igetter.get(startDir + "/" + normHistName); if (!element) { if (verbose_ >= 2 || (verbose_ == 1 && !isWildcardUsed_)) { LogInfo("DQMGenericClient") << "normalizeToEntries() : " << "No such element '" << histName << "' found\n"; } return; } if (!normME) { if (verbose_ >= 2 || (verbose_ == 1 && !isWildcardUsed_)) { LogInfo("DQMGenericClient") << "normalizeToEntries() : " << "No such element '" << normHistName << "' found\n"; } return; } TH1F* hist = element->getTH1F(); if (!hist) { if (verbose_ >= 2 || (verbose_ == 1 && !isWildcardUsed_)) { LogInfo("DQMGenericClient") << "normalizeToEntries() : " << "Cannot create TH1F from ME\n"; } return; } TH1F* normHist = normME->getTH1F(); if (!normHist) { if (verbose_ >= 2 || (verbose_ == 1 && !isWildcardUsed_)) { LogInfo("DQMGenericClient") << "normalizeToEntries() : " << "Cannot create TH1F from ME\n"; } return; } const double entries = normHist->GetEntries(); if (entries != 0) { hist->Scale(1. / entries); } else { LogInfo("DQMGenericClient") << "normalizeToEntries() : " << "Zero entries in histogram\n"; } return; } void DQMGenericClient::makeCumulativeDist(DQMStore::IBooker& ibooker, DQMStore::IGetter& igetter, const std::string& startDir, const std::string& cdName, bool ascending) { if (!igetter.dirExists(startDir)) { if (verbose_ >= 2 || (verbose_ == 1 && !isWildcardUsed_)) { LogInfo("DQMGenericClient") << "makeCumulativeDist() : " << "Cannot find sub-directory " << startDir << endl; } return; } ibooker.cd(); ME* element_cd = igetter.get(startDir + "/" + cdName); if (!element_cd) { if (verbose_ >= 2 || (verbose_ == 1 && !isWildcardUsed_)) { LogInfo("DQMGenericClient") << "makeCumulativeDist() : " << "No such element '" << cdName << "' found\n"; } return; } TH1F* cd = element_cd->getTH1F(); if (!cd) { if (verbose_ >= 2 || (verbose_ == 1 && !isWildcardUsed_)) { LogInfo("DQMGenericClient") << "makeCumulativeDist() : " << "Cannot create TH1F from ME\n"; } return; } int n_bins = cd->GetNbinsX() + 1; if (ascending) { for (int i = 1; i <= n_bins; i++) { cd->SetBinContent(i, cd->GetBinContent(i) + cd->GetBinContent(i - 1)); } } else { for (int i = n_bins - 1; i >= 0; i--) { // n_bins points to the overflow bin cd->SetBinContent(i, cd->GetBinContent(i) + cd->GetBinContent(i + 1)); } } return; } void DQMGenericClient::makeNoFlowDist(DQMStore::IBooker& ibooker, DQMStore::IGetter& igetter, const std::string& startDir, const std::string& noFlowName) { if (!igetter.dirExists(startDir)) { if (verbose_ >= 2 || (verbose_ == 1 && !isWildcardUsed_)) { LogInfo("DQMGenericClient") << "makeNoFlowDist() : " << "Cannot find sub-directory " << startDir << endl; } return; } ibooker.cd(); ME* element_noFlow = igetter.get(startDir + "/" + noFlowName); if (!element_noFlow) { if (verbose_ >= 2 || (verbose_ == 1 && !isWildcardUsed_)) { LogInfo("DQMGenericClient") << "makeNoFlowDist() : " << "No such element '" << noFlowName << "' found\n"; } return; } TH1F* noFlow = element_noFlow->getTH1F(); if (!noFlow) { if (verbose_ >= 2 || (verbose_ == 1 && !isWildcardUsed_)) { LogInfo("DQMGenericClient") << "makeNoFlowDist() : " << "Cannot create TH1F from ME\n"; } return; } noFlow->AddBinContent(1, noFlow->GetBinContent(0)); noFlow->SetBinContent(0, 0.); const auto lastBin = noFlow->GetNbinsX(); noFlow->AddBinContent(lastBin, noFlow->GetBinContent(lastBin + 1)); noFlow->SetBinContent(lastBin + 1, 0.); } void DQMGenericClient::limitedFit(MonitorElement* srcME, MonitorElement* meanME, MonitorElement* sigmaME) { TH2F* histo = srcME->getTH2F(); // Fit slices projected along Y from bins in X double cont_min = 100; //Minimum number of entries Int_t binx = histo->GetXaxis()->GetNbins(); for (int i = 1; i <= binx; i++) { TString iString(i); TH1* histoY = histo->ProjectionY(" ", i, i); double cont = histoY->GetEntries(); if (cont >= cont_min) { float minfit = histoY->GetMean() - histoY->GetRMS(); float maxfit = histoY->GetMean() + histoY->GetRMS(); TF1* fitFcn = new TF1(TString("g") + histo->GetName() + iString, "gaus", minfit, maxfit); double x1, x2; fitFcn->GetRange(x1, x2); //To avoid DQMGenericClient maintains state between fit calls fitFcn->SetParameters(histoY->Integral(), histoY->GetMean(), histoY->GetRMS()); histoY->Fit(fitFcn, "QR0 SERIAL", "", x1, x2); // histoY->Fit(fitFcn->GetName(),"RME"); double* par = fitFcn->GetParameters(); const double* err = fitFcn->GetParErrors(); meanME->setBinContent(i, par[1]); meanME->setBinError(i, err[1]); // meanME->setBinEntries(i, 1.); // meanME->setBinError(i,sqrt(err[1]*err[1]+par[1]*par[1])); sigmaME->setBinContent(i, par[2]); sigmaME->setBinError(i, err[2]); // sigmaME->setBinEntries(i, 1.); // sigmaME->setBinError(i,sqrt(err[2]*err[2]+par[2]*par[2])); if (fitFcn) delete fitFcn; if (histoY) delete histoY; } else { if (histoY) delete histoY; continue; } } } //================================= void DQMGenericClient::findAllSubdirectories(DQMStore::IBooker& ibooker, DQMStore::IGetter& igetter, std::string dir, std::set<std::string>* myList, const TString& _pattern = TString("")) { TString pattern = _pattern; if (!igetter.dirExists(dir)) { LogError("DQMGenericClient") << " DQMGenericClient::findAllSubdirectories ==> Missing folder " << dir << " !!!"; return; } if (pattern != "") { if (pattern.Contains(nonPerlWildcard_)) pattern.ReplaceAll("*", ".*"); TPRegexp regexp(pattern); ibooker.cd(dir); vector<string> foundDirs = igetter.getSubdirs(); for (vector<string>::const_iterator iDir = foundDirs.begin(); iDir != foundDirs.end(); ++iDir) { TString dirName = iDir->substr(iDir->rfind('/') + 1, iDir->length()); if (dirName.Contains(regexp)) findAllSubdirectories(ibooker, igetter, *iDir, myList); } } //std::cout << "Looking for directory " << dir ; else if (igetter.dirExists(dir)) { //std::cout << "... it exists! Inserting it into the list "; myList->insert(dir); //std::cout << "... now list has size " << myList->size() << std::endl; ibooker.cd(dir); findAllSubdirectories(ibooker, igetter, dir, myList, "*"); } else { //std::cout << "... DOES NOT EXIST!!! Skip bogus dir" << std::endl; LogInfo("DQMGenericClient") << "Trying to find sub-directories of " << dir << " failed because " << dir << " does not exist"; } return; } void DQMGenericClient::generic_eff(TH1* denom, TH1* numer, MonitorElement* efficiencyHist, const EfficType type) { for (int iBinX = 1; iBinX < denom->GetNbinsX() + 1; iBinX++) { for (int iBinY = 1; iBinY < denom->GetNbinsY() + 1; iBinY++) { for (int iBinZ = 1; iBinZ < denom->GetNbinsZ() + 1; iBinZ++) { int globalBinNum = denom->GetBin(iBinX, iBinY, iBinZ); float numerVal = numer->GetBinContent(globalBinNum); float denomVal = denom->GetBinContent(globalBinNum); float effVal = 0; // fake eff is in use if (type == EfficType::fakerate) { effVal = denomVal ? (1 - numerVal / denomVal) : 0; } else { effVal = denomVal ? numerVal / denomVal : 0; } float errVal = 0; if (type == EfficType::simpleratio) { // errVal = denomVal ? 1.f/denomVal*effVal*(1+effVal) : 0; float numerErr = numer->GetBinError(globalBinNum); float denomErr = denom->GetBinError(globalBinNum); float denomsq = denomVal * denomVal; errVal = denomVal ? sqrt(pow(1.f / denomVal * numerErr, 2.0) + pow(numerVal / denomsq * denomErr, 2)) : 0; } else { errVal = (denomVal && (effVal <= 1)) ? sqrt(effVal * (1 - effVal) / denomVal) : 0; } LogDebug("DQMGenericClient") << "(iBinX, iBinY, iBinZ) = " << iBinX << ", " << iBinY << ", " << iBinZ << "), global bin = " << globalBinNum << "eff = " << numerVal << " / " << denomVal << " = " << effVal << " ... setting the error for that bin ... " << endl << endl; efficiencyHist->setBinContent(globalBinNum, effVal); efficiencyHist->setBinError(globalBinNum, errVal); efficiencyHist->setEfficiencyFlag(); } } } //efficiencyHist->setMinimum(0.0); //efficiencyHist->setMaximum(1.0); } DEFINE_FWK_MODULE(DQMGenericClient); /* vim:set ts=2 sts=2 sw=2 expandtab: */