Index: contrib/contribs/LundPlane/trunk/VERSION
===================================================================
--- contrib/contribs/LundPlane/trunk/VERSION	(revision 1459)
+++ contrib/contribs/LundPlane/trunk/VERSION	(revision 1460)
@@ -1 +0,0 @@
-2.1.2-devel
Index: contrib/contribs/LundPlane/trunk/LundJSON.hh
===================================================================
--- contrib/contribs/LundPlane/trunk/LundJSON.hh	(revision 1459)
+++ contrib/contribs/LundPlane/trunk/LundJSON.hh	(revision 1460)
@@ -1,78 +0,0 @@
-#ifndef __FASTJET_CONTRIB_LUNDJSON_HH__
-#define __FASTJET_CONTRIB_LUNDJSON_HH__
-
-#include "LundGenerator.hh"
-
-FASTJET_BEGIN_NAMESPACE
-
-namespace contrib{
-
-// declaration of helper function
-void lund_elements_to_json(std::ostream & ostr, const LundDeclustering & d);
-
-/// writes json to ostr for an individual declustering
-inline std::ostream & lund_to_json(std::ostream & ostr, const LundDeclustering & d) {
-  // /// we hardcode 6 digits of precision -- is this the right way to do things?
-  // int prec_store = ostr.precision();
-  // ostr.precision(6);
-
-  ostr << "{";
-  lund_elements_to_json(ostr, d);
-  ostr << "}";
-
-  return ostr;
-}
-
-
-/// writes json to ostr for a vector of declusterings
-inline std::ostream & lund_to_json(std::ostream & ostr, const std::vector<LundDeclustering> & d) {
-  ostr << "[";
-  for (std::size_t i = 0; i < d.size(); i++) {
-    if (i != 0) ostr << ",";
-    lund_to_json(ostr, d[i]);
-  } 
-  ostr << "]";
-  return ostr;
-}
-
-// /// writes a full Lund tree recursively to JSON
-// inline std::ostream & lund_to_json(std::ostream & ostr, const LundGenerator & generator, const PseudoJet & jet) {
-//   // we will use these below in the loop; declare them here to avoid
-//   // repeated creation/destruction
-//   PseudoJet p1,p2;
-//   std::vector<LundDeclustering> d = generator(jet);
-//   ostr << "[";
-//   for (std::size_t i = 0; i < d.size(); i++) {
-//     if (i != 0) ostr << ",";
-//     ostr << "{";
-//     lund_elements_to_json(ostr, d[i]);
-//     // add in information on the leaf if it exists
-//     if (d[i].softer().has_parents(p1,p2)) {
-//       ostr << ",";
-//       ostr << "\"leaf\":";
-//       lund_to_json(ostr, generator, d[i].softer());
-//     }
-//     ostr << "}";
-//   } 
-//   ostr << "]";
-//   return ostr;
-// }
-
-// helper function to write individual elements to json
-inline void lund_elements_to_json(std::ostream & ostr, const LundDeclustering & d) {
-  ostr << "\"p_pt\":" << d.pair()  .pt() << ",";
-  ostr << "\"p_m\":"  << d.pair()  .m () << ",";
-  ostr << "\"h_pt\":" << d.harder().pt() << ",";
-  ostr << "\"s_pt\":" << d.softer().pt() << ",";
-  ostr << "\"z\":"      << d.z()     << ",";
-  ostr << "\"Delta\":"  << d.Delta() << ",";
-  ostr << "\"kt\":"     << d.kt()    << ",";
-  ostr << "\"psi\":"    << d.psi()         ;
-}
-
-
-} // namespace contrib
-
-FASTJET_END_NAMESPACE
-
-#endif // __FASTJET_CONTRIB_LUNDJSON_HH__
Index: contrib/contribs/LundPlane/trunk/LundEEHelpers.hh
===================================================================
--- contrib/contribs/LundPlane/trunk/LundEEHelpers.hh	(revision 1459)
+++ contrib/contribs/LundPlane/trunk/LundEEHelpers.hh	(revision 1460)
@@ -1,270 +0,0 @@
-// $Id$
-//
-// Copyright (c) 2018-, Frederic A. Dreyer, Keith Hamilton, Alexander Karlberg,
-// Gavin P. Salam, Ludovic Scyboz, Gregory Soyez, Rob Verheyen
-//
-// This file is part of FastJet contrib.
-//
-// It is free software; you can redistribute it and/or modify it under
-// the terms of the GNU General Public License as published by the
-// Free Software Foundation; either version 2 of the License, or (at
-// your option) any later version.
-//
-// It is distributed in the hope that it will be useful, but WITHOUT
-// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-// or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
-// License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this code. If not, see <http://www.gnu.org/licenses/>.
-//----------------------------------------------------------------------
-
-#ifndef __FASTJET_CONTRIB_EEHELPERS_HH__
-#define __FASTJET_CONTRIB_EEHELPERS_HH__
-
-#include "fastjet/PseudoJet.hh"
-#include <array>
-#include <limits>
-
-FASTJET_BEGIN_NAMESPACE
-
-namespace contrib{
-namespace lund_plane {
-  
-//----------------------------------------------------------------------
-/// Returns the 3-vector cross-product of p1 and p2. If lightlike is false
-/// then the energy component is zero; if it's true the the energy component
-/// is arranged so that the vector is lighlike
-inline PseudoJet cross_product(const PseudoJet & p1, const PseudoJet & p2, bool lightlike=false) {
-  double px = p1.py() * p2.pz() - p2.py() * p1.pz();
-  double py = p1.pz() * p2.px() - p2.pz() * p1.px();
-  double pz = p1.px() * p2.py() - p2.px() * p1.py();
-
-  double E;
-  if (lightlike) {
-    E = sqrt(px*px + py*py + pz*pz);
-  } else {
-    E = 0.0;
-  }
-  return PseudoJet(px, py, pz, E);
-}
-
-/// Map angles to [-pi, pi]
-inline const double map_to_pi(const double &phi) {
-  if (phi < -M_PI)     return phi + 2 * M_PI;
-  else if (phi > M_PI) return phi - 2 * M_PI;
-  else                 return phi;
-}
-
-inline double dot_product_3d(const PseudoJet & a, const PseudoJet & b) {
-  return a.px()*b.px() + a.py()*b.py() + a.pz()*b.pz();
-}
-
-/// Returns (1-cos theta) where theta is the angle between p1 and p2
-inline double one_minus_costheta(const PseudoJet & p1, const PseudoJet & p2) {
-
-  if (p1.m2() == 0 && p2.m2() == 0) {
-    // use the 4-vector dot product. 
-    // For massless particles it gives us E1*E2*(1-cos theta)
-    return dot_product(p1,p2) / (p1.E() * p2.E());
-  } else {
-    double p1mod = p1.modp();
-    double p2mod = p2.modp();
-    double p1p2mod = p1mod*p2mod;
-    double dot = dot_product_3d(p1,p2);
-
-    if (dot > (1-std::numeric_limits<double>::epsilon()) * p1p2mod) {
-      PseudoJet cross_result = cross_product(p1, p2, false);
-      // the mass^2 of cross_result is equal to 
-      // -(px^2 + py^2 + pz^2) = (p1mod*p2mod*sintheta_ab)^2
-      // so we can get
-      return -cross_result.m2()/(p1p2mod * (p1p2mod+dot));
-    }
-
-    return 1.0 - dot/p1p2mod;
-    
-  }
-}
-
-/// Get the angle between two planes defined by normalized vectors
-/// n1, n2. The sign is decided by the direction of a vector n, such that
-/// if n1 x n2 points in the same direction as n, the angle is positive.
-/// The result is in the range -pi < theta < pi.
-///
-/// For example, labelling (x,y,z), and taking n1 = (1,0,0), 
-/// n2 = (0,1,0), n = (0,0,1), then the angle is +pi/2.
-inline double signed_angle_between_planes(const PseudoJet& n1,
-      const PseudoJet& n2, const PseudoJet& n) {
-
-  // Two vectors passed as arguments should be normalised to 1.
-  assert(fabs(n1.modp()-1) < sqrt(std::numeric_limits<double>::epsilon()) && fabs(n2.modp()-1) < sqrt(std::numeric_limits<double>::epsilon()));
-
-  double omcost = one_minus_costheta(n1,n2);
-  double theta;
-
-  // If theta ~ pi, we return pi.
-  if(fabs(omcost-2) < sqrt(std::numeric_limits<double>::epsilon())) {
-    theta = M_PI;
-  } else if (omcost > sqrt(std::numeric_limits<double>::epsilon())) {
-    double cos_theta = 1.0 - omcost;
-    theta = acos(cos_theta);
-  } else {
-    // we are at small angles, so use small-angle formulas
-    theta = sqrt(2. * omcost);
-  }
-
-  PseudoJet cp = cross_product(n1,n2);
-  double sign = dot_product_3d(cp,n);
-
-  if (sign > 0) return theta;
-  else          return -theta;
-}
-
-class Matrix3 {
-public:
-  /// constructs an empty matrix
-  Matrix3() : matrix_({{{{0,0,0}},   {{0,0,0}},   {{0,0,0}}}}) {}
-
-  /// constructs a diagonal matrix with "unit" along each diagonal entry
-  Matrix3(double unit) : matrix_({{{{unit,0,0}},   {{0,unit,0}},   {{0,0,unit}}}}) {}
-
-  /// constructs a matrix from the array<array<...,3>,3> object
-  Matrix3(const std::array<std::array<double,3>,3> & mat) : matrix_(mat) {}
-
-  /// returns the entry at row i, column j
-  inline double operator()(int i, int j) const {
-    return matrix_[i][j];
-  }
-
-  /// returns a matrix for carrying out azimuthal rotation
-  /// around the z direction by an angle phi
-  static Matrix3 azimuthal_rotation(double phi) {
-    double cos_phi = cos(phi);
-    double sin_phi = sin(phi);
-    Matrix3 phi_rot( {{ {{cos_phi, sin_phi, 0}},
-	             {{-sin_phi, cos_phi, 0}},
-	             {{0,0,1}}}});
-    return phi_rot;
-  }
-
-  /// returns a matrix for carrying out a polar-angle
-  /// rotation, in the z-x plane, by an angle theta
-  static Matrix3 polar_rotation(double theta) {
-    double cos_theta = cos(theta);
-    double sin_theta = sin(theta);
-    Matrix3 theta_rot( {{ {{cos_theta, 0, sin_theta}},
-	               {{0,1,0}},
-	               {{-sin_theta, 0, cos_theta}}}});
-    return theta_rot;
-  }
-
-  /// This provides a rotation matrix that takes the z axis to the
-  /// direction of p. With skip_pre_rotation = false (the default), it
-  /// has the characteristic that if p is close to the z axis then the
-  /// azimuthal angle of anything at much larger angle is conserved.
-  ///
-  /// If skip_pre_rotation is true, then the azimuthal angles are not
-  /// when p is close to the z axis.
-  template<class T>
-  static Matrix3 from_direction(const T & p, bool skip_pre_rotation = false) {
-    double pt = p.pt();
-    double modp = p.modp();
-    double cos_theta = p.pz() / modp;
-    double sin_theta = pt / modp;
-    double cos_phi, sin_phi;
-    if (pt > 0.0) {
-      cos_phi = p.px()/pt;
-      sin_phi = p.py()/pt;
-    } else {
-      cos_phi = 1.0;
-      sin_phi = 0.0;
-    }
-
-    Matrix3 phi_rot({{ {{ cos_phi,-sin_phi, 0 }},
-	                     {{ sin_phi, cos_phi, 0 }},
-	                     {{       0,       0, 1 }} }});
-    Matrix3 theta_rot( {{ {{ cos_theta, 0, sin_theta }},
-	                        {{         0, 1,         0 }},
-	                        {{-sin_theta, 0, cos_theta }} }});
-
-    // since we have orthogonal matrices, the inverse and transpose
-    // are identical; we use the transpose for the frontmost rotation
-    // because 
-    if (skip_pre_rotation) {
-      return phi_rot * theta_rot;
-    } else {
-      return phi_rot * (theta_rot * phi_rot.transpose());
-    }
-  }
-
-  template<class T>
-  static Matrix3 from_direction_no_pre_rotn(const T & p) {
-    return from_direction(p,true);
-  }
-
-
-
-  /// returns the transposed matrix
-  Matrix3 transpose() const {
-    // 00 01 02
-    // 10 11 12
-    // 20 21 22
-    Matrix3 result = *this;
-    std::swap(result.matrix_[0][1],result.matrix_[1][0]);
-    std::swap(result.matrix_[0][2],result.matrix_[2][0]);
-    std::swap(result.matrix_[1][2],result.matrix_[2][1]);
-    return result;
-  }
-
-  // returns the product with another matrix
-  Matrix3 operator*(const Matrix3 & other) const {
-    Matrix3 result;
-    // r_{ij} = sum_k this_{ik} & other_{kj}
-    for (int i = 0; i < 3; i++) {
-      for (int j = 0; j < 3; j++) {
-        for (int k = 0; k < 3; k++) {
-          result.matrix_[i][j] += this->matrix_[i][k] * other.matrix_[k][j];
-        }
-      }
-    }
-    return result;
-  }
-  
-  friend std::ostream & operator<<(std::ostream & ostr, const Matrix3 & mat);
-private:
-  std::array<std::array<double,3>,3> matrix_;
-};
-
-inline std::ostream & operator<<(std::ostream & ostr, const Matrix3 & mat) {
-  ostr << mat.matrix_[0][0] << " " << mat.matrix_[0][1] << " " << mat.matrix_[0][2] << std::endl;
-  ostr << mat.matrix_[1][0] << " " << mat.matrix_[1][1] << " " << mat.matrix_[1][2] << std::endl;
-  ostr << mat.matrix_[2][0] << " " << mat.matrix_[2][1] << " " << mat.matrix_[2][2] << std::endl;
-  return ostr;
-}
-
-/// returns the project of this matrix with the PseudoJet,
-/// maintaining the 4th component of the PseudoJet unchanged
-inline PseudoJet operator*(const Matrix3 & mat, const PseudoJet & p) {
-  // r_{i} = m_{ij} p_j
-  std::array<double,3> res3{{0,0,0}};
-  for (unsigned i = 0; i < 3; i++) {
-    for (unsigned j = 0; j < 3; j++) {
-      res3[i] += mat(i,j) * p[j];
-    }
-  }
-  // return a jet that maintains all internal pointers by
-  // initialising the result from the input jet and
-  // then resetting the momentum.
-  PseudoJet result(p);
-  // maintain the energy component as it was
-  result.reset_momentum(res3[0], res3[1], res3[2], p[3]);
-  return result;
-}
-
-} // namespace lund_plane
-} // namespace contrib
-
-FASTJET_END_NAMESPACE
-
-#endif // __FASTJET_CONTRIB_EEHELPERS_HH__
-
Index: contrib/contribs/LundPlane/trunk/LundWithSecondary.hh
===================================================================
--- contrib/contribs/LundPlane/trunk/LundWithSecondary.hh	(revision 1459)
+++ contrib/contribs/LundPlane/trunk/LundWithSecondary.hh	(revision 1460)
@@ -1,126 +0,0 @@
-// $Id$
-//
-// Copyright (c) 2018-, Frederic A. Dreyer, Keith Hamilton, Alexander Karlberg,
-// Gavin P. Salam, Ludovic Scyboz, Gregory Soyez, Rob Verheyen
-//
-//----------------------------------------------------------------------
-// This file is part of FastJet contrib.
-//
-// It is free software; you can redistribute it and/or modify it under
-// the terms of the GNU General Public License as published by the
-// Free Software Foundation; either version 2 of the License, or (at
-// your option) any later version.
-//
-// It is distributed in the hope that it will be useful, but WITHOUT
-// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-// or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
-// License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this code. If not, see <http://www.gnu.org/licenses/>.
-//----------------------------------------------------------------------
-
-#ifndef __FASTJET_CONTRIB_LUNDWITHSECONDARY_HH__
-#define __FASTJET_CONTRIB_LUNDWITHSECONDARY_HH__
-
-#include "LundGenerator.hh"
-#include "SecondaryLund.hh"
-
-FASTJET_BEGIN_NAMESPACE
-
-namespace contrib{
-
-//----------------------------------------------------------------------
-/// \class LundWithSecondary
-/// Define a primary and secondary Lund plane
-///
-///  \param secondary_def definition used for the leading emission.
-//
-class LundWithSecondary {
-public:
-  /// LundWithSecondary constructor
-  LundWithSecondary(SecondaryLund * secondary_def = 0)
-    : secondary_def_(secondary_def) {}
-  
-  /// LundWithSecondary constructor with jet alg
-  LundWithSecondary(JetAlgorithm jet_alg,
-		    SecondaryLund * secondary_def = 0)
-    : lund_gen_(jet_alg), secondary_def_(secondary_def) {}
-  
-  /// LundWithSecondary constructor with jet def
-  LundWithSecondary(const JetDefinition & jet_def,
-		    SecondaryLund * secondary_def = 0)
-    : lund_gen_(jet_def), secondary_def_(secondary_def) {}
-  
-  /// destructor
-  virtual ~LundWithSecondary() {}
-  
-  /// primary Lund declustering
-  std::vector<LundDeclustering> primary(const PseudoJet& jet) const;
-  
-  /// secondary Lund declustering (slow)
-  std::vector<LundDeclustering> secondary(const PseudoJet& jet) const;
-  
-  /// secondary Lund declustering with primary sequence as input
-  std::vector<LundDeclustering> secondary(
-			 const std::vector<LundDeclustering> & declusts) const;
-
-  /// return the index associated of the primary declustering that is to be
-  /// used for the secondary plane.
-  int secondary_index(const std::vector<LundDeclustering> & declusts) const;
-  
-  /// description of the class
-  std::string description() const;
-  
-private:
-  /// lund generator
-  LundGenerator lund_gen_;
-  
-  /// secondary definition
-  SecondaryLund * secondary_def_;
-};
-
-  
-// //----------------------------------------------------------------------
-// /// \class LundWithSecondaryAndTertiary
-// /// Define a primary, secondary and tertiary Lund plane
-// class LundWithSecondaryAndTertiary : public LundWithSecondary {
-// public:
-//   /// LundWithSecondaryAndTertiary constructor
-//   LundWithSecondaryAndTertiary(SecondaryLund * secondary_def = 0,
-// 			       SecondaryLund * tertiary_def = 0)
-//     : LundWithSecondary(secondary_def), tertiary_def_(tertiary_def) {}
-  
-//   /// LundWithSecondaryAndTertiary constructor with jet alg
-//   LundWithSecondaryAndTertiary(JetAlgorithm jet_alg,
-// 		    SecondaryLund * secondary_def = 0,
-// 		    SecondaryLund * tertiary_def = 0)
-//     : LundWithSecondary(jet_alg, secondary_def), tertiary_def_(tertiary_def) {}
-  
-//   /// LundWithSecondaryAndTertiary constructor with jet def
-//   LundWithSecondaryAndTertiary(const JetDefinition & jet_def,
-// 			       SecondaryLund * secondary_def = 0,
-// 			       SecondaryLund * tertiary_def = 0)
-//     : LundWithSecondary(jet_def, secondary_def), tertiary_def_(tertiary_def) {}
-  
-//   /// destructor
-//   virtual ~LundWithSecondaryAndTertiary() {}
-  
-//   /// tertiary Lund declustering
-//   virtual std::vector<LundDeclustering> tertiary(const PseudoJet& jet) const;
-
-//   /// description of the class
-//   virtual std::string description() const;
-  
-// private:
-//   /// tertiary definition
-//   SecondaryLund * tertiary_def_;
-// };
-
-
-} // namespace contrib
-
-FASTJET_END_NAMESPACE
-
-#endif  // __FASTJET_CONTRIB_LUNDWITHSECONDARY_HH__
-
Index: contrib/contribs/LundPlane/trunk/LundGenerator.hh
===================================================================
--- contrib/contribs/LundPlane/trunk/LundGenerator.hh	(revision 1459)
+++ contrib/contribs/LundPlane/trunk/LundGenerator.hh	(revision 1460)
@@ -1,138 +0,0 @@
-// $Id$
-//
-// Copyright (c) 2018-, Frederic A. Dreyer, Keith Hamilton, Alexander Karlberg,
-// Gavin P. Salam, Ludovic Scyboz, Gregory Soyez, Rob Verheyen
-//
-//----------------------------------------------------------------------
-// This file is part of FastJet contrib.
-//
-// It is free software; you can redistribute it and/or modify it under
-// the terms of the GNU General Public License as published by the
-// Free Software Foundation; either version 2 of the License, or (at
-// your option) any later version.
-//
-// It is distributed in the hope that it will be useful, but WITHOUT
-// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-// or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
-// License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this code. If not, see <http://www.gnu.org/licenses/>.
-//----------------------------------------------------------------------
-
-#ifndef __FASTJET_CONTRIB_LUNDGENERATOR_HH__
-#define __FASTJET_CONTRIB_LUNDGENERATOR_HH__
-
-#include <fastjet/internal/base.hh>
-#include "fastjet/tools/Recluster.hh"
-#include "fastjet/JetDefinition.hh"
-#include "fastjet/PseudoJet.hh"
-#include <string>
-#include <vector>
-#include <utility>
-
-// TODO:
-// - add interface to write declusterings to json files
-//   [gps, possibly as a separate header, in order to factorise the json.hh dependence]
-// - something for pileup subtraction?
-// - do we want to update json.hh to latest? And handle
-//   the precision issue more elegantly than the current 
-//   hack of editing json.hh
-// - what do we do about the fact that json.hh is c++11?
-
-FASTJET_BEGIN_NAMESPACE
-
-namespace contrib{
-
-class LundGenerator;
-
-//----------------------------------------------------------------------
-/// \class LundDeclustering
-/// Contains the declustering variables associated with a single qnode
-/// on the Lund plane
-class LundDeclustering {
-public:
-
-  /// return the pair PseudoJet, i.e. sum of the two subjets
-  const PseudoJet & pair()  const {return pair_;}
-  /// returns the subjet with larger transverse momentum
-  const PseudoJet & harder() const {return harder_;}
-  /// returns the subjet with smaller transverse momentum
-  const PseudoJet & softer() const {return softer_;}
-
-
-  /// returns pair().m() [cached]
-  double m()         const {return m_;}
-
-  /// returns the rapidity-azimuth separation of the pair of subjets [cached]
-  double Delta()     const {return Delta_;}
-
-  /// returns softer().pt() / (softer().pt() + harder().pt()) [cached]
-  double z()         const {return z_;}
-
-  /// returns softer().pt() * Delta() [cached]
-  double kt()        const {return kt_;}
-
-  /// returns z() * Delta() [cached]
-  double kappa()     const {return kappa_;}
-  
-  /// returns an azimuthal type angle of softer() around harder()
-  double psi()       const {return psi_;}
-  
-  /// returns the x,y coordinates that are used in the Lund-plane plots
-  /// of arXiv:1807.04758: ln(1/Delta()), and ln(kt()) respectively
-  std::pair<double,double> const lund_coordinates() const {
-    return std::pair<double,double>(std::log(1.0/Delta()),std::log(kt()));
-  }
-
-  virtual ~LundDeclustering() {}
-
-private:
-  double m_, Delta_, z_, kt_, kappa_, psi_;
-  PseudoJet pair_, harder_, softer_;
-
-protected:
-  /// the constructor is private, because users will not generally be
-  /// constructing a LundDeclustering element themselves.
-  LundDeclustering(const PseudoJet& pair,
-		   const PseudoJet& j1, const PseudoJet& j2);
-
-  friend class LundGenerator;
-
-};
-  
-
-//----------------------------------------------------------------------
-/// \class LundGenerator
-/// Generates vector of LundDeclustering for a given jet
-/// corresponding to its Lund plane.
-class LundGenerator : public FunctionOfPseudoJet< std::vector<LundDeclustering> > {
-public:
-  /// LundGenerator constructor
-  LundGenerator(JetAlgorithm jet_alg = cambridge_algorithm)
-    : recluster_(JetDefinition(jet_alg, JetDefinition::max_allowable_R)){}
-    
-  /// LundGenerator constructor with jet definition
-  LundGenerator(const JetDefinition & jet_def) : recluster_(jet_def){}
-  
-  /// destructor
-  virtual ~LundGenerator() {}
-
-  /// obtain the declusterings of the primary plane of the jet
-  virtual std::vector<LundDeclustering> result(const PseudoJet& jet) const;
-
-  /// description of the class
-  virtual std::string description() const;
-  
-private:
-  /// recluster definition
-  Recluster recluster_;
-};
-
-
-} // namespace contrib
-
-FASTJET_END_NAMESPACE
-
-#endif  // __FASTJET_CONTRIB_LUNDGENERATOR_HH__
-
Index: contrib/contribs/LundPlane/trunk/SecondaryLund.hh
===================================================================
--- contrib/contribs/LundPlane/trunk/SecondaryLund.hh	(revision 1459)
+++ contrib/contribs/LundPlane/trunk/SecondaryLund.hh	(revision 1460)
@@ -1,122 +0,0 @@
-// $Id$
-//
-// Copyright (c) 2018-, Frederic A. Dreyer, Keith Hamilton, Alexander Karlberg,
-// Gavin P. Salam, Ludovic Scyboz, Gregory Soyez, Rob Verheyen
-//
-//----------------------------------------------------------------------
-// This file is part of FastJet contrib.
-//
-// It is free software; you can redistribute it and/or modify it under
-// the terms of the GNU General Public License as published by the
-// Free Software Foundation; either version 2 of the License, or (at
-// your option) any later version.
-//
-// It is distributed in the hope that it will be useful, but WITHOUT
-// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-// or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
-// License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this code. If not, see <http://www.gnu.org/licenses/>.
-//----------------------------------------------------------------------
-
-#ifndef __FASTJET_CONTRIB_SECONDARYLUND_HH__
-#define __FASTJET_CONTRIB_SECONDARYLUND_HH__
-
-#include "LundGenerator.hh"
-
-FASTJET_BEGIN_NAMESPACE
-
-namespace contrib{
-  
-//----------------------------------------------------------------------
-/// \class SecondaryLund
-/// Base class for definitions of the leading emission
-class SecondaryLund {
-public:
-  /// SecondaryLund constructor
-  SecondaryLund() {}
-
-  /// destructor
-  virtual ~SecondaryLund() {}
-
-  /// returns the index of branch corresponding to the root of the secondary plane
-  virtual int result(const std::vector<LundDeclustering> & declusts) const = 0;
-
-  int operator()(const std::vector<LundDeclustering> & declusts) const {
-    return result(declusts);
-  }
-
-  /// description of the class
-  virtual std::string description() const;
-};
-  
-//----------------------------------------------------------------------
-/// \class SecondaryLund_mMDT
-/// Contains a definition for the leading emission using mMDTZ
-class SecondaryLund_mMDT : public SecondaryLund {
-public:
-  /// SecondaryLund_mMDT constructor
-  SecondaryLund_mMDT(double zcut = 0.025) : zcut_(zcut) {}
-
-  /// destructor
-  virtual ~SecondaryLund_mMDT() {}
-  
-  /// returns the index of branch corresponding to the root of the secondary plane
-  virtual int result(const std::vector<LundDeclustering> & declusts) const;
-  
-  /// description of the class
-  virtual std::string description() const;  
-private:
-  /// zcut parameter
-  double zcut_;
-};
-  
-//----------------------------------------------------------------------
-/// \class SecondaryLund_dotmMDT
-/// Contains a definition for the leading emission using dotmMDT
-class SecondaryLund_dotmMDT : public SecondaryLund {
-public:
-  /// SecondaryLund_dotmMDT constructor
-  SecondaryLund_dotmMDT(double zcut = 0.025) : zcut_(zcut) {}
-
-  /// destructor
-  virtual ~SecondaryLund_dotmMDT() {}
-  
-  /// returns the index of branch corresponding to the root of the secondary plane
-  virtual int result(const std::vector<LundDeclustering> & declusts) const;
-  
-  /// description of the class
-  virtual std::string description() const;  
-
-private:
-  /// zcut parameter
-  double zcut_;
-};
-  
-//----------------------------------------------------------------------
-/// \class SecondaryLund_Mass
-/// Contains a definition for the leading emission using mass
-class SecondaryLund_Mass : public SecondaryLund {
-public:
-  /// SecondaryLund_Mass constructor (default mass reference is W mass)
-  SecondaryLund_Mass(double ref_mass = 80.4) : mref2_(ref_mass*ref_mass) {}
-
-  /// destructor
-  virtual ~SecondaryLund_Mass() {}
-  
-  /// returns the index of branch corresponding to the root of the secondary plane
-  virtual int result(const std::vector<LundDeclustering> & declusts) const;
-  
-  /// description of the class
-  virtual std::string description() const;  
-private:
-  double mref2_;
-};
-
-} // namespace contrib
-
-FASTJET_END_NAMESPACE
-
-#endif  // __FASTJET_CONTRIB_SECONDARYLUND_HH__
-
Index: contrib/contribs/LundPlane/trunk/RecursiveLundEEGenerator.hh
===================================================================
--- contrib/contribs/LundPlane/trunk/RecursiveLundEEGenerator.hh	(revision 1459)
+++ contrib/contribs/LundPlane/trunk/RecursiveLundEEGenerator.hh	(revision 1460)
@@ -1,364 +0,0 @@
-// $Id$
-//
-// Copyright (c) 2018-, Frederic A. Dreyer, Keith Hamilton, Alexander Karlberg,
-// Gavin P. Salam, Ludovic Scyboz, Gregory Soyez, Rob Verheyen
-//
-//----------------------------------------------------------------------
-// This file is part of FastJet contrib.
-//
-// It is free software; you can redistribute it and/or modify it under
-// the terms of the GNU General Public License as published by the
-// Free Software Foundation; either version 2 of the License, or (at
-// your option) any later version.
-//
-// It is distributed in the hope that it will be useful, but WITHOUT
-// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-// or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
-// License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this code. If not, see <http://www.gnu.org/licenses/>.
-//----------------------------------------------------------------------
-
-#ifndef __FASTJET_CONTRIB_RECURSIVELUNDEEGENERATOR_HH__
-#define __FASTJET_CONTRIB_RECURSIVELUNDEEGENERATOR_HH__
-
-#include "LundEEHelpers.hh"
-
-#include <fastjet/internal/base.hh>
-#include "fastjet/tools/Recluster.hh"
-#include "fastjet/JetDefinition.hh"
-#include "fastjet/PseudoJet.hh"
-#include <string>
-#include <vector>
-#include <utility>
-#include <queue>
-
-using namespace std;
-
-FASTJET_BEGIN_NAMESPACE
-
-namespace contrib{
-
-//----------------------------------------------------------------------
-/// \class LundEEDeclustering
-/// Contains the declustering variables associated with a single node
-/// on the LundEE plane
-class LundEEDeclustering {
-public:
-
-  /// return the pair PseudoJet, i.e. sum of the two subjets
-  const PseudoJet & pair()  const {return pair_;}
-  /// returns the subjet with larger transverse momentum
-  const PseudoJet & harder() const {return harder_;}
-  /// returns the subjet with smaller transverse momentum
-  const PseudoJet & softer() const {return softer_;}
-
-
-  /// returns pair().m() [cached]
-  double m()         const {return m_;}
-
-  /// returns the effective pseudorapidity of the emission [cached]
-  double eta()       const {return eta_;}
-
-  /// returns sin(theta) of the branching [cached]
-  double sin_theta() const {return sin_theta_;}
-
-  /// returns softer().modp() / (softer().modp() + harder().modp()) [cached]
-  double z()         const {return z_;}
-
-  /// returns softer().modp() * sin(theta()) [cached]
-  double kt()        const {return kt_;}
-
-  /// returns ln(softer().modp() * sin(theta())) [cached]
-  double lnkt()      const {return lnkt_;}
-
-  /// returns z() * Delta() [cached]
-  double kappa()     const {return kappa_;}
-
-  /// returns the index of the plane to which this branching belongs
-  int iplane() const {return iplane_;}
-
-  /// returns the depth of the plane on which this declustering
-  /// occurred. 0 is the primary plane, 1 is the first set of leaves, etc. 
-  int depth() const {return depth_;}
-  
-  /// returns iplane (plane index) of the leaf associated with the
-  /// potential further declustering of the softer of the objects in
-  /// this splitting
-  int leaf_iplane() const {return leaf_iplane_;}
-
-  /// Returns sign_s, indicating the initial parent jet index of this splitting
-  int sign_s() const {return sign_s_;}
-  
-  /// returns an azimuthal angle psibar associated with this
-  /// declustering. The actual value of psibar is arbitrary and IR
-  /// unsafe (but see below), while differences in psibar values between
-  /// different clusterings are meaningful.
-  ///
-  /// The absolute value of psibar should in general not be used,  but
-  /// it has the following properties. (1) the first (largest-angle) splitting
-  /// ("ref") in the positive-z hemisphere defines psibar=0 (if there is
-  /// no splitting in that hemisphere then the first splitting in
-  /// the negative-z hemisphere does). If the +z jet aligns along the z
-  /// axis, then psibar of collinear splitting i in that jet is 
-  ///
-  ///   psibar_i = phi_i - phi_ref
-  ///
-  /// For the negative-z jet, the psibar of collinear splitting i is
-  ///
-  ///   psibar_i = phi_i - pi - phi_ref
-  ///
-  double psibar()    const {return psibar_;}
-
-  /// (DEPRECATED)
-  /// returns an azimuthal type angle between this declustering plane and the previous one
-  /// Note: one should use psibar() instead, since we found that this definition of psi is
-  /// not invariant under rotations of the event
-  double psi()       const {return psi_;}
-
-  /// update the azimuthal angle (deprecated)
-  void set_psi(double psi) {psi_ = psi;}
-
-
-  /// returns the coordinates in the Lund plane
-  std::pair<double,double> const lund_coordinates() const {
-    return std::pair<double,double>(eta_,lnkt_);
-  }
-
-  virtual ~LundEEDeclustering() {}
-
-private:
-  int iplane_;
-  double psi_, psibar_, lnkt_, eta_;
-  double m_, z_, kt_, kappa_, sin_theta_;
-  PseudoJet pair_, harder_, softer_;
-  int  depth_ = -1, leaf_iplane_ = -1;
-  int sign_s_;
-
-protected:
-
-  /// default ctor (protected, should not normally be needed by users,
-  /// but can be useful for derived classes)
-  LundEEDeclustering() {}
-
-  /// the constructor is protected, because users will not generally be
-  /// constructing a LundEEDeclustering element themselves.
-  LundEEDeclustering(const PseudoJet& pair,
-		     const PseudoJet& j1, const PseudoJet& j2,
-		     int iplane = -1, double psi = 0.0, double psibar = 0.0, int depth = -1, int leaf_iplane = -1, int sign_s = 1);
-
-  friend class RecursiveLundEEGenerator;
-
-};
-
-
-/// Default comparison operator for LundEEDeclustering, using kt as the ordering.
-/// Useful when including declusterings in structures like priority queues
-inline bool operator<(const LundEEDeclustering& d1, const LundEEDeclustering& d2) {
-  return d1.kt() < d2.kt();
-}
-
-//----------------------------------------------------------------------  
-/// Class to carry out Lund declustering to get anything from the
-/// primary Lund plane declusterings to the full Lund diagram with all
-/// its leaves, etc.
-class RecursiveLundEEGenerator {
- public:
-  /// constructs a RecursiveLundEEGenerator with the specified depth.
-  /// - depth = 0 means only primary declusterings are registered
-  /// - depth = 1 means the first set of leaves are declustered
-  /// - ...
-  /// - depth < 0 means no limit, i.e. recurse through all leaves
-  ///
-  /// The psibar values that are set in the result Lund tree have the
-  /// following property:
-  ///
-  /// - if the jet with the larger pz has splittings, then its
-  ///   first splitting has psibar = 0
-  /// - otherwise the first splitting of the other jet has psibar = 0
-  ///
-  /// Note that this makes psibar IR unsafe (because an arbitrarily soft
-  /// splitting can be the one that gets the reference psibar=0 value), 
-  /// but differences between psibar values are IR safe.
-  /// 
-  /// NB: The dynamical_psi_ref option relates to the deprecated definition of psi
-  /// New code should use the psibar() function and dynamical_psi_ref
-  /// is irrelevant.
-  RecursiveLundEEGenerator(int max_depth = 0, bool dynamical_psi_ref = false) :
-    max_depth_(max_depth), nx_(1,0,0,0), ny_(0,1,0,0), dynamical_psi_ref_(dynamical_psi_ref)
-  {}
-
-  /// destructor
-  virtual ~RecursiveLundEEGenerator() {}
-
-  /// This takes a cluster sequence with an e+e- C/A style algorithm, e.g.
-  /// EECambridgePlugin(ycut=1.0).
-  ///
-  /// The output is a vector of LundEEDeclustering objects, ordered
-  /// according to kt
-  virtual std::vector<LundEEDeclustering> result(const ClusterSequence & cs) const {
-    std::vector<PseudoJet> exclusive_jets = cs.exclusive_jets(2);
-    assert(exclusive_jets.size() == 2);
-    
-    // order the two jets according to momentum along z axis
-    if (exclusive_jets[0].pz() < exclusive_jets[1].pz()) {
-      std::swap(exclusive_jets[0],exclusive_jets[1]);
-    }
-
-    PseudoJet d_ev = exclusive_jets[0] - exclusive_jets[1];
-    lund_plane::Matrix3 rotmat = lund_plane::Matrix3::from_direction(d_ev);
-    
-    std::vector<LundEEDeclustering> declusterings;
-    int depth = 0;
-    int max_iplane_sofar = 1;
-
-// 2024-01: new code, that fixes up issue of psibar differences
-// between hemispheres. If RLEEG_NEWPSIBAR is false, answers
-// will come out wrong.
-#define RLEEG_NEWPSIBAR
-#ifdef RLEEG_NEWPSIBAR
-    // 2024-01 -- attempt at new definition of psibar
-    PseudoJet ref_plane;
-    double last_psibar = 0.;
-    bool first_time = true;
-
-    for (unsigned ijet = 0; ijet < exclusive_jets.size(); ijet++) {
-      int sign_s = ijet == 0? +1 : -1;
-      append_to_vector(declusterings, exclusive_jets[ijet], depth, ijet, max_iplane_sofar,
-                        rotmat, sign_s, ref_plane, last_psibar, first_time);
-    }
-#else 
-    for (unsigned ijet = 0; ijet < exclusive_jets.size(); ijet++) {
-
-      // reference direction for psibar calculation
-      PseudoJet axis = d_ev/sqrt(d_ev.modp2());
-      PseudoJet ref_plane = axis;
-
-      int sign_s = ijet == 0? +1 : -1;
-      bool
-      // We can pass a vector normal to a plane of reference for phi definitions
-      append_to_vector(declusterings, exclusive_jets[ijet], depth, ijet, max_iplane_sofar,
-                       rotmat, sign_s, ref_plane, 0., true);
-    }
-#endif
-
-    // a typedef to save typing below
-    typedef LundEEDeclustering LD;
-    // sort so that declusterings are returned in order of decreasing
-    // kt (if result of the lambda is true, then first object appears
-    // before the second one in the final sorted list)
-    sort(declusterings.begin(), declusterings.end(),
-         [](const LD & d1, const LD & d2){return d1.kt() > d2.kt();});
-
-    return declusterings;
-  }
-  
- private:
-
-  /// internal routine to recursively carry out the declusterings,
-  /// adding each one to the declusterings vector; the primary
-  /// ones are dealt with first (from large to small angle),
-  /// and then secondary ones take place.
-  void append_to_vector(std::vector<LundEEDeclustering> & declusterings,
-                        const PseudoJet & jet, int depth,
-                        int iplane, int & max_iplane_sofar,
-                        const lund_plane::Matrix3 & rotmat, int sign_s,
-                        PseudoJet & psibar_ref_plane,
-                        const double & last_psibar, bool & first_time) const {
-    PseudoJet j1, j2;
-    if (!jet.has_parents(j1, j2)) return;
-    if (j1.modp2() < j2.modp2()) std::swap(j1,j2);
-
-    // calculation of azimuth psi
-    lund_plane::Matrix3 new_rotmat;
-    if (dynamical_psi_ref_) {
-      new_rotmat = lund_plane::Matrix3::from_direction(rotmat.transpose()*(sign_s*jet)) * rotmat;
-    } else {
-      new_rotmat = rotmat;
-    }
-    PseudoJet rx = new_rotmat * nx_;
-    PseudoJet ry = new_rotmat * ny_;
-    PseudoJet u1 = j1/j1.modp(), u2 = j2/j2.modp();
-    PseudoJet du = u2 - u1;
-    double x = du.px() * rx.px() + du.py() * rx.py() + du.pz() * rx.pz();
-    double y = du.px() * ry.px() + du.py() * ry.py() + du.pz() * ry.pz();
-    double psi = atan2(y,x);
-
-    // calculation of psibar
-    double psibar = 0.;
-    PseudoJet n1, n2;
-
-    // First psibar for this jet
-    if (first_time) {
-
-#ifdef RLEEG_NEWPSIBAR
-// 2024-01: new code, that fixes up issue of psibar differences
-// between hemispheres
-      assert(last_psibar == 0.0);
-      psibar = 0.0;
-      n2 = lund_plane::cross_product(j1,j2);
-      n2 /= n2.modp();
-      psibar_ref_plane = n2;
-      first_time = false;
-#else 
-      // Compute the angle between the planes spanned by (some axis,j1) and by (j1,j2)
-      n1 = lund_plane::cross_product(psibar_ref_plane,j1);
-      n2 = lund_plane::cross_product(j1,j2);
-
-      double signed_angle = 0.;
-      n2 /= n2.modp();
-      if (n1.modp() != 0) {
-        n1 /= n1.modp();
-        signed_angle = lund_plane::signed_angle_between_planes(n1,n2,j1);
-      }
-
-      psibar = lund_plane::map_to_pi(j1.phi() + signed_angle);
-#endif
-    }
-    // Else take the value of psibar_i and the plane from the last splitting to define psibar_{i+1}
-    // The signed angle is multiplied by sign_s (+1 for the +z hemisphere, -1 for the -z hemisphere)
-    // to take the correct orientation into account.
-    else {
-      n2 = lund_plane::cross_product(j1,j2);
-      n2 /= n2.modp();
-      psibar = lund_plane::map_to_pi(last_psibar + sign_s*lund_plane::signed_angle_between_planes(psibar_ref_plane, n2, j1));
-    }
-
-    int leaf_iplane = -1;
-    // we will recurse into the softer "parent" only if the depth is
-    // not yet at its limit or if there is no limit on the depth (max_depth<0)
-    bool recurse_into_softer = (depth < max_depth_ || max_depth_ < 0);
-    if (recurse_into_softer) {
-      max_iplane_sofar += 1;
-      leaf_iplane = max_iplane_sofar;
-    }
-    
-    LundEEDeclustering declust(jet, j1, j2, iplane, psi, psibar, depth, leaf_iplane, sign_s);
-    declusterings.push_back(declust);
-
-    // now recurse
-    // for the definition of psibar, we recursively pass the last splitting plane (normal to n2) and the last value
-    // of psibar
-    bool lcl_first_time = false;
-    append_to_vector(declusterings, j1, depth, iplane, max_iplane_sofar, new_rotmat, sign_s, n2, psibar, lcl_first_time);
-    if (recurse_into_softer) {
-      append_to_vector(declusterings, j2, depth+1, leaf_iplane, max_iplane_sofar, new_rotmat, sign_s, n2, psibar, lcl_first_time);
-    }
-  }
-  
-  int max_depth_ = 0;
-  /// vectors used to help define psi
-  PseudoJet nx_;
-  PseudoJet ny_;
-  bool dynamical_psi_ref_;
-};
-  
-} // namespace contrib
-
-FASTJET_END_NAMESPACE
-
-/// for output of declustering information
-std::ostream & operator<<(std::ostream & ostr, const fastjet::contrib::LundEEDeclustering & d);
-
-#endif  // __FASTJET_CONTRIB_RECURSIVELUNDEEGENERATOR_HH__
Index: contrib/contribs/LundPlane/trunk/include/fastjet/contrib/LundWithSecondary.hh
===================================================================
--- contrib/contribs/LundPlane/trunk/include/fastjet/contrib/LundWithSecondary.hh	(revision 0)
+++ contrib/contribs/LundPlane/trunk/include/fastjet/contrib/LundWithSecondary.hh	(revision 1460)
@@ -0,0 +1,126 @@
+// $Id$
+//
+// Copyright (c) 2018-, Frederic A. Dreyer, Keith Hamilton, Alexander Karlberg,
+// Gavin P. Salam, Ludovic Scyboz, Gregory Soyez, Rob Verheyen
+//
+//----------------------------------------------------------------------
+// This file is part of FastJet contrib.
+//
+// It is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 2 of the License, or (at
+// your option) any later version.
+//
+// It is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+// or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+// License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this code. If not, see <http://www.gnu.org/licenses/>.
+//----------------------------------------------------------------------
+
+#ifndef __FASTJET_CONTRIB_LUNDWITHSECONDARY_HH__
+#define __FASTJET_CONTRIB_LUNDWITHSECONDARY_HH__
+
+#include "LundGenerator.hh"
+#include "SecondaryLund.hh"
+
+FASTJET_BEGIN_NAMESPACE
+
+namespace contrib{
+
+//----------------------------------------------------------------------
+/// \class LundWithSecondary
+/// Define a primary and secondary Lund plane
+///
+///  \param secondary_def definition used for the leading emission.
+//
+class LundWithSecondary {
+public:
+  /// LundWithSecondary constructor
+  LundWithSecondary(SecondaryLund * secondary_def = 0)
+    : secondary_def_(secondary_def) {}
+  
+  /// LundWithSecondary constructor with jet alg
+  LundWithSecondary(JetAlgorithm jet_alg,
+		    SecondaryLund * secondary_def = 0)
+    : lund_gen_(jet_alg), secondary_def_(secondary_def) {}
+  
+  /// LundWithSecondary constructor with jet def
+  LundWithSecondary(const JetDefinition & jet_def,
+		    SecondaryLund * secondary_def = 0)
+    : lund_gen_(jet_def), secondary_def_(secondary_def) {}
+  
+  /// destructor
+  virtual ~LundWithSecondary() {}
+  
+  /// primary Lund declustering
+  std::vector<LundDeclustering> primary(const PseudoJet& jet) const;
+  
+  /// secondary Lund declustering (slow)
+  std::vector<LundDeclustering> secondary(const PseudoJet& jet) const;
+  
+  /// secondary Lund declustering with primary sequence as input
+  std::vector<LundDeclustering> secondary(
+			 const std::vector<LundDeclustering> & declusts) const;
+
+  /// return the index associated of the primary declustering that is to be
+  /// used for the secondary plane.
+  int secondary_index(const std::vector<LundDeclustering> & declusts) const;
+  
+  /// description of the class
+  std::string description() const;
+  
+private:
+  /// lund generator
+  LundGenerator lund_gen_;
+  
+  /// secondary definition
+  SecondaryLund * secondary_def_;
+};
+
+  
+// //----------------------------------------------------------------------
+// /// \class LundWithSecondaryAndTertiary
+// /// Define a primary, secondary and tertiary Lund plane
+// class LundWithSecondaryAndTertiary : public LundWithSecondary {
+// public:
+//   /// LundWithSecondaryAndTertiary constructor
+//   LundWithSecondaryAndTertiary(SecondaryLund * secondary_def = 0,
+// 			       SecondaryLund * tertiary_def = 0)
+//     : LundWithSecondary(secondary_def), tertiary_def_(tertiary_def) {}
+  
+//   /// LundWithSecondaryAndTertiary constructor with jet alg
+//   LundWithSecondaryAndTertiary(JetAlgorithm jet_alg,
+// 		    SecondaryLund * secondary_def = 0,
+// 		    SecondaryLund * tertiary_def = 0)
+//     : LundWithSecondary(jet_alg, secondary_def), tertiary_def_(tertiary_def) {}
+  
+//   /// LundWithSecondaryAndTertiary constructor with jet def
+//   LundWithSecondaryAndTertiary(const JetDefinition & jet_def,
+// 			       SecondaryLund * secondary_def = 0,
+// 			       SecondaryLund * tertiary_def = 0)
+//     : LundWithSecondary(jet_def, secondary_def), tertiary_def_(tertiary_def) {}
+  
+//   /// destructor
+//   virtual ~LundWithSecondaryAndTertiary() {}
+  
+//   /// tertiary Lund declustering
+//   virtual std::vector<LundDeclustering> tertiary(const PseudoJet& jet) const;
+
+//   /// description of the class
+//   virtual std::string description() const;
+  
+// private:
+//   /// tertiary definition
+//   SecondaryLund * tertiary_def_;
+// };
+
+
+} // namespace contrib
+
+FASTJET_END_NAMESPACE
+
+#endif  // __FASTJET_CONTRIB_LUNDWITHSECONDARY_HH__
+

Property changes on: contrib/contribs/LundPlane/trunk/include/fastjet/contrib/LundWithSecondary.hh
___________________________________________________________________
Added: svn:keywords
## -0,0 +1 ##
+Id
\ No newline at end of property
Index: contrib/contribs/LundPlane/trunk/include/fastjet/contrib/LundGenerator.hh
===================================================================
--- contrib/contribs/LundPlane/trunk/include/fastjet/contrib/LundGenerator.hh	(revision 0)
+++ contrib/contribs/LundPlane/trunk/include/fastjet/contrib/LundGenerator.hh	(revision 1460)
@@ -0,0 +1,138 @@
+// $Id$
+//
+// Copyright (c) 2018-, Frederic A. Dreyer, Keith Hamilton, Alexander Karlberg,
+// Gavin P. Salam, Ludovic Scyboz, Gregory Soyez, Rob Verheyen
+//
+//----------------------------------------------------------------------
+// This file is part of FastJet contrib.
+//
+// It is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 2 of the License, or (at
+// your option) any later version.
+//
+// It is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+// or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+// License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this code. If not, see <http://www.gnu.org/licenses/>.
+//----------------------------------------------------------------------
+
+#ifndef __FASTJET_CONTRIB_LUNDGENERATOR_HH__
+#define __FASTJET_CONTRIB_LUNDGENERATOR_HH__
+
+#include <fastjet/internal/base.hh>
+#include "fastjet/tools/Recluster.hh"
+#include "fastjet/JetDefinition.hh"
+#include "fastjet/PseudoJet.hh"
+#include <string>
+#include <vector>
+#include <utility>
+
+// TODO:
+// - add interface to write declusterings to json files
+//   [gps, possibly as a separate header, in order to factorise the json.hh dependence]
+// - something for pileup subtraction?
+// - do we want to update json.hh to latest? And handle
+//   the precision issue more elegantly than the current 
+//   hack of editing json.hh
+// - what do we do about the fact that json.hh is c++11?
+
+FASTJET_BEGIN_NAMESPACE
+
+namespace contrib{
+
+class LundGenerator;
+
+//----------------------------------------------------------------------
+/// \class LundDeclustering
+/// Contains the declustering variables associated with a single qnode
+/// on the Lund plane
+class LundDeclustering {
+public:
+
+  /// return the pair PseudoJet, i.e. sum of the two subjets
+  const PseudoJet & pair()  const {return pair_;}
+  /// returns the subjet with larger transverse momentum
+  const PseudoJet & harder() const {return harder_;}
+  /// returns the subjet with smaller transverse momentum
+  const PseudoJet & softer() const {return softer_;}
+
+
+  /// returns pair().m() [cached]
+  double m()         const {return m_;}
+
+  /// returns the rapidity-azimuth separation of the pair of subjets [cached]
+  double Delta()     const {return Delta_;}
+
+  /// returns softer().pt() / (softer().pt() + harder().pt()) [cached]
+  double z()         const {return z_;}
+
+  /// returns softer().pt() * Delta() [cached]
+  double kt()        const {return kt_;}
+
+  /// returns z() * Delta() [cached]
+  double kappa()     const {return kappa_;}
+  
+  /// returns an azimuthal type angle of softer() around harder()
+  double psi()       const {return psi_;}
+  
+  /// returns the x,y coordinates that are used in the Lund-plane plots
+  /// of arXiv:1807.04758: ln(1/Delta()), and ln(kt()) respectively
+  std::pair<double,double> const lund_coordinates() const {
+    return std::pair<double,double>(std::log(1.0/Delta()),std::log(kt()));
+  }
+
+  virtual ~LundDeclustering() {}
+
+private:
+  double m_, Delta_, z_, kt_, kappa_, psi_;
+  PseudoJet pair_, harder_, softer_;
+
+protected:
+  /// the constructor is private, because users will not generally be
+  /// constructing a LundDeclustering element themselves.
+  LundDeclustering(const PseudoJet& pair,
+		   const PseudoJet& j1, const PseudoJet& j2);
+
+  friend class LundGenerator;
+
+};
+  
+
+//----------------------------------------------------------------------
+/// \class LundGenerator
+/// Generates vector of LundDeclustering for a given jet
+/// corresponding to its Lund plane.
+class LundGenerator : public FunctionOfPseudoJet< std::vector<LundDeclustering> > {
+public:
+  /// LundGenerator constructor
+  LundGenerator(JetAlgorithm jet_alg = cambridge_algorithm)
+    : recluster_(JetDefinition(jet_alg, JetDefinition::max_allowable_R)){}
+    
+  /// LundGenerator constructor with jet definition
+  LundGenerator(const JetDefinition & jet_def) : recluster_(jet_def){}
+  
+  /// destructor
+  virtual ~LundGenerator() {}
+
+  /// obtain the declusterings of the primary plane of the jet
+  virtual std::vector<LundDeclustering> result(const PseudoJet& jet) const;
+
+  /// description of the class
+  virtual std::string description() const;
+  
+private:
+  /// recluster definition
+  Recluster recluster_;
+};
+
+
+} // namespace contrib
+
+FASTJET_END_NAMESPACE
+
+#endif  // __FASTJET_CONTRIB_LUNDGENERATOR_HH__
+

Property changes on: contrib/contribs/LundPlane/trunk/include/fastjet/contrib/LundGenerator.hh
___________________________________________________________________
Added: svn:keywords
## -0,0 +1 ##
+Id
\ No newline at end of property
Index: contrib/contribs/LundPlane/trunk/include/fastjet/contrib/SecondaryLund.hh
===================================================================
--- contrib/contribs/LundPlane/trunk/include/fastjet/contrib/SecondaryLund.hh	(revision 0)
+++ contrib/contribs/LundPlane/trunk/include/fastjet/contrib/SecondaryLund.hh	(revision 1460)
@@ -0,0 +1,122 @@
+// $Id$
+//
+// Copyright (c) 2018-, Frederic A. Dreyer, Keith Hamilton, Alexander Karlberg,
+// Gavin P. Salam, Ludovic Scyboz, Gregory Soyez, Rob Verheyen
+//
+//----------------------------------------------------------------------
+// This file is part of FastJet contrib.
+//
+// It is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 2 of the License, or (at
+// your option) any later version.
+//
+// It is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+// or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+// License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this code. If not, see <http://www.gnu.org/licenses/>.
+//----------------------------------------------------------------------
+
+#ifndef __FASTJET_CONTRIB_SECONDARYLUND_HH__
+#define __FASTJET_CONTRIB_SECONDARYLUND_HH__
+
+#include "LundGenerator.hh"
+
+FASTJET_BEGIN_NAMESPACE
+
+namespace contrib{
+  
+//----------------------------------------------------------------------
+/// \class SecondaryLund
+/// Base class for definitions of the leading emission
+class SecondaryLund {
+public:
+  /// SecondaryLund constructor
+  SecondaryLund() {}
+
+  /// destructor
+  virtual ~SecondaryLund() {}
+
+  /// returns the index of branch corresponding to the root of the secondary plane
+  virtual int result(const std::vector<LundDeclustering> & declusts) const = 0;
+
+  int operator()(const std::vector<LundDeclustering> & declusts) const {
+    return result(declusts);
+  }
+
+  /// description of the class
+  virtual std::string description() const;
+};
+  
+//----------------------------------------------------------------------
+/// \class SecondaryLund_mMDT
+/// Contains a definition for the leading emission using mMDTZ
+class SecondaryLund_mMDT : public SecondaryLund {
+public:
+  /// SecondaryLund_mMDT constructor
+  SecondaryLund_mMDT(double zcut = 0.025) : zcut_(zcut) {}
+
+  /// destructor
+  virtual ~SecondaryLund_mMDT() {}
+  
+  /// returns the index of branch corresponding to the root of the secondary plane
+  virtual int result(const std::vector<LundDeclustering> & declusts) const;
+  
+  /// description of the class
+  virtual std::string description() const;  
+private:
+  /// zcut parameter
+  double zcut_;
+};
+  
+//----------------------------------------------------------------------
+/// \class SecondaryLund_dotmMDT
+/// Contains a definition for the leading emission using dotmMDT
+class SecondaryLund_dotmMDT : public SecondaryLund {
+public:
+  /// SecondaryLund_dotmMDT constructor
+  SecondaryLund_dotmMDT(double zcut = 0.025) : zcut_(zcut) {}
+
+  /// destructor
+  virtual ~SecondaryLund_dotmMDT() {}
+  
+  /// returns the index of branch corresponding to the root of the secondary plane
+  virtual int result(const std::vector<LundDeclustering> & declusts) const;
+  
+  /// description of the class
+  virtual std::string description() const;  
+
+private:
+  /// zcut parameter
+  double zcut_;
+};
+  
+//----------------------------------------------------------------------
+/// \class SecondaryLund_Mass
+/// Contains a definition for the leading emission using mass
+class SecondaryLund_Mass : public SecondaryLund {
+public:
+  /// SecondaryLund_Mass constructor (default mass reference is W mass)
+  SecondaryLund_Mass(double ref_mass = 80.4) : mref2_(ref_mass*ref_mass) {}
+
+  /// destructor
+  virtual ~SecondaryLund_Mass() {}
+  
+  /// returns the index of branch corresponding to the root of the secondary plane
+  virtual int result(const std::vector<LundDeclustering> & declusts) const;
+  
+  /// description of the class
+  virtual std::string description() const;  
+private:
+  double mref2_;
+};
+
+} // namespace contrib
+
+FASTJET_END_NAMESPACE
+
+#endif  // __FASTJET_CONTRIB_SECONDARYLUND_HH__
+

Property changes on: contrib/contribs/LundPlane/trunk/include/fastjet/contrib/SecondaryLund.hh
___________________________________________________________________
Added: svn:keywords
## -0,0 +1 ##
+Id
\ No newline at end of property
Index: contrib/contribs/LundPlane/trunk/include/fastjet/contrib/RecursiveLundEEGenerator.hh
===================================================================
--- contrib/contribs/LundPlane/trunk/include/fastjet/contrib/RecursiveLundEEGenerator.hh	(revision 0)
+++ contrib/contribs/LundPlane/trunk/include/fastjet/contrib/RecursiveLundEEGenerator.hh	(revision 1460)
@@ -0,0 +1,364 @@
+// $Id$
+//
+// Copyright (c) 2018-, Frederic A. Dreyer, Keith Hamilton, Alexander Karlberg,
+// Gavin P. Salam, Ludovic Scyboz, Gregory Soyez, Rob Verheyen
+//
+//----------------------------------------------------------------------
+// This file is part of FastJet contrib.
+//
+// It is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 2 of the License, or (at
+// your option) any later version.
+//
+// It is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+// or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+// License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this code. If not, see <http://www.gnu.org/licenses/>.
+//----------------------------------------------------------------------
+
+#ifndef __FASTJET_CONTRIB_RECURSIVELUNDEEGENERATOR_HH__
+#define __FASTJET_CONTRIB_RECURSIVELUNDEEGENERATOR_HH__
+
+#include "LundEEHelpers.hh"
+
+#include <fastjet/internal/base.hh>
+#include "fastjet/tools/Recluster.hh"
+#include "fastjet/JetDefinition.hh"
+#include "fastjet/PseudoJet.hh"
+#include <string>
+#include <vector>
+#include <utility>
+#include <queue>
+
+using namespace std;
+
+FASTJET_BEGIN_NAMESPACE
+
+namespace contrib{
+
+//----------------------------------------------------------------------
+/// \class LundEEDeclustering
+/// Contains the declustering variables associated with a single node
+/// on the LundEE plane
+class LundEEDeclustering {
+public:
+
+  /// return the pair PseudoJet, i.e. sum of the two subjets
+  const PseudoJet & pair()  const {return pair_;}
+  /// returns the subjet with larger transverse momentum
+  const PseudoJet & harder() const {return harder_;}
+  /// returns the subjet with smaller transverse momentum
+  const PseudoJet & softer() const {return softer_;}
+
+
+  /// returns pair().m() [cached]
+  double m()         const {return m_;}
+
+  /// returns the effective pseudorapidity of the emission [cached]
+  double eta()       const {return eta_;}
+
+  /// returns sin(theta) of the branching [cached]
+  double sin_theta() const {return sin_theta_;}
+
+  /// returns softer().modp() / (softer().modp() + harder().modp()) [cached]
+  double z()         const {return z_;}
+
+  /// returns softer().modp() * sin(theta()) [cached]
+  double kt()        const {return kt_;}
+
+  /// returns ln(softer().modp() * sin(theta())) [cached]
+  double lnkt()      const {return lnkt_;}
+
+  /// returns z() * Delta() [cached]
+  double kappa()     const {return kappa_;}
+
+  /// returns the index of the plane to which this branching belongs
+  int iplane() const {return iplane_;}
+
+  /// returns the depth of the plane on which this declustering
+  /// occurred. 0 is the primary plane, 1 is the first set of leaves, etc. 
+  int depth() const {return depth_;}
+  
+  /// returns iplane (plane index) of the leaf associated with the
+  /// potential further declustering of the softer of the objects in
+  /// this splitting
+  int leaf_iplane() const {return leaf_iplane_;}
+
+  /// Returns sign_s, indicating the initial parent jet index of this splitting
+  int sign_s() const {return sign_s_;}
+  
+  /// returns an azimuthal angle psibar associated with this
+  /// declustering. The actual value of psibar is arbitrary and IR
+  /// unsafe (but see below), while differences in psibar values between
+  /// different clusterings are meaningful.
+  ///
+  /// The absolute value of psibar should in general not be used,  but
+  /// it has the following properties. (1) the first (largest-angle) splitting
+  /// ("ref") in the positive-z hemisphere defines psibar=0 (if there is
+  /// no splitting in that hemisphere then the first splitting in
+  /// the negative-z hemisphere does). If the +z jet aligns along the z
+  /// axis, then psibar of collinear splitting i in that jet is 
+  ///
+  ///   psibar_i = phi_i - phi_ref
+  ///
+  /// For the negative-z jet, the psibar of collinear splitting i is
+  ///
+  ///   psibar_i = phi_i - pi - phi_ref
+  ///
+  double psibar()    const {return psibar_;}
+
+  /// (DEPRECATED)
+  /// returns an azimuthal type angle between this declustering plane and the previous one
+  /// Note: one should use psibar() instead, since we found that this definition of psi is
+  /// not invariant under rotations of the event
+  double psi()       const {return psi_;}
+
+  /// update the azimuthal angle (deprecated)
+  void set_psi(double psi) {psi_ = psi;}
+
+
+  /// returns the coordinates in the Lund plane
+  std::pair<double,double> const lund_coordinates() const {
+    return std::pair<double,double>(eta_,lnkt_);
+  }
+
+  virtual ~LundEEDeclustering() {}
+
+private:
+  int iplane_;
+  double psi_, psibar_, lnkt_, eta_;
+  double m_, z_, kt_, kappa_, sin_theta_;
+  PseudoJet pair_, harder_, softer_;
+  int  depth_ = -1, leaf_iplane_ = -1;
+  int sign_s_;
+
+protected:
+
+  /// default ctor (protected, should not normally be needed by users,
+  /// but can be useful for derived classes)
+  LundEEDeclustering() {}
+
+  /// the constructor is protected, because users will not generally be
+  /// constructing a LundEEDeclustering element themselves.
+  LundEEDeclustering(const PseudoJet& pair,
+		     const PseudoJet& j1, const PseudoJet& j2,
+		     int iplane = -1, double psi = 0.0, double psibar = 0.0, int depth = -1, int leaf_iplane = -1, int sign_s = 1);
+
+  friend class RecursiveLundEEGenerator;
+
+};
+
+
+/// Default comparison operator for LundEEDeclustering, using kt as the ordering.
+/// Useful when including declusterings in structures like priority queues
+inline bool operator<(const LundEEDeclustering& d1, const LundEEDeclustering& d2) {
+  return d1.kt() < d2.kt();
+}
+
+//----------------------------------------------------------------------  
+/// Class to carry out Lund declustering to get anything from the
+/// primary Lund plane declusterings to the full Lund diagram with all
+/// its leaves, etc.
+class RecursiveLundEEGenerator {
+ public:
+  /// constructs a RecursiveLundEEGenerator with the specified depth.
+  /// - depth = 0 means only primary declusterings are registered
+  /// - depth = 1 means the first set of leaves are declustered
+  /// - ...
+  /// - depth < 0 means no limit, i.e. recurse through all leaves
+  ///
+  /// The psibar values that are set in the result Lund tree have the
+  /// following property:
+  ///
+  /// - if the jet with the larger pz has splittings, then its
+  ///   first splitting has psibar = 0
+  /// - otherwise the first splitting of the other jet has psibar = 0
+  ///
+  /// Note that this makes psibar IR unsafe (because an arbitrarily soft
+  /// splitting can be the one that gets the reference psibar=0 value), 
+  /// but differences between psibar values are IR safe.
+  /// 
+  /// NB: The dynamical_psi_ref option relates to the deprecated definition of psi
+  /// New code should use the psibar() function and dynamical_psi_ref
+  /// is irrelevant.
+  RecursiveLundEEGenerator(int max_depth = 0, bool dynamical_psi_ref = false) :
+    max_depth_(max_depth), nx_(1,0,0,0), ny_(0,1,0,0), dynamical_psi_ref_(dynamical_psi_ref)
+  {}
+
+  /// destructor
+  virtual ~RecursiveLundEEGenerator() {}
+
+  /// This takes a cluster sequence with an e+e- C/A style algorithm, e.g.
+  /// EECambridgePlugin(ycut=1.0).
+  ///
+  /// The output is a vector of LundEEDeclustering objects, ordered
+  /// according to kt
+  virtual std::vector<LundEEDeclustering> result(const ClusterSequence & cs) const {
+    std::vector<PseudoJet> exclusive_jets = cs.exclusive_jets(2);
+    assert(exclusive_jets.size() == 2);
+    
+    // order the two jets according to momentum along z axis
+    if (exclusive_jets[0].pz() < exclusive_jets[1].pz()) {
+      std::swap(exclusive_jets[0],exclusive_jets[1]);
+    }
+
+    PseudoJet d_ev = exclusive_jets[0] - exclusive_jets[1];
+    lund_plane::Matrix3 rotmat = lund_plane::Matrix3::from_direction(d_ev);
+    
+    std::vector<LundEEDeclustering> declusterings;
+    int depth = 0;
+    int max_iplane_sofar = 1;
+
+// 2024-01: new code, that fixes up issue of psibar differences
+// between hemispheres. If RLEEG_NEWPSIBAR is false, answers
+// will come out wrong.
+#define RLEEG_NEWPSIBAR
+#ifdef RLEEG_NEWPSIBAR
+    // 2024-01 -- attempt at new definition of psibar
+    PseudoJet ref_plane;
+    double last_psibar = 0.;
+    bool first_time = true;
+
+    for (unsigned ijet = 0; ijet < exclusive_jets.size(); ijet++) {
+      int sign_s = ijet == 0? +1 : -1;
+      append_to_vector(declusterings, exclusive_jets[ijet], depth, ijet, max_iplane_sofar,
+                        rotmat, sign_s, ref_plane, last_psibar, first_time);
+    }
+#else 
+    for (unsigned ijet = 0; ijet < exclusive_jets.size(); ijet++) {
+
+      // reference direction for psibar calculation
+      PseudoJet axis = d_ev/sqrt(d_ev.modp2());
+      PseudoJet ref_plane = axis;
+
+      int sign_s = ijet == 0? +1 : -1;
+      bool
+      // We can pass a vector normal to a plane of reference for phi definitions
+      append_to_vector(declusterings, exclusive_jets[ijet], depth, ijet, max_iplane_sofar,
+                       rotmat, sign_s, ref_plane, 0., true);
+    }
+#endif
+
+    // a typedef to save typing below
+    typedef LundEEDeclustering LD;
+    // sort so that declusterings are returned in order of decreasing
+    // kt (if result of the lambda is true, then first object appears
+    // before the second one in the final sorted list)
+    sort(declusterings.begin(), declusterings.end(),
+         [](const LD & d1, const LD & d2){return d1.kt() > d2.kt();});
+
+    return declusterings;
+  }
+  
+ private:
+
+  /// internal routine to recursively carry out the declusterings,
+  /// adding each one to the declusterings vector; the primary
+  /// ones are dealt with first (from large to small angle),
+  /// and then secondary ones take place.
+  void append_to_vector(std::vector<LundEEDeclustering> & declusterings,
+                        const PseudoJet & jet, int depth,
+                        int iplane, int & max_iplane_sofar,
+                        const lund_plane::Matrix3 & rotmat, int sign_s,
+                        PseudoJet & psibar_ref_plane,
+                        const double & last_psibar, bool & first_time) const {
+    PseudoJet j1, j2;
+    if (!jet.has_parents(j1, j2)) return;
+    if (j1.modp2() < j2.modp2()) std::swap(j1,j2);
+
+    // calculation of azimuth psi
+    lund_plane::Matrix3 new_rotmat;
+    if (dynamical_psi_ref_) {
+      new_rotmat = lund_plane::Matrix3::from_direction(rotmat.transpose()*(sign_s*jet)) * rotmat;
+    } else {
+      new_rotmat = rotmat;
+    }
+    PseudoJet rx = new_rotmat * nx_;
+    PseudoJet ry = new_rotmat * ny_;
+    PseudoJet u1 = j1/j1.modp(), u2 = j2/j2.modp();
+    PseudoJet du = u2 - u1;
+    double x = du.px() * rx.px() + du.py() * rx.py() + du.pz() * rx.pz();
+    double y = du.px() * ry.px() + du.py() * ry.py() + du.pz() * ry.pz();
+    double psi = atan2(y,x);
+
+    // calculation of psibar
+    double psibar = 0.;
+    PseudoJet n1, n2;
+
+    // First psibar for this jet
+    if (first_time) {
+
+#ifdef RLEEG_NEWPSIBAR
+// 2024-01: new code, that fixes up issue of psibar differences
+// between hemispheres
+      assert(last_psibar == 0.0);
+      psibar = 0.0;
+      n2 = lund_plane::cross_product(j1,j2);
+      n2 /= n2.modp();
+      psibar_ref_plane = n2;
+      first_time = false;
+#else 
+      // Compute the angle between the planes spanned by (some axis,j1) and by (j1,j2)
+      n1 = lund_plane::cross_product(psibar_ref_plane,j1);
+      n2 = lund_plane::cross_product(j1,j2);
+
+      double signed_angle = 0.;
+      n2 /= n2.modp();
+      if (n1.modp() != 0) {
+        n1 /= n1.modp();
+        signed_angle = lund_plane::signed_angle_between_planes(n1,n2,j1);
+      }
+
+      psibar = lund_plane::map_to_pi(j1.phi() + signed_angle);
+#endif
+    }
+    // Else take the value of psibar_i and the plane from the last splitting to define psibar_{i+1}
+    // The signed angle is multiplied by sign_s (+1 for the +z hemisphere, -1 for the -z hemisphere)
+    // to take the correct orientation into account.
+    else {
+      n2 = lund_plane::cross_product(j1,j2);
+      n2 /= n2.modp();
+      psibar = lund_plane::map_to_pi(last_psibar + sign_s*lund_plane::signed_angle_between_planes(psibar_ref_plane, n2, j1));
+    }
+
+    int leaf_iplane = -1;
+    // we will recurse into the softer "parent" only if the depth is
+    // not yet at its limit or if there is no limit on the depth (max_depth<0)
+    bool recurse_into_softer = (depth < max_depth_ || max_depth_ < 0);
+    if (recurse_into_softer) {
+      max_iplane_sofar += 1;
+      leaf_iplane = max_iplane_sofar;
+    }
+    
+    LundEEDeclustering declust(jet, j1, j2, iplane, psi, psibar, depth, leaf_iplane, sign_s);
+    declusterings.push_back(declust);
+
+    // now recurse
+    // for the definition of psibar, we recursively pass the last splitting plane (normal to n2) and the last value
+    // of psibar
+    bool lcl_first_time = false;
+    append_to_vector(declusterings, j1, depth, iplane, max_iplane_sofar, new_rotmat, sign_s, n2, psibar, lcl_first_time);
+    if (recurse_into_softer) {
+      append_to_vector(declusterings, j2, depth+1, leaf_iplane, max_iplane_sofar, new_rotmat, sign_s, n2, psibar, lcl_first_time);
+    }
+  }
+  
+  int max_depth_ = 0;
+  /// vectors used to help define psi
+  PseudoJet nx_;
+  PseudoJet ny_;
+  bool dynamical_psi_ref_;
+};
+  
+} // namespace contrib
+
+FASTJET_END_NAMESPACE
+
+/// for output of declustering information
+std::ostream & operator<<(std::ostream & ostr, const fastjet::contrib::LundEEDeclustering & d);
+
+#endif  // __FASTJET_CONTRIB_RECURSIVELUNDEEGENERATOR_HH__

Property changes on: contrib/contribs/LundPlane/trunk/include/fastjet/contrib/RecursiveLundEEGenerator.hh
___________________________________________________________________
Added: svn:keywords
## -0,0 +1 ##
+Id
\ No newline at end of property
Index: contrib/contribs/LundPlane/trunk/include/fastjet/contrib/LundJSON.hh
===================================================================
--- contrib/contribs/LundPlane/trunk/include/fastjet/contrib/LundJSON.hh	(revision 0)
+++ contrib/contribs/LundPlane/trunk/include/fastjet/contrib/LundJSON.hh	(revision 1460)
@@ -0,0 +1,78 @@
+#ifndef __FASTJET_CONTRIB_LUNDJSON_HH__
+#define __FASTJET_CONTRIB_LUNDJSON_HH__
+
+#include "LundGenerator.hh"
+
+FASTJET_BEGIN_NAMESPACE
+
+namespace contrib{
+
+// declaration of helper function
+void lund_elements_to_json(std::ostream & ostr, const LundDeclustering & d);
+
+/// writes json to ostr for an individual declustering
+inline std::ostream & lund_to_json(std::ostream & ostr, const LundDeclustering & d) {
+  // /// we hardcode 6 digits of precision -- is this the right way to do things?
+  // int prec_store = ostr.precision();
+  // ostr.precision(6);
+
+  ostr << "{";
+  lund_elements_to_json(ostr, d);
+  ostr << "}";
+
+  return ostr;
+}
+
+
+/// writes json to ostr for a vector of declusterings
+inline std::ostream & lund_to_json(std::ostream & ostr, const std::vector<LundDeclustering> & d) {
+  ostr << "[";
+  for (std::size_t i = 0; i < d.size(); i++) {
+    if (i != 0) ostr << ",";
+    lund_to_json(ostr, d[i]);
+  } 
+  ostr << "]";
+  return ostr;
+}
+
+// /// writes a full Lund tree recursively to JSON
+// inline std::ostream & lund_to_json(std::ostream & ostr, const LundGenerator & generator, const PseudoJet & jet) {
+//   // we will use these below in the loop; declare them here to avoid
+//   // repeated creation/destruction
+//   PseudoJet p1,p2;
+//   std::vector<LundDeclustering> d = generator(jet);
+//   ostr << "[";
+//   for (std::size_t i = 0; i < d.size(); i++) {
+//     if (i != 0) ostr << ",";
+//     ostr << "{";
+//     lund_elements_to_json(ostr, d[i]);
+//     // add in information on the leaf if it exists
+//     if (d[i].softer().has_parents(p1,p2)) {
+//       ostr << ",";
+//       ostr << "\"leaf\":";
+//       lund_to_json(ostr, generator, d[i].softer());
+//     }
+//     ostr << "}";
+//   } 
+//   ostr << "]";
+//   return ostr;
+// }
+
+// helper function to write individual elements to json
+inline void lund_elements_to_json(std::ostream & ostr, const LundDeclustering & d) {
+  ostr << "\"p_pt\":" << d.pair()  .pt() << ",";
+  ostr << "\"p_m\":"  << d.pair()  .m () << ",";
+  ostr << "\"h_pt\":" << d.harder().pt() << ",";
+  ostr << "\"s_pt\":" << d.softer().pt() << ",";
+  ostr << "\"z\":"      << d.z()     << ",";
+  ostr << "\"Delta\":"  << d.Delta() << ",";
+  ostr << "\"kt\":"     << d.kt()    << ",";
+  ostr << "\"psi\":"    << d.psi()         ;
+}
+
+
+} // namespace contrib
+
+FASTJET_END_NAMESPACE
+
+#endif // __FASTJET_CONTRIB_LUNDJSON_HH__

Property changes on: contrib/contribs/LundPlane/trunk/include/fastjet/contrib/LundJSON.hh
___________________________________________________________________
Added: svn:keywords
## -0,0 +1 ##
+Id
\ No newline at end of property
Index: contrib/contribs/LundPlane/trunk/include/fastjet/contrib/LundEEHelpers.hh
===================================================================
--- contrib/contribs/LundPlane/trunk/include/fastjet/contrib/LundEEHelpers.hh	(revision 0)
+++ contrib/contribs/LundPlane/trunk/include/fastjet/contrib/LundEEHelpers.hh	(revision 1460)
@@ -0,0 +1,270 @@
+// $Id$
+//
+// Copyright (c) 2018-, Frederic A. Dreyer, Keith Hamilton, Alexander Karlberg,
+// Gavin P. Salam, Ludovic Scyboz, Gregory Soyez, Rob Verheyen
+//
+// This file is part of FastJet contrib.
+//
+// It is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 2 of the License, or (at
+// your option) any later version.
+//
+// It is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+// or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+// License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this code. If not, see <http://www.gnu.org/licenses/>.
+//----------------------------------------------------------------------
+
+#ifndef __FASTJET_CONTRIB_EEHELPERS_HH__
+#define __FASTJET_CONTRIB_EEHELPERS_HH__
+
+#include "fastjet/PseudoJet.hh"
+#include <array>
+#include <limits>
+
+FASTJET_BEGIN_NAMESPACE
+
+namespace contrib{
+namespace lund_plane {
+  
+//----------------------------------------------------------------------
+/// Returns the 3-vector cross-product of p1 and p2. If lightlike is false
+/// then the energy component is zero; if it's true the the energy component
+/// is arranged so that the vector is lighlike
+inline PseudoJet cross_product(const PseudoJet & p1, const PseudoJet & p2, bool lightlike=false) {
+  double px = p1.py() * p2.pz() - p2.py() * p1.pz();
+  double py = p1.pz() * p2.px() - p2.pz() * p1.px();
+  double pz = p1.px() * p2.py() - p2.px() * p1.py();
+
+  double E;
+  if (lightlike) {
+    E = sqrt(px*px + py*py + pz*pz);
+  } else {
+    E = 0.0;
+  }
+  return PseudoJet(px, py, pz, E);
+}
+
+/// Map angles to [-pi, pi]
+inline const double map_to_pi(const double &phi) {
+  if (phi < -M_PI)     return phi + 2 * M_PI;
+  else if (phi > M_PI) return phi - 2 * M_PI;
+  else                 return phi;
+}
+
+inline double dot_product_3d(const PseudoJet & a, const PseudoJet & b) {
+  return a.px()*b.px() + a.py()*b.py() + a.pz()*b.pz();
+}
+
+/// Returns (1-cos theta) where theta is the angle between p1 and p2
+inline double one_minus_costheta(const PseudoJet & p1, const PseudoJet & p2) {
+
+  if (p1.m2() == 0 && p2.m2() == 0) {
+    // use the 4-vector dot product. 
+    // For massless particles it gives us E1*E2*(1-cos theta)
+    return dot_product(p1,p2) / (p1.E() * p2.E());
+  } else {
+    double p1mod = p1.modp();
+    double p2mod = p2.modp();
+    double p1p2mod = p1mod*p2mod;
+    double dot = dot_product_3d(p1,p2);
+
+    if (dot > (1-std::numeric_limits<double>::epsilon()) * p1p2mod) {
+      PseudoJet cross_result = cross_product(p1, p2, false);
+      // the mass^2 of cross_result is equal to 
+      // -(px^2 + py^2 + pz^2) = (p1mod*p2mod*sintheta_ab)^2
+      // so we can get
+      return -cross_result.m2()/(p1p2mod * (p1p2mod+dot));
+    }
+
+    return 1.0 - dot/p1p2mod;
+    
+  }
+}
+
+/// Get the angle between two planes defined by normalized vectors
+/// n1, n2. The sign is decided by the direction of a vector n, such that
+/// if n1 x n2 points in the same direction as n, the angle is positive.
+/// The result is in the range -pi < theta < pi.
+///
+/// For example, labelling (x,y,z), and taking n1 = (1,0,0), 
+/// n2 = (0,1,0), n = (0,0,1), then the angle is +pi/2.
+inline double signed_angle_between_planes(const PseudoJet& n1,
+      const PseudoJet& n2, const PseudoJet& n) {
+
+  // Two vectors passed as arguments should be normalised to 1.
+  assert(fabs(n1.modp()-1) < sqrt(std::numeric_limits<double>::epsilon()) && fabs(n2.modp()-1) < sqrt(std::numeric_limits<double>::epsilon()));
+
+  double omcost = one_minus_costheta(n1,n2);
+  double theta;
+
+  // If theta ~ pi, we return pi.
+  if(fabs(omcost-2) < sqrt(std::numeric_limits<double>::epsilon())) {
+    theta = M_PI;
+  } else if (omcost > sqrt(std::numeric_limits<double>::epsilon())) {
+    double cos_theta = 1.0 - omcost;
+    theta = acos(cos_theta);
+  } else {
+    // we are at small angles, so use small-angle formulas
+    theta = sqrt(2. * omcost);
+  }
+
+  PseudoJet cp = cross_product(n1,n2);
+  double sign = dot_product_3d(cp,n);
+
+  if (sign > 0) return theta;
+  else          return -theta;
+}
+
+class Matrix3 {
+public:
+  /// constructs an empty matrix
+  Matrix3() : matrix_({{{{0,0,0}},   {{0,0,0}},   {{0,0,0}}}}) {}
+
+  /// constructs a diagonal matrix with "unit" along each diagonal entry
+  Matrix3(double unit) : matrix_({{{{unit,0,0}},   {{0,unit,0}},   {{0,0,unit}}}}) {}
+
+  /// constructs a matrix from the array<array<...,3>,3> object
+  Matrix3(const std::array<std::array<double,3>,3> & mat) : matrix_(mat) {}
+
+  /// returns the entry at row i, column j
+  inline double operator()(int i, int j) const {
+    return matrix_[i][j];
+  }
+
+  /// returns a matrix for carrying out azimuthal rotation
+  /// around the z direction by an angle phi
+  static Matrix3 azimuthal_rotation(double phi) {
+    double cos_phi = cos(phi);
+    double sin_phi = sin(phi);
+    Matrix3 phi_rot( {{ {{cos_phi, sin_phi, 0}},
+	             {{-sin_phi, cos_phi, 0}},
+	             {{0,0,1}}}});
+    return phi_rot;
+  }
+
+  /// returns a matrix for carrying out a polar-angle
+  /// rotation, in the z-x plane, by an angle theta
+  static Matrix3 polar_rotation(double theta) {
+    double cos_theta = cos(theta);
+    double sin_theta = sin(theta);
+    Matrix3 theta_rot( {{ {{cos_theta, 0, sin_theta}},
+	               {{0,1,0}},
+	               {{-sin_theta, 0, cos_theta}}}});
+    return theta_rot;
+  }
+
+  /// This provides a rotation matrix that takes the z axis to the
+  /// direction of p. With skip_pre_rotation = false (the default), it
+  /// has the characteristic that if p is close to the z axis then the
+  /// azimuthal angle of anything at much larger angle is conserved.
+  ///
+  /// If skip_pre_rotation is true, then the azimuthal angles are not
+  /// when p is close to the z axis.
+  template<class T>
+  static Matrix3 from_direction(const T & p, bool skip_pre_rotation = false) {
+    double pt = p.pt();
+    double modp = p.modp();
+    double cos_theta = p.pz() / modp;
+    double sin_theta = pt / modp;
+    double cos_phi, sin_phi;
+    if (pt > 0.0) {
+      cos_phi = p.px()/pt;
+      sin_phi = p.py()/pt;
+    } else {
+      cos_phi = 1.0;
+      sin_phi = 0.0;
+    }
+
+    Matrix3 phi_rot({{ {{ cos_phi,-sin_phi, 0 }},
+	                     {{ sin_phi, cos_phi, 0 }},
+	                     {{       0,       0, 1 }} }});
+    Matrix3 theta_rot( {{ {{ cos_theta, 0, sin_theta }},
+	                        {{         0, 1,         0 }},
+	                        {{-sin_theta, 0, cos_theta }} }});
+
+    // since we have orthogonal matrices, the inverse and transpose
+    // are identical; we use the transpose for the frontmost rotation
+    // because 
+    if (skip_pre_rotation) {
+      return phi_rot * theta_rot;
+    } else {
+      return phi_rot * (theta_rot * phi_rot.transpose());
+    }
+  }
+
+  template<class T>
+  static Matrix3 from_direction_no_pre_rotn(const T & p) {
+    return from_direction(p,true);
+  }
+
+
+
+  /// returns the transposed matrix
+  Matrix3 transpose() const {
+    // 00 01 02
+    // 10 11 12
+    // 20 21 22
+    Matrix3 result = *this;
+    std::swap(result.matrix_[0][1],result.matrix_[1][0]);
+    std::swap(result.matrix_[0][2],result.matrix_[2][0]);
+    std::swap(result.matrix_[1][2],result.matrix_[2][1]);
+    return result;
+  }
+
+  // returns the product with another matrix
+  Matrix3 operator*(const Matrix3 & other) const {
+    Matrix3 result;
+    // r_{ij} = sum_k this_{ik} & other_{kj}
+    for (int i = 0; i < 3; i++) {
+      for (int j = 0; j < 3; j++) {
+        for (int k = 0; k < 3; k++) {
+          result.matrix_[i][j] += this->matrix_[i][k] * other.matrix_[k][j];
+        }
+      }
+    }
+    return result;
+  }
+  
+  friend std::ostream & operator<<(std::ostream & ostr, const Matrix3 & mat);
+private:
+  std::array<std::array<double,3>,3> matrix_;
+};
+
+inline std::ostream & operator<<(std::ostream & ostr, const Matrix3 & mat) {
+  ostr << mat.matrix_[0][0] << " " << mat.matrix_[0][1] << " " << mat.matrix_[0][2] << std::endl;
+  ostr << mat.matrix_[1][0] << " " << mat.matrix_[1][1] << " " << mat.matrix_[1][2] << std::endl;
+  ostr << mat.matrix_[2][0] << " " << mat.matrix_[2][1] << " " << mat.matrix_[2][2] << std::endl;
+  return ostr;
+}
+
+/// returns the project of this matrix with the PseudoJet,
+/// maintaining the 4th component of the PseudoJet unchanged
+inline PseudoJet operator*(const Matrix3 & mat, const PseudoJet & p) {
+  // r_{i} = m_{ij} p_j
+  std::array<double,3> res3{{0,0,0}};
+  for (unsigned i = 0; i < 3; i++) {
+    for (unsigned j = 0; j < 3; j++) {
+      res3[i] += mat(i,j) * p[j];
+    }
+  }
+  // return a jet that maintains all internal pointers by
+  // initialising the result from the input jet and
+  // then resetting the momentum.
+  PseudoJet result(p);
+  // maintain the energy component as it was
+  result.reset_momentum(res3[0], res3[1], res3[2], p[3]);
+  return result;
+}
+
+} // namespace lund_plane
+} // namespace contrib
+
+FASTJET_END_NAMESPACE
+
+#endif // __FASTJET_CONTRIB_EEHELPERS_HH__
+

Property changes on: contrib/contribs/LundPlane/trunk/include/fastjet/contrib/LundEEHelpers.hh
___________________________________________________________________
Added: svn:keywords
## -0,0 +1 ##
+Id
\ No newline at end of property
Index: contrib/contribs/LundPlane/trunk/example_secondary.cc
===================================================================
--- contrib/contribs/LundPlane/trunk/example_secondary.cc	(revision 1459)
+++ contrib/contribs/LundPlane/trunk/example_secondary.cc	(revision 1460)
@@ -1,117 +1,118 @@
 //----------------------------------------------------------------------
 /// \file example_secondary.cc
 ///
 /// This example program is meant to illustrate how the
 /// fastjet::contrib::LundWithSecondary class is used.
 ///
 /// Run this example with
 ///
 /// \verbatim
 ///     ./example_secondary < ../data/single-event.dat
 /// \endverbatim
 
 //----------------------------------------------------------------------
 // $Id$
 //
 // Copyright (c) 2018-, Frederic A. Dreyer, Keith Hamilton, Alexander Karlberg,
 // Gavin P. Salam, Ludovic Scyboz, Gregory Soyez, Rob Verheyen
 //
 //----------------------------------------------------------------------
 // This file is part of FastJet contrib.
 //
 // It is free software; you can redistribute it and/or modify it under
 // the terms of the GNU General Public License as published by the
 // Free Software Foundation; either version 2 of the License, or (at
 // your option) any later version.
 //
 // It is distributed in the hope that it will be useful, but WITHOUT
 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 // or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
 // License for more details.
 //
 // You should have received a copy of the GNU General Public License
 // along with this code. If not, see <http://www.gnu.org/licenses/>.
 //----------------------------------------------------------------------
 
 #include <iostream>
 #include <fstream>
 #include <sstream>
 
 #include "fastjet/PseudoJet.hh"
 #include <string>
-#include "LundWithSecondary.hh" // In external code, this should be fastjet/contrib/LundWithSecondary.hh
+#include "fastjet/contrib/LundWithSecondary.hh"
+
 using namespace std;
 using namespace fastjet;
 
 // forward declaration to make things clearer
 void read_event(vector<PseudoJet> &event);
 
 //----------------------------------------------------------------------
 int main(){
 
   //----------------------------------------------------------
   // read in input particles
   vector<PseudoJet> event;
   read_event(event);
   cout << "# read an event with " << event.size() << " particles" << endl;
   
   // first get some anti-kt jets
   double R = 1.0, ptmin = 100.0;
   JetDefinition jet_def(antikt_algorithm, R);
   ClusterSequence cs(event, jet_def);
   vector<PseudoJet> jets = sorted_by_pt(cs.inclusive_jets(ptmin));
   
   //----------------------------------------------------------
   // create an instance of LundWithSecondary, with default options
   contrib::SecondaryLund_mMDT secondary;
   contrib::LundWithSecondary lund(&secondary);
 
   cout << lund.description() << endl;
   
   for (unsigned ijet = 0; ijet < jets.size(); ijet++) {
     cout << endl << "Lund coordinates ( ln 1/Delta, ln kt ) of declusterings of jet " 
          << ijet << " are:" << endl;
     vector<contrib::LundDeclustering> declusts = lund.primary(jets[ijet]);
 
     for (unsigned int idecl = 0; idecl < declusts.size(); ++idecl) {
       pair<double,double> coords = declusts[idecl].lund_coordinates();
       cout << "["<< idecl<< "](" << coords.first << ", " << coords.second << ")";
       if (idecl < declusts.size() - 1) cout << "; ";
     }
 
     cout << endl;
 
     vector<contrib::LundDeclustering> sec_declusts = lund.secondary(declusts);
     cout << endl << "with Lund coordinates for the secondary plane (from primary declustering ["
          << lund.secondary_index(declusts) <<"]):" << endl;
     for (unsigned int idecl = 0; idecl < sec_declusts.size(); ++idecl) {
       pair<double,double> coords = sec_declusts[idecl].lund_coordinates();
       cout << "["<< idecl<< "](" << coords.first << ", " << coords.second << ")";
       if (idecl < sec_declusts.size() - 1) cout << "; ";      
     }
 
     cout << endl;
   }
 
 
 
   return 0;
 }
 
 // read in input particles
 void read_event(vector<PseudoJet> &event){  
   string line;
   while (getline(cin, line)) {
     istringstream linestream(line);
     // take substrings to avoid problems when there is extra "pollution"
     // characters (e.g. line-feed).
     if (line.substr(0,4) == "#END") {return;}
     if (line.substr(0,1) == "#") {continue;}
     double px,py,pz,E;
     linestream >> px >> py >> pz >> E;
     PseudoJet particle(px,py,pz,E);
 
     // push event onto back of full_event vector
     event.push_back(particle);
   }
 }
Index: contrib/contribs/LundPlane/trunk/example_dpsi_collinear.cc
===================================================================
--- contrib/contribs/LundPlane/trunk/example_dpsi_collinear.cc	(revision 1459)
+++ contrib/contribs/LundPlane/trunk/example_dpsi_collinear.cc	(revision 1460)
@@ -1,167 +1,168 @@
 //----------------------------------------------------------------------
 /// \file example_dpsi_collinear.cc
 ///
 /// This example program is meant to illustrate how the
 /// fastjet::contrib::RecursiveLundEEGenerator class is used.
 ///
 /// Run this example with
 ///
 /// \verbatim
 ///     ./example_dpsi_collinear < ../data/single-ee-event.dat
 /// \endverbatim
 
 //----------------------------------------------------------------------
 // $Id$
 //
 // Copyright (c) 2018-, Frederic A. Dreyer, Keith Hamilton, Alexander Karlberg,
 // Gavin P. Salam, Ludovic Scyboz, Gregory Soyez, Rob Verheyen
 //
 //----------------------------------------------------------------------
 // This file is part of FastJet contrib.
 //
 // It is free software; you can redistribute it and/or modify it under
 // the terms of the GNU General Public License as published by the
 // Free Software Foundation; either version 2 of the License, or (at
 // your option) any later version.
 //
 // It is distributed in the hope that it will be useful, but WITHOUT
 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 // or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
 // License for more details.
 //
 // You should have received a copy of the GNU General Public License
 // along with this code. If not, see <http://www.gnu.org/licenses/>.
 //----------------------------------------------------------------------
 
 #include <iostream>
 #include <fstream>
 #include <sstream>
 #include <limits>
 
 #include "fastjet/PseudoJet.hh"
 #include "fastjet/EECambridgePlugin.hh"
 #include <string>
-#include "RecursiveLundEEGenerator.hh" // In external code, this should be fastjet/contrib/RecursiveLundEEGenerator.hh
+#include "fastjet/contrib/RecursiveLundEEGenerator.hh"
+
 using namespace std;
 using namespace fastjet;
 
 // Definitions for the collinear observable
 double z1_cut = 0.1;
 double z2_cut = 0.1;
 
 // forward declaration to make things clearer
 void read_event(vector<PseudoJet> &event);
 
 //----------------------------------------------------------------------
 int main(){
 
   //----------------------------------------------------------
   // read in input particles
   vector<PseudoJet> event;
   read_event(event);
 
   cout << "# read an event with " << event.size() << " particles" << endl;
   //----------------------------------------------------------
   // create an instance of RecursiveLundEEGenerator, with default options
   int depth = -1;
   fastjet::contrib::RecursiveLundEEGenerator lund(depth);
   
   // first get some C/A jets
   double y3_cut = 1.0;
   JetDefinition::Plugin* ee_plugin = new EECambridgePlugin(y3_cut);
   JetDefinition jet_def(ee_plugin);
   ClusterSequence cs(event, jet_def);
 
   // Get the list of primary declusterings
   const vector<contrib::LundEEDeclustering> declusts = lund.result(cs);
   
   // Find the two highest-kt primary declustering (ordered in kt by default)
   int i_primary_1 = -1, i_primary_2 = -1;
   double psi_primary_1, psi_primary_2;
   double dpsi_11 = numeric_limits<double>::max(); //< initialisation prevents gcc warning
   for (unsigned int i=0; i<declusts.size(); ++i) {
     if (declusts[i].depth() == 0 && declusts[i].z() > z1_cut) {
       if (i_primary_1 < 0) {
         i_primary_1 = i;
         psi_primary_1 = declusts[i].psibar();
       } else {
         i_primary_2 = i;
         psi_primary_2 = declusts[i].psibar();
         dpsi_11 = contrib::lund_plane::map_to_pi(psi_primary_2-psi_primary_1);
         break;
       }
     }
   }
   // If no primary at all, just return
   if (i_primary_1 < 0) return 0;
 
   // For the highest-kt primary: find the highest-kt secondary associated to that Lund leaf
   // that passes the zcut of z2_cut
   int iplane_to_follow = declusts[i_primary_1].leaf_iplane();
   vector<const contrib::LundEEDeclustering *> secondaries;
   for (const auto & declust: declusts){
     if (declust.iplane() == iplane_to_follow) secondaries.push_back(&declust);
   }
   int i_secondary = -1;
   double dpsi_12 = numeric_limits<double>::max(); //< initialisation prevents gcc warning;
   if (secondaries.size() > 0) {
     for (unsigned int i=0; i<secondaries.size(); ++i) {
       if (secondaries[i]->z() > z2_cut) {
         i_secondary = i;
         double psi_2 = secondaries[i]->psibar();
         dpsi_12 = contrib::lund_plane::map_to_pi(psi_2-psi_primary_1);
         break;
       }
     }
   }
 
   cout << "Highest-kt primary that passes the zcut of "
        << z1_cut << ", with Lund coordinates  ( ln 1/Delta, ln kt, psibar ):" << endl;
   pair<double,double> coords = declusts[i_primary_1].lund_coordinates();
   cout << "index [" << i_primary_1 << "](" << coords.first << ", " << coords.second << ", "
        << declusts[i_primary_1].psibar() << ")" << endl;
 
   // dpsi_12 is the angle between the primary and the secondary
   if (i_secondary >= 0) {
     cout << endl << "with Lund coordinates for the secondary plane that passes the zcut of "
         << z2_cut << endl;
     coords = secondaries[i_secondary]->lund_coordinates();
     cout << "index [" << i_secondary << "](" << coords.first << ", " << coords.second << ", "
         << secondaries[i_secondary]->psibar() << ")";
 
     cout << " --> delta_psi(primary,secondary) = " << dpsi_12 << endl;
   }
   // dpsi_11 is the angle between the two primaries
   if (i_primary_2 >= 0) {
     cout << endl << "with Lund coordinates for the second primary plane that passes the zcut of "
         << z1_cut << endl;
     coords = declusts[i_primary_2].lund_coordinates();
     cout << "index [" << i_primary_2 << "](" << coords.first << ", " << coords.second << ", "
         << declusts[i_primary_2].psibar() << ")";
 
     cout << " --> delta_psi(primary_1, primary_2) = " << dpsi_11 << endl;
   }
 
   // Delete the EECambridge plugin
   delete ee_plugin;
 
   return 0;
 }
 
 // read in input particles
 void read_event(vector<PseudoJet> &event){  
   string line;
   while (getline(cin, line)) {
     istringstream linestream(line);
     // take substrings to avoid problems when there is extra "pollution"
     // characters (e.g. line-feed).
     if (line.substr(0,4) == "#END") {return;}
     if (line.substr(0,1) == "#") {continue;}
     double px,py,pz,E;
     linestream >> px >> py >> pz >> E;
     PseudoJet particle(px,py,pz,E);
 
     // push event onto back of full_event vector
     event.push_back(particle);
   }
 }
Index: contrib/contribs/LundPlane/trunk/ChangeLog
===================================================================
--- contrib/contribs/LundPlane/trunk/ChangeLog	(revision 1459)
+++ contrib/contribs/LundPlane/trunk/ChangeLog	(revision 1460)
@@ -1,204 +1,231 @@
+2024-12-11  Gregory Soyez  <soyez@fastjet.fr>
+
+	* FJCONTRIB.cfg:           *** ADDED ***
+	* VERSION:               *** REMOVED ***
+	replaced the VERSION file witrh the new syntax which is a
+	"version" line in FJCONTRIB.cfg
+
+	* LundGenerator.cc:
+	* LundWithSecondary.cc:
+	* RecursiveLundEEGenerator.cc:
+	* SecondaryLund.cc:
+	* example.cc:
+	* example_dpsi_collinear.cc:
+	* example_dpsi_slice.cc:
+	* example_secondary.cc:
+	* Makefile:
+	updated source code and build script to reflect the headre
+	relocation
+
+	* LundEEHelpers.hh            -> include/fastjet/contrib/LundEEHelpers.hh
+	* LundGenerator.hh            -> include/fastjet/contrib/LundGenerator.hh
+	* LundJSON.hh                 -> include/fastjet/contrib/LundJSON.hh
+	* LundWithSecondary.hh        -> include/fastjet/contrib/LundWithSecondary.hh
+	* RecursiveLundEEGenerator.hh -> include/fastjet/contrib/RecursiveLundEEGenerator.hh
+	* SecondaryLund.hh            -> include/fastjet/contrib/SecondaryLund.hh
+	moved installed hjeaders to the include/fastjet/contrib/ directory
+
 2024-12-09 Mon  <gavin.salam@physics.ox.ac.uk>
 
 	* Makefile:
 	fixed a bug in the `fastjet-config --libs` call, adding --plugins so that
 	one gets a consistent set of plugin libraries according to the
 	specific fastjet configuration.
 
 2024-02-28  Gregory Soyez  <soyez@fastjet.fr>
 
 	* example_dpsi_collinear.cc:  fixed maybe-uninitialized gcc warnings
 
 2024-01-18 Ludo Scyboz (+ minor contribs from Gregory Soyez + Gavin Salam)
 
 	* RecursiveLundEEGenerator.hh:
 	* example_dpsi_collinear.ref:
 	* example_dpsi_slice.ref:
 	* python/gen-test-event.py:
 	* NEWS:
 	another bug-fix for opposite hemispheres differences of psibar, where
 	a missing sign needed to be added in the second hemisphere. This
 	changes the reference files for opposite hemisphere dpsibar. For 
 	same-hemisphere dpsibar, the sign can change (depending on the hemisphere). 
 	Also updated python/gen-test-event.py  to have command-line options
 	for more flexibility in examining output and for testing explanation
 	of psibar absolute value in RecursiveLundEEGenerator comments.
 
 2024-01-10  Gavin Salam + Alexander Karlberg
 
 	* NEWS: 
 	* VERSION:
 	preparing for release 2.1.0 (NEWS still needs correct date to be added)
 
     * AUTHORS:
 	added publication info for soft spin paper
 
 2024-01-10  Gavin Salam + Ludo Scyboz + Alexander Karlberg
 
 	* LundEEHelpers.hh:
 	extended the comments in the signed_angle_between_planes function
 
 	* RecursiveLundEEGenerator.hh:
 	changed definition of psibar, which fixes a bug in differences
 	of psibar values between opposite hemispheres. Differences
 	within a same hemisphere should stay the same.
 
 	* example_dpsi_collinear.cc:
 	added extra output showing the primary declustering in the 
 	second hemisphere. Also eliminated deprecated
 	dynamic_psi_reference argument in setting up the RecursiveLundEEGenerator.
 
 	* example_dpsi_collinear.ref:
 	* example_dpsi_slice.ref:
 	updated these reference files so that are consistent with 
 	the new definition of psibar. Note the delta psibar values
 	do not change. The collinear reference has acquired extra
 	output showing a primary declustering in the second hemisphere. 
 
 	* python/gen-test-event.py: *** ADDED ***
 	small script to generate test events for verifying output from
 	example_dpsi_collinear.ref
 
 2024-01-08  Gavin Salam  <gavin.salam@physics.ox.ac.uk>
 
 	* example_dpsi_slice.cc:
 	replaced a uint -> unsigned int, to resolve a compilation issue
 	with gcc-13 on MacOS
 
 2023-09-22 Fri  <gavin.salam@physics.ox.ac.uk>
 
 	* NEWS:
 	* VERSION:
 	preparing 2.0.4 release
 
 	* RecursiveLundEEGenerator.hh:
 	fixed const issue in in ternal lambda function (reported by Seryubin Seraphim)
 
 	* LundPlane.hh: *** ADDED ***
 	added this to provide a generic include for the main classes
 	(absence of such a standard-looking reported by Seryubin Seraphim)
 
 2022-10-04  Gregory Soyez  <soyez@fastjet.fr>
 
 	* example.cc:
 	* example_secondary.cc:
 	* example_dpsi_collinear.cc:
 	* example_dpsi_slice.cc:
 	removed (harmless) compilation warnings (+ minor uniformisation
 	of indentation)
 
 2022-10-04 Tue  <gavin.salam@physics.ox.ac.uk> + Ludo Scyboz
 
 	* VERSION:
 	* NEWS:
 	prepared for release 2.0.3
 
 	* EEHelpers.hh ->  LundEEHelpers.hh:
 	EEHelpers.hh was not being installed; given that it's a potentially 
 	common name, renamed it before including among the installation 
 	targets. 
 
 	Also placed whole contents in a new contrib::lund_plane namespace,
 	because of certain potentially common names like cross_product
 
 	* Makefile:
 	replaced EEHelpers.hh ->  LundEEHelpers.hh and made sure that
 	LundEEHelpers.hh gets installed (without which RecursiveLundEEGenerator.hh
 	cannot be used)
 
 	* example_dpsi_collinear.cc:
 	* example_dpsi_slice.cc:
 	use of things from LundEEHelpers.hh updated to use of new namespace
 
 	* RecursiveLundEEGenerator.hh:
 	* RecursiveLundEEGenerator.cc:
 	updated to use LundEEHelpers.hh (and associated namespace); 
 	also added a (protected) default constructor to LundEEDeclustering
 
 2022-08-20  Gavin Salam  <gavin.salam@physics.ox.ac.uk>
 
 	* VERSION:
 	* NEWS:
 	prepared for release 2.0.2
 
 	* Makefile:
 	updated some dependencies
 
 	* EEHelpers.hh:
 	added #include <limits>, as per request from Andy Buckley
 	for compilation with g++-12 on some systems
 
 2021-12-06  Gavin Salam  <gavin.salam@physics.ox.ac.uk>
 
 	* NEWS:
         * VERSION:
 	prepared for release 2.0.1
 
 	* AUTHORS:
 	fixed missing names and publication info
 
 2021-12-06  Gregory Soyez  <soyez@fastjet.fr>
 
 	* SecondaryLund.cc:
 	fixed int v. unsigned int in loop over vector indices
 
 2021-12-06  Gavin Salam  <gavin.salam@physics.ox.ac.uk>
 
 	* example.py:
 	fixed name of executable in comments about how to execute
 	this (thanks to Matteo Cacciari)
 
 2021-11-09  Ludovic Scyboz <ludovic.scyboz@physics.ox.ac.uk>
 
 	* VERSION:
 	preparing for release of 2.0.0
 
 	* RecursiveLundEEGenerator.hh:
 	* RecursiveLundEEGenerator.cc:
 	class for recursive Lund declustering in e+e-
 	* example_dpsi_collinear.cc:
 	spin-sensitive collinear observable from 2103.16526
 	* example_dpsi_slice.cc:
 	spin-sensitive non-global observable from 2111.01161
 
 2020-02-23  Gavin Salam  <gavin.salam@cern.ch>
 
 	* NEWS:
 	* VERSION:
 	preparing for release of 1.0.3
 
 	* example.cc:
 	changed outfile open(filename) to outfile.open(filename.c_str());
 	to attempt to solve issue reported by Steven Schramm.
 
 2018-10-26  Gavin Salam <gavin.salam@cern.ch>
 
 	* read_lund_json.py:
 	removed extraneous normalisation of zeroth bin in
 	the LundImage class.
 	Added documentation.
 
 
 2018-08-30  Gavin Salam  <gavin.salam@cern.ch>
 
 	* VERSION: 
 	* NEWS:
 
 	Release of version 1.0.1
 
 2018-08-23  Gavin Salam  <gavin.salam@cern.ch>
 
 	* LundWithSecondary.hh:
 	* LundWithSecondary.cc:
 	added secondary_index(...), removed virtual qualifier from various
 	functions
 
 	* example_secondary.cc:
 	* example_secondary.ref:
 	example now prints out index of the primary declustering being
 	used for the secondary. Referemce file updated accordingly.
 
 2018-08-09  Frédéric Dreyer  <fdreyer@mit.edu>
 
 	First version of LundPlane.
 
Index: contrib/contribs/LundPlane/trunk/LundWithSecondary.cc
===================================================================
--- contrib/contribs/LundPlane/trunk/LundWithSecondary.cc	(revision 1459)
+++ contrib/contribs/LundPlane/trunk/LundWithSecondary.cc	(revision 1460)
@@ -1,78 +1,78 @@
 // $Id$
 //
 // Copyright (c) 2018-, Frederic A. Dreyer, Keith Hamilton, Alexander Karlberg,
 // Gavin P. Salam, Ludovic Scyboz, Gregory Soyez, Rob Verheyen
 //
 //----------------------------------------------------------------------
 // This file is part of FastJet contrib.
 //
 // It is free software; you can redistribute it and/or modify it under
 // the terms of the GNU General Public License as published by the
 // Free Software Foundation; either version 2 of the License, or (at
 // your option) any later version.
 //
 // It is distributed in the hope that it will be useful, but WITHOUT
 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 // or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
 // License for more details.
 //
 // You should have received a copy of the GNU General Public License
 // along with this code. If not, see <http://www.gnu.org/licenses/>.
 //----------------------------------------------------------------------
 
-#include "LundWithSecondary.hh"
+#include "fastjet/contrib/LundWithSecondary.hh"
 #include <sstream>
 
 FASTJET_BEGIN_NAMESPACE      // defined in fastjet/internal/base.hh
 
 namespace contrib{
 
 //----------------------------------------------------------------------
 /// return LundDeclustering sequence of primary plane
 std::vector<LundDeclustering> LundWithSecondary::primary(const PseudoJet& jet) const {
   return lund_gen_(jet);
 }
 
 //----------------------------------------------------------------------
 /// return LundDeclustering sequence of secondary plane (slow version)
 std::vector<LundDeclustering> LundWithSecondary::secondary(const PseudoJet& jet) const {
   // this is not optimal as one is computing the primary plane twice.
   std::vector<LundDeclustering> declusts = lund_gen_(jet);
   return secondary(declusts);
 }
 //----------------------------------------------------------------------
 /// return LundDeclustering sequence of secondary plane with primary sequence as input
 std::vector<LundDeclustering> LundWithSecondary::secondary(
 				  const std::vector<LundDeclustering> & declusts) const {
 
   int sec_index = secondary_index(declusts);
   // if we found the index of secondary emission, return its declustering sequence
   if (sec_index >= 0) {
     return lund_gen_(declusts[sec_index].softer());
   } else  {
     return std::vector<LundDeclustering>();
   }
 }
 
 //----------------------------------------------------------------------
 /// return the index associated of the primary declustering that is to be
 /// used for the secondary plane.
 int LundWithSecondary::secondary_index(const std::vector<LundDeclustering> & declusts) const {
   if (secondary_def_ == 0) {
     throw Error("secondary class is a null pointer, cannot identify element to use for secondary plane");
   }
   return (*secondary_def_)(declusts);
 }
   
 //----------------------------------------------------------------------
 /// description
 std::string LundWithSecondary::description() const {
   std::ostringstream oss;
   oss << "LundWithSecondary using " << secondary_def_->description()
       << " and " << lund_gen_.description();
   return oss.str();
 }
 
 } // namespace contrib
 
 FASTJET_END_NAMESPACE
Index: contrib/contribs/LundPlane/trunk/LundGenerator.cc
===================================================================
--- contrib/contribs/LundPlane/trunk/LundGenerator.cc	(revision 1459)
+++ contrib/contribs/LundPlane/trunk/LundGenerator.cc	(revision 1460)
@@ -1,76 +1,76 @@
 // $Id$
 //
 // Copyright (c) 2018-, Frederic A. Dreyer, Keith Hamilton, Alexander Karlberg,
 // Gavin P. Salam, Ludovic Scyboz, Gregory Soyez, Rob Verheyen
 //
 //----------------------------------------------------------------------
 // This file is part of FastJet contrib.
 //
 // It is free software; you can redistribute it and/or modify it under
 // the terms of the GNU General Public License as published by the
 // Free Software Foundation; either version 2 of the License, or (at
 // your option) any later version.
 //
 // It is distributed in the hope that it will be useful, but WITHOUT
 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 // or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
 // License for more details.
 //
 // You should have received a copy of the GNU General Public License
 // along with this code. If not, see <http://www.gnu.org/licenses/>.
 //----------------------------------------------------------------------
 
 #include <sstream>
-#include "LundGenerator.hh"
+#include "fastjet/contrib/LundGenerator.hh"
 
 FASTJET_BEGIN_NAMESPACE      // defined in fastjet/internal/base.hh
 
 namespace contrib{
 
 LundDeclustering::LundDeclustering(const PseudoJet& pair,
 				   const PseudoJet& j1, const PseudoJet& j2)
   : m_(pair.m()), Delta_(j1.delta_R(j2)), pair_(pair) {
 
   // establish which of j1 and j2 is softer
   if (j1.pt2() > j2.pt2()) {
     harder_ = j1;
     softer_ = j2;
   } else {
     harder_ = j2;
     softer_ = j1;
   }
 
   // now work out the various Lund declustering variables
   double softer_pt = softer_.pt();
   z_   = softer_pt / (softer_pt + harder_.pt());
   kt_  = softer_pt * Delta_;
   psi_ = atan2(softer_.rap()-harder_.rap(), harder_.delta_phi_to(softer_));
   kappa_ = z_ * Delta_;
 }
 
 //----------------------------------------------------------------------
 /// retrieve the vector of declusterings of the primary plane of a jet
 std::vector<LundDeclustering> LundGenerator::result(const PseudoJet& jet) const {
   std::vector<LundDeclustering> result;
   PseudoJet j = recluster_(jet);
   PseudoJet pair, j1, j2;
   pair = j;
   while (pair.has_parents(j1, j2)) {
     if (j1.pt2() < j2.pt2()) std::swap(j1,j2);
     result.push_back(LundDeclustering(pair, j1, j2));
     pair = j1;
   }
   return result;
 }
 
 //----------------------------------------------------------------------
 /// description
 std::string LundGenerator::description() const {
   std::ostringstream oss;
   oss << "LundGenerator with " << recluster_.description();
   return oss.str();
 }
 
 } // namespace contrib
 
 FASTJET_END_NAMESPACE
Index: contrib/contribs/LundPlane/trunk/SecondaryLund.cc
===================================================================
--- contrib/contribs/LundPlane/trunk/SecondaryLund.cc	(revision 1459)
+++ contrib/contribs/LundPlane/trunk/SecondaryLund.cc	(revision 1460)
@@ -1,124 +1,124 @@
 // $Id$
 //
 // Copyright (c) 2018-, Frederic A. Dreyer, Keith Hamilton, Alexander Karlberg,
 // Gavin P. Salam, Ludovic Scyboz, Gregory Soyez, Rob Verheyen
 //
 //----------------------------------------------------------------------
 // This file is part of FastJet contrib.
 //
 // It is free software; you can redistribute it and/or modify it under
 // the terms of the GNU General Public License as published by the
 // Free Software Foundation; either version 2 of the License, or (at
 // your option) any later version.
 //
 // It is distributed in the hope that it will be useful, but WITHOUT
 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 // or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
 // License for more details.
 //
 // You should have received a copy of the GNU General Public License
 // along with this code. If not, see <http://www.gnu.org/licenses/>.
 //----------------------------------------------------------------------
 
-#include "SecondaryLund.hh"
+#include "fastjet/contrib/SecondaryLund.hh"
 #include <math.h>
 #include <sstream>
 #include <limits>
 
 
 FASTJET_BEGIN_NAMESPACE      // defined in fastjet/internal/base.hh
 
 namespace contrib{
 
 //----------------------------------------------------------------------
 /// retrieve the vector of declusterings of the secondary plane of a jet
 int SecondaryLund_mMDT::result(const std::vector<LundDeclustering>& declusts) const {
   // iterate through primary branchings
   for (unsigned int i=0; i < declusts.size(); ++i) {
     // mMDTZ: find the first emission passing z>zcut
     if (declusts[i].z() > zcut_) return i;
   }
   return -1;
 }
 
 int SecondaryLund_dotmMDT::result(const std::vector<LundDeclustering>& declusts) const {
   // set up leading emission pointer and bookkeeping variables
   int secondary_index  = -1;
   double dot_prod_max   = 0.0;
   
   // iterate through primary branchings
   for (unsigned int i=0; i < declusts.size(); ++i) {
     // dotmMDTZ: find emission passing z>zcut with largest dot product
     if (declusts[i].z() > zcut_) {
       double dot_prod = declusts[i].harder().pt()*declusts[i].softer().pt()
 	*declusts[i].Delta()*declusts[i].Delta();
       if (dot_prod > dot_prod_max) {
 	dot_prod_max    = dot_prod;
 	secondary_index = i;
       }
     }
   }
   
   // return index of secondary emission
   return secondary_index;
 }
 
 
 int SecondaryLund_Mass::result(const std::vector<LundDeclustering>& declusts) const {
   // set up leading emission pointer and bookkeeping variables
   int secondary_index  = -1;
   double mass_diff     = std::numeric_limits<double>::max();
   
   // iterate through primary branchings
   for (unsigned int i=0; i < declusts.size(); ++i) {
     // Mass: find emission that minimises the distance to reference mass
     double dist =
       std::abs(log(declusts[i].harder().pt()*declusts[i].softer().pt()
 		   * declusts[i].Delta()*declusts[i].Delta() / mref2_)
 	       * log(1.0/declusts[i].z()));
     if (dist < mass_diff) {
       mass_diff     = dist;
       secondary_index = i;
     }
   }
   
   // return index of secondary emission
   return secondary_index;
 }
 
 
 //----------------------------------------------------------------------
 /// description
 std::string SecondaryLund::description() const {
   std::ostringstream oss;
   oss << "SecondaryLund";
   return oss.str();
 }
 
 //----------------------------------------------------------------------
 /// description
 std::string SecondaryLund_mMDT::description() const {
   std::ostringstream oss;
   oss << "SecondaryLund (mMDT selection of leading emission, zcut=" << zcut_<<")";
   return oss.str();
 }
 
 //----------------------------------------------------------------------
 /// description
 std::string SecondaryLund_dotmMDT::description() const {
   std::ostringstream oss;
   oss << "SecondaryLund (dotmMDT selection of leading emission, zcut=" << zcut_<<")";
   return oss.str();
 }
 
 //----------------------------------------------------------------------
 /// description
 std::string SecondaryLund_Mass::description() const {
   std::ostringstream oss;
   oss << " (Mass selection of leading emission, m="<<sqrt(mref2_)<<")";
   return oss.str();
 }
 
 } // namespace contrib
 
 FASTJET_END_NAMESPACE
Index: contrib/contribs/LundPlane/trunk/RecursiveLundEEGenerator.cc
===================================================================
--- contrib/contribs/LundPlane/trunk/RecursiveLundEEGenerator.cc	(revision 1459)
+++ contrib/contribs/LundPlane/trunk/RecursiveLundEEGenerator.cc	(revision 1460)
@@ -1,88 +1,88 @@
 // $Id$
 //
 // Copyright (c) 2018-, Frederic A. Dreyer, Keith Hamilton, Alexander Karlberg,
 // Gavin P. Salam, Ludovic Scyboz, Gregory Soyez, Rob Verheyen
 //
 //----------------------------------------------------------------------
 // This file is part of FastJet contrib.
 //
 // It is free software; you can redistribute it and/or modify it under
 // the terms of the GNU General Public License as published by the
 // Free Software Foundation; either version 2 of the License, or (at
 // your option) any later version.
 //
 // It is distributed in the hope that it will be useful, but WITHOUT
 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 // or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
 // License for more details.
 //
 // You should have received a copy of the GNU General Public License
 // along with this code. If not, see <http://www.gnu.org/licenses/>.
 //----------------------------------------------------------------------
 
 #include <sstream>
-#include "RecursiveLundEEGenerator.hh"
+#include "fastjet/contrib/RecursiveLundEEGenerator.hh"
 
 using namespace std;
 
 FASTJET_BEGIN_NAMESPACE
 
 namespace contrib{
 
 using namespace lund_plane;  
   
 LundEEDeclustering::LundEEDeclustering(const PseudoJet& pair,
 		const PseudoJet& j1, const PseudoJet& j2,
 		int iplane, double psi, double psibar,
 		int depth, int leaf_iplane, int sign_s)
   : iplane_(iplane), psi_(psi), psibar_(psibar), m_(pair.m()), pair_(pair), depth_(depth), leaf_iplane_(leaf_iplane), sign_s_(sign_s) {
 
   double omc = one_minus_costheta(j1,j2);
   
   if (omc > sqrt(numeric_limits<double>::epsilon())) {
     double cos_theta = 1.0 - omc;
     double theta     = acos(cos_theta);
     sin_theta_ = sin(theta);
     eta_       = -log(tan(theta/2.0));
   } else {
     // we are at small angles, so use small-angle formulas
     double theta = sqrt(2. * omc);
     sin_theta_ = theta;
     eta_       = -log(theta/2);
   }
 
   // establish which of j1 and j2 is softer
   if (j1.modp2() > j2.modp2()) {
     harder_ = j1;
     softer_ = j2;
   } else {
     harder_ = j2;
     softer_ = j1;
   }
 
   // now work out the various LundEE declustering variables
   double softer_modp = softer_.modp();
   z_   = softer_modp / (softer_modp + harder_.modp());
   kt_  = softer_modp * sin_theta_;
   lnkt_ = log(kt_);
   kappa_ = z_ * sin_theta_;
 }
 
 } // namespace contrib
 
 
 FASTJET_END_NAMESPACE
 
 std::ostream & operator<<(std::ostream & ostr, const fastjet::contrib::LundEEDeclustering & d) {
   ostr << "kt = "   << d.kt()
        << " z = "   << d.z()
        << " eta = " << d.eta()
        << " psi = " << d.psi()
        << " psibar = " << d.psibar()
        << " m = "   << d.m()
        << " iplane = " << d.iplane()
        << " depth = " << d.depth()
        << " leaf_iplane = " << d.leaf_iplane();
   return ostr;
 }
 
Index: contrib/contribs/LundPlane/trunk/example_dpsi_slice.cc
===================================================================
--- contrib/contribs/LundPlane/trunk/example_dpsi_slice.cc	(revision 1459)
+++ contrib/contribs/LundPlane/trunk/example_dpsi_slice.cc	(revision 1460)
@@ -1,174 +1,175 @@
 //----------------------------------------------------------------------
 /// \file example_dpsi_slice.cc
 ///
 /// This example program is meant to illustrate how the
 /// fastjet::contrib::RecursiveLundEEGenerator class is used.
 ///
 /// Run this example with
 ///
 /// \verbatim
 ///     ./example_dpsi_slice < ../data/single-ee-event.dat
 /// \endverbatim
 
 //----------------------------------------------------------------------
 // $Id$
 //
 // Copyright (c) 2018-, Frederic A. Dreyer, Keith Hamilton, Alexander Karlberg,
 // Gavin P. Salam, Ludovic Scyboz, Gregory Soyez, Rob Verheyen
 //
 //----------------------------------------------------------------------
 // This file is part of FastJet contrib.
 //
 // It is free software; you can redistribute it and/or modify it under
 // the terms of the GNU General Public License as published by the
 // Free Software Foundation; either version 2 of the License, or (at
 // your option) any later version.
 //
 // It is distributed in the hope that it will be useful, but WITHOUT
 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 // or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
 // License for more details.
 //
 // You should have received a copy of the GNU General Public License
 // along with this code. If not, see <http://www.gnu.org/licenses/>.
 //----------------------------------------------------------------------
 
 #include <iostream>
 #include <fstream>
 #include <sstream>
 
 #include "fastjet/PseudoJet.hh"
 #include "fastjet/EECambridgePlugin.hh"
 #include <string>
-#include "RecursiveLundEEGenerator.hh" // In external code, this should be fastjet/contrib/RecursiveLundEEGenerator.hh
+#include "fastjet/contrib/RecursiveLundEEGenerator.hh"
+
 using namespace std;
 using namespace fastjet;
 
 // Definitions for the slice observable (ymax = 1, zcut = 0.1)
 double abs_rap_slice = 1;
 double z2_cut = 0.1;
 
 // forward declaration to make things clearer
 void read_event(vector<PseudoJet> &event);
 
 // returns true if PseudoJet p is in the central slice of half-width abs_rap_slice
 // w.r.t. the event axis pref
 bool in_slice(const PseudoJet & p, const PseudoJet & pref) {
   
   // Rotate p, and use the rapidity to determine if p is in the slice
   contrib::lund_plane::Matrix3 rotmat = contrib::lund_plane::Matrix3::from_direction(pref).transpose();
   const PseudoJet p_rot = rotmat*p;
 
   return fabs(p_rot.rap()) < abs_rap_slice;
 }
 
 //----------------------------------------------------------------------
 int main(){
 
   //----------------------------------------------------------
   // read in input particles
   vector<PseudoJet> event;
   read_event(event);
 
   cout << "# read an event with " << event.size() << " particles" << endl;
   //----------------------------------------------------------
   // create an instance of RecursiveLundEEGenerator, with default options
   int depth = -1;
   bool dynamic_psi_reference = true;
   fastjet::contrib::RecursiveLundEEGenerator lund(depth, dynamic_psi_reference);
   
   // first get some C/A jets
   double y3_cut = 1.0;
   JetDefinition::Plugin* ee_plugin = new EECambridgePlugin(y3_cut);
   JetDefinition jet_def(ee_plugin);
   ClusterSequence cs(event, jet_def);
 
   // Get the event axis (to be used for the slice)
   std::vector<PseudoJet> excl = cs.exclusive_jets(2);
   assert(excl.size() == 2);
   // order the two jets according to momentum along z axis
   if (excl[0].pz() < excl[1].pz()) {
     std::swap(excl[0],excl[1]);
   }
   const PseudoJet ev_axis = excl[0]-excl[1];
 
   // Get the list of primary declusterings
   const vector<contrib::LundEEDeclustering> declusts = lund.result(cs);
 
   // find the declustering that throws something into a fixed slice
   // (from a parent that was not in the slice) and that throws the
   // largest pt (relative to the z axis) into that slice
 
   int index_of_max_pt_in_slice = -1;
   double max_pt_in_slice = 0.0;
   double psi_1 = 0.0;  //< init just to avoid a compiler warning (the
                        //< test in L115 makes it safe already)
   for (unsigned i = 0; i < declusts.size(); i++) {
     const auto & decl = declusts[i];
     if (!in_slice(decl.harder(), ev_axis) && in_slice(decl.softer(), ev_axis)) {
       if (decl.softer().pt() > max_pt_in_slice) {
         index_of_max_pt_in_slice = i;
         max_pt_in_slice = decl.softer().pt();
         psi_1 = decl.psibar();
       }
     }
   }
   if (index_of_max_pt_in_slice < 0) return 0;
 
   // establish what we need to follow and the reference psi_1
   int iplane_to_follow = declusts[index_of_max_pt_in_slice].leaf_iplane();
   
   vector<const contrib::LundEEDeclustering *> secondaries;
   for (const auto & declust: declusts){
     if (declust.iplane() == iplane_to_follow) secondaries.push_back(&declust);
   }
 
   int index_of_max_kt_secondary = -1;
   double dpsi;
   for (unsigned int i_secondary=0; i_secondary<secondaries.size(); i_secondary++) {
     if (secondaries[i_secondary]->z() > z2_cut) {
 
       index_of_max_kt_secondary = i_secondary;
       double psi_2 = secondaries[i_secondary]->psibar();
       dpsi = contrib::lund_plane::map_to_pi(psi_2 - psi_1);
 
       break;
     }
   }
   if (index_of_max_kt_secondary < 0) return 0;
 
   cout << "Primary in the central slice, with Lund coordinates ( ln 1/Delta, ln kt, psibar ):" << endl;
   pair<double,double> coords = declusts[index_of_max_pt_in_slice].lund_coordinates();
   cout << "index [" << index_of_max_pt_in_slice << "](" << coords.first << ", " << coords.second << ", "
        << declusts[index_of_max_pt_in_slice].psibar() << ")" << endl;
   cout << endl << "with Lund coordinates for the (highest-kT) secondary plane that passes the zcut of "
        << z2_cut << endl;
   coords = secondaries[index_of_max_kt_secondary]->lund_coordinates();
   cout << "index [" << index_of_max_kt_secondary << "](" << coords.first << ", " << coords.second << ", "
        << secondaries[index_of_max_kt_secondary]->psibar() << ")";
 
   cout << " --> delta_psi,slice = " << dpsi << endl;
 
   // Delete the EECambridge plugin
   delete ee_plugin;
 
   return 0;
 }
 
 // read in input particles
 void read_event(vector<PseudoJet> &event){  
   string line;
   while (getline(cin, line)) {
     istringstream linestream(line);
     // take substrings to avoid problems when there is extra "pollution"
     // characters (e.g. line-feed).
     if (line.substr(0,4) == "#END") {return;}
     if (line.substr(0,1) == "#") {continue;}
     double px,py,pz,E;
     linestream >> px >> py >> pz >> E;
     PseudoJet particle(px,py,pz,E);
 
     // push event onto back of full_event vector
     event.push_back(particle);
   }
 }
Index: contrib/contribs/LundPlane/trunk/Makefile
===================================================================
--- contrib/contribs/LundPlane/trunk/Makefile	(revision 1459)
+++ contrib/contribs/LundPlane/trunk/Makefile	(revision 1460)
@@ -1,91 +1,112 @@
 # If you are using this Makefile standalone and fastjet-config is not
 # in your path, edit this line to specify the full path
 FASTJETCONFIG=fastjet-config
 PREFIX=`$(FASTJETCONFIG) --prefix`
 CXX=g++
 CXXFLAGS= -O3 -Wall -g
 install_script = $(SHELL) ../utils/install-sh
 check_script = ../utils/check.sh
 
 # global contrib-wide Makefile include may override some of the above
 # variables (leading "-" means don't give an error if you can't find
 # the file)
 -include ../.Makefile.inc
 
 #------------------------------------------------------------------------
 # things that are specific to this contrib
 NAME=LundPlane
 SRCS=LundGenerator.cc LundWithSecondary.cc SecondaryLund.cc RecursiveLundEEGenerator.cc
 EXAMPLES=example example_secondary example_dpsi_collinear example_dpsi_slice
 INSTALLED_HEADERS=LundGenerator.hh LundWithSecondary.hh SecondaryLund.hh RecursiveLundEEGenerator.hh LundJSON.hh LundEEHelpers.hh
+# List here any dependencies on other contribs. Note that they 
+# must be listed (potentially with versioning constraints) also
+# in the FJCONTRIB.cfg file.
+DEPENDS_ON =
 #------------------------------------------------------------------------
 
 CXXFLAGS+= $(shell $(FASTJETCONFIG) --cxxflags)
 LDFLAGS += -lm $(shell $(FASTJETCONFIG) --libs --plugins)
 
+INCLUDE += -Iinclude/
+# loop over all entries in DEPENDS_ON and for each entry ENTRY
+# add -I../ENTRY to INCLUDE, -L../ENTRY to LDFLAGS and -lENTRY to LDFLAGS
+INCLUDE += $(foreach ENTRY,$(DEPENDS_ON),-I../$(ENTRY)/include)
+LDFLAGS += $(foreach ENTRY,$(DEPENDS_ON),-L../$(ENTRY) -l$(ENTRY))
+CXXFLAGS+= $(INCLUDE)
+
 OBJS  = $(SRCS:.cc=.o)
 EXAMPLES_SRCS  = $(EXAMPLES:=.cc)
 
 install_HEADER  = $(install_script) -c -m 644
 install_LIB     = $(install_script) -c -m 644
 install_DIR     = $(install_script) -d
 install_DATA    = $(install_script) -c -m 644
 install_PROGRAM = $(install_script) -c -s
 install_SCRIPT  = $(install_script) -c
 
 .PHONY: clean distclean examples check install
 
 # compilation of the code (default target)
 all: lib$(NAME).a
 
 lib$(NAME).a: $(OBJS) 
 	ar cru lib$(NAME).a $(OBJS)
 	ranlib lib$(NAME).a
 
 # building the examples
 examples: $(EXAMPLES)
 
 # the following construct makes it possible to automatically build
 # each of the examples listed in $EXAMPLES
 $(EXAMPLES): % : %.o all
 	$(CXX) $(CXXFLAGS) -o $@ $< -L. -l$(NAME) $(LDFLAGS)
 
 # check that everything went fine
 check: examples
 	@for prog in $(EXAMPLES); do\
 	  if [ "$${prog}" = "example_dpsi_collinear" ] || [ "$${prog}" = "example_dpsi_slice" ]; then \
 	    $(check_script) $${prog} ../data/single-ee-event.dat || exit 1; \
 	  else \
 	    $(check_script) $${prog} ../data/single-event.dat || exit 1; \
 	  fi; \
 	done
 	@echo "All tests successful"
 
 # cleaning the directory
 clean:
 	rm -f *~ *.o
 
 distclean: clean
 	rm -f lib$(NAME).a $(EXAMPLES)
 
 # install things in PREFIX/...
 install: all
 	$(install_DIR) $(PREFIX)/include/fastjet/contrib
 	for header in $(INSTALLED_HEADERS); do\
-	  $(install_HEADER) $$header $(PREFIX)/include/fastjet/contrib/;\
+	  $(install_HEADER) include/fastjet/contrib/$$header $(PREFIX)/include/fastjet/contrib/;\
 	done
 	$(install_DIR) $(PREFIX)/lib
 	$(install_LIB) lib$(NAME).a $(PREFIX)/lib
 
 depend:
-	makedepend -Y --   -- $(SRCS) $(EXAMPLES_SRCS)
+	makedepend -Y -- -Iinclude -- $(SRCS) $(EXAMPLES_SRCS)
 # DO NOT DELETE
 
-LundGenerator.o: LundGenerator.hh
-LundWithSecondary.o: LundWithSecondary.hh LundGenerator.hh SecondaryLund.hh
-SecondaryLund.o: SecondaryLund.hh LundGenerator.hh
-RecursiveLundEEGenerator.o: RecursiveLundEEGenerator.hh LundEEHelpers.hh
-example.o: LundGenerator.hh LundJSON.hh
-example_secondary.o: LundWithSecondary.hh LundGenerator.hh SecondaryLund.hh
-example_dpsi_collinear.o: RecursiveLundEEGenerator.hh LundEEHelpers.hh
-example_dpsi_slice.o: RecursiveLundEEGenerator.hh LundEEHelpers.hh
+LundGenerator.o: include/fastjet/contrib/LundGenerator.hh
+LundWithSecondary.o: include/fastjet/contrib/LundWithSecondary.hh
+LundWithSecondary.o: include/fastjet/contrib/LundGenerator.hh
+LundWithSecondary.o: include/fastjet/contrib/SecondaryLund.hh
+SecondaryLund.o: include/fastjet/contrib/SecondaryLund.hh
+SecondaryLund.o: include/fastjet/contrib/LundGenerator.hh
+RecursiveLundEEGenerator.o: include/fastjet/contrib/RecursiveLundEEGenerator.hh
+RecursiveLundEEGenerator.o: include/fastjet/contrib/LundEEHelpers.hh
+example.o: include/fastjet/contrib/LundGenerator.hh
+example.o: include/fastjet/contrib/LundJSON.hh
+example.o: include/fastjet/contrib/LundGenerator.hh
+example_secondary.o: include/fastjet/contrib/LundWithSecondary.hh
+example_secondary.o: include/fastjet/contrib/LundGenerator.hh
+example_secondary.o: include/fastjet/contrib/SecondaryLund.hh
+example_dpsi_collinear.o: include/fastjet/contrib/RecursiveLundEEGenerator.hh
+example_dpsi_collinear.o: include/fastjet/contrib/LundEEHelpers.hh
+example_dpsi_slice.o: include/fastjet/contrib/RecursiveLundEEGenerator.hh
+example_dpsi_slice.o: include/fastjet/contrib/LundEEHelpers.hh
Index: contrib/contribs/LundPlane/trunk/FJCONTRIB.cfg
===================================================================
--- contrib/contribs/LundPlane/trunk/FJCONTRIB.cfg	(revision 0)
+++ contrib/contribs/LundPlane/trunk/FJCONTRIB.cfg	(revision 1460)
@@ -0,0 +1 @@
+version: 2.1.2-devel
Index: contrib/contribs/LundPlane/trunk/example.cc
===================================================================
--- contrib/contribs/LundPlane/trunk/example.cc	(revision 1459)
+++ contrib/contribs/LundPlane/trunk/example.cc	(revision 1460)
@@ -1,119 +1,120 @@
 //----------------------------------------------------------------------
 /// \file example.cc
 ///
 /// This example program is meant to illustrate how the
 /// fastjet::contrib::LundGenerator class is used.
 ///
 /// Run this example with
 ///
 /// \verbatim
 ///     ./example < ../data/single-event.dat
 /// \endverbatim
 
 //----------------------------------------------------------------------
 // $Id$
 //
 // Copyright (c) 2018-, Frederic A. Dreyer, Keith Hamilton, Alexander Karlberg,
 // Gavin P. Salam, Ludovic Scyboz, Gregory Soyez, Rob Verheyen
 //
 //----------------------------------------------------------------------
 // This file is part of FastJet contrib.
 //
 // It is free software; you can redistribute it and/or modify it under
 // the terms of the GNU General Public License as published by the
 // Free Software Foundation; either version 2 of the License, or (at
 // your option) any later version.
 //
 // It is distributed in the hope that it will be useful, but WITHOUT
 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 // or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
 // License for more details.
 //
 // You should have received a copy of the GNU General Public License
 // along with this code. If not, see <http://www.gnu.org/licenses/>.
 //----------------------------------------------------------------------
 
 #include <iostream>
 #include <fstream>
 #include <sstream>
 
 #include "fastjet/PseudoJet.hh"
 #include <string>
-#include "LundGenerator.hh" // In external code, this should be fastjet/contrib/LundGenerator.hh
-#include "LundJSON.hh"  // In external code, this should be fastjet/contrib/LundJSON.hh
+#include "fastjet/contrib/LundGenerator.hh"
+#include "fastjet/contrib/LundJSON.hh"
+
 using namespace std;
 using namespace fastjet;
 
 // forward declaration to make things clearer
 void read_event(vector<PseudoJet> &event);
 
 //----------------------------------------------------------------------
 int main(){
 
   //----------------------------------------------------------
   // read in input particles
   vector<PseudoJet> event;
   read_event(event);
   string filename = "jets.json";
   cout << "# read an event with " << event.size() << " particles" << endl;
   cout << "# writing declusterings of primary and secondary plane to file "
        << filename << endl;
 
   ofstream outfile;
   outfile.open(filename.c_str());
   
   // first get some anti-kt jets
   double R = 1.0, ptmin = 100.0;
   JetDefinition jet_def(antikt_algorithm, R);
   ClusterSequence cs(event, jet_def);
   vector<PseudoJet> jets = sorted_by_pt(cs.inclusive_jets(ptmin));
   
   //----------------------------------------------------------
   // create an instance of LundGenerator, with default options
   contrib::LundGenerator lund;
 
   cout << lund.description() << endl;
   
   for (unsigned ijet = 0; ijet < jets.size(); ijet++) {
     cout << endl << "Lund coordinates ( ln 1/Delta, ln kt ) of declusterings of jet " 
          << ijet << " are:" << endl;
     vector<contrib::LundDeclustering> declusts = lund(jets[ijet]);
 
     for (unsigned int idecl = 0; idecl < declusts.size(); ++idecl) {
       pair<double,double> coords = declusts[idecl].lund_coordinates();
       cout << "(" << coords.first << ", " << coords.second << ")";
       if (idecl < declusts.size() - 1) cout << "; ";
     }
 
     cout << endl;
     
     // outputs the primary Lund plane
     lund_to_json(outfile, declusts); outfile << endl;
     // outputs the full Lund tree
     //to_json(cout, lund_gen, jets[ijet]); cout << endl;
   }
 
   cout << endl << "File " << filename << " written." << endl;
 
 
 
   return 0;
 }
 
 // read in input particles
 void read_event(vector<PseudoJet> &event){  
   string line;
   while (getline(cin, line)) {
     istringstream linestream(line);
     // take substrings to avoid problems when there is extra "pollution"
     // characters (e.g. line-feed).
     if (line.substr(0,4) == "#END") {return;}
     if (line.substr(0,1) == "#") {continue;}
     double px,py,pz,E;
     linestream >> px >> py >> pz >> E;
     PseudoJet particle(px,py,pz,E);
 
     // push event onto back of full_event vector
     event.push_back(particle);
   }
 }