Index: external/fastjet/plugins/Jade/JadePlugin.cc
===================================================================
--- external/fastjet/plugins/Jade/JadePlugin.cc	(revision 35cdc461e095e63247ab9dded070d76bc2c888e2)
+++ external/fastjet/plugins/Jade/JadePlugin.cc	(revision 151255d0f9cb4a68b5448a546c75c7ce53fc2abd)
@@ -1,4 +1,4 @@
 //FJSTARTHEADER
-// $Id: JadePlugin.cc 3433 2014-07-23 08:17:03Z salam $
+// $Id: JadePlugin.cc 4063 2016-03-04 10:31:40Z salam $
 //
 // Copyright (c) 2007-2014, Matteo Cacciari, Gavin P. Salam and Gregory Soyez
@@ -35,4 +35,5 @@
 //#include "fastjet/internal/ClusterSequence_N2.icc"
 #include "fastjet/NNH.hh"
+#include "fastjet/NNFJN2Plain.hh"
 
 // other stuff
@@ -51,4 +52,23 @@
 //----------------------------------------------------------------------
 /// class to help run a JADE algorithm
+///
+/// This class works both with NNH and NNFJN2Plain clustering
+/// helpers. They both use the same init(...) call, but for the
+/// clustering:
+///
+/// - NNH uses distance(...) and beam_distance()
+/// - NNFJPlainN2 uses geometrical_distance(...), momentum_factor()
+///   and geometrical_beam_distance()
+///
+/// For NNFJPlainN2 the 2 E_i E_j (1-cos theta_{ij}) factor
+/// gets broken up into
+///
+///     sqrt(2)*min(E_i,E_j) * [sqrt(2)*max(E_i,E_j) (1 - cos \theta_{ij})]
+///
+/// The second factor is what we call the "geometrical_distance" even
+/// though it isn't actually purely geometrical. But the fact that it
+/// gets multiplied by min(E_i,E_j) to get the full distance is
+/// sufficient for the validity of the FJ lemma, allowing for the use
+/// of NNFJN2Plain.
 class JadeBriefJet {
 public:
@@ -69,8 +89,28 @@
   }
 
+  double geometrical_distance(const JadeBriefJet * jet) const {
+    double dij = 1 - nx*jet->nx
+                   - ny*jet->ny
+                   - nz*jet->nz;
+    dij *= max(rt2E,jet->rt2E);
+    return dij;
+  }
+
+  double momentum_factor() const {
+    return rt2E;
+  }
+  
   double beam_distance() const {
     return numeric_limits<double>::max();
   }
 
+  double geometrical_beam_distance() const {
+    // get a number that is almost the same as max(), just a little
+    // smaller so as to ensure that when we divide it by rt2E and then
+    // multiply it again, we won't get an overflow
+    const double almost_max = numeric_limits<double>::max() * (1 - 1e-13);
+    return almost_max / rt2E;
+  }
+  
 private:
   double rt2E, nx, ny, nz;
@@ -82,11 +122,64 @@
   ostringstream desc;
   desc << "e+e- JADE algorithm plugin";
+  switch(_strategy) {
+  case strategy_NNH:
+    desc << ", using NNH strategy"; break;
+  case strategy_NNFJN2Plain:
+    desc << ", using NNFJN2Plain strategy"; break;
+  default:
+    throw Error("Unrecognized strategy in JadePlugin");
+  }
+
   return desc.str();
 }
 
-//----------------------------------------------------------------------
-void JadePlugin::run_clustering(ClusterSequence & cs) const {
+// //----------------------------------------------------------------------
+// void JadePlugin::run_clustering(ClusterSequence & cs) const {
+//   int njets = cs.jets().size();
+// 
+//   //SharedPtr<NNBase<> > nn;
+//   NNBase<> * nn;
+//   switch(_strategy) {
+//   case strategy_NNH:
+//     //nn.reset(new NNH<JadeBriefJet>(cs.jets()));
+//     nn = new NNH<JadeBriefJet>(cs.jets());
+//     break;
+//   case strategy_NNFJN2Plain:
+//     //nn.reset(new NNFJN2Plain<JadeBriefJet>(cs.jets()));
+//     nn = new NNFJN2Plain<JadeBriefJet>(cs.jets());
+//     break;
+//   default:
+//     throw Error("Unrecognized strategy in JadePlugin");
+//   }
+//   //NNH<JadeBriefJet> nnh(cs.jets());
+//   //NNFJN2Plain<JadeBriefJet> nnh(cs.jets());
+// 
+//   // if testing against Hoeth's implementation, need to rescale the
+//   // dij by Q^2.
+//   //double Q2 = cs.Q2(); 
+// 
+//   while (njets > 0) {
+//     int i, j, k;
+//     double dij = nn->dij_min(i, j);
+// 
+//     if (j >= 0) {
+//       cs.plugin_record_ij_recombination(i, j, dij, k);
+//       nn->merge_jets(i, j, cs.jets()[k], k);
+//     } else {
+//       double diB = cs.jets()[i].E()*cs.jets()[i].E(); // get new diB
+//       cs.plugin_record_iB_recombination(i, diB);
+//       nn->remove_jet(i);
+//     }
+//     njets--;
+//   }
+//   delete nn;
+// }
+
+
+template<class N> void JadePlugin::_actual_run_clustering(ClusterSequence & cs) const {
+
   int njets = cs.jets().size();
-  NNH<JadeBriefJet> nnh(cs.jets());
+
+  N nn(cs.jets());
 
   // if testing against Hoeth's implementation, need to rescale the
@@ -96,17 +189,34 @@
   while (njets > 0) {
     int i, j, k;
-    double dij = nnh.dij_min(i, j);
+    double dij = nn.dij_min(i, j);
 
     if (j >= 0) {
       cs.plugin_record_ij_recombination(i, j, dij, k);
-      nnh.merge_jets(i, j, cs.jets()[k], k);
+      nn.merge_jets(i, j, cs.jets()[k], k);
     } else {
       double diB = cs.jets()[i].E()*cs.jets()[i].E(); // get new diB
       cs.plugin_record_iB_recombination(i, diB);
-      nnh.remove_jet(i);
+      nn.remove_jet(i);
     }
     njets--;
   }
+
 }
 
+//----------------------------------------------------------------------
+void JadePlugin::run_clustering(ClusterSequence & cs) const {
+
+  switch(_strategy) {
+  case strategy_NNH:
+    _actual_run_clustering<NNH<JadeBriefJet> >(cs);
+    break;
+  case strategy_NNFJN2Plain:
+    _actual_run_clustering<NNFJN2Plain<JadeBriefJet> >(cs);
+    break;
+  default:
+    throw Error("Unrecognized strategy in JadePlugin");
+  }
+}
+
+
 FASTJET_END_NAMESPACE      // defined in fastjet/internal/base.hh
Index: external/fastjet/plugins/Jade/fastjet/JadePlugin.hh
===================================================================
--- external/fastjet/plugins/Jade/fastjet/JadePlugin.hh	(revision 35cdc461e095e63247ab9dded070d76bc2c888e2)
+++ external/fastjet/plugins/Jade/fastjet/JadePlugin.hh	(revision 151255d0f9cb4a68b5448a546c75c7ce53fc2abd)
@@ -3,5 +3,5 @@
 
 //FJSTARTHEADER
-// $Id: JadePlugin.hh 3433 2014-07-23 08:17:03Z salam $
+// $Id: JadePlugin.hh 4061 2016-03-03 21:51:25Z salam $
 //
 // Copyright (c) 2005-2014, Matteo Cacciari, Gavin P. Salam and Gregory Soyez
@@ -77,6 +77,11 @@
 class JadePlugin : public JetDefinition::Plugin {
 public:
+  /// enum that contains the two clustering strategy options; for
+  /// higher multiplicities, strategy_NNFJN2Plain is about a factor of
+  /// two faster.
+  enum Strategy { strategy_NNH = 0, strategy_NNFJN2Plain = 1};
+  
   /// Main constructor for the Jade Plugin class.  
-  JadePlugin (){}
+  JadePlugin (Strategy strategy = strategy_NNFJN2Plain) : _strategy(strategy) {}
 
   /// copy constructor
@@ -100,4 +105,7 @@
 private:
 
+  template<class N> void _actual_run_clustering(ClusterSequence &) const;
+  
+  Strategy _strategy;
 };
 
