diff --git a/L1Trigger/L1TGlobal/interface/CorrThreeBodyCondition.h b/L1Trigger/L1TGlobal/interface/CorrThreeBodyCondition.h
new file mode 100644
index 0000000000000..33560b4508c6b
--- /dev/null
+++ b/L1Trigger/L1TGlobal/interface/CorrThreeBodyCondition.h
@@ -0,0 +1,110 @@
+#ifndef L1Trigger_L1TGlobal_CorrThreeBodyCondition_h
+#define L1Trigger_L1TGlobal_CorrThreeBodyCondition_h
+
+/**
+ * \class CorrThreeBodyCondition
+ *
+ * Description: L1 Global Trigger three-body correlation conditions:                                                                      
+ *              evaluation of a three-body correlation condition (= three-muon invariant mass)    
+ *                                                                                                                                               
+ * Implementation:                                                                                                                                             
+ *    <TODO: enter implementation details>                                                                                                 
+ *                                                                                                                                                                         
+ * \author: Elisa Fontanesi - Boston University                                                                                                                                                            
+ *          CorrCondition and CorrWithOverlapRemovalCondition classes used as a starting point
+ *                                                                                                                                                       
+ */
+
+// system include files
+#include <iosfwd>
+#include <string>
+
+// user include files
+//   base classes
+#include "L1Trigger/L1TGlobal/interface/ConditionEvaluation.h"
+#include "L1Trigger/L1TGlobal/interface/GlobalScales.h"
+
+// forward declarations
+class GlobalCondition;
+class CorrelationThreeBodyTemplate;
+
+namespace l1t {
+
+  class L1Candidate;
+
+  class GlobalBoard;
+
+  // class declaration
+  class CorrThreeBodyCondition : public ConditionEvaluation {
+  public:
+    /// constructors
+    ///     default
+    CorrThreeBodyCondition();
+
+    ///     from base template condition (from event setup usually)
+    CorrThreeBodyCondition(const GlobalCondition*,
+                           const GlobalCondition*,
+                           const GlobalCondition*,
+                           const GlobalCondition*,
+                           const GlobalBoard*
+
+    );
+
+    // copy constructor
+    CorrThreeBodyCondition(const CorrThreeBodyCondition&);
+
+    // destructor
+    ~CorrThreeBodyCondition() override;
+
+    // assign operator
+    CorrThreeBodyCondition& operator=(const CorrThreeBodyCondition&);
+
+  public:
+    /// the core function to check if the condition matches
+    const bool evaluateCondition(const int bxEval) const override;
+
+    /// print condition
+    void print(std::ostream& myCout) const override;
+
+  public:
+    ///   get / set the pointer to a Condition
+    inline const CorrelationThreeBodyTemplate* gtCorrelationThreeBodyTemplate() const {
+      return m_gtCorrelationThreeBodyTemplate;
+    }
+
+    void setGtCorrelationThreeBodyTemplate(const CorrelationThreeBodyTemplate*);
+
+    ///   get / set the pointer to uGt GlobalBoard
+    inline const GlobalBoard* getuGtB() const { return m_uGtB; }
+
+    void setuGtB(const GlobalBoard*);
+
+    void setScales(const GlobalScales*);
+
+  private:
+    ///  copy function for copy constructor and operator=
+    void copy(const CorrThreeBodyCondition& cp);
+
+    /// load  candidates
+    const l1t::L1Candidate* getCandidate(const int bx, const int indexCand) const;
+
+    /// function to check a single object if it matches a condition
+    const bool checkObjectParameter(const int iCondition, const l1t::L1Candidate& cand) const;
+
+  private:
+    /// pointer to a CorrelationThreeBodyTemplate
+    const CorrelationThreeBodyTemplate* m_gtCorrelationThreeBodyTemplate;
+
+    // pointer to subconditions
+    const GlobalCondition* m_gtCond0;
+    const GlobalCondition* m_gtCond1;
+    const GlobalCondition* m_gtCond2;
+
+    /// pointer to uGt GlobalBoard, to be able to get the trigger objects
+    const GlobalBoard* m_uGtB;
+
+    const GlobalScales* m_gtScales;
+  };
+
+}  // namespace l1t
+#endif
diff --git a/L1Trigger/L1TGlobal/interface/CorrelationThreeBodyTemplate.h b/L1Trigger/L1TGlobal/interface/CorrelationThreeBodyTemplate.h
new file mode 100644
index 0000000000000..dd3be14cd8e73
--- /dev/null
+++ b/L1Trigger/L1TGlobal/interface/CorrelationThreeBodyTemplate.h
@@ -0,0 +1,127 @@
+#ifndef L1Trigger_L1TGlobal_CorrelationThreeBodyTemplate_h
+#define L1Trigger_L1TGlobal_CorrelationThreeBodyTemplate_h
+
+/**
+ * \class CorrelationThreeBodyTemplate
+ *
+ *
+ * Description: L1 Global Trigger three-body correlation template:
+ *              include invariant mass calculation for three-muon events
+ *
+ * Implementation:
+ *    <TODO: enter implementation details>
+ *
+ * \author: Elisa Fontanesi - Boston University 
+ *          Starting from CorrelationTemplate.h written by Vasile Mihai Ghete - HEPHY Vienna
+ *
+ * $Date$
+ * $Revision$
+ *
+ */
+
+// system include files
+#include <string>
+#include <iosfwd>
+
+// user include files
+
+//   base class
+#include "L1Trigger/L1TGlobal/interface/GlobalCondition.h"
+#include "L1Trigger/L1TGlobal/interface/GlobalDefinitions.h"
+
+// forward declarations
+
+// class declaration
+class CorrelationThreeBodyTemplate : public GlobalCondition {
+public:
+  /// constructor(s)
+  ///   default
+  CorrelationThreeBodyTemplate();
+
+  ///   from condition name
+  CorrelationThreeBodyTemplate(const std::string&);
+
+  ///   from condition name, the category of first, second, and third subcondition,
+  ///   the index of first, second, third subcondition in the cor* vector
+  CorrelationThreeBodyTemplate(const std::string&,
+                               const l1t::GtConditionCategory&,
+                               const l1t::GtConditionCategory&,
+                               const l1t::GtConditionCategory&,
+                               const int,
+                               const int,
+                               const int);
+
+  /// copy constructor
+  CorrelationThreeBodyTemplate(const CorrelationThreeBodyTemplate&);
+
+  /// destructor
+  ~CorrelationThreeBodyTemplate() override;
+
+  /// assign operator
+  CorrelationThreeBodyTemplate& operator=(const CorrelationThreeBodyTemplate&);
+
+public:
+  /// typedef for correlation three-body parameters
+  struct CorrelationThreeBodyParameter {
+    //Cut values in hardware
+    long long minEtaCutValue;
+    long long maxEtaCutValue;
+    unsigned int precEtaCut;
+
+    long long minPhiCutValue;
+    long long maxPhiCutValue;
+    unsigned int precPhiCut;
+
+    long long minMassCutValue;
+    long long maxMassCutValue;
+    unsigned int precMassCut;
+
+    int corrCutType;
+  };
+
+public:
+  /// get / set the category of the three subconditions
+  inline const l1t::GtConditionCategory cond0Category() const { return m_cond0Category; }
+  inline const l1t::GtConditionCategory cond1Category() const { return m_cond1Category; }
+  inline const l1t::GtConditionCategory cond2Category() const { return m_cond2Category; }
+
+  void setCond0Category(const l1t::GtConditionCategory&);
+  void setCond1Category(const l1t::GtConditionCategory&);
+  void setCond2Category(const l1t::GtConditionCategory&);
+
+  /// get / set the index of the three subconditions in the cor* vector from menu
+  inline const int cond0Index() const { return m_cond0Index; }
+  inline const int cond1Index() const { return m_cond1Index; }
+  inline const int cond2Index() const { return m_cond2Index; }
+
+  void setCond0Index(const int&);
+  void setCond1Index(const int&);
+  void setCond2Index(const int&);
+
+  /// get / set correlation parameters
+  inline const CorrelationThreeBodyParameter* correlationThreeBodyParameter() const {
+    return &m_correlationThreeBodyParameter;
+  }
+  void setCorrelationThreeBodyParameter(const CorrelationThreeBodyParameter& corrThreeBodyParameter);
+
+  /// print the condition
+  void print(std::ostream& myCout) const override;
+
+  /// output stream operator
+  friend std::ostream& operator<<(std::ostream&, const CorrelationThreeBodyTemplate&);
+
+private:
+  /// copy function for copy constructor and operator=
+  void copy(const CorrelationThreeBodyTemplate& cp);
+
+private:
+  l1t::GtConditionCategory m_cond0Category;
+  l1t::GtConditionCategory m_cond1Category;
+  l1t::GtConditionCategory m_cond2Category;
+  int m_cond0Index;
+  int m_cond1Index;
+  int m_cond2Index;
+  CorrelationThreeBodyParameter m_correlationThreeBodyParameter;
+};
+
+#endif
diff --git a/L1Trigger/L1TGlobal/interface/GlobalCondition.h b/L1Trigger/L1TGlobal/interface/GlobalCondition.h
index bc3eecbc8c89f..1bb3f17679e62 100644
--- a/L1Trigger/L1TGlobal/interface/GlobalCondition.h
+++ b/L1Trigger/L1TGlobal/interface/GlobalCondition.h
@@ -11,6 +11,7 @@
  *    <TODO: enter implementation details>
  *
  * \author: Brian Winer, OSU   Vasile Mihai Ghete - HEPHY Vienna
+ *          Elisa Fontanesi - extended for three-body correlation conditions
  *
  * $Date$
  * $Revision$
@@ -93,6 +94,9 @@ class GlobalCondition {
   /// and with spatial correlations
   const bool corr() const;
 
+  /// get logic flag for three-body conditions, trigger objects are muons
+  const bool corrThree() const;
+
   /// print condition
   virtual void print(std::ostream& myCout) const;
 
diff --git a/L1Trigger/L1TGlobal/interface/GlobalDefinitions.h b/L1Trigger/L1TGlobal/interface/GlobalDefinitions.h
index 0340ef5e80cba..16b13af902d7b 100644
--- a/L1Trigger/L1TGlobal/interface/GlobalDefinitions.h
+++ b/L1Trigger/L1TGlobal/interface/GlobalDefinitions.h
@@ -12,6 +12,7 @@
  *
  *
  * \author: Vladimir Rekovic,   Brian Winer, OSU   Vasile Mihai Ghete - HEPHY Vienna
+ *          Elisa Fontanesi - extended for three-body correlation conditions
  *
  * $Date$
  * $Revision$
@@ -96,7 +97,8 @@ namespace l1t {
     CondEnergySum,
     CondCorrelation,
     CondExternal,
-    CondCorrelationWithOverlapRemoval
+    CondCorrelationWithOverlapRemoval,
+    CondCorrelationThreeBody
   };
 
   struct GtConditionCategoryStringToEnum {
diff --git a/L1Trigger/L1TGlobal/interface/TriggerMenu.h b/L1Trigger/L1TGlobal/interface/TriggerMenu.h
index 73443ce82ac40..6ab26ec8d79b4 100644
--- a/L1Trigger/L1TGlobal/interface/TriggerMenu.h
+++ b/L1Trigger/L1TGlobal/interface/TriggerMenu.h
@@ -12,6 +12,7 @@
  *
  * \author: Vasile Mihai Ghete - HEPHY Vienna
  *          Vladimir Rekovic - extend for overlap removal
+ *          Elisa Fontanesi - extended for three-body correlation conditions
  *
  * $Date$
  * $Revision$
@@ -35,6 +36,7 @@
 #include "L1Trigger/L1TGlobal/interface/EnergySumTemplate.h"
 #include "L1Trigger/L1TGlobal/interface/ExternalTemplate.h"
 #include "L1Trigger/L1TGlobal/interface/CorrelationTemplate.h"
+#include "L1Trigger/L1TGlobal/interface/CorrelationThreeBodyTemplate.h"
 #include "L1Trigger/L1TGlobal/interface/CorrelationWithOverlapRemovalTemplate.h"
 
 // forward declarations
@@ -55,6 +57,7 @@ class TriggerMenu {
               const std::vector<std::vector<EnergySumTemplate> >&,
               const std::vector<std::vector<ExternalTemplate> >&,
               const std::vector<std::vector<CorrelationTemplate> >&,
+              const std::vector<std::vector<CorrelationThreeBodyTemplate> >&,
               const std::vector<std::vector<CorrelationWithOverlapRemovalTemplate> >&,
               const std::vector<std::vector<MuonTemplate> >&,
               const std::vector<std::vector<CaloTemplate> >&,
@@ -131,6 +134,13 @@ class TriggerMenu {
 
   void setVecCorrelationTemplate(const std::vector<std::vector<CorrelationTemplate> >&);
 
+  //
+  inline const std::vector<std::vector<CorrelationThreeBodyTemplate> >& vecCorrelationThreeBodyTemplate() const {
+    return m_vecCorrelationThreeBodyTemplate;
+  }
+
+  void setVecCorrelationThreeBodyTemplate(const std::vector<std::vector<CorrelationThreeBodyTemplate> >&);
+
   //
   inline const std::vector<std::vector<CorrelationWithOverlapRemovalTemplate> >&
   vecCorrelationWithOverlapRemovalTemplate() const {
@@ -214,6 +224,7 @@ class TriggerMenu {
   std::vector<std::vector<ExternalTemplate> > m_vecExternalTemplate;
 
   std::vector<std::vector<CorrelationTemplate> > m_vecCorrelationTemplate;
+  std::vector<std::vector<CorrelationThreeBodyTemplate> > m_vecCorrelationThreeBodyTemplate;
   std::vector<std::vector<CorrelationWithOverlapRemovalTemplate> > m_vecCorrelationWithOverlapRemovalTemplate;
   std::vector<std::vector<MuonTemplate> > m_corMuonTemplate;
   std::vector<std::vector<CaloTemplate> > m_corCaloTemplate;
diff --git a/L1Trigger/L1TGlobal/plugins/L1TGlobalProducer.cc b/L1Trigger/L1TGlobal/plugins/L1TGlobalProducer.cc
index 3584ee55f4355..34e6a526ea58d 100644
--- a/L1Trigger/L1TGlobal/plugins/L1TGlobalProducer.cc
+++ b/L1Trigger/L1TGlobal/plugins/L1TGlobalProducer.cc
@@ -1,6 +1,7 @@
 // L1TGlobalProducer.cc
 //author:   Brian Winer - Ohio State
 //          Vladimir Rekovic - extend for overlap removal
+//          Elisa Fontanesi - extended for three-body correlation conditions
 
 #include "L1Trigger/L1TGlobal/plugins/L1TGlobalProducer.h"
 
@@ -333,6 +334,7 @@ void L1TGlobalProducer::produce(edm::Event& iEvent, const edm::EventSetup& evSet
                                                gtParser.vecEnergySumTemplate(),
                                                gtParser.vecExternalTemplate(),
                                                gtParser.vecCorrelationTemplate(),
+                                               gtParser.vecCorrelationThreeBodyTemplate(),
                                                gtParser.vecCorrelationWithOverlapRemovalTemplate(),
                                                gtParser.corMuonTemplate(),
                                                gtParser.corCaloTemplate(),
diff --git a/L1Trigger/L1TGlobal/plugins/TriggerMenuParser.cc b/L1Trigger/L1TGlobal/plugins/TriggerMenuParser.cc
index 6f632881570fd..d7a33924800e4 100644
--- a/L1Trigger/L1TGlobal/plugins/TriggerMenuParser.cc
+++ b/L1Trigger/L1TGlobal/plugins/TriggerMenuParser.cc
@@ -14,6 +14,9 @@
  *                - correlations with overlap object removal
  *                - displaced muons by R.Cavanaugh
  *
+ * \new features: Elisa Fontanesi                                                      
+ *                - extended for three-body correlation conditions                                         
+ *                                                                
  * $Date$
  * $Revision$
  *
@@ -127,6 +130,11 @@ void l1t::TriggerMenuParser::setVecCorrelationTemplate(
   m_vecCorrelationTemplate = vecCorrelationTempl;
 }
 
+void l1t::TriggerMenuParser::setVecCorrelationThreeBodyTemplate(
+    const std::vector<std::vector<CorrelationThreeBodyTemplate> >& vecCorrelationThreeBodyTempl) {
+  m_vecCorrelationThreeBodyTemplate = vecCorrelationThreeBodyTempl;
+}
+
 void l1t::TriggerMenuParser::setVecCorrelationWithOverlapRemovalTemplate(
     const std::vector<std::vector<CorrelationWithOverlapRemovalTemplate> >& vecCorrelationWithOverlapRemovalTempl) {
   m_vecCorrelationWithOverlapRemovalTemplate = vecCorrelationWithOverlapRemovalTempl;
@@ -199,6 +207,7 @@ void l1t::TriggerMenuParser::parseCondFormats(const L1TUtmTriggerMenu* utmMenu)
   m_vecExternalTemplate.resize(m_numberConditionChips);
 
   m_vecCorrelationTemplate.resize(m_numberConditionChips);
+  m_vecCorrelationThreeBodyTemplate.resize(m_numberConditionChips);
   m_vecCorrelationWithOverlapRemovalTemplate.resize(m_numberConditionChips);
   m_corMuonTemplate.resize(m_numberConditionChips);
   m_corCaloTemplate.resize(m_numberConditionChips);
@@ -302,6 +311,10 @@ void l1t::TriggerMenuParser::parseCondFormats(const L1TUtmTriggerMenu* utmMenu)
                    condition.getType() == esConditionType::InvariantMassUpt) {  // Added for displaced muons
           parseCorrelation(condition, chipNr);
 
+          //parse three-body Correlation Conditions
+        } else if (condition.getType() == esConditionType::InvariantMass3) {
+          parseCorrelationThreeBody(condition, chipNr);
+
           //parse Externals
         } else if (condition.getType() == esConditionType::Externals) {
           parseExternal(condition, chipNr);
@@ -655,7 +668,6 @@ bool l1t::TriggerMenuParser::parseScales(std::map<std::string, tmeventsetup::esS
   std::map<std::string, unsigned int> precisions;
   getPrecisions(precisions, scaleMap);
   for (std::map<std::string, unsigned int>::const_iterator cit = precisions.begin(); cit != precisions.end(); cit++) {
-    //std::cout << cit->first << " = " << cit->second << "\n";
     hasPrecision = true;
   }
 
@@ -2586,7 +2598,7 @@ bool l1t::TriggerMenuParser::parseCorrelation(tmeventsetup::esCondition corrCond
         corrParameter.chargeCorrelation = 1;  //ignore charge correlation
     } else {
       //
-      //  Unitl utm has method to calculate these, do the integer value calculation with precision.
+      //  Until utm has method to calculate these, do the integer value calculation with precision.
       //
       double minV = cut.getMinimum().value;
       double maxV = cut.getMaximum().value;
@@ -2664,10 +2676,10 @@ bool l1t::TriggerMenuParser::parseCorrelation(tmeventsetup::esCondition corrCond
   // loop over legs
   for (size_t jj = 0; jj < objects.size(); jj++) {
     const esObject object = objects.at(jj);
-    //std::cout << "      obj name = " << object.getName() << "\n";
-    //std::cout << "      obj type = " << object.getType() << "\n";
-    //std::cout << "      obj op = " << object.getComparisonOperator() << "\n";
-    //std::cout << "      obj bx = " << object.getBxOffset() << "\n";
+    LogDebug("TriggerMenuParser") << "      obj name = " << object.getName() << "\n";
+    LogDebug("TriggerMenuParser") << "      obj type = " << object.getType() << "\n";
+    LogDebug("TriggerMenuParser") << "      obj op = " << object.getComparisonOperator() << "\n";
+    LogDebug("TriggerMenuParser") << "      obj bx = " << object.getBxOffset() << "\n";
 
     // check the leg type
     if (object.getType() == esObjectType::Muon) {
@@ -2810,6 +2822,151 @@ bool l1t::TriggerMenuParser::parseCorrelation(tmeventsetup::esCondition corrCond
   return true;
 }
 
+//////////////////////////////////////////////////////////////////////////////////////
+/**
+ * parseCorrelationThreeBody Parse a correlation condition between three objects and
+ * insert an entry to the conditions map
+ *
+ * @param node The corresponding node.
+ * @param name The name of the condition.
+ * @param chipNr The number of the chip this condition is located.
+ *
+ * @return "true" if succeeded, "false" if an error occurred.
+ *
+ */
+
+bool l1t::TriggerMenuParser::parseCorrelationThreeBody(tmeventsetup::esCondition corrCond, unsigned int chipNr) {
+  using namespace tmeventsetup;
+
+  std::string condition = "corrThreeBody";
+  std::string particle = "muon";
+  std::string type = l1t2string(corrCond.getType());
+  std::string name = l1t2string(corrCond.getName());
+
+  LogDebug("TriggerMenuParser") << " ****************************************** " << std::endl
+                                << "     (in parseCorrelationThreeBody) " << std::endl
+                                << " condition = " << condition << std::endl
+                                << " particle  = " << particle << std::endl
+                                << " type      = " << type << std::endl
+                                << " name      = " << name << std::endl;
+
+  // create a new correlation condition
+  CorrelationThreeBodyTemplate correlationThreeBodyCond(name);
+
+  // check that the condition does not exist already in the map
+  if (!insertConditionIntoMap(correlationThreeBodyCond, chipNr)) {
+    edm::LogError("TriggerMenuParser") << "    Error: duplicate correlation condition (" << name << ")" << std::endl;
+    return false;
+  }
+
+  // Define some of the quantities to store the parsed information
+  GtConditionType cType = l1t::Type3s;
+
+  // three objects (for sure)
+  const int nrObj = 3;
+
+  // object types and greater equal flag - filled in the loop
+  std::vector<GlobalObject> objType(nrObj);
+  std::vector<GtConditionCategory> condCateg(nrObj);
+
+  // correlation flag and index in the cor*vector
+  const bool corrFlag = true;
+  int corrIndexVal[nrObj] = {-1, -1, -1};
+
+  // Storage of the correlation selection
+  CorrelationThreeBodyTemplate::CorrelationThreeBodyParameter corrThreeBodyParameter;
+
+  // Get the correlation cuts on the legs
+  int cutType = 0;
+  const std::vector<esCut>& cuts = corrCond.getCuts();
+  for (size_t lll = 0; lll < cuts.size(); lll++) {
+    const esCut cut = cuts.at(lll);
+
+    //
+    //  Until utm has method to calculate these, do the integer value calculation with precision.
+    //
+    double minV = cut.getMinimum().value;
+    double maxV = cut.getMaximum().value;
+
+    //Scale down very large numbers out of xml
+    if (maxV > 1.0e8)
+      maxV = 1.0e8;
+
+    if (cut.getCutType() == esCutType::Mass) {
+      LogDebug("TriggerMenuParser") << "CutType: " << cut.getCutType() << "\tMass Cut minV = " << minV
+                                    << "\tMass Cut maxV = " << maxV << " precMin = " << cut.getMinimum().index
+                                    << " precMax = " << cut.getMaximum().index << std::endl;
+      corrThreeBodyParameter.minMassCutValue = (long long)(minV * pow(10., cut.getMinimum().index));
+      corrThreeBodyParameter.maxMassCutValue = (long long)(maxV * pow(10., cut.getMaximum().index));
+      corrThreeBodyParameter.precMassCut = cut.getMinimum().index;
+      cutType = cutType | 0x8;
+    }
+  }
+  corrThreeBodyParameter.corrCutType = cutType;
+
+  // Get the three objects that form the legs
+  const std::vector<esObject>& objects = corrCond.getObjects();
+  if (objects.size() != 3) {
+    edm::LogError("TriggerMenuParser") << "incorrect number of objects for the correlation condition " << name
+                                       << " corrFlag " << corrFlag << std::endl;
+    return false;
+  }
+
+  // Loop over legs
+  for (size_t lll = 0; lll < objects.size(); lll++) {
+    const esObject object = objects.at(lll);
+    LogDebug("TriggerMenuParser") << "      obj name = " << object.getName() << "\n";
+    LogDebug("TriggerMenuParser") << "      obj type = " << object.getType() << "\n";
+    LogDebug("TriggerMenuParser") << "      obj bx = " << object.getBxOffset() << "\n";
+
+    // check the leg type
+    if (object.getType() == esObjectType::Muon) {
+      // we have a muon
+      parseMuonCorr(&object, chipNr);
+      corrIndexVal[lll] = (m_corMuonTemplate[chipNr]).size() - 1;
+
+      //Now set some flags for this subCondition
+      objType[lll] = gtMu;
+      condCateg[lll] = CondMuon;
+
+    } else {
+      edm::LogError("TriggerMenuParser") << "Checked the object Type " << object.getType()
+                                         << " for the correlation condition " << name
+                                         << ": no three muons in the event!" << std::endl;
+    }
+  }  // End loop over legs
+
+  // fill the three-body correlation condition
+  correlationThreeBodyCond.setCondType(cType);
+  correlationThreeBodyCond.setObjectType(objType);
+  correlationThreeBodyCond.setCondChipNr(chipNr);
+
+  correlationThreeBodyCond.setCond0Category(condCateg[0]);
+  correlationThreeBodyCond.setCond1Category(condCateg[1]);
+  correlationThreeBodyCond.setCond2Category(condCateg[2]);
+
+  correlationThreeBodyCond.setCond0Index(corrIndexVal[0]);
+  correlationThreeBodyCond.setCond1Index(corrIndexVal[1]);
+  correlationThreeBodyCond.setCond2Index(corrIndexVal[2]);
+
+  correlationThreeBodyCond.setCorrelationThreeBodyParameter(corrThreeBodyParameter);
+
+  if (edm::isDebugEnabled()) {
+    std::ostringstream myCoutStream;
+    correlationThreeBodyCond.print(myCoutStream);
+    LogTrace("TriggerMenuParser") << myCoutStream.str() << "\n" << std::endl;
+  }
+
+  // insert condition into the map
+  // condition is not duplicate, check was done at the beginning
+
+  (m_vecCorrelationThreeBodyTemplate[chipNr]).push_back(correlationThreeBodyCond);
+
+  //
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////////////////////
 /**
  * parseCorrelationWithOverlapRemoval Parse a correlation condition and
  * insert an entry to the conditions map
@@ -2950,14 +3107,14 @@ bool l1t::TriggerMenuParser::parseCorrelationWithOverlapRemoval(const tmeventset
     return false;
   }
 
-  // loop over legs
+  // Loop over legs
   for (size_t jj = 0; jj < objects.size(); jj++) {
     const esObject& object = objects.at(jj);
-    //std::cout << "      obj name = " << object.getName() << "\n";
-    //std::cout << "      obj type = " << object.getType() << "\n";
-    //std::cout << "      obj op = " << object.getComparisonOperator() << "\n";
-    //std::cout << "      obj bx = " << object.getBxOffset() << "\n";
-    //std::cout << "type = done" << std::endl;
+    LogDebug("TriggerMenuParser") << "      obj name = " << object.getName() << "\n";
+    LogDebug("TriggerMenuParser") << "      obj type = " << object.getType() << "\n";
+    LogDebug("TriggerMenuParser") << "      obj op = " << object.getComparisonOperator() << "\n";
+    LogDebug("TriggerMenuParser") << "      obj bx = " << object.getBxOffset() << "\n";
+    LogDebug("TriggerMenuParser") << "type = done" << std::endl;
 
     // check the leg type
     if (object.getType() == esObjectType::Muon) {
diff --git a/L1Trigger/L1TGlobal/plugins/TriggerMenuParser.h b/L1Trigger/L1TGlobal/plugins/TriggerMenuParser.h
index 11538263d9827..85111e1a0f4bd 100644
--- a/L1Trigger/L1TGlobal/plugins/TriggerMenuParser.h
+++ b/L1Trigger/L1TGlobal/plugins/TriggerMenuParser.h
@@ -17,6 +17,9 @@
  *                - correlations with overlap object removal
  * \author R. Cavanaugh
  *                - displaced muons
+ * \author Elisa Fontanesi                                                                               
+ *                - extended for three-body correlation conditions                                                               
+ *                                                                  
  *
  * $Date$
  * $Revision$
@@ -33,6 +36,7 @@
 #include "L1Trigger/L1TGlobal/interface/CaloTemplate.h"
 #include "L1Trigger/L1TGlobal/interface/EnergySumTemplate.h"
 #include "L1Trigger/L1TGlobal/interface/CorrelationTemplate.h"
+#include "L1Trigger/L1TGlobal/interface/CorrelationThreeBodyTemplate.h"
 #include "L1Trigger/L1TGlobal/interface/CorrelationWithOverlapRemovalTemplate.h"
 #include "L1Trigger/L1TGlobal/interface/ExternalTemplate.h"
 
@@ -133,7 +137,6 @@ namespace l1t {
     void setVecEnergySumTemplate(const std::vector<std::vector<EnergySumTemplate> >&);
 
     //
-
     inline const std::vector<std::vector<ExternalTemplate> >& vecExternalTemplate() const {
       return m_vecExternalTemplate;
     }
@@ -147,6 +150,14 @@ namespace l1t {
 
     void setVecCorrelationTemplate(const std::vector<std::vector<CorrelationTemplate> >&);
 
+    //
+    inline const std::vector<std::vector<CorrelationThreeBodyTemplate> >& vecCorrelationThreeBodyTemplate() const {
+      return m_vecCorrelationThreeBodyTemplate;
+    }
+
+    void setVecCorrelationThreeBodyTemplate(const std::vector<std::vector<CorrelationThreeBodyTemplate> >&);
+
+    //
     inline const std::vector<std::vector<CorrelationWithOverlapRemovalTemplate> >&
     vecCorrelationWithOverlapRemovalTemplate() const {
       return m_vecCorrelationWithOverlapRemovalTemplate;
@@ -277,6 +288,9 @@ namespace l1t {
     /// parse a correlation condition
     bool parseCorrelation(tmeventsetup::esCondition corrCond, unsigned int chipNr = 0);
 
+    /// parse a three-body correlation condition
+    bool parseCorrelationThreeBody(tmeventsetup::esCondition corrCond, unsigned int chipNr = 0);
+
     /// parse a correlation condition with overlap removal
     bool parseCorrelationWithOverlapRemoval(const tmeventsetup::esCondition& corrCond, unsigned int chipNr = 0);
 
@@ -374,6 +388,7 @@ namespace l1t {
     std::vector<std::vector<ExternalTemplate> > m_vecExternalTemplate;
 
     std::vector<std::vector<CorrelationTemplate> > m_vecCorrelationTemplate;
+    std::vector<std::vector<CorrelationThreeBodyTemplate> > m_vecCorrelationThreeBodyTemplate;
     std::vector<std::vector<CorrelationWithOverlapRemovalTemplate> > m_vecCorrelationWithOverlapRemovalTemplate;
     std::vector<std::vector<MuonTemplate> > m_corMuonTemplate;
     std::vector<std::vector<CaloTemplate> > m_corCaloTemplate;
diff --git a/L1Trigger/L1TGlobal/src/CorrThreeBodyCondition.cc b/L1Trigger/L1TGlobal/src/CorrThreeBodyCondition.cc
new file mode 100644
index 0000000000000..fcfc5037477a0
--- /dev/null
+++ b/L1Trigger/L1TGlobal/src/CorrThreeBodyCondition.cc
@@ -0,0 +1,761 @@
+/**
+ * \class CorrThreeBodyCondition
+ *
+ * \orig author: Elisa Fontanesi - Boston University
+ *               CorrCondition and CorrWithOverlapRemovalCondition classes used as a starting point
+ *
+ * Description: L1 Global Trigger three-body correlation conditions:                                                                                     
+ *              evaluation of a three-body correlation condition (= three-muon invariant mass)
+ *
+ */
+
+// this class header
+#include "L1Trigger/L1TGlobal/interface/CorrCondition.h"
+#include "L1Trigger/L1TGlobal/interface/CorrThreeBodyCondition.h"
+
+// system include files
+#include <iostream>
+#include <iomanip>
+
+#include <string>
+#include <vector>
+#include <algorithm>
+
+// user include files
+//   base classes
+#include "L1Trigger/L1TGlobal/interface/CorrelationTemplate.h"
+#include "L1Trigger/L1TGlobal/interface/CorrelationThreeBodyTemplate.h"
+#include "L1Trigger/L1TGlobal/interface/ConditionEvaluation.h"
+
+#include "L1Trigger/L1TGlobal/interface/MuCondition.h"
+#include "L1Trigger/L1TGlobal/interface/MuonTemplate.h"
+#include "L1Trigger/L1TGlobal/interface/GlobalScales.h"
+#include "L1Trigger/L1TGlobal/interface/GlobalBoard.h"
+
+#include "DataFormats/L1Trigger/interface/L1Candidate.h"
+#include "FWCore/MessageLogger/interface/MessageLogger.h"
+#include "FWCore/MessageLogger/interface/MessageDrop.h"
+
+// constructors
+//     default
+l1t::CorrThreeBodyCondition::CorrThreeBodyCondition() : ConditionEvaluation() {}
+
+//     from base template condition (from event setup usually)
+l1t::CorrThreeBodyCondition::CorrThreeBodyCondition(const GlobalCondition* corrTemplate,
+                                                    const GlobalCondition* cond0Condition,
+                                                    const GlobalCondition* cond1Condition,
+                                                    const GlobalCondition* cond2Condition,
+                                                    const GlobalBoard* ptrGTB)
+    : ConditionEvaluation(),
+      m_gtCorrelationThreeBodyTemplate(static_cast<const CorrelationThreeBodyTemplate*>(corrTemplate)),
+      m_gtCond0(cond0Condition),
+      m_gtCond1(cond1Condition),
+      m_gtCond2(cond2Condition),
+      m_uGtB(ptrGTB) {}
+
+// copy constructor
+void l1t::CorrThreeBodyCondition::copy(const l1t::CorrThreeBodyCondition& cp) {
+  m_gtCorrelationThreeBodyTemplate = cp.gtCorrelationThreeBodyTemplate();
+  m_uGtB = cp.getuGtB();
+
+  m_condMaxNumberObjects = cp.condMaxNumberObjects();
+  m_condLastResult = cp.condLastResult();
+  m_combinationsInCond = cp.getCombinationsInCond();
+
+  m_verbosity = cp.m_verbosity;
+}
+
+l1t::CorrThreeBodyCondition::CorrThreeBodyCondition(const l1t::CorrThreeBodyCondition& cp) : ConditionEvaluation() {
+  copy(cp);
+}
+
+// destructor
+l1t::CorrThreeBodyCondition::~CorrThreeBodyCondition() {
+  // empty
+}
+
+// equal operator
+l1t::CorrThreeBodyCondition& l1t::CorrThreeBodyCondition::operator=(const l1t::CorrThreeBodyCondition& cp) {
+  copy(cp);
+  return *this;
+}
+
+///   set the pointer to uGT GlobalBoard
+void l1t::CorrThreeBodyCondition::setuGtB(const GlobalBoard* ptrGTB) { m_uGtB = ptrGTB; }
+
+void l1t::CorrThreeBodyCondition::setScales(const GlobalScales* sc) { m_gtScales = sc; }
+
+// try all object permutations and check spatial correlations, if required
+const bool l1t::CorrThreeBodyCondition::evaluateCondition(const int bxEval) const {
+  if (m_verbosity) {
+    std::ostringstream myCout;
+    m_gtCorrelationThreeBodyTemplate->print(myCout);
+    LogDebug("L1TGlobal") << "Three-body Correlation Condition Evaluation..." << std::endl;
+  }
+
+  bool condResult = false;
+  bool reqObjResult = false;
+
+  // number of objects in the condition (three) and their type
+  int nObjInCond = 3;
+  std::vector<GlobalObject> cndObjTypeVec(nObjInCond);
+
+  // evaluate first the three subconditions (Type1s)
+  const GtConditionCategory cond0Categ = m_gtCorrelationThreeBodyTemplate->cond0Category();
+  const GtConditionCategory cond1Categ = m_gtCorrelationThreeBodyTemplate->cond1Category();
+  const GtConditionCategory cond2Categ = m_gtCorrelationThreeBodyTemplate->cond2Category();
+
+  const MuonTemplate* corrMuon = nullptr;
+
+  CombinationsInCond cond0Comb;
+  CombinationsInCond cond1Comb;
+  CombinationsInCond cond2Comb;
+
+  int cond0bx(0);
+  int cond1bx(0);
+  int cond2bx(0);
+
+  // FIRST OBJECT
+  if (cond0Categ == CondMuon) {
+    LogDebug("L1TGlobal") << "\n --------------------- First muon checks ---------------------" << std::endl;
+    corrMuon = static_cast<const MuonTemplate*>(m_gtCond0);
+    MuCondition muCondition(corrMuon, m_uGtB, 0, 0);
+
+    muCondition.evaluateConditionStoreResult(bxEval);
+    reqObjResult = muCondition.condLastResult();
+
+    cond0Comb = (muCondition.getCombinationsInCond());
+    cond0bx = bxEval + (corrMuon->condRelativeBx());
+    cndObjTypeVec[0] = (corrMuon->objectType())[0];
+
+    if (m_verbosity) {
+      std::ostringstream myCout;
+      muCondition.print(myCout);
+      LogDebug("L1TGlobal") << myCout.str() << std::endl;
+    }
+  } else {
+    // Interested only in three-muon correlations
+    LogDebug("L1TGlobal") << "CondMuon not satisfied for Leg 0" << std::endl;
+    return false;
+  }
+
+  // return if first subcondition is false
+  if (!reqObjResult) {
+    LogDebug("L1TGlobal") << "\n  First subcondition false, second subcondition not evaluated and not printed."
+                          << std::endl;
+    return false;
+  }
+
+  // SECOND OBJECT
+  reqObjResult = false;
+
+  if (cond1Categ == CondMuon) {
+    LogDebug("L1TGlobal") << "\n --------------------- Second muon checks ---------------------" << std::endl;
+    corrMuon = static_cast<const MuonTemplate*>(m_gtCond1);
+    MuCondition muCondition(corrMuon, m_uGtB, 0, 0);
+
+    muCondition.evaluateConditionStoreResult(bxEval);
+    reqObjResult = muCondition.condLastResult();
+
+    cond1Comb = (muCondition.getCombinationsInCond());
+    cond1bx = bxEval + (corrMuon->condRelativeBx());
+    cndObjTypeVec[1] = (corrMuon->objectType())[0];
+
+    if (m_verbosity) {
+      std::ostringstream myCout;
+      muCondition.print(myCout);
+      LogDebug("L1TGlobal") << myCout.str() << std::endl;
+    }
+  }
+
+  else {
+    // Interested only in three-muon correlations
+    LogDebug("L1TGlobal") << "CondMuon not satisfied for Leg 1" << std::endl;
+    return false;
+  }
+
+  // return if second subcondition is false
+  if (!reqObjResult) {
+    LogDebug("L1TGlobal") << "\n  Second subcondition false, third subcondition not evaluated and not printed."
+                          << std::endl;
+    return false;
+  }
+
+  // THIRD OBJECT
+  reqObjResult = false;
+
+  if (cond2Categ == CondMuon) {
+    LogDebug("L1TGlobal") << "\n --------------------- Third muon checks ---------------------" << std::endl;
+    corrMuon = static_cast<const MuonTemplate*>(m_gtCond2);
+    MuCondition muCondition(corrMuon, m_uGtB, 0, 0);
+
+    muCondition.evaluateConditionStoreResult(bxEval);
+    reqObjResult = muCondition.condLastResult();
+
+    cond2Comb = (muCondition.getCombinationsInCond());
+    cond2bx = bxEval + (corrMuon->condRelativeBx());
+    cndObjTypeVec[2] = (corrMuon->objectType())[0];
+
+    if (m_verbosity) {
+      std::ostringstream myCout;
+      muCondition.print(myCout);
+      LogDebug("L1TGlobal") << myCout.str() << std::endl;
+    }
+  }
+
+  else {
+    // Interested only in three-muon correlations
+    LogDebug("L1TGlobal") << "CondMuon not satisfied for Leg 2" << std::endl;
+    return false;
+  }
+
+  // return if third subcondition is false
+  if (!reqObjResult) {
+    return false;
+  } else {
+    LogDebug("L1TGlobal")
+        << "\n"
+        << "Found three objects satisfying subconditions: evaluate three-body correlation requirements.\n"
+        << std::endl;
+  }
+
+  // since we have three good legs get the correlation parameters
+  CorrelationThreeBodyTemplate::CorrelationThreeBodyParameter corrPar =
+      *(m_gtCorrelationThreeBodyTemplate->correlationThreeBodyParameter());
+
+  // vector to store the indices of the objects involved in the condition evaluation
+  SingleCombInCond objectsInComb;
+  objectsInComb.reserve(nObjInCond);
+
+  // clear the m_combinationsInCond vector:
+  // it will store the set of objects satisfying the condition evaluated as true
+  (combinationsInCond()).clear();
+
+  // pointers to objects
+  const BXVector<const l1t::Muon*>* candMuVec = nullptr;
+
+  // make the conversions of the indices, depending on the combination of objects involved
+  int phiIndex0 = 0;
+  double phi0Phy = 0.;
+  int phiIndex1 = 0;
+  double phi1Phy = 0.;
+  int phiIndex2 = 0;
+  double phi2Phy = 0.;
+
+  int etaIndex0 = 0;
+  double eta0Phy = 0.;
+  int etaBin0 = 0;
+  int etaIndex1 = 0;
+  double eta1Phy = 0.;
+  int etaBin1 = 0;
+  int etaIndex2 = 0;
+  double eta2Phy = 0.;
+  int etaBin2 = 0;
+
+  int etIndex0 = 0;
+  int etBin0 = 0;
+  double et0Phy = 0.;
+  int etIndex1 = 0;
+  int etBin1 = 0;
+  double et1Phy = 0.;
+  int etIndex2 = 0;
+  int etBin2 = 0;
+  double et2Phy = 0.;
+
+  // Determine the number of phi bins to get cutoff at pi
+  int phiBound = 0;
+  if (cond0Categ == CondMuon || cond1Categ == CondMuon || cond2Categ == CondMuon) {
+    const GlobalScales::ScaleParameters& par = m_gtScales->getMUScales();
+    phiBound = (int)((par.phiMax - par.phiMin) / par.phiStep) / 2;
+  } else {
+    //Assumes all objects are on same phi scale
+    const GlobalScales::ScaleParameters& par = m_gtScales->getEGScales();
+    phiBound = (int)((par.phiMax - par.phiMin) / par.phiStep) / 2;
+  }
+  LogDebug("L1TGlobal") << "Phi Bound = " << phiBound << std::endl;
+
+  // Keep track of objects for LUTS
+  std::string lutObj0 = "NULL";
+  std::string lutObj1 = "NULL";
+  std::string lutObj2 = "NULL";
+
+  LogTrace("L1TGlobal") << "  Number of objects satisfying the subcondition 0: " << (cond0Comb.size()) << std::endl;
+  LogTrace("L1TGlobal") << "  Number of objects satisfying the subcondition 1: " << (cond1Comb.size()) << std::endl;
+  LogTrace("L1TGlobal") << "  Number of objects satisfying the subcondition 2: " << (cond2Comb.size()) << std::endl;
+
+  ////////////////////////////////
+  // LOOP OVER ALL COMBINATIONS //
+  ////////////////////////////////
+  unsigned int preShift = 0;
+
+  // *** Looking for a set of three objects
+  for (std::vector<SingleCombInCond>::const_iterator it0Comb = cond0Comb.begin(); it0Comb != cond0Comb.end();
+       it0Comb++) {
+    // Type1s: there is 1 object only, no need for a loop, index 0 should be OK in (*it0Comb)[0]
+    // ... but add protection to not crash
+    LogDebug("L1TGlobal") << "Looking at first subcondition" << std::endl;
+    int obj0Index = -1;
+
+    if (!(*it0Comb).empty()) {
+      obj0Index = (*it0Comb)[0];
+    } else {
+      LogTrace("L1TGlobal") << "\n  SingleCombInCond (*it0Comb).size() " << ((*it0Comb).size()) << std::endl;
+      return false;
+    }
+
+    // FIRST OBJECT: Collect the information on the first leg of the correlation
+    if (cond0Categ == CondMuon) {
+      lutObj0 = "MU";
+      candMuVec = m_uGtB->getCandL1Mu();
+      phiIndex0 = (candMuVec->at(cond0bx, obj0Index))->hwPhiAtVtx();  //(*candMuVec)[obj0Index]->phiIndex();
+      etaIndex0 = (candMuVec->at(cond0bx, obj0Index))->hwEtaAtVtx();
+      etIndex0 = (candMuVec->at(cond0bx, obj0Index))->hwPt();
+      etaBin0 = etaIndex0;
+      if (etaBin0 < 0)
+        etaBin0 = m_gtScales->getMUScales().etaBins.size() + etaBin0;  //twos complement
+      // LogDebug("L1TGlobal") << "Muon phi" << phiIndex0 << " eta " << etaIndex0 << " etaBin0 = " << etaBin0  << " et " << etIndex0 << std::endl;
+
+      etBin0 = etIndex0;
+      int ssize = m_gtScales->getMUScales().etBins.size();
+      if (etBin0 >= ssize) {
+        etBin0 = ssize - 1;
+        LogTrace("L1TGlobal") << "MU0 hw et" << etBin0 << " out of scale range.  Setting to maximum.";
+      }
+
+      // Determine Floating Pt numbers for floating point caluclation
+      std::pair<double, double> binEdges = m_gtScales->getMUScales().phiBins.at(phiIndex0);
+      phi0Phy = 0.5 * (binEdges.second + binEdges.first);
+      binEdges = m_gtScales->getMUScales().etaBins.at(etaBin0);
+      eta0Phy = 0.5 * (binEdges.second + binEdges.first);
+      binEdges = m_gtScales->getMUScales().etBins.at(etBin0);
+      et0Phy = 0.5 * (binEdges.second + binEdges.first);
+      LogDebug("L1TGlobal") << "Found all quantities for MU0" << std::endl;
+    } else {
+      // Interested only in three-muon correlations
+      LogDebug("L1TGlobal") << "CondMuon not satisfied for Leg 0" << std::endl;
+      return false;
+    }
+
+    // SECOND OBJECT: Now loop over the second leg to get its information
+    for (std::vector<SingleCombInCond>::const_iterator it1Comb = cond1Comb.begin(); it1Comb != cond1Comb.end();
+         it1Comb++) {
+      LogDebug("L1TGlobal") << "Looking at second subdondition" << std::endl;
+      int obj1Index = -1;
+
+      if (!(*it1Comb).empty()) {
+        obj1Index = (*it1Comb)[0];
+      } else {
+        LogTrace("L1TGlobal") << "\n  SingleCombInCond (*it1Comb).size() " << ((*it1Comb).size()) << std::endl;
+        return false;
+      }
+
+      //If we are dealing with the same object type avoid the two legs
+      // either being the same object
+      if (cndObjTypeVec[0] == cndObjTypeVec[1] && obj0Index == obj1Index && cond0bx == cond1bx) {
+        LogDebug("L1TGlobal") << "Corr Condition looking at same leg...skip" << std::endl;
+        continue;
+      }
+
+      if (cond1Categ == CondMuon) {
+        lutObj1 = "MU";
+        candMuVec = m_uGtB->getCandL1Mu();
+        phiIndex1 = (candMuVec->at(cond1bx, obj1Index))->hwPhiAtVtx();  //(*candMuVec)[obj0Index]->phiIndex();
+        etaIndex1 = (candMuVec->at(cond1bx, obj1Index))->hwEtaAtVtx();
+        etIndex1 = (candMuVec->at(cond1bx, obj1Index))->hwPt();
+        etaBin1 = etaIndex1;
+        if (etaBin1 < 0)
+          etaBin1 = m_gtScales->getMUScales().etaBins.size() + etaBin1;
+        // LogDebug("L1TGlobal") << "Muon phi" << phiIndex1 << " eta " << etaIndex1 << " etaBin1 = " << etaBin1  << " et " << etIndex1 << std::endl;
+
+        etBin1 = etIndex1;
+        int ssize = m_gtScales->getMUScales().etBins.size();
+        if (etBin1 >= ssize) {
+          LogTrace("L1TGlobal") << "MU1 hw et" << etBin1 << " out of scale range.  Setting to maximum.";
+          etBin1 = ssize - 1;
+        }
+
+        // Determine Floating Pt numbers for floating point calculation
+        std::pair<double, double> binEdges = m_gtScales->getMUScales().phiBins.at(phiIndex1);
+        phi1Phy = 0.5 * (binEdges.second + binEdges.first);
+        binEdges = m_gtScales->getMUScales().etaBins.at(etaBin1);
+        eta1Phy = 0.5 * (binEdges.second + binEdges.first);
+        binEdges = m_gtScales->getMUScales().etBins.at(etBin1);
+        et1Phy = 0.5 * (binEdges.second + binEdges.first);
+        LogDebug("L1TGlobal") << "Found all quantities for MU1" << std::endl;
+      } else {
+        // Interested only in three-muon correlations
+        LogDebug("L1TGlobal") << "CondMuon not satisfied for Leg 1" << std::endl;
+        return false;
+      }
+
+      // THIRD OBJECT: Finally loop over the third leg to get its information
+      for (std::vector<SingleCombInCond>::const_iterator it2Comb = cond2Comb.begin(); it2Comb != cond2Comb.end();
+           it2Comb++) {
+        LogDebug("L1TGlobal") << "Looking at the third object for the three-body condition" << std::endl;
+        int obj2Index = -1;
+
+        if (!(*it2Comb).empty()) {
+          obj2Index = (*it2Comb)[0];
+        } else {
+          LogTrace("L1TGlobal") << "\n  SingleCombInCond (*it2Comb).size() " << ((*it2Comb).size()) << std::endl;
+          return false;
+        }
+
+        //If we are dealing with the same object type avoid the two legs
+        // either being the same object
+        if ((cndObjTypeVec[0] == cndObjTypeVec[2] && obj0Index == obj2Index && cond0bx == cond2bx) ||
+            (cndObjTypeVec[1] == cndObjTypeVec[2] && obj1Index == obj2Index && cond1bx == cond2bx)) {
+          LogDebug("L1TGlobal") << "Corr Condition looking at same leg...skip" << std::endl;
+          continue;
+        }
+
+        if (cond2Categ == CondMuon) {
+          lutObj2 = "MU";
+          candMuVec = m_uGtB->getCandL1Mu();
+          phiIndex2 = (candMuVec->at(cond2bx, obj2Index))->hwPhiAtVtx();  //(*candMuVec)[obj0Index]->phiIndex();
+          etaIndex2 = (candMuVec->at(cond2bx, obj2Index))->hwEtaAtVtx();
+          etIndex2 = (candMuVec->at(cond2bx, obj2Index))->hwPt();
+          etaBin2 = etaIndex2;
+          if (etaBin2 < 0)
+            etaBin2 = m_gtScales->getMUScales().etaBins.size() + etaBin2;
+
+          etBin2 = etIndex2;
+          int ssize = m_gtScales->getMUScales().etBins.size();
+          if (etBin2 >= ssize) {
+            LogTrace("L1TGlobal") << "MU2 hw et" << etBin2 << " out of scale range.  Setting to maximum.";
+            etBin2 = ssize - 1;
+          }
+
+          // Determine Floating Pt numbers for floating point calculation
+          std::pair<double, double> binEdges = m_gtScales->getMUScales().phiBins.at(phiIndex2);
+          phi2Phy = 0.5 * (binEdges.second + binEdges.first);
+          binEdges = m_gtScales->getMUScales().etaBins.at(etaBin2);
+          eta2Phy = 0.5 * (binEdges.second + binEdges.first);
+          binEdges = m_gtScales->getMUScales().etBins.at(etBin2);
+          et2Phy = 0.5 * (binEdges.second + binEdges.first);
+          LogDebug("L1TGlobal") << "Found all quantities for MU2" << std::endl;
+        }
+
+        else {
+          // Interested only in three-muon correlations
+          LogDebug("L1TGlobal") << "CondMuon not satisfied for Leg 2" << std::endl;
+          return false;
+        };
+
+        if (m_verbosity) {
+          LogDebug("L1TGlobal") << "\n >>>>>> THREE-MUON EVENT!" << std::endl;
+          LogDebug("L1TGlobal") << ">>>>>> Object involved in the three-body correlation condition are ["
+                                << l1TGtObjectEnumToString(cndObjTypeVec[0]) << ", "
+                                << l1TGtObjectEnumToString(cndObjTypeVec[1]) << ", "
+                                << l1TGtObjectEnumToString(cndObjTypeVec[2]) << "] with collection indices ["
+                                << obj0Index << ", " << obj1Index << obj2Index << "] "
+                                << " having: \n"
+                                << "     Et  values  = [" << etIndex0 << ", " << etIndex1 << ", " << etIndex2 << "]\n"
+                                << "     phi indices = [" << phiIndex0 << ", " << phiIndex1 << ", " << phiIndex2
+                                << "]\n"
+                                << "     eta indices = [" << etaIndex0 << ", " << etaIndex1 << ", " << etaIndex2
+                                << "]\n"
+                                << std::endl;
+        }
+
+        // Now perform the desired correlation on these three objects:
+        //reqResult will be set true in case all checks were successful for a given combination of three muons
+        bool reqResult = false;
+
+        // Clear the vector containing indices of the objects of the combination involved in the condition evaluation
+        objectsInComb.clear();
+        objectsInComb.push_back(obj0Index);
+        objectsInComb.push_back(obj1Index);
+        objectsInComb.push_back(obj2Index);
+
+        // Delta eta and phi calculations needed to evaluate the three-body invariant mass
+        double deltaPhiPhy_01 = fabs(phi1Phy - phi0Phy);
+        if (deltaPhiPhy_01 > M_PI)
+          deltaPhiPhy_01 = 2. * M_PI - deltaPhiPhy_01;
+        double deltaEtaPhy_01 = fabs(eta1Phy - eta0Phy);
+
+        double deltaPhiPhy_02 = fabs(phi2Phy - phi0Phy);
+        if (deltaPhiPhy_02 > M_PI)
+          deltaPhiPhy_02 = 2. * M_PI - deltaPhiPhy_02;
+        double deltaEtaPhy_02 = fabs(eta2Phy - eta0Phy);
+
+        double deltaPhiPhy_12 = fabs(phi2Phy - phi1Phy);
+        if (deltaPhiPhy_12 > M_PI)
+          deltaPhiPhy_12 = 2. * M_PI - deltaPhiPhy_12;
+        double deltaEtaPhy_12 = fabs(eta2Phy - eta1Phy);
+
+        // Determine the integer based delta eta and delta phi
+        int deltaPhiFW_01 = abs(phiIndex0 - phiIndex1);
+        if (deltaPhiFW_01 >= phiBound)
+          deltaPhiFW_01 = 2 * phiBound - deltaPhiFW_01;
+        std::string lutName_01 = lutObj0;
+        lutName_01 += "-";
+        lutName_01 += lutObj1;
+        long long deltaPhiLUT_01 = m_gtScales->getLUT_DeltaPhi(lutName_01, deltaPhiFW_01);
+        unsigned int precDeltaPhiLUT_01 = m_gtScales->getPrec_DeltaPhi(lutName_01);
+
+        int deltaEtaFW_01 = abs(etaIndex0 - etaIndex1);
+        long long deltaEtaLUT_01 = 0;
+        unsigned int precDeltaEtaLUT_01 = 0;
+        deltaEtaLUT_01 = m_gtScales->getLUT_DeltaEta(lutName_01, deltaEtaFW_01);
+        precDeltaEtaLUT_01 = m_gtScales->getPrec_DeltaEta(lutName_01);
+        ///
+        int deltaPhiFW_02 = abs(phiIndex0 - phiIndex2);
+        if (deltaPhiFW_02 >= phiBound)
+          deltaPhiFW_02 = 2 * phiBound - deltaPhiFW_02;
+        std::string lutName_02 = lutObj0;
+        lutName_02 += "-";
+        lutName_02 += lutObj2;
+        long long deltaPhiLUT_02 = m_gtScales->getLUT_DeltaPhi(lutName_02, deltaPhiFW_02);
+        unsigned int precDeltaPhiLUT_02 = m_gtScales->getPrec_DeltaPhi(lutName_02);
+
+        int deltaEtaFW_02 = abs(etaIndex0 - etaIndex2);
+        long long deltaEtaLUT_02 = 0;
+        unsigned int precDeltaEtaLUT_02 = 0;
+        deltaEtaLUT_02 = m_gtScales->getLUT_DeltaEta(lutName_02, deltaEtaFW_02);
+        precDeltaEtaLUT_02 = m_gtScales->getPrec_DeltaEta(lutName_02);
+        ///
+        int deltaPhiFW_12 = abs(phiIndex1 - phiIndex2);
+        if (deltaPhiFW_12 >= phiBound)
+          deltaPhiFW_12 = 2 * phiBound - deltaPhiFW_12;
+        std::string lutName_12 = lutObj1;
+        lutName_12 += "-";
+        lutName_12 += lutObj2;
+        long long deltaPhiLUT_12 = m_gtScales->getLUT_DeltaPhi(lutName_12, deltaPhiFW_12);
+        unsigned int precDeltaPhiLUT_12 = m_gtScales->getPrec_DeltaPhi(lutName_12);
+
+        int deltaEtaFW_12 = abs(etaIndex1 - etaIndex2);
+        long long deltaEtaLUT_12 = 0;
+        unsigned int precDeltaEtaLUT_12 = 0;
+        deltaEtaLUT_12 = m_gtScales->getLUT_DeltaEta(lutName_12, deltaEtaFW_12);
+        precDeltaEtaLUT_12 = m_gtScales->getPrec_DeltaEta(lutName_12);
+        ///
+
+        LogDebug("L1TGlobal") << "### Obj0 phiFW = " << phiIndex0 << " Obj1 phiFW = " << phiIndex1 << "\n"
+                              << "    DeltaPhiFW = " << deltaPhiFW_01 << "    LUT Name 01= " << lutName_01
+                              << " Prec = " << precDeltaPhiLUT_01 << "\n"
+                              << "    LUT Name 02= " << lutName_02 << " Prec = " << precDeltaPhiLUT_02 << "\n"
+                              << "    LUT Name 12= " << lutName_12 << " Prec = " << precDeltaPhiLUT_12 << "\n"
+                              << "    DeltaPhiLUT_01 = " << deltaPhiLUT_01 << "\n"
+                              << "    DeltaPhiLUT_02 = " << deltaPhiLUT_02 << "\n"
+                              << "    DeltaPhiLUT_12 = " << deltaPhiLUT_12 << "\n"
+                              << "### Obj0 etaFW = " << etaIndex0 << " Obj1 etaFW = " << etaIndex1 << "\n"
+                              << "    DeltaEtaFW = " << deltaEtaFW_01 << "    LUT Name 01 = " << lutName_01
+                              << " Prec 01 = " << precDeltaEtaLUT_01 << "\n"
+                              << "    LUT Name 02 = " << lutName_02 << " Prec 02 = " << precDeltaEtaLUT_02 << "\n"
+                              << "    LUT Name 12 = " << lutName_12 << " Prec 12 = " << precDeltaEtaLUT_12 << "\n"
+                              << "    DeltaEtaLUT_01 = " << deltaEtaLUT_01 << "    DeltaEtaLUT_02 = " << deltaEtaLUT_02
+                              << "    DeltaEtaLUT_12 = " << deltaEtaLUT_12 << std::endl;
+
+        if (corrPar.corrCutType & 0x9) {
+          //invariant mass calculation based for each pair on
+          // M = sqrt(2*p1*p2(cosh(eta1-eta2) - cos(phi1 - phi2)))
+          // but we calculate (1/2)M^2
+          //
+          double cosDeltaPhiPhy_01 = cos(deltaPhiPhy_01);
+          double coshDeltaEtaPhy_01 = cosh(deltaEtaPhy_01);
+          double massSqPhy_01 = et0Phy * et1Phy * (coshDeltaEtaPhy_01 - cosDeltaPhiPhy_01);
+
+          long long cosDeltaPhiLUT_01 = m_gtScales->getLUT_DeltaPhi_Cos(lutName_01, deltaPhiFW_01);
+          unsigned int precCosLUT_01 = m_gtScales->getPrec_DeltaPhi_Cos(lutName_01);
+
+          long long coshDeltaEtaLUT_01;
+          coshDeltaEtaLUT_01 = m_gtScales->getLUT_DeltaEta_Cosh(lutName_01, deltaEtaFW_01);
+          unsigned int precCoshLUT_01 = m_gtScales->getPrec_DeltaEta_Cosh(lutName_01);
+          if (precCoshLUT_01 - precCosLUT_01 != 0)
+            LogDebug("L1TGlobal") << "Warning: Cos and Cosh LUTs on different Precision" << std::endl;
+
+          double cosDeltaPhiPhy_02 = cos(deltaPhiPhy_02);
+          double coshDeltaEtaPhy_02 = cosh(deltaEtaPhy_02);
+          if (corrPar.corrCutType & 0x10)
+            coshDeltaEtaPhy_02 = 1.;
+          double massSqPhy_02 = et0Phy * et2Phy * (coshDeltaEtaPhy_02 - cosDeltaPhiPhy_02);
+          long long cosDeltaPhiLUT_02 = m_gtScales->getLUT_DeltaPhi_Cos(lutName_02, deltaPhiFW_02);
+          unsigned int precCosLUT_02 = m_gtScales->getPrec_DeltaPhi_Cos(lutName_02);
+          long long coshDeltaEtaLUT_02;
+          if (corrPar.corrCutType & 0x10) {
+            coshDeltaEtaLUT_02 = 1 * pow(10, precCosLUT_02);
+          } else {
+            coshDeltaEtaLUT_02 = m_gtScales->getLUT_DeltaEta_Cosh(lutName_02, deltaEtaFW_02);
+            unsigned int precCoshLUT_02 = m_gtScales->getPrec_DeltaEta_Cosh(lutName_02);
+            if (precCoshLUT_02 - precCosLUT_02 != 0)
+              LogDebug("L1TGlobal") << "Warning: Cos and Cosh LUTs on different Precision" << std::endl;
+          }
+
+          double cosDeltaPhiPhy_12 = cos(deltaPhiPhy_12);
+          double coshDeltaEtaPhy_12 = cosh(deltaEtaPhy_12);
+          if (corrPar.corrCutType & 0x10)
+            coshDeltaEtaPhy_12 = 1.;
+          double massSqPhy_12 = et1Phy * et2Phy * (coshDeltaEtaPhy_12 - cosDeltaPhiPhy_12);
+          long long cosDeltaPhiLUT_12 = m_gtScales->getLUT_DeltaPhi_Cos(lutName_12, deltaPhiFW_12);
+          unsigned int precCosLUT_12 = m_gtScales->getPrec_DeltaPhi_Cos(lutName_12);
+          long long coshDeltaEtaLUT_12;
+          if (corrPar.corrCutType & 0x10) {
+            coshDeltaEtaLUT_12 = 1 * pow(10, precCosLUT_12);
+          } else {
+            coshDeltaEtaLUT_12 = m_gtScales->getLUT_DeltaEta_Cosh(lutName_12, deltaEtaFW_12);
+            unsigned int precCoshLUT_12 = m_gtScales->getPrec_DeltaEta_Cosh(lutName_12);
+            if (precCoshLUT_12 - precCosLUT_12 != 0)
+              LogDebug("L1TGlobal") << "Warning: Cos and Cosh LUTs on different Precision" << std::endl;
+          }
+
+          std::string lutName = lutObj0;
+          lutName += "-ET";
+          long long ptObj0 = m_gtScales->getLUT_Pt("Mass_" + lutName, etIndex0);
+          unsigned int precPtLUTObj0 = m_gtScales->getPrec_Pt("Mass_" + lutName);
+
+          lutName = lutObj1;
+          lutName += "-ET";
+          long long ptObj1 = m_gtScales->getLUT_Pt("Mass_" + lutName, etIndex1);
+          unsigned int precPtLUTObj1 = m_gtScales->getPrec_Pt("Mass_" + lutName);
+
+          lutName = lutObj2;
+          lutName += "-ET";
+          long long ptObj2 = m_gtScales->getLUT_Pt("Mass_" + lutName, etIndex2);
+          unsigned int precPtLUTObj2 = m_gtScales->getPrec_Pt("Mass_" + lutName);
+
+          // Pt and Angles are at different precission.
+          long long massSq_01 = ptObj0 * ptObj1 * (coshDeltaEtaLUT_01 - cosDeltaPhiLUT_01);
+          long long massSq_02 = ptObj0 * ptObj2 * (coshDeltaEtaLUT_02 - cosDeltaPhiLUT_02);
+          long long massSq_12 = ptObj1 * ptObj2 * (coshDeltaEtaLUT_12 - cosDeltaPhiLUT_12);
+
+          //Note: There is an assumption here that Cos and Cosh have the same precission
+          //unsigned int preShift_01 = precPtLUTObj0 + precPtLUTObj1 + precCosLUT - corrPar.precMassCut;
+          unsigned int preShift_01 = precPtLUTObj0 + precPtLUTObj1 + precCosLUT_01 - corrPar.precMassCut;
+          unsigned int preShift_02 = precPtLUTObj0 + precPtLUTObj2 + precCosLUT_02 - corrPar.precMassCut;
+          unsigned int preShift_12 = precPtLUTObj1 + precPtLUTObj2 + precCosLUT_12 - corrPar.precMassCut;
+
+          LogDebug("L1TGlobal") << "####################################\n";
+          LogDebug("L1TGlobal")
+              << "    Testing the dimuon invariant mass between the FIRST PAIR 0-1 (" << lutObj0 << "," << lutObj1
+              << ") \n"
+              //<< (long long)(corrPar.minMassCutValue * pow(10, preShift_01)) << ","
+              //<< (long long)(corrPar.maxMassCutValue * pow(10, preShift_01))
+              //<< "] with precision = " << corrPar.precMassCut << "\n"
+              //<< "    deltaPhiLUT  = " << deltaPhiLUT_01 << "  cosLUT  = " << cosDeltaPhiLUT_01 << "\n"
+              //<< "    deltaEtaLUT  = " << deltaEtaLUT_01 << "  coshLUT = " << coshDeltaEtaLUT_01 << "\n"
+              //<< "    etIndex0     = " << etIndex0 << "    pt0LUT      = " << ptObj0
+              //<< " PhyEt0 = " << et0Phy << "\n"
+              //<< "    etIndex1     = " << etIndex1 << "    pt1LUT      = " << ptObj1
+              //<< " PhyEt1 = " << et1Phy << "\n"
+              << "    massSq/2     = " << massSq_01 << "\n"
+              << "    Precision Shift = " << preShift_01 << "\n"
+              << "    massSq   (shift)= " << (massSq_01 / pow(10, preShift_01 + corrPar.precMassCut))
+              << "\n"
+              //<< "    deltaPhiPhy  = " << deltaPhiPhy_01 << "  cos() = " << cosDeltaPhiPhy_01 << "\n"
+              //<< "    deltaEtaPhy  = " << deltaEtaPhy_01 << "  cosh()= " << coshDeltaEtaPhy_01 << "\n"
+              << "    massSqPhy/2  = " << massSqPhy_01 << "  sqrt(|massSq|) = " << sqrt(fabs(2. * massSqPhy_01))
+              << std::endl;
+
+          LogDebug("L1TGlobal") << "####################################\n";
+          LogDebug("L1TGlobal")
+              << "    Testing the dimuon invariant mass between the SECOND PAIR 0-2 (" << lutObj0 << "," << lutObj2
+              << ") \n"
+              //<< (long long)(corrPar.minMassCutValue * pow(10, preShift_02)) << ","
+              //<< (long long)(corrPar.maxMassCutValue * pow(10, preShift_02))
+              //<< "] with precision = " << corrPar.precMassCut << "\n"
+              //<< "    deltaPhiLUT  = " << deltaPhiLUT_02 << "  cosLUT  = " << cosDeltaPhiLUT_02 << "\n"
+              //<< "    deltaEtaLUT  = " << deltaEtaLUT_02 << "  coshLUT = " << coshDeltaEtaLUT_02 << "\n"
+              //<< "    etIndex0     = " << etIndex0 << "    pt0LUT      = " << ptObj0
+              //<< " PhyEt0 = " << et0Phy << "\n"
+              //<< "    etIndex2     = " << etIndex2 << "    pt2LUT      = " << ptObj2
+              //<< " PhyEt2 = " << et2Phy << "\n"
+              << "    massSq/2     = " << massSq_02 << "\n"
+              << "    Precision Shift = " << preShift_02 << "\n"
+              << "    massSq   (shift)= " << (massSq_02 / pow(10, preShift_02 + corrPar.precMassCut))
+              << "\n"
+              //<< "    deltaPhiPhy  = " << deltaPhiPhy_02 << "  cos() = " << cosDeltaPhiPhy_02 << "\n"
+              //<< "    deltaEtaPhy  = " << deltaEtaPhy_02 << "  cosh()= " << coshDeltaEtaPhy_02 << "\n"
+              << "    massSqPhy/2  = " << massSqPhy_02 << "  sqrt(|massSq|) = " << sqrt(fabs(2. * massSqPhy_02))
+              << std::endl;
+
+          LogDebug("L1TGlobal") << "####################################\n";
+          LogDebug("L1TGlobal")
+              << "    Testing the dimuon invariant mass between the THIRD PAIR 1-2 (" << lutObj1 << "," << lutObj2
+              << ") \n"
+              //<< (long long)(corrPar.minMassCutValue * pow(10, preShift_12)) << ","
+              //<< (long long)(corrPar.maxMassCutValue * pow(10, preShift_12))
+              //<< "] with precision = " << corrPar.precMassCut << "\n"
+              //<< "    deltaPhiLUT  = " << deltaPhiLUT_12 << "  cosLUT  = " << cosDeltaPhiLUT_12 << "\n"
+              //<< "    deltaEtaLUT  = " << deltaEtaLUT_12 << "  coshLUT = " << coshDeltaEtaLUT_12 << "\n"
+              //<< "    etIndex1     = " << etIndex1 << "    pt1LUT      = " << ptObj1
+              //<< " PhyEt1 = " << et0Phy << "\n"
+              //<< "    etIndex2     = " << etIndex2 << "    pt2LUT      = " << ptObj2
+              //<< " PhyEt2 = " << et2Phy << "\n"
+              << "    massSq/2     = " << massSq_12 << "\n"
+              << "    Precision Shift = " << preShift_12 << "\n"
+              << "    massSq   (shift)= " << (massSq_12 / pow(10, preShift_12 + corrPar.precMassCut))
+              << "\n"
+              //<< "    deltaPhiPhy  = " << deltaPhiPhy_12 << "  cos() = " << cosDeltaPhiPhy_12 << "\n"
+              //<< "    deltaEtaPhy  = " << deltaEtaPhy_12 << "  cosh()= " << coshDeltaEtaPhy_12 << "\n"
+              << "    massSqPhy/2  = " << massSqPhy_12 << "  sqrt(|massSq|) = " << sqrt(fabs(2. * massSqPhy_12))
+              << std::endl;
+
+          LogDebug("L1TGlobal") << "\n ########### THREE-BODY INVARIANT MASS #########################\n";
+          long long massSq = 0;
+
+          if (preShift_01 == preShift_02 && preShift_01 == preShift_12 && preShift_02 == preShift_12) {
+            LogDebug("L1TGlobal") << "Check the preshift value: " << preShift_01 << " = " << preShift_02 << " = "
+                                  << preShift_12 << std::endl;
+            preShift = preShift_01;
+          } else {
+            LogDebug("L1TGlobal")
+                << "Preshift values considered for the sum of the dimuon invariant masses are different!" << std::endl;
+          }
+
+          if ((massSq_01 != massSq_02) && (massSq_01 != massSq_12) && (massSq_02 != massSq_12)) {
+            massSq = massSq_01 + massSq_02 + massSq_12;
+            LogDebug("L1TGlobal") << "massSq = " << massSq << std::endl;
+          } else {
+            LogDebug("L1TGlobal") << "Same pair of muons considered, three-body invariant mass do not computed"
+                                  << std::endl;
+          }
+
+          if (massSq >= 0 && massSq >= (long long)(corrPar.minMassCutValue * pow(10, preShift)) &&
+              massSq <= (long long)(corrPar.maxMassCutValue * pow(10, preShift))) {
+            LogDebug("L1TGlobal") << "    Passed Invariant Mass Cut ["
+                                  << (long long)(corrPar.minMassCutValue * pow(10, preShift)) << ","
+                                  << (long long)(corrPar.maxMassCutValue * pow(10, preShift)) << "]" << std::endl;
+            reqResult = true;
+          } else {
+            LogDebug("L1TGlobal") << "    Failed Invariant Mass Cut ["
+                                  << (long long)(corrPar.minMassCutValue * pow(10, preShift)) << ","
+                                  << (long long)(corrPar.maxMassCutValue * pow(10, preShift)) << "]" << std::endl;
+            reqResult = false;
+          }
+        }
+
+        if (reqResult) {
+          condResult = true;
+          (combinationsInCond()).push_back(objectsInComb);
+        }
+
+      }  //end loop over third leg
+    }    //end loop over second leg
+  }      //end loop over first leg
+
+  if (m_verbosity && condResult) {
+    LogDebug("L1TGlobal") << " pass(es) the correlation condition.\n" << std::endl;
+  }
+  return condResult;
+}
+
+/**
+ * checkObjectParameter - Compare a single particle with a numbered condition.
+ *
+ * @param iCondition The number of the condition.
+ * @param cand The candidate to compare.
+ *
+ * @return The result of the comparison (false if a condition does not exist).
+ */
+
+const bool l1t::CorrThreeBodyCondition::checkObjectParameter(const int iCondition, const l1t::L1Candidate& cand) const {
+  return true;
+}
+
+void l1t::CorrThreeBodyCondition::print(std::ostream& myCout) const {
+  myCout << "Dummy Print for CorrThreeBodyCondition" << std::endl;
+  m_gtCorrelationThreeBodyTemplate->print(myCout);
+
+  ConditionEvaluation::print(myCout);
+}
diff --git a/L1Trigger/L1TGlobal/src/CorrelationThreeBodyTemplate.cc b/L1Trigger/L1TGlobal/src/CorrelationThreeBodyTemplate.cc
new file mode 100644
index 0000000000000..6afb5602fce27
--- /dev/null
+++ b/L1Trigger/L1TGlobal/src/CorrelationThreeBodyTemplate.cc
@@ -0,0 +1,198 @@
+/**
+ * \class CorrelationThreeBodyTemplate
+ *
+ * Description: L1 Global Trigger three-body correlation template:                                                                                                               
+ *              include invariant mass calculation for three-muon events                                                                                                                                   
+ *
+ * Implementation:
+ *    <TODO: enter implementation details>
+ *
+ * \author: Elisa Fontanesi - Boston University                                                                                                                                                            
+ *          CorrelationTemplate and CorrelationWithOverlapRemovalTemplate classes used as a starting point                                                                           
+ *
+ * $Date$
+ * $Revision$
+ *
+ */
+
+// this class header
+#include "L1Trigger/L1TGlobal/interface/CorrelationThreeBodyTemplate.h"
+
+// system include files
+
+#include <iostream>
+#include <iomanip>
+
+// user include files
+//   base class
+
+// forward declarations
+
+// constructors
+//   default
+
+CorrelationThreeBodyTemplate::CorrelationThreeBodyTemplate() : GlobalCondition() {
+  m_condCategory = l1t::CondCorrelationThreeBody;
+  m_condType = l1t::Type3s;
+  m_condChipNr = -1;
+
+  // there are in fact three objects according to m_condType = l1t::Type3s as defined in CondFormats/L1TObjects/src/L1GtCondition.cc
+  int nObjects = nrObjects();
+
+  if (nObjects > 0) {
+    m_objectType.reserve(nObjects);
+  }
+
+  m_cond0Category = l1t::CondNull;
+  m_cond1Category = l1t::CondNull;
+  m_cond2Category = l1t::CondNull;
+  m_cond0Index = -1;
+  m_cond1Index = -1;
+  m_cond2Index = -1;
+}
+
+//   from condition name
+CorrelationThreeBodyTemplate::CorrelationThreeBodyTemplate(const std::string& cName) : GlobalCondition(cName) {
+  m_condCategory = l1t::CondCorrelationThreeBody;
+  m_condType = l1t::Type3s;
+  m_condChipNr = -1;
+
+  // there are in fact three objects according to m_condType = l1t::Type3s as defined in CondFormats/L1TObjects/src/L1GtCondition.cc
+  int nObjects = nrObjects();
+
+  if (nObjects > 0) {
+    m_objectType.reserve(nObjects);
+  }
+
+  m_cond0Category = l1t::CondNull;
+  m_cond1Category = l1t::CondNull;
+  m_cond2Category = l1t::CondNull;
+  m_cond0Index = -1;
+  m_cond1Index = -1;
+  m_cond2Index = -1;
+}
+
+//   from condition name, the category of first sub-condition, the category of the
+//   second sub-condition, the index of first sub-condition in the cor* vector,
+//   the index of second sub-condition in the cor* vector
+CorrelationThreeBodyTemplate::CorrelationThreeBodyTemplate(const std::string& cName,
+                                                           const l1t::GtConditionCategory& cond0Cat,
+                                                           const l1t::GtConditionCategory& cond1Cat,
+                                                           const l1t::GtConditionCategory& cond2Cat,
+                                                           const int cond0Index,
+                                                           const int cond1index,
+                                                           const int cond2index)
+    : GlobalCondition(cName),
+      m_cond0Category(cond0Cat),
+      m_cond1Category(cond1Cat),
+      m_cond2Category(cond2Cat),
+      m_cond0Index(cond0Index),
+      m_cond1Index(cond1index),
+      m_cond2Index(cond2index)
+
+{
+  m_condCategory = l1t::CondCorrelationThreeBody;
+  m_condType = l1t::Type3s;
+  m_condChipNr = -1;
+
+  // there are in fact three objects according to m_condType = l1t::Type3s as defined in CondFormats/L1TObjects/src/L1GtCondition.cc
+  int nObjects = nrObjects();
+
+  if (nObjects > 0) {
+    m_objectType.resize(nObjects);
+  }
+}
+
+// copy constructor
+CorrelationThreeBodyTemplate::CorrelationThreeBodyTemplate(const CorrelationThreeBodyTemplate& cp)
+    : GlobalCondition(cp.m_condName) {
+  copy(cp);
+}
+
+// destructor
+CorrelationThreeBodyTemplate::~CorrelationThreeBodyTemplate() {
+  // empty now
+}
+
+// assign operator
+CorrelationThreeBodyTemplate& CorrelationThreeBodyTemplate::operator=(const CorrelationThreeBodyTemplate& cp) {
+  copy(cp);
+  return *this;
+}
+
+// set the category of the three sub-conditions
+void CorrelationThreeBodyTemplate::setCond0Category(const l1t::GtConditionCategory& condCateg) {
+  m_cond0Category = condCateg;
+}
+void CorrelationThreeBodyTemplate::setCond1Category(const l1t::GtConditionCategory& condCateg) {
+  m_cond1Category = condCateg;
+}
+void CorrelationThreeBodyTemplate::setCond2Category(const l1t::GtConditionCategory& condCateg) {
+  m_cond2Category = condCateg;
+}
+
+// set the index of the three sub-conditions in the cor* vector from menu
+void CorrelationThreeBodyTemplate::setCond0Index(const int& condIndex) { m_cond0Index = condIndex; }
+void CorrelationThreeBodyTemplate::setCond1Index(const int& condIndex) { m_cond1Index = condIndex; }
+void CorrelationThreeBodyTemplate::setCond2Index(const int& condIndex) { m_cond2Index = condIndex; }
+
+// set the correlation parameters of the condition
+void CorrelationThreeBodyTemplate::setCorrelationThreeBodyParameter(
+    const CorrelationThreeBodyParameter& corrThreeBodyParameter) {
+  m_correlationThreeBodyParameter = corrThreeBodyParameter;
+}
+
+void CorrelationThreeBodyTemplate::print(std::ostream& myCout) const {
+  myCout << "\n  CorrelationThreeBodyTemplate print..." << std::endl;
+
+  GlobalCondition::print(myCout);
+
+  myCout << "\n  First subcondition category:  " << m_cond0Category << std::endl;
+  myCout << "  Second subcondition category: " << m_cond1Category << std::endl;
+  myCout << "  Third subcondition category: " << m_cond2Category << std::endl;
+
+  myCout << "\n  First subcondition index:  " << m_cond0Index << std::endl;
+  myCout << "  Second subcondition index: " << m_cond1Index << std::endl;
+  myCout << "  Third subcondition index: " << m_cond2Index << std::endl;
+
+  myCout << "\n  Correlation parameter: "
+         << "[ hex ]" << std::endl;
+
+  myCout << "    Cut Type:  " << m_correlationThreeBodyParameter.corrCutType << std::endl;
+  myCout << "    minEtaCutValue        = " << std::dec << m_correlationThreeBodyParameter.minEtaCutValue << std::endl;
+  myCout << "    maxEtaCutValue        = " << std::dec << m_correlationThreeBodyParameter.maxEtaCutValue << std::endl;
+  myCout << "    precEtaCut            = " << std::dec << m_correlationThreeBodyParameter.precEtaCut << std::endl;
+  myCout << "    minPhiCutValue        = " << std::dec << m_correlationThreeBodyParameter.minPhiCutValue << std::endl;
+  myCout << "    maxPhiCutValue        = " << std::dec << m_correlationThreeBodyParameter.maxPhiCutValue << std::endl;
+  myCout << "    precPhiCut            = " << std::dec << m_correlationThreeBodyParameter.precPhiCut << std::endl;
+  myCout << "    minMassCutValue       = " << std::dec << m_correlationThreeBodyParameter.minMassCutValue << std::endl;
+  myCout << "    maxMassCutValue       = " << std::dec << m_correlationThreeBodyParameter.maxMassCutValue << std::endl;
+  myCout << "    precMassCut           = " << std::dec << m_correlationThreeBodyParameter.precMassCut << std::endl;
+
+  // reset to decimal output
+  myCout << std::dec << std::endl;
+}
+
+void CorrelationThreeBodyTemplate::copy(const CorrelationThreeBodyTemplate& cp) {
+  m_condName = cp.condName();
+  m_condCategory = cp.condCategory();
+  m_condType = cp.condType();
+  m_objectType = cp.objectType();
+  m_condGEq = cp.condGEq();
+  m_condChipNr = cp.condChipNr();
+
+  m_cond0Category = cp.cond0Category();
+  m_cond1Category = cp.cond1Category();
+  m_cond2Category = cp.cond2Category();
+  m_cond0Index = cp.cond0Index();
+  m_cond1Index = cp.cond1Index();
+  m_cond2Index = cp.cond2Index();
+
+  m_correlationThreeBodyParameter = *(cp.correlationThreeBodyParameter());
+}
+
+// output stream operator
+std::ostream& operator<<(std::ostream& os, const CorrelationThreeBodyTemplate& result) {
+  result.print(os);
+  return os;
+}
diff --git a/L1Trigger/L1TGlobal/src/GlobalBoard.cc b/L1Trigger/L1TGlobal/src/GlobalBoard.cc
index c21d7544d718d..b71505623fdd6 100644
--- a/L1Trigger/L1TGlobal/src/GlobalBoard.cc
+++ b/L1Trigger/L1TGlobal/src/GlobalBoard.cc
@@ -11,6 +11,7 @@
  * \author: Vasile Mihai Ghete   - HEPHY Vienna - CMSSW version
  * \author: Vladimir Rekovic     - add correlation with overlap removal cases
  *                               - fractional prescales
+ * \author: Elisa Fontanesi      - extended for three-body correlation conditions
  *
  * $Date$
  * $Revision$
@@ -33,6 +34,7 @@
 #include "L1Trigger/L1TGlobal/interface/EnergySumTemplate.h"
 #include "L1Trigger/L1TGlobal/interface/ExternalTemplate.h"
 #include "L1Trigger/L1TGlobal/interface/CorrelationTemplate.h"
+#include "L1Trigger/L1TGlobal/interface/CorrelationThreeBodyTemplate.h"
 #include "L1Trigger/L1TGlobal/interface/CorrelationWithOverlapRemovalTemplate.h"
 #include "L1Trigger/L1TGlobal/interface/GlobalCondition.h"
 #include "L1Trigger/L1TGlobal/interface/CorrCondition.h"
@@ -46,7 +48,9 @@
 #include "L1Trigger/L1TGlobal/interface/CaloCondition.h"
 #include "L1Trigger/L1TGlobal/interface/EnergySumCondition.h"
 #include "L1Trigger/L1TGlobal/interface/ExternalCondition.h"
-
+#include "L1Trigger/L1TGlobal/interface/CorrCondition.h"
+#include "L1Trigger/L1TGlobal/interface/CorrThreeBodyCondition.h"
+#include "L1Trigger/L1TGlobal/interface/CorrWithOverlapRemovalCondition.h"
 #include "FWCore/Utilities/interface/Exception.h"
 
 #include "FWCore/MessageLogger/interface/MessageLogger.h"
@@ -627,6 +631,60 @@ void l1t::GlobalBoard::runGTL(edm::Event& iEvent,
           //  		delete correlationCond;
 
         } break;
+        case CondCorrelationThreeBody: {
+          // get first the sub-conditions
+          const CorrelationThreeBodyTemplate* corrTemplate =
+              static_cast<const CorrelationThreeBodyTemplate*>(itCond->second);
+          const GtConditionCategory cond0Categ = corrTemplate->cond0Category();
+          const GtConditionCategory cond1Categ = corrTemplate->cond1Category();
+          const GtConditionCategory cond2Categ = corrTemplate->cond2Category();
+          const int cond0Ind = corrTemplate->cond0Index();
+          const int cond1Ind = corrTemplate->cond1Index();
+          const int cond2Ind = corrTemplate->cond2Index();
+
+          const GlobalCondition* cond0Condition = nullptr;
+          const GlobalCondition* cond1Condition = nullptr;
+          const GlobalCondition* cond2Condition = nullptr;
+
+          // maximum number of objects received for evaluation of l1t::Type1s condition
+          int cond0NrL1Objects = 0;
+          int cond1NrL1Objects = 0;
+          int cond2NrL1Objects = 0;
+          LogDebug("L1TGlobal") << "  cond0NrL1Objects  " << cond0NrL1Objects << "  cond1NrL1Objects  "
+                                << cond1NrL1Objects << "  cond2NrL1Objects  " << cond2NrL1Objects << std::endl;
+          if (cond0Categ == CondMuon) {
+            cond0Condition = &((corrMuon[iChip])[cond0Ind]);
+          } else {
+            LogDebug("L1TGlobal") << "No muon0 to evaluate three-body correlation condition";
+          }
+          if (cond1Categ == CondMuon) {
+            cond1Condition = &((corrMuon[iChip])[cond1Ind]);
+          } else {
+            LogDebug("L1TGlobal") << "No muon1 to evaluate three-body correlation condition";
+          }
+          if (cond2Categ == CondMuon) {
+            cond2Condition = &((corrMuon[iChip])[cond2Ind]);
+          } else {
+            LogDebug("L1TGlobal") << "No muon2 to evaluate three-body correlation condition";
+          }
+
+          CorrThreeBodyCondition* correlationThreeBodyCond =
+              new CorrThreeBodyCondition(itCond->second, cond0Condition, cond1Condition, cond2Condition, this);
+
+          correlationThreeBodyCond->setVerbosity(m_verbosity);
+          correlationThreeBodyCond->setScales(&gtScales);
+          correlationThreeBodyCond->evaluateConditionStoreResult(iBxInEvent);
+          cMapResults[itCond->first] = correlationThreeBodyCond;
+
+          if (m_verbosity && m_isDebugEnabled) {
+            std::ostringstream myCout;
+            correlationThreeBodyCond->print(myCout);
+
+            LogTrace("L1TGlobal") << myCout.str() << std::endl;
+          }
+          //              delete correlationThreeBodyCond;
+        } break;
+
         case CondCorrelationWithOverlapRemoval: {
           // get first the sub-conditions
           const CorrelationWithOverlapRemovalTemplate* corrTemplate =
diff --git a/L1Trigger/L1TGlobal/src/GlobalCondition.cc b/L1Trigger/L1TGlobal/src/GlobalCondition.cc
index e4e5c9d13442f..05b28bdde1549 100644
--- a/L1Trigger/L1TGlobal/src/GlobalCondition.cc
+++ b/L1Trigger/L1TGlobal/src/GlobalCondition.cc
@@ -8,6 +8,7 @@
  *    <TODO: enter implementation details>
  *
  * \author: Vladimir Rekovic,   Brian Winer, OSU   Vasile Mihai Ghete - HEPHY Vienna
+ *          Elisa Fontanesi - extended for three-body correlation conditions
  *
  * $Date$
  * $Revision$
@@ -152,6 +153,15 @@ const bool GlobalCondition::corr() const {
   return false;
 }
 
+// get logic flag for conditions, trigger objects are muons
+const bool GlobalCondition::corrThree() const {
+  if (m_condType == l1t::Type3s) {
+    return true;
+  }
+
+  return false;
+}
+
 // print condition
 void GlobalCondition::print(std::ostream& myCout) const {
   myCout << "\n  Condition name:     " << m_condName << std::endl;
@@ -187,6 +197,12 @@ void GlobalCondition::print(std::ostream& myCout) const {
              << "CondCorrelation" << std::endl;
     }
 
+    break;
+    case l1t::CondCorrelationThreeBody: {
+      myCout << "  Condition category: "
+             << "CondCorrelationThreeBody" << std::endl;
+    }
+
     break;
     case l1t::CondCorrelationWithOverlapRemoval: {
       myCout << "  Condition category: "
diff --git a/L1Trigger/L1TGlobal/src/GlobalDefinitions.cc b/L1Trigger/L1TGlobal/src/GlobalDefinitions.cc
index 971325f20aa4d..af6fc03e1c44a 100644
--- a/L1Trigger/L1TGlobal/src/GlobalDefinitions.cc
+++ b/L1Trigger/L1TGlobal/src/GlobalDefinitions.cc
@@ -6,6 +6,7 @@
  *
  * \author: Vasile Mihai Ghete - HEPHY Vienna
  *          Vladimir Rekovic - extend for overlap removal
+ *          Elisa Fontanesi - extended for three-body correlation conditions
  *
  * $Date$
  * $Revision$
@@ -33,14 +34,16 @@ namespace {
 
   template <class T>
   constexpr T keyToValue(char const *label, entry<T> const *entries) {
-    return !entries->label ? entries->value
-                           : same(entries->label, label) ? entries->value : /*default*/ keyToValue(label, entries + 1);
+    return !entries->label               ? entries->value
+           : same(entries->label, label) ? entries->value
+                                         : /*default*/ keyToValue(label, entries + 1);
   }
 
   template <class T>
   constexpr char const *valueToKey(T value, entry<T> const *entries) {
-    return !entries->label ? entries->label
-                           : entries->value == value ? entries->label : /*default*/ valueToKey(value, entries + 1);
+    return !entries->label           ? entries->label
+           : entries->value == value ? entries->label
+                                     : /*default*/ valueToKey(value, entries + 1);
   }
   constexpr entry<l1t::L1GtBoardType> l1GtBoardTypeStringToEnumMap[] = {
       {"l1t::MP7", l1t::MP7}, {"l1t::BoardNull", l1t::BoardNull}, {nullptr, (l1t::L1GtBoardType)-1}};
@@ -87,9 +90,10 @@ namespace {
       {"l1t::CondCalo", l1t::CondCalo},
       {"l1t::CondEnergySum", l1t::CondEnergySum},
       {"l1t::CondCorrelation", l1t::CondCorrelation},
+      {"l1t::CondCorrelationThreeBody", l1t::CondCorrelationThreeBody},
+      {"l1t::CondCorrelationWithOverlapRemoval", l1t::CondCorrelationWithOverlapRemoval},
       {"l1t::CondExternal", l1t::CondExternal},
-      {nullptr, (l1t::GtConditionCategory)-1},
-      {"l1t::CondCorrelationWithOverlapRemoval", l1t::CondCorrelationWithOverlapRemoval}};
+      {nullptr, (l1t::GtConditionCategory)-1}};
 
 }  // namespace
 // l1t::L1GtBoardType
diff --git a/L1Trigger/L1TGlobal/src/TriggerMenu.cc b/L1Trigger/L1TGlobal/src/TriggerMenu.cc
index fbca8f1cc9449..74e6d5ff7eff2 100644
--- a/L1Trigger/L1TGlobal/src/TriggerMenu.cc
+++ b/L1Trigger/L1TGlobal/src/TriggerMenu.cc
@@ -9,6 +9,7 @@
  *
  * \author: Vasile Mihai Ghete - HEPHY Vienna
  *          Vladimir Rekovic - extend for overlap removal
+ *          Elisa Fontanesi - extended for three-body correlation conditions
  *
  * $Date$
  * $Revision$
@@ -44,6 +45,7 @@ TriggerMenu::TriggerMenu(
     const std::vector<std::vector<EnergySumTemplate> >& vecEnergySumTemplateVal,
     const std::vector<std::vector<ExternalTemplate> >& vecExternalTemplateVal,
     const std::vector<std::vector<CorrelationTemplate> >& vecCorrelationTemplateVal,
+    const std::vector<std::vector<CorrelationThreeBodyTemplate> >& vecCorrelationThreeBodyTemplateVal,
     const std::vector<std::vector<CorrelationWithOverlapRemovalTemplate> >& vecCorrelationWithOverlapRemovalTemplateVal,
     const std::vector<std::vector<MuonTemplate> >& corMuonTemplateVal,
     const std::vector<std::vector<CaloTemplate> >& corCaloTemplateVal,
@@ -59,6 +61,7 @@ TriggerMenu::TriggerMenu(
       m_vecEnergySumTemplate(vecEnergySumTemplateVal),
       m_vecExternalTemplate(vecExternalTemplateVal),
       m_vecCorrelationTemplate(vecCorrelationTemplateVal),
+      m_vecCorrelationThreeBodyTemplate(vecCorrelationThreeBodyTemplateVal),
       m_vecCorrelationWithOverlapRemovalTemplate(vecCorrelationWithOverlapRemovalTemplateVal),
       m_corMuonTemplate(corMuonTemplateVal),
       m_corCaloTemplate(corCaloTemplateVal),
@@ -83,6 +86,7 @@ TriggerMenu::TriggerMenu(const TriggerMenu& rhs) {
   m_vecExternalTemplate = rhs.m_vecExternalTemplate;
 
   m_vecCorrelationTemplate = rhs.m_vecCorrelationTemplate;
+  m_vecCorrelationThreeBodyTemplate = rhs.m_vecCorrelationThreeBodyTemplate;
   m_vecCorrelationWithOverlapRemovalTemplate = rhs.m_vecCorrelationWithOverlapRemovalTemplate;
   m_corMuonTemplate = rhs.m_corMuonTemplate;
   m_corCaloTemplate = rhs.m_corCaloTemplate;
@@ -129,6 +133,7 @@ TriggerMenu& TriggerMenu::operator=(const TriggerMenu& rhs) {
     m_vecExternalTemplate = rhs.m_vecExternalTemplate;
 
     m_vecCorrelationTemplate = rhs.m_vecCorrelationTemplate;
+    m_vecCorrelationThreeBodyTemplate = rhs.m_vecCorrelationThreeBodyTemplate;
     m_vecCorrelationWithOverlapRemovalTemplate = rhs.m_vecCorrelationWithOverlapRemovalTemplate;
     m_corMuonTemplate = rhs.m_corMuonTemplate;
     m_corCaloTemplate = rhs.m_corCaloTemplate;
@@ -261,6 +266,27 @@ void TriggerMenu::buildGtConditionMap() {
     }
   }
 
+  //
+  size_t vecCorrelationThreeBodySize = m_vecCorrelationThreeBodyTemplate.size();
+  if (condMapSize < vecCorrelationThreeBodySize) {
+    m_conditionMap.resize(vecCorrelationThreeBodySize);
+    condMapSize = m_conditionMap.size();
+  }
+
+  chipNr = -1;
+  for (std::vector<std::vector<CorrelationThreeBodyTemplate> >::iterator itCondOnChip =
+           m_vecCorrelationThreeBodyTemplate.begin();
+       itCondOnChip != m_vecCorrelationThreeBodyTemplate.end();
+       itCondOnChip++) {
+    chipNr++;
+
+    for (std::vector<CorrelationThreeBodyTemplate>::iterator itCond = itCondOnChip->begin();
+         itCond != itCondOnChip->end();
+         itCond++) {
+      (m_conditionMap.at(chipNr))[itCond->condName()] = &(*itCond);
+    }
+  }
+
   //
   size_t vecCorrelationWORSize = m_vecCorrelationWithOverlapRemovalTemplate.size();
   if (condMapSize < vecCorrelationWORSize) {
@@ -323,6 +349,11 @@ void TriggerMenu::setVecCorrelationTemplate(const std::vector<std::vector<Correl
   m_vecCorrelationTemplate = vecCorrelationTempl;
 }
 
+void TriggerMenu::setVecCorrelationThreeBodyTemplate(
+    const std::vector<std::vector<CorrelationThreeBodyTemplate> >& vecCorrelationThreeBodyTempl) {
+  m_vecCorrelationThreeBodyTemplate = vecCorrelationThreeBodyTempl;
+}
+
 void TriggerMenu::setVecCorrelationWithOverlapRemovalTemplate(
     const std::vector<std::vector<CorrelationWithOverlapRemovalTemplate> >& vecCorrelationTempl) {
   m_vecCorrelationWithOverlapRemovalTemplate = vecCorrelationTempl;
diff --git a/L1Trigger/L1TGlobal/src/classes.h b/L1Trigger/L1TGlobal/src/classes.h
index de38057cac3c7..6a935d541760f 100644
--- a/L1Trigger/L1TGlobal/src/classes.h
+++ b/L1Trigger/L1TGlobal/src/classes.h
@@ -6,6 +6,7 @@ namespace L1Trigger_L1TGlobal {
     std::vector<MuonTemplate> dummy1;
     std::vector<CaloTemplate> dummy2;
     std::vector<CorrelationTemplate> dummy3;
-    std::vector<CorrelationWithOverlapRemovalTemplate> dummy4;
+    std::vector<CorrelationThreeBodyTemplate> dummy4;
+    std::vector<CorrelationWithOverlapRemovalTemplate> dummy5;
   };
 }  // namespace L1Trigger_L1TGlobal
diff --git a/L1Trigger/L1TGlobal/src/classes_def.xml b/L1Trigger/L1TGlobal/src/classes_def.xml
index d025ea6192a82..39b771b22d5ae 100644
--- a/L1Trigger/L1TGlobal/src/classes_def.xml
+++ b/L1Trigger/L1TGlobal/src/classes_def.xml
@@ -1,10 +1,14 @@
 <lcgdict>
   <class name="CorrelationTemplate"/>
+  <class name="CorrelationThreeBodyTemplate"/>
   <class name="CorrelationWithOverlapRemovalTemplate"/>
   <class name="CorrelationTemplate::CorrelationParameter"/>
+  <class name="CorrelationThreeBodyTemplate::CorrelationThreeBodyParameter"/>
   <class name="CorrelationWithOverlapRemovalTemplate::CorrelationWithOverlapRemovalParameter"/>
   <class name="std::vector<CorrelationTemplate>"/>
   <class name="std::vector<std::vector<CorrelationTemplate> >"/>
+  <class name="std::vector<CorrelationThreeBodyTemplate>"/>
+  <class name="std::vector<std::vector<CorrelationThreeBodyTemplate> >"/>
   <class name="std::vector<CorrelationWithOverlapRemovalTemplate>"/>
   <class name="std::vector<std::vector<CorrelationWithOverlapRemovalTemplate> >"/>
   <class name="TriggerMenu" class_version="TriggerMenu_V01">
@@ -19,6 +23,7 @@
     <field name="m_vecCaloTemplate" mapping="blob" />
     <field name="m_vecCastorTemplate" mapping="blob" />
     <field name="m_vecCorrelationTemplate" mapping="blob" />
+    <field name="m_vecCorrelationThreeBodyTemplate" mapping="blob" />
     <field name="m_vecCorrelationWithOverlapRemovalTemplate" mapping="blob" />
     <field name="m_vecEnergySumTemplate" mapping="blob" />
     <field name="m_vecExternalTemplate" mapping="blob" />
diff --git a/L1Trigger/L1TGlobal/test/runGlobalFakeInputProducer.py b/L1Trigger/L1TGlobal/test/runGlobalFakeInputProducer.py
index 8ef6cc094340d..dfac4714c991d 100644
--- a/L1Trigger/L1TGlobal/test/runGlobalFakeInputProducer.py
+++ b/L1Trigger/L1TGlobal/test/runGlobalFakeInputProducer.py
@@ -55,7 +55,6 @@
 process.load('Configuration/StandardSequences/FrontierConditions_GlobalTag_cff')
 
 
-
 # Select the Message Logger output you would like to see:
 #
 process.load('FWCore.MessageService.MessageLogger_cfi')
@@ -65,11 +64,14 @@
 process.load('L1Trigger/L1TGlobal/debug_messages_cfi')
 process.MessageLogger.l1t_debug.l1t.limit = cms.untracked.int32(100000)
 
-#
-#process.MessageLogger.debugModules = cms.untracked.vstring('*')
-#process.MessageLogger.cerr.threshold = cms.untracked.string('DEBUG')
+process.MessageLogger.categories.append('l1t|Global')
+# DEBUG
+#process.MessageLogger.debugModules = cms.untracked.vstring('simGtStage2Digis') 
+#process.MessageLogger.cerr.threshold = cms.untracked.string('DEBUG') 
 
+# set the number of events
 process.maxEvents = cms.untracked.PSet(
+    #input = cms.untracked.int32(10)
     input = cms.untracked.int32(neventsPerJob)
     )
 
@@ -77,24 +79,15 @@
 process.source = cms.Source("PoolSource",
     secondaryFileNames = cms.untracked.vstring(),
     fileNames = cms.untracked.vstring(
-        "/store/mc/PhaseIFall16DR/TT_TuneCUETP8M2T4_13TeV-powheg-pythia8/GEN-SIM-RAW/FlatPU28to62HcalNZSRAW_81X_upgrade2017_realistic_v26-v1/110000/444C2036-84FC-E611-A86D-02163E01433C.root",
-        "/store/mc/PhaseIFall16DR/TT_TuneCUETP8M2T4_13TeV-powheg-pythia8/GEN-SIM-RAW/FlatPU28to62HcalNZSRAW_81X_upgrade2017_realistic_v26-v1/110000/E0A9F101-84FC-E611-9B29-02163E01A4AA.root",
-        "/store/mc/PhaseIFall16DR/TT_TuneCUETP8M2T4_13TeV-powheg-pythia8/GEN-SIM-RAW/FlatPU28to62HcalNZSRAW_81X_upgrade2017_realistic_v26-v1/110000/563E9F08-84FC-E611-BEA2-02163E01A2F7.root",
-        ## "/store/mc/PhaseIFall16DR/QCD_Pt_50to80_TuneCUETP8M1_13TeV_pythia8/GEN-SIM-RAW/FlatPU28to62HcalNZSRAW_81X_upgrade2017_realistic_v26-v2/120002/C023E584-8700-E711-AE30-002590747E28.root",
-        ## "/store/mc/RunIISpring16DR80/TT_TuneCUETP8M1_13TeV-powheg-pythia8/GEN-SIM-RAW/FlatPU20to70HcalNZSRAW_withHLT_80X_mcRun2_asymptotic_v14_ext3-v1/50000/CE22C0CB-9965-E611-9101-0025905C4262.root",
-        ## "/store/mc/RunIISpring16DR80/TT_TuneCUETP8M1_13TeV-powheg-pythia8/GEN-SIM-RAW/FlatPU20to70HcalNZSRAW_withHLT_80X_mcRun2_asymptotic_v14_ext3-v1/50000/D6D4CAF2-AD65-E611-9642-001EC94BA169.root",
-        ## "/store/mc/RunIISpring16DR80/TT_TuneCUETP8M1_13TeV-powheg-pythia8/GEN-SIM-RAW/FlatPU20to70HcalNZSRAW_withHLT_80X_mcRun2_asymptotic_v14_ext3-v1/50000/DACA98C0-9A65-E611-8626-0025905C54C6.root"
-        #"/store/user/puigh/L1Upgrade/GEN-SIM-DIGI-RAW-HLTDEBUG/CMSSW_7_6_0/4C462F65-9F7F-E511-972A-0026189438A9.root",
+        "/store/mc/RunIISummer19UL18RECO/GluGluToContinToZZTo4mu_13TeV_MCFM701_pythia8/AODSIM/106X_upgrade2018_realistic_v11_L1v1-v2/110000/664BBEBB-93A9-5B40-AD9C-DE835A79B712.root",
+        #"/store/mc/RunIISummer20UL18RECO/BuToTau_To3Mu_MuFilter_TuneCP5_13TeV-pythia8-evtgen/AODSIM/106X_upgrade2018_realistic_v11_L1v1-v1/20000/00901296-D966-DF40-AA25-5F7A959B79CA.root",
+        #"/store/mc/RunIISummer20UL18RECO/DsToTau_To3Mu_MuFilter_TuneCP5_13TeV-pythia8-evtgen/AODSIM/106X_upgrade2018_realistic_v11_L1v1-v1/00000/0003B7FD-6C1E-BF4C-8DA9-BA8A27AF0290.root",
+        #"/store/mc/RunIISummer19UL18RECO/ZZ_TuneCP5_13TeV-pythia8/AODSIM/106X_upgrade2018_realistic_v11_L1v1-v2/280000/04530FC4-E54D-D34A-950E-9F300321E037.root",
+        #"/store/mc/RunIIFall15DR76/TT_TuneCUETP8M1_13TeV-powheg-pythia8/AODSIM/25nsFlat10to25TSG_76X_mcRun2_asymptotic_v11_ext3-v1/20000/F03B8956-5D87-E511-8AE9-002590D0AFFC.root",
+        #"/store/mc/RunIISummer19UL18HLT/TTTo2L2Nu_mtop178p5_TuneCP5_13TeV-powheg-pythia8/GEN-SIM-RAW/102X_upgrade2018_realistic_v15-v2/280000/00429618-85B5-124F-9C16-0C9F07A39E73.root+"
+        #"/store/mc/PhaseIFall16DR/TT_TuneCUETP8M2T4_13TeV-powheg-pythia8/GEN-SIM-RAW/FlatPU28to62HcalNZSRAW_81X_upgrade2017_realistic_v26-v1/110000/444C2036-84FC-E611-A86D-02163E01433C.root",
+        #"/store/mc/RunIISpring16DR80/TT_TuneCUETP8M1_13TeV-powheg-pythia8/GEN-SIM-RAW/FlatPU20to70HcalNZSRAW_withHLT_80X_mcRun2_asymptotic_v14_ext3-v1/50000/D6D4CAF2-AD65-E611-9642-001EC94BA169.root",
         #"/store/relval/CMSSW_7_6_0_pre7/RelValTTbar_13/GEN-SIM/76X_mcRun2_asymptotic_v9_realBS-v1/00000/0A812333-427C-E511-A80A-0025905964A2.root",
-        #"root://xrootd.ba.infn.it//store/relval/CMSSW_7_6_0/RelValTTbar_13/GEN-SIM-DIGI-RAW-HLTDEBUG/76X_mcRun2_asymptotic_v11-v1/00000/4C462F65-9F7F-E511-972A-0026189438A9.root",
-        #"root://xrootd.ba.infn.it//store/relval/CMSSW_7_6_0/RelValTTbar_13/GEN-SIM-DIGI-RAW-HLTDEBUG/76X_mcRun2_asymptotic_v11-v1/00000/703E7EAB-9D7F-E511-B886-003048FFCBFC.root",
-        #"root://xrootd.ba.infn.it//store/relval/CMSSW_7_6_0/RelValTTbar_13/GEN-SIM-DIGI-RAW-HLTDEBUG/76X_mcRun2_asymptotic_v11-v1/00000/8AF07AAB-9D7F-E511-B8B4-003048FFCBFC.root",
-        #"root://xrootd.ba.infn.it//store/relval/CMSSW_7_6_0/RelValTTbar_13/GEN-SIM-DIGI-RAW-HLTDEBUG/76X_mcRun2_asymptotic_v11-v1/00000/962BEF7C-9D7F-E511-A2BB-0025905B85AA.root",
-        #"root://xrootd.ba.infn.it//store/relval/CMSSW_7_6_0/RelValTTbar_13/GEN-SIM-DIGI-RAW-HLTDEBUG/76X_mcRun2_asymptotic_v11-v1/00000/C409A519-9E7F-E511-BD4C-0025905B8590.root",
-        #"root://xrootd.ba.infn.it//store/relval/CMSSW_7_6_0/RelValTTbar_13/GEN-SIM-DIGI-RAW-HLTDEBUG/76X_mcRun2_asymptotic_v11-v1/00000/E8D41D6A-9F7F-E511-A10A-003048FFD740.root",
-        #"root://xrootd.ba.infn.it//store/relval/CMSSW_7_6_0/RelValTTbar_13/GEN-SIM-DIGI-RAW-HLTDEBUG/76X_mcRun2_asymptotic_v11-v1/00000/EE048767-9E7F-E511-B1AA-0025905B8606.root",
-        #"root://xrootd.ba.infn.it//store/relval/CMSSW_7_6_0/RelValTTbar_13/GEN-SIM-DIGI-RAW-HLTDEBUG/76X_mcRun2_asymptotic_v11-v1/00000/4431031E-9E7F-E511-9F42-0025905938A4.root",
-        #"root://cmsxrootd.fnal.gov//store/relval/CMSSW_7_6_0/RelValTTbar_13/GEN-SIM-DIGI-RAW-HLTDEBUG/76X_mcRun2_asymptotic_v11-v1/00000/4431031E-9E7F-E511-9F42-0025905938A4.root",
 	),
     skipEvents = cms.untracked.uint32(skip)
     )
@@ -104,7 +97,9 @@
 	fileName = cms.untracked.string('testGlobalMCInputProducer_'+repr(job)+'.root')
 	)
 
-process.options = cms.untracked.PSet()
+process.options = cms.untracked.PSet(
+    wantSummary = cms.bool(True)
+)
 
 
 # Additional output definition
@@ -115,7 +110,9 @@
 # Other statements
 from Configuration.AlCa.GlobalTag import GlobalTag
 ## process.GlobalTag = GlobalTag(process.GlobalTag, 'auto:upgradePLS1', '')
-process.GlobalTag = GlobalTag(process.GlobalTag, '90X_upgrade2017_realistic_PerfectEcalIc_EGM_PFCalib', '')
+#process.GlobalTag = GlobalTag(process.GlobalTag, '106X_upgrade2018_realistic_v11', '')
+process.GlobalTag = GlobalTag(process.GlobalTag, '112X_mcRun2_asymptotic_v2', '')
+## process.GlobalTag = GlobalTag(process.GlobalTag, '90X_upgrade2017_realistic_PerfectEcalIc_EGM_PFCalib', '')
 ## auto:upgradePLS1
 ## 81X_upgrade2017_realistic_v26
 ## 80X_mcRun2_asymptotic_v14
@@ -217,21 +214,13 @@
 
 process.load("L1Trigger.L1TGlobal.TriggerMenu_cff")
 
-## process.TriggerMenu.L1TriggerMenuFile = cms.string('L1Menu_Collisions2016_v2c.xml')
-## process.TriggerMenu.L1TriggerMenuFile = cms.string('towercount.xml')
-## process.TriggerMenu.L1TriggerMenuFile = cms.string('L1Menu_Collisions2016_v3_HIDilepton_v5.xml')
-## process.TriggerMenu.L1TriggerMenuFile = cms.string('L1Menu_HeavyIons2016_v0.xml')
-## process.TriggerMenu.L1TriggerMenuFile = cms.string('L1Menu_HeavyIons2016_v2.xml')
-## process.TriggerMenu.L1TriggerMenuFile = cms.string('L1Menu_HeavyIons2016_v3_m2.xml')
-## process.TriggerMenu.L1TriggerMenuFile = cms.string('L1Menu_Collisions2016_v8_m2.xml')
-## process.TriggerMenu.L1TriggerMenuFile = cms.string('L1Menu_test_mass_trv.xml')
-
-## xmlMenu="L1Menu_test_mass_trv.xml"
-##xmlMenu="L1Menu_BPH2017_v0.xml"
-xmlMenu="L1Menu_test_mass_tbpt.xml"
+xmlMenu="L1Menu_test_mass_3_body_reduced_v2.xml"
 process.TriggerMenu.L1TriggerMenuFile = cms.string(xmlMenu)
+process.ESPreferL1TXML = cms.ESPrefer("L1TUtmTriggerMenuESProducer","TriggerMenu")
 
-#process.menuDumper = cms.EDAnalyzer("L1TUtmTriggerMenuDumper")
+process.dumpMenu = cms.EDAnalyzer("L1MenuViewer")
+# DEBUG: Information about names and types of algos parsed by the emulator from the menu
+#process.menuDumper = cms.EDAnalyzer("L1TUtmTriggerMenuDumper") 
 
 ## Fill External conditions
 process.load('L1Trigger.L1TGlobal.simGtExtFakeProd_cfi')
@@ -285,14 +274,12 @@
                 unmaskL1Algos     = cms.bool(False)
 		 )
 
-
-
 process.load("L1Trigger.GlobalTriggerAnalyzer.l1GtTrigReport_cfi")
 process.l1GtTrigReport.L1GtRecordInputTag = "simGtStage2Digis"
 process.l1GtTrigReport.PrintVerbosity = 2
 process.report = cms.Path(process.l1GtTrigReport)
 
-process.MessageLogger.MuConditon=cms.untracked.PSet()
+process.MessageLogger.categories.append("MuConditon")
 
 if useMCtoGT:
     process.gtInput = process.mcL1GTinput.clone()
@@ -312,7 +299,8 @@
 process.load('EventFilter.L1TRawToDigi.gtStage2Digis_cfi')
 process.newGtStage2Digis = process.gtStage2Digis.clone()
 process.newGtStage2Digis.InputLabel = cms.InputTag('gtStage2Raw')
-process.newGtStage2Digis.debug = cms.untracked.bool(False)
+# DEBUG 
+#process.newGtStage2Digis.debug = cms.untracked.bool(True) 
 
 process.dumpRaw = cms.EDAnalyzer(
     "DumpFEDRawDataProduct",
@@ -368,7 +356,8 @@
 process.p1 = cms.Path(
 
 ## Generate input, emulate, dump results
-    process.gtInput
+    process.dumpMenu
+    *process.gtInput
 #    *process.dumpGT
     *process.simGtExtFakeProd
     *process.simGtStage2Digis
@@ -382,7 +371,7 @@
 
 ## Analysis/Dumping
     *process.l1tGlobalAnalyzer
-#    *process.menuDumper
+#    *process.menuDumper # DEBUG -> to activate the menuDumper
 #    *process.debug
 #    *process.dumpED
 #    *process.dumpES