From 22ac078f773855c818ef73393dc8add9af1e689f Mon Sep 17 00:00:00 2001 From: "Jack Y. Araz" <jackaraz@gmail.com> Date: Sat, 24 Jun 2023 12:04:58 +0100 Subject: [PATCH 001/107] mitigating weight to multiweight --- .../SampleAnalyzer/Process/Counter/Counter.h | 153 ++-- .../Process/Counter/CounterManager.cpp | 123 ++- .../Process/Counter/CounterManager.h | 165 ++-- .../Process/RegionSelection/RegionSelection.h | 210 +++-- .../RegionSelectionManager.cpp | 9 +- .../RegionSelection/RegionSelectionManager.h | 862 +++++++++--------- 6 files changed, 800 insertions(+), 722 deletions(-) diff --git a/tools/SampleAnalyzer/Process/Counter/Counter.h b/tools/SampleAnalyzer/Process/Counter/Counter.h index e2c468d7..10459f6b 100644 --- a/tools/SampleAnalyzer/Process/Counter/Counter.h +++ b/tools/SampleAnalyzer/Process/Counter/Counter.h @@ -1,31 +1,29 @@ //////////////////////////////////////////////////////////////////////////////// -// +// // Copyright (C) 2012-2023 Jack Araz, Eric Conte & Benjamin Fuks // The MadAnalysis development team, email: <ma5team@iphc.cnrs.fr> -// +// // This file is part of MadAnalysis 5. // Official website: <https://github.com/MadAnalysis/madanalysis5> -// +// // MadAnalysis 5 is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // MadAnalysis 5 is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with MadAnalysis 5. If not, see <http://www.gnu.org/licenses/> -// +// //////////////////////////////////////////////////////////////////////////////// - #ifndef COUNTER_h #define COUNTER_h - // SampleAnalyzer headers #include "SampleAnalyzer/Commons/Base/PortableDatatypes.h" @@ -34,81 +32,80 @@ #include <string> #include <map> - namespace MA5 { -class CounterCollection; + class CounterCollection; -class Counter -{ - friend class CounterCollection; - - // ------------------------------------------------------------- - // data members - // ------------------------------------------------------------- - public : - - /// name of the analysis - std::string name_; - - /// number of times the function Increment is called - /// first = positive weight ; second = negative weight - std::pair<MAint64,MAint64> nentries_; - - /// sum of weights - /// first = positive weight ; second = negative weight - std::pair<MAfloat64,MAfloat64> sumweight_; - - /// sum of squared weights - /// first = positive weight ; second = negative weight - std::pair<MAfloat64,MAfloat64> sumweight2_; - - - // ------------------------------------------------------------- - // method members - // ------------------------------------------------------------- - public : - - /// Constructor without argument - Counter(const std::string& name = "unkwown") - { - name_ = name; - nentries_ = std::make_pair(0,0); - sumweight_ = std::make_pair(0.,0.); - sumweight2_ = std::make_pair(0.,0.); - } - - /// Destructor - ~Counter() - { } - - /// Reset - void Reset() - { - nentries_ = std::make_pair(0,0); - sumweight_ = std::make_pair(0.,0.); - sumweight2_ = std::make_pair(0.,0.); - } - - /// Increment the counter - void Increment(const MAfloat32& weight=1.) - { - if (weight>0) - { - nentries_.first++; - sumweight_.first+=weight; - sumweight2_.first+=weight*weight; - } - else if (weight<0) + class Counter { - nentries_.second++; - sumweight_.second+=weight; - sumweight2_.second+=weight*weight; - } - } - -}; + friend class CounterCollection; + + // ------------------------------------------------------------- + // data members + // ------------------------------------------------------------- + public: + /// name of the analysis + std::string name_; + + /// number of times the function Increment is called + /// first = positive weight ; second = negative weight + std::pair<MAint64, MAint64> nentries_; + + /// sum of weights + /// first = positive weight ; second = negative weight + std::map<MAuint32, std::pair<MAfloat64, MAfloat64>> sumweight_; + + /// sum of squared weights + /// first = positive weight ; second = negative weight + std::map<MAuint32, std::pair<MAfloat64, MAfloat64>> sumweight2_; + + // ------------------------------------------------------------- + // method members + // ------------------------------------------------------------- + public: + /// Constructor without argument + Counter(const std::string &name = "unkwown") + { + name_ = name; + nentries_ = std::make_pair(0, 0); + sumweight_[0] = std::make_pair(0., 0.); + sumweight2_[0] = std::make_pair(0., 0.); + } + + /// Destructor + ~Counter() {} + + /// Reset + void Reset() + { + nentries_ = std::make_pair(0, 0); + sumweight_.clear(); + sumweight2_.clear(); + } + + /// Increment the counter + void Increment(const std::map<MAuint32, MAfloat64> &multiweight) + { + for (auto ¤t_weight : multiweight) + { + MAfloat64 weight = current_weight.second; + MAuint32 idx = current_weight.first; + if (weight > 0) + { + nentries_.first++; + sumweight_[idx].first += weight; + sumweight2_[idx].first += weight * weight; + } + else if (weight < 0) + { + nentries_.second++; + sumweight_[idx].second += weight; + sumweight2_[idx].second += weight * weight; + } + } + } + }; } diff --git a/tools/SampleAnalyzer/Process/Counter/CounterManager.cpp b/tools/SampleAnalyzer/Process/Counter/CounterManager.cpp index e2233a30..69c8d39c 100644 --- a/tools/SampleAnalyzer/Process/Counter/CounterManager.cpp +++ b/tools/SampleAnalyzer/Process/Counter/CounterManager.cpp @@ -1,31 +1,29 @@ //////////////////////////////////////////////////////////////////////////////// -// +// // Copyright (C) 2012-2023 Jack Araz, Eric Conte & Benjamin Fuks // The MadAnalysis development team, email: <ma5team@iphc.cnrs.fr> -// +// // This file is part of MadAnalysis 5. // Official website: <https://github.com/MadAnalysis/madanalysis5> -// +// // MadAnalysis 5 is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // MadAnalysis 5 is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with MadAnalysis 5. If not, see <http://www.gnu.org/licenses/> -// +// //////////////////////////////////////////////////////////////////////////////// - // SampleAnalyzer headers #include "SampleAnalyzer/Process/Counter/CounterManager.h" - using namespace MA5; /* @@ -73,85 +71,84 @@ void CounterManager::Write_RootFormat(TFile* output) const } */ - /// Write the counters in a TEXT file -void CounterManager::Write_TextFormat(SAFWriter& output) const +void CounterManager::Write_TextFormat(SAFWriter &output) const { - // header - *output.GetStream() << "<InitialCounter>" << std::endl; - - // name - *output.GetStream() << "\"Initial number of events\" #" << std::endl; - - // nentries - output.GetStream()->width(15); - *output.GetStream() << std::left << std::scientific << initial_.nentries_.first; - *output.GetStream() << " "; - output.GetStream()->width(15); - *output.GetStream() << std::left << std::scientific << initial_.nentries_.second; - *output.GetStream() << " # nentries" << std::endl; - - // sum of weights - output.GetStream()->width(15); - *output.GetStream() << std::left << std::scientific << initial_.sumweight_.first; - *output.GetStream() << " "; - output.GetStream()->width(15); - *output.GetStream() << std::left << std::scientific << initial_.sumweight_.second; - *output.GetStream() << " # sum of weights" << std::endl; - - // sum of weights^2 - output.GetStream()->width(15); - *output.GetStream() << std::left << std::scientific << initial_.sumweight2_.first; - *output.GetStream() << " "; - output.GetStream()->width(15); - *output.GetStream() << std::left << std::scientific << initial_.sumweight2_.second; - *output.GetStream() << " # sum of weights^2" << std::endl; - - // foot - *output.GetStream() << "</InitialCounter>" << std::endl; - *output.GetStream() << std::endl; - - - - // Loop over the counters - for (MAuint32 i=0;i<counters_.size();i++) - { // header - *output.GetStream() << "<Counter>" << std::endl; + *output.GetStream() << "<InitialCounter>" << std::endl; // name - MAint32 nsp = 30-counters_[i].name_.size(); - if(nsp<0) nsp=0; - *output.GetStream() << "\"" << counters_[i].name_ << "\""; - for (MAuint32 jj=0; jj<static_cast<MAuint32>(nsp);jj++) *output.GetStream() << " "; - *output.GetStream() << "# " << i+1 <<"st cut" << std::endl; + *output.GetStream() << "\"Initial number of events\" #" << std::endl; // nentries output.GetStream()->width(15); - *output.GetStream() << std::left << std::scientific << counters_[i].nentries_.first; + *output.GetStream() << std::left << std::scientific << initial_.nentries_.first; *output.GetStream() << " "; output.GetStream()->width(15); - *output.GetStream() << std::left << std::scientific << counters_[i].nentries_.second; + *output.GetStream() << std::left << std::scientific << initial_.nentries_.second; *output.GetStream() << " # nentries" << std::endl; // sum of weights output.GetStream()->width(15); - *output.GetStream() << std::left << std::scientific << counters_[i].sumweight_.first; + *output.GetStream() << std::left << std::scientific << initial_.sumweight_.at(0).first; *output.GetStream() << " "; output.GetStream()->width(15); - *output.GetStream() << std::left << std::scientific << counters_[i].sumweight_.second; + *output.GetStream() << std::left << std::scientific << initial_.sumweight_.at(0).second; *output.GetStream() << " # sum of weights" << std::endl; // sum of weights^2 output.GetStream()->width(15); - *output.GetStream() << std::left << std::scientific << counters_[i].sumweight2_.first; + *output.GetStream() << std::left << std::scientific << initial_.sumweight2_.at(0).first; *output.GetStream() << " "; output.GetStream()->width(15); - *output.GetStream() << std::left << std::scientific << counters_[i].sumweight2_.second; + *output.GetStream() << std::left << std::scientific << initial_.sumweight2_.at(0).second; *output.GetStream() << " # sum of weights^2" << std::endl; // foot - *output.GetStream() << "</Counter>" << std::endl; + *output.GetStream() << "</InitialCounter>" << std::endl; *output.GetStream() << std::endl; - } + + // Loop over the counters + for (MAuint32 i = 0; i < counters_.size(); i++) + { + // header + *output.GetStream() << "<Counter>" << std::endl; + + // name + MAint32 nsp = 30 - counters_[i].name_.size(); + if (nsp < 0) + nsp = 0; + *output.GetStream() << "\"" << counters_[i].name_ << "\""; + for (MAuint32 jj = 0; jj < static_cast<MAuint32>(nsp); jj++) + *output.GetStream() << " "; + *output.GetStream() << "# " << i + 1 << "st cut" << std::endl; + + // nentries + output.GetStream()->width(15); + *output.GetStream() << std::left << std::scientific << counters_[i].nentries_.first; + *output.GetStream() << " "; + output.GetStream()->width(15); + *output.GetStream() << std::left << std::scientific << counters_[i].nentries_.second; + *output.GetStream() << " # nentries" << std::endl; + + // sum of weights + output.GetStream()->width(15); + *output.GetStream() << std::left << std::scientific << counters_[i].sumweight_.at(0).first; + *output.GetStream() << " "; + output.GetStream()->width(15); + *output.GetStream() << std::left << std::scientific << counters_[i].sumweight_.at(0).second; + *output.GetStream() << " # sum of weights" << std::endl; + + // sum of weights^2 + output.GetStream()->width(15); + *output.GetStream() << std::left << std::scientific << counters_[i].sumweight2_.at(0).first; + *output.GetStream() << " "; + output.GetStream()->width(15); + *output.GetStream() << std::left << std::scientific << counters_[i].sumweight2_.at(0).second; + *output.GetStream() << " # sum of weights^2" << std::endl; + + // foot + *output.GetStream() << "</Counter>" << std::endl; + *output.GetStream() << std::endl; + } } diff --git a/tools/SampleAnalyzer/Process/Counter/CounterManager.h b/tools/SampleAnalyzer/Process/Counter/CounterManager.h index 12182e88..d712c105 100644 --- a/tools/SampleAnalyzer/Process/Counter/CounterManager.h +++ b/tools/SampleAnalyzer/Process/Counter/CounterManager.h @@ -1,31 +1,29 @@ //////////////////////////////////////////////////////////////////////////////// -// +// // Copyright (C) 2012-2023 Jack Araz, Eric Conte & Benjamin Fuks // The MadAnalysis development team, email: <ma5team@iphc.cnrs.fr> -// +// // This file is part of MadAnalysis 5. // Official website: <https://github.com/MadAnalysis/madanalysis5> -// +// // MadAnalysis 5 is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // MadAnalysis 5 is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with MadAnalysis 5. If not, see <http://www.gnu.org/licenses/> -// +// //////////////////////////////////////////////////////////////////////////////// - #ifndef COUNTER_MANAGER_H #define COUNTER_MANAGER_H - // STL headers #include <iostream> #include <ostream> @@ -35,80 +33,89 @@ #include "SampleAnalyzer/Process/Counter/Counter.h" #include "SampleAnalyzer/Process/Writer/SAFWriter.h" - namespace MA5 { -class CounterManager -{ - - // ------------------------------------------------------------- - // data members - // ------------------------------------------------------------- - private : - - // Collection of counters - std::vector<Counter> counters_; - - // Initial number of events - Counter initial_; - - // ------------------------------------------------------------- - // method members - // ------------------------------------------------------------- - public : - - /// Constructor without argument - CounterManager() - { } - - /// Destructor - ~CounterManager() - { } - - /// Initialize - void Initialize(const MAuint32& n) - { counters_.resize(n); } - - - // Specifying a cut name - void InitCut(const std::string myname) - { - Counter tmpcnt(myname); - counters_.push_back(tmpcnt); - } - - /// Reset - void Reset() - { counters_.clear(); } - - /// Overloading operator [] - const Counter& operator[] (const MAuint32& index) const - { return counters_[index];} - Counter& operator[] (const MAuint32& index) - { return counters_[index];} - - /// Incrementing the initial number of events - void IncrementNInitial(MAfloat32 weight=1.0) - { initial_.Increment(weight); } - - /// Incrementing the initial number of events - Counter& GetInitial() - { return initial_; } - const Counter& GetInitial() const - { return initial_; } - - /// Write the counters in a Text file - void Write_TextFormat(SAFWriter& output) const; - - /// Write the counters in a ROOT file - // void Write_RootFormat(TFile* output) const; - - /// Finalizing - void Finalize() - { Reset(); } - -}; + class CounterManager + { + + // ------------------------------------------------------------- + // data members + // ------------------------------------------------------------- + private: + // Collection of counters + std::vector<Counter> counters_; + + // Initial number of events + Counter initial_; + + // ------------------------------------------------------------- + // method members + // ------------------------------------------------------------- + public: + /// Constructor without argument + CounterManager() {} + + /// Destructor + ~CounterManager() {} + + /// Initialize + void Initialize(const MAuint32 &n) + { + counters_.resize(n); + } + + // Specifying a cut name + void InitCut(const std::string myname) + { + Counter tmpcnt(myname); + counters_.push_back(tmpcnt); + } + + /// Reset + void Reset() + { + counters_.clear(); + } + + /// Overloading operator [] + const Counter &operator[](const MAuint32 &index) const + { + return counters_[index]; + } + Counter &operator[](const MAuint32 &index) + { + return counters_[index]; + } + + /// Incrementing the initial number of events + void IncrementNInitial(std::map<MAuint32, MAfloat64> weight) + { + initial_.Increment(weight); + } + + /// Incrementing the initial number of events + Counter &GetInitial() + { + return initial_; + } + const Counter &GetInitial() const + { + return initial_; + } + + /// Write the counters in a Text file + void Write_TextFormat(SAFWriter &output) const; + + /// Write the counters in a ROOT file + // void Write_RootFormat(TFile* output) const; + + /// Finalizing + void Finalize() + { + Reset(); + } + }; } diff --git a/tools/SampleAnalyzer/Process/RegionSelection/RegionSelection.h b/tools/SampleAnalyzer/Process/RegionSelection/RegionSelection.h index f38ffad0..07fa4e55 100644 --- a/tools/SampleAnalyzer/Process/RegionSelection/RegionSelection.h +++ b/tools/SampleAnalyzer/Process/RegionSelection/RegionSelection.h @@ -1,31 +1,29 @@ //////////////////////////////////////////////////////////////////////////////// -// +// // Copyright (C) 2012-2023 Jack Araz, Eric Conte & Benjamin Fuks // The MadAnalysis development team, email: <ma5team@iphc.cnrs.fr> -// +// // This file is part of MadAnalysis 5. // Official website: <https://github.com/MadAnalysis/madanalysis5> -// +// // MadAnalysis 5 is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // MadAnalysis 5 is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with MadAnalysis 5. If not, see <http://www.gnu.org/licenses/> -// +// //////////////////////////////////////////////////////////////////////////////// - #ifndef __REGIONSELECTION_H #define __REGIONSELECTION_H - // STL headers #include <string> #include <vector> @@ -34,90 +32,124 @@ #include "SampleAnalyzer/Process/Counter/CounterManager.h" #include "SampleAnalyzer/Process/Writer/SAFWriter.h" - namespace MA5 { -class RegionSelection -{ - // ------------------------------------------------------------- - // data members - // ------------------------------------------------------------- - private: - std::string name_; - MAbool surviving_; - MAuint32 NumberOfCutsAppliedSoFar_; - MAfloat64 weight_; - - CounterManager cutflow_; - - // ------------------------------------------------------------- - // method members - // ------------------------------------------------------------- - public : - /// Constructor without argument - RegionSelection() {name_ = "";}; - - /// Constructor with argument - RegionSelection(const std::string& name) { name_=name; }; - - /// Destructor - ~RegionSelection() { }; - - /// Get methods - std::string GetName() - { return name_; } - - MAbool IsSurviving() - { return surviving_; } - - MAuint32 GetNumberOfCutsAppliedSoFar() - { return NumberOfCutsAppliedSoFar_; } - - /// Printing the list of histograms - void WriteDefinition(SAFWriter &output); - - /// Printing the cutflow - void WriteCutflow(SAFWriter& output) - { cutflow_.Write_TextFormat(output); } - - /// Set methods - void SetName(std::string name) - { name_ = name; } - - /// Set weight - void SetWeight(MAfloat64 weight) { weight_=weight;} - - /// Set weight - MAfloat64 GetWeight() { return weight_;} - - void SetSurvivingTest(MAbool surviving) - { surviving_ = surviving; } - - void SetNumberOfCutsAppliedSoFar(MAuint32 NumberOfCutsAppliedSoFar) - { NumberOfCutsAppliedSoFar_ = NumberOfCutsAppliedSoFar; } - - // Increment CutFlow (when this region passes a cut) - void IncrementCutFlow(MAfloat64 weight) - { - cutflow_[NumberOfCutsAppliedSoFar_].Increment(weight); - NumberOfCutsAppliedSoFar_++; - } - - // Add a cut to the CutFlow - void AddCut(std::string const &CutName) - { cutflow_.InitCut(CutName); } - - /// Getting ready for a new event - void InitializeForNewEvent(const MAfloat64 &weight) - { - SetSurvivingTest(true); - SetNumberOfCutsAppliedSoFar(0); - cutflow_.IncrementNInitial(weight); - weight_=weight; - } - -}; + class RegionSelection + { + // ------------------------------------------------------------- + // data members + // ------------------------------------------------------------- + private: + std::string name_; + MAbool surviving_; + MAuint32 NumberOfCutsAppliedSoFar_; + + /// @brief multi weight definition string is the name of the weight + /// float corresponds to the weight's value + std::map<MAuint32, MAfloat64> weight_; + + CounterManager cutflow_; + + // ------------------------------------------------------------- + // method members + // ------------------------------------------------------------- + public: + /// Constructor without argument + RegionSelection() { name_ = ""; }; + + /// Constructor with argument + RegionSelection(const std::string &name) { name_ = name; }; + + /// Destructor + ~RegionSelection(){}; + + /// Get methods + std::string GetName() + { + return name_; + } + + MAbool IsSurviving() + { + return surviving_; + } + + MAuint32 GetNumberOfCutsAppliedSoFar() + { + return NumberOfCutsAppliedSoFar_; + } + + /// Printing the list of histograms + void WriteDefinition(SAFWriter &output); + + /// Printing the cutflow + void WriteCutflow(SAFWriter &output) + { + cutflow_.Write_TextFormat(output); + } + + /// Set methods + void SetName(std::string name) + { + name_ = name; + } + + /// Set weight + void SetWeight(MAfloat64 weight) + { + weight_.clear(); + weight_.insert(std::make_pair(0, weight)); + } + + /// Set weight + void SetWeight(std::map<MAuint32, MAfloat64> weight) { weight_ = weight; } + + /// Get weight + MAfloat64 GetWeight() { return weight_[0]; } + + /// @brief get weight with a certain id + /// @return weight value + MAfloat64 GetWeight(MAint32 id) { return weight_.at(id); } + + /// Get multi weight + std::map<MAuint32, MAfloat64> GetMultiWeight() { return weight_; } + + void SetSurvivingTest(MAbool surviving) { surviving_ = surviving; } + + void SetNumberOfCutsAppliedSoFar(MAuint32 NumberOfCutsAppliedSoFar) + { + NumberOfCutsAppliedSoFar_ = NumberOfCutsAppliedSoFar; + } + + // Increment CutFlow (when this region passes a cut) + void IncrementCutFlow(std::map<MAuint32, MAfloat64> weight) + { + cutflow_[NumberOfCutsAppliedSoFar_].Increment(weight); + NumberOfCutsAppliedSoFar_++; + } + + // Add a cut to the CutFlow + void AddCut(std::string const &CutName) { cutflow_.InitCut(CutName); } + + /// Getting ready for a new event + void InitializeForNewEvent(const MAfloat64 &weight) + { + SetWeight(weight); + SetSurvivingTest(true); + SetNumberOfCutsAppliedSoFar(0); + cutflow_.IncrementNInitial(weight_); + } + + /// Getting ready for a new event + void InitializeForNewEvent(const std::map<MAuint32, MAfloat64> &weight) + { + SetWeight(weight); + SetSurvivingTest(true); + SetNumberOfCutsAppliedSoFar(0); + cutflow_.IncrementNInitial(weight); + } + }; } diff --git a/tools/SampleAnalyzer/Process/RegionSelection/RegionSelectionManager.cpp b/tools/SampleAnalyzer/Process/RegionSelection/RegionSelectionManager.cpp index df47c49f..2cd7ad57 100644 --- a/tools/SampleAnalyzer/Process/RegionSelection/RegionSelectionManager.cpp +++ b/tools/SampleAnalyzer/Process/RegionSelection/RegionSelectionManager.cpp @@ -76,7 +76,7 @@ MAbool RegionSelectionManager::ApplyCut(MAbool condition, std::string const &cut /// Check the current cut: if (condition) { - ThisRegion->IncrementCutFlow(ThisRegion->GetWeight()); + ThisRegion->IncrementCutFlow(ThisRegion->GetMultiWeight()); } else { @@ -205,8 +205,9 @@ void RegionSelectionManager::HeadSR(std::ostream &outwriter, const std::string & void RegionSelectionManager::DumpSR(std::ostream &outwriter, MAbool &is_first) { // Set first SR out of the for loop to avoid many if executions - if (regions_.size() > 0 && is_first) outwriter << regions_[0]->IsSurviving(); + if (regions_.size() > 0 && is_first) + outwriter << regions_[0]->IsSurviving(); - for (MAuint32 i = is_first ? 1 : 0; i < regions_.size(); i++) - outwriter << "," << regions_[i]->IsSurviving(); + for (MAuint32 i = is_first ? 1 : 0; i < regions_.size(); i++) + outwriter << "," << regions_[i]->IsSurviving(); } diff --git a/tools/SampleAnalyzer/Process/RegionSelection/RegionSelectionManager.h b/tools/SampleAnalyzer/Process/RegionSelection/RegionSelectionManager.h index 5b6ec7ac..80cb20bb 100644 --- a/tools/SampleAnalyzer/Process/RegionSelection/RegionSelectionManager.h +++ b/tools/SampleAnalyzer/Process/RegionSelection/RegionSelectionManager.h @@ -40,469 +40,513 @@ namespace MA5 { - class RegionSelectionManager - { - // ------------------------------------------------------------- - // data members - // ------------------------------------------------------------- - private: - /// Collection of Region selections - std::vector<RegionSelection *> regions_; - - /// Collection of plots that will be generated during the analysis - PlotManager plotmanager_; - - /// Collection of cuts that will be applied to the analysis - MultiRegionCounterManager cutmanager_; - - /// Index related to the number of surviving regions in an analysis - MAuint32 NumberOfSurvivingRegions_; - - /// Weight associated with the processed event - MAfloat64 weight_; - - // ------------------------------------------------------------- - // method members - // ------------------------------------------------------------- - public: - /// constructor - RegionSelectionManager(){}; - - /// Destructor - ~RegionSelectionManager() + class RegionSelectionManager { - for (auto ®ion_pointer : regions_) - { - delete region_pointer; - } - }; - - /// Reset - void Reset() - { - for (MAuint32 i = 0; i < regions_.size(); i++) - { - if (regions_[i] != 0) - delete regions_[i]; - } - regions_.clear(); - cutmanager_.Finalize(); - plotmanager_.Finalize(); - } - - /// Finalizing - void Finalize() { Reset(); } - - /// Get methods - std::vector<RegionSelection *> Regions() - { - return regions_; - } + // ------------------------------------------------------------- + // data members + // ------------------------------------------------------------- + private: + /// Collection of Region selections + std::vector<RegionSelection *> regions_; + + /// Collection of plots that will be generated during the analysis + PlotManager plotmanager_; + + /// Collection of cuts that will be applied to the analysis + MultiRegionCounterManager cutmanager_; + + /// Index related to the number of surviving regions in an analysis + MAuint32 NumberOfSurvivingRegions_; + + /// Weight associated with the processed event + std::map<MAuint32, MAfloat64> weight_; + + // ------------------------------------------------------------- + // method members + // ------------------------------------------------------------- + public: + /// constructor + RegionSelectionManager(){}; + + /// Destructor + ~RegionSelectionManager() + { + for (auto ®ion_pointer : regions_) + { + delete region_pointer; + } + }; + + /// Reset + void Reset() + { + for (MAuint32 i = 0; i < regions_.size(); i++) + { + if (regions_[i] != 0) + delete regions_[i]; + } + regions_.clear(); + cutmanager_.Finalize(); + plotmanager_.Finalize(); + weight_.clear(); + } - MultiRegionCounterManager *GetCutManager() - { - return &cutmanager_; - } + /// Finalizing + void Finalize() { Reset(); } - PlotManager *GetPlotManager() - { - return &plotmanager_; - } + /// Get methods + std::vector<RegionSelection *> Regions() + { + return regions_; + } - MAfloat64 GetCurrentEventWeight() - { - return weight_; - } + MultiRegionCounterManager *GetCutManager() + { + return &cutmanager_; + } - /// Set method - void SetCurrentEventWeight(MAfloat64 weight) - { - weight_ = weight; - for (MAuint16 i = 0; i < regions_.size(); i++) - { - regions_[i]->SetWeight(weight); - } - } - - /// Set method - void SetRegionWeight(std::string name, MAfloat64 weight) - { - for (MAuint16 i = 0; i < regions_.size(); i++) - { - if (regions_[i]->GetName() == name) + PlotManager *GetPlotManager() { - regions_[i]->SetWeight(weight); - break; + return &plotmanager_; } - } - } - /// Adding a RegionSelection to the manager - void AddRegionSelection(const std::string &name) - { - std::string myname = name; - if (myname.compare("") == 0) - { - std::stringstream numstream; - numstream << regions_.size(); - myname = "RegionSelection" + numstream.str(); - } - RegionSelection *myregion = new RegionSelection(name); - regions_.push_back(myregion); - } - - /// Getting ready for a new event - void InitializeForNewEvent(MAfloat64 EventWeight) - { - weight_ = EventWeight; - NumberOfSurvivingRegions_ = regions_.size(); - for (MAuint32 i = 0; i < regions_.size(); i++) - regions_[i]->InitializeForNewEvent(EventWeight); - for (MAuint32 i = 0; i < plotmanager_.GetNplots(); i++) - plotmanager_.GetHistos()[i]->SetFreshEvent(true); - } - - /// This method associates all regions with a cut - void AddCut(const std::string &name) - { - // The name of the cut - std::string myname = name; - if (myname.compare("") == 0) - { - std::stringstream numstream; - numstream << cutmanager_.GetCuts().size(); - myname = "Cut" + numstream.str(); - } - // Adding the cut to all the regions - cutmanager_.AddCut(myname, regions_); - } - - /// This method associates one single region with a cut - void AddCut(const std::string &name, const std::string &RSname) - { - std::string RSnameA[] = {RSname}; - AddCut(name, RSnameA); - } + std::map<MAuint32, MAfloat64> GetCurrentEventWeight() + { + return weight_; + } - /// this method associates an arbitrary number of RS with a cut - template <int NRS> - void AddCut(const std::string &name, std::string const (&RSnames)[NRS]) - { - // The name of the cut - std::string myname = name; - if (myname.compare("") == 0) - { - std::stringstream numstream; - numstream << cutmanager_.GetCuts().size(); - myname = "Cut" + numstream.str(); - } - - // Creating the vector of SR of interests - std::vector<RegionSelection *> myregions; - for (MAuint32 i = 0; i < NRS; i++) - { - for (MAuint32 j = 0; j < regions_.size(); j++) + /// @brief Set current event weight with a single weight value + /// @param weight single weight value + void SetCurrentEventWeight(MAfloat64 weight) { - if (regions_[j]->GetName().compare(RSnames[i]) == 0) - { - myregions.push_back(regions_[j]); - break; - } + weight_.clear(); + weight_.insert(std::make_pair(0, weight)); + for (MAuint16 i = 0; i < regions_.size(); i++) + { + regions_[i]->SetWeight(weight_); + } } - try + /// @brief Set current event weight with a weight map + /// @param weight weight index and value + void SetCurrentEventWeight(std::map<MAuint32, MAfloat64> weight) { - if (myregions.size() == i) - throw EXCEPTION_WARNING("Assigning the cut \"" + name + - "\" to the non-existing signal region \"" + RSnames[i] + - "\"", - "", 0); + weight_.clear(); + weight_ = weight; + for (MAuint16 i = 0; i < regions_.size(); i++) + { + regions_[i]->SetWeight(weight_); + } } - catch (const std::exception &e) + + /// Set method + void SetRegionWeight(std::string name, MAfloat64 weight) { - MANAGE_EXCEPTION(e); + for (auto ® : regions_) + { + if (reg->GetName() == name) + { + reg->SetWeight(weight); + break; + } + } } - } - // Creating the cut - cutmanager_.AddCut(myname, myregions); - } + /// @brief set region weight with a weight map + /// @param name name of the region + /// @param weight weight map + void SetRegionWeight(std::string name, std::map<MAuint32, MAfloat64> weight) + { + for (auto ® : regions_) + { + if (reg->GetName() == name) + { + reg->SetWeight(weight); + break; + } + } + } - void AddCut(const std::string &name, std::vector<std::string> SRnames) - { - // The name of the cut - std::string myname = name; - if (myname.compare("") == 0) - { - std::stringstream numstream; - numstream << cutmanager_.GetCuts().size(); - myname = "Cut" + numstream.str(); - } - - // Creating the vector of SR of interests - std::vector<RegionSelection *> myregions; - for (MAuint32 i = 0; i < SRnames.size(); i++) - { - for (MAuint32 j = 0; j < regions_.size(); j++) + /// Adding a RegionSelection to the manager + void AddRegionSelection(const std::string &name) { - if (regions_[j]->GetName().compare(SRnames[i]) == 0) - { - myregions.push_back(regions_[j]); - break; - } + std::string myname = name; + if (myname.compare("") == 0) + { + std::stringstream numstream; + numstream << regions_.size(); + myname = "RegionSelection" + numstream.str(); + } + RegionSelection *myregion = new RegionSelection(name); + regions_.push_back(myregion); } - try + /// Getting ready for a new event + void InitializeForNewEvent(MAfloat64 EventWeight) { - if (myregions.size() == i) - throw EXCEPTION_WARNING("Assigning the cut \"" + name + - "\" to the non-existing signal region \"" + SRnames[i] + - "\"", - "", 0); + weight_.clear(); + weight_.insert(std::make_pair(0, EventWeight)); + NumberOfSurvivingRegions_ = regions_.size(); + for (auto ® : regions_) + reg->InitializeForNewEvent(EventWeight); + for (MAuint32 i = 0; i < plotmanager_.GetNplots(); i++) + plotmanager_.GetHistos()[i]->SetFreshEvent(true); } - catch (const std::exception &e) + + /// @brief initialise new event with multiweight definition + /// @param EventWeight weight map + void InitializeForNewEvent(std::map<MAuint32, MAfloat64> EventWeight) { - MANAGE_EXCEPTION(e); + weight_.clear(); + weight_ = EventWeight; + NumberOfSurvivingRegions_ = regions_.size(); + for (auto ® : regions_) + reg->InitializeForNewEvent(EventWeight); + for (MAuint32 i = 0; i < plotmanager_.GetNplots(); i++) + plotmanager_.GetHistos()[i]->SetFreshEvent(true); } - } - // Creating the cut - cutmanager_.AddCut(myname, myregions); - } + /// This method associates all regions with a cut + void AddCut(const std::string &name) + { + // The name of the cut + std::string myname = name; + if (myname.compare("") == 0) + { + std::stringstream numstream; + numstream << cutmanager_.GetCuts().size(); + myname = "Cut" + numstream.str(); + } + // Adding the cut to all the regions + cutmanager_.AddCut(myname, regions_); + } - /// Apply a cut - MAbool ApplyCut(MAbool, std::string const &); + /// This method associates one single region with a cut + void AddCut(const std::string &name, const std::string &RSname) + { + std::string RSnameA[] = {RSname}; + AddCut(name, RSnameA); + } - /// This method associates all signal regions with an histo - void AddHistoFrequency(const std::string &name) - { - // The name of the histo - std::string myname = name; - if (myname.compare("") == 0) - { - std::stringstream numstream; - numstream << plotmanager_.GetHistos().size(); - myname = "Histo" + numstream.str(); - } - // Adding the histo and linking all regions to the histo - plotmanager_.Add_HistoFrequency(myname, regions_); - } - - /// This method associates all signal regions with an histo - void AddHisto(const std::string &name, MAuint32 nb, MAfloat64 xmin, MAfloat64 xmax) - { - // The name of the histo - std::string myname = name; - if (myname.compare("") == 0) - { - std::stringstream numstream; - numstream << plotmanager_.GetHistos().size(); - myname = "Histo" + numstream.str(); - } - // Adding the histo and linking all regions to the histo - plotmanager_.Add_Histo(myname, nb, xmin, xmax, regions_); - } - - /// This method associates all signal regions with an histo - void AddHistoLogX(const std::string &name, MAuint32 nb, MAfloat64 xmin, MAfloat64 xmax) - { - // The name of the histo - std::string myname = name; - if (myname.compare("") == 0) - { - std::stringstream numstream; - numstream << plotmanager_.GetHistos().size(); - myname = "Histo" + numstream.str(); - } - // Adding the histo and linking all regions to the histo - plotmanager_.Add_HistoLogX(myname, nb, xmin, xmax, regions_); - } - - /// This method associates one single signal region with an histo - void AddHisto(const std::string &name, MAuint32 nb, MAfloat64 xmin, MAfloat64 xmax, - const std::string &RSname) - { - std::string RSnameA[] = {RSname}; - AddHisto(name, nb, xmin, xmax, RSnameA); - } + /// this method associates an arbitrary number of RS with a cut + template <int NRS> + void AddCut(const std::string &name, std::string const (&RSnames)[NRS]) + { + // The name of the cut + std::string myname = name; + if (myname.compare("") == 0) + { + std::stringstream numstream; + numstream << cutmanager_.GetCuts().size(); + myname = "Cut" + numstream.str(); + } + + // Creating the vector of SR of interests + std::vector<RegionSelection *> myregions; + for (MAuint32 i = 0; i < NRS; i++) + { + for (MAuint32 j = 0; j < regions_.size(); j++) + { + if (regions_[j]->GetName().compare(RSnames[i]) == 0) + { + myregions.push_back(regions_[j]); + break; + } + } + + try + { + if (myregions.size() == i) + throw EXCEPTION_WARNING("Assigning the cut \"" + name + + "\" to the non-existing signal region \"" + RSnames[i] + + "\"", + "", 0); + } + catch (const std::exception &e) + { + MANAGE_EXCEPTION(e); + } + } + + // Creating the cut + cutmanager_.AddCut(myname, myregions); + } - /// This method associates one single signal region with an histo - void AddHistoLogX(const std::string &name, MAuint32 nb, MAfloat64 xmin, MAfloat64 xmax, - const std::string &RSname) - { - std::string RSnameA[] = {RSname}; - AddHistoLogX(name, nb, xmin, xmax, RSnameA); - } - /// This method associates one single signal region with an histo - void AddHistoFrequency(const std::string &name, const std::string &RSname) - { - std::string RSnameA[] = {RSname}; - AddHistoFrequency(name, RSnameA); - } - - /// this method associates an arbitrary number of RS with an histo - template <int NRS> - void AddHisto(const std::string &name, MAuint32 nb, - MAfloat64 xmin, MAfloat64 xmax, std::string const (&RSnames)[NRS]) - { - // The name of the histo - std::string myname = name; - if (myname.compare("") == 0) - { - std::stringstream numstream; - numstream << plotmanager_.GetNplots(); - myname = "Histo" + numstream.str(); - } - // Creating the vector of SR of interests - std::vector<RegionSelection *> myregions; - for (MAuint32 i = 0; i < NRS; i++) - { - for (MAuint32 j = 0; j < regions_.size(); j++) + void AddCut(const std::string &name, std::vector<std::string> SRnames) { - if (regions_[j]->GetName().compare(RSnames[i]) == 0) - { - myregions.push_back(regions_[j]); - break; - } + // The name of the cut + std::string myname = name; + if (myname.compare("") == 0) + { + std::stringstream numstream; + numstream << cutmanager_.GetCuts().size(); + myname = "Cut" + numstream.str(); + } + + // Creating the vector of SR of interests + std::vector<RegionSelection *> myregions; + for (MAuint32 i = 0; i < SRnames.size(); i++) + { + for (MAuint32 j = 0; j < regions_.size(); j++) + { + if (regions_[j]->GetName().compare(SRnames[i]) == 0) + { + myregions.push_back(regions_[j]); + break; + } + } + + try + { + if (myregions.size() == i) + throw EXCEPTION_WARNING("Assigning the cut \"" + name + + "\" to the non-existing signal region \"" + SRnames[i] + + "\"", + "", 0); + } + catch (const std::exception &e) + { + MANAGE_EXCEPTION(e); + } + } + + // Creating the cut + cutmanager_.AddCut(myname, myregions); } - try + + /// Apply a cut + MAbool ApplyCut(MAbool, std::string const &); + + /// This method associates all signal regions with an histo + void AddHistoFrequency(const std::string &name) { - if (myregions.size() == i) - throw EXCEPTION_WARNING("Assigning the histo \"" + name + - "\" to the non-existing signal region \"" + RSnames[i] + - "\"", - "", 0); + // The name of the histo + std::string myname = name; + if (myname.compare("") == 0) + { + std::stringstream numstream; + numstream << plotmanager_.GetHistos().size(); + myname = "Histo" + numstream.str(); + } + // Adding the histo and linking all regions to the histo + plotmanager_.Add_HistoFrequency(myname, regions_); } - catch (const std::exception &e) + + /// This method associates all signal regions with an histo + void AddHisto(const std::string &name, MAuint32 nb, MAfloat64 xmin, MAfloat64 xmax) { - MANAGE_EXCEPTION(e); + // The name of the histo + std::string myname = name; + if (myname.compare("") == 0) + { + std::stringstream numstream; + numstream << plotmanager_.GetHistos().size(); + myname = "Histo" + numstream.str(); + } + // Adding the histo and linking all regions to the histo + plotmanager_.Add_Histo(myname, nb, xmin, xmax, regions_); } - } - // Creating the histo - plotmanager_.Add_Histo(myname, nb, xmin, xmax, myregions); - } + /// This method associates all signal regions with an histo + void AddHistoLogX(const std::string &name, MAuint32 nb, MAfloat64 xmin, MAfloat64 xmax) + { + // The name of the histo + std::string myname = name; + if (myname.compare("") == 0) + { + std::stringstream numstream; + numstream << plotmanager_.GetHistos().size(); + myname = "Histo" + numstream.str(); + } + // Adding the histo and linking all regions to the histo + plotmanager_.Add_HistoLogX(myname, nb, xmin, xmax, regions_); + } - /// this method associates an arbitrary number of RS with an histo - template <int NRS> - void AddHistoLogX(const std::string &name, MAuint32 nb, - MAfloat64 xmin, MAfloat64 xmax, std::string const (&RSnames)[NRS]) - { - // The name of the histo - std::string myname = name; - if (myname.compare("") == 0) - { - std::stringstream numstream; - numstream << plotmanager_.GetNplots(); - myname = "Histo" + numstream.str(); - } - // Creating the vector of SR of interests - std::vector<RegionSelection *> myregions; - for (MAuint32 i = 0; i < NRS; i++) - { - for (MAuint32 j = 0; j < regions_.size(); j++) + /// This method associates one single signal region with an histo + void AddHisto(const std::string &name, MAuint32 nb, MAfloat64 xmin, MAfloat64 xmax, + const std::string &RSname) { - if (regions_[j]->GetName().compare(RSnames[i]) == 0) - { - myregions.push_back(regions_[j]); - break; - } + std::string RSnameA[] = {RSname}; + AddHisto(name, nb, xmin, xmax, RSnameA); } - try + + /// This method associates one single signal region with an histo + void AddHistoLogX(const std::string &name, MAuint32 nb, MAfloat64 xmin, MAfloat64 xmax, + const std::string &RSname) { - if (myregions.size() == i) - throw EXCEPTION_WARNING("Assigning the histo \"" + name + - "\" to the non-existing signal region \"" + RSnames[i] + - "\"", - "", 0); + std::string RSnameA[] = {RSname}; + AddHistoLogX(name, nb, xmin, xmax, RSnameA); } - catch (const std::exception &e) + /// This method associates one single signal region with an histo + void AddHistoFrequency(const std::string &name, const std::string &RSname) { - MANAGE_EXCEPTION(e); + std::string RSnameA[] = {RSname}; + AddHistoFrequency(name, RSnameA); } - } - // Creating the histo - plotmanager_.Add_HistoLogX(myname, nb, xmin, xmax, myregions); - } - - /// this method associates an arbitrary number of RS with an histo - template <int NRS> - void AddHistoFrequency(const std::string &name, std::string const (&RSnames)[NRS]) - { - // The name of the histo - std::string myname = name; - if (myname.compare("") == 0) - { - std::stringstream numstream; - numstream << plotmanager_.GetNplots(); - myname = "Histo" + numstream.str(); - } - // Creating the vector of SR of interests - std::vector<RegionSelection *> myregions; - for (MAuint32 i = 0; i < NRS; i++) - { - for (MAuint32 j = 0; j < regions_.size(); j++) + /// this method associates an arbitrary number of RS with an histo + template <int NRS> + void AddHisto(const std::string &name, MAuint32 nb, + MAfloat64 xmin, MAfloat64 xmax, std::string const (&RSnames)[NRS]) { - if (regions_[j]->GetName().compare(RSnames[i]) == 0) - { - myregions.push_back(regions_[j]); - break; - } + // The name of the histo + std::string myname = name; + if (myname.compare("") == 0) + { + std::stringstream numstream; + numstream << plotmanager_.GetNplots(); + myname = "Histo" + numstream.str(); + } + // Creating the vector of SR of interests + std::vector<RegionSelection *> myregions; + for (MAuint32 i = 0; i < NRS; i++) + { + for (MAuint32 j = 0; j < regions_.size(); j++) + { + if (regions_[j]->GetName().compare(RSnames[i]) == 0) + { + myregions.push_back(regions_[j]); + break; + } + } + try + { + if (myregions.size() == i) + throw EXCEPTION_WARNING("Assigning the histo \"" + name + + "\" to the non-existing signal region \"" + RSnames[i] + + "\"", + "", 0); + } + catch (const std::exception &e) + { + MANAGE_EXCEPTION(e); + } + } + + // Creating the histo + plotmanager_.Add_Histo(myname, nb, xmin, xmax, myregions); } - try + + /// this method associates an arbitrary number of RS with an histo + template <int NRS> + void AddHistoLogX(const std::string &name, MAuint32 nb, + MAfloat64 xmin, MAfloat64 xmax, std::string const (&RSnames)[NRS]) { - if (myregions.size() == i) - throw EXCEPTION_WARNING("Assigning the histo \"" + name + - "\" to the non-existing signal region \"" + RSnames[i] + - "\"", - "", 0); + // The name of the histo + std::string myname = name; + if (myname.compare("") == 0) + { + std::stringstream numstream; + numstream << plotmanager_.GetNplots(); + myname = "Histo" + numstream.str(); + } + // Creating the vector of SR of interests + std::vector<RegionSelection *> myregions; + for (MAuint32 i = 0; i < NRS; i++) + { + for (MAuint32 j = 0; j < regions_.size(); j++) + { + if (regions_[j]->GetName().compare(RSnames[i]) == 0) + { + myregions.push_back(regions_[j]); + break; + } + } + try + { + if (myregions.size() == i) + throw EXCEPTION_WARNING("Assigning the histo \"" + name + + "\" to the non-existing signal region \"" + RSnames[i] + + "\"", + "", 0); + } + catch (const std::exception &e) + { + MANAGE_EXCEPTION(e); + } + } + + // Creating the histo + plotmanager_.Add_HistoLogX(myname, nb, xmin, xmax, myregions); } - catch (const std::exception &e) + + /// this method associates an arbitrary number of RS with an histo + template <int NRS> + void AddHistoFrequency(const std::string &name, std::string const (&RSnames)[NRS]) { - MANAGE_EXCEPTION(e); + // The name of the histo + std::string myname = name; + if (myname.compare("") == 0) + { + std::stringstream numstream; + numstream << plotmanager_.GetNplots(); + myname = "Histo" + numstream.str(); + } + // Creating the vector of SR of interests + std::vector<RegionSelection *> myregions; + for (MAuint32 i = 0; i < NRS; i++) + { + for (MAuint32 j = 0; j < regions_.size(); j++) + { + if (regions_[j]->GetName().compare(RSnames[i]) == 0) + { + myregions.push_back(regions_[j]); + break; + } + } + try + { + if (myregions.size() == i) + throw EXCEPTION_WARNING("Assigning the histo \"" + name + + "\" to the non-existing signal region \"" + RSnames[i] + + "\"", + "", 0); + } + catch (const std::exception &e) + { + MANAGE_EXCEPTION(e); + } + } + + // Creating the histo + plotmanager_.Add_HistoFrequency(myname, myregions); } - } - // Creating the histo - plotmanager_.Add_HistoFrequency(myname, myregions); - } + /// Filling an histo with a value val + void FillHisto(std::string const &, MAfloat64 val); - /// Filling an histo with a value val - void FillHisto(std::string const &, MAfloat64 val); + /// Writing the definition saf file + void WriteHistoDefinition(SAFWriter &output); - /// Writing the definition saf file - void WriteHistoDefinition(SAFWriter &output); + /// Checking if a given RS is surviging + MAbool IsSurviving(const std::string &RSname) + { + // Looking for the region and checking its status + for (MAuint32 i = 0; i < regions_.size(); i++) + { + if (regions_[i]->GetName().compare(RSname) == 0) + return regions_[i]->IsSurviving(); + } + + // The region has not been found + try + { + throw EXCEPTION_WARNING("Checking whether the non-declared region \"" + + RSname + "\" is surviving the applied cuts.", + "", 0); + } + catch (const std::exception &e) + { + MANAGE_EXCEPTION(e); + } + + return false; + } - /// Checking if a given RS is surviging - MAbool IsSurviving(const std::string &RSname) - { - // Looking for the region and checking its status - for (MAuint32 i = 0; i < regions_.size(); i++) - { - if (regions_[i]->GetName().compare(RSname) == 0) - return regions_[i]->IsSurviving(); - } - - // The region has not been found - try - { - throw EXCEPTION_WARNING("Checking whether the non-declared region \"" + - RSname + "\" is surviving the applied cuts.", - "", 0); - } - catch (const std::exception &e) - { - MANAGE_EXCEPTION(e); - } - - return false; - } - - /// Dumping the content of the counters - void HeadSR(std::ostream &, const std::string &, MAbool &); - void DumpSR(std::ostream &, MAbool &); - }; + /// Dumping the content of the counters + void HeadSR(std::ostream &, const std::string &, MAbool &); + void DumpSR(std::ostream &, MAbool &); + }; } #endif From bfab5b20b5cb99bc19b43c73dc88c1d499c5d41c Mon Sep 17 00:00:00 2001 From: "Jack Y. Araz" <jackaraz@gmail.com> Date: Sat, 24 Jun 2023 12:05:11 +0100 Subject: [PATCH 002/107] multiweight adaptation --- tools/SampleAnalyzer/Process/Plot/Histo.cpp | 110 +++--- tools/SampleAnalyzer/Process/Plot/Histo.h | 377 ++++++++++---------- 2 files changed, 259 insertions(+), 228 deletions(-) diff --git a/tools/SampleAnalyzer/Process/Plot/Histo.cpp b/tools/SampleAnalyzer/Process/Plot/Histo.cpp index fea5447f..eada9936 100644 --- a/tools/SampleAnalyzer/Process/Plot/Histo.cpp +++ b/tools/SampleAnalyzer/Process/Plot/Histo.cpp @@ -1,35 +1,33 @@ //////////////////////////////////////////////////////////////////////////////// -// +// // Copyright (C) 2012-2023 Jack Araz, Eric Conte & Benjamin Fuks // The MadAnalysis development team, email: <ma5team@iphc.cnrs.fr> -// +// // This file is part of MadAnalysis 5. // Official website: <https://github.com/MadAnalysis/madanalysis5> -// +// // MadAnalysis 5 is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // MadAnalysis 5 is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with MadAnalysis 5. If not, see <http://www.gnu.org/licenses/> -// +// //////////////////////////////////////////////////////////////////////////////// - // SampleAnalyzer headers #include "SampleAnalyzer/Process/Plot/Histo.h" using namespace MA5; - /// Write the plot in a Text file -void Histo::Write_TextFormat(std::ostream* output) +void Histo::Write_TextFormat(std::ostream *output) { // Header *output << "<Histo>" << std::endl; @@ -42,9 +40,8 @@ void Histo::Write_TextFormat(std::ostream* output) *output << std::endl; } - /// Write the plot in a Text file -void Histo::Write_TextFormatBody(std::ostream* output) +void Histo::Write_TextFormatBody(std::ostream *output) { // Description *output << " <Description>" << std::endl; @@ -52,7 +49,7 @@ void Histo::Write_TextFormatBody(std::ostream* output) // Name *output << " \"" << name_ << "\"" << std::endl; - // Title + // Title *output << " "; output->width(10); *output << std::left << "# nbins"; @@ -63,21 +60,25 @@ void Histo::Write_TextFormatBody(std::ostream* output) // Data *output << " "; - output->width( 8); *output << std::left << nbins_; - output->width(15); *output << std::left << std::scientific << xmin_; - output->width(15); *output << std::left << std::scientific << xmax_ << std::endl; + output->width(8); + *output << std::left << nbins_; + output->width(15); + *output << std::left << std::scientific << xmin_; + output->width(15); + *output << std::left << std::scientific << xmax_ << std::endl; // SelectionRegions - if(regions_.size()!=0) + if (regions_.size() != 0) { - MAuint32 maxlength=0; - for(MAuint32 i=0; i < regions_.size(); i++) - if (regions_[i]->GetName().size()>maxlength) maxlength=regions_[i]->GetName().size(); + MAuint32 maxlength = 0; + for (MAuint32 i = 0; i < regions_.size(); i++) + if (regions_[i]->GetName().size() > maxlength) + maxlength = regions_[i]->GetName().size(); *output << std::left << " # Defined regions" << std::endl; - for(MAuint32 i=0; i < regions_.size(); i++) + for (MAuint32 i = 0; i < regions_.size(); i++) { *output << " " << std::setw(maxlength) << std::left << regions_[i]->GetName(); - *output << " # Region nr. " << std::fixed << i+1 << std::endl; + *output << " # Region nr. " << std::fixed << i + 1 << std::endl; } } @@ -88,54 +89,73 @@ void Histo::Write_TextFormatBody(std::ostream* output) *output << " <Statistics>" << std::endl; *output << " "; - output->width(15); *output << std::fixed << nevents_.first; - output->width(15); *output << std::fixed << nevents_.second; + output->width(15); + *output << std::fixed << nevents_.first; + output->width(15); + *output << std::fixed << nevents_.second; *output << " # nevents" << std::endl; *output << " "; - output->width(15); *output << std::scientific << nevents_w_.first; - output->width(15); *output << std::scientific << nevents_w_.second; + output->width(15); + *output << std::scientific << nevents_w_.first; + output->width(15); + *output << std::scientific << nevents_w_.second; *output << " # sum of event-weights over events" << std::endl; *output << " "; - output->width(15); *output << std::fixed << nentries_.first; - output->width(15); *output << std::fixed << nentries_.second; + output->width(15); + *output << std::fixed << nentries_.first; + output->width(15); + *output << std::fixed << nentries_.second; *output << " # nentries" << std::endl; *output << " "; - output->width(15); *output << std::scientific << sum_w_.first; - output->width(15); *output << std::scientific << sum_w_.second; + output->width(15); + *output << std::scientific << sum_w_[0].first; + output->width(15); + *output << std::scientific << sum_w_[0].second; *output << " # sum of event-weights over entries" << std::endl; *output << " "; - output->width(15); *output << std::scientific << sum_ww_.first; - output->width(15); *output << std::scientific << sum_ww_.second; + output->width(15); + *output << std::scientific << sum_ww_[0].first; + output->width(15); + *output << std::scientific << sum_ww_[0].second; *output << " # sum weights^2" << std::endl; *output << " "; - output->width(15); *output << std::scientific << sum_xw_.first; - output->width(15); *output << std::scientific << sum_xw_.second; + output->width(15); + *output << std::scientific << sum_xw_[0].first; + output->width(15); + *output << std::scientific << sum_xw_[0].second; *output << " # sum value*weight" << std::endl; *output << " "; - output->width(15); *output << std::scientific << sum_xxw_.first; - output->width(15); *output << std::scientific << sum_xxw_.second; + output->width(15); + *output << std::scientific << sum_xxw_[0].first; + output->width(15); + *output << std::scientific << sum_xxw_[0].second; *output << " # sum value^2*weight" << std::endl; *output << " </Statistics>" << std::endl; // Data *output << " <Data>" << std::endl; *output << " "; - output->width(15); *output << std::scientific << underflow_.first; - output->width(15); *output << std::scientific << underflow_.second; + output->width(15); + *output << std::scientific << underflow_[0].first; + output->width(15); + *output << std::scientific << underflow_[0].second; *output << " # underflow" << std::endl; - for (MAuint32 i=0;i<histo_.size();i++) + for (MAuint32 i = 0; i < histo_.size(); i++) { *output << " "; - output->width(15); *output << std::scientific << histo_[i].first; - output->width(15); *output << std::scientific << histo_[i].second; - if (i<2 || i>=(histo_.size()-2)) - *output << " # bin " << i+1 << " / " << histo_.size(); + output->width(15); + *output << std::scientific << histo_[0][i].first; + output->width(15); + *output << std::scientific << histo_[0][i].second; + if (i < 2 || i >= (histo_.size() - 2)) + *output << " # bin " << i + 1 << " / " << histo_.size(); *output << std::endl; } *output << " "; - output->width(15); *output << std::scientific << overflow_.first; - output->width(15); *output << std::scientific << overflow_.second; + output->width(15); + *output << std::scientific << overflow_[0].first; + output->width(15); + *output << std::scientific << overflow_[0].second; *output << " # overflow" << std::endl; *output << " </Data>" << std::endl; } - diff --git a/tools/SampleAnalyzer/Process/Plot/Histo.h b/tools/SampleAnalyzer/Process/Plot/Histo.h index c4b1474d..28b91852 100644 --- a/tools/SampleAnalyzer/Process/Plot/Histo.h +++ b/tools/SampleAnalyzer/Process/Plot/Histo.h @@ -1,31 +1,29 @@ //////////////////////////////////////////////////////////////////////////////// -// +// // Copyright (C) 2012-2023 Jack Araz, Eric Conte & Benjamin Fuks // The MadAnalysis development team, email: <ma5team@iphc.cnrs.fr> -// +// // This file is part of MadAnalysis 5. // Official website: <https://github.com/MadAnalysis/madanalysis5> -// +// // MadAnalysis 5 is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // MadAnalysis 5 is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with MadAnalysis 5. If not, see <http://www.gnu.org/licenses/> -// +// //////////////////////////////////////////////////////////////////////////////// - #ifndef HISTO_H #define HISTO_H - // STL headers #include <map> #include <cmath> @@ -36,186 +34,199 @@ #include "SampleAnalyzer/Process/RegionSelection/RegionSelection.h" #include "SampleAnalyzer/Commons/Service/ExceptionService.h" - namespace MA5 { -class Histo : public PlotBase -{ - - // ------------------------------------------------------------- - // data members - // ------------------------------------------------------------- - protected : - - /// Histogram arrays - std::vector< std::pair<MAfloat64,MAfloat64> > histo_; - std::pair<MAfloat64, MAfloat64> underflow_; - std::pair<MAfloat64, MAfloat64> overflow_; - - /// Histogram description - MAuint32 nbins_; - MAfloat64 xmin_; - MAfloat64 xmax_; - MAfloat64 step_; - - /// Sum of event-weights over entries - std::pair<MAfloat64,MAfloat64> sum_w_; - - /// Sum of squared weights - std::pair<MAfloat64,MAfloat64> sum_ww_; - - /// Sum of value * weight - std::pair<MAfloat64,MAfloat64> sum_xw_; - - /// Sum of value * value * weight - std::pair<MAfloat64,MAfloat64> sum_xxw_; - - /// RegionSelections attached to the histo - std::vector<RegionSelection*> regions_; - - // ------------------------------------------------------------- - // method members - // ------------------------------------------------------------- - public : - - /// Constructor without argument - Histo() : PlotBase() - { - nbins_=100; xmin_=0; xmax_=100; - step_ = (xmax_ - xmin_)/static_cast<MAfloat64>(nbins_); - } - - /// Constructor with argument - Histo(const std::string& name) : PlotBase(name) - { } - - /// Constructor with argument - Histo(const std::string& name, MAuint32 nbins, MAfloat64 xmin, MAfloat64 xmax) : - PlotBase(name) - { - // Setting the description: nbins - try - { - if (nbins==0) throw EXCEPTION_WARNING("nbins cannot be equal to 0. Set 100.","",0); - nbins_ = nbins; - } - catch (const std::exception& e) + class Histo : public PlotBase { - MANAGE_EXCEPTION(e); - nbins_ = 100; - } - // Setting the description: min & max - try - { - if (xmin>=xmax) throw EXCEPTION_WARNING("xmin cannot be equal to or greater than xmax. Setting xmin to 0 and xmax to 100.","",0); - xmin_ = xmin; - xmax_ = xmax; - } - catch (const std::exception& e) - { - MANAGE_EXCEPTION(e); - xmin_=0.; - xmax_=100.; - } - - step_ = (xmax_ - xmin_)/static_cast<MAfloat64>(nbins_); - - // Reseting the histogram array - histo_.resize(nbins_,std::make_pair(0.,0.)); - underflow_ = std::make_pair(0.,0.); - overflow_ = std::make_pair(0.,0.); - - // Reseting statistical counters - sum_w_ = std::make_pair(0.,0.); - sum_ww_ = std::make_pair(0.,0.); - sum_xw_ = std::make_pair(0.,0.); - sum_xxw_ = std::make_pair(0.,0.); - } - - /// Destructor - virtual ~Histo() - { } - - /// Setting the linked regions - void SetSelectionRegions(std::vector<RegionSelection*> myregions) - { regions_.insert(regions_.end(), myregions.begin(), myregions.end()); } - - /// Checking that all regions of the histo are surviving - /// Returns 0 if all regions are failing (includes te case with 0 SR) - /// Returns 1 if all regions are passing - // returns -1 otherwise - MAint32 AllSurviving() - { - if (regions_.size() == 0) return 0; - MAbool FirstRegionSurvival = regions_[0]->IsSurviving(); - for(MAuint32 ii=1; ii < regions_.size(); ii++) - if(regions_[ii]->IsSurviving() != FirstRegionSurvival) return -1; - if(FirstRegionSurvival) return 1; - else return 0; - } - - /// Filling histogram - void Fill(MAfloat64 value, MAfloat64 weight=1.0) - { - // Safety : nan or isinf - try - { - if (std::isnan(value)) throw EXCEPTION_WARNING("Skipping a NaN (Not a Number) value in an histogram.","",0); - if (std::isinf(value)) throw EXCEPTION_WARNING("Skipping a Infinity value in an histogram.","",0); - } - catch (const std::exception& e) - { - MANAGE_EXCEPTION(e); - } - - // Positive weight - if (weight>=0) - { - nentries_.first++; - sum_w_.first +=weight; - sum_ww_.first +=weight*weight; - sum_xw_.first +=value*weight; - sum_xxw_.first +=value*value*weight; - if (value < xmin_) underflow_.first+=weight; - else if (value >= xmax_) overflow_.first+=weight; - else - { - histo_[std::floor((value-xmin_)/step_)].first+=weight; - } - } - - // Negative weight - else - { - nentries_.second++; - weight=std::abs(weight); - sum_w_.second += weight; - sum_ww_.second += weight*weight; - sum_xw_.second += value*weight; - sum_xxw_.second += value*value*weight; - if (value < xmin_) underflow_.second+=weight; - else if (value >= xmax_) overflow_.second+=weight; - else - { - histo_[std::floor((value-xmin_)/step_)].second+=weight; - } - } - } - - /// Write the plot in a ROOT file - virtual void Write_TextFormat(std::ostream* output); - - /// Write the plot in a ROOT file - // virtual void Write_RootFormat(std::pair<TH1F*,TH1F*>& histos); - - protected: - - /// Write the plot in a ROOT file - virtual void Write_TextFormatBody(std::ostream* output); - -}; + // ------------------------------------------------------------- + // data members + // ------------------------------------------------------------- + protected: + /// Histogram arrays + std::map<MAint32, std::vector<std::pair<MAfloat64, MAfloat64>>> histo_; + std::map<MAint32, std::pair<MAfloat64, MAfloat64>> underflow_; + std::map<MAint32, std::pair<MAfloat64, MAfloat64>> overflow_; + + /// Histogram description + MAuint32 nbins_; + MAfloat64 xmin_; + MAfloat64 xmax_; + MAfloat64 step_; + + /// Sum of event-weights over entries + std::map<MAint32, std::pair<MAfloat64, MAfloat64>> sum_w_; + + /// Sum of squared weights + std::map<MAint32, std::pair<MAfloat64, MAfloat64>> sum_ww_; + + /// Sum of value * weight + std::map<MAint32, std::pair<MAfloat64, MAfloat64>> sum_xw_; + + /// Sum of value * value * weight + std::map<MAint32, std::pair<MAfloat64, MAfloat64>> sum_xxw_; + + /// RegionSelections attached to the histo + std::vector<RegionSelection *> regions_; + + // ------------------------------------------------------------- + // method members + // ------------------------------------------------------------- + public: + /// Constructor without argument + Histo() : PlotBase() + { + nbins_ = 100; + xmin_ = 0; + xmax_ = 100; + step_ = (xmax_ - xmin_) / static_cast<MAfloat64>(nbins_); + } + + /// Constructor with argument + Histo(const std::string &name) : PlotBase(name) {} + + /// Constructor with argument + Histo(const std::string &name, MAuint32 nbins, MAfloat64 xmin, MAfloat64 xmax) : PlotBase(name) + { + // Setting the description: nbins + try + { + if (nbins == 0) + throw EXCEPTION_WARNING("nbins cannot be equal to 0. Set 100.", "", 0); + nbins_ = nbins; + } + catch (const std::exception &e) + { + MANAGE_EXCEPTION(e); + nbins_ = 100; + } + + // Setting the description: min & max + try + { + if (xmin >= xmax) + throw EXCEPTION_WARNING("xmin cannot be equal to or greater than xmax. Setting xmin to 0 and xmax to 100.", "", 0); + xmin_ = xmin; + xmax_ = xmax; + } + catch (const std::exception &e) + { + MANAGE_EXCEPTION(e); + xmin_ = 0.; + xmax_ = 100.; + } + + step_ = (xmax_ - xmin_) / static_cast<MAfloat64>(nbins_); + + // Reseting the histogram array + histo_[0].resize(nbins_, std::make_pair(0., 0.)); + underflow_[0] = std::make_pair(0., 0.); + overflow_[0] = std::make_pair(0., 0.); + + // Reseting statistical counters + sum_w_[0] = std::make_pair(0., 0.); + sum_ww_[0] = std::make_pair(0., 0.); + sum_xw_[0] = std::make_pair(0., 0.); + sum_xxw_[0] = std::make_pair(0., 0.); + } + + /// Destructor + virtual ~Histo() {} + + /// Setting the linked regions + void SetSelectionRegions(std::vector<RegionSelection *> myregions) + { + regions_.insert(regions_.end(), myregions.begin(), myregions.end()); + } + + /// Checking that all regions of the histo are surviving + /// Returns 0 if all regions are failing (includes te case with 0 SR) + /// Returns 1 if all regions are passing + // returns -1 otherwise + MAint32 AllSurviving() + { + if (regions_.size() == 0) + return 0; + MAbool FirstRegionSurvival = regions_[0]->IsSurviving(); + for (MAuint32 ii = 1; ii < regions_.size(); ii++) + if (regions_[ii]->IsSurviving() != FirstRegionSurvival) + return -1; + if (FirstRegionSurvival) + return 1; + else + return 0; + } + + /// Filling histogram + void Fill(MAfloat64 value, std::map<MAint32, MAdouble64> weights) + { + // Safety : nan or isinf + try + { + if (std::isnan(value)) + throw EXCEPTION_WARNING("Skipping a NaN (Not a Number) value in an histogram.", "", 0); + if (std::isinf(value)) + throw EXCEPTION_WARNING("Skipping a Infinity value in an histogram.", "", 0); + } + catch (const std::exception &e) + { + MANAGE_EXCEPTION(e); + } + + for (auto &wmap : weights) + { + MAdouble64 weight = wmap.second; + MAint32 idx = wmap.first; + // Positive weight + if (weight >= 0) + { + nentries_.first++; + sum_w_[idx].first += weight; + sum_ww_[idx].first += weight * weight; + sum_xw_[idx].first += value * weight; + sum_xxw_[idx].first += value * value * weight; + if (value < xmin_) + underflow_[idx].first += weight; + else if (value >= xmax_) + overflow_[idx].first += weight; + else + { + histo_[idx][std::floor((value - xmin_) / step_)].first += weight; + } + } + + // Negative weight + else + { + nentries_.second++; + weight = std::abs(weight); + sum_w_[idx].second += weight; + sum_ww_[idx].second += weight * weight; + sum_xw_[idx].second += value * weight; + sum_xxw_[idx].second += value * value * weight; + if (value < xmin_) + underflow_[idx].second += weight; + else if (value >= xmax_) + overflow_[idx].second += weight; + else + { + histo_[idx][std::floor((value - xmin_) / step_)].second += weight; + } + } + } + } + + /// Write the plot in a ROOT file + virtual void Write_TextFormat(std::ostream *output); + + /// Write the plot in a ROOT file + // virtual void Write_RootFormat(std::pair<TH1F*,TH1F*>& histos); + + protected: + /// Write the plot in a ROOT file + virtual void Write_TextFormatBody(std::ostream *output); + }; } From 5e405c6dc5353d9fe69dcb141a65f76926e4194b Mon Sep 17 00:00:00 2001 From: "Jack Y. Araz" <jackaraz@gmail.com> Date: Mon, 26 Jun 2023 17:29:45 +0100 Subject: [PATCH 003/107] refactor --- tools/SampleAnalyzer/Process/Counter/Basics.h | 44 +++++++++++++ .../SampleAnalyzer/Process/Counter/Counter.h | 64 +++++++++++------- .../Process/Counter/CounterManager.h | 52 ++++++--------- .../Process/RegionSelection/RegionSelection.h | 65 +++---------------- 4 files changed, 111 insertions(+), 114 deletions(-) create mode 100644 tools/SampleAnalyzer/Process/Counter/Basics.h diff --git a/tools/SampleAnalyzer/Process/Counter/Basics.h b/tools/SampleAnalyzer/Process/Counter/Basics.h new file mode 100644 index 00000000..7d87fda1 --- /dev/null +++ b/tools/SampleAnalyzer/Process/Counter/Basics.h @@ -0,0 +1,44 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2012-2023 Jack Araz, Eric Conte & Benjamin Fuks +// The MadAnalysis development team, email: <ma5team@iphc.cnrs.fr> +// +// This file is part of MadAnalysis 5. +// Official website: <https://github.com/MadAnalysis/madanalysis5> +// +// MadAnalysis 5 is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// MadAnalysis 5 is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with MadAnalysis 5. If not, see <http://www.gnu.org/licenses/> +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef BASICS_h +#define BASICS_h + +#include "SampleAnalyzer/Commons/Base/PortableDatatypes.h" + +namespace MA5 +{ + struct ENTRIES + { + MAint32 positive = 0; + MAint32 negative = 0; + }; + + struct WEIGHTS + { + MAdouble64 positive = 0.0; + MAdouble64 negative = 0.0; + }; +} + +#endif \ No newline at end of file diff --git a/tools/SampleAnalyzer/Process/Counter/Counter.h b/tools/SampleAnalyzer/Process/Counter/Counter.h index 10459f6b..435b1ecd 100644 --- a/tools/SampleAnalyzer/Process/Counter/Counter.h +++ b/tools/SampleAnalyzer/Process/Counter/Counter.h @@ -26,6 +26,7 @@ // SampleAnalyzer headers #include "SampleAnalyzer/Commons/Base/PortableDatatypes.h" +#include "SampleAnalyzer/Process/Counter/Basics.h" // STL headers #include <iostream> @@ -34,12 +35,11 @@ namespace MA5 { - - class CounterCollection; + class CounterManager; class Counter { - friend class CounterCollection; + friend class CounterManager; // ------------------------------------------------------------- // data members @@ -50,15 +50,15 @@ namespace MA5 /// number of times the function Increment is called /// first = positive weight ; second = negative weight - std::pair<MAint64, MAint64> nentries_; + std::map<MAint32, ENTRIES> nentries_; /// sum of weights /// first = positive weight ; second = negative weight - std::map<MAuint32, std::pair<MAfloat64, MAfloat64>> sumweight_; + std::map<MAint32, WEIGHTS> sumweights_; /// sum of squared weights /// first = positive weight ; second = negative weight - std::map<MAuint32, std::pair<MAfloat64, MAfloat64>> sumweight2_; + std::map<MAint32, WEIGHTS> sumweights2_; // ------------------------------------------------------------- // method members @@ -68,9 +68,7 @@ namespace MA5 Counter(const std::string &name = "unkwown") { name_ = name; - nentries_ = std::make_pair(0, 0); - sumweight_[0] = std::make_pair(0., 0.); - sumweight2_[0] = std::make_pair(0., 0.); + Reset(); } /// Destructor @@ -79,29 +77,47 @@ namespace MA5 /// Reset void Reset() { - nentries_ = std::make_pair(0, 0); - sumweight_.clear(); - sumweight2_.clear(); + nentries_.clear(); + sumweights_.clear(); + sumweights2_.clear(); } + MAint32 size() { return nentries_.size(); } + + void Initialise(const WeightCollection &multiweight) + { + Reset(); + for (auto &weight : multiweight.GetWeights()) + { + + nentries_[weight.first] = ENTRIES(); + sumweights_[weight.first] = WEIGHTS(); + sumweights2_[weight.first] = WEIGHTS(); + } + } + + std::map<MAint32, ENTRIES> nentries() { return nentries_; } + std::map<MAint32, WEIGHTS> sumW() { return sumweights_; } + std::map<MAint32, WEIGHTS> sumW2() { return sumweights2_; } + /// Increment the counter - void Increment(const std::map<MAuint32, MAfloat64> &multiweight) + void Increment(const WeightCollection &multiweight) { - for (auto ¤t_weight : multiweight) + for (auto &weight : multiweight.GetWeights()) { - MAfloat64 weight = current_weight.second; - MAuint32 idx = current_weight.first; - if (weight > 0) + MAint32 idx = weight.first; + MAdouble64 w = weight.second; + if (w >= 0) { - nentries_.first++; - sumweight_[idx].first += weight; - sumweight2_[idx].first += weight * weight; + nentries_[idx].positive++; + sumweights_[idx].positive += w; + sumweights2_[idx].positive += w * w; } - else if (weight < 0) + else { - nentries_.second++; - sumweight_[idx].second += weight; - sumweight2_[idx].second += weight * weight; + nentries_[idx].negative++; + sumweights_[idx].negative += w; + sumweights2_[idx].negative += w * w; } } } diff --git a/tools/SampleAnalyzer/Process/Counter/CounterManager.h b/tools/SampleAnalyzer/Process/Counter/CounterManager.h index d712c105..11a31813 100644 --- a/tools/SampleAnalyzer/Process/Counter/CounterManager.h +++ b/tools/SampleAnalyzer/Process/Counter/CounterManager.h @@ -43,6 +43,9 @@ namespace MA5 // data members // ------------------------------------------------------------- private: + /// @brief intialisation indicator + MAbool initialised_; + // Collection of counters std::vector<Counter> counters_; @@ -54,16 +57,13 @@ namespace MA5 // ------------------------------------------------------------- public: /// Constructor without argument - CounterManager() {} + CounterManager() { initialised_ = false; } /// Destructor ~CounterManager() {} /// Initialize - void Initialize(const MAuint32 &n) - { - counters_.resize(n); - } + void Initialize(const MAuint32 &n) { counters_.resize(n); } // Specifying a cut name void InitCut(const std::string myname) @@ -73,48 +73,34 @@ namespace MA5 } /// Reset - void Reset() - { - counters_.clear(); - } + void Reset() { counters_.clear(); } /// Overloading operator [] - const Counter &operator[](const MAuint32 &index) const - { - return counters_[index]; - } - Counter &operator[](const MAuint32 &index) - { - return counters_[index]; - } + const Counter &operator[](const MAuint32 &index) const { return counters_[index]; } + Counter &operator[](const MAuint32 &index) { return counters_[index]; } /// Incrementing the initial number of events - void IncrementNInitial(std::map<MAuint32, MAfloat64> weight) + void IncrementNInitial(const WeightCollection &weight) { initial_.Increment(weight); + if (!initialised_) + { + for (auto &counter : counters_) + counter.Initialise(weight); + initialised_ = true; + } } /// Incrementing the initial number of events - Counter &GetInitial() - { - return initial_; - } - const Counter &GetInitial() const - { - return initial_; - } + Counter &GetInitial() { return initial_; } + + const Counter &GetInitial() const { return initial_; } /// Write the counters in a Text file void Write_TextFormat(SAFWriter &output) const; - /// Write the counters in a ROOT file - // void Write_RootFormat(TFile* output) const; - /// Finalizing - void Finalize() - { - Reset(); - } + void Finalize() { Reset(); } }; } diff --git a/tools/SampleAnalyzer/Process/RegionSelection/RegionSelection.h b/tools/SampleAnalyzer/Process/RegionSelection/RegionSelection.h index 07fa4e55..6fb9ecde 100644 --- a/tools/SampleAnalyzer/Process/RegionSelection/RegionSelection.h +++ b/tools/SampleAnalyzer/Process/RegionSelection/RegionSelection.h @@ -45,10 +45,6 @@ namespace MA5 MAbool surviving_; MAuint32 NumberOfCutsAppliedSoFar_; - /// @brief multi weight definition string is the name of the weight - /// float corresponds to the weight's value - std::map<MAuint32, MAfloat64> weight_; - CounterManager cutflow_; // ------------------------------------------------------------- @@ -65,55 +61,20 @@ namespace MA5 ~RegionSelection(){}; /// Get methods - std::string GetName() - { - return name_; - } + std::string GetName() { return name_; } - MAbool IsSurviving() - { - return surviving_; - } + MAbool IsSurviving() { return surviving_; } - MAuint32 GetNumberOfCutsAppliedSoFar() - { - return NumberOfCutsAppliedSoFar_; - } + MAuint32 GetNumberOfCutsAppliedSoFar() { return NumberOfCutsAppliedSoFar_; } /// Printing the list of histograms void WriteDefinition(SAFWriter &output); /// Printing the cutflow - void WriteCutflow(SAFWriter &output) - { - cutflow_.Write_TextFormat(output); - } + void WriteCutflow(SAFWriter &output) { cutflow_.Write_TextFormat(output); } /// Set methods - void SetName(std::string name) - { - name_ = name; - } - - /// Set weight - void SetWeight(MAfloat64 weight) - { - weight_.clear(); - weight_.insert(std::make_pair(0, weight)); - } - - /// Set weight - void SetWeight(std::map<MAuint32, MAfloat64> weight) { weight_ = weight; } - - /// Get weight - MAfloat64 GetWeight() { return weight_[0]; } - - /// @brief get weight with a certain id - /// @return weight value - MAfloat64 GetWeight(MAint32 id) { return weight_.at(id); } - - /// Get multi weight - std::map<MAuint32, MAfloat64> GetMultiWeight() { return weight_; } + void SetName(std::string name) { name_ = name; } void SetSurvivingTest(MAbool surviving) { surviving_ = surviving; } @@ -123,7 +84,7 @@ namespace MA5 } // Increment CutFlow (when this region passes a cut) - void IncrementCutFlow(std::map<MAuint32, MAfloat64> weight) + void IncrementCutFlow(const WeightCollection &weight) { cutflow_[NumberOfCutsAppliedSoFar_].Increment(weight); NumberOfCutsAppliedSoFar_++; @@ -133,21 +94,11 @@ namespace MA5 void AddCut(std::string const &CutName) { cutflow_.InitCut(CutName); } /// Getting ready for a new event - void InitializeForNewEvent(const MAfloat64 &weight) - { - SetWeight(weight); - SetSurvivingTest(true); - SetNumberOfCutsAppliedSoFar(0); - cutflow_.IncrementNInitial(weight_); - } - - /// Getting ready for a new event - void InitializeForNewEvent(const std::map<MAuint32, MAfloat64> &weight) + void InitializeForNewEvent(const WeightCollection &weights) { - SetWeight(weight); SetSurvivingTest(true); SetNumberOfCutsAppliedSoFar(0); - cutflow_.IncrementNInitial(weight); + cutflow_.IncrementNInitial(weights); } }; From 2c717173b06d89bf71a4101db7f0d819a4a65ef5 Mon Sep 17 00:00:00 2001 From: "Jack Y. Araz" <jackaraz@gmail.com> Date: Tue, 27 Jun 2023 15:14:04 +0100 Subject: [PATCH 004/107] add basic positive/negative weight strucutre --- tools/SampleAnalyzer/Commons/Base/Basics.h | 44 ++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 tools/SampleAnalyzer/Commons/Base/Basics.h diff --git a/tools/SampleAnalyzer/Commons/Base/Basics.h b/tools/SampleAnalyzer/Commons/Base/Basics.h new file mode 100644 index 00000000..7d87fda1 --- /dev/null +++ b/tools/SampleAnalyzer/Commons/Base/Basics.h @@ -0,0 +1,44 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2012-2023 Jack Araz, Eric Conte & Benjamin Fuks +// The MadAnalysis development team, email: <ma5team@iphc.cnrs.fr> +// +// This file is part of MadAnalysis 5. +// Official website: <https://github.com/MadAnalysis/madanalysis5> +// +// MadAnalysis 5 is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// MadAnalysis 5 is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with MadAnalysis 5. If not, see <http://www.gnu.org/licenses/> +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef BASICS_h +#define BASICS_h + +#include "SampleAnalyzer/Commons/Base/PortableDatatypes.h" + +namespace MA5 +{ + struct ENTRIES + { + MAint32 positive = 0; + MAint32 negative = 0; + }; + + struct WEIGHTS + { + MAdouble64 positive = 0.0; + MAdouble64 negative = 0.0; + }; +} + +#endif \ No newline at end of file From c0648c2e0e10e9363b64756b1e4fd9302c255018 Mon Sep 17 00:00:00 2001 From: "Jack Y. Araz" <jackaraz@gmail.com> Date: Tue, 27 Jun 2023 15:15:14 +0100 Subject: [PATCH 005/107] update weight base --- .../Commons/DataFormat/MCEventFormat.h | 387 +++++++++--------- .../Commons/DataFormat/MCSampleFormat.h | 231 +++++++---- .../Commons/DataFormat/WeightCollection.h | 310 ++++++++------ tools/SampleAnalyzer/Process/Counter/Basics.h | 44 -- 4 files changed, 523 insertions(+), 449 deletions(-) delete mode 100644 tools/SampleAnalyzer/Process/Counter/Basics.h diff --git a/tools/SampleAnalyzer/Commons/DataFormat/MCEventFormat.h b/tools/SampleAnalyzer/Commons/DataFormat/MCEventFormat.h index a9eac6a2..9dc08d57 100644 --- a/tools/SampleAnalyzer/Commons/DataFormat/MCEventFormat.h +++ b/tools/SampleAnalyzer/Commons/DataFormat/MCEventFormat.h @@ -1,31 +1,29 @@ //////////////////////////////////////////////////////////////////////////////// -// +// // Copyright (C) 2012-2023 Jack Araz, Eric Conte & Benjamin Fuks // The MadAnalysis development team, email: <ma5team@iphc.cnrs.fr> -// +// // This file is part of MadAnalysis 5. // Official website: <https://github.com/MadAnalysis/madanalysis5> -// +// // MadAnalysis 5 is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // MadAnalysis 5 is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with MadAnalysis 5. If not, see <http://www.gnu.org/licenses/> -// +// //////////////////////////////////////////////////////////////////////////////// - #ifndef MCEventFormat_h #define MCEventFormat_h - // STL headers #include <iostream> #include <sstream> @@ -37,206 +35,203 @@ #include "SampleAnalyzer/Commons/DataFormat/WeightCollection.h" #include "SampleAnalyzer/Commons/Service/LogService.h" - namespace MA5 { -class LHEReader; -class LHCOReader; -class STDHEPreader; -class HEPMCReader; -class LHEWriter; -class ROOTReader; -class DelphesTreeReader; -class DelphesMA5tuneTreeReader; - -class MCEventFormat -{ - friend class LHEReader; - friend class LHCOReader; - friend class STDHEPreader; - friend class HEPMCReader; - friend class ROOTReader; - friend class LHEWriter; - friend class DelphesTreeReader; - friend class DelphesMA5tuneTreeReader; - - // ------------------------------------------------------------- - // data members - // ------------------------------------------------------------- - private : - - MAuint32 processId_; /// identity of the current process - mutable MAfloat64 weight_; /// event weight - MAfloat64 scale_; /// scale Q of the event - MAfloat64 alphaQED_; /// ALPHA_em value used - MAfloat64 alphaQCD_; /// ALPHA_s value used - MAfloat64 PDFscale_; /// scale for PDF - std::pair<MAfloat64,MAfloat64> x_; /// x values - std::pair<MAfloat64,MAfloat64> xpdf_; /// xpdf values - - /// List of generated particles - std::vector<MCParticleFormat> particles_; - - /// Computed Missing Transverse Energy - MCParticleFormat MET_; - - /// Computed Missing Hadronic Transverse Energy - MCParticleFormat MHT_; - - /// Computed Scalar sum of transverse energy - MAfloat64 TET_; - - /// Computed Scalar sum of hadronic transverse energy - MAfloat64 THT_; - - /// Computed total effective mass (sum of jet's PT + MET - MAfloat64 Meff_; - - /// List of weights - WeightCollection multiweights_; - - - // ------------------------------------------------------------- - // method members - // ------------------------------------------------------------- - public : - - /// Constructor withtout arguments - MCEventFormat() - { - processId_=0; - weight_=1.; - scale_=0.; - alphaQED_=0.; - alphaQCD_=0.; - TET_ = 0.; - THT_ = 0.; - Meff_= 0.; - } - - /// Destructor - ~MCEventFormat() - { } - - /// Accessor to the Missing Transverse Energy (read-only) - const MCParticleFormat& MET() const {return MET_;} - - /// Accessor to the Missing Hadronic Transverse Energy (read-only) - const MCParticleFormat& MHT() const {return MHT_;} - - /// Accessor to the Total Transverse Energy (read-only) - const MAfloat64& TET() const {return TET_;} - - /// Accessor to the Total Hadronic Transverse Energy (read-only) - const MAfloat64& THT() const {return THT_;} - - /// Accessor to the Total effective mass (read-only) - const MAfloat64& Meff() const {return Meff_;} - - /// Accessor to the Missing Transverse Energy - MCParticleFormat& MET() {return MET_;} - - /// Accessor to the Missing Hadronic Transverse Energy - MCParticleFormat& MHT() {return MHT_;} - - /// Accessor to the Total Transverse Energy - MAfloat64& TET() {return TET_;} - - /// Accessor to the Total Hadronic Transverse Energy - MAfloat64& THT() {return THT_;} - - /// Accessor to the Total effective mass - MAfloat64& Meff() {return Meff_;} - - /// Accessor to the process identity - const MAuint32& processId() const {return processId_;} - - /// Accessor to the event weight - const MAfloat64& weight() const {return weight_; } - - /// Accessor to the scale - const MAfloat64& scale() const {return scale_; } - - /// Accessor to alpha_QED - const MAfloat64& alphaQED() const {return alphaQED_; } - - /// Accessor to alpha_QCD - const MAfloat64& alphaQCD() const {return alphaQCD_; } - - /// Accessor to multiweights - const WeightCollection& multiweights() const {return multiweights_; } - - /// Accessor to multiweights - WeightCollection& multiweights() {return multiweights_; } - - /// Accessor to multiweights - const MAfloat64& multiweights(MAuint32 weight) const {return multiweights_[weight]; } - - /// Accessor to the generated particle collection (read-only) - const std::vector<MCParticleFormat>& particles() const {return particles_;} - - /// Accessor to the generated particle collection - std::vector<MCParticleFormat>& particles() {return particles_;} - - /// Setting the process identity - void setProcessId(MAuint32 v) {processId_=v;} - - /// Setting the event weight - void setWeight (MAfloat64 v) const {weight_=v; } - - /// Setting the scale - void setScale (MAfloat64 v) {scale_=v; } + class LHEReader; + class LHCOReader; + class STDHEPreader; + class HEPMCReader; + class LHEWriter; + class ROOTReader; + class DelphesTreeReader; + class DelphesMA5tuneTreeReader; + + class MCEventFormat + { + friend class LHEReader; + friend class LHCOReader; + friend class STDHEPreader; + friend class HEPMCReader; + friend class ROOTReader; + friend class LHEWriter; + friend class DelphesTreeReader; + friend class DelphesMA5tuneTreeReader; + + // ------------------------------------------------------------- + // data members + // ------------------------------------------------------------- + private: + MAuint32 processId_; /// identity of the current process + // mutable MAfloat64 weight_; /// event weight + MAfloat64 scale_; /// scale Q of the event + MAfloat64 alphaQED_; /// ALPHA_em value used + MAfloat64 alphaQCD_; /// ALPHA_s value used + MAfloat64 PDFscale_; /// scale for PDF + std::pair<MAfloat64, MAfloat64> x_; /// x values + std::pair<MAfloat64, MAfloat64> xpdf_; /// xpdf values + + /// List of generated particles + std::vector<MCParticleFormat> particles_; + + /// Computed Missing Transverse Energy + MCParticleFormat MET_; + + /// Computed Missing Hadronic Transverse Energy + MCParticleFormat MHT_; - /// Setting AlphaQED - void setAlphaQED (MAfloat64 v) {alphaQED_=v; } + /// Computed Scalar sum of transverse energy + MAfloat64 TET_; - /// Setting AlphaQCD - void setAlphaQCD (MAfloat64 v) {alphaQCD_=v; } + /// Computed Scalar sum of hadronic transverse energy + MAfloat64 THT_; - /// Clearing all information - void Reset() - { - processId_=0; weight_=1.; - scale_=0.; alphaQED_=0.; alphaQCD_=0.; - particles_.clear(); - multiweights_.Reset(); - MET_.Reset(); - MHT_.Reset(); - TET_ = 0.; - THT_ = 0.; - Meff_ = 0.; - } + /// Computed total effective mass (sum of jet's PT + MET + MAfloat64 Meff_; - /// Displaying data member values - void Print() const - { - INFO << "nparts=" << particles_.size() - << " - processId=" << processId_ - << " - weight=" << weight_ - << " - scale=" << scale_ - << " - alphaQED=" << alphaQED_ - << " - alphaQCD=" << alphaQCD_ << endmsg; - INFO << "nweights=" << multiweights_.size() << endmsg; - } + /// List of weights + WeightCollection multiweights_; - /// Displaying data - void PrintVertices() const; + // ------------------------------------------------------------- + // method members + // ------------------------------------------------------------- + public: + /// Constructor withtout arguments + MCEventFormat() + { + processId_ = 0; + // weight_ = 1.; + scale_ = 0.; + alphaQED_ = 0.; + alphaQCD_ = 0.; + TET_ = 0.; + THT_ = 0.; + Meff_ = 0.; + } + + /// Destructor + ~MCEventFormat() {} + + /// Accessor to the Missing Transverse Energy (read-only) + const MCParticleFormat &MET() const { return MET_; } + + /// Accessor to the Missing Hadronic Transverse Energy (read-only) + const MCParticleFormat &MHT() const { return MHT_; } + + /// Accessor to the Total Transverse Energy (read-only) + const MAfloat64 &TET() const { return TET_; } + + /// Accessor to the Total Hadronic Transverse Energy (read-only) + const MAfloat64 &THT() const { return THT_; } + + /// Accessor to the Total effective mass (read-only) + const MAfloat64 &Meff() const { return Meff_; } + + /// Accessor to the Missing Transverse Energy + MCParticleFormat &MET() { return MET_; } + + /// Accessor to the Missing Hadronic Transverse Energy + MCParticleFormat &MHT() { return MHT_; } + + /// Accessor to the Total Transverse Energy + MAfloat64 &TET() { return TET_; } + + /// Accessor to the Total Hadronic Transverse Energy + MAfloat64 &THT() { return THT_; } + + /// Accessor to the Total effective mass + MAfloat64 &Meff() { return Meff_; } + + /// Accessor to the process identity + const MAuint32 &processId() const { return processId_; } + + /// Accessor to the event weight + const MAfloat64 &weight() const { return multiweights_.Get(0); } + + /// Accessor to the scale + const MAfloat64 &scale() const { return scale_; } + + /// Accessor to alpha_QED + const MAfloat64 &alphaQED() const { return alphaQED_; } + + /// Accessor to alpha_QCD + const MAfloat64 &alphaQCD() const { return alphaQCD_; } + + /// Accessor to multiweights + const WeightCollection &multiweights() const { return multiweights_; } + + /// Accessor to multiweights + WeightCollection &weights() { return multiweights_; } + + /// Accessor to multiweights + const MAfloat64 &get_weight(MAuint32 id) const { return multiweights_.Get(id); } + + /// Accessor to the generated particle collection (read-only) + const std::vector<MCParticleFormat> &particles() const { return particles_; } + + /// Accessor to the generated particle collection + std::vector<MCParticleFormat> &particles() { return particles_; } + + /// Setting the process identity + void setProcessId(MAuint32 v) { processId_ = v; } + + /// Setting the event weight + // void setWeight(MAfloat64 v) const { weight_ = v; } + + /// Setting the scale + void setScale(MAfloat64 v) { scale_ = v; } + + /// Setting AlphaQED + void setAlphaQED(MAfloat64 v) { alphaQED_ = v; } + + /// Setting AlphaQCD + void setAlphaQCD(MAfloat64 v) { alphaQCD_ = v; } + + /// Clearing all information + void Reset() + { + processId_ = 0; + // weight_ = 1.; + scale_ = 0.; + alphaQED_ = 0.; + alphaQCD_ = 0.; + particles_.clear(); + multiweights_.Reset(); + MET_.Reset(); + MHT_.Reset(); + TET_ = 0.; + THT_ = 0.; + Meff_ = 0.; + } - /// Displaying mothers - void PrintMothers() const; + /// Displaying data member values + void Print() const + { + INFO << "nparts=" << particles_.size() + << " - processId=" << processId_ + << " - weight=" << multiweights_.Get(0) + << " - scale=" << scale_ + << " - alphaQED=" << alphaQED_ + << " - alphaQCD=" << alphaQCD_ << endmsg; + INFO << "nweights=" << multiweights_.size() << endmsg; + } - /// Displaying daughters - void PrintDaughters() const; + /// Displaying data + void PrintVertices() const; - /// Giving a new particle - MCParticleFormat* GetNewParticle() - { - particles_.push_back(MCParticleFormat()); - return &particles_.back(); - } + /// Displaying mothers + void PrintMothers() const; -}; + /// Displaying daughters + void PrintDaughters() const; + + /// Giving a new particle + MCParticleFormat *GetNewParticle() + { + particles_.push_back(MCParticleFormat()); + return &particles_.back(); + } + }; } diff --git a/tools/SampleAnalyzer/Commons/DataFormat/MCSampleFormat.h b/tools/SampleAnalyzer/Commons/DataFormat/MCSampleFormat.h index 532e1c30..7d17dc71 100644 --- a/tools/SampleAnalyzer/Commons/DataFormat/MCSampleFormat.h +++ b/tools/SampleAnalyzer/Commons/DataFormat/MCSampleFormat.h @@ -1,31 +1,29 @@ //////////////////////////////////////////////////////////////////////////////// -// +// // Copyright (C) 2012-2023 Jack Araz, Eric Conte & Benjamin Fuks // The MadAnalysis development team, email: <ma5team@iphc.cnrs.fr> -// +// // This file is part of MadAnalysis 5. // Official website: <https://github.com/MadAnalysis/madanalysis5> -// +// // MadAnalysis 5 is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // MadAnalysis 5 is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with MadAnalysis 5. If not, see <http://www.gnu.org/licenses/> -// +// //////////////////////////////////////////////////////////////////////////////// - #ifndef MCSAMPLE_DATAFORMAT_H #define MCSAMPLE_DATAFORMAT_H - // STL headers #include <map> #include <iostream> @@ -38,7 +36,6 @@ #include "SampleAnalyzer/Commons/DataFormat/WeightDefinition.h" #include "SampleAnalyzer/Commons/Service/LogService.h" - namespace MA5 { @@ -51,7 +48,6 @@ namespace MA5 class LHEWriter; class SampleAnalyzer; - class MCSampleFormat { friend class LHEReader; @@ -63,182 +59,240 @@ namespace MA5 friend class STDHEPReader; friend class STDHEPreader; - // ------------------------------------------------------------- // data members // ------------------------------------------------------------- private: - // ---------------------- physics info ------------------------- - std::pair<MAint32,MAint32> beamPDGID_; - std::pair<MAfloat64,MAfloat64> beamE_; - std::pair<MAuint32,MAuint32> beamPDFauthor_; - std::pair<MAuint32,MAuint32> beamPDFID_; - MAint32 weightMode_; - std::vector<ProcessFormat> processes_; - const MA5GEN::GeneratorType* sample_generator_; - MAfloat32 length_unit_; /// Length unit: mm=1 cm=0.1 - MAfloat32 energy_unit_; /// Energy unit: GeV=1 MeV=0.001 keV=0.000001 + std::pair<MAint32, MAint32> beamPDGID_; + std::pair<MAfloat64, MAfloat64> beamE_; + std::pair<MAuint32, MAuint32> beamPDFauthor_; + std::pair<MAuint32, MAuint32> beamPDFID_; + MAint32 weightMode_; + std::vector<ProcessFormat> processes_; + const MA5GEN::GeneratorType *sample_generator_; + MAfloat32 length_unit_; /// Length unit: mm=1 cm=0.1 + MAfloat32 energy_unit_; /// Energy unit: GeV=1 MeV=0.001 keV=0.000001 // ----------------------- multiweights ------------------------ + /// @jackaraz: not sure if this is doing anything WeightDefinition weight_definition_; + /// @brief store weight names + std::map<int, std::string> weight_names_; // ----------------------- file info --------------------------- MAfloat64 xsection_; MAfloat64 xsection_error_; - MAfloat64 sumweight_positive_; // all events with positive weights - MAfloat64 sumweight_negative_; // all events with negative weights - + MAfloat64 sumweight_positive_; // all events with positive weights + MAfloat64 sumweight_negative_; // all events with negative weights // ------------------------------------------------------------- // method members // ------------------------------------------------------------- - public : - + public: /// Constructor withtout arguments - MCSampleFormat(const MA5GEN::GeneratorType* gen) + MCSampleFormat(const MA5GEN::GeneratorType *gen) { - sample_generator_=gen; + sample_generator_ = gen; Reset(); } /// Destructor - ~MCSampleFormat() - { } + ~MCSampleFormat() {} /// Clear all the content void Reset() { // Physics info - beamPDGID_ = std::make_pair(0,0); - beamE_ = std::make_pair(0,0); - beamPDFauthor_ = std::make_pair(0,0); - beamPDFID_ = std::make_pair(0,0); - weightMode_ = 0; + beamPDGID_ = std::make_pair(0, 0); + beamE_ = std::make_pair(0, 0); + beamPDFauthor_ = std::make_pair(0, 0); + beamPDFID_ = std::make_pair(0, 0); + weightMode_ = 0; processes_.clear(); length_unit_ = 1.0; energy_unit_ = 1.0; // WeightDefinition weight_definition_.Reset(); + weight_names_.clear(); // File info - xsection_ = 0.; - xsection_error_ = 0.; + xsection_ = 0.; + xsection_error_ = 0.; sumweight_positive_ = 0.; sumweight_negative_ = 0.; } /// Accessoir to the generator type - const MA5GEN::GeneratorType* GeneratorType() const - { return sample_generator_; } + const MA5GEN::GeneratorType *GeneratorType() const + { + return sample_generator_; + } /// Accessor to PDG ID of the intial partons - const std::pair<MAint32,MAint32>& beamPDGID() const - { return beamPDGID_; } + const std::pair<MAint32, MAint32> &beamPDGID() const + { + return beamPDGID_; + } /// Accessor to the beam energy - const std::pair<MAfloat64,MAfloat64>& beamE() const - { return beamE_; } + const std::pair<MAfloat64, MAfloat64> &beamE() const + { + return beamE_; + } /// Accessor to the PDF authors - const std::pair<MAuint32,MAuint32>& beamPDFauthor() const - { return beamPDFauthor_; } + const std::pair<MAuint32, MAuint32> &beamPDFauthor() const + { + return beamPDFauthor_; + } /// Accessor to the PDF identity - const std::pair<MAuint32,MAuint32>& beamPDFID() const - { return beamPDFID_; } + const std::pair<MAuint32, MAuint32> &beamPDFID() const + { + return beamPDFID_; + } /// Accessor to the weight mode - const MAint32& weightMode() const - { return weightMode_; } + const MAint32 &weightMode() const + { + return weightMode_; + } /// Accessor to the xsection mean - const MAfloat64& xsection() const - { return xsection_; } + const MAfloat64 &xsection() const + { + return xsection_; + } /// Accessor to the xsection mean - const MAfloat64& xsection_mean() const - { return xsection_; } + const MAfloat64 &xsection_mean() const + { + return xsection_; + } /// Accessor to the xsection error - const MAfloat64& xsection_error() const - { return xsection_error_; } + const MAfloat64 &xsection_error() const + { + return xsection_error_; + } /// Accessor to the number of events with positive weight - const MAfloat64& sumweight_positive() const - { return sumweight_positive_; } + const MAfloat64 &sumweight_positive() const + { + return sumweight_positive_; + } /// Accessor to the number of events with negative weight - const MAfloat64& sumweight_negative() const - { return sumweight_negative_; } + const MAfloat64 &sumweight_negative() const + { + return sumweight_negative_; + } /// Accessor to the process collection (read-only) - const std::vector<ProcessFormat>& processes() const - { return processes_; } + const std::vector<ProcessFormat> &processes() const + { + return processes_; + } /// Accessor to the process collection - std::vector<ProcessFormat>& processes() - { return processes_; } + std::vector<ProcessFormat> &processes() + { + return processes_; + } /// Accessor to the weight definition (read-only) - const WeightDefinition& weight_definition() const - { return weight_definition_; } + const WeightDefinition &weight_definition() const + { + return weight_definition_; + } /// Accessor to the weight definition - WeightDefinition& weight_definition() - { return weight_definition_; } + WeightDefinition &weight_definition() + { + return weight_definition_; + } /// Set the PDG ID of the intial partons void setBeamPDGID(MAint32 a, MAint32 b) - {beamPDGID_=std::make_pair(a,b); } + { + beamPDGID_ = std::make_pair(a, b); + } /// Set the beam energy void setBeamE(MAfloat64 a, MAfloat64 b) - {beamE_=std::make_pair(a,b); } + { + beamE_ = std::make_pair(a, b); + } /// Set the PDF authors void setBeamPDFauthor(MAuint32 a, MAuint32 b) - {beamPDFauthor_=std::make_pair(a,b); } + { + beamPDFauthor_ = std::make_pair(a, b); + } /// Set the the PDF identity void setBeamPDFid(MAuint32 a, MAuint32 b) - {beamPDFID_=std::make_pair(a,b); } + { + beamPDFID_ = std::make_pair(a, b); + } /// Set the weight mode void setWeightMode(MAint32 v) - {weightMode_=v;} + { + weightMode_ = v; + } /// Set the cross section mean // BENJ: the normalization in the pythia lhe output by madgraph has been changed // the 1e9 factor is not needed anymore void setXsection(MAfloat64 value) -// { xsection_=value*getXsectionUnitFactor();} - { xsection_=value;} + // { xsection_=value*getXsectionUnitFactor();} + { + xsection_ = value; + } /// Set the cross section mean void setXsectionMean(MAfloat64 value) - { xsection_=value;} + { + xsection_ = value; + } /// Set the cross section mean void setXsectionError(MAfloat64 value) - { xsection_error_=value;} + { + xsection_error_ = value; + } + + /// @brief set weight names + /// @param id location of the weight + /// @param name name of the weight + void SetWeightName(int id, std::string name) { weight_names_[id] = name; } /// Adding a weight void addWeightedEvents(MAfloat64 weight) - { if (weight>=0) sumweight_positive_ += std::abs(weight); - else sumweight_negative_ += std::abs(weight); } + { + if (weight >= 0) + sumweight_positive_ += std::abs(weight); + else + sumweight_negative_ += std::abs(weight); + } /// Accessor to the number of events with positive weight void setSumweight_positive(MAfloat64 sum) - { sumweight_positive_ += sum; } + { + sumweight_positive_ += sum; + } /// Accessor to the number of events with negative weight void setSumweight_negative(MAfloat64 sum) - { sumweight_negative_ += sum; } + { + sumweight_negative_ += sum; + } /// Giving a new process entry - ProcessFormat* GetNewProcess() + ProcessFormat *GetNewProcess() { processes_.push_back(ProcessFormat()); return &processes_.back(); @@ -247,28 +301,29 @@ namespace MA5 /// Get scale factor required to set the cross section in pb unit MAfloat64 getXsectionUnitFactor() { - if (*sample_generator_==MA5GEN::PYTHIA6) return 1e9; - else return 1.; + if (*sample_generator_ == MA5GEN::PYTHIA6) + return 1e9; + else + return 1.; } /// Length unit setter void SetLengthUnit(MAfloat32 val) { length_unit_ = val; } /// Accessor to the length unit - MAfloat32 LengthUnit() {return length_unit_;} + MAfloat32 LengthUnit() { return length_unit_; } /// Accessor to the length unit - const MAfloat32 LengthUnit() const {return length_unit_;} + const MAfloat32 LengthUnit() const { return length_unit_; } /// Energy unit setter void SetEnergyUnit(MAfloat32 val) { energy_unit_ = val; } /// Accessor to the energy unit - MAfloat32 EnergyUnit() {return energy_unit_;} + MAfloat32 EnergyUnit() { return energy_unit_; } /// Accessor to the energy unit - const MAfloat32 EnergyUnit() const {return energy_unit_;} - + const MAfloat32 EnergyUnit() const { return energy_unit_; } }; } diff --git a/tools/SampleAnalyzer/Commons/DataFormat/WeightCollection.h b/tools/SampleAnalyzer/Commons/DataFormat/WeightCollection.h index b154a245..0d125e8a 100644 --- a/tools/SampleAnalyzer/Commons/DataFormat/WeightCollection.h +++ b/tools/SampleAnalyzer/Commons/DataFormat/WeightCollection.h @@ -1,5 +1,5 @@ //////////////////////////////////////////////////////////////////////////////// -// +// // Copyright (C) 2012-2023 Jack Araz, Eric Conte & Benjamin Fuks // The MadAnalysis development team, email: <ma5team@iphc.cnrs.fr> // @@ -39,137 +39,205 @@ namespace MA5 { - class WeightCollection - { - - // ------------------------------------------------------------- - // data members - // ------------------------------------------------------------- - private: - std::map<MAuint32, MAfloat64> weights_; - static const MAfloat64 emptyvalue_; - - // ------------------------------------------------------------- - // method members - // ------------------------------------------------------------- - public: - /// Constructor withtout arguments - WeightCollection() + class WeightCollection { - } - /// Destructor - ~WeightCollection() - { - } + // ------------------------------------------------------------- + // data members + // ------------------------------------------------------------- + private: + std::map<MAuint32, MAfloat64> weights_; + static const MAfloat64 emptyvalue_; + + // ------------------------------------------------------------- + // method members + // ------------------------------------------------------------- + public: + /// Constructor withtout arguments + WeightCollection() {} + + // copy constructor + WeightCollection(const WeightCollection &rhs) + { + weights_.clear(); + for (auto &id_weights : rhs.weights_) + weights_[id_weights.first] = id_weights.second; + } - /// Clear all the content - void Reset() - { - weights_.clear(); - } - void clear() { Reset(); } + /// @brief Initialise weights with a certain size and default value + /// @param size number of weights + /// @param default_value default value for each weight + WeightCollection(const MAint32 &size, MAdouble64 default_value = 0.0) + { + for (MAuint32 i = 0; i < size; i++) + weights_[i] = default_value; + } - /// Size - MAuint32 size() const - { - return weights_.size(); - } + /// Destructor + ~WeightCollection() {} - /// Add a new weight group - MAbool Add(MAuint32 id, MAfloat64 value) - { - // Try to add the item - std::pair<std::map<MAuint32, MAfloat64>::iterator, bool> ret; - ret = weights_.insert(std::pair<MAuint32, MAfloat64>(id, value)); - - // Is it added? - try - { - if (!ret.second) + /// Clear all the content + void Reset() { weights_.clear(); } + void clear() { Reset(); } + + /// Size + MAuint32 size() const { return weights_.size(); } + + /// Size + MAuint32 size() { return weights_.size(); } + + /// Add a new weight group + MAbool Add(MAuint32 id, MAfloat64 value) { - std::stringstream str; - str << id; - std::string idname; - str >> idname; - throw EXCEPTION_WARNING("The Weight '" + idname + - "' is defined at two times. Redundant values are skipped.", - "", 0); + // Try to add the item + std::pair<std::map<MAuint32, MAfloat64>::iterator, bool> ret; + ret = weights_.insert(std::pair<MAuint32, MAfloat64>(id, value)); + + // Is it added? + try + { + if (!ret.second) + { + std::stringstream str; + str << id; + std::string idname; + str >> idname; + throw EXCEPTION_WARNING("The Weight '" + idname + + "' is defined at two times. Redundant values are skipped.", + "", 0); + } + } + catch (const std::exception &e) + { + MANAGE_EXCEPTION(e); + return false; + } + + return true; } - } - catch (const std::exception &e) - { - MANAGE_EXCEPTION(e); - return false; - } - - return true; - } - - /// Get all the Weight Collection - const std::map<MAuint32, MAfloat64> &GetWeights() const - { - return weights_; - } - /// Get a weight - const MAfloat64 &Get(MAuint32 id) const - { - // Try to get the item - std::map<MAuint32, MAfloat64>::const_iterator it = weights_.find(id); - try - { - if (it == weights_.end()) + /// Get all the Weight Collection + const std::map<MAuint32, MAfloat64> &GetWeights() const { return weights_; } + + /// Get a weight + const MAfloat64 &Get(MAuint32 id) const { - std::stringstream str; - str << id; - std::string idname; - str >> idname; - throw EXCEPTION_ERROR("The Weight '" + idname + - "' is not defined. Return null value.", - "", 0); + // Try to get the item + std::map<MAuint32, MAfloat64>::const_iterator it = weights_.find(id); + try + { + if (it == weights_.end()) + { + std::stringstream str; + str << id; + std::string idname; + str >> idname; + throw EXCEPTION_ERROR("The Weight '" + idname + + "' is not defined. Return null value.", + "", 0); + } + } + catch (const std::exception &e) + { + MANAGE_EXCEPTION(e); + return emptyvalue_; + } + + return it->second; } - } - catch (const std::exception &e) - { - MANAGE_EXCEPTION(e); - return emptyvalue_; - } - - return it->second; - } - - /// Get a weight - const MAfloat64 &operator[](MAuint32 id) const - { - return Get(id); - } - /// Add a new weight group - void Print() const - { - if (weights_.empty()) - return; - - // Loop over weights for getting max - MAuint32 maxi = 0; - for (std::map<MAuint32, MAfloat64>::const_iterator - it = weights_.begin(); - it != weights_.end(); it++) - { - if (it->first > maxi) - maxi = it->first; - } - - // Loop over weights - for (std::map<MAuint32, MAfloat64>::const_iterator - it = weights_.begin(); - it != weights_.end(); it++) - { - INFO << "ID=" << it->first << " : " << it->second << endmsg; - } - } - }; + /// Get a weight + const MAfloat64 &operator[](MAuint32 id) const { return Get(id); } + + /// Add a new weight group + void Print() const + { + if (weights_.empty()) + return; + + // Loop over weights for getting max + MAuint32 maxi = 0; + for (std::map<MAuint32, MAfloat64>::const_iterator + it = weights_.begin(); + it != weights_.end(); it++) + { + if (it->first > maxi) + maxi = it->first; + } + + // Loop over weights + for (auto &w : weights_) + INFO << "ID=" << w.first << " : " << w.second << endmsg; + } + + /// @brief add weight to specific location + /// @param idx location + /// @param weight weight value + void add_weight_to(MAint32 idx, MAdouble64 weight) { weights_[idx] += weight; } + + /// @brief multiply operator + /// @param multiple + WeightCollection &operator*=(const MAfloat64 multiple) + { + for (auto &id_value : weights_) + id_value.second *= multiple; + return *this; + } + + /// @brief add operator + /// @param input + WeightCollection &operator+=(const MAfloat64 input) + { + for (auto &id_value : weights_) + id_value.second += input; + return *this; + } + + /// @brief add operator + /// @param input + WeightCollection &operator+=(const WeightCollection input) + { + for (auto &id_value : weights_) + id_value.second += input.Get(id_value.first); + return *this; + } + + /// @brief subtract operator + /// @param input + WeightCollection &operator-=(const MAfloat64 input) + { + for (auto &id_value : weights_) + id_value.second -= input; + return *this; + } + + /// @brief divide operator + /// @param input + WeightCollection &operator/=(const MAfloat64 input) + { + for (auto &id_value : weights_) + id_value.second /= input; + return *this; + } + + /// @brief assignment operator + /// @param input + WeightCollection &operator=(const MAfloat64 input) + { + for (auto &id_value : weights_) + id_value.second = input; + return *this; + } + + /// @brief assignment operator + /// @param input + WeightCollection &operator=(const WeightCollection input) + { + for (auto &id_value : weights_) + id_value.second = input.Get(id_value.first); + return *this; + } + }; } diff --git a/tools/SampleAnalyzer/Process/Counter/Basics.h b/tools/SampleAnalyzer/Process/Counter/Basics.h deleted file mode 100644 index 7d87fda1..00000000 --- a/tools/SampleAnalyzer/Process/Counter/Basics.h +++ /dev/null @@ -1,44 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// Copyright (C) 2012-2023 Jack Araz, Eric Conte & Benjamin Fuks -// The MadAnalysis development team, email: <ma5team@iphc.cnrs.fr> -// -// This file is part of MadAnalysis 5. -// Official website: <https://github.com/MadAnalysis/madanalysis5> -// -// MadAnalysis 5 is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// MadAnalysis 5 is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with MadAnalysis 5. If not, see <http://www.gnu.org/licenses/> -// -//////////////////////////////////////////////////////////////////////////////// - -#ifndef BASICS_h -#define BASICS_h - -#include "SampleAnalyzer/Commons/Base/PortableDatatypes.h" - -namespace MA5 -{ - struct ENTRIES - { - MAint32 positive = 0; - MAint32 negative = 0; - }; - - struct WEIGHTS - { - MAdouble64 positive = 0.0; - MAdouble64 negative = 0.0; - }; -} - -#endif \ No newline at end of file From 8b32077d8058f34664d43e65347e9c43b5f148ad Mon Sep 17 00:00:00 2001 From: "Jack Y. Araz" <jackaraz@gmail.com> Date: Tue, 27 Jun 2023 15:15:38 +0100 Subject: [PATCH 006/107] update readers --- .../Process/Reader/HEPMCReader.cpp | 312 +++-- .../Process/Reader/HEPMCReader.h | 187 +-- .../Process/Reader/LHEReader.cpp | 885 ++++++------ .../Process/Reader/STDHEPreader.cpp | 1237 +++++++++-------- 4 files changed, 1327 insertions(+), 1294 deletions(-) diff --git a/tools/SampleAnalyzer/Process/Reader/HEPMCReader.cpp b/tools/SampleAnalyzer/Process/Reader/HEPMCReader.cpp index fdf9e942..7fa91698 100644 --- a/tools/SampleAnalyzer/Process/Reader/HEPMCReader.cpp +++ b/tools/SampleAnalyzer/Process/Reader/HEPMCReader.cpp @@ -1,27 +1,26 @@ //////////////////////////////////////////////////////////////////////////////// -// +// // Copyright (C) 2012-2023 Jack Araz, Eric Conte & Benjamin Fuks // The MadAnalysis development team, email: <ma5team@iphc.cnrs.fr> -// +// // This file is part of MadAnalysis 5. // Official website: <https://github.com/MadAnalysis/madanalysis5> -// +// // MadAnalysis 5 is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // MadAnalysis 5 is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with MadAnalysis 5. If not, see <http://www.gnu.org/licenses/> -// +// //////////////////////////////////////////////////////////////////////////////// - // STL headers #include <sstream> @@ -30,32 +29,31 @@ #include "SampleAnalyzer/Commons/Service/LogService.h" #include "SampleAnalyzer/Commons/Service/ExceptionService.h" - using namespace MA5; - // ----------------------------------------------------------------------------- // ReadHeader // ----------------------------------------------------------------------------- -MAbool HEPMCReader::ReadHeader(SampleFormat& mySample) +MAbool HEPMCReader::ReadHeader(SampleFormat &mySample) { // Reset the saved line - savedline_=""; + savedline_ = ""; // Initialize MC mySample.InitializeMC(); mySample.SetSampleFormat(MA5FORMAT::HEPMC); mySample.SetSampleGenerator(MA5GEN::UNKNOWN); - warnmother_=true; + warnmother_ = true; // Skipping header line until first event line std::string firstWord; std::string line; - while(firstWord!="E") + while (firstWord != "E") { // Getting the next non-empty line - if (!ReadLine(line)) return false; + if (!ReadLine(line)) + return false; // Splitting the line in words std::stringstream str; @@ -65,17 +63,16 @@ MAbool HEPMCReader::ReadHeader(SampleFormat& mySample) str >> firstWord; } - savedline_ = line; + savedline_ = line; // Normal end return true; } - // ----------------------------------------------------------------------------- // FinalizeHeader // ----------------------------------------------------------------------------- -MAbool HEPMCReader::FinalizeHeader(SampleFormat& mySample) +MAbool HEPMCReader::FinalizeHeader(SampleFormat &mySample) { return true; } @@ -83,7 +80,7 @@ MAbool HEPMCReader::FinalizeHeader(SampleFormat& mySample) // ----------------------------------------------------------------------------- // ReadEvent // ----------------------------------------------------------------------------- -StatusCode::Type HEPMCReader::ReadEvent(EventFormat& myEvent, SampleFormat& mySample) +StatusCode::Type HEPMCReader::ReadEvent(EventFormat &myEvent, SampleFormat &mySample) { // Initializing MC event myEvent.InitializeMC(); @@ -91,27 +88,30 @@ StatusCode::Type HEPMCReader::ReadEvent(EventFormat& myEvent, SampleFormat& mySa // Allocating memory for all particles myEvent.mc()->particles_.reserve(nparts_max_); - MAbool eventOnGoing=false; + MAbool eventOnGoing = false; // Read the saved line - if (savedline_!="") + if (savedline_ != "") { FillEvent(savedline_, myEvent, mySample); - eventOnGoing=true; - savedline_=""; + eventOnGoing = true; + savedline_ = ""; } - MAbool endEvent=false; + MAbool endEvent = false; // Loop over particle - while(!endEvent) + while (!endEvent) { std::string line; // Getting a line from the file if (!ReadLine(line)) { - if (eventOnGoing) return StatusCode::KEEP; else return StatusCode::FAILURE; + if (eventOnGoing) + return StatusCode::KEEP; + else + return StatusCode::FAILURE; } // Splitting the line in words @@ -123,16 +123,16 @@ StatusCode::Type HEPMCReader::ReadEvent(EventFormat& myEvent, SampleFormat& mySa str >> firstWord; // Is next event ? - if (firstWord=="E") + if (firstWord == "E") { - savedline_ = line; + savedline_ = line; return StatusCode::KEEP; } else { // Decoding the line - endEvent=!FillEvent(line, myEvent, mySample); - eventOnGoing=true; + endEvent = !FillEvent(line, myEvent, mySample); + eventOnGoing = true; } } @@ -140,67 +140,74 @@ StatusCode::Type HEPMCReader::ReadEvent(EventFormat& myEvent, SampleFormat& mySa return StatusCode::KEEP; } - - // ----------------------------------------------------------------------------- // FinalizeEvent // ----------------------------------------------------------------------------- -MAbool HEPMCReader::FinalizeEvent(SampleFormat& mySample, EventFormat& myEvent) +MAbool HEPMCReader::FinalizeEvent(SampleFormat &mySample, EventFormat &myEvent) { // Compute max numbers of particles & vertices - if (myEvent.mc()->particles_.size()>nparts_max_) nparts_max_=myEvent.mc()->particles_.size(); - + if (myEvent.mc()->particles_.size() > nparts_max_) + nparts_max_ = myEvent.mc()->particles_.size(); // Fill vertices information - for (std::map<MAint32,HEPVertex>::iterator it=vertices_.begin(); it!=vertices_.end(); it++) + for (std::map<MAint32, HEPVertex>::iterator it = vertices_.begin(); it != vertices_.end(); it++) { // Decay position & lifetime - for (MAuint32 i=0;i<it->second.in_.size();i++) + for (MAuint32 i = 0; i < it->second.in_.size(); i++) { - MCParticleFormat* part = &(myEvent.mc()->particles_[it->second.in_[i]]); - part->decay_vertex_.SetXYZT(it->second.x_,it->second.y_,it->second.z_,it->second.ctau_); + MCParticleFormat *part = &(myEvent.mc()->particles_[it->second.in_[i]]); + part->decay_vertex_.SetXYZT(it->second.x_, it->second.y_, it->second.z_, it->second.ctau_); } // Mother+daughter relations - for (MAuint32 i=0;i<it->second.in_.size();i++) + for (MAuint32 i = 0; i < it->second.in_.size(); i++) { - for (MAuint32 j=0;j<it->second.out_.size();j++) + for (MAuint32 j = 0; j < it->second.out_.size(); j++) { - MCParticleFormat* mum = &(myEvent.mc()->particles_[it->second.in_[i]]); - MCParticleFormat* dau = &(myEvent.mc()->particles_[it->second.out_[j]]); + MCParticleFormat *mum = &(myEvent.mc()->particles_[it->second.in_[i]]); + MCParticleFormat *dau = &(myEvent.mc()->particles_[it->second.out_[j]]); // Deal with HERWIG initial particle : initial part = part whose mother is itself - if (mum!=dau) + if (mum != dau) { // Safety: be sure to have not 2 same daughters - MAbool found=false; - for (MAuint32 h=0;h<mum->daughters().size();h++) + MAbool found = false; + for (MAuint32 h = 0; h < mum->daughters().size(); h++) { - if (mum->daughters()[h]==dau) {found=true; break;} + if (mum->daughters()[h] == dau) + { + found = true; + break; + } } - if (!found) mum -> daughters().push_back(dau); + if (!found) + mum->daughters().push_back(dau); // Safety: be sure to have not 2 same mothers - found=false; - for (MAuint32 h=0;h<dau->mothers().size();h++) + found = false; + for (MAuint32 h = 0; h < dau->mothers().size(); h++) { - if (dau->mothers()[h]==mum) {found=true; break;} + if (dau->mothers()[h] == mum) + { + found = true; + break; + } } - if (!found) dau -> mothers().push_back(mum); + if (!found) + dau->mothers().push_back(mum); } } } } vertices_.clear(); - // Computing met, mht, ... - for (MAuint32 i=0; i<myEvent.mc()->particles_.size();i++) + for (MAuint32 i = 0; i < myEvent.mc()->particles_.size(); i++) { - MCParticleFormat& part = myEvent.mc()->particles_[i]; + MCParticleFormat &part = myEvent.mc()->particles_[i]; // MET, MHT, TET, THT - if (part.statuscode()==1 && !PHYSICS->Id->IsInvisible(part)) + if (part.statuscode() == 1 && !PHYSICS->Id->IsInvisible(part)) { myEvent.mc()->MET_ -= part.momentum(); myEvent.mc()->TET_ += part.pt(); @@ -224,15 +231,14 @@ MAbool HEPMCReader::FinalizeEvent(SampleFormat& mySample, EventFormat& myEvent) return true; } - //------------------------------------------------------------------------------ // FillWeightNames //------------------------------------------------------------------------------ -MAbool HEPMCReader::FillWeightNames(const std::string& line) +MAbool HEPMCReader::FillWeightNames(const std::string &line, SampleFormat &mySample) { // Splitting line in words std::stringstream str; - str << line ; + str << line; // Getting the first word std::string firstWord; @@ -246,80 +252,92 @@ MAbool HEPMCReader::FillWeightNames(const std::string& line) std::vector<std::string> weight_names(nweights); // Filling weight names - for (MAuint32 i=0;i<weight_names.size();i++) + for (MAuint32 i = 0; i < weight_names.size(); i++) { std::string tmp; str >> tmp; - if (tmp=="") continue; + if (tmp == "") + continue; - if (tmp[0]=='"' && tmp[tmp.size()-1]=='"') tmp=tmp.substr(1,tmp.size()-2); - weight_names[i]=tmp; + if (tmp[0] == '"' && tmp[tmp.size() - 1] == '"') + tmp = tmp.substr(1, tmp.size() - 2); + weight_names[i] = tmp; + mySample.mc()->SetWeightName(i, tmp); } // Ok return true; } - //------------------------------------------------------------------------------ // FillHeavyIons //------------------------------------------------------------------------------ -MAbool HEPMCReader::FillHeavyIons(const std::string& line) +MAbool HEPMCReader::FillHeavyIons(const std::string &line) { try { - if (line!="") if (firstHeavyIons_) throw EXCEPTION_WARNING("HeavyIons block is not read by SampleAnalyzer","",0); + if (line != "") + if (firstHeavyIons_) + throw EXCEPTION_WARNING("HeavyIons block is not read by SampleAnalyzer", "", 0); } - catch(const std::exception& e) + catch (const std::exception &e) { MANAGE_EXCEPTION(e); } - firstHeavyIons_=false; + firstHeavyIons_ = false; return false; } - //------------------------------------------------------------------------------ // FillEventHeader //------------------------------------------------------------------------------ -MAbool HEPMCReader::FillEvent(const std::string& line, - EventFormat& myEvent, - SampleFormat& mySample) +MAbool HEPMCReader::FillEvent(const std::string &line, + EventFormat &myEvent, + SampleFormat &mySample) { // Splitting line in words std::stringstream str; - str << line ; + str << line; // Getting the first word std::string firstWord; str >> firstWord; // Event global info - if(firstWord=="E") FillEventInformations(line, myEvent); + if (firstWord == "E") + FillEventInformations(line, myEvent); // Weight names - else if (firstWord=="N") FillWeightNames(line); + else if (firstWord == "N") + FillWeightNames(line, mySample); // Event units - else if (firstWord=="U") FillUnits(line, mySample); + else if (firstWord == "U") + FillUnits(line, mySample); // Cross section - else if (firstWord=="C") FillCrossSection(line,mySample); + else if (firstWord == "C") + FillCrossSection(line, mySample); // HeavyIon line - else if (firstWord=="H") FillHeavyIons(line); + else if (firstWord == "H") + FillHeavyIons(line); // PDF Info - else if (firstWord=="F") FillEventPDFInfo(line,mySample,myEvent); + else if (firstWord == "F") + FillEventPDFInfo(line, mySample, myEvent); // Vertex line - else if (firstWord=="V") FillEventVertexLine(line,myEvent); + else if (firstWord == "V") + FillEventVertexLine(line, myEvent); // Particle Line - else if (firstWord=="P") FillEventParticleLine(line,myEvent); + else if (firstWord == "P") + FillEventParticleLine(line, myEvent); // End - else if (firstWord=="HepMC::IO_GenEvent-END_EVENT_LISTING") return false; + else if (firstWord == "HepMC::IO_GenEvent-END_EVENT_LISTING") + return false; // Other cases else @@ -327,9 +345,9 @@ MAbool HEPMCReader::FillEvent(const std::string& line, // ignore other cases try { - throw EXCEPTION_WARNING("HEPMC linecode unknown","",0); + throw EXCEPTION_WARNING("HEPMC linecode unknown", "", 0); } - catch(const std::exception& e) + catch (const std::exception &e) { MANAGE_EXCEPTION(e); } @@ -342,14 +360,14 @@ MAbool HEPMCReader::FillEvent(const std::string& line, // ----------------------------------------------------------------------------- // FillEventInformations // ----------------------------------------------------------------------------- -void HEPMCReader::FillEventInformations(const std::string& line, - EventFormat& myEvent) +void HEPMCReader::FillEventInformations(const std::string &line, + EventFormat &myEvent) { std::stringstream str; str << line; std::string firstc; - MAint32 tmp=0; + MAint32 tmp = 0; // Filling general info str >> firstc; // character 'E' @@ -366,32 +384,33 @@ void HEPMCReader::FillEventInformations(const std::string& line, // Extracting random state list str >> tmp; - if (tmp>0) + if (tmp > 0) { std::vector<MAint64> randoms(static_cast<MAuint32>(tmp)); - for (MAuint32 i=0;i<randoms.size();i++) str >> randoms[i]; + for (MAuint32 i = 0; i < randoms.size(); i++) + str >> randoms[i]; } // Extracting weight lists str >> tmp; - if (tmp>0) + if (tmp > 0) { - MAuint32 nweights=static_cast<MAuint32>(tmp); - for (MAuint32 i=0;i<nweights;i++) + MAuint32 nweights = static_cast<MAuint32>(tmp); + for (MAuint32 i = 0; i < nweights; i++) { MAfloat64 value; str >> value; - if (i==0) myEvent.mc()->weight_=value; - myEvent.mc()->multiweights().Add(i+1,value); + // if (i == 0) + // myEvent.mc()->weight_ = value; + myEvent.mc()->weights().Add(i, value); } } - } // ----------------------------------------------------------------------------- // FillUnits // ----------------------------------------------------------------------------- -void HEPMCReader::FillUnits(const std::string& line, SampleFormat& mySample) +void HEPMCReader::FillUnits(const std::string &line, SampleFormat &mySample) { std::stringstream str; str << line; @@ -402,29 +421,34 @@ void HEPMCReader::FillUnits(const std::string& line, SampleFormat& mySample) // Unit of energy str >> tmp; - if (tmp=="GEV") energy_unit_=1; - else if (tmp=="MEV") energy_unit_=0.001; - else if (tmp=="KEV") energy_unit_=0.000001; - else ERROR << "Unknown unit of energy: " << tmp << endmsg; + if (tmp == "GEV") + energy_unit_ = 1; + else if (tmp == "MEV") + energy_unit_ = 0.001; + else if (tmp == "KEV") + energy_unit_ = 0.000001; + else + ERROR << "Unknown unit of energy: " << tmp << endmsg; // Unit of length str >> tmp; - if (tmp=="MM") length_unit_=1; - else if (tmp=="CM") length_unit_=0.1; - else ERROR << "Unknown unit of length: " << tmp << endmsg; + if (tmp == "MM") + length_unit_ = 1; + else if (tmp == "CM") + length_unit_ = 0.1; + else + ERROR << "Unknown unit of length: " << tmp << endmsg; /// Set length and energy units mySample.mc()->SetLengthUnit(length_unit_); mySample.mc()->SetEnergyUnit(energy_unit_); - } - // ----------------------------------------------------------------------------- // FillCrossSection // ----------------------------------------------------------------------------- -void HEPMCReader::FillCrossSection(const std::string& line, - SampleFormat& mySample) +void HEPMCReader::FillCrossSection(const std::string &line, + SampleFormat &mySample) { // Splitting the line in words std::stringstream str; @@ -435,15 +459,15 @@ void HEPMCReader::FillCrossSection(const std::string& line, str >> firstc; // xsection mean - MAfloat64 xsectmp=0; + MAfloat64 xsectmp = 0; str >> xsectmp; // xsection error - MAfloat64 xsectmp_err=0; + MAfloat64 xsectmp_err = 0; str >> xsectmp_err; // saving xsection mean & error - if (mySample.mc()!=0) + if (mySample.mc() != 0) { mySample.mc()->setXsectionMean(xsectmp); mySample.mc()->setXsectionError(xsectmp_err); @@ -453,9 +477,9 @@ void HEPMCReader::FillCrossSection(const std::string& line, // ----------------------------------------------------------------------------- // FillEventPDFInfo // ----------------------------------------------------------------------------- -void HEPMCReader::FillEventPDFInfo(const std::string& line, - SampleFormat& mySample, - EventFormat& myEvent) +void HEPMCReader::FillEventPDFInfo(const std::string &line, + SampleFormat &mySample, + EventFormat &myEvent) { std::stringstream str; str << line; @@ -475,23 +499,23 @@ void HEPMCReader::FillEventPDFInfo(const std::string& line, // ----------------------------------------------------------------------------- // FillEventParticleLine // ----------------------------------------------------------------------------- -void HEPMCReader::FillEventParticleLine(const std::string& line, - EventFormat& myEvent) +void HEPMCReader::FillEventParticleLine(const std::string &line, + EventFormat &myEvent) { std::stringstream str; str << line; - MAfloat64 tmp; // temporary variable to fill in LorentzVector + MAfloat64 tmp; // temporary variable to fill in LorentzVector // Get a new particle - MCParticleFormat * part = myEvent.mc()->GetNewParticle(); + MCParticleFormat *part = myEvent.mc()->GetNewParticle(); MAchar linecode; - MAfloat64 px=0.; - MAfloat64 py=0.; - MAfloat64 pz=0.; - MAfloat64 e=0.; - MAuint32 partnum; - MAint32 decay_barcode; + MAfloat64 px = 0.; + MAfloat64 py = 0.; + MAfloat64 pz = 0.; + MAfloat64 e = 0.; + MAuint32 partnum; + MAint32 decay_barcode; str >> linecode; // letter 'P' str >> partnum; // particle number @@ -509,21 +533,20 @@ void HEPMCReader::FillEventParticleLine(const std::string& line, // MAuint32 barcode; // barcode = an integer which uniquely // str >> barcode; // identifies the GenParticle within the event. + part->momentum_.SetPxPyPzE(px * energy_unit_, + py * energy_unit_, + pz * energy_unit_, + e * energy_unit_); - part->momentum_.SetPxPyPzE (px * energy_unit_, - py * energy_unit_, - pz * energy_unit_, - e * energy_unit_); - - MAuint32 part_index = myEvent.mc()->particles_.size()-1; + MAuint32 part_index = myEvent.mc()->particles_.size() - 1; // Set production vertex - std::pair<std::map<MAint32,HEPVertex>::iterator,MAbool> ret; - ret = vertices_.insert(std::make_pair(currentvertex_,HEPVertex())); + std::pair<std::map<MAint32, HEPVertex>::iterator, MAbool> ret; + ret = vertices_.insert(std::make_pair(currentvertex_, HEPVertex())); ret.first->second.out_.push_back(part_index); // Set decay vertex - ret = vertices_.insert(std::make_pair(decay_barcode,HEPVertex())); + ret = vertices_.insert(std::make_pair(decay_barcode, HEPVertex())); ret.first->second.in_.push_back(part_index); // Ok @@ -533,7 +556,7 @@ void HEPMCReader::FillEventParticleLine(const std::string& line, // ----------------------------------------------------------------------------- // FillEventVertexLine // ----------------------------------------------------------------------------- -void HEPMCReader::FillEventVertexLine(const std::string& line, EventFormat& myEvent) +void HEPMCReader::FillEventVertexLine(const std::string &line, EventFormat &myEvent) { std::stringstream str; str << line; @@ -542,26 +565,25 @@ void HEPMCReader::FillEventVertexLine(const std::string& line, EventFormat& myEv MAint32 barcode; HEPVertex vertex; - str >> linecode; // character 'V' - str >> barcode; // barcode - str >> vertex.id_; // id - str >> vertex.x_; // x - str >> vertex.y_; // y - str >> vertex.z_; // z - str >> vertex.ctau_; // ctau + str >> linecode; // character 'V' + str >> barcode; // barcode + str >> vertex.id_; // id + str >> vertex.x_; // x + str >> vertex.y_; // y + str >> vertex.z_; // z + str >> vertex.ctau_; // ctau // Adding this vertex to the vertex collection - std::pair<std::map<MAint32,HEPVertex>::iterator,MAbool> res = vertices_.insert(std::make_pair(barcode,vertex)); + std::pair<std::map<MAint32, HEPVertex>::iterator, MAbool> res = vertices_.insert(std::make_pair(barcode, vertex)); if (!res.second) { - res.first->second.id_ = vertex.id_; - res.first->second.x_ = vertex.x_; - res.first->second.y_ = vertex.y_; - res.first->second.z_ = vertex.z_; + res.first->second.id_ = vertex.id_; + res.first->second.x_ = vertex.x_; + res.first->second.y_ = vertex.y_; + res.first->second.z_ = vertex.z_; res.first->second.ctau_ = vertex.ctau_; } // Set the current vertex barcode currentvertex_ = barcode; } - diff --git a/tools/SampleAnalyzer/Process/Reader/HEPMCReader.h b/tools/SampleAnalyzer/Process/Reader/HEPMCReader.h index 0de07782..9cb10b11 100644 --- a/tools/SampleAnalyzer/Process/Reader/HEPMCReader.h +++ b/tools/SampleAnalyzer/Process/Reader/HEPMCReader.h @@ -1,122 +1,123 @@ //////////////////////////////////////////////////////////////////////////////// -// +// // Copyright (C) 2012-2023 Jack Araz, Eric Conte & Benjamin Fuks // The MadAnalysis development team, email: <ma5team@iphc.cnrs.fr> -// +// // This file is part of MadAnalysis 5. // Official website: <https://github.com/MadAnalysis/madanalysis5> -// +// // MadAnalysis 5 is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // MadAnalysis 5 is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with MadAnalysis 5. If not, see <http://www.gnu.org/licenses/> -// +// //////////////////////////////////////////////////////////////////////////////// - #ifndef HEPMC_READER_h #define HEPMC_READER_h - // SampleAnalyzer headers #include "SampleAnalyzer/Process/Reader/ReaderTextBase.h" - namespace MA5 { -class HEPMCReader : public ReaderTextBase -{ - - // ------------------------------------------------------------- - // data members - // ------------------------------------------------------------- - protected: - - MAbool firstevent_; - MAbool endevent_; - MAbool saved_; - MAbool EndOfFile_; - MAbool warnmother_; - MAint32 partcode_; - MAint32 vertcode_; - MAfloat32 energy_unit_; - MAfloat32 length_unit_; - std::string savedline_; // last saved line - MAbool firstHeavyIons_; - MAuint64 nparts_max_; - MAuint64 nvertices_max_; - - struct HEPVertex - { - MAfloat64 ctau_; - MAfloat64 id_; - MAfloat64 x_; - MAfloat64 y_; - MAfloat64 z_; - MAint32 barcode_; - std::vector<MAuint32> in_; - std::vector<MAuint32> out_; - HEPVertex() - { ctau_=0; id_=0; x_=0; y_=0; z_=0; barcode_=0; } - }; - - std::map<MAint32,HEPVertex> vertices_; - MAint32 currentvertex_; - - // ------------------------------------------------------------- - // method members - // ------------------------------------------------------------- - public: - - /// Constructor without argument - HEPMCReader() - { - firstevent_=false; - firstHeavyIons_=true; - nparts_max_=0; - nvertices_max_=0; - energy_unit_ = 1.0; - length_unit_ = 1.0; - } - - /// Destructor - virtual ~HEPMCReader() - { } - - /// Read the header - virtual MAbool ReadHeader(SampleFormat& mySample); - - /// Finalize the header - virtual MAbool FinalizeHeader(SampleFormat& mySample); - - /// Read the event - virtual StatusCode::Type ReadEvent(EventFormat& myEvent, SampleFormat& mySample); - - /// Finalize the event - virtual MAbool FinalizeEvent(SampleFormat& mySample, EventFormat& myEvent); - - private: - - MAbool FillEvent(const std::string& line, EventFormat& myEvent, SampleFormat& mySample); - void FillEventInformations(const std::string& line, EventFormat& myEvent); - void FillCrossSection(const std::string& line, SampleFormat& mySample); - void FillUnits(const std::string& line, SampleFormat& mySample); - void FillEventPDFInfo(const std::string& line, SampleFormat& mySample, EventFormat& myEvent); - void FillEventParticleLine(const std::string& line, EventFormat& myEvent); - void FillEventVertexLine(const std::string& line, EventFormat& myEvent); - MAbool FillWeightNames(const std::string& line); - MAbool FillHeavyIons(const std::string& line); - -}; + class HEPMCReader : public ReaderTextBase + { + + // ------------------------------------------------------------- + // data members + // ------------------------------------------------------------- + protected: + MAbool firstevent_; + MAbool endevent_; + MAbool saved_; + MAbool EndOfFile_; + MAbool warnmother_; + MAint32 partcode_; + MAint32 vertcode_; + MAfloat32 energy_unit_; + MAfloat32 length_unit_; + std::string savedline_; // last saved line + MAbool firstHeavyIons_; + MAuint64 nparts_max_; + MAuint64 nvertices_max_; + + struct HEPVertex + { + MAfloat64 ctau_; + MAfloat64 id_; + MAfloat64 x_; + MAfloat64 y_; + MAfloat64 z_; + MAint32 barcode_; + std::vector<MAuint32> in_; + std::vector<MAuint32> out_; + HEPVertex() + { + ctau_ = 0; + id_ = 0; + x_ = 0; + y_ = 0; + z_ = 0; + barcode_ = 0; + } + }; + + std::map<MAint32, HEPVertex> vertices_; + MAint32 currentvertex_; + + // ------------------------------------------------------------- + // method members + // ------------------------------------------------------------- + public: + /// Constructor without argument + HEPMCReader() + { + firstevent_ = false; + firstHeavyIons_ = true; + nparts_max_ = 0; + nvertices_max_ = 0; + energy_unit_ = 1.0; + length_unit_ = 1.0; + } + + /// Destructor + virtual ~HEPMCReader() + { + } + + /// Read the header + virtual MAbool ReadHeader(SampleFormat &mySample); + + /// Finalize the header + virtual MAbool FinalizeHeader(SampleFormat &mySample); + + /// Read the event + virtual StatusCode::Type ReadEvent(EventFormat &myEvent, SampleFormat &mySample); + + /// Finalize the event + virtual MAbool FinalizeEvent(SampleFormat &mySample, EventFormat &myEvent); + + private: + MAbool FillEvent(const std::string &line, EventFormat &myEvent, SampleFormat &mySample); + void FillEventInformations(const std::string &line, EventFormat &myEvent); + void FillCrossSection(const std::string &line, SampleFormat &mySample); + void FillUnits(const std::string &line, SampleFormat &mySample); + void FillEventPDFInfo(const std::string &line, SampleFormat &mySample, EventFormat &myEvent); + void FillEventParticleLine(const std::string &line, EventFormat &myEvent); + void FillEventVertexLine(const std::string &line, EventFormat &myEvent); + MAbool FillWeightNames(const std::string &line, SampleFormat &mySample); + MAbool FillHeavyIons(const std::string &line); + }; } diff --git a/tools/SampleAnalyzer/Process/Reader/LHEReader.cpp b/tools/SampleAnalyzer/Process/Reader/LHEReader.cpp index 73b49a5a..2d9f248a 100644 --- a/tools/SampleAnalyzer/Process/Reader/LHEReader.cpp +++ b/tools/SampleAnalyzer/Process/Reader/LHEReader.cpp @@ -1,27 +1,26 @@ //////////////////////////////////////////////////////////////////////////////// -// +// // Copyright (C) 2012-2023 Jack Araz, Eric Conte & Benjamin Fuks // The MadAnalysis development team, email: <ma5team@iphc.cnrs.fr> -// +// // This file is part of MadAnalysis 5. // Official website: <https://github.com/MadAnalysis/madanalysis5> -// +// // MadAnalysis 5 is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // MadAnalysis 5 is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with MadAnalysis 5. If not, see <http://www.gnu.org/licenses/> -// +// //////////////////////////////////////////////////////////////////////////////// - // STL headers #include <sstream> #include <cmath> @@ -31,262 +30,263 @@ #include "SampleAnalyzer/Commons/Service/LogService.h" #include "SampleAnalyzer/Commons/Service/ExceptionService.h" - using namespace MA5; // ----------------------------------------------------------------------------- // ReadHeader // ----------------------------------------------------------------------------- -MAbool LHEReader::ReadHeader(SampleFormat& mySample) +MAbool LHEReader::ReadHeader(SampleFormat &mySample) { - // Initiliaze MC - mySample.InitializeMC(); + // Initiliaze MC + mySample.InitializeMC(); - // Declaring a new string for line - std::string line; + // Declaring a new string for line + std::string line; - // Generator tags - MAbool tag_calchep = false; - MAbool tag_mg5 = false; - MAbool tag_ma5 = false; - MAbool tag_simplified_pythia = false; - MAbool tag_simplified_ma5 = false; + // Generator tags + MAbool tag_calchep = false; + MAbool tag_mg5 = false; + MAbool tag_ma5 = false; + MAbool tag_simplified_pythia = false; + MAbool tag_simplified_ma5 = false; - // Read line by line the file until tag <header> - // Note from Benj: the header tags are optional according to LHE standards - // the init tags are alsways the last ones before the events - MAbool EndOfLoop=false, GoodInit = false; + // Read line by line the file until tag <header> + // Note from Benj: the header tags are optional according to LHE standards + // the init tags are alsways the last ones before the events + MAbool EndOfLoop = false, GoodInit = false; - while(!GoodInit) - { - MAbool HeaderFound = false, InitFound = false; - do + while (!GoodInit) { - if (!ReadLine(line)) return false; - HeaderFound = (line.find("<header>")!=std::string::npos); - InitFound = (line.find("<init>")!=std::string::npos); - EndOfLoop = HeaderFound || InitFound; + MAbool HeaderFound = false, InitFound = false; + do + { + if (!ReadLine(line)) + return false; + HeaderFound = (line.find("<header>") != std::string::npos); + InitFound = (line.find("<init>") != std::string::npos); + EndOfLoop = HeaderFound || InitFound; + } while (!EndOfLoop); + + // Read line by line the file until tag </header> + // Store the header + if (HeaderFound) + { + EndOfLoop = false; + do + { + if (!ReadLine(line, false)) + return false; + EndOfLoop = (line.find("</header>") != std::string::npos); + if (EndOfLoop) + continue; + else + mySample.AddHeader(line); + if ((line.find("<MGGenerationInfo>") != std::string::npos) || + (line.find("<mgversion>") != std::string::npos) || + (line.find("<MG5ProcCard>") != std::string::npos)) + tag_mg5 = true; + if ((line.find("<MA5Format> LHE format </MA5Format>") != std::string::npos)) + tag_ma5 = true; + if ((line.find("<name>CalcHEP</name>") != std::string::npos)) + tag_calchep = true; + if ((line.find("<MGPythiaCard>") != std::string::npos) || + (line.find("<mgpythiacard>") != std::string::npos)) + tag_simplified_pythia = true; + if ((line.find("<MA5Format> Simplified LHE format </MA5Format>") != std::string::npos)) + tag_simplified_ma5 = true; + } while (!EndOfLoop); + } + + if (InitFound) + { + // Read line by line the file until tag </init> + EndOfLoop = false; + MAbool first = true; + do + { + if (!ReadLine(line)) + return false; + EndOfLoop = (line.find("</init>") != std::string::npos); + if (!EndOfLoop) + { + if (first) + FillHeaderInitLine(line, mySample); + else + FillHeaderProcessLine(line, mySample); + } + first = false; + } while (!EndOfLoop); + GoodInit = true; + } } - while(!EndOfLoop); - // Read line by line the file until tag </header> - // Store the header - if(HeaderFound) + // Read line by line the file until tag <event> + EndOfLoop = false; + do { - EndOfLoop=false; - do - { - if (!ReadLine(line,false)) return false; - EndOfLoop = (line.find("</header>")!=std::string::npos); - if (EndOfLoop) continue; - else mySample.AddHeader(line); - if ( (line.find("<MGGenerationInfo>")!=std::string::npos) || - (line.find("<mgversion>")!=std::string::npos) || - (line.find("<MG5ProcCard>")!=std::string::npos) ) - tag_mg5=true; - if ( (line.find("<MA5Format> LHE format </MA5Format>")!=std::string::npos) ) - tag_ma5=true; - if ( (line.find("<name>CalcHEP</name>")!=std::string::npos) ) tag_calchep=true; - if ( (line.find("<MGPythiaCard>")!=std::string::npos) || - (line.find("<mgpythiacard>")!=std::string::npos) ) - tag_simplified_pythia=true; - if ( (line.find("<MA5Format> Simplified LHE format </MA5Format>")!=std::string::npos) ) - tag_simplified_ma5=true; - } - while(!EndOfLoop); + if (!ReadLine(line)) + return false; + if ((line.find("<MGGenerationInfo>") != std::string::npos) || + (line.find("<mgversion>") != std::string::npos) || + (line.find("<MG5ProcCard>") != std::string::npos)) + tag_mg5 = true; + if ((line.find("<MA5Format> LHE format </MA5Format>") != std::string::npos)) + tag_ma5 = true; + if ((line.find("<MGPythiaCard>") != std::string::npos) || + (line.find("<mgpythiacard>") != std::string::npos)) + tag_simplified_pythia = true; + if ((line.find("<MA5Format> Simplified LHE format </MA5Format>") != std::string::npos)) + tag_simplified_ma5 = true; + EndOfLoop = (line.find("<event>") != std::string::npos); + } while (!EndOfLoop); + + // Determining sample format + if (tag_simplified_pythia || tag_simplified_ma5) + { + mySample.SetSampleFormat(MA5FORMAT::SIMPLIFIED_LHE); } - - if(InitFound) + else { - // Read line by line the file until tag </init> - EndOfLoop=false; - MAbool first=true; - do - { - if (!ReadLine(line)) return false; - EndOfLoop = (line.find("</init>")!=std::string::npos); - if (!EndOfLoop) - { - if (first) FillHeaderInitLine(line,mySample); - else FillHeaderProcessLine(line,mySample); - } - first=false; - } - while(!EndOfLoop); - GoodInit = true; + mySample.SetSampleFormat(MA5FORMAT::LHE); } - } - - // Read line by line the file until tag <event> - EndOfLoop=false; - do - { - if (!ReadLine(line)) return false; - if ( (line.find("<MGGenerationInfo>")!=std::string::npos) || - (line.find("<mgversion>")!=std::string::npos) || - (line.find("<MG5ProcCard>")!=std::string::npos) ) - tag_mg5=true; - if ( (line.find("<MA5Format> LHE format </MA5Format>")!=std::string::npos) ) - tag_ma5=true; - if ( (line.find("<MGPythiaCard>")!=std::string::npos) || - (line.find("<mgpythiacard>")!=std::string::npos) ) - tag_simplified_pythia=true; - if ( (line.find("<MA5Format> Simplified LHE format </MA5Format>")!=std::string::npos) ) - tag_simplified_ma5=true; - EndOfLoop = (line.find("<event>")!=std::string::npos); - } - while(!EndOfLoop); - - - // Determining sample format - if (tag_simplified_pythia || tag_simplified_ma5) - { - mySample.SetSampleFormat(MA5FORMAT::SIMPLIFIED_LHE); - } - else - { - mySample.SetSampleFormat(MA5FORMAT::LHE); - } - - - // Determining generator format - if (tag_ma5 || tag_simplified_ma5) // must be treated before mg5 - { - mySample.SetSampleGenerator(MA5GEN::MA5); - } - else if (tag_simplified_pythia) - { - mySample.SetSampleGenerator(MA5GEN::PYTHIA6); - } - else if (tag_mg5) - { - mySample.SetSampleGenerator(MA5GEN::MG5); - } - else if (tag_calchep) - { - mySample.SetSampleGenerator(MA5GEN::CALCHEP); - } - else - { - mySample.SetSampleGenerator(MA5GEN::UNKNOWN); - } + // Determining generator format + if (tag_ma5 || tag_simplified_ma5) // must be treated before mg5 + { + mySample.SetSampleGenerator(MA5GEN::MA5); + } + else if (tag_simplified_pythia) + { + mySample.SetSampleGenerator(MA5GEN::PYTHIA6); + } + else if (tag_mg5) + { + mySample.SetSampleGenerator(MA5GEN::MG5); + } + else if (tag_calchep) + { + mySample.SetSampleGenerator(MA5GEN::CALCHEP); + } + else + { + mySample.SetSampleGenerator(MA5GEN::UNKNOWN); + } - // Normal end - firstevent_=true; - return true; + // Normal end + firstevent_ = true; + return true; } - // ----------------------------------------------------------------------------- // FinalizeHeader // ----------------------------------------------------------------------------- -MAbool LHEReader::FinalizeHeader(SampleFormat& mySample) +MAbool LHEReader::FinalizeHeader(SampleFormat &mySample) { - // Computing xsection an its error for the sample - MAfloat64 xsection = 0.; - MAfloat64 xerror = 0.; - for (MAuint32 i=0;i<mySample.mc()->processes().size();i++) - { - xsection += mySample.mc()->processes()[i].xsectionMean(); - xerror += mySample.mc()->processes()[i].xsectionError() * - mySample.mc()->processes()[i].xsectionError(); - } + // Computing xsection an its error for the sample + MAfloat64 xsection = 0.; + MAfloat64 xerror = 0.; + for (MAuint32 i = 0; i < mySample.mc()->processes().size(); i++) + { + xsection += mySample.mc()->processes()[i].xsectionMean(); + xerror += mySample.mc()->processes()[i].xsectionError() * + mySample.mc()->processes()[i].xsectionError(); + } - // Filling xsection and its error - mySample.mc()->setXsection(xsection); - mySample.mc()->setXsectionError(std::sqrt(xerror)); + // Filling xsection and its error + mySample.mc()->setXsection(xsection); + mySample.mc()->setXsectionError(std::sqrt(xerror)); - // Normal end - return true; + // Normal end + return true; } - // ----------------------------------------------------------------------------- // ReadEvent // ----------------------------------------------------------------------------- -StatusCode::Type LHEReader::ReadEvent(EventFormat& myEvent, SampleFormat& mySample) +StatusCode::Type LHEReader::ReadEvent(EventFormat &myEvent, SampleFormat &mySample) { - // Initiliaze MC - myEvent.InitializeMC(); - - // Declaring a new string for line - std::string line; - MAbool EndOfEvent=false; - MAbool event_block=false; - MAbool event_header=false; - MAbool multiweight_block = false; - MAbool clustering_block = false; - - // Loop over the LHE lines - while(!EndOfEvent) - { - // Read the line - if (!firstevent_ && !ReadLine(line)) return StatusCode::FAILURE; - // Detect tags - if (line.find("<event>")!=std::string::npos || firstevent_) + // Initiliaze MC + myEvent.InitializeMC(); + + // Declaring a new string for line + std::string line; + MAbool EndOfEvent = false; + MAbool event_block = false; + MAbool event_header = false; + MAbool multiweight_block = false; + MAbool clustering_block = false; + + // Loop over the LHE lines + while (!EndOfEvent) { - event_block=true; - event_header=true; - firstevent_=false; - continue; - } - else if (line.find("</event>")!=std::string::npos) - { - event_block=false; - EndOfEvent=true; - continue; - } - else if (line.find("<rwgt>")!=std::string::npos || line.find("mgrwt")!=std::string::npos) - { - multiweight_block=true; - continue; - } - else if (line.find("</rwgt>")!=std::string::npos || line.find("/mgrwt")!=std::string::npos) - { - multiweight_block=false; - continue; - } - else if (line.find("<scales>")!=std::string::npos || line.find("</scales")!=std::string::npos) - continue; - else if (line.find("<clustering")!=std::string::npos) - { - clustering_block=true; - continue; - } - else if (line.find("</clustering")!=std::string::npos) - { - clustering_block=false; - continue; - } + // Read the line + if (!firstevent_ && !ReadLine(line)) + return StatusCode::FAILURE; + // Detect tags + if (line.find("<event>") != std::string::npos || firstevent_) + { + event_block = true; + event_header = true; + firstevent_ = false; + continue; + } + else if (line.find("</event>") != std::string::npos) + { + event_block = false; + EndOfEvent = true; + continue; + } + else if (line.find("<rwgt>") != std::string::npos || line.find("mgrwt") != std::string::npos) + { + multiweight_block = true; + continue; + } + else if (line.find("</rwgt>") != std::string::npos || line.find("/mgrwt") != std::string::npos) + { + multiweight_block = false; + continue; + } + else if (line.find("<scales>") != std::string::npos || line.find("</scales") != std::string::npos) + continue; + else if (line.find("<clustering") != std::string::npos) + { + clustering_block = true; + continue; + } + else if (line.find("</clustering") != std::string::npos) + { + clustering_block = false; + continue; + } - // Actions - if (event_block && !multiweight_block && !clustering_block) - { - if (event_header) - { - FillEventInitLine(line,myEvent); - event_header=false; - } - else FillEventParticleLine(line,myEvent); - } - else if (event_block && multiweight_block && !clustering_block) - { - FillWeightLine(line,myEvent); - } - else if (event_block && !multiweight_block && clustering_block) - { - continue; + // Actions + if (event_block && !multiweight_block && !clustering_block) + { + if (event_header) + { + FillEventInitLine(line, myEvent); + event_header = false; + } + else + FillEventParticleLine(line, myEvent); + } + else if (event_block && multiweight_block && !clustering_block) + { + FillWeightLine(line, myEvent); + } + else if (event_block && !multiweight_block && clustering_block) + { + continue; + } } - } /* // Read line by line the file until tag <event> if (!firstevent_) { EndOfLoop=false; - do - { + do + { if (!ReadLine(line)) return StatusCode::FAILURE; EndOfLoop = (line.find("<event>")!=std::string::npos); } @@ -297,14 +297,14 @@ StatusCode::Type LHEReader::ReadEvent(EventFormat& myEvent, SampleFormat& mySamp EndOfLoop=false; firstevent_=false; MAbool first=true; - do - { + do + { if (!ReadLine(line)) return StatusCode::FAILURE; - if (line.find("<rwgt>")!=std::string::npos) + if (line.find("<rwgt>")!=std::string::npos) { MAbool EndReweighting = false; do - { + { if (!ReadLine(line)) return StatusCode::FAILURE; EndReweighting = (line.find("</rwgt>")!=std::string::npos); FillWeightLine(line,myEvent); @@ -323,272 +323,273 @@ StatusCode::Type LHEReader::ReadEvent(EventFormat& myEvent, SampleFormat& mySamp while(!EndOfLoop); */ - // Normal end - return StatusCode::KEEP; + // Normal end + return StatusCode::KEEP; } - // ----------------------------------------------------------------------------- // FinalizeEvent // ----------------------------------------------------------------------------- -MAbool LHEReader::FinalizeEvent(SampleFormat& mySample, EventFormat& myEvent) +MAbool LHEReader::FinalizeEvent(SampleFormat &mySample, EventFormat &myEvent) { - // Traditional LHE or simplified LHE ? - MAbool simplified = (mySample.sampleFormat()==MA5FORMAT::SIMPLIFIED_LHE); + // Traditional LHE or simplified LHE ? + MAbool simplified = (mySample.sampleFormat() == MA5FORMAT::SIMPLIFIED_LHE); - // Mother-daughter relations - for (MAuint32 i=0; i<mothers_.size();i++) - { - MCParticleFormat* part = &(myEvent.mc()->particles_[i]); - MAint32& mothup1 = mothers_[i].first; - MAint32& mothup2 = mothers_[i].second; + // Mother-daughter relations + for (MAuint32 i = 0; i < mothers_.size(); i++) + { + MCParticleFormat *part = &(myEvent.mc()->particles_[i]); + MAint32 &mothup1 = mothers_[i].first; + MAint32 &mothup2 = mothers_[i].second; - if (mothup1>0) - { - if (static_cast<MAuint32>(mothup1)<=myEvent.mc()->particles().size()) - { - MCParticleFormat* mum = &(myEvent.mc()->particles()[static_cast<MAuint32>(mothup1-1)]); - if (mum!=part) + if (mothup1 > 0) { - part->mothers().push_back(mum); - mum->daughters().push_back(part); + if (static_cast<MAuint32>(mothup1) <= myEvent.mc()->particles().size()) + { + MCParticleFormat *mum = &(myEvent.mc()->particles()[static_cast<MAuint32>(mothup1 - 1)]); + if (mum != part) + { + part->mothers().push_back(mum); + mum->daughters().push_back(part); + } + } + else + { + std::stringstream str; + str << "index=" << mothup1 << " but #particles=" << myEvent.mc()->particles().size(); + try + { + throw EXCEPTION_WARNING("internal problem with mother-daughter particles", str.str(), 0); + } + catch (const std::exception &e) + { + MANAGE_EXCEPTION(e); + } + } } - } - else - { - std::stringstream str; - str << "index=" << mothup1 << " but #particles=" << myEvent.mc()->particles().size(); - try + if (mothup2 > 0 && mothup1 != mothup2) { - throw EXCEPTION_WARNING("internal problem with mother-daughter particles",str.str(),0); + if (static_cast<MAuint32>(mothup2) <= myEvent.mc()->particles().size()) + { + MCParticleFormat *mum = &(myEvent.mc()->particles()[static_cast<MAuint32>(mothup2 - 1)]); + if (mum != part) + { + part->mothers().push_back(mum); + mum->daughters().push_back(part); + } + } + else + { + std::stringstream str; + str << "index=" << mothup2 << " but #particles=" << myEvent.mc()->particles().size(); + try + { + throw EXCEPTION_WARNING("internal problem with mother-daughter particles", str.str(), 0); + } + catch (const std::exception &e) + { + MANAGE_EXCEPTION(e); + } + } } - catch(const std::exception& e) - { - MANAGE_EXCEPTION(e); - } - } } - if (mothup2>0 && mothup1!=mothup2) + mothers_.clear(); + + // Global event observable + for (MAuint32 i = 0; i < myEvent.mc()->particles_.size(); i++) { - if (static_cast<MAuint32>(mothup2)<=myEvent.mc()->particles().size()) - { - MCParticleFormat* mum = &(myEvent.mc()->particles()[static_cast<MAuint32>(mothup2-1)]); - if (mum!=part) - { - part->mothers().push_back(mum); - mum->daughters().push_back(part); - } - } - else - { - std::stringstream str; - str << "index=" << mothup2 << " but #particles=" << myEvent.mc()->particles().size(); - try + MCParticleFormat &part = myEvent.mc()->particles_[i]; + + // MET in case of simplified LHE + if (((part.pdgid() == 12 && part.statuscode() == 1) || (part.statuscode() == 1 && PHYSICS->Id->IsInvisible(part))) && simplified) { - throw EXCEPTION_WARNING("internal problem with mother-daughter particles",str.str(),0); + myEvent.mc()->MET_ += part.momentum(); } - catch(const std::exception& e) + + // MET, MHT, TET, THT + if (part.statuscode() == 1 && !PHYSICS->Id->IsInvisible(part)) { - MANAGE_EXCEPTION(e); + if (!simplified) + { + myEvent.mc()->MET_ -= part.momentum(); + } + myEvent.mc()->TET_ += part.pt(); + if (PHYSICS->Id->IsHadronic(part)) + { + myEvent.mc()->MHT_ -= part.momentum(); + myEvent.mc()->THT_ += part.pt(); + myEvent.mc()->Meff_ += part.pt(); + } } - } } - } - mothers_.clear(); - // Global event observable - for (MAuint32 i=0; i<myEvent.mc()->particles_.size();i++) - { - MCParticleFormat& part = myEvent.mc()->particles_[i]; + // Finalize event + myEvent.mc()->MET_.momentum().SetPz(0.); + myEvent.mc()->MET_.momentum().SetE(myEvent.mc()->MET_.momentum().Pt()); + myEvent.mc()->MHT_.momentum().SetPz(0.); + myEvent.mc()->MHT_.momentum().SetE(myEvent.mc()->MHT_.momentum().Pt()); + myEvent.mc()->Meff_ += myEvent.mc()->MET_.pt(); - // MET in case of simplified LHE - if ( ( (part.pdgid()==12 && part.statuscode()==1) || (part.statuscode()==1 && PHYSICS->Id->IsInvisible(part)) ) && simplified) - { - myEvent.mc()->MET_ += part.momentum(); - } - - // MET, MHT, TET, THT - if (part.statuscode()==1 && !PHYSICS->Id->IsInvisible(part)) - { - if (!simplified) - { - myEvent.mc()->MET_ -= part.momentum(); - } - myEvent.mc()->TET_ += part.pt(); - if (PHYSICS->Id->IsHadronic(part)) - { - myEvent.mc()->MHT_ -= part.momentum(); - myEvent.mc()->THT_ += part.pt(); - myEvent.mc()->Meff_ += part.pt(); - } - } - } - - // Finalize event - myEvent.mc()->MET_.momentum().SetPz(0.); - myEvent.mc()->MET_.momentum().SetE(myEvent.mc()->MET_.momentum().Pt()); - myEvent.mc()->MHT_.momentum().SetPz(0.); - myEvent.mc()->MHT_.momentum().SetE(myEvent.mc()->MHT_.momentum().Pt()); - myEvent.mc()->Meff_ += myEvent.mc()->MET_.pt(); - - // Normal end - return true; + // Normal end + return true; } - // ----------------------------------------------------------------------------- // FillHeaderInitLine // ----------------------------------------------------------------------------- -void LHEReader::FillHeaderInitLine(const std::string& line, - SampleFormat& mySample) +void LHEReader::FillHeaderInitLine(const std::string &line, + SampleFormat &mySample) { - std::stringstream str; - str << line; - - str >> mySample.mc()->beamPDGID_.first; - str >> mySample.mc()->beamPDGID_.second; - str >> mySample.mc()->beamE_.first; - str >> mySample.mc()->beamE_.second; - str >> mySample.mc()->beamPDFauthor_.first; - str >> mySample.mc()->beamPDFauthor_.second; - str >> mySample.mc()->beamPDFID_.first; - str >> mySample.mc()->beamPDFID_.second; - str >> mySample.mc()->weightMode_; - // str >> mySample.mc()->nProcesses_; UNUSED + std::stringstream str; + str << line; + + str >> mySample.mc()->beamPDGID_.first; + str >> mySample.mc()->beamPDGID_.second; + str >> mySample.mc()->beamE_.first; + str >> mySample.mc()->beamE_.second; + str >> mySample.mc()->beamPDFauthor_.first; + str >> mySample.mc()->beamPDFauthor_.second; + str >> mySample.mc()->beamPDFID_.first; + str >> mySample.mc()->beamPDFID_.second; + str >> mySample.mc()->weightMode_; + // str >> mySample.mc()->nProcesses_; UNUSED } - // ----------------------------------------------------------------------------- // FillHeaderProcessLine // ----------------------------------------------------------------------------- -void LHEReader::FillHeaderProcessLine(const std::string& line, - SampleFormat& mySample) +void LHEReader::FillHeaderProcessLine(const std::string &line, + SampleFormat &mySample) { - std::string tmpline=line; - size_t posi = 0; - while( (posi = tmpline.find("D", posi)) != std::string::npos) - tmpline=tmpline.replace(posi, 1, "E"); - posi=0; - while( (posi = tmpline.find("d", posi)) != std::string::npos) - tmpline=tmpline.replace(posi, 1, "E"); - - std::stringstream str; - str << tmpline; - - // Get a new process - ProcessFormat * proc = mySample.mc()->GetNewProcess(); - - str >> proc->xsectionMean_; - str >> proc->xsectionError_; - str >> proc->weightMax_; - str >> proc->processId_; + std::string tmpline = line; + size_t posi = 0; + while ((posi = tmpline.find("D", posi)) != std::string::npos) + tmpline = tmpline.replace(posi, 1, "E"); + posi = 0; + while ((posi = tmpline.find("d", posi)) != std::string::npos) + tmpline = tmpline.replace(posi, 1, "E"); + + std::stringstream str; + str << tmpline; + + // Get a new process + ProcessFormat *proc = mySample.mc()->GetNewProcess(); + + str >> proc->xsectionMean_; + str >> proc->xsectionError_; + str >> proc->weightMax_; + str >> proc->processId_; } - // ----------------------------------------------------------------------------- // FillEventInitLine // ----------------------------------------------------------------------------- -void LHEReader::FillEventInitLine(const std::string& line, - EventFormat& myEvent) +void LHEReader::FillEventInitLine(const std::string &line, + EventFormat &myEvent) { - std::stringstream str; - str << line; - MAuint32 nparts; - str >> nparts; - str >> myEvent.mc()->processId_; - str >> myEvent.mc()->weight_; - str >> myEvent.mc()->scale_; - str >> myEvent.mc()->alphaQED_; - str >> myEvent.mc()->alphaQCD_; - myEvent.mc()->particles_.reserve(nparts); - mothers_.reserve(nparts); + MAdouble64 weight; + std::stringstream str; + str << line; + MAuint32 nparts; + str >> nparts; + str >> myEvent.mc()->processId_; + str >> weight; + str >> myEvent.mc()->scale_; + str >> myEvent.mc()->alphaQED_; + str >> myEvent.mc()->alphaQCD_; + myEvent.mc()->particles_.reserve(nparts); + myEvent.mc()->weights().Add(0, weight); + mothers_.reserve(nparts); } - // ----------------------------------------------------------------------------- // FillEventParticleLine // ----------------------------------------------------------------------------- -void LHEReader::FillEventParticleLine(const std::string& line, - EventFormat& myEvent) +void LHEReader::FillEventParticleLine(const std::string &line, + EventFormat &myEvent) { - std::string tmpline=line; - size_t posi = 0; - while( (posi = tmpline.find("D", posi)) != std::string::npos) - tmpline=tmpline.replace(posi, 1, "E"); - posi=0; - while( (posi = tmpline.find("d", posi)) != std::string::npos) - tmpline=tmpline.replace(posi, 1, "E"); - - std::stringstream str; - str << tmpline; - - MAint32 color1; // color 1 not stored - MAint32 color2; // color 2 not stored - MAfloat64 tmp; // temporary - MAfloat64 px; // temporary variable to fill in LorentzVector - MAfloat64 py; // temporary variable to fill in LorentzVector - MAfloat64 pz; // temporary variable to fill in LorentzVector - MAfloat64 e; // temporary variable to fill in LorentzVector - MAfloat64 ctau; // temporary variable to fill in LorentzVector - MAint32 mothup1; // mother1 - MAint32 mothup2; // mother2 - - // Get a new particle - MCParticleFormat * part = myEvent.mc()->GetNewParticle(); - - str >> part->pdgid_; - str >> part->statuscode_; - str >> mothup1; - str >> mothup2; - str >> color1; - str >> color2; - str >> px; - str >> py; - str >> pz; - str >> e; - str >> tmp; - str >> ctau; - str >> part->spin_; - part->momentum_.SetPxPyPzE(px,py,pz,e); - part->decay_vertex_.SetT(ctau); - mothers_.push_back(std::make_pair(mothup1,mothup2)); + std::string tmpline = line; + size_t posi = 0; + while ((posi = tmpline.find("D", posi)) != std::string::npos) + tmpline = tmpline.replace(posi, 1, "E"); + posi = 0; + while ((posi = tmpline.find("d", posi)) != std::string::npos) + tmpline = tmpline.replace(posi, 1, "E"); + + std::stringstream str; + str << tmpline; + + MAint32 color1; // color 1 not stored + MAint32 color2; // color 2 not stored + MAfloat64 tmp; // temporary + MAfloat64 px; // temporary variable to fill in LorentzVector + MAfloat64 py; // temporary variable to fill in LorentzVector + MAfloat64 pz; // temporary variable to fill in LorentzVector + MAfloat64 e; // temporary variable to fill in LorentzVector + MAfloat64 ctau; // temporary variable to fill in LorentzVector + MAint32 mothup1; // mother1 + MAint32 mothup2; // mother2 + + // Get a new particle + MCParticleFormat *part = myEvent.mc()->GetNewParticle(); + + str >> part->pdgid_; + str >> part->statuscode_; + str >> mothup1; + str >> mothup2; + str >> color1; + str >> color2; + str >> px; + str >> py; + str >> pz; + str >> e; + str >> tmp; + str >> ctau; + str >> part->spin_; + part->momentum_.SetPxPyPzE(px, py, pz, e); + part->decay_vertex_.SetT(ctau); + mothers_.push_back(std::make_pair(mothup1, mothup2)); } - // ----------------------------------------------------------------------------- // FillWeightLine // ----------------------------------------------------------------------------- -void LHEReader::FillWeightLine(const std::string& line, - EventFormat& myEvent) +void LHEReader::FillWeightLine(const std::string &line, + EventFormat &myEvent) { - std::stringstream str; - str << line; - - std::string tmp; - str >> tmp; - if (tmp!="<wgt") return; - - std::size_t found1 = line.find("\""); - if (found1==std::string::npos) return; - std::size_t found2 = line.find("\"",found1+1); - if (found2==std::string::npos) return; - std::string idstring = line.substr(found1+1,found2-found1-1); - - std::stringstream str2; - str2<<idstring; - MAuint32 id; - str2>>id; - - found1 = line.find(">"); - if (found1==std::string::npos) return; - found2 = line.find("<",found1+1); - if (found2==std::string::npos) return; - std::string valuestring = line.substr(found1+1,found2-found1-1); - - std::stringstream str3; - str3<<valuestring; - MAfloat64 value; - str3>>value; - - myEvent.mc()->multiweights().Add(id,value); + std::stringstream str; + str << line; + + std::string tmp; + str >> tmp; + if (tmp != "<wgt") + return; + + std::size_t found1 = line.find("\""); + if (found1 == std::string::npos) + return; + std::size_t found2 = line.find("\"", found1 + 1); + if (found2 == std::string::npos) + return; + std::string idstring = line.substr(found1 + 1, found2 - found1 - 1); + + std::stringstream str2; + str2 << idstring; + MAuint32 id; + str2 >> id; + + found1 = line.find(">"); + if (found1 == std::string::npos) + return; + found2 = line.find("<", found1 + 1); + if (found2 == std::string::npos) + return; + std::string valuestring = line.substr(found1 + 1, found2 - found1 - 1); + + std::stringstream str3; + str3 << valuestring; + MAfloat64 value; + str3 >> value; + + myEvent.mc()->weights().Add(id, value); } diff --git a/tools/SampleAnalyzer/Process/Reader/STDHEPreader.cpp b/tools/SampleAnalyzer/Process/Reader/STDHEPreader.cpp index f35ab135..a3568b0b 100644 --- a/tools/SampleAnalyzer/Process/Reader/STDHEPreader.cpp +++ b/tools/SampleAnalyzer/Process/Reader/STDHEPreader.cpp @@ -1,842 +1,851 @@ //////////////////////////////////////////////////////////////////////////////// -// +// // Copyright (C) 2012-2023 Jack Araz, Eric Conte & Benjamin Fuks // The MadAnalysis development team, email: <ma5team@iphc.cnrs.fr> -// +// // This file is part of MadAnalysis 5. // Official website: <https://github.com/MadAnalysis/madanalysis5> -// +// // MadAnalysis 5 is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // MadAnalysis 5 is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with MadAnalysis 5. If not, see <http://www.gnu.org/licenses/> -// +// //////////////////////////////////////////////////////////////////////////////// - // SampleAnalyzer headers #include "SampleAnalyzer/Process/Reader/STDHEPreader.h" #include "SampleAnalyzer/Commons/Service/LogService.h" #include "SampleAnalyzer/Commons/Service/ConvertService.h" #include "SampleAnalyzer/Commons/Service/ExceptionService.h" - using namespace MA5; // ----------------------------------------------------------------------------- // Initialize // ----------------------------------------------------------------------------- -MAbool STDHEPreader::Initialize(const std::string& rawfilename, - const Configuration& cfg) +MAbool STDHEPreader::Initialize(const std::string &rawfilename, + const Configuration &cfg) { - nevhept_before_ = 0; - firstevent=true; + nevhept_before_ = 0; + firstevent = true; - if (!ReaderTextBase::Initialize(rawfilename, cfg)) return false; - xdrinput_=new xdr_istream(*input_); + if (!ReaderTextBase::Initialize(rawfilename, cfg)) + return false; + xdrinput_ = new xdr_istream(*input_); - return true; + return true; } - // ----------------------------------------------------------------------------- // ReadHeader // ----------------------------------------------------------------------------- void STDHEPreader::Reset() { - nevhept_=0; - nhept_=0; - isthept_.clear(); - idhept_.clear(); - jmohept_.clear(); - jdahept_.clear(); - phept_.clear(); - vhept_.clear(); + nevhept_ = 0; + nhept_ = 0; + isthept_.clear(); + idhept_.clear(); + jmohept_.clear(); + jdahept_.clear(); + phept_.clear(); + vhept_.clear(); } // ----------------------------------------------------------------------------- // ReadHeader // ----------------------------------------------------------------------------- -MAbool STDHEPreader::ReadHeader(SampleFormat& mySample) +MAbool STDHEPreader::ReadHeader(SampleFormat &mySample) { - // Initiliaze MC - mySample.InitializeMC(); - mySample.SetSampleFormat(MA5FORMAT::STDHEP); + // Initiliaze MC + mySample.InitializeMC(); + mySample.SetSampleFormat(MA5FORMAT::STDHEP); - if (!DecodeFileHeader(mySample)) return false; + if (!DecodeFileHeader(mySample)) + return false; - return true; + return true; } - // ----------------------------------------------------------------------------- // ReadEvent // ----------------------------------------------------------------------------- -StatusCode::Type STDHEPreader::ReadEvent(EventFormat& myEvent, SampleFormat& mySample) +StatusCode::Type STDHEPreader::ReadEvent(EventFormat &myEvent, SampleFormat &mySample) { - // Initiliaze MC - myEvent.InitializeMC(); - - MAbool eventRead=false; - MAbool eventskip=false; - while(!eventRead) - { - // Read blockid - MAint32 blockid=0; - *xdrinput_ >> blockid; - if (xdrinput_->eof()) return StatusCode::FAILURE; - - MAint32 ntot=0; - *xdrinput_ >> ntot; - - std::string version; - *xdrinput_ >> version; - - if (blockid==EVENTTABLE ) DecodeEventTable (version); - else if (blockid==EVENTHEADER) DecodeEventHeader(version); - else if (blockid==MCFIO_STDHEPBEG || - blockid==MCFIO_STDHEPEND) {DecodeSTDCM1 (version,mySample); } - else if (blockid==MCFIO_STDHEP) + // Initiliaze MC + myEvent.InitializeMC(); + + MAbool eventRead = false; + MAbool eventskip = false; + while (!eventRead) { - eventskip = !DecodeEventData(version, myEvent); - eventRead = true; + // Read blockid + MAint32 blockid = 0; + *xdrinput_ >> blockid; + if (xdrinput_->eof()) + return StatusCode::FAILURE; + + MAint32 ntot = 0; + *xdrinput_ >> ntot; + + std::string version; + *xdrinput_ >> version; + + if (blockid == EVENTTABLE) + DecodeEventTable(version); + else if (blockid == EVENTHEADER) + DecodeEventHeader(version); + else if (blockid == MCFIO_STDHEPBEG || + blockid == MCFIO_STDHEPEND) + { + DecodeSTDCM1(version, mySample); + } + else if (blockid == MCFIO_STDHEP) + { + eventskip = !DecodeEventData(version, myEvent); + eventRead = true; + } + else if (blockid == MCFIO_STDHEP4) + { + eventskip = !DecodeSTDHEP4(version, myEvent); + eventRead = true; + } + else + { + ERROR << "Block with the ID=" << blockid + << " is not managed by SampleAnalyzer" << endmsg; + return StatusCode::SKIP; + } } - else if (blockid==MCFIO_STDHEP4) + + // return + if (eventskip) + return StatusCode::SKIP; + return StatusCode::KEEP; +} + +// ----------------------------------------------------------------------------- +// DecodeFileHeader +// ----------------------------------------------------------------------------- +MAbool STDHEPreader::DecodeFileHeader(SampleFormat &mySample) +{ + // temporary variables used for reading the xdr format file + std::string tmps; + MAint32 tmpi = 0; + MAuint32 tmpui = 0; + + // BlockID + *xdrinput_ >> tmpi; + if (tmpi != FILEHEADER) + { + ERROR << "header block not found" << endmsg; + return false; + } + + // Ntot + *xdrinput_ >> tmpi; + + // STDHEP version + *xdrinput_ >> tmps; + SetVersion(tmps); + if (version_ == UNKNOWN) + { + ERROR << "stdhep version unknown : '" << tmps << endmsg; + return false; + } + + // Title + tmps = ""; + *xdrinput_ >> tmps; + // std::cout << "title=" << tmps << std::cout; + + // Set the title in lower case + tmps = CONVERT->ToLower(tmps); + if (tmps.find("pythia") != std::string::npos) { - eventskip = !DecodeSTDHEP4 (version, myEvent); - eventRead = true; + mySample.SetSampleGenerator(MA5GEN::PYTHIA6); + } + else if (tmps.find("herwig") != std::string::npos) + { + mySample.SetSampleGenerator(MA5GEN::HERWIG6); } else { - ERROR << "Block with the ID=" << blockid - << " is not managed by SampleAnalyzer" << endmsg; - return StatusCode::SKIP; + mySample.SetSampleGenerator(MA5GEN::UNKNOWN); } - } - // return - if(eventskip) return StatusCode::SKIP; - return StatusCode::KEEP; -} + // std::cout << "title=" << tmps << std::endl; + // Comment + *xdrinput_ >> tmps; + // std::cout << "comment=" << tmps << std::endl; -// ----------------------------------------------------------------------------- -// DecodeFileHeader -// ----------------------------------------------------------------------------- -MAbool STDHEPreader::DecodeFileHeader(SampleFormat& mySample) -{ - // temporary variables used for reading the xdr format file - std::string tmps; - MAint32 tmpi = 0; - MAuint32 tmpui = 0; - - // BlockID - *xdrinput_ >> tmpi; - if (tmpi != FILEHEADER) - { - ERROR << "header block not found" << endmsg; - return false; - } - - // Ntot - *xdrinput_ >> tmpi; - - // STDHEP version - *xdrinput_ >> tmps; - SetVersion(tmps); - if (version_==UNKNOWN) - { - ERROR << "stdhep version unknown : '" << tmps << endmsg; - return false; - } - - // Title - tmps=""; - *xdrinput_ >> tmps; - // std::cout << "title=" << tmps << std::cout; - - // Set the title in lower case - tmps = CONVERT->ToLower(tmps); - if (tmps.find("pythia")!=std::string::npos) - { - mySample.SetSampleGenerator(MA5GEN::PYTHIA6); - } - else if (tmps.find("herwig")!=std::string::npos) - { - mySample.SetSampleGenerator(MA5GEN::HERWIG6); - } - else - { - mySample.SetSampleGenerator(MA5GEN::UNKNOWN); - } - - //std::cout << "title=" << tmps << std::endl; - - // Comment - *xdrinput_ >> tmps; - //std::cout << "comment=" << tmps << std::endl; - - // Creation date - *xdrinput_ >> tmps; - //std::cout << "date=" << tmps << endmsg; - - // Closing date (only in version 2.01) - if (version_==V21) - { + // Creation date *xdrinput_ >> tmps; - //std::cout << "cdate=" << tmps << endmsg; - } - - // Expected number of events - *xdrinput_ >> tmpui; - //std::cout << "Nevents = " << tmpui << endmsg; - - // Number of events - *xdrinput_ >> tmpui; - //std::cout << "Nevents = " << tmpui << endmsg; - - // First table - *xdrinput_ >> tmpui; - //std::cout << "First table=" << tmpui << endmsg; - - // Dim Table - MAuint32 dimTable; - *xdrinput_ >> dimTable; - //std::cout << "Dim table=" << dimTable << endmsg; - - // Number of blocks - MAuint32 nBlocks; - *xdrinput_ >> nBlocks; - //std::cout << "N blocks = " << nBlocks << endmsg; - - // Number of NTuples - MAuint32 nNTuples = 0; - if (version_!=V1) - { - *xdrinput_ >> nNTuples; - //std::cout << "Nb NTuples = " << nNTuples << endmsg; - } - - // Processing blocks extraction - if (nBlocks!=0) - { - // Extracting blocks - std::vector<MAint32> blocks; - *xdrinput_ >> blocks; - - // Extracting block names - for (MAuint32 i=0;i<blocks.size();i++) + // std::cout << "date=" << tmps << endmsg; + + // Closing date (only in version 2.01) + if (version_ == V21) + { + *xdrinput_ >> tmps; + // std::cout << "cdate=" << tmps << endmsg; + } + + // Expected number of events + *xdrinput_ >> tmpui; + // std::cout << "Nevents = " << tmpui << endmsg; + + // Number of events + *xdrinput_ >> tmpui; + // std::cout << "Nevents = " << tmpui << endmsg; + + // First table + *xdrinput_ >> tmpui; + // std::cout << "First table=" << tmpui << endmsg; + + // Dim Table + MAuint32 dimTable; + *xdrinput_ >> dimTable; + // std::cout << "Dim table=" << dimTable << endmsg; + + // Number of blocks + MAuint32 nBlocks; + *xdrinput_ >> nBlocks; + // std::cout << "N blocks = " << nBlocks << endmsg; + + // Number of NTuples + MAuint32 nNTuples = 0; + if (version_ != V1) { - *xdrinput_ >> tmps; - //std::cout << "Block " << i << " = " << tmps; + *xdrinput_ >> nNTuples; + // std::cout << "Nb NTuples = " << nNTuples << endmsg; } - } - // Processing ntuple extraction (only in version 2) - /*if (version_!=V1 && nNTuples!=0) - { - // Loop over ntuple - for (MAuint32 i=0;i<nNTuples;i++) + // Processing blocks extraction + if (nBlocks != 0) { - // Number of characters in title - if ( !xdr_int(&xdr_, &tmpi) ) return false; - MAuint32 nctitle = tmpi; + // Extracting blocks + std::vector<MAint32> blocks; + *xdrinput_ >> blocks; - // Number of characters in category - if ( !xdr_int(&xdr_, &tmpi) ) return false; - MAuint32 nccategory = tmpi; + // Extracting block names + for (MAuint32 i = 0; i < blocks.size(); i++) + { + *xdrinput_ >> tmps; + // std::cout << "Block " << i << " = " << tmps; + } + } - // IdRef - if ( !xdr_int(&xdr_, &tmpi) ) return false; + // Processing ntuple extraction (only in version 2) + /*if (version_!=V1 && nNTuples!=0) + { + // Loop over ntuple + for (MAuint32 i=0;i<nNTuples;i++) + { + // Number of characters in title + if ( !xdr_int(&xdr_, &tmpi) ) return false; + MAuint32 nctitle = tmpi; + + // Number of characters in category + if ( !xdr_int(&xdr_, &tmpi) ) return false; + MAuint32 nccategory = tmpi; - // uid - if ( !xdr_int(&xdr_, &tmpi) ) return false; + // IdRef + if ( !xdr_int(&xdr_, &tmpi) ) return false; - // Title of the Ntuple - if ( !xdr_string(&xdr_, &tmps,nctitle) ) return false; + // uid + if ( !xdr_int(&xdr_, &tmpi) ) return false; - // Category of the Ntuple - if ( !xdr_string(&xdr_, &tmps,nccategory) ) return false; + // Title of the Ntuple + if ( !xdr_string(&xdr_, &tmps,nctitle) ) return false; - INFO << "ntu ... to finish" << endmsg; + // Category of the Ntuple + if ( !xdr_string(&xdr_, &tmps,nccategory) ) return false; + INFO << "ntu ... to finish" << endmsg; + + } } - } - */ + */ - return true; + return true; } - // ----------------------------------------------------------------------------- // FinalizeHeader // ----------------------------------------------------------------------------- -MAbool STDHEPreader::FinalizeHeader(SampleFormat& mySample) +MAbool STDHEPreader::FinalizeHeader(SampleFormat &mySample) { - return true; + return true; } - // ----------------------------------------------------------------------------- // DecodeEventTable // ----------------------------------------------------------------------------- -MAbool STDHEPreader::DecodeEventTable(const std::string& evt_version) +MAbool STDHEPreader::DecodeEventTable(const std::string &evt_version) { - // Decoding the event - // Case: classical - if (evt_version=="1.00") - { - MAint32 idat=0; - *xdrinput_ >> idat; + // Decoding the event + // Case: classical + if (evt_version == "1.00") + { + MAint32 idat = 0; + *xdrinput_ >> idat; - MAuint32 uidat=0; - *xdrinput_ >> uidat; + MAuint32 uidat = 0; + *xdrinput_ >> uidat; - // Extracting evtnums - std::vector<MAint32> evtnums; - *xdrinput_ >> evtnums; + // Extracting evtnums + std::vector<MAint32> evtnums; + *xdrinput_ >> evtnums; - // Extracting storenums - std::vector<MAint32> storenums; - *xdrinput_ >> storenums; + // Extracting storenums + std::vector<MAint32> storenums; + *xdrinput_ >> storenums; - // Extracting runnums - std::vector<MAint32> runnums; - *xdrinput_ >> runnums; + // Extracting runnums + std::vector<MAint32> runnums; + *xdrinput_ >> runnums; - // Extracting trigMasks - std::vector<MAuint32> NtrigMasks; - *xdrinput_ >> NtrigMasks; + // Extracting trigMasks + std::vector<MAuint32> NtrigMasks; + *xdrinput_ >> NtrigMasks; - // Extracting prtEvents - std::vector<MAuint32> NptrEvents; - *xdrinput_ >> NptrEvents; - } + // Extracting prtEvents + std::vector<MAuint32> NptrEvents; + *xdrinput_ >> NptrEvents; + } - // Pavel's adding: 64-bit adress - else if (evt_version=="2.00") - { - MAint32 idat=0; - *xdrinput_ >> idat; + // Pavel's adding: 64-bit adress + else if (evt_version == "2.00") + { + MAint32 idat = 0; + *xdrinput_ >> idat; - MAuint64 uidat=0; - *xdrinput_ >> uidat; + MAuint64 uidat = 0; + *xdrinput_ >> uidat; - // Extracting evtnums - std::vector<MAint32> evtnums; - *xdrinput_ >> evtnums; + // Extracting evtnums + std::vector<MAint32> evtnums; + *xdrinput_ >> evtnums; - // Extracting storenums - std::vector<MAint32> storenums; - *xdrinput_ >> storenums; + // Extracting storenums + std::vector<MAint32> storenums; + *xdrinput_ >> storenums; - // Extracting runnums - std::vector<MAint32> runnums; - *xdrinput_ >> runnums; + // Extracting runnums + std::vector<MAint32> runnums; + *xdrinput_ >> runnums; - // Extracting trigMasks - std::vector<MAuint32> NtrigMasks; - *xdrinput_ >> NtrigMasks; + // Extracting trigMasks + std::vector<MAuint32> NtrigMasks; + *xdrinput_ >> NtrigMasks; - // Extracting prtEvents - std::vector<MAuint64> NptrEvents; - *xdrinput_ >> NptrEvents; - } + // Extracting prtEvents + std::vector<MAuint64> NptrEvents; + *xdrinput_ >> NptrEvents; + } - // Case: other version? - else - { - ERROR << "version '" << evt_version << "' is not supported" << endmsg; - return false; - } + // Case: other version? + else + { + ERROR << "version '" << evt_version << "' is not supported" << endmsg; + return false; + } - return true; + return true; } - // ----------------------------------------------------------------------------- // DecodeEventHeader // ----------------------------------------------------------------------------- -MAbool STDHEPreader::DecodeEventHeader(const std::string& evt_version) +MAbool STDHEPreader::DecodeEventHeader(const std::string &evt_version) { - MAint32 evtnum=0; - *xdrinput_ >> evtnum; + MAint32 evtnum = 0; + *xdrinput_ >> evtnum; - MAint32 storenums=0; - *xdrinput_ >> storenums; - - MAint32 runnum=0; - *xdrinput_ >> runnum; - - MAint32 trigMask=0; - *xdrinput_ >> trigMask; + MAint32 storenums = 0; + *xdrinput_ >> storenums; - MAuint32 nBlocks=0; - *xdrinput_ >> nBlocks; + MAint32 runnum = 0; + *xdrinput_ >> runnum; - MAuint32 dimBlocks=0; - *xdrinput_ >> dimBlocks; + MAint32 trigMask = 0; + *xdrinput_ >> trigMask; - MAuint32 nNTuples=0; - MAuint32 dimNTuples=0; + MAuint32 nBlocks = 0; + *xdrinput_ >> nBlocks; - // Is there NTuple - MAbool skipNTuples = false; - MAbool add64bit=false; - if (evt_version=="2.00" || evt_version=="3.00") skipNTuples=true; - if (evt_version=="3.00") add64bit=true; + MAuint32 dimBlocks = 0; + *xdrinput_ >> dimBlocks; - // NTuple - if (skipNTuples) - { - *xdrinput_ >> nNTuples; - *xdrinput_ >> dimNTuples; - } + MAuint32 nNTuples = 0; + MAuint32 dimNTuples = 0; - // Processing blocks extraction - if (dimBlocks>0) - { - // Extracting blocks - std::vector<MAint32> blocks; - *xdrinput_ >> blocks; + // Is there NTuple + MAbool skipNTuples = false; + MAbool add64bit = false; + if (evt_version == "2.00" || evt_version == "3.00") + skipNTuples = true; + if (evt_version == "3.00") + add64bit = true; - // Extracting blocks - if (!add64bit) - { - std::vector<MAuint32> ptrBlocks; - *xdrinput_ >> ptrBlocks; - } - else + // NTuple + if (skipNTuples) { - std::vector<MAuint64> ptrBlocks; - *xdrinput_ >> ptrBlocks; + *xdrinput_ >> nNTuples; + *xdrinput_ >> dimNTuples; } - } - - // Processing blocks extraction - if (skipNTuples && dimNTuples>0) - { - // Extracting blocks - std::vector<MAint32> nTupleIds; - *xdrinput_ >> nTupleIds; - // Extracting blocks - if (!add64bit) + // Processing blocks extraction + if (dimBlocks > 0) { - std::vector<MAuint32> ptrNTuples; - *xdrinput_ >> ptrNTuples; + // Extracting blocks + std::vector<MAint32> blocks; + *xdrinput_ >> blocks; + + // Extracting blocks + if (!add64bit) + { + std::vector<MAuint32> ptrBlocks; + *xdrinput_ >> ptrBlocks; + } + else + { + std::vector<MAuint64> ptrBlocks; + *xdrinput_ >> ptrBlocks; + } } - else + + // Processing blocks extraction + if (skipNTuples && dimNTuples > 0) { - std::vector<MAuint64> ptrNTuples; - *xdrinput_ >> ptrNTuples; + // Extracting blocks + std::vector<MAint32> nTupleIds; + *xdrinput_ >> nTupleIds; + + // Extracting blocks + if (!add64bit) + { + std::vector<MAuint32> ptrNTuples; + *xdrinput_ >> ptrNTuples; + } + else + { + std::vector<MAuint64> ptrNTuples; + *xdrinput_ >> ptrNTuples; + } } - } - return true; + return true; } - // ----------------------------------------------------------------------------- // DecodeSTDCM1 // ----------------------------------------------------------------------------- -MAbool STDHEPreader::DecodeSTDCM1(const std::string& version, SampleFormat& mySample) +MAbool STDHEPreader::DecodeSTDCM1(const std::string &version, SampleFormat &mySample) { - MAint32 nevtreq; - *xdrinput_ >> nevtreq; - - MAint32 nevtgen; - *xdrinput_ >> nevtgen; + MAint32 nevtreq; + *xdrinput_ >> nevtreq; - MAint32 nevtwrt; - *xdrinput_ >> nevtwrt; + MAint32 nevtgen; + *xdrinput_ >> nevtgen; - MAfloat32 stdecom; - *xdrinput_ >> stdecom; + MAint32 nevtwrt; + *xdrinput_ >> nevtwrt; - MAfloat32 stdxsec; - *xdrinput_ >> stdxsec; - if (mySample.mc()!=0) - { - mySample.mc()->setXsectionMean(stdxsec); - mySample.mc()->setXsectionError(0); - } + MAfloat32 stdecom; + *xdrinput_ >> stdecom; - MAfloat64 stdseed1; - *xdrinput_ >> stdseed1; + MAfloat32 stdxsec; + *xdrinput_ >> stdxsec; + if (mySample.mc() != 0) + { + mySample.mc()->setXsectionMean(stdxsec); + mySample.mc()->setXsectionError(0); + } - MAfloat64 stdseed2; - *xdrinput_ >> stdseed2; + MAfloat64 stdseed1; + *xdrinput_ >> stdseed1; - if (version.find("1.")==0 || version.find("2.")==0 || - version.find("3.")==0 || version.find("4.")==0 || - version.find("5.00")==0) return true; + MAfloat64 stdseed2; + *xdrinput_ >> stdseed2; - std::string tmps; - *xdrinput_ >> tmps; - *xdrinput_ >> tmps; + if (version.find("1.") == 0 || version.find("2.") == 0 || + version.find("3.") == 0 || version.find("4.") == 0 || + version.find("5.00") == 0) + return true; - if (version.find("5.00")==0 || version.find("5.01")==0 ) - return true; + std::string tmps; + *xdrinput_ >> tmps; + *xdrinput_ >> tmps; - MAint32 nevtlh=0; - *xdrinput_ >> nevtlh; + if (version.find("5.00") == 0 || version.find("5.01") == 0) + return true; - return true; + MAint32 nevtlh = 0; + *xdrinput_ >> nevtlh; + return true; } - // ----------------------------------------------------------------------------- // DecodeEventFormat // ----------------------------------------------------------------------------- -MAbool STDHEPreader::DecodeEventData(const std::string& version, - EventFormat& myEvent) +MAbool STDHEPreader::DecodeEventData(const std::string &version, + EventFormat &myEvent) { - Reset(); - - // Extracting the event number - *xdrinput_ >> nevhept_; - - // Extracting the number of particles - *xdrinput_ >> nhept_; + Reset(); - // Extracting isthept - *xdrinput_ >> isthept_; + // Extracting the event number + *xdrinput_ >> nevhept_; - // Extracting idhept - *xdrinput_ >> idhept_; + // Extracting the number of particles + *xdrinput_ >> nhept_; - // Extracting jmohept - *xdrinput_ >> jmohept_; + // Extracting isthept + *xdrinput_ >> isthept_; - // Extracting jdahept - *xdrinput_ >> jdahept_; + // Extracting idhept + *xdrinput_ >> idhept_; - // Extracting - *xdrinput_ >> phept_; + // Extracting jmohept + *xdrinput_ >> jmohept_; - // Extracting - *xdrinput_ >> vhept_; + // Extracting jdahept + *xdrinput_ >> jdahept_; - // Check the consistency of the event - if(!CheckEvent(myEvent,"STDHEP")) return false; + // Extracting + *xdrinput_ >> phept_; - // Reserve memory for all particles - myEvent.mc()->particles_.reserve(nhept_); - mothers_.reserve(nhept_); + // Extracting + *xdrinput_ >> vhept_; - // Loop over particles - for (MAuint32 i=0;i<static_cast<MAuint32>(nhept_);i++) - { - // Get a new particle - MCParticleFormat * part = myEvent.mc()->GetNewParticle(); + // Check the consistency of the event + if (!CheckEvent(myEvent, "STDHEP")) + return false; - MAuint32 mothup1=0; - MAuint32 mothup2=0; + // Reserve memory for all particles + myEvent.mc()->particles_.reserve(nhept_); + mothers_.reserve(nhept_); - // Fill the data format - part->pdgid_ = idhept_[i]; - part->statuscode_ = isthept_[i]; - mothup1 = jmohept_[2*i]; - mothup2 = jmohept_[2*i+1]; - // daughter1_ = jdahept_[2*i]; - // daughter2_ = jdahept_[2*i+1]; - part->momentum_.SetPxPyPzE(phept_[5*i],phept_[5*i+1],phept_[5*i+2],phept_[5*i+3]); - mothers_.push_back(std::make_pair(mothup1,mothup2)); - - // For debug - // std::cout << "pdgid=" << part->pdgid_ << " status=" << part->statuscode_ - // << " mothup1=" << mothup1 <<" mothup2=" << mothup2 << std::endl; - } + // Loop over particles + for (MAuint32 i = 0; i < static_cast<MAuint32>(nhept_); i++) + { + // Get a new particle + MCParticleFormat *part = myEvent.mc()->GetNewParticle(); + + MAuint32 mothup1 = 0; + MAuint32 mothup2 = 0; + + // Fill the data format + part->pdgid_ = idhept_[i]; + part->statuscode_ = isthept_[i]; + mothup1 = jmohept_[2 * i]; + mothup2 = jmohept_[2 * i + 1]; + // daughter1_ = jdahept_[2*i]; + // daughter2_ = jdahept_[2*i+1]; + part->momentum_.SetPxPyPzE(phept_[5 * i], phept_[5 * i + 1], phept_[5 * i + 2], phept_[5 * i + 3]); + mothers_.push_back(std::make_pair(mothup1, mothup2)); + + // For debug + // std::cout << "pdgid=" << part->pdgid_ << " status=" << part->statuscode_ + // << " mothup1=" << mothup1 <<" mothup2=" << mothup2 << std::endl; + } - return true; + return true; } -MAbool STDHEPreader::CheckEvent(const EventFormat& myEvent, - const std::string& blk) +MAbool STDHEPreader::CheckEvent(const EventFormat &myEvent, + const std::string &blk) { - if(nhept_<0) - { - ERROR << "Corrupted " << blk << " block: negative number of particles." - << " Event ignored ." << endmsg; - return false; - } - if(nhept_!=static_cast<MAint32>(isthept_.size())) - { - ERROR << "Corrupted " << blk << " block: missing status codes." - << " Event ignored." << endmsg; - return false; - } - if(nhept_!=static_cast<MAint32>(idhept_.size())) - { - ERROR << "Corrupted " << blk << " block: missing PDG codes." - << " Event ignored." << endmsg; - return false; - } - if((2*nhept_)!=static_cast<MAint32>(jmohept_.size())) - { - ERROR << "Corrupted " << blk << " block: missing mother information." - << " Event ignored." << endmsg; - return false; - } - if((2*nhept_)!=static_cast<MAint32>(jdahept_.size())) - { - ERROR << "Corrupted " << blk << " block: missing daughter information." - << " Event ignored." << endmsg; - return false; - } - if((5*nhept_)!=static_cast<MAint32>(phept_.size())) - { - ERROR << "Corrupted " << blk << " block: missing 4-momentum " << - "information." << " Event ignored." << endmsg; - return false; - } - if((4*nhept_)!=static_cast<MAint32>(vhept_.size())) - { - ERROR << "Corrupted " << blk << " block: missing vertex information." - << " Event ignored." << endmsg; - return false; - } - return true; + if (nhept_ < 0) + { + ERROR << "Corrupted " << blk << " block: negative number of particles." + << " Event ignored ." << endmsg; + return false; + } + if (nhept_ != static_cast<MAint32>(isthept_.size())) + { + ERROR << "Corrupted " << blk << " block: missing status codes." + << " Event ignored." << endmsg; + return false; + } + if (nhept_ != static_cast<MAint32>(idhept_.size())) + { + ERROR << "Corrupted " << blk << " block: missing PDG codes." + << " Event ignored." << endmsg; + return false; + } + if ((2 * nhept_) != static_cast<MAint32>(jmohept_.size())) + { + ERROR << "Corrupted " << blk << " block: missing mother information." + << " Event ignored." << endmsg; + return false; + } + if ((2 * nhept_) != static_cast<MAint32>(jdahept_.size())) + { + ERROR << "Corrupted " << blk << " block: missing daughter information." + << " Event ignored." << endmsg; + return false; + } + if ((5 * nhept_) != static_cast<MAint32>(phept_.size())) + { + ERROR << "Corrupted " << blk << " block: missing 4-momentum " + << "information." + << " Event ignored." << endmsg; + return false; + } + if ((4 * nhept_) != static_cast<MAint32>(vhept_.size())) + { + ERROR << "Corrupted " << blk << " block: missing vertex information." + << " Event ignored." << endmsg; + return false; + } + return true; } -MAbool STDHEPreader::DecodeSTDHEP4(const std::string& version, - EventFormat& myEvent) +MAbool STDHEPreader::DecodeSTDHEP4(const std::string &version, + EventFormat &myEvent) { - Reset(); - - // Extracting the event number - *xdrinput_ >> nevhept_; + Reset(); - // Extracting the number of particles - *xdrinput_ >> nhept_; + // Extracting the event number + *xdrinput_ >> nevhept_; - // Extracting isthept - *xdrinput_ >> isthept_; + // Extracting the number of particles + *xdrinput_ >> nhept_; - // Extracting idhept - *xdrinput_ >> idhept_; + // Extracting isthept + *xdrinput_ >> isthept_; - // Extracting jmohept - *xdrinput_ >> jmohept_; + // Extracting idhept + *xdrinput_ >> idhept_; - // Extracting jdahept - *xdrinput_ >> jdahept_; + // Extracting jmohept + *xdrinput_ >> jmohept_; - // Extracting - *xdrinput_ >> phept_; + // Extracting jdahept + *xdrinput_ >> jdahept_; - // Extracting - *xdrinput_ >> vhept_; + // Extracting + *xdrinput_ >> phept_; - // Extracting the event weight - MAfloat64 eventweight=1; - *xdrinput_ >> eventweight; - myEvent.mc()->setWeight(eventweight); + // Extracting + *xdrinput_ >> vhept_; - // Extracting alpha QED - MAfloat64 alphaQED=0; - *xdrinput_ >> alphaQED; + // Extracting the event weight + MAfloat64 eventweight = 1; + *xdrinput_ >> eventweight; + myEvent.mc()->weights().Add(0, eventweight); - // Extracting alpha QCD - MAfloat64 alphaQCD=0; - *xdrinput_ >> alphaQCD; + // Extracting alpha QED + MAfloat64 alphaQED = 0; + *xdrinput_ >> alphaQED; - // Extracing dat - std::vector<MAfloat64> dat; - *xdrinput_ >> dat; + // Extracting alpha QCD + MAfloat64 alphaQCD = 0; + *xdrinput_ >> alphaQCD; - // Extracing dat - std::vector<MAfloat64> spint; - *xdrinput_ >> spint; + // Extracing dat + std::vector<MAfloat64> dat; + *xdrinput_ >> dat; - // Extracting idat - std::vector<MAint32> idat; - *xdrinput_ >> idat; + // Extracing dat + std::vector<MAfloat64> spint; + *xdrinput_ >> spint; - // Extracting idrupt - MAint32 idrupt; - *xdrinput_ >> idrupt; - - // Check the consistency of the entries in the event table - if(!CheckEvent(myEvent, "STDHEP4")) return false; + // Extracting idat + std::vector<MAint32> idat; + *xdrinput_ >> idat; - // Reserve memory for all particles - myEvent.mc()->particles_.reserve(nhept_); + // Extracting idrupt + MAint32 idrupt; + *xdrinput_ >> idrupt; - // Loop over particles - for (MAuint32 i=0;i<static_cast<MAuint32>(nhept_);i++) - { - // Get a new particle - MCParticleFormat * part = myEvent.mc()->GetNewParticle(); - - MAuint32 mothup1=0; - MAuint32 mothup2=0; + // Check the consistency of the entries in the event table + if (!CheckEvent(myEvent, "STDHEP4")) + return false; - // Fill the data format - part->pdgid_ = idhept_[i]; - part->statuscode_ = isthept_[i]; - mothup1 = jmohept_[2*i]; - mothup2 = jmohept_[2*i+1]; - // daughter1_ = jdahept_[2*i]; - // daughter2_ = jdahept_[2*i+1]; - part->momentum_.SetPxPyPzE(phept_[5*i],phept_[5*i+1],phept_[5*i+2],phept_[5*i+3]); - mothers_.push_back(std::make_pair(mothup1,mothup2)); + // Reserve memory for all particles + myEvent.mc()->particles_.reserve(nhept_); - // For debug - // std::cout << "pdgid=" << part->pdgid_ << " status=" << part->statuscode_ - // << " mothup1=" << mothup1 <<" mothup2=" << mothup2 << std::endl; - } + // Loop over particles + for (MAuint32 i = 0; i < static_cast<MAuint32>(nhept_); i++) + { + // Get a new particle + MCParticleFormat *part = myEvent.mc()->GetNewParticle(); + + MAuint32 mothup1 = 0; + MAuint32 mothup2 = 0; + + // Fill the data format + part->pdgid_ = idhept_[i]; + part->statuscode_ = isthept_[i]; + mothup1 = jmohept_[2 * i]; + mothup2 = jmohept_[2 * i + 1]; + // daughter1_ = jdahept_[2*i]; + // daughter2_ = jdahept_[2*i+1]; + part->momentum_.SetPxPyPzE(phept_[5 * i], phept_[5 * i + 1], phept_[5 * i + 2], phept_[5 * i + 3]); + mothers_.push_back(std::make_pair(mothup1, mothup2)); + + // For debug + // std::cout << "pdgid=" << part->pdgid_ << " status=" << part->statuscode_ + // << " mothup1=" << mothup1 <<" mothup2=" << mothup2 << std::endl; + } - return true; + return true; } - // ----------------------------------------------------------------------------- // AddMothers // ----------------------------------------------------------------------------- -MAbool AddMothers(MCParticleFormat* part,MCParticleFormat* mum) +MAbool AddMothers(MCParticleFormat *part, MCParticleFormat *mum) { - for (MAuint32 i=0;i<part->mothers().size();i++) - { - MCParticleFormat* m = part->mothers()[i]; - if (m==mum) return false; - } - part->mothers().push_back(mum); - return true; + for (MAuint32 i = 0; i < part->mothers().size(); i++) + { + MCParticleFormat *m = part->mothers()[i]; + if (m == mum) + return false; + } + part->mothers().push_back(mum); + return true; } - // ----------------------------------------------------------------------------- // AddDaughters // ----------------------------------------------------------------------------- -MAbool AddDaughters(MCParticleFormat* part,MCParticleFormat* dau) +MAbool AddDaughters(MCParticleFormat *part, MCParticleFormat *dau) { - for (MAuint32 i=0;i<part->daughters().size();i++) - { - MCParticleFormat* d = part->daughters()[i]; - if (d==dau) return false; - } - part->daughters().push_back(dau); - return true; + for (MAuint32 i = 0; i < part->daughters().size(); i++) + { + MCParticleFormat *d = part->daughters()[i]; + if (d == dau) + return false; + } + part->daughters().push_back(dau); + return true; } - // ----------------------------------------------------------------------------- // FinalizeEvent // ----------------------------------------------------------------------------- -MAbool STDHEPreader::FinalizeEvent(SampleFormat& mySample, EventFormat& myEvent) +MAbool STDHEPreader::FinalizeEvent(SampleFormat &mySample, EventFormat &myEvent) { - // Is it a bugged event ? - if (!firstevent && nevhept_ == nevhept_before_) return false; - nevhept_before_ = nevhept_; - firstevent=false; - - // BUG FIX HERE : myEvent.mc()->particles()[i] LEADs TO CRASH - // MUST USE myEvent.mc()->particles_[i]; - // WHY????? - - // Mother-daughter relations - for (MAuint32 i=0; i<myEvent.mc()->particles_.size();i++) - { - MCParticleFormat* part = &(myEvent.mc()->particles_[i]); - MAint32& mothup1 = mothers_[i].first; - MAint32& mothup2 = mothers_[i].second; - - if (mothup1>0) + // Is it a bugged event ? + if (!firstevent && nevhept_ == nevhept_before_) + return false; + nevhept_before_ = nevhept_; + firstevent = false; + + // BUG FIX HERE : myEvent.mc()->particles()[i] LEADs TO CRASH + // MUST USE myEvent.mc()->particles_[i]; + // WHY????? + + // Mother-daughter relations + for (MAuint32 i = 0; i < myEvent.mc()->particles_.size(); i++) { - if (static_cast<MAuint32>(mothup1)<=myEvent.mc()->particles_.size()) - { - MCParticleFormat* mum = &(myEvent.mc()->particles_[static_cast<MAuint32>(mothup1-1)]); - if (part!=mum) + MCParticleFormat *part = &(myEvent.mc()->particles_[i]); + MAint32 &mothup1 = mothers_[i].first; + MAint32 &mothup2 = mothers_[i].second; + + if (mothup1 > 0) { - AddMothers(part,mum); - AddDaughters(mum,part); + if (static_cast<MAuint32>(mothup1) <= myEvent.mc()->particles_.size()) + { + MCParticleFormat *mum = &(myEvent.mc()->particles_[static_cast<MAuint32>(mothup1 - 1)]); + if (part != mum) + { + AddMothers(part, mum); + AddDaughters(mum, part); + } + } + else + { + std::cout << "ERROR: a particle is its own mother" << std::endl; + } } - } - else - { - std::cout << "ERROR: a particle is its own mother" << std::endl; - } - } - if (mothup2>0) - { - if (static_cast<MAuint32>(mothup2)<=myEvent.mc()->particles_.size()) - { - MCParticleFormat* mum = &(myEvent.mc()->particles_[static_cast<MAuint32>(mothup2-1)]); - if (mum!=part) + if (mothup2 > 0) { - AddMothers(part,mum); - AddDaughters(mum,part); + if (static_cast<MAuint32>(mothup2) <= myEvent.mc()->particles_.size()) + { + MCParticleFormat *mum = &(myEvent.mc()->particles_[static_cast<MAuint32>(mothup2 - 1)]); + if (mum != part) + { + AddMothers(part, mum); + AddDaughters(mum, part); + } + } + else + { + std::cout << "ERROR: a particle is its own mother" << std::endl; + } } - } - else - { - std::cout << "ERROR: a particle is its own mother" << std::endl; - } } - } - mothers_.clear(); + mothers_.clear(); - // Global event observable - for (MAuint32 i=0; i<myEvent.mc()->particles_.size();i++) - { - MCParticleFormat& part = myEvent.mc()->particles_[i]; - - // MET, MHT, TET, THT - if (part.statuscode()==1 && !PHYSICS->Id->IsInvisible(part)) + // Global event observable + for (MAuint32 i = 0; i < myEvent.mc()->particles_.size(); i++) { - myEvent.mc()->MET_ -= part.momentum(); - myEvent.mc()->TET_ += part.pt(); - if (PHYSICS->Id->IsHadronic(part)) - { - myEvent.mc()->MHT_ -= part.momentum(); - myEvent.mc()->THT_ += part.pt(); - myEvent.mc()->Meff_ += part.pt(); - } + MCParticleFormat &part = myEvent.mc()->particles_[i]; + + // MET, MHT, TET, THT + if (part.statuscode() == 1 && !PHYSICS->Id->IsInvisible(part)) + { + myEvent.mc()->MET_ -= part.momentum(); + myEvent.mc()->TET_ += part.pt(); + if (PHYSICS->Id->IsHadronic(part)) + { + myEvent.mc()->MHT_ -= part.momentum(); + myEvent.mc()->THT_ += part.pt(); + myEvent.mc()->Meff_ += part.pt(); + } + } } - } - // Finalize event - myEvent.mc()->MET_.momentum().SetPz(0.); - myEvent.mc()->MET_.momentum().SetE(myEvent.mc()->MET_.momentum().Pt()); - myEvent.mc()->MHT_.momentum().SetPz(0.); - myEvent.mc()->MHT_.momentum().SetE(myEvent.mc()->MHT_.momentum().Pt()); - myEvent.mc()->Meff_ += myEvent.mc()->MET_.pt(); + // Finalize event + myEvent.mc()->MET_.momentum().SetPz(0.); + myEvent.mc()->MET_.momentum().SetE(myEvent.mc()->MET_.momentum().Pt()); + myEvent.mc()->MHT_.momentum().SetPz(0.); + myEvent.mc()->MHT_.momentum().SetE(myEvent.mc()->MHT_.momentum().Pt()); + myEvent.mc()->Meff_ += myEvent.mc()->MET_.pt(); - // Normal end - return true; + // Normal end + return true; } - // ----------------------------------------------------------------------------- // Finalize // ----------------------------------------------------------------------------- MAbool STDHEPreader::Finalize() { - if (!ReaderTextBase::Finalize()) return false; - if (xdrinput_!=0) delete xdrinput_; - return true; + if (!ReaderTextBase::Finalize()) + return false; + if (xdrinput_ != 0) + delete xdrinput_; + return true; } - // ----------------------------------------------------------------------------- // SetVersion // ----------------------------------------------------------------------------- -void STDHEPreader::SetVersion(const std::string& version) +void STDHEPreader::SetVersion(const std::string &version) { - if (version.size()<2) version_=UNKNOWN; - else if (version[0]==1) version_=V1; - else if (version=="2.01") version_=V21; - else if (version[0]==2) version_=V2; - else version_=UNKNOWN; + if (version.size() < 2) + version_ = UNKNOWN; + else if (version[0] == 1) + version_ = V1; + else if (version == "2.01") + version_ = V21; + else if (version[0] == 2) + version_ = V2; + else + version_ = UNKNOWN; } From b7fad97e19f02095f7ce9bc9a60a25a6f850e97f Mon Sep 17 00:00:00 2001 From: "Jack Y. Araz" <jackaraz@gmail.com> Date: Tue, 27 Jun 2023 15:15:52 +0100 Subject: [PATCH 007/107] update region selection manager --- .../RegionSelectionManager.cpp | 14 +-- .../RegionSelection/RegionSelectionManager.h | 102 ++++-------------- 2 files changed, 29 insertions(+), 87 deletions(-) diff --git a/tools/SampleAnalyzer/Process/RegionSelection/RegionSelectionManager.cpp b/tools/SampleAnalyzer/Process/RegionSelection/RegionSelectionManager.cpp index 2cd7ad57..ecdf8fb0 100644 --- a/tools/SampleAnalyzer/Process/RegionSelection/RegionSelectionManager.cpp +++ b/tools/SampleAnalyzer/Process/RegionSelection/RegionSelectionManager.cpp @@ -35,9 +35,7 @@ MAbool RegionSelectionManager::ApplyCut(MAbool condition, std::string const &cut { /// Skip the cut if all regions are already failing the previous cut if (NumberOfSurvivingRegions_ == 0) - { return false; - } /// Get the cut under consideration MultiRegionCounter *mycut = 0; @@ -69,23 +67,25 @@ MAbool RegionSelectionManager::ApplyCut(MAbool condition, std::string const &cut /// Skip the current region if it has failed a previous cut if (!ThisRegion->IsSurviving()) - { continue; - } + + WeightCollection current_region_weight; + if (region_weight_.find(ThisRegion->GetName()) != region_weight_.end()) + current_region_weight = region_weight_[ThisRegion->GetName()]; + else + current_region_weight = weight_; /// Check the current cut: if (condition) { - ThisRegion->IncrementCutFlow(ThisRegion->GetMultiWeight()); + ThisRegion->IncrementCutFlow(current_region_weight); } else { ThisRegion->SetSurvivingTest(false); NumberOfSurvivingRegions_--; if (NumberOfSurvivingRegions_ == 0) - { return false; - } } } diff --git a/tools/SampleAnalyzer/Process/RegionSelection/RegionSelectionManager.h b/tools/SampleAnalyzer/Process/RegionSelection/RegionSelectionManager.h index 80cb20bb..c569a040 100644 --- a/tools/SampleAnalyzer/Process/RegionSelection/RegionSelectionManager.h +++ b/tools/SampleAnalyzer/Process/RegionSelection/RegionSelectionManager.h @@ -29,6 +29,8 @@ #include <string> #include <sstream> +#define assertm(exp, msg) assert(((void)msg, exp)) + // SampleAnalyzer headers #include "SampleAnalyzer/Process/Counter/MultiRegionCounterManager.h" #include "SampleAnalyzer/Process/Plot/PlotManager.h" @@ -59,7 +61,10 @@ namespace MA5 MAuint32 NumberOfSurvivingRegions_; /// Weight associated with the processed event - std::map<MAuint32, MAfloat64> weight_; + WeightCollection weight_; + + /// Weight associated with specific regions + std::map<std::string, WeightCollection> region_weight_; // ------------------------------------------------------------- // method members @@ -72,99 +77,46 @@ namespace MA5 ~RegionSelectionManager() { for (auto ®ion_pointer : regions_) - { delete region_pointer; - } }; /// Reset void Reset() { for (MAuint32 i = 0; i < regions_.size(); i++) - { if (regions_[i] != 0) delete regions_[i]; - } regions_.clear(); cutmanager_.Finalize(); plotmanager_.Finalize(); weight_.clear(); + region_weight_.clear(); } /// Finalizing void Finalize() { Reset(); } /// Get methods - std::vector<RegionSelection *> Regions() - { - return regions_; - } - - MultiRegionCounterManager *GetCutManager() - { - return &cutmanager_; - } + std::vector<RegionSelection *> Regions() { return regions_; } - PlotManager *GetPlotManager() - { - return &plotmanager_; - } + MultiRegionCounterManager *GetCutManager() { return &cutmanager_; } - std::map<MAuint32, MAfloat64> GetCurrentEventWeight() - { - return weight_; - } + PlotManager *GetPlotManager() { return &plotmanager_; } - /// @brief Set current event weight with a single weight value - /// @param weight single weight value - void SetCurrentEventWeight(MAfloat64 weight) - { - weight_.clear(); - weight_.insert(std::make_pair(0, weight)); - for (MAuint16 i = 0; i < regions_.size(); i++) - { - regions_[i]->SetWeight(weight_); - } - } + /// @brief Accessor to the current event weight + /// @return weight collection object + const WeightCollection GetCurrentEventWeight() const { return weight_; } /// @brief Set current event weight with a weight map /// @param weight weight index and value - void SetCurrentEventWeight(std::map<MAuint32, MAfloat64> weight) - { - weight_.clear(); - weight_ = weight; - for (MAuint16 i = 0; i < regions_.size(); i++) - { - regions_[i]->SetWeight(weight_); - } - } + void SetCurrentEventWeight(WeightCollection &weight) { weight_ = WeightCollection(weight); } - /// Set method - void SetRegionWeight(std::string name, MAfloat64 weight) + /// @brief Set a specific weight to a region different than the others + /// @param name region name + /// @param weight weight collection object + void SetRegionWeight(std::string name, WeightCollection &weight) { - for (auto ® : regions_) - { - if (reg->GetName() == name) - { - reg->SetWeight(weight); - break; - } - } - } - - /// @brief set region weight with a weight map - /// @param name name of the region - /// @param weight weight map - void SetRegionWeight(std::string name, std::map<MAuint32, MAfloat64> weight) - { - for (auto ® : regions_) - { - if (reg->GetName() == name) - { - reg->SetWeight(weight); - break; - } - } + region_weight_.insert(std::make_pair(name, WeightCollection(weight))); } /// Adding a RegionSelection to the manager @@ -181,23 +133,13 @@ namespace MA5 regions_.push_back(myregion); } - /// Getting ready for a new event - void InitializeForNewEvent(MAfloat64 EventWeight) - { - weight_.clear(); - weight_.insert(std::make_pair(0, EventWeight)); - NumberOfSurvivingRegions_ = regions_.size(); - for (auto ® : regions_) - reg->InitializeForNewEvent(EventWeight); - for (MAuint32 i = 0; i < plotmanager_.GetNplots(); i++) - plotmanager_.GetHistos()[i]->SetFreshEvent(true); - } + /// THIS FUNCTION HAS BEEN DEPRECATED + void InitializeForNewEvent(MAfloat64 EventWeight) {} /// @brief initialise new event with multiweight definition /// @param EventWeight weight map - void InitializeForNewEvent(std::map<MAuint32, MAfloat64> EventWeight) + void InitializeForNewEvent(WeightCollection &EventWeight) { - weight_.clear(); weight_ = EventWeight; NumberOfSurvivingRegions_ = regions_.size(); for (auto ® : regions_) From 66c0680a652cedc8f658fb08ef0b212f96314e8c Mon Sep 17 00:00:00 2001 From: "Jack Y. Araz" <jackaraz@gmail.com> Date: Tue, 27 Jun 2023 15:16:05 +0100 Subject: [PATCH 008/107] update cutflow --- .../SampleAnalyzer/Process/Counter/Counter.h | 3 +- .../Process/Counter/CounterManager.cpp | 123 +++++++----------- 2 files changed, 50 insertions(+), 76 deletions(-) diff --git a/tools/SampleAnalyzer/Process/Counter/Counter.h b/tools/SampleAnalyzer/Process/Counter/Counter.h index 435b1ecd..1be99bad 100644 --- a/tools/SampleAnalyzer/Process/Counter/Counter.h +++ b/tools/SampleAnalyzer/Process/Counter/Counter.h @@ -26,7 +26,8 @@ // SampleAnalyzer headers #include "SampleAnalyzer/Commons/Base/PortableDatatypes.h" -#include "SampleAnalyzer/Process/Counter/Basics.h" +#include "SampleAnalyzer/Commons/Base/Basics.h" +#include "SampleAnalyzer/Commons/DataFormat/WeightCollection.h" // STL headers #include <iostream> diff --git a/tools/SampleAnalyzer/Process/Counter/CounterManager.cpp b/tools/SampleAnalyzer/Process/Counter/CounterManager.cpp index 69c8d39c..981db2e1 100644 --- a/tools/SampleAnalyzer/Process/Counter/CounterManager.cpp +++ b/tools/SampleAnalyzer/Process/Counter/CounterManager.cpp @@ -26,51 +26,6 @@ using namespace MA5; -/* -/// Write the counters in a ROOT file -void CounterManager::Write_RootFormat(TFile* output) const -{ - // Creating ROOT containers - TVector nentries_pos (counters_.size()); - TVector sumweight_pos (counters_.size()); - TVector sumweight2_pos (counters_.size()); - TVector nentries_neg (counters_.size()); - TVector sumweight_neg (counters_.size()); - TVector sumweight2_neg (counters_.size()); - TVector initial_pos (1); - TVector initial_neg (1); - TVector initial2_pos (1); - TVector initial2_neg (1); - - // Filling ROOT containers with info - for (MAuint32 i=0; i<counters_.size();i++) - { - nentries_pos[i] = counters_[i].nentries_.first; - sumweight_pos[i] = counters_[i].sumweight_.first; - sumweight2_pos[i] = counters_[i].sumweight2_.first; - nentries_neg[i] = counters_[i].nentries_.second; - sumweight_neg[i] = counters_[i].sumweight_.second; - sumweight2_neg[i] = counters_[i].sumweight2_.second; - } - initial_pos[0] = initial_.sumweight_.first; - initial_neg[0] = initial_.sumweight_.second; - initial2_pos[0] = initial_.sumweight2_.first; - initial2_neg[0] = initial_.sumweight2_.second; - - // Saving info - initial_pos.Write("initial_sumw_positive_weight"); - initial_neg.Write("initial_sumw_negative_weight"); - initial2_pos.Write("initial_sumw2_positive_weight"); - initial2_neg.Write("initial_sumw2_negative_weight"); - nentries_pos.Write("nentries_pos"); - sumweight_pos.Write("accepted_sumw_positive_weight"); - sumweight2_pos.Write("accepted_sumw2_positive_weight"); - nentries_neg.Write("nentries_neg"); - sumweight_neg.Write("accepted_sumw_negative_weight"); - sumweight2_neg.Write("accepted_sumw2_negative_weight"); -} -*/ - /// Write the counters in a TEXT file void CounterManager::Write_TextFormat(SAFWriter &output) const { @@ -81,27 +36,36 @@ void CounterManager::Write_TextFormat(SAFWriter &output) const *output.GetStream() << "\"Initial number of events\" #" << std::endl; // nentries - output.GetStream()->width(15); - *output.GetStream() << std::left << std::scientific << initial_.nentries_.first; - *output.GetStream() << " "; - output.GetStream()->width(15); - *output.GetStream() << std::left << std::scientific << initial_.nentries_.second; + for (auto &event : initial_.nentries_) + { + output.GetStream()->width(15); + *output.GetStream() << std::left << std::scientific << event.second.positive; + *output.GetStream() << " "; + output.GetStream()->width(15); + *output.GetStream() << std::left << std::scientific << event.second.negative; + } *output.GetStream() << " # nentries" << std::endl; // sum of weights - output.GetStream()->width(15); - *output.GetStream() << std::left << std::scientific << initial_.sumweight_.at(0).first; - *output.GetStream() << " "; - output.GetStream()->width(15); - *output.GetStream() << std::left << std::scientific << initial_.sumweight_.at(0).second; + for (auto &event : initial_.sumweights_) + { + output.GetStream()->width(15); + *output.GetStream() << std::left << std::scientific << event.second.positive; + *output.GetStream() << " "; + output.GetStream()->width(15); + *output.GetStream() << std::left << std::scientific << event.second.negative; + } *output.GetStream() << " # sum of weights" << std::endl; // sum of weights^2 - output.GetStream()->width(15); - *output.GetStream() << std::left << std::scientific << initial_.sumweight2_.at(0).first; - *output.GetStream() << " "; - output.GetStream()->width(15); - *output.GetStream() << std::left << std::scientific << initial_.sumweight2_.at(0).second; + for (auto &event : initial_.sumweights2_) + { + output.GetStream()->width(15); + *output.GetStream() << std::left << std::scientific << event.second.positive; + *output.GetStream() << " "; + output.GetStream()->width(15); + *output.GetStream() << std::left << std::scientific << event.second.negative; + } *output.GetStream() << " # sum of weights^2" << std::endl; // foot @@ -124,27 +88,36 @@ void CounterManager::Write_TextFormat(SAFWriter &output) const *output.GetStream() << "# " << i + 1 << "st cut" << std::endl; // nentries - output.GetStream()->width(15); - *output.GetStream() << std::left << std::scientific << counters_[i].nentries_.first; - *output.GetStream() << " "; - output.GetStream()->width(15); - *output.GetStream() << std::left << std::scientific << counters_[i].nentries_.second; + for (auto &event : counters_[i].nentries_) + { + output.GetStream()->width(15); + *output.GetStream() << std::left << std::scientific << event.second.positive; + *output.GetStream() << " "; + output.GetStream()->width(15); + *output.GetStream() << std::left << std::scientific << event.second.negative; + } *output.GetStream() << " # nentries" << std::endl; // sum of weights - output.GetStream()->width(15); - *output.GetStream() << std::left << std::scientific << counters_[i].sumweight_.at(0).first; - *output.GetStream() << " "; - output.GetStream()->width(15); - *output.GetStream() << std::left << std::scientific << counters_[i].sumweight_.at(0).second; + for (auto &event : counters_[i].sumweights_) + { + output.GetStream()->width(15); + *output.GetStream() << std::left << std::scientific << event.second.positive; + *output.GetStream() << " "; + output.GetStream()->width(15); + *output.GetStream() << std::left << std::scientific << event.second.negative; + } *output.GetStream() << " # sum of weights" << std::endl; // sum of weights^2 - output.GetStream()->width(15); - *output.GetStream() << std::left << std::scientific << counters_[i].sumweight2_.at(0).first; - *output.GetStream() << " "; - output.GetStream()->width(15); - *output.GetStream() << std::left << std::scientific << counters_[i].sumweight2_.at(0).second; + for (auto &event : counters_[i].sumweights2_) + { + output.GetStream()->width(15); + *output.GetStream() << std::left << std::scientific << event.second.positive; + *output.GetStream() << " "; + output.GetStream()->width(15); + *output.GetStream() << std::left << std::scientific << event.second.negative; + } *output.GetStream() << " # sum of weights^2" << std::endl; // foot From f7d5e8bee2ab5876df6245b34933a43a5bafe0e2 Mon Sep 17 00:00:00 2001 From: "Jack Y. Araz" <jackaraz@gmail.com> Date: Tue, 27 Jun 2023 15:16:20 +0100 Subject: [PATCH 009/107] update histograms --- tools/SampleAnalyzer/Process/Plot/Histo.cpp | 357 ++++++++++----- tools/SampleAnalyzer/Process/Plot/Histo.h | 99 +---- .../Process/Plot/HistoFrequency.h | 408 +++++++++--------- .../SampleAnalyzer/Process/Plot/HistoLogX.cpp | 121 +++--- tools/SampleAnalyzer/Process/Plot/HistoLogX.h | 227 ++++------ tools/SampleAnalyzer/Process/Plot/PlotBase.h | 208 ++++----- 6 files changed, 721 insertions(+), 699 deletions(-) diff --git a/tools/SampleAnalyzer/Process/Plot/Histo.cpp b/tools/SampleAnalyzer/Process/Plot/Histo.cpp index eada9936..04fe88f7 100644 --- a/tools/SampleAnalyzer/Process/Plot/Histo.cpp +++ b/tools/SampleAnalyzer/Process/Plot/Histo.cpp @@ -29,133 +29,252 @@ using namespace MA5; /// Write the plot in a Text file void Histo::Write_TextFormat(std::ostream *output) { - // Header - *output << "<Histo>" << std::endl; + // Header + *output << "<Histo>" << std::endl; - // Write the body - Write_TextFormatBody(output); + // Write the body + Write_TextFormatBody(output); - // Foot - *output << "</Histo>" << std::endl; - *output << std::endl; + // Foot + *output << "</Histo>" << std::endl; + *output << std::endl; } /// Write the plot in a Text file void Histo::Write_TextFormatBody(std::ostream *output) { - // Description - *output << " <Description>" << std::endl; - - // Name - *output << " \"" << name_ << "\"" << std::endl; - - // Title - *output << " "; - output->width(10); - *output << std::left << "# nbins"; - output->width(15); - *output << std::left << "xmin"; - output->width(15); - *output << std::left << "xmax" << std::endl; - - // Data - *output << " "; - output->width(8); - *output << std::left << nbins_; - output->width(15); - *output << std::left << std::scientific << xmin_; - output->width(15); - *output << std::left << std::scientific << xmax_ << std::endl; - - // SelectionRegions - if (regions_.size() != 0) - { - MAuint32 maxlength = 0; - for (MAuint32 i = 0; i < regions_.size(); i++) - if (regions_[i]->GetName().size() > maxlength) - maxlength = regions_[i]->GetName().size(); - *output << std::left << " # Defined regions" << std::endl; - for (MAuint32 i = 0; i < regions_.size(); i++) - { - *output << " " << std::setw(maxlength) << std::left << regions_[i]->GetName(); - *output << " # Region nr. " << std::fixed << i + 1 << std::endl; - } - } - - // End description - *output << " </Description>" << std::endl; - - // Statistics - *output << " <Statistics>" << std::endl; - - *output << " "; - output->width(15); - *output << std::fixed << nevents_.first; - output->width(15); - *output << std::fixed << nevents_.second; - *output << " # nevents" << std::endl; - *output << " "; - output->width(15); - *output << std::scientific << nevents_w_.first; - output->width(15); - *output << std::scientific << nevents_w_.second; - *output << " # sum of event-weights over events" << std::endl; - *output << " "; - output->width(15); - *output << std::fixed << nentries_.first; - output->width(15); - *output << std::fixed << nentries_.second; - *output << " # nentries" << std::endl; - *output << " "; - output->width(15); - *output << std::scientific << sum_w_[0].first; - output->width(15); - *output << std::scientific << sum_w_[0].second; - *output << " # sum of event-weights over entries" << std::endl; - *output << " "; - output->width(15); - *output << std::scientific << sum_ww_[0].first; - output->width(15); - *output << std::scientific << sum_ww_[0].second; - *output << " # sum weights^2" << std::endl; - *output << " "; - output->width(15); - *output << std::scientific << sum_xw_[0].first; - output->width(15); - *output << std::scientific << sum_xw_[0].second; - *output << " # sum value*weight" << std::endl; - *output << " "; - output->width(15); - *output << std::scientific << sum_xxw_[0].first; - output->width(15); - *output << std::scientific << sum_xxw_[0].second; - *output << " # sum value^2*weight" << std::endl; - *output << " </Statistics>" << std::endl; - - // Data - *output << " <Data>" << std::endl; - *output << " "; - output->width(15); - *output << std::scientific << underflow_[0].first; - output->width(15); - *output << std::scientific << underflow_[0].second; - *output << " # underflow" << std::endl; - for (MAuint32 i = 0; i < histo_.size(); i++) - { + // Description + *output << " <Description>" << std::endl; + + // Name + *output << " \"" << name_ << "\"" << std::endl; + + // Title + *output << " "; + output->width(10); + *output << std::left << "# nbins"; + output->width(15); + *output << std::left << "xmin"; + output->width(15); + *output << std::left << "xmax" << std::endl; + + // Data *output << " "; + output->width(8); + *output << std::left << nbins_; output->width(15); - *output << std::scientific << histo_[0][i].first; + *output << std::left << std::scientific << xmin_; output->width(15); - *output << std::scientific << histo_[0][i].second; - if (i < 2 || i >= (histo_.size() - 2)) - *output << " # bin " << i + 1 << " / " << histo_.size(); - *output << std::endl; - } - *output << " "; - output->width(15); - *output << std::scientific << overflow_[0].first; - output->width(15); - *output << std::scientific << overflow_[0].second; - *output << " # overflow" << std::endl; - *output << " </Data>" << std::endl; + *output << std::left << std::scientific << xmax_ << std::endl; + + // SelectionRegions + if (regions_.size() != 0) + { + MAuint32 maxlength = 0; + for (MAuint32 i = 0; i < regions_.size(); i++) + if (regions_[i]->GetName().size() > maxlength) + maxlength = regions_[i]->GetName().size(); + *output << std::left << " # Defined regions" << std::endl; + for (MAuint32 i = 0; i < regions_.size(); i++) + { + *output << " " << std::setw(maxlength) << std::left << regions_[i]->GetName(); + *output << " # Region nr. " << std::fixed << i + 1 << std::endl; + } + } + + // End description + *output << " </Description>" << std::endl; + + // Statistics + *output << " <Statistics>" << std::endl; + + *output << " "; + for (auto &event : nevents_) + { + output->width(15); + *output << std::fixed << event.second.positive; + output->width(15); + *output << std::fixed << event.second.negative; + } + *output << " # nevents" << std::endl; + *output << " "; + for (auto &event : nevents_w_) + { + output->width(15); + *output << std::scientific << event.second.positive; + output->width(15); + *output << std::scientific << event.second.negative; + } + *output << " # sum of event-weights over events" << std::endl; + *output << " "; + for (auto &event : nentries_) + { + output->width(15); + *output << std::fixed << event.second.positive; + output->width(15); + *output << std::fixed << event.second.negative; + } + *output << " # nentries" << std::endl; + *output << " "; + for (auto &event : sum_w_) + { + output->width(15); + *output << std::scientific << event.second.positive; + output->width(15); + *output << std::scientific << event.second.negative; + } + *output << " # sum of event-weights over entries" << std::endl; + *output << " "; + for (auto &event : sum_ww_) + { + output->width(15); + *output << std::scientific << event.second.positive; + output->width(15); + *output << std::scientific << event.second.negative; + } + *output << " # sum weights^2" << std::endl; + *output << " "; + for (auto &event : sum_xw_) + { + output->width(15); + *output << std::scientific << event.second.positive; + output->width(15); + *output << std::scientific << event.second.negative; + } + *output << " # sum value*weight" << std::endl; + *output << " "; + for (auto &event : sum_xxw_) + { + output->width(15); + *output << std::scientific << event.second.positive; + output->width(15); + *output << std::scientific << event.second.negative; + } + *output << " # sum value^2*weight" << std::endl; + *output << " </Statistics>" << std::endl; + + // Data + *output << " <Data>" << std::endl; + *output << " "; + for (auto &event : underflow_) + { + output->width(15); + *output << std::scientific << event.second.positive; + output->width(15); + *output << std::scientific << event.second.negative; + } + *output << " # underflow" << std::endl; + for (MAuint32 ibin = 0; ibin < histo_.size(); ibin++) + { + *output << " "; + for (auto &bin : histo_[ibin]) + { + output->width(15); + *output << std::scientific << bin.second.positive; + output->width(15); + *output << std::scientific << bin.second.negative; + } + if (ibin < 2 || ibin >= (histo_.size() - 2)) + *output << " # bin " << ibin + 1 << " / " << histo_.size(); + *output << std::endl; + } + *output << " "; + for (auto &event : overflow_) + { + output->width(15); + *output << std::scientific << event.second.positive; + output->width(15); + *output << std::scientific << event.second.negative; + } + *output << " # overflow" << std::endl; + *output << " </Data>" << std::endl; +} + +/// @brief Initialise the containers +/// @param weights weight collection +void Histo::Initialise(const WeightCollection &weights) +{ + if (!initialised_) + { + for (auto &w : weights.GetWeights()) + { + MAint32 idx = w.first; + for (MAuint16 i = 0; i < nbins_; i++) + { + std::map<MAint32, WEIGHTS> current; + current[idx] = WEIGHTS(); + if (histo_.size() < i) + histo_.push_back(current); + else + histo_[i] = current; + } + underflow_[idx] = WEIGHTS(); + overflow_[idx] = WEIGHTS(); + sum_w_[idx] = WEIGHTS(); + sum_ww_[idx] = WEIGHTS(); + sum_xw_[idx] = WEIGHTS(); + sum_xxw_[idx] = WEIGHTS(); + } + initialised_ = true; + } +} + +/// Filling histogram +void Histo::Fill(MAfloat64 value, const WeightCollection &weights) +{ + Initialise(weights); + // Safety : nan or isinf + try + { + if (std::isnan(value)) + throw EXCEPTION_WARNING("Skipping a NaN (Not a Number) value in an histogram.", "", 0); + if (std::isinf(value)) + throw EXCEPTION_WARNING("Skipping a Infinity value in an histogram.", "", 0); + } + catch (const std::exception &e) + { + MANAGE_EXCEPTION(e); + } + + for (auto &w : weights.GetWeights()) + { + MAdouble64 weight = w.second; + MAint32 idx = w.first; + // Positive weight + if (weight >= 0) + { + nentries_[idx].positive++; + sum_w_[idx].positive += weight; + sum_ww_[idx].positive += weight * weight; + sum_xw_[idx].positive += value * weight; + sum_xxw_[idx].positive += value * value * weight; + if (value < xmin_) + underflow_[idx].positive += weight; + else if (value >= xmax_) + overflow_[idx].positive += weight; + else + { + histo_[std::floor((value - xmin_) / step_)][idx].positive += weight; + } + } + + // Negative weight + else + { + MAdouble64 pw = std::fabs(weight); + nentries_[idx].negative++; + sum_w_[idx].negative += pw; + sum_ww_[idx].negative += pw * pw; + sum_xw_[idx].negative += value * pw; + sum_xxw_[idx].negative += value * value * pw; + if (value < xmin_) + underflow_[idx].negative += pw; + else if (value >= xmax_) + overflow_[idx].negative += pw; + else + { + histo_[std::floor((value - xmin_) / step_)][idx].negative += pw; + } + } + } } diff --git a/tools/SampleAnalyzer/Process/Plot/Histo.h b/tools/SampleAnalyzer/Process/Plot/Histo.h index 28b91852..cbd68b10 100644 --- a/tools/SampleAnalyzer/Process/Plot/Histo.h +++ b/tools/SampleAnalyzer/Process/Plot/Histo.h @@ -33,6 +33,7 @@ #include "SampleAnalyzer/Process/Plot/PlotBase.h" #include "SampleAnalyzer/Process/RegionSelection/RegionSelection.h" #include "SampleAnalyzer/Commons/Service/ExceptionService.h" +#include "SampleAnalyzer/Commons/Base/Basics.h" namespace MA5 { @@ -44,10 +45,14 @@ namespace MA5 // data members // ------------------------------------------------------------- protected: + /// Each variable is defined with WEIGHTS object which includes positive and negative accessors + /// these are for positive and negative bins. std::map<MAint32,WEIGHTS> contains a map of + /// different PDF and their corresponding positive and negative weights. + /// Histogram arrays - std::map<MAint32, std::vector<std::pair<MAfloat64, MAfloat64>>> histo_; - std::map<MAint32, std::pair<MAfloat64, MAfloat64>> underflow_; - std::map<MAint32, std::pair<MAfloat64, MAfloat64>> overflow_; + std::vector<std::map<MAint32, WEIGHTS>> histo_; + std::map<MAint32, WEIGHTS> underflow_; + std::map<MAint32, WEIGHTS> overflow_; /// Histogram description MAuint32 nbins_; @@ -56,20 +61,23 @@ namespace MA5 MAfloat64 step_; /// Sum of event-weights over entries - std::map<MAint32, std::pair<MAfloat64, MAfloat64>> sum_w_; + std::map<MAint32, WEIGHTS> sum_w_; /// Sum of squared weights - std::map<MAint32, std::pair<MAfloat64, MAfloat64>> sum_ww_; + std::map<MAint32, WEIGHTS> sum_ww_; /// Sum of value * weight - std::map<MAint32, std::pair<MAfloat64, MAfloat64>> sum_xw_; + std::map<MAint32, WEIGHTS> sum_xw_; /// Sum of value * value * weight - std::map<MAint32, std::pair<MAfloat64, MAfloat64>> sum_xxw_; + std::map<MAint32, WEIGHTS> sum_xxw_; /// RegionSelections attached to the histo std::vector<RegionSelection *> regions_; + /// @brief If the class is initialised or not + MAbool initialised_; + // ------------------------------------------------------------- // method members // ------------------------------------------------------------- @@ -81,6 +89,7 @@ namespace MA5 xmin_ = 0; xmax_ = 100; step_ = (xmax_ - xmin_) / static_cast<MAfloat64>(nbins_); + initialised_ = false; } /// Constructor with argument @@ -89,6 +98,7 @@ namespace MA5 /// Constructor with argument Histo(const std::string &name, MAuint32 nbins, MAfloat64 xmin, MAfloat64 xmax) : PlotBase(name) { + initialised_ = false; // Setting the description: nbins try { @@ -119,16 +129,7 @@ namespace MA5 step_ = (xmax_ - xmin_) / static_cast<MAfloat64>(nbins_); - // Reseting the histogram array - histo_[0].resize(nbins_, std::make_pair(0., 0.)); - underflow_[0] = std::make_pair(0., 0.); - overflow_[0] = std::make_pair(0., 0.); - - // Reseting statistical counters - sum_w_[0] = std::make_pair(0., 0.); - sum_ww_[0] = std::make_pair(0., 0.); - sum_xw_[0] = std::make_pair(0., 0.); - sum_xxw_[0] = std::make_pair(0., 0.); + histo_.resize(nbins_); } /// Destructor @@ -158,71 +159,15 @@ namespace MA5 return 0; } - /// Filling histogram - void Fill(MAfloat64 value, std::map<MAint32, MAdouble64> weights) - { - // Safety : nan or isinf - try - { - if (std::isnan(value)) - throw EXCEPTION_WARNING("Skipping a NaN (Not a Number) value in an histogram.", "", 0); - if (std::isinf(value)) - throw EXCEPTION_WARNING("Skipping a Infinity value in an histogram.", "", 0); - } - catch (const std::exception &e) - { - MANAGE_EXCEPTION(e); - } + /// Initialise the class + void Initialise(const WeightCollection &weights); - for (auto &wmap : weights) - { - MAdouble64 weight = wmap.second; - MAint32 idx = wmap.first; - // Positive weight - if (weight >= 0) - { - nentries_.first++; - sum_w_[idx].first += weight; - sum_ww_[idx].first += weight * weight; - sum_xw_[idx].first += value * weight; - sum_xxw_[idx].first += value * value * weight; - if (value < xmin_) - underflow_[idx].first += weight; - else if (value >= xmax_) - overflow_[idx].first += weight; - else - { - histo_[idx][std::floor((value - xmin_) / step_)].first += weight; - } - } - - // Negative weight - else - { - nentries_.second++; - weight = std::abs(weight); - sum_w_[idx].second += weight; - sum_ww_[idx].second += weight * weight; - sum_xw_[idx].second += value * weight; - sum_xxw_[idx].second += value * value * weight; - if (value < xmin_) - underflow_[idx].second += weight; - else if (value >= xmax_) - overflow_[idx].second += weight; - else - { - histo_[idx][std::floor((value - xmin_) / step_)].second += weight; - } - } - } - } + /// Filling histogram + void Fill(MAfloat64 value, const WeightCollection &weights); /// Write the plot in a ROOT file virtual void Write_TextFormat(std::ostream *output); - /// Write the plot in a ROOT file - // virtual void Write_RootFormat(std::pair<TH1F*,TH1F*>& histos); - protected: /// Write the plot in a ROOT file virtual void Write_TextFormatBody(std::ostream *output); diff --git a/tools/SampleAnalyzer/Process/Plot/HistoFrequency.h b/tools/SampleAnalyzer/Process/Plot/HistoFrequency.h index 00a35023..f6d72940 100644 --- a/tools/SampleAnalyzer/Process/Plot/HistoFrequency.h +++ b/tools/SampleAnalyzer/Process/Plot/HistoFrequency.h @@ -1,31 +1,29 @@ //////////////////////////////////////////////////////////////////////////////// -// +// // Copyright (C) 2012-2023 Jack Araz, Eric Conte & Benjamin Fuks // The MadAnalysis development team, email: <ma5team@iphc.cnrs.fr> -// +// // This file is part of MadAnalysis 5. // Official website: <https://github.com/MadAnalysis/madanalysis5> -// +// // MadAnalysis 5 is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // MadAnalysis 5 is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with MadAnalysis 5. If not, see <http://www.gnu.org/licenses/> -// +// //////////////////////////////////////////////////////////////////////////////// - #ifndef HISTO_FREQUENCY_H #define HISTO_FREQUENCY_H - // STL headers #include <map> #include <string> @@ -33,212 +31,208 @@ // SampleAnalyzer headers #include "SampleAnalyzer/Process/Plot/PlotBase.h" - +#include "SampleAnalyzer/Commons/Base/Basics.h" namespace MA5 { -class HistoFrequency : public PlotBase -{ - - // ------------------------------------------------------------- - // data members - // ------------------------------------------------------------- - protected : - - /// Collection of observables - std::map<int, std::pair<MAfloat64,MAfloat64> > stack_; - - /// Sum of event-weights over entries - std::pair<MAfloat64,MAfloat64> sum_w_; - - /// RegionSelections attached to the histo - std::vector<RegionSelection*> regions_; - - // ------------------------------------------------------------- - // method members - // ------------------------------------------------------------- - public : - - typedef std::map<int,std::pair<MAfloat64,MAfloat64> >::iterator iterator; - typedef std::map<int,std::pair<MAfloat64,MAfloat64> >::const_iterator const_iterator; - typedef std::map<int,std::pair<MAfloat64,MAfloat64> >::size_type size_type; - - /// Constructor with argument - HistoFrequency(const std::string& name) : PlotBase(name) - { - // Reseting statistical counters - sum_w_ = std::make_pair(0.,0.); - } - - /// Destructor - virtual ~HistoFrequency() - { } - - /// Setting the linked regions - void SetSelectionRegions(std::vector<RegionSelection*> myregions) - { regions_.insert(regions_.end(), myregions.begin(), myregions.end()); } - - /// Checking that all regions of the histo are surviving - /// Returns 0 if all regions are failing (includes te case with 0 SR) - /// Returns 1 if all regions are passing - // returns -1 otherwise - MAint32 AllSurviving() - { - if (regions_.size() == 0) return 0; - MAbool FirstRegionSurvival = regions_[0]->IsSurviving(); - for(MAuint32 ii=1; ii < regions_.size(); ii++) - if(regions_[ii]->IsSurviving() != FirstRegionSurvival) return -1; - if(FirstRegionSurvival) return 1; - else return 0; - } - - - /// Adding an entry for a given observable - void Fill(const MAint32& obs, MAfloat64 weight=1.0) - { - // Looking for the value - iterator it = stack_.find(obs); - - // Value not found - if (it==stack_.end()) + class HistoFrequency : public PlotBase { - stack_[obs]=std::make_pair(0.,0.); - } - // Value found - else - { - if (weight>=0) - { - nentries_.first++; - sum_w_.first+=weight; - stack_[obs].first+=weight; - } - else - { - nentries_.second++; - weight=std::abs(weight); - sum_w_.second+=weight; - stack_[obs].second+=weight; - } - } - } - - /// Write the plot in a ROOT file - virtual void Write_TextFormat(std::ostream* output) - { - // Header - *output << "<HistoFrequency>" << std::endl; - - // Description - *output << " <Description>" << std::endl; - *output << " \"" << name_ << "\"" << std::endl; - - // SelectionRegions - if(regions_.size()!=0) - { - MAuint32 maxlength=0; - for(MAuint32 i=0; i < regions_.size(); i++) - if (regions_[i]->GetName().size()>maxlength) maxlength=regions_[i]->GetName().size(); - *output << std::left << " # Defined regions" << std::endl; - for(MAuint32 i=0; i < regions_.size(); i++) - { - *output << " " << std::setw(maxlength) << std::left << regions_[i]->GetName(); - *output << " # Region nr. " << std::fixed << i+1 << std::endl; - } - } - - // End description - *output << " </Description>" << std::endl; - - // Statistics - *output << " <Statistics>" << std::endl; - *output << " "; - output->width(15); *output << std::fixed << nevents_.first; - output->width(15); *output << std::fixed << nevents_.second; - *output << " # nevents" << std::endl; - *output << " "; - output->width(15); *output << std::scientific << nevents_w_.first; - output->width(15); *output << std::scientific << nevents_w_.second; - *output << " # sum of event-weights over events" << std::endl; - *output << " "; - output->width(15); *output << std::fixed << nentries_.first; - output->width(15); *output << std::fixed << nentries_.second; - *output << " # nentries" << std::endl; - *output << " "; - output->width(15); *output << std::scientific << sum_w_.first; - output->width(15); *output << std::scientific << sum_w_.second; - *output << " # sum of event-weights over entries" << std::endl; - *output << " </Statistics>" << std::endl; - - // Data - *output << " <Data>" << std::endl; - MAuint32 i=0; - for (const_iterator it = stack_.begin(); it!=stack_.end(); it++) - { - *output << " "; - output->width(15); *output << std::left << std::fixed << it->first; - output->width(15); *output << std::left << std::scientific << it->second.first; - output->width(15); *output << std::left << std::scientific << it->second.second; - if (i<2 || i>=(stack_.size()-2)) - *output << " # bin " << i+1 << " / " << stack_.size(); - *output << std::endl; - i++; - } - *output << " </Data>" << std::endl; - - // Footer - *output << "</HistoFrequency>" << std::endl; - *output << std::endl; - } - - /// Write the plot in a ROOT file - /* - virtual void Write_RootFormat(std::pair<TH1F*,TH1F*>& histo) - { - - if (stack_.size()==0) - { - // Creating ROOT histograms - histo.first -> SetBins(1,0.,1.); - histo.second -> SetBins(1,0.,1.); - histo.first -> SetBinContent(1,0); - histo.first->GetXaxis()->SetBinLabel(1,"666"); - histo.second -> SetBinContent(1,0); - histo.second->GetXaxis()->SetBinLabel(1,"666"); - return; - } - - // Creating ROOT histograms - histo.first -> SetBins(stack_.size(),0., - static_cast<MAfloat64>(stack_.size())); - histo.second -> SetBins(stack_.size(),0., - static_cast<MAfloat64>(stack_.size())); - - // Layouting the histogram - MAuint32 i=0; - for (const_iterator it=stack_.begin();it!=stack_.end();it++) - { - std::string tmp; - std::stringstream str; - str << it->first; - str >> tmp; - - histo.first -> SetBinContent(i+1,it->second.first); - histo.first->GetXaxis()->SetBinLabel(i+1,tmp.c_str()); - - histo.second -> SetBinContent(i+1,it->second.second); - histo.second->GetXaxis()->SetBinLabel(i+1,tmp.c_str()); - - i++; - } - } - */ - -}; + // ------------------------------------------------------------- + // data members + // ------------------------------------------------------------- + protected: + /// Collection of observables + std::map<int, std::map<MAint32, WEIGHTS>> stack_; + + /// Sum of event-weights over entries + std::map<MAint32, WEIGHTS> sum_w_; + + /// RegionSelections attached to the histo + std::vector<RegionSelection *> regions_; + + /// @brief is the class initialised + MAbool initialised_; + + // ------------------------------------------------------------- + // method members + // ------------------------------------------------------------- + public: + // @jackaraz: these may not be necessary: + // typedef std::map<int, std::pair<MAfloat64, MAfloat64>>::iterator iterator; + // typedef std::map<int, std::pair<MAfloat64, MAfloat64>>::const_iterator const_iterator; + // typedef std::map<int, std::pair<MAfloat64, MAfloat64>>::size_type size_type; + + /// Constructor with argument + HistoFrequency(const std::string &name) : PlotBase(name) { initialised_ = false; } + + /// Destructor + virtual ~HistoFrequency() {} + + void initialise_weights(const WeightCollection &multiweight) + { + if (!initialised_) + { + for (auto &weight : multiweight.GetWeights()) + sum_w_[weight.first] = WEIGHTS(); + initialised_ = true; + } + } + + /// Setting the linked regions + void SetSelectionRegions(std::vector<RegionSelection *> myregions) + { + regions_.insert(regions_.end(), myregions.begin(), myregions.end()); + } + + /// Checking that all regions of the histo are surviving + /// Returns 0 if all regions are failing (includes te case with 0 SR) + /// Returns 1 if all regions are passing + // returns -1 otherwise + MAint32 AllSurviving() + { + if (regions_.size() == 0) + return 0; + MAbool FirstRegionSurvival = regions_[0]->IsSurviving(); + for (MAuint32 ii = 1; ii < regions_.size(); ii++) + if (regions_[ii]->IsSurviving() != FirstRegionSurvival) + return -1; + if (FirstRegionSurvival) + return 1; + else + return 0; + } + + /// Adding an entry for a given observable + void Fill(const MAint32 &obs, WeightCollection &weights) + { + + initialise_weights(weights); + for (auto &weight : weights.GetWeights()) + { + MAint32 idx = weight.first; + MAdouble64 w = weight.second; + // Value not found + if (stack_.find(obs) == stack_.end()) + stack_[obs][idx] = WEIGHTS(); + + // Value found + else + { + if (w >= 0) + { + nentries_[idx].positive++; + sum_w_[idx].positive += w; + stack_[obs][idx].positive += w; + } + else + { + nentries_[idx].negative++; + sum_w_[idx].negative += std::fabs(w); + stack_[obs][idx].negative += std::fabs(w); + } + } + } + } + + /// Write the plot in a ROOT file + virtual void Write_TextFormat(std::ostream *output) + { + // Header + *output << "<HistoFrequency>" << std::endl; + + // Description + *output << " <Description>" << std::endl; + *output << " \"" << name_ << "\"" << std::endl; + + // SelectionRegions + if (regions_.size() != 0) + { + MAuint32 maxlength = 0; + for (MAuint32 i = 0; i < regions_.size(); i++) + if (regions_[i]->GetName().size() > maxlength) + maxlength = regions_[i]->GetName().size(); + *output << std::left << " # Defined regions" << std::endl; + for (MAuint32 i = 0; i < regions_.size(); i++) + { + *output << " " << std::setw(maxlength) << std::left << regions_[i]->GetName(); + *output << " # Region nr. " << std::fixed << i + 1 << std::endl; + } + } + + // End description + *output << " </Description>" << std::endl; + + // Statistics + *output << " <Statistics>" << std::endl; + *output << " "; + for (auto &event : nevents_) + { + output->width(15); + *output << std::fixed << event.second.positive; + output->width(15); + *output << std::fixed << event.second.negative; + } + *output << " # nevents" << std::endl; + *output << " "; + for (auto &event : nevents_w_) + { + output->width(15); + *output << std::scientific << event.second.positive; + output->width(15); + *output << std::scientific << event.second.negative; + } + *output << " # sum of event-weights over events" << std::endl; + *output << " "; + for (auto &event : nentries_) + { + output->width(15); + *output << std::fixed << event.second.positive; + output->width(15); + *output << std::fixed << event.second.negative; + } + *output << " # nentries" << std::endl; + *output << " "; + for (auto &event : sum_w_) + { + output->width(15); + *output << std::scientific << event.second.positive; + output->width(15); + *output << std::scientific << event.second.negative; + } + *output << " # sum of event-weights over entries" << std::endl; + *output << " </Statistics>" << std::endl; + + // Data + *output << " <Data>" << std::endl; + MAuint32 i = 0; + for (auto &it : stack_) + { + *output << " "; + output->width(15); + *output << std::left << std::fixed << it.first; + + for (auto &weight : it.second) + { + output->width(15); + *output << std::left << std::scientific << weight.second.positive; + output->width(15); + *output << std::left << std::scientific << weight.second.negative; + } + if (i < 2 || i >= (stack_.size() - 2)) + *output << " # bin " << i + 1 << " / " << stack_.size(); + *output << std::endl; + i++; + } + *output << " </Data>" << std::endl; + + // Footer + *output << "</HistoFrequency>" << std::endl; + *output << std::endl; + } + }; } - #endif diff --git a/tools/SampleAnalyzer/Process/Plot/HistoLogX.cpp b/tools/SampleAnalyzer/Process/Plot/HistoLogX.cpp index 58381f8b..6b677fca 100644 --- a/tools/SampleAnalyzer/Process/Plot/HistoLogX.cpp +++ b/tools/SampleAnalyzer/Process/Plot/HistoLogX.cpp @@ -1,89 +1,96 @@ //////////////////////////////////////////////////////////////////////////////// -// +// // Copyright (C) 2012-2023 Jack Araz, Eric Conte & Benjamin Fuks // The MadAnalysis development team, email: <ma5team@iphc.cnrs.fr> -// +// // This file is part of MadAnalysis 5. // Official website: <https://github.com/MadAnalysis/madanalysis5> -// +// // MadAnalysis 5 is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // MadAnalysis 5 is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with MadAnalysis 5. If not, see <http://www.gnu.org/licenses/> -// +// //////////////////////////////////////////////////////////////////////////////// - // SampleAnalyzer headers #include "SampleAnalyzer/Process/Plot/HistoLogX.h" using namespace MA5; /// Write the plot in a Text file -void HistoLogX::Write_TextFormat(std::ostream* output) +void HistoLogX::Write_TextFormat(std::ostream *output) { - // Header - *output << "<HistoLogX>" << std::endl; + // Header + *output << "<HistoLogX>" << std::endl; - // Write the body - Write_TextFormatBody(output); + // Write the body + Write_TextFormatBody(output); - // Foot - *output << "</HistoLogX>" << std::endl; - *output << std::endl; + // Foot + *output << "</HistoLogX>" << std::endl; + *output << std::endl; } - -/// Write the plot in a ROOT file -/* -void HistoLogX::Write_RootFormat(std::pair<TH1F*,TH1F*>& histo) +void HistoLogX::Fill(MAfloat64 value, const WeightCollection &weights) { - // Creating binning for histograms - MAfloat64 binnings[histo_.size()+1]; - for (MAuint32 i=0;i<histo_.size();i++) - { - binnings[i]=std::pow(static_cast<MAfloat32>(10.),static_cast<MAfloat32>(log_xmin_+i*step_)); - } - binnings[histo_.size()]=xmax_; - - // Creating ROOT histograms - histo.first -> SetBins(nbins_,binnings); - histo.second -> SetBins(nbins_,binnings); + Initialise(weights); + // Safety : nan or isinf + try + { + if (std::isnan(value)) + throw EXCEPTION_WARNING("Skipping a NaN (Not a Number) value in an histogram.", "", 0); + if (std::isinf(value)) + throw EXCEPTION_WARNING("Skipping a Infinity value in an histogram.", "", 0); + } + catch (const std::exception &e) + { + MANAGE_EXCEPTION(e); + } - // Filling histos - for (MAuint32 i=0;i<histo_.size();i++) - { - histo.first -> SetBinContent(i+1,histo_[i].first); - histo.second -> SetBinContent(i+1,histo_[i].second); - } - histo.first -> SetBinContent(0,underflow_.first); - histo.second -> SetBinContent(0,underflow_.second); - histo.first -> SetBinContent(histo_.size()+1,overflow_.first); - histo.second -> SetBinContent(histo_.size()+1,overflow_.second); + for (auto &w : weights.GetWeights()) + { + MAdouble64 weight = w.second; + MAint32 idx = w.first; + // Positive weight + if (weight >= 0) + { + nentries_[idx].positive++; + sum_w_[idx].positive += weight; + sum_ww_[idx].positive += weight * weight; + sum_xw_[idx].positive += value * weight; + sum_xxw_[idx].positive += value * value * weight; + if (value < xmin_) + underflow_[idx].positive += weight; + else if (value >= xmax_) + overflow_[idx].positive += weight; + else + histo_[std::floor((std::log10(value) - log_xmin_) / step_)][idx].positive += weight; + } - // Filling statistics for histo with positive weight - histo.first -> SetEntries(nentries_.first); - MAfloat64 stats[4]; - stats[0]=sum_w_.first; - stats[1]=sum_ww_.first; - stats[2]=sum_xw_.first; - stats[3]=sum_xxw_.first; - histo.first -> PutStats(stats); - - histo.second -> SetEntries(nentries_.second); - stats[0]=sum_w_.second; - stats[1]=sum_ww_.second; - stats[2]=sum_xw_.second; - stats[3]=sum_xxw_.second; - histo.second -> PutStats(stats); + // Negative weight + else + { + nentries_[idx].negative++; + weight = std::fabs(weight); + sum_w_[idx].negative += weight; + sum_ww_[idx].negative += weight * weight; + sum_xw_[idx].negative += value * weight; + sum_xxw_[idx].negative += value * value * weight; + if (value < xmin_) + underflow_[idx].negative += weight; + else if (value >= xmax_) + overflow_[idx].negative += weight; + else + histo_[std::floor((std::log10(value) - log_xmin_) / step_)][idx].negative += weight; + } + } } - -*/ diff --git a/tools/SampleAnalyzer/Process/Plot/HistoLogX.h b/tools/SampleAnalyzer/Process/Plot/HistoLogX.h index f89f3584..a7135669 100644 --- a/tools/SampleAnalyzer/Process/Plot/HistoLogX.h +++ b/tools/SampleAnalyzer/Process/Plot/HistoLogX.h @@ -1,31 +1,29 @@ //////////////////////////////////////////////////////////////////////////////// -// +// // Copyright (C) 2012-2023 Jack Araz, Eric Conte & Benjamin Fuks // The MadAnalysis development team, email: <ma5team@iphc.cnrs.fr> -// +// // This file is part of MadAnalysis 5. // Official website: <https://github.com/MadAnalysis/madanalysis5> -// +// // MadAnalysis 5 is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // MadAnalysis 5 is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with MadAnalysis 5. If not, see <http://www.gnu.org/licenses/> -// +// //////////////////////////////////////////////////////////////////////////////// - #ifndef HISTO_LOGX_H #define HISTO_LOGX_H - // STL headers #include <cmath> @@ -33,146 +31,89 @@ #include "SampleAnalyzer/Process/Plot/Histo.h" #include "SampleAnalyzer/Commons/Service/ExceptionService.h" - namespace MA5 { -class HistoLogX : public Histo -{ - - // ------------------------------------------------------------- - // data members - // ------------------------------------------------------------- - protected : - - // Histogram boundaries in Log scale - MAfloat64 log_xmin_; - MAfloat64 log_xmax_; - - // ------------------------------------------------------------- - // method members - // ------------------------------------------------------------- - public : - - /// Constructor withtout argument - HistoLogX() - { } - - /// Constructor with argument - HistoLogX(const std::string& name, MAuint32 nbins, - MAfloat64 xmin, MAfloat64 xmax) : Histo(name) - { - // Setting the description: nbins - try - { - if (nbins==0) throw EXCEPTION_WARNING("nbins cannot be equal to 0. Set 100.","",0); - nbins_ = nbins; - } - catch (const std::exception& e) - { - MANAGE_EXCEPTION(e); - nbins_ = 100; - } - - // Setting the description: min - try + class HistoLogX : public Histo { - if (xmin<=0) throw EXCEPTION_WARNING("xmin cannot be less than or equal to zero. Setting xmin to 0.1","",0); - xmin_ = xmin; - } - catch (const std::exception& e) - { - MANAGE_EXCEPTION(e); - xmin_=.1; - } - - // Setting the description: max - try - { - if (xmin>=xmax) throw EXCEPTION_WARNING("xmin cannot be equal to or greater than xmax. Setting xmin to 0.1 and xmax to 100.","",0); - xmax_ = xmax; - } - catch (const std::exception& e) - { - MANAGE_EXCEPTION(e); - xmin_=.1; - xmax_=100.; - } - - - log_xmin_=std::log10(xmin_); - log_xmax_=std::log10(xmax_); - step_ = (log_xmax_ - log_xmin_)/static_cast<MAfloat64>(nbins_); - - // Reseting the histogram array - histo_.resize(nbins_,std::make_pair(0.,0.)); - underflow_ = std::make_pair(0.,0.); - overflow_ = std::make_pair(0.,0.); - - // Reseting statistical counters - sum_w_ = std::make_pair(0.,0.); - sum_ww_ = std::make_pair(0.,0.); - sum_xw_ = std::make_pair(0.,0.); - } - - /// Destructor - virtual ~HistoLogX() - { } - - /// Filling histogram - void Fill(MAfloat64 value, MAfloat64 weight=1.0) - { - // Safety : nan or isinf - try - { - if (std::isnan(value)) throw EXCEPTION_WARNING("Skipping a NaN (Not a Number) value in an histogram.","",0); - if (std::isinf(value)) throw EXCEPTION_WARNING("Skipping a Infinity value in an histogram.","",0); - } - catch (const std::exception& e) - { - MANAGE_EXCEPTION(e); - } - // Positive weight - if (weight>=0) - { - nentries_.first++; - sum_w_.first +=weight; - sum_ww_.first +=weight*weight; - sum_xw_.first +=value*weight; - if (value < xmin_) underflow_.first+=weight; - else if (value >= xmax_) overflow_.first+=weight; - else - { - histo_[std::floor((std::log10(value)-log_xmin_)/step_)].first+=weight; - } - } - - // Negative weight - else - { - nentries_.second++; - weight=std::abs(weight); - sum_w_.second += weight; - sum_ww_.second += weight*weight; - sum_xw_.second += value*weight; - if (value < xmin_) underflow_.second+=weight; - else if (value >= xmax_) overflow_.second+=weight; - else - { - histo_[std::floor((std::log10(value)-log_xmin_)/step_)].second+=weight; - } - } - } - - - /// Write the plot in a Text file - virtual void Write_TextFormat(std::ostream* output); - - // Write the plot in a ROOT file - // virtual void Write_RootFormat(std::pair<TH1F*,TH1F*>& histos); - -}; + // ------------------------------------------------------------- + // data members + // ------------------------------------------------------------- + protected: + // Histogram boundaries in Log scale + MAfloat64 log_xmin_; + MAfloat64 log_xmax_; + + // ------------------------------------------------------------- + // method members + // ------------------------------------------------------------- + public: + /// Constructor withtout argument + HistoLogX() { initialised_ = false; } + + /// Constructor with argument + HistoLogX(const std::string &name, MAuint32 nbins, + MAfloat64 xmin, MAfloat64 xmax) : Histo(name) + { + // Setting the description: nbins + try + { + if (nbins == 0) + throw EXCEPTION_WARNING("nbins cannot be equal to 0. Set 100.", "", 0); + nbins_ = nbins; + } + catch (const std::exception &e) + { + MANAGE_EXCEPTION(e); + nbins_ = 100; + } + + // Setting the description: min + try + { + if (xmin <= 0) + throw EXCEPTION_WARNING("xmin cannot be less than or equal to zero. Setting xmin to 0.1", "", 0); + xmin_ = xmin; + } + catch (const std::exception &e) + { + MANAGE_EXCEPTION(e); + xmin_ = .1; + } + + // Setting the description: max + try + { + if (xmin >= xmax) + throw EXCEPTION_WARNING("xmin cannot be equal to or greater than xmax. Setting xmin to 0.1 and xmax to 100.", "", 0); + xmax_ = xmax; + } + catch (const std::exception &e) + { + MANAGE_EXCEPTION(e); + xmin_ = .1; + xmax_ = 100.; + } + + log_xmin_ = std::log10(xmin_); + log_xmax_ = std::log10(xmax_); + step_ = (log_xmax_ - log_xmin_) / static_cast<MAfloat64>(nbins_); + + // Reseting the histogram array + histo_.resize(nbins_); + initialised_ = false; + } + + /// Destructor + virtual ~HistoLogX() {} + + /// Filling histogram + void Fill(MAfloat64 value, const WeightCollection &weights); + + /// Write the plot in a Text file + virtual void Write_TextFormat(std::ostream *output); + }; } diff --git a/tools/SampleAnalyzer/Process/Plot/PlotBase.h b/tools/SampleAnalyzer/Process/Plot/PlotBase.h index 18204ec9..72d07b4e 100644 --- a/tools/SampleAnalyzer/Process/Plot/PlotBase.h +++ b/tools/SampleAnalyzer/Process/Plot/PlotBase.h @@ -1,31 +1,29 @@ //////////////////////////////////////////////////////////////////////////////// -// +// // Copyright (C) 2012-2023 Jack Araz, Eric Conte & Benjamin Fuks // The MadAnalysis development team, email: <ma5team@iphc.cnrs.fr> -// +// // This file is part of MadAnalysis 5. // Official website: <https://github.com/MadAnalysis/madanalysis5> -// +// // MadAnalysis 5 is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // MadAnalysis 5 is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with MadAnalysis 5. If not, see <http://www.gnu.org/licenses/> -// +// //////////////////////////////////////////////////////////////////////////////// - #ifndef PLOT_BASE_H #define PLOT_BASE_H - // STL headers #include <iostream> #include <map> @@ -34,99 +32,117 @@ // SampleAnalyzer headers #include "SampleAnalyzer/Commons/Service/LogService.h" - +#include "SampleAnalyzer/Commons/Base/Basics.h" +#include "SampleAnalyzer/Commons/DataFormat/WeightCollection.h" namespace MA5 { -class PlotBase -{ - - // ------------------------------------------------------------- - // data members - // ------------------------------------------------------------- - protected : - - /// Name of the plots - std::string name_; - - /// Number of events - std::pair<MAint64,MAint64> nevents_; - - /// Number of entries - std::pair<MAint64,MAint64> nentries_; - - /// Sum of event-weight over events - std::pair<MAfloat64,MAfloat64> nevents_w_; - - /// Flag telling whether a given histo has already been modified for an event - MAbool fresh_event_; - - - // ------------------------------------------------------------- - // method members - // ------------------------------------------------------------- - public : - - /// Constructor without argument - PlotBase() - { - // Reseting statistical counters - nevents_ = std::make_pair(0,0); - nentries_ = std::make_pair(0,0); - nevents_w_ = std::make_pair(0,0); - fresh_event_ = true; - } - - /// Constructor with argument - PlotBase(const std::string& name) - { - name_ = name; - nevents_ = std::make_pair(0,0); - nevents_w_ = std::make_pair(0,0); - nentries_ = std::make_pair(0,0); - fresh_event_ = true; - } - - /// Destructor - virtual ~PlotBase() - { } - - /// Accesor for fresh_event - MAbool FreshEvent() { return fresh_event_;} - - /// Modifier for fresh_event - void SetFreshEvent(MAbool tag) { fresh_event_ = tag;} - - /// Write the plot in a ROOT file - virtual void Write_TextFormat(std::ostream* output) = 0; - - /// Increment number of events - void IncrementNEvents(MAfloat64 weight=1.0) - { - if (weight>=0) - { - nevents_.first++; - nevents_w_.first+=weight; - } - else + class PlotBase { - weight = std::abs(weight); - nevents_.second++; - nevents_w_.second+=weight; - } - SetFreshEvent(false); - } - - /// Return Number of events - const std::pair<MAint64,MAint64>& GetNEvents() - { return nevents_; } - - // Return the name - std::string GetName() - { return name_; } - -}; + + // ------------------------------------------------------------- + // data members + // ------------------------------------------------------------- + protected: + /// Name of the plots + std::string name_; + + /// @brief number of events. entries object includes positive and negative accessors + std::map<MAint32, ENTRIES> nevents_; + + /// @brief Number of entries + std::map<MAint32, ENTRIES> nentries_; + + /// @brief Sum of event-weight over events + std::map<MAint32, WEIGHTS> nevents_w_; + + /// Flag telling whether a given histo has already been modified for an event + MAbool fresh_event_; + + /// @brief is the plot initialised + MAbool initialised_; + + // ------------------------------------------------------------- + // method members + // ------------------------------------------------------------- + public: + /// Constructor without argument + PlotBase() + { + // Reseting statistical counters + nevents_.insert(std::make_pair(0, ENTRIES())); + nentries_.insert(std::make_pair(0, ENTRIES())); + nevents_w_.insert(std::make_pair(0, WEIGHTS())); + fresh_event_ = true; + } + + /// Constructor with argument + PlotBase(const std::string &name) + { + name_ = name; + nevents_.insert(std::make_pair(0, ENTRIES())); + nentries_.insert(std::make_pair(0, ENTRIES())); + nevents_w_.insert(std::make_pair(0, WEIGHTS())); + fresh_event_ = true; + } + + /// Destructor + virtual ~PlotBase() {} + + /// Accesor for fresh_event + MAbool FreshEvent() { return fresh_event_; } + + /// Modifier for fresh_event + void SetFreshEvent(MAbool tag) { fresh_event_ = tag; } + + /// Write the plot in a ROOT file + virtual void Write_TextFormat(std::ostream *output) = 0; + + /// @brief Initialise the containers + /// @param multiweight multiweight collection + void Initialise(const WeightCollection &multiweight) + { + if (!initialised_) + { + for (auto &weight : multiweight.GetWeights()) + { + + nevents_[weight.first] = ENTRIES(); + nentries_[weight.first] = ENTRIES(); + nevents_w_[weight.first] = WEIGHTS(); + } + } + } + + /// Increment number of events + void IncrementNEvents(const WeightCollection &weights) + { + Initialise(weights); + for (auto &weight : weights.GetWeights()) + { + MAint32 idx = weight.first; + MAdouble64 w = weight.second; + if (w >= 0) + { + nevents_[idx].positive++; + nevents_w_[idx].positive += w; + } + else + { + nevents_[idx].negative++; + nevents_w_[idx].negative += std::fabs(w); + } + } + SetFreshEvent(false); + } + + /// Return Number of events + const std::map<MAint32, ENTRIES> &GetNEvents() { return nevents_; } + + // Return the name + std::string GetName() { return name_; } + }; } From f9d2e25182edb797ec7e82ff63397b51107e9643 Mon Sep 17 00:00:00 2001 From: "Jack Y. Araz" <jackaraz@gmail.com> Date: Tue, 27 Jun 2023 15:16:29 +0100 Subject: [PATCH 010/107] update LHE writer --- .../Process/Writer/LHEWriter.cpp | 1279 +++++++++-------- 1 file changed, 659 insertions(+), 620 deletions(-) diff --git a/tools/SampleAnalyzer/Process/Writer/LHEWriter.cpp b/tools/SampleAnalyzer/Process/Writer/LHEWriter.cpp index db884c92..ac7f23dd 100644 --- a/tools/SampleAnalyzer/Process/Writer/LHEWriter.cpp +++ b/tools/SampleAnalyzer/Process/Writer/LHEWriter.cpp @@ -1,27 +1,26 @@ //////////////////////////////////////////////////////////////////////////////// -// +// // Copyright (C) 2012-2023 Jack Araz, Eric Conte & Benjamin Fuks // The MadAnalysis development team, email: <ma5team@iphc.cnrs.fr> -// +// // This file is part of MadAnalysis 5. // Official website: <https://github.com/MadAnalysis/madanalysis5> -// +// // MadAnalysis 5 is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // MadAnalysis 5 is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with MadAnalysis 5. If not, see <http://www.gnu.org/licenses/> -// +// //////////////////////////////////////////////////////////////////////////////// - // STL headers #include <sstream> @@ -29,713 +28,753 @@ #include "SampleAnalyzer/Process/Writer/LHEWriter.h" #include "SampleAnalyzer/Commons/Service/ExceptionService.h" - using namespace MA5; - -MAbool MCParticleToSave(const MCParticleFormat& part, const SampleFormat& sample) +MAbool MCParticleToSave(const MCParticleFormat &part, const SampleFormat &sample) { - // Special Herwig6 - if (sample.sampleGenerator()==MA5GEN::HERWIG6) - { - return part.statuscode()>=110 && - part.statuscode()<=125; - } - - // Else Herwig6 - else - { - return part.statuscode()==3 || - ( part.statuscode()>=21 && - part.statuscode()<=29); - } -} - + // Special Herwig6 + if (sample.sampleGenerator() == MA5GEN::HERWIG6) + { + return part.statuscode() >= 110 && + part.statuscode() <= 125; + } -MAbool InitialMCParticleToSave(const MCParticleFormat& part, const SampleFormat& sample) -{ - // Special Herwig6 - if (sample.sampleGenerator()==MA5GEN::HERWIG6) - { - return part.statuscode()>=101 && - part.statuscode()<=102; - } - - // Else Herwig6 - else - { - return (part.statuscode()==3 && part.pt()==0) || - (part.statuscode()>=11 && part.statuscode()<=19) || - (part.statuscode()==21 && part.pt()==0); - } + // Else Herwig6 + else + { + return part.statuscode() == 3 || + (part.statuscode() >= 21 && + part.statuscode() <= 29); + } } +MAbool InitialMCParticleToSave(const MCParticleFormat &part, const SampleFormat &sample) +{ + // Special Herwig6 + if (sample.sampleGenerator() == MA5GEN::HERWIG6) + { + return part.statuscode() >= 101 && + part.statuscode() <= 102; + } + // Else Herwig6 + else + { + return (part.statuscode() == 3 && part.pt() == 0) || + (part.statuscode() >= 11 && part.statuscode() <= 19) || + (part.statuscode() == 21 && part.pt() == 0); + } +} -MAuint32 Find(const MCParticleFormat* part, - const std::vector<const MCParticleFormat*>& collection) +MAuint32 Find(const MCParticleFormat *part, + const std::vector<const MCParticleFormat *> &collection) { - if (part==0) return 0; - for (MAuint32 i=0;i<collection.size();i++) - if (collection[i]==part) return i+1; - return 0; + if (part == 0) + return 0; + for (MAuint32 i = 0; i < collection.size(); i++) + if (collection[i] == part) + return i + 1; + return 0; } -MAuint32 FindDeeply(const MCParticleFormat* part, - const std::vector<const MCParticleFormat*>& collection) +MAuint32 FindDeeply(const MCParticleFormat *part, + const std::vector<const MCParticleFormat *> &collection) { - if (part==0) return 0; - MAbool test=false; - const MCParticleFormat* thepart = part; - MAuint32 counter=0; - - while(!test) - { - counter++; - if (counter>=100000) + if (part == 0) + return 0; + MAbool test = false; + const MCParticleFormat *thepart = part; + MAuint32 counter = 0; + + while (!test) { - try - { - throw EXCEPTION_ERROR("Number of calls exceed: infinite loop is detected","",0); - } - catch(const std::exception& e) - { - MANAGE_EXCEPTION(e); - break; - } + counter++; + if (counter >= 100000) + { + try + { + throw EXCEPTION_ERROR("Number of calls exceed: infinite loop is detected", "", 0); + } + catch (const std::exception &e) + { + MANAGE_EXCEPTION(e); + break; + } + } + if (thepart->mothers().size() == 0) + { + test = true; + thepart = 0; + } + else if (thepart->mothers()[0]->statuscode() == 3 || + (thepart->mothers()[0]->statuscode() >= 11 && + thepart->mothers()[0]->statuscode() <= 29)) + { + test = true; + thepart = thepart->mothers()[0]; + } + else + { + thepart = thepart->mothers()[0]; + } } - if (thepart->mothers().size()==0) + if (thepart == 0) + return 0; + for (MAuint32 i = 0; i < collection.size(); i++) + if (collection[i] == thepart) + return i + 1; + return 0; +} + +std::string LHEWriter::FortranFormat_SimplePrecision(MAfloat32 value, MAuint32 precision) +{ + std::stringstream str; + str.precision(precision); + std::string word; + + MAbool negative = false; + if (value < 0.) { - test=true; - thepart=0; + negative = true; + value *= -1.; } - else if (thepart->mothers()[0]->statuscode()==3 || - ( thepart->mothers()[0]->statuscode()>=11 && - thepart->mothers()[0]->statuscode()<=29) ) + + MAint32 exponent = 0; + if (value != 0.) { - test=true; - thepart=thepart->mothers()[0]; + for (; value >= 10.; exponent++) + value /= 10.; + for (; value < 1.; exponent--) + value *= 10.; } + + str << std::uppercase << std::fixed << value << "E"; + if (exponent >= 0) + str << "+"; else - { - thepart=thepart->mothers()[0]; - } - } - if (thepart==0) return 0; - for (MAuint32 i=0;i<collection.size();i++) - if (collection[i]==thepart) return i+1; - return 0; + str << "-"; + if (abs(exponent) < 10) + str << "0"; + str << abs(exponent); + str >> word; + if (!negative) + return word; + else + return "-" + word; } - -std::string LHEWriter::FortranFormat_SimplePrecision(MAfloat32 value,MAuint32 precision) +std::string LHEWriter::FortranFormat_DoublePrecision(MAfloat64 value, MAuint32 precision) { - std::stringstream str; - str.precision(precision); - std::string word; - - MAbool negative=false; - if (value<0.) {negative=true; value*=-1.;} - - MAint32 exponent = 0; - if (value!=0.) - { - for (; value >= 10.; exponent++) value/=10.; - for (; value < 1. ; exponent--) value*=10.; - } - - str << std::uppercase << std::fixed << value << "E"; - if (exponent>=0) str << "+"; else str << "-"; - if (abs(exponent)<10) str << "0"; - str << abs(exponent); - str >> word; - if (!negative) return word; - else return "-"+word; -} + std::stringstream str; + str.precision(precision); + std::string word; + MAbool negative = false; + if (value < 0.) + { + negative = true; + value *= -1.; + } -std::string LHEWriter::FortranFormat_DoublePrecision(MAfloat64 value,MAuint32 precision) -{ - std::stringstream str; - str.precision(precision); - std::string word; - - MAbool negative=false; - if (value<0.) {negative=true; value*=-1.;} - - MAint32 exponent = 0.; - if (value!=0.) - { - for (; value >= 10.; exponent++) value/=10.; - for (; value < 1. ; exponent--) value*=10.; - } - - str << std::uppercase << std::fixed << value << "E"; - if (exponent>=0) str << "+"; else str << "-"; - if (abs(exponent)<10) str << "0"; - str << abs(exponent); - str >> word; - if (!negative) return word; - else return "-"+word; -} + MAint32 exponent = 0.; + if (value != 0.) + { + for (; value >= 10.; exponent++) + value /= 10.; + for (; value < 1.; exponent--) + value *= 10.; + } + str << std::uppercase << std::fixed << value << "E"; + if (exponent >= 0) + str << "+"; + else + str << "-"; + if (abs(exponent) < 10) + str << "0"; + str << abs(exponent); + str >> word; + if (!negative) + return word; + else + return "-" + word; +} /// Read the sample -MAbool LHEWriter::WriteHeader(const SampleFormat& mySample) +MAbool LHEWriter::WriteHeader(const SampleFormat &mySample) { - // Opening tag - *output_ << "<LesHouchesEvents version=\"1.0\">" << std::endl; - - // Header tag - *output_ << "<header>" << std::endl; - *output_ << "<!--" << std::endl; - - // MA5 logo - WriteMA5header(); - - // LHE format - if (mySample.rec()!=0) - { - *output_ << "<MA5Format> Simplified LHE format </MA5Format>" << std::endl; - } - else - { - *output_ << "<MA5Format> LHE format </MA5Format>" << std::endl; - } - - // Python interface version - *output_ << "<MadAnalysis5Version> " << cfg_->GetPythonInterfaceVersion() - << " " << cfg_->GetPythonInterfaceDate() - << "</MadAnalysis5Version>" << std::endl; - - // SampleAnalyzer version - *output_ << "<SampleAnalyzerVersion> "<< cfg_->GetSampleAnalyzerVersion() - << " " << cfg_->GetSampleAnalyzerVersion() - << " </SampleAnalyzerVersion>" << std::endl; - - // Explanation about the LHE - *output_ << "<FormatDescription>" << std::endl; - *output_ << "#################################################################################" << std::endl; - *output_ << "# The original Les Houches Event (LHE) format is defined in hep-ph/0609017 #" << std::endl; - *output_ << "#################################################################################" << std::endl; - *output_ << "# The <init> ... </init> block contains global information about the samples #" << std::endl; - *output_ << "# given as a single line: #" << std::endl; - *output_ << "# IDBM1 IDBM2 EBM1 EBM2 PDFG1 PDFG2 PDFS1 PDFS1 PDFS2 IDWT NPR #" << std::endl; - *output_ << "# with: #" << std::endl; - *output_ << "# - IDBM1: PDG code of the first beam. #" << std::endl; - *output_ << "# - IDBM2: PDG code of the second beam. #" << std::endl; - *output_ << "# - EBM1: energy of the first beam. #" << std::endl; - *output_ << "# - EBM2: energy of the second beam. #" << std::endl; - *output_ << "# - PDFG1: author group of the PDF employed for the first beam. #" << std::endl; - *output_ << "# - PDFG2: author group of the PDF employed for the second beam. #" << std::endl; - *output_ << "# - PDFS1: id of the PDF set employed for the first beam. #" << std::endl; - *output_ << "# - PDFS2: id of the PDF set employed for the second beam. #" << std::endl; - *output_ << "# - IDWT: weighting strategy. #" << std::endl; - *output_ << "# - NPR: number of physics processes involved during the generation of #" << std::endl; - *output_ << "# the sample. #" << std::endl; - *output_ << "# The following lines give detailed process information (one line for each #" << std::endl; - *output_ << "# process): #" << std::endl; - *output_ << "# XSEC XERR XMAX LPR #" << std::endl; - *output_ << "# with: #" << std::endl; - *output_ << "# - XSEC: cross section #" << std::endl; - *output_ << "# - XERR: cross section error #" << std::endl; - *output_ << "# - XMAX: maximum event weight #" << std::endl; - *output_ << "# - LPR: process id #" << std::endl; - *output_ << "#################################################################################" << std::endl; - *output_ << "# Each event is described by an <event> ... </event> block. This block always #" << std::endl; - *output_ << "# starts by a single line containing general information on the event: #" << std::endl; - *output_ << "# N IDPR XWGT SCAL AQED AQCD #" << std::endl; - *output_ << "# with: #" << std::endl; - *output_ << "# - N: number of particles #" << std::endl; - *output_ << "# - IDPR: process id #" << std::endl; - *output_ << "# - XWGT: event weight #" << std::endl; - *output_ << "# - SCAL: scale #" << std::endl; - *output_ << "# - AQED: alpha QED #" << std::endl; - *output_ << "# - AQCD: alpha QCD #" << std::endl; - *output_ << "# This line is then followed by one line for each particle in the event: #" << std::endl; - *output_ << "# ID IST MOTH1 MOTH2 ICOL1 ICOL2 P1 P2 P3 P4 P5 VTIM SPIN #" << std::endl; - *output_ << "# with: #" << std::endl; - *output_ << "# - ID: PDG code #" << std::endl; - *output_ << "# - IST: status code #" << std::endl; - *output_ << "# - MOTH1: row number corresponding to the first mother particle #" << std::endl; - *output_ << "# - MOTH2: row number corresponding to the second mother particle #" << std::endl; - *output_ << "# - ICOL1: first color tag #" << std::endl; - *output_ << "# - ICOL2: second color tag #" << std::endl; - *output_ << "# - P1: PX #" << std::endl; - *output_ << "# - P2: PY #" << std::endl; - *output_ << "# - P3: PZ #" << std::endl; - *output_ << "# - P4: E #" << std::endl; - *output_ << "# - P5: M (a space-like virtuality is denoted by a negative mass) #" << std::endl; - *output_ << "# - VTIM: c tau #" << std::endl; - *output_ << "# - SPIN: cosine of the angle between the spin vector of the particle and #" << std::endl; - *output_ << "# its three-momentum #" << std::endl; - *output_ << "#################################################################################" << std::endl; - - // Explanation about the Simplified LHE - if (mySample.rec()!=0) - { - *output_ << "# In the 'simplified LHE' format, there are three types of objects classified #" << std::endl; - *output_ << "# according to their statuscode: #" << std::endl; - *output_ << "# - objects with StatusCode = -1: initial interacting partons. #" << std::endl; - *output_ << "# - objects with StatusCode = +3: particles produced during the hard process. #" << std::endl; - *output_ << "# - objects with StatusCode = +1: physics objects reconstructed by a fast #" << std::endl; - *output_ << "# detector simulation (or perfect detector). #" << std::endl; - *output_ << "# When MadAnalysis is in charge of the reconstruction (i.e., applying the #" << std::endl; - *output_ << "# jet-clustering algorithm), the particle codes follow the conventions: #" << std::endl; - *output_ << "# - particle with a PDG code = +11 or -11: electrons and positrons. #" << std::endl; - *output_ << "# They can be isolated or not as well as possibly issued from the #" << std::endl; - *output_ << "# hadronization process. #" << std::endl; - *output_ << "# - particle with a PDG code = +13 or -13: muons and antimuons. #" << std::endl; - *output_ << "# They can be isolated or not as well as possibly issued from the #" << std::endl; - *output_ << "# hadronization process. #" << std::endl; - *output_ << "# - particle with a PDG code = +15 or -15: hadronically decaying (anti)taus. #" << std::endl; - *output_ << "# These consist of jets matching a hadronically-decaying tau when #" << std::endl; - *output_ << "# inspecting the Monte Carlo history. (Mis)Identification efficiency can be #" << std::endl; - *output_ << "# possibly included. #" << std::endl; - *output_ << "# - particle with a PDG code = 5: b-jets. #" << std::endl; - *output_ << "# These consist of jets matching a b-quark when inspecting the Monte Carlo #" << std::endl; - *output_ << "# history. (Mis)Identification efficiency can be possibly included. #" << std::endl; - *output_ << "# - particle with a PDG code = 21: jets which are not b-tagged and taus which #" << std::endl; - *output_ << "# are not tau-tagged. The jet collection includes also electrons collection #" << std::endl; - *output_ << "# and hadronic taus collection #" << std::endl; - *output_ << "# - particle with a PDG code = 12: the missing transverse energy. #" << std::endl; - *output_ << "# The missing transverse energy is computed as opposite to the sum of the #" << std::endl; - *output_ << "# four-momenta of all jets, electrons, muons and hadronic taus. #" << std::endl; - *output_ << "#################################################################################" << std::endl; - } - *output_ << "</FormatDescription>" << std::endl; - if (mySample.mc()!=0) - { - *output_ << "Original header:" << std::endl; - *output_ << "" << std::endl; - - for (MAuint32 i=0;i<mySample.header().size();i++) - *output_ << mySample.header()[i] << std::endl; - } - *output_ << "-->" << std::endl; - *output_ << "</header>" << std::endl; - - // Init block - *output_ << "<init>" << std::endl; - - // To fill - if (mySample.mc()==0) - { - *output_ << std::setw(9) << std::right << 0 << " "; // PDGID1 - *output_ << std::setw(8) << std::right << 0 << " "; // PDGID2 - *output_ << std::setw(18) << std::right << LHEWriter::FortranFormat_DoublePrecision(0) << " "; // E1 - *output_ << std::setw(18) << std::right << LHEWriter::FortranFormat_DoublePrecision(0) << " "; // E2 - *output_ << std::setw(1) << std::right << 0 << " "; // PDF1 - *output_ << std::setw(1) << std::right << 0 << " "; // PDF2 - *output_ << std::setw(5) << std::right << 0 << " "; // PDFID1 - *output_ << std::setw(5) << std::right << 0 << " "; // PDFID2 - *output_ << std::setw(1) << std::right << 1 << " "; // WEIGHT - *output_ << std::setw(2) << std::right << 1; // NPROCESSES - *output_ << std::endl; - - // one process - *output_ << std::setw(19) << std::right << LHEWriter::FortranFormat_DoublePrecision(1.0) << " "; - *output_ << std::setw(18) << std::right << LHEWriter::FortranFormat_DoublePrecision(0.0) << " "; - *output_ << std::setw(18) << std::right << LHEWriter::FortranFormat_DoublePrecision(1.0) << " "; - *output_ << std::setw(3) << std::right << 1; - *output_ << std::endl; - } - else - { - *output_ << std::setw(9) << std::right << mySample.mc()->beamPDGID_.first << " "; - *output_ << std::setw(8) << std::right << mySample.mc()->beamPDGID_.second << " "; - *output_ << std::setw(18) << std::right << LHEWriter::FortranFormat_DoublePrecision(mySample.mc()->beamE_.first) << " "; - *output_ << std::setw(18) << std::right << LHEWriter::FortranFormat_DoublePrecision(mySample.mc()->beamE_.second) << " "; - *output_ << std::setw(1) << std::right << mySample.mc()->beamPDFauthor_.first << " "; - *output_ << std::setw(1) << std::right << mySample.mc()->beamPDFauthor_.second << " "; - *output_ << std::setw(5) << std::right << mySample.mc()->beamPDFID_.first << " "; - *output_ << std::setw(5) << std::right << mySample.mc()->beamPDFID_.second << " "; - *output_ << std::setw(1) << std::right << mySample.mc()->weightMode_ << " "; - if (mySample.mc()->processes().size()==0) + // Opening tag + *output_ << "<LesHouchesEvents version=\"1.0\">" << std::endl; + + // Header tag + *output_ << "<header>" << std::endl; + *output_ << "<!--" << std::endl; + + // MA5 logo + WriteMA5header(); + + // LHE format + if (mySample.rec() != 0) { - *output_ << std::setw(2) << std::right << 1; + *output_ << "<MA5Format> Simplified LHE format </MA5Format>" << std::endl; } else { - *output_ << std::setw(2) << std::right << mySample.mc()->processes().size(); + *output_ << "<MA5Format> LHE format </MA5Format>" << std::endl; } - *output_ << std::endl; - for (MAuint32 i=0;i<mySample.mc()->processes().size();i++) + + // Python interface version + *output_ << "<MadAnalysis5Version> " << cfg_->GetPythonInterfaceVersion() + << " " << cfg_->GetPythonInterfaceDate() + << "</MadAnalysis5Version>" << std::endl; + + // SampleAnalyzer version + *output_ << "<SampleAnalyzerVersion> " << cfg_->GetSampleAnalyzerVersion() + << " " << cfg_->GetSampleAnalyzerVersion() + << " </SampleAnalyzerVersion>" << std::endl; + + // Explanation about the LHE + *output_ << "<FormatDescription>" << std::endl; + *output_ << "#################################################################################" << std::endl; + *output_ << "# The original Les Houches Event (LHE) format is defined in hep-ph/0609017 #" << std::endl; + *output_ << "#################################################################################" << std::endl; + *output_ << "# The <init> ... </init> block contains global information about the samples #" << std::endl; + *output_ << "# given as a single line: #" << std::endl; + *output_ << "# IDBM1 IDBM2 EBM1 EBM2 PDFG1 PDFG2 PDFS1 PDFS1 PDFS2 IDWT NPR #" << std::endl; + *output_ << "# with: #" << std::endl; + *output_ << "# - IDBM1: PDG code of the first beam. #" << std::endl; + *output_ << "# - IDBM2: PDG code of the second beam. #" << std::endl; + *output_ << "# - EBM1: energy of the first beam. #" << std::endl; + *output_ << "# - EBM2: energy of the second beam. #" << std::endl; + *output_ << "# - PDFG1: author group of the PDF employed for the first beam. #" << std::endl; + *output_ << "# - PDFG2: author group of the PDF employed for the second beam. #" << std::endl; + *output_ << "# - PDFS1: id of the PDF set employed for the first beam. #" << std::endl; + *output_ << "# - PDFS2: id of the PDF set employed for the second beam. #" << std::endl; + *output_ << "# - IDWT: weighting strategy. #" << std::endl; + *output_ << "# - NPR: number of physics processes involved during the generation of #" << std::endl; + *output_ << "# the sample. #" << std::endl; + *output_ << "# The following lines give detailed process information (one line for each #" << std::endl; + *output_ << "# process): #" << std::endl; + *output_ << "# XSEC XERR XMAX LPR #" << std::endl; + *output_ << "# with: #" << std::endl; + *output_ << "# - XSEC: cross section #" << std::endl; + *output_ << "# - XERR: cross section error #" << std::endl; + *output_ << "# - XMAX: maximum event weight #" << std::endl; + *output_ << "# - LPR: process id #" << std::endl; + *output_ << "#################################################################################" << std::endl; + *output_ << "# Each event is described by an <event> ... </event> block. This block always #" << std::endl; + *output_ << "# starts by a single line containing general information on the event: #" << std::endl; + *output_ << "# N IDPR XWGT SCAL AQED AQCD #" << std::endl; + *output_ << "# with: #" << std::endl; + *output_ << "# - N: number of particles #" << std::endl; + *output_ << "# - IDPR: process id #" << std::endl; + *output_ << "# - XWGT: event weight #" << std::endl; + *output_ << "# - SCAL: scale #" << std::endl; + *output_ << "# - AQED: alpha QED #" << std::endl; + *output_ << "# - AQCD: alpha QCD #" << std::endl; + *output_ << "# This line is then followed by one line for each particle in the event: #" << std::endl; + *output_ << "# ID IST MOTH1 MOTH2 ICOL1 ICOL2 P1 P2 P3 P4 P5 VTIM SPIN #" << std::endl; + *output_ << "# with: #" << std::endl; + *output_ << "# - ID: PDG code #" << std::endl; + *output_ << "# - IST: status code #" << std::endl; + *output_ << "# - MOTH1: row number corresponding to the first mother particle #" << std::endl; + *output_ << "# - MOTH2: row number corresponding to the second mother particle #" << std::endl; + *output_ << "# - ICOL1: first color tag #" << std::endl; + *output_ << "# - ICOL2: second color tag #" << std::endl; + *output_ << "# - P1: PX #" << std::endl; + *output_ << "# - P2: PY #" << std::endl; + *output_ << "# - P3: PZ #" << std::endl; + *output_ << "# - P4: E #" << std::endl; + *output_ << "# - P5: M (a space-like virtuality is denoted by a negative mass) #" << std::endl; + *output_ << "# - VTIM: c tau #" << std::endl; + *output_ << "# - SPIN: cosine of the angle between the spin vector of the particle and #" << std::endl; + *output_ << "# its three-momentum #" << std::endl; + *output_ << "#################################################################################" << std::endl; + + // Explanation about the Simplified LHE + if (mySample.rec() != 0) { - *output_ << std::setw(19) << std::right << LHEWriter::FortranFormat_DoublePrecision(mySample.mc()->processes_[i].xsectionMean_) << " "; - *output_ << std::setw(18) << std::right << LHEWriter::FortranFormat_DoublePrecision(mySample.mc()->processes_[i].xsectionError_) << " "; - *output_ << std::setw(18) << std::right << LHEWriter::FortranFormat_DoublePrecision(mySample.mc()->processes_[i].weightMax_) << " "; - *output_ << std::setw(3) << std::right << mySample.mc()->processes_[i].processId_; - *output_ << std::endl; + *output_ << "# In the 'simplified LHE' format, there are three types of objects classified #" << std::endl; + *output_ << "# according to their statuscode: #" << std::endl; + *output_ << "# - objects with StatusCode = -1: initial interacting partons. #" << std::endl; + *output_ << "# - objects with StatusCode = +3: particles produced during the hard process. #" << std::endl; + *output_ << "# - objects with StatusCode = +1: physics objects reconstructed by a fast #" << std::endl; + *output_ << "# detector simulation (or perfect detector). #" << std::endl; + *output_ << "# When MadAnalysis is in charge of the reconstruction (i.e., applying the #" << std::endl; + *output_ << "# jet-clustering algorithm), the particle codes follow the conventions: #" << std::endl; + *output_ << "# - particle with a PDG code = +11 or -11: electrons and positrons. #" << std::endl; + *output_ << "# They can be isolated or not as well as possibly issued from the #" << std::endl; + *output_ << "# hadronization process. #" << std::endl; + *output_ << "# - particle with a PDG code = +13 or -13: muons and antimuons. #" << std::endl; + *output_ << "# They can be isolated or not as well as possibly issued from the #" << std::endl; + *output_ << "# hadronization process. #" << std::endl; + *output_ << "# - particle with a PDG code = +15 or -15: hadronically decaying (anti)taus. #" << std::endl; + *output_ << "# These consist of jets matching a hadronically-decaying tau when #" << std::endl; + *output_ << "# inspecting the Monte Carlo history. (Mis)Identification efficiency can be #" << std::endl; + *output_ << "# possibly included. #" << std::endl; + *output_ << "# - particle with a PDG code = 5: b-jets. #" << std::endl; + *output_ << "# These consist of jets matching a b-quark when inspecting the Monte Carlo #" << std::endl; + *output_ << "# history. (Mis)Identification efficiency can be possibly included. #" << std::endl; + *output_ << "# - particle with a PDG code = 21: jets which are not b-tagged and taus which #" << std::endl; + *output_ << "# are not tau-tagged. The jet collection includes also electrons collection #" << std::endl; + *output_ << "# and hadronic taus collection #" << std::endl; + *output_ << "# - particle with a PDG code = 12: the missing transverse energy. #" << std::endl; + *output_ << "# The missing transverse energy is computed as opposite to the sum of the #" << std::endl; + *output_ << "# four-momenta of all jets, electrons, muons and hadronic taus. #" << std::endl; + *output_ << "#################################################################################" << std::endl; } - - if (mySample.mc()->processes().size()==0) + *output_ << "</FormatDescription>" << std::endl; + if (mySample.mc() != 0) { - *output_ << std::setw(19) << std::right << LHEWriter::FortranFormat_DoublePrecision(0) << " "; - *output_ << std::setw(18) << std::right << LHEWriter::FortranFormat_DoublePrecision(0) << " "; - *output_ << std::setw(18) << std::right << LHEWriter::FortranFormat_DoublePrecision(1.0) << " "; - *output_ << std::setw(3) << std::right << 1; - *output_ << std::endl; + *output_ << "Original header:" << std::endl; + *output_ << "" << std::endl; + + for (MAuint32 i = 0; i < mySample.header().size(); i++) + *output_ << mySample.header()[i] << std::endl; } + *output_ << "-->" << std::endl; + *output_ << "</header>" << std::endl; + // Init block + *output_ << "<init>" << std::endl; - } + // To fill + if (mySample.mc() == 0) + { + *output_ << std::setw(9) << std::right << 0 << " "; // PDGID1 + *output_ << std::setw(8) << std::right << 0 << " "; // PDGID2 + *output_ << std::setw(18) << std::right << LHEWriter::FortranFormat_DoublePrecision(0) << " "; // E1 + *output_ << std::setw(18) << std::right << LHEWriter::FortranFormat_DoublePrecision(0) << " "; // E2 + *output_ << std::setw(1) << std::right << 0 << " "; // PDF1 + *output_ << std::setw(1) << std::right << 0 << " "; // PDF2 + *output_ << std::setw(5) << std::right << 0 << " "; // PDFID1 + *output_ << std::setw(5) << std::right << 0 << " "; // PDFID2 + *output_ << std::setw(1) << std::right << 1 << " "; // WEIGHT + *output_ << std::setw(2) << std::right << 1; // NPROCESSES + *output_ << std::endl; + + // one process + *output_ << std::setw(19) << std::right << LHEWriter::FortranFormat_DoublePrecision(1.0) << " "; + *output_ << std::setw(18) << std::right << LHEWriter::FortranFormat_DoublePrecision(0.0) << " "; + *output_ << std::setw(18) << std::right << LHEWriter::FortranFormat_DoublePrecision(1.0) << " "; + *output_ << std::setw(3) << std::right << 1; + *output_ << std::endl; + } + else + { + *output_ << std::setw(9) << std::right << mySample.mc()->beamPDGID_.first << " "; + *output_ << std::setw(8) << std::right << mySample.mc()->beamPDGID_.second << " "; + *output_ << std::setw(18) << std::right << LHEWriter::FortranFormat_DoublePrecision(mySample.mc()->beamE_.first) << " "; + *output_ << std::setw(18) << std::right << LHEWriter::FortranFormat_DoublePrecision(mySample.mc()->beamE_.second) << " "; + *output_ << std::setw(1) << std::right << mySample.mc()->beamPDFauthor_.first << " "; + *output_ << std::setw(1) << std::right << mySample.mc()->beamPDFauthor_.second << " "; + *output_ << std::setw(5) << std::right << mySample.mc()->beamPDFID_.first << " "; + *output_ << std::setw(5) << std::right << mySample.mc()->beamPDFID_.second << " "; + *output_ << std::setw(1) << std::right << mySample.mc()->weightMode_ << " "; + if (mySample.mc()->processes().size() == 0) + { + *output_ << std::setw(2) << std::right << 1; + } + else + { + *output_ << std::setw(2) << std::right << mySample.mc()->processes().size(); + } + *output_ << std::endl; + for (MAuint32 i = 0; i < mySample.mc()->processes().size(); i++) + { + *output_ << std::setw(19) << std::right << LHEWriter::FortranFormat_DoublePrecision(mySample.mc()->processes_[i].xsectionMean_) << " "; + *output_ << std::setw(18) << std::right << LHEWriter::FortranFormat_DoublePrecision(mySample.mc()->processes_[i].xsectionError_) << " "; + *output_ << std::setw(18) << std::right << LHEWriter::FortranFormat_DoublePrecision(mySample.mc()->processes_[i].weightMax_) << " "; + *output_ << std::setw(3) << std::right << mySample.mc()->processes_[i].processId_; + *output_ << std::endl; + } + + if (mySample.mc()->processes().size() == 0) + { + *output_ << std::setw(19) << std::right << LHEWriter::FortranFormat_DoublePrecision(0) << " "; + *output_ << std::setw(18) << std::right << LHEWriter::FortranFormat_DoublePrecision(0) << " "; + *output_ << std::setw(18) << std::right << LHEWriter::FortranFormat_DoublePrecision(1.0) << " "; + *output_ << std::setw(3) << std::right << 1; + *output_ << std::endl; + } + } - *output_ << "</init>" << std::endl; + *output_ << "</init>" << std::endl; - return true; + return true; } - MAint32 GetMotherIndex(MAint32 index) { - if (index==0) return 0; - if (index==1 || index==3 || index==5) return 1; - else if (index==2 || index==4 || index==6) return 2; - else return index-4; + if (index == 0) + return 0; + if (index == 1 || index == 3 || index == 5) + return 1; + else if (index == 2 || index == 4 || index == 6) + return 2; + else + return index - 4; } /// Read the event -MAbool LHEWriter::WriteEvent(const EventFormat& myEvent, - const SampleFormat& mySample) +MAbool LHEWriter::WriteEvent(const EventFormat &myEvent, + const SampleFormat &mySample) { - // FirstEvent - if (FirstEvent_) - { - FirstEvent_=false; - WriteHeader(mySample); - } - - // Event header - *output_ << "<event>" << std::endl; - - // Container for particles - std::vector<LHEParticleFormat> particles; - std::vector<const MCParticleFormat*> pointers; - MAuint32 counter=0; - - // Writing MC particles : only MC info case - // -> hypothesis : input = LHE - if (myEvent.mc()!=0 && myEvent.rec()==0) - { - counter += myEvent.mc()->particles().size(); - } - - // Writing MC particles : MC+REC info case - // -> hypothesis : input = HEP - else if (myEvent.mc()!=0 && myEvent.rec()!=0) - { - for (MAuint32 i=0;i<myEvent.mc()->particles().size();i++) + // FirstEvent + if (FirstEvent_) { - if ( InitialMCParticleToSave(myEvent.mc()->particles()[i],mySample) || - MCParticleToSave(myEvent.mc()->particles()[i],mySample) ) counter++; + FirstEvent_ = false; + WriteHeader(mySample); } - } - - // Writing REC particles - if (myEvent.rec()!=0) - { - counter += myEvent.rec()->muons().size() + - myEvent.rec()->electrons().size() + - myEvent.rec()->taus().size() + - myEvent.rec()->photons().size() + - myEvent.rec()->jets().size() + 1 /*MET*/; - } - - // Writing event global information - particles.reserve(counter); - pointers.reserve(counter); - WriteEventHeader(myEvent,counter); - - // Writing MC particles : only MC info case - // -> hypothesis : input = LHE - if (myEvent.mc()!=0 && myEvent.rec()==0) - { - // Filling the temporary gen table for mother-daughter relation - std::map<const MCParticleFormat*, MAuint32> gentable; - for (MAuint32 i=0;i<myEvent.mc()->particles().size();i++) - { - gentable[&(myEvent.mc()->particles()[i])]=i+1; - } - - // Writing each particle - for (MAuint32 i=0;i<myEvent.mc()->particles().size();i++) + + // Event header + *output_ << "<event>" << std::endl; + + // Container for particles + std::vector<LHEParticleFormat> particles; + std::vector<const MCParticleFormat *> pointers; + MAuint32 counter = 0; + + // Writing MC particles : only MC info case + // -> hypothesis : input = LHE + if (myEvent.mc() != 0 && myEvent.rec() == 0) { - particles.push_back(LHEParticleFormat()); - const MCParticleFormat* part = &(myEvent.mc()->particles()[i]); - std::vector<MAuint32> mothup(2,0); - for (MAuint32 m=0;m<part->mothers().size();m++) - { - if (m>=2) continue; - mothup[m]=gentable[part->mothers()[m]]; - } - if (part->mothers().size()==1) mothup[1]=mothup[0]; - WriteParticle(myEvent.mc()->particles()[i], - mothup[0], - mothup[1], - 0, - particles.back()); + counter += myEvent.mc()->particles().size(); } - } - - // Writing MC particles : MC+REC info case - // -> hypothesis : input = HEP - if (myEvent.mc()!=0 && myEvent.rec()!=0) - { - MAbool firstpart=true; - for (MAuint32 i=0;i<myEvent.mc()->particles().size();i++) - { - const MCParticleFormat* part = &(myEvent.mc()->particles()[i]); - - if ( firstpart && InitialMCParticleToSave(*part,mySample) ) - { - particles.push_back(LHEParticleFormat()); - pointers.push_back(part); - WriteParticle(myEvent.mc()->particles()[i],0,0,-1, particles.back()); - } - else if ( InitialMCParticleToSave(*part,mySample) ) - { - firstpart=false; - particles.push_back(LHEParticleFormat()); - pointers.push_back(part); - WriteParticle(myEvent.mc()->particles()[i],0,0,-1, particles.back()); - } - else if (MCParticleToSave(*part,mySample)) - { - firstpart=false; - particles.push_back(LHEParticleFormat()); - pointers.push_back(part); - std::vector<MAint32> mothers(2,0); - for (MAuint32 m=0;m<part->mothers().size();m++) + // Writing MC particles : MC+REC info case + // -> hypothesis : input = HEP + else if (myEvent.mc() != 0 && myEvent.rec() != 0) + { + for (MAuint32 i = 0; i < myEvent.mc()->particles().size(); i++) { - if (m>=2) continue; - mothers[m]=Find(part->mothers()[m],pointers); + if (InitialMCParticleToSave(myEvent.mc()->particles()[i], mySample) || + MCParticleToSave(myEvent.mc()->particles()[i], mySample)) + counter++; } - WriteParticle(myEvent.mc()->particles()[i],mothers[0],mothers[1],3, particles.back()); - } - else - { - firstpart=false; - } - } - } - - // Writing REC particles - if (myEvent.rec()!=0) - { - for (MAuint32 i=0;i<myEvent.rec()->muons().size();i++) - { - particles.push_back(LHEParticleFormat()); - MAint32 mother = 0; - if (mySample.sampleGenerator()!=MA5GEN::HERWIG6) mother=FindDeeply(myEvent.rec()->muons()[i].mc(),pointers); - WriteMuon(myEvent.rec()->muons()[i],particles.back(),mother); } - for (MAuint32 i=0;i<myEvent.rec()->electrons().size();i++) + + // Writing REC particles + if (myEvent.rec() != 0) { - particles.push_back(LHEParticleFormat()); - MAint32 mother = 0; - if (mySample.sampleGenerator()!=MA5GEN::HERWIG6) mother=FindDeeply(myEvent.rec()->electrons()[i].mc(),pointers); - WriteElectron(myEvent.rec()->electrons()[i],particles.back(),mother); + counter += myEvent.rec()->muons().size() + + myEvent.rec()->electrons().size() + + myEvent.rec()->taus().size() + + myEvent.rec()->photons().size() + + myEvent.rec()->jets().size() + 1 /*MET*/; } - for (MAuint32 i=0;i<myEvent.rec()->taus().size();i++) + + // Writing event global information + particles.reserve(counter); + pointers.reserve(counter); + WriteEventHeader(myEvent, counter); + + // Writing MC particles : only MC info case + // -> hypothesis : input = LHE + if (myEvent.mc() != 0 && myEvent.rec() == 0) { - particles.push_back(LHEParticleFormat()); - MAint32 mother = 0; - if (mySample.sampleGenerator()!=MA5GEN::HERWIG6) mother=FindDeeply(myEvent.rec()->taus()[i].mc(),pointers); - WriteTau(myEvent.rec()->taus()[i],particles.back(),mother); + // Filling the temporary gen table for mother-daughter relation + std::map<const MCParticleFormat *, MAuint32> gentable; + for (MAuint32 i = 0; i < myEvent.mc()->particles().size(); i++) + { + gentable[&(myEvent.mc()->particles()[i])] = i + 1; + } + + // Writing each particle + for (MAuint32 i = 0; i < myEvent.mc()->particles().size(); i++) + { + particles.push_back(LHEParticleFormat()); + const MCParticleFormat *part = &(myEvent.mc()->particles()[i]); + std::vector<MAuint32> mothup(2, 0); + for (MAuint32 m = 0; m < part->mothers().size(); m++) + { + if (m >= 2) + continue; + mothup[m] = gentable[part->mothers()[m]]; + } + if (part->mothers().size() == 1) + mothup[1] = mothup[0]; + WriteParticle(myEvent.mc()->particles()[i], + mothup[0], + mothup[1], + 0, + particles.back()); + } } - for (MAuint32 i=0;i<myEvent.rec()->jets().size();i++) + + // Writing MC particles : MC+REC info case + // -> hypothesis : input = HEP + if (myEvent.mc() != 0 && myEvent.rec() != 0) { - particles.push_back(LHEParticleFormat()); - MAint32 mother = 0; - if (mySample.sampleGenerator()!=MA5GEN::HERWIG6) mother=FindDeeply(myEvent.rec()->jets()[i].mc(),pointers); - WriteJet(myEvent.rec()->jets()[i],particles.back(),mother); + MAbool firstpart = true; + for (MAuint32 i = 0; i < myEvent.mc()->particles().size(); i++) + { + const MCParticleFormat *part = &(myEvent.mc()->particles()[i]); + + if (firstpart && InitialMCParticleToSave(*part, mySample)) + { + particles.push_back(LHEParticleFormat()); + pointers.push_back(part); + WriteParticle(myEvent.mc()->particles()[i], 0, 0, -1, particles.back()); + } + else if (InitialMCParticleToSave(*part, mySample)) + { + firstpart = false; + particles.push_back(LHEParticleFormat()); + pointers.push_back(part); + WriteParticle(myEvent.mc()->particles()[i], 0, 0, -1, particles.back()); + } + + else if (MCParticleToSave(*part, mySample)) + { + firstpart = false; + particles.push_back(LHEParticleFormat()); + pointers.push_back(part); + std::vector<MAint32> mothers(2, 0); + for (MAuint32 m = 0; m < part->mothers().size(); m++) + { + if (m >= 2) + continue; + mothers[m] = Find(part->mothers()[m], pointers); + } + WriteParticle(myEvent.mc()->particles()[i], mothers[0], mothers[1], 3, particles.back()); + } + else + { + firstpart = false; + } + } } - for (MAuint32 i=0;i<myEvent.rec()->photons().size();i++) + + // Writing REC particles + if (myEvent.rec() != 0) { - particles.push_back(LHEParticleFormat()); - MAint32 mother = 0; - if (mySample.sampleGenerator()!=MA5GEN::HERWIG6) mother=FindDeeply(myEvent.rec()->photons()[i].mc(),pointers); - WritePhoton(myEvent.rec()->photons()[i],particles.back(),mother); + for (MAuint32 i = 0; i < myEvent.rec()->muons().size(); i++) + { + particles.push_back(LHEParticleFormat()); + MAint32 mother = 0; + if (mySample.sampleGenerator() != MA5GEN::HERWIG6) + mother = FindDeeply(myEvent.rec()->muons()[i].mc(), pointers); + WriteMuon(myEvent.rec()->muons()[i], particles.back(), mother); + } + for (MAuint32 i = 0; i < myEvent.rec()->electrons().size(); i++) + { + particles.push_back(LHEParticleFormat()); + MAint32 mother = 0; + if (mySample.sampleGenerator() != MA5GEN::HERWIG6) + mother = FindDeeply(myEvent.rec()->electrons()[i].mc(), pointers); + WriteElectron(myEvent.rec()->electrons()[i], particles.back(), mother); + } + for (MAuint32 i = 0; i < myEvent.rec()->taus().size(); i++) + { + particles.push_back(LHEParticleFormat()); + MAint32 mother = 0; + if (mySample.sampleGenerator() != MA5GEN::HERWIG6) + mother = FindDeeply(myEvent.rec()->taus()[i].mc(), pointers); + WriteTau(myEvent.rec()->taus()[i], particles.back(), mother); + } + for (MAuint32 i = 0; i < myEvent.rec()->jets().size(); i++) + { + particles.push_back(LHEParticleFormat()); + MAint32 mother = 0; + if (mySample.sampleGenerator() != MA5GEN::HERWIG6) + mother = FindDeeply(myEvent.rec()->jets()[i].mc(), pointers); + WriteJet(myEvent.rec()->jets()[i], particles.back(), mother); + } + for (MAuint32 i = 0; i < myEvent.rec()->photons().size(); i++) + { + particles.push_back(LHEParticleFormat()); + MAint32 mother = 0; + if (mySample.sampleGenerator() != MA5GEN::HERWIG6) + mother = FindDeeply(myEvent.rec()->photons()[i].mc(), pointers); + WritePhoton(myEvent.rec()->photons()[i], particles.back(), mother); + } + particles.push_back(LHEParticleFormat()); + WriteMET(myEvent.rec()->MET(), particles.back()); } - particles.push_back(LHEParticleFormat()); - WriteMET(myEvent.rec()->MET(),particles.back()); - } - - // Event foot - for (MAuint32 i=0;i<particles.size();i++) particles[i].Print(i+1, output_); - *output_ << "</event>" << std::endl; - return true; -} + // Event foot + for (MAuint32 i = 0; i < particles.size(); i++) + particles[i].Print(i + 1, output_); + *output_ << "</event>" << std::endl; + return true; +} /// Finalize the event -MAbool LHEWriter::WriteFoot(const SampleFormat& mySample) +MAbool LHEWriter::WriteFoot(const SampleFormat &mySample) { - // FirstEvent - if (FirstEvent_) return false; + // FirstEvent + if (FirstEvent_) + return false; - // Foot - *output_ << "</LesHouchesEvents>" << std::endl; - return true; + // Foot + *output_ << "</LesHouchesEvents>" << std::endl; + return true; } - /// Writing event global information -MAbool LHEWriter::WriteEventHeader(const EventFormat& myEvent, - MAuint32 nevents) +MAbool LHEWriter::WriteEventHeader(const EventFormat &myEvent, + MAuint32 nevents) { - if (myEvent.mc()!=0) - { - *output_ << std::setw(2) << std::right << nevents << " "; - *output_ << std::setw(3) << std::right << myEvent.mc()->processId_ << " "; - MAfloat64 myweight = myEvent.mc()->weight_; - if (myweight==0) myweight=1; - *output_ << std::setw(14) << std::right << LHEWriter::FortranFormat_SimplePrecision(myweight) << " "; - *output_ << std::setw(14) << std::right << LHEWriter::FortranFormat_SimplePrecision(myEvent.mc()->scale_) << " "; - *output_ << std::setw(14) << std::right << LHEWriter::FortranFormat_SimplePrecision(myEvent.mc()->alphaQED_) << " "; - *output_ << std::setw(14) << std::right << LHEWriter::FortranFormat_SimplePrecision(myEvent.mc()->alphaQCD_) << std::endl; - } - else - { - *output_ << std::setw(2) << std::right << nevents << " "; - *output_ << std::setw(3) << std::right << 1 << " "; - *output_ << std::setw(14) << std::right << LHEWriter::FortranFormat_SimplePrecision(1.0) << " "; - *output_ << std::setw(14) << std::right << LHEWriter::FortranFormat_SimplePrecision(0.0) << " "; - *output_ << std::setw(14) << std::right << LHEWriter::FortranFormat_SimplePrecision(0.0) << " "; - *output_ << std::setw(14) << std::right << LHEWriter::FortranFormat_SimplePrecision(0.0) << std::endl; - } - return true; + if (myEvent.mc() != 0) + { + *output_ << std::setw(2) << std::right << nevents << " "; + *output_ << std::setw(3) << std::right << myEvent.mc()->processId_ << " "; + MAfloat64 myweight = myEvent.mc()->get_weight(0); + if (myweight == 0) + myweight = 1; + *output_ << std::setw(14) << std::right << LHEWriter::FortranFormat_SimplePrecision(myweight) << " "; + *output_ << std::setw(14) << std::right << LHEWriter::FortranFormat_SimplePrecision(myEvent.mc()->scale_) << " "; + *output_ << std::setw(14) << std::right << LHEWriter::FortranFormat_SimplePrecision(myEvent.mc()->alphaQED_) << " "; + *output_ << std::setw(14) << std::right << LHEWriter::FortranFormat_SimplePrecision(myEvent.mc()->alphaQCD_) << std::endl; + } + else + { + *output_ << std::setw(2) << std::right << nevents << " "; + *output_ << std::setw(3) << std::right << 1 << " "; + *output_ << std::setw(14) << std::right << LHEWriter::FortranFormat_SimplePrecision(1.0) << " "; + *output_ << std::setw(14) << std::right << LHEWriter::FortranFormat_SimplePrecision(0.0) << " "; + *output_ << std::setw(14) << std::right << LHEWriter::FortranFormat_SimplePrecision(0.0) << " "; + *output_ << std::setw(14) << std::right << LHEWriter::FortranFormat_SimplePrecision(0.0) << std::endl; + } + return true; } - /// Writing a particle -void LHEWriter::WriteParticle(const MCParticleFormat& myPart, - MAint32 mother1, MAint32 mother2, - MAint32 statuscode, LHEParticleFormat& lhe) +void LHEWriter::WriteParticle(const MCParticleFormat &myPart, + MAint32 mother1, MAint32 mother2, + MAint32 statuscode, LHEParticleFormat &lhe) { - if (statuscode!=0) lhe.status = statuscode; - else lhe.status = myPart.statuscode_; - lhe.id = myPart.pdgid_; - lhe.mother1 = mother1; - lhe.mother2 = mother2; - lhe.color1 = 0; - lhe.color2 = 0; - lhe.px = myPart.momentum().Px(); - lhe.py = myPart.momentum().Py(); - lhe.pz = myPart.momentum().Pz(); - lhe.e = myPart.momentum().E(); - lhe.m = myPart.momentum().M(); - lhe.ctau = myPart.decay_vertex().T(); - lhe.spin = myPart.spin_; + if (statuscode != 0) + lhe.status = statuscode; + else + lhe.status = myPart.statuscode_; + lhe.id = myPart.pdgid_; + lhe.mother1 = mother1; + lhe.mother2 = mother2; + lhe.color1 = 0; + lhe.color2 = 0; + lhe.px = myPart.momentum().Px(); + lhe.py = myPart.momentum().Py(); + lhe.pz = myPart.momentum().Pz(); + lhe.e = myPart.momentum().E(); + lhe.m = myPart.momentum().M(); + lhe.ctau = myPart.decay_vertex().T(); + lhe.spin = myPart.spin_; } - -void LHEWriter::WriteJet(const RecJetFormat& jet, LHEParticleFormat& lhe, MAint32& mother) +void LHEWriter::WriteJet(const RecJetFormat &jet, LHEParticleFormat &lhe, MAint32 &mother) { - if (jet.btag()) lhe.id = 5; - else if (jet.ctag()) lhe.id = 4; - else lhe.id = 21; - lhe.status = 1; - lhe.mother1 = mother; - lhe.mother2 = mother; - lhe.color1 = 0; - lhe.color2 = 0; - lhe.px = jet.momentum().Px(); - lhe.py = jet.momentum().Py(); - lhe.pz = jet.momentum().Pz(); - lhe.e = jet.momentum().E(); - lhe.m = jet.momentum().M(); - lhe.ctau = 0.; - lhe.spin = 0.; + if (jet.btag()) + lhe.id = 5; + else if (jet.ctag()) + lhe.id = 4; + else + lhe.id = 21; + lhe.status = 1; + lhe.mother1 = mother; + lhe.mother2 = mother; + lhe.color1 = 0; + lhe.color2 = 0; + lhe.px = jet.momentum().Px(); + lhe.py = jet.momentum().Py(); + lhe.pz = jet.momentum().Pz(); + lhe.e = jet.momentum().E(); + lhe.m = jet.momentum().M(); + lhe.ctau = 0.; + lhe.spin = 0.; } - -void LHEWriter::WriteMuon(const RecLeptonFormat& muon, LHEParticleFormat& lhe, MAint32& mother) +void LHEWriter::WriteMuon(const RecLeptonFormat &muon, LHEParticleFormat &lhe, MAint32 &mother) { - if (muon.charge()>0) lhe.id = -13; else lhe.id = +13; - lhe.status = 1; - lhe.mother1 = mother; - lhe.mother2 = mother; - lhe.color1 = 0; - lhe.color2 = 0; - lhe.px = muon.momentum().Px(); - lhe.py = muon.momentum().Py(); - lhe.pz = muon.momentum().Pz(); - lhe.e = muon.momentum().E(); - lhe.m = muon.momentum().M(); - lhe.ctau = 0.; - lhe.spin = 0.; + if (muon.charge() > 0) + lhe.id = -13; + else + lhe.id = +13; + lhe.status = 1; + lhe.mother1 = mother; + lhe.mother2 = mother; + lhe.color1 = 0; + lhe.color2 = 0; + lhe.px = muon.momentum().Px(); + lhe.py = muon.momentum().Py(); + lhe.pz = muon.momentum().Pz(); + lhe.e = muon.momentum().E(); + lhe.m = muon.momentum().M(); + lhe.ctau = 0.; + lhe.spin = 0.; } -void LHEWriter::WriteElectron(const RecLeptonFormat& electron, LHEParticleFormat& lhe, MAint32& mother) +void LHEWriter::WriteElectron(const RecLeptonFormat &electron, LHEParticleFormat &lhe, MAint32 &mother) { - if (electron.charge()>0) lhe.id = -11; else lhe.id = +11; - lhe.status = 1; - lhe.mother1 = mother; - lhe.mother2 = mother; - lhe.color1 = 0; - lhe.color2 = 0; - lhe.px = electron.momentum().Px(); - lhe.py = electron.momentum().Py(); - lhe.pz = electron.momentum().Pz(); - lhe.e = electron.momentum().E(); - lhe.m = electron.momentum().M(); - lhe.ctau = 0.; - lhe.spin = 0.; + if (electron.charge() > 0) + lhe.id = -11; + else + lhe.id = +11; + lhe.status = 1; + lhe.mother1 = mother; + lhe.mother2 = mother; + lhe.color1 = 0; + lhe.color2 = 0; + lhe.px = electron.momentum().Px(); + lhe.py = electron.momentum().Py(); + lhe.pz = electron.momentum().Pz(); + lhe.e = electron.momentum().E(); + lhe.m = electron.momentum().M(); + lhe.ctau = 0.; + lhe.spin = 0.; } - -void LHEWriter::WritePhoton(const RecPhotonFormat& photon, LHEParticleFormat& lhe, MAint32& mother) +void LHEWriter::WritePhoton(const RecPhotonFormat &photon, LHEParticleFormat &lhe, MAint32 &mother) { - lhe.id = 22; - lhe.status = 1; - lhe.mother1 = mother; - lhe.mother2 = mother; - lhe.color1 = 0; - lhe.color2 = 0; - lhe.px = photon.momentum().Px(); - lhe.py = photon.momentum().Py(); - lhe.pz = photon.momentum().Pz(); - lhe.e = photon.momentum().E(); - lhe.m = photon.momentum().M(); - lhe.ctau = 0.; - lhe.spin = 0.; + lhe.id = 22; + lhe.status = 1; + lhe.mother1 = mother; + lhe.mother2 = mother; + lhe.color1 = 0; + lhe.color2 = 0; + lhe.px = photon.momentum().Px(); + lhe.py = photon.momentum().Py(); + lhe.pz = photon.momentum().Pz(); + lhe.e = photon.momentum().E(); + lhe.m = photon.momentum().M(); + lhe.ctau = 0.; + lhe.spin = 0.; } - -void LHEWriter::WriteTau(const RecTauFormat& tau, LHEParticleFormat& lhe, MAint32& mother) +void LHEWriter::WriteTau(const RecTauFormat &tau, LHEParticleFormat &lhe, MAint32 &mother) { - if (tau.charge()>0) lhe.id = -15; else lhe.id = +15; - lhe.status = 1; - lhe.mother1 = mother; - lhe.mother2 = mother; - lhe.color1 = 0; - lhe.color2 = 0; - lhe.px = tau.momentum().Px(); - lhe.py = tau.momentum().Py(); - lhe.pz = tau.momentum().Pz(); - lhe.e = tau.momentum().E(); - lhe.m = tau.momentum().M(); - lhe.ctau = 0.; - lhe.spin = 0.; + if (tau.charge() > 0) + lhe.id = -15; + else + lhe.id = +15; + lhe.status = 1; + lhe.mother1 = mother; + lhe.mother2 = mother; + lhe.color1 = 0; + lhe.color2 = 0; + lhe.px = tau.momentum().Px(); + lhe.py = tau.momentum().Py(); + lhe.pz = tau.momentum().Pz(); + lhe.e = tau.momentum().E(); + lhe.m = tau.momentum().M(); + lhe.ctau = 0.; + lhe.spin = 0.; } - -void LHEWriter::WriteMET(const ParticleBaseFormat& met, LHEParticleFormat& lhe) +void LHEWriter::WriteMET(const ParticleBaseFormat &met, LHEParticleFormat &lhe) { - lhe.id = 12; - lhe.status = 1; - lhe.mother1 = 0; - lhe.mother2 = 0; - lhe.color1 = 0; - lhe.color2 = 0; - lhe.px = met.px(); - lhe.py = met.py(); - lhe.pz = 0.; - lhe.e = met.pt(); - lhe.m = 0.; - lhe.ctau = 0.; - lhe.spin = 0.; + lhe.id = 12; + lhe.status = 1; + lhe.mother1 = 0; + lhe.mother2 = 0; + lhe.color1 = 0; + lhe.color2 = 0; + lhe.px = met.px(); + lhe.py = met.py(); + lhe.pz = 0.; + lhe.e = met.pt(); + lhe.m = 0.; + lhe.ctau = 0.; + lhe.spin = 0.; } From a3cbd62b6b729f2aba3f40106b43ceeb88bf2f5a Mon Sep 17 00:00:00 2001 From: "Jack Y. Araz" <jackaraz@gmail.com> Date: Tue, 27 Jun 2023 16:57:03 +0100 Subject: [PATCH 011/107] bug fixes --- .../SampleAnalyzer/Commons/DataFormat/MCEventFormat.h | 3 +++ .../Commons/DataFormat/WeightCollection.h | 2 +- tools/SampleAnalyzer/Process/Plot/PlotBase.h | 9 +++------ tools/SampleAnalyzer/Process/Reader/LHEReader.cpp | 10 +++++----- .../Process/RegionSelection/RegionSelectionManager.h | 9 ++++----- 5 files changed, 16 insertions(+), 17 deletions(-) diff --git a/tools/SampleAnalyzer/Commons/DataFormat/MCEventFormat.h b/tools/SampleAnalyzer/Commons/DataFormat/MCEventFormat.h index 9dc08d57..0dabfbb2 100644 --- a/tools/SampleAnalyzer/Commons/DataFormat/MCEventFormat.h +++ b/tools/SampleAnalyzer/Commons/DataFormat/MCEventFormat.h @@ -163,6 +163,9 @@ namespace MA5 /// Accessor to multiweights WeightCollection &weights() { return multiweights_; } + /// Accessor to multiweights + const WeightCollection &weights() const { return multiweights_; } + /// Accessor to multiweights const MAfloat64 &get_weight(MAuint32 id) const { return multiweights_.Get(id); } diff --git a/tools/SampleAnalyzer/Commons/DataFormat/WeightCollection.h b/tools/SampleAnalyzer/Commons/DataFormat/WeightCollection.h index 0d125e8a..a72fe76a 100644 --- a/tools/SampleAnalyzer/Commons/DataFormat/WeightCollection.h +++ b/tools/SampleAnalyzer/Commons/DataFormat/WeightCollection.h @@ -61,7 +61,7 @@ namespace MA5 { weights_.clear(); for (auto &id_weights : rhs.weights_) - weights_[id_weights.first] = id_weights.second; + Add(id_weights.first, id_weights.second); } /// @brief Initialise weights with a certain size and default value diff --git a/tools/SampleAnalyzer/Process/Plot/PlotBase.h b/tools/SampleAnalyzer/Process/Plot/PlotBase.h index 72d07b4e..c9ac5030 100644 --- a/tools/SampleAnalyzer/Process/Plot/PlotBase.h +++ b/tools/SampleAnalyzer/Process/Plot/PlotBase.h @@ -71,20 +71,16 @@ namespace MA5 PlotBase() { // Reseting statistical counters - nevents_.insert(std::make_pair(0, ENTRIES())); - nentries_.insert(std::make_pair(0, ENTRIES())); - nevents_w_.insert(std::make_pair(0, WEIGHTS())); fresh_event_ = true; + initialised_ = false; } /// Constructor with argument PlotBase(const std::string &name) { name_ = name; - nevents_.insert(std::make_pair(0, ENTRIES())); - nentries_.insert(std::make_pair(0, ENTRIES())); - nevents_w_.insert(std::make_pair(0, WEIGHTS())); fresh_event_ = true; + initialised_ = false; } /// Destructor @@ -112,6 +108,7 @@ namespace MA5 nentries_[weight.first] = ENTRIES(); nevents_w_[weight.first] = WEIGHTS(); } + initialised_ = true; } } diff --git a/tools/SampleAnalyzer/Process/Reader/LHEReader.cpp b/tools/SampleAnalyzer/Process/Reader/LHEReader.cpp index 2d9f248a..a4aa9e05 100644 --- a/tools/SampleAnalyzer/Process/Reader/LHEReader.cpp +++ b/tools/SampleAnalyzer/Process/Reader/LHEReader.cpp @@ -498,7 +498,7 @@ void LHEReader::FillEventInitLine(const std::string &line, str >> myEvent.mc()->alphaQED_; str >> myEvent.mc()->alphaQCD_; myEvent.mc()->particles_.reserve(nparts); - myEvent.mc()->weights().Add(0, weight); + myEvent.mc()->multiweights_.Add(0, weight); mothers_.reserve(nparts); } @@ -565,10 +565,12 @@ void LHEReader::FillWeightLine(const std::string &line, if (tmp != "<wgt") return; - std::size_t found1 = line.find("\""); + /// @jackaraz: Note that changing "\"" to "\'". this may cause problems in certain files + /// with the LHE example that I have the quotes are written with ' not with " + std::size_t found1 = line.find("\'"); if (found1 == std::string::npos) return; - std::size_t found2 = line.find("\"", found1 + 1); + std::size_t found2 = line.find("\'", found1 + 1); if (found2 == std::string::npos) return; std::string idstring = line.substr(found1 + 1, found2 - found1 - 1); @@ -577,7 +579,6 @@ void LHEReader::FillWeightLine(const std::string &line, str2 << idstring; MAuint32 id; str2 >> id; - found1 = line.find(">"); if (found1 == std::string::npos) return; @@ -590,6 +591,5 @@ void LHEReader::FillWeightLine(const std::string &line, str3 << valuestring; MAfloat64 value; str3 >> value; - myEvent.mc()->weights().Add(id, value); } diff --git a/tools/SampleAnalyzer/Process/RegionSelection/RegionSelectionManager.h b/tools/SampleAnalyzer/Process/RegionSelection/RegionSelectionManager.h index c569a040..faf93718 100644 --- a/tools/SampleAnalyzer/Process/RegionSelection/RegionSelectionManager.h +++ b/tools/SampleAnalyzer/Process/RegionSelection/RegionSelectionManager.h @@ -83,9 +83,6 @@ namespace MA5 /// Reset void Reset() { - for (MAuint32 i = 0; i < regions_.size(); i++) - if (regions_[i] != 0) - delete regions_[i]; regions_.clear(); cutmanager_.Finalize(); plotmanager_.Finalize(); @@ -138,9 +135,11 @@ namespace MA5 /// @brief initialise new event with multiweight definition /// @param EventWeight weight map - void InitializeForNewEvent(WeightCollection &EventWeight) + void InitializeForNewEvent(const WeightCollection &EventWeight) { - weight_ = EventWeight; + weight_.Reset(); + for (auto &w : EventWeight.GetWeights()) + weight_.Add(w.first, w.second); NumberOfSurvivingRegions_ = regions_.size(); for (auto ® : regions_) reg->InitializeForNewEvent(EventWeight); From 13db6907edc69e328273f1a22b9232cd489e4be0 Mon Sep 17 00:00:00 2001 From: "Jack Y. Araz" <jackaraz@gmail.com> Date: Tue, 27 Jun 2023 17:30:15 +0100 Subject: [PATCH 012/107] addd accesor for weight names --- tools/SampleAnalyzer/Commons/DataFormat/MCSampleFormat.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tools/SampleAnalyzer/Commons/DataFormat/MCSampleFormat.h b/tools/SampleAnalyzer/Commons/DataFormat/MCSampleFormat.h index 7d17dc71..95f3d74f 100644 --- a/tools/SampleAnalyzer/Commons/DataFormat/MCSampleFormat.h +++ b/tools/SampleAnalyzer/Commons/DataFormat/MCSampleFormat.h @@ -270,6 +270,9 @@ namespace MA5 /// @param name name of the weight void SetWeightName(int id, std::string name) { weight_names_[id] = name; } + /// @brief accessor to weight names + const std::map<int, std::string> WeightNames() const { return weight_names_; } + /// Adding a weight void addWeightedEvents(MAfloat64 weight) { From d56d2010ae63f5feb639e67bba792a418256a204 Mon Sep 17 00:00:00 2001 From: "Jack Y. Araz" <jackaraz@gmail.com> Date: Tue, 27 Jun 2023 17:30:29 +0100 Subject: [PATCH 013/107] add preparation for execution --- .../Process/Core/SampleAnalyzer.cpp | 10 + .../Process/Core/SampleAnalyzer.h | 206 +++++++++--------- 2 files changed, 108 insertions(+), 108 deletions(-) diff --git a/tools/SampleAnalyzer/Process/Core/SampleAnalyzer.cpp b/tools/SampleAnalyzer/Process/Core/SampleAnalyzer.cpp index 7956d57f..99cba93e 100644 --- a/tools/SampleAnalyzer/Process/Core/SampleAnalyzer.cpp +++ b/tools/SampleAnalyzer/Process/Core/SampleAnalyzer.cpp @@ -789,6 +789,16 @@ StatusCode::Type SampleAnalyzer::NextEvent(SampleFormat &mySample, EventFormat & return StatusCode::KEEP; } +/// @brief Prepare analyzers for the execution by initialising the weights +/// @param mySample sample dataset +/// @param myEvent event dataset +void SampleAnalyzer::PrepareForExecution(SampleFormat &mySample, EventFormat &myEvent) +{ + if (myEvent.mc() != 0) + for (auto &analyzer : analyzers_) + analyzer->Manager()->InitializeForNewEvent(myEvent.mc()->weights()); +} + /// Home made functions to make reasonnable filenames inline void ReplaceAll(std::string &name, const std::string &In, const std::string &Out) { diff --git a/tools/SampleAnalyzer/Process/Core/SampleAnalyzer.h b/tools/SampleAnalyzer/Process/Core/SampleAnalyzer.h index 101d1c63..7d8dd63c 100644 --- a/tools/SampleAnalyzer/Process/Core/SampleAnalyzer.h +++ b/tools/SampleAnalyzer/Process/Core/SampleAnalyzer.h @@ -1,31 +1,29 @@ //////////////////////////////////////////////////////////////////////////////// -// +// // Copyright (C) 2012-2023 Jack Araz, Eric Conte & Benjamin Fuks // The MadAnalysis development team, email: <ma5team@iphc.cnrs.fr> -// +// // This file is part of MadAnalysis 5. // Official website: <https://github.com/MadAnalysis/madanalysis5> -// +// // MadAnalysis 5 is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // MadAnalysis 5 is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with MadAnalysis 5. If not, see <http://www.gnu.org/licenses/> -// +// //////////////////////////////////////////////////////////////////////////////// - #ifndef SAMPLE_ANALYZER_H #define SAMPLE_ANALYZER_H - // STL headers #include <iostream> #include <string> @@ -43,139 +41,131 @@ #include "SampleAnalyzer/Process/JetClustering/JetClustererManager.h" #include "SampleAnalyzer/Process/Detector/DetectorManager.h" - namespace MA5 { -class ProgressBar; -class Configuration; - -class SampleAnalyzer -{ - private : - - std::string analysisName_; - std::string datasetName_; - MAbool LastFileFail_; - - /// Configuration of SampleAnalyzer - Configuration cfg_; - - /// List of input files - std::vector<std::string> inputs_; - - /// List of managers - WriterManager fullWriters_; - ReaderManager fullReaders_; - AnalyzerManager fullAnalyses_; - JetClustererManager fullJetClusterers_; - DetectorManager fullDetectors_; + class ProgressBar; + class Configuration; - /// List of managers - std::vector<WriterBase*> writers_; - std::vector<ReaderBase*> readers_; - std::vector<AnalyzerBase*> analyzers_; - std::vector<JetClusterer*> clusters_; - std::vector<DetectorBase*> detectors_; + class SampleAnalyzer + { + private: + std::string analysisName_; + std::string datasetName_; + MAbool LastFileFail_; - /// Reading status - MAuint32 file_index_; - MAbool next_file_; + /// Configuration of SampleAnalyzer + Configuration cfg_; - /// Counters - std::vector<MAuint64> counter_read_; - std::vector<MAuint64> counter_passed_; + /// List of input files + std::vector<std::string> inputs_; - /// The only one pointer to the reader - ReaderBase* myReader_; + /// List of managers + WriterManager fullWriters_; + ReaderManager fullReaders_; + AnalyzerManager fullAnalyses_; + JetClustererManager fullJetClusterers_; + DetectorManager fullDetectors_; - /// Progress bar for event reading - ProgressBar* progressBar_; + /// List of managers + std::vector<WriterBase *> writers_; + std::vector<ReaderBase *> readers_; + std::vector<AnalyzerBase *> analyzers_; + std::vector<JetClusterer *> clusters_; + std::vector<DetectorBase *> detectors_; - - public: + /// Reading status + MAuint32 file_index_; + MAbool next_file_; - /// Constructor withtout arguments - SampleAnalyzer(); + /// Counters + std::vector<MAuint64> counter_read_; + std::vector<MAuint64> counter_passed_; - /// Adding Analyzer - AnalyzerManager& AnalyzerList() - { return fullAnalyses_; } - ReaderManager& ReaderList() - { return fullReaders_; } - WriterManager& WriterList() - { return fullWriters_; } - JetClustererManager& JetClustererList() - { return fullJetClusterers_; } - DetectorManager& DetectorSimList() - { return fullDetectors_; } + /// The only one pointer to the reader + ReaderBase *myReader_; - /// Initialization of the SampleAnalyzer - MAbool Initialize(MAint32 argc, MAchar **argv, const std::string& filename); + /// Progress bar for event reading + ProgressBar *progressBar_; - /// Getting pointer to an analyzer - AnalyzerBase* InitializeAnalyzer(const std::string& name, - const std::string& outputname, - const std::map<std::string,std::string>& parameters); + public: + /// Constructor withtout arguments + SampleAnalyzer(); - AnalyzerBase* InitializeAnalyzer(const std::string& name, - const std::string& outputname); + /// Adding Analyzer + AnalyzerManager &AnalyzerList() { return fullAnalyses_; } + ReaderManager &ReaderList() { return fullReaders_; } + WriterManager &WriterList() { return fullWriters_; } + JetClustererManager &JetClustererList() { return fullJetClusterers_; } + DetectorManager &DetectorSimList() { return fullDetectors_; } - /// Getting pointer to a writer - WriterBase* InitializeWriter(const std::string& name, - const std::string& outputname); + /// Initialization of the SampleAnalyzer + MAbool Initialize(MAint32 argc, MAchar **argv, const std::string &filename); - /// Getting pointer to a jet clusterer - JetClusterer* InitializeJetClusterer(const std::string& name, - const std::map<std::string,std::string>& parameters); + /// Getting pointer to an analyzer + AnalyzerBase *InitializeAnalyzer(const std::string &name, + const std::string &outputname, + const std::map<std::string, std::string> ¶meters); - /// Getting pointer to a detector - DetectorBase* InitializeDetector(const std::string& name, - const std::string& configFile, - const std::map<std::string,std::string>& parameters); + AnalyzerBase *InitializeAnalyzer(const std::string &name, + const std::string &outputname); - /// Reading the next event - StatusCode::Type NextEvent(SampleFormat& mysample, EventFormat& myevent); + /// Getting pointer to a writer + WriterBase *InitializeWriter(const std::string &name, + const std::string &outputname); - /// Reading the next file - StatusCode::Type NextFile(SampleFormat& mysample); + /// Getting pointer to a jet clusterer + JetClusterer *InitializeJetClusterer(const std::string &name, + const std::map<std::string, std::string> ¶meters); - /// Finalization of the SampleAnalyzer - MAbool Finalize(std::vector<SampleFormat>& mysamples, EventFormat& myevent); + /// Getting pointer to a detector + DetectorBase *InitializeDetector(const std::string &name, + const std::string &configFile, + const std::map<std::string, std::string> ¶meters); - /// Updating the progress bar - void UpdateProgressBar(); + /// Reading the next event + StatusCode::Type NextEvent(SampleFormat &mysample, EventFormat &myevent); - /// Creating the directory structure associated with the SRM - MAbool PostInitialize(); + /// @brief Prepare the analyses for execution by initialising the weights + /// @param mysample sample data + /// @param myevent event data + void PrepareForExecution(SampleFormat &mysample, EventFormat &myevent); - /// Dumping the content of the counters - void DumpSR(std::ostream &); - void HeadSR(std::ostream &); + /// Reading the next file + StatusCode::Type NextFile(SampleFormat &mysample); - std::map<std::string, std::string> options() {return cfg_.Options();} + /// Finalization of the SampleAnalyzer + MAbool Finalize(std::vector<SampleFormat> &mysamples, EventFormat &myevent); - // Default Hadronic particles - void AddDefaultHadronic(); + /// Updating the progress bar + void UpdateProgressBar(); - // Default Hadronic particles - void AddDefaultInvisible(); + /// Creating the directory structure associated with the SRM + MAbool PostInitialize(); - private: + /// Dumping the content of the counters + void DumpSR(std::ostream &); + void HeadSR(std::ostream &); - /// CheckDatatypes - void CheckDatatypes() const; + std::map<std::string, std::string> options() { return cfg_.Options(); } - /// Filling the summary format - void FillSummary(SampleFormat& summary, - const std::vector<SampleFormat>& mysamples); + // Default Hadronic particles + void AddDefaultHadronic(); + // Default Hadronic particles + void AddDefaultInvisible(); - /// Creating the directory structure associated with the SRM - MAbool CreateDirectoryStructure(); + private: + /// CheckDatatypes + void CheckDatatypes() const; + /// Filling the summary format + void FillSummary(SampleFormat &summary, + const std::vector<SampleFormat> &mysamples); -}; + /// Creating the directory structure associated with the SRM + MAbool CreateDirectoryStructure(); + }; } From a92eabd86f7a4a55ec85dbf6f61442ac7c5c15c4 Mon Sep 17 00:00:00 2001 From: "Jack Y. Araz" <jackaraz@gmail.com> Date: Tue, 27 Jun 2023 17:39:12 +0100 Subject: [PATCH 014/107] update `main.cpp` writers --- madanalysis/IOinterface/job_writer.py | 1 + madanalysis/job/job_execute.py | 429 ++++++++++++++------------ madanalysis/misc/run_recast.py | 1 + 3 files changed, 239 insertions(+), 192 deletions(-) diff --git a/madanalysis/IOinterface/job_writer.py b/madanalysis/IOinterface/job_writer.py index 90051ac1..6c80e255 100644 --- a/madanalysis/IOinterface/job_writer.py +++ b/madanalysis/IOinterface/job_writer.py @@ -605,6 +605,7 @@ def CreateMainFct(self,file,analysisName,outputName): file.write(' fastsim1->Execute(mySample,myEvent);\n') elif self.main.fastsim.package=="delphesMA5tune": file.write(' fastsim1->Execute(mySample,myEvent);\n') + file.write(' manager.PrepareForExecution(mySample, myEvent);\n') file.write(' if (!analyzer1->Execute(mySample,myEvent)) continue;\n') if self.output!="" and not self.output.lower().endswith('root'): file.write(' writer1->WriteEvent(myEvent,mySample);\n') diff --git a/madanalysis/job/job_execute.py b/madanalysis/job/job_execute.py index 4d61d949..3e46b7b2 100644 --- a/madanalysis/job/job_execute.py +++ b/madanalysis/job/job_execute.py @@ -1,342 +1,386 @@ ################################################################################ -# +# # Copyright (C) 2012-2023 Jack Araz, Eric Conte & Benjamin Fuks # The MadAnalysis development team, email: <ma5team@iphc.cnrs.fr> -# +# # This file is part of MadAnalysis 5. # Official website: <https://github.com/MadAnalysis/madanalysis5> -# +# # MadAnalysis 5 is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. -# +# # MadAnalysis 5 is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. -# +# # You should have received a copy of the GNU General Public License # along with MadAnalysis 5. If not, see <http://www.gnu.org/licenses/> -# +# ################################################################################ from __future__ import absolute_import -from madanalysis.selection.histogram import Histogram -from madanalysis.selection.instance_name import InstanceName -from madanalysis.enumeration.observable_type import ObservableType +from madanalysis.selection.histogram import Histogram +from madanalysis.selection.instance_name import InstanceName +from madanalysis.enumeration.observable_type import ObservableType from madanalysis.enumeration.ma5_running_type import MA5RunningType -from madanalysis.interpreter.cmd_cut import CmdCut +from madanalysis.interpreter.cmd_cut import CmdCut import logging import copy from six.moves import range -def WriteExecute(file,main,part_list): + +def WriteExecute(file, main, part_list): # Function header - file.write('MAbool user::Execute(SampleFormat& sample, ' +\ - 'const EventFormat& event)\n{\n') + file.write("MAbool user::Execute(SampleFormat& sample, " + "const EventFormat& event)\n{\n") + # @jackaraz: This is now handled in tools/SampleAnalyzer/Process/Core/SampleAnalyzer.cpp:PrepareForExecution # Getting the event weight - file.write(' MAfloat32 __event_weight__ = 1.0;\n') - file.write(' if (weighted_events_ && event.mc()!=0) ' +\ - '__event_weight__ = event.mc()->weight();\n\n') - file.write(' if (sample.mc()!=0) sample.mc()->addWeightedEvents(__event_weight__);\n') - file.write(' Manager()->InitializeForNewEvent(__event_weight__);\n') - file.write('\n') + # file.write(' MAfloat32 __event_weight__ = 1.0;\n') + # file.write(' if (weighted_events_ && event.mc()!=0) ' +\ + # '__event_weight__ = event.mc()->weight();\n\n') + # file.write(' if (sample.mc()!=0) sample.mc()->addWeightedEvents(__event_weight__);\n') + # file.write(' Manager()->InitializeForNewEvent(__event_weight__);\n') + # file.write('\n') # Reseting instance name InstanceName.Clear() # Clearing and filling containers - WriteContainer(file,main,part_list) + WriteContainer(file, main, part_list) # Writing each step of the selection - WriteSelection(file,main,part_list) + WriteSelection(file, main, part_list) # End - file.write(' return true;\n') - file.write('}\n\n') + file.write(" return true;\n") + file.write("}\n\n") + -def WriteJobRank(part,file,rank,status,regions): +def WriteJobRank(part, file, rank, status, regions): - if part.PTrank==0: + if part.PTrank == 0: return # Skipping if already defined - if InstanceName.Find("PTRANK_"+part.name+rank+status): + if InstanceName.Find("PTRANK_" + part.name + rank + status): return - container=InstanceName.Get('P_'+part.name+rank+status+'_REG_'+'_'.join(regions)) + container = InstanceName.Get("P_" + part.name + rank + status + "_REG_" + "_".join(regions)) refpart = copy.copy(part) - refpart.PTrank=0 - newcontainer=InstanceName.Get('P_'+refpart.name+'PTordering'+status+'_REG_'+'_'.join(regions)); - - file.write(' // Sorting particle collection according to '+rank+'\n') - file.write(' // for getting '+str(part.PTrank)+'th particle\n') - file.write(' '+container+'=SORTER->rankFilter('+\ - newcontainer+','+str(part.PTrank)+','+rank+');\n\n') - - -def WriteCleanContainer(part,file,rank,status,regions): + refpart.PTrank = 0 + newcontainer = InstanceName.Get( + "P_" + refpart.name + "PTordering" + status + "_REG_" + "_".join(regions) + ) + + file.write(" // Sorting particle collection according to " + rank + "\n") + file.write(" // for getting " + str(part.PTrank) + "th particle\n") + file.write( + " " + + container + + "=SORTER->rankFilter(" + + newcontainer + + "," + + str(part.PTrank) + + "," + + rank + + ");\n\n" + ) + + +def WriteCleanContainer(part, file, rank, status, regions): # Skipping if already defined - if InstanceName.Find('P_'+part.name+rank+status+'_REG_'+'_'.join(regions)): + if InstanceName.Find("P_" + part.name + rank + status + "_REG_" + "_".join(regions)): return # Getting container name - container=InstanceName.Get('P_'+part.name+rank+status+'_REG_'+'_'.join(regions)) + container = InstanceName.Get("P_" + part.name + rank + status + "_REG_" + "_".join(regions)) # Getting id name - id='isP_'+InstanceName.Get(part.name+rank+status+'_REG_'+'_'.join(regions)) + id = "isP_" + InstanceName.Get(part.name + rank + status + "_REG_" + "_".join(regions)) - file.write(' ' + container + '.clear();\n') + file.write(" " + container + ".clear();\n") -def WriteFillContainer(part,file,rank,status,regions): +def WriteFillContainer(part, file, rank, status, regions): # If PTrank, no fill - if part.PTrank!=0: + if part.PTrank != 0: return # Skipping if already defined - if InstanceName.Find('P_'+part.name+rank+status+'_REG_'+'_'.join(regions)): + if InstanceName.Find("P_" + part.name + rank + status + "_REG_" + "_".join(regions)): return # Getting container name - container=InstanceName.Get('P_'+part.name+rank+status+'_REG_'+'_'.join(regions)) + container = InstanceName.Get("P_" + part.name + rank + status + "_REG_" + "_".join(regions)) # Getting id name - id='isP_'+InstanceName.Get(part.name+rank+status) + id = "isP_" + InstanceName.Get(part.name + rank + status) - file.write(' if ('+id+'((&(event.mc()->particles()[i])))) ' +\ - container + '.push_back(&(event.mc()->particles()[i]));\n') + file.write( + " if (" + + id + + "((&(event.mc()->particles()[i])))) " + + container + + ".push_back(&(event.mc()->particles()[i]));\n" + ) -def WriteFillWithJetContainer(part,file,rank,status,regions): +def WriteFillWithJetContainer(part, file, rank, status, regions): # If PTrank, no fill - if part.PTrank!=0: + if part.PTrank != 0: return # Skipping if already defined - if InstanceName.Find('P_'+part.name+rank+status+'_REG_'+'_'.join(regions)): + if InstanceName.Find("P_" + part.name + rank + status + "_REG_" + "_".join(regions)): return # Getting container name - container=InstanceName.Get('P_'+part.name+rank+status+'_REG_'+'_'.join(regions)) + container = InstanceName.Get("P_" + part.name + rank + status + "_REG_" + "_".join(regions)) # Put jet if part.particle.Find(21): - file.write(' '+container+\ - '.push_back(&(event.rec()->jets()[i]));\n') + file.write(" " + container + ".push_back(&(event.rec()->jets()[i]));\n") return # Put b jet if part.particle.Find(5): - file.write(' if (event.rec()->jets()[i].btag()) '+\ - container+'.push_back(&(event.rec()->jets()[i]));\n') + file.write( + " if (event.rec()->jets()[i].btag()) " + + container + + ".push_back(&(event.rec()->jets()[i]));\n" + ) # Put nb jet if part.particle.Find(1): - file.write(' if (!event.rec()->jets()[i].btag()) '+\ - container+'.push_back(&(event.rec()->jets()[i]));\n') + file.write( + " if (!event.rec()->jets()[i].btag()) " + + container + + ".push_back(&(event.rec()->jets()[i]));\n" + ) -def WriteFillWithElectronContainer(part,file,rank,status,regions): +def WriteFillWithElectronContainer(part, file, rank, status, regions): # If PTrank, no fill - if part.PTrank!=0: + if part.PTrank != 0: return # Skipping if already defined - if InstanceName.Find('P_'+part.name+rank+status+'_REG_'+'_'.join(regions)): + if InstanceName.Find("P_" + part.name + rank + status + "_REG_" + "_".join(regions)): return # Getting container name - container=InstanceName.Get('P_'+part.name+rank+status+'_REG_'+'_'.join(regions)) + container = InstanceName.Get("P_" + part.name + rank + status + "_REG_" + "_".join(regions)) # Put negative electron if part.particle.Find(11): - file.write(' if (event.rec()->electrons()[i].charge()<0) '+\ - container+'.push_back(&(event.rec()->electrons()[i]));\n') + file.write( + " if (event.rec()->electrons()[i].charge()<0) " + + container + + ".push_back(&(event.rec()->electrons()[i]));\n" + ) # Put positive electron if part.particle.Find(-11): - file.write(' if (event.rec()->electrons()[i].charge()>0) '+\ - container+'.push_back(&(event.rec()->electrons()[i]));\n') + file.write( + " if (event.rec()->electrons()[i].charge()>0) " + + container + + ".push_back(&(event.rec()->electrons()[i]));\n" + ) -def WriteFillWithPhotonContainer(part,file,rank,status,regions): +def WriteFillWithPhotonContainer(part, file, rank, status, regions): # If PTrank, no fill - if part.PTrank!=0: + if part.PTrank != 0: return # Skipping if already defined - if InstanceName.Find('P_'+part.name+rank+status+'_REG_'+'_'.join(regions)): + if InstanceName.Find("P_" + part.name + rank + status + "_REG_" + "_".join(regions)): return # Getting container name - container=InstanceName.Get('P_'+part.name+rank+status+'_REG_'+'_'.join(regions)) + container = InstanceName.Get("P_" + part.name + rank + status + "_REG_" + "_".join(regions)) # Put photon if part.particle.Find(22): - file.write(' '+container+'.push_back(&(event.rec()->photons()[i]));\n') + file.write(" " + container + ".push_back(&(event.rec()->photons()[i]));\n") -def WriteFillWithMuonContainer(part,file,rank,status,regions): +def WriteFillWithMuonContainer(part, file, rank, status, regions): # If PTrank, no fill - if part.PTrank!=0: + if part.PTrank != 0: return # Skipping if already defined - if InstanceName.Find('P_'+part.name+rank+status+'_REG_'+'_'.join(regions)): + if InstanceName.Find("P_" + part.name + rank + status + "_REG_" + "_".join(regions)): return # Getting container name - container=InstanceName.Get('P_'+part.name+rank+status+'_REG_'+'_'.join(regions)) + container = InstanceName.Get("P_" + part.name + rank + status + "_REG_" + "_".join(regions)) # Put negative muon if part.particle.Find(13): - file.write(' if (event.rec()->muons()[i].charge()<0) '+\ - container+'.push_back(&(event.rec()->muons()[i]));\n') + file.write( + " if (event.rec()->muons()[i].charge()<0) " + + container + + ".push_back(&(event.rec()->muons()[i]));\n" + ) # Put positive muon if part.particle.Find(-13): - file.write(' if (event.rec()->muons()[i].charge()>0) '+\ - container+'.push_back(&(event.rec()->muons()[i]));\n') + file.write( + " if (event.rec()->muons()[i].charge()>0) " + + container + + ".push_back(&(event.rec()->muons()[i]));\n" + ) # Put isolated negative muon if part.particle.Find(130): - file.write(' if ( (event.rec()->muons()[i].charge()<0) &&'+\ - ' PHYSICS->Id->IsIsolatedMuon(event.rec()->muons()[i],event.rec()) ) '+\ - container+'.push_back(&(event.rec()->muons()[i]));\n') + file.write( + " if ( (event.rec()->muons()[i].charge()<0) &&" + + " PHYSICS->Id->IsIsolatedMuon(event.rec()->muons()[i],event.rec()) ) " + + container + + ".push_back(&(event.rec()->muons()[i]));\n" + ) # Put isolated positive muon if part.particle.Find(-130): - file.write(' if ( (event.rec()->muons()[i].charge()>0) &&'+\ - ' PHYSICS->Id->IsIsolatedMuon(event.rec()->muons()[i],event.rec()) ) '+\ - container+'.push_back(&(event.rec()->muons()[i]));\n') + file.write( + " if ( (event.rec()->muons()[i].charge()>0) &&" + + " PHYSICS->Id->IsIsolatedMuon(event.rec()->muons()[i],event.rec()) ) " + + container + + ".push_back(&(event.rec()->muons()[i]));\n" + ) -def WriteFillWithTauContainer(part,file,rank,status,regions): +def WriteFillWithTauContainer(part, file, rank, status, regions): # If PTrank, no fill - if part.PTrank!=0: + if part.PTrank != 0: return # Skipping if already defined - if InstanceName.Find('P_'+part.name+rank+status+'_REG_'+'_'.join(regions)): + if InstanceName.Find("P_" + part.name + rank + status + "_REG_" + "_".join(regions)): return # Getting container name - container=InstanceName.Get('P_'+part.name+rank+status+'_REG_'+'_'.join(regions)) + container = InstanceName.Get("P_" + part.name + rank + status + "_REG_" + "_".join(regions)) # Put negative tau if part.particle.Find(15): - file.write(' if (event.rec()->taus()[i].charge()<0) '+\ - container+'.push_back(&(event.rec()->taus()[i]));\n') + file.write( + " if (event.rec()->taus()[i].charge()<0) " + + container + + ".push_back(&(event.rec()->taus()[i]));\n" + ) # Put positive tau if part.particle.Find(-15): - file.write(' if (event.rec()->taus()[i].charge()>0) '+\ - container+'.push_back(&(event.rec()->taus()[i]));\n') + file.write( + " if (event.rec()->taus()[i].charge()>0) " + + container + + ".push_back(&(event.rec()->taus()[i]));\n" + ) -def WriteFillWithMETContainer(part,file,rank,status,regions): + +def WriteFillWithMETContainer(part, file, rank, status, regions): # If PTrank, no fill - if part.PTrank!=0: + if part.PTrank != 0: return # Skipping if already defined - if InstanceName.Find('P_'+part.name+rank+status): + if InstanceName.Find("P_" + part.name + rank + status): return # Getting container name - container=InstanceName.Get('P_'+part.name+rank+status+'_REG_'+'_'.join(regions)) + container = InstanceName.Get("P_" + part.name + rank + status + "_REG_" + "_".join(regions)) # Put MET if part.particle.Find(100): - file.write(' '+container+\ - '.push_back(&(event.rec()->MET()));\n') + file.write(" " + container + ".push_back(&(event.rec()->MET()));\n") -def WriteFillWithMHTContainer(part,file,rank,status,regions): +def WriteFillWithMHTContainer(part, file, rank, status, regions): # If PTrank, no fill - if part.PTrank!=0: + if part.PTrank != 0: return # Skipping if already defined - if InstanceName.Find('P_'+part.name+rank+status): + if InstanceName.Find("P_" + part.name + rank + status): return # Getting container name - container=InstanceName.Get('P_'+part.name+rank+status+'_REG_'+'_'.join(regions)) + container = InstanceName.Get("P_" + part.name + rank + status + "_REG_" + "_".join(regions)) # Put MHT if part.particle.Find(99): - file.write(' '+container+\ - '.push_back(&(event.rec()->MHT()));\n') + file.write(" " + container + ".push_back(&(event.rec()->MHT()));\n") -def WriteFillWithMETContainerMC(part,file,rank,status,regions): +def WriteFillWithMETContainerMC(part, file, rank, status, regions): # If PTrank, no fill - if part.PTrank!=0: + if part.PTrank != 0: return # Skipping if already defined - if InstanceName.Find('P_'+part.name+rank+status): + if InstanceName.Find("P_" + part.name + rank + status): return # Getting container name - container=InstanceName.Get('P_'+part.name+rank+status+'_REG_'+'_'.join(regions)) + container = InstanceName.Get("P_" + part.name + rank + status + "_REG_" + "_".join(regions)) # Put MET if part.particle.Find(100): - file.write(' '+container+\ - '.push_back(&(event.mc()->MET()));\n') + file.write(" " + container + ".push_back(&(event.mc()->MET()));\n") + +def WriteFillWithMHTContainerMC(part, file, rank, status, regions): -def WriteFillWithMHTContainerMC(part,file,rank,status,regions): - # If PTrank, no fill - if part.PTrank!=0: + if part.PTrank != 0: return # Skipping if already defined - if InstanceName.Find('P_'+part.name+rank+status): + if InstanceName.Find("P_" + part.name + rank + status): return # Getting container name - container=InstanceName.Get('P_'+part.name+rank+status+'_REG_'+'_'.join(regions)) + container = InstanceName.Get("P_" + part.name + rank + status + "_REG_" + "_".join(regions)) # Put MHT if part.particle.Find(99): - file.write(' '+container+\ - '.push_back(&(event.mc()->MHT()));\n') + file.write(" " + container + ".push_back(&(event.mc()->MHT()));\n") -def WriteContainer(file,main,part_list): +def WriteContainer(file, main, part_list): # Skipping empty case - if len(part_list)==0: + if len(part_list) == 0: return # Cleaning particle containers - file.write(' // Clearing particle containers\n') - file.write(' {\n') + file.write(" // Clearing particle containers\n") + file.write(" {\n") for item in part_list: - WriteCleanContainer(item[0],file,item[1],item[2], item[3]) - file.write(' }\n') + WriteCleanContainer(item[0], file, item[1], item[2], item[3]) + file.write(" }\n") InstanceName.Clear() - file.write('\n') + file.write("\n") # Filling particle containers - file.write(' // Filling particle containers\n') - file.write(' {\n') + file.write(" // Filling particle containers\n") + file.write(" {\n") InstanceName.Clear() # Filling particle containers in PARTON and HADRON mode @@ -345,125 +389,126 @@ def WriteContainer(file,main,part_list): # Special particles : MET or MHT for item in part_list: if item[0].particle.Find(99) or item[0].particle.Find(100): - WriteFillWithMETContainerMC(item[0],file,item[1],item[2],item[3]) - WriteFillWithMHTContainerMC(item[0],file,item[1],item[2],item[3]) + WriteFillWithMETContainerMC(item[0], file, item[1], item[2], item[3]) + WriteFillWithMHTContainerMC(item[0], file, item[1], item[2], item[3]) # Ordinary particles - file.write(' for (MAuint32 i=0;i<event.mc()->particles().size();i++)\n') - file.write(' {\n') + file.write(" for (MAuint32 i=0;i<event.mc()->particles().size();i++)\n") + file.write(" {\n") for item in part_list: if item[0].particle.Find(99) or item[0].particle.Find(100): pass else: - WriteFillContainer(item[0],file,item[1],item[2],item[3]) - file.write(' }\n') + WriteFillContainer(item[0], file, item[1], item[2], item[3]) + file.write(" }\n") InstanceName.Clear() - # Filling particle containers in RECO mode + # Filling particle containers in RECO mode else: # Filling with jets - file.write(' for (MAuint32 i=0;i<event.rec()->jets().size();i++)\n') - file.write(' {\n') + file.write(" for (MAuint32 i=0;i<event.rec()->jets().size();i++)\n") + file.write(" {\n") for item in part_list: - WriteFillWithJetContainer(item[0],file,item[1],item[2],item[3]) - file.write(' }\n') + WriteFillWithJetContainer(item[0], file, item[1], item[2], item[3]) + file.write(" }\n") InstanceName.Clear() # Filling with photons - file.write(' for (MAuint32 i=0;i<event.rec()->photons().size();i++)\n') - file.write(' {\n') + file.write(" for (MAuint32 i=0;i<event.rec()->photons().size();i++)\n") + file.write(" {\n") for item in part_list: - WriteFillWithPhotonContainer(item[0],file,item[1],item[2],item[3]) - file.write(' }\n') + WriteFillWithPhotonContainer(item[0], file, item[1], item[2], item[3]) + file.write(" }\n") InstanceName.Clear() # Filling with electrons - file.write(' for (MAuint32 i=0;i<event.rec()->electrons().size();i++)\n') - file.write(' {\n') + file.write(" for (MAuint32 i=0;i<event.rec()->electrons().size();i++)\n") + file.write(" {\n") for item in part_list: - WriteFillWithElectronContainer(item[0],file,item[1],item[2],item[3]) - file.write(' }\n') + WriteFillWithElectronContainer(item[0], file, item[1], item[2], item[3]) + file.write(" }\n") InstanceName.Clear() # Filling with muons - file.write(' for (MAuint32 i=0;i<event.rec()->muons().size();i++)\n') - file.write(' {\n') + file.write(" for (MAuint32 i=0;i<event.rec()->muons().size();i++)\n") + file.write(" {\n") for item in part_list: - WriteFillWithMuonContainer(item[0],file,item[1],item[2],item[3]) - file.write(' }\n') + WriteFillWithMuonContainer(item[0], file, item[1], item[2], item[3]) + file.write(" }\n") InstanceName.Clear() # Filling with taus - file.write(' for (MAuint32 i=0;i<event.rec()->taus().size();i++)\n') - file.write(' {\n') + file.write(" for (MAuint32 i=0;i<event.rec()->taus().size();i++)\n") + file.write(" {\n") for item in part_list: - WriteFillWithTauContainer(item[0],file,item[1],item[2],item[3]) - file.write(' }\n') + WriteFillWithTauContainer(item[0], file, item[1], item[2], item[3]) + file.write(" }\n") InstanceName.Clear() # Filling with MET - file.write(' {\n') + file.write(" {\n") for item in part_list: - WriteFillWithMETContainer(item[0],file,item[1],item[2],item[3]) - file.write(' }\n') + WriteFillWithMETContainer(item[0], file, item[1], item[2], item[3]) + file.write(" }\n") InstanceName.Clear() # Filling with MHT - file.write(' {\n') + file.write(" {\n") for item in part_list: - WriteFillWithMHTContainer(item[0],file,item[1],item[2],item[3]) - file.write(' }\n') + WriteFillWithMHTContainer(item[0], file, item[1], item[2], item[3]) + file.write(" }\n") InstanceName.Clear() - file.write(' }\n\n') + file.write(" }\n\n") # Managing PT rank - file.write(' // Sorting particles\n') + file.write(" // Sorting particles\n") for item in part_list: - WriteJobRank(item[0],file,item[1],item[2],item[3]) + WriteJobRank(item[0], file, item[1], item[2], item[3]) InstanceName.Clear() -def WriteSelection(file,main,part_list): +def WriteSelection(file, main, part_list): - import madanalysis.job.job_plot as JobPlot - import madanalysis.job.job_event_cut as JobEventCut + import madanalysis.job.job_plot as JobPlot + import madanalysis.job.job_event_cut as JobEventCut import madanalysis.job.job_candidate_cut as JobCandidateCut # Loop over histogram and cut - ihisto = 1 - icut = 1 + ihisto = 1 + icut = 1 iobject = 1 for iabs in range(len(main.selection.table)): - logging.getLogger('MA5').debug("--------------------------------------------") - logging.getLogger('MA5').debug("SELECTION STEP "+str(iabs)+": "+main.selection[iabs].GetStringDisplay()) + logging.getLogger("MA5").debug("--------------------------------------------") + logging.getLogger("MA5").debug( + "SELECTION STEP " + str(iabs) + ": " + main.selection[iabs].GetStringDisplay() + ) - if main.selection[iabs].__class__.__name__=="Histogram": - logging.getLogger('MA5').debug("- selection step = histogram") - file.write(' // Histogram number '+str(ihisto)+'\n') - file.write(' // '+main.selection[iabs].GetStringDisplay()+'\n') - JobPlot.WritePlot(file,main,iabs,ihisto) - ihisto+=1 + if main.selection[iabs].__class__.__name__ == "Histogram": + logging.getLogger("MA5").debug("- selection step = histogram") + file.write(" // Histogram number " + str(ihisto) + "\n") + file.write(" // " + main.selection[iabs].GetStringDisplay() + "\n") + JobPlot.WritePlot(file, main, iabs, ihisto) + ihisto += 1 - elif main.selection[iabs].__class__.__name__=="Cut": + elif main.selection[iabs].__class__.__name__ == "Cut": # Event cut - if len(main.selection[iabs].part)==0: - logging.getLogger('MA5').debug("- selection step = cut on event") - file.write(' // Event selection number '+str(icut)+'\n') - file.write(' // '+main.selection[iabs].GetStringDisplay()+'\n') - JobEventCut.WriteEventCut(file,main,iabs,icut) - icut+=1 + if len(main.selection[iabs].part) == 0: + logging.getLogger("MA5").debug("- selection step = cut on event") + file.write(" // Event selection number " + str(icut) + "\n") + file.write(" // " + main.selection[iabs].GetStringDisplay() + "\n") + JobEventCut.WriteEventCut(file, main, iabs, icut) + icut += 1 # Candidate cut else: - logging.getLogger('MA5').debug("- selection step = cut on candidate") - file.write(' // Object selection number '+str(iobject)+'\n') - file.write(' // '+main.selection[iabs].GetStringDisplay()+'\n') - JobCandidateCut.WriteCandidateCut(file,main,iabs,part_list) - iobject+=1 - - file.write('\n') - logging.getLogger('MA5').debug("--------------------------------------------") - + logging.getLogger("MA5").debug("- selection step = cut on candidate") + file.write(" // Object selection number " + str(iobject) + "\n") + file.write(" // " + main.selection[iabs].GetStringDisplay() + "\n") + JobCandidateCut.WriteCandidateCut(file, main, iabs, part_list) + iobject += 1 + + file.write("\n") + logging.getLogger("MA5").debug("--------------------------------------------") diff --git a/madanalysis/misc/run_recast.py b/madanalysis/misc/run_recast.py index 0b7a999c..8ab83d9b 100644 --- a/madanalysis/misc/run_recast.py +++ b/madanalysis/misc/run_recast.py @@ -416,6 +416,7 @@ def run_SimplifiedFastSim(self,dataset,card,analysislist): ignore=True if self.main.recasting.store_events: newfile.write(' writer1->WriteEvent(myEvent,mySample);\n') + newfile.write(' manager.PrepareForExecution(mySample, myEvent);\n') for analysis in analysislist: newfile.write(' if (!analyzer_'+analysis+'->Execute(mySample,myEvent)) continue;\n') if self.TACO_output!='': From ef9177c929c00d3d82a340e421918886719f4310 Mon Sep 17 00:00:00 2001 From: "Jack Y. Araz" <jackaraz@gmail.com> Date: Wed, 28 Jun 2023 10:55:22 +0100 Subject: [PATCH 015/107] bug fix in initialisation --- tools/SampleAnalyzer/Process/Plot/Histo.cpp | 38 ++-- tools/SampleAnalyzer/Process/Plot/Histo.h | 9 +- .../Process/Plot/HistoFrequency.h | 15 +- .../SampleAnalyzer/Process/Plot/HistoLogX.cpp | 1 - tools/SampleAnalyzer/Process/Plot/HistoLogX.h | 3 + tools/SampleAnalyzer/Process/Plot/PlotBase.h | 16 +- .../SampleAnalyzer/Process/Plot/PlotManager.h | 209 +++++++++--------- .../RegionSelectionManager.cpp | 1 + .../RegionSelection/RegionSelectionManager.h | 2 +- 9 files changed, 138 insertions(+), 156 deletions(-) diff --git a/tools/SampleAnalyzer/Process/Plot/Histo.cpp b/tools/SampleAnalyzer/Process/Plot/Histo.cpp index 04fe88f7..056758cc 100644 --- a/tools/SampleAnalyzer/Process/Plot/Histo.cpp +++ b/tools/SampleAnalyzer/Process/Plot/Histo.cpp @@ -192,37 +192,33 @@ void Histo::Write_TextFormatBody(std::ostream *output) /// @brief Initialise the containers /// @param weights weight collection -void Histo::Initialise(const WeightCollection &weights) +void Histo::_initialize(const WeightCollection &weights) { - if (!initialised_) + for (auto &w : weights.GetWeights()) { - for (auto &w : weights.GetWeights()) + MAint32 idx = w.first; + for (MAuint16 i = 0; i < nbins_; i++) { - MAint32 idx = w.first; - for (MAuint16 i = 0; i < nbins_; i++) - { - std::map<MAint32, WEIGHTS> current; - current[idx] = WEIGHTS(); - if (histo_.size() < i) - histo_.push_back(current); - else - histo_[i] = current; - } - underflow_[idx] = WEIGHTS(); - overflow_[idx] = WEIGHTS(); - sum_w_[idx] = WEIGHTS(); - sum_ww_[idx] = WEIGHTS(); - sum_xw_[idx] = WEIGHTS(); - sum_xxw_[idx] = WEIGHTS(); + std::map<MAint32, WEIGHTS> current; + current[idx] = WEIGHTS(); + if (histo_.size() < i) + histo_.push_back(current); + else + histo_[i] = current; } - initialised_ = true; + underflow_[idx] = WEIGHTS(); + overflow_[idx] = WEIGHTS(); + sum_w_[idx] = WEIGHTS(); + sum_ww_[idx] = WEIGHTS(); + sum_xw_[idx] = WEIGHTS(); + sum_xxw_[idx] = WEIGHTS(); } } /// Filling histogram void Histo::Fill(MAfloat64 value, const WeightCollection &weights) { - Initialise(weights); + Initialize(weights); // Safety : nan or isinf try { diff --git a/tools/SampleAnalyzer/Process/Plot/Histo.h b/tools/SampleAnalyzer/Process/Plot/Histo.h index cbd68b10..08b9d8d9 100644 --- a/tools/SampleAnalyzer/Process/Plot/Histo.h +++ b/tools/SampleAnalyzer/Process/Plot/Histo.h @@ -75,9 +75,6 @@ namespace MA5 /// RegionSelections attached to the histo std::vector<RegionSelection *> regions_; - /// @brief If the class is initialised or not - MAbool initialised_; - // ------------------------------------------------------------- // method members // ------------------------------------------------------------- @@ -89,7 +86,6 @@ namespace MA5 xmin_ = 0; xmax_ = 100; step_ = (xmax_ - xmin_) / static_cast<MAfloat64>(nbins_); - initialised_ = false; } /// Constructor with argument @@ -98,7 +94,6 @@ namespace MA5 /// Constructor with argument Histo(const std::string &name, MAuint32 nbins, MAfloat64 xmin, MAfloat64 xmax) : PlotBase(name) { - initialised_ = false; // Setting the description: nbins try { @@ -160,7 +155,9 @@ namespace MA5 } /// Initialise the class - void Initialise(const WeightCollection &weights); + /// @brief Initialise the containers + /// @param weights weight collection + virtual void _initialize(const WeightCollection &multiweight); /// Filling histogram void Fill(MAfloat64 value, const WeightCollection &weights); diff --git a/tools/SampleAnalyzer/Process/Plot/HistoFrequency.h b/tools/SampleAnalyzer/Process/Plot/HistoFrequency.h index f6d72940..7aeecf48 100644 --- a/tools/SampleAnalyzer/Process/Plot/HistoFrequency.h +++ b/tools/SampleAnalyzer/Process/Plot/HistoFrequency.h @@ -52,9 +52,6 @@ namespace MA5 /// RegionSelections attached to the histo std::vector<RegionSelection *> regions_; - /// @brief is the class initialised - MAbool initialised_; - // ------------------------------------------------------------- // method members // ------------------------------------------------------------- @@ -70,14 +67,10 @@ namespace MA5 /// Destructor virtual ~HistoFrequency() {} - void initialise_weights(const WeightCollection &multiweight) + void _initialize(const WeightCollection &multiweight) { - if (!initialised_) - { - for (auto &weight : multiweight.GetWeights()) - sum_w_[weight.first] = WEIGHTS(); - initialised_ = true; - } + for (auto &weight : multiweight.GetWeights()) + sum_w_[weight.first] = WEIGHTS(); } /// Setting the linked regions @@ -107,8 +100,6 @@ namespace MA5 /// Adding an entry for a given observable void Fill(const MAint32 &obs, WeightCollection &weights) { - - initialise_weights(weights); for (auto &weight : weights.GetWeights()) { MAint32 idx = weight.first; diff --git a/tools/SampleAnalyzer/Process/Plot/HistoLogX.cpp b/tools/SampleAnalyzer/Process/Plot/HistoLogX.cpp index 6b677fca..0bbc2347 100644 --- a/tools/SampleAnalyzer/Process/Plot/HistoLogX.cpp +++ b/tools/SampleAnalyzer/Process/Plot/HistoLogX.cpp @@ -42,7 +42,6 @@ void HistoLogX::Write_TextFormat(std::ostream *output) void HistoLogX::Fill(MAfloat64 value, const WeightCollection &weights) { - Initialise(weights); // Safety : nan or isinf try { diff --git a/tools/SampleAnalyzer/Process/Plot/HistoLogX.h b/tools/SampleAnalyzer/Process/Plot/HistoLogX.h index a7135669..d61c9e39 100644 --- a/tools/SampleAnalyzer/Process/Plot/HistoLogX.h +++ b/tools/SampleAnalyzer/Process/Plot/HistoLogX.h @@ -113,6 +113,9 @@ namespace MA5 /// Write the plot in a Text file virtual void Write_TextFormat(std::ostream *output); + + /// @brief initialise the class + virtual void _initialize(const WeightCollection &weights) {} }; } diff --git a/tools/SampleAnalyzer/Process/Plot/PlotBase.h b/tools/SampleAnalyzer/Process/Plot/PlotBase.h index c9ac5030..e44a4dc8 100644 --- a/tools/SampleAnalyzer/Process/Plot/PlotBase.h +++ b/tools/SampleAnalyzer/Process/Plot/PlotBase.h @@ -90,24 +90,31 @@ namespace MA5 MAbool FreshEvent() { return fresh_event_; } /// Modifier for fresh_event - void SetFreshEvent(MAbool tag) { fresh_event_ = tag; } + void SetFreshEvent(MAbool tag, const WeightCollection &EventWeight) + { + Initialize(EventWeight); + fresh_event_ = tag; + } /// Write the plot in a ROOT file virtual void Write_TextFormat(std::ostream *output) = 0; + /// @brief Initialiser for the classes that inherits this class + virtual void _initialize(const WeightCollection &multiweight) = 0; + /// @brief Initialise the containers /// @param multiweight multiweight collection - void Initialise(const WeightCollection &multiweight) + void Initialize(const WeightCollection &multiweight) { if (!initialised_) { for (auto &weight : multiweight.GetWeights()) { - nevents_[weight.first] = ENTRIES(); nentries_[weight.first] = ENTRIES(); nevents_w_[weight.first] = WEIGHTS(); } + _initialize(multiweight); initialised_ = true; } } @@ -115,7 +122,6 @@ namespace MA5 /// Increment number of events void IncrementNEvents(const WeightCollection &weights) { - Initialise(weights); for (auto &weight : weights.GetWeights()) { MAint32 idx = weight.first; @@ -131,7 +137,7 @@ namespace MA5 nevents_w_[idx].negative += std::fabs(w); } } - SetFreshEvent(false); + SetFreshEvent(false, weights); } /// Return Number of events diff --git a/tools/SampleAnalyzer/Process/Plot/PlotManager.h b/tools/SampleAnalyzer/Process/Plot/PlotManager.h index 1e86b082..e6023e98 100644 --- a/tools/SampleAnalyzer/Process/Plot/PlotManager.h +++ b/tools/SampleAnalyzer/Process/Plot/PlotManager.h @@ -1,31 +1,29 @@ //////////////////////////////////////////////////////////////////////////////// -// +// // Copyright (C) 2012-2023 Jack Araz, Eric Conte & Benjamin Fuks // The MadAnalysis development team, email: <ma5team@iphc.cnrs.fr> -// +// // This file is part of MadAnalysis 5. // Official website: <https://github.com/MadAnalysis/madanalysis5> -// +// // MadAnalysis 5 is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // MadAnalysis 5 is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with MadAnalysis 5. If not, see <http://www.gnu.org/licenses/> -// +// //////////////////////////////////////////////////////////////////////////////// - #ifndef PLOT_MANAGER_H #define PLOT_MANAGER_H - // STL headers #include <iostream> #include <ostream> @@ -39,111 +37,102 @@ #include "SampleAnalyzer/Process/Writer/SAFWriter.h" #include "SampleAnalyzer/Process/RegionSelection/RegionSelection.h" - namespace MA5 { -class PlotManager -{ - - // ------------------------------------------------------------- - // data members - // ------------------------------------------------------------- - protected : - - /// Collection of plots - std::vector<PlotBase*> plots_; - - - // ------------------------------------------------------------- - // method members - // ------------------------------------------------------------- - public : - - /// Constructor without argument - PlotManager() - { } - - /// Destructor - ~PlotManager() - { } - - /// Reset - void Reset() - { - for (MAuint32 i=0;i<plots_.size();i++) - { if (plots_[i]!=0) delete plots_[i]; } - plots_.clear(); - } - - /// Get method - std::vector<PlotBase*> GetHistos() - { return plots_; } - - /// Getting thenumber of plots - MAuint32 GetNplots() - { return plots_.size(); } - - /// Adding a 1D histogram with fixed bins - Histo* Add_Histo(const std::string& name, MAuint32 bins, - MAfloat64 xmin, MAfloat64 xmax) - { - Histo* myhisto = new Histo(name, bins, xmin, xmax); - plots_.push_back(myhisto); - return myhisto; - } - - Histo* Add_Histo(const std::string& name, MAuint32 bins, - MAfloat64 xmin, MAfloat64 xmax, std::vector<RegionSelection*> regions) - { - Histo* myhisto = new Histo(name, bins, xmin, xmax); - myhisto->SetSelectionRegions(regions); - plots_.push_back(myhisto); - return myhisto; - } - - /// Adding a 1D histogram with a log binning - HistoLogX* Add_HistoLogX(const std::string& name, MAuint32 bins, - MAfloat64 xmin, MAfloat64 xmax) - { - HistoLogX* myhisto = new HistoLogX(name, bins, xmin, xmax); - plots_.push_back(myhisto); - return myhisto; - } - - HistoLogX* Add_HistoLogX(const std::string& name, MAuint32 bins, - MAfloat64 xmin, MAfloat64 xmax, std::vector<RegionSelection*> regions) - { - HistoLogX* myhisto = new HistoLogX(name, bins, xmin, xmax); - myhisto->SetSelectionRegions(regions); - plots_.push_back(myhisto); - return myhisto; - } - - /// Adding a 1D histogram for frequency - HistoFrequency* Add_HistoFrequency(const std::string& name) - { - HistoFrequency* myhisto = new HistoFrequency(name); - plots_.push_back(myhisto); - return myhisto; - } - - HistoFrequency* Add_HistoFrequency(const std::string& name, std::vector<RegionSelection*> regions) - { - HistoFrequency* myhisto = new HistoFrequency(name); - myhisto->SetSelectionRegions(regions); - plots_.push_back(myhisto); - return myhisto; - } - - /// Write the counters in a Text file - void Write_TextFormat(SAFWriter& output); - - /// Finalizing - void Finalize() - { Reset(); } - -}; + class PlotManager + { + + // ------------------------------------------------------------- + // data members + // ------------------------------------------------------------- + protected: + /// Collection of plots + std::vector<PlotBase *> plots_; + + // ------------------------------------------------------------- + // method members + // ------------------------------------------------------------- + public: + /// Constructor without argument + PlotManager() {} + + /// Destructor + ~PlotManager() {} + + /// Reset + void Reset() + { + for (MAuint32 i = 0; i < plots_.size(); i++) + if (plots_[i] != 0) + delete plots_[i]; + plots_.clear(); + } + + /// Get method + std::vector<PlotBase *> GetHistos() { return plots_; } + + /// Getting thenumber of plots + MAuint32 GetNplots() { return plots_.size(); } + + /// Adding a 1D histogram with fixed bins + Histo *Add_Histo(const std::string &name, MAuint32 bins, + MAfloat64 xmin, MAfloat64 xmax) + { + Histo *myhisto = new Histo(name, bins, xmin, xmax); + plots_.push_back(myhisto); + return myhisto; + } + + Histo *Add_Histo(const std::string &name, MAuint32 bins, + MAfloat64 xmin, MAfloat64 xmax, std::vector<RegionSelection *> regions) + { + Histo *myhisto = new Histo(name, bins, xmin, xmax); + myhisto->SetSelectionRegions(regions); + plots_.push_back(myhisto); + return myhisto; + } + + /// Adding a 1D histogram with a log binning + HistoLogX *Add_HistoLogX(const std::string &name, MAuint32 bins, + MAfloat64 xmin, MAfloat64 xmax) + { + HistoLogX *myhisto = new HistoLogX(name, bins, xmin, xmax); + plots_.push_back(myhisto); + return myhisto; + } + + HistoLogX *Add_HistoLogX(const std::string &name, MAuint32 bins, + MAfloat64 xmin, MAfloat64 xmax, std::vector<RegionSelection *> regions) + { + HistoLogX *myhisto = new HistoLogX(name, bins, xmin, xmax); + myhisto->SetSelectionRegions(regions); + plots_.push_back(myhisto); + return myhisto; + } + + /// Adding a 1D histogram for frequency + HistoFrequency *Add_HistoFrequency(const std::string &name) + { + HistoFrequency *myhisto = new HistoFrequency(name); + plots_.push_back(myhisto); + return myhisto; + } + + HistoFrequency *Add_HistoFrequency(const std::string &name, std::vector<RegionSelection *> regions) + { + HistoFrequency *myhisto = new HistoFrequency(name); + myhisto->SetSelectionRegions(regions); + plots_.push_back(myhisto); + return myhisto; + } + + /// Write the counters in a Text file + void Write_TextFormat(SAFWriter &output); + + /// Finalizing + void Finalize() { Reset(); } + }; } diff --git a/tools/SampleAnalyzer/Process/RegionSelection/RegionSelectionManager.cpp b/tools/SampleAnalyzer/Process/RegionSelection/RegionSelectionManager.cpp index ecdf8fb0..dd7a78ab 100644 --- a/tools/SampleAnalyzer/Process/RegionSelection/RegionSelectionManager.cpp +++ b/tools/SampleAnalyzer/Process/RegionSelection/RegionSelectionManager.cpp @@ -110,6 +110,7 @@ void RegionSelectionManager::FillHisto(std::string const &histname, MAfloat64 va if (dynamic_cast<HistoFrequency *>(plotmanager_.GetHistos()[i]) != 0) { myhistof = dynamic_cast<HistoFrequency *>(plotmanager_.GetHistos()[i]); + if (myhistof->AllSurviving() == 0) return; try diff --git a/tools/SampleAnalyzer/Process/RegionSelection/RegionSelectionManager.h b/tools/SampleAnalyzer/Process/RegionSelection/RegionSelectionManager.h index faf93718..8a113f22 100644 --- a/tools/SampleAnalyzer/Process/RegionSelection/RegionSelectionManager.h +++ b/tools/SampleAnalyzer/Process/RegionSelection/RegionSelectionManager.h @@ -144,7 +144,7 @@ namespace MA5 for (auto ® : regions_) reg->InitializeForNewEvent(EventWeight); for (MAuint32 i = 0; i < plotmanager_.GetNplots(); i++) - plotmanager_.GetHistos()[i]->SetFreshEvent(true); + plotmanager_.GetHistos()[i]->SetFreshEvent(true, EventWeight); } /// This method associates all regions with a cut From fd84f092eda287524e30a2501431af1529ccbe4e Mon Sep 17 00:00:00 2001 From: "Jack Y. Araz" <jackaraz@gmail.com> Date: Wed, 28 Jun 2023 11:29:15 +0100 Subject: [PATCH 016/107] bugfix in histogramming --- tools/SampleAnalyzer/Process/Plot/Histo.cpp | 18 ++++-------------- tools/SampleAnalyzer/Process/Plot/Histo.h | 2 +- 2 files changed, 5 insertions(+), 15 deletions(-) diff --git a/tools/SampleAnalyzer/Process/Plot/Histo.cpp b/tools/SampleAnalyzer/Process/Plot/Histo.cpp index 056758cc..96b804fc 100644 --- a/tools/SampleAnalyzer/Process/Plot/Histo.cpp +++ b/tools/SampleAnalyzer/Process/Plot/Histo.cpp @@ -194,18 +194,11 @@ void Histo::Write_TextFormatBody(std::ostream *output) /// @param weights weight collection void Histo::_initialize(const WeightCollection &weights) { + std::map<MAint32, WEIGHTS> current; for (auto &w : weights.GetWeights()) { MAint32 idx = w.first; - for (MAuint16 i = 0; i < nbins_; i++) - { - std::map<MAint32, WEIGHTS> current; - current[idx] = WEIGHTS(); - if (histo_.size() < i) - histo_.push_back(current); - else - histo_[i] = current; - } + current[idx] = WEIGHTS(); underflow_[idx] = WEIGHTS(); overflow_[idx] = WEIGHTS(); sum_w_[idx] = WEIGHTS(); @@ -213,12 +206,13 @@ void Histo::_initialize(const WeightCollection &weights) sum_xw_[idx] = WEIGHTS(); sum_xxw_[idx] = WEIGHTS(); } + for (MAuint16 i = 0; i < nbins_; i++) + histo_.push_back(current); } /// Filling histogram void Histo::Fill(MAfloat64 value, const WeightCollection &weights) { - Initialize(weights); // Safety : nan or isinf try { @@ -249,9 +243,7 @@ void Histo::Fill(MAfloat64 value, const WeightCollection &weights) else if (value >= xmax_) overflow_[idx].positive += weight; else - { histo_[std::floor((value - xmin_) / step_)][idx].positive += weight; - } } // Negative weight @@ -268,9 +260,7 @@ void Histo::Fill(MAfloat64 value, const WeightCollection &weights) else if (value >= xmax_) overflow_[idx].negative += pw; else - { histo_[std::floor((value - xmin_) / step_)][idx].negative += pw; - } } } } diff --git a/tools/SampleAnalyzer/Process/Plot/Histo.h b/tools/SampleAnalyzer/Process/Plot/Histo.h index 08b9d8d9..e4388a60 100644 --- a/tools/SampleAnalyzer/Process/Plot/Histo.h +++ b/tools/SampleAnalyzer/Process/Plot/Histo.h @@ -124,7 +124,7 @@ namespace MA5 step_ = (xmax_ - xmin_) / static_cast<MAfloat64>(nbins_); - histo_.resize(nbins_); + // histo_.resize(nbins_); } /// Destructor From c12766def9dc706f90dedabc255ad51cfc6c9d53 Mon Sep 17 00:00:00 2001 From: "Jack Y. Araz" <jackaraz@gmail.com> Date: Thu, 29 Jun 2023 12:09:56 +0100 Subject: [PATCH 017/107] change basics to histo structures --- tools/SampleAnalyzer/Commons/Base/{Basics.h => HistoStructures.h} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tools/SampleAnalyzer/Commons/Base/{Basics.h => HistoStructures.h} (100%) diff --git a/tools/SampleAnalyzer/Commons/Base/Basics.h b/tools/SampleAnalyzer/Commons/Base/HistoStructures.h similarity index 100% rename from tools/SampleAnalyzer/Commons/Base/Basics.h rename to tools/SampleAnalyzer/Commons/Base/HistoStructures.h From 32fc38407ea0548512ec13b75ad602921ce80410 Mon Sep 17 00:00:00 2001 From: "Jack Y. Araz" <jackaraz@gmail.com> Date: Thu, 29 Jun 2023 12:51:21 +0100 Subject: [PATCH 018/107] update basics.h --- tools/SampleAnalyzer/Process/Counter/Counter.h | 2 +- tools/SampleAnalyzer/Process/Plot/Histo.h | 1 - tools/SampleAnalyzer/Process/Plot/HistoFrequency.h | 1 - tools/SampleAnalyzer/Process/Plot/PlotBase.h | 2 +- 4 files changed, 2 insertions(+), 4 deletions(-) diff --git a/tools/SampleAnalyzer/Process/Counter/Counter.h b/tools/SampleAnalyzer/Process/Counter/Counter.h index 1be99bad..c52d7a00 100644 --- a/tools/SampleAnalyzer/Process/Counter/Counter.h +++ b/tools/SampleAnalyzer/Process/Counter/Counter.h @@ -26,7 +26,7 @@ // SampleAnalyzer headers #include "SampleAnalyzer/Commons/Base/PortableDatatypes.h" -#include "SampleAnalyzer/Commons/Base/Basics.h" +#include "SampleAnalyzer/Commons/Base/HistoStructures.h" #include "SampleAnalyzer/Commons/DataFormat/WeightCollection.h" // STL headers diff --git a/tools/SampleAnalyzer/Process/Plot/Histo.h b/tools/SampleAnalyzer/Process/Plot/Histo.h index e4388a60..82c46b7c 100644 --- a/tools/SampleAnalyzer/Process/Plot/Histo.h +++ b/tools/SampleAnalyzer/Process/Plot/Histo.h @@ -33,7 +33,6 @@ #include "SampleAnalyzer/Process/Plot/PlotBase.h" #include "SampleAnalyzer/Process/RegionSelection/RegionSelection.h" #include "SampleAnalyzer/Commons/Service/ExceptionService.h" -#include "SampleAnalyzer/Commons/Base/Basics.h" namespace MA5 { diff --git a/tools/SampleAnalyzer/Process/Plot/HistoFrequency.h b/tools/SampleAnalyzer/Process/Plot/HistoFrequency.h index 7aeecf48..4993e1ac 100644 --- a/tools/SampleAnalyzer/Process/Plot/HistoFrequency.h +++ b/tools/SampleAnalyzer/Process/Plot/HistoFrequency.h @@ -31,7 +31,6 @@ // SampleAnalyzer headers #include "SampleAnalyzer/Process/Plot/PlotBase.h" -#include "SampleAnalyzer/Commons/Base/Basics.h" namespace MA5 { diff --git a/tools/SampleAnalyzer/Process/Plot/PlotBase.h b/tools/SampleAnalyzer/Process/Plot/PlotBase.h index e44a4dc8..fa08dd54 100644 --- a/tools/SampleAnalyzer/Process/Plot/PlotBase.h +++ b/tools/SampleAnalyzer/Process/Plot/PlotBase.h @@ -32,7 +32,7 @@ // SampleAnalyzer headers #include "SampleAnalyzer/Commons/Service/LogService.h" -#include "SampleAnalyzer/Commons/Base/Basics.h" +#include "SampleAnalyzer/Commons/Base/HistoStructures.h" #include "SampleAnalyzer/Commons/DataFormat/WeightCollection.h" namespace MA5 From 8c3553bab980acc17b9d81e3df75d77600cc744c Mon Sep 17 00:00:00 2001 From: "Jack Y. Araz" <jackaraz@gmail.com> Date: Thu, 29 Jun 2023 13:04:24 +0100 Subject: [PATCH 019/107] remove `weight_definition_` --- tools/SampleAnalyzer/Commons/DataFormat/MCSampleFormat.h | 1 - 1 file changed, 1 deletion(-) diff --git a/tools/SampleAnalyzer/Commons/DataFormat/MCSampleFormat.h b/tools/SampleAnalyzer/Commons/DataFormat/MCSampleFormat.h index 95f3d74f..b8b4b560 100644 --- a/tools/SampleAnalyzer/Commons/DataFormat/MCSampleFormat.h +++ b/tools/SampleAnalyzer/Commons/DataFormat/MCSampleFormat.h @@ -76,7 +76,6 @@ namespace MA5 // ----------------------- multiweights ------------------------ /// @jackaraz: not sure if this is doing anything - WeightDefinition weight_definition_; /// @brief store weight names std::map<int, std::string> weight_names_; From e95b46a7bed268bcd03c1e3231d764f6c492ba80 Mon Sep 17 00:00:00 2001 From: "Jack Y. Araz" <jackaraz@gmail.com> Date: Thu, 29 Jun 2023 13:04:46 +0100 Subject: [PATCH 020/107] remove `weight_definition_` --- tools/SampleAnalyzer/Commons/DataFormat/MCSampleFormat.h | 1 - 1 file changed, 1 deletion(-) diff --git a/tools/SampleAnalyzer/Commons/DataFormat/MCSampleFormat.h b/tools/SampleAnalyzer/Commons/DataFormat/MCSampleFormat.h index b8b4b560..0605dade 100644 --- a/tools/SampleAnalyzer/Commons/DataFormat/MCSampleFormat.h +++ b/tools/SampleAnalyzer/Commons/DataFormat/MCSampleFormat.h @@ -113,7 +113,6 @@ namespace MA5 energy_unit_ = 1.0; // WeightDefinition - weight_definition_.Reset(); weight_names_.clear(); // File info From 4aa439d8a46cd82f174f2bdcc53b396514070048 Mon Sep 17 00:00:00 2001 From: "Jack Y. Araz" <jackaraz@gmail.com> Date: Thu, 29 Jun 2023 13:05:22 +0100 Subject: [PATCH 021/107] update exception --- tools/SampleAnalyzer/Commons/DataFormat/WeightCollection.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/SampleAnalyzer/Commons/DataFormat/WeightCollection.h b/tools/SampleAnalyzer/Commons/DataFormat/WeightCollection.h index a72fe76a..02f1ead8 100644 --- a/tools/SampleAnalyzer/Commons/DataFormat/WeightCollection.h +++ b/tools/SampleAnalyzer/Commons/DataFormat/WeightCollection.h @@ -103,7 +103,7 @@ namespace MA5 std::string idname; str >> idname; throw EXCEPTION_WARNING("The Weight '" + idname + - "' is defined at two times. Redundant values are skipped.", + "' is defined at twice. Redundant values are skipped.", "", 0); } } From 9ad2634e1beccf10e72e2615fe0a7a5b42befbeb Mon Sep 17 00:00:00 2001 From: "Jack Y. Araz" <jackaraz@gmail.com> Date: Thu, 29 Jun 2023 13:05:42 +0100 Subject: [PATCH 022/107] update exception text --- tools/SampleAnalyzer/Commons/DataFormat/WeightCollection.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/SampleAnalyzer/Commons/DataFormat/WeightCollection.h b/tools/SampleAnalyzer/Commons/DataFormat/WeightCollection.h index 02f1ead8..6cd44b45 100644 --- a/tools/SampleAnalyzer/Commons/DataFormat/WeightCollection.h +++ b/tools/SampleAnalyzer/Commons/DataFormat/WeightCollection.h @@ -133,7 +133,7 @@ namespace MA5 std::string idname; str >> idname; throw EXCEPTION_ERROR("The Weight '" + idname + - "' is not defined. Return null value.", + "' is not defined. A null value is returned.", "", 0); } } From 55da958402ae01093c4ad7d4e5c0d0e504b72c1c Mon Sep 17 00:00:00 2001 From: "Jack Y. Araz" <jackaraz@gmail.com> Date: Thu, 29 Jun 2023 13:06:02 +0100 Subject: [PATCH 023/107] update docstring --- tools/SampleAnalyzer/Commons/DataFormat/WeightCollection.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/SampleAnalyzer/Commons/DataFormat/WeightCollection.h b/tools/SampleAnalyzer/Commons/DataFormat/WeightCollection.h index 6cd44b45..60178da8 100644 --- a/tools/SampleAnalyzer/Commons/DataFormat/WeightCollection.h +++ b/tools/SampleAnalyzer/Commons/DataFormat/WeightCollection.h @@ -149,7 +149,7 @@ namespace MA5 /// Get a weight const MAfloat64 &operator[](MAuint32 id) const { return Get(id); } - /// Add a new weight group + /// @brief Print weight information void Print() const { if (weights_.empty()) From e6e19fc84ce1633a5f7d0cff2b2a914b6d572473 Mon Sep 17 00:00:00 2001 From: "Jack Y. Araz" <jackaraz@gmail.com> Date: Thu, 29 Jun 2023 13:06:36 +0100 Subject: [PATCH 024/107] update exception message --- tools/SampleAnalyzer/Process/Plot/Histo.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/SampleAnalyzer/Process/Plot/Histo.h b/tools/SampleAnalyzer/Process/Plot/Histo.h index 82c46b7c..b8d8f815 100644 --- a/tools/SampleAnalyzer/Process/Plot/Histo.h +++ b/tools/SampleAnalyzer/Process/Plot/Histo.h @@ -97,7 +97,7 @@ namespace MA5 try { if (nbins == 0) - throw EXCEPTION_WARNING("nbins cannot be equal to 0. Set 100.", "", 0); + throw EXCEPTION_WARNING("nbins cannot be equal to 0. 100 bins will be used.", "", 0); nbins_ = nbins; } catch (const std::exception &e) From 12b3f26ebb60a142c264159b07133cb77d4199c5 Mon Sep 17 00:00:00 2001 From: "Jack Y. Araz" <jackaraz@gmail.com> Date: Thu, 29 Jun 2023 13:07:40 +0100 Subject: [PATCH 025/107] update docstring --- tools/SampleAnalyzer/Process/Plot/HistoFrequency.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/SampleAnalyzer/Process/Plot/HistoFrequency.h b/tools/SampleAnalyzer/Process/Plot/HistoFrequency.h index 4993e1ac..a18fca3f 100644 --- a/tools/SampleAnalyzer/Process/Plot/HistoFrequency.h +++ b/tools/SampleAnalyzer/Process/Plot/HistoFrequency.h @@ -126,7 +126,7 @@ namespace MA5 } } - /// Write the plot in a ROOT file + /// Write the plot in a text file virtual void Write_TextFormat(std::ostream *output) { // Header From c0c91394386d33491692c596e1b0827645413936 Mon Sep 17 00:00:00 2001 From: "Jack Y. Araz" <jackaraz@gmail.com> Date: Thu, 29 Jun 2023 13:08:14 +0100 Subject: [PATCH 026/107] update execution order --- tools/SampleAnalyzer/Process/Counter/CounterManager.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/SampleAnalyzer/Process/Counter/CounterManager.h b/tools/SampleAnalyzer/Process/Counter/CounterManager.h index 11a31813..61d60535 100644 --- a/tools/SampleAnalyzer/Process/Counter/CounterManager.h +++ b/tools/SampleAnalyzer/Process/Counter/CounterManager.h @@ -82,13 +82,13 @@ namespace MA5 /// Incrementing the initial number of events void IncrementNInitial(const WeightCollection &weight) { - initial_.Increment(weight); if (!initialised_) { for (auto &counter : counters_) counter.Initialise(weight); initialised_ = true; } + initial_.Increment(weight); } /// Incrementing the initial number of events From ac3a7a00c5fabf4b30eaef972a746d5165f2ea41 Mon Sep 17 00:00:00 2001 From: "Jack Y. Araz" <jackaraz@gmail.com> Date: Thu, 29 Jun 2023 13:08:38 +0100 Subject: [PATCH 027/107] update docstring --- tools/SampleAnalyzer/Process/Plot/Histo.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/SampleAnalyzer/Process/Plot/Histo.h b/tools/SampleAnalyzer/Process/Plot/Histo.h index b8d8f815..7ef848d5 100644 --- a/tools/SampleAnalyzer/Process/Plot/Histo.h +++ b/tools/SampleAnalyzer/Process/Plot/Histo.h @@ -161,7 +161,7 @@ namespace MA5 /// Filling histogram void Fill(MAfloat64 value, const WeightCollection &weights); - /// Write the plot in a ROOT file + /// Write the plot in a text file virtual void Write_TextFormat(std::ostream *output); protected: From 214b6720a64a28871b890c501208aa19ec2dd349 Mon Sep 17 00:00:00 2001 From: "Jack Y. Araz" <jackaraz@gmail.com> Date: Thu, 29 Jun 2023 13:09:42 +0100 Subject: [PATCH 028/107] update exception handler --- tools/SampleAnalyzer/Process/Plot/HistoLogX.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/SampleAnalyzer/Process/Plot/HistoLogX.h b/tools/SampleAnalyzer/Process/Plot/HistoLogX.h index d61c9e39..57898d19 100644 --- a/tools/SampleAnalyzer/Process/Plot/HistoLogX.h +++ b/tools/SampleAnalyzer/Process/Plot/HistoLogX.h @@ -60,7 +60,7 @@ namespace MA5 try { if (nbins == 0) - throw EXCEPTION_WARNING("nbins cannot be equal to 0. Set 100.", "", 0); + throw EXCEPTION_WARNING("nbins cannot be equal to 0. Using 100 bins.", "", 0); nbins_ = nbins; } catch (const std::exception &e) From f20edd7ff53859acebdb2b8a6b425f14902284a8 Mon Sep 17 00:00:00 2001 From: "Jack Y. Araz" <jackaraz@gmail.com> Date: Thu, 29 Jun 2023 13:10:10 +0100 Subject: [PATCH 029/107] update docstring --- tools/SampleAnalyzer/Process/Plot/Histo.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/SampleAnalyzer/Process/Plot/Histo.h b/tools/SampleAnalyzer/Process/Plot/Histo.h index 7ef848d5..7c9b0e41 100644 --- a/tools/SampleAnalyzer/Process/Plot/Histo.h +++ b/tools/SampleAnalyzer/Process/Plot/Histo.h @@ -165,7 +165,7 @@ namespace MA5 virtual void Write_TextFormat(std::ostream *output); protected: - /// Write the plot in a ROOT file + /// Write the plot in a text file virtual void Write_TextFormatBody(std::ostream *output); }; From 9234845cd5b9d00b60040a46b272e0ed423cd771 Mon Sep 17 00:00:00 2001 From: "Jack Y. Araz" <jackaraz@gmail.com> Date: Thu, 29 Jun 2023 13:11:02 +0100 Subject: [PATCH 030/107] remove unnecessary decleration --- tools/SampleAnalyzer/Process/Plot/HistoFrequency.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tools/SampleAnalyzer/Process/Plot/HistoFrequency.h b/tools/SampleAnalyzer/Process/Plot/HistoFrequency.h index a18fca3f..87a7ebf7 100644 --- a/tools/SampleAnalyzer/Process/Plot/HistoFrequency.h +++ b/tools/SampleAnalyzer/Process/Plot/HistoFrequency.h @@ -55,10 +55,6 @@ namespace MA5 // method members // ------------------------------------------------------------- public: - // @jackaraz: these may not be necessary: - // typedef std::map<int, std::pair<MAfloat64, MAfloat64>>::iterator iterator; - // typedef std::map<int, std::pair<MAfloat64, MAfloat64>>::const_iterator const_iterator; - // typedef std::map<int, std::pair<MAfloat64, MAfloat64>>::size_type size_type; /// Constructor with argument HistoFrequency(const std::string &name) : PlotBase(name) { initialised_ = false; } From 3779599e5cee95d24fbb128bfd299cef1482c985 Mon Sep 17 00:00:00 2001 From: "Jack Y. Araz" <jackaraz@gmail.com> Date: Thu, 29 Jun 2023 13:11:28 +0100 Subject: [PATCH 031/107] remove comment --- tools/SampleAnalyzer/Commons/DataFormat/MCSampleFormat.h | 1 - 1 file changed, 1 deletion(-) diff --git a/tools/SampleAnalyzer/Commons/DataFormat/MCSampleFormat.h b/tools/SampleAnalyzer/Commons/DataFormat/MCSampleFormat.h index 0605dade..7ef56d90 100644 --- a/tools/SampleAnalyzer/Commons/DataFormat/MCSampleFormat.h +++ b/tools/SampleAnalyzer/Commons/DataFormat/MCSampleFormat.h @@ -75,7 +75,6 @@ namespace MA5 MAfloat32 energy_unit_; /// Energy unit: GeV=1 MeV=0.001 keV=0.000001 // ----------------------- multiweights ------------------------ - /// @jackaraz: not sure if this is doing anything /// @brief store weight names std::map<int, std::string> weight_names_; From 9174303e3bca22b7c8534c071cb07517c63775df Mon Sep 17 00:00:00 2001 From: "Jack Y. Araz" <jackaraz@gmail.com> Date: Thu, 29 Jun 2023 13:26:12 +0100 Subject: [PATCH 032/107] uncomment resize --- tools/SampleAnalyzer/Process/Plot/Histo.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/SampleAnalyzer/Process/Plot/Histo.h b/tools/SampleAnalyzer/Process/Plot/Histo.h index 7c9b0e41..30bbd015 100644 --- a/tools/SampleAnalyzer/Process/Plot/Histo.h +++ b/tools/SampleAnalyzer/Process/Plot/Histo.h @@ -123,7 +123,7 @@ namespace MA5 step_ = (xmax_ - xmin_) / static_cast<MAfloat64>(nbins_); - // histo_.resize(nbins_); + histo_.resize(nbins_); } /// Destructor From 3c9e6103e50895daaa5c12abc6ba2a7ba233650c Mon Sep 17 00:00:00 2001 From: "Jack Y. Araz" <jackaraz@gmail.com> Date: Thu, 29 Jun 2023 13:32:41 +0100 Subject: [PATCH 033/107] remove weight definition --- .../Commons/DataFormat/MCSampleFormat.h | 117 ++++-------------- 1 file changed, 21 insertions(+), 96 deletions(-) diff --git a/tools/SampleAnalyzer/Commons/DataFormat/MCSampleFormat.h b/tools/SampleAnalyzer/Commons/DataFormat/MCSampleFormat.h index 7ef56d90..7676fbe1 100644 --- a/tools/SampleAnalyzer/Commons/DataFormat/MCSampleFormat.h +++ b/tools/SampleAnalyzer/Commons/DataFormat/MCSampleFormat.h @@ -122,124 +122,58 @@ namespace MA5 } /// Accessoir to the generator type - const MA5GEN::GeneratorType *GeneratorType() const - { - return sample_generator_; - } + const MA5GEN::GeneratorType *GeneratorType() const { return sample_generator_; } /// Accessor to PDG ID of the intial partons - const std::pair<MAint32, MAint32> &beamPDGID() const - { - return beamPDGID_; - } + const std::pair<MAint32, MAint32> &beamPDGID() const { return beamPDGID_; } /// Accessor to the beam energy - const std::pair<MAfloat64, MAfloat64> &beamE() const - { - return beamE_; - } + const std::pair<MAfloat64, MAfloat64> &beamE() const { return beamE_; } /// Accessor to the PDF authors - const std::pair<MAuint32, MAuint32> &beamPDFauthor() const - { - return beamPDFauthor_; - } + const std::pair<MAuint32, MAuint32> &beamPDFauthor() const { return beamPDFauthor_; } /// Accessor to the PDF identity - const std::pair<MAuint32, MAuint32> &beamPDFID() const - { - return beamPDFID_; - } + const std::pair<MAuint32, MAuint32> &beamPDFID() const { return beamPDFID_; } /// Accessor to the weight mode - const MAint32 &weightMode() const - { - return weightMode_; - } + const MAint32 &weightMode() const { return weightMode_; } /// Accessor to the xsection mean - const MAfloat64 &xsection() const - { - return xsection_; - } + const MAfloat64 &xsection() const { return xsection_; } /// Accessor to the xsection mean - const MAfloat64 &xsection_mean() const - { - return xsection_; - } + const MAfloat64 &xsection_mean() const { return xsection_; } /// Accessor to the xsection error - const MAfloat64 &xsection_error() const - { - return xsection_error_; - } + const MAfloat64 &xsection_error() const { return xsection_error_; } /// Accessor to the number of events with positive weight - const MAfloat64 &sumweight_positive() const - { - return sumweight_positive_; - } + const MAfloat64 &sumweight_positive() const { return sumweight_positive_; } /// Accessor to the number of events with negative weight - const MAfloat64 &sumweight_negative() const - { - return sumweight_negative_; - } + const MAfloat64 &sumweight_negative() const { return sumweight_negative_; } /// Accessor to the process collection (read-only) - const std::vector<ProcessFormat> &processes() const - { - return processes_; - } + const std::vector<ProcessFormat> &processes() const { return processes_; } /// Accessor to the process collection - std::vector<ProcessFormat> &processes() - { - return processes_; - } - - /// Accessor to the weight definition (read-only) - const WeightDefinition &weight_definition() const - { - return weight_definition_; - } - - /// Accessor to the weight definition - WeightDefinition &weight_definition() - { - return weight_definition_; - } + std::vector<ProcessFormat> &processes() { return processes_; } /// Set the PDG ID of the intial partons - void setBeamPDGID(MAint32 a, MAint32 b) - { - beamPDGID_ = std::make_pair(a, b); - } + void setBeamPDGID(MAint32 a, MAint32 b) { beamPDGID_ = std::make_pair(a, b); } /// Set the beam energy - void setBeamE(MAfloat64 a, MAfloat64 b) - { - beamE_ = std::make_pair(a, b); - } + void setBeamE(MAfloat64 a, MAfloat64 b) { beamE_ = std::make_pair(a, b); } /// Set the PDF authors - void setBeamPDFauthor(MAuint32 a, MAuint32 b) - { - beamPDFauthor_ = std::make_pair(a, b); - } + void setBeamPDFauthor(MAuint32 a, MAuint32 b) { beamPDFauthor_ = std::make_pair(a, b); } /// Set the the PDF identity - void setBeamPDFid(MAuint32 a, MAuint32 b) - { - beamPDFID_ = std::make_pair(a, b); - } + void setBeamPDFid(MAuint32 a, MAuint32 b) { beamPDFID_ = std::make_pair(a, b); } /// Set the weight mode - void setWeightMode(MAint32 v) - { - weightMode_ = v; - } + void setWeightMode(MAint32 v) { weightMode_ = v; } /// Set the cross section mean // BENJ: the normalization in the pythia lhe output by madgraph has been changed @@ -251,16 +185,10 @@ namespace MA5 } /// Set the cross section mean - void setXsectionMean(MAfloat64 value) - { - xsection_ = value; - } + void setXsectionMean(MAfloat64 value) { xsection_ = value; } /// Set the cross section mean - void setXsectionError(MAfloat64 value) - { - xsection_error_ = value; - } + void setXsectionError(MAfloat64 value) { xsection_error_ = value; } /// @brief set weight names /// @param id location of the weight @@ -286,10 +214,7 @@ namespace MA5 } /// Accessor to the number of events with negative weight - void setSumweight_negative(MAfloat64 sum) - { - sumweight_negative_ += sum; - } + void setSumweight_negative(MAfloat64 sum) { sumweight_negative_ += sum; } /// Giving a new process entry ProcessFormat *GetNewProcess() From fd692beefb5c96bcbc545d1585a78e286c42a039 Mon Sep 17 00:00:00 2001 From: "Jack Y. Araz" <jackaraz@gmail.com> Date: Thu, 29 Jun 2023 13:39:12 +0100 Subject: [PATCH 034/107] add weight shortcut --- tools/SampleAnalyzer/Commons/DataFormat/MCEventFormat.h | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/tools/SampleAnalyzer/Commons/DataFormat/MCEventFormat.h b/tools/SampleAnalyzer/Commons/DataFormat/MCEventFormat.h index 0dabfbb2..c63b2537 100644 --- a/tools/SampleAnalyzer/Commons/DataFormat/MCEventFormat.h +++ b/tools/SampleAnalyzer/Commons/DataFormat/MCEventFormat.h @@ -157,9 +157,6 @@ namespace MA5 /// Accessor to alpha_QCD const MAfloat64 &alphaQCD() const { return alphaQCD_; } - /// Accessor to multiweights - const WeightCollection &multiweights() const { return multiweights_; } - /// Accessor to multiweights WeightCollection &weights() { return multiweights_; } @@ -167,7 +164,7 @@ namespace MA5 const WeightCollection &weights() const { return multiweights_; } /// Accessor to multiweights - const MAfloat64 &get_weight(MAuint32 id) const { return multiweights_.Get(id); } + const MAfloat64 &GetWeight(MAuint32 id) const { return multiweights_.Get(id); } /// Accessor to the generated particle collection (read-only) const std::vector<MCParticleFormat> &particles() const { return particles_; } @@ -179,7 +176,7 @@ namespace MA5 void setProcessId(MAuint32 v) { processId_ = v; } /// Setting the event weight - // void setWeight(MAfloat64 v) const { weight_ = v; } + void setWeight(MAuint32 id, MAfloat64 value) { multiweights_.Add(id, value); } /// Setting the scale void setScale(MAfloat64 v) { scale_ = v; } From bcc6eb37cabf8a688acfd9bbcce64e7384cf82b0 Mon Sep 17 00:00:00 2001 From: "Jack Y. Araz" <jackaraz@gmail.com> Date: Thu, 29 Jun 2023 13:40:56 +0100 Subject: [PATCH 035/107] clean the code --- tools/SampleAnalyzer/Commons/DataFormat/MCEventFormat.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tools/SampleAnalyzer/Commons/DataFormat/MCEventFormat.h b/tools/SampleAnalyzer/Commons/DataFormat/MCEventFormat.h index c63b2537..491a9016 100644 --- a/tools/SampleAnalyzer/Commons/DataFormat/MCEventFormat.h +++ b/tools/SampleAnalyzer/Commons/DataFormat/MCEventFormat.h @@ -100,13 +100,13 @@ namespace MA5 MCEventFormat() { processId_ = 0; - // weight_ = 1.; scale_ = 0.; alphaQED_ = 0.; alphaQCD_ = 0.; TET_ = 0.; THT_ = 0.; Meff_ = 0.; + multiweights_.clear(); } /// Destructor @@ -191,7 +191,6 @@ namespace MA5 void Reset() { processId_ = 0; - // weight_ = 1.; scale_ = 0.; alphaQED_ = 0.; alphaQCD_ = 0.; From ac59bd25c33daec98129616317e36d86452f56e9 Mon Sep 17 00:00:00 2001 From: "Jack Y. Araz" <jackaraz@gmail.com> Date: Thu, 29 Jun 2023 14:58:41 +0100 Subject: [PATCH 036/107] update getweight --- tools/SampleAnalyzer/Process/Writer/LHEWriter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/SampleAnalyzer/Process/Writer/LHEWriter.cpp b/tools/SampleAnalyzer/Process/Writer/LHEWriter.cpp index ac7f23dd..7c6f6e87 100644 --- a/tools/SampleAnalyzer/Process/Writer/LHEWriter.cpp +++ b/tools/SampleAnalyzer/Process/Writer/LHEWriter.cpp @@ -620,7 +620,7 @@ MAbool LHEWriter::WriteEventHeader(const EventFormat &myEvent, { *output_ << std::setw(2) << std::right << nevents << " "; *output_ << std::setw(3) << std::right << myEvent.mc()->processId_ << " "; - MAfloat64 myweight = myEvent.mc()->get_weight(0); + MAfloat64 myweight = myEvent.mc()->GetWeight(0); if (myweight == 0) myweight = 1; *output_ << std::setw(14) << std::right << LHEWriter::FortranFormat_SimplePrecision(myweight) << " "; From 99796ed7f255bfb083c1361739e9e03ce0f65845 Mon Sep 17 00:00:00 2001 From: "Jack Y. Araz" <jackaraz@gmail.com> Date: Thu, 29 Jun 2023 16:03:19 +0100 Subject: [PATCH 037/107] bugfix --- tools/SampleAnalyzer/Process/Plot/Histo.cpp | 3 - tools/SampleAnalyzer/Process/Plot/Histo.h | 1 + .../Process/Plot/HistoFrequency.cpp | 153 ++++++++++++++++++ .../Process/Plot/HistoFrequency.h | 126 +-------------- 4 files changed, 157 insertions(+), 126 deletions(-) create mode 100644 tools/SampleAnalyzer/Process/Plot/HistoFrequency.cpp diff --git a/tools/SampleAnalyzer/Process/Plot/Histo.cpp b/tools/SampleAnalyzer/Process/Plot/Histo.cpp index 96b804fc..7d0bb558 100644 --- a/tools/SampleAnalyzer/Process/Plot/Histo.cpp +++ b/tools/SampleAnalyzer/Process/Plot/Histo.cpp @@ -198,7 +198,6 @@ void Histo::_initialize(const WeightCollection &weights) for (auto &w : weights.GetWeights()) { MAint32 idx = w.first; - current[idx] = WEIGHTS(); underflow_[idx] = WEIGHTS(); overflow_[idx] = WEIGHTS(); sum_w_[idx] = WEIGHTS(); @@ -206,8 +205,6 @@ void Histo::_initialize(const WeightCollection &weights) sum_xw_[idx] = WEIGHTS(); sum_xxw_[idx] = WEIGHTS(); } - for (MAuint16 i = 0; i < nbins_; i++) - histo_.push_back(current); } /// Filling histogram diff --git a/tools/SampleAnalyzer/Process/Plot/Histo.h b/tools/SampleAnalyzer/Process/Plot/Histo.h index 30bbd015..74665b15 100644 --- a/tools/SampleAnalyzer/Process/Plot/Histo.h +++ b/tools/SampleAnalyzer/Process/Plot/Histo.h @@ -123,6 +123,7 @@ namespace MA5 step_ = (xmax_ - xmin_) / static_cast<MAfloat64>(nbins_); + /// resize takes care of initialisation histo_.resize(nbins_); } diff --git a/tools/SampleAnalyzer/Process/Plot/HistoFrequency.cpp b/tools/SampleAnalyzer/Process/Plot/HistoFrequency.cpp new file mode 100644 index 00000000..02499fbb --- /dev/null +++ b/tools/SampleAnalyzer/Process/Plot/HistoFrequency.cpp @@ -0,0 +1,153 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2012-2023 Jack Araz, Eric Conte & Benjamin Fuks +// The MadAnalysis development team, email: <ma5team@iphc.cnrs.fr> +// +// This file is part of MadAnalysis 5. +// Official website: <https://github.com/MadAnalysis/madanalysis5> +// +// MadAnalysis 5 is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// MadAnalysis 5 is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with MadAnalysis 5. If not, see <http://www.gnu.org/licenses/> +// +//////////////////////////////////////////////////////////////////////////////// + +// SampleAnalyzer headers +#include "SampleAnalyzer/Process/Plot/HistoFrequency.h" + +using namespace MA5; + +/// Adding an entry for a given observable +void HistoFrequency::Fill(const MAint32 &obs, WeightCollection &weights) +{ + for (auto &weight : weights.GetWeights()) + { + MAint32 idx = weight.first; + MAdouble64 w = weight.second; + // Value not found + if (stack_.find(obs) == stack_.end()) + stack_[obs][idx] = WEIGHTS(); + + // Value found + else + { + if (w >= 0) + { + nentries_[idx].positive++; + sum_w_[idx].positive += w; + stack_[obs][idx].positive += w; + } + else + { + nentries_[idx].negative++; + sum_w_[idx].negative += std::fabs(w); + stack_[obs][idx].negative += std::fabs(w); + } + } + } +} + +/// Write the plot in a text file +void HistoFrequency::Write_TextFormat(std::ostream *output) +{ + // Header + *output << "<HistoFrequency>" << std::endl; + + // Description + *output << " <Description>" << std::endl; + *output << " \"" << name_ << "\"" << std::endl; + + // SelectionRegions + if (regions_.size() != 0) + { + MAuint32 maxlength = 0; + for (MAuint32 i = 0; i < regions_.size(); i++) + if (regions_[i]->GetName().size() > maxlength) + maxlength = regions_[i]->GetName().size(); + *output << std::left << " # Defined regions" << std::endl; + for (MAuint32 i = 0; i < regions_.size(); i++) + { + *output << " " << std::setw(maxlength) << std::left << regions_[i]->GetName(); + *output << " # Region nr. " << std::fixed << i + 1 << std::endl; + } + } + + // End description + *output << " </Description>" << std::endl; + + // Statistics + *output << " <Statistics>" << std::endl; + *output << " "; + for (auto &event : nevents_) + { + output->width(15); + *output << std::fixed << event.second.positive; + output->width(15); + *output << std::fixed << event.second.negative; + } + *output << " # nevents" << std::endl; + *output << " "; + for (auto &event : nevents_w_) + { + output->width(15); + *output << std::scientific << event.second.positive; + output->width(15); + *output << std::scientific << event.second.negative; + } + *output << " # sum of event-weights over events" << std::endl; + *output << " "; + for (auto &event : nentries_) + { + output->width(15); + *output << std::fixed << event.second.positive; + output->width(15); + *output << std::fixed << event.second.negative; + } + *output << " # nentries" << std::endl; + *output << " "; + for (auto &event : sum_w_) + { + output->width(15); + *output << std::scientific << event.second.positive; + output->width(15); + *output << std::scientific << event.second.negative; + } + *output << " # sum of event-weights over entries" << std::endl; + *output << " </Statistics>" << std::endl; + + // Data + *output << " <Data>" << std::endl; + MAuint32 i = 0; + for (auto &it : stack_) + { + *output << " "; + output->width(15); + *output << std::left << std::fixed << it.first; + + for (auto &weight : it.second) + { + output->width(15); + *output << std::left << std::scientific << weight.second.positive; + output->width(15); + *output << std::left << std::scientific << weight.second.negative; + } + if (i < 2 || i >= (stack_.size() - 2)) + *output << " # bin " << i + 1 << " / " << stack_.size(); + *output << std::endl; + i++; + } + *output << " </Data>" << std::endl; + + // Footer + *output << "</HistoFrequency>" << std::endl; + *output << std::endl; +} diff --git a/tools/SampleAnalyzer/Process/Plot/HistoFrequency.h b/tools/SampleAnalyzer/Process/Plot/HistoFrequency.h index 87a7ebf7..54964a75 100644 --- a/tools/SampleAnalyzer/Process/Plot/HistoFrequency.h +++ b/tools/SampleAnalyzer/Process/Plot/HistoFrequency.h @@ -31,6 +31,7 @@ // SampleAnalyzer headers #include "SampleAnalyzer/Process/Plot/PlotBase.h" +#include "SampleAnalyzer/Process/RegionSelection/RegionSelection.h" namespace MA5 { @@ -55,7 +56,6 @@ namespace MA5 // method members // ------------------------------------------------------------- public: - /// Constructor with argument HistoFrequency(const std::string &name) : PlotBase(name) { initialised_ = false; } @@ -93,130 +93,10 @@ namespace MA5 } /// Adding an entry for a given observable - void Fill(const MAint32 &obs, WeightCollection &weights) - { - for (auto &weight : weights.GetWeights()) - { - MAint32 idx = weight.first; - MAdouble64 w = weight.second; - // Value not found - if (stack_.find(obs) == stack_.end()) - stack_[obs][idx] = WEIGHTS(); - - // Value found - else - { - if (w >= 0) - { - nentries_[idx].positive++; - sum_w_[idx].positive += w; - stack_[obs][idx].positive += w; - } - else - { - nentries_[idx].negative++; - sum_w_[idx].negative += std::fabs(w); - stack_[obs][idx].negative += std::fabs(w); - } - } - } - } + void Fill(const MAint32 &obs, WeightCollection &weights); /// Write the plot in a text file - virtual void Write_TextFormat(std::ostream *output) - { - // Header - *output << "<HistoFrequency>" << std::endl; - - // Description - *output << " <Description>" << std::endl; - *output << " \"" << name_ << "\"" << std::endl; - - // SelectionRegions - if (regions_.size() != 0) - { - MAuint32 maxlength = 0; - for (MAuint32 i = 0; i < regions_.size(); i++) - if (regions_[i]->GetName().size() > maxlength) - maxlength = regions_[i]->GetName().size(); - *output << std::left << " # Defined regions" << std::endl; - for (MAuint32 i = 0; i < regions_.size(); i++) - { - *output << " " << std::setw(maxlength) << std::left << regions_[i]->GetName(); - *output << " # Region nr. " << std::fixed << i + 1 << std::endl; - } - } - - // End description - *output << " </Description>" << std::endl; - - // Statistics - *output << " <Statistics>" << std::endl; - *output << " "; - for (auto &event : nevents_) - { - output->width(15); - *output << std::fixed << event.second.positive; - output->width(15); - *output << std::fixed << event.second.negative; - } - *output << " # nevents" << std::endl; - *output << " "; - for (auto &event : nevents_w_) - { - output->width(15); - *output << std::scientific << event.second.positive; - output->width(15); - *output << std::scientific << event.second.negative; - } - *output << " # sum of event-weights over events" << std::endl; - *output << " "; - for (auto &event : nentries_) - { - output->width(15); - *output << std::fixed << event.second.positive; - output->width(15); - *output << std::fixed << event.second.negative; - } - *output << " # nentries" << std::endl; - *output << " "; - for (auto &event : sum_w_) - { - output->width(15); - *output << std::scientific << event.second.positive; - output->width(15); - *output << std::scientific << event.second.negative; - } - *output << " # sum of event-weights over entries" << std::endl; - *output << " </Statistics>" << std::endl; - - // Data - *output << " <Data>" << std::endl; - MAuint32 i = 0; - for (auto &it : stack_) - { - *output << " "; - output->width(15); - *output << std::left << std::fixed << it.first; - - for (auto &weight : it.second) - { - output->width(15); - *output << std::left << std::scientific << weight.second.positive; - output->width(15); - *output << std::left << std::scientific << weight.second.negative; - } - if (i < 2 || i >= (stack_.size() - 2)) - *output << " # bin " << i + 1 << " / " << stack_.size(); - *output << std::endl; - i++; - } - *output << " </Data>" << std::endl; - - // Footer - *output << "</HistoFrequency>" << std::endl; - *output << std::endl; - } + virtual void Write_TextFormat(std::ostream *output); }; } From 250d98a63baab6dee0914c98d44b995c136cadac Mon Sep 17 00:00:00 2001 From: "Jack Y. Araz" <jackaraz@gmail.com> Date: Thu, 29 Jun 2023 16:45:30 +0100 Subject: [PATCH 038/107] update histogram structure --- madanalysis/IOinterface/job_reader.py | 790 ++++++++------- madanalysis/interpreter/cmd_submit.py | 345 ++++--- madanalysis/layout/plotflow.py | 1323 +++++++++++++------------ 3 files changed, 1319 insertions(+), 1139 deletions(-) diff --git a/madanalysis/IOinterface/job_reader.py b/madanalysis/IOinterface/job_reader.py index 584994a5..3e563350 100644 --- a/madanalysis/IOinterface/job_reader.py +++ b/madanalysis/IOinterface/job_reader.py @@ -1,224 +1,243 @@ ################################################################################ -# +# # Copyright (C) 2012-2023 Jack Araz, Eric Conte & Benjamin Fuks # The MadAnalysis development team, email: <ma5team@iphc.cnrs.fr> -# +# # This file is part of MadAnalysis 5. # Official website: <https://github.com/MadAnalysis/madanalysis5> -# +# # MadAnalysis 5 is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. -# +# # MadAnalysis 5 is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. -# +# # You should have received a copy of the GNU General Public License # along with MadAnalysis 5. If not, see <http://www.gnu.org/licenses/> -# +# ################################################################################ from __future__ import absolute_import -from madanalysis.selection.instance_name import InstanceName -from madanalysis.dataset.sample_info import SampleInfo -from madanalysis.layout.cut_info import CutInfo + +from typing import Callable, Any, List, Tuple +import glob, logging, os, copy + +from madanalysis.selection.instance_name import InstanceName +from madanalysis.dataset.sample_info import SampleInfo +from madanalysis.layout.cut_info import CutInfo from madanalysis.IOinterface.saf_block_status import SafBlockStatus -from madanalysis.layout.histogram import Histogram -from madanalysis.layout.histogram_logx import HistogramLogX -from madanalysis.layout.histogram_frequency import HistogramFrequency -import glob -import logging -import shutil -import os -import copy +from madanalysis.layout.histogram import Histogram +from madanalysis.layout.histogram_logx import HistogramLogX +from madanalysis.layout.histogram_frequency import HistogramFrequency + +def check_instance(instance: str, instance_type: Callable[[str], Any]) -> bool: + """ + Check if a given instance can be converted to a desired type -class JobReader(): + Args: + instance (``str``): instance + instance_type (``Callable[[str], Any]``): type to be converted - def __init__(self,jobdir): - self.path = jobdir - self.safdir = os.path.normpath(self.path+"/Output/SAF/") + Returns: + ``bool``: + Returns true if the instance is convertable. + """ + try: + _ = instance_type(instance) + return True + except ValueError: + return False + + +class JobReader: + def __init__(self, jobdir): + self.path = jobdir + self.safdir = os.path.normpath(self.path + "/Output/SAF/") def CheckDir(self): if not os.path.isdir(self.path): - logging.getLogger('MA5').error("Directory called '"+self.path+"' is not found.") + logging.getLogger("MA5").error("Directory called '" + self.path + "' is not found.") return False elif not os.path.isdir(self.safdir): - logging.getLogger('MA5').error("Directory called '"+self.safdir+"' is not found.") + logging.getLogger("MA5").error("Directory called '" + self.safdir + "' is not found.") return False else: return True - def CheckFile(self,dataset): - name=InstanceName.Get(dataset.name) - if os.path.isfile(self.safdir+"/"+name+"/"+name+".saf"): + def CheckFile(self, dataset): + name = InstanceName.Get(dataset.name) + if os.path.isfile(self.safdir + "/" + name + "/" + name + ".saf"): return True else: - logging.getLogger('MA5').error("File called '"+self.safdir+"/"+name+'/'+name+".saf' is not found.") + logging.getLogger("MA5").error( + "File called '" + self.safdir + "/" + name + "/" + name + ".saf' is not found." + ) return False - - def ExtractSampleInfo(self,words,numline,filename): + def ExtractSampleInfo(self, words, numline, filename): # Creating container for info results = SampleInfo() # Extracting xsection try: - results.xsection=float(words[0]) + results.xsection = float(words[0]) except: - logging.getLogger('MA5').error("xsection is not a float value:"+\ - words[0]) + logging.getLogger("MA5").error("xsection is not a float value:" + words[0]) # Extracting xsection error try: - results.xerror=float(words[1]) + results.xerror = float(words[1]) except: - logging.getLogger('MA5').error("xsection_error is not a float value:"+\ - words[1]) + logging.getLogger("MA5").error("xsection_error is not a float value:" + words[1]) # Extracting number of events try: - results.nevents=int(words[2]) + results.nevents = int(words[2]) except: - logging.getLogger('MA5').error("nevents is not an integer value:"+\ - words[2]) + logging.getLogger("MA5").error("nevents is not an integer value:" + words[2]) # Extracting sum positive weights try: - results.sumw_positive=float(words[3]) + results.sumw_positive = float(words[3]) except: - logging.getLogger('MA5').error("sum_weight+ is not a float value:"+\ - words[3]) + logging.getLogger("MA5").error("sum_weight+ is not a float value:" + words[3]) # Extracting sum negative weights try: - results.sumw_negative=float(words[4]) + results.sumw_negative = float(words[4]) except: - logging.getLogger('MA5').error("sum_weight- is not a float value:"+\ - words[4]) + logging.getLogger("MA5").error("sum_weight- is not a float value:" + words[4]) return results + def ExtractCutLine( + self, words: List[str], numline, filename + ) -> Tuple[List[float], List[float]]: + """ + Extract float values from list - def ExtractCutLine(self,words,numline,filename): - - # Extracting xsection - try: - a=float(words[0]) - except: - logging.getLogger('MA5').error("Counter is not a float value:"+words[0]) - - # Extracting xsection error - try: - b=float(words[1]) - except: - logging.getLogger('MA5').error("Counter is not a float value:"+words[1]) - - # Returning exracting values - return [a,b] - + Args: + words (``list[str]``): line inputs + Returns: + ``Tuple[List[int], List[int]]``: + positive and negative weights + """ + return self.ExtractStatisticsFloat(words, numline, filename) - def ExtractDescription(self,words,numline,filename): + def ExtractDescription(self, words, numline, filename): # Extracting nbins try: - a=int(words[0]) + a = int(words[0]) except: - logging.getLogger('MA5').error("nbin is not a int value:"+words[0]) + logging.getLogger("MA5").error("nbin is not a int value:" + words[0]) # Extracting xmin try: - b=float(words[1]) + b = float(words[1]) except: - logging.getLogger('MA5').error("xmin is not a float value:"+words[1]) + logging.getLogger("MA5").error("xmin is not a float value:" + words[1]) # Extracting xmax try: - c=float(words[2]) - except: - logging.getLogger('MA5').error("xmax is not a float value:"+words[2]) - - # Returning exracting values - return [a,b,c] - - def ExtractStatisticsInt(self,words,numline,filename): - - # Extracting positive - try: - a=int(words[0]) - except: - logging.getLogger('MA5').error(str(words[0])+' must be a positive integer value @ "'+filename+'" line='+str(numline)) - a=0 - if a<0: - logging.getLogger('MA5').error(str(words[0])+' must be a positive integer value @ "'+filename+'" line='+str(numline)) - a=0 - - # Extracting negative - try: - b=int(words[1]) - except: - logging.getLogger('MA5').error(str(words[1])+' must be a positive integer value @ "'+filename+'" line='+str(numline)) - b=0 - if b<0: - logging.getLogger('MA5').error(str(words[1])+' must be a positive integer value @ "'+filename+'" line='+str(numline)) - b=0 - - # Returning exracting values - return [a,b] - - - def ExtractStatisticsFloat(self,words,numline,filename): - - # Extracting positive - try: - a=float(words[0]) + c = float(words[2]) except: - logging.getLogger('MA5').error(str(words[0])+' must be a float value @ "'+filename+'" line='+str(numline)) - a=0. - - # Extracting negative - try: - b=float(words[1]) - except: - logging.getLogger('MA5').error(str(words[1])+' must be a float value @ "'+filename+'" line='+str(numline)) - b=0. + logging.getLogger("MA5").error("xmax is not a float value:" + words[2]) # Returning exracting values - return [a,b] + return [a, b, c] + + def ExtractStatisticsInt( + self, words: List[str], numline, filename + ) -> Tuple[List[int], List[int]]: + """ + Extract integer values from list + + Args: + words (``list[str]``): line inputs + + Returns: + ``Tuple[List[int], List[int]]``: + positive and negative weights + """ + # Collect positive weights + positive_weights, negative_weights = [], [] + for idx, instance in enumerate(words): + if check_instance(instance, int): + if idx % 2 == 0: + positive_weights.append(int(instance)) + else: + negative_weights.append(int(instance)) + + return positive_weights, negative_weights + + def ExtractStatisticsFloat( + self, words: List[str], numline, filename + ) -> Tuple[List[float], List[float]]: + """ + Extract float values from list + + Args: + words (``list[str]``): line inputs + + Returns: + ``Tuple[List[int], List[int]]``: + positive and negative weights + """ + # Collect positive weights + positive_weights, negative_weights = [], [] + for idx, instance in enumerate(words): + if check_instance(instance, float): + if idx % 2 == 0: + positive_weights.append(float(instance)) + else: + negative_weights.append(float(instance)) + return positive_weights, negative_weights - def ExtractDataFreq(self,words,numline,filename): + def ExtractDataFreq(self, words, numline, filename): # Extracting label try: - a=int(words[0]) + a = int(words[0]) except: - logging.getLogger('MA5').error(str(words[0])+' must be an integer value @ "'+filename+'" line='+str(numline)) - a=0. + logging.getLogger("MA5").error( + str(words[0]) + + ' must be an integer value @ "' + + filename + + '" line=' + + str(numline) + ) + a = 0.0 # Extracting positive try: - b=float(words[1]) + b = float(words[1]) except: - logging.getLogger('MA5').error(str(words[1])+' must be a float value @ "'+filename+'" line='+str(numline)) - b=0. + logging.getLogger("MA5").error( + str(words[1]) + ' must be a float value @ "' + filename + '" line=' + str(numline) + ) + b = 0.0 # Extracting negative try: - c=float(words[2]) + c = float(words[2]) except: - logging.getLogger('MA5').error(str(words[2])+' must be a float value @ "'+filename+'" line='+str(numline)) - c=0. + logging.getLogger("MA5").error( + str(words[2]) + ' must be a float value @ "' + filename + '" line=' + str(numline) + ) + c = 0.0 # Returning exracting values - return [a,b,c] - + return [a, b, c] # Extracting data from the SAF file # sample & file info -> dataset @@ -226,171 +245,184 @@ def ExtractDataFreq(self,words,numline,filename): # merging plots -> merging # selection plots -> plot - def ExtractGeneral(self,dataset): + def ExtractGeneral(self, dataset): # Getting the output file name - name=InstanceName.Get(dataset.name) - filename = self.safdir+"/"+name+"/"+name+".saf" + name = InstanceName.Get(dataset.name) + filename = self.safdir + "/" + name + "/" + name + ".saf" # Opening the file try: - file = open(filename,'r') + file = open(filename, "r") except: - logging.getLogger('MA5').error("File called '"+filename+"' is not found") + logging.getLogger("MA5").error("File called '" + filename + "' is not found") return # Initializing tags - beginTag = SafBlockStatus() - endTag = SafBlockStatus() - globalTag = SafBlockStatus() - detailTag = SafBlockStatus() + beginTag = SafBlockStatus() + endTag = SafBlockStatus() + globalTag = SafBlockStatus() + detailTag = SafBlockStatus() # Loop over the lines - numline=0 + numline = 0 for line in file: # Incrementing line counter - numline+=1 + numline += 1 # Removing comments - index=line.find('#') - if index!=-1: - line=line[:index] + index = line.find("#") + if index != -1: + line = line[:index] # Treating line - line=line.lstrip() - line=line.rstrip() - words=line.split() - if len(words)==0: + line = line.lstrip() + line = line.rstrip() + words = line.split() + if len(words) == 0: continue # Looking for tag 'SampleGlobalInfo' - if len(words)==1 and words[0][0]=='<' and words[0][-1]=='>': - if words[0].lower()=='<safheader>': + if len(words) == 1 and words[0][0] == "<" and words[0][-1] == ">": + if words[0].lower() == "<safheader>": beginTag.activate() - elif words[0].lower()=='</safheader>': + elif words[0].lower() == "</safheader>": beginTag.desactivate() - if words[0].lower()=='<saffooter>': + if words[0].lower() == "<saffooter>": endTag.activate() - elif words[0].lower()=='</saffooter>': + elif words[0].lower() == "</saffooter>": endTag.desactivate() - if words[0].lower()=='<sampleglobalinfo>': + if words[0].lower() == "<sampleglobalinfo>": globalTag.activate() - elif words[0].lower()=='</sampleglobalinfo>': + elif words[0].lower() == "</sampleglobalinfo>": globalTag.desactivate() - elif words[0].lower()=='<sampledetailedinfo>': + elif words[0].lower() == "<sampledetailedinfo>": detailTag.activate() - elif words[0].lower()=='</sampledetailedinfo>': + elif words[0].lower() == "</sampledetailedinfo>": detailTag.desactivate() # Looking for summary sample info - elif globalTag.activated and len(words)==5: - dataset.measured_global = self.ExtractSampleInfo(words,numline,filename) + elif globalTag.activated and len(words) == 5: + dataset.measured_global = self.ExtractSampleInfo(words, numline, filename) # Looking for detail sample info (one line for each file) - elif detailTag.activated and len(words)==5: - dataset.measured_detail.append(self.ExtractSampleInfo(words,numline,filename)) + elif detailTag.activated and len(words) == 5: + dataset.measured_detail.append(self.ExtractSampleInfo(words, numline, filename)) # Information found ? - if beginTag.Nactivated==0 or beginTag.activated: - logging.getLogger('MA5').error("SAF header <SAFheader> and </SAFheader> is not found.") - if endTag.Nactivated==0 or endTag.activated: - logging.getLogger('MA5').error("SAF footer <SAFfooter> and </SAFfooter> is not found.") - if globalTag.Nactivated==0 or globalTag.activated: - logging.getLogger('MA5').error("Information corresponding to the block "+\ - "<SampleGlobalInfo> is not found.") - logging.getLogger('MA5').error("Information on the dataset '"+dataset.name+\ - "' are not updated.") - if detailTag.Nactivated==0 or globalTag.activated: - logging.getLogger('MA5').error("Information corresponding to the block "+\ - "<SampleDetailInfo> is not found.") - logging.getLogger('MA5').error("Information on the dataset '"+dataset.name+\ - "' are not updated.") + if beginTag.Nactivated == 0 or beginTag.activated: + logging.getLogger("MA5").error("SAF header <SAFheader> and </SAFheader> is not found.") + if endTag.Nactivated == 0 or endTag.activated: + logging.getLogger("MA5").error("SAF footer <SAFfooter> and </SAFfooter> is not found.") + if globalTag.Nactivated == 0 or globalTag.activated: + logging.getLogger("MA5").error( + "Information corresponding to the block " + "<SampleGlobalInfo> is not found." + ) + logging.getLogger("MA5").error( + "Information on the dataset '" + dataset.name + "' are not updated." + ) + if detailTag.Nactivated == 0 or globalTag.activated: + logging.getLogger("MA5").error( + "Information corresponding to the block " + "<SampleDetailInfo> is not found." + ) + logging.getLogger("MA5").error( + "Information on the dataset '" + dataset.name + "' are not updated." + ) # Closing the file file.close() - def ExtractHistos(self,dataset,plot,merging=False): + def ExtractHistos(self, dataset, plot, merging=False): # Getting the output file name - name=InstanceName.Get(dataset.name) - i=0 + name = InstanceName.Get(dataset.name) + i = 0 if merging: - while(os.path.isdir(self.safdir+"/"+name+"/MergingPlots_"+str(i))): - i+=1 - filename = self.safdir+"/"+name+"/MergingPlots_"+str(i-1)+"/Histograms/histos.saf" + while os.path.isdir(self.safdir + "/" + name + "/MergingPlots_" + str(i)): + i += 1 + filename = ( + self.safdir + "/" + name + "/MergingPlots_" + str(i - 1) + "/Histograms/histos.saf" + ) else: - while(os.path.isdir(self.safdir+"/"+name+"/MadAnalysis5job_"+str(i))): - i+=1 - filename = self.safdir+"/"+name+"/MadAnalysis5job_"+str(i-1)+"/Histograms/histos.saf" + while os.path.isdir(self.safdir + "/" + name + "/MadAnalysis5job_" + str(i)): + i += 1 + filename = ( + self.safdir + + "/" + + name + + "/MadAnalysis5job_" + + str(i - 1) + + "/Histograms/histos.saf" + ) # Opening the file try: - file = open(filename,'r') + file = open(filename, "r") except: - logging.getLogger('MA5').error("File called '"+filename+"' is not found") + logging.getLogger("MA5").error("File called '" + filename + "' is not found") return # Initializing tags - beginTag = SafBlockStatus() - endTag = SafBlockStatus() - histoTag = SafBlockStatus() - histoLogXTag = SafBlockStatus() - histoFreqTag = SafBlockStatus() + beginTag = SafBlockStatus() + endTag = SafBlockStatus() + histoTag = SafBlockStatus() + histoLogXTag = SafBlockStatus() + histoFreqTag = SafBlockStatus() descriptionTag = SafBlockStatus() - statisticsTag = SafBlockStatus() - dataTag = SafBlockStatus() + statisticsTag = SafBlockStatus() + dataTag = SafBlockStatus() # Initializing temporary containers - histoinfo = Histogram() - histologxinfo = HistogramLogX() + histoinfo = Histogram() + histologxinfo = HistogramLogX() histofreqinfo = HistogramFrequency() data_positive = [] data_negative = [] - labels = [] + labels = [] # Loop over the lines - numline=0 + numline = 0 for line in file: # Incrementing line counter - numline+=1 + numline += 1 # Removing comments - index=line.find('#') - if index!=-1: - line=line[:index] + index = line.find("#") + if index != -1: + line = line[:index] # Treating line - line=line.lstrip() - line=line.rstrip() - words=line.split() - if len(words)==0: + line = line.lstrip() + line = line.rstrip() + words = line.split() + if len(words) == 0: continue # decoding the file - if len(words)==1 and words[0][0]=='<' and words[0][-1]=='>': - if words[0].lower()=='<safheader>': + if len(words) == 1 and words[0][0] == "<" and words[0][-1] == ">": + if words[0].lower() == "<safheader>": beginTag.activate() - elif words[0].lower()=='</safheader>': + elif words[0].lower() == "</safheader>": beginTag.desactivate() - elif words[0].lower()=='<saffooter>': + elif words[0].lower() == "<saffooter>": endTag.activate() - elif words[0].lower()=='</saffooter>': + elif words[0].lower() == "</saffooter>": endTag.desactivate() - elif words[0].lower()=='<description>': + elif words[0].lower() == "<description>": descriptionTag.activate() - elif words[0].lower()=='</description>': + elif words[0].lower() == "</description>": descriptionTag.desactivate() - elif words[0].lower()=='<statistics>': + elif words[0].lower() == "<statistics>": statisticsTag.activate() - elif words[0].lower()=='</statistics>': + elif words[0].lower() == "</statistics>": statisticsTag.desactivate() - elif words[0].lower()=='<data>': + elif words[0].lower() == "<data>": dataTag.activate() - elif words[0].lower()=='</data>': + elif words[0].lower() == "</data>": dataTag.desactivate() - elif words[0].lower()=='<histo>': + elif words[0].lower() == "<histo>": histoTag.activate() - elif words[0].lower()=='</histo>': + elif words[0].lower() == "</histo>": histoTag.desactivate() plot.histos.append(copy.copy(histoinfo)) plot.histos[-1].positive.array = data_positive[:] @@ -398,9 +430,9 @@ def ExtractHistos(self,dataset,plot,merging=False): histoinfo.Reset() data_positive = [] data_negative = [] - elif words[0].lower()=='<histofrequency>': + elif words[0].lower() == "<histofrequency>": histoFreqTag.activate() - elif words[0].lower()=='</histofrequency>': + elif words[0].lower() == "</histofrequency>": histoFreqTag.desactivate() plot.histos.append(copy.copy(histofreqinfo)) plot.histos[-1].labels = labels[:] @@ -409,10 +441,10 @@ def ExtractHistos(self,dataset,plot,merging=False): histofreqinfo.Reset() data_positive = [] data_negative = [] - labels = [] - elif words[0].lower()=='<histologx>': + labels = [] + elif words[0].lower() == "<histologx>": histoLogXTag.activate() - elif words[0].lower()=='</histologx>': + elif words[0].lower() == "</histologx>": histoLogXTag.desactivate() plot.histos.append(copy.copy(histologxinfo)) plot.histos[-1].positive.array = data_positive[:] @@ -423,277 +455,301 @@ def ExtractHistos(self,dataset,plot,merging=False): # Looking from histogram description elif descriptionTag.activated: - if descriptionTag.Nlines==0: - if len(line)>1 and line[0]=='"' and line[-1]=='"': - myname=line[1:-1] + if descriptionTag.Nlines == 0: + if len(line) > 1 and line[0] == '"' and line[-1] == '"': + myname = line[1:-1] if histoTag.activated: - histoinfo.name=myname + histoinfo.name = myname elif histoLogXTag.activated: - histologxinfo.name=myname + histologxinfo.name = myname elif histoFreqTag.activated: - histofreqinfo.name=myname + histofreqinfo.name = myname else: - logging.getLogger('MA5').error('invalid name for histogram @ line=' + str(numline) +' : ') - logging.getLogger('MA5').error(str(line)) - elif descriptionTag.Nlines==1 and not histoFreqTag.activated and len(words)==3: - results = self.ExtractDescription(words,numline,filename) + logging.getLogger("MA5").error( + "invalid name for histogram @ line=" + str(numline) + " : " + ) + logging.getLogger("MA5").error(str(line)) + elif descriptionTag.Nlines == 1 and not histoFreqTag.activated and len(words) >= 3: + results = self.ExtractDescription(words, numline, filename) if histoTag.activated: - histoinfo.nbins=results[0] - histoinfo.xmin=results[1] - histoinfo.xmax=results[2] + histoinfo.nbins = results[0] + histoinfo.xmin = results[1] + histoinfo.xmax = results[2] elif histoLogXTag.activated: - histologxinfo.nbins=results[0] - histologxinfo.xmin=results[1] - histologxinfo.xmax=results[2] + histologxinfo.nbins = results[0] + histologxinfo.xmin = results[1] + histologxinfo.xmax = results[2] else: - logging.getLogger('MA5').error('invalid histogram description @ line=' + str(numline) +' : ') - logging.getLogger('MA5').error(str(line)) - elif descriptionTag.Nlines>=1: - if histoTag.activated and len(words)==1: + logging.getLogger("MA5").error( + "invalid histogram description @ line=" + str(numline) + " : " + ) + logging.getLogger("MA5").error(str(line)) + elif descriptionTag.Nlines >= 1: + if histoTag.activated and len(words) == 1: histoinfo.regions.append(words[0]) - elif histoLogXTag.activated and len(words)==1: + elif histoLogXTag.activated and len(words) == 1: histologxinfo.regions.append(words[0]) - elif histoFreqTag.activated and len(words)==1: + elif histoFreqTag.activated and len(words) == 1: histofreqinfo.regions.append(words[0]) else: - logging.getLogger('MA5').error('invalid region for a histogram @ line=' + str(numline) +' : ') - logging.getLogger('MA5').error(str(line)) + logging.getLogger("MA5").error( + "invalid region for a histogram @ line=" + str(numline) + " : " + ) + logging.getLogger("MA5").error(str(line)) else: - logging.getLogger('MA5').warning('Extra line is found: '+line) + logging.getLogger("MA5").warning("Extra line is found: " + line) descriptionTag.newline() # Looking from histogram statistics - elif statisticsTag.activated and len(words)==2: - if statisticsTag.Nlines==0: - results = self.ExtractStatisticsInt(words,numline,filename) + elif statisticsTag.activated and len(words) >= 2: + if statisticsTag.Nlines == 0: + results = self.ExtractStatisticsInt(words, numline, filename) if histoTag.activated: - histoinfo.positive.nevents=results[0] - histoinfo.negative.nevents=results[1] + histoinfo.positive.nevents = results[0] + histoinfo.negative.nevents = results[1] elif histoLogXTag.activated: - histologxinfo.positive.nevents=results[0] - histologxinfo.negative.nevents=results[1] + histologxinfo.positive.nevents = results[0] + histologxinfo.negative.nevents = results[1] elif histoFreqTag.activated: - histofreqinfo.positive.nevents=results[0] - histofreqinfo.negative.nevents=results[1] + histofreqinfo.positive.nevents = results[0] + histofreqinfo.negative.nevents = results[1] - elif statisticsTag.Nlines==1: - results = self.ExtractStatisticsFloat(words,numline,filename) + elif statisticsTag.Nlines == 1: + results = self.ExtractStatisticsFloat(words, numline, filename) if histoTag.activated: - histoinfo.positive.sumwentries=results[0] - histoinfo.negative.sumwentries=results[1] + histoinfo.positive.sumwentries = results[0] + histoinfo.negative.sumwentries = results[1] elif histoLogXTag.activated: - histologxinfo.positive.sumwentries=results[0] - histologxinfo.negative.sumwentries=results[1] + histologxinfo.positive.sumwentries = results[0] + histologxinfo.negative.sumwentries = results[1] elif histoFreqTag.activated: - histofreqinfo.positive.sumwentries=results[0] - histofreqinfo.negative.sumwentries=results[1] + histofreqinfo.positive.sumwentries = results[0] + histofreqinfo.negative.sumwentries = results[1] - elif statisticsTag.Nlines==2: - results = self.ExtractStatisticsInt(words,numline,filename) + elif statisticsTag.Nlines == 2: + results = self.ExtractStatisticsInt(words, numline, filename) if histoTag.activated: - histoinfo.positive.nentries=results[0] - histoinfo.negative.nentries=results[1] + histoinfo.positive.nentries = results[0] + histoinfo.negative.nentries = results[1] elif histoLogXTag.activated: - histologxinfo.positive.nentries=results[0] - histologxinfo.negative.nentries=results[1] + histologxinfo.positive.nentries = results[0] + histologxinfo.negative.nentries = results[1] elif histoFreqTag.activated: - histofreqinfo.positive.nentries=results[0] - histofreqinfo.negative.nentries=results[1] + histofreqinfo.positive.nentries = results[0] + histofreqinfo.negative.nentries = results[1] - elif statisticsTag.Nlines==3: - results = self.ExtractStatisticsFloat(words,numline,filename) + elif statisticsTag.Nlines == 3: + results = self.ExtractStatisticsFloat(words, numline, filename) if histoTag.activated: - histoinfo.positive.sumw=results[0] - histoinfo.negative.sumw=results[1] + histoinfo.positive.sumw = results[0] + histoinfo.negative.sumw = results[1] elif histoLogXTag.activated: - histologxinfo.positive.sumw=results[0] - histologxinfo.negative.sumw=results[1] + histologxinfo.positive.sumw = results[0] + histologxinfo.negative.sumw = results[1] elif histoFreqTag.activated: - histofreqinfo.positive.sumw=results[0] - histofreqinfo.negative.sumw=results[1] + histofreqinfo.positive.sumw = results[0] + histofreqinfo.negative.sumw = results[1] - elif statisticsTag.Nlines==4 and not histoFreqTag.activated: - results = self.ExtractStatisticsFloat(words,numline,filename) + elif statisticsTag.Nlines == 4 and not histoFreqTag.activated: + results = self.ExtractStatisticsFloat(words, numline, filename) if histoTag.activated: - histoinfo.positive.sumw2=results[0] - histoinfo.negative.sumw2=results[1] + histoinfo.positive.sumw2 = results[0] + histoinfo.negative.sumw2 = results[1] elif histoLogXTag.activated: - histologxinfo.positive.sumw2=results[0] - histologxinfo.negative.sumw2=results[1] + histologxinfo.positive.sumw2 = results[0] + histologxinfo.negative.sumw2 = results[1] - elif statisticsTag.Nlines==5 and not histoFreqTag.activated: - results = self.ExtractStatisticsFloat(words,numline,filename) + elif statisticsTag.Nlines == 5 and not histoFreqTag.activated: + results = self.ExtractStatisticsFloat(words, numline, filename) if histoTag.activated: - histoinfo.positive.sumwx=results[0] - histoinfo.negative.sumwx=results[1] + histoinfo.positive.sumwx = results[0] + histoinfo.negative.sumwx = results[1] elif histoLogXTag.activated: - histologxinfo.positive.sumwx=results[0] - histologxinfo.negative.sumwx=results[1] + histologxinfo.positive.sumwx = results[0] + histologxinfo.negative.sumwx = results[1] - elif statisticsTag.Nlines==6 and not histoFreqTag.activated: - results = self.ExtractStatisticsFloat(words,numline,filename) + elif statisticsTag.Nlines == 6 and not histoFreqTag.activated: + results = self.ExtractStatisticsFloat(words, numline, filename) if histoTag.activated: - histoinfo.positive.sumw2x=results[0] - histoinfo.negative.sumw2x=results[1] + histoinfo.positive.sumw2x = results[0] + histoinfo.negative.sumw2x = results[1] elif histoLogXTag.activated: - histologxinfo.positive.sumw2x=results[0] - histologxinfo.negative.sumw2x=results[1] + histologxinfo.positive.sumw2x = results[0] + histologxinfo.negative.sumw2x = results[1] else: - logging.getLogger('MA5').warning('Extra line is found: '+line) + logging.getLogger("MA5").warning("Extra line is found: " + line) statisticsTag.newline() # Looking from histogram data [ histo and histoLogX ] - elif dataTag.activated and len(words)==2 and (histoTag.activated or histoLogXTag.activated): - results = self.ExtractStatisticsFloat(words,numline,filename) - if dataTag.Nlines==0: + elif ( + dataTag.activated + and len(words) >= 2 + and (histoTag.activated or histoLogXTag.activated) + ): + results = self.ExtractStatisticsFloat(words, numline, filename) + if dataTag.Nlines == 0: if histoTag.activated: - histoinfo.positive.underflow=results[0] - histoinfo.negative.underflow=results[1] + histoinfo.positive.underflow = results[0] + histoinfo.negative.underflow = results[1] elif histoLogXTag.activated: - histologxinfo.positive.underflow=results[0] - histologxinfo.negative.underflow=results[1] - elif dataTag.Nlines==(histoinfo.nbins+1): + histologxinfo.positive.underflow = results[0] + histologxinfo.negative.underflow = results[1] + elif dataTag.Nlines == (histoinfo.nbins + 1): if histoTag.activated: - histoinfo.positive.overflow=results[0] - histoinfo.negative.overflow=results[1] + histoinfo.positive.overflow = results[0] + histoinfo.negative.overflow = results[1] elif histoLogXTag.activated: - histologxinfo.positive.overflow=results[0] - histologxinfo.negative.overflow=results[1] - elif dataTag.Nlines>=1 and dataTag.Nlines<=histoinfo.nbins: + histologxinfo.positive.overflow = results[0] + histologxinfo.negative.overflow = results[1] + elif dataTag.Nlines >= 1 and dataTag.Nlines <= histoinfo.nbins: if histoTag.activated or histoLogXTag.activated: data_positive.append(results[0]) data_negative.append(results[1]) else: - logging.getLogger('MA5').warning('Extra line is found: '+line) + logging.getLogger("MA5").warning("Extra line is found: " + line) dataTag.newline() # Looking from histogram data [ histoFreq ] - elif dataTag.activated and len(words)==3 and histoFreqTag.activated: - results = self.ExtractDataFreq(words,numline,filename) + elif dataTag.activated and len(words) == 3 and histoFreqTag.activated: + results = self.ExtractDataFreq(words, numline, filename) labels.append(results[0]) data_positive.append(results[1]) data_negative.append(results[2]) - dataTag.newline() + dataTag.newline() # Information found ? - if beginTag.Nactivated==0 or beginTag.activated: - logging.getLogger('MA5').error("histos.saf: SAF header <SAFheader> and </SAFheader> is not found.") - if endTag.Nactivated==0 or endTag.activated: - logging.getLogger('MA5').error("histos.saf: SAF footer <SAFfooter> and </SAFfooter> is not found.") + if beginTag.Nactivated == 0 or beginTag.activated: + logging.getLogger("MA5").error( + "histos.saf: SAF header <SAFheader> and </SAFheader> is not found." + ) + if endTag.Nactivated == 0 or endTag.activated: + logging.getLogger("MA5").error( + "histos.saf: SAF footer <SAFfooter> and </SAFfooter> is not found." + ) # Closing the file file.close() - def ExtractCuts(self,dataset,cut): + def ExtractCuts(self, dataset, cut): # Getting the output file name - name=InstanceName.Get(dataset.name) - i=0 - while(os.path.isdir(self.safdir+"/"+name+"/MadAnalysis5job_"+str(i))): - i+=1 - filenames = sorted(glob.glob(self.safdir+"/"+name+"/MadAnalysis5job_"+str(i-1)+"/Cutflows/*.saf")) + name = InstanceName.Get(dataset.name) + i = 0 + while os.path.isdir(self.safdir + "/" + name + "/MadAnalysis5job_" + str(i)): + i += 1 + filenames = sorted( + glob.glob( + self.safdir + "/" + name + "/MadAnalysis5job_" + str(i - 1) + "/Cutflows/*.saf" + ) + ) # Treating the files one by one for myfile in filenames: # Opening the file try: - file = open(myfile,'r') + file = open(myfile, "r") except: - logging.getLogger('MA5').error("File called '"+myfile+"' is not found") + logging.getLogger("MA5").error("File called '" + myfile + "' is not found") return # Initializing tags - beginTag = SafBlockStatus() - endTag = SafBlockStatus() - initialTag = SafBlockStatus() - cutTag = SafBlockStatus() - cutinfo = CutInfo() + beginTag = SafBlockStatus() + endTag = SafBlockStatus() + initialTag = SafBlockStatus() + cutTag = SafBlockStatus() + cutinfo = CutInfo() cutflow_for_region = [] # Loop over the lines - numline=0 + numline = 0 for line in file: # Incrementing line counter - numline+=1 + numline += 1 # Removing comments - index=line.find('#') - if index!=-1: - line=line[:index] + index = line.find("#") + if index != -1: + line = line[:index] # Treating line - line=line.lstrip() - line=line.rstrip() - words=line.split() - if len(words)==0: + line = line.lstrip() + line = line.rstrip() + words = line.split() + if len(words) == 0: continue # Looking for tag 'SampleGlobalInfo' - if len(words)==1 and words[0][0]=='<' and words[0][-1]=='>': - if words[0].lower()=='<safheader>': + if len(words) == 1 and words[0][0] == "<" and words[0][-1] == ">": + if words[0].lower() == "<safheader>": beginTag.activate() - elif words[0].lower()=='</safheader>': + elif words[0].lower() == "</safheader>": beginTag.desactivate() - elif words[0].lower()=='<saffooter>': + elif words[0].lower() == "<saffooter>": endTag.activate() - elif words[0].lower()=='</saffooter>': + elif words[0].lower() == "</saffooter>": endTag.desactivate() - elif words[0].lower()=='<initialcounter>': + elif words[0].lower() == "<initialcounter>": initialTag.activate() - elif words[0].lower()=='</initialcounter>': + elif words[0].lower() == "</initialcounter>": initialTag.desactivate() - elif words[0].lower()=='<counter>': + elif words[0].lower() == "<counter>": cutTag.activate() - elif words[0].lower()=='</counter>': + elif words[0].lower() == "</counter>": cutTag.desactivate() - cutinfo.cutregion = myfile.split('/')[-1].split('.')[:-1] + cutinfo.cutregion = myfile.split("/")[-1].split(".")[:-1] cutflow_for_region.append(copy.copy(cutinfo)) cutinfo.Reset() - elif initialTag.activated and len(words)==2: - results = self.ExtractCutLine(words,numline,myfile) - if initialTag.Nlines==0: + elif initialTag.activated and len(words) == 2: + results = self.ExtractCutLine(words, numline, myfile) + if initialTag.Nlines == 0: cut.initial.nentries_pos = results[0] cut.initial.nentries_neg = results[1] - elif initialTag.Nlines==1: + elif initialTag.Nlines == 1: cut.initial.sumw_pos = results[0] cut.initial.sumw_neg = results[1] - elif initialTag.Nlines==2: + elif initialTag.Nlines == 2: cut.initial.sumw2_pos = results[0] cut.initial.sumw2_neg = results[1] else: - logging.getLogger('MA5').warning('Extra line is found: '+line) + logging.getLogger("MA5").warning("Extra line is found: " + line) initialTag.newline() # Looking for cut counter elif cutTag.activated and '"' in line: - if cutTag.Nlines==0: + if cutTag.Nlines == 0: cutinfo.cutname = line.strip() else: - logging.getLogger('MA5').warning('Extra line is found: '+line) + logging.getLogger("MA5").warning("Extra line is found: " + line) cutTag.newline() - elif cutTag.activated and len(words)==2: - results = self.ExtractCutLine(words,numline,myfile) - if cutTag.Nlines==1: + elif cutTag.activated and len(words) == 2: + results = self.ExtractCutLine(words, numline, myfile) + if cutTag.Nlines == 1: cutinfo.nentries_pos = results[0] cutinfo.nentries_neg = results[1] - elif cutTag.Nlines==2: + elif cutTag.Nlines == 2: cutinfo.sumw_pos = results[0] cutinfo.sumw_neg = results[1] - elif cutTag.Nlines==3: + elif cutTag.Nlines == 3: cutinfo.sumw2_pos = results[0] cutinfo.sumw2_neg = results[1] else: - logging.getLogger('MA5').warning('Extra line is found: '+line) + logging.getLogger("MA5").warning("Extra line is found: " + line) cutTag.newline() # Information found ? - if beginTag.Nactivated==0 or beginTag.activated: - logging.getLogger('MA5').error(myfile.split('/')[-1]+": SAF header <SAFheader> and </SAFheader> is not found.") - if endTag.Nactivated==0 or endTag.activated: - logging.getLogger('MA5').error(myfile.split('/')[-1]+": SAF footer <SAFfooter> and </SAFfooter> is not found.") + if beginTag.Nactivated == 0 or beginTag.activated: + logging.getLogger("MA5").error( + myfile.split("/")[-1] + + ": SAF header <SAFheader> and </SAFheader> is not found." + ) + if endTag.Nactivated == 0 or endTag.activated: + logging.getLogger("MA5").error( + myfile.split("/")[-1] + + ": SAF footer <SAFfooter> and </SAFfooter> is not found." + ) # Closing the file file.close() diff --git a/madanalysis/interpreter/cmd_submit.py b/madanalysis/interpreter/cmd_submit.py index f8817048..9673584d 100644 --- a/madanalysis/interpreter/cmd_submit.py +++ b/madanalysis/interpreter/cmd_submit.py @@ -1,84 +1,83 @@ ################################################################################ -# +# # Copyright (C) 2012-2023 Jack Araz, Eric Conte & Benjamin Fuks # The MadAnalysis development team, email: <ma5team@iphc.cnrs.fr> -# +# # This file is part of MadAnalysis 5. # Official website: <https://github.com/MadAnalysis/madanalysis5> -# +# # MadAnalysis 5 is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. -# +# # MadAnalysis 5 is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. -# +# # You should have received a copy of the GNU General Public License # along with MadAnalysis 5. If not, see <http://www.gnu.org/licenses/> -# +# ################################################################################ from __future__ import absolute_import -from madanalysis.interpreter.cmd_base import CmdBase -from madanalysis.IOinterface.job_writer import JobWriter -from madanalysis.IOinterface.layout_writer import LayoutWriter -from madanalysis.IOinterface.job_reader import JobReader -from madanalysis.IOinterface.folder_writer import FolderWriter -from madanalysis.enumeration.report_format_type import ReportFormatType -from madanalysis.layout.layout import Layout -from madanalysis.install.install_manager import InstallManager -from madanalysis.install.detector_manager import DetectorManager -from madanalysis.misc.run_recast import RunRecast -from madanalysis.IOinterface.delphescard_checker import DelphesCardChecker - - -from chronometer import Chronometer -from string_tools import StringTools -import logging -import glob -import os -import shutil + +import logging, glob, os from six.moves import range +from madanalysis.interpreter.cmd_base import CmdBase +from madanalysis.IOinterface.job_writer import JobWriter +from madanalysis.IOinterface.layout_writer import LayoutWriter +from madanalysis.IOinterface.job_reader import JobReader +from madanalysis.enumeration.report_format_type import ReportFormatType +from madanalysis.layout.layout import Layout +from madanalysis.install.detector_manager import DetectorManager +from madanalysis.misc.run_recast import RunRecast +from madanalysis.IOinterface.delphescard_checker import DelphesCardChecker + +from chronometer import Chronometer +from string_tools import StringTools + + class CmdSubmit(CmdBase): """Command SUBMIT""" - def __init__(self,main,resubmit=False): - self.resubmit=resubmit + def __init__(self, main, resubmit=False): + self.resubmit = resubmit if not resubmit: - CmdBase.__init__(self,main,"submit") + CmdBase.__init__(self, main, "submit") else: - CmdBase.__init__(self,main,"resubmit") - self.forbiddenpaths=[] - self.forbiddenpaths.append(os.path.normpath(self.main.archi_info.ma5dir+'/lib')) - self.forbiddenpaths.append(os.path.normpath(self.main.archi_info.ma5dir+'/bin')) - self.forbiddenpaths.append(os.path.normpath(self.main.archi_info.ma5dir+'/madanalysis')) + CmdBase.__init__(self, main, "resubmit") + self.forbiddenpaths = [] + self.forbiddenpaths.append(os.path.normpath(self.main.archi_info.ma5dir + "/lib")) + self.forbiddenpaths.append(os.path.normpath(self.main.archi_info.ma5dir + "/bin")) + self.forbiddenpaths.append(os.path.normpath(self.main.archi_info.ma5dir + "/madanalysis")) - - def do(self,args,history): + def do(self, args, history): if not self.resubmit: - return self.do_submit(args,history) + return self.do_submit(args, history) else: - return self.do_resubmit(args,history) - + return self.do_resubmit(args, history) - def do_resubmit(self,args,history): + def do_resubmit(self, args, history): # Start time chrono = Chronometer() chrono.Start() # Checking argument number - if len(args)!=0: - self.logger.warning("Command 'resubmit' takes no argument. Any argument will be skipped.") + if len(args) != 0: + self.logger.warning( + "Command 'resubmit' takes no argument. Any argument will be skipped." + ) # Checking presence of a valid job if self.main.lastjob_name == "": - self.logger.error("an analysis must be defined and ran before using the resubmit command.") + self.logger.error( + "an analysis must be defined and ran before using the resubmit command." + ) return False self.main.lastjob_status = False @@ -88,20 +87,28 @@ def do_resubmit(self,args,history): # Look for the last submit and resubmit last_submit_cmd = -1 - for i in range(len(history)-1): # Last history entry should be resubmit - if history[i].startswith('submit') or history[i].startswith('resubmit'): + for i in range(len(history) - 1): # Last history entry should be resubmit + if history[i].startswith("submit") or history[i].startswith("resubmit"): last_submit_cmd = i newhistory = [] - if last_submit_cmd==-1: + if last_submit_cmd == -1: ToReAnalyze = True else: - for i in range(last_submit_cmd+1,len(history)): + for i in range(last_submit_cmd + 1, len(history)): newhistory.append(history[i]) - ReAnalyzeCmdList = ['plot','select','reject','set main.clustering', - 'set main.merging', 'define', 'set main.recast', - 'import', 'set main.isolation'] + ReAnalyzeCmdList = [ + "plot", + "select", + "reject", + "set main.clustering", + "set main.merging", + "define", + "set main.recast", + "import", + "set main.isolation", + ] # Determining if we have to resubmit the job for cmd in newhistory: @@ -110,14 +117,14 @@ def do_resubmit(self,args,history): words = cmd.split() # Creating a line with one whitespace between each word - cmd2 = '' + cmd2 = "" for word in words: - if word!='': - cmd2+=word+' ' + if word != "": + cmd2 += word + " " # Looping over patterns for pattern in ReAnalyzeCmdList: - if cmd2.startswith(pattern): + if cmd2.startswith(pattern): ToReAnalyze = True break @@ -128,7 +135,7 @@ def do_resubmit(self,args,history): if ToReAnalyze: self.logger.info(" Creating the new histograms and/or applying the new cuts...") # Submission - if not self.submit(self.main.lastjob_name,history): + if not self.submit(self.main.lastjob_name, history): return self.logger.info(" Updating the reports...") else: @@ -136,7 +143,7 @@ def do_resubmit(self,args,history): # Reading info from job output layout = Layout(self.main) - if not self.extract(self.main.lastjob_name,layout): + if not self.extract(self.main.lastjob_name, layout): return # Status = GOOD @@ -145,49 +152,53 @@ def do_resubmit(self,args,history): layout.Initialize() # Creating the reports - self.CreateReports([self.main.lastjob_name],history,layout) + self.CreateReports([self.main.lastjob_name], history, layout) - # End of time + # End of time chrono.Stop() - self.logger.info(" Well done! Elapsed time = "+chrono.Display()) + self.logger.info(" Well done! Elapsed time = " + chrono.Display()) - def do_submit(self,args,history): + def do_submit(self, args, history): # Start time chrono = Chronometer() chrono.Start() # No arguments - if len(args)==0: + if len(args) == 0: dirlist = os.listdir(self.main.currentdir) ii = 0 - while ('ANALYSIS_'+str(ii) in dirlist): - ii = ii+1 - args.append(self.main.currentdir+'/ANALYSIS_'+str(ii)) + while "ANALYSIS_" + str(ii) in dirlist: + ii = ii + 1 + args.append(self.main.currentdir + "/ANALYSIS_" + str(ii)) # Checking argument number - if len(args)>1: - self.logger.error("wrong number of arguments for the command 'submit'.") - self.help() - return + if len(args) > 1: + self.logger.error("wrong number of arguments for the command 'submit'.") + self.help() + return # Checking if a dataset has been defined - if len(self.main.datasets)==0: + if len(self.main.datasets) == 0: self.logger.error("no dataset found; please define a dataset (via the command import).") self.logger.error("job submission aborted.") return # Treat the filename filename = os.path.expanduser(args[0]) - if not filename.startswith('/'): + if not filename.startswith("/"): filename = self.main.currentdir + "/" + filename filename = os.path.normpath(filename) # Checking folder if filename in self.forbiddenpaths: - self.logger.error("the folder '"+filename+"' is a MadAnalysis folder. " + \ - "You cannot overwrite it. Please choose another folder.") + self.logger.error( + "the folder '" + + filename + + "' is a MadAnalysis folder. " + + "You cannot overwrite it. Please choose another folder." + ) return # Saving job name as global variable @@ -195,14 +206,14 @@ def do_submit(self,args,history): self.main.lastjob_status = False # Submission - self.logger.debug('Launching SampleAnalyzer ...') - if not self.submit(filename,history): + self.logger.debug("Launching SampleAnalyzer ...") + if not self.submit(filename, history): return # Reading info from job output - self.logger.debug('Go back to the Python interface ...') + self.logger.debug("Go back to the Python interface ...") layout = Layout(self.main) - if not self.extract(filename,layout): + if not self.extract(filename, layout): return # Status = GOOD @@ -213,34 +224,33 @@ def do_submit(self,args,history): layout.Initialize() # Creating the reports - if not self.main.recasting.status=="on": - self.CreateReports(args,history,layout) + if not self.main.recasting.status == "on": + self.CreateReports(args, history, layout) - # End of time + # End of time chrono.Stop() - self.logger.info(" Well done! Elapsed time = "+chrono.Display()) - + self.logger.info(" Well done! Elapsed time = " + chrono.Display()) # Generating the reports - def CreateReports(self,args,history,layout): + def CreateReports(self, args, history, layout): output_paths = [] - modes = [] + modes = [] # Getting output filename for histo folder - i=0 - while(os.path.isdir(args[0]+"/Output/Histos/MadAnalysis5job_"+str(i))): - i+=1 + i = 0 + while os.path.isdir(args[0] + "/Output/Histos/MadAnalysis5job_" + str(i)): + i += 1 - histopath = os.path.expanduser(args[0]+'/Output/Histos/MadAnalysis5job_'+str(i)) - if not histopath.startswith('/'): + histopath = os.path.expanduser(args[0] + "/Output/Histos/MadAnalysis5job_" + str(i)) + if not histopath.startswith("/"): histopath = self.main.currentdir + "/" + histopath histopath = os.path.normpath(histopath) # Getting output filename for HTML report - htmlpath = os.path.expanduser(args[0]+'/Output/HTML/MadAnalysis5job_'+str(i)) - if not htmlpath.startswith('/'): + htmlpath = os.path.expanduser(args[0] + "/Output/HTML/MadAnalysis5job_" + str(i)) + if not htmlpath.startswith("/"): htmlpath = self.main.currentdir + "/" + htmlpath htmlpath = os.path.normpath(htmlpath) output_paths.append(htmlpath) @@ -248,8 +258,8 @@ def CreateReports(self,args,history,layout): # Getting output filename for PDF report if self.main.session_info.has_pdflatex: - pdfpath = os.path.expanduser(args[0]+'/Output/PDF/MadAnalysis5job_'+str(i)) - if not pdfpath.startswith('/'): + pdfpath = os.path.expanduser(args[0] + "/Output/PDF/MadAnalysis5job_" + str(i)) + if not pdfpath.startswith("/"): pdfpath = self.main.currentdir + "/" + pdfpath pdfpath = os.path.normpath(pdfpath) output_paths.append(pdfpath) @@ -257,25 +267,25 @@ def CreateReports(self,args,history,layout): # Getting output filename for DVI report if self.main.session_info.has_latex: - dvipath = os.path.expanduser(args[0]+'/Output/DVI/MadAnalysis5job_'+str(i)) - if not dvipath.startswith('/'): + dvipath = os.path.expanduser(args[0] + "/Output/DVI/MadAnalysis5job_" + str(i)) + if not dvipath.startswith("/"): dvipath = self.main.currentdir + "/" + dvipath dvipath = os.path.normpath(dvipath) output_paths.append(dvipath) modes.append(ReportFormatType.LATEX) # Creating folders - if not layout.CreateFolders(histopath,output_paths,modes): + if not layout.CreateFolders(histopath, output_paths, modes): return # Draw plots self.logger.info(" Generating all plots ...") - if not layout.DoPlots(histopath,modes,output_paths): + if not layout.DoPlots(histopath, modes, output_paths): return # Generating the HTML report self.logger.info(" Generating the HMTL report ...") - layout.GenerateReport(history,htmlpath,ReportFormatType.HTML) + layout.GenerateReport(history, htmlpath, ReportFormatType.HTML) self.logger.info(" -> To open this HTML report, please type 'open'.") # PDF report @@ -283,14 +293,14 @@ def CreateReports(self,args,history,layout): # Generating the PDF report self.logger.info(" Generating the PDF report ...") - layout.GenerateReport(history,pdfpath,ReportFormatType.PDFLATEX) - layout.CompileReport(ReportFormatType.PDFLATEX,pdfpath) + layout.GenerateReport(history, pdfpath, ReportFormatType.PDFLATEX) + layout.CompileReport(ReportFormatType.PDFLATEX, pdfpath) # Displaying message for opening PDF if self.main.currentdir in pdfpath: - pdfpath = pdfpath[len(self.main.currentdir):] - if pdfpath[0]=='/': - pdfpath=pdfpath[1:] + pdfpath = pdfpath[len(self.main.currentdir) :] + if pdfpath[0] == "/": + pdfpath = pdfpath[1:] self.logger.info(" -> To open this PDF report, please type 'open " + pdfpath + "'.") else: @@ -301,59 +311,61 @@ def CreateReports(self,args,history,layout): # Warning message for DVI -> PDF self.logger.info(" Generating the DVI report ...") -# if not self.main.session_info.has_dvipdf: -# self.logger.warning("dvipdf not installed -> the DVI report will not be converted to a PDF file.") + # if not self.main.session_info.has_dvipdf: + # self.logger.warning("dvipdf not installed -> the DVI report will not be converted to a PDF file.") # Generating the DVI report - layout.GenerateReport(history,dvipath,ReportFormatType.LATEX) - layout.CompileReport(ReportFormatType.LATEX,dvipath) + layout.GenerateReport(history, dvipath, ReportFormatType.LATEX) + layout.CompileReport(ReportFormatType.LATEX, dvipath) # Displaying message for opening DVI if self.main.session_info.has_dvipdf: - pdfpath = os.path.expanduser(args[0]+'/Output/DVI/MadAnalysis5job_'+str(i)) + pdfpath = os.path.expanduser(args[0] + "/Output/DVI/MadAnalysis5job_" + str(i)) if self.main.currentdir in pdfpath: - pdfpath = pdfpath[len(self.main.currentdir):] - if pdfpath[0]=='/': - pdfpath=pdfpath[1:] - self.logger.info(" -> To open the corresponding Latex file, please type 'open " + pdfpath + "'.") + pdfpath = pdfpath[len(self.main.currentdir) :] + if pdfpath[0] == "/": + pdfpath = pdfpath[1:] + self.logger.info( + " -> To open the corresponding Latex file, please type 'open " + + pdfpath + + "'." + ) else: self.logger.warning("latex not installed -> no DVI/PDF report.") - - - def submit(self,dirname,history): + def submit(self, dirname, history): # checking if delphes is needed and installing/activating it if relevant detector_handler = DetectorManager(self.main) - if not detector_handler.manage('delphes'): - logging.getLogger('MA5').error('Problem with the handling of delphes/delphesMA5tune') + if not detector_handler.manage("delphes"): + logging.getLogger("MA5").error("Problem with the handling of delphes/delphesMA5tune") return False - if not detector_handler.manage('delphesMA5tune'): - logging.getLogger('MA5').error('Problem with the handling of delphes/delphesMA5tune') + if not detector_handler.manage("delphesMA5tune"): + logging.getLogger("MA5").error("Problem with the handling of delphes/delphesMA5tune") return False # Initializing the JobWriter - jobber = JobWriter(self.main,dirname,self.resubmit) + jobber = JobWriter(self.main, dirname, self.resubmit) # Writing process if not self.resubmit: - self.logger.info(" Creating folder '"+dirname.split('/')[-1] \ - +"'...") + self.logger.info(" Creating folder '" + dirname.split("/")[-1] + "'...") else: - self.logger.info(" Checking the structure of the folder '"+\ - dirname.split('/')[-1]+"'...") + self.logger.info( + " Checking the structure of the folder '" + dirname.split("/")[-1] + "'..." + ) if not jobber.Open(): self.logger.error("job submission aborted.") return False if not self.resubmit: - if self.main.recasting.status != 'on': + if self.main.recasting.status != "on": self.logger.info(" Copying 'SampleAnalyzer' source files...") if not jobber.CopyLHEAnalysis(): self.logger.error(" job submission aborted.") return False - if self.main.recasting.status != 'on' and not jobber.CreateBldDir(): + if self.main.recasting.status != "on" and not jobber.CreateBldDir(): self.logger.error(" job submission aborted.") return False @@ -383,26 +395,31 @@ def submit(self,dirname,history): jobber.WriteDatasetList(item) self.logger.info(" Writing the command line history...") - jobber.WriteHistory(history,self.main.firstdir) + jobber.WriteHistory(history, self.main.firstdir) if self.main.recasting.status == "on": - self.main.recasting.collect_outputs(dirname,self.main.datasets) - self.logger.info(' -> the results can be found in:') - self.logger.info(' '+ dirname + '/Output/SAF/CLs_output_summary.dat') + self.main.recasting.collect_outputs(dirname, self.main.datasets) + self.logger.info(" -> the results can be found in:") + self.logger.info(" " + dirname + "/Output/SAF/CLs_output_summary.dat") for item in self.main.datasets: - self.logger.info(' '+ dirname + '/Output/SAF/'+ item.name + '/CLs_output.dat') + self.logger.info( + " " + dirname + "/Output/SAF/" + item.name + "/CLs_output.dat" + ) else: layouter = LayoutWriter(self.main, dirname) layouter.WriteLayoutConfig() - if not self.main.recasting.status=='on' and not self.resubmit: + if not self.main.recasting.status == "on" and not self.resubmit: self.logger.info(" Creating Makefiles...") if not jobber.WriteMakefiles(): self.logger.error("job submission aborted.") return False # Edit & check the delphes or recasting cards - if self.main.fastsim.package in ["delphes","delphesMA5tune"] and not self.main.recasting.status=='on': - delphesCheck = DelphesCardChecker(dirname,self.main) + if ( + self.main.fastsim.package in ["delphes", "delphesMA5tune"] + and not self.main.recasting.status == "on" + ): + delphesCheck = DelphesCardChecker(dirname, self.main) if not delphesCheck.checkPresenceCard(): self.logger.error("job submission aborted.") return False @@ -427,23 +444,27 @@ def submit(self,dirname,history): root_dataset = True elif "lhco" in sample: lhco_dataset = True - if self.main.fastsim.package in ["delphes","delphesMA5tune"] or root_dataset: + if self.main.fastsim.package in ["delphes", "delphesMA5tune"] or root_dataset: os.environ["FASTJET_FLAG"] = "" elif self.main.fastsim.package in ["fastjet"] and hepmc_dataset: if root_dataset and hepmc_dataset: self.logger.error("ROOT input files not allowed for SFS-FastJet based analyses.") return False os.environ["FASTJET_FLAG"] = "-DMA5_FASTJET_MODE" - elif self.main.fastsim.package == 'none' and self.main.archi_info.has_fastjet and lhco_dataset: + elif ( + self.main.fastsim.package == "none" + and self.main.archi_info.has_fastjet + and lhco_dataset + ): os.environ["FASTJET_FLAG"] = "-DMA5_FASTJET_MODE" - if self.resubmit and not self.main.recasting.status=='on': + if self.resubmit and not self.main.recasting.status == "on": self.logger.info(" Cleaning 'SampleAnalyzer'...") if not jobber.MrproperJob(): self.logger.error("job submission aborted.") return False - if not self.main.recasting.status=='on': + if not self.main.recasting.status == "on": self.logger.info(" Compiling 'SampleAnalyzer'...") if not jobber.CompileJob(): self.logger.error("job submission aborted.") @@ -455,16 +476,14 @@ def submit(self,dirname,history): return False for item in self.main.datasets: - self.logger.info(" Running 'SampleAnalyzer' over dataset '" - +item.name+"'...") + self.logger.info(" Running 'SampleAnalyzer' over dataset '" + item.name + "'...") self.logger.info(" *******************************************************") if not jobber.RunJob(item): - self.logger.error("run over '"+item.name+"' aborted.") + self.logger.error("run over '" + item.name + "' aborted.") self.logger.info(" *******************************************************") return True - - def extract(self,dirname,layout): + def extract(self, dirname, layout): self.logger.info(" Checking SampleAnalyzer output...") jobber = JobReader(dirname) if not jobber.CheckDir(): @@ -472,54 +491,56 @@ def extract(self,dirname,layout): return False for item in self.main.datasets: - if self.main.recasting.status=='on': - if not self.main.recasting.CheckFile(dirname,item): + if self.main.recasting.status == "on": + if not self.main.recasting.CheckFile(dirname, item): return False elif not jobber.CheckFile(item): self.logger.error("errors have occured during the analysis.") return False - if self.main.recasting.status!='on': + if self.main.recasting.status != "on": self.logger.info(" Extracting data from the output files...") - for i in range(0,len(self.main.datasets)): - jobber.ExtractGeneral(self.main.datasets[i]) - jobber.ExtractHistos(self.main.datasets[i],layout.plotflow.detail[i]) - jobber.ExtractCuts(self.main.datasets[i],layout.cutflow.detail[i]) + for i, dataset in enumerate(self.main.datasets): + jobber.ExtractGeneral(dataset) + jobber.ExtractHistos(dataset, layout.plotflow.detail[i]) + jobber.ExtractCuts(dataset, layout.cutflow.detail[i]) if self.main.merging.enable: - jobber.ExtractHistos(self.main.datasets[i],layout.merging.detail[i],merging=True) + jobber.ExtractHistos(dataset, layout.merging.detail[i], merging=True) return True - def help(self): if not self.resubmit: self.logger.info(" Syntax: submit <dirname>") - self.logger.info(" Performs an analysis over a list of datasets. Output is stored into the directory <dirname>.") - self.logger.info(" If the optional argument is omitted, MadAnalysis creates a fresh directory automatically.") + self.logger.info( + " Performs an analysis over a list of datasets. Output is stored into the directory <dirname>." + ) + self.logger.info( + " If the optional argument is omitted, MadAnalysis creates a fresh directory automatically." + ) self.logger.info(" HTML and PDF reports are automatically created.") else: self.logger.info(" Syntax: resubmit") self.logger.info(" Update of an analysis already performed, if relevant.") self.logger.info(" In all cases, the HTML and PDF reports are regenerated.") + def complete(self, text, line, begidx, endidx): - def complete(self,text,line,begidx,endidx): - - #Resubmission case + # Resubmission case if self.resubmit: - return + return - #Getting back arguments + # Getting back arguments args = line.split() nargs = len(args) if not text: nargs += 1 - #Checking number of arguments - if nargs==2: - output=[] - for file in glob.glob(text+"*"): + # Checking number of arguments + if nargs == 2: + output = [] + for file in glob.glob(text + "*"): if os.path.isdir(file): output.append(file) - return self.finalize_complete(text,output) + return self.finalize_complete(text, output) else: return [] diff --git a/madanalysis/layout/plotflow.py b/madanalysis/layout/plotflow.py index f05a9115..e6864839 100644 --- a/madanalysis/layout/plotflow.py +++ b/madanalysis/layout/plotflow.py @@ -1,36 +1,36 @@ ################################################################################ -# +# # Copyright (C) 2012-2023 Jack Araz, Eric Conte & Benjamin Fuks # The MadAnalysis development team, email: <ma5team@iphc.cnrs.fr> -# +# # This file is part of MadAnalysis 5. # Official website: <https://github.com/MadAnalysis/madanalysis5> -# +# # MadAnalysis 5 is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. -# +# # MadAnalysis 5 is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. -# +# # You should have received a copy of the GNU General Public License # along with MadAnalysis 5. If not, see <http://www.gnu.org/licenses/> -# +# ################################################################################ from __future__ import absolute_import -from madanalysis.enumeration.uncertainty_type import UncertaintyType -from madanalysis.enumeration.normalize_type import NormalizeType -from madanalysis.enumeration.report_format_type import ReportFormatType -from madanalysis.enumeration.color_type import ColorType -from madanalysis.enumeration.linestyle_type import LineStyleType -from madanalysis.enumeration.backstyle_type import BackStyleType +from madanalysis.enumeration.uncertainty_type import UncertaintyType +from madanalysis.enumeration.normalize_type import NormalizeType +from madanalysis.enumeration.report_format_type import ReportFormatType +from madanalysis.enumeration.color_type import ColorType +from madanalysis.enumeration.linestyle_type import LineStyleType +from madanalysis.enumeration.backstyle_type import BackStyleType from madanalysis.enumeration.stacking_method_type import StackingMethodType -from madanalysis.layout.plotflow_for_dataset import PlotFlowForDataset +from madanalysis.layout.plotflow_for_dataset import PlotFlowForDataset import madanalysis.enumeration.color_hex import logging import six @@ -39,36 +39,34 @@ class PlotFlow: - diconicetitle = {' ^ {':'^{', ' _ {':'_{', '\\\\':'#'} + diconicetitle = {" ^ {": "^{", " _ {": "_{", "\\\\": "#"} - counter=0 - - def __init__(self,main): - self.main = main - self.detail = [] - for i in range(0,len(main.datasets)): - self.detail.append(PlotFlowForDataset(main,main.datasets[i])) + counter = 0 + def __init__(self, main): + self.main = main + self.detail = [] + for dataset in main.datasets: + self.detail.append(PlotFlowForDataset(main, dataset)) def Initialize(self): # Initializing NPID - if len(self.detail)>0: - for ihisto in range(0,len(self.detail[0])): + if len(self.detail) > 0: + for ihisto in range(0, len(self.detail[0])): if self.detail[0].histos[ihisto].__class__.__name__ == "HistogramFrequency": self.InitializeHistoFrequency(ihisto) # Creating plots - for i in range(0, len(self.detail)): - self.detail[i].FinalizeReading() - self.detail[i].ComputeScale() - self.detail[i].CreateHistogram() - + for detail in self.detail: + detail.FinalizeReading() + detail.ComputeScale() + detail.CreateHistogram() - def InitializeHistoFrequency(self,ihisto): + def InitializeHistoFrequency(self, ihisto): # New collection of labels - newlabels=[] + newlabels = [] # Loop over datasets for histo in self.detail: @@ -76,7 +74,7 @@ def InitializeHistoFrequency(self,ihisto): # Loop over the label for label in histo[ihisto].labels: - # Add in the collection + # Add in the collection if label not in newlabels: newlabels.append(label) @@ -87,9 +85,9 @@ def InitializeHistoFrequency(self,ihisto): for histo in self.detail: # New array for data - array_positive=[] - array_negative=[] - + array_positive = [] + array_negative = [] + # Loop over the new labels for newlabel in newlabels: @@ -99,7 +97,7 @@ def InitializeHistoFrequency(self,ihisto): value_negative = 0 for i in range(len(histo[ihisto].labels)): - if newlabel==histo[ihisto].labels[i]: + if newlabel == histo[ihisto].labels[i]: value_positive = histo[ihisto].positive.array[i] value_negative = histo[ihisto].negative.array[i] found = True @@ -110,729 +108,831 @@ def InitializeHistoFrequency(self,ihisto): array_positive.append(value_positive) array_negative.append(value_negative) else: - array_positive.append(0.) - array_negative.append(0.) + array_positive.append(0.0) + array_negative.append(0.0) # save result # PS: [:] -> clone the arrays histo[ihisto].positive.array = array_positive[:] histo[ihisto].negative.array = array_negative[:] - histo[ihisto].labels = newlabels[:] - + histo[ihisto].labels = newlabels[:] @staticmethod def NiceTitle(text): - newtext=text - for i,j in six.iteritems(PlotFlow.diconicetitle): - newtext = newtext.replace(i,j) + newtext = text + for i, j in six.iteritems(PlotFlow.diconicetitle): + newtext = newtext.replace(i, j) return newtext @staticmethod def NiceTitleMatplotlib(text): - text=PlotFlow.NiceTitle(text) - text=text.replace('#DeltaR','#Delta R') - text='$'+text.replace('#','\\\\')+'$' + text = PlotFlow.NiceTitle(text) + text = text.replace("#DeltaR", "#Delta R") + text = "$" + text.replace("#", "\\\\") + "$" return text - - def DrawAll(self,histo_path,modes,output_paths,ListROOTplots): + def DrawAll(self, histo_path, modes, output_paths, ListROOTplots): # Loop on each histo type - irelhisto=0 - for iabshisto in range(0,len(self.main.selection)): - if self.main.selection[iabshisto].__class__.__name__!="Histogram": + irelhisto = 0 + for iabshisto, select in enumerate(self.main.selection): + if select.__class__.__name__ != "Histogram": continue - self.color=1 - histos=[] - scales=[] + self.color = 1 + histos = [] + scales = [] # Name of output files - filenameC = histo_path+"/selection_"+str(irelhisto)+".C" - filenamePy = histo_path+"/selection_"+str(irelhisto)+".py" - - output_files=[] - for iout in range(0,len(output_paths)): - output_files.append('../../'+output_paths[iout].split('/')[-2]+'/'+\ - output_paths[iout].split('/')[-1]+"/selection_"+str(irelhisto)+"."+\ - ReportFormatType.convert2filetype(modes[iout])) - - for iset in range(0,len(self.detail)): - # Appending histo - histos.append(self.detail[iset][irelhisto]) -# if mode==2: - scales.append(self.detail[iset][irelhisto].scale) -# else: -# scales.append(1) - - logging.getLogger('MA5').debug('Producing file '+filenameC+' ...') - self.DrawROOT(histos,scales,self.main.selection[iabshisto],\ - irelhisto,filenameC,output_files) - - logging.getLogger('MA5').debug('Producing file '+filenamePy+' ...') - self.DrawMATPLOTLIB\ - (histos,scales,self.main.selection[iabshisto],\ - irelhisto,filenamePy,output_files) - - irelhisto+=1 - + filenameC = histo_path + "/selection_" + str(irelhisto) + ".C" + filenamePy = histo_path + "/selection_" + str(irelhisto) + ".py" + + output_files = [] + for iout, outp in enumerate(output_paths): + output_files.append( + "../../" + + outp.split("/")[-2] + + "/" + + outp.split("/")[-1] + + "/selection_" + + str(irelhisto) + + "." + + ReportFormatType.convert2filetype(modes[iout]) + ) + + for iset, detail in enumerate(self.detail): + # Appending histo + histos.append(detail[irelhisto]) + # if mode==2: + scales.append(detail[irelhisto].scale) + # else: + # scales.append(1) + + logging.getLogger("MA5").debug("Producing file " + filenameC + " ...") + if self.main.archi_info.has_root: + self.DrawROOT( + histos, + scales, + select, + irelhisto, + filenameC, + output_files, + ) + + logging.getLogger("MA5").debug("Producing file " + filenamePy + " ...") + self.DrawMATPLOTLIB(histos, scales, select, irelhisto, filenamePy, output_files) + + irelhisto += 1 # Save ROOT files - for ind in range(0,irelhisto): - ListROOTplots.append(histo_path+'/selection_'+str(ind)) - - return True + for ind in range(0, irelhisto): + ListROOTplots.append(histo_path + "/selection_" + str(ind)) + return True - def DrawROOT(self,histos,scales,ref,irelhisto,filenameC,outputnames): + def DrawROOT(self, histos, scales, ref, irelhisto, filenameC, outputnames): # Is there any legend? legendmode = False - if len(self.main.datasets)>1: + if len(self.main.datasets) > 1: legendmode = True # Type of histogram frequencyhisto = True for histo in histos: - if histo.__class__.__name__!='HistogramFrequency': + if histo.__class__.__name__ != "HistogramFrequency": frequencyhisto = False break logxhisto = True for histo in histos: - if histo.__class__.__name__!='HistogramLogX': + if histo.__class__.__name__ != "HistogramLogX": logxhisto = False break # Stacking or superimposing histos ? stackmode = False - if ref.stack==StackingMethodType.STACK or \ - ( ref.stack==StackingMethodType.AUTO and \ - self.main.stack==StackingMethodType.STACK ): - stackmode=True + if ref.stack == StackingMethodType.STACK or ( + ref.stack == StackingMethodType.AUTO and self.main.stack == StackingMethodType.STACK + ): + stackmode = True # Open the file in write-mode try: - outputC = open(filenameC,'w') + outputC = open(filenameC, "w") except: - logging.getLogger('MA5').error('Impossible to write the file: '+filenameC) + logging.getLogger("MA5").error("Impossible to write the file: " + filenameC) return False # File header function_name = filenameC[:-2] - function_name = function_name.split('/')[-1] - outputC.write('void '+function_name+'()\n') - outputC.write('{\n\n') + function_name = function_name.split("/")[-1] + outputC.write("void " + function_name + "()\n") + outputC.write("{\n\n") # ROOT version - outputC.write(' // ROOT version\n') - outputC.write(' Int_t root_version = gROOT->GetVersionInt();\n') - outputC.write('\n') + outputC.write(" // ROOT version\n") + outputC.write(" Int_t root_version = gROOT->GetVersionInt();\n") + outputC.write("\n") # Creating the TCanvas - PlotFlow.counter=PlotFlow.counter+1 - canvas_name='canvas_plotflow_tempo'+str(PlotFlow.counter) - outputC.write(' // Creating a new TCanvas\n') - widthx=700 + PlotFlow.counter = PlotFlow.counter + 1 + canvas_name = "canvas_plotflow_tempo" + str(PlotFlow.counter) + outputC.write(" // Creating a new TCanvas\n") + widthx = 700 if legendmode: - widthx=1000 - outputC.write(' TCanvas* canvas = new TCanvas("'+canvas_name+'","'+canvas_name+'",0,0,'+str(widthx)+',500);\n') - outputC.write(' gStyle->SetOptStat(0);\n') - outputC.write(' gStyle->SetOptTitle(0);\n') - outputC.write(' canvas->SetHighLightColor(2);\n') -# outputC.write(' canvas->Range(-2.419355,-0.005372711,16.93548,0.03939988);\n') - outputC.write(' canvas->SetFillColor(0);\n') - outputC.write(' canvas->SetBorderMode(0);\n') - outputC.write(' canvas->SetBorderSize(3);\n') - outputC.write(' canvas->SetFrameBorderMode(0);\n') - outputC.write(' canvas->SetFrameBorderSize(0);\n') - outputC.write(' canvas->SetTickx(1);\n') - outputC.write(' canvas->SetTicky(1);\n') - outputC.write(' canvas->SetLeftMargin(0.14);\n') - margin=0.05 + widthx = 1000 + outputC.write( + ' TCanvas* canvas = new TCanvas("' + + canvas_name + + '","' + + canvas_name + + '",0,0,' + + str(widthx) + + ",500);\n" + ) + outputC.write(" gStyle->SetOptStat(0);\n") + outputC.write(" gStyle->SetOptTitle(0);\n") + outputC.write(" canvas->SetHighLightColor(2);\n") + # outputC.write(' canvas->Range(-2.419355,-0.005372711,16.93548,0.03939988);\n') + outputC.write(" canvas->SetFillColor(0);\n") + outputC.write(" canvas->SetBorderMode(0);\n") + outputC.write(" canvas->SetBorderSize(3);\n") + outputC.write(" canvas->SetFrameBorderMode(0);\n") + outputC.write(" canvas->SetFrameBorderSize(0);\n") + outputC.write(" canvas->SetTickx(1);\n") + outputC.write(" canvas->SetTicky(1);\n") + outputC.write(" canvas->SetLeftMargin(0.14);\n") + margin = 0.05 if legendmode: - margin=0.3 - outputC.write(' canvas->SetRightMargin('+str(margin)+');\n') - outputC.write(' canvas->SetBottomMargin(0.15);\n') - outputC.write(' canvas->SetTopMargin(0.05);\n') - outputC.write('\n') + margin = 0.3 + outputC.write(" canvas->SetRightMargin(" + str(margin) + ");\n") + outputC.write(" canvas->SetBottomMargin(0.15);\n") + outputC.write(" canvas->SetTopMargin(0.05);\n") + outputC.write("\n") # Binning - xnbin=histos[0].nbins + xnbin = histos[0].nbins if logxhisto: - outputC.write(' // Histo binning\n') - outputC.write(' Double_t xBinning['+str(xnbin+1)+'] = {') - for bin in range(1,xnbin+2): - if bin!=1: - outputC.write(',') + outputC.write(" // Histo binning\n") + outputC.write(" Double_t xBinning[" + str(xnbin + 1) + "] = {") + for bin in range(1, xnbin + 2): + if bin != 1: + outputC.write(",") outputC.write(str(histos[0].GetBinLowEdge(bin))) - outputC.write('};\n') - outputC.write('\n') + outputC.write("};\n") + outputC.write("\n") # Loop over datasets and histos ntot = 0 - for ind in range(0,len(histos)): + for ind, hist in enumerate(histos): # Creating TH1F - outputC.write(' // Creating a new TH1F\n') - histoname="S"+histos[ind].name+'_'+str(ind) - xmin=histos[ind].xmin - xmax=histos[ind].xmax + outputC.write(" // Creating a new TH1F\n") + histoname = "S" + hist.name + "_" + str(ind) + xmin = hist.xmin + xmax = hist.xmax if logxhisto: - outputC.write(' TH1F* '+histoname+' = new TH1F("'+histoname+'","'+\ - histoname+'",'+str(xnbin)+',xBinning);\n') + outputC.write( + " TH1F* " + + histoname + + ' = new TH1F("' + + histoname + + '","' + + histoname + + '",' + + str(xnbin) + + ",xBinning);\n" + ) else: - outputC.write(' TH1F* '+histoname+' = new TH1F("'+histoname+'","'+\ - histoname+'",'+str(xnbin)+','+\ - str(xmin)+','+str(xmax)+');\n') + outputC.write( + " TH1F* " + + histoname + + ' = new TH1F("' + + histoname + + '","' + + histoname + + '",' + + str(xnbin) + + "," + + str(xmin) + + "," + + str(xmax) + + ");\n" + ) # TH1F content - outputC.write(' // Content\n') - outputC.write(' '+histoname+'->SetBinContent(0'+\ - ','+str(histos[ind].summary.underflow*scales[ind])+'); // underflow\n') - for bin in range(1,xnbin+1): - ntot+= histos[ind].summary.array[bin-1]*scales[ind] - outputC.write(' '+histoname+'->SetBinContent('+str(bin)+\ - ','+str(histos[ind].summary.array[bin-1]*scales[ind])+');\n') - nentries=histos[ind].summary.nentries - outputC.write(' '+histoname+'->SetBinContent('+str(xnbin+1)+\ - ','+str(histos[ind].summary.overflow*scales[ind])+'); // overflow\n') - outputC.write(' '+histoname+'->SetEntries('+str(nentries)+');\n') + outputC.write(" // Content\n") + outputC.write( + " " + + histoname + + "->SetBinContent(0" + + "," + + str(hist.summary.underflow * scales[ind]) + + "); // underflow\n" + ) + for bin in range(1, xnbin + 1): + print(hist.summary.array, scales) + ntot += hist.summary.array[bin - 1] * scales[ind] + outputC.write( + " " + + histoname + + "->SetBinContent(" + + str(bin) + + "," + + str(hist.summary.array[bin - 1] * scales[ind]) + + ");\n" + ) + nentries = hist.summary.nentries + outputC.write( + " " + + histoname + + "->SetBinContent(" + + str(xnbin + 1) + + "," + + str(hist.summary.overflow * scales[ind]) + + "); // overflow\n" + ) + outputC.write(" " + histoname + "->SetEntries(" + str(nentries) + ");\n") # reset - linecolor=0 - linestyle=0 - backcolor=0 - backstyle=0 - linewidth=1 + linecolor = 0 + linestyle = 0 + backcolor = 0 + backstyle = 0 + linewidth = 1 # Setting AUTO settings - if len(histos)==1: + if len(histos) == 1: linecolor1 = [9] - linecolor = linecolor1[ind] + linecolor = linecolor1[ind] if stackmode: backstyle1 = [3004] - backstyle = backstyle1[ind] - backcolor = linecolor1[ind] - elif len(histos)==2: - linecolor2 = [9,46] - linecolor = linecolor2[ind] + backstyle = backstyle1[ind] + backcolor = linecolor1[ind] + elif len(histos) == 2: + linecolor2 = [9, 46] + linecolor = linecolor2[ind] if stackmode: - backstyle2 = [3004,3005] - backstyle = backstyle2[ind] - backcolor = linecolor2[ind] - elif len(histos)==3: - linecolor3 = [9,46,8] - linecolor = linecolor3[ind] + backstyle2 = [3004, 3005] + backstyle = backstyle2[ind] + backcolor = linecolor2[ind] + elif len(histos) == 3: + linecolor3 = [9, 46, 8] + linecolor = linecolor3[ind] if stackmode: - backstyle3 = [3004,3005,3006] - backstyle = backstyle3[ind] - backcolor = linecolor3[ind] - elif len(histos)==4: - linecolor4 = [9,46,8,4] - linecolor = linecolor4[ind] + backstyle3 = [3004, 3005, 3006] + backstyle = backstyle3[ind] + backcolor = linecolor3[ind] + elif len(histos) == 4: + linecolor4 = [9, 46, 8, 4] + linecolor = linecolor4[ind] if stackmode: - backstyle4 = [3004,3005,3006,3007] - backstyle = backstyle4[ind] - backcolor = linecolor4[ind] - elif len(histos)==5: - linecolor5 = [9,46,8,4,6] - linecolor = linecolor5[ind] + backstyle4 = [3004, 3005, 3006, 3007] + backstyle = backstyle4[ind] + backcolor = linecolor4[ind] + elif len(histos) == 5: + linecolor5 = [9, 46, 8, 4, 6] + linecolor = linecolor5[ind] if stackmode: - backstyle5 = [3004,3005,3006,3007,3013] - backstyle = backstyle5[ind] - backcolor = linecolor5[ind] - elif len(histos)==6: - linecolor6 = [9,46,8,4,6,2] - linecolor = linecolor6[ind] + backstyle5 = [3004, 3005, 3006, 3007, 3013] + backstyle = backstyle5[ind] + backcolor = linecolor5[ind] + elif len(histos) == 6: + linecolor6 = [9, 46, 8, 4, 6, 2] + linecolor = linecolor6[ind] if stackmode: - backstyle6 = [3004,3005,3006,3007,3013,3017] - backstyle = backstyle6[ind] - backcolor = linecolor6[ind] - elif len(histos)==7: - linecolor7 = [9,46,8,4,6,2,7] - linecolor = linecolor7[ind] + backstyle6 = [3004, 3005, 3006, 3007, 3013, 3017] + backstyle = backstyle6[ind] + backcolor = linecolor6[ind] + elif len(histos) == 7: + linecolor7 = [9, 46, 8, 4, 6, 2, 7] + linecolor = linecolor7[ind] if stackmode: - backstyle7 = [3004,3005,3006,3007,3013,3017,3022] - backstyle = backstyle7[ind] - backcolor = linecolor7[ind] - elif len(histos)==8: - linecolor8 = [9,46,8,4,6,2,7,3] - linecolor = linecolor8[ind] + backstyle7 = [3004, 3005, 3006, 3007, 3013, 3017, 3022] + backstyle = backstyle7[ind] + backcolor = linecolor7[ind] + elif len(histos) == 8: + linecolor8 = [9, 46, 8, 4, 6, 2, 7, 3] + linecolor = linecolor8[ind] if stackmode: - backstyle8 = [3004,3005,3006,3007,3013,3017,3022,3315] - backstyle = backstyle8[ind] - backcolor = linecolor8[ind] - elif len(histos)==9: - linecolor9 = [9,46,8,4,6,2,7,3,42] - linecolor = linecolor9[ind] + backstyle8 = [3004, 3005, 3006, 3007, 3013, 3017, 3022, 3315] + backstyle = backstyle8[ind] + backcolor = linecolor8[ind] + elif len(histos) == 9: + linecolor9 = [9, 46, 8, 4, 6, 2, 7, 3, 42] + linecolor = linecolor9[ind] if stackmode: - backstyle9 = [3004,3005,3006,3007,3013,3017,3022,3315,3351] - backstyle = backstyle9[ind] - backcolor = linecolor9[ind] - elif len(histos)==10: - linecolor10 = [9,46,8,4,6,2,7,3,42,48] - linecolor = linecolor10[ind] + backstyle9 = [3004, 3005, 3006, 3007, 3013, 3017, 3022, 3315, 3351] + backstyle = backstyle9[ind] + backcolor = linecolor9[ind] + elif len(histos) == 10: + linecolor10 = [9, 46, 8, 4, 6, 2, 7, 3, 42, 48] + linecolor = linecolor10[ind] if stackmode: - backstyle10 = [3004,3005,3006,3007,3013,3017,3022,3315,3351,3481] - backstyle = backstyle10[ind] - backcolor = linecolor10[ind] + backstyle10 = [3004, 3005, 3006, 3007, 3013, 3017, 3022, 3315, 3351, 3481] + backstyle = backstyle10[ind] + backcolor = linecolor10[ind] else: - linecolor=self.color + linecolor = self.color self.color += 1 # linecolor - if self.main.datasets[ind].linecolor!=ColorType.AUTO: - linecolor=ColorType.convert2root( \ - self.main.datasets[ind].linecolor,\ - self.main.datasets[ind].lineshade) + if self.main.datasets[ind].linecolor != ColorType.AUTO: + linecolor = ColorType.convert2root( + self.main.datasets[ind].linecolor, self.main.datasets[ind].lineshade + ) # lineStyle - linestyle=LineStyleType.convert2code(self.main.datasets[ind].linestyle) + linestyle = LineStyleType.convert2code(self.main.datasets[ind].linestyle) # linewidth - linewidth=self.main.datasets[ind].linewidth + linewidth = self.main.datasets[ind].linewidth # background color - if self.main.datasets[ind].backcolor!=ColorType.AUTO: - backcolor=ColorType.convert2root( \ - self.main.datasets[ind].backcolor,\ - self.main.datasets[ind].backshade) + if self.main.datasets[ind].backcolor != ColorType.AUTO: + backcolor = ColorType.convert2root( + self.main.datasets[ind].backcolor, self.main.datasets[ind].backshade + ) - # background color - if self.main.datasets[ind].backstyle!=BackStyleType.AUTO: - backstyle=BackStyleType.convert2code( \ - self.main.datasets[ind].backstyle) + # background color + if self.main.datasets[ind].backstyle != BackStyleType.AUTO: + backstyle = BackStyleType.convert2code(self.main.datasets[ind].backstyle) # style - outputC.write(' // Style\n') - outputC.write(' '+histoname+'->SetLineColor('+str(linecolor)+');\n') - outputC.write(' '+histoname+'->SetLineStyle('+str(linestyle)+');\n') - outputC.write(' '+histoname+'->SetLineWidth('+str(linewidth)+');\n') - outputC.write(' '+histoname+'->SetFillColor('+str(backcolor)+');\n') - outputC.write(' '+histoname+'->SetFillStyle('+str(backstyle)+');\n') + outputC.write(" // Style\n") + outputC.write(" " + histoname + "->SetLineColor(" + str(linecolor) + ");\n") + outputC.write(" " + histoname + "->SetLineStyle(" + str(linestyle) + ");\n") + outputC.write(" " + histoname + "->SetLineWidth(" + str(linewidth) + ");\n") + outputC.write(" " + histoname + "->SetFillColor(" + str(backcolor) + ");\n") + outputC.write(" " + histoname + "->SetFillStyle(" + str(backstyle) + ");\n") if frequencyhisto: - outputC.write(' '+histoname+'->SetBarWidth(0.8);\n') - outputC.write(' '+histoname+'->SetBarOffset(0.1);\n') - outputC.write('\n') + outputC.write(" " + histoname + "->SetBarWidth(0.8);\n") + outputC.write(" " + histoname + "->SetBarOffset(0.1);\n") + outputC.write("\n") # Creating the THStack - outputC.write(' // Creating a new THStack\n') - PlotFlow.counter+=1 - outputC.write(' THStack* stack = new THStack("mystack_'+str(PlotFlow.counter)+'","mystack");\n') + outputC.write(" // Creating a new THStack\n") + PlotFlow.counter += 1 + outputC.write( + ' THStack* stack = new THStack("mystack_' + str(PlotFlow.counter) + '","mystack");\n' + ) # Loop over datasets and histos - for ind in range(0,len(histos)): - histoname='S'+histos[ind].name+'_'+str(ind) - outputC.write(' stack->Add('+histoname+');\n') + for ind in range(0, len(histos)): + histoname = "S" + histos[ind].name + "_" + str(ind) + outputC.write(" stack->Add(" + histoname + ");\n") - drawoptions=[] + drawoptions = [] if not stackmode: - drawoptions.append('nostack') + drawoptions.append("nostack") if frequencyhisto: - drawoptions.append('bar1') - outputC.write(' stack->Draw("'+''.join(drawoptions)+'");\n') - outputC.write('\n') + drawoptions.append("bar1") + outputC.write(' stack->Draw("' + "".join(drawoptions) + '");\n') + outputC.write("\n") # Setting Y axis label - outputC.write(' // Y axis\n') + outputC.write(" // Y axis\n") axis_titleY = ref.GetYaxis() # Scale to one ? scale2one = False - if ref.stack==StackingMethodType.NORMALIZE2ONE or \ - (self.main.stack==StackingMethodType.NORMALIZE2ONE and \ - ref.stack==StackingMethodType.AUTO): + if ref.stack == StackingMethodType.NORMALIZE2ONE or ( + self.main.stack == StackingMethodType.NORMALIZE2ONE + and ref.stack == StackingMethodType.AUTO + ): scale2one = True if scale2one: axis_titleY += " ( scaled to one )" - elif self.main.normalize == NormalizeType.LUMI or \ - self.main.normalize == NormalizeType.LUMI_WEIGHT: - axis_titleY += " ( L_{int} = " + str(self.main.lumi)+ " fb^{-1} )" + elif ( + self.main.normalize == NormalizeType.LUMI + or self.main.normalize == NormalizeType.LUMI_WEIGHT + ): + axis_titleY += " ( L_{int} = " + str(self.main.lumi) + " fb^{-1} )" elif self.main.normalize == NormalizeType.NONE: axis_titleY += " (not normalized)" - if ref.titleY!="": + if ref.titleY != "": axis_titleY = PlotFlow.NiceTitle(ref.titleY) - if(len(axis_titleY) > 35): - titlesize=0.04 + if len(axis_titleY) > 35: + titlesize = 0.04 else: - titlesize=0.06 - outputC.write(' stack->GetYaxis()->SetLabelSize(0.04);\n') - outputC.write(' stack->GetYaxis()->SetLabelOffset(0.005);\n') - outputC.write(' stack->GetYaxis()->SetTitleSize('+str(titlesize)+');\n') - outputC.write(' stack->GetYaxis()->SetTitleFont(22);\n') - outputC.write(' stack->GetYaxis()->SetTitleOffset(1);\n') - outputC.write(' stack->GetYaxis()->SetTitle("'+axis_titleY+'");\n') - if ref.ymin!=[]: - outputC.write(' stack->SetMinimum('+str(ref.ymin)+');\n') - if ref.ymax!=[]: - outputC.write(' stack->SetMaximum('+str(ref.ymax)+');\n') - - outputC.write('\n') - outputC.write(' // X axis\n') + titlesize = 0.06 + outputC.write(" stack->GetYaxis()->SetLabelSize(0.04);\n") + outputC.write(" stack->GetYaxis()->SetLabelOffset(0.005);\n") + outputC.write(" stack->GetYaxis()->SetTitleSize(" + str(titlesize) + ");\n") + outputC.write(" stack->GetYaxis()->SetTitleFont(22);\n") + outputC.write(" stack->GetYaxis()->SetTitleOffset(1);\n") + outputC.write(' stack->GetYaxis()->SetTitle("' + axis_titleY + '");\n') + if ref.ymin != []: + outputC.write(" stack->SetMinimum(" + str(ref.ymin) + ");\n") + if ref.ymax != []: + outputC.write(" stack->SetMaximum(" + str(ref.ymax) + ");\n") + + outputC.write("\n") + outputC.write(" // X axis\n") # Setting X axis label - if ref.titleX=="": + if ref.titleX == "": axis_titleX = ref.GetXaxis_Root() else: axis_titleX = PlotFlow.NiceTitle(ref.titleX) # Setting X axis label - outputC.write(' stack->GetXaxis()->SetLabelSize(0.04);\n') - outputC.write(' stack->GetXaxis()->SetLabelOffset(0.005);\n') - outputC.write(' stack->GetXaxis()->SetTitleSize(0.06);\n') - outputC.write(' stack->GetXaxis()->SetTitleFont(22);\n') - outputC.write(' stack->GetXaxis()->SetTitleOffset(1);\n') - outputC.write(' stack->GetXaxis()->SetTitle("'+axis_titleX+'");\n') + outputC.write(" stack->GetXaxis()->SetLabelSize(0.04);\n") + outputC.write(" stack->GetXaxis()->SetLabelOffset(0.005);\n") + outputC.write(" stack->GetXaxis()->SetTitleSize(0.06);\n") + outputC.write(" stack->GetXaxis()->SetTitleFont(22);\n") + outputC.write(" stack->GetXaxis()->SetTitleOffset(1);\n") + outputC.write(' stack->GetXaxis()->SetTitle("' + axis_titleX + '");\n') if frequencyhisto: - for bin in range(1,xnbin+1): - outputC.write(' stack->GetXaxis()->SetBinLabel('+str(bin)+','\ - '"'+str(histos[ind].stringlabels[bin-1])+'");\n') - outputC.write('\n') + for bin in range(1, xnbin + 1): + outputC.write( + " stack->GetXaxis()->SetBinLabel(" + str(bin) + "," + '"' + str(histos[ind].stringlabels[bin - 1]) + '");\n' + ) + outputC.write("\n") # Setting Log scale - outputC.write(' // Finalizing the TCanvas\n') - logx=0 + outputC.write(" // Finalizing the TCanvas\n") + logx = 0 if ref.logX and ntot != 0: - logx=1 - logy=0 + logx = 1 + logy = 0 if ref.logY and ntot != 0: - logy=1 - outputC.write(' canvas->SetLogx('+str(logx)+');\n') - outputC.write(' canvas->SetLogy('+str(logy)+');\n') - outputC.write('\n') + logy = 1 + outputC.write(" canvas->SetLogx(" + str(logx) + ");\n") + outputC.write(" canvas->SetLogy(" + str(logy) + ");\n") + outputC.write("\n") # Displaying a legend if legendmode: - outputC.write(' // Creating a TLegend\n') - outputC.write(' TLegend* legend = new TLegend(.73,.5,.97,.95);\n') - for ind in range(0,len(histos)): - histoname='S'+histos[ind].name+'_'+str(ind) - nicetitle=PlotFlow.NiceTitle(self.main.datasets[ind].title) - outputC.write(' legend->AddEntry('+histoname+',"'+nicetitle+'");\n') - outputC.write(' legend->SetFillColor(0);\n') - outputC.write(' legend->SetTextSize(0.05);\n') - outputC.write(' legend->SetTextFont(22);\n') - outputC.write(' legend->SetY1(TMath::Max(0.15,0.97-0.10*legend->GetListOfPrimitives()->GetSize()));\n') - outputC.write(' legend->Draw();\n') - outputC.write('\n') + outputC.write(" // Creating a TLegend\n") + outputC.write(" TLegend* legend = new TLegend(.73,.5,.97,.95);\n") + for ind in range(0, len(histos)): + histoname = "S" + histos[ind].name + "_" + str(ind) + nicetitle = PlotFlow.NiceTitle(self.main.datasets[ind].title) + outputC.write(" legend->AddEntry(" + histoname + ',"' + nicetitle + '");\n') + outputC.write(" legend->SetFillColor(0);\n") + outputC.write(" legend->SetTextSize(0.05);\n") + outputC.write(" legend->SetTextFont(22);\n") + outputC.write( + " legend->SetY1(TMath::Max(0.15,0.97-0.10*legend->GetListOfPrimitives()->GetSize()));\n" + ) + outputC.write(" legend->Draw();\n") + outputC.write("\n") # Producing the image - outputC.write(' // Saving the image\n') + outputC.write(" // Saving the image\n") for outputname in outputnames: - outputC.write(' canvas->SaveAs("'+outputname+'");\n') - outputC.write('\n') + outputC.write(' canvas->SaveAs("' + outputname + '");\n') + outputC.write("\n") # File foot - outputC.write('}\n') + outputC.write("}\n") # Close the file try: outputC.close() except: - logging.getLogger('MA5').error('Impossible to close the file: '+outputC) + logging.getLogger("MA5").error("Impossible to close the file: " + outputC) return False # Ok return True - - - def DrawMATPLOTLIB(self,histos,scales,ref,irelhisto,filenamePy,outputnames): + def DrawMATPLOTLIB(self, histos, scales, ref, irelhisto, filenamePy, outputnames): # Is there any legend? legendmode = False - if len(self.main.datasets)>1: + if len(self.main.datasets) > 1: legendmode = True # Type of histogram frequencyhisto = True for histo in histos: - if histo.__class__.__name__!='HistogramFrequency': + if histo.__class__.__name__ != "HistogramFrequency": frequencyhisto = False break logxhisto = True for histo in histos: - if histo.__class__.__name__!='HistogramLogX': + if histo.__class__.__name__ != "HistogramLogX": logxhisto = False break # Stacking or superimposing histos ? stackmode = False - if ref.stack==StackingMethodType.STACK or \ - ( ref.stack==StackingMethodType.AUTO and \ - self.main.stack==StackingMethodType.STACK ): - stackmode=True - + if ref.stack == StackingMethodType.STACK or ( + ref.stack == StackingMethodType.AUTO and self.main.stack == StackingMethodType.STACK + ): + stackmode = True # Open the file in write-mode try: - outputPy = open(filenamePy,'w') + outputPy = open(filenamePy, "w") except: - logging.getLogger('MA5').error('Impossible to write the file: '+filenamePy) + logging.getLogger("MA5").error("Impossible to write the file: " + filenamePy) return False # File header function_name = filenamePy[:-3] - function_name = function_name.split('/')[-1] - outputPy.write('def '+function_name+'():\n') - outputPy.write('\n') + function_name = function_name.split("/")[-1] + outputPy.write("def " + function_name + "():\n") + outputPy.write("\n") # Import Libraries - outputPy.write(' # Library import\n') - outputPy.write(' import numpy\n') - outputPy.write(' import matplotlib\n') -# outputPy.write(" matplotlib.use('Agg')\n") - outputPy.write(' import matplotlib.pyplot as plt\n') - outputPy.write(' import matplotlib.gridspec as gridspec\n') - outputPy.write('\n') + outputPy.write(" # Library import\n") + outputPy.write(" import numpy\n") + outputPy.write(" import matplotlib\n") + # outputPy.write(" matplotlib.use('Agg')\n") + outputPy.write(" import matplotlib.pyplot as plt\n") + outputPy.write(" import matplotlib.gridspec as gridspec\n") + outputPy.write("\n") # Matplotlib & numpy version - outputPy.write(' # Library version\n') - outputPy.write(' matplotlib_version = matplotlib.__version__\n') - outputPy.write(' numpy_version = numpy.__version__\n') - outputPy.write('\n') + outputPy.write(" # Library version\n") + outputPy.write(" matplotlib_version = matplotlib.__version__\n") + outputPy.write(" numpy_version = numpy.__version__\n") + outputPy.write("\n") # Binning # Loop over datasets and histos - xnbin=histos[0].nbins - xmin =histos[0].xmin - xmax =histos[0].xmax - outputPy.write(' # Histo binning\n') + xnbin = histos[0].nbins + xmin = histos[0].xmin + xmax = histos[0].xmax + outputPy.write(" # Histo binning\n") if logxhisto: - outputPy.write(' xBinning = [') - for bin in range(1,xnbin+2): - if bin!=1: - outputPy.write(',') + outputPy.write(" xBinning = [") + for bin in range(1, xnbin + 2): + if bin != 1: + outputPy.write(",") outputPy.write(str(histos[0].GetBinLowEdge(bin))) - outputPy.write(']\n') - outputPy.write('\n') + outputPy.write("]\n") + outputPy.write("\n") else: - outputPy.write(' xBinning = numpy.linspace('+\ - str(xmin)+','+str(xmax)+','+str(xnbin+1)+\ - ',endpoint=True)\n') - outputPy.write('\n') - + outputPy.write( + " xBinning = numpy.linspace(" + + str(xmin) + + "," + + str(xmax) + + "," + + str(xnbin + 1) + + ",endpoint=True)\n" + ) + outputPy.write("\n") # Data - outputPy.write(' # Creating data sequence: middle of each bin\n') - outputPy.write(' xData = numpy.array([') - for bin in range(0,xnbin): - if bin!=0: - outputPy.write(',') + outputPy.write(" # Creating data sequence: middle of each bin\n") + outputPy.write(" xData = numpy.array([") + for bin in range(0, xnbin): + if bin != 0: + outputPy.write(",") outputPy.write(str(histos[0].GetBinMean(bin))) - outputPy.write('])\n\n') + outputPy.write("])\n\n") # Loop over datasets and histos ntot = 0 - for ind in range(0,len(histos)): + for ind, hist in enumerate(histos): # Creating a new histo - histoname='y'+histos[ind].name+'_'+str(ind) - outputPy.write(' # Creating weights for histo: '+histoname+'\n') - outputPy.write(' '+histoname+'_weights = numpy.array([') - for bin in range(1,xnbin+1): - ntot+=histos[ind].summary.array[bin-1]*scales[ind] - if bin!=1: - outputPy.write(',') - outputPy.write(str(histos[ind].summary.array[bin-1]*scales[ind])) - outputPy.write('])\n\n') - - + histoname = "y" + hist.name + "_" + str(ind) + outputPy.write(" # Creating weights for histo: " + histoname + "\n") + outputPy.write(" " + histoname + "_weights = numpy.array([") + for bin in range(1, xnbin + 1): + ntot += hist.summary.array[bin - 1] * scales[ind] + if bin != 1: + outputPy.write(",") + outputPy.write(str(hist.summary.array[bin - 1] * scales[ind])) + outputPy.write("])\n\n") # Canvas - outputPy.write(' # Creating a new Canvas\n') - dpi=80 - height=500 - widthx=700 + outputPy.write(" # Creating a new Canvas\n") + dpi = 80 + height = 500 + widthx = 700 if legendmode: - widthx=1000 - outputPy.write(' fig = plt.figure(figsize=('+\ - str(widthx/dpi)+','+str(height/dpi)+\ - '),dpi='+str(dpi)+')\n') + widthx = 1000 + outputPy.write( + " fig = plt.figure(figsize=(" + + str(widthx / dpi) + + "," + + str(height / dpi) + + "),dpi=" + + str(dpi) + + ")\n" + ) if not legendmode: - outputPy.write(' frame = gridspec.GridSpec(1,1)\n') + outputPy.write(" frame = gridspec.GridSpec(1,1)\n") else: - outputPy.write(' frame = gridspec.GridSpec(1,1,right=0.7)\n') + outputPy.write(" frame = gridspec.GridSpec(1,1,right=0.7)\n") # subplot argument: nrows, ncols, plot_number # outputPy.write(' pad = fig.add_subplot(111)\n') - outputPy.write(' pad = fig.add_subplot(frame[0])\n') - outputPy.write('\n') + outputPy.write(" pad = fig.add_subplot(frame[0])\n") + outputPy.write("\n") # Stack - outputPy.write(' # Creating a new Stack\n') - for ind in range(len(histos)-1,-1,-1): - myweight = 'y'+histos[ind].name+'_'+str(ind)+'_weights' - mytitle = '"'+PlotFlow.NiceTitleMatplotlib(self.main.datasets[ind].title)+'"' - mytitle = mytitle.replace('_','\_') + outputPy.write(" # Creating a new Stack\n") + for ind in range(len(histos) - 1, -1, -1): + myweight = "y" + histos[ind].name + "_" + str(ind) + "_weights" + mytitle = '"' + PlotFlow.NiceTitleMatplotlib(self.main.datasets[ind].title) + '"' + mytitle = mytitle.replace("_", "\_") if not stackmode: - myweights='y'+histos[ind].name+'_'+str(ind)+'_weights' + myweights = "y" + histos[ind].name + "_" + str(ind) + "_weights" else: - myweights='' - for ind2 in range(0,ind+1): - if ind2>=1: - myweights+='+' - myweights+='y'+histos[ind2].name+'_'+str(ind2)+'_weights' + myweights = "" + for ind2 in range(0, ind + 1): + if ind2 >= 1: + myweights += "+" + myweights += "y" + histos[ind2].name + "_" + str(ind2) + "_weights" # reset - linecolor=0 - linestyle=0 - backcolor=0 - backstyle=0 - linewidth=1 + linecolor = 0 + linestyle = 0 + backcolor = 0 + backstyle = 0 + linewidth = 1 # Setting AUTO settings - if len(histos)==1: + if len(histos) == 1: linecolor1 = [9] - linecolor = linecolor1[ind] + linecolor = linecolor1[ind] if stackmode: backstyle1 = [3004] - backstyle = backstyle1[ind] - backcolor = linecolor1[ind] - elif len(histos)==2: - linecolor2 = [9,46] - linecolor = linecolor2[ind] + backstyle = backstyle1[ind] + backcolor = linecolor1[ind] + elif len(histos) == 2: + linecolor2 = [9, 46] + linecolor = linecolor2[ind] if stackmode: - backstyle2 = [3004,3005] - backstyle = backstyle2[ind] - backcolor = linecolor2[ind] - elif len(histos)==3: - linecolor3 = [9,46,8] - linecolor = linecolor3[ind] + backstyle2 = [3004, 3005] + backstyle = backstyle2[ind] + backcolor = linecolor2[ind] + elif len(histos) == 3: + linecolor3 = [9, 46, 8] + linecolor = linecolor3[ind] if stackmode: - backstyle3 = [3004,3005,3006] - backstyle = backstyle3[ind] - backcolor = linecolor3[ind] - elif len(histos)==4: - linecolor4 = [9,46,8,4] - linecolor = linecolor4[ind] + backstyle3 = [3004, 3005, 3006] + backstyle = backstyle3[ind] + backcolor = linecolor3[ind] + elif len(histos) == 4: + linecolor4 = [9, 46, 8, 4] + linecolor = linecolor4[ind] if stackmode: - backstyle4 = [3004,3005,3006,3007] - backstyle = backstyle4[ind] - backcolor = linecolor4[ind] - elif len(histos)==5: - linecolor5 = [9,46,8,4,6] - linecolor = linecolor5[ind] + backstyle4 = [3004, 3005, 3006, 3007] + backstyle = backstyle4[ind] + backcolor = linecolor4[ind] + elif len(histos) == 5: + linecolor5 = [9, 46, 8, 4, 6] + linecolor = linecolor5[ind] if stackmode: - backstyle5 = [3004,3005,3006,3007,3013] - backstyle = backstyle5[ind] - backcolor = linecolor5[ind] - elif len(histos)==6: - linecolor6 = [9,46,8,4,6,2] - linecolor = linecolor6[ind] + backstyle5 = [3004, 3005, 3006, 3007, 3013] + backstyle = backstyle5[ind] + backcolor = linecolor5[ind] + elif len(histos) == 6: + linecolor6 = [9, 46, 8, 4, 6, 2] + linecolor = linecolor6[ind] if stackmode: - backstyle6 = [3004,3005,3006,3007,3013,3017] - backstyle = backstyle6[ind] - backcolor = linecolor6[ind] - elif len(histos)==7: - linecolor7 = [9,46,8,4,6,2,7] - linecolor = linecolor7[ind] + backstyle6 = [3004, 3005, 3006, 3007, 3013, 3017] + backstyle = backstyle6[ind] + backcolor = linecolor6[ind] + elif len(histos) == 7: + linecolor7 = [9, 46, 8, 4, 6, 2, 7] + linecolor = linecolor7[ind] if stackmode: - backstyle7 = [3004,3005,3006,3007,3013,3017,3022] - backstyle = backstyle7[ind] - backcolor = linecolor7[ind] - elif len(histos)==8: - linecolor8 = [9,46,8,4,6,2,7,3] - linecolor = linecolor8[ind] + backstyle7 = [3004, 3005, 3006, 3007, 3013, 3017, 3022] + backstyle = backstyle7[ind] + backcolor = linecolor7[ind] + elif len(histos) == 8: + linecolor8 = [9, 46, 8, 4, 6, 2, 7, 3] + linecolor = linecolor8[ind] if stackmode: - backstyle8 = [3004,3005,3006,3007,3013,3017,3022,3315] - backstyle = backstyle8[ind] - backcolor = linecolor8[ind] - elif len(histos)==9: - linecolor9 = [9,46,8,4,6,2,7,3,42] - linecolor = linecolor9[ind] + backstyle8 = [3004, 3005, 3006, 3007, 3013, 3017, 3022, 3315] + backstyle = backstyle8[ind] + backcolor = linecolor8[ind] + elif len(histos) == 9: + linecolor9 = [9, 46, 8, 4, 6, 2, 7, 3, 42] + linecolor = linecolor9[ind] if stackmode: - backstyle9 = [3004,3005,3006,3007,3013,3017,3022,3315,3351] - backstyle = backstyle9[ind] - backcolor = linecolor9[ind] - elif len(histos)==10: - linecolor10 = [9,46,8,4,6,2,7,3,42,48] - linecolor = linecolor10[ind] + backstyle9 = [3004, 3005, 3006, 3007, 3013, 3017, 3022, 3315, 3351] + backstyle = backstyle9[ind] + backcolor = linecolor9[ind] + elif len(histos) == 10: + linecolor10 = [9, 46, 8, 4, 6, 2, 7, 3, 42, 48] + linecolor = linecolor10[ind] if stackmode: - backstyle10 = [3004,3005,3006,3007,3013,3017,3022,3315,3351,3481] - backstyle = backstyle10[ind] - backcolor = linecolor10[ind] + backstyle10 = [3004, 3005, 3006, 3007, 3013, 3017, 3022, 3315, 3351, 3481] + backstyle = backstyle10[ind] + backcolor = linecolor10[ind] else: - linecolor=self.color + linecolor = self.color self.color += 1 # linecolor - if self.main.datasets[ind].linecolor!=ColorType.AUTO: - linecolor=ColorType.convert2root( \ - self.main.datasets[ind].linecolor,\ - self.main.datasets[ind].lineshade) + if self.main.datasets[ind].linecolor != ColorType.AUTO: + linecolor = ColorType.convert2root( + self.main.datasets[ind].linecolor, self.main.datasets[ind].lineshade + ) # lineStyle - linestyle=LineStyleType.convert2code(self.main.datasets[ind].linestyle) + linestyle = LineStyleType.convert2code(self.main.datasets[ind].linestyle) # linewidth - linewidth=self.main.datasets[ind].linewidth + linewidth = self.main.datasets[ind].linewidth # background color - if self.main.datasets[ind].backcolor!=ColorType.AUTO: - backcolor=ColorType.convert2root( \ - self.main.datasets[ind].backcolor,\ - self.main.datasets[ind].backshade) + if self.main.datasets[ind].backcolor != ColorType.AUTO: + backcolor = ColorType.convert2root( + self.main.datasets[ind].backcolor, self.main.datasets[ind].backshade + ) # background style - if self.main.datasets[ind].backstyle!=BackStyleType.AUTO: - backstyle=BackStyleType.convert2matplotlib( \ - self.main.datasets[ind].backstyle) - - mylinecolor = '"'+madanalysis.enumeration.color_hex.color_hex[linecolor]+'"' - mybackcolor = '"'+madanalysis.enumeration.color_hex.color_hex[backcolor]+'"' - - filledmode='"stepfilled"' - rWidth=1. - if backcolor==0: #invisible - filledmode='"step"' - mybackcolor = 'None' -# if frequencyhisto: -# filledmode='"bar"' -# rWidth=0.8 - mylinewidth = self.main.datasets[ind].linewidth - mylinestyle = LineStyleType.convert2matplotlib(self.main.datasets[ind].linestyle) - - outputPy.write(' pad.hist('+\ - 'x=xData, '+\ - 'bins=xBinning, '+\ - 'weights='+myweights+',\\\n'+\ - ' label='+mytitle+', ') - if ntot!=0: - outputPy.write('histtype='+filledmode+', ') + if self.main.datasets[ind].backstyle != BackStyleType.AUTO: + backstyle = BackStyleType.convert2matplotlib(self.main.datasets[ind].backstyle) + + mylinecolor = '"' + madanalysis.enumeration.color_hex.color_hex[linecolor] + '"' + mybackcolor = '"' + madanalysis.enumeration.color_hex.color_hex[backcolor] + '"' + + filledmode = '"stepfilled"' + rWidth = 1.0 + if backcolor == 0: # invisible + filledmode = '"step"' + mybackcolor = "None" + # if frequencyhisto: + # filledmode='"bar"' + # rWidth=0.8 + mylinewidth = self.main.datasets[ind].linewidth + mylinestyle = LineStyleType.convert2matplotlib(self.main.datasets[ind].linestyle) + + outputPy.write( + " pad.hist(" + + "x=xData, " + + "bins=xBinning, " + + "weights=" + + myweights + + ",\\\n" + + " label=" + + mytitle + + ", " + ) + if ntot != 0: + outputPy.write("histtype=" + filledmode + ", ") try: import matplotlib.pyplot as plt - plt.hist([0],normed=True) - outputPy.write( 'rwidth='+str(rWidth)+',\\\n'+\ - ' color='+mybackcolor+', '+\ - 'edgecolor='+mylinecolor+', '+\ - 'linewidth='+str(mylinewidth)+', '+\ - 'linestyle='+mylinestyle+',\\\n'+\ - ' bottom=None, '+\ - 'cumulative=False, normed=False, align="mid", orientation="vertical")\n\n') + + plt.hist([0], normed=True) + outputPy.write( + "rwidth=" + + str(rWidth) + + ",\\\n" + + " color=" + + mybackcolor + + ", " + + "edgecolor=" + + mylinecolor + + ", " + + "linewidth=" + + str(mylinewidth) + + ", " + + "linestyle=" + + mylinestyle + + ",\\\n" + + " bottom=None, " + + 'cumulative=False, normed=False, align="mid", orientation="vertical")\n\n' + ) except: - outputPy.write( 'rwidth='+str(rWidth)+',\\\n'+\ - ' color='+mybackcolor+', '+\ - 'edgecolor='+mylinecolor+', '+\ - 'linewidth='+str(mylinewidth)+', '+\ - 'linestyle='+mylinestyle+',\\\n'+\ - ' bottom=None, '+\ - 'cumulative=False, density=False, align="mid",'+\ - ' orientation="vertical")\n\n') - outputPy.write('\n') + outputPy.write( + "rwidth=" + + str(rWidth) + + ",\\\n" + + " color=" + + mybackcolor + + ", " + + "edgecolor=" + + mylinecolor + + ", " + + "linewidth=" + + str(mylinewidth) + + ", " + + "linestyle=" + + mylinestyle + + ",\\\n" + + " bottom=None, " + + 'cumulative=False, density=False, align="mid",' + + ' orientation="vertical")\n\n' + ) + outputPy.write("\n") # Label - outputPy.write(' # Axis\n') + outputPy.write(" # Axis\n") outputPy.write(" plt.rc('text',usetex=False)\n") # X-axis - if ref.titleX=="": + if ref.titleX == "": axis_titleX = ref.GetXaxis_Matplotlib() else: axis_titleX = ref.titleX - axis_titleX = axis_titleX.replace('#DeltaR','#Delta R') - axis_titleX = axis_titleX.replace('#','\\') - outputPy.write(' plt.xlabel(r"'+axis_titleX+'",\\\n') + axis_titleX = axis_titleX.replace("#DeltaR", "#Delta R") + axis_titleX = axis_titleX.replace("#", "\\") + outputPy.write(' plt.xlabel(r"' + axis_titleX + '",\\\n') outputPy.write(' fontsize=16,color="black")\n') # Y-axis @@ -840,135 +940,138 @@ def DrawMATPLOTLIB(self,histos,scales,ref,irelhisto,filenamePy,outputnames): # Scale to one ? scale2one = False - if ref.stack==StackingMethodType.NORMALIZE2ONE or \ - (self.main.stack==StackingMethodType.NORMALIZE2ONE and \ - ref.stack==StackingMethodType.AUTO): + if ref.stack == StackingMethodType.NORMALIZE2ONE or ( + self.main.stack == StackingMethodType.NORMALIZE2ONE + and ref.stack == StackingMethodType.AUTO + ): scale2one = True if scale2one: axis_titleY += " $(#mathrm{scaled}\ #mathrm{to}# #mathrm{one})$" - elif self.main.normalize == NormalizeType.LUMI or \ - self.main.normalize == NormalizeType.LUMI_WEIGHT: - axis_titleY += " $(#mathcal{L}_{#mathrm{int}} = " + str(self.main.lumi)+ "# #mathrm{fb}^{-1})$ " + elif ( + self.main.normalize == NormalizeType.LUMI + or self.main.normalize == NormalizeType.LUMI_WEIGHT + ): + axis_titleY += ( + " $(#mathcal{L}_{#mathrm{int}} = " + str(self.main.lumi) + "# #mathrm{fb}^{-1})$ " + ) elif self.main.normalize == NormalizeType.NONE: axis_titleY += " $(#mathrm{not}# #mathrm{normalized})$" - if ref.titleY!="": + if ref.titleY != "": axis_titleY = PlotFlow.NiceTitle(ref.titleY) - axis_titleY = axis_titleY.replace('#','\\') - outputPy.write(' plt.ylabel(r"'+axis_titleY+'",\\\n') + axis_titleY = axis_titleY.replace("#", "\\") + outputPy.write(' plt.ylabel(r"' + axis_titleY + '",\\\n') outputPy.write(' fontsize=16,color="black")\n') - outputPy.write('\n') + outputPy.write("\n") # Tag Log/Linear - is_logx=False + is_logx = False if ref.logX and ntot != 0: - is_logx=True - is_logy=False + is_logx = True + is_logy = False if ref.logY and ntot != 0: - is_logy=True + is_logy = True # Bound y - outputPy.write(' # Boundary of y-axis\n') - myweights='' + outputPy.write(" # Boundary of y-axis\n") + myweights = "" if stackmode: - for ind in range(0,len(histos)): - if ind>=1: - myweights+='+' - myweights+='y'+histos[ind].name+'_'+str(ind)+'_weights' + for ind in range(0, len(histos)): + if ind >= 1: + myweights += "+" + myweights += "y" + histos[ind].name + "_" + str(ind) + "_weights" else: - myweights='numpy.array([' - for ind in range(0,len(histos)): - if ind>=1: - myweights+=',' - myweights+='y'+histos[ind].name+'_'+str(ind)+'_weights.max()' - myweights+='])' - if ref.ymax==[]: - outputPy.write(' ymax=('+myweights+').max()*1.1\n') + myweights = "numpy.array([" + for ind in range(0, len(histos)): + if ind >= 1: + myweights += "," + myweights += "y" + histos[ind].name + "_" + str(ind) + "_weights.max()" + myweights += "])" + if ref.ymax == []: + outputPy.write(" ymax=(" + myweights + ").max()*1.1\n") else: - outputPy.write(' ymax='+str(ref.ymax)+'\n') - outputPy.write(' ') - if ref.ymin==[]: + outputPy.write(" ymax=" + str(ref.ymax) + "\n") + outputPy.write(" ") + if ref.ymin == []: if is_logy: - outputPy.write('#') - outputPy.write('ymin=0 # linear scale\n') + outputPy.write("#") + outputPy.write("ymin=0 # linear scale\n") else: - if is_logy and ref.ymin<=0: - outputPy.write('#') - outputPy.write('ymin=' + str(ref.ymin)+' # linear scale\n') + if is_logy and ref.ymin <= 0: + outputPy.write("#") + outputPy.write("ymin=" + str(ref.ymin) + " # linear scale\n") - myweights='' + myweights = "" if stackmode: - for ind in range(0,len(histos)): - if ind>=1: - myweights+='+' - myweights+='y'+histos[ind].name+'_'+str(ind)+'_weights' + for ind in range(0, len(histos)): + if ind >= 1: + myweights += "+" + myweights += "y" + histos[ind].name + "_" + str(ind) + "_weights" else: - myweights='numpy.array([' - for ind in range(0,len(histos)): - if ind>=1: - myweights+=',' - myweights+='y'+histos[ind].name+'_'+str(ind)+'_weights.min()' - myweights+=',1.])' - outputPy.write(' ') - if ref.ymin==[]: + myweights = "numpy.array([" + for ind in range(0, len(histos)): + if ind >= 1: + myweights += "," + myweights += "y" + histos[ind].name + "_" + str(ind) + "_weights.min()" + myweights += ",1.])" + outputPy.write(" ") + if ref.ymin == []: if not is_logy: - outputPy.write('#') - outputPy.write('ymin=min([x for x in ('+myweights+') if x])/100. # log scale\n') + outputPy.write("#") + outputPy.write("ymin=min([x for x in (" + myweights + ") if x])/100. # log scale\n") else: - if is_logy and ref.ymin<=0: - outputPy.write('#') - outputPy.write('ymin=' + str(ref.ymin)+' # log scale\n') - outputPy.write(' plt.gca().set_ylim(ymin,ymax)\n') - outputPy.write('\n') + if is_logy and ref.ymin <= 0: + outputPy.write("#") + outputPy.write("ymin=" + str(ref.ymin) + " # log scale\n") + outputPy.write(" plt.gca().set_ylim(ymin,ymax)\n") + outputPy.write("\n") # X axis - outputPy.write(' # Log/Linear scale for X-axis\n') + outputPy.write(" # Log/Linear scale for X-axis\n") # - Linear - outputPy.write(' ') + outputPy.write(" ") if is_logx: - outputPy.write('#') + outputPy.write("#") outputPy.write('plt.gca().set_xscale("linear")\n') # - Log - outputPy.write(' ') + outputPy.write(" ") if not is_logx: - outputPy.write('#') + outputPy.write("#") outputPy.write('plt.gca().set_xscale("log",nonpositive="clip")\n') - outputPy.write('\n') - + outputPy.write("\n") # Y axis - outputPy.write(' # Log/Linear scale for Y-axis\n') + outputPy.write(" # Log/Linear scale for Y-axis\n") # - Linear - outputPy.write(' ') + outputPy.write(" ") if is_logy: - outputPy.write('#') + outputPy.write("#") outputPy.write('plt.gca().set_yscale("linear")\n') # - Log - outputPy.write(' ') + outputPy.write(" ") if not is_logy: - outputPy.write('#') + outputPy.write("#") outputPy.write('plt.gca().set_yscale("log",nonpositive="clip")\n') - outputPy.write('\n') + outputPy.write("\n") - # Labels if frequencyhisto: - outputPy.write(' # Labels for x-Axis\n') - outputPy.write(' xLabels = numpy.array([') - for bin in range(0,xnbin): - if bin>=1: - outputPy.write(',') - outputPy.write('"'+str(histos[0].stringlabels[bin]).replace('_','\_')+'"') - outputPy.write('])\n') + outputPy.write(" # Labels for x-Axis\n") + outputPy.write(" xLabels = numpy.array([") + for bin in range(0, xnbin): + if bin >= 1: + outputPy.write(",") + outputPy.write('"' + str(histos[0].stringlabels[bin]).replace("_", "\_") + '"') + outputPy.write("])\n") outputPy.write(' plt.xticks(xData, xLabels, rotation="vertical")\n') - outputPy.write('\n') + outputPy.write("\n") -### BENJ: not necessary for getting the png and pdf files + ### BENJ: not necessary for getting the png and pdf files # Draw -# outputPy.write(' # Draw\n') -# outputPy.write(' plt.show()\n') -# outputPy.write('\n') + # outputPy.write(' # Draw\n') + # outputPy.write(' plt.show()\n') + # outputPy.write('\n') # Legend if legendmode: @@ -986,28 +1089,28 @@ def DrawMATPLOTLIB(self,histos,scales,ref,irelhisto,filenamePy,outputnames): # -'upper center' : 9, # -'center' : 10, - - outputPy.write(' # Legend\n') - outputPy.write(' plt.legend(bbox_to_anchor=(1.05,1), loc=2,'+\ - ' borderaxespad=0.)\n') - outputPy.write('\n') - + outputPy.write(" # Legend\n") + outputPy.write( + " plt.legend(bbox_to_anchor=(1.05,1), loc=2," + " borderaxespad=0.)\n" + ) + outputPy.write("\n") + # Producing the image - outputPy.write(' # Saving the image\n') + outputPy.write(" # Saving the image\n") for outputname in outputnames: - outputPy.write(" plt.savefig('"+outputname+"')\n") - outputPy.write('\n') + outputPy.write(" plt.savefig('" + outputname + "')\n") + outputPy.write("\n") # Call the function - outputPy.write('# Running!\n') + outputPy.write("# Running!\n") outputPy.write("if __name__ == '__main__':\n") - outputPy.write(' '+function_name+'()\n') + outputPy.write(" " + function_name + "()\n") # Close the file try: outputPy.close() except: - logging.getLogger('MA5').error('Impossible to close the file: '+outputPy) + logging.getLogger("MA5").error("Impossible to close the file: " + outputPy) return False # Ok From 80d5b01b1c4fc9a4fcf9f22e54278e832a164250 Mon Sep 17 00:00:00 2001 From: "Jack Y. Araz" <jackaraz@gmail.com> Date: Thu, 29 Jun 2023 16:45:43 +0100 Subject: [PATCH 039/107] update histogramming module --- madanalysis/layout/histogram.py | 148 +++++++++++---------- madanalysis/layout/histogram_core.py | 95 ++++++------- madanalysis/layout/plotflow_for_dataset.py | 142 +++++++++----------- 3 files changed, 186 insertions(+), 199 deletions(-) diff --git a/madanalysis/layout/histogram.py b/madanalysis/layout/histogram.py index c3a75701..4ace9ea3 100644 --- a/madanalysis/layout/histogram.py +++ b/madanalysis/layout/histogram.py @@ -1,99 +1,115 @@ ################################################################################ -# +# # Copyright (C) 2012-2023 Jack Araz, Eric Conte & Benjamin Fuks # The MadAnalysis development team, email: <ma5team@iphc.cnrs.fr> -# +# # This file is part of MadAnalysis 5. # Official website: <https://github.com/MadAnalysis/madanalysis5> -# +# # MadAnalysis 5 is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. -# +# # MadAnalysis 5 is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. -# +# # You should have received a copy of the GNU General Public License # along with MadAnalysis 5. If not, see <http://www.gnu.org/licenses/> -# +# ################################################################################ from __future__ import absolute_import -from madanalysis.layout.histogram_core import HistogramCore import logging -from six.moves import range +import numpy as np +from madanalysis.layout.histogram_core import HistogramCore class Histogram: - def __init__(self): self.Reset() - def Print(self): # General info - inform = self.name + ' ' + str(self.nbins) + str(self.xmin) + ' ' + str(self.xmax) - if self.ymin!=[] or self.ymax!=[]: - inform = inform + ' ' + str(self.ymin) + ' ' + str(self.ymax) - logging.getLogger('MA5').info(inform) + inform = self.name + " " + str(self.nbins) + str(self.xmin) + " " + str(self.xmax) + if self.ymin != [] or self.ymax != []: + inform = inform + " " + str(self.ymin) + " " + str(self.ymax) + logging.getLogger("MA5").info(inform) # Data self.positive.Print() self.negative.Print() self.summary.Print() - - def FinalizeReading(self,main,dataset): + def FinalizeReading(self, main, dataset): + + # convert everything to numpy arrays + for loc in ["positive", "negative", "summary"]: + for tp in [ + "nevents", + "nentries", + "sumwentries", + "sumw", + "sumw2", + "sumwx", + "sumw2x", + "underflow", + "overflow", + ]: + setattr(getattr(self, loc), tp, np.array(getattr(getattr(self, loc), tp))) # Statistics - self.summary.nevents = self.positive.nevents + self.negative.nevents - self.summary.nentries = self.positive.nentries + self.negative.nentries + self.summary.nevents = np.array(self.positive.nevents) + np.array(self.negative.nevents) + self.summary.nentries = np.array(self.positive.nentries) + np.array(self.negative.nentries) # sumw - self.summary.sumw = self.positive.sumw - self.negative.sumw - if self.summary.sumw<0: - self.summary.sumw=0 + self.summary.sumw = np.clip( + np.array(self.positive.sumw) - np.array(self.negative.sumw), 0, None + ) # sumw2 - self.summary.sumw2 = self.positive.sumw2 - self.negative.sumw2 - if self.summary.sumw2<0: - self.summary.sumw2=0 + self.summary.sumw2 = np.clip( + np.array(self.positive.sumw2) - np.array(self.negative.sumw2), 0, None + ) # sumwx - self.summary.sumwx = self.positive.sumwx - self.negative.sumwx + self.summary.sumwx = np.array(self.positive.sumwx) - np.array(self.negative.sumwx) # no correction on it # sumw2x - self.summary.sumw2x = self.positive.sumw2x - self.negative.sumw2x + self.summary.sumw2x = np.array(self.positive.sumw2x) - np.array(self.negative.sumw2x) # no correction on it # underflow - self.summary.underflow = self.positive.underflow - self.negative.underflow - if self.summary.underflow<0: - self.summary.underflow=0 + self.summary.underflow = np.clip( + np.array(self.positive.underflow) - np.array(self.negative.underflow), 0, None + ) # overflow - self.summary.overflow = self.positive.overflow - self.negative.overflow - if self.summary.overflow<0: - self.summary.overflow=0 + self.summary.overflow = np.clip( + np.array(self.positive.overflow) - np.array(self.negative.overflow), 0, None + ) # Data data = [] - for i in range(0,len(self.positive.array)): - data.append(self.positive.array[i]-self.negative.array[i]) - if data[-1]<0: - self.warnings.append(\ - 'dataset='+dataset.name+\ - ' -> bin '+str(i)+\ - ' has a negative content : '+\ - str(data[-1])+'. This value is set to zero') - data[-1]=0 - self.summary.array = data[:] # [:] -> clone of data + for i, array in enumerate(self.positive.array): + data.append(np.array(self.positive.array[i]) - np.array(self.negative.array[i])) + if np.any(data[-1] < 0): + self.warnings.append( + "dataset=" + + dataset.name + + " -> bin " + + str(i) + + " has a negative content : " + + str(data[-1]) + + ". This value is set to zero" + ) + data[-1] = np.clip(data[-1], 0, None) + self.summary.array = np.array(data[:]) # [:] -> clone of data # Integral self.positive.ComputeIntegral() @@ -103,23 +119,21 @@ def FinalizeReading(self,main,dataset): def CreateHistogram(self): pass - - def Reset(self): # General info - self.name = "" + self.name = "" self.nbins = 100 - self.xmin = 0. - self.xmax = 100. - self.ymin = [] - self.ymax = [] - self.scale = 0. + self.xmin = 0.0 + self.xmax = 100.0 + self.ymin = [] + self.ymax = [] + self.scale = 0.0 # Data self.positive = HistogramCore() self.negative = HistogramCore() - self.summary = HistogramCore() + self.summary = HistogramCore() # ROOT histo self.myhisto = 0 @@ -133,49 +147,47 @@ def Reset(self): def GetRegions(self): return self.regions - def GetBinLowEdge(self,bin): + def GetBinLowEdge(self, bin): # Special case - if bin<=0: + if bin <= 0: return self.xmin - if bin>=self.nbins: + if bin >= self.nbins: return self.xmax # Computing steps - step = (self.xmax - self.xmin) / float (self.nbins) + step = (self.xmax - self.xmin) / float(self.nbins) # value - return self.xmin+bin*step + return self.xmin + bin * step - - def GetBinUpperEdge(self,bin): + def GetBinUpperEdge(self, bin): # Special case - if bin<=0: + if bin <= 0: return self.xmin - if bin>=self.nbins: + if bin >= self.nbins: return self.xmax # Computing steps - step = (self.xmax - self.xmin) / float (self.nbins) + step = (self.xmax - self.xmin) / float(self.nbins) # value - return self.xmin+(bin+1)*step - + return self.xmin + (bin + 1) * step - def GetBinMean(self,bin): + def GetBinMean(self, bin): # Special case - if bin<0: + if bin < 0: return self.xmin - if bin>=self.nbins: + if bin >= self.nbins: return self.xmax # Computing steps - step = (self.xmax - self.xmin) / float (self.nbins) + step = (self.xmax - self.xmin) / float(self.nbins) # value - return self.xmin+(bin+0.5)*step + return self.xmin + (bin + 0.5) * step diff --git a/madanalysis/layout/histogram_core.py b/madanalysis/layout/histogram_core.py index 21ece63f..a98b96c5 100644 --- a/madanalysis/layout/histogram_core.py +++ b/madanalysis/layout/histogram_core.py @@ -1,96 +1,85 @@ ################################################################################ -# +# # Copyright (C) 2012-2023 Jack Araz, Eric Conte & Benjamin Fuks # The MadAnalysis development team, email: <ma5team@iphc.cnrs.fr> -# +# # This file is part of MadAnalysis 5. # Official website: <https://github.com/MadAnalysis/madanalysis5> -# +# # MadAnalysis 5 is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. -# +# # MadAnalysis 5 is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. -# +# # You should have received a copy of the GNU General Public License # along with MadAnalysis 5. If not, see <http://www.gnu.org/licenses/> -# +# ################################################################################ from __future__ import absolute_import import logging +import numpy as np from math import sqrt from six.moves import range class HistogramCore: - def __init__(self): # statistics # - int - self.nevents = 0 - self.nentries = 0 + self.nevents = np.array([0]) + self.nentries = np.array([0]) # - float - self.integral = 0. - self.sumwentries = 0. - self.sumw = 0. - self.sumw2 = 0. - self.sumwx = 0. - self.sumw2x = 0. + self.integral = np.array([0.0]) + self.sumwentries = np.array([0.0]) + self.sumw = np.array([0.0]) + self.sumw2 = np.array([0.0]) + self.sumwx = np.array([0.0]) + self.sumw2x = np.array([0.0]) # content - self.underflow = 0. - self.overflow = 0. - self.nan = 0. - self.inf = 0. - self.array = [] - + self.underflow = np.array([0.0]) + self.overflow = np.array([0.0]) + self.nan = np.array([0.0]) + self.inf = np.array([0.0]) + self.array = [] def ComputeIntegral(self): - self.integral = 0 - for i in range(0,len(self.array)): - self.integral+=self.array[i] + self.integral = np.sum(self.array, axis=0) self.integral += self.overflow self.integral += self.underflow - def Print(self): - logging.getLogger('MA5').info('nevents='+str(self.nevents)+\ - ' entries='+str(self.entries)) - - logging.getLogger('MA5').info('sumw='+str(self.sumw)+\ - ' sumw2='+str(self.sumw2)+\ - ' sumwx='+str(self.sumwx)+\ - ' sumw2x='+str(self.sumw2x)) - - logging.getLogger('MA5').info('underflow='+str(self.underflow)+\ - ' overflow='+str(self.overflow)) - + logging.getLogger("MA5").info( + "nevents=" + str(self.nevents) + " entries=" + str(self.nentries) + ) + + logging.getLogger("MA5").info( + "sumw=" + + str(self.sumw) + + " sumw2=" + + str(self.sumw2) + + " sumwx=" + + str(self.sumwx) + + " sumw2x=" + + str(self.sumw2x) + ) + + logging.getLogger("MA5").info( + "underflow=" + str(self.underflow) + " overflow=" + str(self.overflow) + ) def GetMean(self): - - if self.sumw==0: - return 0. - else: - return self.sumwx / self.sumw - + return np.array([wx / w for wx, w in zip(self.sumwx, self.sumw) if w != 0]) def GetRMS(self): - - if self.sumw==0: - return 0. - else: - mean = self.GetMean() - return sqrt(abs(self.sumw2x/self.sumw - mean*mean)) - - - - - + mean = self.GetMean() + return sqrt(abs(self.sumw2x / self.sumw - mean * mean)) diff --git a/madanalysis/layout/plotflow_for_dataset.py b/madanalysis/layout/plotflow_for_dataset.py index 0d912b11..197d6490 100644 --- a/madanalysis/layout/plotflow_for_dataset.py +++ b/madanalysis/layout/plotflow_for_dataset.py @@ -1,173 +1,159 @@ ################################################################################ -# +# # Copyright (C) 2012-2023 Jack Araz, Eric Conte & Benjamin Fuks # The MadAnalysis development team, email: <ma5team@iphc.cnrs.fr> -# +# # This file is part of MadAnalysis 5. # Official website: <https://github.com/MadAnalysis/madanalysis5> -# +# # MadAnalysis 5 is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. -# +# # MadAnalysis 5 is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. -# +# # You should have received a copy of the GNU General Public License # along with MadAnalysis 5. If not, see <http://www.gnu.org/licenses/> -# +# ################################################################################ from __future__ import absolute_import -from madanalysis.enumeration.uncertainty_type import UncertaintyType -from madanalysis.enumeration.normalize_type import NormalizeType -from madanalysis.enumeration.report_format_type import ReportFormatType -from madanalysis.enumeration.observable_type import ObservableType -from madanalysis.enumeration.color_type import ColorType -from madanalysis.enumeration.linestyle_type import LineStyleType -from madanalysis.enumeration.backstyle_type import BackStyleType + +from madanalysis.enumeration.normalize_type import NormalizeType from madanalysis.enumeration.stacking_method_type import StackingMethodType + import copy from six.moves import range class PlotFlowForDataset: - - def __init__(self,main,dataset): - self.histos = [] - self.main = main + def __init__(self, main, dataset): + self.histos = [] + self.main = main self.dataset = dataset # Getting xsection self.xsection = self.dataset.measured_global.xsection - if self.dataset.xsection!=0.: + if self.dataset.xsection != 0.0: self.xsection = self.dataset.xsection - def __len__(self): return len(self.histos) - - def __getitem__(self,i): + def __getitem__(self, i): return self.histos[i] - # Computing integral def FinalizeReading(self): for histo in self.histos: - histo.FinalizeReading(self.main,self.dataset) + histo.FinalizeReading(self.main, self.dataset) # Updating the value of the cross section (BENJ) self.xsection = self.dataset.measured_global.xsection - if self.dataset.xsection!=0.: + if self.dataset.xsection != 0.0: self.xsection = self.dataset.xsection # Computing integral def CreateHistogram(self): - iplot=0 + iplot = 0 # Loop over plot - for iabshisto in range(0,len(self.main.selection)): + for iabshisto in range(0, len(self.main.selection)): # Keep only histogram - if self.main.selection[iabshisto].__class__.__name__!="Histogram": + if self.main.selection[iabshisto].__class__.__name__ != "Histogram": continue # Case of histogram frequency - if self.histos[iplot].__class__.__name__=="HistogramFrequency": - if self.main.selection[iabshisto].observable.name=="NPID": - NPID=True + if self.histos[iplot].__class__.__name__ == "HistogramFrequency": + if self.main.selection[iabshisto].observable.name == "NPID": + NPID = True else: - NPID=False - self.histos[iplot].CreateHistogram(NPID,self.main) + NPID = False + self.histos[iplot].CreateHistogram(NPID, self.main) else: self.histos[iplot].CreateHistogram() - iplot+=1 - + iplot += 1 # Computing scales def ComputeScale(self): - iplot=0 + iplot = 0 # Loop over plot - for iabshisto in range(0,len(self.main.selection)): - + for iabshisto, select in enumerate(self.main.selection): # Keep only histogram - if self.main.selection[iabshisto].__class__.__name__!="Histogram": + if select.__class__.__name__ != "Histogram": continue - # Reset scale - scale=0. - + scale = 0.0 # Case 1: Normalization to ONE - if self.main.selection[iabshisto].stack==StackingMethodType.NORMALIZE2ONE or \ - (self.main.stack==StackingMethodType.NORMALIZE2ONE and \ - self.main.selection[iabshisto].stack==StackingMethodType.AUTO): - integral=self.histos[iplot].positive.integral -\ - self.histos[iplot].negative.integral - if integral>0.: - scale = 1./integral + if select.stack == StackingMethodType.NORMALIZE2ONE or ( + self.main.stack == StackingMethodType.NORMALIZE2ONE + and self.main.selection[iabshisto].stack == StackingMethodType.AUTO + ): + integral = ( + self.histos[iplot].positive.integral - self.histos[iplot].negative.integral + ) + if integral > 0.0: + scale = 1.0 / integral else: - scale = 0. - + scale = 0.0 # Case 2: No normalization elif self.main.normalize == NormalizeType.NONE: - scale = 1. - + scale = 1.0 # Case 3 and 4 : Normalization formula depends on LUMI - # or depends on WEIGHT+LUMI - elif self.main.normalize in [NormalizeType.LUMI, \ - NormalizeType.LUMI_WEIGHT]: + # or depends on WEIGHT+LUMI + elif self.main.normalize in [NormalizeType.LUMI, NormalizeType.LUMI_WEIGHT]: # integral - integral=self.histos[iplot].positive.integral -\ - self.histos[iplot].negative.integral + integral = ( + self.histos[iplot].positive.integral - self.histos[iplot].negative.integral + ) # compute efficiency : Nevent / Ntotal - if self.dataset.measured_global.nevents==0: + if self.dataset.measured_global.nevents == 0: eff = 0 else: - eff = (self.histos[iplot].positive.nevents + \ - self.histos[iplot].negative.nevents) / \ - float(self.dataset.measured_global.nevents) + eff = ( + self.histos[iplot].positive.nevents + self.histos[iplot].negative.nevents + ) / float(self.dataset.measured_global.nevents) # compute the good xsection value thexsection = self.xsection - if self.main.normalize==NormalizeType.LUMI_WEIGHT: + if self.main.normalize == NormalizeType.LUMI_WEIGHT: thexsection = thexsection * self.dataset.weight - + # compute final entries/event ratio entries_per_events = 0 - sumw = self.histos[iplot].positive.sumw - \ - self.histos[iplot].negative.sumw - Nentries = self.histos[iplot].positive.sumwentries - \ - self.histos[iplot].negative.sumwentries - if sumw!=0 and Nentries!=0: + sumw = self.histos[iplot].positive.sumw - self.histos[iplot].negative.sumw + Nentries = ( + self.histos[iplot].positive.sumwentries + - self.histos[iplot].negative.sumwentries + ) + if sumw != 0 and Nentries != 0: entries_per_events = sumw / Nentries # compute the scale - if integral!=0: - scale = thexsection * \ - self.main.lumi * 1000 * \ - eff * \ - entries_per_events / \ - integral + if integral != 0: + scale = ( + thexsection * self.main.lumi * 1000 * eff * entries_per_events / integral + ) else: - scale = 1 # no scale for empty plot + scale = 1 # no scale for empty plot # Setting the computing scale - self.histos[iplot].scale=copy.copy(scale) + self.histos[iplot].scale = copy.copy(scale) # Incrementing counter - iplot+=1 - + iplot += 1 From c3ff020047c4ff346021daafea063811b1cc3fdf Mon Sep 17 00:00:00 2001 From: "Jack Y. Araz" <jackaraz@gmail.com> Date: Thu, 29 Jun 2023 16:48:59 +0100 Subject: [PATCH 040/107] update changelog --- doc/releases/changelog-v2.0.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/releases/changelog-v2.0.md b/doc/releases/changelog-v2.0.md index 31fd8b7c..6700dec2 100644 --- a/doc/releases/changelog-v2.0.md +++ b/doc/releases/changelog-v2.0.md @@ -35,6 +35,9 @@ * Command to fix random seed has been added. [(#86)](https://github.com/MadAnalysis/madanalysis5/pull/86) +* Multiweight handler has been implemented. + [(#205)](https://github.com/MadAnalysis/madanalysis5/pull/205) + ## Improvements * The SFS libraries are now included in the file `analysisList.h`, instead of in From cc192ae9a0cc881fbfa825771e80c1e85849da18 Mon Sep 17 00:00:00 2001 From: "Jack Y. Araz" <jackaraz@gmail.com> Date: Fri, 30 Jun 2023 14:41:33 +0100 Subject: [PATCH 041/107] write weight names --- .../Process/Writer/SAFWriter.cpp | 319 +++++++++--------- .../SampleAnalyzer/Process/Writer/SAFWriter.h | 92 +++-- 2 files changed, 204 insertions(+), 207 deletions(-) diff --git a/tools/SampleAnalyzer/Process/Writer/SAFWriter.cpp b/tools/SampleAnalyzer/Process/Writer/SAFWriter.cpp index 87038e39..5b066b0a 100644 --- a/tools/SampleAnalyzer/Process/Writer/SAFWriter.cpp +++ b/tools/SampleAnalyzer/Process/Writer/SAFWriter.cpp @@ -1,27 +1,26 @@ //////////////////////////////////////////////////////////////////////////////// -// +// // Copyright (C) 2012-2023 Jack Araz, Eric Conte & Benjamin Fuks // The MadAnalysis development team, email: <ma5team@iphc.cnrs.fr> -// +// // This file is part of MadAnalysis 5. // Official website: <https://github.com/MadAnalysis/madanalysis5> -// +// // MadAnalysis 5 is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // MadAnalysis 5 is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with MadAnalysis 5. If not, see <http://www.gnu.org/licenses/> -// +// //////////////////////////////////////////////////////////////////////////////// - // SampleHeader headers #include "SampleAnalyzer/Process/Writer/SAFWriter.h" @@ -32,192 +31,200 @@ using namespace MA5; // ----------------------------------------------------------------------------- MAbool SAFWriter::WriteHeader() { - // Header - *output_ << "<SAFheader>" << std::endl; - *output_ << "</SAFheader>" << std::endl; - *output_ << std::endl; - return true; + // Header + *output_ << "<SAFheader>" << std::endl; + *output_ << "</SAFheader>" << std::endl; + *output_ << std::endl; + return true; } -MAbool SAFWriter::WriteHeader(const SampleFormat& mySample) +MAbool SAFWriter::WriteHeader(const SampleFormat &mySample) { - // Header - *output_ << "<SAFheader>" << std::endl; - *output_ << "</SAFheader>" << std::endl; - *output_ << std::endl; - - // SampleGlobalInfo - *output_ << "<SampleGlobalInfo>" << std::endl; - - // title line - output_->width(15); - *output_ << std::left << "# xsection "; - output_->width(15); - *output_ << std::left << "xsection_error "; - output_->width(15); - *output_ << std::left << "nevents "; - output_->width(15); - *output_ << std::left << "sum_weight+ "; - output_->width(15); - *output_ << std::left << "sum_weight- "; - *output_ << std::endl; - - // data - if (mySample.mc()!=0) - { - output_->width(15); - *output_ << std::left << std::scientific - << mySample.mc()->xsection(); - output_->width(15); - *output_ << std::left << std::scientific - << mySample.mc()->xsection_error(); - output_->width(15); - *output_ << std::left << std::scientific - << mySample.nevents(); - output_->width(15); - *output_ << std::left << std::scientific - << mySample.mc()->sumweight_positive(); - output_->width(15); - *output_ << std::left << std::scientific - << mySample.mc()->sumweight_negative(); + // Header + *output_ << "<SAFheader>" << std::endl; + *output_ << "</SAFheader>" << std::endl; *output_ << std::endl; - } - else - { + + // SampleGlobalInfo + *output_ << "<SampleGlobalInfo>" << std::endl; + + // title line output_->width(15); - *output_ << std::left << std::scientific - << 0; + *output_ << std::left << "# xsection "; output_->width(15); - *output_ << std::left << std::scientific - << 0; + *output_ << std::left << "xsection_error "; output_->width(15); - *output_ << std::left << std::scientific - << mySample.nevents(); + *output_ << std::left << "nevents "; output_->width(15); - *output_ << std::left << std::scientific - << 0; + *output_ << std::left << "sum_weight+ "; output_->width(15); - *output_ << std::left << std::scientific - << 0; + *output_ << std::left << "sum_weight- "; *output_ << std::endl; - } - *output_ << "</SampleGlobalInfo>" << std::endl; - *output_ << std::endl; - return true; -} + // data + if (mySample.mc() != 0) + { + output_->width(15); + *output_ << std::left << std::scientific + << mySample.mc()->xsection(); + output_->width(15); + *output_ << std::left << std::scientific + << mySample.mc()->xsection_error(); + output_->width(15); + *output_ << std::left << std::scientific + << mySample.nevents(); + output_->width(15); + *output_ << std::left << std::scientific + << mySample.mc()->sumweight_positive(); + output_->width(15); + *output_ << std::left << std::scientific + << mySample.mc()->sumweight_negative(); + *output_ << std::endl; + *output_ << "<WeightNames>"; + for (auto &name_map : mySample.mc()->WeightNames()) + { + *output_ << std::endl; + output_->width(15); + *output_ << name_map.first; + output_->width(15); + *output_ << name_map.second; + } + *output_ << std::endl; + *output_ << "</WeightNames>" << std::endl; + } + else + { + output_->width(15); + *output_ << std::left << std::scientific + << 0; + output_->width(15); + *output_ << std::left << std::scientific + << 0; + output_->width(15); + *output_ << std::left << std::scientific + << mySample.nevents(); + output_->width(15); + *output_ << std::left << std::scientific + << 0; + output_->width(15); + *output_ << std::left << std::scientific + << 0; + *output_ << std::endl; + } + *output_ << "</SampleGlobalInfo>" << std::endl; + *output_ << std::endl; + return true; +} // ----------------------------------------------------------------------------- // WriteFiles // ----------------------------------------------------------------------------- -MAbool SAFWriter::WriteFiles(const std::vector<SampleFormat>& mySamples) +MAbool SAFWriter::WriteFiles(const std::vector<SampleFormat> &mySamples) { - // FileInfo - *output_ << "<FileInfo>" << std::endl; - for (MAuint32 i=0;i<mySamples.size();i++) - { - output_->width(40); - *output_ << std::left << "\""+mySamples[i].name()+"\""; - if (i<2 || i>=(mySamples.size()-2)) - *output_ << " # file " << i+1 << " / " << mySamples.size(); - *output_ << std::endl; - } - *output_ << "</FileInfo>" << std::endl; - *output_ << std::endl; - - // SampleDetailedInfo - *output_ << "<SampleDetailedInfo>" << std::endl; - - // title line - output_->width(15); - *output_ << std::left << "# xsection "; - output_->width(15); - *output_ << std::left << "xsection_error "; - output_->width(15); - *output_ << std::left << "nevents "; - output_->width(15); - *output_ << std::left << "sum_weight+ "; - output_->width(15); - *output_ << std::left << "sum_weight- "; - *output_ << std::endl; - - // data - for (MAuint32 i=0;i<mySamples.size();i++) - { - if (mySamples[i].mc()!=0) + // FileInfo + *output_ << "<FileInfo>" << std::endl; + for (MAuint32 i = 0; i < mySamples.size(); i++) { - output_->width(15); - *output_ << std::left << std::scientific - << mySamples[i].mc()->xsection(); - output_->width(15); - *output_ << std::left << std::scientific - << mySamples[i].mc()->xsection_error(); - output_->width(15); - *output_ << std::left << std::scientific - << mySamples[i].nevents(); - output_->width(15); - *output_ << std::left << std::scientific - << mySamples[i].mc()->sumweight_positive(); - output_->width(15); - *output_ << std::left << std::scientific - << mySamples[i].mc()->sumweight_negative(); + output_->width(40); + *output_ << std::left << "\"" + mySamples[i].name() + "\""; + if (i < 2 || i >= (mySamples.size() - 2)) + *output_ << " # file " << i + 1 << " / " << mySamples.size(); + *output_ << std::endl; } - else - { - output_->width(15); - *output_ << std::left << std::scientific - << 0; - output_->width(15); - *output_ << std::left << std::scientific - << 0; - output_->width(15); - *output_ << std::left << std::scientific - << mySamples[i].nevents(); - output_->width(15); - *output_ << std::left << std::scientific - << 0; - output_->width(15); - *output_ << std::left << std::scientific - << 0; - } - if (i<2 || i>=(mySamples.size()-2)) - *output_ << " # file " << i+1 << " / " << mySamples.size(); + *output_ << "</FileInfo>" << std::endl; *output_ << std::endl; - } - *output_ << "</SampleDetailedInfo>" << std::endl; - *output_ << std::endl; + // SampleDetailedInfo + *output_ << "<SampleDetailedInfo>" << std::endl; - return true; -} + // title line + output_->width(15); + *output_ << std::left << "# xsection "; + output_->width(15); + *output_ << std::left << "xsection_error "; + output_->width(15); + *output_ << std::left << "nevents "; + output_->width(15); + *output_ << std::left << "sum_weight+ "; + output_->width(15); + *output_ << std::left << "sum_weight- "; + *output_ << std::endl; + + // data + for (MAuint32 i = 0; i < mySamples.size(); i++) + { + if (mySamples[i].mc() != 0) + { + output_->width(15); + *output_ << std::left << std::scientific + << mySamples[i].mc()->xsection(); + output_->width(15); + *output_ << std::left << std::scientific + << mySamples[i].mc()->xsection_error(); + output_->width(15); + *output_ << std::left << std::scientific + << mySamples[i].nevents(); + output_->width(15); + *output_ << std::left << std::scientific + << mySamples[i].mc()->sumweight_positive(); + output_->width(15); + *output_ << std::left << std::scientific + << mySamples[i].mc()->sumweight_negative(); + } + else + { + output_->width(15); + *output_ << std::left << std::scientific + << 0; + output_->width(15); + *output_ << std::left << std::scientific + << 0; + output_->width(15); + *output_ << std::left << std::scientific + << mySamples[i].nevents(); + output_->width(15); + *output_ << std::left << std::scientific + << 0; + output_->width(15); + *output_ << std::left << std::scientific + << 0; + } + if (i < 2 || i >= (mySamples.size() - 2)) + *output_ << " # file " << i + 1 << " / " << mySamples.size(); + *output_ << std::endl; + } + *output_ << "</SampleDetailedInfo>" << std::endl; + *output_ << std::endl; + return true; +} // ----------------------------------------------------------------------------- // WriteEvent // ----------------------------------------------------------------------------- -MAbool SAFWriter::WriteEvent(const EventFormat& myEvent, - const SampleFormat& mySample) +MAbool SAFWriter::WriteEvent(const EventFormat &myEvent, + const SampleFormat &mySample) { - if (myEvent.mc()==0 && mySample.mc()==0) return true; - return true; + if (myEvent.mc() == 0 && mySample.mc() == 0) + return true; + return true; } - // ----------------------------------------------------------------------------- // WriteFoot // ----------------------------------------------------------------------------- -MAbool SAFWriter::WriteFoot(const SampleFormat& mySample) +MAbool SAFWriter::WriteFoot(const SampleFormat &mySample) { - *output_ << "<SAFfooter>" << std::endl; - *output_ << "</SAFfooter>" << std::endl; - return true; + *output_ << "<SAFfooter>" << std::endl; + *output_ << "</SAFfooter>" << std::endl; + return true; } MAbool SAFWriter::WriteFoot() { - *output_ << "<SAFfooter>" << std::endl; - *output_ << "</SAFfooter>" << std::endl; - return true; + *output_ << "<SAFfooter>" << std::endl; + *output_ << "</SAFfooter>" << std::endl; + return true; } diff --git a/tools/SampleAnalyzer/Process/Writer/SAFWriter.h b/tools/SampleAnalyzer/Process/Writer/SAFWriter.h index 8b4aba12..e984620d 100644 --- a/tools/SampleAnalyzer/Process/Writer/SAFWriter.h +++ b/tools/SampleAnalyzer/Process/Writer/SAFWriter.h @@ -1,31 +1,29 @@ //////////////////////////////////////////////////////////////////////////////// -// +// // Copyright (C) 2012-2023 Jack Araz, Eric Conte & Benjamin Fuks // The MadAnalysis development team, email: <ma5team@iphc.cnrs.fr> -// +// // This file is part of MadAnalysis 5. // Official website: <https://github.com/MadAnalysis/madanalysis5> -// +// // MadAnalysis 5 is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // MadAnalysis 5 is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with MadAnalysis 5. If not, see <http://www.gnu.org/licenses/> -// +// //////////////////////////////////////////////////////////////////////////////// - #ifndef WRITER_SAF_h #define WRITER_SAF_h - // STL headers #include <fstream> #include <iostream> @@ -34,52 +32,44 @@ // SampleAnalyzer headers #include "SampleAnalyzer/Process/Writer/WriterTextBase.h" - namespace MA5 { -class SAFWriter : public WriterTextBase -{ - - // ------------------------------------------------------------- - // data members - // ------------------------------------------------------------- - protected: - - - // ------------------------------------------------------------- - // method members - // ------------------------------------------------------------- - public: - - /// Constructor without argument - SAFWriter() - { } - - /// Destructor - virtual ~SAFWriter() - { } - - /// Read the sample (virtual pure) - virtual MAbool WriteHeader(const SampleFormat& mySample); - virtual MAbool WriteHeader(); - - /// Read the sample (virtual pure) - MAbool WriteFiles(const std::vector<SampleFormat>& mySample); - - /// Read the event (virtual pure) - virtual MAbool WriteEvent(const EventFormat& myEvent, - const SampleFormat& mySample); - - /// Finalize the event (virtual pure) - virtual MAbool WriteFoot(const SampleFormat& mySample); - virtual MAbool WriteFoot(); - - /// Getting stream - std::ostream* GetStream() - { return output_; } - -}; + class SAFWriter : public WriterTextBase + { + + // ------------------------------------------------------------- + // data members + // ------------------------------------------------------------- + protected: + // ------------------------------------------------------------- + // method members + // ------------------------------------------------------------- + public: + /// Constructor without argument + SAFWriter() {} + + /// Destructor + virtual ~SAFWriter() {} + + /// Read the sample (virtual pure) + virtual MAbool WriteHeader(const SampleFormat &mySample); + virtual MAbool WriteHeader(); + + /// Read the sample (virtual pure) + MAbool WriteFiles(const std::vector<SampleFormat> &mySample); + + /// Read the event (virtual pure) + virtual MAbool WriteEvent(const EventFormat &myEvent, + const SampleFormat &mySample); + + /// Finalize the event (virtual pure) + virtual MAbool WriteFoot(const SampleFormat &mySample); + virtual MAbool WriteFoot(); + + /// Getting stream + std::ostream *GetStream() { return output_; } + }; } From 7ad2f015fe27c4b97b76073b3da0fd26051e2778 Mon Sep 17 00:00:00 2001 From: "Jack Y. Araz" <jackaraz@gmail.com> Date: Fri, 30 Jun 2023 14:41:51 +0100 Subject: [PATCH 042/107] add weight names to the summary --- tools/SampleAnalyzer/Process/Core/SampleAnalyzer.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tools/SampleAnalyzer/Process/Core/SampleAnalyzer.cpp b/tools/SampleAnalyzer/Process/Core/SampleAnalyzer.cpp index 99cba93e..924be6b5 100644 --- a/tools/SampleAnalyzer/Process/Core/SampleAnalyzer.cpp +++ b/tools/SampleAnalyzer/Process/Core/SampleAnalyzer.cpp @@ -1004,6 +1004,10 @@ void SampleAnalyzer::FillSummary(SampleFormat &summary, summary.mc()->xsection_ = 0; summary.mc()->xsection_error_ = 0; } + + /// ! this assumes all the weight identifiers are the same through out the sample set + for (auto &name_map : samples.back().mc()->WeightNames()) + summary.mc()->SetWeightName(name_map.first, name_map.second); } /// Updating the progress bar From 4f1230c408558fc7e332cd0072c39296eac6f890 Mon Sep 17 00:00:00 2001 From: "Jack Y. Araz" <jackaraz@gmail.com> Date: Fri, 30 Jun 2023 14:42:02 +0100 Subject: [PATCH 043/107] cleaning --- tools/SampleAnalyzer/Process/Reader/HEPMCReader.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/tools/SampleAnalyzer/Process/Reader/HEPMCReader.cpp b/tools/SampleAnalyzer/Process/Reader/HEPMCReader.cpp index 7fa91698..5d7aecc9 100644 --- a/tools/SampleAnalyzer/Process/Reader/HEPMCReader.cpp +++ b/tools/SampleAnalyzer/Process/Reader/HEPMCReader.cpp @@ -400,8 +400,6 @@ void HEPMCReader::FillEventInformations(const std::string &line, { MAfloat64 value; str >> value; - // if (i == 0) - // myEvent.mc()->weight_ = value; myEvent.mc()->weights().Add(i, value); } } From ed028955d1aa7a5d735fef1c55e5966e27054bcc Mon Sep 17 00:00:00 2001 From: "Jack Y. Araz" <jackaraz@gmail.com> Date: Fri, 30 Jun 2023 14:42:28 +0100 Subject: [PATCH 044/107] update reference to weight names --- tools/SampleAnalyzer/Commons/DataFormat/MCSampleFormat.h | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/tools/SampleAnalyzer/Commons/DataFormat/MCSampleFormat.h b/tools/SampleAnalyzer/Commons/DataFormat/MCSampleFormat.h index 7676fbe1..5aa7e3a7 100644 --- a/tools/SampleAnalyzer/Commons/DataFormat/MCSampleFormat.h +++ b/tools/SampleAnalyzer/Commons/DataFormat/MCSampleFormat.h @@ -111,7 +111,6 @@ namespace MA5 length_unit_ = 1.0; energy_unit_ = 1.0; - // WeightDefinition weight_names_.clear(); // File info @@ -178,11 +177,7 @@ namespace MA5 /// Set the cross section mean // BENJ: the normalization in the pythia lhe output by madgraph has been changed // the 1e9 factor is not needed anymore - void setXsection(MAfloat64 value) - // { xsection_=value*getXsectionUnitFactor();} - { - xsection_ = value; - } + void setXsection(MAfloat64 value) { xsection_ = value; } /// Set the cross section mean void setXsectionMean(MAfloat64 value) { xsection_ = value; } @@ -196,7 +191,7 @@ namespace MA5 void SetWeightName(int id, std::string name) { weight_names_[id] = name; } /// @brief accessor to weight names - const std::map<int, std::string> WeightNames() const { return weight_names_; } + const std::map<int, std::string> &WeightNames() const { return weight_names_; } /// Adding a weight void addWeightedEvents(MAfloat64 weight) From ccc354987c6a92e2e1e721c5940dd4715349050b Mon Sep 17 00:00:00 2001 From: "Jack Y. Araz" <jackaraz@gmail.com> Date: Fri, 30 Jun 2023 17:08:33 +0100 Subject: [PATCH 045/107] initialise weight configuration --- .../configuration/weight_configuration.py | 156 ++++++++++++++++++ 1 file changed, 156 insertions(+) create mode 100644 madanalysis/configuration/weight_configuration.py diff --git a/madanalysis/configuration/weight_configuration.py b/madanalysis/configuration/weight_configuration.py new file mode 100644 index 00000000..b286e5de --- /dev/null +++ b/madanalysis/configuration/weight_configuration.py @@ -0,0 +1,156 @@ +################################################################################ +# +# Copyright (C) 2012-2023 Jack Araz, Eric Conte & Benjamin Fuks +# The MadAnalysis development team, email: <ma5team@iphc.cnrs.fr> +# +# This file is part of MadAnalysis 5. +# Official website: <https://github.com/MadAnalysis/madanalysis5> +# +# MadAnalysis 5 is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# MadAnalysis 5 is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with MadAnalysis 5. If not, see <http://www.gnu.org/licenses/> +# +################################################################################ + + +from typing import Text, List +from dataclasses import dataclass, field +import numpy as np + + +@dataclass +class Weight: + """Weight identifier class""" + + name: Text + loc: int + _aux: int = field(init=False, default=None) + _dyn_scale: int = field(init=False, default=None) + _muf: float = field(init=False, default=None) + _mur: float = field(init=False, default=None) + _pdf: int = field(init=False, default=None) + _merging: float = field(init=False, default=None) + + def __post_init__(self) -> None: + sectors = self.name.split("_") + + for sector in sectors: + if "AUX" in sector: + self._aux = int(sectors[1]) + break + if "MERGING" in sector: + self._merging = float(sector.split("=")[1]) + elif "DYN_SCALE" in sector: + self._dyn_scale = int(sector.split("=")[1]) + elif "MUF" in sector: + self._muf = float(sector.split("=")[1]) + elif "MUR" in sector: + self._mur = float(sector.split("=")[1]) + elif "PDF" in sector: + self._pdf = int(sector.split("=")[1]) + + @property + def aux(self) -> int: + """retreive aux value""" + return self._aux + + @property + def dynamic_scale(self) -> int: + """retreive dynamic scale""" + return self._dyn_scale + + @property + def muf(self) -> float: + """retreive factorisation scale""" + return self._muf + + @property + def mur(self) -> float: + """retreive **forget the name** scale""" + return self._mur + + @property + def pdfset(self) -> int: + """retreive pdf set id""" + return self._pdf + + @property + def merging(self) -> float: + """retreive merging scale""" + return self._merging + + @property + def is_nominal(self) -> bool: + """Return true if the weight is nominal""" + if all( + x is None + for x in [ + self.aux, + self.pdfset, + self.dynamic_scale, + self.muf, + self.mur, + self.merging, + ] + ): + return True + + return False + + +class WeightCollection: + """Create a weight collection""" + + def __init__(self, collection: List[Weight] = None): + self._collection = [] if collection is None else collection + + def append(self, name: Text, idx: int): + """Add weight into the collection""" + self._collection.append(Weight(name=name, loc=idx)) + + def __iter__(self): + yield from self._collection + + @property + def nominal(self) -> Weight: + """Get nominal weight""" + for w in self: + if w.is_nominal: + return w + raise ValueError("Can not find nominal weight") + + def group_for(self, group: Text): + """Create a group""" + assert group in ["muf", "mur", "pdfset", "dynamic_scale"] + + unique = np.unique( + [getattr(w, group) for w in self if getattr(w, group) is not None] + ) + + if len(unique) == 0: + return {} + + group_dict = {v: [] for v in unique} + for w in self: + if getattr(w, group) is not None: + group_dict[getattr(w, group)].append(w) + + return group_dict + + def pdfset(self, pdfid: int) -> List[Weight]: + """retreive weights corresponding to one pdf set""" + return WeightCollection([w for w in self if w.pdfset == pdfid]) + + @property + def pdfsets(self) -> List[int]: + """Retreive a list of pdfsets""" + return np.unique([w.pdfset for w in self if w.pdfset is not None]).tolist() From 7a6d1c702eb2d8edaa040759580fbe654614ac6d Mon Sep 17 00:00:00 2001 From: "Jack Y. Araz" <jackaraz@gmail.com> Date: Fri, 30 Jun 2023 17:08:43 +0100 Subject: [PATCH 046/107] integrate weight config --- madanalysis/dataset/dataset.py | 649 +++++++++++++++++++-------------- 1 file changed, 382 insertions(+), 267 deletions(-) diff --git a/madanalysis/dataset/dataset.py b/madanalysis/dataset/dataset.py index 63b438bd..8ac86552 100644 --- a/madanalysis/dataset/dataset.py +++ b/madanalysis/dataset/dataset.py @@ -1,85 +1,115 @@ ################################################################################ -# +# # Copyright (C) 2012-2023 Jack Araz, Eric Conte & Benjamin Fuks # The MadAnalysis development team, email: <ma5team@iphc.cnrs.fr> -# +# # This file is part of MadAnalysis 5. # Official website: <https://github.com/MadAnalysis/madanalysis5> -# +# # MadAnalysis 5 is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. -# +# # MadAnalysis 5 is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. -# +# # You should have received a copy of the GNU General Public License # along with MadAnalysis 5. If not, see <http://www.gnu.org/licenses/> -# +# ################################################################################ from __future__ import absolute_import +from typing import Dict, Text from madanalysis.enumeration.linestyle_type import LineStyleType from madanalysis.enumeration.backstyle_type import BackStyleType from madanalysis.enumeration.color_type import ColorType from madanalysis.dataset.sample_info import SampleInfo from madanalysis.layout.layout import Layout +from madanalysis.configuration.weight_configuration import Weight, WeightCollection import logging + class Dataset: - userVariables = { "type" : ["signal","background"], \ - "linecolor" : ["auto","none","red","black","white","yellow",\ - "blue","grey","green","purple","cyan","orange"], \ - "backcolor" : ["auto","none","red","black","white","yellow",\ - "blue","grey","green","purple","cyan","orange"], \ - "backstyle" : ["solid","dotted","hline","dline","vline"], \ - "linestyle" : ["solid","dashed","dotted","dash-dotted"],\ - "linewidth" : [], \ - "weight" : [], \ - "xsection" : [], \ - "scale_up_variation" : [], \ - "scale_down_variation" : [], \ - "scale_variation" : [], \ - "pdf_up_variation" : [], \ - "pdf_down_variation" : [], \ - "pdf_variation" : [], \ - "title" : [], \ - "weighted_events": ["true","false"]} - - def __init__(self,name): - self.name = name.lower() - self.weight = 1. - self.xsection = 0. - self.scaleup = None - self.scaledn = None - self.pdfup = None - self.pdfdn = None - self.background = False - self.linecolor = ColorType.AUTO - self.linestyle = LineStyleType.SOLID - self.lineshade = 0 - self.linewidth = 1 - self.backcolor = ColorType.AUTO - self.backstyle = BackStyleType.SOLID - self.backshade = 0 - self.filenames = [] - self.title = name - self.weighted_events = True - self.measured_global = SampleInfo() - self.measured_detail = [] + userVariables = { + "type": ["signal", "background"], + "linecolor": [ + "auto", + "none", + "red", + "black", + "white", + "yellow", + "blue", + "grey", + "green", + "purple", + "cyan", + "orange", + ], + "backcolor": [ + "auto", + "none", + "red", + "black", + "white", + "yellow", + "blue", + "grey", + "green", + "purple", + "cyan", + "orange", + ], + "backstyle": ["solid", "dotted", "hline", "dline", "vline"], + "linestyle": ["solid", "dashed", "dotted", "dash-dotted"], + "linewidth": [], + "weight": [], + "xsection": [], + "scale_up_variation": [], + "scale_down_variation": [], + "scale_variation": [], + "pdf_up_variation": [], + "pdf_down_variation": [], + "pdf_variation": [], + "title": [], + "weighted_events": ["true", "false"], + } + + def __init__(self, name): + self.name = name.lower() + self.weight = 1.0 + self.xsection = 0.0 + self.scaleup = None + self.scaledn = None + self.pdfup = None + self.pdfdn = None + self.background = False + self.linecolor = ColorType.AUTO + self.linestyle = LineStyleType.SOLID + self.lineshade = 0 + self.linewidth = 1 + self.backcolor = ColorType.AUTO + self.backstyle = BackStyleType.SOLID + self.backshade = 0 + self.filenames = [] + self.title = name + self.weighted_events = True + self.measured_global = SampleInfo() + self.measured_detail = [] + self.weight_collection: WeightCollection = WeightCollection() def __len__(self): return len(self.filenames) - def __getitem__(self,i): + def __getitem__(self, i): return self.filenames[i] - def user_GetValues(self,variable): + def user_GetValues(self, variable): try: return Dataset.userVariables[variable] except: @@ -88,219 +118,257 @@ def user_GetValues(self,variable): def user_GetParameters(self): return list(Dataset.userVariables.keys()) - def user_SetParameter(self,variable,value,value2="",value3=""): - #type + def user_SetParameter(self, variable, value, value2="", value3=""): + # type if variable == "type": - if value=="signal": - self.background=False - elif value=="background": - self.background=True + if value == "signal": + self.background = False + elif value == "background": + self.background = True else: - logging.getLogger('MA5').error("The possible values for the attribute 'type' "+\ - "are 'signal' and 'background'.") + logging.getLogger("MA5").error( + "The possible values for the attribute 'type' " + + "are 'signal' and 'background'." + ) - #weighted events + # weighted events elif variable == "weighted_events": - if value=="true": - self.weighted_events=True - elif value=="false": - self.weighted_events=False + if value == "true": + self.weighted_events = True + elif value == "false": + self.weighted_events = False else: - logging.getLogger('MA5').error("The possible values for the attribute "+\ - "'weighted_events' are 'true' and 'false'.") + logging.getLogger("MA5").error( + "The possible values for the attribute " + + "'weighted_events' are 'true' and 'false'." + ) - #linecolor + # linecolor elif variable == "linecolor": # COLOR - if value=="red": - self.linecolor=ColorType.RED - elif value=="none": - self.linecolor=ColorType.NONE - elif value=="black": - self.linecolor=ColorType.BLACK - elif value=="white": - self.linecolor=ColorType.WHITE - elif value=="yellow": - self.linecolor=ColorType.YELLOW - elif value=="blue": - self.linecolor=ColorType.BLUE - elif value=="grey": - self.linecolor=ColorType.GREY - elif value=="green": - self.linecolor=ColorType.GREEN - elif value=="purple": - self.linecolor=ColorType.PURPLE - elif value=="cyan": - self.linecolor=ColorType.CYAN - elif value=="orange": - self.linecolor=ColorType.ORANGE - elif value=="auto": - self.linecolor=ColorType.AUTO + if value == "red": + self.linecolor = ColorType.RED + elif value == "none": + self.linecolor = ColorType.NONE + elif value == "black": + self.linecolor = ColorType.BLACK + elif value == "white": + self.linecolor = ColorType.WHITE + elif value == "yellow": + self.linecolor = ColorType.YELLOW + elif value == "blue": + self.linecolor = ColorType.BLUE + elif value == "grey": + self.linecolor = ColorType.GREY + elif value == "green": + self.linecolor = ColorType.GREEN + elif value == "purple": + self.linecolor = ColorType.PURPLE + elif value == "cyan": + self.linecolor = ColorType.CYAN + elif value == "orange": + self.linecolor = ColorType.ORANGE + elif value == "auto": + self.linecolor = ColorType.AUTO else: - logging.getLogger('MA5').error("the possible values for the attribute 'linecolor' are "+\ - "'auto', 'none', 'black', 'white', 'red', 'yellow'," + \ - "'blue', 'grey', 'purple', 'cyan', 'orange'.") + logging.getLogger("MA5").error( + "the possible values for the attribute 'linecolor' are " + + "'auto', 'none', 'black', 'white', 'red', 'yellow'," + + "'blue', 'grey', 'purple', 'cyan', 'orange'." + ) return - #SHADE - if value3=="": - self.lineshade=0 + # SHADE + if value3 == "": + self.lineshade = 0 return try: - code=int(value3) + code = int(value3) except: - logging.getLogger('MA5').error("the parameter '"+value3+"' is not an integer") + logging.getLogger("MA5").error( + "the parameter '" + value3 + "' is not an integer" + ) return - - if value2=='+': - self.lineshade=code - elif value2=='-': - self.lineshade=code*-1 + + if value2 == "+": + self.lineshade = code + elif value2 == "-": + self.lineshade = code * -1 else: - logging.getLogger('MA5').error("the parameter '"+value2+"' is not '+' or '-'") + logging.getLogger("MA5").error( + "the parameter '" + value2 + "' is not '+' or '-'" + ) return - #linestyle + # linestyle elif variable == "linestyle": - if value=="solid": - self.linestyle=LineStyleType.SOLID - elif value=="dashed": - self.linestyle=LineStyleType.DASHED - elif value=="dotted": - self.linestyle=LineStyleType.DOTTED - elif value=="dash-dotted": - self.linestyle=LineStyleType.DASHDOTTED + if value == "solid": + self.linestyle = LineStyleType.SOLID + elif value == "dashed": + self.linestyle = LineStyleType.DASHED + elif value == "dotted": + self.linestyle = LineStyleType.DOTTED + elif value == "dash-dotted": + self.linestyle = LineStyleType.DASHDOTTED else: - logging.getLogger('MA5').error("the possible values for the attribute 'linestyle' are "+\ - "'solid', 'dashed', 'dotted', 'dash-dotted'.") - - #linewidth + logging.getLogger("MA5").error( + "the possible values for the attribute 'linestyle' are " + + "'solid', 'dashed', 'dotted', 'dash-dotted'." + ) + + # linewidth elif variable == "linewidth": try: - code=int(value) + code = int(value) except: - logging.getLogger('MA5').error("the parameter '"+value+"' is not an integer value") + logging.getLogger("MA5").error( + "the parameter '" + value + "' is not an integer value" + ) return - if code>0 and code<10: - self.linewidth=code + if code > 0 and code < 10: + self.linewidth = code else: - logging.getLogger('MA5').error("the parameter '"+value+"' must be > 0 and < 11") + logging.getLogger("MA5").error( + "the parameter '" + value + "' must be > 0 and < 11" + ) - #backstyle + # backstyle elif variable == "backstyle": - if value=="solid": - self.backstyle=BackStyleType.SOLID - elif value=="dotted": - self.backstyle=BackStyleType.DOTTED - elif value=="hline": - self.backstyle=BackStyleType.HLINE - elif value=="dline": - self.backstyle=BackStyleType.DLINE - elif value=="vline": - self.backstyle=BackStyleType.VLINE + if value == "solid": + self.backstyle = BackStyleType.SOLID + elif value == "dotted": + self.backstyle = BackStyleType.DOTTED + elif value == "hline": + self.backstyle = BackStyleType.HLINE + elif value == "dline": + self.backstyle = BackStyleType.DLINE + elif value == "vline": + self.backstyle = BackStyleType.VLINE else: - logging.getLogger('MA5').error("the possible values for the attribute 'backstyle' are "+\ - "'solid', 'dotted', 'hline', 'dline', 'vline'.") + logging.getLogger("MA5").error( + "the possible values for the attribute 'backstyle' are " + + "'solid', 'dotted', 'hline', 'dline', 'vline'." + ) - #backcolor + # backcolor elif variable == "backcolor": - if value=="red": - self.backcolor=ColorType.RED - elif value=="black": - self.backcolor=ColorType.BLACK - elif value=="none": - self.backcolor=ColorType.NONE - elif value=="white": - self.backcolor=ColorType.WHITE - elif value=="yellow": - self.backcolor=ColorType.YELLOW - elif value=="blue": - self.backcolor=ColorType.BLUE - elif value=="grey": - self.backcolor=ColorType.GREY - elif value=="green": - self.backcolor=ColorType.GREEN - elif value=="purple": - self.backcolor=ColorType.PURPLE - elif value=="cyan": - self.backcolor=ColorType.CYAN - elif value=="orange": - self.backcolor=ColorType.ORANGE - elif value=="auto": - self.backcolor=ColorType.AUTO + if value == "red": + self.backcolor = ColorType.RED + elif value == "black": + self.backcolor = ColorType.BLACK + elif value == "none": + self.backcolor = ColorType.NONE + elif value == "white": + self.backcolor = ColorType.WHITE + elif value == "yellow": + self.backcolor = ColorType.YELLOW + elif value == "blue": + self.backcolor = ColorType.BLUE + elif value == "grey": + self.backcolor = ColorType.GREY + elif value == "green": + self.backcolor = ColorType.GREEN + elif value == "purple": + self.backcolor = ColorType.PURPLE + elif value == "cyan": + self.backcolor = ColorType.CYAN + elif value == "orange": + self.backcolor = ColorType.ORANGE + elif value == "auto": + self.backcolor = ColorType.AUTO else: - logging.getLogger('MA5').error("the possible value for the attribute 'backcolor' are "+\ - "'auto', 'none', 'black', 'white', 'red', 'yellow'," + \ - "'blue', 'grey', 'purple', 'cyan', 'orange'.") + logging.getLogger("MA5").error( + "the possible value for the attribute 'backcolor' are " + + "'auto', 'none', 'black', 'white', 'red', 'yellow'," + + "'blue', 'grey', 'purple', 'cyan', 'orange'." + ) return - - #SHADE - if value3=="": - self.backshade=0 + + # SHADE + if value3 == "": + self.backshade = 0 return try: - code=int(value3) + code = int(value3) except: - logging.getLogger('MA5').error("the parameter '"+value3+"' is not an integer") + logging.getLogger("MA5").error( + "the parameter '" + value3 + "' is not an integer" + ) return - - if value2=='+': - self.backshade=code - elif value2=='-': - self.backshade=code*-1 + + if value2 == "+": + self.backshade = code + elif value2 == "-": + self.backshade = code * -1 else: - logging.getLogger('MA5').error("the parameter '"+value2+"' is not '+' or '-'") + logging.getLogger("MA5").error( + "the parameter '" + value2 + "' is not '+' or '-'" + ) return - #weight + # weight elif variable in ["weight", "xsection"]: try: tmp = float(value) except: - logging.getLogger('MA5').error("the value of the attribute '"+variable+\ - "' must be set to a positive floating number.") + logging.getLogger("MA5").error( + "the value of the attribute '" + + variable + + "' must be set to a positive floating number." + ) return - if tmp>=0: + if tmp >= 0: if variable == "weight": - self.weight=tmp + self.weight = tmp elif variable == "xsection": - self.xsection=tmp + self.xsection = tmp self.measured_global.xsection = tmp else: - logging.getLogger('MA5').error("the value of the attribute '"+variable+\ - "' must be set to a positive floating number.") + logging.getLogger("MA5").error( + "the value of the attribute '" + + variable + + "' must be set to a positive floating number." + ) return # uncertainties - elif variable in ["scale_up_variation","scale_down_variation",\ - "pdf_up_variation","pdf_down_variation",\ - "scale_variation", "pdf_variation"]: + elif variable in [ + "scale_up_variation", + "scale_down_variation", + "pdf_up_variation", + "pdf_down_variation", + "scale_variation", + "pdf_variation", + ]: try: tmp = float(value) except: - logging.getLogger('MA5').error("the value of the attribute '"+variable+\ - "' must be set to a positive floating-point number") + logging.getLogger("MA5").error( + "the value of the attribute '" + + variable + + "' must be set to a positive floating-point number" + ) return - if tmp>=0: + if tmp >= 0: if variable == "scale_up_variation": self.scaleup = tmp if self.scaledn == None: - self.scaledn = .0 + self.scaledn = 0.0 elif variable == "scale_down_variation": self.scaledn = tmp if self.scaleup == None: - self.scaleup = 0. + self.scaleup = 0.0 elif variable == "pdf_up_variation": self.pdfup = tmp if self.pdfdn == None: - self.pdfdn = 0. + self.pdfdn = 0.0 elif variable == "pdf_down_variation": self.pdfdn = tmp if self.pdfup == None: - self.pdfup = 0. + self.pdfup = 0.0 elif variable == "scale_variation": self.scaledn = tmp self.scaleup = tmp @@ -308,28 +376,37 @@ def user_SetParameter(self,variable,value,value2="",value3=""): self.pdfdn = tmp self.pdfup = tmp else: - logging.getLogger('MA5').error("the value of the attribute '"+variable+\ - "' must be set to a positive floating-point number") + logging.getLogger("MA5").error( + "the value of the attribute '" + + variable + + "' must be set to a positive floating-point number" + ) return # title elif variable == "title": quoteTag = False - if value[0] in ["'",'"'] and value[-1] in ["'",'"']: - value=value[1:-1] - self.title=value + if value[0] in ["'", '"'] and value[-1] in ["'", '"']: + value = value[1:-1] + self.title = value else: - logging.getLogger('MA5').error("the value of the attribute '"+variable+\ - "' must be set to a string.") - - # other + logging.getLogger("MA5").error( + "the value of the attribute '" + + variable + + "' must be set to a string." + ) + + # other else: - logging.getLogger('MA5').error("the class dataset has no attribute denoted by '"+variable+"'.") - + logging.getLogger("MA5").error( + "the class dataset has no attribute denoted by '" + variable + "'." + ) def Display(self): - logging.getLogger('MA5').info(" ******************************************" ) - logging.getLogger('MA5').info(" Name of the dataset = " + self.name + " (" + self.GetStringTag() + ")") + logging.getLogger("MA5").info(" ******************************************") + logging.getLogger("MA5").info( + " Name of the dataset = " + self.name + " (" + self.GetStringTag() + ")" + ) self.user_DisplayParameter("title") self.user_DisplayParameter("xsection") self.user_DisplayParameter("scale_unc") @@ -341,76 +418,104 @@ def Display(self): self.user_DisplayParameter("linewidth") self.user_DisplayParameter("backcolor") self.user_DisplayParameter("backstyle") - logging.getLogger('MA5').info(" List of event files included in this dataset:") + logging.getLogger("MA5").info(" List of event files included in this dataset:") for item in self.filenames: - logging.getLogger('MA5').info(" - " + item) - logging.getLogger('MA5').info(" ******************************************" ) + logging.getLogger("MA5").info(" - " + item) + logging.getLogger("MA5").info(" ******************************************") msg = " Cross section = " - if self.measured_global.xsection==0 or self.measured_global.xerror!=0: - msg+="(" - msg += Layout.DisplayXsection(self.measured_global.xsection,self.measured_global.xerror) - if self.measured_global.xsection==0 or self.measured_global.xerror!=0: - msg+=")" + if self.measured_global.xsection == 0 or self.measured_global.xerror != 0: + msg += "(" + msg += Layout.DisplayXsection( + self.measured_global.xsection, self.measured_global.xerror + ) + if self.measured_global.xsection == 0 or self.measured_global.xerror != 0: + msg += ")" msg += " pb" - logging.getLogger('MA5').info(msg) - logging.getLogger('MA5').info(" Total number of events = " + str(self.measured_global.nevents)) - if (self.measured_global.sumw_positive + self.measured_global.sumw_negative)==0: - msg='0.0' + logging.getLogger("MA5").info(msg) + logging.getLogger("MA5").info( + " Total number of events = " + str(self.measured_global.nevents) + ) + if (self.measured_global.sumw_positive + self.measured_global.sumw_negative) == 0: + msg = "0.0" else: - msg=str(Layout.Round_to_Ndigits(100.*self.measured_global.sumw_negative / \ - (self.measured_global.sumw_positive + self.measured_global.sumw_negative ),2 )) - logging.getLogger('MA5').info(" Ratio of negative weights = " + str(msg) + ' %') - logging.getLogger('MA5').info(" ******************************************" ) - - - def user_DisplayParameter(self,parameter): - if parameter=="weight": - logging.getLogger('MA5').info(" User-imposed weight value for the set = "+str(self.weight)) - elif parameter=="xsection": - logging.getLogger('MA5').info(" User-imposed cross section = "+str(self.xsection)) - elif parameter=="scale_unc": + msg = str( + Layout.Round_to_Ndigits( + 100.0 + * self.measured_global.sumw_negative + / ( + self.measured_global.sumw_positive + + self.measured_global.sumw_negative + ), + 2, + ) + ) + logging.getLogger("MA5").info(" Ratio of negative weights = " + str(msg) + " %") + logging.getLogger("MA5").info(" ******************************************") + + def user_DisplayParameter(self, parameter): + if parameter == "weight": + logging.getLogger("MA5").info( + " User-imposed weight value for the set = " + str(self.weight) + ) + elif parameter == "xsection": + logging.getLogger("MA5").info( + " User-imposed cross section = " + str(self.xsection) + ) + elif parameter == "scale_unc": if not self.scaleup == None and not self.scaledn == None: - logging.getLogger('MA5').info(" User-imposed scale uncertainties: "+\ - "-{:.1%}, +{:.1%}".format(self.scaledn,self.scaleup)) - elif parameter=="PDF_unc": + logging.getLogger("MA5").info( + " User-imposed scale uncertainties: " + + "-{:.1%}, +{:.1%}".format(self.scaledn, self.scaleup) + ) + elif parameter == "PDF_unc": if not self.pdfup == None and not self.pdfdn == None: - logging.getLogger('MA5').info(" User-imposed PDF uncertainties: "+\ - "-{:.1%}, +{:.1%}".format(self.pdfdn,self.pdfup)) - elif parameter=="type": - logging.getLogger('MA5').info(" Type = "+self.GetStringTag()) - elif parameter=="weighted_events": + logging.getLogger("MA5").info( + " User-imposed PDF uncertainties: " + + "-{:.1%}, +{:.1%}".format(self.pdfdn, self.pdfup) + ) + elif parameter == "type": + logging.getLogger("MA5").info(" Type = " + self.GetStringTag()) + elif parameter == "weighted_events": if self.weighted_events: - logging.getLogger('MA5').info(" Taking account of event weight: true") + logging.getLogger("MA5").info(" Taking account of event weight: true") else: - logging.getLogger('MA5').info(" Taking account of event weight: false") - elif parameter=="title": - logging.getLogger('MA5').info(" Title = '"+self.title+"'") - elif parameter=="linecolor": - msg=ColorType.convert2string(self.linecolor) - if self.lineshade!=0 and self.linecolor!=ColorType.AUTO: - if self.lineshade>0: - msg+="+"+str(self.lineshade) + logging.getLogger("MA5").info(" Taking account of event weight: false") + elif parameter == "title": + logging.getLogger("MA5").info(" Title = '" + self.title + "'") + elif parameter == "linecolor": + msg = ColorType.convert2string(self.linecolor) + if self.lineshade != 0 and self.linecolor != ColorType.AUTO: + if self.lineshade > 0: + msg += "+" + str(self.lineshade) else: - msg+=str(self.lineshade) - logging.getLogger('MA5').info(" Line color in histograms = "+msg) - elif parameter=="linestyle": - logging.getLogger('MA5').info(" Line style in histograms = "+\ - LineStyleType.convert2string(self.linestyle)) - elif parameter=="linewidth": - logging.getLogger('MA5').info(" Line width in histograms = "+str(self.linewidth)) - elif parameter=="backcolor": - msg=ColorType.convert2string(self.backcolor) - if self.backshade!=0 and self.backcolor!=ColorType.AUTO: - if self.backshade>0: - msg+="+"+str(self.backshade) + msg += str(self.lineshade) + logging.getLogger("MA5").info(" Line color in histograms = " + msg) + elif parameter == "linestyle": + logging.getLogger("MA5").info( + " Line style in histograms = " + + LineStyleType.convert2string(self.linestyle) + ) + elif parameter == "linewidth": + logging.getLogger("MA5").info( + " Line width in histograms = " + str(self.linewidth) + ) + elif parameter == "backcolor": + msg = ColorType.convert2string(self.backcolor) + if self.backshade != 0 and self.backcolor != ColorType.AUTO: + if self.backshade > 0: + msg += "+" + str(self.backshade) else: - msg+=str(self.backshade) - logging.getLogger('MA5').info(" Background color in histograms = "+msg) - elif parameter=="backstyle": - logging.getLogger('MA5').info(" Background style in histograms = "+\ - BackStyleType.convert2string(self.backstyle)) + msg += str(self.backshade) + logging.getLogger("MA5").info(" Background color in histograms = " + msg) + elif parameter == "backstyle": + logging.getLogger("MA5").info( + " Background style in histograms = " + + BackStyleType.convert2string(self.backstyle) + ) else: - logging.getLogger('MA5').error(" the class dataset has no attribute denoted by '"+parameter+"'") + logging.getLogger("MA5").error( + " the class dataset has no attribute denoted by '" + parameter + "'" + ) def GetStringTag(self): if self.background: @@ -418,18 +523,28 @@ def GetStringTag(self): else: return "signal" - def Find(self,file): + def Find(self, file): if file in self.filenames: return True return False - def Add(self,file): + def Add(self, file): if not self.Find(file): self.filenames.append(file) - - def Remove(self,file): + + def Remove(self, file): if self.Find(file): del self.filenames[file] def GetIds(self): return self.filenames + + def AddWeight(self, idx: int, name: str): + """ + Add weight to the dictionary + + Args: + idx (``int``): weight location in the list + name (``str``): name of the weight + """ + self.weight_collection.append(name=name, idx=idx) From fc7862e99fe6af8f9f2f7814212d801bcfe36dea Mon Sep 17 00:00:00 2001 From: "Jack Y. Araz" <jackaraz@gmail.com> Date: Fri, 30 Jun 2023 17:20:57 +0100 Subject: [PATCH 047/107] add properties --- .../configuration/weight_configuration.py | 31 +++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/madanalysis/configuration/weight_configuration.py b/madanalysis/configuration/weight_configuration.py index b286e5de..add4f6ae 100644 --- a/madanalysis/configuration/weight_configuration.py +++ b/madanalysis/configuration/weight_configuration.py @@ -22,7 +22,7 @@ ################################################################################ -from typing import Text, List +from typing import Text, List, Dict, Any from dataclasses import dataclass, field import numpy as np @@ -58,6 +58,10 @@ def __post_init__(self) -> None: elif "PDF" in sector: self._pdf = int(sector.split("=")[1]) + def to_dict(self) -> Dict[Text, Any]: + """Convert to dictionary""" + return {"loc": self.loc, "name": self.name} + @property def aux(self) -> int: """retreive aux value""" @@ -112,14 +116,37 @@ class WeightCollection: def __init__(self, collection: List[Weight] = None): self._collection = [] if collection is None else collection + self._names = [] def append(self, name: Text, idx: int): """Add weight into the collection""" - self._collection.append(Weight(name=name, loc=idx)) + if name not in self.names: + self._collection.append(Weight(name=name, loc=idx)) def __iter__(self): yield from self._collection + def __len__(self): + return len(self._collection) + + @property + def names(self) -> List[Text]: + """retreive weight names""" + if len(self) == len(self._names): + return self._names + + self._names = [x.name for x in self] + return self._names + + def to_dict(self) -> List[Dict[Text, Any]]: + """Convert to dictionary""" + return [x.to_dict() for x in self] + + def from_dict(self, data: List[Dict[Text, Any]]) -> None: + """Construct collection from data""" + for dat in data: + self.append(dat["name"], dat["loc"]) + @property def nominal(self) -> Weight: """Get nominal weight""" From 5406657bbd0d555aa800b4e364204111127bdf9f Mon Sep 17 00:00:00 2001 From: "Jack Y. Araz" <jackaraz@gmail.com> Date: Fri, 30 Jun 2023 17:27:56 +0100 Subject: [PATCH 048/107] add weight reader --- madanalysis/IOinterface/job_reader.py | 86 ++++++++++++++++++++++----- 1 file changed, 70 insertions(+), 16 deletions(-) diff --git a/madanalysis/IOinterface/job_reader.py b/madanalysis/IOinterface/job_reader.py index 3e563350..5b260c15 100644 --- a/madanalysis/IOinterface/job_reader.py +++ b/madanalysis/IOinterface/job_reader.py @@ -62,10 +62,14 @@ def __init__(self, jobdir): def CheckDir(self): if not os.path.isdir(self.path): - logging.getLogger("MA5").error("Directory called '" + self.path + "' is not found.") + logging.getLogger("MA5").error( + "Directory called '" + self.path + "' is not found." + ) return False elif not os.path.isdir(self.safdir): - logging.getLogger("MA5").error("Directory called '" + self.safdir + "' is not found.") + logging.getLogger("MA5").error( + "Directory called '" + self.safdir + "' is not found." + ) return False else: return True @@ -76,7 +80,13 @@ def CheckFile(self, dataset): return True else: logging.getLogger("MA5").error( - "File called '" + self.safdir + "/" + name + "/" + name + ".saf' is not found." + "File called '" + + self.safdir + + "/" + + name + + "/" + + name + + ".saf' is not found." ) return False @@ -95,7 +105,9 @@ def ExtractSampleInfo(self, words, numline, filename): try: results.xerror = float(words[1]) except: - logging.getLogger("MA5").error("xsection_error is not a float value:" + words[1]) + logging.getLogger("MA5").error( + "xsection_error is not a float value:" + words[1] + ) # Extracting number of events try: @@ -223,7 +235,11 @@ def ExtractDataFreq(self, words, numline, filename): b = float(words[1]) except: logging.getLogger("MA5").error( - str(words[1]) + ' must be a float value @ "' + filename + '" line=' + str(numline) + str(words[1]) + + ' must be a float value @ "' + + filename + + '" line=' + + str(numline) ) b = 0.0 @@ -232,7 +248,11 @@ def ExtractDataFreq(self, words, numline, filename): c = float(words[2]) except: logging.getLogger("MA5").error( - str(words[2]) + ' must be a float value @ "' + filename + '" line=' + str(numline) + str(words[2]) + + ' must be a float value @ "' + + filename + + '" line=' + + str(numline) ) c = 0.0 @@ -261,6 +281,7 @@ def ExtractGeneral(self, dataset): # Initializing tags beginTag = SafBlockStatus() endTag = SafBlockStatus() + weightTag = SafBlockStatus() globalTag = SafBlockStatus() detailTag = SafBlockStatus() @@ -301,6 +322,10 @@ def ExtractGeneral(self, dataset): detailTag.activate() elif words[0].lower() == "</sampledetailedinfo>": detailTag.desactivate() + if words[0].lower() == "<weightnames>": + weightTag.activate() + elif words[0].lower() == "</weightnames>": + weightTag.desactivate() # Looking for summary sample info elif globalTag.activated and len(words) == 5: @@ -308,23 +333,34 @@ def ExtractGeneral(self, dataset): # Looking for detail sample info (one line for each file) elif detailTag.activated and len(words) == 5: - dataset.measured_detail.append(self.ExtractSampleInfo(words, numline, filename)) + dataset.measured_detail.append( + self.ExtractSampleInfo(words, numline, filename) + ) + # Read weights + if globalTag.activated and weightTag.activated and len(words) == 2: + dataset.AddWeight(int(words[0]), words[1]) # Information found ? if beginTag.Nactivated == 0 or beginTag.activated: - logging.getLogger("MA5").error("SAF header <SAFheader> and </SAFheader> is not found.") + logging.getLogger("MA5").error( + "SAF header <SAFheader> and </SAFheader> is not found." + ) if endTag.Nactivated == 0 or endTag.activated: - logging.getLogger("MA5").error("SAF footer <SAFfooter> and </SAFfooter> is not found.") + logging.getLogger("MA5").error( + "SAF footer <SAFfooter> and </SAFfooter> is not found." + ) if globalTag.Nactivated == 0 or globalTag.activated: logging.getLogger("MA5").error( - "Information corresponding to the block " + "<SampleGlobalInfo> is not found." + "Information corresponding to the block " + + "<SampleGlobalInfo> is not found." ) logging.getLogger("MA5").error( "Information on the dataset '" + dataset.name + "' are not updated." ) if detailTag.Nactivated == 0 or globalTag.activated: logging.getLogger("MA5").error( - "Information corresponding to the block " + "<SampleDetailInfo> is not found." + "Information corresponding to the block " + + "<SampleDetailInfo> is not found." ) logging.getLogger("MA5").error( "Information on the dataset '" + dataset.name + "' are not updated." @@ -341,7 +377,12 @@ def ExtractHistos(self, dataset, plot, merging=False): while os.path.isdir(self.safdir + "/" + name + "/MergingPlots_" + str(i)): i += 1 filename = ( - self.safdir + "/" + name + "/MergingPlots_" + str(i - 1) + "/Histograms/histos.saf" + self.safdir + + "/" + + name + + "/MergingPlots_" + + str(i - 1) + + "/Histograms/histos.saf" ) else: while os.path.isdir(self.safdir + "/" + name + "/MadAnalysis5job_" + str(i)): @@ -469,7 +510,11 @@ def ExtractHistos(self, dataset, plot, merging=False): "invalid name for histogram @ line=" + str(numline) + " : " ) logging.getLogger("MA5").error(str(line)) - elif descriptionTag.Nlines == 1 and not histoFreqTag.activated and len(words) >= 3: + elif ( + descriptionTag.Nlines == 1 + and not histoFreqTag.activated + and len(words) >= 3 + ): results = self.ExtractDescription(words, numline, filename) if histoTag.activated: histoinfo.nbins = results[0] @@ -493,7 +538,9 @@ def ExtractHistos(self, dataset, plot, merging=False): histofreqinfo.regions.append(words[0]) else: logging.getLogger("MA5").error( - "invalid region for a histogram @ line=" + str(numline) + " : " + "invalid region for a histogram @ line=" + + str(numline) + + " : " ) logging.getLogger("MA5").error(str(line)) else: @@ -639,7 +686,12 @@ def ExtractCuts(self, dataset, cut): i += 1 filenames = sorted( glob.glob( - self.safdir + "/" + name + "/MadAnalysis5job_" + str(i - 1) + "/Cutflows/*.saf" + self.safdir + + "/" + + name + + "/MadAnalysis5job_" + + str(i - 1) + + "/Cutflows/*.saf" ) ) @@ -649,7 +701,9 @@ def ExtractCuts(self, dataset, cut): try: file = open(myfile, "r") except: - logging.getLogger("MA5").error("File called '" + myfile + "' is not found") + logging.getLogger("MA5").error( + "File called '" + myfile + "' is not found" + ) return # Initializing tags From 981c36ec5856f8fdf5f8c910f89e727d0725d960 Mon Sep 17 00:00:00 2001 From: "Jack Y. Araz" <jackaraz@gmail.com> Date: Fri, 30 Jun 2023 17:28:17 +0100 Subject: [PATCH 049/107] revert some of the structure --- madanalysis/IOinterface/text_file_reader.py | 38 ++++++++------- madanalysis/layout/histogram_core.py | 51 +++++++++++++++------ 2 files changed, 54 insertions(+), 35 deletions(-) diff --git a/madanalysis/IOinterface/text_file_reader.py b/madanalysis/IOinterface/text_file_reader.py index 369dbc9b..3a385e59 100644 --- a/madanalysis/IOinterface/text_file_reader.py +++ b/madanalysis/IOinterface/text_file_reader.py @@ -1,56 +1,54 @@ ################################################################################ -# +# # Copyright (C) 2012-2023 Jack Araz, Eric Conte & Benjamin Fuks # The MadAnalysis development team, email: <ma5team@iphc.cnrs.fr> -# +# # This file is part of MadAnalysis 5. # Official website: <https://github.com/MadAnalysis/madanalysis5> -# +# # MadAnalysis 5 is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. -# +# # MadAnalysis 5 is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. -# +# # You should have received a copy of the GNU General Public License # along with MadAnalysis 5. If not, see <http://www.gnu.org/licenses/> -# +# ################################################################################ from __future__ import absolute_import import logging -class TextFileReader(): - def __init__(self,filename): + +class TextFileReader: + def __init__(self, filename): self.filename = filename self.isopen = False def Open(self): if self.isopen: - logging.getLogger('MA5').error("Cannot open the file '"+self.filename+"' because it is already opened") + logging.getLogger("MA5").error( + "Cannot open the file '" + + self.filename + + "' because it is already opened" + ) return False try: - self.file = open ( self.filename, "r" ) + self.file = open(self.filename, "r") self.isopen = True return True except: - logging.getLogger('MA5').error("File called '" + self.filename + "' is not found") + logging.getLogger("MA5").error( + "File called '" + self.filename + "' is not found" + ) return False def Close(self): if self.isopen: self.file.close() - - - - - - - - - diff --git a/madanalysis/layout/histogram_core.py b/madanalysis/layout/histogram_core.py index a98b96c5..6b6bd4ae 100644 --- a/madanalysis/layout/histogram_core.py +++ b/madanalysis/layout/histogram_core.py @@ -24,9 +24,8 @@ from __future__ import absolute_import import logging -import numpy as np from math import sqrt -from six.moves import range +import numpy as np class HistogramCore: @@ -34,22 +33,38 @@ def __init__(self): # statistics # - int - self.nevents = np.array([0]) - self.nentries = np.array([0]) + self.nevents = 0 + self.nentries = 0 # - float - self.integral = np.array([0.0]) - self.sumwentries = np.array([0.0]) - self.sumw = np.array([0.0]) - self.sumw2 = np.array([0.0]) - self.sumwx = np.array([0.0]) - self.sumw2x = np.array([0.0]) + self.integral = 0.0 + self.sumwentries = 0.0 + self.sumw = 0.0 + self.sumw2 = 0.0 + self.sumwx = 0.0 + self.sumw2x = 0.0 # content - self.underflow = np.array([0.0]) - self.overflow = np.array([0.0]) - self.nan = np.array([0.0]) - self.inf = np.array([0.0]) + self.underflow = 0.0 + self.overflow = 0.0 + self.nan = 0.0 + self.inf = 0.0 self.array = [] + self.array_unc = [] + + def convert_to_numpy(self) -> None: + """Convert data containers into numpy arrays for convenience""" + for tp in [ + "nevents", + "nentries", + "sumwentries", + "sumw", + "sumw2", + "sumwx", + "sumw2x", + "underflow", + "overflow", + ]: + setattr(self, tp, np.array(getattr(self, tp))) def ComputeIntegral(self): self.integral = np.sum(self.array, axis=0) @@ -78,8 +93,14 @@ def Print(self): ) def GetMean(self): - return np.array([wx / w for wx, w in zip(self.sumwx, self.sumw) if w != 0]) + if self.sumw == 0: + return 0.0 + + return self.sumwx / self.sumw def GetRMS(self): + if self.sumw == 0: + return 0.0 + mean = self.GetMean() return sqrt(abs(self.sumw2x / self.sumw - mean * mean)) From 7c3f9c45722a9a002d7256c0979ef4256743ce00 Mon Sep 17 00:00:00 2001 From: "Jack Y. Araz" <jackaraz@gmail.com> Date: Fri, 30 Jun 2023 17:28:28 +0100 Subject: [PATCH 050/107] add processor --- madanalysis/layout/histogram_processor.py | 120 ++++++++++++++++++++++ 1 file changed, 120 insertions(+) create mode 100644 madanalysis/layout/histogram_processor.py diff --git a/madanalysis/layout/histogram_processor.py b/madanalysis/layout/histogram_processor.py new file mode 100644 index 00000000..b0cebcf3 --- /dev/null +++ b/madanalysis/layout/histogram_processor.py @@ -0,0 +1,120 @@ +################################################################################ +# +# Copyright (C) 2012-2023 Jack Araz, Eric Conte & Benjamin Fuks +# The MadAnalysis development team, email: <ma5team@iphc.cnrs.fr> +# +# This file is part of MadAnalysis 5. +# Official website: <https://github.com/MadAnalysis/madanalysis5> +# +# MadAnalysis 5 is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# MadAnalysis 5 is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with MadAnalysis 5. If not, see <http://www.gnu.org/licenses/> +# +################################################################################ + +from typing import List, Union, Text, Dict +import json +from dataclasses import dataclass +from .histogram import Histogram +from madanalysis.configuration.weight_configuration import WeightCollection + +import numpy as np + + +@dataclass +class HistogramProcessor: + """ + Processor for multiweight histograms + + Args: + positive_bin_weights (``Union[List[float], np.ndarray]``): positive sum of weights per bin + negative_bin_weights (``Union[List[float], np.ndarray]``): negative sum of weights per bin + weight_names (``Dict[int, Text]``): names of the weights + xsection (``float``): cross section of the data + name (``Text``): name of the histogram + """ + + histogram: Histogram + weight_collection: WeightCollection + total_nevents: int + xsection: float + name: Text = "__unknown_histogram__" + + def __post_init__(self): + positive_bin_weights = np.array(self.histogram.positive.array) + negative_bin_weights = np.abs(np.array(self.histogram.negative.array)) + + positive_sumw = np.array(self.histogram.positive.sumw) + negative_sumw = np.abs(np.array(self.histogram.negative.sumw)) + self.sumw = positive_sumw - negative_sumw + + positive_sumwentries = np.array(self.histogram.positive.sumwentries) + negative_sumwentries = np.abs(np.array(self.histogram.negative.sumwentries)) + self.sumwentries = positive_sumwentries - negative_sumwentries + + positive_nevents = np.array(self.histogram.positive.nevents) + negative_nevents = np.abs(np.array(self.histogram.negative.nevents)) + nevents = positive_nevents + negative_nevents + + self.eff = 0 if self.total_nevents == 0 else nevents[0] / self.total_nevents + + positive_overflow = np.array(self.histogram.positive.overflow) + negative_overflow = np.abs(np.array(self.histogram.negative.overflow)) + self.overflow = positive_overflow - negative_overflow + + positive_underflow = np.array(self.histogram.positive.underflow) + negative_underflow = np.abs(np.array(self.histogram.negative.underflow)) + self.underflow = positive_underflow - negative_underflow + + assert ( + positive_bin_weights.shape == negative_bin_weights.shape + ), "Invalid bin shapes." + + self.bin_weights = positive_bin_weights - negative_bin_weights + self.integral = np.sum(self.bin_weights, axis=0) + self.overflow + self.underflow + + def scale(self, lumi: float) -> float: + """ + Compute the scale of the nominal histogram + + Args: + lumi (``float``): luminosity in fb-1 + + Returns: + ``float``: + scale of the histogram + """ + # find nominal weight location + idx = self.weight_collection.nominal.loc + + if self.integral[idx] == 0: + return 0.0 + + sumw = self.sumw[idx] + sumwentries = self.sumwentries[idx] + entries_per_events = 0 if sumwentries == 0 else sumw / sumwentries + + return float( + self.xsection + * lumi + * 1000.0 + * self.eff + * entries_per_events + / self.integral[idx] + ) + + def uncertainty(self, lumi: float) -> np.ndarray: + pass + + def to_json(self, file_path: "."): + """Convert histogram to json file""" + pass From 66196618bb43695bc9cebd8fff3db519c0d141bc Mon Sep 17 00:00:00 2001 From: "Jack Y. Araz" <jackaraz@gmail.com> Date: Fri, 30 Jun 2023 17:28:59 +0100 Subject: [PATCH 051/107] adaptation --- madanalysis/layout/histogram.py | 76 +- madanalysis/layout/layout.py | 1134 +++++++++++--------- madanalysis/layout/plotflow.py | 133 ++- madanalysis/layout/plotflow_for_dataset.py | 119 +- 4 files changed, 817 insertions(+), 645 deletions(-) diff --git a/madanalysis/layout/histogram.py b/madanalysis/layout/histogram.py index 4ace9ea3..1057b585 100644 --- a/madanalysis/layout/histogram.py +++ b/madanalysis/layout/histogram.py @@ -47,70 +47,78 @@ def Print(self): def FinalizeReading(self, main, dataset): - # convert everything to numpy arrays - for loc in ["positive", "negative", "summary"]: - for tp in [ - "nevents", - "nentries", - "sumwentries", - "sumw", - "sumw2", - "sumwx", - "sumw2x", - "underflow", - "overflow", - ]: - setattr(getattr(self, loc), tp, np.array(getattr(getattr(self, loc), tp))) + self.positive.convert_to_numpy() + self.negative.convert_to_numpy() + self.summary.convert_to_numpy() # Statistics - self.summary.nevents = np.array(self.positive.nevents) + np.array(self.negative.nevents) - self.summary.nentries = np.array(self.positive.nentries) + np.array(self.negative.nentries) + self.summary.nevents = self.positive.nevents + self.negative.nevents + self.summary.nentries = self.positive.nentries + self.negative.nentries # sumw - self.summary.sumw = np.clip( - np.array(self.positive.sumw) - np.array(self.negative.sumw), 0, None - ) + self.summary.sumw = np.clip(self.positive.sumw - self.negative.sumw, 0, None) # sumw2 - self.summary.sumw2 = np.clip( - np.array(self.positive.sumw2) - np.array(self.negative.sumw2), 0, None - ) + self.summary.sumw2 = np.clip(self.positive.sumw2 - self.negative.sumw2, 0, None) # sumwx - self.summary.sumwx = np.array(self.positive.sumwx) - np.array(self.negative.sumwx) + self.summary.sumwx = self.positive.sumwx - self.negative.sumwx # no correction on it # sumw2x - self.summary.sumw2x = np.array(self.positive.sumw2x) - np.array(self.negative.sumw2x) + self.summary.sumw2x = self.positive.sumw2x - self.negative.sumw2x # no correction on it # underflow self.summary.underflow = np.clip( - np.array(self.positive.underflow) - np.array(self.negative.underflow), 0, None + self.positive.underflow - self.negative.underflow, 0, None ) # overflow self.summary.overflow = np.clip( - np.array(self.positive.overflow) - np.array(self.negative.overflow), 0, None + self.positive.overflow - self.negative.overflow, 0, None ) + # compute mean and uncertainties for the statistics + # ! @jackaraz: this portion of the code should be changed to accomodate different types of + # ! PDF + scale unc combination for now its just mean and std + for tp in [ + "nevents", + "nentries", + "sumw", + "sumw2", + "sumwx", + "sumw2x", + "underflow", + "overflow", + ]: + # compute unc shape: (lower, upper) + std = float(np.std(getattr(self.summary, tp))) + setattr(self.summary, tp + "_unc", (std, std)) + # compute mean + setattr(self.summary, tp, float(np.mean(getattr(self.summary, tp)))) + # Data data = [] for i, array in enumerate(self.positive.array): - data.append(np.array(self.positive.array[i]) - np.array(self.negative.array[i])) + data.append(np.array(array) - np.array(self.negative.array[i])) if np.any(data[-1] < 0): self.warnings.append( - "dataset=" - + dataset.name - + " -> bin " - + str(i) - + " has a negative content : " - + str(data[-1]) - + ". This value is set to zero" + f"dataset={dataset.name} -> bin {i} has a negative content : " + f"{str(data[-1])}. This value is set to zero." ) data[-1] = np.clip(data[-1], 0, None) self.summary.array = np.array(data[:]) # [:] -> clone of data + # Compute the mean and the error on the data + # mean shape should be (Nbins, ) and the histogram unc shape should be (Nbins, 2) + # where first column is the lower envelop and second is upper envelop + histogram_mean = np.mean(self.summary.array, axis=1) + std = np.std(self.summary.array, axis=1) + histogram_unc = np.hstack([std, std]) + self.summary.array = histogram_mean.reshape(-1) + self.summary.array_unc = histogram_unc + # Integral self.positive.ComputeIntegral() self.negative.ComputeIntegral() diff --git a/madanalysis/layout/layout.py b/madanalysis/layout/layout.py index 1e25ba63..00378683 100644 --- a/madanalysis/layout/layout.py +++ b/madanalysis/layout/layout.py @@ -1,62 +1,61 @@ ################################################################################ -# +# # Copyright (C) 2012-2023 Jack Araz, Eric Conte & Benjamin Fuks # The MadAnalysis development team, email: <ma5team@iphc.cnrs.fr> -# +# # This file is part of MadAnalysis 5. # Official website: <https://github.com/MadAnalysis/madanalysis5> -# +# # MadAnalysis 5 is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. -# +# # MadAnalysis 5 is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. -# +# # You should have received a copy of the GNU General Public License # along with MadAnalysis 5. If not, see <http://www.gnu.org/licenses/> -# +# ################################################################################ from __future__ import absolute_import -from madanalysis.enumeration.sb_ratio_type import SBratioType -from madanalysis.enumeration.color_type import ColorType -from madanalysis.enumeration.cut_type import CutType -from madanalysis.enumeration.report_format_type import ReportFormatType -from madanalysis.enumeration.normalize_type import NormalizeType -from madanalysis.enumeration.observable_type import ObservableType -from madanalysis.enumeration.graphic_render_type import GraphicRenderType -from madanalysis.enumeration.font_type import FontType -from madanalysis.enumeration.script_type import ScriptType -from madanalysis.IOinterface.folder_writer import FolderWriter -from madanalysis.IOinterface.text_report import TextReport -from madanalysis.IOinterface.html_report_writer import HTMLReportWriter -from madanalysis.IOinterface.latex_report_writer import LATEXReportWriter -from madanalysis.IOinterface.histo_root_producer import HistoRootProducer -from madanalysis.IOinterface.histo_matplotlib_producer import HistoMatplotlibProducer -from madanalysis.layout.cutflow import CutFlow -from madanalysis.layout.plotflow import PlotFlow -from madanalysis.layout.merging_plots import MergingPlots -from madanalysis.selection.instance_name import InstanceName -from math import log10, floor, ceil, isnan, isinf + +from math import ceil, isnan, isinf import os import shutil import logging from six.moves import range -class Layout: +from madanalysis.enumeration.color_type import ColorType +from madanalysis.enumeration.cut_type import CutType +from madanalysis.enumeration.report_format_type import ReportFormatType +from madanalysis.enumeration.normalize_type import NormalizeType +from madanalysis.enumeration.graphic_render_type import GraphicRenderType +from madanalysis.enumeration.font_type import FontType +from madanalysis.enumeration.script_type import ScriptType +from madanalysis.IOinterface.folder_writer import FolderWriter +from madanalysis.IOinterface.text_report import TextReport +from madanalysis.IOinterface.html_report_writer import HTMLReportWriter +from madanalysis.IOinterface.latex_report_writer import LATEXReportWriter +from madanalysis.IOinterface.histo_root_producer import HistoRootProducer +from madanalysis.IOinterface.histo_matplotlib_producer import HistoMatplotlibProducer +from madanalysis.layout.cutflow import CutFlow +from madanalysis.layout.plotflow import PlotFlow +from madanalysis.layout.merging_plots import MergingPlots - def __init__(self,main): - self.main = main - self.input_path = self.main.lastjob_name - self.cutflow = CutFlow(self.main) - self.plotflow = PlotFlow(self.main) - self.merging = MergingPlots(self.main) - self.logger = logging.getLogger('MA5') + +class Layout: + def __init__(self, main): + self.main = main + self.input_path = self.main.lastjob_name + self.cutflow = CutFlow(self.main) + self.plotflow = PlotFlow(self.main) + self.merging = MergingPlots(self.main) + self.logger = logging.getLogger("MA5") def Initialize(self): @@ -71,268 +70,260 @@ def Initialize(self): def DisplayInteger(value): if type(value) is not int: return "" - if value<0: + if value < 0: return "-" + Layout.DisplayInteger(-value) elif value < 1000: return str(value) else: - return Layout.DisplayInteger(value / 1000) +\ - "," + '%03d' % (value % 1000) - + return Layout.DisplayInteger(value / 1000) + "," + "%03d" % (value % 1000) @staticmethod - def Round_to_Ndigits(x,N): + def Round_to_Ndigits(x, N): # Safety 1 - if N<1: + if N < 1: return "" - + # Safety 2 - if isnan(x): - return "nan" - elif isinf(x): - return "inf" + if isnan(x) or isinf(x): + return "nan" if isnan(x) else "inf" # Convert - if x<(10**(N-1)): - convert = '%.'+str(N)+'G' - return '%s' % float(convert % x) - else: - tmp = '%s' % float('%.12G' % int(x)) - if len(tmp)>=3 and tmp.endswith('.0'): - tmp = tmp[:-2] - return tmp + if x < (10 ** (N - 1)): + convert = "%." + str(N) + "G" + return "%s" % float(convert % x) + tmp = "%s" % float("%.12G" % int(x)) + if len(tmp) >= 3 and tmp.endswith(".0"): + tmp = tmp[:-2] + return tmp @staticmethod - def DisplayXsection(xsection,xerror): + def DisplayXsection(xsection, xerror): # xsection and xerror are null - if xsection==0. and xerror==0.: + if xsection == 0.0 and xerror == 0.0: return "0.0 @ 0.0%" - + # xsection is not null but xerror is # keep the 3 significative digit - elif xerror==0: - return Layout.Round_to_Ndigits(xsection,3) - - # error greater than xsection ? + elif xerror == 0: + return Layout.Round_to_Ndigits(xsection, 3) + + # error greater than xsection ? else: - string1 = Layout.Round_to_Ndigits(xsection,3) - if xsection ==0.: - string2="0.0" + string1 = Layout.Round_to_Ndigits(xsection, 3) + if xsection == 0.0: + string2 = "0.0" else: - string2 = Layout.Round_to_Ndigits(100.*xerror/xsection,2) - return string1 + " @ " + string2 + '%' - + string2 = Layout.Round_to_Ndigits(100.0 * xerror / xsection, 2) + return string1 + " @ " + string2 + "%" @staticmethod - def DisplayXsecCut(xsection,xerror): + def DisplayXsecCut(xsection, xerror): # xsection and xerror are null - if xsection==0. and xerror==0.: + if xsection == 0.0 and xerror == 0.0: return "0.0 +/- 0.0" - + # xsection is not null but xerror is # keep the 3 significative digit - elif xerror==0: - return Layout.Round_to_Ndigits(xsection,3) - - # error greater than xsection ? + elif xerror == 0: + return Layout.Round_to_Ndigits(xsection, 3) + + # error greater than xsection ? elif xsection > xerror: - string1 = Layout.Round_to_Ndigits(xerror,3) - if 'e' in string1 or 'E' in string1: - string2='%.2e' % xsection - string1='%.2e' % xerror - elif '.' in string1: - convert='%.'+str(len(string1.split('.')[1]))+'f' - string2=convert % xsection + string1 = Layout.Round_to_Ndigits(xerror, 3) + if "e" in string1 or "E" in string1: + string2 = "%.2e" % xsection + string1 = "%.2e" % xerror + elif "." in string1: + convert = "%." + str(len(string1.split(".")[1])) + "f" + string2 = convert % xsection else: - string2=str(int(xsection)) - return string2 + " +/- " + string1 + string2 = str(int(xsection)) + return string2 + " +/- " + string1 else: - string1 = Layout.Round_to_Ndigits(xsection,3) - if 'e' in string1 or 'E' in string1: - string2='%.2e' % xerror - string1='%.2e' % xsection - elif '.' in string1: - convert='%.'+str(len(string1.split('.')[1]))+'f' - string2=convert % xerror + string1 = Layout.Round_to_Ndigits(xsection, 3) + if "e" in string1 or "E" in string1: + string2 = "%.2e" % xerror + string1 = "%.2e" % xsection + elif "." in string1: + convert = "%." + str(len(string1.split(".")[1])) + "f" + string2 = convert % xerror else: - string2=str(int(xerror)) + string2 = str(int(xerror)) return string1 + " +/- " + string2 - - - def DoPlots(self,histo_path,modes,output_paths): + def DoPlots(self, histo_path, modes, output_paths): ListPlots = [] - + # Header plots - self.logger.debug('Producing scripts for header plots ...') + self.logger.debug("Producing scripts for header plots ...") if self.main.merging.enable: - self.merging.DrawAll(histo_path,modes,output_paths,ListPlots) + self.merging.DrawAll(histo_path, modes, output_paths, ListPlots) # Selection plots - self.logger.debug('Producing scripts for selection plots ...') - if self.main.selection.Nhistos!=0: - self.plotflow.DrawAll(histo_path,modes,output_paths,ListPlots) + self.logger.debug("Producing scripts for selection plots ...") + if self.main.selection.Nhistos != 0: + self.plotflow.DrawAll(histo_path, modes, output_paths, ListPlots) # Foot plots - self.logger.debug('Producing scripts for foot plots ...') + self.logger.debug("Producing scripts for foot plots ...") # to do # Launching ROOT - if self.main.graphic_render==GraphicRenderType.ROOT: - producer=HistoRootProducer(histo_path,ListPlots) + if self.main.graphic_render == GraphicRenderType.ROOT: + producer = HistoRootProducer(histo_path, ListPlots) producer.Execute() - elif self.main.graphic_render==GraphicRenderType.MATPLOTLIB: - producer=HistoMatplotlibProducer(histo_path,ListPlots) + elif self.main.graphic_render == GraphicRenderType.MATPLOTLIB: + producer = HistoMatplotlibProducer(histo_path, ListPlots) producer.Execute() # Ok return True + def CopyLogo(self, mode, output_path): - def CopyLogo(self,mode,output_path): - # Filename - filename = self.main.archi_info.ma5dir+"/madanalysis/input/" + \ - "logo." + \ - ReportFormatType.convert2filetype(mode) + filename = ( + self.main.archi_info.ma5dir + + "/madanalysis/input/" + + "logo." + + ReportFormatType.convert2filetype(mode) + ) # Checking file presence if not os.path.isfile(filename): - self.logger.error("the image '" + \ - filename + \ - "' is not found.") + self.logger.error("the image '" + filename + "' is not found.") return False # Copy file - try : - shutil.copy(filename,output_path) + try: + shutil.copy(filename, output_path) return True except: self.logger.error("Errors have occured during the copy of the file ") - self.logger.error(" "+filename) + self.logger.error(" " + filename) return False - def WriteDatasetTable(self,report,dataset): + def WriteDatasetTable(self, report, dataset): # Datatype - datatype="signal" + datatype = "signal" if dataset.background: - datatype="background" + datatype = "background" report.OpenBullet() - text=TextReport() + text = TextReport() # Must we specify the sample folder ? - specify=False - for ind in range(0,len(dataset.filenames)): - samplename = dataset.filenames[ind].replace(self.main.currentdir,'') - if samplename[0]!='/' or samplename==dataset.filenames[ind]: - specify=True + specify = False + for ind in range(0, len(dataset.filenames)): + samplename = dataset.filenames[ind].replace(self.main.currentdir, "") + if samplename[0] != "/" or samplename == dataset.filenames[ind]: + specify = True break # Displaying the folder if specify: - text.Add('Samples stored in the directory: ') + text.Add("Samples stored in the directory: ") text.SetColor(ColorType.BLUE) text.Add(self.main.currentdir) text.SetColor(ColorType.BLACK) - text.Add('.\n') + text.Add(".\n") report.WriteText(text) text.Reset() # Signal or background sample - text.Add('Sample consisting of: ') + text.Add("Sample consisting of: ") text.SetColor(ColorType.BLUE) text.Add(datatype) text.SetColor(ColorType.BLACK) - text.Add(' events.\n') + text.Add(" events.\n") report.WriteText(text) text.Reset() - + # Number of generated events - text.Add('Generated events: ') + text.Add("Generated events: ") text.SetColor(ColorType.BLUE) - ngen = int(dataset.measured_global.nevents); + ngen = int(dataset.measured_global.nevents) text.Add(str(ngen) + " ") text.SetColor(ColorType.BLACK) - text.Add(' events.\n') + text.Add(" events.\n") report.WriteText(text) text.Reset() # Cross section imposed by the user if dataset.xsection != 0.0: - text.Add('Cross section imposed by the user: ') + text.Add("Cross section imposed by the user: ") text.SetColor(ColorType.BLUE) text.Add(str(dataset.xsection)) text.SetColor(ColorType.BLACK) - text.Add(' pb.\n') + text.Add(" pb.\n") report.WriteText(text) text.Reset() # Weight of the events, if different from one if dataset.weight != 1.0: - text.Add('Event weight imposed by the user: ') + text.Add("Event weight imposed by the user: ") text.SetColor(ColorType.BLUE) text.Add(str(dataset.weight)) text.SetColor(ColorType.BLACK) - text.Add('.\n') + text.Add(".\n") report.WriteText(text) text.Reset() # Number of events after normalization, with the error - text.Add('Normalization to the luminosity: ') + text.Add("Normalization to the luminosity: ") text.SetColor(ColorType.BLUE) if dataset.xsection != 0.0: nlumi = int(dataset.xsection * 1000 * self.main.lumi) else: - nlumi = int(dataset.measured_global.xsection * \ - 1000*self.main.lumi * \ - dataset.weight) + nlumi = int( + dataset.measured_global.xsection * 1000 * self.main.lumi * dataset.weight + ) text.Add(str(nlumi)) - text.Add(' +/- ') + text.Add(" +/- ") if dataset.xsection != 0.0: elumi = 0.0 else: - elumi = ceil(dataset.measured_global.xerror * 1000 * \ - self.main.lumi * dataset.weight) - text.Add(str(int(elumi))+ " ") + elumi = ceil( + dataset.measured_global.xerror * 1000 * self.main.lumi * dataset.weight + ) + text.Add(str(int(elumi)) + " ") text.SetColor(ColorType.BLACK) - text.Add(' events.\n') + text.Add(" events.\n") report.WriteText(text) text.Reset() # Statistical significance of the sample - evw = 0. - if ngen!=0: - evw = float(nlumi)/float(ngen)*dataset.weight - + evw = 0.0 + if ngen != 0: + evw = float(nlumi) / float(ngen) * dataset.weight + if evw > 1: text.SetColor(ColorType.RED) - text.Add('Ratio (event weight): ') + text.Add("Ratio (event weight): ") if evw < 1: text.SetColor(ColorType.BLUE) - text.Add(str(Layout.Round_to_Ndigits(evw,2)) + " ") + text.Add(str(Layout.Round_to_Ndigits(evw, 2)) + " ") if evw < 1: text.SetColor(ColorType.BLACK) - text.Add('.') + text.Add(".") if evw > 1: - text.Add(' - warning: please generate more events (weight larger than 1)!\n') + text.Add(" - warning: please generate more events (weight larger than 1)!\n") text.SetColor(ColorType.BLACK) else: - text.Add(' \n') + text.Add(" \n") report.WriteText(text) text.Reset() - report.CloseBullet() - + report.CloseBullet() # table with information # titles of the columns - report.CreateTable([6.5,3,3.5,3.5],text) + report.CreateTable([6.5, 3, 3.5, 3.5], text) report.NewCell(ColorType.YELLOW) - if len(dataset.filenames)>=2: + if len(dataset.filenames) >= 2: text.Add(" Paths to the event files") else: text.Add(" Path to the event file") @@ -353,15 +344,15 @@ def WriteDatasetTable(self,report,dataset): report.NewLine() # information - for ind in range(0,len(dataset.filenames)): + for ind in range(0, len(dataset.filenames)): color = ColorType.BLACK # path to the file report.NewCell() - text.Add(' ') + text.Add(" ") text.SetColor(color) - samplename = str(dataset.filenames[ind]).replace(self.main.currentdir,'') - if samplename[0]=='/' and samplename!=dataset.filenames[ind]: + samplename = str(dataset.filenames[ind]).replace(self.main.currentdir, "") + if samplename[0] == "/" and samplename != dataset.filenames[ind]: samplename = samplename[1:] text.Add(samplename) report.WriteText(text) @@ -369,7 +360,7 @@ def WriteDatasetTable(self,report,dataset): # number of events report.NewCell() - text.Add(' ') + text.Add(" ") text.SetColor(color) text.Add(str(int(dataset.measured_detail[ind].nevents))) report.WriteText(text) @@ -377,110 +368,128 @@ def WriteDatasetTable(self,report,dataset): # cross section report.NewCell() - text.Add(' ') + text.Add(" ") text.SetColor(color) if dataset.xsection != 0.0: text.Add(str(dataset.xsection)) else: value = dataset.measured_detail[ind].xsection * dataset.weight error = dataset.measured_detail[ind].xerror * dataset.weight - text.Add(Layout.DisplayXsection(value,error)) + text.Add(Layout.DisplayXsection(value, error)) report.WriteText(text) text.Reset() # Negative weigths report.NewCell() - text.Add(' ') + text.Add(" ") text.SetColor(color) - if (dataset.measured_detail[ind].sumw_positive +\ - dataset.measured_detail[ind].sumw_negative)==0: + if ( + dataset.measured_detail[ind].sumw_positive + + dataset.measured_detail[ind].sumw_negative + ) == 0: text.Add(str(0.0)) else: - text.Add(Layout.Round_to_Ndigits( 100 * \ - dataset.measured_detail[ind].sumw_negative / \ - (dataset.measured_detail[ind].sumw_positive + \ - dataset.measured_detail[ind].sumw_negative),2 )) + text.Add( + Layout.Round_to_Ndigits( + 100 + * dataset.measured_detail[ind].sumw_negative + / ( + dataset.measured_detail[ind].sumw_positive + + dataset.measured_detail[ind].sumw_negative + ), + 2, + ) + ) report.WriteText(text) text.Reset() # end of the line - if len(dataset.filenames)==1: - report.EndLine() + if len(dataset.filenames) == 1: + report.EndLine() else: - report.NewLine() + report.NewLine() # sum if many datasets - if len(dataset.filenames)!=1: - color = ColorType.BLUE - report.NewCell() - text.Add(' ') - text.SetColor(color) - text.Add("Sum") - report.WriteText(text) - text.Reset() - - # number of events - report.NewCell() - text.Add(' ') - text.SetColor(color) - text.Add(str(int(dataset.measured_global.nevents))) - report.WriteText(text) - text.Reset() - - # cross section - report.NewCell() - text.Add(' ') - text.SetColor(color) - if dataset.xsection != 0.0: - text.Add(str(dataset.xsection)) - else: - value = dataset.measured_global.xsection * dataset.weight - error = dataset.measured_global.xerror * dataset.weight - text.Add(Layout.DisplayXsection(value,error)) - report.WriteText(text) - text.Reset() - - # Negative weigths - report.NewCell() - text.Add(' ') - text.SetColor(color) - if (dataset.measured_detail[ind].sumw_positive +\ - dataset.measured_detail[ind].sumw_negative)==0: - text.Add(str(0.0)) - else: - text.Add(Layout.Round_to_Ndigits( 100 * \ - dataset.measured_global.sumw_negative / \ - (dataset.measured_global.sumw_positive + \ - dataset.measured_global.sumw_negative),2 )) - report.WriteText(text) - text.Reset() - - ## The end of line - report.EndLine() - - report.EndTable() + if len(dataset.filenames) != 1: + color = ColorType.BLUE + report.NewCell() + text.Add(" ") + text.SetColor(color) + text.Add("Sum") + report.WriteText(text) + text.Reset() + + # number of events + report.NewCell() + text.Add(" ") + text.SetColor(color) + text.Add(str(int(dataset.measured_global.nevents))) + report.WriteText(text) + text.Reset() + + # cross section + report.NewCell() + text.Add(" ") + text.SetColor(color) + if dataset.xsection != 0.0: + text.Add(str(dataset.xsection)) + else: + value = dataset.measured_global.xsection * dataset.weight + error = dataset.measured_global.xerror * dataset.weight + text.Add(Layout.DisplayXsection(value, error)) + report.WriteText(text) + text.Reset() + + # Negative weigths + report.NewCell() + text.Add(" ") + text.SetColor(color) + if ( + dataset.measured_detail[ind].sumw_positive + + dataset.measured_detail[ind].sumw_negative + ) == 0: + text.Add(str(0.0)) + else: + text.Add( + Layout.Round_to_Ndigits( + 100 + * dataset.measured_global.sumw_negative + / ( + dataset.measured_global.sumw_positive + + dataset.measured_global.sumw_negative + ), + 2, + ) + ) + report.WriteText(text) + text.Reset() + + ## The end of line + report.EndLine() + + report.EndTable() text.Reset() # Writing Final Table - def WriteFinalTable(self,report,cutinfo): + def WriteFinalTable(self, report, cutinfo): # Information report.OpenBullet() - text=TextReport() + text = TextReport() text.Reset() text.Add("How to compare signal (S) and background (B): ") text.SetColor(ColorType.BLUE) text.Add(self.main.fom.getFormula()) text.SetColor(ColorType.BLACK) - text.Add('.\n') + text.Add(".\n") report.WriteText(text) text.Reset() -# text.Add("Associated uncertainty: ") -# text.SetColor(ColorType.BLUE) -# text.Add(self.main.SBerror) -# text.SetColor(ColorType.BLACK) -# text.Add('.\n') -# report.WriteText(text) -# text.Reset() + # text.Add("Associated uncertainty: ") + # text.SetColor(ColorType.BLUE) + # text.Add(self.main.SBerror) + # text.SetColor(ColorType.BLACK) + # text.Add('.\n') + # report.WriteText(text) + # text.Reset() text.Add("Object definition selections are indicated in cyan.") report.WriteText(text) text.Reset() @@ -491,20 +500,20 @@ def WriteFinalTable(self,report,cutinfo): myregs = self.main.regions.GetNames() noreg = False - if myregs==[]: + if myregs == []: myregs = ["myregion"] noreg = True for reg in myregs: # Getting the cutflow names - reg_cflow = [ x[0] for x in cutinfo if reg in x[1]] - type_cflow = [ x[2] for x in cutinfo if reg in x[1]] + reg_cflow = [x[0] for x in cutinfo if reg in x[1]] + type_cflow = [x[2] for x in cutinfo if reg in x[1]] # Printing the table - report.CreateTable([3.25,3.25,3.25,3.00],text) + report.CreateTable([3.25, 3.25, 3.25, 3.00], text) if not noreg: - report.NewCell(ColorType.GREY,span=4) + report.NewCell(ColorType.GREY, span=4) text.Reset() text.SetColor(ColorType.WHITE) - text.Add("Region: \"" + reg + '\"') + text.Add('Region: "' + reg + '"') report.WriteText(text) text.Reset() report.NewLine() @@ -518,7 +527,7 @@ def WriteFinalTable(self,report,cutinfo): report.WriteText(text) report.NewCell(ColorType.YELLOW) text.Reset() - text.Add(" Background (B)")# (+/- err)") + text.Add(" Background (B)") # (+/- err)") report.WriteText(text) report.NewCell(ColorType.YELLOW) text.Reset() @@ -534,45 +543,53 @@ def WriteFinalTable(self,report,cutinfo): report.NewCell() text.Reset() if self.cutflow.isSignal: - text.Add(" " +\ - Layout.DisplayXsecCut(self.cutflow.signal.Ntotal.mean, - self.cutflow.signal.Ntotal.error)) + text.Add( + " " + + Layout.DisplayXsecCut( + self.cutflow.signal.Ntotal.mean, self.cutflow.signal.Ntotal.error + ) + ) else: text.Add(" ") report.WriteText(text) report.NewCell() text.Reset() if self.cutflow.isBackground: - text.Add(" " +\ - Layout.DisplayXsecCut(self.cutflow.background.Ntotal.mean,\ - self.cutflow.background.Ntotal.error)) + text.Add( + " " + + Layout.DisplayXsecCut( + self.cutflow.background.Ntotal.mean, + self.cutflow.background.Ntotal.error, + ) + ) else: text.Add(" ") report.WriteText(text) report.NewCell() text.Reset() if self.cutflow.isSignal and self.cutflow.isBackground: - value = self.cutflow.calculateBSratio(\ - self.cutflow.background.Ntotal.mean,\ - self.cutflow.background.Ntotal.error,\ - self.cutflow.signal.Ntotal.mean,\ - self.cutflow.signal.Ntotal.error) - text.Add(" " + Layout.DisplayXsecCut(value.mean,value.error)) + value = self.cutflow.calculateBSratio( + self.cutflow.background.Ntotal.mean, + self.cutflow.background.Ntotal.error, + self.cutflow.signal.Ntotal.mean, + self.cutflow.signal.Ntotal.error, + ) + text.Add(" " + Layout.DisplayXsecCut(value.mean, value.error)) else: text.Add(" ") report.WriteText(text) # Loop - id_flow=0 + id_flow = 0 for myflow in self.cutflow.detail[0].cuts: - if len(myflow)==0: - id_flow+=1 + if len(myflow) == 0: + id_flow += 1 continue - if len(myflow[0].cutregion)!=1: - self.logger.error('Problem with the interpretation of the output') + if len(myflow[0].cutregion) != 1: + self.logger.error("Problem with the interpretation of the output") return False if reg in myflow[0].cutregion: break - id_flow+=1 + id_flow += 1 if id_flow == len(self.cutflow.detail[0].cuts): report.EndLine() report.EndTable() @@ -580,16 +597,25 @@ def WriteFinalTable(self,report,cutinfo): continue report.NewLine() text.Reset() - iregf=0 - for ind in range(0,len(self.cutflow.detail[0].Nselected[id_flow])): - if not self.cutflow.detail[0].cuts[id_flow][ind].cutname\ - [(self.cutflow.detail[0].cuts[id_flow][ind].cutname.find('_')+1):-1] in reg_cflow[iregf]: + iregf = 0 + for ind in range(0, len(self.cutflow.detail[0].Nselected[id_flow])): + if ( + not self.cutflow.detail[0] + .cuts[id_flow][ind] + .cutname[ + ( + self.cutflow.detail[0].cuts[id_flow][ind].cutname.find("_") + + 1 + ) : -1 + ] + in reg_cflow[iregf] + ): report.NewCell(ColorType.CYAN) text.Reset() - if 'select' in reg_cflow[iregf]: - text.Add('SEL: '+ reg_cflow[iregf].strip()[14:][:45]) + if "select" in reg_cflow[iregf]: + text.Add("SEL: " + reg_cflow[iregf].strip()[14:][:45]) else: - text.Add('REJ: '+ reg_cflow[iregf].strip()[14:][:45]) + text.Add("REJ: " + reg_cflow[iregf].strip()[14:][:45]) report.WriteText(text) report.NewCell(ColorType.CYAN) text.Reset() @@ -605,59 +631,74 @@ def WriteFinalTable(self,report,cutinfo): report.WriteText(text) report.NewLine() text.Reset() - iregf+=1 - iregf+=1 + iregf += 1 + iregf += 1 report.NewCell() text.Reset() - if type_cflow[iregf-1]==CutType.SELECT: - text.Add('SEL: ' + self.cutflow.detail[0].cuts[id_flow][ind].cutname[3:-1][:45]) + if type_cflow[iregf - 1] == CutType.SELECT: + text.Add( + "SEL: " + + self.cutflow.detail[0].cuts[id_flow][ind].cutname[3:-1][:45] + ) else: - text.Add('REJ: ' + self.cutflow.detail[0].cuts[id_flow][ind].cutname[3:-1][:45]) + text.Add( + "REJ: " + + self.cutflow.detail[0].cuts[id_flow][ind].cutname[3:-1][:45] + ) report.WriteText(text) report.NewCell() text.Reset() if self.cutflow.isSignal: - text.Add(" " + \ - Layout.DisplayXsecCut(\ - self.cutflow.signal.Nselected[id_flow][ind].mean,\ - self.cutflow.signal.Nselected[id_flow][ind].error) ) + text.Add( + " " + + Layout.DisplayXsecCut( + self.cutflow.signal.Nselected[id_flow][ind].mean, + self.cutflow.signal.Nselected[id_flow][ind].error, + ) + ) else: text.Add(" ") report.WriteText(text) report.NewCell() text.Reset() if self.cutflow.isBackground: - text.Add(" " + \ - Layout.DisplayXsecCut(\ - self.cutflow.background.Nselected[id_flow][ind].mean,\ - self.cutflow.background.Nselected[id_flow][ind].error) ) + text.Add( + " " + + Layout.DisplayXsecCut( + self.cutflow.background.Nselected[id_flow][ind].mean, + self.cutflow.background.Nselected[id_flow][ind].error, + ) + ) else: text.Add(" ") report.WriteText(text) report.NewCell() text.Reset() if self.cutflow.isSignal and self.cutflow.isBackground: - value = self.cutflow.calculateBSratio(\ - self.cutflow.background.Nselected[id_flow][ind].mean,\ - self.cutflow.background.Nselected[id_flow][ind].error,\ - self.cutflow.signal.Nselected[id_flow][ind].mean,\ - self.cutflow.signal.Nselected[id_flow][ind].error) - text.Add(" " + Layout.DisplayXsecCut(value.mean,value.error)) + value = self.cutflow.calculateBSratio( + self.cutflow.background.Nselected[id_flow][ind].mean, + self.cutflow.background.Nselected[id_flow][ind].error, + self.cutflow.signal.Nselected[id_flow][ind].mean, + self.cutflow.signal.Nselected[id_flow][ind].error, + ) + text.Add(" " + Layout.DisplayXsecCut(value.mean, value.error)) else: text.Add(" ") report.WriteText(text) - if ind == (len(self.cutflow.detail[0].Nselected[id_flow])-1) and iregf==len(reg_cflow): + if ind == ( + len(self.cutflow.detail[0].Nselected[id_flow]) - 1 + ) and iregf == len(reg_cflow): report.EndLine() else: report.NewLine() text.Reset() - for cand in range(iregf,len(reg_cflow)): + for cand in range(iregf, len(reg_cflow)): report.NewCell(ColorType.CYAN) text.Reset() - if 'select' in reg_cflow[cand]: - text.Add('SEL: '+ reg_cflow[cand].strip()[14:][:45]) + if "select" in reg_cflow[cand]: + text.Add("SEL: " + reg_cflow[cand].strip()[14:][:45]) else: - text.Add('REJ: '+ reg_cflow[cand].strip()[14:][:45]) + text.Add("REJ: " + reg_cflow[cand].strip()[14:][:45]) report.WriteText(text) report.NewCell(ColorType.CYAN) text.Reset() @@ -671,7 +712,7 @@ def WriteFinalTable(self,report,cutinfo): text.Reset() text.Add(" - ") report.WriteText(text) - if cand == len(reg_cflow)-1: + if cand == len(reg_cflow) - 1: report.EndLine() else: report.NewLine() @@ -679,22 +720,22 @@ def WriteFinalTable(self,report,cutinfo): report.EndTable() # Writing Efficiency Table - def WriteEfficiencyTable(self,index,icut,report): + def WriteEfficiencyTable(self, index, icut, report): warning_test = False - text=TextReport() + text = TextReport() myregs = self.main.selection[index].regions noreg = False - if myregs==[]: + if myregs == []: myregs = ["myregion"] noreg = True for reg in myregs: text.Reset() - report.CreateTable([2.1,2.8,2.8,3.4,3.3],text) + report.CreateTable([2.1, 2.8, 2.8, 3.4, 3.3], text) if not noreg: - report.NewCell(ColorType.GREY,span=5) + report.NewCell(ColorType.GREY, span=5) text.Reset() text.SetColor(ColorType.WHITE) - text.Add("Region: \"" + reg + '\"') + text.Add('Region: "' + reg + '"') report.WriteText(text) text.Reset() report.NewLine() @@ -725,68 +766,88 @@ def WriteEfficiencyTable(self,index,icut,report): text.Reset() report.NewLine() warnings = [] - for i in range(0,len(self.main.datasets)): + for i in range(0, len(self.main.datasets)): # DatasetName report.NewCell() text.Reset() - text.Add(' '+self.main.datasets[i].name) + text.Add(" " + self.main.datasets[i].name) report.WriteText(text) # get the right region (and thus the right cutflow) - id_flow=0 + id_flow = 0 for myflow in self.cutflow.detail[i].cuts: - if len(myflow)==0: - id_flow+=1 + if len(myflow) == 0: + id_flow += 1 continue - if len(myflow[0].cutregion)!=1: - self.logger.error('Problem with the interpretation of the output') + if len(myflow[0].cutregion) != 1: + self.logger.error("Problem with the interpretation of the output") return False if reg in myflow[0].cutregion: break - id_flow+=1 + id_flow += 1 # getting the right cut in the cutflow - id_cut=0 + id_cut = 0 for running_cut in self.cutflow.detail[i].cuts[id_flow]: - if running_cut.cutname.startswith('\"'+str(icut+1)+'_'): + if running_cut.cutname.startswith('"' + str(icut + 1) + "_"): break - id_cut+=1 + id_cut += 1 # SelectedEvents report.NewCell() text.Reset() - text.Add(' ' + Layout.DisplayXsecCut(self.cutflow.detail[i].Nselected[id_flow][id_cut].mean,\ - self.cutflow.detail[i].Nselected[id_flow][id_cut].error)) + text.Add( + " " + + Layout.DisplayXsecCut( + self.cutflow.detail[i].Nselected[id_flow][id_cut].mean, + self.cutflow.detail[i].Nselected[id_flow][id_cut].error, + ) + ) report.WriteText(text) # RejectedEvents report.NewCell() text.Reset() - text.Add(' ' + Layout.DisplayXsecCut(self.cutflow.detail[i].Nrejected[id_flow][id_cut].mean,\ - self.cutflow.detail[i].Nrejected[id_flow][id_cut].error)) + text.Add( + " " + + Layout.DisplayXsecCut( + self.cutflow.detail[i].Nrejected[id_flow][id_cut].mean, + self.cutflow.detail[i].Nrejected[id_flow][id_cut].error, + ) + ) report.WriteText(text) # Efficiency Events report.NewCell() text.Reset() - text.Add(' ' + Layout.DisplayXsecCut(self.cutflow.detail[i].eff[id_flow][id_cut].mean,\ - self.cutflow.detail[i].eff[id_flow][id_cut].error)) + text.Add( + " " + + Layout.DisplayXsecCut( + self.cutflow.detail[i].eff[id_flow][id_cut].mean, + self.cutflow.detail[i].eff[id_flow][id_cut].error, + ) + ) report.WriteText(text) # Cumulative efficiency events report.NewCell() text.Reset() - text.Add(' ' + Layout.DisplayXsecCut(self.cutflow.detail[i].effcumu[id_flow][id_cut].mean,\ - self.cutflow.detail[i].effcumu[id_flow][id_cut].error)) + text.Add( + " " + + Layout.DisplayXsecCut( + self.cutflow.detail[i].effcumu[id_flow][id_cut].mean, + self.cutflow.detail[i].effcumu[id_flow][id_cut].error, + ) + ) report.WriteText(text) - if i == (len(self.main.datasets)-1): + if i == (len(self.main.datasets) - 1): report.EndLine() else: report.NewLine() # warnings ? - if len(self.cutflow.detail[i].warnings[id_flow][id_cut])!=0: - warning_test=True - warnings.append([i,id_flow,id_cut]) + if len(self.cutflow.detail[i].warnings[id_flow][id_cut]) != 0: + warning_test = True + warnings.append([i, id_flow, id_cut]) text.Reset() report.EndTable() text.Reset() # Displaying warnings if warning_test: - report.CreateTable([12],text) + report.CreateTable([12], text) report.NewCell() text.SetColor(ColorType.RED) text.Add("Warnings related to negative event-weights:") @@ -802,19 +863,18 @@ def WriteEfficiencyTable(self,index,icut,report): report.NewLine() report.EndTable() - # Writing Statistics Table - def WriteStatisticsTable(self,index,report): - text=TextReport() -# text.Add("Statistics table") - report.CreateTable([2.6,2.5,2.0,2.1,2.1,2.1,2.1],text) + def WriteStatisticsTable(self, index, report): + text = TextReport() + # text.Add("Statistics table") + report.CreateTable([2.6, 2.5, 2.0, 2.1, 2.1, 2.1, 2.1], text) report.NewCell(ColorType.YELLOW) text.Reset() text.Add(" Dataset") report.WriteText(text) report.NewCell(ColorType.YELLOW) text.Reset() - text.Add(' Integral') + text.Add(" Integral") report.WriteText(text) report.NewCell(ColorType.YELLOW) text.Reset() @@ -822,11 +882,11 @@ def WriteStatisticsTable(self,index,report): report.WriteText(text) report.NewCell(ColorType.YELLOW) text.Reset() - text.Add(" Mean")# (+/- err)") + text.Add(" Mean") # (+/- err)") report.WriteText(text) report.NewCell(ColorType.YELLOW) text.Reset() - text.Add(" RMS")# (+/- err)") + text.Add(" RMS") # (+/- err)") report.WriteText(text) report.NewCell(ColorType.YELLOW) text.Reset() @@ -839,11 +899,11 @@ def WriteStatisticsTable(self,index,report): report.NewLine() # Looping over dataset - warning_test=False - for iset in range(0,len(self.plotflow.detail)): + warning_test = False + for iset in range(0, len(self.plotflow.detail)): # Is there warning ? - if len(self.plotflow.detail[iset][index].warnings)!=0: - warning_test=True + if len(self.plotflow.detail[iset][index].warnings) != 0: + warning_test = True # Getting the number of entries integral = self.plotflow.detail[iset][index].summary.integral @@ -853,40 +913,47 @@ def WriteStatisticsTable(self,index,report): oflow = self.plotflow.detail[iset][index].summary.overflow # Computing underflow and overflow ratio / integral - uflow_percent=0 - oflow_percent=0 - if integral!=0: - uflow_percent = uflow*100/integral - oflow_percent = oflow*100/integral + uflow_percent = 0 + oflow_percent = 0 + if integral != 0: + uflow_percent = uflow * 100 / integral + oflow_percent = oflow * 100 / integral # mean value mean = self.plotflow.detail[iset][index].summary.GetMean() - # root mean square + error + # root mean square + error rms = self.plotflow.detail[iset][index].summary.GetRMS() # writing the table report.NewCell() text.Reset() - text.Add(' '+self.main.datasets[iset].name) + text.Add(" " + self.main.datasets[iset].name) report.WriteText(text) report.NewCell() # Nentries text.Reset() - text.Add(' '+Layout.DisplayXsecCut(integral*self.plotflow.detail[iset][index].scale,0)) + text.Add( + " " + + Layout.DisplayXsecCut( + integral * self.plotflow.detail[iset][index].scale, 0 + ) + ) report.WriteText(text) report.NewCell() # Getting the number of events and number of entries nentries = self.plotflow.detail[iset][index].summary.nentries - nevents = self.plotflow.detail[iset][index].summary.nevents + nevents = self.plotflow.detail[iset][index].summary.nevents # Nentries / Nevents text.Reset() - if nevents!=0.: - text.Add(' ' + \ - str(Layout.Round_to_Ndigits(float(nentries)/float(nevents),3))) + if nevents != 0.0: + text.Add( + " " + + str(Layout.Round_to_Ndigits(float(nentries) / float(nevents), 3)) + ) else: text.Add(" 0.") report.WriteText(text) @@ -894,35 +961,35 @@ def WriteStatisticsTable(self,index,report): # Mean value text.Reset() - text.Add(' '+ str(Layout.Round_to_Ndigits(mean,6))) -# +"(+/- "+str(Layout.Round_to_Ndigits(mean_error,3))+")") + text.Add(" " + str(Layout.Round_to_Ndigits(mean, 6))) + # +"(+/- "+str(Layout.Round_to_Ndigits(mean_error,3))+")") report.WriteText(text) report.NewCell() text.Reset() - text.Add(' '+str(Layout.Round_to_Ndigits(rms,4))) -# +"(+/- "+str(Layout.Round_to_Ndigits(rms_error,3))+")") + text.Add(" " + str(Layout.Round_to_Ndigits(rms, 4))) + # +"(+/- "+str(Layout.Round_to_Ndigits(rms_error,3))+")") report.WriteText(text) - if uflow_percent+oflow_percent<=5: + if uflow_percent + oflow_percent <= 5: report.NewCell(ColorType.GREEN) - if uflow_percent+oflow_percent>5 and uflow_percent+oflow_percent<15: + if uflow_percent + oflow_percent > 5 and uflow_percent + oflow_percent < 15: report.NewCell(ColorType.ORANGE) - if uflow_percent+oflow_percent>15: + if uflow_percent + oflow_percent > 15: report.NewCell(ColorType.RED) text.Reset() - text.Add(' '+str(Layout.Round_to_Ndigits(uflow_percent,4))) + text.Add(" " + str(Layout.Round_to_Ndigits(uflow_percent, 4))) report.WriteText(text) - if uflow_percent+oflow_percent<=5: + if uflow_percent + oflow_percent <= 5: report.NewCell(ColorType.GREEN) - if uflow_percent+oflow_percent>5 and uflow_percent+oflow_percent<15: + if uflow_percent + oflow_percent > 5 and uflow_percent + oflow_percent < 15: report.NewCell(ColorType.ORANGE) - if uflow_percent+oflow_percent>15: + if uflow_percent + oflow_percent > 15: report.NewCell(ColorType.RED) text.Reset() - text.Add(' '+str(Layout.Round_to_Ndigits(oflow_percent,4))) + text.Add(" " + str(Layout.Round_to_Ndigits(oflow_percent, 4))) report.WriteText(text) - if iset==(len(self.plotflow.detail)-1): + if iset == (len(self.plotflow.detail) - 1): report.EndLine() - else: + else: report.NewLine() text.Reset() report.EndTable() @@ -931,13 +998,13 @@ def WriteStatisticsTable(self,index,report): # Displaying warnings if warning_test: - report.CreateTable([12],text) + report.CreateTable([12], text) report.NewCell() text.SetColor(ColorType.RED) text.Add("Warnings related to negative event-weights:") report.WriteText(text) report.NewLine() - for iset in range(0,len(self.plotflow.detail)): + for iset in range(0, len(self.plotflow.detail)): for line in self.plotflow.detail[iset][index].warnings: report.NewCell() text.Reset() @@ -948,17 +1015,17 @@ def WriteStatisticsTable(self,index,report): report.EndTable() # Writing Statistics Table - def WriteStatisticsTablePID(self,index,report): - text=TextReport() + def WriteStatisticsTablePID(self, index, report): + text = TextReport() text.Add("Statistics table") - report.CreateTable([2.6,4.1,2.3],text) + report.CreateTable([2.6, 4.1, 2.3], text) report.NewCell(ColorType.YELLOW) text.Reset() text.Add(" Dataset") report.WriteText(text) report.NewCell(ColorType.YELLOW) text.Reset() - text.Add(' Integral') + text.Add(" Integral") report.WriteText(text) report.NewCell(ColorType.YELLOW) text.Reset() @@ -967,11 +1034,11 @@ def WriteStatisticsTablePID(self,index,report): report.NewLine() # Looping over dataset - warning_test=False - for iset in range(0,len(self.plotflow.detail)): + warning_test = False + for iset in range(0, len(self.plotflow.detail)): # Is there warning ? - if len(self.plotflow.detail[iset][index].warnings)!=0: - warning_test=True + if len(self.plotflow.detail[iset][index].warnings) != 0: + warning_test = True # Getting the number of entries integral = self.plotflow.detail[iset][index].summary.integral @@ -979,30 +1046,37 @@ def WriteStatisticsTablePID(self,index,report): # writing the table report.NewCell() text.Reset() - text.Add(' '+self.main.datasets[iset].name) + text.Add(" " + self.main.datasets[iset].name) report.WriteText(text) report.NewCell() # Nentries text.Reset() - text.Add(' '+Layout.DisplayXsecCut(integral*self.plotflow.detail[iset][index].scale,0)) + text.Add( + " " + + Layout.DisplayXsecCut( + integral * self.plotflow.detail[iset][index].scale, 0 + ) + ) report.WriteText(text) report.NewCell() # Getting the number of events and number of entries nentries = self.plotflow.detail[iset][index].summary.nentries - nevents = self.plotflow.detail[iset][index].summary.nevents + nevents = self.plotflow.detail[iset][index].summary.nevents # Nentries / Nevents text.Reset() - if nevents!=0.: - text.Add(' ' + \ - str(Layout.Round_to_Ndigits(float(nentries)/float(nevents),3))) + if nevents != 0.0: + text.Add( + " " + + str(Layout.Round_to_Ndigits(float(nentries) / float(nevents), 3)) + ) else: text.Add(" 0.") report.WriteText(text) - if iset==(len(self.plotflow.detail)-1): + if iset == (len(self.plotflow.detail) - 1): report.EndLine() else: report.NewLine() @@ -1012,13 +1086,13 @@ def WriteStatisticsTablePID(self,index,report): # Displaying warnings if warning_test: - report.CreateTable([12],text) + report.CreateTable([12], text) report.NewCell() text.SetColor(ColorType.RED) text.Add("Warnings related to negative event-weights:") report.WriteText(text) report.NewLine() - for iset in range(0,len(self.plotflow.detail)): + for iset in range(0, len(self.plotflow.detail)): for line in self.plotflow.detail[iset][index].warnings: report.NewCell() text.Reset() @@ -1028,150 +1102,159 @@ def WriteStatisticsTablePID(self,index,report): report.NewLine() report.EndTable() - - def CreateFolders(self,histo_folder,output_paths,modes): + def CreateFolders(self, histo_folder, output_paths, modes): # Creating histo folder - if not FolderWriter.CreateDirectory(histo_folder,True): + if not FolderWriter.CreateDirectory(histo_folder, True): return False - for ind in range(0,len(output_paths)): - + for ind in range(0, len(output_paths)): + # Creating production directory - if not FolderWriter.CreateDirectory(output_paths[ind],True): + if not FolderWriter.CreateDirectory(output_paths[ind], True): return False # Copying MA5 logo - if not self.CopyLogo(modes[ind],output_paths[ind]): + if not self.CopyLogo(modes[ind], output_paths[ind]): return False - - return True + return True - def GenerateReport(self,history,output_path,mode): + def GenerateReport(self, history, output_path, mode): # Find a name for PDF file - ma5_id = output_path.split('/')[-1] + ma5_id = output_path.split("/")[-1] if self.main.session_info.has_pdflatex: - self.pdffile=self.main.lastjob_name+'/Output/PDF/'+ma5_id+'/main.pdf' + self.pdffile = self.main.lastjob_name + "/Output/PDF/" + ma5_id + "/main.pdf" elif self.main.session_info.has_latex and self.main.session_info.has_dvipdf: - self.pdffile=self.main.lastjob_name+'/Output/DVI/'+ma5_id+'/main.pdf' + self.pdffile = self.main.lastjob_name + "/Output/DVI/" + ma5_id + "/main.pdf" else: - self.pdffile='' + self.pdffile = "" # Defining report writing if mode == ReportFormatType.HTML: - mypdf='' - if self.pdffile!='': - mypdf=os.path.relpath(self.pdffile,output_path) - report = HTMLReportWriter(output_path+"/index.html",mypdf) + mypdf = "" + if self.pdffile != "": + mypdf = os.path.relpath(self.pdffile, output_path) + report = HTMLReportWriter(output_path + "/index.html", mypdf) elif mode == ReportFormatType.LATEX: - report = LATEXReportWriter(output_path+"/main.tex",\ - self.main.archi_info.ma5dir+"/madanalysis/input",False) - else : - report = LATEXReportWriter(output_path+"/main.tex",\ - self.main.archi_info.ma5dir+"/madanalysis/input",True) + report = LATEXReportWriter( + output_path + "/main.tex", + self.main.archi_info.ma5dir + "/madanalysis/input", + False, + ) + else: + report = LATEXReportWriter( + output_path + "/main.tex", + self.main.archi_info.ma5dir + "/madanalysis/input", + True, + ) # Opening if not report.Open(): return False # Create text - text=TextReport() + text = TextReport() # Header report.WriteHeader() - report.WriteTitle('MadAnalysis 5 report') + report.WriteTitle("MadAnalysis 5 report") # History of commands - report.WriteSubTitle('Setup') - report.WriteSubSubTitle('Command history') + report.WriteSubTitle("Setup") + report.WriteSubSubTitle("Command history") text.Reset() text.SetFont(FontType.TT) for item in history.history: - text.Add('ma5>'+ item+'\n\n') + text.Add("ma5>" + item + "\n\n") report.WriteText(text) # Configuration - report.WriteSubSubTitle('Configuration') + report.WriteSubSubTitle("Configuration") - # Integrated luminosity + # Integrated luminosity report.OpenBullet() text.Reset() - text.Add('MadAnalysis version ' + self.main.archi_info.ma5_version + \ - ' (' + self.main.archi_info.ma5_date + ').\n') + text.Add( + "MadAnalysis version " + + self.main.archi_info.ma5_version + + " (" + + self.main.archi_info.ma5_date + + ").\n" + ) report.WriteText(text) - # Integrated luminosity + # Integrated luminosity text.Reset() # Normalization - if self.main.normalize == NormalizeType.LUMI or \ - self.main.normalize == NormalizeType.LUMI_WEIGHT: - text.Add('Histograms given for an integrated luminosity of ') + if ( + self.main.normalize == NormalizeType.LUMI + or self.main.normalize == NormalizeType.LUMI_WEIGHT + ): + text.Add("Histograms given for an integrated luminosity of ") text.SetColor(ColorType.BLUE) text.Add(str(self.main.lumi)) - text.Add(' fb') + text.Add(" fb") text.SetScript(ScriptType.SUP) - text.Add('-1') + text.Add("-1") text.SetScript(ScriptType.none) - text.Add('.\n') + text.Add(".\n") elif self.main.normalize == NormalizeType.NONE: - text.Add('Histograms are not scaled.\n') + text.Add("Histograms are not scaled.\n") report.WriteText(text) report.CloseBullet() # Datasets - report.WriteSubTitle('Datasets') - for ind in range(0,len(self.main.datasets)): + report.WriteSubTitle("Datasets") + for ind in range(0, len(self.main.datasets)): report.WriteSubSubTitle(self.main.datasets[ind].name) - self.WriteDatasetTable(report,\ - self.main.datasets[ind]) + self.WriteDatasetTable(report, self.main.datasets[ind]) # Merging plots if self.main.merging.enable: # Title : merging plots - report.WriteSubTitle('Merging plots') + report.WriteSubTitle("Merging plots") # Getting all plot names - allnames = self.merging.GetPlotNames(mode,\ - output_path) + allnames = self.merging.GetPlotNames(mode, output_path) # Loop over datasets - for i in range(0,len(allnames)): + for i in range(0, len(allnames)): # Subtitle : dataset names report.WriteSubSubTitle(self.main.datasets[i].name) # Loop over DJR plots - for j in range(0,len(allnames[i])): + for j in range(0, len(allnames[i])): text.Reset() - title = "DJR"+str(j+1)+" : "+str(j) - if j>1: - title +=" jets -> " + title = "DJR" + str(j + 1) + " : " + str(j) + if j > 1: + title += " jets -> " else: - title +=" jet -> " - title += str(j+1) - if j>0: + title += " jet -> " + title += str(j + 1) + if j > 0: title += " jets" else: title += " jet" text.Add(title) - if self.main.graphic_render!=GraphicRenderType.NONE: - report.WriteFigure(text,allnames[i][j]) + if self.main.graphic_render != GraphicRenderType.NONE: + report.WriteFigure(text, allnames[i][j]) # Plots display - if len(self.main.selection)!=0: - report.WriteSubTitle('Histos and cuts') + if len(self.main.selection) != 0: + report.WriteSubTitle("Histos and cuts") # Plots - ihisto=0 - icut=0 - iobject=0 + ihisto = 0 + icut = 0 + iobject = 0 cutinfo = [] - for ind in range(0,len(self.main.selection)): - if self.main.selection[ind].__class__.__name__=="Histogram": - report.WriteSubSubTitle("Histogram "+str(ihisto+1)) + for ind in range(0, len(self.main.selection)): + if self.main.selection[ind].__class__.__name__ == "Histogram": + report.WriteSubSubTitle("Histogram " + str(ihisto + 1)) text.Reset() text.SetFont(FontType.BF) text.Add(self.main.selection[ind].GetStringDisplay().lstrip()) @@ -1179,42 +1262,42 @@ def GenerateReport(self,history,output_path,mode): text.Reset() text.SetFont(FontType.BF) report.NewBlankLine() - if self.main.regions.GetNames()!=[]: - text.Add('* Regions: ') + if self.main.regions.GetNames() != []: + text.Add("* Regions: ") text.SetFont(FontType.none) for reg in self.main.selection[ind].regions: text.Add(reg) - if reg!=self.main.selection[ind].regions[-1]: - text.Add(', ') + if reg != self.main.selection[ind].regions[-1]: + text.Add(", ") report.WriteText(text) report.NewBlankLine() text.Reset() - text.Add('\n\n') + text.Add("\n\n") report.WriteText(text) text.Reset() - text.Add('\n\n') - if self.main.selection[ind].observable.name not in ['NPID','NAPID']: - self.WriteStatisticsTable(ihisto,report) + text.Add("\n\n") + if self.main.selection[ind].observable.name not in ["NPID", "NAPID"]: + self.WriteStatisticsTable(ihisto, report) else: - self.WriteStatisticsTablePID(ihisto,report) - if self.main.graphic_render!=GraphicRenderType.NONE: - report.WriteFigure(text,output_path +'/selection_'+str(ihisto)) - text.Add('\n\n') + self.WriteStatisticsTablePID(ihisto, report) + if self.main.graphic_render != GraphicRenderType.NONE: + report.WriteFigure(text, output_path + "/selection_" + str(ihisto)) + text.Add("\n\n") report.WriteText(text) text.Reset() - ihisto+=1 - elif self.main.selection[ind].__class__.__name__=="Cut": + ihisto += 1 + elif self.main.selection[ind].__class__.__name__ == "Cut": cutstring = self.main.selection[ind].GetStringDisplay().lstrip() - if ', regions' in cutstring: - cutstring=cutstring[:cutstring.find(', regions')] - cutregions =[] + if ", regions" in cutstring: + cutstring = cutstring[: cutstring.find(", regions")] + cutregions = [] for reg in self.main.selection[ind].regions: cutregions.append(reg) if cutregions == []: - cutregions = ['myregion'] + cutregions = ["myregion"] cutinfo.append([cutstring, cutregions, self.main.selection[ind].cut_type]) - if len(self.main.selection[ind].part)==0: - report.WriteSubSubTitle("Cut "+str(icut+1)) + if len(self.main.selection[ind].part) == 0: + report.WriteSubSubTitle("Cut " + str(icut + 1)) text.Reset() text.SetFont(FontType.BF) text.Add(cutstring) @@ -1222,26 +1305,26 @@ def GenerateReport(self,history,output_path,mode): text.Reset() report.NewBlankLine() text.SetFont(FontType.BF) - if self.main.regions.GetNames()!=[]: - text.Add('* Regions: ') + if self.main.regions.GetNames() != []: + text.Add("* Regions: ") text.SetFont(FontType.none) for reg in self.main.selection[ind].regions: text.Add(reg) - if reg!=self.main.selection[ind].regions[-1]: - text.Add(', ') + if reg != self.main.selection[ind].regions[-1]: + text.Add(", ") report.WriteText(text) report.NewBlankLine() text.Reset() - text.Add('\n\n') + text.Add("\n\n") report.WriteText(text) text.Reset() - self.WriteEfficiencyTable(ind,icut,report) - text.Add('\n\n') + self.WriteEfficiencyTable(ind, icut, report) + text.Add("\n\n") report.WriteText(text) text.Reset() - icut+=1 + icut += 1 else: - report.WriteSubSubTitle("Object definition "+str(iobject+1)) + report.WriteSubSubTitle("Object definition " + str(iobject + 1)) text.Reset() text.SetFont(FontType.BF) text.Add(cutstring) @@ -1249,26 +1332,26 @@ def GenerateReport(self,history,output_path,mode): text.Reset() report.NewBlankLine() text.SetFont(FontType.BF) - if self.main.regions.GetNames()!=[]: - text.Add('* Regions: ') + if self.main.regions.GetNames() != []: + text.Add("* Regions: ") text.SetFont(FontType.none) for reg in self.main.selection[ind].regions: text.Add(reg) - if reg!=self.main.selection[ind].regions[-1]: - text.Add(', ') + if reg != self.main.selection[ind].regions[-1]: + text.Add(", ") report.WriteText(text) report.NewBlankLine() text.Reset() - text.Add('\n\n') + text.Add("\n\n") report.WriteText(text) text.Reset() - iobject+=1 + iobject += 1 # Final table - if self.main.selection.Ncuts!=0: - report.WriteSubTitle('Summary') - report.WriteSubSubTitle('Cut-flow charts') - self.WriteFinalTable(report,cutinfo) + if self.main.selection.Ncuts != 0: + report.WriteSubTitle("Summary") + report.WriteSubSubTitle("Cut-flow charts") + self.WriteFinalTable(report, cutinfo) # Foot report.WriteFoot() @@ -1278,65 +1361,84 @@ def GenerateReport(self,history,output_path,mode): return True - @staticmethod def CheckLatexLog(file): if not os.path.isfile(file): return False for line in file: - if line.startswith('!'): + if line.startswith("!"): return False return True - def CompileReport(self,mode,output_path): - + def CompileReport(self, mode, output_path): + # ---- LATEX MODE ---- - if mode==ReportFormatType.LATEX: + if mode == ReportFormatType.LATEX: # Launching latex and producing DVI file - os.system('cd '+output_path+'; latex -interaction=nonstopmode main.tex > latex.log 2>&1;'+\ - ' latex -interaction=nonstopmode main.tex >> latex.log 2>&1') - - name=os.path.normpath(output_path+'/main.dvi') + os.system( + "cd " + + output_path + + "; latex -interaction=nonstopmode main.tex > latex.log 2>&1;" + + " latex -interaction=nonstopmode main.tex >> latex.log 2>&1" + ) + + name = os.path.normpath(output_path + "/main.dvi") if not os.path.isfile(name): - self.logger.error('DVI file cannot be produced') - self.logger.error('Please have a look to the log file '+output_path+'/latex.log') + self.logger.error("DVI file cannot be produced") + self.logger.error( + "Please have a look to the log file " + output_path + "/latex.log" + ) return False - + # Checking latex log : are there errors - if not Layout.CheckLatexLog(output_path+'/latex.log'): - self.logger.error('some errors occured during LATEX compilation') - self.logger.error('for more details, have a look to the log file : '+output_path+'/latex.log') + if not Layout.CheckLatexLog(output_path + "/latex.log"): + self.logger.error("some errors occured during LATEX compilation") + self.logger.error( + "for more details, have a look to the log file : " + + output_path + + "/latex.log" + ) return False # Converting DVI file to PDF file -# if self.main.session_info.has_dvipdf: -# self.logger.info(" -> Converting the DVI report to a PDF report.") -# os.system('cd '+output_path+'; dvipdf main.dvi > dvipdf.log 2>&1') -# name=os.path.normpath(output_path+'/main.pdf') -# -# # Checking PDF file presence -# if not os.path.isfile(name): -# self.logger.error('PDF file cannot be produced') -# self.logger.error('Please have a look to the log file '+output_path+'/dvipdf.log') -# return False + # if self.main.session_info.has_dvipdf: + # self.logger.info(" -> Converting the DVI report to a PDF report.") + # os.system('cd '+output_path+'; dvipdf main.dvi > dvipdf.log 2>&1') + # name=os.path.normpath(output_path+'/main.pdf') + # + # # Checking PDF file presence + # if not os.path.isfile(name): + # self.logger.error('PDF file cannot be produced') + # self.logger.error('Please have a look to the log file '+output_path+'/dvipdf.log') + # return False # ---- PDFLATEX MODE ---- - elif mode==ReportFormatType.PDFLATEX: + elif mode == ReportFormatType.PDFLATEX: # Launching latex and producing PDF file - os.system('cd '+output_path+'; pdflatex -interaction=nonstopmode main.tex > latex.log 2>&1;'+\ - ' pdflatex -interaction=nonstopmode main.tex >> latex.log 2>&1'); + os.system( + "cd " + + output_path + + "; pdflatex -interaction=nonstopmode main.tex > latex.log 2>&1;" + + " pdflatex -interaction=nonstopmode main.tex >> latex.log 2>&1" + ) # Checking latex log : are there errors - if not Layout.CheckLatexLog(output_path+'/latex.log'): - self.logger.error('some errors occured during LATEX compilation') - self.logger.error('for more details, have a look to the log file : '+output_path+'/latex.log') + if not Layout.CheckLatexLog(output_path + "/latex.log"): + self.logger.error("some errors occured during LATEX compilation") + self.logger.error( + "for more details, have a look to the log file : " + + output_path + + "/latex.log" + ) return False # Checking PDF file presence - name=os.path.normpath(output_path+'/main.pdf') + name = os.path.normpath(output_path + "/main.pdf") if not os.path.isfile(name): - self.logger.error('PDF file cannot be produced') - self.logger.error('Please have a look to the log file '+output_path+'/latex2.log') + self.logger.error("PDF file cannot be produced") + self.logger.error( + "Please have a look to the log file " + output_path + "/latex2.log" + ) return False diff --git a/madanalysis/layout/plotflow.py b/madanalysis/layout/plotflow.py index e6864839..5256af56 100644 --- a/madanalysis/layout/plotflow.py +++ b/madanalysis/layout/plotflow.py @@ -23,7 +23,11 @@ from __future__ import absolute_import -from madanalysis.enumeration.uncertainty_type import UncertaintyType + +import logging +import six +from six.moves import range + from madanalysis.enumeration.normalize_type import NormalizeType from madanalysis.enumeration.report_format_type import ReportFormatType from madanalysis.enumeration.color_type import ColorType @@ -32,9 +36,6 @@ from madanalysis.enumeration.stacking_method_type import StackingMethodType from madanalysis.layout.plotflow_for_dataset import PlotFlowForDataset import madanalysis.enumeration.color_hex -import logging -import six -from six.moves import range class PlotFlow: @@ -54,7 +55,10 @@ def Initialize(self): # Initializing NPID if len(self.detail) > 0: for ihisto in range(0, len(self.detail[0])): - if self.detail[0].histos[ihisto].__class__.__name__ == "HistogramFrequency": + if ( + self.detail[0].histos[ihisto].__class__.__name__ + == "HistogramFrequency" + ): self.InitializeHistoFrequency(ihisto) # Creating plots @@ -95,9 +99,9 @@ def InitializeHistoFrequency(self, ihisto): found = False value_positive = 0 value_negative = 0 - for i in range(len(histo[ihisto].labels)): + for i, label in enumerate(histo[ihisto].labels): - if newlabel == histo[ihisto].labels[i]: + if newlabel == label: value_positive = histo[ihisto].positive.array[i] value_negative = histo[ihisto].negative.array[i] found = True @@ -158,27 +162,19 @@ def DrawAll(self, histo_path, modes, output_paths, ListROOTplots): + ReportFormatType.convert2filetype(modes[iout]) ) - for iset, detail in enumerate(self.detail): + for detail in self.detail: # Appending histo histos.append(detail[irelhisto]) - # if mode==2: scales.append(detail[irelhisto].scale) - # else: - # scales.append(1) logging.getLogger("MA5").debug("Producing file " + filenameC + " ...") if self.main.archi_info.has_root: - self.DrawROOT( - histos, - scales, - select, - irelhisto, - filenameC, - output_files, - ) + self.DrawROOT(histos, scales, select, irelhisto, filenameC, output_files) logging.getLogger("MA5").debug("Producing file " + filenamePy + " ...") - self.DrawMATPLOTLIB(histos, scales, select, irelhisto, filenamePy, output_files) + self.DrawMATPLOTLIB( + histos, scales, select, irelhisto, filenamePy, output_files + ) irelhisto += 1 @@ -210,7 +206,8 @@ def DrawROOT(self, histos, scales, ref, irelhisto, filenameC, outputnames): # Stacking or superimposing histos ? stackmode = False if ref.stack == StackingMethodType.STACK or ( - ref.stack == StackingMethodType.AUTO and self.main.stack == StackingMethodType.STACK + ref.stack == StackingMethodType.AUTO + and self.main.stack == StackingMethodType.STACK ): stackmode = True @@ -427,7 +424,18 @@ def DrawROOT(self, histos, scales, ref, irelhisto, filenameC, outputnames): linecolor10 = [9, 46, 8, 4, 6, 2, 7, 3, 42, 48] linecolor = linecolor10[ind] if stackmode: - backstyle10 = [3004, 3005, 3006, 3007, 3013, 3017, 3022, 3315, 3351, 3481] + backstyle10 = [ + 3004, + 3005, + 3006, + 3007, + 3013, + 3017, + 3022, + 3315, + 3351, + 3481, + ] backstyle = backstyle10[ind] backcolor = linecolor10[ind] else: @@ -472,7 +480,9 @@ def DrawROOT(self, histos, scales, ref, irelhisto, filenameC, outputnames): outputC.write(" // Creating a new THStack\n") PlotFlow.counter += 1 outputC.write( - ' THStack* stack = new THStack("mystack_' + str(PlotFlow.counter) + '","mystack");\n' + ' THStack* stack = new THStack("mystack_' + + str(PlotFlow.counter) + + '","mystack");\n' ) # Loop over datasets and histos for ind in range(0, len(histos)): @@ -570,7 +580,9 @@ def DrawROOT(self, histos, scales, ref, irelhisto, filenameC, outputnames): for ind in range(0, len(histos)): histoname = "S" + histos[ind].name + "_" + str(ind) nicetitle = PlotFlow.NiceTitle(self.main.datasets[ind].title) - outputC.write(" legend->AddEntry(" + histoname + ',"' + nicetitle + '");\n') + outputC.write( + " legend->AddEntry(" + histoname + ',"' + nicetitle + '");\n' + ) outputC.write(" legend->SetFillColor(0);\n") outputC.write(" legend->SetTextSize(0.05);\n") outputC.write(" legend->SetTextFont(22);\n") @@ -621,15 +633,16 @@ def DrawMATPLOTLIB(self, histos, scales, ref, irelhisto, filenamePy, outputnames # Stacking or superimposing histos ? stackmode = False if ref.stack == StackingMethodType.STACK or ( - ref.stack == StackingMethodType.AUTO and self.main.stack == StackingMethodType.STACK + ref.stack == StackingMethodType.AUTO + and self.main.stack == StackingMethodType.STACK ): stackmode = True # Open the file in write-mode try: outputPy = open(filenamePy, "w") - except: - logging.getLogger("MA5").error("Impossible to write the file: " + filenamePy) + except Exception: + logging.getLogger("MA5").error(f"Impossible to write the file: {filenamePy}") return False # File header @@ -642,7 +655,6 @@ def DrawMATPLOTLIB(self, histos, scales, ref, irelhisto, filenamePy, outputnames outputPy.write(" # Library import\n") outputPy.write(" import numpy\n") outputPy.write(" import matplotlib\n") - # outputPy.write(" matplotlib.use('Agg')\n") outputPy.write(" import matplotlib.pyplot as plt\n") outputPy.write(" import matplotlib.gridspec as gridspec\n") outputPy.write("\n") @@ -681,12 +693,11 @@ def DrawMATPLOTLIB(self, histos, scales, ref, irelhisto, filenamePy, outputnames # Data outputPy.write(" # Creating data sequence: middle of each bin\n") - outputPy.write(" xData = numpy.array([") - for bin in range(0, xnbin): - if bin != 0: - outputPy.write(",") - outputPy.write(str(histos[0].GetBinMean(bin))) - outputPy.write("])\n\n") + outputPy.write( + " xData = numpy.array([" + + ", ".join([f"{histos[0].GetBinMean(ibin):.5e}" for ibin in range(xnbin)]) + + "])\n\n" + ) # Loop over datasets and histos ntot = 0 @@ -696,12 +707,9 @@ def DrawMATPLOTLIB(self, histos, scales, ref, irelhisto, filenamePy, outputnames histoname = "y" + hist.name + "_" + str(ind) outputPy.write(" # Creating weights for histo: " + histoname + "\n") outputPy.write(" " + histoname + "_weights = numpy.array([") - for bin in range(1, xnbin + 1): - ntot += hist.summary.array[bin - 1] * scales[ind] - if bin != 1: - outputPy.write(",") - outputPy.write(str(hist.summary.array[bin - 1] * scales[ind])) - outputPy.write("])\n\n") + current_histo = hist.summary.array * scales[ind] + outputPy.write(", ".join(f"{x:.8e}" for x in current_histo) + "])\n\n") + ntot = float(sum(current_histo)) # Canvas outputPy.write(" # Creating a new Canvas\n") @@ -732,7 +740,9 @@ def DrawMATPLOTLIB(self, histos, scales, ref, irelhisto, filenamePy, outputnames outputPy.write(" # Creating a new Stack\n") for ind in range(len(histos) - 1, -1, -1): myweight = "y" + histos[ind].name + "_" + str(ind) + "_weights" - mytitle = '"' + PlotFlow.NiceTitleMatplotlib(self.main.datasets[ind].title) + '"' + mytitle = ( + '"' + PlotFlow.NiceTitleMatplotlib(self.main.datasets[ind].title) + '"' + ) mytitle = mytitle.replace("_", "\_") if not stackmode: @@ -819,7 +829,18 @@ def DrawMATPLOTLIB(self, histos, scales, ref, irelhisto, filenamePy, outputnames linecolor10 = [9, 46, 8, 4, 6, 2, 7, 3, 42, 48] linecolor = linecolor10[ind] if stackmode: - backstyle10 = [3004, 3005, 3006, 3007, 3013, 3017, 3022, 3315, 3351, 3481] + backstyle10 = [ + 3004, + 3005, + 3006, + 3007, + 3013, + 3017, + 3022, + 3315, + 3351, + 3481, + ] backstyle = backstyle10[ind] backcolor = linecolor10[ind] else: @@ -845,10 +866,16 @@ def DrawMATPLOTLIB(self, histos, scales, ref, irelhisto, filenamePy, outputnames # background style if self.main.datasets[ind].backstyle != BackStyleType.AUTO: - backstyle = BackStyleType.convert2matplotlib(self.main.datasets[ind].backstyle) + backstyle = BackStyleType.convert2matplotlib( + self.main.datasets[ind].backstyle + ) - mylinecolor = '"' + madanalysis.enumeration.color_hex.color_hex[linecolor] + '"' - mybackcolor = '"' + madanalysis.enumeration.color_hex.color_hex[backcolor] + '"' + mylinecolor = ( + '"' + madanalysis.enumeration.color_hex.color_hex[linecolor] + '"' + ) + mybackcolor = ( + '"' + madanalysis.enumeration.color_hex.color_hex[backcolor] + '"' + ) filledmode = '"stepfilled"' rWidth = 1.0 @@ -859,7 +886,9 @@ def DrawMATPLOTLIB(self, histos, scales, ref, irelhisto, filenamePy, outputnames # filledmode='"bar"' # rWidth=0.8 mylinewidth = self.main.datasets[ind].linewidth - mylinestyle = LineStyleType.convert2matplotlib(self.main.datasets[ind].linestyle) + mylinestyle = LineStyleType.convert2matplotlib( + self.main.datasets[ind].linestyle + ) outputPy.write( " pad.hist(" @@ -953,7 +982,9 @@ def DrawMATPLOTLIB(self, histos, scales, ref, irelhisto, filenamePy, outputnames or self.main.normalize == NormalizeType.LUMI_WEIGHT ): axis_titleY += ( - " $(#mathcal{L}_{#mathrm{int}} = " + str(self.main.lumi) + "# #mathrm{fb}^{-1})$ " + " $(#mathcal{L}_{#mathrm{int}} = " + + str(self.main.lumi) + + "# #mathrm{fb}^{-1})$ " ) elif self.main.normalize == NormalizeType.NONE: axis_titleY += " $(#mathrm{not}# #mathrm{normalized})$" @@ -1019,7 +1050,9 @@ def DrawMATPLOTLIB(self, histos, scales, ref, irelhisto, filenamePy, outputnames if ref.ymin == []: if not is_logy: outputPy.write("#") - outputPy.write("ymin=min([x for x in (" + myweights + ") if x])/100. # log scale\n") + outputPy.write( + "ymin=min([x for x in (" + myweights + ") if x])/100. # log scale\n" + ) else: if is_logy and ref.ymin <= 0: outputPy.write("#") @@ -1062,7 +1095,9 @@ def DrawMATPLOTLIB(self, histos, scales, ref, irelhisto, filenamePy, outputnames for bin in range(0, xnbin): if bin >= 1: outputPy.write(",") - outputPy.write('"' + str(histos[0].stringlabels[bin]).replace("_", "\_") + '"') + outputPy.write( + '"' + str(histos[0].stringlabels[bin]).replace("_", "\_") + '"' + ) outputPy.write("])\n") outputPy.write(' plt.xticks(xData, xLabels, rotation="vertical")\n') outputPy.write("\n") diff --git a/madanalysis/layout/plotflow_for_dataset.py b/madanalysis/layout/plotflow_for_dataset.py index 197d6490..e822485f 100644 --- a/madanalysis/layout/plotflow_for_dataset.py +++ b/madanalysis/layout/plotflow_for_dataset.py @@ -24,18 +24,21 @@ from __future__ import absolute_import -from madanalysis.enumeration.normalize_type import NormalizeType -from madanalysis.enumeration.stacking_method_type import StackingMethodType - import copy from six.moves import range +import numpy as np + +from madanalysis.enumeration.normalize_type import NormalizeType +from madanalysis.enumeration.stacking_method_type import StackingMethodType +from madanalysis.dataset import dataset as Dataset +from .histogram_processor import HistogramProcessor class PlotFlowForDataset: - def __init__(self, main, dataset): + def __init__(self, main, dataset: Dataset): self.histos = [] self.main = main - self.dataset = dataset + self.dataset: Dataset = dataset # Getting xsection self.xsection = self.dataset.measured_global.xsection @@ -64,17 +67,14 @@ def CreateHistogram(self): iplot = 0 # Loop over plot - for iabshisto in range(0, len(self.main.selection)): + for select in self.main.selection: # Keep only histogram - if self.main.selection[iabshisto].__class__.__name__ != "Histogram": + if select.__class__.__name__ != "Histogram": continue # Case of histogram frequency if self.histos[iplot].__class__.__name__ == "HistogramFrequency": - if self.main.selection[iabshisto].observable.name == "NPID": - NPID = True - else: - NPID = False + NPID = True if select.observable.name == "NPID" else False self.histos[iplot].CreateHistogram(NPID, self.main) else: self.histos[iplot].CreateHistogram() @@ -85,6 +85,9 @@ def ComputeScale(self): iplot = 0 + # ! @jackaraz: this portion of the code should be changed to accomodate different types of + # ! PDF + scale unc combination for now its just mean and std + # Loop over plot for iabshisto, select in enumerate(self.main.selection): @@ -92,17 +95,28 @@ def ComputeScale(self): if select.__class__.__name__ != "Histogram": continue + processor = HistogramProcessor( + self.histos[iplot], + self.dataset.weight_collection, + self.dataset.measured_global.nevents, + thexsection, + ) + # Reset scale scale = 0.0 + # integral + integral = ( + self.histos[iplot].positive.integral + - self.histos[iplot].negative.integral + ) + integral = np.mean(integral) + # Case 1: Normalization to ONE if select.stack == StackingMethodType.NORMALIZE2ONE or ( self.main.stack == StackingMethodType.NORMALIZE2ONE and self.main.selection[iabshisto].stack == StackingMethodType.AUTO ): - integral = ( - self.histos[iplot].positive.integral - self.histos[iplot].negative.integral - ) if integral > 0.0: scale = 1.0 / integral else: @@ -116,44 +130,57 @@ def ComputeScale(self): # or depends on WEIGHT+LUMI elif self.main.normalize in [NormalizeType.LUMI, NormalizeType.LUMI_WEIGHT]: - # integral - integral = ( - self.histos[iplot].positive.integral - self.histos[iplot].negative.integral - ) - - # compute efficiency : Nevent / Ntotal - if self.dataset.measured_global.nevents == 0: - eff = 0 - else: - eff = ( - self.histos[iplot].positive.nevents + self.histos[iplot].negative.nevents - ) / float(self.dataset.measured_global.nevents) - - # compute the good xsection value + # # compute efficiency : Nevent / Ntotal + # if self.dataset.measured_global.nevents == 0: + # eff = 0 + # else: + # eff = ( + # self.histos[iplot].positive.nevents + # + self.histos[iplot].negative.nevents + # ) / float(self.dataset.measured_global.nevents) + # print("eff", eff) + # eff = np.mean(eff) + + # # compute the good xsection value thexsection = self.xsection if self.main.normalize == NormalizeType.LUMI_WEIGHT: thexsection = thexsection * self.dataset.weight - # compute final entries/event ratio - entries_per_events = 0 - sumw = self.histos[iplot].positive.sumw - self.histos[iplot].negative.sumw - Nentries = ( - self.histos[iplot].positive.sumwentries - - self.histos[iplot].negative.sumwentries - ) - if sumw != 0 and Nentries != 0: - entries_per_events = sumw / Nentries - - # compute the scale - if integral != 0: - scale = ( - thexsection * self.main.lumi * 1000 * eff * entries_per_events / integral - ) - else: - scale = 1 # no scale for empty plot + # # compute final entries/event ratio + # entries_per_events = 0 + # sumw = self.histos[iplot].positive.sumw - self.histos[iplot].negative.sumw + # Nentries = ( + # self.histos[iplot].positive.sumwentries + # - self.histos[iplot].negative.sumwentries + # ) + + # std_entries = float(np.std(Nentries)) + # Nentries_unc = (std_entries, std_entries) + # Nentries = float(np.mean(Nentries)) + # std_sumw = float(np.std(sumw)) + # sumw = float(np.mean(sumw)) + + # print(sumw, Nentries) + # if sumw != 0 and Nentries != 0: + # entries_per_events = sumw / Nentries + + # # compute the scale + # if integral != 0: + # scale = ( + # thexsection + # * self.main.lumi + # * 1000 + # * eff + # * entries_per_events + # / integral + # ) + # else: + # scale = 1 # no scale for empty plot + + scale = processor.scale(lumi=self.main.lumi) # Setting the computing scale self.histos[iplot].scale = copy.copy(scale) - + setattr(self.histos[iplot], "processor", processor) # Incrementing counter iplot += 1 From f1d912637054dedf5eb39cbc7d56a30a8c3070fd Mon Sep 17 00:00:00 2001 From: "Jack Y. Araz" <jackaraz@gmail.com> Date: Fri, 14 Jul 2023 16:35:49 +0100 Subject: [PATCH 052/107] add lhapdf list --- madanalysis/input/LHAPDF.txt | 1439 ++++++++++++++++++++++++++++++++++ 1 file changed, 1439 insertions(+) create mode 100644 madanalysis/input/LHAPDF.txt diff --git a/madanalysis/input/LHAPDF.txt b/madanalysis/input/LHAPDF.txt new file mode 100644 index 00000000..470376c0 --- /dev/null +++ b/madanalysis/input/LHAPDF.txt @@ -0,0 +1,1439 @@ +pdfid,name,members +251,GRVPI0,1 +252,GRVPI1,1 +270,xFitterPI_NLO_EIG,8 +280,xFitterPI_NLO_VAR,6 +1000,JAM21PionPDFnlo,786 +2000,JAM21PionPDFnlo_pT,786 +3000,JAM21PionPDFnlonll_cosine,756 +4000,JAM21PionPDFnlonll_expansion,780 +5000,JAM21PionPDFnlonll_double_Mellin,778 +10042,cteq6l1,1 +10150,cteq61,41 +10550,cteq66,45 +10770,CT09MCS,1 +10771,CT09MC1,1 +10772,CT09MC2,1 +10800,CT10,53 +10860,CT10as,11 +10900,CT10w,53 +10960,CT10was,11 +10980,CT10f3,1 +10981,CT10f4,1 +10982,CT10wf3,1 +10983,CT10wf4,1 +11000,CT10nlo,53 +11062,CT10nlo_as_0112,1 +11063,CT10nlo_as_0113,1 +11064,CT10nlo_as_0114,1 +11065,CT10nlo_as_0115,1 +11066,CT10nlo_as_0116,1 +11067,CT10nlo_as_0117,1 +11068,CT10nlo_as_0118,1 +11069,CT10nlo_as_0119,1 +11070,CT10nlo_as_0120,1 +11071,CT10nlo_as_0121,1 +11072,CT10nlo_as_0122,1 +11073,CT10nlo_as_0123,1 +11074,CT10nlo_as_0124,1 +11075,CT10nlo_as_0125,1 +11076,CT10nlo_as_0126,1 +11077,CT10nlo_as_0127,1 +11080,CT10nlo_nf3,2 +11082,CT10nlo_nf4,2 +11100,CT10wnlo,53 +11162,CT10wnlo_as_0112,1 +11163,CT10wnlo_as_0113,1 +11164,CT10wnlo_as_0114,1 +11165,CT10wnlo_as_0115,1 +11166,CT10wnlo_as_0116,1 +11167,CT10wnlo_as_0117,1 +11168,CT10wnlo_as_0118,1 +11169,CT10wnlo_as_0119,1 +11170,CT10wnlo_as_0120,1 +11171,CT10wnlo_as_0121,1 +11172,CT10wnlo_as_0122,1 +11173,CT10wnlo_as_0123,1 +11174,CT10wnlo_as_0124,1 +11175,CT10wnlo_as_0125,1 +11176,CT10wnlo_as_0126,1 +11177,CT10wnlo_as_0127,1 +11180,CT10wnlo_nf3,2 +11182,CT10wnlo_nf4,2 +11200,CT10nnlo,51 +11260,CT10nnlo_as_0110,1 +11261,CT10nnlo_as_0111,1 +11262,CT10nnlo_as_0112,1 +11263,CT10nnlo_as_0113,1 +11264,CT10nnlo_as_0114,1 +11265,CT10nnlo_as_0115,1 +11266,CT10nnlo_as_0116,1 +11267,CT10nnlo_as_0117,1 +11268,CT10nnlo_as_0118,1 +11269,CT10nnlo_as_0119,1 +11270,CT10nnlo_as_0120,1 +11271,CT10nnlo_as_0121,1 +11272,CT10nnlo_as_0122,1 +11273,CT10nnlo_as_0123,1 +11274,CT10nnlo_as_0124,1 +11275,CT10nnlo_as_0125,1 +11276,CT10nnlo_as_0126,1 +11277,CT10nnlo_as_0127,1 +11278,CT10nnlo_as_0128,1 +11279,CT10nnlo_as_0129,1 +11280,CT10nnlo_as_0130,1 +12000,CJ12min,39 +12100,CJ12mid,39 +12200,CJ12max,39 +12300,CJ15lo,49 +12400,CJ15nlo,49 +13000,CT14nnlo,57 +13060,CT14nnlo_as_0111,1 +13061,CT14nnlo_as_0112,1 +13062,CT14nnlo_as_0113,1 +13063,CT14nnlo_as_0114,1 +13064,CT14nnlo_as_0115,1 +13065,CT14nnlo_as_0116,1 +13066,CT14nnlo_as_0117,1 +13067,CT14nnlo_as_0118,1 +13068,CT14nnlo_as_0119,1 +13069,CT14nnlo_as_0120,1 +13070,CT14nnlo_as_0121,1 +13071,CT14nnlo_as_0122,1 +13072,CT14nnlo_as_0123,1 +13081,CT14nnloIC,6 +13090,CT14nnlo_NF3,1 +13091,CT14nnlo_NF4,1 +13092,CT14nnlo_NF6,1 +13100,CT14nlo,57 +13158,CT14nlo_as_0111,1 +13159,CT14nlo_as_0112,1 +13160,CT14nlo_as_0113,1 +13161,CT14nlo_as_0114,1 +13162,CT14nlo_as_0115,1 +13163,CT14nlo_as_0116,1 +13164,CT14nlo_as_0117,1 +13165,CT14nlo_as_0118,1 +13166,CT14nlo_as_0119,1 +13167,CT14nlo_as_0120,1 +13168,CT14nlo_as_0121,1 +13169,CT14nlo_as_0122,1 +13170,CT14nlo_as_0123,1 +13190,CT14nlo_NF3,1 +13191,CT14nlo_NF4,1 +13192,CT14nlo_NF6,1 +13200,CT14lo,1 +13201,CT14lo_NF3,1 +13202,CT14lo_NF4,1 +13203,CT14lo_NF6,1 +13205,CT14llo,1 +13206,CT14llo_NF3,1 +13207,CT14llo_NF4,1 +13208,CT14llo_NF6,1 +13300,CT14qed_proton,31 +13350,CT14qed_neutron,31 +13400,CT14qed_inc_proton,31 +13450,CT14qed_inc_neutron,31 +14000,CT18NNLO,59 +14060,CT18NNLO_as_0110,1 +14061,CT18NNLO_as_0111,1 +14062,CT18NNLO_as_0112,1 +14063,CT18NNLO_as_0113,1 +14064,CT18NNLO_as_0114,1 +14065,CT18NNLO_as_0115,1 +14066,CT18NNLO_as_0116,1 +14067,CT18NNLO_as_0117,1 +14068,CT18NNLO_as_0118,1 +14069,CT18NNLO_as_0119,1 +14070,CT18NNLO_as_0120,1 +14071,CT18NNLO_as_0121,1 +14072,CT18NNLO_as_0122,1 +14073,CT18NNLO_as_0123,1 +14074,CT18NNLO_as_0124,1 +14100,CT18ZNNLO,59 +14160,CT18ZNNLO_as_0110,1 +14161,CT18ZNNLO_as_0111,1 +14162,CT18ZNNLO_as_0112,1 +14163,CT18ZNNLO_as_0113,1 +14164,CT18ZNNLO_as_0114,1 +14165,CT18ZNNLO_as_0115,1 +14166,CT18ZNNLO_as_0116,1 +14167,CT18ZNNLO_as_0117,1 +14168,CT18ZNNLO_as_0118,1 +14169,CT18ZNNLO_as_0119,1 +14170,CT18ZNNLO_as_0120,1 +14171,CT18ZNNLO_as_0121,1 +14172,CT18ZNNLO_as_0122,1 +14173,CT18ZNNLO_as_0123,1 +14174,CT18ZNNLO_as_0124,1 +14200,CT18ANNLO,59 +14260,CT18ANNLO_as_0110,1 +14261,CT18ANNLO_as_0111,1 +14262,CT18ANNLO_as_0112,1 +14263,CT18ANNLO_as_0113,1 +14264,CT18ANNLO_as_0114,1 +14265,CT18ANNLO_as_0115,1 +14266,CT18ANNLO_as_0116,1 +14267,CT18ANNLO_as_0117,1 +14268,CT18ANNLO_as_0118,1 +14269,CT18ANNLO_as_0119,1 +14270,CT18ANNLO_as_0120,1 +14271,CT18ANNLO_as_0121,1 +14272,CT18ANNLO_as_0122,1 +14273,CT18ANNLO_as_0123,1 +14274,CT18ANNLO_as_0124,1 +14300,CT18XNNLO,59 +14360,CT18XNNLO_as_0110,1 +14361,CT18XNNLO_as_0111,1 +14362,CT18XNNLO_as_0112,1 +14363,CT18XNNLO_as_0113,1 +14364,CT18XNNLO_as_0114,1 +14365,CT18XNNLO_as_0115,1 +14366,CT18XNNLO_as_0116,1 +14367,CT18XNNLO_as_0117,1 +14368,CT18XNNLO_as_0118,1 +14369,CT18XNNLO_as_0119,1 +14370,CT18XNNLO_as_0120,1 +14371,CT18XNNLO_as_0121,1 +14372,CT18XNNLO_as_0122,1 +14373,CT18XNNLO_as_0123,1 +14374,CT18XNNLO_as_0124,1 +14400,CT18NLO,59 +14460,CT18NLO_as_0110,1 +14461,CT18NLO_as_0111,1 +14462,CT18NLO_as_0112,1 +14463,CT18NLO_as_0113,1 +14464,CT18NLO_as_0114,1 +14465,CT18NLO_as_0115,1 +14466,CT18NLO_as_0116,1 +14467,CT18NLO_as_0117,1 +14468,CT18NLO_as_0118,1 +14469,CT18NLO_as_0119,1 +14470,CT18NLO_as_0120,1 +14471,CT18NLO_as_0121,1 +14472,CT18NLO_as_0122,1 +14473,CT18NLO_as_0123,1 +14474,CT18NLO_as_0124,1 +14500,CT18ZNLO,59 +14560,CT18ZNLO_as_0110,1 +14561,CT18ZNLO_as_0111,1 +14562,CT18ZNLO_as_0112,1 +14563,CT18ZNLO_as_0113,1 +14564,CT18ZNLO_as_0114,1 +14565,CT18ZNLO_as_0115,1 +14566,CT18ZNLO_as_0116,1 +14567,CT18ZNLO_as_0117,1 +14568,CT18ZNLO_as_0118,1 +14569,CT18ZNLO_as_0119,1 +14570,CT18ZNLO_as_0120,1 +14571,CT18ZNLO_as_0121,1 +14572,CT18ZNLO_as_0122,1 +14573,CT18ZNLO_as_0123,1 +14574,CT18ZNLO_as_0124,1 +14600,CT18ANLO,59 +14660,CT18ANLO_as_0110,1 +14661,CT18ANLO_as_0111,1 +14662,CT18ANLO_as_0112,1 +14663,CT18ANLO_as_0113,1 +14664,CT18ANLO_as_0114,1 +14665,CT18ANLO_as_0115,1 +14666,CT18ANLO_as_0116,1 +14667,CT18ANLO_as_0117,1 +14668,CT18ANLO_as_0118,1 +14669,CT18ANLO_as_0119,1 +14670,CT18ANLO_as_0120,1 +14671,CT18ANLO_as_0121,1 +14672,CT18ANLO_as_0122,1 +14673,CT18ANLO_as_0123,1 +14674,CT18ANLO_as_0124,1 +14700,CT18XNLO,59 +14760,CT18XNLO_as_0110,1 +14761,CT18XNLO_as_0111,1 +14762,CT18XNLO_as_0112,1 +14763,CT18XNLO_as_0113,1 +14764,CT18XNLO_as_0114,1 +14765,CT18XNLO_as_0115,1 +14766,CT18XNLO_as_0116,1 +14767,CT18XNLO_as_0117,1 +14768,CT18XNLO_as_0118,1 +14769,CT18XNLO_as_0119,1 +14770,CT18XNLO_as_0120,1 +14771,CT18XNLO_as_0121,1 +14772,CT18XNLO_as_0122,1 +14773,CT18XNLO_as_0123,1 +14774,CT18XNLO_as_0124,1 +20463,MRST2004qed_proton,2 +20465,MRST2004qed_neutron,2 +20650,MRST2007lomod,1 +20651,MRSTMCal,1 +21000,MSTW2008lo68cl,41 +21050,MSTW2008lo90cl,41 +21100,MSTW2008nlo68cl,41 +21150,MSTW2008nlo90cl,41 +21200,MSTW2008nnlo68cl,41 +21250,MSTW2008nnlo90cl,41 +22000,MSTW2008nlo_asmzrange,22 +22100,MSTW2008nlo68cl_asmz+68cl,41 +22150,MSTW2008nlo68cl_asmz-68cl,41 +22200,MSTW2008nlo68cl_asmz+68clhalf,41 +22250,MSTW2008nlo68cl_asmz-68clhalf,41 +22300,MSTW2008nlo90cl_asmz+90cl,41 +22350,MSTW2008nlo90cl_asmz-90cl,41 +22400,MSTW2008nlo90cl_asmz+90clhalf,41 +22450,MSTW2008nlo90cl_asmz-90clhalf,41 +22500,MSTW2008nnlo_asmzrange,22 +22600,MSTW2008nnlo68cl_asmz+68cl,41 +22650,MSTW2008nnlo68cl_asmz-68cl,41 +22700,MSTW2008nnlo68cl_asmz+68clhalf,41 +22750,MSTW2008nnlo68cl_asmz-68clhalf,41 +22800,MSTW2008nnlo90cl_asmz+90cl,41 +22850,MSTW2008nnlo90cl_asmz-90cl,41 +22900,MSTW2008nnlo90cl_asmz+90clhalf,41 +22950,MSTW2008nnlo90cl_asmz-90clhalf,41 +23000,MSTW2008lo68cl_nf3,41 +23050,MSTW2008lo90cl_nf3,41 +23100,MSTW2008lo68cl_nf4,41 +23150,MSTW2008lo90cl_nf4,41 +23200,MSTW2008nlo68cl_nf3,41 +23250,MSTW2008nlo90cl_nf3,41 +23300,MSTW2008nlo68cl_nf4,41 +23350,MSTW2008nlo90cl_nf4,41 +23400,MSTW2008nlo_mcrange,15 +23420,MSTW2008nlo_mcrange_nf3,15 +23440,MSTW2008nlo_mcrange_fixasmz,15 +23460,MSTW2008nlo_mcrange_fixasmz_nf3,15 +23480,MSTW2008nlo_mbrange,7 +23490,MSTW2008nlo_mbrange_nf4,7 +23500,MSTW2008nnlo68cl_nf3,41 +23550,MSTW2008nnlo90cl_nf3,41 +23600,MSTW2008nnlo68cl_nf4,41 +23650,MSTW2008nnlo90cl_nf4,41 +23700,MSTW2008nnlo_mcrange,15 +23720,MSTW2008nnlo_mcrange_nf3,15 +23740,MSTW2008nnlo_mcrange_fixasmz,15 +23760,MSTW2008nnlo_mcrange_fixasmz_nf3,15 +23780,MSTW2008nnlo_mbrange,7 +23790,MSTW2008nnlo_mbrange_nf4,7 +23800,MSTW2008CPdeutnlo68cl,47 +23850,MSTW2008CPdeutnnlo68cl,47 +23900,MSTW2008lo68cl_nf4as5,41 +23950,MSTW2008lo90cl_nf4as5,41 +24000,MSTW2008nlo68cl_nf4as5,41 +24050,MSTW2008nlo90cl_nf4as5,41 +24100,MSTW2008nnlo68cl_nf4as5,41 +24150,MSTW2008nnlo90cl_nf4as5,41 +25000,MMHT2014lo68cl,51 +25060,MMHT2014lo_asmzsmallrange,3 +25100,MMHT2014nlo68cl,51 +25200,MMHT2014nlo68clas118,51 +25260,MMHT2014nlo_asmzsmallrange,5 +25270,MMHT2014nlo_asmzlargerange,21 +25300,MMHT2014nnlo68cl,51 +25360,MMHT2014nnlo_asmzsmallrange,3 +25370,MMHT2014nnlo_asmzlargerange,21 +25400,MMHT2014nlo68cl_nf3,51 +25410,MMHT2014nlo68cl_nf4,51 +25420,MMHT2014nlo68cl_nf4as5,51 +25500,MMHT2014nlo68clas118_nf3,51 +25510,MMHT2014nlo68clas118_nf4,51 +25520,MMHT2014nlo68clas118_nf4as5,51 +25560,MMHT2014nlo_asmzsmallrange_nf3,5 +25570,MMHT2014nlo_asmzsmallrange_nf4,5 +25600,MMHT2014nlo_mcrange_nf3,9 +25605,MMHT2014nlo_mcrange_nf4,9 +25610,MMHT2014nlo_mcrange_nf5,9 +25615,MMHT2014nlo_mbrange_nf3,5 +25620,MMHT2014nlo_mbrange_nf4,5 +25625,MMHT2014nlo_mbrange_nf5,5 +25630,MMHT2014nloas118_mcrange_nf3,9 +25635,MMHT2014nloas118_mcrange_nf4,9 +25640,MMHT2014nloas118_mcrange_nf5,9 +25645,MMHT2014nloas118_mbrange_nf3,5 +25650,MMHT2014nloas118_mbrange_nf4,5 +25655,MMHT2014nloas118_mbrange_nf5,5 +25700,MMHT2014nnlo68cl_nf3,51 +25710,MMHT2014nnlo68cl_nf4,51 +25720,MMHT2014nnlo68cl_nf4as5,51 +25760,MMHT2014nnlo_asmzsmallrange_nf3,3 +25770,MMHT2014nnlo_asmzsmallrange_nf4,3 +25800,MMHT2014nnlo_mcrange_nf3,9 +25805,MMHT2014nnlo_mcrange_nf4,9 +25810,MMHT2014nnlo_mcrange_nf5,9 +25830,MMHT2014nnlo_mbrange_nf3,5 +25840,MMHT2014nnlo_mbrange_nf4,5 +25850,MMHT2014nnlo_mbrange_nf5,5 +26000,MMHT2015qed_nlo,63 +26100,MMHT2015qed_nlo_elastic,63 +26200,MMHT2015qed_nlo_inelastic,63 +26300,MMHT2015qed_nnlo,63 +26400,MMHT2015qed_nnlo_elastic,63 +26500,MMHT2015qed_nnlo_inelastic,63 +27000,MSHT20lo_as130,61 +27100,MSHT20nlo_as118,65 +27200,MSHT20nlo_as120,65 +27300,MSHT20nlo_as_smallrange,8 +27350,MSHT20nlo_as_largerange,23 +27400,MSHT20nnlo_as118,65 +27500,MSHT20nnlo_as_smallrange,7 +27550,MSHT20nnlo_as_largerange,23 +27600,MSHT20nlo_nf3,65 +27700,MSHT20nlo_nf4,65 +27800,MSHT20nlo_as120_nf3,65 +27900,MSHT20nlo_as120_nf4,65 +28000,MSHT20nlo_as_smallrange_nf3,5 +28010,MSHT20nlo_as_smallrange_nf4,5 +28020,MSHT20nlo_mcrange_nf3,9 +28030,MSHT20nlo_mcrange_nf4,9 +28040,MSHT20nlo_mcrange_nf5,9 +28050,MSHT20nlo_mbrange_nf3,7 +28060,MSHT20nlo_mbrange_nf4,7 +28070,MSHT20nlo_mbrange_nf5,7 +28080,MSHT20nlo_as120_mcrange_nf3,9 +28090,MSHT20nlo_as120_mcrange_nf4,9 +28100,MSHT20nlo_as120_mcrange_nf5,9 +28110,MSHT20nlo_as120_mbrange_nf3,7 +28120,MSHT20nlo_as120_mbrange_nf4,7 +28130,MSHT20nlo_as120_mbrange_nf5,7 +28200,MSHT20nnlo_nf3,65 +28300,MSHT20nnlo_nf4,65 +28400,MSHT20nnlo_as_smallrange_nf3,3 +28405,MSHT20nnlo_as_smallrange_nf4,3 +28410,MSHT20nnlo_mcrange_nf3,9 +28420,MSHT20nnlo_mcrange_nf4,9 +28430,MSHT20nnlo_mcrange_nf5,9 +28440,MSHT20nnlo_mbrange_nf3,7 +28450,MSHT20nnlo_mbrange_nf4,7 +28460,MSHT20nnlo_mbrange_nf5,7 +28500,MSHT20qed_nnlo,77 +28600,MSHT20qed_nnlo_elastic,77 +28700,MSHT20qed_nnlo_inelastic,77 +28800,MSHT20qed_nnlo_neutron,77 +28900,MSHT20qed_nnlo_neutron_elastic,77 +29000,MSHT20qed_nnlo_neutron_inelastic,77 +29100,MSHT20an3lo_as118,105 +29250,MSHT20an3lo_as118_Kcorr,105 +33000,GKG18_DPDF_FitA_LO,19 +33020,GKG18_DPDF_FitB_LO,19 +33040,GKG18_DPDF_FitA_NLO,19 +33060,GKG18_DPDF_FitB_NLO,19 +40650,abkm09_3_nlo,26 +40750,abkm09_3_nnlo,26 +40780,abkm09_4_nlo,26 +40810,abkm09_4_nnlo,26 +40850,abkm09_5_nlo,26 +40950,abkm09_5_nnlo,26 +42000,abm11_3n_nlo,29 +42030,abm11_4n_nlo,29 +42060,abm11_5n_nlo,29 +42100,abm11_3n_nnlo,29 +42130,abm11_4n_nnlo,29 +42160,abm11_5n_nnlo,29 +42200,abm11_5n_as_nlo,21 +42230,abm11_5n_as_nnlo,17 +42300,abm12lhc_3_nnlo,29 +42330,abm12lhc_4_nnlo,29 +42360,abm12lhc_5_nnlo,29 +42400,ABMP15_3_nnlo,29 +42430,ABMP15_4_nnlo,29 +42460,ABMP15_5_nnlo,29 +42500,ABMP16_3_nnlo,30 +42530,ABMP16_4_nnlo,30 +42560,ABMP16_5_nnlo,30 +42600,ABMP16als112_5_nnlo,30 +42630,ABMP16als113_5_nnlo,30 +42660,ABMP16als114_5_nnlo,30 +42690,ABMP16als115_5_nnlo,30 +42720,ABMP16als116_5_nnlo,30 +42750,ABMP16als117_5_nnlo,30 +42780,ABMP16als118_5_nnlo,30 +42810,ABMP16als119_5_nnlo,30 +42840,ABMP16als120_5_nnlo,30 +42900,ABMP16_3_nlo,30 +42930,ABMP16_4_nlo,30 +42960,ABMP16_5_nlo,30 +42990,ABMP16als114_5_nlo,30 +43020,ABMP16als115_5_nlo,30 +43050,ABMP16als116_5_nlo,30 +43080,ABMP16als117_5_nlo,30 +43110,ABMP16als118_5_nlo,30 +43140,ABMP16als119_5_nlo,30 +43170,ABMP16als120_5_nlo,30 +43200,ABMP16als121_5_nlo,30 +43230,ABMP16als122_5_nlo,30 +43260,ABMP16als123_5_nlo,30 +43290,ABMP16free_3_nlo,30 +43320,ABMP16free_4_nlo,30 +43350,ABMP16free_5_nlo,30 +60600,HERAPDF15NNLO_EIG,29 +60630,HERAPDF15NNLO_VAR,11 +60650,HERAPDF15NNLO_ALPHAS,12 +60700,HERAPDF15NLO_EIG,21 +60730,HERAPDF15NLO_VAR,13 +60750,HERAPDF15NLO_ALPHAS,12 +60800,HERAPDF15LO_EIG,21 +61000,HERAPDF20_LO_EIG,27 +61100,HERAPDF20_NLO_EIG,29 +61130,HERAPDF20_NLO_VAR,14 +61200,HERAPDF20_NNLO_EIG,29 +61230,HERAPDF20_NNLO_VAR,14 +61300,HERAPDF20_NLO_FF3A_EIG,29 +61330,HERAPDF20_NLO_FF3B_EIG,29 +61360,HERAPDF20_NLO_FF3A_VAR,14 +61380,HERAPDF20_NLO_FF3B_VAR,14 +61400,HERAPDF20_AG_NLO_EIG,27 +61430,HERAPDF20_AG_NNLO_EIG,27 +61500,HERAPDF20_HiQ2_NLO_EIG,29 +61530,HERAPDF20_HiQ2_NLO_VAR,14 +61600,HERAPDF20_HiQ2_NNLO_EIG,29 +61630,HERAPDF20_HiQ2_NNLO_VAR,14 +61650,HERAPDF20_Jets_NLO_EIG,31 +61690,HERAPDF20_Jets_NLO_VAR_Duv,1 +61691,HERAPDF20_Jets_NLO_VAR_fsdn,1 +61692,HERAPDF20_Jets_NLO_VAR_fsup,1 +61693,HERAPDF20_Jets_NLO_VAR_fshdn,1 +61694,HERAPDF20_Jets_NLO_VAR_fshup,1 +61695,HERAPDF20_Jets_NLO_VAR_haddn,1 +61696,HERAPDF20_Jets_NLO_VAR_hadup,1 +61697,HERAPDF20_Jets_NLO_VAR_mbdn,1 +61698,HERAPDF20_Jets_NLO_VAR_mbup,1 +61699,HERAPDF20_Jets_NLO_VAR_mcdn,1 +61700,HERAPDF20_Jets_NLO_VAR_mcup,1 +61701,HERAPDF20_Jets_NLO_VAR_q0dn,1 +61702,HERAPDF20_Jets_NLO_VAR_q0up,1 +61703,HERAPDF20_Jets_NLO_VAR_q2mdn,1 +61704,HERAPDF20_Jets_NLO_VAR_q2mup,1 +61710,HERAPDF20_NLO_ALPHAS_110,1 +61711,HERAPDF20_NLO_ALPHAS_111,1 +61712,HERAPDF20_NLO_ALPHAS_112,1 +61713,HERAPDF20_NLO_ALPHAS_113,1 +61714,HERAPDF20_NLO_ALPHAS_114,1 +61715,HERAPDF20_NLO_ALPHAS_115,1 +61716,HERAPDF20_NLO_ALPHAS_116,1 +61717,HERAPDF20_NLO_ALPHAS_117,1 +61718,HERAPDF20_NLO_ALPHAS_118,1 +61719,HERAPDF20_NLO_ALPHAS_119,1 +61720,HERAPDF20_NLO_ALPHAS_120,1 +61721,HERAPDF20_NLO_ALPHAS_121,1 +61722,HERAPDF20_NLO_ALPHAS_122,1 +61723,HERAPDF20_NLO_ALPHAS_123,1 +61724,HERAPDF20_NLO_ALPHAS_124,1 +61725,HERAPDF20_NLO_ALPHAS_125,1 +61726,HERAPDF20_NLO_ALPHAS_126,1 +61727,HERAPDF20_NLO_ALPHAS_127,1 +61728,HERAPDF20_NLO_ALPHAS_128,1 +61729,HERAPDF20_NLO_ALPHAS_129,1 +61730,HERAPDF20_NLO_ALPHAS_130,1 +61740,HERAPDF20_NNLO_ALPHAS_110,1 +61741,HERAPDF20_NNLO_ALPHAS_111,1 +61742,HERAPDF20_NNLO_ALPHAS_112,1 +61743,HERAPDF20_NNLO_ALPHAS_113,1 +61744,HERAPDF20_NNLO_ALPHAS_114,1 +61745,HERAPDF20_NNLO_ALPHAS_115,1 +61746,HERAPDF20_NNLO_ALPHAS_116,1 +61747,HERAPDF20_NNLO_ALPHAS_117,1 +61748,HERAPDF20_NNLO_ALPHAS_118,1 +61749,HERAPDF20_NNLO_ALPHAS_119,1 +61750,HERAPDF20_NNLO_ALPHAS_120,1 +61751,HERAPDF20_NNLO_ALPHAS_121,1 +61752,HERAPDF20_NNLO_ALPHAS_122,1 +61753,HERAPDF20_NNLO_ALPHAS_123,1 +61754,HERAPDF20_NNLO_ALPHAS_124,1 +61755,HERAPDF20_NNLO_ALPHAS_125,1 +61756,HERAPDF20_NNLO_ALPHAS_126,1 +61757,HERAPDF20_NNLO_ALPHAS_127,1 +61758,HERAPDF20_NNLO_ALPHAS_128,1 +61759,HERAPDF20_NNLO_ALPHAS_129,1 +61760,HERAPDF20_NNLO_ALPHAS_130,1 +65000,ATLAS-epWZ12-EIG,31 +65040,ATLAS-epWZ12-VAR,12 +65060,ATLAS-epWZ16-EIG,31 +65100,ATLAS-epWZ16-VAR,16 +65120,ATLAS-epWZ16-THEO,14 +65140,ATLAS-epWZtop18-EIG,33 +65180,ATLAS-epWZtop18-VAR,13 +65200,ATLASepWZVjet20-EIG,33 +65240,ATLASepWZVjet20-MOD,9 +65250,ATLASepWZVjet20-PAR,18 +65600,ATLASpdf21_T1,53 +65700,ATLASpdf21_T3,53 +69000,CSKK_nnlo_EIG,31 +69100,CSKK_nnlo_VAR,16 +69200,CSKK_nnlo_THEO,5 +70400,H1PDF2017,27 +80000,METAv10LHC,101 +80111,METAv10LHCas0116,1 +80112,METAv10LHCas0120,1 +80120,METAv10LHCH,13 +80200,METAv10LHCHfull,101 +81000,JR14NNLO08VF,39 +81050,JR14NNLO20VF,39 +81100,JR14NNLO08FF,39 +81150,JR14NNLO20FF,39 +81200,JR14NLO08VF,39 +81250,JR14NLO08FF,39 +82000,LUXqed_plus_PDF4LHC15_nnlo_100,108 +82200,LUXqed17_plus_PDF4LHC15_nnlo_100,108 +82350,LUXqed17_plus_PDF4LHC15_nnlo_30,38 +82400,LUXlep-NNPDF31_nlo_as_0118_luxqed,101 +90000,PDF4LHC15_nlo_mc_pdfas,103 +90200,PDF4LHC15_nlo_100_pdfas,103 +90400,PDF4LHC15_nlo_30_pdfas,33 +90500,PDF4LHC15_nlo_mc,101 +90700,PDF4LHC15_nlo_100,101 +90900,PDF4LHC15_nlo_30,31 +90950,PDF4LHC15_nlo_asvar,2 +91000,PDF4LHC15_nnlo_mc_pdfas,103 +91200,PDF4LHC15_nnlo_100_pdfas,103 +91400,PDF4LHC15_nnlo_30_pdfas,33 +91500,PDF4LHC15_nnlo_mc,101 +91700,PDF4LHC15_nnlo_100,101 +91900,PDF4LHC15_nnlo_30,31 +91950,PDF4LHC15_nnlo_asvar,2 +92000,PDF4LHC15_nlo_nf4_30,31 +93000,PDF4LHC21_mc,101 +93100,PDF4LHC21_40,41 +93200,PDF4LHC21_mc_pdfas,103 +93300,PDF4LHC21_40_pdfas,43 +93400,PDF4LHC21_mc_nf4,101 +93500,PDF4LHC21_40_nf4,41 +93600,PDF4LHC21_mc_pdfas_nf4,103 +93700,PDF4LHC21_40_pdfas_nf4,43 +100000,nCTEQ15_1_1,1 +100050,nCTEQ15_3_2,33 +100100,nCTEQ15_4_2,33 +100150,nCTEQ15_6_3,33 +100200,nCTEQ15_7_3,33 +100250,nCTEQ15_9_4,33 +100300,nCTEQ15_12_6,33 +100350,nCTEQ15_14_7,33 +100400,nCTEQ15_20_10,33 +100450,nCTEQ15_27_13,33 +100500,nCTEQ15_40_18,33 +100550,nCTEQ15_40_20,33 +100600,nCTEQ15_56_26,33 +100650,nCTEQ15_64_32,33 +100700,nCTEQ15_84_42,33 +100750,nCTEQ15_108_54,33 +100800,nCTEQ15_119_59,33 +100850,nCTEQ15_131_54,33 +100900,nCTEQ15_184_74,33 +100950,nCTEQ15_197_79,33 +101000,nCTEQ15_197_98,33 +101050,nCTEQ15_207_103,33 +101100,nCTEQ15_208_82,33 +102000,nCTEQ15FullNuc_1_1,1 +102050,nCTEQ15FullNuc_3_2,33 +102100,nCTEQ15FullNuc_4_2,33 +102150,nCTEQ15FullNuc_6_3,33 +102200,nCTEQ15FullNuc_7_3,33 +102250,nCTEQ15FullNuc_9_4,33 +102300,nCTEQ15FullNuc_12_6,33 +102350,nCTEQ15FullNuc_14_7,33 +102400,nCTEQ15FullNuc_20_10,33 +102450,nCTEQ15FullNuc_27_13,33 +102500,nCTEQ15FullNuc_40_18,33 +102550,nCTEQ15FullNuc_40_20,33 +102600,nCTEQ15FullNuc_56_26,33 +102650,nCTEQ15FullNuc_64_32,33 +102700,nCTEQ15FullNuc_84_42,33 +102750,nCTEQ15FullNuc_108_54,33 +102800,nCTEQ15FullNuc_119_59,33 +102850,nCTEQ15FullNuc_131_54,33 +102900,nCTEQ15FullNuc_184_74,33 +102950,nCTEQ15FullNuc_197_79,33 +103000,nCTEQ15FullNuc_197_98,33 +103050,nCTEQ15FullNuc_207_103,33 +103100,nCTEQ15FullNuc_208_82,33 +104000,nCTEQ15np_1_1,1 +104050,nCTEQ15np_3_2,33 +104100,nCTEQ15np_4_2,33 +104150,nCTEQ15np_6_3,33 +104200,nCTEQ15np_7_3,33 +104250,nCTEQ15np_9_4,33 +104300,nCTEQ15np_12_6,33 +104350,nCTEQ15np_14_7,33 +104400,nCTEQ15np_20_10,33 +104450,nCTEQ15np_27_13,33 +104500,nCTEQ15np_40_18,33 +104550,nCTEQ15np_40_20,33 +104600,nCTEQ15np_56_26,33 +104650,nCTEQ15np_64_32,33 +104700,nCTEQ15np_84_42,33 +104750,nCTEQ15np_108_54,33 +104800,nCTEQ15np_119_59,33 +104850,nCTEQ15np_131_54,33 +104900,nCTEQ15np_184_74,33 +104950,nCTEQ15np_197_79,33 +105000,nCTEQ15np_197_98,33 +105050,nCTEQ15np_207_103,33 +105100,nCTEQ15np_208_82,33 +106000,nCTEQ15npFullNuc_1_1,1 +106050,nCTEQ15npFullNuc_3_2,33 +106100,nCTEQ15npFullNuc_4_2,33 +106150,nCTEQ15npFullNuc_6_3,33 +106200,nCTEQ15npFullNuc_7_3,33 +106250,nCTEQ15npFullNuc_9_4,33 +106300,nCTEQ15npFullNuc_12_6,33 +106350,nCTEQ15npFullNuc_14_7,33 +106400,nCTEQ15npFullNuc_20_10,33 +106450,nCTEQ15npFullNuc_27_13,33 +106500,nCTEQ15npFullNuc_40_18,33 +106550,nCTEQ15npFullNuc_40_20,33 +106600,nCTEQ15npFullNuc_56_26,33 +106650,nCTEQ15npFullNuc_64_32,33 +106700,nCTEQ15npFullNuc_84_42,33 +106750,nCTEQ15npFullNuc_108_54,33 +106800,nCTEQ15npFullNuc_119_59,33 +106850,nCTEQ15npFullNuc_131_54,33 +106900,nCTEQ15npFullNuc_184_74,33 +106950,nCTEQ15npFullNuc_197_79,33 +107000,nCTEQ15npFullNuc_197_98,33 +107050,nCTEQ15npFullNuc_207_103,33 +107100,nCTEQ15npFullNuc_208_82,33 +108000,nCTEQ15HIX_1_1,43 +108050,nCTEQ15HIX_2_1,43 +108100,nCTEQ15HIX_3_2,43 +108150,nCTEQ15HIX_4_2,43 +108200,nCTEQ15HIX_6_3,43 +108250,nCTEQ15HIX_7_3,43 +108300,nCTEQ15HIX_9_4,43 +108350,nCTEQ15HIX_12_6,43 +108400,nCTEQ15HIX_14_7,43 +108450,nCTEQ15HIX_27_13,43 +108500,nCTEQ15HIX_40_20,43 +108550,nCTEQ15HIX_56_26,43 +108600,nCTEQ15HIX_64_29,43 +108650,nCTEQ15HIX_84_36,43 +108700,nCTEQ15HIX_108_47,43 +108750,nCTEQ15HIX_119_50,43 +108800,nCTEQ15HIX_131_54,43 +108850,nCTEQ15HIX_184_74,43 +108900,nCTEQ15HIX_197_79,43 +108950,nCTEQ15HIX_208_82,43 +110000,nCTEQ15HIX_FullNuc_1_1,43 +110050,nCTEQ15HIX_FullNuc_2_1,43 +110100,nCTEQ15HIX_FullNuc_3_2,43 +110150,nCTEQ15HIX_FullNuc_4_2,43 +110200,nCTEQ15HIX_FullNuc_6_3,43 +110250,nCTEQ15HIX_FullNuc_7_3,43 +110300,nCTEQ15HIX_FullNuc_9_4,43 +110350,nCTEQ15HIX_FullNuc_12_6,43 +110400,nCTEQ15HIX_FullNuc_14_7,43 +110450,nCTEQ15HIX_FullNuc_27_13,43 +110500,nCTEQ15HIX_FullNuc_40_20,43 +110550,nCTEQ15HIX_FullNuc_56_26,43 +110600,nCTEQ15HIX_FullNuc_64_29,43 +110650,nCTEQ15HIX_FullNuc_84_36,43 +110700,nCTEQ15HIX_FullNuc_108_47,43 +110750,nCTEQ15HIX_FullNuc_119_50,43 +110800,nCTEQ15HIX_FullNuc_131_54,43 +110850,nCTEQ15HIX_FullNuc_184_74,43 +110900,nCTEQ15HIX_FullNuc_197_79,43 +110950,nCTEQ15HIX_FullNuc_208_82,43 +112000,nCTEQ15WZ_1_1,39 +112050,nCTEQ15WZ_1_0,39 +112100,nCTEQ15WZ_2_1,39 +112150,nCTEQ15WZ_3_1,39 +112200,nCTEQ15WZ_3_2,39 +112250,nCTEQ15WZ_4_2,39 +112300,nCTEQ15WZ_6_3,39 +112350,nCTEQ15WZ_7_3,39 +112400,nCTEQ15WZ_9_4,39 +112450,nCTEQ15WZ_9_4_iso,39 +112500,nCTEQ15WZ_12_6,39 +112550,nCTEQ15WZ_14_7,39 +112600,nCTEQ15WZ_16_8,39 +112650,nCTEQ15WZ_20_10,39 +112700,nCTEQ15WZ_27_13,39 +112750,nCTEQ15WZ_40_18,39 +112800,nCTEQ15WZ_40_20,39 +112850,nCTEQ15WZ_56_26,39 +112900,nCTEQ15WZ_56_28,39 +112950,nCTEQ15WZ_64_29,39 +113000,nCTEQ15WZ_64_32,39 +113050,nCTEQ15WZ_84_36,39 +113100,nCTEQ15WZ_84_42,39 +113150,nCTEQ15WZ_108_47,39 +113200,nCTEQ15WZ_108_54,39 +113250,nCTEQ15WZ_119_50,39 +113300,nCTEQ15WZ_119_59,39 +113350,nCTEQ15WZ_131_54,39 +113400,nCTEQ15WZ_184_74,39 +113450,nCTEQ15WZ_197_79,39 +113500,nCTEQ15WZ_197_98,39 +113550,nCTEQ15WZ_207_82,39 +113600,nCTEQ15WZ_207_103,39 +113650,nCTEQ15WZ_208_82,39 +114000,nCTEQ15WZ_FullNuc_1_1,39 +114050,nCTEQ15WZ_FullNuc_1_0,39 +114100,nCTEQ15WZ_FullNuc_2_1,39 +114150,nCTEQ15WZ_FullNuc_3_1,39 +114200,nCTEQ15WZ_FullNuc_3_2,39 +114250,nCTEQ15WZ_FullNuc_4_2,39 +114300,nCTEQ15WZ_FullNuc_6_3,39 +114350,nCTEQ15WZ_FullNuc_7_3,39 +114400,nCTEQ15WZ_FullNuc_9_4,39 +114450,nCTEQ15WZ_FullNuc_9_4_iso,39 +114500,nCTEQ15WZ_FullNuc_12_6,39 +114550,nCTEQ15WZ_FullNuc_14_7,39 +114600,nCTEQ15WZ_FullNuc_16_8,39 +114650,nCTEQ15WZ_FullNuc_20_10,39 +114700,nCTEQ15WZ_FullNuc_27_13,39 +114750,nCTEQ15WZ_FullNuc_40_18,39 +114800,nCTEQ15WZ_FullNuc_40_20,39 +114850,nCTEQ15WZ_FullNuc_56_26,39 +114900,nCTEQ15WZ_FullNuc_56_28,39 +114950,nCTEQ15WZ_FullNuc_64_29,39 +115000,nCTEQ15WZ_FullNuc_64_32,39 +115050,nCTEQ15WZ_FullNuc_84_36,39 +115100,nCTEQ15WZ_FullNuc_84_42,39 +115150,nCTEQ15WZ_FullNuc_108_47,39 +115200,nCTEQ15WZ_FullNuc_108_54,39 +115250,nCTEQ15WZ_FullNuc_119_50,39 +115300,nCTEQ15WZ_FullNuc_119_59,39 +115350,nCTEQ15WZ_FullNuc_131_54,39 +115400,nCTEQ15WZ_FullNuc_184_74,39 +115450,nCTEQ15WZ_FullNuc_197_79,39 +115500,nCTEQ15WZ_FullNuc_197_98,39 +115550,nCTEQ15WZ_FullNuc_207_82,39 +115600,nCTEQ15WZ_FullNuc_207_103,39 +115650,nCTEQ15WZ_FullNuc_208_82,39 +116000,nCTEQ15WZSIH_1_1,39 +116050,nCTEQ15WZSIH_2_1,39 +116100,nCTEQ15WZSIH_3_1,39 +116150,nCTEQ15WZSIH_4_2,39 +116200,nCTEQ15WZSIH_6_3,39 +116250,nCTEQ15WZSIH_7_3,39 +116300,nCTEQ15WZSIH_9_4,39 +116350,nCTEQ15WZSIH_12_6,39 +116400,nCTEQ15WZSIH_14_7,39 +116450,nCTEQ15WZSIH_16_8,39 +116500,nCTEQ15WZSIH_27_13,39 +116550,nCTEQ15WZSIH_40_20,39 +116600,nCTEQ15WZSIH_56_26,39 +116650,nCTEQ15WZSIH_56_28,39 +116700,nCTEQ15WZSIH_64_32,39 +116750,nCTEQ15WZSIH_84_42,39 +116800,nCTEQ15WZSIH_108_54,39 +116850,nCTEQ15WZSIH_119_59,39 +116900,nCTEQ15WZSIH_131_54,39 +116950,nCTEQ15WZSIH_184_74,39 +117000,nCTEQ15WZSIH_197_79,39 +117050,nCTEQ15WZSIH_197_98,39 +117100,nCTEQ15WZSIH_207_103,39 +117150,nCTEQ15WZSIH_208_82,39 +118000,nCTEQ15WZSIH_FullNuc_1_1,39 +118050,nCTEQ15WZSIH_FullNuc_2_1,39 +118100,nCTEQ15WZSIH_FullNuc_3_1,39 +118150,nCTEQ15WZSIH_FullNuc_4_2,39 +118200,nCTEQ15WZSIH_FullNuc_6_3,39 +118250,nCTEQ15WZSIH_FullNuc_7_3,39 +118300,nCTEQ15WZSIH_FullNuc_9_4,39 +118350,nCTEQ15WZSIH_FullNuc_12_6,39 +118400,nCTEQ15WZSIH_FullNuc_14_7,39 +118450,nCTEQ15WZSIH_FullNuc_16_8,39 +118500,nCTEQ15WZSIH_FullNuc_27_13,39 +118550,nCTEQ15WZSIH_FullNuc_40_20,39 +118600,nCTEQ15WZSIH_FullNuc_56_26,39 +118650,nCTEQ15WZSIH_FullNuc_56_28,39 +118700,nCTEQ15WZSIH_FullNuc_64_32,39 +118750,nCTEQ15WZSIH_FullNuc_84_42,39 +118800,nCTEQ15WZSIH_FullNuc_108_54,39 +118850,nCTEQ15WZSIH_FullNuc_119_59,39 +118900,nCTEQ15WZSIH_FullNuc_131_54,39 +118950,nCTEQ15WZSIH_FullNuc_184_74,39 +119000,nCTEQ15WZSIH_FullNuc_197_79,39 +119050,nCTEQ15WZSIH_FullNuc_197_98,39 +119100,nCTEQ15WZSIH_FullNuc_207_103,39 +119150,nCTEQ15WZSIH_FullNuc_208_82,39 +200200,NNPDF21_lo_as_0119_100,101 +200400,NNPDF21_lo_as_0130_100,101 +200600,NNPDF21_lostar_as_0119_100,101 +200800,NNPDF21_lostar_as_0130_100,101 +229000,NNPDF23_nlo_as_0114,101 +229200,NNPDF23_nlo_as_0115,101 +229400,NNPDF23_nlo_as_0116,101 +229600,NNPDF23_nlo_as_0117,101 +229800,NNPDF23_nlo_as_0118,101 +230000,NNPDF23_nlo_as_0119,101 +230200,NNPDF23_nlo_as_0120,101 +230400,NNPDF23_nlo_as_0121,101 +230600,NNPDF23_nlo_as_0122,101 +230800,NNPDF23_nlo_as_0123,101 +231000,NNPDF23_nlo_as_0124,101 +231200,NNPDF23_nnlo_as_0114,101 +231400,NNPDF23_nnlo_as_0115,101 +231600,NNPDF23_nnlo_as_0116,101 +231800,NNPDF23_nnlo_as_0117,101 +232000,NNPDF23_nnlo_as_0118,101 +232200,NNPDF23_nnlo_as_0119,101 +232400,NNPDF23_nnlo_as_0120,101 +232600,NNPDF23_nnlo_as_0121,101 +232800,NNPDF23_nnlo_as_0122,101 +233000,NNPDF23_nnlo_as_0123,101 +233200,NNPDF23_nnlo_as_0124,101 +233400,NNPDF23_nlo_noLHC_as_0116,101 +233600,NNPDF23_nlo_noLHC_as_0117,101 +233800,NNPDF23_nlo_noLHC_as_0118,101 +234000,NNPDF23_nlo_noLHC_as_0119,101 +234200,NNPDF23_nlo_noLHC_as_0120,101 +234400,NNPDF23_nnlo_noLHC_as_0116,101 +234600,NNPDF23_nnlo_noLHC_as_0117,101 +234800,NNPDF23_nnlo_noLHC_as_0118,101 +235000,NNPDF23_nnlo_noLHC_as_0119,101 +235200,NNPDF23_nnlo_noLHC_as_0120,101 +235400,NNPDF23_nlo_collider_as_0116,101 +235600,NNPDF23_nlo_collider_as_0117,101 +235800,NNPDF23_nlo_collider_as_0118,101 +236000,NNPDF23_nlo_collider_as_0119,101 +236200,NNPDF23_nlo_collider_as_0120,101 +236400,NNPDF23_nnlo_collider_as_0116,101 +236600,NNPDF23_nnlo_collider_as_0117,101 +236800,NNPDF23_nnlo_collider_as_0118,101 +237000,NNPDF23_nnlo_collider_as_0119,101 +237200,NNPDF23_nnlo_collider_as_0120,101 +237400,NNPDF23_nlo_FFN_NF4_as_0116,101 +237600,NNPDF23_nlo_FFN_NF4_as_0117,101 +237800,NNPDF23_nlo_FFN_NF4_as_0118,101 +238000,NNPDF23_nlo_FFN_NF4_as_0119,101 +238200,NNPDF23_nlo_FFN_NF4_as_0120,101 +238400,NNPDF23_nnlo_FFN_NF4_as_0116,101 +238600,NNPDF23_nnlo_FFN_NF4_as_0117,101 +238800,NNPDF23_nnlo_FFN_NF4_as_0118,101 +239000,NNPDF23_nnlo_FFN_NF4_as_0119,101 +239200,NNPDF23_nnlo_FFN_NF4_as_0120,101 +239400,NNPDF23_nlo_FFN_NF5_as_0116,101 +239600,NNPDF23_nlo_FFN_NF5_as_0117,101 +239800,NNPDF23_nlo_FFN_NF5_as_0118,101 +240000,NNPDF23_nlo_FFN_NF5_as_0119,101 +240200,NNPDF23_nlo_FFN_NF5_as_0120,101 +240400,NNPDF23_nnlo_FFN_NF5_as_0116,101 +240600,NNPDF23_nnlo_FFN_NF5_as_0117,101 +240800,NNPDF23_nnlo_FFN_NF5_as_0118,101 +241000,NNPDF23_nnlo_FFN_NF5_as_0119,101 +241200,NNPDF23_nnlo_FFN_NF5_as_0120,101 +241400,NNPDF23_nlo_as_0116_mc,101 +241600,NNPDF23_nlo_as_0117_mc,101 +241800,NNPDF23_nlo_as_0118_mc,101 +242000,NNPDF23_nlo_as_0119_mc,101 +242200,NNPDF23_nlo_as_0120_mc,101 +242400,NNPDF23_nlo_FFN_NF4_as_0116_mc,101 +242600,NNPDF23_nlo_FFN_NF4_as_0117_mc,101 +242800,NNPDF23_nlo_FFN_NF4_as_0118_mc,101 +243000,NNPDF23_nlo_FFN_NF4_as_0119_mc,101 +243200,NNPDF23_nlo_FFN_NF4_as_0120_mc,101 +243400,NNPDF23_nlo_FFN_NF5_as_0116_mc,101 +243600,NNPDF23_nlo_FFN_NF5_as_0117_mc,101 +243800,NNPDF23_nlo_FFN_NF5_as_0118_mc,101 +244000,NNPDF23_nlo_FFN_NF5_as_0119_mc,101 +244200,NNPDF23_nlo_FFN_NF5_as_0120_mc,101 +244400,NNPDF23_nlo_as_0117_qed,101 +244600,NNPDF23_nlo_as_0118_qed,101 +244800,NNPDF23_nlo_as_0119_qed,101 +245000,NNPDF23_nlo_as_0117_qed_neutron,101 +245200,NNPDF23_nlo_as_0118_qed_neutron,101 +245400,NNPDF23_nlo_as_0119_qed_neutron,101 +245600,NNPDF23_nnlo_as_0117_qed,101 +245800,NNPDF23_nnlo_as_0118_qed,101 +246000,NNPDF23_nnlo_as_0119_qed,101 +246200,NNPDF23_nnlo_as_0117_qed_neutron,101 +246400,NNPDF23_nnlo_as_0118_qed_neutron,101 +246600,NNPDF23_nnlo_as_0119_qed_neutron,101 +246800,NNPDF23_lo_as_0119_qed,101 +247000,NNPDF23_lo_as_0130_qed,101 +247200,NNPDF23_nlo_as_0119_qed_mc,101 +247400,NNPDF23_nnlo_as_0119_qed_mc,101 +250000,NNPDFpol10_100,101 +251000,NNPDFpol11_100,101 +260000,NNPDF30_nlo_as_0118,101 +260200,NNPDF30_nlo_as_0118_nf_3,101 +260400,NNPDF30_nlo_as_0118_nf_4,101 +260600,NNPDF30_nlo_as_0118_nf_6,101 +260800,NNPDF30_nlo_as_0118_mc,101 +261000,NNPDF30_nnlo_as_0118,101 +261200,NNPDF30_nnlo_as_0118_nf_3,101 +261400,NNPDF30_nnlo_as_0118_nf_4,101 +261600,NNPDF30_nnlo_as_0118_nf_6,101 +261800,NNPDF30_nnlo_as_0118_mc,101 +262000,NNPDF30_lo_as_0118,101 +262200,NNPDF30_lo_as_0118_nf_3,101 +262400,NNPDF30_lo_as_0118_nf_4,101 +262600,NNPDF30_lo_as_0118_nf_6,101 +263000,NNPDF30_lo_as_0130,101 +263200,NNPDF30_lo_as_0130_nf_3,101 +263400,NNPDF30_lo_as_0130_nf_4,101 +263600,NNPDF30_lo_as_0130_nf_6,101 +264000,NNPDF30_nlo_as_0115,101 +264200,NNPDF30_nlo_as_0115_nf_3,101 +264400,NNPDF30_nlo_as_0115_nf_4,101 +264600,NNPDF30_nlo_as_0115_nf_6,101 +265000,NNPDF30_nlo_as_0117,101 +265200,NNPDF30_nlo_as_0117_nf_3,101 +265400,NNPDF30_nlo_as_0117_nf_4,101 +265600,NNPDF30_nlo_as_0117_nf_6,101 +266000,NNPDF30_nlo_as_0119,101 +266200,NNPDF30_nlo_as_0119_nf_3,101 +266400,NNPDF30_nlo_as_0119_nf_4,101 +266600,NNPDF30_nlo_as_0119_nf_6,101 +267000,NNPDF30_nlo_as_0121,101 +267200,NNPDF30_nlo_as_0121_nf_3,101 +267400,NNPDF30_nlo_as_0121_nf_4,101 +267600,NNPDF30_nlo_as_0121_nf_6,101 +268000,NNPDF30_nnlo_as_0115,101 +268200,NNPDF30_nnlo_as_0115_nf_3,101 +268400,NNPDF30_nnlo_as_0115_nf_4,101 +268600,NNPDF30_nnlo_as_0115_nf_6,101 +269000,NNPDF30_nnlo_as_0117,101 +269200,NNPDF30_nnlo_as_0117_nf_3,101 +269400,NNPDF30_nnlo_as_0117_nf_4,101 +269600,NNPDF30_nnlo_as_0117_nf_6,101 +270000,NNPDF30_nnlo_as_0119,101 +270200,NNPDF30_nnlo_as_0119_nf_3,101 +270400,NNPDF30_nnlo_as_0119_nf_4,101 +270600,NNPDF30_nnlo_as_0119_nf_6,101 +271000,NNPDF30_nnlo_as_0121,101 +271200,NNPDF30_nnlo_as_0121_nf_3,101 +271400,NNPDF30_nnlo_as_0121_nf_4,101 +271600,NNPDF30_nnlo_as_0121_nf_6,101 +272000,NNPDF30_nlo_as_0117_cons,101 +272200,NNPDF30_nlo_as_0118_cons,101 +272400,NNPDF30_nlo_as_0119_cons,101 +273000,NNPDF30_nnlo_as_0117_cons,101 +273200,NNPDF30_nnlo_as_0118_cons,101 +273400,NNPDF30_nnlo_as_0119_cons,101 +274000,NNPDF30_nlo_as_0117_hera,101 +274200,NNPDF30_nlo_as_0118_hera,101 +274400,NNPDF30_nlo_as_0119_hera,101 +275000,NNPDF30_nnlo_as_0117_hera,101 +275200,NNPDF30_nnlo_as_0118_hera,101 +275400,NNPDF30_nnlo_as_0119_hera,101 +280000,NNPDF30_nlo_as_0117_atlas,101 +280200,NNPDF30_nlo_as_0118_atlas,101 +280400,NNPDF30_nlo_as_0119_atlas,101 +281000,NNPDF30_nnlo_as_0117_atlas,101 +281200,NNPDF30_nnlo_as_0118_atlas,101 +281400,NNPDF30_nnlo_as_0119_atlas,101 +282000,NNPDF30_nlo_as_0117_cms,101 +282200,NNPDF30_nlo_as_0118_cms,101 +282400,NNPDF30_nlo_as_0119_cms,101 +283000,NNPDF30_nnlo_as_0117_cms,101 +283200,NNPDF30_nnlo_as_0118_cms,101 +283400,NNPDF30_nnlo_as_0119_cms,101 +284000,NNPDF30_nlo_as_0117_nolhc,101 +284200,NNPDF30_nlo_as_0118_nolhc,101 +284400,NNPDF30_nlo_as_0119_nolhc,101 +285000,NNPDF30_nnlo_as_0117_nolhc,101 +285200,NNPDF30_nnlo_as_0118_nolhc,101 +285400,NNPDF30_nnlo_as_0119_nolhc,101 +288000,NNPDF30_nnlo_as_0118_nolhc_1000,1001 +290000,NNPDF30_nlo_as_0117_nojet,101 +290200,NNPDF30_nlo_as_0118_nojet,101 +290400,NNPDF30_nlo_as_0119_nojet,101 +291000,NNPDF30_nnlo_as_0117_nojet,101 +291200,NNPDF30_nnlo_as_0118_nojet,101 +291400,NNPDF30_nnlo_as_0119_nojet,101 +292000,NNPDF30_nlo_nf_4_pdfas,103 +292200,NNPDF30_nlo_nf_5_pdfas,103 +292400,NNPDF30_nnlo_nf_4_pdfas,103 +292600,NNPDF30_nnlo_nf_5_pdfas,103 +293000,NNPDF30_nlo_as_0118_1000,1001 +295000,NNPDF30_nnlo_as_0118_1000,1001 +297000,NNPDF30_nlo_as_0118_hera_1000,1001 +299000,NNPDF30_nnlo_as_0118_hera_1000,1001 +301000,NNPDF30_nlo_as_0118_nolhc_1000,1001 +303000,NNPDF30_nlo_as_0118_hessian,101 +303200,NNPDF30_nnlo_as_0118_hessian,101 +303400,NNPDF31_nlo_as_0118,101 +303600,NNPDF31_nnlo_as_0118,101 +303800,NNPDF31_nlo_pch_as_0118,101 +304000,NNPDF31_nnlo_pch_as_0118,101 +304200,NNPDF31_nlo_as_0118_hessian,101 +304400,NNPDF31_nnlo_as_0118_hessian,101 +304600,NNPDF31_nlo_pch_as_0118_hessian,101 +304800,NNPDF31_nnlo_pch_as_0118_hessian,101 +305000,NNPDF31_nlo_pdfas,103 +305200,NNPDF31_nnlo_pdfas,103 +305400,NNPDF31_nlo_pch_pdfas,103 +305600,NNPDF31_nnlo_pch_pdfas,103 +305800,NNPDF31_nlo_hessian_pdfas,103 +306000,NNPDF31_nnlo_hessian_pdfas,103 +306200,NNPDF31_nlo_pch_hessian_pdfas,103 +306400,NNPDF31_nnlo_pch_hessian_pdfas,103 +307000,NNPDF31_nlo_as_0118_1000,1001 +309000,NNPDF31_nnlo_as_0118_1000,1001 +311000,NNPDF31_nlo_pch_as_0118_1000,1001 +313000,NNPDF31_nnlo_pch_as_0118_1000,1001 +315000,NNPDF31_lo_as_0118,101 +315200,NNPDF31_lo_as_0130,101 +315400,NNPDF31_lo_pch_as_0118,101 +315600,NNPDF31_lo_pch_as_0130,101 +315800,NNPDF31_nlo_as_0118_mc,101 +316000,NNPDF31_nlo_pch_as_0118_mc,101 +316200,NNPDF31_nnlo_as_0118_mc,101 +316400,NNPDF31_nnlo_pch_as_0118_mc,101 +316600,NNPDF31_nlo_as_0118_C1p6,11 +316700,NNPDF31_nnlo_as_0118_collider,101 +316900,NNPDF31_nnlo_as_0118_proton,101 +317100,NNPDF31_nnlo_as_0118_noZpt,101 +317300,NNPDF31_nnlo_as_0118_notop,101 +317500,NNPDF31_nnlo_as_0118_nojets,101 +317700,NNPDF31_nnlo_as_0118_noLHC,101 +317900,NNPDF31_nnlo_as_0118_wEMC,101 +318100,NNPDF31_nnlo_as_0118_mc_138,101 +318300,NNPDF31_nnlo_as_0118_mc_164,101 +318500,NNPDF31_nnlo_pch_as_0118_mc_138,101 +318700,NNPDF31_nnlo_pch_as_0118_mc_164,101 +318900,NNPDF31_nlo_as_0116,101 +319100,NNPDF31_nlo_as_0120,101 +319300,NNPDF31_nnlo_as_0116,101 +319500,NNPDF31_nnlo_as_0120,101 +319700,NNPDF31_nlo_pch_as_0116,101 +319900,NNPDF31_nlo_pch_as_0120,101 +320100,NNPDF31_nnlo_pch_as_0116,101 +320300,NNPDF31_nnlo_pch_as_0120,101 +320500,NNPDF31_nlo_as_0118_nf_4,101 +320700,NNPDF31_nlo_as_0118_nf_6,101 +320900,NNPDF31_nnlo_as_0118_nf_4,101 +321100,NNPDF31_nnlo_as_0118_nf_6,101 +321300,NNPDF31_nlo_pch_as_0118_nf_3,101 +321500,NNPDF31_nlo_pch_as_0118_nf_4,101 +321700,NNPDF31_nlo_pch_as_0118_nf_6,101 +321900,NNPDF31_nnlo_pch_as_0118_nf_3,101 +322100,NNPDF31_nnlo_pch_as_0118_nf_4,101 +322300,NNPDF31_nnlo_pch_as_0118_nf_6,101 +322500,NNPDF31_nnlo_as_0108,101 +322700,NNPDF31_nnlo_as_0110,101 +322900,NNPDF31_nnlo_as_0112,101 +323100,NNPDF31_nnlo_as_0114,101 +323300,NNPDF31_nnlo_as_0117,101 +323500,NNPDF31_nnlo_as_0119,101 +323700,NNPDF31_nnlo_as_0122,101 +323900,NNPDF31_nnlo_as_0124,101 +324100,NNPDF31_nnlo_as_0118_CMSW1,101 +324300,NNPDF31_nnlo_as_0118_CMSW2,101 +324500,NNPDF31_nnlo_as_0118_CMSW3,101 +324700,NNPDF31_nnlo_as_0118_CMSW4,101 +324900,NNPDF31_nlo_as_0118_luxqed,101 +325100,NNPDF31_nnlo_as_0118_luxqed,101 +325300,NNPDF31_nnlo_as_0118_mc_hessian_pdfas,103 +325500,NNPDF31_nnlo_as_0118_nf_4_mc_hessian,101 +325700,NNPDF31_nnlo_as_0118_CMSW1_hessian_100,101 +325900,NNPDF31_nnlo_as_0118_CMSW2_hessian_100,101 +326100,NNPDF31_nnlo_as_0118_CMSW3_hessian_100,101 +326300,NNPDF31_nnlo_as_0118_CMSW4_hessian_100,101 +330000,NNPDF40_nnlo_as_01180_1000,1001 +331100,NNPDF40_nnlo_as_01180,101 +331300,NNPDF40_nnlo_pdfas,103 +331500,NNPDF40_nnlo_as_01180_hessian,51 +331600,NNPDF40_nnlo_hessian_pdfas,53 +331700,NNPDF40_nlo_as_01180,101 +331900,NNPDF40_lo_as_01180,101 +332100,NNPDF40_nnlo_pch_as_01180,101 +332300,NNPDF40_nlo_pch_as_01180,101 +332500,NNPDF40_lo_pch_as_01180,101 +332700,NNPDF40_nnlo_as_01160,101 +332900,NNPDF40_nnlo_as_01170,101 +333100,NNPDF40_nnlo_as_01175,101 +333300,NNPDF40_nnlo_as_01185,101 +333500,NNPDF40_nnlo_as_01190,101 +333700,NNPDF40_nnlo_as_01200,101 +333900,NNPDF40_nlo_as_01170,101 +334100,NNPDF40_nlo_as_01190,101 +334300,NNPDF40_nnlo_as_01180_nf_4,101 +334500,NNPDF40_nnlo_as_01180_nf_6,101 +334700,NNPDF40_nlo_as_01180_nf_4,101 +334900,NNPDF40_nlo_as_01180_nf_6,101 +335100,NNPDF40_nnlo_pch_as_01180_nf_3,101 +335300,NNPDF40_nlo_pch_as_01180_nf_3,101 +335500,NNPDF40_nnlo_nf_4_pdfas,103 +335700,NNPDF40_nlo_nf_4_pdfas,103 +500000,CT14MC1nlo,1001 +502000,CT14MC2nlo,1001 +504000,CT14MC1nnlo,1001 +506000,CT14MC2nnlo,1001 +900000,EPPS16nlo_CT14nlo_He4,97 +900100,EPPS16nlo_CT14nlo_Li6,97 +900200,EPPS16nlo_CT14nlo_Be9,97 +900300,EPPS16nlo_CT14nlo_C12,97 +900400,EPPS16nlo_CT14nlo_Al27,97 +900500,EPPS16nlo_CT14nlo_Ca40,97 +900600,EPPS16nlo_CT14nlo_Fe56,97 +900700,EPPS16nlo_CT14nlo_Cu64,97 +900800,EPPS16nlo_CT14nlo_Ag108,97 +900900,EPPS16nlo_CT14nlo_Sn119,97 +901000,EPPS16nlo_CT14nlo_W184,97 +901100,EPPS16nlo_CT14nlo_Pt195,97 +901200,EPPS16nlo_CT14nlo_Au197,97 +901300,EPPS16nlo_CT14nlo_Pb208,97 +902000,EPPS21nlo_CT18Anlo_He3,107 +902150,EPPS21nlo_CT18Anlo_He4,107 +902300,EPPS21nlo_CT18Anlo_Li6,107 +902450,EPPS21nlo_CT18Anlo_Be9,107 +902600,EPPS21nlo_CT18Anlo_C12,107 +902750,EPPS21nlo_CT18Anlo_O16,107 +902900,EPPS21nlo_CT18Anlo_Al27,107 +903050,EPPS21nlo_CT18Anlo_Ca40,107 +903200,EPPS21nlo_CT18Anlo_Ar40,107 +903350,EPPS21nlo_CT18Anlo_Fe56,107 +903500,EPPS21nlo_CT18Anlo_Cu64,107 +903650,EPPS21nlo_CT18Anlo_Ag108,107 +903800,EPPS21nlo_CT18Anlo_Sn119,107 +903950,EPPS21nlo_CT18Anlo_W184,107 +904100,EPPS21nlo_CT18Anlo_Pt195,107 +904250,EPPS21nlo_CT18Anlo_Au197,107 +904400,EPPS21nlo_CT18Anlo_Pb208,107 +950000,JAM19PDF_proton_nlo,582 +951500,JAM20-SIDIS_PDF_proton_nlo,196 +2000000,NNFF10_PIm_lo,101 +2000200,NNFF10_PIp_lo,101 +2000400,NNFF10_PIsum_lo,101 +2000600,NNFF10_PIm_nlo,101 +2000800,NNFF10_PIp_nlo,101 +2001000,NNFF10_PIsum_nlo,101 +2001200,NNFF10_PIm_nnlo,101 +2001400,NNFF10_PIp_nnlo,101 +2001600,NNFF10_PIsum_nnlo,101 +2001800,NNFF10_KAm_lo,101 +2002000,NNFF10_KAp_lo,101 +2002200,NNFF10_KAsum_lo,101 +2002400,NNFF10_KAm_nlo,101 +2002600,NNFF10_KAp_nlo,101 +2002800,NNFF10_KAsum_nlo,101 +2003000,NNFF10_KAm_nnlo,101 +2003200,NNFF10_KAp_nnlo,101 +2003400,NNFF10_KAsum_nnlo,101 +2003600,NNFF10_PRm_lo,101 +2003800,NNFF10_PRp_lo,101 +2004000,NNFF10_PRsum_lo,101 +2004200,NNFF10_PRm_nlo,101 +2004400,NNFF10_PRp_nlo,101 +2004600,NNFF10_PRsum_nlo,101 +2004800,NNFF10_PRm_nnlo,101 +2005000,NNFF10_PRp_nnlo,101 +2005200,NNFF10_PRsum_nnlo,101 +2006000,NNFF11_HadronSum_nlo,101 +2020000,MAPFF10NLOPIp,201 +2020250,MAPFF10NLOPIm,201 +2020500,MAPFF10NLOPIsum,201 +2021000,MAPFF10NNLOPIp,201 +2021250,MAPFF10NNLOPIm,201 +2021500,MAPFF10NNLOPIsum,201 +2022000,MAPFF10NLOKAp,201 +2022250,MAPFF10NLOKAm,201 +2022500,MAPFF10NLOKAsum,201 +2023000,MAPFF10NNLOKAp,201 +2023250,MAPFF10NNLOKAm,201 +2023500,MAPFF10NNLOKAsum,201 +2050000,JAM19FF_pion_nlo,582 +2051000,JAM19FF_kaon_nlo,582 +2052000,JAM20-SIDIS_FF_pion_nlo,196 +2052250,JAM20-SIDIS_FF_kaon_nlo,196 +2052500,JAM20-SIDIS_FF_hadron_nlo,196 +2060000,CGMP_B-hadron_NNLO_as_0118,100 +2060100,CGMP_B-hadron_to_Jpsi_NNLO_as_0118,100 +2060200,CGMP_B-hadron_to_muon_NNLO_as_0118,100 +3000000,nNNPDF10_nlo_as_0118_N1,251 +3000300,nNNPDF10_nlo_as_0118_D2,251 +3000600,nNNPDF10_nlo_as_0118_He4,251 +3000900,nNNPDF10_nlo_as_0118_Li6,251 +3001200,nNNPDF10_nlo_as_0118_Be9,251 +3001500,nNNPDF10_nlo_as_0118_C12,251 +3001800,nNNPDF10_nlo_as_0118_N14,251 +3002100,nNNPDF10_nlo_as_0118_Al27,251 +3002400,nNNPDF10_nlo_as_0118_Ca40,251 +3002700,nNNPDF10_nlo_as_0118_Fe56,251 +3003000,nNNPDF10_nlo_as_0118_Cu64,251 +3003300,nNNPDF10_nlo_as_0118_Ag108,251 +3003600,nNNPDF10_nlo_as_0118_Sn119,251 +3003900,nNNPDF10_nlo_as_0118_Xe131,251 +3004200,nNNPDF10_nlo_as_0118_Au197,251 +3004500,nNNPDF10_nlo_as_0118_Pb208,251 +3100000,nNNPDF10_nnlo_as_0118_N1,251 +3100300,nNNPDF10_nnlo_as_0118_D2,251 +3100600,nNNPDF10_nnlo_as_0118_He4,251 +3100900,nNNPDF10_nnlo_as_0118_Li6,251 +3101200,nNNPDF10_nnlo_as_0118_Be9,251 +3101500,nNNPDF10_nnlo_as_0118_C12,251 +3101800,nNNPDF10_nnlo_as_0118_N14,251 +3102100,nNNPDF10_nnlo_as_0118_Al27,251 +3102400,nNNPDF10_nnlo_as_0118_Ca40,251 +3102700,nNNPDF10_nnlo_as_0118_Fe56,251 +3103000,nNNPDF10_nnlo_as_0118_Cu64,251 +3103300,nNNPDF10_nnlo_as_0118_Ag108,251 +3103600,nNNPDF10_nnlo_as_0118_Sn119,251 +3103900,nNNPDF10_nnlo_as_0118_Xe131,251 +3104200,nNNPDF10_nnlo_as_0118_Au197,251 +3104500,nNNPDF10_nnlo_as_0118_Pb208,251 +3200000,TUJU19_nlo_1_1,27 +3200100,TUJU19_nlo_2_1,59 +3200200,TUJU19_nlo_3_2,59 +3200300,TUJU19_nlo_4_2,59 +3200400,TUJU19_nlo_7_3,59 +3200500,TUJU19_nlo_12_6,59 +3200600,TUJU19_nlo_27_13,59 +3200700,TUJU19_nlo_40_20,59 +3200800,TUJU19_nlo_56_26,59 +3200900,TUJU19_nlo_64_29,59 +3201000,TUJU19_nlo_131_54,59 +3201100,TUJU19_nlo_197_79,59 +3201200,TUJU19_nlo_208_82,59 +3201300,TUJU19_nlo_119_50,59 +3205000,TUJU19_nnlo_1_1,27 +3205100,TUJU19_nnlo_2_1,59 +3205200,TUJU19_nnlo_3_2,59 +3205300,TUJU19_nnlo_4_2,59 +3205400,TUJU19_nnlo_7_3,59 +3205500,TUJU19_nnlo_12_6,59 +3205600,TUJU19_nnlo_27_13,59 +3205700,TUJU19_nnlo_40_20,59 +3205800,TUJU19_nnlo_56_26,59 +3205900,TUJU19_nnlo_64_29,59 +3206000,TUJU19_nnlo_131_54,59 +3206100,TUJU19_nnlo_197_79,59 +3206200,TUJU19_nnlo_208_82,59 +3206300,TUJU19_nnlo_119_50,59 +3210000,TUJU21_nlo_1_1,27 +3210100,TUJU21_nlo_2_1,59 +3210300,TUJU21_nlo_4_2,59 +3210500,TUJU21_nlo_12_6,59 +3210600,TUJU21_nlo_14_7,59 +3210700,TUJU21_nlo_16_8,59 +3210900,TUJU21_nlo_27_13,59 +3211000,TUJU21_nlo_56_26,59 +3211200,TUJU21_nlo_131_54,59 +3211400,TUJU21_nlo_197_79,59 +3211600,TUJU21_nlo_208_82,59 +3215000,TUJU21_nnlo_1_1,27 +3215100,TUJU21_nnlo_2_1,59 +3215300,TUJU21_nnlo_4_2,59 +3215500,TUJU21_nnlo_12_6,59 +3215600,TUJU21_nnlo_14_7,59 +3215700,TUJU21_nnlo_16_8,59 +3215900,TUJU21_nnlo_27_13,59 +3216000,TUJU21_nnlo_56_26,59 +3216200,TUJU21_nnlo_131_54,59 +3216400,TUJU21_nnlo_197_79,59 +3216600,TUJU21_nnlo_208_82,59 +30010000,nNNPDF20_nlo_as_0118_N1,250 +30010300,nNNPDF20_nlo_as_0118_D2,250 +30010600,nNNPDF20_nlo_as_0118_He4,250 +30010900,nNNPDF20_nlo_as_0118_Li6,250 +30011200,nNNPDF20_nlo_as_0118_Be9,250 +30011500,nNNPDF20_nlo_as_0118_C12,250 +30011800,nNNPDF20_nlo_as_0118_N14,250 +30012100,nNNPDF20_nlo_as_0118_Al27,250 +30012400,nNNPDF20_nlo_as_0118_Ca40,250 +30012700,nNNPDF20_nlo_as_0118_Fe56,250 +30013000,nNNPDF20_nlo_as_0118_Cu64,250 +30013300,nNNPDF20_nlo_as_0118_Ag108,250 +30013600,nNNPDF20_nlo_as_0118_Sn119,250 +30013900,nNNPDF20_nlo_as_0118_Xe131,250 +30014200,nNNPDF20_nlo_as_0118_Au197,250 +30014500,nNNPDF20_nlo_as_0118_Pb208,250 +30014800,nNNPDF20_nlo_as_0118_O16,250 +30015100,nNNPDF20_nlo_as_0118_W184,250 +30020000,nNNPDF30_nlo_as_0118_p,201 +30020300,nNNPDF30_nlo_as_0118_A2_Z1,201 +30020600,nNNPDF30_nlo_as_0118_A4_Z2,201 +30020900,nNNPDF30_nlo_as_0118_A6_Z3,201 +30021200,nNNPDF30_nlo_as_0118_A9_Z4,201 +30021500,nNNPDF30_nlo_as_0118_A12_Z6,201 +30021800,nNNPDF30_nlo_as_0118_A14_Z7,201 +30022100,nNNPDF30_nlo_as_0118_A16_Z8,201 +30022400,nNNPDF30_nlo_as_0118_A27_Z13,201 +30022700,nNNPDF30_nlo_as_0118_A31_Z15,201 +30023000,nNNPDF30_nlo_as_0118_A40_Z20,201 +30023300,nNNPDF30_nlo_as_0118_A56_Z26,201 +30023600,nNNPDF30_nlo_as_0118_A64_Z29,201 +30023900,nNNPDF30_nlo_as_0118_A108_Z54,201 +30024200,nNNPDF30_nlo_as_0118_A119_Z59,201 +30024500,nNNPDF30_nlo_as_0118_A131_Z54,201 +30024800,nNNPDF30_nlo_as_0118_A184_Z74,201 +30025100,nNNPDF30_nlo_as_0118_A197_Z79,201 +30025400,nNNPDF30_nlo_as_0118_A208_Z82,201 +30100000,nCTEQ15_Jpsi_c_90CL_Pb_hess,17 +30100025,nCTEQ15_Jpsi_u_90CL_Pb_hess,17 +30100050,nCTEQ15_Jpsi_d_90CL_Pb_hess,17 +30100075,nCTEQ15_Jpsi_90CL_Pb_hess,17 +30100100,nCTEQ15_D_c_90CL_Pb_hess,17 +30100125,nCTEQ15_D_u_90CL_Pb_hess,17 +30100150,nCTEQ15_D_d_90CL_Pb_hess,17 +30100175,nCTEQ15_D_90CL_Pb_hess,17 +30100200,nCTEQ15_B_c_90CL_Pb_hess,17 +30100225,nCTEQ15_B_u_90CL_Pb_hess,17 +30100250,nCTEQ15_B_d_90CL_Pb_hess,17 +30100275,nCTEQ15_B_90CL_Pb_hess,17 +30100300,nCTEQ15_Jpsi_c_90CL_Au_hess,17 +30100325,nCTEQ15_Jpsi_d_90CL_Au_hess,17 +30100350,nCTEQ15_Jpsi_u_90CL_Au_hess,17 +30100375,nCTEQ15_Jpsi_90CL_Au_hess,17 +30100400,nCTEQ15_D_c_90CL_Au_hess,17 +30100425,nCTEQ15_D_u_90CL_Au_hess,17 +30100450,nCTEQ15_D_d_90CL_Au_hess,17 +30100475,nCTEQ15_D_90CL_Au_hess,17 +30100500,nCTEQ15_B_c_90CL_Au_hess,17 +30100525,nCTEQ15_B_u_90CL_Au_hess,17 +30100550,nCTEQ15_B_d_90CL_Au_hess,17 +30100575,nCTEQ15_B_90CL_Au_hess,17 +30100600,EPPS16_Jpsi_c_90CL_Pb_hess,21 +30100625,EPPS16_Jpsi_u_90CL_Pb_hess,21 +30100650,EPPS16_Jpsi_d_90CL_Pb_hess,21 +30100675,EPPS16_Jpsi_90CL_Pb_hess,21 +30100700,EPPS16_D_c_90CL_Pb_hess,21 +30100725,EPPS16_D_u_90CL_Pb_hess,21 +30100750,EPPS16_D_d_90CL_Pb_hess,21 +30100775,EPPS16_D_90CL_Pb_hess,21 +30100800,EPPS16_B_c_90CL_Pb_hess,21 +30100825,EPPS16_B_u_90CL_Pb_hess,21 +30100850,EPPS16_B_d_90CL_Pb_hess,21 +30100875,EPPS16_B_90CL_Pb_hess,21 +30100900,EPPS16_Jpsi_c_90CL_Au_hess,21 +30100925,EPPS16_Jpsi_u_90CL_Au_hess,21 +30100950,EPPS16_Jpsi_d_90CL_Au_hess,21 +30100975,EPPS16_Jpsi_90CL_Au_hess,21 +30101000,EPPS16_D_c_90CL_Au_hess,21 +30101025,EPPS16_D_u_90CL_Au_hess,21 +30101050,EPPS16_D_d_90CL_Au_hess,21 +30101075,EPPS16_D_90CL_Au_hess,21 +30101100,EPPS16_B_c_90CL_Au_hess,21 +30101125,EPPS16_B_u_90CL_Au_hess,21 +30101150,EPPS16_B_d_90CL_Au_hess,21 +30101175,EPPS16_B_90CL_Au_hess,21 +40000000,NNSFnu_D_lowQ,201 +40000300,NNSFnu_D_highQ,210 +40000600,NNSFnu_He_lowQ,201 +40000900,NNSFnu_He_highQ,210 +40001200,NNSFnu_Li_lowQ,201 +40001500,NNSFnu_Li_highQ,210 +40001800,NNSFnu_Be_lowQ,201 +40002100,NNSFnu_Be_highQ,210 +40002400,NNSFnu_C_lowQ,201 +40002700,NNSFnu_C_highQ,210 +40003000,NNSFnu_N_lowQ,201 +40003300,NNSFnu_N_highQ,210 +40003600,NNSFnu_O_lowQ,201 +40003900,NNSFnu_O_highQ,210 +40004200,NNSFnu_Al_lowQ,201 +40004500,NNSFnu_Al_highQ,210 +40004800,NNSFnu_Ea_lowQ,201 +40005100,NNSFnu_Ea_highQ,210 +40005400,NNSFnu_Ca_lowQ,201 +40005700,NNSFnu_Ca_highQ,210 +40006000,NNSFnu_Fe_lowQ,201 +40006300,NNSFnu_Fe_highQ,210 +40006600,NNSFnu_Cu_lowQ,201 +40006900,NNSFnu_Cu_highQ,210 +40007200,NNSFnu_Ag_lowQ,201 +40007500,NNSFnu_Ag_highQ,210 +40007800,NNSFnu_Sn_lowQ,201 +40008100,NNSFnu_Sn_highQ,210 +40008400,NNSFnu_Xe_lowQ,201 +40008700,NNSFnu_Xe_highQ,210 +40009000,NNSFnu_W_lowQ,201 +40009300,NNSFnu_W_highQ,210 +40009600,NNSFnu_Au_lowQ,201 +40009900,NNSFnu_Au_highQ,210 +40010200,NNSFnu_Pb_lowQ,201 +40010500,NNSFnu_Pb_highQ,210 +40010800,NNSFnu_Ar_lowQ,201 +40011100,NNSFnu_Ar_highQ,210 From e2bd263e9dcc636889ba6c603876ffc79661b288 Mon Sep 17 00:00:00 2001 From: "Jack Y. Araz" <jackaraz@gmail.com> Date: Mon, 17 Jul 2023 11:48:57 +0100 Subject: [PATCH 053/107] create dataset for weight collection --- .../configuration/weight_configuration.py | 25 ++++++++++++++++--- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/madanalysis/configuration/weight_configuration.py b/madanalysis/configuration/weight_configuration.py index add4f6ae..9bc86c5f 100644 --- a/madanalysis/configuration/weight_configuration.py +++ b/madanalysis/configuration/weight_configuration.py @@ -118,15 +118,15 @@ def __init__(self, collection: List[Weight] = None): self._collection = [] if collection is None else collection self._names = [] - def append(self, name: Text, idx: int): + def append(self, name: Text, idx: int) -> None: """Add weight into the collection""" if name not in self.names: self._collection.append(Weight(name=name, loc=idx)) - def __iter__(self): + def __iter__(self) -> Weight: yield from self._collection - def __len__(self): + def __len__(self) -> int: return len(self._collection) @property @@ -155,7 +155,7 @@ def nominal(self) -> Weight: return w raise ValueError("Can not find nominal weight") - def group_for(self, group: Text): + def group_for(self, group: Text) -> Dict: """Create a group""" assert group in ["muf", "mur", "pdfset", "dynamic_scale"] @@ -177,6 +177,23 @@ def pdfset(self, pdfid: int) -> List[Weight]: """retreive weights corresponding to one pdf set""" return WeightCollection([w for w in self if w.pdfset == pdfid]) + def get(self, **kwargs) -> List[Weight]: + if len(kwargs) == 0: + return [] + collection = [] + keys = ["muf", "mur", "dynamic_scale", "pdfset", "merging"] + + for weight in self: + add = True + for key in (key for key in keys if key in kwargs): + if getattr(weight, key) != kwargs.get(key): + add = False + break + if add: + collection.append(weight) + + return WeightCollection(collection) + @property def pdfsets(self) -> List[int]: """Retreive a list of pdfsets""" From 82d7a02f9f4d7653eb39696c1d828ccb1cbe7669 Mon Sep 17 00:00:00 2001 From: "Jack Y. Araz" <jackaraz@gmail.com> Date: Mon, 17 Jul 2023 22:37:48 +0100 Subject: [PATCH 054/107] additional features --- .../configuration/weight_configuration.py | 104 +++++++++++++++++- 1 file changed, 102 insertions(+), 2 deletions(-) diff --git a/madanalysis/configuration/weight_configuration.py b/madanalysis/configuration/weight_configuration.py index 9bc86c5f..61531d61 100644 --- a/madanalysis/configuration/weight_configuration.py +++ b/madanalysis/configuration/weight_configuration.py @@ -22,7 +22,7 @@ ################################################################################ -from typing import Text, List, Dict, Any +from typing import Text, List, Dict, Any, Tuple from dataclasses import dataclass, field import numpy as np @@ -41,6 +41,7 @@ class Weight: _merging: float = field(init=False, default=None) def __post_init__(self) -> None: + self.name = self.name.replace("DYN_SCALE", "DYNSCALE") sectors = self.name.split("_") for sector in sectors: @@ -49,7 +50,7 @@ def __post_init__(self) -> None: break if "MERGING" in sector: self._merging = float(sector.split("=")[1]) - elif "DYN_SCALE" in sector: + elif "DYNSCALE" in sector: self._dyn_scale = int(sector.split("=")[1]) elif "MUF" in sector: self._muf = float(sector.split("=")[1]) @@ -58,6 +59,16 @@ def __post_init__(self) -> None: elif "PDF" in sector: self._pdf = int(sector.split("=")[1]) + def __repr__(self) -> Text: + return ( + f"Weight(loc={self.loc}, pdf={self.pdfset}, " + + f"muf={self.muf}, mur={self.mur}, dynamic={self.dynamic_scale}, " + + f"merging={self.merging}, aux={self.aux})" + ) + + def __str__(self) -> Text: + return self.__repr__() + def to_dict(self) -> Dict[Text, Any]: """Convert to dictionary""" return {"loc": self.loc, "name": self.name} @@ -123,6 +134,15 @@ def append(self, name: Text, idx: int) -> None: if name not in self.names: self._collection.append(Weight(name=name, loc=idx)) + def __repr__(self) -> Text: + # if len(self) < 5: + return "WeightCollection(" + ",".join([str(x) for x in self]) + ")" + + # return f"WeightCollection(contains {len(self)} weight definitions)" + + def __str__(self) -> Text: + return self.__repr__() + def __iter__(self) -> Weight: yield from self._collection @@ -198,3 +218,83 @@ def get(self, **kwargs) -> List[Weight]: def pdfsets(self) -> List[int]: """Retreive a list of pdfsets""" return np.unique([w.pdfset for w in self if w.pdfset is not None]).tolist() + + @property + def scales(self) -> Dict[Text, List[float]]: + """return scale for muf and mur""" + muf = np.unique([w.muf for w in self if w.muf is not None]).tolist() + muf.sort() + mur = np.unique([w.mur for w in self if w.mur is not None]).tolist() + mur.sort() + return {"muf": muf, "mur": mur} + + @property + def has_scale(self) -> bool: + """is there any scale variations""" + return len(self.scales["muf"]) > 0 + + @property + def central_scale(self) -> float: + """retreive central scale""" + scales = self.scales["muf"] + return scales[len(scales) // 2] + + def get_scale_vars(self, point: int = 3, dynamic: int = None) -> Tuple: + if dynamic is not None: + dynamic = dynamic if self.has_dyn_scale(dynamic) else None + + scales = self.scales["muf"] + if len(scales) == 5 and point == 3: + scales = scales[1:-1] + elif len(scales) == 7: + if point == 3: + scales = scales[2:-2] + if point == 5: + scales = scales[1:-1] + elif len(scales) == 9: + if point == 3: + scales = scales[3:-3] + elif point == 5: + scales = scales[2:-2] + elif point == 7: + scales = scales[1:-1] + + min_scale = min(scales) + max_scale = max(scales) + + return ( + self.get_scale(dynamic=dynamic, muf=min_scale, mur=min_scale), + self.get_scale(dynamic=dynamic, muf=max_scale, mur=max_scale), + ) + + def get_scale( + self, dynamic: int = None, muf: float = 1.0, mur: float = 1.0 + ) -> List[Weight]: + if dynamic is not None: + dynamic = dynamic if self.has_dyn_scale(dynamic) else None + return WeightCollection( + [ + w + for w in self + if w.dynamic_scale == dynamic and w.muf == muf and w.mur == mur + ] + ) + + def has_dyn_scale(self, scale: int) -> bool: + """If weight collection has a particular dynamic scale""" + assert scale in [1, 2, 3, 4], "invalid dynamic scale" + for w in self: + if w.dynamic_scale == scale: + return True + return False + + @property + def loc(self) -> List[int]: + """retreive the locations of the weights""" + return [w.loc for w in self] + + def __iadd__(self, other): + assert isinstance(other, WeightCollection) + for items in other: + self._collection.append(items) + return self From 0ea58746884a98c2f7e1db96abb32209cb41cf5e Mon Sep 17 00:00:00 2001 From: "Jack Y. Araz" <jackaraz@gmail.com> Date: Mon, 17 Jul 2023 22:38:02 +0100 Subject: [PATCH 055/107] bugfix --- madanalysis/dataset/dataset_collection.py | 107 ++++++++++------------ 1 file changed, 50 insertions(+), 57 deletions(-) diff --git a/madanalysis/dataset/dataset_collection.py b/madanalysis/dataset/dataset_collection.py index 3f680371..cfc83a6d 100644 --- a/madanalysis/dataset/dataset_collection.py +++ b/madanalysis/dataset/dataset_collection.py @@ -1,24 +1,24 @@ ################################################################################ -# +# # Copyright (C) 2012-2023 Jack Araz, Eric Conte & Benjamin Fuks # The MadAnalysis development team, email: <ma5team@iphc.cnrs.fr> -# +# # This file is part of MadAnalysis 5. # Official website: <https://github.com/MadAnalysis/madanalysis5> -# +# # MadAnalysis 5 is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. -# +# # MadAnalysis 5 is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. -# +# # You should have received a copy of the GNU General Public License # along with MadAnalysis 5. If not, see <http://www.gnu.org/licenses/> -# +# ################################################################################ @@ -28,24 +28,26 @@ import madanalysis.dataset.dataset as Dataset import six -class DatasetCollection: +class DatasetCollection: def __init__(self): self.table = [] def __len__(self): return len(self.table) - def __getitem__(self,i): + def __getitem__(self, i): return self.table[i][1] def Display(self): - logging.getLogger('MA5').info(" ********* List of defined datasets *********" ) + logging.getLogger("MA5").info(" ********* List of defined datasets *********") for value in self.table: - logging.getLogger('MA5').info(" "+value[0]+" ("+value[1].GetStringTag()+")") - logging.getLogger('MA5').info(" ********************************************" ) + logging.getLogger("MA5").info( + " " + value[0] + " (" + value[1].GetStringTag() + ")" + ) + logging.getLogger("MA5").info(" ********************************************") - def Find(self,name): + def Find(self, name): name.lower() for item in self.table: if name == item[0]: @@ -54,58 +56,54 @@ def Find(self,name): def Reset(self): self.table = [] - - def Add(self,name): + + def Add(self, name): name.lower() if not self.Find(name): - self.table.append([name,Dataset.Dataset(name)]) + self.table.append([name, Dataset.Dataset(name)]) - def Get(self,name): + def Get(self, name): name.lower() for item in self.table: if name == item[0]: return item[1] return None - def Remove(self,name): + def Remove(self, name): name.lower() if self.Find(name): newtable = [] for item in self.table: if name != item[0]: newtable.append(item) - self.table = newtable - - def Reset(self): - self.table = [] + self.table = newtable def GetNames(self): - names=[] + names = [] for item in self.table: names.append(item[0]) return names - - def LoadWithSAF(self,ast): + def LoadWithSAF(self, ast): # Reseting the multiparticle collection self.Reset() - + # Getting datasets branches - datasets = ast.GetBranch("datasets",1) - if datasets==None: + datasets = ast.GetBranch("datasets", 1) + if datasets == None: return # Looping over the branches of the tree for key, value in six.iteritems(datasets.GetBranches()): # Keeping only 'dataset' branches - if key[0]!='dataset': + if key[0] != "dataset": continue # Getting the name of the dataset (if it exists) - name = value.GetParameterToStringWithoutQuotes('name') - if name==None: - logging.getLogger('MA5').error('dataset name is not found in the tree') + name = value.GetParameterToStringWithoutQuotes("name") + if name == None: + logging.getLogger("MA5").error("dataset name is not found in the tree") continue # Creating a new dataset @@ -113,53 +111,48 @@ def LoadWithSAF(self,ast): dataset = self.Get(name) # Getting physics parameters - physics = value.GetBranch('physics',1) - if physics==None: + physics = value.GetBranch("physics", 1) + if physics == None: print("ERROR: no physics branch") continue else: background = physics.GetParameterToBool("background") - dataset.background = dataset.background if background==None else background - + dataset.background = ( + dataset.background if background == None else background + ) + weight = physics.GetParameterToFloat("weight") - dataset.weight = dataset.weight if weight==None else weight - + dataset.weight = dataset.weight if weight == None else weight + xsection = physics.GetParameterToFloat("xsection") - dataset.xsection = dataset.xsection if xsection==None else xsection + dataset.xsection = dataset.xsection if xsection == None else xsection # Getting layout parameters - layout = value.GetBranch('layout',1) - if layout==None: + layout = value.GetBranch("layout", 1) + if layout == None: print("ERROR: no layout branch") continue else: title = layout.GetParameterToStringWithoutQuotes("title") - dataset.title = dataset.title if title==None else title + dataset.title = dataset.title if title == None else title linecolor = layout.GetParameterToUInt("linecolor") - dataset.linecolor = dataset.linecolor if linecolor==None else linecolor - + dataset.linecolor = dataset.linecolor if linecolor == None else linecolor + linestyle = layout.GetParameterToUInt("linestyle") - dataset.linestyle = dataset.linestyle if linestyle==None else linestyle + dataset.linestyle = dataset.linestyle if linestyle == None else linestyle lineshade = layout.GetParameterToUInt("lineshade") - dataset.lineshade = dataset.lineshade if lineshade==None else lineshade + dataset.lineshade = dataset.lineshade if lineshade == None else lineshade linewidth = layout.GetParameterToUInt("linewidth") - dataset.linewidth = dataset.linewidth if linewidth==None else linewidth + dataset.linewidth = dataset.linewidth if linewidth == None else linewidth backcolor = layout.GetParameterToUInt("backcolor") - dataset.backcolor = dataset.backcolor if backcolor==None else backcolor - + dataset.backcolor = dataset.backcolor if backcolor == None else backcolor + backstyle = layout.GetParameterToUInt("backstyle") - dataset.backstyle = dataset.backstyle if backstyle==None else backstyle + dataset.backstyle = dataset.backstyle if backstyle == None else backstyle backshade = layout.GetParameterToUInt("backshade") - dataset.backshade = dataset.backshade if backshade==None else backshade - - - - - - - + dataset.backshade = dataset.backshade if backshade == None else backshade From b41247973796b21767afaacf4bfc515aaaf1fd24 Mon Sep 17 00:00:00 2001 From: "Jack Y. Araz" <jackaraz@gmail.com> Date: Mon, 17 Jul 2023 22:38:23 +0100 Subject: [PATCH 056/107] add dynamic scale choice and npoint scale var --- madanalysis/dataset/dataset.py | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/madanalysis/dataset/dataset.py b/madanalysis/dataset/dataset.py index 8ac86552..ab628335 100644 --- a/madanalysis/dataset/dataset.py +++ b/madanalysis/dataset/dataset.py @@ -76,6 +76,8 @@ class Dataset: "pdf_up_variation": [], "pdf_down_variation": [], "pdf_variation": [], + "dynamic_scale_choice": ["1", "2", "3", "4"], + "n_point_scale_variation": ["3", "5", "7", "9"], "title": [], "weighted_events": ["true", "false"], } @@ -102,6 +104,8 @@ def __init__(self, name): self.measured_global = SampleInfo() self.measured_detail = [] self.weight_collection: WeightCollection = WeightCollection() + self.dynamic_scale_choice = None + self.n_point_scale_variation = 3 def __len__(self): return len(self.filenames) @@ -112,7 +116,7 @@ def __getitem__(self, i): def user_GetValues(self, variable): try: return Dataset.userVariables[variable] - except: + except KeyError: return [] def user_GetParameters(self): @@ -345,7 +349,7 @@ def user_SetParameter(self, variable, value, value2="", value3=""): ]: try: tmp = float(value) - except: + except ValueError: logging.getLogger("MA5").error( "the value of the attribute '" + variable @@ -383,6 +387,31 @@ def user_SetParameter(self, variable, value, value2="", value3=""): ) return + # Dynamic scale choice + elif variable == "dynamic_scale_choice": + try: + tmp = int(value) + if tmp not in [1, 2, 3, 4]: + raise ValueError("dynamic_scale_choice is not within 1,2,3,4") + except ValueError: + logging.getLogger("MA5").error( + "Dynamic scale choice can only be 1,2,3 or 4." + ) + return + self.dynamic_scale_choice = tmp + + elif variable == "n_point_scale_variation": + try: + tmp = int(value) + if tmp not in [3, 5, 7, 9]: + raise ValueError("n_point_scale_variation is not within 3,5,7 or 9") + except ValueError: + logging.getLogger("MA5").error( + "n-point scale variation can only be 3,5,7 or 9." + ) + return + self.n_point_scale_variation = tmp + # title elif variable == "title": quoteTag = False From 59911c0da13806d5c21698a96dc1f85ea8a02e5d Mon Sep 17 00:00:00 2001 From: "Jack Y. Araz" <jackaraz@gmail.com> Date: Mon, 17 Jul 2023 22:39:06 +0100 Subject: [PATCH 057/107] add an extra array --- madanalysis/layout/histogram_core.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/madanalysis/layout/histogram_core.py b/madanalysis/layout/histogram_core.py index 6b6bd4ae..92b08dca 100644 --- a/madanalysis/layout/histogram_core.py +++ b/madanalysis/layout/histogram_core.py @@ -49,7 +49,7 @@ def __init__(self): self.nan = 0.0 self.inf = 0.0 self.array = [] - self.array_unc = [] + self.array_full = [] def convert_to_numpy(self) -> None: """Convert data containers into numpy arrays for convenience""" From a6232c9b15ad2caa9f529201fa0bf49357ffe88e Mon Sep 17 00:00:00 2001 From: "Jack Y. Araz" <jackaraz@gmail.com> Date: Mon, 17 Jul 2023 22:39:33 +0100 Subject: [PATCH 058/107] extend data handling --- madanalysis/layout/histogram.py | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/madanalysis/layout/histogram.py b/madanalysis/layout/histogram.py index 1057b585..e0462b61 100644 --- a/madanalysis/layout/histogram.py +++ b/madanalysis/layout/histogram.py @@ -108,25 +108,19 @@ def FinalizeReading(self, main, dataset): f"{str(data[-1])}. This value is set to zero." ) data[-1] = np.clip(data[-1], 0, None) - self.summary.array = np.array(data[:]) # [:] -> clone of data + self.summary.array_full = np.array(data[:]) # [:] -> clone of data # Compute the mean and the error on the data # mean shape should be (Nbins, ) and the histogram unc shape should be (Nbins, 2) # where first column is the lower envelop and second is upper envelop - histogram_mean = np.mean(self.summary.array, axis=1) - std = np.std(self.summary.array, axis=1) - histogram_unc = np.hstack([std, std]) + histogram_mean = np.mean(self.summary.array_full, axis=1) self.summary.array = histogram_mean.reshape(-1) - self.summary.array_unc = histogram_unc # Integral self.positive.ComputeIntegral() self.negative.ComputeIntegral() self.summary.ComputeIntegral() - def CreateHistogram(self): - pass - def Reset(self): # General info From 3eef3af650e7a29bee45b8d33a5e37bc280195c3 Mon Sep 17 00:00:00 2001 From: "Jack Y. Araz" <jackaraz@gmail.com> Date: Mon, 17 Jul 2023 22:40:06 +0100 Subject: [PATCH 059/107] simplify the code --- madanalysis/layout/plotflow_for_dataset.py | 53 ++-------------------- 1 file changed, 4 insertions(+), 49 deletions(-) diff --git a/madanalysis/layout/plotflow_for_dataset.py b/madanalysis/layout/plotflow_for_dataset.py index e822485f..40c2b855 100644 --- a/madanalysis/layout/plotflow_for_dataset.py +++ b/madanalysis/layout/plotflow_for_dataset.py @@ -84,10 +84,6 @@ def CreateHistogram(self): def ComputeScale(self): iplot = 0 - - # ! @jackaraz: this portion of the code should be changed to accomodate different types of - # ! PDF + scale unc combination for now its just mean and std - # Loop over plot for iabshisto, select in enumerate(self.main.selection): @@ -99,9 +95,9 @@ def ComputeScale(self): self.histos[iplot], self.dataset.weight_collection, self.dataset.measured_global.nevents, - thexsection, + self.xsection, ) - + # Reset scale scale = 0.0 @@ -110,6 +106,7 @@ def ComputeScale(self): self.histos[iplot].positive.integral - self.histos[iplot].negative.integral ) + integral = np.mean(integral) # Case 1: Normalization to ONE @@ -130,53 +127,11 @@ def ComputeScale(self): # or depends on WEIGHT+LUMI elif self.main.normalize in [NormalizeType.LUMI, NormalizeType.LUMI_WEIGHT]: - # # compute efficiency : Nevent / Ntotal - # if self.dataset.measured_global.nevents == 0: - # eff = 0 - # else: - # eff = ( - # self.histos[iplot].positive.nevents - # + self.histos[iplot].negative.nevents - # ) / float(self.dataset.measured_global.nevents) - # print("eff", eff) - # eff = np.mean(eff) - - # # compute the good xsection value + # compute the good xsection value thexsection = self.xsection if self.main.normalize == NormalizeType.LUMI_WEIGHT: thexsection = thexsection * self.dataset.weight - # # compute final entries/event ratio - # entries_per_events = 0 - # sumw = self.histos[iplot].positive.sumw - self.histos[iplot].negative.sumw - # Nentries = ( - # self.histos[iplot].positive.sumwentries - # - self.histos[iplot].negative.sumwentries - # ) - - # std_entries = float(np.std(Nentries)) - # Nentries_unc = (std_entries, std_entries) - # Nentries = float(np.mean(Nentries)) - # std_sumw = float(np.std(sumw)) - # sumw = float(np.mean(sumw)) - - # print(sumw, Nentries) - # if sumw != 0 and Nentries != 0: - # entries_per_events = sumw / Nentries - - # # compute the scale - # if integral != 0: - # scale = ( - # thexsection - # * self.main.lumi - # * 1000 - # * eff - # * entries_per_events - # / integral - # ) - # else: - # scale = 1 # no scale for empty plot - scale = processor.scale(lumi=self.main.lumi) # Setting the computing scale From 946f72664f506fad46729bb7db919c1ab2507d93 Mon Sep 17 00:00:00 2001 From: "Jack Y. Araz" <jackaraz@gmail.com> Date: Mon, 17 Jul 2023 22:40:56 +0100 Subject: [PATCH 060/107] incomplete multiweight treatment --- madanalysis/layout/plotflow.py | 190 +++++++++++++++++++++++++++++++-- 1 file changed, 179 insertions(+), 11 deletions(-) diff --git a/madanalysis/layout/plotflow.py b/madanalysis/layout/plotflow.py index 5256af56..be2da802 100644 --- a/madanalysis/layout/plotflow.py +++ b/madanalysis/layout/plotflow.py @@ -25,8 +25,9 @@ from __future__ import absolute_import import logging -import six +import six, os, json, copy, logging from six.moves import range +import numpy as np from madanalysis.enumeration.normalize_type import NormalizeType from madanalysis.enumeration.report_format_type import ReportFormatType @@ -36,6 +37,7 @@ from madanalysis.enumeration.stacking_method_type import StackingMethodType from madanalysis.layout.plotflow_for_dataset import PlotFlowForDataset import madanalysis.enumeration.color_hex +from madanalysis.configuration.weight_configuration import WeightCollection class PlotFlow: @@ -46,6 +48,15 @@ class PlotFlow: def __init__(self, main): self.main = main + self.pdftable = {} + with open( + os.path.join(self.main.archi_info.ma5dir, "madanalysis/input/LHAPDF.txt"), "r" + ) as f: + for line in f.readlines()[1:]: + pdf = line.split(",") + self.pdftable.update( + {int(pdf[0]): {"name": pdf[1], "members": int(pdf[-1])}} + ) self.detail = [] for dataset in main.datasets: self.detail.append(PlotFlowForDataset(main, dataset)) @@ -144,6 +155,7 @@ def DrawAll(self, histo_path, modes, output_paths, ListROOTplots): self.color = 1 histos = [] scales = [] + datasets = [] # Name of output files filenameC = histo_path + "/selection_" + str(irelhisto) + ".C" @@ -164,6 +176,7 @@ def DrawAll(self, histo_path, modes, output_paths, ListROOTplots): for detail in self.detail: # Appending histo + datasets.append(detail.dataset) histos.append(detail[irelhisto]) scales.append(detail[irelhisto].scale) @@ -173,7 +186,7 @@ def DrawAll(self, histo_path, modes, output_paths, ListROOTplots): logging.getLogger("MA5").debug("Producing file " + filenamePy + " ...") self.DrawMATPLOTLIB( - histos, scales, select, irelhisto, filenamePy, output_files + histos, scales, datasets, select, irelhisto, filenamePy, output_files ) irelhisto += 1 @@ -611,7 +624,9 @@ def DrawROOT(self, histos, scales, ref, irelhisto, filenameC, outputnames): # Ok return True - def DrawMATPLOTLIB(self, histos, scales, ref, irelhisto, filenamePy, outputnames): + def DrawMATPLOTLIB( + self, histos, scales, datasets, ref, irelhisto, filenamePy, outputnames + ): # Is there any legend? legendmode = False @@ -653,7 +668,7 @@ def DrawMATPLOTLIB(self, histos, scales, ref, irelhisto, filenamePy, outputnames # Import Libraries outputPy.write(" # Library import\n") - outputPy.write(" import numpy\n") + outputPy.write(" import numpy as np\n") outputPy.write(" import matplotlib\n") outputPy.write(" import matplotlib.pyplot as plt\n") outputPy.write(" import matplotlib.gridspec as gridspec\n") @@ -662,7 +677,7 @@ def DrawMATPLOTLIB(self, histos, scales, ref, irelhisto, filenamePy, outputnames # Matplotlib & numpy version outputPy.write(" # Library version\n") outputPy.write(" matplotlib_version = matplotlib.__version__\n") - outputPy.write(" numpy_version = numpy.__version__\n") + outputPy.write(" numpy_version = np.__version__\n") outputPy.write("\n") # Binning @@ -681,7 +696,7 @@ def DrawMATPLOTLIB(self, histos, scales, ref, irelhisto, filenamePy, outputnames outputPy.write("\n") else: outputPy.write( - " xBinning = numpy.linspace(" + " xBinning = np.linspace(" + str(xmin) + "," + str(xmax) @@ -694,7 +709,7 @@ def DrawMATPLOTLIB(self, histos, scales, ref, irelhisto, filenamePy, outputnames # Data outputPy.write(" # Creating data sequence: middle of each bin\n") outputPy.write( - " xData = numpy.array([" + " xData = np.array([" + ", ".join([f"{histos[0].GetBinMean(ibin):.5e}" for ibin in range(xnbin)]) + "])\n\n" ) @@ -703,12 +718,140 @@ def DrawMATPLOTLIB(self, histos, scales, ref, irelhisto, filenamePy, outputnames ntot = 0 for ind, hist in enumerate(histos): + # pdfset dictionary structure: + # "weights": are the nominal weights including scale uncertainties + # "replicas": are PDF variations + pdfset = {} + if len(datasets[ind].weight_collection) > 1: + # find pdf set + for pdfid in datasets[ind].weight_collection.pdfsets: + if pdfid in self.pdftable: + pdfset = copy.deepcopy(self.pdftable[pdfid]) + pdfset.update( + {"weights": datasets[ind].weight_collection.pdfset(pdfid)} + ) + pdfset.update({"replicas": WeightCollection()}) + for idx in range(1, pdfset["members"]): + pdfset["replicas"] += datasets[ind].weight_collection.pdfset( + pdfid + idx + ) + break + + print("Scales", pdfset["weights"].get_scale(muf=1.0, mur=1.0)) + + # with open("/Users/jackaraz/Desktop/test.json", "w") as f: + # json.dump( + # pdfset["weights"].get_scale(muf=1.0, mur=1.0).to_dict(), f, indent=4 + # ) + + # TODO: If there is only scale variations + if len(pdfset) == 0: + pass + # Creating a new histo histoname = "y" + hist.name + "_" + str(ind) outputPy.write(" # Creating weights for histo: " + histoname + "\n") - outputPy.write(" " + histoname + "_weights = numpy.array([") + outputPy.write(" " + histoname + "_weights = np.array([") + print(hist.summary.array_full.shape) current_histo = hist.summary.array * scales[ind] + full_histo = hist.summary.array_full * scales[ind] + upper_scale, lower_scale = None, None + upper_pdf, lower_pdf = None, None + scale_unc, pdf_unc = None, None + if len(pdfset) != 0: + if pdfset["weights"].has_scale: + dyn_scale = datasets[ind].dynamic_scale_choice + n_point_scale = datasets[ind].n_point_scale_variation + + # Get the nominal weight + central_scale = pdfset["weights"].central_scale + nominal_loc = ( + pdfset["weights"] + .get_scale( + dynamic=dyn_scale, muf=central_scale, mur=central_scale + ) + .loc + ) + current_histo = np.squeeze(full_histo[:, nominal_loc]) + print("current_histo", current_histo.shape) + + scale_vars = pdfset["weights"].get_scale_vars( + point=n_point_scale, dynamic=dyn_scale + ) + + scale_upper_loc = scale_vars[1].loc + scale_lower_loc = scale_vars[0].loc + upper_scale = np.abs( + np.squeeze(full_histo[:, scale_upper_loc]) - current_histo + ) + lower_scale = np.abs( + np.squeeze(full_histo[:, scale_lower_loc]) - current_histo + ) + scale_unc = np.vstack([lower_scale, upper_scale]) + + if len(pdfset["replicas"]) != 0: + pdfvar_loc = pdfset["replicas"].loc + nominal_loc + pdfvar_histo = full_histo[:, pdfvar_loc] + + ### Choose method + method = "replicas" + known_hessians = ["CT18", "MSHT20"] + if "hessian" in pdfset["name"].lower() or any( + x in pdfset["name"] for x in known_hessians + ): + method = "hessian" + + logging.getLogger("MA5").debug( + f"Using {method} pdf combination for {pdfset['name']} pdf set." + ) + + ### Replicas method + if method == "replicas": + mean_histo = np.mean(pdfvar_histo, axis=1) + pdf_unc = np.sqrt( + np.sum( + np.square(pdfvar_histo - mean_histo.reshape(-1, 1)), + axis=1, + ) + / pdfvar_histo.shape[0] + ) + pdf_unc = np.vstack([pdf_unc, pdf_unc]) + else: + print("I dont know how to do this yet!!!") + pass + ### Hessian method + # upper = np.sqrt( + + # ) + + total_unc = None + if scale_unc is not None: + total_unc = scale_unc + + if pdf_unc is not None: + lower_scale = total_unc[0] / current_histo + upper_scale = total_unc[1] / current_histo + + lower_pdf = pdf_unc[0] / current_histo + upper_pdf = pdf_unc[0] / current_histo + + lower_unc = np.sqrt(lower_scale**2 + lower_pdf**2) + upper_unc = np.sqrt(upper_scale**2 + upper_pdf**2) + total_unc = np.vstack( + [lower_unc * current_histo, upper_unc * current_histo] + ) + + elif pdf_unc is not None: + total_unc = pdf_unc + outputPy.write(", ".join(f"{x:.8e}" for x in current_histo) + "])\n\n") + + if upper_scale is not None: + outputPy.write(" " + histoname + "_scale_up_weights = np.array([") + outputPy.write(", ".join(f"{x:.8e}" for x in upper_scale) + "])\n\n") + outputPy.write(" " + histoname + "_scale_dn_weights = np.array([") + outputPy.write(", ".join(f"{x:.8e}" for x in lower_scale) + "])\n\n") + ntot = float(sum(current_histo)) # Canvas @@ -747,12 +890,28 @@ def DrawMATPLOTLIB(self, histos, scales, ref, irelhisto, filenamePy, outputnames if not stackmode: myweights = "y" + histos[ind].name + "_" + str(ind) + "_weights" + myweights_scale_up = ( + "y" + histos[ind].name + "_" + str(ind) + "_scale_up_weights" + ) + myweights_scale_dn = ( + "y" + histos[ind].name + "_" + str(ind) + "_scale_dn_weights" + ) else: myweights = "" + myweights_scale_up = "" + myweights_scale_dn = "" for ind2 in range(0, ind + 1): if ind2 >= 1: myweights += "+" + myweights_scale_up += "+" + myweights_scale_dn += "+" myweights += "y" + histos[ind2].name + "_" + str(ind2) + "_weights" + myweights_scale_up += ( + "y" + histos[ind2].name + "_" + str(ind2) + "_scale_up_weights" + ) + myweights_scale_dn += ( + "y" + histos[ind2].name + "_" + str(ind2) + "_scale_dn_weights" + ) # reset linecolor = 0 @@ -901,6 +1060,7 @@ def DrawMATPLOTLIB(self, histos, scales, ref, irelhisto, filenamePy, outputnames + mytitle + ", " ) + if ntot != 0: outputPy.write("histtype=" + filledmode + ", ") @@ -950,6 +1110,14 @@ def DrawMATPLOTLIB(self, histos, scales, ref, irelhisto, filenamePy, outputnames ) outputPy.write("\n") + if upper_scale is not None: + outputPy.write( + " pad.errorbar(" + + "[x + (xBinning[0] + xBinning[1])/2 for x in xBinning[:-1]]," + + f"{myweights}, yerr={total_unc.tolist()}," + + " fmt='.', elinewidth=1, capsize=2)\n\n" + ) + # Label outputPy.write(" # Axis\n") outputPy.write(" plt.rc('text',usetex=False)\n") @@ -1013,7 +1181,7 @@ def DrawMATPLOTLIB(self, histos, scales, ref, irelhisto, filenamePy, outputnames myweights += "+" myweights += "y" + histos[ind].name + "_" + str(ind) + "_weights" else: - myweights = "numpy.array([" + myweights = "np.array([" for ind in range(0, len(histos)): if ind >= 1: myweights += "," @@ -1040,7 +1208,7 @@ def DrawMATPLOTLIB(self, histos, scales, ref, irelhisto, filenamePy, outputnames myweights += "+" myweights += "y" + histos[ind].name + "_" + str(ind) + "_weights" else: - myweights = "numpy.array([" + myweights = "np.array([" for ind in range(0, len(histos)): if ind >= 1: myweights += "," @@ -1091,7 +1259,7 @@ def DrawMATPLOTLIB(self, histos, scales, ref, irelhisto, filenamePy, outputnames # Labels if frequencyhisto: outputPy.write(" # Labels for x-Axis\n") - outputPy.write(" xLabels = numpy.array([") + outputPy.write(" xLabels = np.array([") for bin in range(0, xnbin): if bin >= 1: outputPy.write(",") From 746240d3d9b0bb60f1808ba958ea7724dc30925e Mon Sep 17 00:00:00 2001 From: "Jack Y. Araz" <jackaraz@gmail.com> Date: Tue, 18 Jul 2023 09:39:43 +0100 Subject: [PATCH 061/107] extended reporting --- madanalysis/configuration/weight_configuration.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/madanalysis/configuration/weight_configuration.py b/madanalysis/configuration/weight_configuration.py index 61531d61..163e7d13 100644 --- a/madanalysis/configuration/weight_configuration.py +++ b/madanalysis/configuration/weight_configuration.py @@ -135,10 +135,10 @@ def append(self, name: Text, idx: int) -> None: self._collection.append(Weight(name=name, loc=idx)) def __repr__(self) -> Text: - # if len(self) < 5: - return "WeightCollection(" + ",".join([str(x) for x in self]) + ")" + if len(self) < 5: + return "WeightCollection(" + ",".join([str(x) for x in self]) + ")" - # return f"WeightCollection(contains {len(self)} weight definitions)" + return f"WeightCollection(contains {len(self)} weight definitions)" def __str__(self) -> Text: return self.__repr__() @@ -149,6 +149,9 @@ def __iter__(self) -> Weight: def __len__(self) -> int: return len(self._collection) + def __getitem__(self, index: int) -> Weight: + return self._collection[index] + @property def names(self) -> List[Text]: """retreive weight names""" From 0083d63867183bbd3cf3c9ba39194ce1bbf448de Mon Sep 17 00:00:00 2001 From: "Jack Y. Araz" <jackaraz@gmail.com> Date: Tue, 18 Jul 2023 09:41:34 +0100 Subject: [PATCH 062/107] add debug sections --- madanalysis/layout/plotflow.py | 54 ++++++++++++++++++++++++---------- 1 file changed, 39 insertions(+), 15 deletions(-) diff --git a/madanalysis/layout/plotflow.py b/madanalysis/layout/plotflow.py index be2da802..9d42dc1a 100644 --- a/madanalysis/layout/plotflow.py +++ b/madanalysis/layout/plotflow.py @@ -717,6 +717,7 @@ def DrawMATPLOTLIB( # Loop over datasets and histos ntot = 0 for ind, hist in enumerate(histos): + logging.getLogger("MA5").debug(f"<><><><><><> {hist.name} <><><><><><>") # pdfset dictionary structure: # "weights": are the nominal weights including scale uncertainties @@ -737,16 +738,10 @@ def DrawMATPLOTLIB( ) break - print("Scales", pdfset["weights"].get_scale(muf=1.0, mur=1.0)) - - # with open("/Users/jackaraz/Desktop/test.json", "w") as f: - # json.dump( - # pdfset["weights"].get_scale(muf=1.0, mur=1.0).to_dict(), f, indent=4 - # ) - - # TODO: If there is only scale variations if len(pdfset) == 0: - pass + logging.getLogger("MA5").debug("No additional source of uncertainty") + else: + logging.getLogger("MA5").debug(pdfset) # Creating a new histo histoname = "y" + hist.name + "_" + str(ind) @@ -795,7 +790,11 @@ def DrawMATPLOTLIB( ### Choose method method = "replicas" - known_hessians = ["CT18", "MSHT20"] + # TODO this list may need to be extended + known_hessians = [ + "CT18", + "MSHT20", + ] if "hessian" in pdfset["name"].lower() or any( x in pdfset["name"] for x in known_hessians ): @@ -817,12 +816,37 @@ def DrawMATPLOTLIB( ) pdf_unc = np.vstack([pdf_unc, pdf_unc]) else: - print("I dont know how to do this yet!!!") - pass - ### Hessian method - # upper = np.sqrt( + upper = np.zeros(full_histo.shape[0]) + lower = np.zeros(full_histo.shape[0]) + for idx, replica in enumerate(pdfset["replicas"]): + if idx % 2 != 0: + continue + other_replica = pdfset["replicas"][idx + 1] + first = np.squeeze(full_histo[:, replica.loc]) - current_histo + second = ( + np.squeeze(full_histo[:, other_replica.loc]) + - current_histo + ) + + upper += np.square( + np.max( + np.vstack([first, second, np.zeros(first.shape)]), + axis=0, + ) + ) + + first = current_histo - np.squeeze(full_histo[:, replica.loc]) + second = current_histo - np.squeeze( + full_histo[:, other_replica.loc] + ) + lower += np.square( + np.max( + np.vstack([first, second, np.zeros(first.shape)]), + axis=0, + ) + ) - # ) + pdf_unc = np.sqrt(np.vstack([lower, upper])) total_unc = None if scale_unc is not None: From f329ab8ea5e8b3e6b5552b369d0a3f7553109042 Mon Sep 17 00:00:00 2001 From: "Jack Y. Araz" <jackaraz@gmail.com> Date: Tue, 18 Jul 2023 09:44:34 +0100 Subject: [PATCH 063/107] bugfix --- madanalysis/layout/histogram.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/madanalysis/layout/histogram.py b/madanalysis/layout/histogram.py index e0462b61..84f8db7f 100644 --- a/madanalysis/layout/histogram.py +++ b/madanalysis/layout/histogram.py @@ -45,6 +45,9 @@ def Print(self): self.negative.Print() self.summary.Print() + def CreateHistogram(self): + pass + def FinalizeReading(self, main, dataset): self.positive.convert_to_numpy() From 9205e66866550307b9625c5c6dafde5218855916 Mon Sep 17 00:00:00 2001 From: "Jack Y. Araz" <jackaraz@gmail.com> Date: Tue, 18 Jul 2023 09:51:45 +0100 Subject: [PATCH 064/107] bugfix --- madanalysis/layout/plotflow.py | 24 ++---------------------- 1 file changed, 2 insertions(+), 22 deletions(-) diff --git a/madanalysis/layout/plotflow.py b/madanalysis/layout/plotflow.py index 9d42dc1a..1e5b722b 100644 --- a/madanalysis/layout/plotflow.py +++ b/madanalysis/layout/plotflow.py @@ -768,7 +768,6 @@ def DrawMATPLOTLIB( .loc ) current_histo = np.squeeze(full_histo[:, nominal_loc]) - print("current_histo", current_histo.shape) scale_vars = pdfset["weights"].get_scale_vars( point=n_point_scale, dynamic=dyn_scale @@ -848,6 +847,7 @@ def DrawMATPLOTLIB( pdf_unc = np.sqrt(np.vstack([lower, upper])) + # TODO give options for both linear and quadrature combination total_unc = None if scale_unc is not None: total_unc = scale_unc @@ -857,7 +857,7 @@ def DrawMATPLOTLIB( upper_scale = total_unc[1] / current_histo lower_pdf = pdf_unc[0] / current_histo - upper_pdf = pdf_unc[0] / current_histo + upper_pdf = pdf_unc[1] / current_histo lower_unc = np.sqrt(lower_scale**2 + lower_pdf**2) upper_unc = np.sqrt(upper_scale**2 + upper_pdf**2) @@ -870,12 +870,6 @@ def DrawMATPLOTLIB( outputPy.write(", ".join(f"{x:.8e}" for x in current_histo) + "])\n\n") - if upper_scale is not None: - outputPy.write(" " + histoname + "_scale_up_weights = np.array([") - outputPy.write(", ".join(f"{x:.8e}" for x in upper_scale) + "])\n\n") - outputPy.write(" " + histoname + "_scale_dn_weights = np.array([") - outputPy.write(", ".join(f"{x:.8e}" for x in lower_scale) + "])\n\n") - ntot = float(sum(current_histo)) # Canvas @@ -914,28 +908,14 @@ def DrawMATPLOTLIB( if not stackmode: myweights = "y" + histos[ind].name + "_" + str(ind) + "_weights" - myweights_scale_up = ( - "y" + histos[ind].name + "_" + str(ind) + "_scale_up_weights" - ) - myweights_scale_dn = ( - "y" + histos[ind].name + "_" + str(ind) + "_scale_dn_weights" - ) else: myweights = "" - myweights_scale_up = "" - myweights_scale_dn = "" for ind2 in range(0, ind + 1): if ind2 >= 1: myweights += "+" myweights_scale_up += "+" myweights_scale_dn += "+" myweights += "y" + histos[ind2].name + "_" + str(ind2) + "_weights" - myweights_scale_up += ( - "y" + histos[ind2].name + "_" + str(ind2) + "_scale_up_weights" - ) - myweights_scale_dn += ( - "y" + histos[ind2].name + "_" + str(ind2) + "_scale_dn_weights" - ) # reset linecolor = 0 From c4738af25135da08a0d4bfb5e43b19f222557fb9 Mon Sep 17 00:00:00 2001 From: BFuks <fuks@lpthe.jussieu.fr> Date: Tue, 18 Jul 2023 23:13:07 +0200 Subject: [PATCH 065/107] temporary fix allowing to at least install delphes. To be further fixed --- .../Interfaces/delphes/DelphesTreeReader.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tools/SampleAnalyzer/Interfaces/delphes/DelphesTreeReader.cpp b/tools/SampleAnalyzer/Interfaces/delphes/DelphesTreeReader.cpp index c956ac60..f673cb45 100644 --- a/tools/SampleAnalyzer/Interfaces/delphes/DelphesTreeReader.cpp +++ b/tools/SampleAnalyzer/Interfaces/delphes/DelphesTreeReader.cpp @@ -227,7 +227,7 @@ void DelphesTreeReader::FillEvent(EventFormat& myEvent, SampleFormat& mySample) if (weight==0) continue; // creating new particle and filling particle info - myEvent.mc()->multiweights().Add(weight->ID,weight->Weight); + myEvent.mc()->weights().Add(weight->ID,weight->Weight); } } @@ -397,14 +397,16 @@ void DelphesTreeReader::FillEvent(EventFormat& myEvent, SampleFormat& mySample) if (header1!=0) { // Set event-weight - myEvent.mc()->setWeight(header1->Weight); + INFO << " FIX ME " << header1->Weight << endmsg; + myEvent.mc()->setWeight(0,header1->Weight); } else { HepMCEvent* header2 = dynamic_cast<HepMCEvent*>(data_.Event_->At(i)); if (header2==0) continue; // Set event-weight - myEvent.mc()->setWeight(header2->Weight); + INFO << " FIX ME " << header2->Weight << endmsg; + myEvent.mc()->setWeight(0,header2->Weight); } } } From f1c3927db61ddc8d2f057cd927d1e0630a3e49f1 Mon Sep 17 00:00:00 2001 From: BFuks <fuks@lpthe.jussieu.fr> Date: Thu, 20 Jul 2023 18:02:06 +0200 Subject: [PATCH 066/107] Updating uncertainty calculations --- .../configuration/weight_configuration.py | 46 ++-- madanalysis/dataset/dataset.py | 6 +- madanalysis/layout/plotflow.py | 200 +++++++----------- 3 files changed, 103 insertions(+), 149 deletions(-) diff --git a/madanalysis/configuration/weight_configuration.py b/madanalysis/configuration/weight_configuration.py index 163e7d13..f4e28935 100644 --- a/madanalysis/configuration/weight_configuration.py +++ b/madanalysis/configuration/weight_configuration.py @@ -176,7 +176,7 @@ def nominal(self) -> Weight: for w in self: if w.is_nominal: return w - raise ValueError("Can not find nominal weight") + raise ValueError("Cannot find nominal weight") def group_for(self, group: Text) -> Dict: """Create a group""" @@ -246,29 +246,27 @@ def get_scale_vars(self, point: int = 3, dynamic: int = None) -> Tuple: if dynamic is not None: dynamic = dynamic if self.has_dyn_scale(dynamic) else None - scales = self.scales["muf"] - if len(scales) == 5 and point == 3: - scales = scales[1:-1] - elif len(scales) == 7: - if point == 3: - scales = scales[2:-2] - if point == 5: - scales = scales[1:-1] - elif len(scales) == 9: - if point == 3: - scales = scales[3:-3] - elif point == 5: - scales = scales[2:-2] - elif point == 7: - scales = scales[1:-1] - - min_scale = min(scales) - max_scale = max(scales) - - return ( - self.get_scale(dynamic=dynamic, muf=min_scale, mur=min_scale), - self.get_scale(dynamic=dynamic, muf=max_scale, mur=max_scale), - ) + scale_choices = []; + all_scale_choices = []; + for w in self: + if w.dynamic_scale==dynamic: + all_scale_choices.append([w.muf, w.mur]) + if point==3: + if w.muf==w.mur and w.muf in [0.5,1.0,2.0]: + scale_choices.append([w.muf, w.mur]) + elif point==7: + if [w.muf, w.mur] in [ [0.5,0.5], [0.5,1.0], [1.0,0.5], [1.0,1.0], [1.0,2.0], [2.0,1.0], [2.0,2.0] ]: + scale_choices.append([w.muf, w.mur]) + elif point==9: + if w.muf in [0.5,1.0,2.0] and w.mur in [0.5,1.0,2.0]: + scale_choices.append([w.muf, w.mur]) + else: + scale_choices.append([w.muf, w.mur]) + + if len(scale_choices) != point: + scale_choices = all_scale_choices + + return ( [self.get_scale(dynamic=dynamic, muf=x[0], mur=x[1]) for x in scale_choices] ) def get_scale( self, dynamic: int = None, muf: float = 1.0, mur: float = 1.0 diff --git a/madanalysis/dataset/dataset.py b/madanalysis/dataset/dataset.py index ab628335..a2fecd8b 100644 --- a/madanalysis/dataset/dataset.py +++ b/madanalysis/dataset/dataset.py @@ -403,11 +403,11 @@ def user_SetParameter(self, variable, value, value2="", value3=""): elif variable == "n_point_scale_variation": try: tmp = int(value) - if tmp not in [3, 5, 7, 9]: - raise ValueError("n_point_scale_variation is not within 3,5,7 or 9") + if tmp not in [3, 7, 9]: + raise ValueError("n_point_scale_variation is not within 3,7 or 9") except ValueError: logging.getLogger("MA5").error( - "n-point scale variation can only be 3,5,7 or 9." + "n-point scale variation can only be 3,7 or 9." ) return self.n_point_scale_variation = tmp diff --git a/madanalysis/layout/plotflow.py b/madanalysis/layout/plotflow.py index 1e5b722b..3250eef4 100644 --- a/madanalysis/layout/plotflow.py +++ b/madanalysis/layout/plotflow.py @@ -719,157 +719,113 @@ def DrawMATPLOTLIB( for ind, hist in enumerate(histos): logging.getLogger("MA5").debug(f"<><><><><><> {hist.name} <><><><><><>") - # pdfset dictionary structure: - # "weights": are the nominal weights including scale uncertainties - # "replicas": are PDF variations - pdfset = {} + ######################################################################## + # weight_set - dictionary structure: # + # - "weights": are nominal weights including scale uncertainties # + # - "pdf_variations": PDF variations # + ######################################################################## + weight_set = {} if len(datasets[ind].weight_collection) > 1: - # find pdf set + # separate the weights related to PDF variations from the other weights for pdfid in datasets[ind].weight_collection.pdfsets: if pdfid in self.pdftable: - pdfset = copy.deepcopy(self.pdftable[pdfid]) - pdfset.update( - {"weights": datasets[ind].weight_collection.pdfset(pdfid)} - ) - pdfset.update({"replicas": WeightCollection()}) - for idx in range(1, pdfset["members"]): - pdfset["replicas"] += datasets[ind].weight_collection.pdfset( - pdfid + idx - ) - break + weight_set.update( {"weights": datasets[ind].weight_collection.pdfset(pdfid)} ) + weight_set.update( {"pdf_variations": {self.pdftable[pdfid]["name"]:WeightCollection()} } ) + for idx in range(1, self.pdftable[pdfid]["members"]): + weight_set["pdf_variations"][self.pdftable[pdfid]["name"]] += datasets[ind].weight_collection.pdfset(pdfid + idx) - if len(pdfset) == 0: + # Some checks + if len(weight_set) == 0: logging.getLogger("MA5").debug("No additional source of uncertainty") else: - logging.getLogger("MA5").debug(pdfset) + logging.getLogger("MA5").debug(weight_set) # Creating a new histo histoname = "y" + hist.name + "_" + str(ind) outputPy.write(" # Creating weights for histo: " + histoname + "\n") outputPy.write(" " + histoname + "_weights = np.array([") - print(hist.summary.array_full.shape) current_histo = hist.summary.array * scales[ind] full_histo = hist.summary.array_full * scales[ind] upper_scale, lower_scale = None, None upper_pdf, lower_pdf = None, None scale_unc, pdf_unc = None, None - if len(pdfset) != 0: - if pdfset["weights"].has_scale: + if len(weight_set) != 0: + # Get the nominal weight + if weight_set["weights"].has_scale: + # Configuration dyn_scale = datasets[ind].dynamic_scale_choice n_point_scale = datasets[ind].n_point_scale_variation - - # Get the nominal weight - central_scale = pdfset["weights"].central_scale - nominal_loc = ( - pdfset["weights"] - .get_scale( - dynamic=dyn_scale, muf=central_scale, mur=central_scale - ) - .loc - ) + scale_vars = weight_set["weights"].get_scale_vars(point=n_point_scale, dynamic=dyn_scale) + logging.getLogger("MA5").debug("Dyn. scale configuration " + str(dyn_scale) + "; " + str(n_point_scale) + "points") + logging.getLogger("MA5").debug("Scale variations = " + str(scale_vars)) + + # Nominal histo + central_scale = weight_set["weights"].central_scale + nominal_loc = weight_set["weights"].get_scale(dynamic=dyn_scale, muf=central_scale, mur=central_scale).loc + logging.getLogger("MA5").debug("Nominal weight location = " + str(nominal_loc)) current_histo = np.squeeze(full_histo[:, nominal_loc]) - scale_vars = pdfset["weights"].get_scale_vars( - point=n_point_scale, dynamic=dyn_scale - ) - - scale_upper_loc = scale_vars[1].loc - scale_lower_loc = scale_vars[0].loc - upper_scale = np.abs( - np.squeeze(full_histo[:, scale_upper_loc]) - current_histo - ) - lower_scale = np.abs( - np.squeeze(full_histo[:, scale_lower_loc]) - current_histo - ) + # Scale variation envelope + if weight_set["weights"].has_scale: + upper_histo = np.copy(current_histo) + lower_histo = np.copy(current_histo) + for x in scale_vars: + scale_histo = np.squeeze(full_histo[:, x.loc]) + for i, mybin in enumerate(current_histo): + if upper_histo[i] < scale_histo[i]: upper_histo[i] = scale_histo[i] + if lower_histo[i] > scale_histo[i]: lower_histo[i] = scale_histo[i] + upper_scale = np.abs(upper_histo - current_histo) + lower_scale = np.abs(lower_histo - current_histo) scale_unc = np.vstack([lower_scale, upper_scale]) - if len(pdfset["replicas"]) != 0: - pdfvar_loc = pdfset["replicas"].loc + nominal_loc - pdfvar_histo = full_histo[:, pdfvar_loc] - - ### Choose method - method = "replicas" - # TODO this list may need to be extended - known_hessians = [ - "CT18", - "MSHT20", - ] - if "hessian" in pdfset["name"].lower() or any( - x in pdfset["name"] for x in known_hessians - ): - method = "hessian" - - logging.getLogger("MA5").debug( - f"Using {method} pdf combination for {pdfset['name']} pdf set." - ) - - ### Replicas method - if method == "replicas": - mean_histo = np.mean(pdfvar_histo, axis=1) - pdf_unc = np.sqrt( - np.sum( - np.square(pdfvar_histo - mean_histo.reshape(-1, 1)), - axis=1, - ) - / pdfvar_histo.shape[0] - ) - pdf_unc = np.vstack([pdf_unc, pdf_unc]) - else: - upper = np.zeros(full_histo.shape[0]) - lower = np.zeros(full_histo.shape[0]) - for idx, replica in enumerate(pdfset["replicas"]): - if idx % 2 != 0: - continue - other_replica = pdfset["replicas"][idx + 1] - first = np.squeeze(full_histo[:, replica.loc]) - current_histo - second = ( - np.squeeze(full_histo[:, other_replica.loc]) - - current_histo - ) - - upper += np.square( - np.max( - np.vstack([first, second, np.zeros(first.shape)]), - axis=0, - ) - ) - - first = current_histo - np.squeeze(full_histo[:, replica.loc]) - second = current_histo - np.squeeze( - full_histo[:, other_replica.loc] - ) - lower += np.square( - np.max( - np.vstack([first, second, np.zeros(first.shape)]), - axis=0, - ) - ) - - pdf_unc = np.sqrt(np.vstack([lower, upper])) + # PDF variations + if len(weight_set["pdf_variations"]) != 0: + pdf_unc = {}; + for pdf_set, pdf_weights in weight_set["pdf_variations"].items(): + pdfvar_loc = pdf_weights.loc + nominal_loc + pdfvar_histo = full_histo[:, pdf_weights.loc] + + ### Method to use for PDF uncertainties + ### TODO: verify that this works for all standard sets + method = "replicas" if (("NNPDF" in pdf_set and not "hessian" in pdf_set) or ("PDF4LHC" in pdf_set and "_mc_" in pdf_set)) else "hessian" + logging.getLogger("MA5").debug(f"Using {method} pdf combination for {pdf_set} pdf set.") + + ### Replicas method + if method == "replicas": + mean_histo = np.mean(pdfvar_histo, axis=1) + uncertainties = np.sqrt(np.sum(np.square(pdfvar_histo - mean_histo.reshape(-1, 1)),axis=1)/pdfvar_histo.shape[1]) + ### Hessian method + else: + uncertainties = np.sqrt(np.sum(np.square(pdfvar_histo - current_histo.reshape(-1, 1)),axis=1)) + pdf_unc[pdf_set] = np.vstack([uncertainties, uncertainties]) # TODO give options for both linear and quadrature combination total_unc = None - if scale_unc is not None: + # Two sets of uncertainties + if scale_unc is not None and pdf_unc is not None: + lower_unc = scale_unc[0] + upper_unc = scale_unc[1] + for pdf_set, pdf_error in pdf_unc.items(): + lower = np.sqrt(np.square(scale_unc[0]) + np.square(pdf_error[0])) + upper = np.sqrt(np.square(scale_unc[1]) + np.square(pdf_error[1])) + for i, mybin in enumerate(lower): + if lower[i] > lower_unc[i]: lower_unc[i] = lower[i] + if upper[i] > upper_unc[i]: upper_unc[i] = upper[i] + total_unc = np.vstack([lower_unc, upper_unc]) + # only scale uncertainties + elif scale_unc is not None: total_unc = scale_unc - - if pdf_unc is not None: - lower_scale = total_unc[0] / current_histo - upper_scale = total_unc[1] / current_histo - - lower_pdf = pdf_unc[0] / current_histo - upper_pdf = pdf_unc[1] / current_histo - - lower_unc = np.sqrt(lower_scale**2 + lower_pdf**2) - upper_unc = np.sqrt(upper_scale**2 + upper_pdf**2) - total_unc = np.vstack( - [lower_unc * current_histo, upper_unc * current_histo] - ) - + # only PDF uncertainties elif pdf_unc is not None: - total_unc = pdf_unc + for pdf_set, pdf_error in pdf_unc.items(): + if total_unc is None: + total_unc = pdf_error + else: + for i, mybin in enumerate(pdf_error[0]): + if total_unc[0][i] > pdf_error[0][i]: total_unc[0][i] = pdf_error[0][i] + if total_unc[1][i] > pdf_error[1][i]: total_unc[1][i] = pdf_error[1][i] outputPy.write(", ".join(f"{x:.8e}" for x in current_histo) + "])\n\n") - ntot = float(sum(current_histo)) # Canvas From 2a909132ba96bf9f980787ca24d81e4a9c049822 Mon Sep 17 00:00:00 2001 From: "Jack Y. Araz" <jackaraz@gmail.com> Date: Fri, 21 Jul 2023 17:26:11 +0100 Subject: [PATCH 067/107] return weight collection object for queries --- .../configuration/weight_configuration.py | 53 +++++++++++++------ 1 file changed, 37 insertions(+), 16 deletions(-) diff --git a/madanalysis/configuration/weight_configuration.py b/madanalysis/configuration/weight_configuration.py index f4e28935..78991a07 100644 --- a/madanalysis/configuration/weight_configuration.py +++ b/madanalysis/configuration/weight_configuration.py @@ -246,27 +246,39 @@ def get_scale_vars(self, point: int = 3, dynamic: int = None) -> Tuple: if dynamic is not None: dynamic = dynamic if self.has_dyn_scale(dynamic) else None - scale_choices = []; - all_scale_choices = []; + scale_choices = [] + all_scale_choices = [] for w in self: - if w.dynamic_scale==dynamic: - all_scale_choices.append([w.muf, w.mur]) - if point==3: - if w.muf==w.mur and w.muf in [0.5,1.0,2.0]: - scale_choices.append([w.muf, w.mur]) - elif point==7: - if [w.muf, w.mur] in [ [0.5,0.5], [0.5,1.0], [1.0,0.5], [1.0,1.0], [1.0,2.0], [2.0,1.0], [2.0,2.0] ]: - scale_choices.append([w.muf, w.mur]) - elif point==9: - if w.muf in [0.5,1.0,2.0] and w.mur in [0.5,1.0,2.0]: - scale_choices.append([w.muf, w.mur]) - else: - scale_choices.append([w.muf, w.mur]) + if w.dynamic_scale == dynamic: + all_scale_choices.append([w.muf, w.mur]) + if point == 3: + if w.muf == w.mur and w.muf in [0.5, 1.0, 2.0]: + scale_choices.append([w.muf, w.mur]) + elif point == 7: + if [w.muf, w.mur] in [ + [0.5, 0.5], + [0.5, 1.0], + [1.0, 0.5], + [1.0, 1.0], + [1.0, 2.0], + [2.0, 1.0], + [2.0, 2.0], + ]: + scale_choices.append([w.muf, w.mur]) + elif point == 9: + if w.muf in [0.5, 1.0, 2.0] and w.mur in [0.5, 1.0, 2.0]: + scale_choices.append([w.muf, w.mur]) + else: + scale_choices.append([w.muf, w.mur]) if len(scale_choices) != point: scale_choices = all_scale_choices - return ( [self.get_scale(dynamic=dynamic, muf=x[0], mur=x[1]) for x in scale_choices] ) + output = WeightCollection() + for x in scale_choices: + output += self.get_scale(dynamic=dynamic, muf=x[0], mur=x[1]) + + return output def get_scale( self, dynamic: int = None, muf: float = 1.0, mur: float = 1.0 @@ -299,3 +311,12 @@ def __iadd__(self, other): for items in other: self._collection.append(items) return self + + def __add__(self, other): + assert isinstance(other, WeightCollection) + for item in other: + if item not in self._collection: + self._collection.append(item) + else: + raise ValueError(f"{item} already exists.") + return self From b23ebd8ecffcc747aed8c66e16fc6e7c74eec254 Mon Sep 17 00:00:00 2001 From: "Jack Y. Araz" <jackaraz@gmail.com> Date: Fri, 21 Jul 2023 17:26:19 +0100 Subject: [PATCH 068/107] efficiency updates --- madanalysis/layout/plotflow.py | 153 ++++++++++++++++++++++++--------- 1 file changed, 113 insertions(+), 40 deletions(-) diff --git a/madanalysis/layout/plotflow.py b/madanalysis/layout/plotflow.py index 3250eef4..a51af5bd 100644 --- a/madanalysis/layout/plotflow.py +++ b/madanalysis/layout/plotflow.py @@ -729,10 +729,20 @@ def DrawMATPLOTLIB( # separate the weights related to PDF variations from the other weights for pdfid in datasets[ind].weight_collection.pdfsets: if pdfid in self.pdftable: - weight_set.update( {"weights": datasets[ind].weight_collection.pdfset(pdfid)} ) - weight_set.update( {"pdf_variations": {self.pdftable[pdfid]["name"]:WeightCollection()} } ) + weight_set.update( + {"weights": datasets[ind].weight_collection.pdfset(pdfid)} + ) + weight_set.update( + { + "pdf_variations": { + self.pdftable[pdfid]["name"]: WeightCollection() + } + } + ) for idx in range(1, self.pdftable[pdfid]["members"]): - weight_set["pdf_variations"][self.pdftable[pdfid]["name"]] += datasets[ind].weight_collection.pdfset(pdfid + idx) + weight_set["pdf_variations"][ + self.pdftable[pdfid]["name"] + ] += datasets[ind].weight_collection.pdfset(pdfid + idx) # Some checks if len(weight_set) == 0: @@ -755,75 +765,138 @@ def DrawMATPLOTLIB( # Configuration dyn_scale = datasets[ind].dynamic_scale_choice n_point_scale = datasets[ind].n_point_scale_variation - scale_vars = weight_set["weights"].get_scale_vars(point=n_point_scale, dynamic=dyn_scale) - logging.getLogger("MA5").debug("Dyn. scale configuration " + str(dyn_scale) + "; " + str(n_point_scale) + "points") - logging.getLogger("MA5").debug("Scale variations = " + str(scale_vars)) + scale_vars = weight_set["weights"].get_scale_vars( + point=n_point_scale, dynamic=dyn_scale + ) + logging.getLogger("MA5").debug( + "Dyn. scale configuration " + + str(dyn_scale) + + "; " + + str(n_point_scale) + + "points" + ) + logging.getLogger("MA5").debug( + "Scale variations = " + str(scale_vars) + ) # Nominal histo central_scale = weight_set["weights"].central_scale - nominal_loc = weight_set["weights"].get_scale(dynamic=dyn_scale, muf=central_scale, mur=central_scale).loc - logging.getLogger("MA5").debug("Nominal weight location = " + str(nominal_loc)) + nominal_loc = ( + weight_set["weights"] + .get_scale( + dynamic=dyn_scale, muf=central_scale, mur=central_scale + ) + .loc + ) + logging.getLogger("MA5").debug( + "Nominal weight location = " + str(nominal_loc) + ) current_histo = np.squeeze(full_histo[:, nominal_loc]) # Scale variation envelope if weight_set["weights"].has_scale: - upper_histo = np.copy(current_histo) - lower_histo = np.copy(current_histo) - for x in scale_vars: - scale_histo = np.squeeze(full_histo[:, x.loc]) - for i, mybin in enumerate(current_histo): - if upper_histo[i] < scale_histo[i]: upper_histo[i] = scale_histo[i] - if lower_histo[i] > scale_histo[i]: lower_histo[i] = scale_histo[i] - upper_scale = np.abs(upper_histo - current_histo) - lower_scale = np.abs(lower_histo - current_histo) - scale_unc = np.vstack([lower_scale, upper_scale]) + upper_histo = np.max( + np.hstack( + [ + np.copy(current_histo).reshape(-1, 1), + full_histo[:, scale_vars.loc], + ] + ), + axis=1, + ) + lower_histo = np.min( + np.hstack( + [ + np.copy(current_histo).reshape(-1, 1), + full_histo[:, scale_vars.loc], + ] + ), + axis=1, + ) + scale_unc = np.vstack( + [ + np.abs(lower_histo - current_histo), + np.abs(upper_histo - current_histo), + ] + ) # PDF variations if len(weight_set["pdf_variations"]) != 0: - pdf_unc = {}; + pdf_unc = {} for pdf_set, pdf_weights in weight_set["pdf_variations"].items(): - pdfvar_loc = pdf_weights.loc + nominal_loc + pdfvar_loc = pdf_weights.loc + nominal_loc pdfvar_histo = full_histo[:, pdf_weights.loc] ### Method to use for PDF uncertainties ### TODO: verify that this works for all standard sets - method = "replicas" if (("NNPDF" in pdf_set and not "hessian" in pdf_set) or ("PDF4LHC" in pdf_set and "_mc_" in pdf_set)) else "hessian" - logging.getLogger("MA5").debug(f"Using {method} pdf combination for {pdf_set} pdf set.") + method = ( + "replicas" + if ( + ("NNPDF" in pdf_set and not "hessian" in pdf_set) + or ("PDF4LHC" in pdf_set and "_mc_" in pdf_set) + ) + else "hessian" + ) + logging.getLogger("MA5").debug( + f"Using {method} pdf combination for {pdf_set} pdf set." + ) ### Replicas method if method == "replicas": mean_histo = np.mean(pdfvar_histo, axis=1) - uncertainties = np.sqrt(np.sum(np.square(pdfvar_histo - mean_histo.reshape(-1, 1)),axis=1)/pdfvar_histo.shape[1]) + uncertainties = np.sqrt( + np.sum( + np.square(pdfvar_histo - mean_histo.reshape(-1, 1)), + axis=1, + ) + / pdfvar_histo.shape[1] + ) ### Hessian method else: - uncertainties = np.sqrt(np.sum(np.square(pdfvar_histo - current_histo.reshape(-1, 1)),axis=1)) + uncertainties = np.sqrt( + np.sum( + np.square( + pdfvar_histo - current_histo.reshape(-1, 1) + ), + axis=1, + ) + ) pdf_unc[pdf_set] = np.vstack([uncertainties, uncertainties]) # TODO give options for both linear and quadrature combination total_unc = None # Two sets of uncertainties if scale_unc is not None and pdf_unc is not None: - lower_unc = scale_unc[0] - upper_unc = scale_unc[1] - for pdf_set, pdf_error in pdf_unc.items(): - lower = np.sqrt(np.square(scale_unc[0]) + np.square(pdf_error[0])) - upper = np.sqrt(np.square(scale_unc[1]) + np.square(pdf_error[1])) - for i, mybin in enumerate(lower): - if lower[i] > lower_unc[i]: lower_unc[i] = lower[i] - if upper[i] > upper_unc[i]: upper_unc[i] = upper[i] + lower_unc = np.hstack( + [ + np.sqrt(np.square(scale_unc[0]) + np.square(pdf_error[0])) + for _, pdf_error in pdf_unc.items() + ] + ) + if len(lower_unc.shape) > 1: + lower_unc = np.min(lower_unc, axis=1) + + upper_unc = np.hstack( + [ + np.sqrt(np.square(scale_unc[1]) + np.square(pdf_error[1])) + for _, pdf_error in pdf_unc.items() + ] + ) + if len(upper_unc.shape) > 1: + upper_unc = np.max(upper_unc, axis=1) total_unc = np.vstack([lower_unc, upper_unc]) # only scale uncertainties elif scale_unc is not None: total_unc = scale_unc # only PDF uncertainties elif pdf_unc is not None: - for pdf_set, pdf_error in pdf_unc.items(): - if total_unc is None: - total_unc = pdf_error - else: - for i, mybin in enumerate(pdf_error[0]): - if total_unc[0][i] > pdf_error[0][i]: total_unc[0][i] = pdf_error[0][i] - if total_unc[1][i] > pdf_error[1][i]: total_unc[1][i] = pdf_error[1][i] + lower_pdf = np.hstack([pdf_error[0] for _, pdf_error in pdf_unc.items()]) + if len(lower_pdf.shape) > 1: + lower_pdf = np.min(lower_pdf, axis=1) + upper_pdf = np.hstack([pdf_error[1] for _, pdf_error in pdf_unc.items()]) + if len(upper_pdf.shape) > 1: + upper_pdf = np.max(upper_pdf, axis=1) + total_unc = np.vstack([lower_pdf, upper_pdf]) outputPy.write(", ".join(f"{x:.8e}" for x in current_histo) + "])\n\n") ntot = float(sum(current_histo)) @@ -1070,7 +1143,7 @@ def DrawMATPLOTLIB( ) outputPy.write("\n") - if upper_scale is not None: + if total_unc is not None: outputPy.write( " pad.errorbar(" + "[x + (xBinning[0] + xBinning[1])/2 for x in xBinning[:-1]]," From dc8f0cd6548f080ac69abc66368f876460cc10fc Mon Sep 17 00:00:00 2001 From: BFuks <fuks@lpthe.jussieu.fr> Date: Tue, 25 Jul 2023 17:20:29 +0200 Subject: [PATCH 069/107] root plots --- .../configuration/weight_configuration.py | 2 +- madanalysis/layout/plotflow.py | 437 ++++++++++-------- 2 files changed, 238 insertions(+), 201 deletions(-) diff --git a/madanalysis/configuration/weight_configuration.py b/madanalysis/configuration/weight_configuration.py index 78991a07..deaddd95 100644 --- a/madanalysis/configuration/weight_configuration.py +++ b/madanalysis/configuration/weight_configuration.py @@ -234,7 +234,7 @@ def scales(self) -> Dict[Text, List[float]]: @property def has_scale(self) -> bool: """is there any scale variations""" - return len(self.scales["muf"]) > 0 + return (len(self.scales["mur"]) > 0) or (len(self.scales["muf"]) > 0) @property def central_scale(self) -> float: diff --git a/madanalysis/layout/plotflow.py b/madanalysis/layout/plotflow.py index a51af5bd..40e6aafc 100644 --- a/madanalysis/layout/plotflow.py +++ b/madanalysis/layout/plotflow.py @@ -182,7 +182,7 @@ def DrawAll(self, histo_path, modes, output_paths, ListROOTplots): logging.getLogger("MA5").debug("Producing file " + filenameC + " ...") if self.main.archi_info.has_root: - self.DrawROOT(histos, scales, select, irelhisto, filenameC, output_files) + self.DrawROOT(histos, scales, datasets, select, irelhisto, filenameC, output_files) logging.getLogger("MA5").debug("Producing file " + filenamePy + " ...") self.DrawMATPLOTLIB( @@ -197,7 +197,7 @@ def DrawAll(self, histo_path, modes, output_paths, ListROOTplots): return True - def DrawROOT(self, histos, scales, ref, irelhisto, filenameC, outputnames): + def DrawROOT(self, histos, scales, datasets, ref, irelhisto, filenameC, outputnames): # Is there any legend? legendmode = False @@ -261,7 +261,6 @@ def DrawROOT(self, histos, scales, ref, irelhisto, filenameC, outputnames): outputC.write(" gStyle->SetOptStat(0);\n") outputC.write(" gStyle->SetOptTitle(0);\n") outputC.write(" canvas->SetHighLightColor(2);\n") - # outputC.write(' canvas->Range(-2.419355,-0.005372711,16.93548,0.03939988);\n') outputC.write(" canvas->SetFillColor(0);\n") outputC.write(" canvas->SetBorderMode(0);\n") outputC.write(" canvas->SetBorderSize(3);\n") @@ -270,9 +269,7 @@ def DrawROOT(self, histos, scales, ref, irelhisto, filenameC, outputnames): outputC.write(" canvas->SetTickx(1);\n") outputC.write(" canvas->SetTicky(1);\n") outputC.write(" canvas->SetLeftMargin(0.14);\n") - margin = 0.05 - if legendmode: - margin = 0.3 + margin = 0.3 if legendmode else 0.05 outputC.write(" canvas->SetRightMargin(" + str(margin) + ");\n") outputC.write(" canvas->SetBottomMargin(0.15);\n") outputC.write(" canvas->SetTopMargin(0.05);\n") @@ -280,25 +277,29 @@ def DrawROOT(self, histos, scales, ref, irelhisto, filenameC, outputnames): # Binning xnbin = histos[0].nbins + xmin = histos[0].xmin + xmax = histos[0].xmax if logxhisto: outputC.write(" // Histo binning\n") outputC.write(" Double_t xBinning[" + str(xnbin + 1) + "] = {") - for bin in range(1, xnbin + 2): - if bin != 1: + for mybin in range(1, xnbin + 2): + if mybin != 1: outputC.write(",") outputC.write(str(histos[0].GetBinLowEdge(bin))) outputC.write("};\n") outputC.write("\n") - # Loop over datasets and histos + # Loop over datasets for a given histogram ntot = 0 for ind, hist in enumerate(histos): + logging.getLogger("MA5").debug(f"<><><><><><> {hist.name} <><><><><><>") - # Creating TH1F - outputC.write(" // Creating a new TH1F\n") + # Getting the list of weights, if any + weight_set = self.GetWeights(datasets[ind]); + + # Creating a new TH1F histo (one for each dataset) + outputC.write(" // Creating a new TH1F for histo:" + hist.name + "\n") histoname = "S" + hist.name + "_" + str(ind) - xmin = hist.xmin - xmax = hist.xmax if logxhisto: outputC.write( " TH1F* " @@ -314,8 +315,10 @@ def DrawROOT(self, histos, scales, ref, irelhisto, filenameC, outputnames): else: outputC.write( " TH1F* " +# " TGraphAsymmErrors* " + histoname + ' = new TH1F("' +# + ' = new TGraphAsymmErrors("' + histoname + '","' + histoname @@ -328,6 +331,9 @@ def DrawROOT(self, histos, scales, ref, irelhisto, filenameC, outputnames): + ");\n" ) + # Get histogram data + current_histo, uncertainties = self.GetHisto(hist.summary, datasets[ind], scales[ind], weight_set) + # TH1F content outputC.write(" // Content\n") outputC.write( @@ -338,18 +344,27 @@ def DrawROOT(self, histos, scales, ref, irelhisto, filenameC, outputnames): + str(hist.summary.underflow * scales[ind]) + "); // underflow\n" ) - for bin in range(1, xnbin + 1): - print(hist.summary.array, scales) - ntot += hist.summary.array[bin - 1] * scales[ind] + for mybin in range(1, xnbin + 1): + ntot += current_histo[mybin - 1] outputC.write( " " + histoname + "->SetBinContent(" - + str(bin) + + str(mybin) + "," - + str(hist.summary.array[bin - 1] * scales[ind]) + + str(current_histo[mybin - 1]) + ");\n" ) + if uncertainties!=None: + outputC.write( + " " + + histoname + + "->SetBinError(" + + str(mybin) + + "," + + str(max(uncertainties[0, mybin-1],uncertainties[1, mybin-1])) + + ");\n" + ) nentries = hist.summary.nentries outputC.write( " " @@ -688,10 +703,10 @@ def DrawMATPLOTLIB( outputPy.write(" # Histo binning\n") if logxhisto: outputPy.write(" xBinning = [") - for bin in range(1, xnbin + 2): - if bin != 1: + for mybin in range(1, xnbin + 2): + if mybin != 1: outputPy.write(",") - outputPy.write(str(histos[0].GetBinLowEdge(bin))) + outputPy.write(str(histos[0].GetBinLowEdge(mybin))) outputPy.write("]\n") outputPy.write("\n") else: @@ -714,190 +729,21 @@ def DrawMATPLOTLIB( + "])\n\n" ) - # Loop over datasets and histos + # Loop over datasets for a given histogram ntot = 0 for ind, hist in enumerate(histos): logging.getLogger("MA5").debug(f"<><><><><><> {hist.name} <><><><><><>") - ######################################################################## - # weight_set - dictionary structure: # - # - "weights": are nominal weights including scale uncertainties # - # - "pdf_variations": PDF variations # - ######################################################################## - weight_set = {} - if len(datasets[ind].weight_collection) > 1: - # separate the weights related to PDF variations from the other weights - for pdfid in datasets[ind].weight_collection.pdfsets: - if pdfid in self.pdftable: - weight_set.update( - {"weights": datasets[ind].weight_collection.pdfset(pdfid)} - ) - weight_set.update( - { - "pdf_variations": { - self.pdftable[pdfid]["name"]: WeightCollection() - } - } - ) - for idx in range(1, self.pdftable[pdfid]["members"]): - weight_set["pdf_variations"][ - self.pdftable[pdfid]["name"] - ] += datasets[ind].weight_collection.pdfset(pdfid + idx) - - # Some checks - if len(weight_set) == 0: - logging.getLogger("MA5").debug("No additional source of uncertainty") - else: - logging.getLogger("MA5").debug(weight_set) + # Getting the list of weights, if any + weight_set = self.GetWeights(datasets[ind]); - # Creating a new histo + # Creating a new histo (one for each dataset) + outputPy.write(" # Creating weights for histo: " + hist.name + "\n") histoname = "y" + hist.name + "_" + str(ind) - outputPy.write(" # Creating weights for histo: " + histoname + "\n") - outputPy.write(" " + histoname + "_weights = np.array([") - current_histo = hist.summary.array * scales[ind] - full_histo = hist.summary.array_full * scales[ind] - upper_scale, lower_scale = None, None - upper_pdf, lower_pdf = None, None - scale_unc, pdf_unc = None, None - if len(weight_set) != 0: - # Get the nominal weight - if weight_set["weights"].has_scale: - # Configuration - dyn_scale = datasets[ind].dynamic_scale_choice - n_point_scale = datasets[ind].n_point_scale_variation - scale_vars = weight_set["weights"].get_scale_vars( - point=n_point_scale, dynamic=dyn_scale - ) - logging.getLogger("MA5").debug( - "Dyn. scale configuration " - + str(dyn_scale) - + "; " - + str(n_point_scale) - + "points" - ) - logging.getLogger("MA5").debug( - "Scale variations = " + str(scale_vars) - ) - - # Nominal histo - central_scale = weight_set["weights"].central_scale - nominal_loc = ( - weight_set["weights"] - .get_scale( - dynamic=dyn_scale, muf=central_scale, mur=central_scale - ) - .loc - ) - logging.getLogger("MA5").debug( - "Nominal weight location = " + str(nominal_loc) - ) - current_histo = np.squeeze(full_histo[:, nominal_loc]) - - # Scale variation envelope - if weight_set["weights"].has_scale: - upper_histo = np.max( - np.hstack( - [ - np.copy(current_histo).reshape(-1, 1), - full_histo[:, scale_vars.loc], - ] - ), - axis=1, - ) - lower_histo = np.min( - np.hstack( - [ - np.copy(current_histo).reshape(-1, 1), - full_histo[:, scale_vars.loc], - ] - ), - axis=1, - ) - scale_unc = np.vstack( - [ - np.abs(lower_histo - current_histo), - np.abs(upper_histo - current_histo), - ] - ) - - # PDF variations - if len(weight_set["pdf_variations"]) != 0: - pdf_unc = {} - for pdf_set, pdf_weights in weight_set["pdf_variations"].items(): - pdfvar_loc = pdf_weights.loc + nominal_loc - pdfvar_histo = full_histo[:, pdf_weights.loc] - - ### Method to use for PDF uncertainties - ### TODO: verify that this works for all standard sets - method = ( - "replicas" - if ( - ("NNPDF" in pdf_set and not "hessian" in pdf_set) - or ("PDF4LHC" in pdf_set and "_mc_" in pdf_set) - ) - else "hessian" - ) - logging.getLogger("MA5").debug( - f"Using {method} pdf combination for {pdf_set} pdf set." - ) - - ### Replicas method - if method == "replicas": - mean_histo = np.mean(pdfvar_histo, axis=1) - uncertainties = np.sqrt( - np.sum( - np.square(pdfvar_histo - mean_histo.reshape(-1, 1)), - axis=1, - ) - / pdfvar_histo.shape[1] - ) - ### Hessian method - else: - uncertainties = np.sqrt( - np.sum( - np.square( - pdfvar_histo - current_histo.reshape(-1, 1) - ), - axis=1, - ) - ) - pdf_unc[pdf_set] = np.vstack([uncertainties, uncertainties]) - - # TODO give options for both linear and quadrature combination - total_unc = None - # Two sets of uncertainties - if scale_unc is not None and pdf_unc is not None: - lower_unc = np.hstack( - [ - np.sqrt(np.square(scale_unc[0]) + np.square(pdf_error[0])) - for _, pdf_error in pdf_unc.items() - ] - ) - if len(lower_unc.shape) > 1: - lower_unc = np.min(lower_unc, axis=1) - - upper_unc = np.hstack( - [ - np.sqrt(np.square(scale_unc[1]) + np.square(pdf_error[1])) - for _, pdf_error in pdf_unc.items() - ] - ) - if len(upper_unc.shape) > 1: - upper_unc = np.max(upper_unc, axis=1) - total_unc = np.vstack([lower_unc, upper_unc]) - # only scale uncertainties - elif scale_unc is not None: - total_unc = scale_unc - # only PDF uncertainties - elif pdf_unc is not None: - lower_pdf = np.hstack([pdf_error[0] for _, pdf_error in pdf_unc.items()]) - if len(lower_pdf.shape) > 1: - lower_pdf = np.min(lower_pdf, axis=1) - upper_pdf = np.hstack([pdf_error[1] for _, pdf_error in pdf_unc.items()]) - if len(upper_pdf.shape) > 1: - upper_pdf = np.max(upper_pdf, axis=1) - total_unc = np.vstack([lower_pdf, upper_pdf]) + # Get histogram data + current_histo, uncertainties = self.GetHisto(hist.summary, datasets[ind], scales[ind], weight_set) + outputPy.write(" " + histoname + "_weights = np.array([") outputPy.write(", ".join(f"{x:.8e}" for x in current_histo) + "])\n\n") ntot = float(sum(current_histo)) @@ -1143,11 +989,11 @@ def DrawMATPLOTLIB( ) outputPy.write("\n") - if total_unc is not None: + if uncertainties is not None: outputPy.write( " pad.errorbar(" + "[x + (xBinning[0] + xBinning[1])/2 for x in xBinning[:-1]]," - + f"{myweights}, yerr={total_unc.tolist()}," + + f"{myweights}, yerr={uncertainties.tolist()}," + " fmt='.', elinewidth=1, capsize=2)\n\n" ) @@ -1351,3 +1197,194 @@ def DrawMATPLOTLIB( # Ok return True + + + ## Getting the list of weights associated with a histogram + def GetWeights(self, dataset): + ######################################################################## + # weight_set - dictionary structure: # + # - "weights": are nominal weights including scale uncertainties # + # - "pdf_variations": PDF variations # + ######################################################################## + + # Initialisation + weight_set = {} + + # Main body of the function + if len(dataset.weight_collection) > 1: + # separate the weights related to PDF variations from the other weights + for pdfid in dataset.weight_collection.pdfsets: + if pdfid in self.pdftable: + weight_set.update( + {"weights": dataset.weight_collection.pdfset(pdfid)} + ) + weight_set.update( + { + "pdf_variations": { + self.pdftable[pdfid]["name"]: WeightCollection() + } + } + ) + for idx in range(1, self.pdftable[pdfid]["members"]): + weight_set["pdf_variations"][ + self.pdftable[pdfid]["name"] + ] += dataset.weight_collection.pdfset(pdfid + idx) + # Some checks + if len(weight_set) == 0: + logging.getLogger("MA5").debug("No additional source of uncertainty") + else: + logging.getLogger("MA5").debug(weight_set) + + # Return + return weight_set + + + ## Getting the histogram, with error bars + def GetHisto(self, histo_data, dataset, scale, weights): + # default histogram (single weight) + current_histo = histo_data.array * scale + if len(weights) == 0: + return current_histo, None + + # Many weights - initialisation + full_histo = histo_data.array_full * scale + upper_scale, lower_scale = None, None + upper_pdf, lower_pdf = None, None + scale_unc, pdf_unc = None, None + dyn_scale = dataset.dynamic_scale_choice + n_point_scale = dataset.n_point_scale_variation + logging.getLogger("MA5").debug( + "Dyn. scale configuration " + + str(dyn_scale) + + "; " + + str(n_point_scale) + + "points" + ) + + # Get the nominal weight + if weights["weights"].has_scale: + # Configuration + scale_vars = weights["weights"].get_scale_vars(point=n_point_scale, dynamic=dyn_scale) + logging.getLogger("MA5").debug("Scale vars = " + str(scale_vars)) + + # Nominal histo + central_scale = weights["weights"].central_scale + nominal = ( + weights["weights"] + .get_scale( + dynamic=dyn_scale, muf=central_scale, mur=central_scale + ) + .loc + ) + logging.getLogger("MA5").debug("Nominal weight = " + str(nominal)) + current_histo = np.squeeze(full_histo[:, nominal]) + + # Scale variation envelope + if weights["weights"].has_scale: + upper_histo = np.max( + np.hstack( + [ + np.copy(current_histo).reshape(-1, 1), + full_histo[:, scale_vars.loc], + ] + ), + axis=1, + ) + lower_histo = np.min( + np.hstack( + [ + np.copy(current_histo).reshape(-1, 1), + full_histo[:, scale_vars.loc], + ] + ), + axis=1, + ) + scale_unc = np.vstack( + [ + np.abs(lower_histo - current_histo), + np.abs(upper_histo - current_histo), + ] + ) + + # PDF variations + if len(weights["pdf_variations"]) != 0: + pdf_unc = {} + for pdf_set, pdf_weights in weights["pdf_variations"].items(): + pdfvar_loc = pdf_weights.loc + nominal + pdfvar_histo = full_histo[:, pdf_weights.loc] + + ### Method to use for PDF uncertainties + ### TODO: verify that this works for all standard sets + method = ( + "replicas" + if ( + ("NNPDF" in pdf_set and not "hessian" in pdf_set) + or ("PDF4LHC" in pdf_set and "_mc_" in pdf_set) + ) + else "hessian" + ) + logging.getLogger("MA5").debug( + f"Using {method} pdf combination for {pdf_set} pdf set." + ) + + ### Replicas method + if method == "replicas": + mean_histo = np.mean(pdfvar_histo, axis=1) + uncertainties = np.sqrt( + np.sum( + np.square(pdfvar_histo - mean_histo.reshape(-1, 1)), + axis=1, + ) + / pdfvar_histo.shape[1] + ) + ### Hessian method + else: + uncertainties = np.sqrt( + np.sum( + np.square( + pdfvar_histo - current_histo.reshape(-1, 1) + ), + axis=1, + ) + ) + pdf_unc[pdf_set] = np.vstack([uncertainties, uncertainties]) + + # Total uncertainties + # TODO give options for both linear and quadrature combination + total_unc = None + # Two sets of uncertainties + if scale_unc is not None and pdf_unc is not None: + lower_unc = np.hstack( + [ + np.sqrt(np.square(scale_unc[0]) + np.square(pdf_error[0])) + for _, pdf_error in pdf_unc.items() + ] + ) + if len(lower_unc.shape) > 1: + lower_unc = np.min(lower_unc, axis=1) + + upper_unc = np.hstack( + [ + np.sqrt(np.square(scale_unc[1]) + np.square(pdf_error[1])) + for _, pdf_error in pdf_unc.items() + ] + ) + if len(upper_unc.shape) > 1: + upper_unc = np.max(upper_unc, axis=1) + total_unc = np.vstack([lower_unc, upper_unc]) + # only scale uncertainties + elif scale_unc is not None: + total_unc = scale_unc + # only PDF uncertainties + elif pdf_unc is not None: + lower_pdf = np.hstack([pdf_error[0] for _, pdf_error in pdf_unc.items()]) + if len(lower_pdf.shape) > 1: + lower_pdf = np.min(lower_pdf, axis=1) + upper_pdf = np.hstack([pdf_error[1] for _, pdf_error in pdf_unc.items()]) + if len(upper_pdf.shape) > 1: + upper_pdf = np.max(upper_pdf, axis=1) + total_unc = np.vstack([lower_pdf, upper_pdf]) + + # output + return current_histo, total_unc + From 01ef5275a47ba69b3c0bed178b340d4216f6ab03 Mon Sep 17 00:00:00 2001 From: BFuks <fuks@lpthe.jussieu.fr> Date: Tue, 25 Jul 2023 17:24:06 +0200 Subject: [PATCH 070/107] small bug fix in root file generation --- madanalysis/layout/plotflow.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/madanalysis/layout/plotflow.py b/madanalysis/layout/plotflow.py index 40e6aafc..ab4fb63a 100644 --- a/madanalysis/layout/plotflow.py +++ b/madanalysis/layout/plotflow.py @@ -355,7 +355,7 @@ def DrawROOT(self, histos, scales, datasets, ref, irelhisto, filenameC, outputna + str(current_histo[mybin - 1]) + ");\n" ) - if uncertainties!=None: + if not uncertainties is None: outputC.write( " " + histoname From 0572f2231894b49b2bf094a63a7ff79b4a802c3c Mon Sep 17 00:00:00 2001 From: "Jack Y. Araz" <jackaraz@gmail.com> Date: Tue, 25 Jul 2023 17:46:58 +0100 Subject: [PATCH 071/107] bugfix for histogram initialisation --- tools/SampleAnalyzer/Process/Plot/Histo.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tools/SampleAnalyzer/Process/Plot/Histo.cpp b/tools/SampleAnalyzer/Process/Plot/Histo.cpp index 7d0bb558..be18bf3f 100644 --- a/tools/SampleAnalyzer/Process/Plot/Histo.cpp +++ b/tools/SampleAnalyzer/Process/Plot/Histo.cpp @@ -204,6 +204,11 @@ void Histo::_initialize(const WeightCollection &weights) sum_ww_[idx] = WEIGHTS(); sum_xw_[idx] = WEIGHTS(); sum_xxw_[idx] = WEIGHTS(); + for (MAuint32 idb = 0; idb < nbins_; idb++) + { + histo_[idb][idx] = WEIGHTS(); + histo_[idb][idx] = WEIGHTS(); + } } } From 23f55252dac9c1b7ba0871b56cea240667980076 Mon Sep 17 00:00:00 2001 From: BFuks <fuks@lpthe.jussieu.fr> Date: Wed, 26 Jul 2023 17:31:37 +0200 Subject: [PATCH 072/107] starting to fix bugs in cutflows + generalisation --- madanalysis/IOinterface/job_reader.py | 6 +- .../configuration/weight_configuration.py | 71 ++++++++++--------- madanalysis/dataset/dataset.py | 14 +++- madanalysis/layout/histogram_processor.py | 6 +- madanalysis/layout/plotflow.py | 12 ++-- madanalysis/layout/plotflow_for_dataset.py | 7 +- 6 files changed, 73 insertions(+), 43 deletions(-) diff --git a/madanalysis/IOinterface/job_reader.py b/madanalysis/IOinterface/job_reader.py index 5b260c15..24963f77 100644 --- a/madanalysis/IOinterface/job_reader.py +++ b/madanalysis/IOinterface/job_reader.py @@ -722,6 +722,7 @@ def ExtractCuts(self, dataset, cut): numline += 1 # Removing comments + is_comment_line = (len(line.split('#'))==2 and line.split('#')[-1]=='\n') index = line.find("#") if index != -1: line = line[:index] @@ -755,8 +756,9 @@ def ExtractCuts(self, dataset, cut): cutflow_for_region.append(copy.copy(cutinfo)) cutinfo.Reset() - elif initialTag.activated and len(words) == 2: + elif initialTag.activated and not is_comment_line and len(words) >= 2: results = self.ExtractCutLine(words, numline, myfile) + print(numline, results) if initialTag.Nlines == 0: cut.initial.nentries_pos = results[0] cut.initial.nentries_neg = results[1] @@ -778,7 +780,7 @@ def ExtractCuts(self, dataset, cut): logging.getLogger("MA5").warning("Extra line is found: " + line) cutTag.newline() - elif cutTag.activated and len(words) == 2: + elif cutTag.activated and len(words) >= 2: results = self.ExtractCutLine(words, numline, myfile) if cutTag.Nlines == 1: cutinfo.nentries_pos = results[0] diff --git a/madanalysis/configuration/weight_configuration.py b/madanalysis/configuration/weight_configuration.py index deaddd95..7f1a6861 100644 --- a/madanalysis/configuration/weight_configuration.py +++ b/madanalysis/configuration/weight_configuration.py @@ -39,15 +39,24 @@ class Weight: _mur: float = field(init=False, default=None) _pdf: int = field(init=False, default=None) _merging: float = field(init=False, default=None) + _alphas: float = field(init=False, default=None) def __post_init__(self) -> None: self.name = self.name.replace("DYN_SCALE", "DYNSCALE") sectors = self.name.split("_") + # PYTHIA NOMINAL WEIGHT + # -> note: to ignore, we need to use the MG5 nominal weight + if self.name is "Weight": + return + for sector in sectors: if "AUX" in sector: self._aux = int(sectors[1]) break + elif any([x in sector for x in ["scomp", "smax", "smin"]]): + self._aux = float(sector.split("=")[1]) + break if "MERGING" in sector: self._merging = float(sector.split("=")[1]) elif "DYNSCALE" in sector: @@ -58,12 +67,15 @@ def __post_init__(self) -> None: self._mur = float(sector.split("=")[1]) elif "PDF" in sector: self._pdf = int(sector.split("=")[1]) + elif "ALPSFACT" in sector: + self._alphas= float(sector.split("=")[1]) def __repr__(self) -> Text: return ( f"Weight(loc={self.loc}, pdf={self.pdfset}, " + f"muf={self.muf}, mur={self.mur}, dynamic={self.dynamic_scale}, " - + f"merging={self.merging}, aux={self.aux})" + + f"merging={self.merging}, aux={self.aux}, " + + f"alpsfac={self.alphas})" ) def __str__(self) -> Text: @@ -75,51 +87,38 @@ def to_dict(self) -> Dict[Text, Any]: @property def aux(self) -> int: - """retreive aux value""" + """retrieve aux value""" return self._aux @property def dynamic_scale(self) -> int: - """retreive dynamic scale""" + """retrieve dynamic scale""" return self._dyn_scale @property def muf(self) -> float: - """retreive factorisation scale""" + """retrieve the factorisation scale variation""" return self._muf @property def mur(self) -> float: - """retreive **forget the name** scale""" + """retrieve the renormalisation scale variation""" return self._mur @property def pdfset(self) -> int: - """retreive pdf set id""" + """retrieve pdf set id""" return self._pdf @property def merging(self) -> float: - """retreive merging scale""" + """retrieve merging scale""" return self._merging @property - def is_nominal(self) -> bool: - """Return true if the weight is nominal""" - if all( - x is None - for x in [ - self.aux, - self.pdfset, - self.dynamic_scale, - self.muf, - self.mur, - self.merging, - ] - ): - return True - - return False + def alphas(self) -> float: + """retrieve the alpha_s variation""" + return self._alphas class WeightCollection: @@ -154,7 +153,7 @@ def __getitem__(self, index: int) -> Weight: @property def names(self) -> List[Text]: - """retreive weight names""" + """retrieve weight names""" if len(self) == len(self._names): return self._names @@ -170,12 +169,16 @@ def from_dict(self, data: List[Dict[Text, Any]]) -> None: for dat in data: self.append(dat["name"], dat["loc"]) - @property - def nominal(self) -> Weight: + def nominal(self, scale_choice: int, central_pdfs: np.array) -> Weight: """Get nominal weight""" for w in self: - if w.is_nominal: - return w + if any([not x is None for x in [w.aux, w.alphas]]): + continue + if w.muf!=1.0 or w.mur!=1.0 or w.dynamic_scale!=scale_choice: + continue + if not w.pdfset in central_pdfs: + continue + return w raise ValueError("Cannot find nominal weight") def group_for(self, group: Text) -> Dict: @@ -197,14 +200,14 @@ def group_for(self, group: Text) -> Dict: return group_dict def pdfset(self, pdfid: int) -> List[Weight]: - """retreive weights corresponding to one pdf set""" + """retrieve weights corresponding to one pdf set""" return WeightCollection([w for w in self if w.pdfset == pdfid]) def get(self, **kwargs) -> List[Weight]: if len(kwargs) == 0: return [] collection = [] - keys = ["muf", "mur", "dynamic_scale", "pdfset", "merging"] + keys = ["muf", "mur", "dynamic_scale", "pdfset", "merging", "alphas"] for weight in self: add = True @@ -238,7 +241,7 @@ def has_scale(self) -> bool: @property def central_scale(self) -> float: - """retreive central scale""" + """retrieve central scale""" scales = self.scales["muf"] return scales[len(scales) // 2] @@ -249,6 +252,8 @@ def get_scale_vars(self, point: int = 3, dynamic: int = None) -> Tuple: scale_choices = [] all_scale_choices = [] for w in self: + if not w.alphas is None: + continue if w.dynamic_scale == dynamic: all_scale_choices.append([w.muf, w.mur]) if point == 3: @@ -289,7 +294,7 @@ def get_scale( [ w for w in self - if w.dynamic_scale == dynamic and w.muf == muf and w.mur == mur + if w.dynamic_scale == dynamic and w.muf == muf and w.mur == mur and w.alphas is None ] ) @@ -303,7 +308,7 @@ def has_dyn_scale(self, scale: int) -> bool: @property def loc(self) -> List[int]: - """retreive the locations of the weights""" + """retrieve the locations of the weights""" return [w.loc for w in self] def __iadd__(self, other): diff --git a/madanalysis/dataset/dataset.py b/madanalysis/dataset/dataset.py index a2fecd8b..46df892b 100644 --- a/madanalysis/dataset/dataset.py +++ b/madanalysis/dataset/dataset.py @@ -77,7 +77,10 @@ class Dataset: "pdf_down_variation": [], "pdf_variation": [], "dynamic_scale_choice": ["1", "2", "3", "4"], - "n_point_scale_variation": ["3", "5", "7", "9"], + "n_point_scale_variation": ["3", "7", "9"], + "include_merging_scale_variation": [True, False], + "include_pdfset_variation": [True, False], + "include_scale_variation": [True, False], "title": [], "weighted_events": ["true", "false"], } @@ -103,10 +106,19 @@ def __init__(self, name): self.weighted_events = True self.measured_global = SampleInfo() self.measured_detail = [] + + # Reweighting self.weight_collection: WeightCollection = WeightCollection() + + # scale variation calculations self.dynamic_scale_choice = None self.n_point_scale_variation = 3 + # Turning all elements of uncertainty calculations to on or off + self.include_merging_scale_variation = True + self.include_scale_variation = True + self.include_pdfset_variation = True + def __len__(self): return len(self.filenames) diff --git a/madanalysis/layout/histogram_processor.py b/madanalysis/layout/histogram_processor.py index b0cebcf3..cbfcb7d7 100644 --- a/madanalysis/layout/histogram_processor.py +++ b/madanalysis/layout/histogram_processor.py @@ -82,19 +82,21 @@ def __post_init__(self): self.bin_weights = positive_bin_weights - negative_bin_weights self.integral = np.sum(self.bin_weights, axis=0) + self.overflow + self.underflow - def scale(self, lumi: float) -> float: + def scale(self, lumi: float, scale_choice: int, central_pdfs: np.array) -> float: """ Compute the scale of the nominal histogram Args: lumi (``float``): luminosity in fb-1 + scale_choice (``int``): tag indicating how the central scale choice has been made + central_pdfs (``np.array``): list with all acceptable PDF choices for the central set Returns: ``float``: scale of the histogram """ # find nominal weight location - idx = self.weight_collection.nominal.loc + idx = self.weight_collection.nominal(scale_choice=scale_choice, central_pdfs=central_pdfs).loc if self.integral[idx] == 0: return 0.0 diff --git a/madanalysis/layout/plotflow.py b/madanalysis/layout/plotflow.py index ab4fb63a..1791fedd 100644 --- a/madanalysis/layout/plotflow.py +++ b/madanalysis/layout/plotflow.py @@ -315,10 +315,8 @@ def DrawROOT(self, histos, scales, datasets, ref, irelhisto, filenameC, outputna else: outputC.write( " TH1F* " -# " TGraphAsymmErrors* " + histoname + ' = new TH1F("' -# + ' = new TGraphAsymmErrors("' + histoname + '","' + histoname @@ -345,7 +343,6 @@ def DrawROOT(self, histos, scales, datasets, ref, irelhisto, filenameC, outputna + "); // underflow\n" ) for mybin in range(1, xnbin + 1): - ntot += current_histo[mybin - 1] outputC.write( " " + histoname @@ -366,6 +363,7 @@ def DrawROOT(self, histos, scales, datasets, ref, irelhisto, filenameC, outputna + ");\n" ) nentries = hist.summary.nentries + ntot = float(sum(current_histo)) outputC.write( " " + histoname @@ -1248,11 +1246,13 @@ def GetHisto(self, histo_data, dataset, scale, weights): # Many weights - initialisation full_histo = histo_data.array_full * scale + upper_merging, lower_merging = None, None upper_scale, lower_scale = None, None upper_pdf, lower_pdf = None, None - scale_unc, pdf_unc = None, None + scale_unc, pdf_unc, merging_unc = None, None, None dyn_scale = dataset.dynamic_scale_choice n_point_scale = dataset.n_point_scale_variation + merging_scale = dataset.merging_scale_variation logging.getLogger("MA5").debug( "Dyn. scale configuration " + str(dyn_scale) @@ -1260,6 +1260,10 @@ def GetHisto(self, histo_data, dataset, scale, weights): + str(n_point_scale) + "points" ) + logging.getLogger("MA5").debug( + "Merging scale configuration " + + str(merging_scale) + ) # Get the nominal weight if weights["weights"].has_scale: diff --git a/madanalysis/layout/plotflow_for_dataset.py b/madanalysis/layout/plotflow_for_dataset.py index 40c2b855..ed0008e1 100644 --- a/madanalysis/layout/plotflow_for_dataset.py +++ b/madanalysis/layout/plotflow_for_dataset.py @@ -131,8 +131,13 @@ def ComputeScale(self): thexsection = self.xsection if self.main.normalize == NormalizeType.LUMI_WEIGHT: thexsection = thexsection * self.dataset.weight + pdf_list = [] + import os + with open(os.path.join(self.main.archi_info.ma5dir, "madanalysis/input/LHAPDF.txt"), "r") as f: + for line in f.readlines()[1:]: + pdf_list.append(int(line.split(",")[0])) - scale = processor.scale(lumi=self.main.lumi) + scale = processor.scale(lumi=self.main.lumi, scale_choice=self.dataset.dynamic_scale_choice, central_pdfs = pdf_list) # Setting the computing scale self.histos[iplot].scale = copy.copy(scale) From e026f3da06d2cd274c4e79e192ce43e264e2e55b Mon Sep 17 00:00:00 2001 From: "Jack Y. Araz" <jackaraz@gmail.com> Date: Tue, 2 Jan 2024 11:31:32 -0500 Subject: [PATCH 073/107] restore --- madanalysis/layout/histogram.py | 157 +- madanalysis/layout/plotflow.py | 1629 ++++++++------------ madanalysis/layout/plotflow_for_dataset.py | 101 +- 3 files changed, 758 insertions(+), 1129 deletions(-) diff --git a/madanalysis/layout/histogram.py b/madanalysis/layout/histogram.py index 84f8db7f..c3a75701 100644 --- a/madanalysis/layout/histogram.py +++ b/madanalysis/layout/histogram.py @@ -1,144 +1,125 @@ ################################################################################ -# +# # Copyright (C) 2012-2023 Jack Araz, Eric Conte & Benjamin Fuks # The MadAnalysis development team, email: <ma5team@iphc.cnrs.fr> -# +# # This file is part of MadAnalysis 5. # Official website: <https://github.com/MadAnalysis/madanalysis5> -# +# # MadAnalysis 5 is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. -# +# # MadAnalysis 5 is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. -# +# # You should have received a copy of the GNU General Public License # along with MadAnalysis 5. If not, see <http://www.gnu.org/licenses/> -# +# ################################################################################ from __future__ import absolute_import -import logging -import numpy as np from madanalysis.layout.histogram_core import HistogramCore +import logging +from six.moves import range class Histogram: + def __init__(self): self.Reset() + def Print(self): # General info - inform = self.name + " " + str(self.nbins) + str(self.xmin) + " " + str(self.xmax) - if self.ymin != [] or self.ymax != []: - inform = inform + " " + str(self.ymin) + " " + str(self.ymax) - logging.getLogger("MA5").info(inform) + inform = self.name + ' ' + str(self.nbins) + str(self.xmin) + ' ' + str(self.xmax) + if self.ymin!=[] or self.ymax!=[]: + inform = inform + ' ' + str(self.ymin) + ' ' + str(self.ymax) + logging.getLogger('MA5').info(inform) # Data self.positive.Print() self.negative.Print() self.summary.Print() - def CreateHistogram(self): - pass - - def FinalizeReading(self, main, dataset): - self.positive.convert_to_numpy() - self.negative.convert_to_numpy() - self.summary.convert_to_numpy() + def FinalizeReading(self,main,dataset): # Statistics - self.summary.nevents = self.positive.nevents + self.negative.nevents - self.summary.nentries = self.positive.nentries + self.negative.nentries + self.summary.nevents = self.positive.nevents + self.negative.nevents + self.summary.nentries = self.positive.nentries + self.negative.nentries # sumw - self.summary.sumw = np.clip(self.positive.sumw - self.negative.sumw, 0, None) + self.summary.sumw = self.positive.sumw - self.negative.sumw + if self.summary.sumw<0: + self.summary.sumw=0 # sumw2 - self.summary.sumw2 = np.clip(self.positive.sumw2 - self.negative.sumw2, 0, None) + self.summary.sumw2 = self.positive.sumw2 - self.negative.sumw2 + if self.summary.sumw2<0: + self.summary.sumw2=0 # sumwx - self.summary.sumwx = self.positive.sumwx - self.negative.sumwx + self.summary.sumwx = self.positive.sumwx - self.negative.sumwx # no correction on it # sumw2x - self.summary.sumw2x = self.positive.sumw2x - self.negative.sumw2x + self.summary.sumw2x = self.positive.sumw2x - self.negative.sumw2x # no correction on it # underflow - self.summary.underflow = np.clip( - self.positive.underflow - self.negative.underflow, 0, None - ) + self.summary.underflow = self.positive.underflow - self.negative.underflow + if self.summary.underflow<0: + self.summary.underflow=0 # overflow - self.summary.overflow = np.clip( - self.positive.overflow - self.negative.overflow, 0, None - ) - - # compute mean and uncertainties for the statistics - # ! @jackaraz: this portion of the code should be changed to accomodate different types of - # ! PDF + scale unc combination for now its just mean and std - for tp in [ - "nevents", - "nentries", - "sumw", - "sumw2", - "sumwx", - "sumw2x", - "underflow", - "overflow", - ]: - # compute unc shape: (lower, upper) - std = float(np.std(getattr(self.summary, tp))) - setattr(self.summary, tp + "_unc", (std, std)) - # compute mean - setattr(self.summary, tp, float(np.mean(getattr(self.summary, tp)))) + self.summary.overflow = self.positive.overflow - self.negative.overflow + if self.summary.overflow<0: + self.summary.overflow=0 # Data data = [] - for i, array in enumerate(self.positive.array): - data.append(np.array(array) - np.array(self.negative.array[i])) - if np.any(data[-1] < 0): - self.warnings.append( - f"dataset={dataset.name} -> bin {i} has a negative content : " - f"{str(data[-1])}. This value is set to zero." - ) - data[-1] = np.clip(data[-1], 0, None) - self.summary.array_full = np.array(data[:]) # [:] -> clone of data - - # Compute the mean and the error on the data - # mean shape should be (Nbins, ) and the histogram unc shape should be (Nbins, 2) - # where first column is the lower envelop and second is upper envelop - histogram_mean = np.mean(self.summary.array_full, axis=1) - self.summary.array = histogram_mean.reshape(-1) + for i in range(0,len(self.positive.array)): + data.append(self.positive.array[i]-self.negative.array[i]) + if data[-1]<0: + self.warnings.append(\ + 'dataset='+dataset.name+\ + ' -> bin '+str(i)+\ + ' has a negative content : '+\ + str(data[-1])+'. This value is set to zero') + data[-1]=0 + self.summary.array = data[:] # [:] -> clone of data # Integral self.positive.ComputeIntegral() self.negative.ComputeIntegral() self.summary.ComputeIntegral() + def CreateHistogram(self): + pass + + + def Reset(self): # General info - self.name = "" + self.name = "" self.nbins = 100 - self.xmin = 0.0 - self.xmax = 100.0 - self.ymin = [] - self.ymax = [] - self.scale = 0.0 + self.xmin = 0. + self.xmax = 100. + self.ymin = [] + self.ymax = [] + self.scale = 0. # Data self.positive = HistogramCore() self.negative = HistogramCore() - self.summary = HistogramCore() + self.summary = HistogramCore() # ROOT histo self.myhisto = 0 @@ -152,47 +133,49 @@ def Reset(self): def GetRegions(self): return self.regions - def GetBinLowEdge(self, bin): + def GetBinLowEdge(self,bin): # Special case - if bin <= 0: + if bin<=0: return self.xmin - if bin >= self.nbins: + if bin>=self.nbins: return self.xmax # Computing steps - step = (self.xmax - self.xmin) / float(self.nbins) + step = (self.xmax - self.xmin) / float (self.nbins) # value - return self.xmin + bin * step + return self.xmin+bin*step + - def GetBinUpperEdge(self, bin): + def GetBinUpperEdge(self,bin): # Special case - if bin <= 0: + if bin<=0: return self.xmin - if bin >= self.nbins: + if bin>=self.nbins: return self.xmax # Computing steps - step = (self.xmax - self.xmin) / float(self.nbins) + step = (self.xmax - self.xmin) / float (self.nbins) # value - return self.xmin + (bin + 1) * step + return self.xmin+(bin+1)*step + - def GetBinMean(self, bin): + def GetBinMean(self,bin): # Special case - if bin < 0: + if bin<0: return self.xmin - if bin >= self.nbins: + if bin>=self.nbins: return self.xmax # Computing steps - step = (self.xmax - self.xmin) / float(self.nbins) + step = (self.xmax - self.xmin) / float (self.nbins) # value - return self.xmin + (bin + 0.5) * step + return self.xmin+(bin+0.5)*step diff --git a/madanalysis/layout/plotflow.py b/madanalysis/layout/plotflow.py index 1791fedd..6ef6f696 100644 --- a/madanalysis/layout/plotflow.py +++ b/madanalysis/layout/plotflow.py @@ -1,87 +1,74 @@ ################################################################################ -# +# # Copyright (C) 2012-2023 Jack Araz, Eric Conte & Benjamin Fuks # The MadAnalysis development team, email: <ma5team@iphc.cnrs.fr> -# +# # This file is part of MadAnalysis 5. # Official website: <https://github.com/MadAnalysis/madanalysis5> -# +# # MadAnalysis 5 is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. -# +# # MadAnalysis 5 is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. -# +# # You should have received a copy of the GNU General Public License # along with MadAnalysis 5. If not, see <http://www.gnu.org/licenses/> -# +# ################################################################################ from __future__ import absolute_import - -import logging -import six, os, json, copy, logging -from six.moves import range -import numpy as np - -from madanalysis.enumeration.normalize_type import NormalizeType -from madanalysis.enumeration.report_format_type import ReportFormatType -from madanalysis.enumeration.color_type import ColorType -from madanalysis.enumeration.linestyle_type import LineStyleType -from madanalysis.enumeration.backstyle_type import BackStyleType +from madanalysis.enumeration.uncertainty_type import UncertaintyType +from madanalysis.enumeration.normalize_type import NormalizeType +from madanalysis.enumeration.report_format_type import ReportFormatType +from madanalysis.enumeration.color_type import ColorType +from madanalysis.enumeration.linestyle_type import LineStyleType +from madanalysis.enumeration.backstyle_type import BackStyleType from madanalysis.enumeration.stacking_method_type import StackingMethodType -from madanalysis.layout.plotflow_for_dataset import PlotFlowForDataset +from madanalysis.layout.plotflow_for_dataset import PlotFlowForDataset import madanalysis.enumeration.color_hex -from madanalysis.configuration.weight_configuration import WeightCollection +import logging +import six +from six.moves import range class PlotFlow: - diconicetitle = {" ^ {": "^{", " _ {": "_{", "\\\\": "#"} - - counter = 0 - - def __init__(self, main): - self.main = main - self.pdftable = {} - with open( - os.path.join(self.main.archi_info.ma5dir, "madanalysis/input/LHAPDF.txt"), "r" - ) as f: - for line in f.readlines()[1:]: - pdf = line.split(",") - self.pdftable.update( - {int(pdf[0]): {"name": pdf[1], "members": int(pdf[-1])}} - ) - self.detail = [] - for dataset in main.datasets: - self.detail.append(PlotFlowForDataset(main, dataset)) + diconicetitle = {' ^ {':'^{', ' _ {':'_{', '\\\\':'#'} + + counter=0 + + def __init__(self,main): + self.main = main + self.detail = [] + for i in range(0,len(main.datasets)): + self.detail.append(PlotFlowForDataset(main,main.datasets[i])) + def Initialize(self): # Initializing NPID - if len(self.detail) > 0: - for ihisto in range(0, len(self.detail[0])): - if ( - self.detail[0].histos[ihisto].__class__.__name__ - == "HistogramFrequency" - ): + if len(self.detail)>0: + for ihisto in range(0,len(self.detail[0])): + if self.detail[0].histos[ihisto].__class__.__name__ == "HistogramFrequency": self.InitializeHistoFrequency(ihisto) # Creating plots - for detail in self.detail: - detail.FinalizeReading() - detail.ComputeScale() - detail.CreateHistogram() + for i in range(0, len(self.detail)): + self.detail[i].FinalizeReading() + self.detail[i].ComputeScale() + self.detail[i].CreateHistogram() - def InitializeHistoFrequency(self, ihisto): + + def InitializeHistoFrequency(self,ihisto): # New collection of labels - newlabels = [] + newlabels=[] # Loop over datasets for histo in self.detail: @@ -89,7 +76,7 @@ def InitializeHistoFrequency(self, ihisto): # Loop over the label for label in histo[ihisto].labels: - # Add in the collection + # Add in the collection if label not in newlabels: newlabels.append(label) @@ -100,9 +87,9 @@ def InitializeHistoFrequency(self, ihisto): for histo in self.detail: # New array for data - array_positive = [] - array_negative = [] - + array_positive=[] + array_negative=[] + # Loop over the new labels for newlabel in newlabels: @@ -110,9 +97,9 @@ def InitializeHistoFrequency(self, ihisto): found = False value_positive = 0 value_negative = 0 - for i, label in enumerate(histo[ihisto].labels): + for i in range(len(histo[ihisto].labels)): - if newlabel == label: + if newlabel==histo[ihisto].labels[i]: value_positive = histo[ihisto].positive.array[i] value_negative = histo[ihisto].negative.array[i] found = True @@ -123,890 +110,728 @@ def InitializeHistoFrequency(self, ihisto): array_positive.append(value_positive) array_negative.append(value_negative) else: - array_positive.append(0.0) - array_negative.append(0.0) + array_positive.append(0.) + array_negative.append(0.) # save result # PS: [:] -> clone the arrays histo[ihisto].positive.array = array_positive[:] histo[ihisto].negative.array = array_negative[:] - histo[ihisto].labels = newlabels[:] + histo[ihisto].labels = newlabels[:] + @staticmethod def NiceTitle(text): - newtext = text - for i, j in six.iteritems(PlotFlow.diconicetitle): - newtext = newtext.replace(i, j) + newtext=text + for i,j in six.iteritems(PlotFlow.diconicetitle): + newtext = newtext.replace(i,j) return newtext @staticmethod def NiceTitleMatplotlib(text): - text = PlotFlow.NiceTitle(text) - text = text.replace("#DeltaR", "#Delta R") - text = "$" + text.replace("#", "\\\\") + "$" + text=PlotFlow.NiceTitle(text) + text=text.replace('#DeltaR','#Delta R') + text='$'+text.replace('#','\\\\')+'$' return text - def DrawAll(self, histo_path, modes, output_paths, ListROOTplots): + + def DrawAll(self,histo_path,modes,output_paths,ListROOTplots): # Loop on each histo type - irelhisto = 0 - for iabshisto, select in enumerate(self.main.selection): - if select.__class__.__name__ != "Histogram": + irelhisto=0 + for iabshisto in range(0,len(self.main.selection)): + if self.main.selection[iabshisto].__class__.__name__!="Histogram": continue - self.color = 1 - histos = [] - scales = [] - datasets = [] + self.color=1 + histos=[] + scales=[] # Name of output files - filenameC = histo_path + "/selection_" + str(irelhisto) + ".C" - filenamePy = histo_path + "/selection_" + str(irelhisto) + ".py" - - output_files = [] - for iout, outp in enumerate(output_paths): - output_files.append( - "../../" - + outp.split("/")[-2] - + "/" - + outp.split("/")[-1] - + "/selection_" - + str(irelhisto) - + "." - + ReportFormatType.convert2filetype(modes[iout]) - ) - - for detail in self.detail: - # Appending histo - datasets.append(detail.dataset) - histos.append(detail[irelhisto]) - scales.append(detail[irelhisto].scale) - - logging.getLogger("MA5").debug("Producing file " + filenameC + " ...") - if self.main.archi_info.has_root: - self.DrawROOT(histos, scales, datasets, select, irelhisto, filenameC, output_files) - - logging.getLogger("MA5").debug("Producing file " + filenamePy + " ...") - self.DrawMATPLOTLIB( - histos, scales, datasets, select, irelhisto, filenamePy, output_files - ) - - irelhisto += 1 + filenameC = histo_path+"/selection_"+str(irelhisto)+".C" + filenamePy = histo_path+"/selection_"+str(irelhisto)+".py" - # Save ROOT files - for ind in range(0, irelhisto): - ListROOTplots.append(histo_path + "/selection_" + str(ind)) + output_files=[] + for iout in range(0,len(output_paths)): + output_files.append('../../'+output_paths[iout].split('/')[-2]+'/'+\ + output_paths[iout].split('/')[-1]+"/selection_"+str(irelhisto)+"."+\ + ReportFormatType.convert2filetype(modes[iout])) + + for iset in range(0,len(self.detail)): + # Appending histo + histos.append(self.detail[iset][irelhisto]) +# if mode==2: + scales.append(self.detail[iset][irelhisto].scale) +# else: +# scales.append(1) + + logging.getLogger('MA5').debug('Producing file '+filenameC+' ...') + self.DrawROOT(histos,scales,self.main.selection[iabshisto],\ + irelhisto,filenameC,output_files) + logging.getLogger('MA5').debug('Producing file '+filenamePy+' ...') + self.DrawMATPLOTLIB\ + (histos,scales,self.main.selection[iabshisto],\ + irelhisto,filenamePy,output_files) + + irelhisto+=1 + + + # Save ROOT files + for ind in range(0,irelhisto): + ListROOTplots.append(histo_path+'/selection_'+str(ind)) + return True - def DrawROOT(self, histos, scales, datasets, ref, irelhisto, filenameC, outputnames): + + def DrawROOT(self,histos,scales,ref,irelhisto,filenameC,outputnames): # Is there any legend? legendmode = False - if len(self.main.datasets) > 1: + if len(self.main.datasets)>1: legendmode = True # Type of histogram frequencyhisto = True for histo in histos: - if histo.__class__.__name__ != "HistogramFrequency": + if histo.__class__.__name__!='HistogramFrequency': frequencyhisto = False break logxhisto = True for histo in histos: - if histo.__class__.__name__ != "HistogramLogX": + if histo.__class__.__name__!='HistogramLogX': logxhisto = False break # Stacking or superimposing histos ? stackmode = False - if ref.stack == StackingMethodType.STACK or ( - ref.stack == StackingMethodType.AUTO - and self.main.stack == StackingMethodType.STACK - ): - stackmode = True + if ref.stack==StackingMethodType.STACK or \ + ( ref.stack==StackingMethodType.AUTO and \ + self.main.stack==StackingMethodType.STACK ): + stackmode=True # Open the file in write-mode try: - outputC = open(filenameC, "w") + outputC = open(filenameC,'w') except: - logging.getLogger("MA5").error("Impossible to write the file: " + filenameC) + logging.getLogger('MA5').error('Impossible to write the file: '+filenameC) return False # File header function_name = filenameC[:-2] - function_name = function_name.split("/")[-1] - outputC.write("void " + function_name + "()\n") - outputC.write("{\n\n") + function_name = function_name.split('/')[-1] + outputC.write('void '+function_name+'()\n') + outputC.write('{\n\n') # ROOT version - outputC.write(" // ROOT version\n") - outputC.write(" Int_t root_version = gROOT->GetVersionInt();\n") - outputC.write("\n") + outputC.write(' // ROOT version\n') + outputC.write(' Int_t root_version = gROOT->GetVersionInt();\n') + outputC.write('\n') # Creating the TCanvas - PlotFlow.counter = PlotFlow.counter + 1 - canvas_name = "canvas_plotflow_tempo" + str(PlotFlow.counter) - outputC.write(" // Creating a new TCanvas\n") - widthx = 700 + PlotFlow.counter=PlotFlow.counter+1 + canvas_name='canvas_plotflow_tempo'+str(PlotFlow.counter) + outputC.write(' // Creating a new TCanvas\n') + widthx=700 if legendmode: - widthx = 1000 - outputC.write( - ' TCanvas* canvas = new TCanvas("' - + canvas_name - + '","' - + canvas_name - + '",0,0,' - + str(widthx) - + ",500);\n" - ) - outputC.write(" gStyle->SetOptStat(0);\n") - outputC.write(" gStyle->SetOptTitle(0);\n") - outputC.write(" canvas->SetHighLightColor(2);\n") - outputC.write(" canvas->SetFillColor(0);\n") - outputC.write(" canvas->SetBorderMode(0);\n") - outputC.write(" canvas->SetBorderSize(3);\n") - outputC.write(" canvas->SetFrameBorderMode(0);\n") - outputC.write(" canvas->SetFrameBorderSize(0);\n") - outputC.write(" canvas->SetTickx(1);\n") - outputC.write(" canvas->SetTicky(1);\n") - outputC.write(" canvas->SetLeftMargin(0.14);\n") - margin = 0.3 if legendmode else 0.05 - outputC.write(" canvas->SetRightMargin(" + str(margin) + ");\n") - outputC.write(" canvas->SetBottomMargin(0.15);\n") - outputC.write(" canvas->SetTopMargin(0.05);\n") - outputC.write("\n") + widthx=1000 + outputC.write(' TCanvas* canvas = new TCanvas("'+canvas_name+'","'+canvas_name+'",0,0,'+str(widthx)+',500);\n') + outputC.write(' gStyle->SetOptStat(0);\n') + outputC.write(' gStyle->SetOptTitle(0);\n') + outputC.write(' canvas->SetHighLightColor(2);\n') +# outputC.write(' canvas->Range(-2.419355,-0.005372711,16.93548,0.03939988);\n') + outputC.write(' canvas->SetFillColor(0);\n') + outputC.write(' canvas->SetBorderMode(0);\n') + outputC.write(' canvas->SetBorderSize(3);\n') + outputC.write(' canvas->SetFrameBorderMode(0);\n') + outputC.write(' canvas->SetFrameBorderSize(0);\n') + outputC.write(' canvas->SetTickx(1);\n') + outputC.write(' canvas->SetTicky(1);\n') + outputC.write(' canvas->SetLeftMargin(0.14);\n') + margin=0.05 + if legendmode: + margin=0.3 + outputC.write(' canvas->SetRightMargin('+str(margin)+');\n') + outputC.write(' canvas->SetBottomMargin(0.15);\n') + outputC.write(' canvas->SetTopMargin(0.05);\n') + outputC.write('\n') # Binning - xnbin = histos[0].nbins - xmin = histos[0].xmin - xmax = histos[0].xmax + xnbin=histos[0].nbins if logxhisto: - outputC.write(" // Histo binning\n") - outputC.write(" Double_t xBinning[" + str(xnbin + 1) + "] = {") - for mybin in range(1, xnbin + 2): - if mybin != 1: - outputC.write(",") + outputC.write(' // Histo binning\n') + outputC.write(' Double_t xBinning['+str(xnbin+1)+'] = {') + for bin in range(1,xnbin+2): + if bin!=1: + outputC.write(',') outputC.write(str(histos[0].GetBinLowEdge(bin))) - outputC.write("};\n") - outputC.write("\n") + outputC.write('};\n') + outputC.write('\n') - # Loop over datasets for a given histogram + # Loop over datasets and histos ntot = 0 - for ind, hist in enumerate(histos): - logging.getLogger("MA5").debug(f"<><><><><><> {hist.name} <><><><><><>") - - # Getting the list of weights, if any - weight_set = self.GetWeights(datasets[ind]); + for ind in range(0,len(histos)): - # Creating a new TH1F histo (one for each dataset) - outputC.write(" // Creating a new TH1F for histo:" + hist.name + "\n") - histoname = "S" + hist.name + "_" + str(ind) + # Creating TH1F + outputC.write(' // Creating a new TH1F\n') + histoname="S"+histos[ind].name+'_'+str(ind) + xmin=histos[ind].xmin + xmax=histos[ind].xmax if logxhisto: - outputC.write( - " TH1F* " - + histoname - + ' = new TH1F("' - + histoname - + '","' - + histoname - + '",' - + str(xnbin) - + ",xBinning);\n" - ) + outputC.write(' TH1F* '+histoname+' = new TH1F("'+histoname+'","'+\ + histoname+'",'+str(xnbin)+',xBinning);\n') else: - outputC.write( - " TH1F* " - + histoname - + ' = new TH1F("' - + histoname - + '","' - + histoname - + '",' - + str(xnbin) - + "," - + str(xmin) - + "," - + str(xmax) - + ");\n" - ) - - # Get histogram data - current_histo, uncertainties = self.GetHisto(hist.summary, datasets[ind], scales[ind], weight_set) + outputC.write(' TH1F* '+histoname+' = new TH1F("'+histoname+'","'+\ + histoname+'",'+str(xnbin)+','+\ + str(xmin)+','+str(xmax)+');\n') # TH1F content - outputC.write(" // Content\n") - outputC.write( - " " - + histoname - + "->SetBinContent(0" - + "," - + str(hist.summary.underflow * scales[ind]) - + "); // underflow\n" - ) - for mybin in range(1, xnbin + 1): - outputC.write( - " " - + histoname - + "->SetBinContent(" - + str(mybin) - + "," - + str(current_histo[mybin - 1]) - + ");\n" - ) - if not uncertainties is None: - outputC.write( - " " - + histoname - + "->SetBinError(" - + str(mybin) - + "," - + str(max(uncertainties[0, mybin-1],uncertainties[1, mybin-1])) - + ");\n" - ) - nentries = hist.summary.nentries - ntot = float(sum(current_histo)) - outputC.write( - " " - + histoname - + "->SetBinContent(" - + str(xnbin + 1) - + "," - + str(hist.summary.overflow * scales[ind]) - + "); // overflow\n" - ) - outputC.write(" " + histoname + "->SetEntries(" + str(nentries) + ");\n") + outputC.write(' // Content\n') + outputC.write(' '+histoname+'->SetBinContent(0'+\ + ','+str(histos[ind].summary.underflow*scales[ind])+'); // underflow\n') + for bin in range(1,xnbin+1): + ntot+= histos[ind].summary.array[bin-1]*scales[ind] + outputC.write(' '+histoname+'->SetBinContent('+str(bin)+\ + ','+str(histos[ind].summary.array[bin-1]*scales[ind])+');\n') + nentries=histos[ind].summary.nentries + outputC.write(' '+histoname+'->SetBinContent('+str(xnbin+1)+\ + ','+str(histos[ind].summary.overflow*scales[ind])+'); // overflow\n') + outputC.write(' '+histoname+'->SetEntries('+str(nentries)+');\n') # reset - linecolor = 0 - linestyle = 0 - backcolor = 0 - backstyle = 0 - linewidth = 1 + linecolor=0 + linestyle=0 + backcolor=0 + backstyle=0 + linewidth=1 # Setting AUTO settings - if len(histos) == 1: + if len(histos)==1: linecolor1 = [9] - linecolor = linecolor1[ind] + linecolor = linecolor1[ind] if stackmode: backstyle1 = [3004] - backstyle = backstyle1[ind] - backcolor = linecolor1[ind] - elif len(histos) == 2: - linecolor2 = [9, 46] - linecolor = linecolor2[ind] + backstyle = backstyle1[ind] + backcolor = linecolor1[ind] + elif len(histos)==2: + linecolor2 = [9,46] + linecolor = linecolor2[ind] if stackmode: - backstyle2 = [3004, 3005] - backstyle = backstyle2[ind] - backcolor = linecolor2[ind] - elif len(histos) == 3: - linecolor3 = [9, 46, 8] - linecolor = linecolor3[ind] + backstyle2 = [3004,3005] + backstyle = backstyle2[ind] + backcolor = linecolor2[ind] + elif len(histos)==3: + linecolor3 = [9,46,8] + linecolor = linecolor3[ind] if stackmode: - backstyle3 = [3004, 3005, 3006] - backstyle = backstyle3[ind] - backcolor = linecolor3[ind] - elif len(histos) == 4: - linecolor4 = [9, 46, 8, 4] - linecolor = linecolor4[ind] + backstyle3 = [3004,3005,3006] + backstyle = backstyle3[ind] + backcolor = linecolor3[ind] + elif len(histos)==4: + linecolor4 = [9,46,8,4] + linecolor = linecolor4[ind] if stackmode: - backstyle4 = [3004, 3005, 3006, 3007] - backstyle = backstyle4[ind] - backcolor = linecolor4[ind] - elif len(histos) == 5: - linecolor5 = [9, 46, 8, 4, 6] - linecolor = linecolor5[ind] + backstyle4 = [3004,3005,3006,3007] + backstyle = backstyle4[ind] + backcolor = linecolor4[ind] + elif len(histos)==5: + linecolor5 = [9,46,8,4,6] + linecolor = linecolor5[ind] if stackmode: - backstyle5 = [3004, 3005, 3006, 3007, 3013] - backstyle = backstyle5[ind] - backcolor = linecolor5[ind] - elif len(histos) == 6: - linecolor6 = [9, 46, 8, 4, 6, 2] - linecolor = linecolor6[ind] + backstyle5 = [3004,3005,3006,3007,3013] + backstyle = backstyle5[ind] + backcolor = linecolor5[ind] + elif len(histos)==6: + linecolor6 = [9,46,8,4,6,2] + linecolor = linecolor6[ind] if stackmode: - backstyle6 = [3004, 3005, 3006, 3007, 3013, 3017] - backstyle = backstyle6[ind] - backcolor = linecolor6[ind] - elif len(histos) == 7: - linecolor7 = [9, 46, 8, 4, 6, 2, 7] - linecolor = linecolor7[ind] + backstyle6 = [3004,3005,3006,3007,3013,3017] + backstyle = backstyle6[ind] + backcolor = linecolor6[ind] + elif len(histos)==7: + linecolor7 = [9,46,8,4,6,2,7] + linecolor = linecolor7[ind] if stackmode: - backstyle7 = [3004, 3005, 3006, 3007, 3013, 3017, 3022] - backstyle = backstyle7[ind] - backcolor = linecolor7[ind] - elif len(histos) == 8: - linecolor8 = [9, 46, 8, 4, 6, 2, 7, 3] - linecolor = linecolor8[ind] + backstyle7 = [3004,3005,3006,3007,3013,3017,3022] + backstyle = backstyle7[ind] + backcolor = linecolor7[ind] + elif len(histos)==8: + linecolor8 = [9,46,8,4,6,2,7,3] + linecolor = linecolor8[ind] if stackmode: - backstyle8 = [3004, 3005, 3006, 3007, 3013, 3017, 3022, 3315] - backstyle = backstyle8[ind] - backcolor = linecolor8[ind] - elif len(histos) == 9: - linecolor9 = [9, 46, 8, 4, 6, 2, 7, 3, 42] - linecolor = linecolor9[ind] + backstyle8 = [3004,3005,3006,3007,3013,3017,3022,3315] + backstyle = backstyle8[ind] + backcolor = linecolor8[ind] + elif len(histos)==9: + linecolor9 = [9,46,8,4,6,2,7,3,42] + linecolor = linecolor9[ind] if stackmode: - backstyle9 = [3004, 3005, 3006, 3007, 3013, 3017, 3022, 3315, 3351] - backstyle = backstyle9[ind] - backcolor = linecolor9[ind] - elif len(histos) == 10: - linecolor10 = [9, 46, 8, 4, 6, 2, 7, 3, 42, 48] - linecolor = linecolor10[ind] + backstyle9 = [3004,3005,3006,3007,3013,3017,3022,3315,3351] + backstyle = backstyle9[ind] + backcolor = linecolor9[ind] + elif len(histos)==10: + linecolor10 = [9,46,8,4,6,2,7,3,42,48] + linecolor = linecolor10[ind] if stackmode: - backstyle10 = [ - 3004, - 3005, - 3006, - 3007, - 3013, - 3017, - 3022, - 3315, - 3351, - 3481, - ] - backstyle = backstyle10[ind] - backcolor = linecolor10[ind] + backstyle10 = [3004,3005,3006,3007,3013,3017,3022,3315,3351,3481] + backstyle = backstyle10[ind] + backcolor = linecolor10[ind] else: - linecolor = self.color + linecolor=self.color self.color += 1 # linecolor - if self.main.datasets[ind].linecolor != ColorType.AUTO: - linecolor = ColorType.convert2root( - self.main.datasets[ind].linecolor, self.main.datasets[ind].lineshade - ) + if self.main.datasets[ind].linecolor!=ColorType.AUTO: + linecolor=ColorType.convert2root( \ + self.main.datasets[ind].linecolor,\ + self.main.datasets[ind].lineshade) # lineStyle - linestyle = LineStyleType.convert2code(self.main.datasets[ind].linestyle) + linestyle=LineStyleType.convert2code(self.main.datasets[ind].linestyle) # linewidth - linewidth = self.main.datasets[ind].linewidth + linewidth=self.main.datasets[ind].linewidth # background color - if self.main.datasets[ind].backcolor != ColorType.AUTO: - backcolor = ColorType.convert2root( - self.main.datasets[ind].backcolor, self.main.datasets[ind].backshade - ) + if self.main.datasets[ind].backcolor!=ColorType.AUTO: + backcolor=ColorType.convert2root( \ + self.main.datasets[ind].backcolor,\ + self.main.datasets[ind].backshade) - # background color - if self.main.datasets[ind].backstyle != BackStyleType.AUTO: - backstyle = BackStyleType.convert2code(self.main.datasets[ind].backstyle) + # background color + if self.main.datasets[ind].backstyle!=BackStyleType.AUTO: + backstyle=BackStyleType.convert2code( \ + self.main.datasets[ind].backstyle) # style - outputC.write(" // Style\n") - outputC.write(" " + histoname + "->SetLineColor(" + str(linecolor) + ");\n") - outputC.write(" " + histoname + "->SetLineStyle(" + str(linestyle) + ");\n") - outputC.write(" " + histoname + "->SetLineWidth(" + str(linewidth) + ");\n") - outputC.write(" " + histoname + "->SetFillColor(" + str(backcolor) + ");\n") - outputC.write(" " + histoname + "->SetFillStyle(" + str(backstyle) + ");\n") + outputC.write(' // Style\n') + outputC.write(' '+histoname+'->SetLineColor('+str(linecolor)+');\n') + outputC.write(' '+histoname+'->SetLineStyle('+str(linestyle)+');\n') + outputC.write(' '+histoname+'->SetLineWidth('+str(linewidth)+');\n') + outputC.write(' '+histoname+'->SetFillColor('+str(backcolor)+');\n') + outputC.write(' '+histoname+'->SetFillStyle('+str(backstyle)+');\n') if frequencyhisto: - outputC.write(" " + histoname + "->SetBarWidth(0.8);\n") - outputC.write(" " + histoname + "->SetBarOffset(0.1);\n") - outputC.write("\n") + outputC.write(' '+histoname+'->SetBarWidth(0.8);\n') + outputC.write(' '+histoname+'->SetBarOffset(0.1);\n') + outputC.write('\n') # Creating the THStack - outputC.write(" // Creating a new THStack\n") - PlotFlow.counter += 1 - outputC.write( - ' THStack* stack = new THStack("mystack_' - + str(PlotFlow.counter) - + '","mystack");\n' - ) + outputC.write(' // Creating a new THStack\n') + PlotFlow.counter+=1 + outputC.write(' THStack* stack = new THStack("mystack_'+str(PlotFlow.counter)+'","mystack");\n') # Loop over datasets and histos - for ind in range(0, len(histos)): - histoname = "S" + histos[ind].name + "_" + str(ind) - outputC.write(" stack->Add(" + histoname + ");\n") + for ind in range(0,len(histos)): + histoname='S'+histos[ind].name+'_'+str(ind) + outputC.write(' stack->Add('+histoname+');\n') - drawoptions = [] + drawoptions=[] if not stackmode: - drawoptions.append("nostack") + drawoptions.append('nostack') if frequencyhisto: - drawoptions.append("bar1") - outputC.write(' stack->Draw("' + "".join(drawoptions) + '");\n') - outputC.write("\n") + drawoptions.append('bar1') + outputC.write(' stack->Draw("'+''.join(drawoptions)+'");\n') + outputC.write('\n') # Setting Y axis label - outputC.write(" // Y axis\n") + outputC.write(' // Y axis\n') axis_titleY = ref.GetYaxis() # Scale to one ? scale2one = False - if ref.stack == StackingMethodType.NORMALIZE2ONE or ( - self.main.stack == StackingMethodType.NORMALIZE2ONE - and ref.stack == StackingMethodType.AUTO - ): + if ref.stack==StackingMethodType.NORMALIZE2ONE or \ + (self.main.stack==StackingMethodType.NORMALIZE2ONE and \ + ref.stack==StackingMethodType.AUTO): scale2one = True if scale2one: axis_titleY += " ( scaled to one )" - elif ( - self.main.normalize == NormalizeType.LUMI - or self.main.normalize == NormalizeType.LUMI_WEIGHT - ): - axis_titleY += " ( L_{int} = " + str(self.main.lumi) + " fb^{-1} )" + elif self.main.normalize == NormalizeType.LUMI or \ + self.main.normalize == NormalizeType.LUMI_WEIGHT: + axis_titleY += " ( L_{int} = " + str(self.main.lumi)+ " fb^{-1} )" elif self.main.normalize == NormalizeType.NONE: axis_titleY += " (not normalized)" - if ref.titleY != "": + if ref.titleY!="": axis_titleY = PlotFlow.NiceTitle(ref.titleY) - if len(axis_titleY) > 35: - titlesize = 0.04 + if(len(axis_titleY) > 35): + titlesize=0.04 else: - titlesize = 0.06 - outputC.write(" stack->GetYaxis()->SetLabelSize(0.04);\n") - outputC.write(" stack->GetYaxis()->SetLabelOffset(0.005);\n") - outputC.write(" stack->GetYaxis()->SetTitleSize(" + str(titlesize) + ");\n") - outputC.write(" stack->GetYaxis()->SetTitleFont(22);\n") - outputC.write(" stack->GetYaxis()->SetTitleOffset(1);\n") - outputC.write(' stack->GetYaxis()->SetTitle("' + axis_titleY + '");\n') - if ref.ymin != []: - outputC.write(" stack->SetMinimum(" + str(ref.ymin) + ");\n") - if ref.ymax != []: - outputC.write(" stack->SetMaximum(" + str(ref.ymax) + ");\n") - - outputC.write("\n") - outputC.write(" // X axis\n") + titlesize=0.06 + outputC.write(' stack->GetYaxis()->SetLabelSize(0.04);\n') + outputC.write(' stack->GetYaxis()->SetLabelOffset(0.005);\n') + outputC.write(' stack->GetYaxis()->SetTitleSize('+str(titlesize)+');\n') + outputC.write(' stack->GetYaxis()->SetTitleFont(22);\n') + outputC.write(' stack->GetYaxis()->SetTitleOffset(1);\n') + outputC.write(' stack->GetYaxis()->SetTitle("'+axis_titleY+'");\n') + if ref.ymin!=[]: + outputC.write(' stack->SetMinimum('+str(ref.ymin)+');\n') + if ref.ymax!=[]: + outputC.write(' stack->SetMaximum('+str(ref.ymax)+');\n') + + outputC.write('\n') + outputC.write(' // X axis\n') # Setting X axis label - if ref.titleX == "": + if ref.titleX=="": axis_titleX = ref.GetXaxis_Root() else: axis_titleX = PlotFlow.NiceTitle(ref.titleX) # Setting X axis label - outputC.write(" stack->GetXaxis()->SetLabelSize(0.04);\n") - outputC.write(" stack->GetXaxis()->SetLabelOffset(0.005);\n") - outputC.write(" stack->GetXaxis()->SetTitleSize(0.06);\n") - outputC.write(" stack->GetXaxis()->SetTitleFont(22);\n") - outputC.write(" stack->GetXaxis()->SetTitleOffset(1);\n") - outputC.write(' stack->GetXaxis()->SetTitle("' + axis_titleX + '");\n') + outputC.write(' stack->GetXaxis()->SetLabelSize(0.04);\n') + outputC.write(' stack->GetXaxis()->SetLabelOffset(0.005);\n') + outputC.write(' stack->GetXaxis()->SetTitleSize(0.06);\n') + outputC.write(' stack->GetXaxis()->SetTitleFont(22);\n') + outputC.write(' stack->GetXaxis()->SetTitleOffset(1);\n') + outputC.write(' stack->GetXaxis()->SetTitle("'+axis_titleX+'");\n') if frequencyhisto: - for bin in range(1, xnbin + 1): - outputC.write( - " stack->GetXaxis()->SetBinLabel(" + str(bin) + "," - '"' + str(histos[ind].stringlabels[bin - 1]) + '");\n' - ) - outputC.write("\n") + for bin in range(1,xnbin+1): + outputC.write(' stack->GetXaxis()->SetBinLabel('+str(bin)+','\ + '"'+str(histos[ind].stringlabels[bin-1])+'");\n') + outputC.write('\n') # Setting Log scale - outputC.write(" // Finalizing the TCanvas\n") - logx = 0 + outputC.write(' // Finalizing the TCanvas\n') + logx=0 if ref.logX and ntot != 0: - logx = 1 - logy = 0 + logx=1 + logy=0 if ref.logY and ntot != 0: - logy = 1 - outputC.write(" canvas->SetLogx(" + str(logx) + ");\n") - outputC.write(" canvas->SetLogy(" + str(logy) + ");\n") - outputC.write("\n") + logy=1 + outputC.write(' canvas->SetLogx('+str(logx)+');\n') + outputC.write(' canvas->SetLogy('+str(logy)+');\n') + outputC.write('\n') # Displaying a legend if legendmode: - outputC.write(" // Creating a TLegend\n") - outputC.write(" TLegend* legend = new TLegend(.73,.5,.97,.95);\n") - for ind in range(0, len(histos)): - histoname = "S" + histos[ind].name + "_" + str(ind) - nicetitle = PlotFlow.NiceTitle(self.main.datasets[ind].title) - outputC.write( - " legend->AddEntry(" + histoname + ',"' + nicetitle + '");\n' - ) - outputC.write(" legend->SetFillColor(0);\n") - outputC.write(" legend->SetTextSize(0.05);\n") - outputC.write(" legend->SetTextFont(22);\n") - outputC.write( - " legend->SetY1(TMath::Max(0.15,0.97-0.10*legend->GetListOfPrimitives()->GetSize()));\n" - ) - outputC.write(" legend->Draw();\n") - outputC.write("\n") + outputC.write(' // Creating a TLegend\n') + outputC.write(' TLegend* legend = new TLegend(.73,.5,.97,.95);\n') + for ind in range(0,len(histos)): + histoname='S'+histos[ind].name+'_'+str(ind) + nicetitle=PlotFlow.NiceTitle(self.main.datasets[ind].title) + outputC.write(' legend->AddEntry('+histoname+',"'+nicetitle+'");\n') + outputC.write(' legend->SetFillColor(0);\n') + outputC.write(' legend->SetTextSize(0.05);\n') + outputC.write(' legend->SetTextFont(22);\n') + outputC.write(' legend->SetY1(TMath::Max(0.15,0.97-0.10*legend->GetListOfPrimitives()->GetSize()));\n') + outputC.write(' legend->Draw();\n') + outputC.write('\n') # Producing the image - outputC.write(" // Saving the image\n") + outputC.write(' // Saving the image\n') for outputname in outputnames: - outputC.write(' canvas->SaveAs("' + outputname + '");\n') - outputC.write("\n") + outputC.write(' canvas->SaveAs("'+outputname+'");\n') + outputC.write('\n') # File foot - outputC.write("}\n") + outputC.write('}\n') # Close the file try: outputC.close() except: - logging.getLogger("MA5").error("Impossible to close the file: " + outputC) + logging.getLogger('MA5').error('Impossible to close the file: '+outputC) return False # Ok return True - def DrawMATPLOTLIB( - self, histos, scales, datasets, ref, irelhisto, filenamePy, outputnames - ): + + + def DrawMATPLOTLIB(self,histos,scales,ref,irelhisto,filenamePy,outputnames): # Is there any legend? legendmode = False - if len(self.main.datasets) > 1: + if len(self.main.datasets)>1: legendmode = True # Type of histogram frequencyhisto = True for histo in histos: - if histo.__class__.__name__ != "HistogramFrequency": + if histo.__class__.__name__!='HistogramFrequency': frequencyhisto = False break logxhisto = True for histo in histos: - if histo.__class__.__name__ != "HistogramLogX": + if histo.__class__.__name__!='HistogramLogX': logxhisto = False break # Stacking or superimposing histos ? stackmode = False - if ref.stack == StackingMethodType.STACK or ( - ref.stack == StackingMethodType.AUTO - and self.main.stack == StackingMethodType.STACK - ): - stackmode = True + if ref.stack==StackingMethodType.STACK or \ + ( ref.stack==StackingMethodType.AUTO and \ + self.main.stack==StackingMethodType.STACK ): + stackmode=True + # Open the file in write-mode try: - outputPy = open(filenamePy, "w") - except Exception: - logging.getLogger("MA5").error(f"Impossible to write the file: {filenamePy}") + outputPy = open(filenamePy,'w') + except: + logging.getLogger('MA5').error('Impossible to write the file: '+filenamePy) return False # File header function_name = filenamePy[:-3] - function_name = function_name.split("/")[-1] - outputPy.write("def " + function_name + "():\n") - outputPy.write("\n") + function_name = function_name.split('/')[-1] + outputPy.write('def '+function_name+'():\n') + outputPy.write('\n') # Import Libraries - outputPy.write(" # Library import\n") - outputPy.write(" import numpy as np\n") - outputPy.write(" import matplotlib\n") - outputPy.write(" import matplotlib.pyplot as plt\n") - outputPy.write(" import matplotlib.gridspec as gridspec\n") - outputPy.write("\n") + outputPy.write(' # Library import\n') + outputPy.write(' import numpy\n') + outputPy.write(' import matplotlib\n') +# outputPy.write(" matplotlib.use('Agg')\n") + outputPy.write(' import matplotlib.pyplot as plt\n') + outputPy.write(' import matplotlib.gridspec as gridspec\n') + outputPy.write('\n') # Matplotlib & numpy version - outputPy.write(" # Library version\n") - outputPy.write(" matplotlib_version = matplotlib.__version__\n") - outputPy.write(" numpy_version = np.__version__\n") - outputPy.write("\n") + outputPy.write(' # Library version\n') + outputPy.write(' matplotlib_version = matplotlib.__version__\n') + outputPy.write(' numpy_version = numpy.__version__\n') + outputPy.write('\n') # Binning # Loop over datasets and histos - xnbin = histos[0].nbins - xmin = histos[0].xmin - xmax = histos[0].xmax - outputPy.write(" # Histo binning\n") + xnbin=histos[0].nbins + xmin =histos[0].xmin + xmax =histos[0].xmax + outputPy.write(' # Histo binning\n') if logxhisto: - outputPy.write(" xBinning = [") - for mybin in range(1, xnbin + 2): - if mybin != 1: - outputPy.write(",") - outputPy.write(str(histos[0].GetBinLowEdge(mybin))) - outputPy.write("]\n") - outputPy.write("\n") + outputPy.write(' xBinning = [') + for bin in range(1,xnbin+2): + if bin!=1: + outputPy.write(',') + outputPy.write(str(histos[0].GetBinLowEdge(bin))) + outputPy.write(']\n') + outputPy.write('\n') else: - outputPy.write( - " xBinning = np.linspace(" - + str(xmin) - + "," - + str(xmax) - + "," - + str(xnbin + 1) - + ",endpoint=True)\n" - ) - outputPy.write("\n") + outputPy.write(' xBinning = numpy.linspace('+\ + str(xmin)+','+str(xmax)+','+str(xnbin+1)+\ + ',endpoint=True)\n') + outputPy.write('\n') + # Data - outputPy.write(" # Creating data sequence: middle of each bin\n") - outputPy.write( - " xData = np.array([" - + ", ".join([f"{histos[0].GetBinMean(ibin):.5e}" for ibin in range(xnbin)]) - + "])\n\n" - ) - - # Loop over datasets for a given histogram + outputPy.write(' # Creating data sequence: middle of each bin\n') + outputPy.write(' xData = numpy.array([') + for bin in range(0,xnbin): + if bin!=0: + outputPy.write(',') + outputPy.write(str(histos[0].GetBinMean(bin))) + outputPy.write('])\n\n') + + # Loop over datasets and histos ntot = 0 - for ind, hist in enumerate(histos): - logging.getLogger("MA5").debug(f"<><><><><><> {hist.name} <><><><><><>") + for ind in range(0,len(histos)): - # Getting the list of weights, if any - weight_set = self.GetWeights(datasets[ind]); + # Creating a new histo + histoname='y'+histos[ind].name+'_'+str(ind) + outputPy.write(' # Creating weights for histo: '+histoname+'\n') + outputPy.write(' '+histoname+'_weights = numpy.array([') + for bin in range(1,xnbin+1): + ntot+=histos[ind].summary.array[bin-1]*scales[ind] + if bin!=1: + outputPy.write(',') + outputPy.write(str(histos[ind].summary.array[bin-1]*scales[ind])) + outputPy.write('])\n\n') - # Creating a new histo (one for each dataset) - outputPy.write(" # Creating weights for histo: " + hist.name + "\n") - histoname = "y" + hist.name + "_" + str(ind) - # Get histogram data - current_histo, uncertainties = self.GetHisto(hist.summary, datasets[ind], scales[ind], weight_set) - outputPy.write(" " + histoname + "_weights = np.array([") - outputPy.write(", ".join(f"{x:.8e}" for x in current_histo) + "])\n\n") - ntot = float(sum(current_histo)) # Canvas - outputPy.write(" # Creating a new Canvas\n") - dpi = 80 - height = 500 - widthx = 700 + outputPy.write(' # Creating a new Canvas\n') + dpi=80 + height=500 + widthx=700 if legendmode: - widthx = 1000 - outputPy.write( - " fig = plt.figure(figsize=(" - + str(widthx / dpi) - + "," - + str(height / dpi) - + "),dpi=" - + str(dpi) - + ")\n" - ) + widthx=1000 + outputPy.write(' fig = plt.figure(figsize=('+\ + str(widthx/dpi)+','+str(height/dpi)+\ + '),dpi='+str(dpi)+')\n') if not legendmode: - outputPy.write(" frame = gridspec.GridSpec(1,1)\n") + outputPy.write(' frame = gridspec.GridSpec(1,1)\n') else: - outputPy.write(" frame = gridspec.GridSpec(1,1,right=0.7)\n") + outputPy.write(' frame = gridspec.GridSpec(1,1,right=0.7)\n') # subplot argument: nrows, ncols, plot_number # outputPy.write(' pad = fig.add_subplot(111)\n') - outputPy.write(" pad = fig.add_subplot(frame[0])\n") - outputPy.write("\n") + outputPy.write(' pad = fig.add_subplot(frame[0])\n') + outputPy.write('\n') # Stack - outputPy.write(" # Creating a new Stack\n") - for ind in range(len(histos) - 1, -1, -1): - myweight = "y" + histos[ind].name + "_" + str(ind) + "_weights" - mytitle = ( - '"' + PlotFlow.NiceTitleMatplotlib(self.main.datasets[ind].title) + '"' - ) - mytitle = mytitle.replace("_", "\_") + outputPy.write(' # Creating a new Stack\n') + for ind in range(len(histos)-1,-1,-1): + myweight = 'y'+histos[ind].name+'_'+str(ind)+'_weights' + mytitle = '"'+PlotFlow.NiceTitleMatplotlib(self.main.datasets[ind].title)+'"' + mytitle = mytitle.replace('_','\_') if not stackmode: - myweights = "y" + histos[ind].name + "_" + str(ind) + "_weights" + myweights='y'+histos[ind].name+'_'+str(ind)+'_weights' else: - myweights = "" - for ind2 in range(0, ind + 1): - if ind2 >= 1: - myweights += "+" - myweights_scale_up += "+" - myweights_scale_dn += "+" - myweights += "y" + histos[ind2].name + "_" + str(ind2) + "_weights" + myweights='' + for ind2 in range(0,ind+1): + if ind2>=1: + myweights+='+' + myweights+='y'+histos[ind2].name+'_'+str(ind2)+'_weights' # reset - linecolor = 0 - linestyle = 0 - backcolor = 0 - backstyle = 0 - linewidth = 1 + linecolor=0 + linestyle=0 + backcolor=0 + backstyle=0 + linewidth=1 # Setting AUTO settings - if len(histos) == 1: + if len(histos)==1: linecolor1 = [9] - linecolor = linecolor1[ind] + linecolor = linecolor1[ind] if stackmode: backstyle1 = [3004] - backstyle = backstyle1[ind] - backcolor = linecolor1[ind] - elif len(histos) == 2: - linecolor2 = [9, 46] - linecolor = linecolor2[ind] + backstyle = backstyle1[ind] + backcolor = linecolor1[ind] + elif len(histos)==2: + linecolor2 = [9,46] + linecolor = linecolor2[ind] if stackmode: - backstyle2 = [3004, 3005] - backstyle = backstyle2[ind] - backcolor = linecolor2[ind] - elif len(histos) == 3: - linecolor3 = [9, 46, 8] - linecolor = linecolor3[ind] + backstyle2 = [3004,3005] + backstyle = backstyle2[ind] + backcolor = linecolor2[ind] + elif len(histos)==3: + linecolor3 = [9,46,8] + linecolor = linecolor3[ind] if stackmode: - backstyle3 = [3004, 3005, 3006] - backstyle = backstyle3[ind] - backcolor = linecolor3[ind] - elif len(histos) == 4: - linecolor4 = [9, 46, 8, 4] - linecolor = linecolor4[ind] + backstyle3 = [3004,3005,3006] + backstyle = backstyle3[ind] + backcolor = linecolor3[ind] + elif len(histos)==4: + linecolor4 = [9,46,8,4] + linecolor = linecolor4[ind] if stackmode: - backstyle4 = [3004, 3005, 3006, 3007] - backstyle = backstyle4[ind] - backcolor = linecolor4[ind] - elif len(histos) == 5: - linecolor5 = [9, 46, 8, 4, 6] - linecolor = linecolor5[ind] + backstyle4 = [3004,3005,3006,3007] + backstyle = backstyle4[ind] + backcolor = linecolor4[ind] + elif len(histos)==5: + linecolor5 = [9,46,8,4,6] + linecolor = linecolor5[ind] if stackmode: - backstyle5 = [3004, 3005, 3006, 3007, 3013] - backstyle = backstyle5[ind] - backcolor = linecolor5[ind] - elif len(histos) == 6: - linecolor6 = [9, 46, 8, 4, 6, 2] - linecolor = linecolor6[ind] + backstyle5 = [3004,3005,3006,3007,3013] + backstyle = backstyle5[ind] + backcolor = linecolor5[ind] + elif len(histos)==6: + linecolor6 = [9,46,8,4,6,2] + linecolor = linecolor6[ind] if stackmode: - backstyle6 = [3004, 3005, 3006, 3007, 3013, 3017] - backstyle = backstyle6[ind] - backcolor = linecolor6[ind] - elif len(histos) == 7: - linecolor7 = [9, 46, 8, 4, 6, 2, 7] - linecolor = linecolor7[ind] + backstyle6 = [3004,3005,3006,3007,3013,3017] + backstyle = backstyle6[ind] + backcolor = linecolor6[ind] + elif len(histos)==7: + linecolor7 = [9,46,8,4,6,2,7] + linecolor = linecolor7[ind] if stackmode: - backstyle7 = [3004, 3005, 3006, 3007, 3013, 3017, 3022] - backstyle = backstyle7[ind] - backcolor = linecolor7[ind] - elif len(histos) == 8: - linecolor8 = [9, 46, 8, 4, 6, 2, 7, 3] - linecolor = linecolor8[ind] + backstyle7 = [3004,3005,3006,3007,3013,3017,3022] + backstyle = backstyle7[ind] + backcolor = linecolor7[ind] + elif len(histos)==8: + linecolor8 = [9,46,8,4,6,2,7,3] + linecolor = linecolor8[ind] if stackmode: - backstyle8 = [3004, 3005, 3006, 3007, 3013, 3017, 3022, 3315] - backstyle = backstyle8[ind] - backcolor = linecolor8[ind] - elif len(histos) == 9: - linecolor9 = [9, 46, 8, 4, 6, 2, 7, 3, 42] - linecolor = linecolor9[ind] + backstyle8 = [3004,3005,3006,3007,3013,3017,3022,3315] + backstyle = backstyle8[ind] + backcolor = linecolor8[ind] + elif len(histos)==9: + linecolor9 = [9,46,8,4,6,2,7,3,42] + linecolor = linecolor9[ind] if stackmode: - backstyle9 = [3004, 3005, 3006, 3007, 3013, 3017, 3022, 3315, 3351] - backstyle = backstyle9[ind] - backcolor = linecolor9[ind] - elif len(histos) == 10: - linecolor10 = [9, 46, 8, 4, 6, 2, 7, 3, 42, 48] - linecolor = linecolor10[ind] + backstyle9 = [3004,3005,3006,3007,3013,3017,3022,3315,3351] + backstyle = backstyle9[ind] + backcolor = linecolor9[ind] + elif len(histos)==10: + linecolor10 = [9,46,8,4,6,2,7,3,42,48] + linecolor = linecolor10[ind] if stackmode: - backstyle10 = [ - 3004, - 3005, - 3006, - 3007, - 3013, - 3017, - 3022, - 3315, - 3351, - 3481, - ] - backstyle = backstyle10[ind] - backcolor = linecolor10[ind] + backstyle10 = [3004,3005,3006,3007,3013,3017,3022,3315,3351,3481] + backstyle = backstyle10[ind] + backcolor = linecolor10[ind] else: - linecolor = self.color + linecolor=self.color self.color += 1 # linecolor - if self.main.datasets[ind].linecolor != ColorType.AUTO: - linecolor = ColorType.convert2root( - self.main.datasets[ind].linecolor, self.main.datasets[ind].lineshade - ) + if self.main.datasets[ind].linecolor!=ColorType.AUTO: + linecolor=ColorType.convert2root( \ + self.main.datasets[ind].linecolor,\ + self.main.datasets[ind].lineshade) # lineStyle - linestyle = LineStyleType.convert2code(self.main.datasets[ind].linestyle) + linestyle=LineStyleType.convert2code(self.main.datasets[ind].linestyle) # linewidth - linewidth = self.main.datasets[ind].linewidth + linewidth=self.main.datasets[ind].linewidth # background color - if self.main.datasets[ind].backcolor != ColorType.AUTO: - backcolor = ColorType.convert2root( - self.main.datasets[ind].backcolor, self.main.datasets[ind].backshade - ) + if self.main.datasets[ind].backcolor!=ColorType.AUTO: + backcolor=ColorType.convert2root( \ + self.main.datasets[ind].backcolor,\ + self.main.datasets[ind].backshade) # background style - if self.main.datasets[ind].backstyle != BackStyleType.AUTO: - backstyle = BackStyleType.convert2matplotlib( - self.main.datasets[ind].backstyle - ) - - mylinecolor = ( - '"' + madanalysis.enumeration.color_hex.color_hex[linecolor] + '"' - ) - mybackcolor = ( - '"' + madanalysis.enumeration.color_hex.color_hex[backcolor] + '"' - ) - - filledmode = '"stepfilled"' - rWidth = 1.0 - if backcolor == 0: # invisible - filledmode = '"step"' - mybackcolor = "None" - # if frequencyhisto: - # filledmode='"bar"' - # rWidth=0.8 - mylinewidth = self.main.datasets[ind].linewidth - mylinestyle = LineStyleType.convert2matplotlib( - self.main.datasets[ind].linestyle - ) - - outputPy.write( - " pad.hist(" - + "x=xData, " - + "bins=xBinning, " - + "weights=" - + myweights - + ",\\\n" - + " label=" - + mytitle - + ", " - ) - - if ntot != 0: - outputPy.write("histtype=" + filledmode + ", ") - + if self.main.datasets[ind].backstyle!=BackStyleType.AUTO: + backstyle=BackStyleType.convert2matplotlib( \ + self.main.datasets[ind].backstyle) + + mylinecolor = '"'+madanalysis.enumeration.color_hex.color_hex[linecolor]+'"' + mybackcolor = '"'+madanalysis.enumeration.color_hex.color_hex[backcolor]+'"' + + filledmode='"stepfilled"' + rWidth=1. + if backcolor==0: #invisible + filledmode='"step"' + mybackcolor = 'None' +# if frequencyhisto: +# filledmode='"bar"' +# rWidth=0.8 + mylinewidth = self.main.datasets[ind].linewidth + mylinestyle = LineStyleType.convert2matplotlib(self.main.datasets[ind].linestyle) + + outputPy.write(' pad.hist('+\ + 'x=xData, '+\ + 'bins=xBinning, '+\ + 'weights='+myweights+',\\\n'+\ + ' label='+mytitle+', ') + if ntot!=0: + outputPy.write('histtype='+filledmode+', ') try: import matplotlib.pyplot as plt - - plt.hist([0], normed=True) - outputPy.write( - "rwidth=" - + str(rWidth) - + ",\\\n" - + " color=" - + mybackcolor - + ", " - + "edgecolor=" - + mylinecolor - + ", " - + "linewidth=" - + str(mylinewidth) - + ", " - + "linestyle=" - + mylinestyle - + ",\\\n" - + " bottom=None, " - + 'cumulative=False, normed=False, align="mid", orientation="vertical")\n\n' - ) + plt.hist([0],normed=True) + outputPy.write( 'rwidth='+str(rWidth)+',\\\n'+\ + ' color='+mybackcolor+', '+\ + 'edgecolor='+mylinecolor+', '+\ + 'linewidth='+str(mylinewidth)+', '+\ + 'linestyle='+mylinestyle+',\\\n'+\ + ' bottom=None, '+\ + 'cumulative=False, normed=False, align="mid", orientation="vertical")\n\n') except: - outputPy.write( - "rwidth=" - + str(rWidth) - + ",\\\n" - + " color=" - + mybackcolor - + ", " - + "edgecolor=" - + mylinecolor - + ", " - + "linewidth=" - + str(mylinewidth) - + ", " - + "linestyle=" - + mylinestyle - + ",\\\n" - + " bottom=None, " - + 'cumulative=False, density=False, align="mid",' - + ' orientation="vertical")\n\n' - ) - outputPy.write("\n") - - if uncertainties is not None: - outputPy.write( - " pad.errorbar(" - + "[x + (xBinning[0] + xBinning[1])/2 for x in xBinning[:-1]]," - + f"{myweights}, yerr={uncertainties.tolist()}," - + " fmt='.', elinewidth=1, capsize=2)\n\n" - ) + outputPy.write( 'rwidth='+str(rWidth)+',\\\n'+\ + ' color='+mybackcolor+', '+\ + 'edgecolor='+mylinecolor+', '+\ + 'linewidth='+str(mylinewidth)+', '+\ + 'linestyle='+mylinestyle+',\\\n'+\ + ' bottom=None, '+\ + 'cumulative=False, density=False, align="mid",'+\ + ' orientation="vertical")\n\n') + outputPy.write('\n') # Label - outputPy.write(" # Axis\n") + outputPy.write(' # Axis\n') outputPy.write(" plt.rc('text',usetex=False)\n") # X-axis - if ref.titleX == "": + if ref.titleX=="": axis_titleX = ref.GetXaxis_Matplotlib() else: axis_titleX = ref.titleX - axis_titleX = axis_titleX.replace("#DeltaR", "#Delta R") - axis_titleX = axis_titleX.replace("#", "\\") - outputPy.write(' plt.xlabel(r"' + axis_titleX + '",\\\n') + axis_titleX = axis_titleX.replace('#DeltaR','#Delta R') + axis_titleX = axis_titleX.replace('#','\\') + outputPy.write(' plt.xlabel(r"'+axis_titleX+'",\\\n') outputPy.write(' fontsize=16,color="black")\n') # Y-axis @@ -1014,144 +839,135 @@ def DrawMATPLOTLIB( # Scale to one ? scale2one = False - if ref.stack == StackingMethodType.NORMALIZE2ONE or ( - self.main.stack == StackingMethodType.NORMALIZE2ONE - and ref.stack == StackingMethodType.AUTO - ): + if ref.stack==StackingMethodType.NORMALIZE2ONE or \ + (self.main.stack==StackingMethodType.NORMALIZE2ONE and \ + ref.stack==StackingMethodType.AUTO): scale2one = True if scale2one: axis_titleY += " $(#mathrm{scaled}\ #mathrm{to}# #mathrm{one})$" - elif ( - self.main.normalize == NormalizeType.LUMI - or self.main.normalize == NormalizeType.LUMI_WEIGHT - ): - axis_titleY += ( - " $(#mathcal{L}_{#mathrm{int}} = " - + str(self.main.lumi) - + "# #mathrm{fb}^{-1})$ " - ) + elif self.main.normalize == NormalizeType.LUMI or \ + self.main.normalize == NormalizeType.LUMI_WEIGHT: + axis_titleY += " $(#mathcal{L}_{#mathrm{int}} = " + str(self.main.lumi)+ "# #mathrm{fb}^{-1})$ " elif self.main.normalize == NormalizeType.NONE: axis_titleY += " $(#mathrm{not}# #mathrm{normalized})$" - if ref.titleY != "": + if ref.titleY!="": axis_titleY = PlotFlow.NiceTitle(ref.titleY) - axis_titleY = axis_titleY.replace("#", "\\") - outputPy.write(' plt.ylabel(r"' + axis_titleY + '",\\\n') + axis_titleY = axis_titleY.replace('#','\\') + outputPy.write(' plt.ylabel(r"'+axis_titleY+'",\\\n') outputPy.write(' fontsize=16,color="black")\n') - outputPy.write("\n") + outputPy.write('\n') # Tag Log/Linear - is_logx = False + is_logx=False if ref.logX and ntot != 0: - is_logx = True - is_logy = False + is_logx=True + is_logy=False if ref.logY and ntot != 0: - is_logy = True + is_logy=True # Bound y - outputPy.write(" # Boundary of y-axis\n") - myweights = "" + outputPy.write(' # Boundary of y-axis\n') + myweights='' if stackmode: - for ind in range(0, len(histos)): - if ind >= 1: - myweights += "+" - myweights += "y" + histos[ind].name + "_" + str(ind) + "_weights" + for ind in range(0,len(histos)): + if ind>=1: + myweights+='+' + myweights+='y'+histos[ind].name+'_'+str(ind)+'_weights' else: - myweights = "np.array([" - for ind in range(0, len(histos)): - if ind >= 1: - myweights += "," - myweights += "y" + histos[ind].name + "_" + str(ind) + "_weights.max()" - myweights += "])" - if ref.ymax == []: - outputPy.write(" ymax=(" + myweights + ").max()*1.1\n") + myweights='numpy.array([' + for ind in range(0,len(histos)): + if ind>=1: + myweights+=',' + myweights+='y'+histos[ind].name+'_'+str(ind)+'_weights.max()' + myweights+='])' + if ref.ymax==[]: + outputPy.write(' ymax=('+myweights+').max()*1.1\n') else: - outputPy.write(" ymax=" + str(ref.ymax) + "\n") - outputPy.write(" ") - if ref.ymin == []: + outputPy.write(' ymax='+str(ref.ymax)+'\n') + outputPy.write(' ') + if ref.ymin==[]: if is_logy: - outputPy.write("#") - outputPy.write("ymin=0 # linear scale\n") + outputPy.write('#') + outputPy.write('ymin=0 # linear scale\n') else: - if is_logy and ref.ymin <= 0: - outputPy.write("#") - outputPy.write("ymin=" + str(ref.ymin) + " # linear scale\n") + if is_logy and ref.ymin<=0: + outputPy.write('#') + outputPy.write('ymin=' + str(ref.ymin)+' # linear scale\n') - myweights = "" + myweights='' if stackmode: - for ind in range(0, len(histos)): - if ind >= 1: - myweights += "+" - myweights += "y" + histos[ind].name + "_" + str(ind) + "_weights" + for ind in range(0,len(histos)): + if ind>=1: + myweights+='+' + myweights+='y'+histos[ind].name+'_'+str(ind)+'_weights' else: - myweights = "np.array([" - for ind in range(0, len(histos)): - if ind >= 1: - myweights += "," - myweights += "y" + histos[ind].name + "_" + str(ind) + "_weights.min()" - myweights += ",1.])" - outputPy.write(" ") - if ref.ymin == []: + myweights='numpy.array([' + for ind in range(0,len(histos)): + if ind>=1: + myweights+=',' + myweights+='y'+histos[ind].name+'_'+str(ind)+'_weights.min()' + myweights+=',1.])' + outputPy.write(' ') + if ref.ymin==[]: if not is_logy: - outputPy.write("#") - outputPy.write( - "ymin=min([x for x in (" + myweights + ") if x])/100. # log scale\n" - ) + outputPy.write('#') + outputPy.write('ymin=min([x for x in ('+myweights+') if x])/100. # log scale\n') else: - if is_logy and ref.ymin <= 0: - outputPy.write("#") - outputPy.write("ymin=" + str(ref.ymin) + " # log scale\n") - outputPy.write(" plt.gca().set_ylim(ymin,ymax)\n") - outputPy.write("\n") + if is_logy and ref.ymin<=0: + outputPy.write('#') + outputPy.write('ymin=' + str(ref.ymin)+' # log scale\n') + outputPy.write(' plt.gca().set_ylim(ymin,ymax)\n') + outputPy.write('\n') # X axis - outputPy.write(" # Log/Linear scale for X-axis\n") + outputPy.write(' # Log/Linear scale for X-axis\n') # - Linear - outputPy.write(" ") + outputPy.write(' ') if is_logx: - outputPy.write("#") + outputPy.write('#') outputPy.write('plt.gca().set_xscale("linear")\n') # - Log - outputPy.write(" ") + outputPy.write(' ') if not is_logx: - outputPy.write("#") + outputPy.write('#') outputPy.write('plt.gca().set_xscale("log",nonpositive="clip")\n') - outputPy.write("\n") + outputPy.write('\n') + # Y axis - outputPy.write(" # Log/Linear scale for Y-axis\n") + outputPy.write(' # Log/Linear scale for Y-axis\n') # - Linear - outputPy.write(" ") + outputPy.write(' ') if is_logy: - outputPy.write("#") + outputPy.write('#') outputPy.write('plt.gca().set_yscale("linear")\n') # - Log - outputPy.write(" ") + outputPy.write(' ') if not is_logy: - outputPy.write("#") + outputPy.write('#') outputPy.write('plt.gca().set_yscale("log",nonpositive="clip")\n') - outputPy.write("\n") + outputPy.write('\n') + # Labels if frequencyhisto: - outputPy.write(" # Labels for x-Axis\n") - outputPy.write(" xLabels = np.array([") - for bin in range(0, xnbin): - if bin >= 1: - outputPy.write(",") - outputPy.write( - '"' + str(histos[0].stringlabels[bin]).replace("_", "\_") + '"' - ) - outputPy.write("])\n") + outputPy.write(' # Labels for x-Axis\n') + outputPy.write(' xLabels = numpy.array([') + for bin in range(0,xnbin): + if bin>=1: + outputPy.write(',') + outputPy.write('"'+str(histos[0].stringlabels[bin]).replace('_','\_')+'"') + outputPy.write('])\n') outputPy.write(' plt.xticks(xData, xLabels, rotation="vertical")\n') - outputPy.write("\n") + outputPy.write('\n') - ### BENJ: not necessary for getting the png and pdf files +### BENJ: not necessary for getting the png and pdf files # Draw - # outputPy.write(' # Draw\n') - # outputPy.write(' plt.show()\n') - # outputPy.write('\n') +# outputPy.write(' # Draw\n') +# outputPy.write(' plt.show()\n') +# outputPy.write('\n') # Legend if legendmode: @@ -1169,226 +985,29 @@ def DrawMATPLOTLIB( # -'upper center' : 9, # -'center' : 10, - outputPy.write(" # Legend\n") - outputPy.write( - " plt.legend(bbox_to_anchor=(1.05,1), loc=2," + " borderaxespad=0.)\n" - ) - outputPy.write("\n") - + + outputPy.write(' # Legend\n') + outputPy.write(' plt.legend(bbox_to_anchor=(1.05,1), loc=2,'+\ + ' borderaxespad=0.)\n') + outputPy.write('\n') + # Producing the image - outputPy.write(" # Saving the image\n") + outputPy.write(' # Saving the image\n') for outputname in outputnames: - outputPy.write(" plt.savefig('" + outputname + "')\n") - outputPy.write("\n") + outputPy.write(" plt.savefig('"+outputname+"')\n") + outputPy.write('\n') # Call the function - outputPy.write("# Running!\n") + outputPy.write('# Running!\n') outputPy.write("if __name__ == '__main__':\n") - outputPy.write(" " + function_name + "()\n") + outputPy.write(' '+function_name+'()\n') # Close the file try: outputPy.close() except: - logging.getLogger("MA5").error("Impossible to close the file: " + outputPy) + logging.getLogger('MA5').error('Impossible to close the file: '+outputPy) return False # Ok return True - - - ## Getting the list of weights associated with a histogram - def GetWeights(self, dataset): - ######################################################################## - # weight_set - dictionary structure: # - # - "weights": are nominal weights including scale uncertainties # - # - "pdf_variations": PDF variations # - ######################################################################## - - # Initialisation - weight_set = {} - - # Main body of the function - if len(dataset.weight_collection) > 1: - # separate the weights related to PDF variations from the other weights - for pdfid in dataset.weight_collection.pdfsets: - if pdfid in self.pdftable: - weight_set.update( - {"weights": dataset.weight_collection.pdfset(pdfid)} - ) - weight_set.update( - { - "pdf_variations": { - self.pdftable[pdfid]["name"]: WeightCollection() - } - } - ) - for idx in range(1, self.pdftable[pdfid]["members"]): - weight_set["pdf_variations"][ - self.pdftable[pdfid]["name"] - ] += dataset.weight_collection.pdfset(pdfid + idx) - # Some checks - if len(weight_set) == 0: - logging.getLogger("MA5").debug("No additional source of uncertainty") - else: - logging.getLogger("MA5").debug(weight_set) - - # Return - return weight_set - - - ## Getting the histogram, with error bars - def GetHisto(self, histo_data, dataset, scale, weights): - # default histogram (single weight) - current_histo = histo_data.array * scale - if len(weights) == 0: - return current_histo, None - - # Many weights - initialisation - full_histo = histo_data.array_full * scale - upper_merging, lower_merging = None, None - upper_scale, lower_scale = None, None - upper_pdf, lower_pdf = None, None - scale_unc, pdf_unc, merging_unc = None, None, None - dyn_scale = dataset.dynamic_scale_choice - n_point_scale = dataset.n_point_scale_variation - merging_scale = dataset.merging_scale_variation - logging.getLogger("MA5").debug( - "Dyn. scale configuration " - + str(dyn_scale) - + "; " - + str(n_point_scale) - + "points" - ) - logging.getLogger("MA5").debug( - "Merging scale configuration " - + str(merging_scale) - ) - - # Get the nominal weight - if weights["weights"].has_scale: - # Configuration - scale_vars = weights["weights"].get_scale_vars(point=n_point_scale, dynamic=dyn_scale) - logging.getLogger("MA5").debug("Scale vars = " + str(scale_vars)) - - # Nominal histo - central_scale = weights["weights"].central_scale - nominal = ( - weights["weights"] - .get_scale( - dynamic=dyn_scale, muf=central_scale, mur=central_scale - ) - .loc - ) - logging.getLogger("MA5").debug("Nominal weight = " + str(nominal)) - current_histo = np.squeeze(full_histo[:, nominal]) - - # Scale variation envelope - if weights["weights"].has_scale: - upper_histo = np.max( - np.hstack( - [ - np.copy(current_histo).reshape(-1, 1), - full_histo[:, scale_vars.loc], - ] - ), - axis=1, - ) - lower_histo = np.min( - np.hstack( - [ - np.copy(current_histo).reshape(-1, 1), - full_histo[:, scale_vars.loc], - ] - ), - axis=1, - ) - scale_unc = np.vstack( - [ - np.abs(lower_histo - current_histo), - np.abs(upper_histo - current_histo), - ] - ) - - # PDF variations - if len(weights["pdf_variations"]) != 0: - pdf_unc = {} - for pdf_set, pdf_weights in weights["pdf_variations"].items(): - pdfvar_loc = pdf_weights.loc + nominal - pdfvar_histo = full_histo[:, pdf_weights.loc] - - ### Method to use for PDF uncertainties - ### TODO: verify that this works for all standard sets - method = ( - "replicas" - if ( - ("NNPDF" in pdf_set and not "hessian" in pdf_set) - or ("PDF4LHC" in pdf_set and "_mc_" in pdf_set) - ) - else "hessian" - ) - logging.getLogger("MA5").debug( - f"Using {method} pdf combination for {pdf_set} pdf set." - ) - - ### Replicas method - if method == "replicas": - mean_histo = np.mean(pdfvar_histo, axis=1) - uncertainties = np.sqrt( - np.sum( - np.square(pdfvar_histo - mean_histo.reshape(-1, 1)), - axis=1, - ) - / pdfvar_histo.shape[1] - ) - ### Hessian method - else: - uncertainties = np.sqrt( - np.sum( - np.square( - pdfvar_histo - current_histo.reshape(-1, 1) - ), - axis=1, - ) - ) - pdf_unc[pdf_set] = np.vstack([uncertainties, uncertainties]) - - # Total uncertainties - # TODO give options for both linear and quadrature combination - total_unc = None - # Two sets of uncertainties - if scale_unc is not None and pdf_unc is not None: - lower_unc = np.hstack( - [ - np.sqrt(np.square(scale_unc[0]) + np.square(pdf_error[0])) - for _, pdf_error in pdf_unc.items() - ] - ) - if len(lower_unc.shape) > 1: - lower_unc = np.min(lower_unc, axis=1) - - upper_unc = np.hstack( - [ - np.sqrt(np.square(scale_unc[1]) + np.square(pdf_error[1])) - for _, pdf_error in pdf_unc.items() - ] - ) - if len(upper_unc.shape) > 1: - upper_unc = np.max(upper_unc, axis=1) - total_unc = np.vstack([lower_unc, upper_unc]) - # only scale uncertainties - elif scale_unc is not None: - total_unc = scale_unc - # only PDF uncertainties - elif pdf_unc is not None: - lower_pdf = np.hstack([pdf_error[0] for _, pdf_error in pdf_unc.items()]) - if len(lower_pdf.shape) > 1: - lower_pdf = np.min(lower_pdf, axis=1) - upper_pdf = np.hstack([pdf_error[1] for _, pdf_error in pdf_unc.items()]) - if len(upper_pdf.shape) > 1: - upper_pdf = np.max(upper_pdf, axis=1) - total_unc = np.vstack([lower_pdf, upper_pdf]) - - # output - return current_histo, total_unc - diff --git a/madanalysis/layout/plotflow_for_dataset.py b/madanalysis/layout/plotflow_for_dataset.py index ed0008e1..6cedb59b 100644 --- a/madanalysis/layout/plotflow_for_dataset.py +++ b/madanalysis/layout/plotflow_for_dataset.py @@ -23,22 +23,23 @@ from __future__ import absolute_import - -import copy -from six.moves import range -import numpy as np - +from madanalysis.enumeration.uncertainty_type import UncertaintyType from madanalysis.enumeration.normalize_type import NormalizeType +from madanalysis.enumeration.report_format_type import ReportFormatType +from madanalysis.enumeration.observable_type import ObservableType +from madanalysis.enumeration.color_type import ColorType +from madanalysis.enumeration.linestyle_type import LineStyleType +from madanalysis.enumeration.backstyle_type import BackStyleType from madanalysis.enumeration.stacking_method_type import StackingMethodType -from madanalysis.dataset import dataset as Dataset -from .histogram_processor import HistogramProcessor +import copy +from six.moves import range class PlotFlowForDataset: - def __init__(self, main, dataset: Dataset): + def __init__(self, main, dataset): self.histos = [] self.main = main - self.dataset: Dataset = dataset + self.dataset = dataset # Getting xsection self.xsection = self.dataset.measured_global.xsection @@ -67,14 +68,17 @@ def CreateHistogram(self): iplot = 0 # Loop over plot - for select in self.main.selection: + for iabshisto in range(0, len(self.main.selection)): # Keep only histogram - if select.__class__.__name__ != "Histogram": + if self.main.selection[iabshisto].__class__.__name__ != "Histogram": continue # Case of histogram frequency if self.histos[iplot].__class__.__name__ == "HistogramFrequency": - NPID = True if select.observable.name == "NPID" else False + if self.main.selection[iabshisto].observable.name == "NPID": + NPID = True + else: + NPID = False self.histos[iplot].CreateHistogram(NPID, self.main) else: self.histos[iplot].CreateHistogram() @@ -84,36 +88,28 @@ def CreateHistogram(self): def ComputeScale(self): iplot = 0 + # Loop over plot - for iabshisto, select in enumerate(self.main.selection): + for iabshisto in range(0, len(self.main.selection)): # Keep only histogram - if select.__class__.__name__ != "Histogram": + if self.main.selection[iabshisto].__class__.__name__ != "Histogram": continue - processor = HistogramProcessor( - self.histos[iplot], - self.dataset.weight_collection, - self.dataset.measured_global.nevents, - self.xsection, - ) - # Reset scale scale = 0.0 - # integral - integral = ( - self.histos[iplot].positive.integral - - self.histos[iplot].negative.integral - ) - - integral = np.mean(integral) - # Case 1: Normalization to ONE - if select.stack == StackingMethodType.NORMALIZE2ONE or ( + if self.main.selection[ + iabshisto + ].stack == StackingMethodType.NORMALIZE2ONE or ( self.main.stack == StackingMethodType.NORMALIZE2ONE and self.main.selection[iabshisto].stack == StackingMethodType.AUTO ): + integral = ( + self.histos[iplot].positive.integral + - self.histos[iplot].negative.integral + ) if integral > 0.0: scale = 1.0 / integral else: @@ -127,20 +123,51 @@ def ComputeScale(self): # or depends on WEIGHT+LUMI elif self.main.normalize in [NormalizeType.LUMI, NormalizeType.LUMI_WEIGHT]: + # integral + integral = ( + self.histos[iplot].positive.integral + - self.histos[iplot].negative.integral + ) + + # compute efficiency : Nevent / Ntotal + if self.dataset.measured_global.nevents == 0: + eff = 0 + else: + eff = ( + self.histos[iplot].positive.nevents + + self.histos[iplot].negative.nevents + ) / float(self.dataset.measured_global.nevents) + # compute the good xsection value thexsection = self.xsection if self.main.normalize == NormalizeType.LUMI_WEIGHT: thexsection = thexsection * self.dataset.weight - pdf_list = [] - import os - with open(os.path.join(self.main.archi_info.ma5dir, "madanalysis/input/LHAPDF.txt"), "r") as f: - for line in f.readlines()[1:]: - pdf_list.append(int(line.split(",")[0])) - scale = processor.scale(lumi=self.main.lumi, scale_choice=self.dataset.dynamic_scale_choice, central_pdfs = pdf_list) + # compute final entries/event ratio + entries_per_events = 0 + sumw = self.histos[iplot].positive.sumw - self.histos[iplot].negative.sumw + Nentries = ( + self.histos[iplot].positive.sumwentries + - self.histos[iplot].negative.sumwentries + ) + if sumw != 0 and Nentries != 0: + entries_per_events = sumw / Nentries + + # compute the scale + if integral != 0: + scale = ( + thexsection + * self.main.lumi + * 1000 + * eff + * entries_per_events + / integral + ) + else: + scale = 1 # no scale for empty plot # Setting the computing scale self.histos[iplot].scale = copy.copy(scale) - setattr(self.histos[iplot], "processor", processor) + # Incrementing counter iplot += 1 From e5e04d008ec9000e228d1f75c382f05870a863ab Mon Sep 17 00:00:00 2001 From: "Jack Y. Araz" <jackaraz@gmail.com> Date: Wed, 3 Jan 2024 13:55:34 -0500 Subject: [PATCH 074/107] add multiweight handler --- madanalysis/multiweight/__init__.py | 0 madanalysis/multiweight/histogram.py | 488 +++++++++++++++++++++++++++ 2 files changed, 488 insertions(+) create mode 100644 madanalysis/multiweight/__init__.py create mode 100644 madanalysis/multiweight/histogram.py diff --git a/madanalysis/multiweight/__init__.py b/madanalysis/multiweight/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/madanalysis/multiweight/histogram.py b/madanalysis/multiweight/histogram.py new file mode 100644 index 00000000..4212022b --- /dev/null +++ b/madanalysis/multiweight/histogram.py @@ -0,0 +1,488 @@ +"""This file includes classes for multiweight histograms""" + +from dataclasses import dataclass +from typing import Callable, List, Text, Tuple, Union +from collections import namedtuple +import copy +import numpy as np +from madanalysis.configuration.weight_configuration import WeightCollection +from madanalysis.enumeration.stacking_method_type import StackingMethodType + + +_nevt = namedtuple("events", ["positive", "negative"]) + +# pylint: disable=C0103 + + +@dataclass +class Description: + """Histogram Description""" + + nbins: int + xmin: float + xmax: float + + def GetBinLowEdge(self, bn: int) -> float: + """ + Retreive lower edge of the bin + + Args: + bn (``int``): bin + """ + + # Special case + if bn <= 0: + return self.xmin + + if bn >= self.nbins: + return self.xmax + + # Computing steps + step = (self.xmax - self.xmin) / float(self.nbins) + + # value + return self.xmin + bn * step + + def GetBinUpperEdge(self, bn: int) -> float: + """ + retreive upper edge of the bin + + Args: + bn (``int``): bin + """ + + # Special case + if bn <= 0: + return self.xmin + if bn >= self.nbins: + return self.xmax + # Computing steps + step = (self.xmax - self.xmin) / float(self.nbins) + + # value + return self.xmin + (bn + 1) * step + + def GetBinMean(self, bn: int) -> float: + """ + Get mean of the bin + + Args: + bn (``int``): bin + """ + + # Special case + if bn < 0: + return self.xmin + if bn >= self.nbins: + return self.xmax + # Computing steps + step = (self.xmax - self.xmin) / float(self.nbins) + # value + return self.xmin + (bn + 0.5) * step + + +@dataclass +class WeightNames: + """ + Representation of weight names + + Args: + names (`List[Text]`): name of the weights + """ + + names: List[Text] + + def __getitem__(self, idx: int) -> Text: + return self.names[idx] + + def __len__(self) -> int: + return len(self.names) + + def __iter__(self) -> Text: + yield from self.names + + def __eq__(self, other) -> bool: + if not isinstance(other, WeightNames): + return False + + return all(i == j for i, j in zip(self, other)) + + +class MultiWeightBin: + """ + Representation of a multiweight bin + + Args: + weights (`List[float]`): sum of weights within the bin per weight + """ + + contract: Callable[[np.ndarray], float] = np.mean + error: Callable[[np.ndarray], Union[float, Tuple[float, float]]] = np.std + + def __init__(self, weights: List[float]): + self.weights = np.array(weights) + + def __repr__(self): + return f"MultiWeightBin({len(self)} weights)" + + def __str__(self): + return self.__repr__() + + @staticmethod + def set_contractor(func: Callable[[np.ndarray], float]) -> None: + """ + Set contractor function which computes central value for the bin + + Args: + func (``Callable[[np.ndarray], float]``): contractor function + """ + MultiWeightBin.contract = func + + @staticmethod + def set_error(func: Union[float, Tuple[float, float]]) -> None: + """ + Set error function + + Args: + func (``Union[float, Tuple[float, float]]``): error function + """ + MultiWeightBin.error = func + + @property + def central_value(self) -> float: + """Retreive the central value of the bin""" + return float(MultiWeightBin.contract(self.weights)) + + @property + def error(self) -> Union[float, Tuple[float, float]]: + """Retreive the error for the bin""" + err = MultiWeightBin.error(self.weights) + if isinstance(err, (tuple, list)): + return float(err[0]), float(err[1]) + return float(err) + + def __getitem__(self, idx: int) -> float: + return self.weights[idx] + + def __len__(self) -> int: + return len(self.weights) + + def __iter__(self) -> float: + yield from self.weights + + def __add__(self, other): + if isinstance(other, MultiWeightBin): + assert len(other) == len(self), "Dimensionality does not match" + return MultiWeightBin(other.weights + self.weights) + elif isinstance(other, (int, float)): + return MultiWeightBin(other + self.weights) + + raise ValueError("Unknown operation") + + __radd__ = __add__ + + def __iadd__(self, other): + return self.__add__(other) + + def __sub__(self, other): + other = -other + return self.__add__(other) + + __rsub__ = __sub__ + + def __pos__(self): + return self + + def __neg__(self): + return MultiWeightBin(-1.0 * self.weights) + + def __mul__(self, other): + if isinstance(other, MultiWeightBin): + assert len(other) == len(self), "Dimensionality does not match" + return MultiWeightBin(other.weights * self.weights) + elif isinstance(other, (int, float)): + return MultiWeightBin(other * self.weights) + + raise ValueError("Unknown operation") + + __rmul__ = __mul__ + + +class MultiWeightHisto: + """ + Multiweight histogram definition + + Args: + name (``Text``, default ``"__unknown_histo__"``): name of the histogram + """ + + def __init__( + self, name: Text = "__unknown_histo__", weight_collection: WeightCollection = None + ): + self.name = name + self.scale = 0.0 + # Scale of the histogram + self.central_idx = 0 + # Central weight location + self.dynamic_scale_choice = None + self.n_point_scale_variation = None + + self._positive_weights: List[MultiWeightBin] = None + # positive weights + self._negative_weights: List[MultiWeightBin] = None + # negative weights + self.weight_collection: WeightCollection = weight_collection + # weights names + + self.overflow: Tuple[MultiWeightBin, MultiWeightBin] = (None, None) + self.underflow: Tuple[MultiWeightBin, MultiWeightBin] = (None, None) + + self._desc: Description = None + self.regions: List[Text] = [] + + self._nevents: _nevt = None + self._nentries: _nevt = None + # Number of events + + self.sumw_over_events: Tuple[MultiWeightBin, MultiWeightBin] = (None, None) + # Sum of event weights over events + self.sumw_over_entries: Tuple[MultiWeightBin, MultiWeightBin] = (None, None) + # Sum of event weights over entries + self.sumw2: Tuple[MultiWeightBin, MultiWeightBin] = (None, None) + # Sum of weights squared + self.sum_value_weights: Tuple[MultiWeightBin, MultiWeightBin] = (None, None) + # Sum of value times weights + self.sum_value2_weights: Tuple[MultiWeightBin, MultiWeightBin] = (None, None) + # Sum of value squared times weights + + def __repr__(self): + return ( + "MultiWeightHisto(" + + f"name={self.name}, " + + str(self.nevents) + + ", " + + str(self._desc) + + ", " + + str(self._positive_weights) + + ")" + ) + + def set_central_weight_loc( + self, scale_choice: int, n_point_scale_variation: int, central_pdfs: List[int] + ) -> None: + self.central_idx = self.weight_collection.nominal(scale_choice, central_pdfs).loc + self.dynamic_scale_choice = scale_choice + self.n_point_scale_variation = n_point_scale_variation + print("Central PDF loc:", self.central_idx) + + @property + def is_consistent(self) -> bool: + """Is histogram consistent""" + if self._positive_weights is None or self._negative_weights is None: + return False + weight_col = len(self.weight_collection) + check_pos_weights = all(weight_col == len(bn) for bn in self._positive_weights) + check_neg_weights = all(weight_col == len(bn) for bn in self._negative_weights) + check_overflow = all( + [weight_col == len(self.overflow[0]), weight_col == len(self.overflow[1])] + ) + check_underflow = all( + [weight_col == len(self.underflow[0]), weight_col == len(self.underflow[1])] + ) + + return all( + [check_pos_weights, check_neg_weights, check_overflow, check_underflow] + ) + + @property + def description(self) -> Description: + """Description""" + return self._desc + + def set_description(self, nbins: int, xmin: float, xmax: float) -> None: + """Set histogram description""" + self._desc = Description(nbins=nbins, xmin=xmin, xmax=xmax) + + def set_nevents(self, positive: int, negative: int) -> None: + """Set number of events""" + self._nevents = _nevt(positive=positive, negative=negative) + + @property + def nevents(self) -> _nevt: + """retreive number of events""" + return self._nevents.positive + self._nevents.negative + + def set_nentries(self, positive: int, negative: int) -> None: + """set number of entries""" + self._nentries = _nevt(positive=positive, negative=negative) + + @property + def nentries(self) -> _nevt: + """retreive number of entries""" + return self._nentries.positive + self._nentries.negative + + @property + def shape(self) -> Tuple[int, int]: + """ + Returns dimensionality of the histogram + + Returns: + ``Tuple[int,int]``: + Number of weights, number of bins + """ + numb_of_weights = len(self.weight_collection) + numb_of_bins = 0 + + if self._positive_weights is not None: + numb_of_bins = len(self._positive_weights) + elif self._negative_weights is not None: + numb_of_bins = len(self._negative_weights) + return (numb_of_weights, numb_of_bins) + + def append_positive_weights(self, weights: List[float]) -> None: + """ + Add positive weights + + Args: + weights (``List[float]``): weights + """ + if self._positive_weights is not None: + assert len(weights) == len( + self._positive_weights[-1] + ), "Dimensionality does not match" + self._positive_weights.append(MultiWeightBin(weights)) + else: + self._positive_weights = [MultiWeightBin(weights)] + + def append_negative_weights(self, weights: List[float]) -> None: + """ + Add negative weights + + Args: + weights (``List[float]``): weights + """ + if self._negative_weights is not None: + assert len(weights) == len( + self._negative_weights[-1] + ), "Dimensionality does not match" + self._negative_weights.append(MultiWeightBin(weights)) + else: + self._negative_weights = [MultiWeightBin(weights)] + + def line_to_bin(self, line: Text) -> None: + """ + Convert line to histogram bin + + Args: + line (``Text``): a dataline from SAF file + """ + positive, negative = [], [] + for iw, word in enumerate(line.split()): + if word == "#": + break + if iw % 2 == 0: + positive.append(float(word)) + else: + negative.append(float(word)) + self.append_positive_weights(positive) + self.append_negative_weights(negative) + + def weights_to_bin( + self, dest: Text, weights: Tuple[List[float], List[float]] + ) -> None: + if len(weights) == 2: + weights = ( + MultiWeightBin(weights=weights[0]), + MultiWeightBin(weights=weights[1]), + ) + else: + weights = MultiWeightBin(weights=weights) + setattr(self, dest, weights) + + @property + def integral(self): + """Compute the integral of the histogram""" + return ( + sum(self._positive_weights) + + self.underflow[0] + + self.overflow[0] + - (sum(self._negative_weights) + self.underflow[1] + self.overflow[1]) + )[self.central_idx] + + @property + def central_sumw_over_events(self) -> float: + """Sum of weights over events""" + return ( + self.sumw_over_events[0][self.central_idx] + - self.sumw_over_events[1][self.central_idx] + ) + + @property + def central_sumw_over_entries(self) -> float: + """Sum of weights over entries""" + return ( + self.sumw_over_entries[0][self.central_idx] + - self.sumw_over_entries[1][self.central_idx] + ) + + @property + def sumw(self) -> float: + """sum of weights""" + if self.central_sumw_over_entries < 0: + return 0.0 + return self.central_sumw_over_entries + + @property + def weights(self) -> np.ndarray: + return np.array( + [ + (pos - neg).weights[self.central_idx] + for pos, neg in zip(self._positive_weights, self._negative_weights) + ] + ) + + @property + def scale_uncertainties(self) -> Tuple[List[float], List[float]]: + """ + Retreive scale uncertainties + + Returns: + ``Tuple[List[float], List[float]]``: + lower and upper uncertainties per bin + """ + bins = [ + (pos - neg) + for pos, neg in zip(self._positive_weights, self._negative_weights) + ] + + if not self.weight_collection.has_scale: + central = [b[self.central_idx] for b in bins] + return central, central + + weight_collection = self.weight_collection.get_scale_vars( + self.n_point_scale_variation, self.dynamic_scale_choice + ) + central_scale_idx = self.n_point_scale_variation // 2 + + upper, lower = [], [] + for current_bin in bins: + central = current_bin[central_scale_idx] + upper_unc = copy.deepcopy(central) + lower_unc = copy.deepcopy(central) + upper_diff, lower_diff = 0, 0 + # find maximum uncertainty + for iw, w in enumerate(weight_collection): + if iw == self.n_point_scale_variation // 2: + continue + if iw < self.n_point_scale_variation // 2: + if abs(central - current_bin[w.loc]) > lower_diff: + lower_diff = abs(central - current_bin[w.loc]) + lower_unc = current_bin[w.loc] + elif iw > self.n_point_scale_variation // 2: + if abs(central - current_bin[w.loc]) > upper_diff: + upper_diff = abs(central - current_bin[w.loc]) + upper_unc = current_bin[w.loc] + + upper.append(upper_unc) + lower.append(lower_unc) + return lower, upper From 93f199363981bb074ef7e94f9bbf244be5b2ac99 Mon Sep 17 00:00:00 2001 From: "Jack Y. Araz" <jackaraz@gmail.com> Date: Wed, 3 Jan 2024 13:55:49 -0500 Subject: [PATCH 075/107] minor fixes --- .../configuration/weight_configuration.py | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/madanalysis/configuration/weight_configuration.py b/madanalysis/configuration/weight_configuration.py index 7f1a6861..8319b954 100644 --- a/madanalysis/configuration/weight_configuration.py +++ b/madanalysis/configuration/weight_configuration.py @@ -22,8 +22,9 @@ ################################################################################ -from typing import Text, List, Dict, Any, Tuple from dataclasses import dataclass, field +from typing import Any, Dict, List, Text, Tuple + import numpy as np @@ -48,15 +49,15 @@ def __post_init__(self) -> None: # PYTHIA NOMINAL WEIGHT # -> note: to ignore, we need to use the MG5 nominal weight if self.name is "Weight": - return + return for sector in sectors: if "AUX" in sector: self._aux = int(sectors[1]) break elif any([x in sector for x in ["scomp", "smax", "smin"]]): - self._aux = float(sector.split("=")[1]) - break + self._aux = float(sector.split("=")[1]) + break if "MERGING" in sector: self._merging = float(sector.split("=")[1]) elif "DYNSCALE" in sector: @@ -68,7 +69,7 @@ def __post_init__(self) -> None: elif "PDF" in sector: self._pdf = int(sector.split("=")[1]) elif "ALPSFACT" in sector: - self._alphas= float(sector.split("=")[1]) + self._alphas = float(sector.split("=")[1]) def __repr__(self) -> Text: return ( @@ -174,7 +175,7 @@ def nominal(self, scale_choice: int, central_pdfs: np.array) -> Weight: for w in self: if any([not x is None for x in [w.aux, w.alphas]]): continue - if w.muf!=1.0 or w.mur!=1.0 or w.dynamic_scale!=scale_choice: + if w.muf != 1.0 or w.mur != 1.0 or w.dynamic_scale != scale_choice: continue if not w.pdfset in central_pdfs: continue @@ -294,7 +295,10 @@ def get_scale( [ w for w in self - if w.dynamic_scale == dynamic and w.muf == muf and w.mur == mur and w.alphas is None + if w.dynamic_scale == dynamic + and w.muf == muf + and w.mur == mur + and w.alphas is None ] ) From 503b28eb456c739f22a57981815365533f235fef Mon Sep 17 00:00:00 2001 From: "Jack Y. Araz" <jackaraz@gmail.com> Date: Wed, 3 Jan 2024 13:56:34 -0500 Subject: [PATCH 076/107] add separate multiweight reader --- madanalysis/IOinterface/job_reader.py | 307 ++++++++++++++++++++------ madanalysis/interpreter/cmd_submit.py | 28 ++- 2 files changed, 256 insertions(+), 79 deletions(-) diff --git a/madanalysis/IOinterface/job_reader.py b/madanalysis/IOinterface/job_reader.py index 24963f77..d4a5b23f 100644 --- a/madanalysis/IOinterface/job_reader.py +++ b/madanalysis/IOinterface/job_reader.py @@ -34,6 +34,7 @@ from madanalysis.layout.histogram import Histogram from madanalysis.layout.histogram_logx import HistogramLogX from madanalysis.layout.histogram_frequency import HistogramFrequency +from madanalysis.multiweight.histogram import MultiWeightHisto def check_instance(instance: str, instance_type: Callable[[str], Any]) -> bool: @@ -91,7 +92,6 @@ def CheckFile(self, dataset): return False def ExtractSampleInfo(self, words, numline, filename): - # Creating container for info results = SampleInfo() @@ -145,7 +145,6 @@ def ExtractCutLine( return self.ExtractStatisticsFloat(words, numline, filename) def ExtractDescription(self, words, numline, filename): - # Extracting nbins try: a = int(words[0]) @@ -216,7 +215,6 @@ def ExtractStatisticsFloat( return positive_weights, negative_weights def ExtractDataFreq(self, words, numline, filename): - # Extracting label try: a = int(words[0]) @@ -266,7 +264,6 @@ def ExtractDataFreq(self, words, numline, filename): # selection plots -> plot def ExtractGeneral(self, dataset): - # Getting the output file name name = InstanceName.Get(dataset.name) filename = self.safdir + "/" + name + "/" + name + ".saf" @@ -288,7 +285,6 @@ def ExtractGeneral(self, dataset): # Loop over the lines numline = 0 for line in file: - # Incrementing line counter numline += 1 @@ -415,6 +411,7 @@ def ExtractHistos(self, dataset, plot, merging=False): # Initializing temporary containers histoinfo = Histogram() + multiweight_histo = MultiWeightHisto(weight_collection=dataset.weight_collection) histologxinfo = HistogramLogX() histofreqinfo = HistogramFrequency() data_positive = [] @@ -438,7 +435,6 @@ def ExtractHistos(self, dataset, plot, merging=False): words = line.split() if len(words) == 0: continue - # decoding the file if len(words) == 1 and words[0][0] == "<" and words[0][-1] == ">": if words[0].lower() == "<safheader>": @@ -469,6 +465,15 @@ def ExtractHistos(self, dataset, plot, merging=False): plot.histos[-1].positive.array = data_positive[:] plot.histos[-1].negative.array = data_negative[:] histoinfo.Reset() + if multiweight_histo.is_consistent: + plot.multiweight_histos.append(copy.deepcopy(multiweight_histo)) + print(multiweight_histo) + print(multiweight_histo.shape) + else: + plot.multiweight_histos.append(False) + multiweight_histo = MultiWeightHisto( + weight_collection=dataset.weight_collection + ) data_positive = [] data_negative = [] elif words[0].lower() == "<histofrequency>": @@ -501,6 +506,7 @@ def ExtractHistos(self, dataset, plot, merging=False): myname = line[1:-1] if histoTag.activated: histoinfo.name = myname + multiweight_histo.name = myname elif histoLogXTag.activated: histologxinfo.name = myname elif histoFreqTag.activated: @@ -520,6 +526,9 @@ def ExtractHistos(self, dataset, plot, merging=False): histoinfo.nbins = results[0] histoinfo.xmin = results[1] histoinfo.xmax = results[2] + multiweight_histo.set_description( + results[0], results[1], results[2] + ) elif histoLogXTag.activated: histologxinfo.nbins = results[0] histologxinfo.xmin = results[1] @@ -532,6 +541,7 @@ def ExtractHistos(self, dataset, plot, merging=False): elif descriptionTag.Nlines >= 1: if histoTag.activated and len(words) == 1: histoinfo.regions.append(words[0]) + multiweight_histo.regions.append(words[0]) elif histoLogXTag.activated and len(words) == 1: histologxinfo.regions.append(words[0]) elif histoFreqTag.activated and len(words) == 1: @@ -552,77 +562,181 @@ def ExtractHistos(self, dataset, plot, merging=False): if statisticsTag.Nlines == 0: results = self.ExtractStatisticsInt(words, numline, filename) if histoTag.activated: - histoinfo.positive.nevents = results[0] - histoinfo.negative.nevents = results[1] + histoinfo.positive.nevents = ( + results[0] if isinstance(results[0], float) else results[0][0] + ) + histoinfo.negative.nevents = ( + results[1] if isinstance(results[1], float) else results[1][0] + ) + multiweight_histo.set_nevents( + results[0] + if isinstance(results[0], float) + else results[0][0], + results[1] + if isinstance(results[1], float) + else results[1][0], + ) + elif histoLogXTag.activated: - histologxinfo.positive.nevents = results[0] - histologxinfo.negative.nevents = results[1] + histologxinfo.positive.nevents = ( + results[0] if isinstance(results[0], float) else results[0][0] + ) + histologxinfo.negative.nevents = ( + results[1] if isinstance(results[1], float) else results[1][0] + ) elif histoFreqTag.activated: - histofreqinfo.positive.nevents = results[0] - histofreqinfo.negative.nevents = results[1] + histofreqinfo.positive.nevents = ( + results[0] if isinstance(results[0], float) else results[0][0] + ) + histofreqinfo.negative.nevents = ( + results[1] if isinstance(results[1], float) else results[1][0] + ) elif statisticsTag.Nlines == 1: results = self.ExtractStatisticsFloat(words, numline, filename) if histoTag.activated: - histoinfo.positive.sumwentries = results[0] - histoinfo.negative.sumwentries = results[1] + histoinfo.positive.sumwentries = ( + results[0] if isinstance(results[0], float) else results[0][0] + ) + histoinfo.negative.sumwentries = ( + results[1] if isinstance(results[1], float) else results[1][0] + ) + multiweight_histo.weights_to_bin( + "sumw_over_entries", (results[0], results[1]) + ) elif histoLogXTag.activated: - histologxinfo.positive.sumwentries = results[0] - histologxinfo.negative.sumwentries = results[1] + histologxinfo.positive.sumwentries = ( + results[0] if isinstance(results[0], float) else results[0][0] + ) + histologxinfo.negative.sumwentries = ( + results[1] if isinstance(results[1], float) else results[1][0] + ) elif histoFreqTag.activated: - histofreqinfo.positive.sumwentries = results[0] - histofreqinfo.negative.sumwentries = results[1] + histofreqinfo.positive.sumwentries = ( + results[0] if isinstance(results[0], float) else results[0][0] + ) + histofreqinfo.negative.sumwentries = ( + results[1] if isinstance(results[1], float) else results[1][0] + ) elif statisticsTag.Nlines == 2: results = self.ExtractStatisticsInt(words, numline, filename) if histoTag.activated: - histoinfo.positive.nentries = results[0] - histoinfo.negative.nentries = results[1] + histoinfo.positive.nentries = ( + results[0] if isinstance(results[0], float) else results[0][0] + ) + histoinfo.negative.nentries = ( + results[1] if isinstance(results[1], float) else results[1][0] + ) + multiweight_histo.set_nentries( + results[0] + if isinstance(results[0], float) + else results[0][0], + results[1] + if isinstance(results[1], float) + else results[1][0], + ) elif histoLogXTag.activated: - histologxinfo.positive.nentries = results[0] - histologxinfo.negative.nentries = results[1] + histologxinfo.positive.nentries = ( + results[0] if isinstance(results[0], float) else results[0][0] + ) + histologxinfo.negative.nentries = ( + results[1] if isinstance(results[1], float) else results[1][0] + ) elif histoFreqTag.activated: - histofreqinfo.positive.nentries = results[0] - histofreqinfo.negative.nentries = results[1] + histofreqinfo.positive.nentries = ( + results[0] if isinstance(results[0], float) else results[0][0] + ) + histofreqinfo.negative.nentries = ( + results[1] if isinstance(results[1], float) else results[1][0] + ) elif statisticsTag.Nlines == 3: results = self.ExtractStatisticsFloat(words, numline, filename) if histoTag.activated: - histoinfo.positive.sumw = results[0] - histoinfo.negative.sumw = results[1] + histoinfo.positive.sumw = ( + results[0] if isinstance(results[0], float) else results[0][0] + ) + histoinfo.negative.sumw = ( + results[1] if isinstance(results[1], float) else results[1][0] + ) + multiweight_histo.weights_to_bin( + "sumw_over_events", (results[0], results[1]) + ) elif histoLogXTag.activated: - histologxinfo.positive.sumw = results[0] - histologxinfo.negative.sumw = results[1] + histologxinfo.positive.sumw = ( + results[0] if isinstance(results[0], float) else results[0][0] + ) + histologxinfo.negative.sumw = ( + results[1] if isinstance(results[1], float) else results[1][0] + ) elif histoFreqTag.activated: - histofreqinfo.positive.sumw = results[0] - histofreqinfo.negative.sumw = results[1] + histofreqinfo.positive.sumw = ( + results[0] if isinstance(results[0], float) else results[0][0] + ) + histofreqinfo.negative.sumw = ( + results[1] if isinstance(results[1], float) else results[1][0] + ) elif statisticsTag.Nlines == 4 and not histoFreqTag.activated: results = self.ExtractStatisticsFloat(words, numline, filename) if histoTag.activated: - histoinfo.positive.sumw2 = results[0] - histoinfo.negative.sumw2 = results[1] + histoinfo.positive.sumw2 = ( + results[0] if isinstance(results[0], float) else results[0][0] + ) + histoinfo.negative.sumw2 = ( + results[1] if isinstance(results[1], float) else results[1][0] + ) + multiweight_histo.weights_to_bin( + "sumw2", (results[0], results[1]) + ) elif histoLogXTag.activated: - histologxinfo.positive.sumw2 = results[0] - histologxinfo.negative.sumw2 = results[1] + histologxinfo.positive.sumw2 = ( + results[0] if isinstance(results[0], float) else results[0][0] + ) + histologxinfo.negative.sumw2 = ( + results[1] if isinstance(results[1], float) else results[1][0] + ) elif statisticsTag.Nlines == 5 and not histoFreqTag.activated: results = self.ExtractStatisticsFloat(words, numline, filename) if histoTag.activated: - histoinfo.positive.sumwx = results[0] - histoinfo.negative.sumwx = results[1] + histoinfo.positive.sumwx = ( + results[0] if isinstance(results[0], float) else results[0][0] + ) + histoinfo.negative.sumwx = ( + results[1] if isinstance(results[1], float) else results[1][0] + ) + multiweight_histo.weights_to_bin( + "sum_value_weights", (results[0], results[1]) + ) elif histoLogXTag.activated: - histologxinfo.positive.sumwx = results[0] - histologxinfo.negative.sumwx = results[1] + histologxinfo.positive.sumwx = ( + results[0] if isinstance(results[0], float) else results[0][0] + ) + histologxinfo.negative.sumwx = ( + results[1] if isinstance(results[1], float) else results[1][0] + ) elif statisticsTag.Nlines == 6 and not histoFreqTag.activated: results = self.ExtractStatisticsFloat(words, numline, filename) if histoTag.activated: - histoinfo.positive.sumw2x = results[0] - histoinfo.negative.sumw2x = results[1] + histoinfo.positive.sumw2x = ( + results[0] if isinstance(results[0], float) else results[0][0] + ) + histoinfo.negative.sumw2x = ( + results[1] if isinstance(results[1], float) else results[1][0] + ) + multiweight_histo.weights_to_bin( + "sum_value2_weights", (results[0], results[1]) + ) elif histoLogXTag.activated: - histologxinfo.positive.sumw2x = results[0] - histologxinfo.negative.sumw2x = results[1] + histologxinfo.positive.sumw2x = ( + results[0] if isinstance(results[0], float) else results[0][0] + ) + histologxinfo.negative.sumw2x = ( + results[1] if isinstance(results[1], float) else results[1][0] + ) else: logging.getLogger("MA5").warning("Extra line is found: " + line) @@ -637,22 +751,57 @@ def ExtractHistos(self, dataset, plot, merging=False): results = self.ExtractStatisticsFloat(words, numline, filename) if dataTag.Nlines == 0: if histoTag.activated: - histoinfo.positive.underflow = results[0] - histoinfo.negative.underflow = results[1] + histoinfo.positive.underflow = ( + results[0] if isinstance(results[0], float) else results[0][0] + ) + histoinfo.negative.underflow = ( + results[1] if isinstance(results[1], float) else results[1][0] + ) + multiweight_histo.weights_to_bin( + "underflow", (results[0], results[1]) + ) elif histoLogXTag.activated: - histologxinfo.positive.underflow = results[0] - histologxinfo.negative.underflow = results[1] + histologxinfo.positive.underflow = ( + results[0] if isinstance(results[0], float) else results[0][0] + ) + histologxinfo.negative.underflow = ( + results[1] if isinstance(results[1], float) else results[1][0] + ) elif dataTag.Nlines == (histoinfo.nbins + 1): if histoTag.activated: - histoinfo.positive.overflow = results[0] - histoinfo.negative.overflow = results[1] + histoinfo.positive.overflow = ( + results[0] if isinstance(results[0], float) else results[0][0] + ) + histoinfo.negative.overflow = ( + results[1] if isinstance(results[1], float) else results[1][0] + ) + multiweight_histo.weights_to_bin( + "overflow", (results[0], results[1]) + ) elif histoLogXTag.activated: - histologxinfo.positive.overflow = results[0] - histologxinfo.negative.overflow = results[1] + histologxinfo.positive.overflow = ( + results[0] if isinstance(results[0], float) else results[0][0] + ) + histologxinfo.negative.overflow = ( + results[1] if isinstance(results[1], float) else results[1][0] + ) elif dataTag.Nlines >= 1 and dataTag.Nlines <= histoinfo.nbins: if histoTag.activated or histoLogXTag.activated: - data_positive.append(results[0]) - data_negative.append(results[1]) + # print( + # "here:", + # histoinfo.name, + # results[0] + # if isinstance(results[0], float) + # else results[0][0], + # ) + data_positive.append( + results[0] if isinstance(results[0], float) else results[0][0] + ) + data_negative.append( + results[1] if isinstance(results[1], float) else results[1][0] + ) + multiweight_histo.append_positive_weights(results[0]) + multiweight_histo.append_negative_weights(results[1]) else: logging.getLogger("MA5").warning("Extra line is found: " + line) dataTag.newline() @@ -717,12 +866,13 @@ def ExtractCuts(self, dataset, cut): # Loop over the lines numline = 0 for line in file: - # Incrementing line counter numline += 1 # Removing comments - is_comment_line = (len(line.split('#'))==2 and line.split('#')[-1]=='\n') + is_comment_line = ( + len(line.split("#")) == 2 and line.split("#")[-1] == "\n" + ) index = line.find("#") if index != -1: line = line[:index] @@ -758,16 +908,27 @@ def ExtractCuts(self, dataset, cut): elif initialTag.activated and not is_comment_line and len(words) >= 2: results = self.ExtractCutLine(words, numline, myfile) - print(numline, results) if initialTag.Nlines == 0: - cut.initial.nentries_pos = results[0] - cut.initial.nentries_neg = results[1] + cut.initial.nentries_pos = ( + results[0] if isinstance(results[0], float) else results[0][0] + ) + cut.initial.nentries_neg = ( + results[1] if isinstance(results[1], float) else results[1][0] + ) elif initialTag.Nlines == 1: - cut.initial.sumw_pos = results[0] - cut.initial.sumw_neg = results[1] + cut.initial.sumw_pos = ( + results[0] if isinstance(results[0], float) else results[0][0] + ) + cut.initial.sumw_neg = ( + results[1] if isinstance(results[1], float) else results[1][0] + ) elif initialTag.Nlines == 2: - cut.initial.sumw2_pos = results[0] - cut.initial.sumw2_neg = results[1] + cut.initial.sumw2_pos = ( + results[0] if isinstance(results[0], float) else results[0][0] + ) + cut.initial.sumw2_neg = ( + results[1] if isinstance(results[1], float) else results[1][0] + ) else: logging.getLogger("MA5").warning("Extra line is found: " + line) initialTag.newline() @@ -783,14 +944,26 @@ def ExtractCuts(self, dataset, cut): elif cutTag.activated and len(words) >= 2: results = self.ExtractCutLine(words, numline, myfile) if cutTag.Nlines == 1: - cutinfo.nentries_pos = results[0] - cutinfo.nentries_neg = results[1] + cutinfo.nentries_pos = ( + results[0] if isinstance(results[0], float) else results[0][0] + ) + cutinfo.nentries_neg = ( + results[1] if isinstance(results[1], float) else results[1][0] + ) elif cutTag.Nlines == 2: - cutinfo.sumw_pos = results[0] - cutinfo.sumw_neg = results[1] + cutinfo.sumw_pos = ( + results[0] if isinstance(results[0], float) else results[0][0] + ) + cutinfo.sumw_neg = ( + results[1] if isinstance(results[1], float) else results[1][0] + ) elif cutTag.Nlines == 3: - cutinfo.sumw2_pos = results[0] - cutinfo.sumw2_neg = results[1] + cutinfo.sumw2_pos = ( + results[0] if isinstance(results[0], float) else results[0][0] + ) + cutinfo.sumw2_neg = ( + results[1] if isinstance(results[1], float) else results[1][0] + ) else: logging.getLogger("MA5").warning("Extra line is found: " + line) cutTag.newline() diff --git a/madanalysis/interpreter/cmd_submit.py b/madanalysis/interpreter/cmd_submit.py index c3d4affa..d4276986 100644 --- a/madanalysis/interpreter/cmd_submit.py +++ b/madanalysis/interpreter/cmd_submit.py @@ -24,21 +24,25 @@ from __future__ import absolute_import -import logging, glob, os +import glob +import logging +import os + +from chronometer import Chronometer from six.moves import range +from string_tools import StringTools +from madanalysis.enumeration.report_format_type import ReportFormatType +from madanalysis.install.detector_manager import DetectorManager from madanalysis.interpreter.cmd_base import CmdBase +from madanalysis.IOinterface.delphescard_checker import DelphesCardChecker +from madanalysis.IOinterface.job_reader import JobReader from madanalysis.IOinterface.job_writer import JobWriter from madanalysis.IOinterface.layout_writer import LayoutWriter -from madanalysis.IOinterface.job_reader import JobReader -from madanalysis.enumeration.report_format_type import ReportFormatType from madanalysis.layout.layout import Layout -from madanalysis.install.detector_manager import DetectorManager from madanalysis.misc.run_recast import RunRecast -from madanalysis.IOinterface.delphescard_checker import DelphesCardChecker -from chronometer import Chronometer -from string_tools import StringTools +# pylint: disable=C0200,C0103 class CmdSubmit(CmdBase): @@ -529,13 +533,13 @@ def extract(self, dirname, layout): if self.main.recasting.status != "on": self.logger.info(" Extracting data from the output files...") - for i in range(0, len(self.main.datasets)): - jobber.ExtractGeneral(self.main.datasets[i]) - jobber.ExtractHistos(self.main.datasets[i], layout.plotflow.detail[i]) - jobber.ExtractCuts(self.main.datasets[i], layout.cutflow.detail[i]) + for idat, dataset in enumerate(self.main.datasets): + jobber.ExtractGeneral(dataset) + jobber.ExtractHistos(dataset, layout.plotflow.detail[idat]) + jobber.ExtractCuts(dataset, layout.cutflow.detail[idat]) if self.main.merging.enable: jobber.ExtractHistos( - self.main.datasets[i], layout.merging.detail[i], merging=True + dataset, layout.merging.detail[idat], merging=True ) return True From 98c6d1cd77b2079035af30b8a9267ae44c7f2103 Mon Sep 17 00:00:00 2001 From: "Jack Y. Araz" <jackaraz@gmail.com> Date: Wed, 3 Jan 2024 13:57:17 -0500 Subject: [PATCH 077/107] adapt --- madanalysis/layout/histogram.py | 132 +- madanalysis/layout/histogram_processor.py | 12 +- madanalysis/layout/plotflow.py | 1932 ++++++++++++++------ madanalysis/layout/plotflow_for_dataset.py | 65 +- 4 files changed, 1454 insertions(+), 687 deletions(-) diff --git a/madanalysis/layout/histogram.py b/madanalysis/layout/histogram.py index c3a75701..0718ae6c 100644 --- a/madanalysis/layout/histogram.py +++ b/madanalysis/layout/histogram.py @@ -1,99 +1,103 @@ ################################################################################ -# +# # Copyright (C) 2012-2023 Jack Araz, Eric Conte & Benjamin Fuks # The MadAnalysis development team, email: <ma5team@iphc.cnrs.fr> -# +# # This file is part of MadAnalysis 5. # Official website: <https://github.com/MadAnalysis/madanalysis5> -# +# # MadAnalysis 5 is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. -# +# # MadAnalysis 5 is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. -# +# # You should have received a copy of the GNU General Public License # along with MadAnalysis 5. If not, see <http://www.gnu.org/licenses/> -# +# ################################################################################ from __future__ import absolute_import -from madanalysis.layout.histogram_core import HistogramCore + import logging + from six.moves import range +from madanalysis.layout.histogram_core import HistogramCore -class Histogram: +class Histogram: def __init__(self): self.Reset() - def Print(self): # General info - inform = self.name + ' ' + str(self.nbins) + str(self.xmin) + ' ' + str(self.xmax) - if self.ymin!=[] or self.ymax!=[]: - inform = inform + ' ' + str(self.ymin) + ' ' + str(self.ymax) - logging.getLogger('MA5').info(inform) + inform = self.name + " " + str(self.nbins) + str(self.xmin) + " " + str(self.xmax) + if self.ymin != [] or self.ymax != []: + inform = inform + " " + str(self.ymin) + " " + str(self.ymax) + logging.getLogger("MA5").info(inform) # Data self.positive.Print() self.negative.Print() self.summary.Print() - - def FinalizeReading(self,main,dataset): + def FinalizeReading(self, main, dataset): # Statistics - self.summary.nevents = self.positive.nevents + self.negative.nevents - self.summary.nentries = self.positive.nentries + self.negative.nentries + self.summary.nevents = self.positive.nevents + self.negative.nevents + self.summary.nentries = self.positive.nentries + self.negative.nentries # sumw - self.summary.sumw = self.positive.sumw - self.negative.sumw - if self.summary.sumw<0: - self.summary.sumw=0 + self.summary.sumw = self.positive.sumw - self.negative.sumw + if self.summary.sumw < 0: + self.summary.sumw = 0 # sumw2 - self.summary.sumw2 = self.positive.sumw2 - self.negative.sumw2 - if self.summary.sumw2<0: - self.summary.sumw2=0 + self.summary.sumw2 = self.positive.sumw2 - self.negative.sumw2 + if self.summary.sumw2 < 0: + self.summary.sumw2 = 0 # sumwx - self.summary.sumwx = self.positive.sumwx - self.negative.sumwx + self.summary.sumwx = self.positive.sumwx - self.negative.sumwx # no correction on it # sumw2x - self.summary.sumw2x = self.positive.sumw2x - self.negative.sumw2x + self.summary.sumw2x = self.positive.sumw2x - self.negative.sumw2x # no correction on it # underflow self.summary.underflow = self.positive.underflow - self.negative.underflow - if self.summary.underflow<0: - self.summary.underflow=0 + if self.summary.underflow < 0: + self.summary.underflow = 0 # overflow - self.summary.overflow = self.positive.overflow - self.negative.overflow - if self.summary.overflow<0: - self.summary.overflow=0 + self.summary.overflow = self.positive.overflow - self.negative.overflow + if self.summary.overflow < 0: + self.summary.overflow = 0 # Data data = [] - for i in range(0,len(self.positive.array)): - data.append(self.positive.array[i]-self.negative.array[i]) - if data[-1]<0: - self.warnings.append(\ - 'dataset='+dataset.name+\ - ' -> bin '+str(i)+\ - ' has a negative content : '+\ - str(data[-1])+'. This value is set to zero') - data[-1]=0 - self.summary.array = data[:] # [:] -> clone of data + for i in range(0, len(self.positive.array)): + data.append(self.positive.array[i] - self.negative.array[i]) + if data[-1] < 0: + self.warnings.append( + "dataset=" + + dataset.name + + " -> bin " + + str(i) + + " has a negative content : " + + str(data[-1]) + + ". This value is set to zero" + ) + data[-1] = 0 + self.summary.array = data[:] # [:] -> clone of data # Integral self.positive.ComputeIntegral() @@ -103,23 +107,21 @@ def FinalizeReading(self,main,dataset): def CreateHistogram(self): pass - - def Reset(self): # General info - self.name = "" + self.name = "" self.nbins = 100 - self.xmin = 0. - self.xmax = 100. - self.ymin = [] - self.ymax = [] - self.scale = 0. + self.xmin = 0.0 + self.xmax = 100.0 + self.ymin = [] + self.ymax = [] + self.scale = 0.0 # Data self.positive = HistogramCore() self.negative = HistogramCore() - self.summary = HistogramCore() + self.summary = HistogramCore() # ROOT histo self.myhisto = 0 @@ -133,49 +135,47 @@ def Reset(self): def GetRegions(self): return self.regions - def GetBinLowEdge(self,bin): + def GetBinLowEdge(self, bin): # Special case - if bin<=0: + if bin <= 0: return self.xmin - if bin>=self.nbins: + if bin >= self.nbins: return self.xmax # Computing steps - step = (self.xmax - self.xmin) / float (self.nbins) + step = (self.xmax - self.xmin) / float(self.nbins) # value - return self.xmin+bin*step - + return self.xmin + bin * step - def GetBinUpperEdge(self,bin): + def GetBinUpperEdge(self, bin): # Special case - if bin<=0: + if bin <= 0: return self.xmin - if bin>=self.nbins: + if bin >= self.nbins: return self.xmax # Computing steps - step = (self.xmax - self.xmin) / float (self.nbins) + step = (self.xmax - self.xmin) / float(self.nbins) # value - return self.xmin+(bin+1)*step - + return self.xmin + (bin + 1) * step - def GetBinMean(self,bin): + def GetBinMean(self, bin): # Special case - if bin<0: + if bin < 0: return self.xmin - if bin>=self.nbins: + if bin >= self.nbins: return self.xmax # Computing steps - step = (self.xmax - self.xmin) / float (self.nbins) + step = (self.xmax - self.xmin) / float(self.nbins) # value - return self.xmin+(bin+0.5)*step + return self.xmin + (bin + 0.5) * step diff --git a/madanalysis/layout/histogram_processor.py b/madanalysis/layout/histogram_processor.py index cbfcb7d7..1be95ede 100644 --- a/madanalysis/layout/histogram_processor.py +++ b/madanalysis/layout/histogram_processor.py @@ -21,14 +21,16 @@ # ################################################################################ -from typing import List, Union, Text, Dict import json from dataclasses import dataclass -from .histogram import Histogram -from madanalysis.configuration.weight_configuration import WeightCollection +from typing import Dict, List, Text, Union import numpy as np +from madanalysis.configuration.weight_configuration import WeightCollection + +from .histogram import Histogram + @dataclass class HistogramProcessor: @@ -96,7 +98,9 @@ def scale(self, lumi: float, scale_choice: int, central_pdfs: np.array) -> float scale of the histogram """ # find nominal weight location - idx = self.weight_collection.nominal(scale_choice=scale_choice, central_pdfs=central_pdfs).loc + idx = self.weight_collection.nominal( + scale_choice=scale_choice, central_pdfs=central_pdfs + ).loc if self.integral[idx] == 0: return 0.0 diff --git a/madanalysis/layout/plotflow.py b/madanalysis/layout/plotflow.py index 6ef6f696..12e40696 100644 --- a/madanalysis/layout/plotflow.py +++ b/madanalysis/layout/plotflow.py @@ -1,74 +1,79 @@ ################################################################################ -# +# # Copyright (C) 2012-2023 Jack Araz, Eric Conte & Benjamin Fuks # The MadAnalysis development team, email: <ma5team@iphc.cnrs.fr> -# +# # This file is part of MadAnalysis 5. # Official website: <https://github.com/MadAnalysis/madanalysis5> -# +# # MadAnalysis 5 is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. -# +# # MadAnalysis 5 is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. -# +# # You should have received a copy of the GNU General Public License # along with MadAnalysis 5. If not, see <http://www.gnu.org/licenses/> -# +# ################################################################################ from __future__ import absolute_import -from madanalysis.enumeration.uncertainty_type import UncertaintyType -from madanalysis.enumeration.normalize_type import NormalizeType -from madanalysis.enumeration.report_format_type import ReportFormatType -from madanalysis.enumeration.color_type import ColorType -from madanalysis.enumeration.linestyle_type import LineStyleType -from madanalysis.enumeration.backstyle_type import BackStyleType -from madanalysis.enumeration.stacking_method_type import StackingMethodType -from madanalysis.layout.plotflow_for_dataset import PlotFlowForDataset -import madanalysis.enumeration.color_hex + import logging + import six from six.moves import range +import madanalysis.enumeration.color_hex +from madanalysis.enumeration.backstyle_type import BackStyleType +from madanalysis.enumeration.color_type import ColorType +from madanalysis.enumeration.linestyle_type import LineStyleType +from madanalysis.enumeration.normalize_type import NormalizeType +from madanalysis.enumeration.report_format_type import ReportFormatType +from madanalysis.enumeration.stacking_method_type import StackingMethodType +from madanalysis.layout.plotflow_for_dataset import PlotFlowForDataset -class PlotFlow: +# pylint: disable=C0200,C0103 - diconicetitle = {' ^ {':'^{', ' _ {':'_{', '\\\\':'#'} - counter=0 +class PlotFlow: + + diconicetitle = {" ^ {": "^{", " _ {": "_{", "\\\\": "#"} - def __init__(self,main): - self.main = main - self.detail = [] - for i in range(0,len(main.datasets)): - self.detail.append(PlotFlowForDataset(main,main.datasets[i])) + counter = 0 + def __init__(self, main): + self.main = main + self.detail = [] + for i in range(0, len(main.datasets)): + self.detail.append(PlotFlowForDataset(main, main.datasets[i])) def Initialize(self): # Initializing NPID - if len(self.detail)>0: - for ihisto in range(0,len(self.detail[0])): - if self.detail[0].histos[ihisto].__class__.__name__ == "HistogramFrequency": + if len(self.detail) > 0: + for ihisto in range(0, len(self.detail[0])): + if ( + self.detail[0].histos[ihisto].__class__.__name__ + == "HistogramFrequency" + ): self.InitializeHistoFrequency(ihisto) # Creating plots for i in range(0, len(self.detail)): - self.detail[i].FinalizeReading() + self.detail[i].FinalizeReading() self.detail[i].ComputeScale() self.detail[i].CreateHistogram() - - def InitializeHistoFrequency(self,ihisto): + def InitializeHistoFrequency(self, ihisto): # New collection of labels - newlabels=[] + newlabels = [] # Loop over datasets for histo in self.detail: @@ -76,7 +81,7 @@ def InitializeHistoFrequency(self,ihisto): # Loop over the label for label in histo[ihisto].labels: - # Add in the collection + # Add in the collection if label not in newlabels: newlabels.append(label) @@ -87,9 +92,9 @@ def InitializeHistoFrequency(self,ihisto): for histo in self.detail: # New array for data - array_positive=[] - array_negative=[] - + array_positive = [] + array_negative = [] + # Loop over the new labels for newlabel in newlabels: @@ -99,7 +104,7 @@ def InitializeHistoFrequency(self,ihisto): value_negative = 0 for i in range(len(histo[ihisto].labels)): - if newlabel==histo[ihisto].labels[i]: + if newlabel == histo[ihisto].labels[i]: value_positive = histo[ihisto].positive.array[i] value_negative = histo[ihisto].negative.array[i] found = True @@ -110,728 +115,883 @@ def InitializeHistoFrequency(self,ihisto): array_positive.append(value_positive) array_negative.append(value_negative) else: - array_positive.append(0.) - array_negative.append(0.) + array_positive.append(0.0) + array_negative.append(0.0) # save result # PS: [:] -> clone the arrays histo[ihisto].positive.array = array_positive[:] histo[ihisto].negative.array = array_negative[:] - histo[ihisto].labels = newlabels[:] - + histo[ihisto].labels = newlabels[:] @staticmethod def NiceTitle(text): - newtext=text - for i,j in six.iteritems(PlotFlow.diconicetitle): - newtext = newtext.replace(i,j) + newtext = text + for i, j in six.iteritems(PlotFlow.diconicetitle): + newtext = newtext.replace(i, j) return newtext @staticmethod def NiceTitleMatplotlib(text): - text=PlotFlow.NiceTitle(text) - text=text.replace('#DeltaR','#Delta R') - text='$'+text.replace('#','\\\\')+'$' + text = PlotFlow.NiceTitle(text) + text = text.replace("#DeltaR", "#Delta R") + text = "$" + text.replace("#", "\\\\") + "$" return text - - def DrawAll(self,histo_path,modes,output_paths,ListROOTplots): + def DrawAll(self, histo_path, modes, output_paths, ListROOTplots): # Loop on each histo type - irelhisto=0 - for iabshisto in range(0,len(self.main.selection)): - if self.main.selection[iabshisto].__class__.__name__!="Histogram": + irelhisto = 0 + for iabshisto in range(0, len(self.main.selection)): + if self.main.selection[iabshisto].__class__.__name__ != "Histogram": continue - self.color=1 - histos=[] - scales=[] + self.color = 1 + histos = [] + scales = [] + multiweight_histos = [] # Name of output files - filenameC = histo_path+"/selection_"+str(irelhisto)+".C" - filenamePy = histo_path+"/selection_"+str(irelhisto)+".py" - - output_files=[] - for iout in range(0,len(output_paths)): - output_files.append('../../'+output_paths[iout].split('/')[-2]+'/'+\ - output_paths[iout].split('/')[-1]+"/selection_"+str(irelhisto)+"."+\ - ReportFormatType.convert2filetype(modes[iout])) - - for iset in range(0,len(self.detail)): - # Appending histo + filenameC = histo_path + "/selection_" + str(irelhisto) + ".C" + filenamePy = histo_path + "/selection_" + str(irelhisto) + ".py" + + output_files = [] + for iout in range(0, len(output_paths)): + output_files.append( + "../../" + + output_paths[iout].split("/")[-2] + + "/" + + output_paths[iout].split("/")[-1] + + "/selection_" + + str(irelhisto) + + "." + + ReportFormatType.convert2filetype(modes[iout]) + ) + + for iset in range(0, len(self.detail)): + # Appending histo histos.append(self.detail[iset][irelhisto]) -# if mode==2: + # if mode==2: scales.append(self.detail[iset][irelhisto].scale) -# else: -# scales.append(1) - - logging.getLogger('MA5').debug('Producing file '+filenameC+' ...') - self.DrawROOT(histos,scales,self.main.selection[iabshisto],\ - irelhisto,filenameC,output_files) - - logging.getLogger('MA5').debug('Producing file '+filenamePy+' ...') - self.DrawMATPLOTLIB\ - (histos,scales,self.main.selection[iabshisto],\ - irelhisto,filenamePy,output_files) - - irelhisto+=1 - + multiweight_histos.append(self.detail[iset].multiweight_histos[irelhisto]) + # else: + # scales.append(1) + + logging.getLogger("MA5").debug("Producing file " + filenameC + " ...") + self.DrawROOT( + histos, + scales, + self.main.selection[iabshisto], + irelhisto, + filenameC, + output_files, + ) + + logging.getLogger("MA5").debug("Producing file " + filenamePy + " ...") + self.DrawMATPLOTLIB( + histos, + scales, + self.main.selection[iabshisto], + irelhisto, + filenamePy, + output_files, + ) + + logging.getLogger("MA5").debug("Producing file " + filenamePy + " ...") + self.DrawMULTIWEIGHT( + multiweight_histos, + self.main.selection[iabshisto], + filenamePy, + output_files, + ) + + irelhisto += 1 # Save ROOT files - for ind in range(0,irelhisto): - ListROOTplots.append(histo_path+'/selection_'+str(ind)) - - return True + for ind in range(0, irelhisto): + ListROOTplots.append(histo_path + "/selection_" + str(ind)) + return True - def DrawROOT(self,histos,scales,ref,irelhisto,filenameC,outputnames): + def DrawROOT(self, histos, scales, ref, irelhisto, filenameC, outputnames): # Is there any legend? legendmode = False - if len(self.main.datasets)>1: + if len(self.main.datasets) > 1: legendmode = True # Type of histogram frequencyhisto = True for histo in histos: - if histo.__class__.__name__!='HistogramFrequency': + if histo.__class__.__name__ != "HistogramFrequency": frequencyhisto = False break logxhisto = True for histo in histos: - if histo.__class__.__name__!='HistogramLogX': + if histo.__class__.__name__ != "HistogramLogX": logxhisto = False break # Stacking or superimposing histos ? stackmode = False - if ref.stack==StackingMethodType.STACK or \ - ( ref.stack==StackingMethodType.AUTO and \ - self.main.stack==StackingMethodType.STACK ): - stackmode=True + if ref.stack == StackingMethodType.STACK or ( + ref.stack == StackingMethodType.AUTO + and self.main.stack == StackingMethodType.STACK + ): + stackmode = True # Open the file in write-mode try: - outputC = open(filenameC,'w') + outputC = open(filenameC, "w") except: - logging.getLogger('MA5').error('Impossible to write the file: '+filenameC) + logging.getLogger("MA5").error("Impossible to write the file: " + filenameC) return False # File header function_name = filenameC[:-2] - function_name = function_name.split('/')[-1] - outputC.write('void '+function_name+'()\n') - outputC.write('{\n\n') + function_name = function_name.split("/")[-1] + outputC.write("void " + function_name + "()\n") + outputC.write("{\n\n") # ROOT version - outputC.write(' // ROOT version\n') - outputC.write(' Int_t root_version = gROOT->GetVersionInt();\n') - outputC.write('\n') + outputC.write(" // ROOT version\n") + outputC.write(" Int_t root_version = gROOT->GetVersionInt();\n") + outputC.write("\n") # Creating the TCanvas - PlotFlow.counter=PlotFlow.counter+1 - canvas_name='canvas_plotflow_tempo'+str(PlotFlow.counter) - outputC.write(' // Creating a new TCanvas\n') - widthx=700 + PlotFlow.counter = PlotFlow.counter + 1 + canvas_name = "canvas_plotflow_tempo" + str(PlotFlow.counter) + outputC.write(" // Creating a new TCanvas\n") + widthx = 700 if legendmode: - widthx=1000 - outputC.write(' TCanvas* canvas = new TCanvas("'+canvas_name+'","'+canvas_name+'",0,0,'+str(widthx)+',500);\n') - outputC.write(' gStyle->SetOptStat(0);\n') - outputC.write(' gStyle->SetOptTitle(0);\n') - outputC.write(' canvas->SetHighLightColor(2);\n') -# outputC.write(' canvas->Range(-2.419355,-0.005372711,16.93548,0.03939988);\n') - outputC.write(' canvas->SetFillColor(0);\n') - outputC.write(' canvas->SetBorderMode(0);\n') - outputC.write(' canvas->SetBorderSize(3);\n') - outputC.write(' canvas->SetFrameBorderMode(0);\n') - outputC.write(' canvas->SetFrameBorderSize(0);\n') - outputC.write(' canvas->SetTickx(1);\n') - outputC.write(' canvas->SetTicky(1);\n') - outputC.write(' canvas->SetLeftMargin(0.14);\n') - margin=0.05 + widthx = 1000 + outputC.write( + ' TCanvas* canvas = new TCanvas("' + + canvas_name + + '","' + + canvas_name + + '",0,0,' + + str(widthx) + + ",500);\n" + ) + outputC.write(" gStyle->SetOptStat(0);\n") + outputC.write(" gStyle->SetOptTitle(0);\n") + outputC.write(" canvas->SetHighLightColor(2);\n") + # outputC.write(' canvas->Range(-2.419355,-0.005372711,16.93548,0.03939988);\n') + outputC.write(" canvas->SetFillColor(0);\n") + outputC.write(" canvas->SetBorderMode(0);\n") + outputC.write(" canvas->SetBorderSize(3);\n") + outputC.write(" canvas->SetFrameBorderMode(0);\n") + outputC.write(" canvas->SetFrameBorderSize(0);\n") + outputC.write(" canvas->SetTickx(1);\n") + outputC.write(" canvas->SetTicky(1);\n") + outputC.write(" canvas->SetLeftMargin(0.14);\n") + margin = 0.05 if legendmode: - margin=0.3 - outputC.write(' canvas->SetRightMargin('+str(margin)+');\n') - outputC.write(' canvas->SetBottomMargin(0.15);\n') - outputC.write(' canvas->SetTopMargin(0.05);\n') - outputC.write('\n') + margin = 0.3 + outputC.write(" canvas->SetRightMargin(" + str(margin) + ");\n") + outputC.write(" canvas->SetBottomMargin(0.15);\n") + outputC.write(" canvas->SetTopMargin(0.05);\n") + outputC.write("\n") # Binning - xnbin=histos[0].nbins + xnbin = histos[0].nbins if logxhisto: - outputC.write(' // Histo binning\n') - outputC.write(' Double_t xBinning['+str(xnbin+1)+'] = {') - for bin in range(1,xnbin+2): - if bin!=1: - outputC.write(',') + outputC.write(" // Histo binning\n") + outputC.write(" Double_t xBinning[" + str(xnbin + 1) + "] = {") + for bin in range(1, xnbin + 2): + if bin != 1: + outputC.write(",") outputC.write(str(histos[0].GetBinLowEdge(bin))) - outputC.write('};\n') - outputC.write('\n') + outputC.write("};\n") + outputC.write("\n") # Loop over datasets and histos ntot = 0 - for ind in range(0,len(histos)): + for ind in range(0, len(histos)): # Creating TH1F - outputC.write(' // Creating a new TH1F\n') - histoname="S"+histos[ind].name+'_'+str(ind) - xmin=histos[ind].xmin - xmax=histos[ind].xmax + outputC.write(" // Creating a new TH1F\n") + histoname = "S" + histos[ind].name + "_" + str(ind) + xmin = histos[ind].xmin + xmax = histos[ind].xmax if logxhisto: - outputC.write(' TH1F* '+histoname+' = new TH1F("'+histoname+'","'+\ - histoname+'",'+str(xnbin)+',xBinning);\n') + outputC.write( + " TH1F* " + + histoname + + ' = new TH1F("' + + histoname + + '","' + + histoname + + '",' + + str(xnbin) + + ",xBinning);\n" + ) else: - outputC.write(' TH1F* '+histoname+' = new TH1F("'+histoname+'","'+\ - histoname+'",'+str(xnbin)+','+\ - str(xmin)+','+str(xmax)+');\n') + outputC.write( + " TH1F* " + + histoname + + ' = new TH1F("' + + histoname + + '","' + + histoname + + '",' + + str(xnbin) + + "," + + str(xmin) + + "," + + str(xmax) + + ");\n" + ) # TH1F content - outputC.write(' // Content\n') - outputC.write(' '+histoname+'->SetBinContent(0'+\ - ','+str(histos[ind].summary.underflow*scales[ind])+'); // underflow\n') - for bin in range(1,xnbin+1): - ntot+= histos[ind].summary.array[bin-1]*scales[ind] - outputC.write(' '+histoname+'->SetBinContent('+str(bin)+\ - ','+str(histos[ind].summary.array[bin-1]*scales[ind])+');\n') - nentries=histos[ind].summary.nentries - outputC.write(' '+histoname+'->SetBinContent('+str(xnbin+1)+\ - ','+str(histos[ind].summary.overflow*scales[ind])+'); // overflow\n') - outputC.write(' '+histoname+'->SetEntries('+str(nentries)+');\n') + outputC.write(" // Content\n") + outputC.write( + " " + + histoname + + "->SetBinContent(0" + + "," + + str(histos[ind].summary.underflow * scales[ind]) + + "); // underflow\n" + ) + for bin in range(1, xnbin + 1): + ntot += histos[ind].summary.array[bin - 1] * scales[ind] + outputC.write( + " " + + histoname + + "->SetBinContent(" + + str(bin) + + "," + + str(histos[ind].summary.array[bin - 1] * scales[ind]) + + ");\n" + ) + nentries = histos[ind].summary.nentries + outputC.write( + " " + + histoname + + "->SetBinContent(" + + str(xnbin + 1) + + "," + + str(histos[ind].summary.overflow * scales[ind]) + + "); // overflow\n" + ) + outputC.write(" " + histoname + "->SetEntries(" + str(nentries) + ");\n") # reset - linecolor=0 - linestyle=0 - backcolor=0 - backstyle=0 - linewidth=1 + linecolor = 0 + linestyle = 0 + backcolor = 0 + backstyle = 0 + linewidth = 1 # Setting AUTO settings - if len(histos)==1: + if len(histos) == 1: linecolor1 = [9] - linecolor = linecolor1[ind] + linecolor = linecolor1[ind] if stackmode: backstyle1 = [3004] - backstyle = backstyle1[ind] - backcolor = linecolor1[ind] - elif len(histos)==2: - linecolor2 = [9,46] - linecolor = linecolor2[ind] + backstyle = backstyle1[ind] + backcolor = linecolor1[ind] + elif len(histos) == 2: + linecolor2 = [9, 46] + linecolor = linecolor2[ind] if stackmode: - backstyle2 = [3004,3005] - backstyle = backstyle2[ind] - backcolor = linecolor2[ind] - elif len(histos)==3: - linecolor3 = [9,46,8] - linecolor = linecolor3[ind] + backstyle2 = [3004, 3005] + backstyle = backstyle2[ind] + backcolor = linecolor2[ind] + elif len(histos) == 3: + linecolor3 = [9, 46, 8] + linecolor = linecolor3[ind] if stackmode: - backstyle3 = [3004,3005,3006] - backstyle = backstyle3[ind] - backcolor = linecolor3[ind] - elif len(histos)==4: - linecolor4 = [9,46,8,4] - linecolor = linecolor4[ind] + backstyle3 = [3004, 3005, 3006] + backstyle = backstyle3[ind] + backcolor = linecolor3[ind] + elif len(histos) == 4: + linecolor4 = [9, 46, 8, 4] + linecolor = linecolor4[ind] if stackmode: - backstyle4 = [3004,3005,3006,3007] - backstyle = backstyle4[ind] - backcolor = linecolor4[ind] - elif len(histos)==5: - linecolor5 = [9,46,8,4,6] - linecolor = linecolor5[ind] + backstyle4 = [3004, 3005, 3006, 3007] + backstyle = backstyle4[ind] + backcolor = linecolor4[ind] + elif len(histos) == 5: + linecolor5 = [9, 46, 8, 4, 6] + linecolor = linecolor5[ind] if stackmode: - backstyle5 = [3004,3005,3006,3007,3013] - backstyle = backstyle5[ind] - backcolor = linecolor5[ind] - elif len(histos)==6: - linecolor6 = [9,46,8,4,6,2] - linecolor = linecolor6[ind] + backstyle5 = [3004, 3005, 3006, 3007, 3013] + backstyle = backstyle5[ind] + backcolor = linecolor5[ind] + elif len(histos) == 6: + linecolor6 = [9, 46, 8, 4, 6, 2] + linecolor = linecolor6[ind] if stackmode: - backstyle6 = [3004,3005,3006,3007,3013,3017] - backstyle = backstyle6[ind] - backcolor = linecolor6[ind] - elif len(histos)==7: - linecolor7 = [9,46,8,4,6,2,7] - linecolor = linecolor7[ind] + backstyle6 = [3004, 3005, 3006, 3007, 3013, 3017] + backstyle = backstyle6[ind] + backcolor = linecolor6[ind] + elif len(histos) == 7: + linecolor7 = [9, 46, 8, 4, 6, 2, 7] + linecolor = linecolor7[ind] if stackmode: - backstyle7 = [3004,3005,3006,3007,3013,3017,3022] - backstyle = backstyle7[ind] - backcolor = linecolor7[ind] - elif len(histos)==8: - linecolor8 = [9,46,8,4,6,2,7,3] - linecolor = linecolor8[ind] + backstyle7 = [3004, 3005, 3006, 3007, 3013, 3017, 3022] + backstyle = backstyle7[ind] + backcolor = linecolor7[ind] + elif len(histos) == 8: + linecolor8 = [9, 46, 8, 4, 6, 2, 7, 3] + linecolor = linecolor8[ind] if stackmode: - backstyle8 = [3004,3005,3006,3007,3013,3017,3022,3315] - backstyle = backstyle8[ind] - backcolor = linecolor8[ind] - elif len(histos)==9: - linecolor9 = [9,46,8,4,6,2,7,3,42] - linecolor = linecolor9[ind] + backstyle8 = [3004, 3005, 3006, 3007, 3013, 3017, 3022, 3315] + backstyle = backstyle8[ind] + backcolor = linecolor8[ind] + elif len(histos) == 9: + linecolor9 = [9, 46, 8, 4, 6, 2, 7, 3, 42] + linecolor = linecolor9[ind] if stackmode: - backstyle9 = [3004,3005,3006,3007,3013,3017,3022,3315,3351] - backstyle = backstyle9[ind] - backcolor = linecolor9[ind] - elif len(histos)==10: - linecolor10 = [9,46,8,4,6,2,7,3,42,48] - linecolor = linecolor10[ind] + backstyle9 = [3004, 3005, 3006, 3007, 3013, 3017, 3022, 3315, 3351] + backstyle = backstyle9[ind] + backcolor = linecolor9[ind] + elif len(histos) == 10: + linecolor10 = [9, 46, 8, 4, 6, 2, 7, 3, 42, 48] + linecolor = linecolor10[ind] if stackmode: - backstyle10 = [3004,3005,3006,3007,3013,3017,3022,3315,3351,3481] - backstyle = backstyle10[ind] - backcolor = linecolor10[ind] + backstyle10 = [ + 3004, + 3005, + 3006, + 3007, + 3013, + 3017, + 3022, + 3315, + 3351, + 3481, + ] + backstyle = backstyle10[ind] + backcolor = linecolor10[ind] else: - linecolor=self.color + linecolor = self.color self.color += 1 # linecolor - if self.main.datasets[ind].linecolor!=ColorType.AUTO: - linecolor=ColorType.convert2root( \ - self.main.datasets[ind].linecolor,\ - self.main.datasets[ind].lineshade) + if self.main.datasets[ind].linecolor != ColorType.AUTO: + linecolor = ColorType.convert2root( + self.main.datasets[ind].linecolor, self.main.datasets[ind].lineshade + ) # lineStyle - linestyle=LineStyleType.convert2code(self.main.datasets[ind].linestyle) + linestyle = LineStyleType.convert2code(self.main.datasets[ind].linestyle) # linewidth - linewidth=self.main.datasets[ind].linewidth + linewidth = self.main.datasets[ind].linewidth # background color - if self.main.datasets[ind].backcolor!=ColorType.AUTO: - backcolor=ColorType.convert2root( \ - self.main.datasets[ind].backcolor,\ - self.main.datasets[ind].backshade) + if self.main.datasets[ind].backcolor != ColorType.AUTO: + backcolor = ColorType.convert2root( + self.main.datasets[ind].backcolor, self.main.datasets[ind].backshade + ) - # background color - if self.main.datasets[ind].backstyle!=BackStyleType.AUTO: - backstyle=BackStyleType.convert2code( \ - self.main.datasets[ind].backstyle) + # background color + if self.main.datasets[ind].backstyle != BackStyleType.AUTO: + backstyle = BackStyleType.convert2code(self.main.datasets[ind].backstyle) # style - outputC.write(' // Style\n') - outputC.write(' '+histoname+'->SetLineColor('+str(linecolor)+');\n') - outputC.write(' '+histoname+'->SetLineStyle('+str(linestyle)+');\n') - outputC.write(' '+histoname+'->SetLineWidth('+str(linewidth)+');\n') - outputC.write(' '+histoname+'->SetFillColor('+str(backcolor)+');\n') - outputC.write(' '+histoname+'->SetFillStyle('+str(backstyle)+');\n') + outputC.write(" // Style\n") + outputC.write(" " + histoname + "->SetLineColor(" + str(linecolor) + ");\n") + outputC.write(" " + histoname + "->SetLineStyle(" + str(linestyle) + ");\n") + outputC.write(" " + histoname + "->SetLineWidth(" + str(linewidth) + ");\n") + outputC.write(" " + histoname + "->SetFillColor(" + str(backcolor) + ");\n") + outputC.write(" " + histoname + "->SetFillStyle(" + str(backstyle) + ");\n") if frequencyhisto: - outputC.write(' '+histoname+'->SetBarWidth(0.8);\n') - outputC.write(' '+histoname+'->SetBarOffset(0.1);\n') - outputC.write('\n') + outputC.write(" " + histoname + "->SetBarWidth(0.8);\n") + outputC.write(" " + histoname + "->SetBarOffset(0.1);\n") + outputC.write("\n") # Creating the THStack - outputC.write(' // Creating a new THStack\n') - PlotFlow.counter+=1 - outputC.write(' THStack* stack = new THStack("mystack_'+str(PlotFlow.counter)+'","mystack");\n') + outputC.write(" // Creating a new THStack\n") + PlotFlow.counter += 1 + outputC.write( + ' THStack* stack = new THStack("mystack_' + + str(PlotFlow.counter) + + '","mystack");\n' + ) # Loop over datasets and histos - for ind in range(0,len(histos)): - histoname='S'+histos[ind].name+'_'+str(ind) - outputC.write(' stack->Add('+histoname+');\n') + for ind in range(0, len(histos)): + histoname = "S" + histos[ind].name + "_" + str(ind) + outputC.write(" stack->Add(" + histoname + ");\n") - drawoptions=[] + drawoptions = [] if not stackmode: - drawoptions.append('nostack') + drawoptions.append("nostack") if frequencyhisto: - drawoptions.append('bar1') - outputC.write(' stack->Draw("'+''.join(drawoptions)+'");\n') - outputC.write('\n') + drawoptions.append("bar1") + outputC.write(' stack->Draw("' + "".join(drawoptions) + '");\n') + outputC.write("\n") # Setting Y axis label - outputC.write(' // Y axis\n') + outputC.write(" // Y axis\n") axis_titleY = ref.GetYaxis() # Scale to one ? scale2one = False - if ref.stack==StackingMethodType.NORMALIZE2ONE or \ - (self.main.stack==StackingMethodType.NORMALIZE2ONE and \ - ref.stack==StackingMethodType.AUTO): + if ref.stack == StackingMethodType.NORMALIZE2ONE or ( + self.main.stack == StackingMethodType.NORMALIZE2ONE + and ref.stack == StackingMethodType.AUTO + ): scale2one = True if scale2one: axis_titleY += " ( scaled to one )" - elif self.main.normalize == NormalizeType.LUMI or \ - self.main.normalize == NormalizeType.LUMI_WEIGHT: - axis_titleY += " ( L_{int} = " + str(self.main.lumi)+ " fb^{-1} )" + elif ( + self.main.normalize == NormalizeType.LUMI + or self.main.normalize == NormalizeType.LUMI_WEIGHT + ): + axis_titleY += " ( L_{int} = " + str(self.main.lumi) + " fb^{-1} )" elif self.main.normalize == NormalizeType.NONE: axis_titleY += " (not normalized)" - if ref.titleY!="": + if ref.titleY != "": axis_titleY = PlotFlow.NiceTitle(ref.titleY) - if(len(axis_titleY) > 35): - titlesize=0.04 + if len(axis_titleY) > 35: + titlesize = 0.04 else: - titlesize=0.06 - outputC.write(' stack->GetYaxis()->SetLabelSize(0.04);\n') - outputC.write(' stack->GetYaxis()->SetLabelOffset(0.005);\n') - outputC.write(' stack->GetYaxis()->SetTitleSize('+str(titlesize)+');\n') - outputC.write(' stack->GetYaxis()->SetTitleFont(22);\n') - outputC.write(' stack->GetYaxis()->SetTitleOffset(1);\n') - outputC.write(' stack->GetYaxis()->SetTitle("'+axis_titleY+'");\n') - if ref.ymin!=[]: - outputC.write(' stack->SetMinimum('+str(ref.ymin)+');\n') - if ref.ymax!=[]: - outputC.write(' stack->SetMaximum('+str(ref.ymax)+');\n') - - outputC.write('\n') - outputC.write(' // X axis\n') + titlesize = 0.06 + outputC.write(" stack->GetYaxis()->SetLabelSize(0.04);\n") + outputC.write(" stack->GetYaxis()->SetLabelOffset(0.005);\n") + outputC.write(" stack->GetYaxis()->SetTitleSize(" + str(titlesize) + ");\n") + outputC.write(" stack->GetYaxis()->SetTitleFont(22);\n") + outputC.write(" stack->GetYaxis()->SetTitleOffset(1);\n") + outputC.write(' stack->GetYaxis()->SetTitle("' + axis_titleY + '");\n') + if ref.ymin != []: + outputC.write(" stack->SetMinimum(" + str(ref.ymin) + ");\n") + if ref.ymax != []: + outputC.write(" stack->SetMaximum(" + str(ref.ymax) + ");\n") + + outputC.write("\n") + outputC.write(" // X axis\n") # Setting X axis label - if ref.titleX=="": + if ref.titleX == "": axis_titleX = ref.GetXaxis_Root() else: axis_titleX = PlotFlow.NiceTitle(ref.titleX) # Setting X axis label - outputC.write(' stack->GetXaxis()->SetLabelSize(0.04);\n') - outputC.write(' stack->GetXaxis()->SetLabelOffset(0.005);\n') - outputC.write(' stack->GetXaxis()->SetTitleSize(0.06);\n') - outputC.write(' stack->GetXaxis()->SetTitleFont(22);\n') - outputC.write(' stack->GetXaxis()->SetTitleOffset(1);\n') - outputC.write(' stack->GetXaxis()->SetTitle("'+axis_titleX+'");\n') + outputC.write(" stack->GetXaxis()->SetLabelSize(0.04);\n") + outputC.write(" stack->GetXaxis()->SetLabelOffset(0.005);\n") + outputC.write(" stack->GetXaxis()->SetTitleSize(0.06);\n") + outputC.write(" stack->GetXaxis()->SetTitleFont(22);\n") + outputC.write(" stack->GetXaxis()->SetTitleOffset(1);\n") + outputC.write(' stack->GetXaxis()->SetTitle("' + axis_titleX + '");\n') if frequencyhisto: - for bin in range(1,xnbin+1): - outputC.write(' stack->GetXaxis()->SetBinLabel('+str(bin)+','\ - '"'+str(histos[ind].stringlabels[bin-1])+'");\n') - outputC.write('\n') + for bin in range(1, xnbin + 1): + outputC.write( + " stack->GetXaxis()->SetBinLabel(" + str(bin) + "," + '"' + str(histos[ind].stringlabels[bin - 1]) + '");\n' + ) + outputC.write("\n") # Setting Log scale - outputC.write(' // Finalizing the TCanvas\n') - logx=0 + outputC.write(" // Finalizing the TCanvas\n") + logx = 0 if ref.logX and ntot != 0: - logx=1 - logy=0 + logx = 1 + logy = 0 if ref.logY and ntot != 0: - logy=1 - outputC.write(' canvas->SetLogx('+str(logx)+');\n') - outputC.write(' canvas->SetLogy('+str(logy)+');\n') - outputC.write('\n') + logy = 1 + outputC.write(" canvas->SetLogx(" + str(logx) + ");\n") + outputC.write(" canvas->SetLogy(" + str(logy) + ");\n") + outputC.write("\n") # Displaying a legend if legendmode: - outputC.write(' // Creating a TLegend\n') - outputC.write(' TLegend* legend = new TLegend(.73,.5,.97,.95);\n') - for ind in range(0,len(histos)): - histoname='S'+histos[ind].name+'_'+str(ind) - nicetitle=PlotFlow.NiceTitle(self.main.datasets[ind].title) - outputC.write(' legend->AddEntry('+histoname+',"'+nicetitle+'");\n') - outputC.write(' legend->SetFillColor(0);\n') - outputC.write(' legend->SetTextSize(0.05);\n') - outputC.write(' legend->SetTextFont(22);\n') - outputC.write(' legend->SetY1(TMath::Max(0.15,0.97-0.10*legend->GetListOfPrimitives()->GetSize()));\n') - outputC.write(' legend->Draw();\n') - outputC.write('\n') + outputC.write(" // Creating a TLegend\n") + outputC.write(" TLegend* legend = new TLegend(.73,.5,.97,.95);\n") + for ind in range(0, len(histos)): + histoname = "S" + histos[ind].name + "_" + str(ind) + nicetitle = PlotFlow.NiceTitle(self.main.datasets[ind].title) + outputC.write( + " legend->AddEntry(" + histoname + ',"' + nicetitle + '");\n' + ) + outputC.write(" legend->SetFillColor(0);\n") + outputC.write(" legend->SetTextSize(0.05);\n") + outputC.write(" legend->SetTextFont(22);\n") + outputC.write( + " legend->SetY1(TMath::Max(0.15,0.97-0.10*legend->GetListOfPrimitives()->GetSize()));\n" + ) + outputC.write(" legend->Draw();\n") + outputC.write("\n") # Producing the image - outputC.write(' // Saving the image\n') + outputC.write(" // Saving the image\n") for outputname in outputnames: - outputC.write(' canvas->SaveAs("'+outputname+'");\n') - outputC.write('\n') + outputC.write(' canvas->SaveAs("' + outputname + '");\n') + outputC.write("\n") # File foot - outputC.write('}\n') + outputC.write("}\n") # Close the file try: outputC.close() except: - logging.getLogger('MA5').error('Impossible to close the file: '+outputC) + logging.getLogger("MA5").error("Impossible to close the file: " + outputC) return False # Ok return True - - - def DrawMATPLOTLIB(self,histos,scales,ref,irelhisto,filenamePy,outputnames): + def DrawMATPLOTLIB(self, histos, scales, ref, irelhisto, filenamePy, outputnames): # Is there any legend? legendmode = False - if len(self.main.datasets)>1: + if len(self.main.datasets) > 1: legendmode = True # Type of histogram frequencyhisto = True for histo in histos: - if histo.__class__.__name__!='HistogramFrequency': + if histo.__class__.__name__ != "HistogramFrequency": frequencyhisto = False break logxhisto = True for histo in histos: - if histo.__class__.__name__!='HistogramLogX': + if histo.__class__.__name__ != "HistogramLogX": logxhisto = False break # Stacking or superimposing histos ? stackmode = False - if ref.stack==StackingMethodType.STACK or \ - ( ref.stack==StackingMethodType.AUTO and \ - self.main.stack==StackingMethodType.STACK ): - stackmode=True - + if ref.stack == StackingMethodType.STACK or ( + ref.stack == StackingMethodType.AUTO + and self.main.stack == StackingMethodType.STACK + ): + stackmode = True # Open the file in write-mode try: - outputPy = open(filenamePy,'w') + outputPy = open(filenamePy, "w") except: - logging.getLogger('MA5').error('Impossible to write the file: '+filenamePy) + logging.getLogger("MA5").error("Impossible to write the file: " + filenamePy) return False # File header function_name = filenamePy[:-3] - function_name = function_name.split('/')[-1] - outputPy.write('def '+function_name+'():\n') - outputPy.write('\n') + function_name = function_name.split("/")[-1] + outputPy.write("def " + function_name + "():\n") + outputPy.write("\n") # Import Libraries - outputPy.write(' # Library import\n') - outputPy.write(' import numpy\n') - outputPy.write(' import matplotlib\n') -# outputPy.write(" matplotlib.use('Agg')\n") - outputPy.write(' import matplotlib.pyplot as plt\n') - outputPy.write(' import matplotlib.gridspec as gridspec\n') - outputPy.write('\n') + outputPy.write(" # Library import\n") + outputPy.write(" import numpy\n") + outputPy.write(" import matplotlib\n") + # outputPy.write(" matplotlib.use('Agg')\n") + outputPy.write(" import matplotlib.pyplot as plt\n") + outputPy.write(" import matplotlib.gridspec as gridspec\n") + outputPy.write("\n") # Matplotlib & numpy version - outputPy.write(' # Library version\n') - outputPy.write(' matplotlib_version = matplotlib.__version__\n') - outputPy.write(' numpy_version = numpy.__version__\n') - outputPy.write('\n') + outputPy.write(" # Library version\n") + outputPy.write(" matplotlib_version = matplotlib.__version__\n") + outputPy.write(" numpy_version = numpy.__version__\n") + outputPy.write("\n") # Binning # Loop over datasets and histos - xnbin=histos[0].nbins - xmin =histos[0].xmin - xmax =histos[0].xmax - outputPy.write(' # Histo binning\n') + xnbin = histos[0].nbins + xmin = histos[0].xmin + xmax = histos[0].xmax + outputPy.write(" # Histo binning\n") if logxhisto: - outputPy.write(' xBinning = [') - for bin in range(1,xnbin+2): - if bin!=1: - outputPy.write(',') + outputPy.write(" xBinning = [") + for bin in range(1, xnbin + 2): + if bin != 1: + outputPy.write(",") outputPy.write(str(histos[0].GetBinLowEdge(bin))) - outputPy.write(']\n') - outputPy.write('\n') + outputPy.write("]\n") + outputPy.write("\n") else: - outputPy.write(' xBinning = numpy.linspace('+\ - str(xmin)+','+str(xmax)+','+str(xnbin+1)+\ - ',endpoint=True)\n') - outputPy.write('\n') - + outputPy.write( + " xBinning = numpy.linspace(" + + str(xmin) + + "," + + str(xmax) + + "," + + str(xnbin + 1) + + ",endpoint=True)\n" + ) + outputPy.write("\n") # Data - outputPy.write(' # Creating data sequence: middle of each bin\n') - outputPy.write(' xData = numpy.array([') - for bin in range(0,xnbin): - if bin!=0: - outputPy.write(',') + outputPy.write(" # Creating data sequence: middle of each bin\n") + outputPy.write(" xData = numpy.array([") + for bin in range(0, xnbin): + if bin != 0: + outputPy.write(",") outputPy.write(str(histos[0].GetBinMean(bin))) - outputPy.write('])\n\n') + outputPy.write("])\n\n") # Loop over datasets and histos ntot = 0 - for ind in range(0,len(histos)): + for ind in range(0, len(histos)): # Creating a new histo - histoname='y'+histos[ind].name+'_'+str(ind) - outputPy.write(' # Creating weights for histo: '+histoname+'\n') - outputPy.write(' '+histoname+'_weights = numpy.array([') - for bin in range(1,xnbin+1): - ntot+=histos[ind].summary.array[bin-1]*scales[ind] - if bin!=1: - outputPy.write(',') - outputPy.write(str(histos[ind].summary.array[bin-1]*scales[ind])) - outputPy.write('])\n\n') - - + histoname = "y" + histos[ind].name + "_" + str(ind) + outputPy.write(" # Creating weights for histo: " + histoname + "\n") + outputPy.write(" " + histoname + "_weights = numpy.array([") + for bin in range(1, xnbin + 1): + ntot += histos[ind].summary.array[bin - 1] * scales[ind] + if bin != 1: + outputPy.write(",") + outputPy.write(str(histos[ind].summary.array[bin - 1] * scales[ind])) + outputPy.write("])\n\n") # Canvas - outputPy.write(' # Creating a new Canvas\n') - dpi=80 - height=500 - widthx=700 + outputPy.write(" # Creating a new Canvas\n") + dpi = 80 + height = 500 + widthx = 700 if legendmode: - widthx=1000 - outputPy.write(' fig = plt.figure(figsize=('+\ - str(widthx/dpi)+','+str(height/dpi)+\ - '),dpi='+str(dpi)+')\n') + widthx = 1000 + outputPy.write( + " fig = plt.figure(figsize=(" + + str(widthx / dpi) + + "," + + str(height / dpi) + + "),dpi=" + + str(dpi) + + ")\n" + ) if not legendmode: - outputPy.write(' frame = gridspec.GridSpec(1,1)\n') + outputPy.write(" frame = gridspec.GridSpec(1,1)\n") else: - outputPy.write(' frame = gridspec.GridSpec(1,1,right=0.7)\n') + outputPy.write(" frame = gridspec.GridSpec(1,1,right=0.7)\n") # subplot argument: nrows, ncols, plot_number # outputPy.write(' pad = fig.add_subplot(111)\n') - outputPy.write(' pad = fig.add_subplot(frame[0])\n') - outputPy.write('\n') + outputPy.write(" pad = fig.add_subplot(frame[0])\n") + outputPy.write("\n") # Stack - outputPy.write(' # Creating a new Stack\n') - for ind in range(len(histos)-1,-1,-1): - myweight = 'y'+histos[ind].name+'_'+str(ind)+'_weights' - mytitle = '"'+PlotFlow.NiceTitleMatplotlib(self.main.datasets[ind].title)+'"' - mytitle = mytitle.replace('_','\_') + outputPy.write(" # Creating a new Stack\n") + for ind in range(len(histos) - 1, -1, -1): + myweight = "y" + histos[ind].name + "_" + str(ind) + "_weights" + mytitle = ( + '"' + PlotFlow.NiceTitleMatplotlib(self.main.datasets[ind].title) + '"' + ) + mytitle = mytitle.replace("_", "\_") if not stackmode: - myweights='y'+histos[ind].name+'_'+str(ind)+'_weights' + myweights = "y" + histos[ind].name + "_" + str(ind) + "_weights" else: - myweights='' - for ind2 in range(0,ind+1): - if ind2>=1: - myweights+='+' - myweights+='y'+histos[ind2].name+'_'+str(ind2)+'_weights' + myweights = "" + for ind2 in range(0, ind + 1): + if ind2 >= 1: + myweights += "+" + myweights += "y" + histos[ind2].name + "_" + str(ind2) + "_weights" # reset - linecolor=0 - linestyle=0 - backcolor=0 - backstyle=0 - linewidth=1 + linecolor = 0 + linestyle = 0 + backcolor = 0 + backstyle = 0 + linewidth = 1 # Setting AUTO settings - if len(histos)==1: + if len(histos) == 1: linecolor1 = [9] - linecolor = linecolor1[ind] + linecolor = linecolor1[ind] if stackmode: backstyle1 = [3004] - backstyle = backstyle1[ind] - backcolor = linecolor1[ind] - elif len(histos)==2: - linecolor2 = [9,46] - linecolor = linecolor2[ind] + backstyle = backstyle1[ind] + backcolor = linecolor1[ind] + elif len(histos) == 2: + linecolor2 = [9, 46] + linecolor = linecolor2[ind] if stackmode: - backstyle2 = [3004,3005] - backstyle = backstyle2[ind] - backcolor = linecolor2[ind] - elif len(histos)==3: - linecolor3 = [9,46,8] - linecolor = linecolor3[ind] + backstyle2 = [3004, 3005] + backstyle = backstyle2[ind] + backcolor = linecolor2[ind] + elif len(histos) == 3: + linecolor3 = [9, 46, 8] + linecolor = linecolor3[ind] if stackmode: - backstyle3 = [3004,3005,3006] - backstyle = backstyle3[ind] - backcolor = linecolor3[ind] - elif len(histos)==4: - linecolor4 = [9,46,8,4] - linecolor = linecolor4[ind] + backstyle3 = [3004, 3005, 3006] + backstyle = backstyle3[ind] + backcolor = linecolor3[ind] + elif len(histos) == 4: + linecolor4 = [9, 46, 8, 4] + linecolor = linecolor4[ind] if stackmode: - backstyle4 = [3004,3005,3006,3007] - backstyle = backstyle4[ind] - backcolor = linecolor4[ind] - elif len(histos)==5: - linecolor5 = [9,46,8,4,6] - linecolor = linecolor5[ind] + backstyle4 = [3004, 3005, 3006, 3007] + backstyle = backstyle4[ind] + backcolor = linecolor4[ind] + elif len(histos) == 5: + linecolor5 = [9, 46, 8, 4, 6] + linecolor = linecolor5[ind] if stackmode: - backstyle5 = [3004,3005,3006,3007,3013] - backstyle = backstyle5[ind] - backcolor = linecolor5[ind] - elif len(histos)==6: - linecolor6 = [9,46,8,4,6,2] - linecolor = linecolor6[ind] + backstyle5 = [3004, 3005, 3006, 3007, 3013] + backstyle = backstyle5[ind] + backcolor = linecolor5[ind] + elif len(histos) == 6: + linecolor6 = [9, 46, 8, 4, 6, 2] + linecolor = linecolor6[ind] if stackmode: - backstyle6 = [3004,3005,3006,3007,3013,3017] - backstyle = backstyle6[ind] - backcolor = linecolor6[ind] - elif len(histos)==7: - linecolor7 = [9,46,8,4,6,2,7] - linecolor = linecolor7[ind] + backstyle6 = [3004, 3005, 3006, 3007, 3013, 3017] + backstyle = backstyle6[ind] + backcolor = linecolor6[ind] + elif len(histos) == 7: + linecolor7 = [9, 46, 8, 4, 6, 2, 7] + linecolor = linecolor7[ind] if stackmode: - backstyle7 = [3004,3005,3006,3007,3013,3017,3022] - backstyle = backstyle7[ind] - backcolor = linecolor7[ind] - elif len(histos)==8: - linecolor8 = [9,46,8,4,6,2,7,3] - linecolor = linecolor8[ind] + backstyle7 = [3004, 3005, 3006, 3007, 3013, 3017, 3022] + backstyle = backstyle7[ind] + backcolor = linecolor7[ind] + elif len(histos) == 8: + linecolor8 = [9, 46, 8, 4, 6, 2, 7, 3] + linecolor = linecolor8[ind] if stackmode: - backstyle8 = [3004,3005,3006,3007,3013,3017,3022,3315] - backstyle = backstyle8[ind] - backcolor = linecolor8[ind] - elif len(histos)==9: - linecolor9 = [9,46,8,4,6,2,7,3,42] - linecolor = linecolor9[ind] + backstyle8 = [3004, 3005, 3006, 3007, 3013, 3017, 3022, 3315] + backstyle = backstyle8[ind] + backcolor = linecolor8[ind] + elif len(histos) == 9: + linecolor9 = [9, 46, 8, 4, 6, 2, 7, 3, 42] + linecolor = linecolor9[ind] if stackmode: - backstyle9 = [3004,3005,3006,3007,3013,3017,3022,3315,3351] - backstyle = backstyle9[ind] - backcolor = linecolor9[ind] - elif len(histos)==10: - linecolor10 = [9,46,8,4,6,2,7,3,42,48] - linecolor = linecolor10[ind] + backstyle9 = [3004, 3005, 3006, 3007, 3013, 3017, 3022, 3315, 3351] + backstyle = backstyle9[ind] + backcolor = linecolor9[ind] + elif len(histos) == 10: + linecolor10 = [9, 46, 8, 4, 6, 2, 7, 3, 42, 48] + linecolor = linecolor10[ind] if stackmode: - backstyle10 = [3004,3005,3006,3007,3013,3017,3022,3315,3351,3481] - backstyle = backstyle10[ind] - backcolor = linecolor10[ind] + backstyle10 = [ + 3004, + 3005, + 3006, + 3007, + 3013, + 3017, + 3022, + 3315, + 3351, + 3481, + ] + backstyle = backstyle10[ind] + backcolor = linecolor10[ind] else: - linecolor=self.color + linecolor = self.color self.color += 1 # linecolor - if self.main.datasets[ind].linecolor!=ColorType.AUTO: - linecolor=ColorType.convert2root( \ - self.main.datasets[ind].linecolor,\ - self.main.datasets[ind].lineshade) + if self.main.datasets[ind].linecolor != ColorType.AUTO: + linecolor = ColorType.convert2root( + self.main.datasets[ind].linecolor, self.main.datasets[ind].lineshade + ) # lineStyle - linestyle=LineStyleType.convert2code(self.main.datasets[ind].linestyle) + linestyle = LineStyleType.convert2code(self.main.datasets[ind].linestyle) # linewidth - linewidth=self.main.datasets[ind].linewidth + linewidth = self.main.datasets[ind].linewidth # background color - if self.main.datasets[ind].backcolor!=ColorType.AUTO: - backcolor=ColorType.convert2root( \ - self.main.datasets[ind].backcolor,\ - self.main.datasets[ind].backshade) + if self.main.datasets[ind].backcolor != ColorType.AUTO: + backcolor = ColorType.convert2root( + self.main.datasets[ind].backcolor, self.main.datasets[ind].backshade + ) # background style - if self.main.datasets[ind].backstyle!=BackStyleType.AUTO: - backstyle=BackStyleType.convert2matplotlib( \ - self.main.datasets[ind].backstyle) - - mylinecolor = '"'+madanalysis.enumeration.color_hex.color_hex[linecolor]+'"' - mybackcolor = '"'+madanalysis.enumeration.color_hex.color_hex[backcolor]+'"' - - filledmode='"stepfilled"' - rWidth=1. - if backcolor==0: #invisible - filledmode='"step"' - mybackcolor = 'None' -# if frequencyhisto: -# filledmode='"bar"' -# rWidth=0.8 - mylinewidth = self.main.datasets[ind].linewidth - mylinestyle = LineStyleType.convert2matplotlib(self.main.datasets[ind].linestyle) - - outputPy.write(' pad.hist('+\ - 'x=xData, '+\ - 'bins=xBinning, '+\ - 'weights='+myweights+',\\\n'+\ - ' label='+mytitle+', ') - if ntot!=0: - outputPy.write('histtype='+filledmode+', ') + if self.main.datasets[ind].backstyle != BackStyleType.AUTO: + backstyle = BackStyleType.convert2matplotlib( + self.main.datasets[ind].backstyle + ) + + mylinecolor = ( + '"' + madanalysis.enumeration.color_hex.color_hex[linecolor] + '"' + ) + mybackcolor = ( + '"' + madanalysis.enumeration.color_hex.color_hex[backcolor] + '"' + ) + + filledmode = '"stepfilled"' + rWidth = 1.0 + if backcolor == 0: # invisible + filledmode = '"step"' + mybackcolor = "None" + # if frequencyhisto: + # filledmode='"bar"' + # rWidth=0.8 + mylinewidth = self.main.datasets[ind].linewidth + mylinestyle = LineStyleType.convert2matplotlib( + self.main.datasets[ind].linestyle + ) + + outputPy.write( + " pad.hist(" + + "x=xData, " + + "bins=xBinning, " + + "weights=" + + myweights + + ",\\\n" + + " label=" + + mytitle + + ", " + ) + if ntot != 0: + outputPy.write("histtype=" + filledmode + ", ") try: import matplotlib.pyplot as plt - plt.hist([0],normed=True) - outputPy.write( 'rwidth='+str(rWidth)+',\\\n'+\ - ' color='+mybackcolor+', '+\ - 'edgecolor='+mylinecolor+', '+\ - 'linewidth='+str(mylinewidth)+', '+\ - 'linestyle='+mylinestyle+',\\\n'+\ - ' bottom=None, '+\ - 'cumulative=False, normed=False, align="mid", orientation="vertical")\n\n') + + plt.hist([0], normed=True) + outputPy.write( + "rwidth=" + + str(rWidth) + + ",\\\n" + + " color=" + + mybackcolor + + ", " + + "edgecolor=" + + mylinecolor + + ", " + + "linewidth=" + + str(mylinewidth) + + ", " + + "linestyle=" + + mylinestyle + + ",\\\n" + + " bottom=None, " + + 'cumulative=False, normed=False, align="mid", orientation="vertical")\n\n' + ) except: - outputPy.write( 'rwidth='+str(rWidth)+',\\\n'+\ - ' color='+mybackcolor+', '+\ - 'edgecolor='+mylinecolor+', '+\ - 'linewidth='+str(mylinewidth)+', '+\ - 'linestyle='+mylinestyle+',\\\n'+\ - ' bottom=None, '+\ - 'cumulative=False, density=False, align="mid",'+\ - ' orientation="vertical")\n\n') - outputPy.write('\n') + outputPy.write( + "rwidth=" + + str(rWidth) + + ",\\\n" + + " color=" + + mybackcolor + + ", " + + "edgecolor=" + + mylinecolor + + ", " + + "linewidth=" + + str(mylinewidth) + + ", " + + "linestyle=" + + mylinestyle + + ",\\\n" + + " bottom=None, " + + 'cumulative=False, density=False, align="mid",' + + ' orientation="vertical")\n\n' + ) + outputPy.write("\n") # Label - outputPy.write(' # Axis\n') + outputPy.write(" # Axis\n") outputPy.write(" plt.rc('text',usetex=False)\n") # X-axis - if ref.titleX=="": + if ref.titleX == "": axis_titleX = ref.GetXaxis_Matplotlib() else: axis_titleX = ref.titleX - axis_titleX = axis_titleX.replace('#DeltaR','#Delta R') - axis_titleX = axis_titleX.replace('#','\\') - outputPy.write(' plt.xlabel(r"'+axis_titleX+'",\\\n') + axis_titleX = axis_titleX.replace("#DeltaR", "#Delta R") + axis_titleX = axis_titleX.replace("#", "\\") + outputPy.write(' plt.xlabel(r"' + axis_titleX + '",\\\n') outputPy.write(' fontsize=16,color="black")\n') # Y-axis @@ -839,135 +999,144 @@ def DrawMATPLOTLIB(self,histos,scales,ref,irelhisto,filenamePy,outputnames): # Scale to one ? scale2one = False - if ref.stack==StackingMethodType.NORMALIZE2ONE or \ - (self.main.stack==StackingMethodType.NORMALIZE2ONE and \ - ref.stack==StackingMethodType.AUTO): + if ref.stack == StackingMethodType.NORMALIZE2ONE or ( + self.main.stack == StackingMethodType.NORMALIZE2ONE + and ref.stack == StackingMethodType.AUTO + ): scale2one = True if scale2one: axis_titleY += " $(#mathrm{scaled}\ #mathrm{to}# #mathrm{one})$" - elif self.main.normalize == NormalizeType.LUMI or \ - self.main.normalize == NormalizeType.LUMI_WEIGHT: - axis_titleY += " $(#mathcal{L}_{#mathrm{int}} = " + str(self.main.lumi)+ "# #mathrm{fb}^{-1})$ " + elif ( + self.main.normalize == NormalizeType.LUMI + or self.main.normalize == NormalizeType.LUMI_WEIGHT + ): + axis_titleY += ( + " $(#mathcal{L}_{#mathrm{int}} = " + + str(self.main.lumi) + + "# #mathrm{fb}^{-1})$ " + ) elif self.main.normalize == NormalizeType.NONE: axis_titleY += " $(#mathrm{not}# #mathrm{normalized})$" - if ref.titleY!="": + if ref.titleY != "": axis_titleY = PlotFlow.NiceTitle(ref.titleY) - axis_titleY = axis_titleY.replace('#','\\') - outputPy.write(' plt.ylabel(r"'+axis_titleY+'",\\\n') + axis_titleY = axis_titleY.replace("#", "\\") + outputPy.write(' plt.ylabel(r"' + axis_titleY + '",\\\n') outputPy.write(' fontsize=16,color="black")\n') - outputPy.write('\n') + outputPy.write("\n") # Tag Log/Linear - is_logx=False + is_logx = False if ref.logX and ntot != 0: - is_logx=True - is_logy=False + is_logx = True + is_logy = False if ref.logY and ntot != 0: - is_logy=True + is_logy = True # Bound y - outputPy.write(' # Boundary of y-axis\n') - myweights='' + outputPy.write(" # Boundary of y-axis\n") + myweights = "" if stackmode: - for ind in range(0,len(histos)): - if ind>=1: - myweights+='+' - myweights+='y'+histos[ind].name+'_'+str(ind)+'_weights' + for ind in range(0, len(histos)): + if ind >= 1: + myweights += "+" + myweights += "y" + histos[ind].name + "_" + str(ind) + "_weights" else: - myweights='numpy.array([' - for ind in range(0,len(histos)): - if ind>=1: - myweights+=',' - myweights+='y'+histos[ind].name+'_'+str(ind)+'_weights.max()' - myweights+='])' - if ref.ymax==[]: - outputPy.write(' ymax=('+myweights+').max()*1.1\n') + myweights = "numpy.array([" + for ind in range(0, len(histos)): + if ind >= 1: + myweights += "," + myweights += "y" + histos[ind].name + "_" + str(ind) + "_weights.max()" + myweights += "])" + if ref.ymax == []: + outputPy.write(" ymax=(" + myweights + ").max()*1.1\n") else: - outputPy.write(' ymax='+str(ref.ymax)+'\n') - outputPy.write(' ') - if ref.ymin==[]: + outputPy.write(" ymax=" + str(ref.ymax) + "\n") + outputPy.write(" ") + if ref.ymin == []: if is_logy: - outputPy.write('#') - outputPy.write('ymin=0 # linear scale\n') + outputPy.write("#") + outputPy.write("ymin=0 # linear scale\n") else: - if is_logy and ref.ymin<=0: - outputPy.write('#') - outputPy.write('ymin=' + str(ref.ymin)+' # linear scale\n') + if is_logy and ref.ymin <= 0: + outputPy.write("#") + outputPy.write("ymin=" + str(ref.ymin) + " # linear scale\n") - myweights='' + myweights = "" if stackmode: - for ind in range(0,len(histos)): - if ind>=1: - myweights+='+' - myweights+='y'+histos[ind].name+'_'+str(ind)+'_weights' + for ind in range(0, len(histos)): + if ind >= 1: + myweights += "+" + myweights += "y" + histos[ind].name + "_" + str(ind) + "_weights" else: - myweights='numpy.array([' - for ind in range(0,len(histos)): - if ind>=1: - myweights+=',' - myweights+='y'+histos[ind].name+'_'+str(ind)+'_weights.min()' - myweights+=',1.])' - outputPy.write(' ') - if ref.ymin==[]: + myweights = "numpy.array([" + for ind in range(0, len(histos)): + if ind >= 1: + myweights += "," + myweights += "y" + histos[ind].name + "_" + str(ind) + "_weights.min()" + myweights += ",1.])" + outputPy.write(" ") + if ref.ymin == []: if not is_logy: - outputPy.write('#') - outputPy.write('ymin=min([x for x in ('+myweights+') if x])/100. # log scale\n') + outputPy.write("#") + outputPy.write( + "ymin=min([x for x in (" + myweights + ") if x])/100. # log scale\n" + ) else: - if is_logy and ref.ymin<=0: - outputPy.write('#') - outputPy.write('ymin=' + str(ref.ymin)+' # log scale\n') - outputPy.write(' plt.gca().set_ylim(ymin,ymax)\n') - outputPy.write('\n') + if is_logy and ref.ymin <= 0: + outputPy.write("#") + outputPy.write("ymin=" + str(ref.ymin) + " # log scale\n") + outputPy.write(" plt.gca().set_ylim(ymin,ymax)\n") + outputPy.write("\n") # X axis - outputPy.write(' # Log/Linear scale for X-axis\n') + outputPy.write(" # Log/Linear scale for X-axis\n") # - Linear - outputPy.write(' ') + outputPy.write(" ") if is_logx: - outputPy.write('#') + outputPy.write("#") outputPy.write('plt.gca().set_xscale("linear")\n') # - Log - outputPy.write(' ') + outputPy.write(" ") if not is_logx: - outputPy.write('#') + outputPy.write("#") outputPy.write('plt.gca().set_xscale("log",nonpositive="clip")\n') - outputPy.write('\n') - + outputPy.write("\n") # Y axis - outputPy.write(' # Log/Linear scale for Y-axis\n') + outputPy.write(" # Log/Linear scale for Y-axis\n") # - Linear - outputPy.write(' ') + outputPy.write(" ") if is_logy: - outputPy.write('#') + outputPy.write("#") outputPy.write('plt.gca().set_yscale("linear")\n') # - Log - outputPy.write(' ') + outputPy.write(" ") if not is_logy: - outputPy.write('#') + outputPy.write("#") outputPy.write('plt.gca().set_yscale("log",nonpositive="clip")\n') - outputPy.write('\n') + outputPy.write("\n") - # Labels if frequencyhisto: - outputPy.write(' # Labels for x-Axis\n') - outputPy.write(' xLabels = numpy.array([') - for bin in range(0,xnbin): - if bin>=1: - outputPy.write(',') - outputPy.write('"'+str(histos[0].stringlabels[bin]).replace('_','\_')+'"') - outputPy.write('])\n') + outputPy.write(" # Labels for x-Axis\n") + outputPy.write(" xLabels = numpy.array([") + for bin in range(0, xnbin): + if bin >= 1: + outputPy.write(",") + outputPy.write( + '"' + str(histos[0].stringlabels[bin]).replace("_", "\_") + '"' + ) + outputPy.write("])\n") outputPy.write(' plt.xticks(xData, xLabels, rotation="vertical")\n') - outputPy.write('\n') + outputPy.write("\n") -### BENJ: not necessary for getting the png and pdf files + ### BENJ: not necessary for getting the png and pdf files # Draw -# outputPy.write(' # Draw\n') -# outputPy.write(' plt.show()\n') -# outputPy.write('\n') + # outputPy.write(' # Draw\n') + # outputPy.write(' plt.show()\n') + # outputPy.write('\n') # Legend if legendmode: @@ -985,28 +1154,575 @@ def DrawMATPLOTLIB(self,histos,scales,ref,irelhisto,filenamePy,outputnames): # -'upper center' : 9, # -'center' : 10, - - outputPy.write(' # Legend\n') - outputPy.write(' plt.legend(bbox_to_anchor=(1.05,1), loc=2,'+\ - ' borderaxespad=0.)\n') - outputPy.write('\n') - + outputPy.write(" # Legend\n") + outputPy.write( + " plt.legend(bbox_to_anchor=(1.05,1), loc=2," + " borderaxespad=0.)\n" + ) + outputPy.write("\n") + # Producing the image - outputPy.write(' # Saving the image\n') + outputPy.write(" # Saving the image\n") for outputname in outputnames: - outputPy.write(" plt.savefig('"+outputname+"')\n") - outputPy.write('\n') + outputPy.write(" plt.savefig('" + outputname + "')\n") + outputPy.write("\n") # Call the function - outputPy.write('# Running!\n') + outputPy.write("# Running!\n") outputPy.write("if __name__ == '__main__':\n") - outputPy.write(' '+function_name+'()\n') + outputPy.write(" " + function_name + "()\n") # Close the file try: outputPy.close() except: - logging.getLogger('MA5').error('Impossible to close the file: '+outputPy) + logging.getLogger("MA5").error("Impossible to close the file: " + outputPy) + return False + + # Ok + return True + + def DrawMULTIWEIGHT(self, histos, ref, filenamePy, outputnames) -> bool: + + # Is there any legend? + legendmode = False + if len(self.main.datasets) > 1: + legendmode = True + + # Stacking or superimposing histos ? + stackmode = False + if ref.stack == StackingMethodType.STACK or ( + ref.stack == StackingMethodType.AUTO + and self.main.stack == StackingMethodType.STACK + ): + stackmode = True + + # Open the file in write-mode + try: + outputPy = open(filenamePy, "w") + except: + logging.getLogger("MA5").error("Impossible to write the file: " + filenamePy) + return False + + # File header + function_name = filenamePy[:-3] + function_name = function_name.split("/")[-1] + outputPy.write("def " + function_name + "():\n") + outputPy.write("\n") + + # Import Libraries + outputPy.write(" # Library import\n") + outputPy.write(" import numpy as np\n") + outputPy.write(" import matplotlib\n") + # outputPy.write(" matplotlib.use('Agg')\n") + outputPy.write(" import matplotlib.pyplot as plt\n") + outputPy.write(" import matplotlib.gridspec as gridspec\n") + outputPy.write("\n") + + # Matplotlib & numpy version + outputPy.write(" # Library version\n") + outputPy.write(" matplotlib_version = matplotlib.__version__\n") + outputPy.write(" numpy_version = np.__version__\n") + outputPy.write("\n") + + # Binning + # Loop over datasets and histos + xnbin = histos[0].description.nbins + outputPy.write(" # Histo binning\n") + outputPy.write( + f" xBinning=np.linspace({histos[0].description.xmin}, " + f"{histos[0].description.xmax}, {xnbin+1}, " + "endpoint=True)\n" + ) + outputPy.write("\n") + + # Data + outputPy.write(" # Creating data sequence: middle of each bin\n") + outputPy.write(" xData = np.array([") + for bn in range(0, xnbin): + if bn != 0: + outputPy.write(",") + outputPy.write(str(histos[0].description.GetBinMean(bn))) + outputPy.write("])\n\n") + + # Loop over datasets and histos + ntot = 0 + for ind in range(0, len(histos)): + if not histos[ind]: + continue + + # Creating a new histo + histoname = "y_MULTIWEIGHT_" + histos[ind].name + "_" + str(ind) + outputPy.write(" # Creating weights for histo: " + histoname + "\n") + outputPy.write(" " + histoname + "_weights = np.array([") + print("weights", histos[ind].weights) + print("scale", histos[ind].scale) + current_weights = histos[ind].weights * histos[ind].scale + for bn in range(1, xnbin + 1): + ntot += current_weights[bn - 1] + if bn != 1: + outputPy.write(",") + outputPy.write(str(current_weights[bn - 1])) + outputPy.write("])\n\n") + + # Creating a new histo + lower_unc, upper_unc = histos[ind].scale_uncertainties + histoname = "y_UPPER_" + histos[ind].name + "_" + str(ind) + outputPy.write(" # Creating weights for histo: " + histoname + "\n") + outputPy.write(" " + histoname + "_weights = np.array([") + for bn in range(1, xnbin + 1): + ntot += current_weights[bn - 1] + if bn != 1: + outputPy.write(",") + outputPy.write(str(upper_unc[bn - 1])) + outputPy.write("])\n\n") + histoname = "y_LOWER_" + histos[ind].name + "_" + str(ind) + outputPy.write(" " + "# " + f"scale = {histos[ind].scale}\n") + outputPy.write(" # Creating weights for histo: " + histoname + "\n") + outputPy.write(" " + histoname + "_weights = np.array([") + for bn in range(1, xnbin + 1): + ntot += current_weights[bn - 1] + if bn != 1: + outputPy.write(",") + outputPy.write(str(lower_unc[bn - 1])) + outputPy.write("])\n\n") + + # Canvas + outputPy.write(" # Creating a new Canvas\n") + dpi = 80 + height = 500 + widthx = 700 + if legendmode: + widthx = 1000 + outputPy.write( + " fig = plt.figure(" + f"figsize=({widthx / dpi},{height / dpi}), dpi={dpi})\n" + ) + if not legendmode: + outputPy.write(" frame = gridspec.GridSpec(1,1)\n") + else: + outputPy.write(" frame = gridspec.GridSpec(1,1,right=0.7)\n") + outputPy.write(" pad = fig.add_subplot(frame[0])\n\n") + + # Stack + outputPy.write(" # Creating a new Stack\n") + for ind in range(len(histos) - 1, -1, -1): + mytitle = ( + '"' + PlotFlow.NiceTitleMatplotlib(self.main.datasets[ind].title) + '"' + ) + mytitle = mytitle.replace("_", "\_") + + if not stackmode: + myweights = ( + "y_MULTIWEIGHT_" + histos[ind].name + "_" + str(ind) + "_weights" + ) + else: + myweights = "" + for ind2 in range(0, ind + 1): + if ind2 >= 1: + myweights += "+" + myweights += ( + "y_MULTIWEIGHT_" + + histos[ind2].name + + "_" + + str(ind2) + + "_weights" + ) + + # reset + linecolor = 0 + linestyle = 0 + backcolor = 0 + backstyle = 0 + linewidth = 1 + + # Setting AUTO settings + if len(histos) == 1: + linecolor1 = [9] + linecolor = linecolor1[ind] + if stackmode: + backstyle1 = [3004] + backstyle = backstyle1[ind] + backcolor = linecolor1[ind] + elif len(histos) == 2: + linecolor2 = [9, 46] + linecolor = linecolor2[ind] + if stackmode: + backstyle2 = [3004, 3005] + backstyle = backstyle2[ind] + backcolor = linecolor2[ind] + elif len(histos) == 3: + linecolor3 = [9, 46, 8] + linecolor = linecolor3[ind] + if stackmode: + backstyle3 = [3004, 3005, 3006] + backstyle = backstyle3[ind] + backcolor = linecolor3[ind] + elif len(histos) == 4: + linecolor4 = [9, 46, 8, 4] + linecolor = linecolor4[ind] + if stackmode: + backstyle4 = [3004, 3005, 3006, 3007] + backstyle = backstyle4[ind] + backcolor = linecolor4[ind] + elif len(histos) == 5: + linecolor5 = [9, 46, 8, 4, 6] + linecolor = linecolor5[ind] + if stackmode: + backstyle5 = [3004, 3005, 3006, 3007, 3013] + backstyle = backstyle5[ind] + backcolor = linecolor5[ind] + elif len(histos) == 6: + linecolor6 = [9, 46, 8, 4, 6, 2] + linecolor = linecolor6[ind] + if stackmode: + backstyle6 = [3004, 3005, 3006, 3007, 3013, 3017] + backstyle = backstyle6[ind] + backcolor = linecolor6[ind] + elif len(histos) == 7: + linecolor7 = [9, 46, 8, 4, 6, 2, 7] + linecolor = linecolor7[ind] + if stackmode: + backstyle7 = [3004, 3005, 3006, 3007, 3013, 3017, 3022] + backstyle = backstyle7[ind] + backcolor = linecolor7[ind] + elif len(histos) == 8: + linecolor8 = [9, 46, 8, 4, 6, 2, 7, 3] + linecolor = linecolor8[ind] + if stackmode: + backstyle8 = [3004, 3005, 3006, 3007, 3013, 3017, 3022, 3315] + backstyle = backstyle8[ind] + backcolor = linecolor8[ind] + elif len(histos) == 9: + linecolor9 = [9, 46, 8, 4, 6, 2, 7, 3, 42] + linecolor = linecolor9[ind] + if stackmode: + backstyle9 = [3004, 3005, 3006, 3007, 3013, 3017, 3022, 3315, 3351] + backstyle = backstyle9[ind] + backcolor = linecolor9[ind] + elif len(histos) == 10: + linecolor10 = [9, 46, 8, 4, 6, 2, 7, 3, 42, 48] + linecolor = linecolor10[ind] + if stackmode: + backstyle10 = [ + 3004, + 3005, + 3006, + 3007, + 3013, + 3017, + 3022, + 3315, + 3351, + 3481, + ] + backstyle = backstyle10[ind] + backcolor = linecolor10[ind] + else: + linecolor = self.color + self.color += 1 + + # linecolor + if self.main.datasets[ind].linecolor != ColorType.AUTO: + linecolor = ColorType.convert2root( + self.main.datasets[ind].linecolor, self.main.datasets[ind].lineshade + ) + # lineStyle + linestyle = LineStyleType.convert2code(self.main.datasets[ind].linestyle) + + # linewidth + linewidth = self.main.datasets[ind].linewidth + + # background color + if self.main.datasets[ind].backcolor != ColorType.AUTO: + backcolor = ColorType.convert2root( + self.main.datasets[ind].backcolor, self.main.datasets[ind].backshade + ) + + # background style + if self.main.datasets[ind].backstyle != BackStyleType.AUTO: + backstyle = BackStyleType.convert2matplotlib( + self.main.datasets[ind].backstyle + ) + + mylinecolor = ( + '"' + madanalysis.enumeration.color_hex.color_hex[linecolor] + '"' + ) + mybackcolor = ( + '"' + madanalysis.enumeration.color_hex.color_hex[backcolor] + '"' + ) + + filledmode = '"stepfilled"' + rWidth = 1.0 + if backcolor == 0: # invisible + filledmode = '"step"' + mybackcolor = "None" + # if frequencyhisto: + # filledmode='"bar"' + # rWidth=0.8 + mylinewidth = self.main.datasets[ind].linewidth + mylinestyle = LineStyleType.convert2matplotlib( + self.main.datasets[ind].linestyle + ) + + outputPy.write( + " pad.hist(" + + "x=xData, " + + "bins=xBinning, " + + "weights=" + + myweights + + ",\\\n" + + " label=" + + mytitle + + ", " + ) + if ntot != 0: + outputPy.write("histtype=" + filledmode + ", ") + try: + import matplotlib.pyplot as plt + + plt.hist([0], normed=True) + outputPy.write( + "rwidth=" + + str(rWidth) + + ",\\\n" + + " color=" + + mybackcolor + + ", " + + "edgecolor=" + + mylinecolor + + ", " + + "linewidth=" + + str(mylinewidth) + + ", " + + "linestyle=" + + mylinestyle + + ",\\\n" + + " bottom=None, " + + 'cumulative=False, normed=False, align="mid", orientation="vertical")\n\n' + ) + except Exception: + outputPy.write( + "rwidth=" + + str(rWidth) + + ",\\\n" + + " color=" + + mybackcolor + + ", " + + "edgecolor=" + + mylinecolor + + ", " + + "linewidth=" + + str(mylinewidth) + + ", " + + "linestyle=" + + mylinestyle + + ",\\\n" + + " bottom=None, " + + 'cumulative=False, density=False, align="mid",' + + ' orientation="vertical")\n\n' + ) + outputPy.write("\n") + + # Label + outputPy.write(" # Axis\n") + outputPy.write(" plt.rc('text',usetex=False)\n") + + # X-axis + if ref.titleX == "": + axis_titleX = ref.GetXaxis_Matplotlib() + else: + axis_titleX = ref.titleX + axis_titleX = axis_titleX.replace("#DeltaR", "#Delta R") + axis_titleX = axis_titleX.replace("#", "\\") + outputPy.write(' plt.xlabel(r"' + axis_titleX + '",\\\n') + outputPy.write(' fontsize=16,color="black")\n') + + # Y-axis + axis_titleY = ref.GetYaxis_Matplotlib() + + # Scale to one ? + scale2one = False + if ref.stack == StackingMethodType.NORMALIZE2ONE or ( + self.main.stack == StackingMethodType.NORMALIZE2ONE + and ref.stack == StackingMethodType.AUTO + ): + scale2one = True + + if scale2one: + axis_titleY += " $(#mathrm{scaled}\ #mathrm{to}# #mathrm{one})$" + elif ( + self.main.normalize == NormalizeType.LUMI + or self.main.normalize == NormalizeType.LUMI_WEIGHT + ): + axis_titleY += ( + " $(#mathcal{L}_{#mathrm{int}} = " + + str(self.main.lumi) + + "# #mathrm{fb}^{-1})$ " + ) + elif self.main.normalize == NormalizeType.NONE: + axis_titleY += " $(#mathrm{not}# #mathrm{normalized})$" + + if ref.titleY != "": + axis_titleY = PlotFlow.NiceTitle(ref.titleY) + axis_titleY = axis_titleY.replace("#", "\\") + outputPy.write(' plt.ylabel(r"' + axis_titleY + '",\\\n') + outputPy.write(' fontsize=16,color="black")\n') + outputPy.write("\n") + + # Tag Log/Linear + is_logx = False + if ref.logX and ntot != 0: + is_logx = True + is_logy = False + if ref.logY and ntot != 0: + is_logy = True + + # Bound y + outputPy.write(" # Boundary of y-axis\n") + myweights = "" + if stackmode: + for ind in range(0, len(histos)): + if ind >= 1: + myweights += "+" + myweights += ( + "y_MULTIWEIGHT_" + histos[ind].name + "_" + str(ind) + "_weights" + ) + else: + myweights = "numpy.array([" + for ind in range(0, len(histos)): + if ind >= 1: + myweights += "," + myweights += ( + "y_MULTIWEIGHT_" + + histos[ind].name + + "_" + + str(ind) + + "_weights.max()" + ) + myweights += "])" + if ref.ymax == []: + outputPy.write(" ymax=(" + myweights + ").max()*1.1\n") + else: + outputPy.write(" ymax=" + str(ref.ymax) + "\n") + outputPy.write(" ") + if ref.ymin == []: + if is_logy: + outputPy.write("#") + outputPy.write("ymin=0 # linear scale\n") + else: + if is_logy and ref.ymin <= 0: + outputPy.write("#") + outputPy.write("ymin=" + str(ref.ymin) + " # linear scale\n") + + myweights = "" + if stackmode: + for ind in range(0, len(histos)): + if ind >= 1: + myweights += "+" + myweights += ( + "y_MULTIWEIGHT_" + histos[ind].name + "_" + str(ind) + "_weights" + ) + else: + myweights = "numpy.array([" + for ind in range(0, len(histos)): + if ind >= 1: + myweights += "," + myweights += ( + "y_MULTIWEIGHT_" + + histos[ind].name + + "_" + + str(ind) + + "_weights.min()" + ) + myweights += ",1.])" + outputPy.write(" ") + if ref.ymin == []: + if not is_logy: + outputPy.write("#") + outputPy.write( + "ymin=min([x for x in (" + myweights + ") if x])/100. # log scale\n" + ) + else: + if is_logy and ref.ymin <= 0: + outputPy.write("#") + outputPy.write("ymin=" + str(ref.ymin) + " # log scale\n") + outputPy.write(" plt.gca().set_ylim(ymin,ymax)\n") + outputPy.write("\n") + + # X axis + outputPy.write(" # Log/Linear scale for X-axis\n") + # - Linear + outputPy.write(" ") + if is_logx: + outputPy.write("#") + outputPy.write('plt.gca().set_xscale("linear")\n') + # - Log + outputPy.write(" ") + if not is_logx: + outputPy.write("#") + outputPy.write('plt.gca().set_xscale("log",nonpositive="clip")\n') + outputPy.write("\n") + + # Y axis + outputPy.write(" # Log/Linear scale for Y-axis\n") + # - Linear + outputPy.write(" ") + if is_logy: + outputPy.write("#") + outputPy.write('plt.gca().set_yscale("linear")\n') + # - Log + outputPy.write(" ") + if not is_logy: + outputPy.write("#") + outputPy.write('plt.gca().set_yscale("log",nonpositive="clip")\n') + outputPy.write("\n") + + # Labels + ### BENJ: not necessary for getting the png and pdf files + # Draw + # outputPy.write(' # Draw\n') + # outputPy.write(' plt.show()\n') + # outputPy.write('\n') + + # Legend + if legendmode: + + # Reminder for 'loc' + # -'best' : 0, (only implemented for axes legends) + # -'upper right' : 1, + # -'upper left' : 2, + # -'lower left' : 3, + # -'lower right' : 4, + # -'right' : 5, + # -'center left' : 6, + # -'center right' : 7, + # -'lower center' : 8, + # -'upper center' : 9, + # -'center' : 10, + + outputPy.write(" # Legend\n") + outputPy.write( + " plt.legend(bbox_to_anchor=(1.05,1), loc=2," + " borderaxespad=0.)\n" + ) + outputPy.write("\n") + + # Producing the image + outputPy.write(" # Saving the image\n") + for outputname in outputnames: + outputPy.write(" plt.savefig('" + outputname + "')\n") + outputPy.write("\n") + + # Call the function + outputPy.write("# Running!\n") + outputPy.write("if __name__ == '__main__':\n") + outputPy.write(" " + function_name + "()\n") + + # Close the file + try: + outputPy.close() + except Exception as err: + logging.getLogger("MA5").error("Impossible to close the file: " + outputPy) + logging.getLogger("MA5").debug(err) return False # Ok diff --git a/madanalysis/layout/plotflow_for_dataset.py b/madanalysis/layout/plotflow_for_dataset.py index 6cedb59b..214b7a50 100644 --- a/madanalysis/layout/plotflow_for_dataset.py +++ b/madanalysis/layout/plotflow_for_dataset.py @@ -23,21 +23,21 @@ from __future__ import absolute_import -from madanalysis.enumeration.uncertainty_type import UncertaintyType + +import copy, os + +from six.moves import range + from madanalysis.enumeration.normalize_type import NormalizeType -from madanalysis.enumeration.report_format_type import ReportFormatType -from madanalysis.enumeration.observable_type import ObservableType -from madanalysis.enumeration.color_type import ColorType -from madanalysis.enumeration.linestyle_type import LineStyleType -from madanalysis.enumeration.backstyle_type import BackStyleType from madanalysis.enumeration.stacking_method_type import StackingMethodType -import copy -from six.moves import range + +# pylint: disable=C0200,C0103 class PlotFlowForDataset: def __init__(self, main, dataset): self.histos = [] + self.multiweight_histos = [] self.main = main self.dataset = dataset @@ -89,6 +89,11 @@ def ComputeScale(self): iplot = 0 + with open( + os.path.join(self.main.archi_info.ma5dir, "madanalysis/input/LHAPDF.txt"), "r" + ) as f: + pdf_list = [int(line.split(",")[0]) for line in f.readlines()[1:]] + # Loop over plot for iabshisto in range(0, len(self.main.selection)): @@ -98,6 +103,13 @@ def ComputeScale(self): # Reset scale scale = 0.0 + multiweight_scale = 0.0 + if self.multiweight_histos[iplot]: + self.multiweight_histos[iplot].set_central_weight_loc( + scale_choice=self.dataset.dynamic_scale_choice, + n_point_scale_variation=self.dataset.n_point_scale_variation, + central_pdfs=pdf_list, + ) # Case 1: Normalization to ONE if self.main.selection[ @@ -110,14 +122,20 @@ def ComputeScale(self): self.histos[iplot].positive.integral - self.histos[iplot].negative.integral ) + multiweight_integral = 0 + if self.multiweight_histos[iplot]: + multiweight_integral = self.multiweight_histos[iplot].integral if integral > 0.0: scale = 1.0 / integral else: scale = 0.0 + if multiweight_integral > 0.0: + multiweight_scale = 1.0 / multiweight_integral # Case 2: No normalization elif self.main.normalize == NormalizeType.NONE: scale = 1.0 + multiweight_scale = 1.0 # Case 3 and 4 : Normalization formula depends on LUMI # or depends on WEIGHT+LUMI @@ -128,15 +146,21 @@ def ComputeScale(self): self.histos[iplot].positive.integral - self.histos[iplot].negative.integral ) + multiweight_integral, multiweight_eff = 0, 0 + if len(self.multiweight_histos) != 0: + multiweight_integral = self.multiweight_histos[iplot].integral # compute efficiency : Nevent / Ntotal if self.dataset.measured_global.nevents == 0: eff = 0 else: + nevt = float(self.dataset.measured_global.nevents) eff = ( self.histos[iplot].positive.nevents + self.histos[iplot].negative.nevents - ) / float(self.dataset.measured_global.nevents) + ) / nevt + if self.multiweight_histos[iplot]: + multiweight_eff = self.multiweight_histos[iplot].nevents / nevt # compute the good xsection value thexsection = self.xsection @@ -166,8 +190,31 @@ def ComputeScale(self): else: scale = 1 # no scale for empty plot + if self.multiweight_histos[iplot]: + entries_per_events = 0 + sumw = self.multiweight_histos[iplot].central_sumw_over_events + Nentries = self.multiweight_histos[iplot].central_sumw_over_entries + if Nentries != 0: + entries_per_events = sumw / Nentries + # compute the scale + if multiweight_integral != 0: + multiweight_scale = ( + thexsection + * self.main.lumi + * 1000 + * multiweight_eff + * entries_per_events + / multiweight_integral + ) + else: + multiweight_scale = 1 # no scale for empty plot + print("here no scale", multiweight_integral) + # Setting the computing scale self.histos[iplot].scale = copy.copy(scale) + if len(self.multiweight_histos) != 0: + self.multiweight_histos[iplot].scale = copy.copy(multiweight_scale) + print("scale", self.multiweight_histos[iplot].scale) # Incrementing counter iplot += 1 From f6360ff8b955b94960f4713d995d6e5ecf73596b Mon Sep 17 00:00:00 2001 From: "Jack Y. Araz" <jackaraz@gmail.com> Date: Wed, 10 Jan 2024 16:50:08 -0500 Subject: [PATCH 078/107] fix for scale vars --- madanalysis/multiweight/histogram.py | 84 ++++++++++++++-------------- 1 file changed, 41 insertions(+), 43 deletions(-) diff --git a/madanalysis/multiweight/histogram.py b/madanalysis/multiweight/histogram.py index 4212022b..c124ecb8 100644 --- a/madanalysis/multiweight/histogram.py +++ b/madanalysis/multiweight/histogram.py @@ -173,9 +173,9 @@ def __iter__(self) -> float: def __add__(self, other): if isinstance(other, MultiWeightBin): assert len(other) == len(self), "Dimensionality does not match" - return MultiWeightBin(other.weights + self.weights) + return MultiWeightBin(other.weights + copy.deepcopy(self.weights)) elif isinstance(other, (int, float)): - return MultiWeightBin(other + self.weights) + return MultiWeightBin(other + copy.deepcopy(self.weights)) raise ValueError("Unknown operation") @@ -194,19 +194,22 @@ def __pos__(self): return self def __neg__(self): - return MultiWeightBin(-1.0 * self.weights) + return MultiWeightBin(-1.0 * copy.deepcopy(self.weights)) def __mul__(self, other): if isinstance(other, MultiWeightBin): assert len(other) == len(self), "Dimensionality does not match" - return MultiWeightBin(other.weights * self.weights) + return MultiWeightBin(other.weights * copy.deepcopy(self.weights)) elif isinstance(other, (int, float)): - return MultiWeightBin(other * self.weights) + return MultiWeightBin(other * copy.deepcopy(self.weights)) raise ValueError("Unknown operation") __rmul__ = __mul__ + def __abs__(self): + return MultiWeightBin(np.abs(self.weights)) + class MultiWeightHisto: """ @@ -224,6 +227,7 @@ def __init__( # Scale of the histogram self.central_idx = 0 # Central weight location + self.nominal_weight = None self.dynamic_scale_choice = None self.n_point_scale_variation = None @@ -270,7 +274,8 @@ def __repr__(self): def set_central_weight_loc( self, scale_choice: int, n_point_scale_variation: int, central_pdfs: List[int] ) -> None: - self.central_idx = self.weight_collection.nominal(scale_choice, central_pdfs).loc + self.nominal_weight = self.weight_collection.nominal(scale_choice, central_pdfs) + self.central_idx = self.nominal_weight.loc self.dynamic_scale_choice = scale_choice self.n_point_scale_variation = n_point_scale_variation print("Central PDF loc:", self.central_idx) @@ -406,23 +411,25 @@ def integral(self): sum(self._positive_weights) + self.underflow[0] + self.overflow[0] - - (sum(self._negative_weights) + self.underflow[1] + self.overflow[1]) + - ( + abs(sum(self._negative_weights)) + + abs(self.underflow[1]) + + abs(self.overflow[1]) + ) )[self.central_idx] @property def central_sumw_over_events(self) -> float: """Sum of weights over events""" - return ( - self.sumw_over_events[0][self.central_idx] - - self.sumw_over_events[1][self.central_idx] + return self.sumw_over_events[0][self.central_idx] - abs( + self.sumw_over_events[1][self.central_idx] ) @property def central_sumw_over_entries(self) -> float: """Sum of weights over entries""" - return ( - self.sumw_over_entries[0][self.central_idx] - - self.sumw_over_entries[1][self.central_idx] + return self.sumw_over_entries[0][self.central_idx] - abs( + self.sumw_over_entries[1][self.central_idx] ) @property @@ -436,53 +443,44 @@ def sumw(self) -> float: def weights(self) -> np.ndarray: return np.array( [ - (pos - neg).weights[self.central_idx] + (pos - abs(neg))[self.central_idx] for pos, neg in zip(self._positive_weights, self._negative_weights) ] ) @property - def scale_uncertainties(self) -> Tuple[List[float], List[float]]: + def all_scaled_weights(self): + return [ + (pos - abs(neg)) * self.scale + for pos, neg in zip(self._positive_weights, self._negative_weights) + ] + + @property + def scale_uncertainties(self) -> Tuple[np.ndarray, np.ndarray]: """ Retreive scale uncertainties Returns: - ``Tuple[List[float], List[float]]``: + ``Tuple[np.ndarray, np.ndarray]``: lower and upper uncertainties per bin """ - bins = [ - (pos - neg) - for pos, neg in zip(self._positive_weights, self._negative_weights) - ] + bins = self.all_scaled_weights if not self.weight_collection.has_scale: central = [b[self.central_idx] for b in bins] return central, central - weight_collection = self.weight_collection.get_scale_vars( - self.n_point_scale_variation, self.dynamic_scale_choice + weight_loc = ( + self.weight_collection.get_scale_vars( + self.n_point_scale_variation, self.dynamic_scale_choice + ) + .pdfset(self.nominal_weight.pdfset) + .loc ) - central_scale_idx = self.n_point_scale_variation // 2 upper, lower = [], [] for current_bin in bins: - central = current_bin[central_scale_idx] - upper_unc = copy.deepcopy(central) - lower_unc = copy.deepcopy(central) - upper_diff, lower_diff = 0, 0 - # find maximum uncertainty - for iw, w in enumerate(weight_collection): - if iw == self.n_point_scale_variation // 2: - continue - if iw < self.n_point_scale_variation // 2: - if abs(central - current_bin[w.loc]) > lower_diff: - lower_diff = abs(central - current_bin[w.loc]) - lower_unc = current_bin[w.loc] - elif iw > self.n_point_scale_variation // 2: - if abs(central - current_bin[w.loc]) > upper_diff: - upper_diff = abs(central - current_bin[w.loc]) - upper_unc = current_bin[w.loc] - - upper.append(upper_unc) - lower.append(lower_unc) - return lower, upper + current_weights = [current_bin[wloc] for wloc in weight_loc] + upper.append(max(current_weights)) + lower.append(min(current_weights)) + return np.array(lower), np.array(upper) From 9ef2cc0c1d4f3e6b947c8ea6da6cf4c937ef0998 Mon Sep 17 00:00:00 2001 From: "Jack Y. Araz" <jackaraz@gmail.com> Date: Wed, 10 Jan 2024 16:50:23 -0500 Subject: [PATCH 079/107] overlap removal --- .../configuration/weight_configuration.py | 80 ++++++++++++------- 1 file changed, 49 insertions(+), 31 deletions(-) diff --git a/madanalysis/configuration/weight_configuration.py b/madanalysis/configuration/weight_configuration.py index 8319b954..43ad5b7b 100644 --- a/madanalysis/configuration/weight_configuration.py +++ b/madanalysis/configuration/weight_configuration.py @@ -23,7 +23,8 @@ from dataclasses import dataclass, field -from typing import Any, Dict, List, Text, Tuple +from typing import Any, Dict, List, Text, Tuple, Union +import copy import numpy as np @@ -42,6 +43,11 @@ class Weight: _merging: float = field(init=False, default=None) _alphas: float = field(init=False, default=None) + def __eq__(self, other): + return all( + getattr(other, attr) == getattr(self, attr) for attr in ["name", "loc"] + ) + def __post_init__(self) -> None: self.name = self.name.replace("DYN_SCALE", "DYNSCALE") sectors = self.name.split("_") @@ -126,8 +132,9 @@ class WeightCollection: """Create a weight collection""" def __init__(self, collection: List[Weight] = None): - self._collection = [] if collection is None else collection + self._collection: List[Weight] = [] if collection is None else collection self._names = [] + self._nominal: Weight = None def append(self, name: Text, idx: int) -> None: """Add weight into the collection""" @@ -172,15 +179,18 @@ def from_dict(self, data: List[Dict[Text, Any]]) -> None: def nominal(self, scale_choice: int, central_pdfs: np.array) -> Weight: """Get nominal weight""" - for w in self: - if any([not x is None for x in [w.aux, w.alphas]]): - continue - if w.muf != 1.0 or w.mur != 1.0 or w.dynamic_scale != scale_choice: - continue - if not w.pdfset in central_pdfs: - continue - return w - raise ValueError("Cannot find nominal weight") + if self._nominal is None: + for w in self: + if any([not x is None for x in [w.aux, w.alphas]]): + continue + if w.muf != 1.0 or w.mur != 1.0 or w.dynamic_scale != scale_choice: + continue + if not w.pdfset in central_pdfs: + continue + # !WARNING: this will fail if there are multiple pdfsets that are used + # ! this search will only return the first one + self._nominal = w + return self._nominal def group_for(self, group: Text) -> Dict: """Create a group""" @@ -200,9 +210,11 @@ def group_for(self, group: Text) -> Dict: return group_dict - def pdfset(self, pdfid: int) -> List[Weight]: + def pdfset(self, pdfid: Union[int, List[int]]) -> List[Weight]: """retrieve weights corresponding to one pdf set""" - return WeightCollection([w for w in self if w.pdfset == pdfid]) + return WeightCollection( + [w for w in self if w.pdfset == pdfid or w.pdfset in pdfid] + ) def get(self, **kwargs) -> List[Weight]: if len(kwargs) == 0: @@ -291,16 +303,16 @@ def get_scale( ) -> List[Weight]: if dynamic is not None: dynamic = dynamic if self.has_dyn_scale(dynamic) else None - return WeightCollection( - [ - w - for w in self - if w.dynamic_scale == dynamic + output = WeightCollection() + for w in self: + if ( + w.dynamic_scale == dynamic and w.muf == muf and w.mur == mur and w.alphas is None - ] - ) + ): + output += w + return output def has_dyn_scale(self, scale: int) -> bool: """If weight collection has a particular dynamic scale""" @@ -313,19 +325,25 @@ def has_dyn_scale(self, scale: int) -> bool: @property def loc(self) -> List[int]: """retrieve the locations of the weights""" - return [w.loc for w in self] + return np.unique([w.loc for w in self]) def __iadd__(self, other): - assert isinstance(other, WeightCollection) - for items in other: - self._collection.append(items) + if isinstance(other, WeightCollection): + for items in other: + if items not in self._collection: + self._collection.append(items) + elif isinstance(other, Weight): + if other not in self._collection: + self._collection.append(other) return self def __add__(self, other): - assert isinstance(other, WeightCollection) - for item in other: - if item not in self._collection: - self._collection.append(item) - else: - raise ValueError(f"{item} already exists.") - return self + current_col = copy.deepcopy(self._collection) + if isinstance(other, WeightCollection): + for item in other: + if item not in current_col: + current_col.append(item) + elif isinstance(other, Weight): + if other not in current_col: + current_col.append(other) + return WeightCollection(current_col) From ec50d438fc83fdf5d4b46dc91ba2fc84c019cc37 Mon Sep 17 00:00:00 2001 From: "Jack Y. Araz" <jackaraz@gmail.com> Date: Wed, 10 Jan 2024 16:50:41 -0500 Subject: [PATCH 080/107] convert print to debug --- madanalysis/IOinterface/job_reader.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/madanalysis/IOinterface/job_reader.py b/madanalysis/IOinterface/job_reader.py index d4a5b23f..3f1f7fb1 100644 --- a/madanalysis/IOinterface/job_reader.py +++ b/madanalysis/IOinterface/job_reader.py @@ -467,8 +467,8 @@ def ExtractHistos(self, dataset, plot, merging=False): histoinfo.Reset() if multiweight_histo.is_consistent: plot.multiweight_histos.append(copy.deepcopy(multiweight_histo)) - print(multiweight_histo) - print(multiweight_histo.shape) + logging.getLogger("MA5").debug(multiweight_histo) + logging.getLogger("MA5").debug(multiweight_histo.shape) else: plot.multiweight_histos.append(False) multiweight_histo = MultiWeightHisto( From 51c62aeca8d04cafa1d8f851c27ec258c10c4abf Mon Sep 17 00:00:00 2001 From: "Jack Y. Araz" <jackaraz@gmail.com> Date: Wed, 10 Jan 2024 16:51:34 -0500 Subject: [PATCH 081/107] add scale vars --- madanalysis/layout/plotflow.py | 139 +++++++++++++++++---------------- 1 file changed, 73 insertions(+), 66 deletions(-) diff --git a/madanalysis/layout/plotflow.py b/madanalysis/layout/plotflow.py index 12e40696..bab9f35a 100644 --- a/madanalysis/layout/plotflow.py +++ b/madanalysis/layout/plotflow.py @@ -26,6 +26,7 @@ import logging +import numpy as np import six from six.moves import range @@ -957,7 +958,7 @@ def DrawMATPLOTLIB(self, histos, scales, ref, irelhisto, filenamePy, outputnames + " bottom=None, " + 'cumulative=False, normed=False, align="mid", orientation="vertical")\n\n' ) - except: + except Exception: outputPy.write( "rwidth=" + str(rWidth) @@ -1199,8 +1200,9 @@ def DrawMULTIWEIGHT(self, histos, ref, filenamePy, outputnames) -> bool: # Open the file in write-mode try: outputPy = open(filenamePy, "w") - except: + except Exception as err: logging.getLogger("MA5").error("Impossible to write the file: " + filenamePy) + logging.getLogger("MA5").debug(err) return False # File header @@ -1237,12 +1239,13 @@ def DrawMULTIWEIGHT(self, histos, ref, filenamePy, outputnames) -> bool: # Data outputPy.write(" # Creating data sequence: middle of each bin\n") - outputPy.write(" xData = np.array([") - for bn in range(0, xnbin): - if bn != 0: - outputPy.write(",") - outputPy.write(str(histos[0].description.GetBinMean(bn))) - outputPy.write("])\n\n") + outputPy.write( + " xData = np.array([" + + ", ".join( + [f"{histos[0].description.GetBinMean(x):.5e}" for x in range(0, xnbin)] + ) + + "])\n\n" + ) # Loop over datasets and histos ntot = 0 @@ -1251,40 +1254,56 @@ def DrawMULTIWEIGHT(self, histos, ref, filenamePy, outputnames) -> bool: continue # Creating a new histo - histoname = "y_MULTIWEIGHT_" + histos[ind].name + "_" + str(ind) + histoname = "y_nominal_" + histos[ind].name + "_" + str(ind) outputPy.write(" # Creating weights for histo: " + histoname + "\n") - outputPy.write(" " + histoname + "_weights = np.array([") - print("weights", histos[ind].weights) - print("scale", histos[ind].scale) current_weights = histos[ind].weights * histos[ind].scale - for bn in range(1, xnbin + 1): - ntot += current_weights[bn - 1] - if bn != 1: - outputPy.write(",") - outputPy.write(str(current_weights[bn - 1])) - outputPy.write("])\n\n") + outputPy.write( + " " + + histoname + + "_weights = np.array([" + + ", ".join([f"{c:.5e}" if c != 0.0 else "0.0" for c in current_weights]) + + "])\n\n" + ) - # Creating a new histo + # extract scale uncertainties lower_unc, upper_unc = histos[ind].scale_uncertainties - histoname = "y_UPPER_" + histos[ind].name + "_" + str(ind) - outputPy.write(" # Creating weights for histo: " + histoname + "\n") - outputPy.write(" " + histoname + "_weights = np.array([") - for bn in range(1, xnbin + 1): - ntot += current_weights[bn - 1] - if bn != 1: - outputPy.write(",") - outputPy.write(str(upper_unc[bn - 1])) - outputPy.write("])\n\n") - histoname = "y_LOWER_" + histos[ind].name + "_" + str(ind) - outputPy.write(" " + "# " + f"scale = {histos[ind].scale}\n") + + # Write upper limits + scale_upper_name = "y_UPPER_" + histos[ind].name + "_" + str(ind) + "_weights" + outputPy.write( + " # Delta Upper limits for the scale uncertainty: " + histoname + "\n" + ) + outputPy.write( + " " + + scale_upper_name + + " = np.array([" + + ", ".join( + [ + f"{u-c:.5e}" if c != 0.0 else "0.0" + for u, c in zip(upper_unc, current_weights) + ] + ) + + "])\n\n" + ) + + # Writing lower limits + outputPy.write( + " # Delta Lower limits for the scale uncertainty: " + histoname + "\n" + ) + scale_lower_name = "y_LOWER_" + histos[ind].name + "_" + str(ind) + "_weights" outputPy.write(" # Creating weights for histo: " + histoname + "\n") - outputPy.write(" " + histoname + "_weights = np.array([") - for bn in range(1, xnbin + 1): - ntot += current_weights[bn - 1] - if bn != 1: - outputPy.write(",") - outputPy.write(str(lower_unc[bn - 1])) - outputPy.write("])\n\n") + outputPy.write( + " " + + scale_lower_name + + " = np.array([" + + ", ".join( + [ + f"{c-l:.5e}" if c != 0.0 else "0.0" + for l, c in zip(lower_unc, current_weights) + ] + ) + + "])\n\n" + ) # Canvas outputPy.write(" # Creating a new Canvas\n") @@ -1312,20 +1331,14 @@ def DrawMULTIWEIGHT(self, histos, ref, filenamePy, outputnames) -> bool: mytitle = mytitle.replace("_", "\_") if not stackmode: - myweights = ( - "y_MULTIWEIGHT_" + histos[ind].name + "_" + str(ind) + "_weights" - ) + myweights = "y_nominal_" + histos[ind].name + "_" + str(ind) + "_weights" else: myweights = "" for ind2 in range(0, ind + 1): if ind2 >= 1: myweights += "+" myweights += ( - "y_MULTIWEIGHT_" - + histos[ind2].name - + "_" - + str(ind2) - + "_weights" + "y_nominal_" + histos[ind2].name + "_" + str(ind2) + "_weights" ) # reset @@ -1456,14 +1469,19 @@ def DrawMULTIWEIGHT(self, histos, ref, filenamePy, outputnames) -> bool: if backcolor == 0: # invisible filledmode = '"step"' mybackcolor = "None" - # if frequencyhisto: - # filledmode='"bar"' - # rWidth=0.8 mylinewidth = self.main.datasets[ind].linewidth mylinestyle = LineStyleType.convert2matplotlib( self.main.datasets[ind].linestyle ) + outputPy.write( + " pad.errorbar(\n" + f" xData, {myweights},\n" + f" yerr=[{scale_lower_name}, {scale_upper_name}],\n" + " fmt='.', elinewidth=1, capsize=3,\n" + " )\n\n" + ) + outputPy.write( " pad.hist(" + "x=xData, " @@ -1500,7 +1518,8 @@ def DrawMULTIWEIGHT(self, histos, ref, filenamePy, outputnames) -> bool: + " bottom=None, " + 'cumulative=False, normed=False, align="mid", orientation="vertical")\n\n' ) - except Exception: + except Exception as err: + logging.getLogger("MA5").debug(err) outputPy.write( "rwidth=" + str(rWidth) @@ -1584,20 +1603,14 @@ def DrawMULTIWEIGHT(self, histos, ref, filenamePy, outputnames) -> bool: for ind in range(0, len(histos)): if ind >= 1: myweights += "+" - myweights += ( - "y_MULTIWEIGHT_" + histos[ind].name + "_" + str(ind) + "_weights" - ) + myweights += "y_nominal_" + histos[ind].name + "_" + str(ind) + "_weights" else: myweights = "numpy.array([" for ind in range(0, len(histos)): if ind >= 1: myweights += "," myweights += ( - "y_MULTIWEIGHT_" - + histos[ind].name - + "_" - + str(ind) - + "_weights.max()" + "y_nominal_" + histos[ind].name + "_" + str(ind) + "_weights.max()" ) myweights += "])" if ref.ymax == []: @@ -1619,20 +1632,14 @@ def DrawMULTIWEIGHT(self, histos, ref, filenamePy, outputnames) -> bool: for ind in range(0, len(histos)): if ind >= 1: myweights += "+" - myweights += ( - "y_MULTIWEIGHT_" + histos[ind].name + "_" + str(ind) + "_weights" - ) + myweights += "y_nominal_" + histos[ind].name + "_" + str(ind) + "_weights" else: myweights = "numpy.array([" for ind in range(0, len(histos)): if ind >= 1: myweights += "," myweights += ( - "y_MULTIWEIGHT_" - + histos[ind].name - + "_" - + str(ind) - + "_weights.min()" + "y_nominal_" + histos[ind].name + "_" + str(ind) + "_weights.min()" ) myweights += ",1.])" outputPy.write(" ") @@ -1710,7 +1717,7 @@ def DrawMULTIWEIGHT(self, histos, ref, filenamePy, outputnames) -> bool: outputPy.write(" # Saving the image\n") for outputname in outputnames: outputPy.write(" plt.savefig('" + outputname + "')\n") - outputPy.write("\n") + outputPy.write(" plt.close('all')\n") # Call the function outputPy.write("# Running!\n") From bed7c97697a107dc52cf063c4570bfacc91146d9 Mon Sep 17 00:00:00 2001 From: "Jack Y. Araz" <jackaraz@gmail.com> Date: Wed, 10 Jan 2024 18:20:04 -0500 Subject: [PATCH 082/107] extend the usage --- madanalysis/configuration/weight_configuration.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/madanalysis/configuration/weight_configuration.py b/madanalysis/configuration/weight_configuration.py index 43ad5b7b..3df9fabf 100644 --- a/madanalysis/configuration/weight_configuration.py +++ b/madanalysis/configuration/weight_configuration.py @@ -212,9 +212,9 @@ def group_for(self, group: Text) -> Dict: def pdfset(self, pdfid: Union[int, List[int]]) -> List[Weight]: """retrieve weights corresponding to one pdf set""" - return WeightCollection( - [w for w in self if w.pdfset == pdfid or w.pdfset in pdfid] - ) + if isinstance(pdfid, int): + return WeightCollection([w for w in self if w.pdfset == pdfid]) + return WeightCollection([w for w in self if w.pdfset in pdfid]) def get(self, **kwargs) -> List[Weight]: if len(kwargs) == 0: @@ -252,6 +252,11 @@ def has_scale(self) -> bool: """is there any scale variations""" return (len(self.scales["mur"]) > 0) or (len(self.scales["muf"]) > 0) + @property + def has_pdf(self) -> bool: + """is there any pdf definition""" + return len(self.pdfsets) > 0 + @property def central_scale(self) -> float: """retrieve central scale""" From b4391c06740766eb583f2f2def91d30715d807b5 Mon Sep 17 00:00:00 2001 From: "Jack Y. Araz" <jackaraz@gmail.com> Date: Wed, 10 Jan 2024 18:20:18 -0500 Subject: [PATCH 083/107] add combination between pdf and scale unc --- madanalysis/multiweight/histogram.py | 130 ++++++++++++++++++++------- 1 file changed, 98 insertions(+), 32 deletions(-) diff --git a/madanalysis/multiweight/histogram.py b/madanalysis/multiweight/histogram.py index c124ecb8..409bb2c1 100644 --- a/madanalysis/multiweight/histogram.py +++ b/madanalysis/multiweight/histogram.py @@ -1,13 +1,14 @@ """This file includes classes for multiweight histograms""" +import copy +import warnings +from collections import namedtuple from dataclasses import dataclass from typing import Callable, List, Text, Tuple, Union -from collections import namedtuple -import copy + import numpy as np -from madanalysis.configuration.weight_configuration import WeightCollection -from madanalysis.enumeration.stacking_method_type import StackingMethodType +from madanalysis.configuration.weight_configuration import WeightCollection _nevt = namedtuple("events", ["positive", "negative"]) @@ -81,33 +82,6 @@ def GetBinMean(self, bn: int) -> float: return self.xmin + (bn + 0.5) * step -@dataclass -class WeightNames: - """ - Representation of weight names - - Args: - names (`List[Text]`): name of the weights - """ - - names: List[Text] - - def __getitem__(self, idx: int) -> Text: - return self.names[idx] - - def __len__(self) -> int: - return len(self.names) - - def __iter__(self) -> Text: - yield from self.names - - def __eq__(self, other) -> bool: - if not isinstance(other, WeightNames): - return False - - return all(i == j for i, j in zip(self, other)) - - class MultiWeightBin: """ Representation of a multiweight bin @@ -455,6 +429,11 @@ def all_scaled_weights(self): for pos, neg in zip(self._positive_weights, self._negative_weights) ] + @property + def has_scale_unc(self) -> bool: + """Does the histogram has scale unc""" + return self.weight_collection.has_scale + @property def scale_uncertainties(self) -> Tuple[np.ndarray, np.ndarray]: """ @@ -464,6 +443,7 @@ def scale_uncertainties(self) -> Tuple[np.ndarray, np.ndarray]: ``Tuple[np.ndarray, np.ndarray]``: lower and upper uncertainties per bin """ + central_weights = self.weights * self.scale bins = self.all_scaled_weights if not self.weight_collection.has_scale: @@ -483,4 +463,90 @@ def scale_uncertainties(self) -> Tuple[np.ndarray, np.ndarray]: current_weights = [current_bin[wloc] for wloc in weight_loc] upper.append(max(current_weights)) lower.append(min(current_weights)) - return np.array(lower), np.array(upper) + return ( + np.clip(central_weights - np.array(lower), 0.0, None), + np.clip(np.array(upper) - central_weights, 0.0, None), + ) + + @property + def has_pdf_unc(self) -> bool: + """Does the histogram has PDFs""" + return len(self.weight_collection.pdfsets) > 1 + + @property + def pdf_uncertainties(self) -> Tuple[np.ndarray, np.ndarray]: + """ + Retreive PDF uncertainties + + Returns: + ``Tuple[np.ndarray, np.ndarray]``: + lower and upper uncertainties per bin + """ + if not self.has_pdf_unc: + return [self.weights * self.scale] * 2 + + method = "replicas" # "eigenvector" + + bins = self.all_scaled_weights + + pdfids = self.weight_collection.pdfsets + pdfids.pop(pdfids.index(self.nominal_weight.pdfset)) + + pdf_sets = WeightCollection([self.nominal_weight]) + + new_bins = [] + + # Replicas + if method == "replicas": + # 2202.13416 eq 3.2 + pdf_sets += self.weight_collection.pdfset(pdfids) + pdf_locs = pdf_sets.loc + mean_bin_value = np.array( + [np.mean([bn[loc] for loc in pdf_locs]) for bn in bins] + ) + + for bn, mean_val in zip(bins, mean_bin_value): + new_bins.append( + np.sqrt( + sum((bn[loc] - mean_val) ** 2 for loc in pdf_locs) + / (len(pdf_locs) - 1) + ) + ) + return new_bins, new_bins + + # Eigenvectors + # ! Unclear 2202.13416 eq 3.1 + # pdf_locs = pdf_sets.loc + # for bn, mean_val in zip(bins, self.weights * self.scale): + + # # upper limit + # [max([bn[loc] - mean_val, ] for loc in pdf_locs] + + @property + def uncertainties(self) -> Tuple[np.ndarray, np.ndarray]: + """Retreive uncertainties per bin""" + nominal = self.weights * self.scale + + scale_lower, scale_upper = np.zeros(self.description.nbins), np.zeros( + self.description.nbins + ) + if self.has_scale_unc: + scale_lower, scale_upper = self.scale_uncertainties + with warnings.catch_warnings(record=False): + scale_lower = np.where(nominal > 0.0, scale_lower / nominal, 0.0) + scale_upper = np.where(nominal > 0.0, scale_upper / nominal, 0.0) + + pdf_lower, pdf_upper = np.zeros(self.description.nbins), np.zeros( + self.description.nbins + ) + if self.has_pdf_unc: + pdf_lower, pdf_upper = self.pdf_uncertainties + with warnings.catch_warnings(record=False): + pdf_lower = np.where(nominal > 0.0, pdf_lower / nominal, 0.0) + pdf_upper = np.where(nominal > 0.0, pdf_upper / nominal, 0.0) + + # add in quadrature + return ( + np.sqrt(scale_lower**2 + pdf_lower**2) * nominal, + np.sqrt(scale_lower**2 + pdf_lower**2) * nominal, + ) From a452b1fcdc1f01eb406634a5de89e151a4de5b7f Mon Sep 17 00:00:00 2001 From: "Jack Y. Araz" <jackaraz@gmail.com> Date: Wed, 10 Jan 2024 18:20:26 -0500 Subject: [PATCH 084/107] only write total unc --- madanalysis/layout/plotflow.py | 34 +++++++++++++--------------------- 1 file changed, 13 insertions(+), 21 deletions(-) diff --git a/madanalysis/layout/plotflow.py b/madanalysis/layout/plotflow.py index bab9f35a..0a91d44b 100644 --- a/madanalysis/layout/plotflow.py +++ b/madanalysis/layout/plotflow.py @@ -1265,43 +1265,33 @@ def DrawMULTIWEIGHT(self, histos, ref, filenamePy, outputnames) -> bool: + "])\n\n" ) - # extract scale uncertainties - lower_unc, upper_unc = histos[ind].scale_uncertainties + # extract uncertainties + lower_unc, upper_unc = histos[ind].uncertainties # Write upper limits - scale_upper_name = "y_UPPER_" + histos[ind].name + "_" + str(ind) + "_weights" + upper_unc_name = "y_UPPER_" + histos[ind].name + "_" + str(ind) + "_weights" outputPy.write( " # Delta Upper limits for the scale uncertainty: " + histoname + "\n" ) outputPy.write( " " - + scale_upper_name + + upper_unc_name + " = np.array([" - + ", ".join( - [ - f"{u-c:.5e}" if c != 0.0 else "0.0" - for u, c in zip(upper_unc, current_weights) - ] - ) + + ", ".join([f"{u:.5e}" if u != 0.0 else "0.0" for u in upper_unc]) + "])\n\n" ) # Writing lower limits outputPy.write( - " # Delta Lower limits for the scale uncertainty: " + histoname + "\n" + " # Delta Lower limits for the uncertainties: " + histoname + "\n" ) - scale_lower_name = "y_LOWER_" + histos[ind].name + "_" + str(ind) + "_weights" + lower_unc_name = "y_LOWER_" + histos[ind].name + "_" + str(ind) + "_weights" outputPy.write(" # Creating weights for histo: " + histoname + "\n") outputPy.write( " " - + scale_lower_name + + lower_unc_name + " = np.array([" - + ", ".join( - [ - f"{c-l:.5e}" if c != 0.0 else "0.0" - for l, c in zip(lower_unc, current_weights) - ] - ) + + ", ".join([f"{l:.5e}" if l != 0.0 else "0.0" for l in lower_unc]) + "])\n\n" ) @@ -1477,7 +1467,7 @@ def DrawMULTIWEIGHT(self, histos, ref, filenamePy, outputnames) -> bool: outputPy.write( " pad.errorbar(\n" f" xData, {myweights},\n" - f" yerr=[{scale_lower_name}, {scale_upper_name}],\n" + f" yerr=[{lower_unc_name}, {upper_unc_name}],\n" " fmt='.', elinewidth=1, capsize=3,\n" " )\n\n" ) @@ -1614,7 +1604,9 @@ def DrawMULTIWEIGHT(self, histos, ref, filenamePy, outputnames) -> bool: ) myweights += "])" if ref.ymax == []: - outputPy.write(" ymax=(" + myweights + ").max()*1.1\n") + outputPy.write( + " ymax=(" + myweights + "+" + upper_unc_name + ").max()*1.1\n" + ) else: outputPy.write(" ymax=" + str(ref.ymax) + "\n") outputPy.write(" ") From 1951263c2cc6198abfd698df68ff031457cbd21e Mon Sep 17 00:00:00 2001 From: "Jack Y. Araz" <jackaraz@gmail.com> Date: Thu, 11 Jan 2024 03:47:55 -0500 Subject: [PATCH 085/107] compactify the loop --- madanalysis/multiweight/histogram.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/madanalysis/multiweight/histogram.py b/madanalysis/multiweight/histogram.py index 409bb2c1..e221c996 100644 --- a/madanalysis/multiweight/histogram.py +++ b/madanalysis/multiweight/histogram.py @@ -494,8 +494,6 @@ def pdf_uncertainties(self) -> Tuple[np.ndarray, np.ndarray]: pdf_sets = WeightCollection([self.nominal_weight]) - new_bins = [] - # Replicas if method == "replicas": # 2202.13416 eq 3.2 @@ -505,13 +503,15 @@ def pdf_uncertainties(self) -> Tuple[np.ndarray, np.ndarray]: [np.mean([bn[loc] for loc in pdf_locs]) for bn in bins] ) - for bn, mean_val in zip(bins, mean_bin_value): - new_bins.append( + new_bins = np.array( + [ np.sqrt( sum((bn[loc] - mean_val) ** 2 for loc in pdf_locs) / (len(pdf_locs) - 1) ) - ) + for bn, mean_val in zip(bins, mean_bin_value) + ] + ) return new_bins, new_bins # Eigenvectors From eef8496f933cfa179c6d70fe3daa5978056f0435 Mon Sep 17 00:00:00 2001 From: "Jack Y. Araz" <jackaraz@gmail.com> Date: Thu, 11 Jan 2024 03:49:27 -0500 Subject: [PATCH 086/107] silence the warnings --- madanalysis/multiweight/histogram.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/madanalysis/multiweight/histogram.py b/madanalysis/multiweight/histogram.py index e221c996..ab296263 100644 --- a/madanalysis/multiweight/histogram.py +++ b/madanalysis/multiweight/histogram.py @@ -532,7 +532,7 @@ def uncertainties(self) -> Tuple[np.ndarray, np.ndarray]: ) if self.has_scale_unc: scale_lower, scale_upper = self.scale_uncertainties - with warnings.catch_warnings(record=False): + with warnings.catch_warnings(record=True): scale_lower = np.where(nominal > 0.0, scale_lower / nominal, 0.0) scale_upper = np.where(nominal > 0.0, scale_upper / nominal, 0.0) @@ -541,7 +541,7 @@ def uncertainties(self) -> Tuple[np.ndarray, np.ndarray]: ) if self.has_pdf_unc: pdf_lower, pdf_upper = self.pdf_uncertainties - with warnings.catch_warnings(record=False): + with warnings.catch_warnings(record=True): pdf_lower = np.where(nominal > 0.0, pdf_lower / nominal, 0.0) pdf_upper = np.where(nominal > 0.0, pdf_upper / nominal, 0.0) From bfb3334be57bcbc6293fd28c799dde1b340f2404 Mon Sep 17 00:00:00 2001 From: "Jack Y. Araz" <jackaraz@gmail.com> Date: Thu, 11 Jan 2024 04:19:39 -0500 Subject: [PATCH 087/107] implement eigvectors method --- madanalysis/multiweight/histogram.py | 47 ++++++++++++++++++++++------ 1 file changed, 37 insertions(+), 10 deletions(-) diff --git a/madanalysis/multiweight/histogram.py b/madanalysis/multiweight/histogram.py index ab296263..82c810a7 100644 --- a/madanalysis/multiweight/histogram.py +++ b/madanalysis/multiweight/histogram.py @@ -485,20 +485,20 @@ def pdf_uncertainties(self) -> Tuple[np.ndarray, np.ndarray]: if not self.has_pdf_unc: return [self.weights * self.scale] * 2 - method = "replicas" # "eigenvector" + method = "replicas" # "eigenvector" # bins = self.all_scaled_weights pdfids = self.weight_collection.pdfsets pdfids.pop(pdfids.index(self.nominal_weight.pdfset)) - pdf_sets = WeightCollection([self.nominal_weight]) - # Replicas if method == "replicas": # 2202.13416 eq 3.2 - pdf_sets += self.weight_collection.pdfset(pdfids) - pdf_locs = pdf_sets.loc + pdf_locs = ( + WeightCollection([self.nominal_weight]) + + self.weight_collection.pdfset(pdfids) + ).loc mean_bin_value = np.array( [np.mean([bn[loc] for loc in pdf_locs]) for bn in bins] ) @@ -515,12 +515,39 @@ def pdf_uncertainties(self) -> Tuple[np.ndarray, np.ndarray]: return new_bins, new_bins # Eigenvectors - # ! Unclear 2202.13416 eq 3.1 - # pdf_locs = pdf_sets.loc - # for bn, mean_val in zip(bins, self.weights * self.scale): + # 2202.13416 eq 3.1 + pdf_locs = self.weight_collection.pdfset(pdfids).loc + upper, lower = [], [] + for bn, mean_val in zip(bins, self.weights * self.scale): + current_upper_bin, current_lower_bin = [], [] + for idx in range(0, len(pdf_locs), 2): + # upper limit + current_upper_bin.append( + np.square( + max( + [ + bn[pdf_locs[idx]] - mean_val, + bn[pdf_locs[idx + 1]] - mean_val, + 0.0, + ] + ) + ) + ) + current_lower_bin.append( + np.square( + max( + [ + -bn[pdf_locs[idx]] + mean_val, + -bn[pdf_locs[idx + 1]] + mean_val, + 0.0, + ] + ) + ) + ) + upper.append(np.sqrt(sum(current_upper_bin))) + lower.append(np.sqrt(sum(current_lower_bin))) - # # upper limit - # [max([bn[loc] - mean_val, ] for loc in pdf_locs] + return np.array(lower), np.array(upper) @property def uncertainties(self) -> Tuple[np.ndarray, np.ndarray]: From dbb376e3101777053c51136a4b318ebfd7ca8c89 Mon Sep 17 00:00:00 2001 From: "Jack Y. Araz" <jackaraz@gmail.com> Date: Thu, 11 Jan 2024 04:31:35 -0500 Subject: [PATCH 088/107] bugfix --- .../Commons/Base/Configuration.cpp | 258 +++++++++--------- 1 file changed, 130 insertions(+), 128 deletions(-) diff --git a/tools/SampleAnalyzer/Commons/Base/Configuration.cpp b/tools/SampleAnalyzer/Commons/Base/Configuration.cpp index e5f656fa..cf563e41 100644 --- a/tools/SampleAnalyzer/Commons/Base/Configuration.cpp +++ b/tools/SampleAnalyzer/Commons/Base/Configuration.cpp @@ -63,9 +63,9 @@ void Configuration::PrintSyntax() // ----------------------------------------------------------------------------- void Configuration::Lower(std::string &word) { - std::transform(word.begin(), word.end(), - word.begin(), - (MAint32(*)(MAint32))std::tolower); + std::transform(word.begin(), word.end(), + word.begin(), + (MAint32(*)(MAint32))std::tolower); } // ----------------------------------------------------------------------------- @@ -73,34 +73,34 @@ void Configuration::Lower(std::string &word) // ----------------------------------------------------------------------------- void Configuration::DecodeMA5version(const std::string &option) { - std::string stamp = option.substr(14, std::string::npos); - std::size_t result = stamp.find(";"); - try - { - // check the syntax - if (result == std::string::npos) - throw EXCEPTION_WARNING("MA5 version '" + stamp + "' is not valid.", "", 0); - - // version - pythoninterface_version_ = stamp.substr(0, result); - if (pythoninterface_version_.find("\"") == 0) - pythoninterface_version_ = pythoninterface_version_.substr(1, std::string::npos); - if (pythoninterface_version_.size() >= 2) - if (pythoninterface_version_.find("\"") == (pythoninterface_version_.size() - 1)) - pythoninterface_version_ = pythoninterface_version_.substr(0, (pythoninterface_version_.size() - 1)); - - // date - pythoninterface_date_ = stamp.substr(result + 1, std::string::npos); - if (pythoninterface_date_.find("\"") == 0) - pythoninterface_date_ = pythoninterface_date_.substr(1, std::string::npos); - if (pythoninterface_date_.size() >= 2) - if (pythoninterface_date_.find("\"") == (pythoninterface_date_.size() - 1)) - pythoninterface_date_ = pythoninterface_date_.substr(0, (pythoninterface_date_.size() - 1)); - } - catch (const std::exception &e) - { - MANAGE_EXCEPTION(e); - } + std::string stamp = option.substr(14, std::string::npos); + std::size_t result = stamp.find(";"); + try + { + // check the syntax + if (result == std::string::npos) + throw EXCEPTION_WARNING("MA5 version '" + stamp + "' is not valid.", "", 0); + + // version + pythoninterface_version_ = stamp.substr(0, result); + if (pythoninterface_version_.find("\"") == 0) + pythoninterface_version_ = pythoninterface_version_.substr(1, std::string::npos); + if (pythoninterface_version_.size() >= 2) + if (pythoninterface_version_.find("\"") == (pythoninterface_version_.size() - 1)) + pythoninterface_version_ = pythoninterface_version_.substr(0, (pythoninterface_version_.size() - 1)); + + // date + pythoninterface_date_ = stamp.substr(result + 1, std::string::npos); + if (pythoninterface_date_.find("\"") == 0) + pythoninterface_date_ = pythoninterface_date_.substr(1, std::string::npos); + if (pythoninterface_date_.size() >= 2) + if (pythoninterface_date_.find("\"") == (pythoninterface_date_.size() - 1)) + pythoninterface_date_ = pythoninterface_date_.substr(0, (pythoninterface_date_.size() - 1)); + } + catch (const std::exception &e) + { + MANAGE_EXCEPTION(e); + } } // ----------------------------------------------------------------------------- @@ -108,86 +108,87 @@ void Configuration::DecodeMA5version(const std::string &option) // ----------------------------------------------------------------------------- MAbool Configuration::Initialize(MAint32 &argc, MAchar *argv[]) { - // Checking number of arguments - // <filelist> is compulsory - if (argc < 2) - { - ERROR << "number of arguments is incorrect." << endmsg; - PrintSyntax(); - return false; - } - - // Decoding arguments - for (MAuint32 i = 1; i < static_cast<MAuint32>(argc); i++) - { - // converting const characters into string - std::string argument = std::string(argv[i]); - Lower(argument); - - // safety : skip empty string - if (argument.size() == 0) - continue; - - // Is it an option? - if (argument.size() >= 2 && argument[0] == '-' && argument[1] == '-') + // Checking number of arguments + // <filelist> is compulsory + if (argc < 2) { - // check event - if (argument == "--check_event") - check_event_ = true; - - // weighted event - else if (argument == "--no_event_weight") - no_event_weight_ = true; - - // version - else if (argument.find("--ma5_version=") == 0) - DecodeMA5version(argument); - - // other = command line options - else - { - std::string arg = argv[i]; - MAuint32 loc = arg.find("="); - if (loc == 0 || loc > arg.length()) - { - ERROR << "option '" << argument << "' unknown." << endmsg; - PrintSyntax(); - return false; - } - std::string name = arg.substr(2, loc - 2); - std::string value = arg.substr(loc + 1, arg.length() - 1); - options_[name] = value; - } + ERROR << "number of arguments is incorrect." << endmsg; + PrintSyntax(); + return false; } - // It is not an option? So it is a list of samples - else + // Decoding arguments + for (MAuint32 i = 1; i < static_cast<MAuint32>(argc); i++) { - if (input_list_name_ == "" || input_list_name_ == std::string(argv[i])) - { - // Extracting the input list - input_list_name_ = std::string(argv[i]); - } - else - { - // only one list of samples is required - ERROR << "several list of samples have been declared: '" - << input_list_name_ << "' and '" << argv[i] - << "'. Only one is required." << endmsg; - return false; + // converting const characters into string + std::string argument = std::string(argv[i]); + Lower(argument); + + // safety : skip empty string + if (argument.size() == 0) + continue; + + // Is it an option? + if (argument.size() >= 2 && argument[0] == '-' && argument[1] == '-') + { + // check event + if (argument == "--check_event") + check_event_ = true; + + // weighted event + else if (argument == "--no_event_weight") + no_event_weight_ = true; + + // version + else if (argument.find("--ma5_version=") == 0) + DecodeMA5version(argument); + + // other = command line options + else + { + std::string arg = argv[i]; + MAuint32 loc = arg.find("="); + if (loc == 0 || loc > arg.length()) + { + ERROR << "option '" << argument << "' unknown." << endmsg; + PrintSyntax(); + return false; + } + std::string name = arg.substr(2, loc - 2); + std::string value = arg.substr(loc + 1, arg.length() - 1); + options_[name] = value; + } + } + + // It is not an option? So it is a list of samples + else + { + if (input_list_name_ == "" || input_list_name_ == std::string(argv[i])) + { + // Extracting the input list + input_list_name_ = std::string(argv[i]); + } + else + { + // only one list of samples is required + ERROR << "several list of samples have been declared: '" + << input_list_name_ << "' and '" << argv[i] + << "'. Only one is required." << endmsg; + return false; + } + } + + // Check that the input list is supplied + if (input_list_name_ == "") + { + ERROR << "no list of samples has been provided." << endmsg; + PrintSyntax(); + return false; + } + + // Ok + return true; } - } - - // Check that the input list is supplied - if (input_list_name_ == "") - { - ERROR << "no list of samples has been provided." << endmsg; - PrintSyntax(); - return false; - } - - // Ok - return true; } // ----------------------------------------------------------------------------- @@ -195,28 +196,29 @@ MAbool Configuration::Initialize(MAint32 &argc, MAchar *argv[]) // ----------------------------------------------------------------------------- void Configuration::Display() { - INFO << " - version: " << sampleanalyzer_version_ << " (" << sampleanalyzer_date_ << ") "; - if ((sampleanalyzer_version_ != pythoninterface_version_ && pythoninterface_version_ != "") || - (sampleanalyzer_date_ != pythoninterface_date_ && pythoninterface_version_ != "")) - INFO << "[ python interface version: " << pythoninterface_version_ - << " (" << pythoninterface_date_ << ") ]"; - INFO << endmsg; - - INFO << " - general: "; - - // Is there option ? - if (!check_event_ && !no_event_weight_) - { - INFO << "everything is default." << endmsg; - return; - } - else - { + INFO << " - version: " << sampleanalyzer_version_ << " (" << sampleanalyzer_date_ << ") "; + if ((sampleanalyzer_version_ != pythoninterface_version_ && pythoninterface_version_ != "") || + (sampleanalyzer_date_ != pythoninterface_date_ && pythoninterface_version_ != "")) + INFO << "[ python interface version: " << pythoninterface_version_ + << " (" << pythoninterface_date_ << ") ]"; INFO << endmsg; - // Displaying options - if (check_event_) - INFO << " -> checking the event file format." << endmsg; - if (no_event_weight_) - INFO << " -> event weights are not used." << endmsg; + INFO << " - general: "; + + // Is there option ? + if (!check_event_ && !no_event_weight_) + { + INFO << "everything is default." << endmsg; + return; + } + else + { + INFO << endmsg; + + // Displaying options + if (check_event_) + INFO << " -> checking the event file format." << endmsg; + if (no_event_weight_) + INFO << " -> event weights are not used." << endmsg; + } } From 255643e7350438f5b7f5e446ac2cf698d10b00d8 Mon Sep 17 00:00:00 2001 From: "Jack Y. Araz" <jackaraz@gmail.com> Date: Thu, 11 Jan 2024 04:55:33 -0500 Subject: [PATCH 089/107] update version --- bin/ma5 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/ma5 b/bin/ma5 index bb2d4739..725bcaaa 100755 --- a/bin/ma5 +++ b/bin/ma5 @@ -74,8 +74,8 @@ sys.path.insert(0, servicedir) # Release version # Do not touch it !!!!! -version = "2.0.8" -date = "2023/05/31" +version = "2.0.9" +date = "2024/01/11" # Loading the MadAnalysis session import madanalysis.core.launcher From 55e6e44af92d46a120bc98ed5aa21fb1a36aada2 Mon Sep 17 00:00:00 2001 From: "Jack Y. Araz" <jackaraz@gmail.com> Date: Thu, 11 Jan 2024 04:56:03 -0500 Subject: [PATCH 090/107] multiple fixes * update version * bugfix probably occured during branch merging --- .../Commons/Base/Configuration.cpp | 306 +++++++++--------- 1 file changed, 154 insertions(+), 152 deletions(-) diff --git a/tools/SampleAnalyzer/Commons/Base/Configuration.cpp b/tools/SampleAnalyzer/Commons/Base/Configuration.cpp index cf563e41..61ba16f9 100644 --- a/tools/SampleAnalyzer/Commons/Base/Configuration.cpp +++ b/tools/SampleAnalyzer/Commons/Base/Configuration.cpp @@ -31,153 +31,155 @@ #include "SampleAnalyzer/Commons/Service/LogService.h" #include "SampleAnalyzer/Commons/Service/ExceptionService.h" -using namespace MA5; - -// ----------------------------------------------------------------------------- -// Initializing static data members -// ----------------------------------------------------------------------------- -// DO NOT TOUCH THESE LINES -const std::string Configuration::sampleanalyzer_version_ = "2.0.8"; -const std::string Configuration::sampleanalyzer_date_ = "2023/05/31"; -// DO NOT TOUCH THESE LINES - -// ----------------------------------------------------------------------------- -// PrintSyntax -// ----------------------------------------------------------------------------- -void Configuration::PrintSyntax() +namespace MA5 { - INFO << endmsg; - INFO << "Syntax : SampleAnalyzer [option] <filelist>" << endmsg; - INFO << " with <filelist> = txt file containing all sample file names" << endmsg; - INFO << " with [option] = " << endmsg; - INFO << " --check_event : check the compliance of the event file" << endmsg; - INFO << " --no_event_weight : the event weights are not used" << endmsg; - INFO << " --ma5_version : returns the version of this release" << endmsg; - INFO << " Any aditional option for the analyzer can be given with the following syntax:" << endmsg; - INFO << " --<opt_name>=<val>" << endmsg; - INFO << endmsg; -} - -// ----------------------------------------------------------------------------- -// Lower -// ----------------------------------------------------------------------------- -void Configuration::Lower(std::string &word) -{ - std::transform(word.begin(), word.end(), - word.begin(), - (MAint32(*)(MAint32))std::tolower); -} - -// ----------------------------------------------------------------------------- -// DecodeMA5version -// ----------------------------------------------------------------------------- -void Configuration::DecodeMA5version(const std::string &option) -{ - std::string stamp = option.substr(14, std::string::npos); - std::size_t result = stamp.find(";"); - try - { - // check the syntax - if (result == std::string::npos) - throw EXCEPTION_WARNING("MA5 version '" + stamp + "' is not valid.", "", 0); - - // version - pythoninterface_version_ = stamp.substr(0, result); - if (pythoninterface_version_.find("\"") == 0) - pythoninterface_version_ = pythoninterface_version_.substr(1, std::string::npos); - if (pythoninterface_version_.size() >= 2) - if (pythoninterface_version_.find("\"") == (pythoninterface_version_.size() - 1)) - pythoninterface_version_ = pythoninterface_version_.substr(0, (pythoninterface_version_.size() - 1)); - - // date - pythoninterface_date_ = stamp.substr(result + 1, std::string::npos); - if (pythoninterface_date_.find("\"") == 0) - pythoninterface_date_ = pythoninterface_date_.substr(1, std::string::npos); - if (pythoninterface_date_.size() >= 2) - if (pythoninterface_date_.find("\"") == (pythoninterface_date_.size() - 1)) - pythoninterface_date_ = pythoninterface_date_.substr(0, (pythoninterface_date_.size() - 1)); - } - catch (const std::exception &e) + + // ----------------------------------------------------------------------------- + // Initializing static data members + // ----------------------------------------------------------------------------- + // DO NOT TOUCH THESE LINES + const std::string Configuration::sampleanalyzer_version_ = "2.0.9"; + const std::string Configuration::sampleanalyzer_date_ = "2024/01/11"; + // DO NOT TOUCH THESE LINES + + // ----------------------------------------------------------------------------- + // PrintSyntax + // ----------------------------------------------------------------------------- + void Configuration::PrintSyntax() { - MANAGE_EXCEPTION(e); + INFO << endmsg; + INFO << "Syntax : SampleAnalyzer [option] <filelist>" << endmsg; + INFO << " with <filelist> = txt file containing all sample file names" << endmsg; + INFO << " with [option] = " << endmsg; + INFO << " --check_event : check the compliance of the event file" << endmsg; + INFO << " --no_event_weight : the event weights are not used" << endmsg; + INFO << " --ma5_version : returns the version of this release" << endmsg; + INFO << " Any aditional option for the analyzer can be given with the following syntax:" << endmsg; + INFO << " --<opt_name>=<val>" << endmsg; + INFO << endmsg; } -} -// ----------------------------------------------------------------------------- -// Initialize -// ----------------------------------------------------------------------------- -MAbool Configuration::Initialize(MAint32 &argc, MAchar *argv[]) -{ - // Checking number of arguments - // <filelist> is compulsory - if (argc < 2) + // ----------------------------------------------------------------------------- + // Lower + // ----------------------------------------------------------------------------- + void Configuration::Lower(std::string &word) { - ERROR << "number of arguments is incorrect." << endmsg; - PrintSyntax(); - return false; + std::transform(word.begin(), word.end(), + word.begin(), + (MAint32(*)(MAint32))std::tolower); } - // Decoding arguments - for (MAuint32 i = 1; i < static_cast<MAuint32>(argc); i++) + // ----------------------------------------------------------------------------- + // DecodeMA5version + // ----------------------------------------------------------------------------- + void Configuration::DecodeMA5version(const std::string &option) { - // converting const characters into string - std::string argument = std::string(argv[i]); - Lower(argument); + std::string stamp = option.substr(14, std::string::npos); + std::size_t result = stamp.find(";"); + try + { + // check the syntax + if (result == std::string::npos) + throw EXCEPTION_WARNING("MA5 version '" + stamp + "' is not valid.", "", 0); - // safety : skip empty string - if (argument.size() == 0) - continue; + // version + pythoninterface_version_ = stamp.substr(0, result); + if (pythoninterface_version_.find("\"") == 0) + pythoninterface_version_ = pythoninterface_version_.substr(1, std::string::npos); + if (pythoninterface_version_.size() >= 2) + if (pythoninterface_version_.find("\"") == (pythoninterface_version_.size() - 1)) + pythoninterface_version_ = pythoninterface_version_.substr(0, (pythoninterface_version_.size() - 1)); + + // date + pythoninterface_date_ = stamp.substr(result + 1, std::string::npos); + if (pythoninterface_date_.find("\"") == 0) + pythoninterface_date_ = pythoninterface_date_.substr(1, std::string::npos); + if (pythoninterface_date_.size() >= 2) + if (pythoninterface_date_.find("\"") == (pythoninterface_date_.size() - 1)) + pythoninterface_date_ = pythoninterface_date_.substr(0, (pythoninterface_date_.size() - 1)); + } + catch (const std::exception &e) + { + MANAGE_EXCEPTION(e); + } + } - // Is it an option? - if (argument.size() >= 2 && argument[0] == '-' && argument[1] == '-') + // ----------------------------------------------------------------------------- + // Initialize + // ----------------------------------------------------------------------------- + MAbool Configuration::Initialize(MAint32 &argc, MAchar *argv[]) + { + // Checking number of arguments + // <filelist> is compulsory + if (argc < 2) { - // check event - if (argument == "--check_event") - check_event_ = true; + ERROR << "number of arguments is incorrect." << endmsg; + PrintSyntax(); + return false; + } - // weighted event - else if (argument == "--no_event_weight") - no_event_weight_ = true; + // Decoding arguments + for (MAuint32 i = 1; i < static_cast<MAuint32>(argc); i++) + { + // converting const characters into string + std::string argument = std::string(argv[i]); + Lower(argument); + INFO << argument << endmsg; - // version - else if (argument.find("--ma5_version=") == 0) - DecodeMA5version(argument); + // safety : skip empty string + if (argument.size() == 0) + continue; - // other = command line options - else + // Is it an option? + if (argument.size() >= 2 && argument[0] == '-' && argument[1] == '-') { - std::string arg = argv[i]; - MAuint32 loc = arg.find("="); - if (loc == 0 || loc > arg.length()) + // check event + if (argument == "--check_event") + check_event_ = true; + + // weighted event + else if (argument == "--no_event_weight") + no_event_weight_ = true; + + // version + else if (argument.find("--ma5_version=") == 0) + DecodeMA5version(argument); + + // other = command line options + else { - ERROR << "option '" << argument << "' unknown." << endmsg; - PrintSyntax(); - return false; + std::string arg = argv[i]; + MAuint32 loc = arg.find("="); + if (loc == 0 || loc > arg.length()) + { + ERROR << "option '" << argument << "' unknown." << endmsg; + PrintSyntax(); + return false; + } + std::string name = arg.substr(2, loc - 2); + std::string value = arg.substr(loc + 1, arg.length() - 1); + options_[name] = value; } - std::string name = arg.substr(2, loc - 2); - std::string value = arg.substr(loc + 1, arg.length() - 1); - options_[name] = value; } - } - // It is not an option? So it is a list of samples - else - { - if (input_list_name_ == "" || input_list_name_ == std::string(argv[i])) - { - // Extracting the input list - input_list_name_ = std::string(argv[i]); - } + // It is not an option? So it is a list of samples else { - // only one list of samples is required - ERROR << "several list of samples have been declared: '" - << input_list_name_ << "' and '" << argv[i] - << "'. Only one is required." << endmsg; - return false; + if (input_list_name_ == "" || input_list_name_ == std::string(argv[i])) + { + // Extracting the input list + input_list_name_ = std::string(argv[i]); + } + else + { + // only one list of samples is required + ERROR << "several list of samples have been declared: '" + << input_list_name_ << "' and '" << argv[i] + << "'. Only one is required." << endmsg; + return false; + } } } - // Check that the input list is supplied if (input_list_name_ == "") { @@ -189,36 +191,36 @@ MAbool Configuration::Initialize(MAint32 &argc, MAchar *argv[]) // Ok return true; } -} -// ----------------------------------------------------------------------------- -// Display -// ----------------------------------------------------------------------------- -void Configuration::Display() -{ - INFO << " - version: " << sampleanalyzer_version_ << " (" << sampleanalyzer_date_ << ") "; - if ((sampleanalyzer_version_ != pythoninterface_version_ && pythoninterface_version_ != "") || - (sampleanalyzer_date_ != pythoninterface_date_ && pythoninterface_version_ != "")) - INFO << "[ python interface version: " << pythoninterface_version_ - << " (" << pythoninterface_date_ << ") ]"; - INFO << endmsg; - - INFO << " - general: "; - - // Is there option ? - if (!check_event_ && !no_event_weight_) - { - INFO << "everything is default." << endmsg; - return; - } - else + // ----------------------------------------------------------------------------- + // Display + // ----------------------------------------------------------------------------- + void Configuration::Display() { + INFO << " - version: " << sampleanalyzer_version_ << " (" << sampleanalyzer_date_ << ") "; + if ((sampleanalyzer_version_ != pythoninterface_version_ && pythoninterface_version_ != "") || + (sampleanalyzer_date_ != pythoninterface_date_ && pythoninterface_version_ != "")) + INFO << "[ python interface version: " << pythoninterface_version_ + << " (" << pythoninterface_date_ << ") ]"; INFO << endmsg; - // Displaying options - if (check_event_) - INFO << " -> checking the event file format." << endmsg; - if (no_event_weight_) - INFO << " -> event weights are not used." << endmsg; + INFO << " - general: "; + + // Is there option ? + if (!check_event_ && !no_event_weight_) + { + INFO << "everything is default." << endmsg; + return; + } + else + { + INFO << endmsg; + + // Displaying options + if (check_event_) + INFO << " -> checking the event file format." << endmsg; + if (no_event_weight_) + INFO << " -> event weights are not used." << endmsg; + } } -} +} \ No newline at end of file From b603745a81d2e2773634bd8cfa5e48db67c96e34 Mon Sep 17 00:00:00 2001 From: "Jack Y. Araz" <jackaraz@gmail.com> Date: Thu, 11 Jan 2024 10:25:23 -0500 Subject: [PATCH 091/107] add lhapdf info --- madanalysis/core/main.py | 11 +++--- madanalysis/multiweight/lhapdf_info.py | 46 ++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 5 deletions(-) create mode 100644 madanalysis/multiweight/lhapdf_info.py diff --git a/madanalysis/core/main.py b/madanalysis/core/main.py index 09ae3c84..91f58bcb 100644 --- a/madanalysis/core/main.py +++ b/madanalysis/core/main.py @@ -37,7 +37,6 @@ from madanalysis.IOinterface.madgraph_interface import MadGraphInterface from madanalysis.enumeration.ma5_running_type import MA5RunningType from madanalysis.enumeration.stacking_method_type import StackingMethodType -from madanalysis.enumeration.uncertainty_type import UncertaintyType from madanalysis.enumeration.normalize_type import NormalizeType from madanalysis.enumeration.graphic_render_type import GraphicRenderType from madanalysis.observable.observable_manager import ObservableManager @@ -48,10 +47,8 @@ from madanalysis.configuration.merging_configuration import MergingConfiguration from string_tools import StringTools from madanalysis.system.checkup import CheckUp -import logging -import os -import sys -import platform +from madanalysis.multiweight.lhapdf_info import LHAPDFInfo +import logging, os, sys from six.moves import range import traceback as tb @@ -93,6 +90,7 @@ def __init__(self): self.logger = logging.getLogger('MA5') self.redirectSAlogger = False self.random_seed = None + self.lhapdf_info: LHAPDFInfo = None def ResetParameters(self): @@ -449,6 +447,9 @@ def CheckConfig(self,debug=False): if not checkup.CheckArchitecture(): return False + self.lhapdf_info = LHAPDFInfo( + os.path.join(self.archi_info.ma5dir, "madanalysis/input/LHAPDF.txt") + ) if not checkup.ReadUserOptions(): return False if not checkup.CheckSessionInfo(): diff --git a/madanalysis/multiweight/lhapdf_info.py b/madanalysis/multiweight/lhapdf_info.py new file mode 100644 index 00000000..476c4b6e --- /dev/null +++ b/madanalysis/multiweight/lhapdf_info.py @@ -0,0 +1,46 @@ +"""This file includes the storage of LHAPDF data from madanalysis/input/LHAPDF.txt""" +from dataclasses import dataclass +from typing import Text + + +@dataclass +class PDF: + """Stores information about PDF set""" + + pdfid: int + name: Text + nmembers: int + # this class should be extended inthe future about information on + # which method to be used for the pdfset i.e. Replicas or Eigenvectors + + def __iter__(self): + yield from (self.pdfid + idx for idx in range(0, self.nmembers)) + + +class LHAPDFInfo(dict): + """ + Storage for LHAPDF information + + Args: + file_path (``Text``): hard coded information abour pdfsets + current file structure is comma separated 3 column + pdfid,name,members + """ + + __slots__ = ["lhapdf"] + + def __init__(self, file_path: Text): + lhapdf = {} + with open(file_path, "r") as f: + for line in f.readlines()[1:]: + current = line.split(",") + lhapdf.update( + { + int(current[0]): PDF( + pdfid=int(current[0]), + name=current[1], + nmembers=int(current[2].replace("\n", "")), + ) + } + ) + super().__init__(lhapdf) From 534099ed71429ea7a7acc60d135fd35be2520f85 Mon Sep 17 00:00:00 2001 From: "Jack Y. Araz" <jackaraz@gmail.com> Date: Thu, 11 Jan 2024 10:26:48 -0500 Subject: [PATCH 092/107] improvement * add control for multiple pdf sets (not available atm) * minor changes for retreiving items --- .../configuration/weight_configuration.py | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/madanalysis/configuration/weight_configuration.py b/madanalysis/configuration/weight_configuration.py index 3df9fabf..de993795 100644 --- a/madanalysis/configuration/weight_configuration.py +++ b/madanalysis/configuration/weight_configuration.py @@ -22,9 +22,10 @@ ################################################################################ +import copy +import logging from dataclasses import dataclass, field from typing import Any, Dict, List, Text, Tuple, Union -import copy import numpy as np @@ -177,8 +178,9 @@ def from_dict(self, data: List[Dict[Text, Any]]) -> None: for dat in data: self.append(dat["name"], dat["loc"]) - def nominal(self, scale_choice: int, central_pdfs: np.array) -> Weight: + def nominal(self, scale_choice: int, central_pdfs) -> Weight: """Get nominal weight""" + weight_set = [] if self._nominal is None: for w in self: if any([not x is None for x in [w.aux, w.alphas]]): @@ -187,10 +189,14 @@ def nominal(self, scale_choice: int, central_pdfs: np.array) -> Weight: continue if not w.pdfset in central_pdfs: continue - # !WARNING: this will fail if there are multiple pdfsets that are used - # ! this search will only return the first one - self._nominal = w - return self._nominal + weight_set.append(w) + if len(weight_set) > 1: + logging.getLogger("MA5").warning( + "Variations on multi-pdf sets are not supported at the moment." + f"{central_pdfs[weight_set[0].pdfset].name} will be used instead" + ) + + return weight_set[0] def group_for(self, group: Text) -> Dict: """Create a group""" @@ -214,7 +220,7 @@ def pdfset(self, pdfid: Union[int, List[int]]) -> List[Weight]: """retrieve weights corresponding to one pdf set""" if isinstance(pdfid, int): return WeightCollection([w for w in self if w.pdfset == pdfid]) - return WeightCollection([w for w in self if w.pdfset in pdfid]) + return WeightCollection([self.get(pdfset=pdf) for pdf in pdfid]) def get(self, **kwargs) -> List[Weight]: if len(kwargs) == 0: @@ -228,7 +234,7 @@ def get(self, **kwargs) -> List[Weight]: if getattr(weight, key) != kwargs.get(key): add = False break - if add: + if add and weight not in collection: collection.append(weight) return WeightCollection(collection) @@ -330,7 +336,7 @@ def has_dyn_scale(self, scale: int) -> bool: @property def loc(self) -> List[int]: """retrieve the locations of the weights""" - return np.unique([w.loc for w in self]) + return np.unique([w.loc for w in self]).tolist() def __iadd__(self, other): if isinstance(other, WeightCollection): From fbb718578ba0fa993d170c58c86de7378705f888 Mon Sep 17 00:00:00 2001 From: "Jack Y. Araz" <jackaraz@gmail.com> Date: Thu, 11 Jan 2024 10:27:09 -0500 Subject: [PATCH 093/107] replace lhapdf info --- madanalysis/layout/plotflow_for_dataset.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/madanalysis/layout/plotflow_for_dataset.py b/madanalysis/layout/plotflow_for_dataset.py index 214b7a50..e1d132cf 100644 --- a/madanalysis/layout/plotflow_for_dataset.py +++ b/madanalysis/layout/plotflow_for_dataset.py @@ -89,11 +89,6 @@ def ComputeScale(self): iplot = 0 - with open( - os.path.join(self.main.archi_info.ma5dir, "madanalysis/input/LHAPDF.txt"), "r" - ) as f: - pdf_list = [int(line.split(",")[0]) for line in f.readlines()[1:]] - # Loop over plot for iabshisto in range(0, len(self.main.selection)): @@ -108,7 +103,7 @@ def ComputeScale(self): self.multiweight_histos[iplot].set_central_weight_loc( scale_choice=self.dataset.dynamic_scale_choice, n_point_scale_variation=self.dataset.n_point_scale_variation, - central_pdfs=pdf_list, + central_pdfs=self.main.lhapdf_info, ) # Case 1: Normalization to ONE From bac598e3eae0d1ca22dde7652aac9b7aab2b7b59 Mon Sep 17 00:00:00 2001 From: "Jack Y. Araz" <jackaraz@gmail.com> Date: Thu, 11 Jan 2024 10:27:46 -0500 Subject: [PATCH 094/107] sort pdfset, improve eff --- madanalysis/multiweight/histogram.py | 51 ++++++++++++++-------------- 1 file changed, 25 insertions(+), 26 deletions(-) diff --git a/madanalysis/multiweight/histogram.py b/madanalysis/multiweight/histogram.py index 82c810a7..a229caf3 100644 --- a/madanalysis/multiweight/histogram.py +++ b/madanalysis/multiweight/histogram.py @@ -10,6 +10,8 @@ from madanalysis.configuration.weight_configuration import WeightCollection +from .lhapdf_info import PDF, LHAPDFInfo + _nevt = namedtuple("events", ["positive", "negative"]) # pylint: disable=C0103 @@ -202,6 +204,7 @@ def __init__( self.central_idx = 0 # Central weight location self.nominal_weight = None + self.pdf: PDF = None self.dynamic_scale_choice = None self.n_point_scale_variation = None @@ -246,10 +249,11 @@ def __repr__(self): ) def set_central_weight_loc( - self, scale_choice: int, n_point_scale_variation: int, central_pdfs: List[int] + self, scale_choice: int, n_point_scale_variation: int, central_pdfs: LHAPDFInfo ) -> None: self.nominal_weight = self.weight_collection.nominal(scale_choice, central_pdfs) self.central_idx = self.nominal_weight.loc + self.pdf = central_pdfs[self.nominal_weight.pdfset] self.dynamic_scale_choice = scale_choice self.n_point_scale_variation = n_point_scale_variation print("Central PDF loc:", self.central_idx) @@ -485,40 +489,35 @@ def pdf_uncertainties(self) -> Tuple[np.ndarray, np.ndarray]: if not self.has_pdf_unc: return [self.weights * self.scale] * 2 - method = "replicas" # "eigenvector" # + method = "replicas" # "eigenvector" # bins = self.all_scaled_weights - pdfids = self.weight_collection.pdfsets - pdfids.pop(pdfids.index(self.nominal_weight.pdfset)) + pdf_locs = [] + for idx, pdfid in enumerate(self.pdf): + if idx != 0: + pdf_locs.append( + *self.weight_collection.get(pdfset=pdfid, muf=1.0, mur=1.0).loc + ) # Replicas if method == "replicas": # 2202.13416 eq 3.2 - pdf_locs = ( - WeightCollection([self.nominal_weight]) - + self.weight_collection.pdfset(pdfids) - ).loc - mean_bin_value = np.array( - [np.mean([bn[loc] for loc in pdf_locs]) for bn in bins] - ) - - new_bins = np.array( - [ - np.sqrt( - sum((bn[loc] - mean_val) ** 2 for loc in pdf_locs) - / (len(pdf_locs) - 1) - ) - for bn, mean_val in zip(bins, mean_bin_value) - ] - ) + pdf_locs.insert(0, self.nominal_weight.loc) + new_bins = np.zeros(self.description.nbins) + for idx, bn in enumerate(bins): + mean_bin_value = np.mean([bn[loc] for loc in pdf_locs]) + + new_bins[idx] = np.sqrt( + sum((bn[loc] - mean_bin_value) ** 2 for loc in pdf_locs) + / (len(pdf_locs) - 1) + ) return new_bins, new_bins # Eigenvectors # 2202.13416 eq 3.1 - pdf_locs = self.weight_collection.pdfset(pdfids).loc - upper, lower = [], [] - for bn, mean_val in zip(bins, self.weights * self.scale): + upper, lower = np.zeros(self.description.nbins), np.zeros(self.description.nbins) + for ibn, (bn, mean_val) in enumerate(zip(bins, self.weights * self.scale)): current_upper_bin, current_lower_bin = [], [] for idx in range(0, len(pdf_locs), 2): # upper limit @@ -544,8 +543,8 @@ def pdf_uncertainties(self) -> Tuple[np.ndarray, np.ndarray]: ) ) ) - upper.append(np.sqrt(sum(current_upper_bin))) - lower.append(np.sqrt(sum(current_lower_bin))) + upper[ibn] = np.sqrt(sum(current_upper_bin)) + lower[ibn] = np.sqrt(sum(current_lower_bin)) return np.array(lower), np.array(upper) From 777622a8a5b6d9b21d84a3a9c0e1c71288e9b6bf Mon Sep 17 00:00:00 2001 From: "Jack Y. Araz" <jackaraz@gmail.com> Date: Mon, 15 Jan 2024 11:07:45 -0500 Subject: [PATCH 095/107] add protection against mistakes in files --- .../configuration/weight_configuration.py | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/madanalysis/configuration/weight_configuration.py b/madanalysis/configuration/weight_configuration.py index de993795..6b4c9be5 100644 --- a/madanalysis/configuration/weight_configuration.py +++ b/madanalysis/configuration/weight_configuration.py @@ -51,6 +51,33 @@ def __eq__(self, other): def __post_init__(self) -> None: self.name = self.name.replace("DYN_SCALE", "DYNSCALE") + + # Check the name to make sure its written correctly + # This is due to the HEPMC files that are written terribly + # wrong so we need to correct them. Some of the files includes + # AUX tag for every weight definition. If the name is AUX_XXX + # where XXX is integer, that is a true aux, if not remove the + # AUX tag. + portions = self.name.split("_") + if portions[0].upper() == "AUX": + if len(portions) > 2: + # This is not a true AUX remove the AUX tag + self.name = "_".join(portions[1:]) + elif len(portions) == 2: + try: + tmp = int(portions[1]) + except ValueError as err: + logging.getLogger("MA5").error( + f"Unknown weight definition: {self.name}" + ) + logging.getLogger("MA5").debug(err) + self.name = "_".join(portions[1:]) + else: + logging.getLogger("MA5").error(f"Unknown weight definition: {self.name}") + logging.getLogger("MA5").error( + "This weight definition will be considered as auxiliary." + ) + sectors = self.name.split("_") # PYTHIA NOMINAL WEIGHT From 9a793702330868681f14274a1caa7a67bf7ed904 Mon Sep 17 00:00:00 2001 From: "Jack Y. Araz" <jackaraz@gmail.com> Date: Wed, 17 Jan 2024 09:21:43 -0500 Subject: [PATCH 096/107] update comment --- madanalysis/configuration/weight_configuration.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/madanalysis/configuration/weight_configuration.py b/madanalysis/configuration/weight_configuration.py index 6b4c9be5..6ae4b76a 100644 --- a/madanalysis/configuration/weight_configuration.py +++ b/madanalysis/configuration/weight_configuration.py @@ -52,12 +52,13 @@ def __eq__(self, other): def __post_init__(self) -> None: self.name = self.name.replace("DYN_SCALE", "DYNSCALE") - # Check the name to make sure its written correctly - # This is due to the HEPMC files that are written terribly - # wrong so we need to correct them. Some of the files includes - # AUX tag for every weight definition. If the name is AUX_XXX - # where XXX is integer, that is a true aux, if not remove the - # AUX tag. + # Check the weight name and make sure its written according + # to standard conventions, and update it if necessary. This is + # needed due to terribly written HEPMC files by MadSTR. + # These files include an `AUX` tag for every weight name. + # Therefore, if the weight name is `AUX_XXX`with XXX being + # an integer, then we have a true `AUX` weight. Otherwise, we + # remove the `AUX` string from the weight name. portions = self.name.split("_") if portions[0].upper() == "AUX": if len(portions) > 2: From 3de9da1f1d1f96ed1b156036f54da367ce7759c8 Mon Sep 17 00:00:00 2001 From: BFuks <fuks@lpthe.jussieu.fr> Date: Fri, 19 Jan 2024 13:53:56 +0200 Subject: [PATCH 097/107] Small extra fix for MadSTR-generated events --- madanalysis/configuration/weight_configuration.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/madanalysis/configuration/weight_configuration.py b/madanalysis/configuration/weight_configuration.py index 6ae4b76a..602b9550 100644 --- a/madanalysis/configuration/weight_configuration.py +++ b/madanalysis/configuration/weight_configuration.py @@ -87,6 +87,7 @@ def __post_init__(self) -> None: return for sector in sectors: + print(sectors) if "AUX" in sector: self._aux = int(sectors[1]) break @@ -98,9 +99,15 @@ def __post_init__(self) -> None: elif "DYNSCALE" in sector: self._dyn_scale = int(sector.split("=")[1]) elif "MUF" in sector: - self._muf = float(sector.split("=")[1]) + if not '=' in sector: + self._muf = float(sector.replace('MUF', 'MUF=').split("=")[1]) + else: + self._muf = float(sector.split("=")[1]) elif "MUR" in sector: - self._mur = float(sector.split("=")[1]) + if not '=' in sector: + self._mur = float(sector.replace('MUR', 'MUR=').split("=")[1]) + else: + self._mur = float(sector.split("=")[1]) elif "PDF" in sector: self._pdf = int(sector.split("=")[1]) elif "ALPSFACT" in sector: From 354307b87407f4a0030e7b8fe46b0f94e0f7681d Mon Sep 17 00:00:00 2001 From: BFuks <fuks@lpthe.jussieu.fr> Date: Fri, 19 Jan 2024 14:04:28 +0200 Subject: [PATCH 098/107] Small extra fix for MadSTR-generated events (part 2) --- madanalysis/configuration/weight_configuration.py | 1 - 1 file changed, 1 deletion(-) diff --git a/madanalysis/configuration/weight_configuration.py b/madanalysis/configuration/weight_configuration.py index 602b9550..cf71d12f 100644 --- a/madanalysis/configuration/weight_configuration.py +++ b/madanalysis/configuration/weight_configuration.py @@ -87,7 +87,6 @@ def __post_init__(self) -> None: return for sector in sectors: - print(sectors) if "AUX" in sector: self._aux = int(sectors[1]) break From 5a77e468ea2709507da3cc0363eabac826213353 Mon Sep 17 00:00:00 2001 From: "Jack Y. Araz" <jackaraz@gmail.com> Date: Wed, 24 Jan 2024 09:21:03 -0500 Subject: [PATCH 099/107] typo fix --- madanalysis/configuration/weight_configuration.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/madanalysis/configuration/weight_configuration.py b/madanalysis/configuration/weight_configuration.py index cf71d12f..dc303c95 100644 --- a/madanalysis/configuration/weight_configuration.py +++ b/madanalysis/configuration/weight_configuration.py @@ -55,7 +55,7 @@ def __post_init__(self) -> None: # Check the weight name and make sure its written according # to standard conventions, and update it if necessary. This is # needed due to terribly written HEPMC files by MadSTR. - # These files include an `AUX` tag for every weight name. + # These files include an `AUX` tag for every weight name. # Therefore, if the weight name is `AUX_XXX`with XXX being # an integer, then we have a true `AUX` weight. Otherwise, we # remove the `AUX` string from the weight name. @@ -83,7 +83,7 @@ def __post_init__(self) -> None: # PYTHIA NOMINAL WEIGHT # -> note: to ignore, we need to use the MG5 nominal weight - if self.name is "Weight": + if self.name == "Weight": return for sector in sectors: @@ -98,13 +98,13 @@ def __post_init__(self) -> None: elif "DYNSCALE" in sector: self._dyn_scale = int(sector.split("=")[1]) elif "MUF" in sector: - if not '=' in sector: - self._muf = float(sector.replace('MUF', 'MUF=').split("=")[1]) + if not "=" in sector: + self._muf = float(sector.replace("MUF", "MUF=").split("=")[1]) else: self._muf = float(sector.split("=")[1]) elif "MUR" in sector: - if not '=' in sector: - self._mur = float(sector.replace('MUR', 'MUR=').split("=")[1]) + if not "=" in sector: + self._mur = float(sector.replace("MUR", "MUR=").split("=")[1]) else: self._mur = float(sector.split("=")[1]) elif "PDF" in sector: From e5e983d3ef31222898a450945e00feef6dc74552 Mon Sep 17 00:00:00 2001 From: "Jack Y. Araz" <jackaraz@gmail.com> Date: Wed, 24 Jan 2024 09:26:46 -0500 Subject: [PATCH 100/107] increase protection --- madanalysis/layout/plotflow_for_dataset.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/madanalysis/layout/plotflow_for_dataset.py b/madanalysis/layout/plotflow_for_dataset.py index e1d132cf..0804f8db 100644 --- a/madanalysis/layout/plotflow_for_dataset.py +++ b/madanalysis/layout/plotflow_for_dataset.py @@ -24,7 +24,7 @@ from __future__ import absolute_import -import copy, os +import copy from six.moves import range @@ -142,7 +142,7 @@ def ComputeScale(self): - self.histos[iplot].negative.integral ) multiweight_integral, multiweight_eff = 0, 0 - if len(self.multiweight_histos) != 0: + if len(self.multiweight_histos) != 0 and self.multiweight_histos[iplot]: multiweight_integral = self.multiweight_histos[iplot].integral # compute efficiency : Nevent / Ntotal @@ -203,13 +203,11 @@ def ComputeScale(self): ) else: multiweight_scale = 1 # no scale for empty plot - print("here no scale", multiweight_integral) # Setting the computing scale self.histos[iplot].scale = copy.copy(scale) - if len(self.multiweight_histos) != 0: + if len(self.multiweight_histos) != 0 and self.multiweight_histos[iplot]: self.multiweight_histos[iplot].scale = copy.copy(multiweight_scale) - print("scale", self.multiweight_histos[iplot].scale) # Incrementing counter iplot += 1 From 947730491cd23fbe940a7e1a308ba67b6927f753 Mon Sep 17 00:00:00 2001 From: BFuks <fuks@lpthe.jussieu.fr> Date: Wed, 7 Feb 2024 23:30:25 +0100 Subject: [PATCH 101/107] fix for multiweighted-events without PDF variation --- madanalysis/configuration/weight_configuration.py | 5 ++++- madanalysis/multiweight/histogram.py | 4 ++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/madanalysis/configuration/weight_configuration.py b/madanalysis/configuration/weight_configuration.py index dc303c95..0b3a3431 100644 --- a/madanalysis/configuration/weight_configuration.py +++ b/madanalysis/configuration/weight_configuration.py @@ -221,7 +221,7 @@ def nominal(self, scale_choice: int, central_pdfs) -> Weight: continue if w.muf != 1.0 or w.mur != 1.0 or w.dynamic_scale != scale_choice: continue - if not w.pdfset in central_pdfs: + if not w.pdfset in central_pdfs and w.pdfset!=None: continue weight_set.append(w) if len(weight_set) > 1: @@ -252,6 +252,9 @@ def group_for(self, group: Text) -> Dict: def pdfset(self, pdfid: Union[int, List[int]]) -> List[Weight]: """retrieve weights corresponding to one pdf set""" + if pdfid is None: + return WeightCollection([self.get(pdfset=None)]) + if isinstance(pdfid, int): return WeightCollection([w for w in self if w.pdfset == pdfid]) return WeightCollection([self.get(pdfset=pdf) for pdf in pdfid]) diff --git a/madanalysis/multiweight/histogram.py b/madanalysis/multiweight/histogram.py index a229caf3..f106a367 100644 --- a/madanalysis/multiweight/histogram.py +++ b/madanalysis/multiweight/histogram.py @@ -253,10 +253,10 @@ def set_central_weight_loc( ) -> None: self.nominal_weight = self.weight_collection.nominal(scale_choice, central_pdfs) self.central_idx = self.nominal_weight.loc - self.pdf = central_pdfs[self.nominal_weight.pdfset] + try: self.pdf = central_pdfs[self.nominal_weight.pdfset] + except: self.pdf = self.central_idx self.dynamic_scale_choice = scale_choice self.n_point_scale_variation = n_point_scale_variation - print("Central PDF loc:", self.central_idx) @property def is_consistent(self) -> bool: From 10df24dda7c58489cbb66d3c931f717594b2487d Mon Sep 17 00:00:00 2001 From: BFuks <fuks@lpthe.jussieu.fr> Date: Mon, 1 Jul 2024 13:48:09 +0200 Subject: [PATCH 102/107] Fixing resubmit bug + invisible state bug (thanks to L. Munoz) --- madanalysis/IOinterface/job_reader.py | 3 ++- madanalysis/IOinterface/job_writer.py | 7 +++---- madanalysis/configuration/weight_configuration.py | 5 +++-- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/madanalysis/IOinterface/job_reader.py b/madanalysis/IOinterface/job_reader.py index 3f1f7fb1..bbc41b14 100644 --- a/madanalysis/IOinterface/job_reader.py +++ b/madanalysis/IOinterface/job_reader.py @@ -334,7 +334,8 @@ def ExtractGeneral(self, dataset): ) # Read weights if globalTag.activated and weightTag.activated and len(words) == 2: - dataset.AddWeight(int(words[0]), words[1]) + if not words[1] in dataset.weight_collection.names: + dataset.AddWeight(int(words[0]), words[1]) # Information found ? if beginTag.Nactivated == 0 or beginTag.activated: diff --git a/madanalysis/IOinterface/job_writer.py b/madanalysis/IOinterface/job_writer.py index 96dada1d..a18d839e 100644 --- a/madanalysis/IOinterface/job_writer.py +++ b/madanalysis/IOinterface/job_writer.py @@ -550,16 +550,15 @@ def CreateMainFct(self,file,analysisName,outputName): file.write("\n\n /// Setting the random seed\n") file.write(f" RANDOM->SetSeed({self.main.random_seed});\n\n") - # Add default hadrons and invisible particles for Reco mode - if self.main.mode == MA5RunningType.RECO: + # Add default hadrons and invisible particles for RECO and HADRON mode + # The invisible container may also be changed when runnign the code in HADRON mode. + if self.main.mode in [MA5RunningType.RECO, MA5RunningType.HADRON]: file.write('\n // Initializing PhysicsService for MC\n') file.write(' PHYSICS->mcConfig().Reset();\n') file.write(' // definition of the multiparticle "hadronic"\n') file.write(' manager.AddDefaultHadronic();\n') file.write(' // definition of the multiparticle "invisible"\n') file.write(' manager.AddDefaultInvisible();\n') - # If expert mode is initiated without an SFS card "invisible" - # collection does not exist. Thus just initiate with default config. if self.main.multiparticles.Find("invisible"): for item in self.main.multiparticles.Get("invisible"): if item not in [-16, -14, -12, 12, 14, 16, 1000022, 1000039]: diff --git a/madanalysis/configuration/weight_configuration.py b/madanalysis/configuration/weight_configuration.py index 0b3a3431..068099a6 100644 --- a/madanalysis/configuration/weight_configuration.py +++ b/madanalysis/configuration/weight_configuration.py @@ -173,8 +173,9 @@ def __init__(self, collection: List[Weight] = None): def append(self, name: Text, idx: int) -> None: """Add weight into the collection""" - if name not in self.names: - self._collection.append(Weight(name=name, loc=idx)) + temp_weight = Weight(name=name, loc=idx) + if not temp_weight.name in self.names: + self._collection.append(temp_weight) def __repr__(self) -> Text: if len(self) < 5: From 923554cb5c016a08c06554ed1829905bd84d1485 Mon Sep 17 00:00:00 2001 From: BFuks <fuks@lpthe.jussieu.fr> Date: Mon, 1 Jul 2024 17:34:22 +0200 Subject: [PATCH 103/107] Adding multiweight support in the LHE writer --- madanalysis/core/main.py | 6 ++--- .../Process/Writer/LHEWriter.cpp | 23 ++++++++++++++++++- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/madanalysis/core/main.py b/madanalysis/core/main.py index 91f58bcb..e2445121 100644 --- a/madanalysis/core/main.py +++ b/madanalysis/core/main.py @@ -430,10 +430,10 @@ def AutoSetGraphicalRenderer(self): self.logger.debug('Function AutoSetGraphicalRenderer:') self.logger.debug(' - ROOT is there: '+str(self.session_info.has_root)) self.logger.debug(' - Matplotlib is there: '+str(self.session_info.has_matplotlib)) - if self.session_info.has_root: - self.graphic_render = GraphicRenderType.ROOT - elif self.session_info.has_matplotlib: + if self.session_info.has_matplotlib: self.graphic_render = GraphicRenderType.MATPLOTLIB + elif self.session_info.has_root: + self.graphic_render = GraphicRenderType.ROOT else: self.graphic_render = GraphicRenderType.NONE self.logger.info("Package used for graphical rendering: "+\ diff --git a/tools/SampleAnalyzer/Process/Writer/LHEWriter.cpp b/tools/SampleAnalyzer/Process/Writer/LHEWriter.cpp index 7c6f6e87..cf5bd8e4 100644 --- a/tools/SampleAnalyzer/Process/Writer/LHEWriter.cpp +++ b/tools/SampleAnalyzer/Process/Writer/LHEWriter.cpp @@ -233,6 +233,15 @@ MAbool LHEWriter::WriteHeader(const SampleFormat &mySample) << " " << cfg_->GetSampleAnalyzerVersion() << " </SampleAnalyzerVersion>" << std::endl; + // Weightnames if any + if (mySample.mc()->WeightNames().size()>0) + { + *output_ << "<initrwgt>" << std::endl; + for (const auto& pair : mySample.mc()->WeightNames()) + *output_ << " <weight id='" << pair.first << "'> " << pair.second << " </weight>" << std::endl; + *output_ << "</initrwgt>" << std::endl; + } + // Explanation about the LHE *output_ << "<FormatDescription>" << std::endl; *output_ << "#################################################################################" << std::endl; @@ -593,9 +602,21 @@ MAbool LHEWriter::WriteEvent(const EventFormat &myEvent, WriteMET(myEvent.rec()->MET(), particles.back()); } - // Event foot + // Particle list for (MAuint32 i = 0; i < particles.size(); i++) particles[i].Print(i + 1, output_); + + // Weights + if (mySample.mc()->WeightNames().size()>0) + { + *output_ << " <rwgt>" << std::endl; + for (const auto& pair : myEvent.mc()->weights().GetWeights()) + *output_ << " <wgt id='" << pair.first << "'> " << std::setw(18) << std::right + << FortranFormat_DoublePrecision(pair.second) << " </wgt>" << std::endl; + *output_ << " </rwgt>" << std::endl; + } + + // Footer *output_ << "</event>" << std::endl; return true; } From cef926e8e2ef11b82ebfb7cfb5ea0b0d4500951a Mon Sep 17 00:00:00 2001 From: BFuks <fuks@lpthe.jussieu.fr> Date: Tue, 2 Jul 2024 15:49:31 +0200 Subject: [PATCH 104/107] LHE files and multiweight support fixed/added --- .../Commons/DataFormat/WeightCollection.h | 7 ++-- .../Commons/Service/IsolationBase.cpp | 12 ------ .../Process/Reader/LHEReader.cpp | 38 ++++++++++++++++++- .../SampleAnalyzer/Process/Reader/LHEReader.h | 1 + .../Process/Writer/LHEWriter.cpp | 4 +- 5 files changed, 44 insertions(+), 18 deletions(-) diff --git a/tools/SampleAnalyzer/Commons/DataFormat/WeightCollection.h b/tools/SampleAnalyzer/Commons/DataFormat/WeightCollection.h index 60178da8..17e35e9f 100644 --- a/tools/SampleAnalyzer/Commons/DataFormat/WeightCollection.h +++ b/tools/SampleAnalyzer/Commons/DataFormat/WeightCollection.h @@ -102,9 +102,10 @@ namespace MA5 str << id; std::string idname; str >> idname; - throw EXCEPTION_WARNING("The Weight '" + idname + - "' is defined at twice. Redundant values are skipped.", - "", 0); + if (idname!="0") + throw EXCEPTION_WARNING("The Weight '" + idname + + "' is defined twice. Redundant values are skipped.", + "", 0); } } catch (const std::exception &e) diff --git a/tools/SampleAnalyzer/Commons/Service/IsolationBase.cpp b/tools/SampleAnalyzer/Commons/Service/IsolationBase.cpp index 9ea56f7d..fa74e2b6 100644 --- a/tools/SampleAnalyzer/Commons/Service/IsolationBase.cpp +++ b/tools/SampleAnalyzer/Commons/Service/IsolationBase.cpp @@ -39,7 +39,6 @@ MAfloat64 IsolationBase::sumPT(const RecLeptonFormat* part, MAfloat64 PTmin) const { MAfloat64 sumPT=0.; - MAuint32 counter=0; // Loop over the towers for (MAuint32 i=0;i<tracks.size();i++) @@ -57,7 +56,6 @@ MAfloat64 IsolationBase::sumPT(const RecLeptonFormat* part, // Sum sumPT += track.pt(); - counter++; } // return PT sum of tracks in the cone @@ -74,7 +72,6 @@ MAfloat64 IsolationBase::sumPT(const RecLeptonFormat* part, MAfloat64 PTmin) const { MAfloat64 sumPT=0.; - MAuint32 counter=0; // Loop over the tracks for (MAuint32 i=0;i<towers.size();i++) @@ -89,7 +86,6 @@ MAfloat64 IsolationBase::sumPT(const RecLeptonFormat* part, // Sum sumPT += tower.pt(); - counter++; } // return PT sum of towers in the cone @@ -106,7 +102,6 @@ MAfloat64 IsolationBase::sumPT(const RecLeptonFormat* part, MAfloat64 PTmin) const { MAfloat64 sumPT=0.; - MAuint32 counter=0; // Loop over the tracks for (MAuint32 i=0;i<towers.size();i++) @@ -121,7 +116,6 @@ MAfloat64 IsolationBase::sumPT(const RecLeptonFormat* part, // Sum sumPT += tower.pt(); - counter++; } // return PT sum of towers in the cone @@ -138,7 +132,6 @@ MAfloat64 IsolationBase::sumPT(const RecPhotonFormat* part, MAfloat64 PTmin) const { MAfloat64 sumPT=0.; - MAuint32 counter=0; // Loop over the towers for (MAuint32 i=0;i<tracks.size();i++) @@ -153,7 +146,6 @@ MAfloat64 IsolationBase::sumPT(const RecPhotonFormat* part, // Sum sumPT += track.pt(); - counter++; } // return PT sum of tracks in the cone @@ -170,7 +162,6 @@ MAfloat64 IsolationBase::sumPT(const RecPhotonFormat* part, MAfloat64 PTmin) const { MAfloat64 sumPT=0.; - MAuint32 counter=0; // Loop over the tracks for (MAuint32 i=0;i<towers.size();i++) @@ -185,7 +176,6 @@ MAfloat64 IsolationBase::sumPT(const RecPhotonFormat* part, // Sum sumPT += tower.pt(); - counter++; } // return PT sum of towers in the cone @@ -202,7 +192,6 @@ MAfloat64 IsolationBase::sumPT(const RecPhotonFormat* part, MAfloat64 PTmin) const { MAfloat64 sumPT=0.; - MAuint32 counter=0; // Loop over the tracks for (MAuint32 i=0;i<towers.size();i++) @@ -220,7 +209,6 @@ MAfloat64 IsolationBase::sumPT(const RecPhotonFormat* part, // Sum sumPT += tower.pt(); - counter++; } // return PT sum of towers in the cone diff --git a/tools/SampleAnalyzer/Process/Reader/LHEReader.cpp b/tools/SampleAnalyzer/Process/Reader/LHEReader.cpp index a4aa9e05..2fee19d6 100644 --- a/tools/SampleAnalyzer/Process/Reader/LHEReader.cpp +++ b/tools/SampleAnalyzer/Process/Reader/LHEReader.cpp @@ -52,7 +52,7 @@ MAbool LHEReader::ReadHeader(SampleFormat &mySample) // Read line by line the file until tag <header> // Note from Benj: the header tags are optional according to LHE standards - // the init tags are alsways the last ones before the events + // the init tags are always the last ones before the events MAbool EndOfLoop = false, GoodInit = false; while (!GoodInit) @@ -72,6 +72,7 @@ MAbool LHEReader::ReadHeader(SampleFormat &mySample) if (HeaderFound) { EndOfLoop = false; + MAbool in_weights=false; do { if (!ReadLine(line, false)) @@ -81,6 +82,12 @@ MAbool LHEReader::ReadHeader(SampleFormat &mySample) continue; else mySample.AddHeader(line); + + // Weight initialisation + if (line.find("<initrwgt>") != std::string::npos) in_weights=true; + if (line.find("</initrwgt>") != std::string::npos) in_weights=false; + if(in_weights) FillWeightNames(line, mySample); + if ((line.find("<MGGenerationInfo>") != std::string::npos) || (line.find("<mgversion>") != std::string::npos) || (line.find("<MG5ProcCard>") != std::string::npos)) @@ -551,6 +558,35 @@ void LHEReader::FillEventParticleLine(const std::string &line, mothers_.push_back(std::make_pair(mothup1, mothup2)); } +//------------------------------------------------------------------------------ +// FillWeightNames +//------------------------------------------------------------------------------ +void LHEReader::FillWeightNames(const std::string &line, SampleFormat &mySample) +{ + // Parsing + std::stringstream str(line); + std::size_t startTagPos = line.find("<weight"); + std::size_t endTagPos = line.find("</weight>"); + if (startTagPos != std::string::npos && endTagPos != std::string::npos) + { + // Extract the weight id + std::size_t idPos = line.find("id='", startTagPos); + std::size_t idEndPos = line.find("'", idPos + 4); + std::string id = line.substr(idPos + 4, idEndPos - (idPos + 4)); + + // Extract the content between the tags + std::size_t nameStart = line.find(">", startTagPos) + 1; + std::string weight_name = line.substr(nameStart, endTagPos - nameStart); + + // Trim the weight_name string + weight_name.erase(0, weight_name.find_first_not_of(" \t\n\r")); + weight_name.erase(weight_name.find_last_not_of(" \t\n\r") + 1); + + // Print the id and weight_name + mySample.mc()->SetWeightName(std::stoi(id), weight_name); + } +} + // ----------------------------------------------------------------------------- // FillWeightLine // ----------------------------------------------------------------------------- diff --git a/tools/SampleAnalyzer/Process/Reader/LHEReader.h b/tools/SampleAnalyzer/Process/Reader/LHEReader.h index b98b3c0e..dcc09a51 100644 --- a/tools/SampleAnalyzer/Process/Reader/LHEReader.h +++ b/tools/SampleAnalyzer/Process/Reader/LHEReader.h @@ -91,6 +91,7 @@ class LHEReader : public ReaderTextBase //! Fill the event from text line void FillEventInitLine(const std::string& line, EventFormat& myFormat); void FillEventParticleLine(const std::string& line, EventFormat& myFormat); + void FillWeightNames(const std::string &line, SampleFormat &mySample); void FillWeightLine(const std::string& line, EventFormat& myEvent); }; diff --git a/tools/SampleAnalyzer/Process/Writer/LHEWriter.cpp b/tools/SampleAnalyzer/Process/Writer/LHEWriter.cpp index cf5bd8e4..73b35862 100644 --- a/tools/SampleAnalyzer/Process/Writer/LHEWriter.cpp +++ b/tools/SampleAnalyzer/Process/Writer/LHEWriter.cpp @@ -611,8 +611,8 @@ MAbool LHEWriter::WriteEvent(const EventFormat &myEvent, { *output_ << " <rwgt>" << std::endl; for (const auto& pair : myEvent.mc()->weights().GetWeights()) - *output_ << " <wgt id='" << pair.first << "'> " << std::setw(18) << std::right - << FortranFormat_DoublePrecision(pair.second) << " </wgt>" << std::endl; + *output_ << " <wgt id='" << pair.first << "'> " << std::setw(18) << std::right + << FortranFormat_DoublePrecision(pair.second) << " </wgt>" << std::endl; *output_ << " </rwgt>" << std::endl; } From a7af8c03baddab0155edc4acbe9d536aad71f208 Mon Sep 17 00:00:00 2001 From: BFuks <fuks@lpthe.jussieu.fr> Date: Wed, 3 Jul 2024 15:43:57 +0200 Subject: [PATCH 105/107] Updating the plotflow and the layout --- bin/ma5 | 4 +- madanalysis/core/main.py | 2 +- madanalysis/layout/plotflow.py | 486 ++++++------------ madanalysis/multiweight/histogram.py | 2 +- .../Commons/Base/Configuration.cpp | 7 +- .../Process/Core/SampleAnalyzer.cpp | 14 +- 6 files changed, 167 insertions(+), 348 deletions(-) diff --git a/bin/ma5 b/bin/ma5 index 725bcaaa..efbd09c4 100755 --- a/bin/ma5 +++ b/bin/ma5 @@ -74,8 +74,8 @@ sys.path.insert(0, servicedir) # Release version # Do not touch it !!!!! -version = "2.0.9" -date = "2024/01/11" +version = "2.0.10" +date = "2024/07/03" # Loading the MadAnalysis session import madanalysis.core.launcher diff --git a/madanalysis/core/main.py b/madanalysis/core/main.py index e2445121..1cd0fd4b 100644 --- a/madanalysis/core/main.py +++ b/madanalysis/core/main.py @@ -104,7 +104,7 @@ def ResetParameters(self): self.lastjob_name = '' self.lastjob_status = False self.random_seed = None - self.stack = StackingMethodType.STACK + self.stack = StackingMethodType.SUPERIMPOSE self.isolation = IsolationConfiguration() self.output = "" self.graphic_render = GraphicRenderType.NONE diff --git a/madanalysis/layout/plotflow.py b/madanalysis/layout/plotflow.py index 0a91d44b..fa60f707 100644 --- a/madanalysis/layout/plotflow.py +++ b/madanalysis/layout/plotflow.py @@ -668,8 +668,9 @@ def DrawMATPLOTLIB(self, histos, scales, ref, irelhisto, filenamePy, outputnames # Open the file in write-mode try: outputPy = open(filenamePy, "w") - except: + except Exception as err: logging.getLogger("MA5").error("Impossible to write the file: " + filenamePy) + logging.getLogger("MA5").debug(err) return False # File header @@ -682,7 +683,6 @@ def DrawMATPLOTLIB(self, histos, scales, ref, irelhisto, filenamePy, outputnames outputPy.write(" # Library import\n") outputPy.write(" import numpy\n") outputPy.write(" import matplotlib\n") - # outputPy.write(" matplotlib.use('Agg')\n") outputPy.write(" import matplotlib.pyplot as plt\n") outputPy.write(" import matplotlib.gridspec as gridspec\n") outputPy.write("\n") @@ -884,17 +884,20 @@ def DrawMATPLOTLIB(self, histos, scales, ref, irelhisto, filenamePy, outputnames linecolor = ColorType.convert2root( self.main.datasets[ind].linecolor, self.main.datasets[ind].lineshade ) + mylinecolor = ('"' + madanalysis.enumeration.color_hex.color_hex[linecolor] + '"') + # lineStyle - linestyle = LineStyleType.convert2code(self.main.datasets[ind].linestyle) + mylinestyle = LineStyleType.convert2matplotlib(self.main.datasets[ind].linestyle) # linewidth - linewidth = self.main.datasets[ind].linewidth + mylinewidth = self.main.datasets[ind].linewidth # background color if self.main.datasets[ind].backcolor != ColorType.AUTO: backcolor = ColorType.convert2root( self.main.datasets[ind].backcolor, self.main.datasets[ind].backshade ) + mybackcolor = ('"' + madanalysis.enumeration.color_hex.color_hex[backcolor] + '"') # background style if self.main.datasets[ind].backstyle != BackStyleType.AUTO: @@ -902,26 +905,14 @@ def DrawMATPLOTLIB(self, histos, scales, ref, irelhisto, filenamePy, outputnames self.main.datasets[ind].backstyle ) - mylinecolor = ( - '"' + madanalysis.enumeration.color_hex.color_hex[linecolor] + '"' - ) - mybackcolor = ( - '"' + madanalysis.enumeration.color_hex.color_hex[backcolor] + '"' - ) - + # Filling mode filledmode = '"stepfilled"' rWidth = 1.0 if backcolor == 0: # invisible filledmode = '"step"' mybackcolor = "None" - # if frequencyhisto: - # filledmode='"bar"' - # rWidth=0.8 - mylinewidth = self.main.datasets[ind].linewidth - mylinestyle = LineStyleType.convert2matplotlib( - self.main.datasets[ind].linestyle - ) + # Histo outputPy.write( " pad.hist(" + "x=xData, " @@ -1189,12 +1180,10 @@ def DrawMULTIWEIGHT(self, histos, ref, filenamePy, outputnames) -> bool: if len(self.main.datasets) > 1: legendmode = True - # Stacking or superimposing histos ? + # Stacking or superimposing histos? + # Default in the multiweight case: superimposed stackmode = False - if ref.stack == StackingMethodType.STACK or ( - ref.stack == StackingMethodType.AUTO - and self.main.stack == StackingMethodType.STACK - ): + if ref.stack == StackingMethodType.STACK or self.main.stack == StackingMethodType.STACK: stackmode = True # Open the file in write-mode @@ -1213,17 +1202,11 @@ def DrawMULTIWEIGHT(self, histos, ref, filenamePy, outputnames) -> bool: # Import Libraries outputPy.write(" # Library import\n") - outputPy.write(" import numpy as np\n") + outputPy.write(" import numpy\n") outputPy.write(" import matplotlib\n") - # outputPy.write(" matplotlib.use('Agg')\n") outputPy.write(" import matplotlib.pyplot as plt\n") outputPy.write(" import matplotlib.gridspec as gridspec\n") - outputPy.write("\n") - - # Matplotlib & numpy version - outputPy.write(" # Library version\n") - outputPy.write(" matplotlib_version = matplotlib.__version__\n") - outputPy.write(" numpy_version = np.__version__\n") + outputPy.write(" import matplotlib.patches as patches\n") outputPy.write("\n") # Binning @@ -1231,22 +1214,14 @@ def DrawMULTIWEIGHT(self, histos, ref, filenamePy, outputnames) -> bool: xnbin = histos[0].description.nbins outputPy.write(" # Histo binning\n") outputPy.write( - f" xBinning=np.linspace({histos[0].description.xmin}, " + f" xBinning=numpy.linspace({histos[0].description.xmin}, " f"{histos[0].description.xmax}, {xnbin+1}, " "endpoint=True)\n" ) + outputPy.write(" bin_centers = 0.5 * (xBinning[1:] + xBinning[:-1])\n") + outputPy.write(" bin_width = xBinning[1] - xBinning[0]\n") outputPy.write("\n") - # Data - outputPy.write(" # Creating data sequence: middle of each bin\n") - outputPy.write( - " xData = np.array([" - + ", ".join( - [f"{histos[0].description.GetBinMean(x):.5e}" for x in range(0, xnbin)] - ) - + "])\n\n" - ) - # Loop over datasets and histos ntot = 0 for ind in range(0, len(histos)): @@ -1254,46 +1229,52 @@ def DrawMULTIWEIGHT(self, histos, ref, filenamePy, outputnames) -> bool: continue # Creating a new histo - histoname = "y_nominal_" + histos[ind].name + "_" + str(ind) - outputPy.write(" # Creating weights for histo: " + histoname + "\n") + histotag = "y_" + histos[ind].name + "_" + str(ind) + histoname = histotag + "_weights" + outputPy.write(f" # Creating weights for histo: {histotag}\n") current_weights = histos[ind].weights * histos[ind].scale + ntot+= sum(current_weights) outputPy.write( - " " - + histoname - + "_weights = np.array([" + f" {histoname} = numpy.array([" + ", ".join([f"{c:.5e}" if c != 0.0 else "0.0" for c in current_weights]) - + "])\n\n" + + "])\n" ) + outputPy.write(f" {histotag}, _ = numpy.histogram(a=numpy.array(bin_centers), bins=xBinning, weights={histoname})\n\n") - # extract uncertainties + # Extract uncertainties lower_unc, upper_unc = histos[ind].uncertainties + # total curve with error + if ind==0: + tot_lower_unc = lower_unc + tot_upper_unc = upper_unc + tot_central = current_weights + else: + tot_lower_unc = np.sqrt(tot_lower_unc**2 + lower_unc**2) + tot_upper_unc = np.sqrt(tot_upper_unc**2 + upper_unc**2) + tot_central = tot_central + current_weights + # Write upper limits - upper_unc_name = "y_UPPER_" + histos[ind].name + "_" + str(ind) + "_weights" + uppertag = "yup_" + histos[ind].name + "_" + str(ind) + uppername = uppertag + "_weights" + outputPy.write(f" # Upper error bar for: {histotag}\n") outputPy.write( - " # Delta Upper limits for the scale uncertainty: " + histoname + "\n" - ) - outputPy.write( - " " - + upper_unc_name - + " = np.array([" + f" {uppername} = numpy.array([" + ", ".join([f"{u:.5e}" if u != 0.0 else "0.0" for u in upper_unc]) - + "])\n\n" + + "])\n" ) + outputPy.write(f" {uppertag} = {histotag} + {uppername}\n\n") # Writing lower limits + lowertag = "ylow_" + histos[ind].name + "_" + str(ind) + lowername = lowertag + "_weights" + outputPy.write(f" # Lower error bar for: {histotag}\n") outputPy.write( - " # Delta Lower limits for the uncertainties: " + histoname + "\n" - ) - lower_unc_name = "y_LOWER_" + histos[ind].name + "_" + str(ind) + "_weights" - outputPy.write(" # Creating weights for histo: " + histoname + "\n") - outputPy.write( - " " - + lower_unc_name - + " = np.array([" + f" {lowername} = numpy.array([" + ", ".join([f"{l:.5e}" if l != 0.0 else "0.0" for l in lower_unc]) - + "])\n\n" + + "])\n" ) + outputPy.write(f" {lowertag} = {histotag} - {lowername}\n\n") # Canvas outputPy.write(" # Creating a new Canvas\n") @@ -1312,225 +1293,115 @@ def DrawMULTIWEIGHT(self, histos, ref, filenamePy, outputnames) -> bool: outputPy.write(" frame = gridspec.GridSpec(1,1,right=0.7)\n") outputPy.write(" pad = fig.add_subplot(frame[0])\n\n") + # Styles and colours + linecolors = [ + [9], [9, 46], [9, 46, 8], [9, 46, 8, 4], [9, 46, 8, 4, 6], [9, 46, 8, 4, 6, 2], + [9, 46, 8, 4, 6, 2, 7], [9, 46, 8, 4, 6, 2, 7, 3], [9, 46, 8, 4, 6, 2, 7, 3, 42], + [9, 46, 8, 4, 6, 2, 7, 3, 42, 48] + ] + backstyles = [ + ['///'], ['///','\\\\\\\\\\\\'], ['///','\\\\\\\\\\','-'], ['///','\\\\\\\\\\\\','---','|||'], ['///','\\\\\\\\\\\\','---','|||','+++'], + ['///','\\\\\\\\\\\\','---','|','+++','xxx'], ['///','\\\\\\\\\\\\','---','|||','+++','xxx','ooo'], + ['///','\\\\\\\\\\\\','---','|','+++','xxx','ooo','...'], ['///','\\\\\\\\\\\\','---','|||','+++','xxx','ooo','...','***'], + ['///','\\\\\\\\\\\\','---','|','+++','xxx','ooo','...','***','/\\'] + ] + # Stack - outputPy.write(" # Creating a new Stack\n") + titles = [] for ind in range(len(histos) - 1, -1, -1): - mytitle = ( - '"' + PlotFlow.NiceTitleMatplotlib(self.main.datasets[ind].title) + '"' - ) + mytitle = ('"' + PlotFlow.NiceTitleMatplotlib(self.main.datasets[ind].title) + '"') mytitle = mytitle.replace("_", "\_") - if not stackmode: - myweights = "y_nominal_" + histos[ind].name + "_" + str(ind) + "_weights" - else: - myweights = "" - for ind2 in range(0, ind + 1): - if ind2 >= 1: - myweights += "+" - myweights += ( - "y_nominal_" + histos[ind2].name + "_" + str(ind2) + "_weights" - ) - - # reset - linecolor = 0 - linestyle = 0 - backcolor = 0 - backstyle = 0 - linewidth = 1 - - # Setting AUTO settings - if len(histos) == 1: - linecolor1 = [9] - linecolor = linecolor1[ind] - if stackmode: - backstyle1 = [3004] - backstyle = backstyle1[ind] - backcolor = linecolor1[ind] - elif len(histos) == 2: - linecolor2 = [9, 46] - linecolor = linecolor2[ind] - if stackmode: - backstyle2 = [3004, 3005] - backstyle = backstyle2[ind] - backcolor = linecolor2[ind] - elif len(histos) == 3: - linecolor3 = [9, 46, 8] - linecolor = linecolor3[ind] - if stackmode: - backstyle3 = [3004, 3005, 3006] - backstyle = backstyle3[ind] - backcolor = linecolor3[ind] - elif len(histos) == 4: - linecolor4 = [9, 46, 8, 4] - linecolor = linecolor4[ind] - if stackmode: - backstyle4 = [3004, 3005, 3006, 3007] - backstyle = backstyle4[ind] - backcolor = linecolor4[ind] - elif len(histos) == 5: - linecolor5 = [9, 46, 8, 4, 6] - linecolor = linecolor5[ind] - if stackmode: - backstyle5 = [3004, 3005, 3006, 3007, 3013] - backstyle = backstyle5[ind] - backcolor = linecolor5[ind] - elif len(histos) == 6: - linecolor6 = [9, 46, 8, 4, 6, 2] - linecolor = linecolor6[ind] - if stackmode: - backstyle6 = [3004, 3005, 3006, 3007, 3013, 3017] - backstyle = backstyle6[ind] - backcolor = linecolor6[ind] - elif len(histos) == 7: - linecolor7 = [9, 46, 8, 4, 6, 2, 7] - linecolor = linecolor7[ind] - if stackmode: - backstyle7 = [3004, 3005, 3006, 3007, 3013, 3017, 3022] - backstyle = backstyle7[ind] - backcolor = linecolor7[ind] - elif len(histos) == 8: - linecolor8 = [9, 46, 8, 4, 6, 2, 7, 3] - linecolor = linecolor8[ind] - if stackmode: - backstyle8 = [3004, 3005, 3006, 3007, 3013, 3017, 3022, 3315] - backstyle = backstyle8[ind] - backcolor = linecolor8[ind] - elif len(histos) == 9: - linecolor9 = [9, 46, 8, 4, 6, 2, 7, 3, 42] - linecolor = linecolor9[ind] - if stackmode: - backstyle9 = [3004, 3005, 3006, 3007, 3013, 3017, 3022, 3315, 3351] - backstyle = backstyle9[ind] - backcolor = linecolor9[ind] - elif len(histos) == 10: - linecolor10 = [9, 46, 8, 4, 6, 2, 7, 3, 42, 48] - linecolor = linecolor10[ind] - if stackmode: - backstyle10 = [ - 3004, - 3005, - 3006, - 3007, - 3013, - 3017, - 3022, - 3315, - 3351, - 3481, - ] - backstyle = backstyle10[ind] - backcolor = linecolor10[ind] + # Set linecolor based on the length of histos + if len(histos) <= 10: + linecolor = linecolors[len(histos) - 1][ind] + backcolor = linecolors[len(histos) - 1][ind] + backstyle = "'" + backstyles[len(histos) - 1][ind] + "'" else: linecolor = self.color + backcolor = self.color self.color += 1 - # linecolor + # line colour, style and width if self.main.datasets[ind].linecolor != ColorType.AUTO: linecolor = ColorType.convert2root( self.main.datasets[ind].linecolor, self.main.datasets[ind].lineshade ) - # lineStyle - linestyle = LineStyleType.convert2code(self.main.datasets[ind].linestyle) - - # linewidth + mylinecolor = ('"' + madanalysis.enumeration.color_hex.color_hex[linecolor] + '"') + titles.append([mytitle, mylinecolor, backstyle]) + linestyle = LineStyleType.convert2matplotlib(self.main.datasets[ind].linestyle) linewidth = self.main.datasets[ind].linewidth - # background color + # background style and colour if self.main.datasets[ind].backcolor != ColorType.AUTO: backcolor = ColorType.convert2root( self.main.datasets[ind].backcolor, self.main.datasets[ind].backshade ) + mybackcolor = ('"' + madanalysis.enumeration.color_hex.color_hex[backcolor] + '"') - # background style - if self.main.datasets[ind].backstyle != BackStyleType.AUTO: - backstyle = BackStyleType.convert2matplotlib( - self.main.datasets[ind].backstyle + # No stacking: error rectangles around each bin + if not stackmode: + # Rectangles around the error bar for each bin + outputPy.write(" # Add rectangles for each bin\n") + outputPy.write(" for center, y_val, y_up, y_low in zip(bin_centers, y_" + histos[ind].name + "_" + str(ind) + ", yup_" + histos[ind].name + "_" + str(ind) + ", ylow_" + histos[ind].name + "_" + str(ind) + "):\n") + outputPy.write(" rect = patches.Rectangle( (center - bin_width / 2, y_low), bin_width, y_up - y_low, facecolor="+mybackcolor+", edgecolor=" + mylinecolor + ", hatch=" + backstyle + ", alpha=0.3)\n") + outputPy.write(" pad.add_patch(rect)\n") + # Error bars + outputPy.write(" # Plot the error bars\n") + outputPy.write( + " pad.errorbar(bin_centers, y_" + histos[ind].name + "_" + str(ind) + + ", yerr=[ylow_" + histos[ind].name + "_" + str(ind) + "_weights, yup_" + histos[ind].name + "_" + str(ind) + "_weights]," + + "label=" + mytitle + "," + + f" fmt='.', elinewidth=1, capsize=3, color='black')\n\n" ) - mylinecolor = ( - '"' + madanalysis.enumeration.color_hex.color_hex[linecolor] + '"' - ) - mybackcolor = ( - '"' + madanalysis.enumeration.color_hex.color_hex[backcolor] + '"' - ) + # Stacking: combined error bar + else: + try: + import matplotlib.pyplot as plt + plt.hist([0], normed=True) + norm_key="normed" + except Exception: + norm_key = "density" + outputPy.write( + " pad.hist(x=bin_centers, bins=xBinning, " + + "weights=y_" + histos[ind].name + "_" + str(ind) + ",\n" + + " label=" + mytitle + ", " + ) + if ntot != 0: + outputPy.write("histtype='stepfilled', ") + outputPy.write(f"rwidth=1.0, color={mybackcolor}, \n") + if ind==0: + outputPy.write(" bottom=None, ") + else: + outputPy.write(" bottom=y_" + histos[ind-1].name + "_" + str(ind-1) + ", ") + outputPy.write(f"cumulative=False, {norm_key}=False, align=\"mid\", orientation=\"vertical\")\n\n") + outputPy.write("\n") - filledmode = '"stepfilled"' - rWidth = 1.0 - if backcolor == 0: # invisible - filledmode = '"step"' - mybackcolor = "None" - mylinewidth = self.main.datasets[ind].linewidth - mylinestyle = LineStyleType.convert2matplotlib( - self.main.datasets[ind].linestyle + # Rectangles around the error bar for each bin + if stackmode: + outputPy.write(" # Add rectangles for each bin around the total\n") + outputPy.write( + f" tot_central = numpy.array([" + + ", ".join([f"{u:.5e}" if u != 0.0 else "0.0" for u in tot_central]) + + "])\n" ) - outputPy.write( - " pad.errorbar(\n" - f" xData, {myweights},\n" - f" yerr=[{lower_unc_name}, {upper_unc_name}],\n" - " fmt='.', elinewidth=1, capsize=3,\n" - " )\n\n" + f" tot_up = numpy.array([" + + ", ".join([f"{u:.5e}" if u != 0.0 else "0.0" for u in tot_upper_unc]) + + "])\n" ) - outputPy.write( - " pad.hist(" - + "x=xData, " - + "bins=xBinning, " - + "weights=" - + myweights - + ",\\\n" - + " label=" - + mytitle - + ", " + f" tot_low = numpy.array([" + + ", ".join([f"{u:.5e}" if u != 0.0 else "0.0" for u in tot_lower_unc]) + + "])\n" ) - if ntot != 0: - outputPy.write("histtype=" + filledmode + ", ") - try: - import matplotlib.pyplot as plt - - plt.hist([0], normed=True) - outputPy.write( - "rwidth=" - + str(rWidth) - + ",\\\n" - + " color=" - + mybackcolor - + ", " - + "edgecolor=" - + mylinecolor - + ", " - + "linewidth=" - + str(mylinewidth) - + ", " - + "linestyle=" - + mylinestyle - + ",\\\n" - + " bottom=None, " - + 'cumulative=False, normed=False, align="mid", orientation="vertical")\n\n' - ) - except Exception as err: - logging.getLogger("MA5").debug(err) - outputPy.write( - "rwidth=" - + str(rWidth) - + ",\\\n" - + " color=" - + mybackcolor - + ", " - + "edgecolor=" - + mylinecolor - + ", " - + "linewidth=" - + str(mylinewidth) - + ", " - + "linestyle=" - + mylinestyle - + ",\\\n" - + " bottom=None, " - + 'cumulative=False, density=False, align="mid",' - + ' orientation="vertical")\n\n' - ) - outputPy.write("\n") + outputPy.write(" ytot, _ = numpy.histogram(a=numpy.array(bin_centers), bins=xBinning, weights=tot_central)\n") + outputPy.write(" yup = ytot + tot_up\n") + outputPy.write(" ylow = ytot - tot_low\n") + outputPy.write(" for center, y, y_up, y_low in zip(bin_centers, ytot, yup, ylow):\n") + outputPy.write(" rect = patches.Rectangle( (center - bin_width / 2, y_low), bin_width, y_up - y_low, facecolor='white', edgecolor='black' , hatch='////', alpha=0.3)\n") + outputPy.write(" pad.add_patch(rect)\n\n") # Label outputPy.write(" # Axis\n") @@ -1542,6 +1413,7 @@ def DrawMULTIWEIGHT(self, histos, ref, filenamePy, outputnames) -> bool: else: axis_titleX = ref.titleX axis_titleX = axis_titleX.replace("#DeltaR", "#Delta R") + axis_titleX = axis_titleX.replace("#slash", "\\not\!\!\!\!") axis_titleX = axis_titleX.replace("#", "\\") outputPy.write(' plt.xlabel(r"' + axis_titleX + '",\\\n') outputPy.write(' fontsize=16,color="black")\n') @@ -1588,63 +1460,28 @@ def DrawMULTIWEIGHT(self, histos, ref, filenamePy, outputnames) -> bool: # Bound y outputPy.write(" # Boundary of y-axis\n") - myweights = "" - if stackmode: - for ind in range(0, len(histos)): - if ind >= 1: - myweights += "+" - myweights += "y_nominal_" + histos[ind].name + "_" + str(ind) + "_weights" - else: - myweights = "numpy.array([" - for ind in range(0, len(histos)): - if ind >= 1: - myweights += "," - myweights += ( - "y_nominal_" + histos[ind].name + "_" + str(ind) + "_weights.max()" - ) - myweights += "])" if ref.ymax == []: - outputPy.write( - " ymax=(" + myweights + "+" + upper_unc_name + ").max()*1.1\n" - ) + if stackmode: + outputPy.write(" ymax = yup.max()*1.1\n") + else: + myweights = "numpy.array([" + ",".join([f"yup_{histos[ind].name}_{ind}.max()" for ind in range(len(histos))]) + "])" + outputPy.write(" ymax=(" + myweights + ").max()*1.1\n") else: outputPy.write(" ymax=" + str(ref.ymax) + "\n") - outputPy.write(" ") if ref.ymin == []: - if is_logy: - outputPy.write("#") - outputPy.write("ymin=0 # linear scale\n") + if stackmode and is_logy: + outputPy.write(" ymin = min([x for x in ylow if x])/100\n") + elif stackmode and not is_logy: + outputPy.write(" ymin = 0 # linear scale\n") + elif is_logy: + myweights = "numpy.array([" + ",".join([f"min([x for x in ylow_{histos[ind].name}_{ind} if x>0])" for ind in range(len(histos))]) + "])" + outputPy.write(" ymin =(" + myweights + ").min()/100\n") + else: + outputPy.write(" ymin = 0 # linear scale") else: if is_logy and ref.ymin <= 0: outputPy.write("#") outputPy.write("ymin=" + str(ref.ymin) + " # linear scale\n") - - myweights = "" - if stackmode: - for ind in range(0, len(histos)): - if ind >= 1: - myweights += "+" - myweights += "y_nominal_" + histos[ind].name + "_" + str(ind) + "_weights" - else: - myweights = "numpy.array([" - for ind in range(0, len(histos)): - if ind >= 1: - myweights += "," - myweights += ( - "y_nominal_" + histos[ind].name + "_" + str(ind) + "_weights.min()" - ) - myweights += ",1.])" - outputPy.write(" ") - if ref.ymin == []: - if not is_logy: - outputPy.write("#") - outputPy.write( - "ymin=min([x for x in (" + myweights + ") if x])/100. # log scale\n" - ) - else: - if is_logy and ref.ymin <= 0: - outputPy.write("#") - outputPy.write("ymin=" + str(ref.ymin) + " # log scale\n") outputPy.write(" plt.gca().set_ylim(ymin,ymax)\n") outputPy.write("\n") @@ -1676,34 +1513,19 @@ def DrawMULTIWEIGHT(self, histos, ref, filenamePy, outputnames) -> bool: outputPy.write('plt.gca().set_yscale("log",nonpositive="clip")\n') outputPy.write("\n") - # Labels - ### BENJ: not necessary for getting the png and pdf files - # Draw - # outputPy.write(' # Draw\n') - # outputPy.write(' plt.show()\n') - # outputPy.write('\n') - # Legend if legendmode: - - # Reminder for 'loc' - # -'best' : 0, (only implemented for axes legends) - # -'upper right' : 1, - # -'upper left' : 2, - # -'lower left' : 3, - # -'lower right' : 4, - # -'right' : 5, - # -'center left' : 6, - # -'center right' : 7, - # -'lower center' : 8, - # -'upper center' : 9, - # -'center' : 10, - outputPy.write(" # Legend\n") - outputPy.write( - " plt.legend(bbox_to_anchor=(1.05,1), loc=2," + " borderaxespad=0.)\n" - ) - outputPy.write("\n") + outputPy.write(" import matplotlib.patches as patches\n") + outputPy.write(" # Create custom legend handles\n") + outputPy.write(" legend_handles = [\n") + for label,color,hatch in titles: + if stackmode: + outputPy.write(" patches.Patch(color=" + color + ", alpha=0.3, label=" + label + "),\n") + else: + outputPy.write(" patches.Patch(color=" + color + ", hatch=" + hatch +", alpha=0.3, label=" + label + "),\n") + outputPy.write(" ]\n") + outputPy.write(" pad.legend(handles=legend_handles, bbox_to_anchor=(1.05,1), loc=2," + " borderaxespad=0.)\n\n") # Producing the image outputPy.write(" # Saving the image\n") diff --git a/madanalysis/multiweight/histogram.py b/madanalysis/multiweight/histogram.py index f106a367..0ed58026 100644 --- a/madanalysis/multiweight/histogram.py +++ b/madanalysis/multiweight/histogram.py @@ -574,5 +574,5 @@ def uncertainties(self) -> Tuple[np.ndarray, np.ndarray]: # add in quadrature return ( np.sqrt(scale_lower**2 + pdf_lower**2) * nominal, - np.sqrt(scale_lower**2 + pdf_lower**2) * nominal, + np.sqrt(scale_upper**2 + pdf_upper**2) * nominal, ) diff --git a/tools/SampleAnalyzer/Commons/Base/Configuration.cpp b/tools/SampleAnalyzer/Commons/Base/Configuration.cpp index 61ba16f9..12fd8d36 100644 --- a/tools/SampleAnalyzer/Commons/Base/Configuration.cpp +++ b/tools/SampleAnalyzer/Commons/Base/Configuration.cpp @@ -38,8 +38,8 @@ namespace MA5 // Initializing static data members // ----------------------------------------------------------------------------- // DO NOT TOUCH THESE LINES - const std::string Configuration::sampleanalyzer_version_ = "2.0.9"; - const std::string Configuration::sampleanalyzer_date_ = "2024/01/11"; + const std::string Configuration::sampleanalyzer_version_ = "2.0.10"; + const std::string Configuration::sampleanalyzer_date_ = "2024/07/03"; // DO NOT TOUCH THESE LINES // ----------------------------------------------------------------------------- @@ -124,7 +124,6 @@ namespace MA5 // converting const characters into string std::string argument = std::string(argv[i]); Lower(argument); - INFO << argument << endmsg; // safety : skip empty string if (argument.size() == 0) @@ -223,4 +222,4 @@ namespace MA5 INFO << " -> event weights are not used." << endmsg; } } -} \ No newline at end of file +} diff --git a/tools/SampleAnalyzer/Process/Core/SampleAnalyzer.cpp b/tools/SampleAnalyzer/Process/Core/SampleAnalyzer.cpp index 924be6b5..9c9da3dc 100644 --- a/tools/SampleAnalyzer/Process/Core/SampleAnalyzer.cpp +++ b/tools/SampleAnalyzer/Process/Core/SampleAnalyzer.cpp @@ -189,15 +189,13 @@ void SampleAnalyzer::CheckDatatypes() const } /// Initialization of the SampleAnalyzer -MAbool SampleAnalyzer::Initialize(MAint32 argc, MAchar **argv, - const std::string &pdgFileName) +MAbool SampleAnalyzer::Initialize(MAint32 argc, MAchar **argv, const std::string &pdgFileName) { - // Initializing general pointers - myReader_ = 0; + // Initializing general pointers + myReader_ = 0; - // Configuration - if (!cfg_.Initialize(argc, argv)) - return false; + // Configuration + if (!cfg_.Initialize(argc, argv)) return false; // Displaying configuration cfg_.Display(); @@ -1412,4 +1410,4 @@ void SampleAnalyzer::AddDefaultInvisible() PHYSICS->mcConfig().AddInvisibleId(16); PHYSICS->mcConfig().AddInvisibleId(1000022); PHYSICS->mcConfig().AddInvisibleId(1000039); -} \ No newline at end of file +} From dbd1944936ba72333d84c90be866f28940189904 Mon Sep 17 00:00:00 2001 From: BFuks <fuks@lpthe.jussieu.fr> Date: Fri, 5 Jul 2024 06:53:21 +0200 Subject: [PATCH 106/107] fixing the importlib issue in bin/ma5 --- bin/ma5 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/ma5 b/bin/ma5 index efbd09c4..c49c91d6 100755 --- a/bin/ma5 +++ b/bin/ma5 @@ -33,7 +33,7 @@ This is the main executable, a simple frontend to set up the PYTHONPATH and call immediately the command line interface scripts """ -import importlib +from importlib import util import os import sys @@ -48,7 +48,7 @@ if sys.version_info[0] != 3 or sys.version_info[1] <= 6: ) # Checking that the 'six' package is present -if not importlib.util.find_spec("six"): +if not util.find_spec("six"): sys.exit( 'The python "six" module is not found on your system and it is required for MadAnalysis 5 for ' + "a question of Python 2/3 compatibility. Please install it with the following command:\n" From cfb879e586554d6e1d738376066076ff65a7a897 Mon Sep 17 00:00:00 2001 From: BFuks <fuks@lpthe.jussieu.fr> Date: Sun, 28 Jul 2024 17:15:42 -0400 Subject: [PATCH 107/107] Adding scale information to the dataset printout --- madanalysis/dataset/dataset.py | 5 +++++ madanalysis/multiweight/histogram.py | 23 +++++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/madanalysis/dataset/dataset.py b/madanalysis/dataset/dataset.py index 46df892b..57185747 100644 --- a/madanalysis/dataset/dataset.py +++ b/madanalysis/dataset/dataset.py @@ -492,6 +492,9 @@ def Display(self): ) logging.getLogger("MA5").info(" Ratio of negative weights = " + str(msg) + " %") logging.getLogger("MA5").info(" ******************************************") + logging.getLogger("MA5").info(" Uncertainty treatment") + self.user_DisplayParameter("n_point_scale_variation") + logging.getLogger("MA5").info(" ******************************************") def user_DisplayParameter(self, parameter): if parameter == "weight": @@ -553,6 +556,8 @@ def user_DisplayParameter(self, parameter): " Background style in histograms = " + BackStyleType.convert2string(self.backstyle) ) + elif parameter == "n_point_scale_variation": + logging.getLogger("MA5").info(f" Scale uncertainties: from {self.n_point_scale_variation} point variations") else: logging.getLogger("MA5").error( " the class dataset has no attribute denoted by '" + parameter + "'" diff --git a/madanalysis/multiweight/histogram.py b/madanalysis/multiweight/histogram.py index 0ed58026..f42ff6a5 100644 --- a/madanalysis/multiweight/histogram.py +++ b/madanalysis/multiweight/histogram.py @@ -1,3 +1,26 @@ +################################################################################ +# +# Copyright (C) 2012-2024 Jack Araz, Eric Conte & Benjamin Fuks +# The MadAnalysis development team, email: <ma5team@iphc.cnrs.fr> +# +# This file is part of MadAnalysis 5. +# Official website: <https://github.com/MadAnalysis/madanalysis5> +# +# MadAnalysis 5 is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# MadAnalysis 5 is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with MadAnalysis 5. If not, see <http://www.gnu.org/licenses/> +# +################################################################################ + """This file includes classes for multiweight histograms""" import copy