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 &current_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 &region_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 &region_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 &reg : 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 &reg : 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 &reg : 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 &reg : 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 &current_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 &region_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 &reg : 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 &reg : 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 &reg : 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 &reg : 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 &reg : 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> &parameters);
 
-  /// 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> &parameters);
 
-  /// 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> &parameters);
 
-  /// 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 &reg : 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