diff --git a/Control/AthenaMonitoring/AthenaMonitoring/HistogramFiller.h b/Control/AthenaMonitoring/AthenaMonitoring/HistogramFiller.h index 39d043ac7dc8f6685791b4e822feb967029a6c00..e198594175bf8bef4456ec024b0f6db445bf746e 100644 --- a/Control/AthenaMonitoring/AthenaMonitoring/HistogramFiller.h +++ b/Control/AthenaMonitoring/AthenaMonitoring/HistogramFiller.h @@ -14,6 +14,7 @@ #include "TH2.h" #include "TProfile.h" #include "TProfile2D.h" +#include "TEfficiency.h" #include "GaudiKernel/ServiceHandle.h" #include "GaudiKernel/ITHistSvc.h" @@ -29,8 +30,13 @@ namespace Monitored { public: HistogramFiller(TH1* hist, const HistogramDef& histDef) : m_hist(hist), m_mutex(std::make_shared<std::mutex>()), m_histDef(new HistogramDef(histDef)) {} + HistogramFiller(TEfficiency* eff, const HistogramDef& histDef) + : m_eff(eff), m_mutex(std::make_shared<std::mutex>()), m_histDef(new HistogramDef(histDef)) {} HistogramFiller(const HistogramFiller& hf) - : m_hist(hf.m_hist), m_mutex(hf.m_mutex), m_histDef(hf.m_histDef) {} + : m_hist(hf.m_hist) + , m_eff(hf.m_eff) + , m_mutex(hf.m_mutex) + , m_histDef(hf.m_histDef) {} HistogramFiller(HistogramFiller&&) = default; virtual ~HistogramFiller() {} @@ -49,6 +55,7 @@ namespace Monitored { virtual TH1* histogram() = 0; TH1* m_hist; + TEfficiency* m_eff; std::shared_ptr<std::mutex> m_mutex; std::shared_ptr<HistogramDef> m_histDef; std::vector<std::reference_wrapper<Monitored::IMonitoredVariable>> m_monVariables; @@ -81,7 +88,9 @@ namespace Monitored { TH1* create2D(const HistogramDef& def); template<class H> TH1* create2DProfile(const HistogramDef& def); + TEfficiency* createEfficiency(const HistogramDef& def); + std::string getFullName(const HistogramDef& def); static void setOpts(TH1* hist, const std::string& opt); static void setLabels(TH1* hist, const std::vector<std::string>& labels); @@ -167,6 +176,19 @@ namespace Monitored { protected: virtual TProfile2D* histogram() override { return static_cast<TProfile2D*>(m_hist); } }; + + /** + * @brief filler for TEfficiency histograms + */ + class HistogramFillerEfficiency : public HistogramFiller { + public: + HistogramFillerEfficiency(TEfficiency* eff, const HistogramDef& histDef) + : HistogramFiller(eff, histDef) {}; + virtual unsigned fill() override; + virtual HistogramFillerEfficiency* clone() override { return new HistogramFillerEfficiency(*this); }; + protected: + virtual TH1* histogram() { return m_hist; } // Keep the compiler happy + }; } - + #endif /* HistogramFiller */ diff --git a/Control/AthenaMonitoring/python/ExampleMonitorAlgorithm.py b/Control/AthenaMonitoring/python/ExampleMonitorAlgorithm.py index 0c50180230cead0cf8023458c9cc62d030e032f6..d7412fc29dff60a729c910864380fa124c793c93 100644 --- a/Control/AthenaMonitoring/python/ExampleMonitorAlgorithm.py +++ b/Control/AthenaMonitoring/python/ExampleMonitorAlgorithm.py @@ -46,6 +46,7 @@ def ExampleMonitoringConfig(inputFlags): ### STEP 3 ### # Edit properties of a algorithm exampleMonAlg.TriggerChain = '' + # exampleMonAlg.RandomHist = True ### STEP 4 ### # Add some tools. N.B. Do not use your own trigger decion tool. Use the @@ -77,17 +78,18 @@ def ExampleMonitoringConfig(inputFlags): ### STEP 5 ### # Configure histograms - myGroup.defineHistogram('lumiPerBCID;lumiPerBCID', title='Luminosity;L/BCID;Events', + myGroup.defineHistogram('lumiPerBCID',title='Luminosity;L/BCID;Events', path='ToRuleThemAll',xbins=10,xmin=0.0,xmax=10.0) - myGroup.defineHistogram('lb;lb', title='Luminosity Block;lb;Events', + myGroup.defineHistogram('lb', title='Luminosity Block;lb;Events', path='ToFindThem',xbins=1000,xmin=-0.5,xmax=999.5) - myGroup.defineHistogram('random;random', title='LB;x;Events', + myGroup.defineHistogram('random', title='LB;x;Events', path='ToBringThemAll',xbins=30,xmin=0,xmax=1) + myGroup.defineHistogram('pT_passed,pT',type='TEfficiency',title='Test TEfficiency;x;Eff', + path='AndInTheDarkness',xbins=100,xmin=0.0,xmax=50.0) - - anotherGroup.defineHistogram('lbWithFilter;lbWithFilter',title='Lumi;lb;Events', + anotherGroup.defineHistogram('lbWithFilter',title='Lumi;lb;Events', path='top',xbins=1000,xmin=-0.5,xmax=999.5) - anotherGroup.defineHistogram('run;run',title='Run Number;run;Events', + anotherGroup.defineHistogram('run',title='Run Number;run;Events', path='top',xbins=1000000,xmin=-0.5,xmax=999999.5) ### STEP 6 ### diff --git a/Control/AthenaMonitoring/src/ExampleMonitorAlgorithm.cxx b/Control/AthenaMonitoring/src/ExampleMonitorAlgorithm.cxx index ed0bfd7abca7b27764319c21d4a8f0f6fbc12100..1c712557e09e978ba44e15e78e6b5ee3816c7df7 100644 --- a/Control/AthenaMonitoring/src/ExampleMonitorAlgorithm.cxx +++ b/Control/AthenaMonitoring/src/ExampleMonitorAlgorithm.cxx @@ -26,17 +26,28 @@ StatusCode ExampleMonitorAlgorithm::fillHistograms( const EventContext& ctx ) co auto lb = Monitored::Scalar<int>("lb",0); auto run = Monitored::Scalar<int>("run",0); auto random = Monitored::Scalar<float>("random",0.0); + + // Two variables (value and passed) needed for TEfficiency + auto pT = Monitored::Scalar<float>("pT",0.0); + auto pT_passed = Monitored::Scalar<float>("pT_passed",false); + // Set the values of the monitored variables for the event lumiPerBCID = lbAverageInteractionsPerCrossing(); lb = GetEventInfo(ctx)->lumiBlock(); run = GetEventInfo(ctx)->runNumber(); + + TRandom3 r(ctx.eventID().event_number()); + // Example of using flags if (m_doRandom) { - TRandom r(ctx.eventID().event_number()); - random = r.Rndm(); + random = r.Rndm(); } + // Fake efficiency calculator + pT = r.Landau(15); + pT_passed = pT>r.Poisson(15); + // Fill. First argument is the tool name, all others are the variables to be saved. - fill("ExampleMonitor",lumiPerBCID,lb,random); + fill("ExampleMonitor",lumiPerBCID,lb,random,pT,pT_passed); // Alternative fill method. Get the group yourself, and pass it to the fill function. auto tool = getGroup("ExampleMonitor"); diff --git a/Control/AthenaMonitoring/src/HistogramDef.cxx b/Control/AthenaMonitoring/src/HistogramDef.cxx index 12403f3219e964ed4b7bec7ba45c95e6a0814fd9..d9fbd06f91f7171c61cf86a15088737d42dee722 100644 --- a/Control/AthenaMonitoring/src/HistogramDef.cxx +++ b/Control/AthenaMonitoring/src/HistogramDef.cxx @@ -52,7 +52,7 @@ const HistogramDef HistogramDef::parse(const std::string& jobOpts) { itr = histProperty.erase(itr); - if (histPar.type.find("TH2") == 0 || histPar.type == "TProfile") { + if (histPar.type.find("TH2") == 0 || histPar.type == "TProfile" || histPar.type == "TEfficiency") { histPar.name.push_back(*itr); itr = histProperty.erase(itr); } diff --git a/Control/AthenaMonitoring/src/HistogramFiller.cxx b/Control/AthenaMonitoring/src/HistogramFiller.cxx index bb0f3057c5c26bf48e567c89f0215cb4d64543d5..9dfd91bbc7739e748120f56e9bc8be310690d8db 100644 --- a/Control/AthenaMonitoring/src/HistogramFiller.cxx +++ b/Control/AthenaMonitoring/src/HistogramFiller.cxx @@ -21,6 +21,7 @@ HistogramFiller* HistogramFillerFactory::create(const HistogramDef& def) { TProfile* histoProfile(0); TH2* histo2D(0); TProfile2D* histo2DProfile(0); + TEfficiency* histoEfficiency(0); if (def.type == "TH1F") { histo1D = histo = create1D<TH1F>(def); @@ -43,16 +44,21 @@ HistogramFiller* HistogramFillerFactory::create(const HistogramDef& def) { } else if (def.type == "TProfile2D") { histo = create2DProfile<TProfile2D>(def); histo2DProfile = dynamic_cast<TProfile2D*>(histo); + } else if (def.type == "TEfficiency") { + histoEfficiency = createEfficiency(def); } - if (histo == 0) { + if (histo == 0 && histoEfficiency == 0) { throw HistogramFillerCreateException("Can not create yet histogram of type: >" + def.type + "<\n" + - "Try one of: TH1[F,D,I], TH2[F,D,I], TProfile, TProfile2D"); + "Try one of: TH1[F,D,I], TH2[F,D,I], TProfile, TProfile2D, " + + "TEfficiency."); + } else if (histo!=0) { + // magic shift to make histograms readable even if no post-procesing is done + histo->GetYaxis()->SetTitleOffset( 1.25 ); + + setLabels(histo, def.labels); + setOpts(histo, def.opt); } - histo->GetYaxis()->SetTitleOffset( 1.25 );// magic shift to make histograms readable even if no post-procesing is done - - setLabels(histo, def.labels); - setOpts(histo, def.opt); HistogramFiller* result(0); @@ -72,11 +78,43 @@ HistogramFiller* HistogramFillerFactory::create(const HistogramDef& def) { result = new HistogramFiller2DProfile(histo2DProfile, def); } else if ( histo2D ) { result = new HistogramFiller2D(histo2D, def); + } else if ( histoEfficiency ) { + result = new HistogramFillerEfficiency(histoEfficiency,def); } return result; } +/** + * Invent path name + * + * If def path contains any of: EXPERT, SHIFT, DEBUG, RUNSTAT, EXPRES this is online + * convention this becomes the first element of the path followed by the group name. + * Else if the def.path is DEFAULT then only the group name is used if the path yet + * different is concatenated with the group name. + */ +std::string HistogramFillerFactory::getFullName(const HistogramDef& def) { + const static std::set<std::string> online( { "EXPERT", "SHIFT", "DEBUG", "RUNSTAT", "EXPRES" } ); + + std::string path; + if( online.count( def.path) != 0 ) { + path = "/" + def.path + "/" + m_groupName; + } else if ( def.path == "DEFAULT" ) { + path = "/" + m_groupName; + } else { + path = "/" + m_groupName + "/"+def.path; + } + + // remove duplicate + std::string fullName = path + "/" + def.alias; + fullName.erase( std::unique( fullName.begin(), fullName.end(), + [](const char a, const char b) { + return a == b and a == '/'; + } ), fullName.end() ); + + return fullName; +} + /** * Create and register histogram * @@ -87,27 +125,9 @@ HistogramFiller* HistogramFillerFactory::create(const HistogramDef& def) { */ template<class H, class HBASE, typename... Types> HBASE* HistogramFillerFactory::create(const HistogramDef& def, Types&&... hargs) { - // invent path name - // if def path contains any of: EXPERT, SHIFT, DEBUG, RUNSTAT, EXPRES this is online convention - // this becomes the first element of the path followed by the group name - // else if the def.path is DEFAULT then only the group name is used - // if the path yet different is concatenated with the group name - // - const static std::set<std::string> online( { "EXPERT", "SHIFT", "DEBUG", "RUNSTAT", "EXPRES" } ); - std::string path; - if( online.count( def.path) != 0 ) - path = "/" + def.path + "/" + m_groupName; - else if ( def.path == "DEFAULT" ) - path = "/" + m_groupName; - else - path = "/" + m_groupName + "/"+def.path; - // remove duplicate // - std::string fullName = path + "/" + def.alias; - fullName.erase( std::unique( fullName.begin(), fullName.end(), - [](const char a, const char b){ - return a == b and a == '/'; - } ), fullName.end() ); - + + std::string fullName = getFullName(def); + // Check if histogram exists already HBASE* histo = nullptr; if ( m_histSvc->exists( fullName ) ) { @@ -149,6 +169,30 @@ TH1* HistogramFillerFactory::create2DProfile(const HistogramDef& def) { def.ybins, def.ymin, def.ymax, def.zmin, def.zmax); } +TEfficiency* HistogramFillerFactory::createEfficiency(const HistogramDef& def) { + + std::string fullName = getFullName(def); + + // Check if efficiency exists already + TEfficiency* e = nullptr; + if ( m_histSvc->exists(fullName) ) { + TGraph* g = reinterpret_cast<TGraph*>(e); + if ( !m_histSvc->getGraph(fullName,g) ) { + throw HistogramFillerCreateException("Histogram >"+ fullName + "< seems to exist but can not be obtained from THistSvc"); + } + return e; + } + + // Otherwise, create the efficiency and register it + e = new TEfficiency(def.alias.c_str(),def.title.c_str(),def.xbins,def.xmin,def.xmax); + TGraph* g = reinterpret_cast<TGraph*>(e); + if ( !m_histSvc->regGraph(fullName,g) ) { + delete e; + throw HistogramFillerCreateException("Histogram >"+ fullName + "< can not be registered in THistSvc"); + } + return e; +} + void HistogramFillerFactory::setOpts(TH1* hist, const std::string& opt) { // try to apply an option if ( opt.find("kCanRebin") != std::string::npos ) { @@ -351,3 +395,20 @@ unsigned HistogramFiller2D::fill() { return i; } + +unsigned HistogramFillerEfficiency::fill() { + if (m_monVariables.size() != 2) { + return 0; + } + + unsigned i(0); + auto valuesVector1 = m_monVariables[0].get().getVectorRepresentation(); + auto valuesVector2 = m_monVariables[1].get().getVectorRepresentation(); + std::lock_guard<std::mutex> lock(*(this->m_mutex)); + + for (i = 0; i < valuesVector1.size(); ++i) { + m_eff->Fill(valuesVector1[i],valuesVector2[i]); + } + + return i; +} diff --git a/Control/AthenaMonitoring/test/test_defineHistogram.py b/Control/AthenaMonitoring/test/test_defineHistogram.py index ac5ad32b62a78e6b16ad2c78d51bdce1c90a9e2e..1b691a41f89f96af64914ed76a9077571b7c1cb9 100644 --- a/Control/AthenaMonitoring/test/test_defineHistogram.py +++ b/Control/AthenaMonitoring/test/test_defineHistogram.py @@ -35,5 +35,9 @@ class Test( unittest.TestCase ): with self.assertRaises(AssertionError): defineHistogram('var', 'TH1F', path='EXPERT', labels='l1:l2') + def test_efficiency( self ): + s = defineHistogram('var', 'TEfficiency', 'EXPERT', 'title', 10, 0.0, 10.0) + self.assertEqual(s, 'EXPERT, TEfficiency, var, title, 10, 0.000000, 10.000000') + if __name__ == '__main__': unittest.main()