diff --git a/include/RHEJ/resummation_jet_momenta.hh b/include/RHEJ/resummation_jet_momenta.hh
index 12cda67..8e42f5b 100644
--- a/include/RHEJ/resummation_jet_momenta.hh
+++ b/include/RHEJ/resummation_jet_momenta.hh
@@ -1,27 +1,20 @@
 /** \file
  *  \brief Function to calculate the momenta of resummation jets
  */
 #pragma once
 
 #include "RHEJ/utility.hh"
 
 namespace RHEJ{
-
-  enum class ReshufflingAlgorithm {
-    linear_in_born,
-    linear_in_resummed
-  };
-
   /**
    * \brief Calculate the resummation jet momenta
    * @param p_born              born Jet Momenta
    * @param qperp               Sum of non-jet Parton Transverse Momenta
    * @returns                   Resummation Jet Momenta
    */
   std::vector<fastjet::PseudoJet> resummation_jet_momenta(
       std::vector<fastjet::PseudoJet> const & p_born,
-      fastjet::PseudoJet const & qperp,
-      ReshufflingAlgorithm algo = ReshufflingAlgorithm::linear_in_born
+      fastjet::PseudoJet const & qperp
   );
 
 }
diff --git a/src/PhaseSpacePoint.cc b/src/PhaseSpacePoint.cc
index 9a57f9a..e3da3ae 100644
--- a/src/PhaseSpacePoint.cc
+++ b/src/PhaseSpacePoint.cc
@@ -1,559 +1,537 @@
 #include "RHEJ/PhaseSpacePoint.hh"
 
 #include <random>
 
 #include <CLHEP/Random/Randomize.h>
 #include <CLHEP/Random/RanluxEngine.h>
 
 #include "RHEJ/Constants.hh"
 #include "RHEJ/resummation_jet_momenta.hh"
 #include "RHEJ/Jacobian.hh"
 #include "RHEJ/uno.hh"
 #include "RHEJ/utility.hh"
 #include "RHEJ/kinematics.hh"
 
 namespace RHEJ{
   namespace {
     constexpr int max_jet_user_idx = PhaseSpacePoint::ng_max;
 
     bool is_nonjet_parton(fastjet::PseudoJet const & parton){
       assert(parton.user_index() != -1);
       return parton.user_index() > max_jet_user_idx;
     }
 
     bool is_jet_parton(fastjet::PseudoJet const & parton){
       assert(parton.user_index() != -1);
       return parton.user_index() <= max_jet_user_idx;
     }
 
     // user indices for partons with extremal rapidity
     constexpr int unob_idx = -5;
     constexpr int unof_idx = -4;
     constexpr int backward_FKL_idx = -3;
     constexpr int forward_FKL_idx = -2;
   }
 
   namespace {
     double estimate_ng_mean(std::vector<fastjet::PseudoJet> const & Born_jets){
       const double delta_y =
         Born_jets.back().rapidity() - Born_jets.front().rapidity();
       assert(delta_y > 0);
       // Formula derived from fit in reversed HEJ intro paper
       return 0.975052*delta_y;
     }
   }
 
   std::vector<fastjet::PseudoJet> PhaseSpacePoint::cluster_jets(
       std::vector<fastjet::PseudoJet> const & partons
   ) const{
     fastjet::ClusterSequence cs(partons, param_.jet_param.def);
     return cs.inclusive_jets(param_.jet_param.min_pt);
   }
 
   bool PhaseSpacePoint::pass_resummation_cuts(
       std::vector<fastjet::PseudoJet> const & jets
   ) const{
     return cluster_jets(jets).size() == jets.size();
   }
 
   int PhaseSpacePoint::sample_ng(std::vector<fastjet::PseudoJet> const & Born_jets){
     const double ng_mean = estimate_ng_mean(Born_jets);
     std::poisson_distribution<int> dist(ng_mean);
     const int ng = dist(ran_.get());
     assert(ng >= 0);
     assert(ng < ng_max);
     weight_ *= std::tgamma(ng + 1)*std::exp(ng_mean)*std::pow(ng_mean, -ng);
     return ng;
   }
 
   void PhaseSpacePoint::copy_AWZH_boson_from(Event const & event){
     auto const & from = event.outgoing();
 
     const auto AWZH_boson = std::find_if(
         begin(from), end(from),
         [](Particle const & p){ return is_AWZH_boson(p); }
     );
     if(AWZH_boson == end(from)) return;
     auto insertion_point = std::lower_bound(
         begin(outgoing_), end(outgoing_), *AWZH_boson, rapidity_less{}
     );
     outgoing_.insert(insertion_point, *AWZH_boson);
 
     // copy decay products
     const int idx = std::distance(begin(from), AWZH_boson);
     const auto decay_it = event.decays().find(idx);
     if(decay_it != end(event.decays())){
       const int new_idx = std::distance(begin(outgoing_), insertion_point);
       assert(outgoing_[new_idx].type == AWZH_boson->type);
       decays_.emplace(new_idx, decay_it->second);
     }
 
     assert(std::is_sorted(begin(outgoing_), end(outgoing_), rapidity_less{}));
   }
 
   PhaseSpacePoint::PhaseSpacePoint(
       Event const & ev, PhaseSpacePointConfig conf, RHEJ::RNG & ran
   ):
     unob_{has_unob_gluon(ev.incoming(), ev.outgoing())},
     unof_{!unob_ && has_unof_gluon(ev.incoming(), ev.outgoing())},
     param_{std::move(conf)},
     ran_{ran}
   {
     weight_ = 1;
     const auto Born_jets = sorted_by_rapidity(ev.jets());
     const int ng = sample_ng(Born_jets);
     weight_ /= std::tgamma(ng + 1);
     const int ng_jets = sample_ng_jets(ng, Born_jets);
     std::vector<fastjet::PseudoJet> out_partons = gen_non_jet(
        ng - ng_jets, CMINPT, param_.jet_param.min_pt
     );
     {
       const auto qperp = std::accumulate(
         begin(out_partons), end(out_partons),
         fastjet::PseudoJet{}
       );
       const auto jets = reshuffle(Born_jets, qperp);
       if(weight_ == 0.) return;
       if(! pass_resummation_cuts(jets)){
        weight_ = 0.;
        return;
       }
       std::vector<fastjet::PseudoJet> jet_partons = split(jets, ng_jets);
       if(weight_ == 0.) return;
       rescale_rapidities(
         out_partons,
         most_backward_FKL(jet_partons).rapidity(),
         most_forward_FKL(jet_partons).rapidity()
       );
       if(! cluster_jets(out_partons).empty()){
         weight_ = 0.;
         return;
       }
       std::sort(begin(out_partons), end(out_partons), rapidity_less{});
       assert(
         std::is_sorted(begin(jet_partons), end(jet_partons), rapidity_less{})
       );
       const auto first_jet_parton = out_partons.insert(
         end(out_partons), begin(jet_partons), end(jet_partons)
       );
       std::inplace_merge(
         begin(out_partons), first_jet_parton, end(out_partons), rapidity_less{}
       );
     }
     if(! jets_ok(Born_jets, out_partons)){
       weight_ = 0.;
       return;
     }
     weight_ *= phase_space_normalisation(Born_jets.size(), out_partons.size());
 
     outgoing_.reserve(out_partons.size() + 1); // one slot for possible A, W, Z, H
     for(auto & p: out_partons){
       outgoing_.emplace_back(Particle{pid::gluon, std::move(p)});
     }
     most_backward_FKL(outgoing_).type = ev.incoming().front().type;
     most_forward_FKL(outgoing_).type = ev.incoming().back().type;
     copy_AWZH_boson_from(ev);
 
     assert(!outgoing_.empty());
     reconstruct_incoming(ev.incoming());
   }
 
   std::vector<fastjet::PseudoJet> PhaseSpacePoint::gen_non_jet(
       int count, double ptmin, double ptmax
   ){
     // heuristic parameters for pt sampling
     const double ptpar = 1.3 + count/5.;
     const double temp1 = atan((ptmax - ptmin)/ptpar);
 
     std::vector<fastjet::PseudoJet> partons(count);
     for(size_t i = 0; i < (size_t) count; ++i){
       const double r1 = ran_.get().flat();
       const double pt = ptmin + ptpar*tan(r1*temp1);
       const double temp2 = cos(r1*temp1);
       const double phi = 2*M_PI*ran_.get().flat();
       weight_ *= 2.0*M_PI*pt*ptpar*temp1/(temp2*temp2);
       // we don't know the allowed rapidity span yet,
       // set a random value to be rescaled later on
       const double y = ran_.get().flat();
       partons[i].reset_PtYPhiM(pt, y, phi);
       // Set user index higher than any jet-parton index
       // in order to assert that these are not inside jets
       partons[i].set_user_index(i + 1 + ng_max);
 
       assert(ptmin-1e-5 <= partons[i].pt() && partons[i].pt() <= ptmax+1e-5);
     }
     assert(std::all_of(partons.cbegin(), partons.cend(), is_nonjet_parton));
     return partons;
   }
 
   void PhaseSpacePoint::rescale_rapidities(
       std::vector<fastjet::PseudoJet> & partons,
       double ymin, double ymax
   ){
     constexpr double ep = 1e-7;
     for(auto & parton: partons){
       assert(0 <= parton.rapidity() && parton.rapidity() <= 1);
       const double dy = ymax - ymin - 2*ep;
       const double y = ymin + ep + dy*parton.rapidity();
       parton.reset_momentum_PtYPhiM(parton.pt(), y, parton.phi());
       weight_ *= dy;
       assert(ymin <= parton.rapidity() && parton.rapidity() <= ymax);
     }
   }
 
   namespace {
     template<typename T, typename... Rest>
     auto min(T const & a, T const & b, Rest&&... r) {
       using std::min;
       return min(a, min(b, std::forward<Rest>(r)...));
     }
   }
 
   double PhaseSpacePoint::probability_in_jet(
       std::vector<fastjet::PseudoJet> const & Born_jets
   ) const{
     assert(std::is_sorted(begin(Born_jets), end(Born_jets), rapidity_less{}));
     assert(Born_jets.size() >= 2);
 
     const double dy =
       Born_jets.back().rapidity() - Born_jets.front().rapidity();
     const double R = param_.jet_param.def.R();
     const int njets = Born_jets.size();
     const double p_J_y_large = (njets-1)*R*R/(2.*dy);
     const double p_J_y0 = njets*R/M_PI;
     return min(p_J_y_large, p_J_y0, 1.);
   }
 
   int PhaseSpacePoint::sample_ng_jets(
       int ng, std::vector<fastjet::PseudoJet> const & Born_jets
   ){
     const double p_J = probability_in_jet(Born_jets);
     std::binomial_distribution<> bin_dist(ng, p_J);
     const int ng_J = bin_dist(ran_.get());
     weight_ *= std::pow(p_J, -ng_J)*std::pow(1 - p_J, ng_J - ng);
     return ng_J;
   }
 
-  namespace {
-    double reshuffling_weight(
-      std::vector<fastjet::PseudoJet> const & Born_jets,
-      std::vector<fastjet::PseudoJet> const & jets,
-      fastjet::PseudoJet const & q,
-      ReshufflingAlgorithm algo
-    ) {
-      switch(algo) {
-      case ReshufflingAlgorithm::linear_in_born:
-        // transform delta functions to integration over resummation momenta
-        return 1/Jacobian(jets, q);
-      case ReshufflingAlgorithm::linear_in_resummed:
-        // additional Jacobian to ensure Born integration over delta gives 1
-        return Jacobian(Born_jets, -1.*q);
-      default:;
-      }
-      throw std::logic_error{"unreachable"};
-      }
-  }
-
-  std::vector<fastjet::PseudoJet>
-  PhaseSpacePoint::reshuffle(
+  std::vector<fastjet::PseudoJet> PhaseSpacePoint::reshuffle(
       std::vector<fastjet::PseudoJet> const & Born_jets,
       fastjet::PseudoJet const & q
   ){
-    static constexpr auto algo = ReshufflingAlgorithm::linear_in_resummed;
-
     if(q == fastjet::PseudoJet{0, 0, 0, 0}) return Born_jets;
-    const auto jets = resummation_jet_momenta(Born_jets, q, algo);
+    const auto jets = resummation_jet_momenta(Born_jets, q);
     if(jets.empty()){
       weight_ = 0;
       return {};
     }
 
-    weight_ *= reshuffling_weight(Born_jets, jets, q, algo);
+    // additional Jacobian to ensure Born integration over delta gives 1
+    weight_ *= Jacobian(Born_jets, -1.*q);
     return jets;
   }
 
   std::vector<int> PhaseSpacePoint::distribute_jet_partons(
       int ng_jets, std::vector<fastjet::PseudoJet> const & jets
   ){
     size_t first_valid_jet = 0;
     size_t num_valid_jets = jets.size();
     const double R_eff = 5./3.*param_.jet_param.def.R();
     // if there is an unordered jet too far away from the FKL jets
     // then extra gluon constituents of the unordered jet would
     // violate the FKL rapidity ordering
     if(unob_ && jets[0].delta_R(jets[1]) > R_eff){
       ++first_valid_jet;
       --num_valid_jets;
     }
     else if(unof_ && jets[jets.size()-1].delta_R(jets[jets.size()-2]) > R_eff){
       --num_valid_jets;
     }
     std::vector<int> np(jets.size(), 1);
     for(int i = 0; i < ng_jets; ++i){
       ++np[first_valid_jet + ran_.get().flat() * num_valid_jets];
     }
     weight_ *= std::pow(num_valid_jets, ng_jets);
     return np;
   }
 
 #ifndef NDEBUG
   namespace{
     bool tagged_FKL_backward(
         std::vector<fastjet::PseudoJet> const & jet_partons
     ){
       return std::find_if(
           begin(jet_partons), end(jet_partons),
           [](fastjet::PseudoJet const & p){
             return p.user_index() == backward_FKL_idx;
           }
       ) != end(jet_partons);
     }
 
     bool tagged_FKL_forward(
         std::vector<fastjet::PseudoJet> const & jet_partons
     ){
       // the most forward FKL parton is most likely near the end of jet_partons;
       // start search from there
       return std::find_if(
           jet_partons.rbegin(), jet_partons.rend(),
           [](fastjet::PseudoJet const & p){
             return p.user_index() == forward_FKL_idx;
           }
       ) != jet_partons.rend();
     }
 
     bool tagged_FKL_extremal(
         std::vector<fastjet::PseudoJet> const & jet_partons
     ){
       return tagged_FKL_backward(jet_partons) && tagged_FKL_forward(jet_partons);
     }
 
   } // namespace anonymous
 #endif
 
   std::vector<fastjet::PseudoJet> PhaseSpacePoint::split(
       std::vector<fastjet::PseudoJet> const & jets,
       int ng_jets
   ){
     return split(jets, distribute_jet_partons(ng_jets, jets));
   }
 
   bool PhaseSpacePoint::pass_extremal_cuts(
       fastjet::PseudoJet const & ext_parton,
       fastjet::PseudoJet const & jet
   ) const{
     if(ext_parton.pt() < param_.min_extparton_pt) return false;
     return (ext_parton - jet).pt()/jet.pt() < param_.max_ext_soft_pt_fraction;
   }
 
   std::vector<fastjet::PseudoJet> PhaseSpacePoint::split(
       std::vector<fastjet::PseudoJet> const & jets,
       std::vector<int> const & np
   ){
     assert(! jets.empty());
     assert(jets.size() == np.size());
     assert(pass_resummation_cuts(jets));
 
     const size_t most_backward_FKL_idx = 0 + unob_;
     const size_t most_forward_FKL_idx = jets.size() - 1 - unof_;
     const auto & jet = param_.jet_param;
     const JetSplitter jet_splitter{jet.def, jet.min_pt, ran_};
 
     std::vector<fastjet::PseudoJet> jet_partons;
     // randomly distribute jet gluons among jets
     for(size_t i = 0; i < jets.size(); ++i){
       auto split_res = jet_splitter.split(jets[i], np[i]);
       weight_ *= split_res.weight;
       if(weight_ == 0) return {};
       assert(
           std::all_of(
               begin(split_res.constituents), end(split_res.constituents),
               is_jet_parton
           )
       );
       const auto first_new_parton = jet_partons.insert(
           end(jet_partons),
           begin(split_res.constituents), end(split_res.constituents)
       );
       // mark uno and extremal FKL emissions here so we can check
       // their position once all emissions are generated
       auto extremal = end(jet_partons);
       if((unob_ && i == 0) || i == most_backward_FKL_idx){
         // unordered or FKL backward emission
         extremal = std::min_element(
             first_new_parton, end(jet_partons), rapidity_less{}
         );
         extremal->set_user_index(
             (i == most_backward_FKL_idx)?backward_FKL_idx:unob_idx
         );
       }
       else if((unof_ && i == jets.size() - 1) || i == most_forward_FKL_idx){
         // unordered or FKL forward emission
         extremal = std::max_element(
             first_new_parton, end(jet_partons), rapidity_less{}
         );
         extremal->set_user_index(
             (i == most_forward_FKL_idx)?forward_FKL_idx:unof_idx
         );
       }
       if(
           extremal != end(jet_partons)
           && !pass_extremal_cuts(*extremal, jets[i])
       ){
         weight_ = 0;
         return {};
       }
     }
     assert(tagged_FKL_extremal(jet_partons));
     std::sort(begin(jet_partons), end(jet_partons), rapidity_less{});
     if(
         !extremal_ok(jet_partons)
         || !split_preserved_jets(jets, jet_partons)
     ){
       weight_ = 0.;
       return {};
     }
     return jet_partons;
   }
 
   bool PhaseSpacePoint::extremal_ok(
       std::vector<fastjet::PseudoJet> const & partons
   ) const{
     assert(std::is_sorted(begin(partons), end(partons), rapidity_less{}));
     if(unob_ && partons.front().user_index() !=  unob_idx) return false;
     if(unof_ && partons.back().user_index() !=  unof_idx) return false;
     return
       most_backward_FKL(partons).user_index() == backward_FKL_idx
       && most_forward_FKL(partons).user_index() == forward_FKL_idx;
   }
 
   bool PhaseSpacePoint::split_preserved_jets(
         std::vector<fastjet::PseudoJet> const & jets,
         std::vector<fastjet::PseudoJet> const & jet_partons
   ) const{
     assert(std::is_sorted(begin(jets), end(jets), rapidity_less{}));
 
     const auto split_jets = sorted_by_rapidity(cluster_jets(jet_partons));
     // this can happen if two overlapping jets
     // are both split into more than one parton
     if(split_jets.size() != jets.size()) return false;
     for(size_t i = 0; i < split_jets.size(); ++i){
       // this can happen if there are two overlapping jets
       // and a parton is assigned to the "wrong" jet
       if(!nearby_ep(jets[i].rapidity(), split_jets[i].rapidity(), 1e-2)){
         return false;
       }
     }
     return true;
   }
 
   template<class Particle>
   Particle const & PhaseSpacePoint::most_backward_FKL(
       std::vector<Particle> const & partons
   ) const{
     return partons[0 + unob_];
   }
 
   template<class Particle>
   Particle const & PhaseSpacePoint::most_forward_FKL(
       std::vector<Particle> const & partons
   ) const{
     const size_t idx = partons.size() - 1 - unof_;
     assert(idx < partons.size());
     return partons[idx];
   }
 
   template<class Particle>
   Particle & PhaseSpacePoint::most_backward_FKL(
       std::vector<Particle> & partons
   ) const{
     return partons[0 + unob_];
   }
 
   template<class Particle>
   Particle & PhaseSpacePoint::most_forward_FKL(
       std::vector<Particle> & partons
   ) const{
     const size_t idx = partons.size() - 1 - unof_;
     assert(idx < partons.size());
     return partons[idx];
   }
 
   namespace {
     bool contains_idx(
         fastjet::PseudoJet const & jet, fastjet::PseudoJet const & parton
     ){
       auto const & constituents = jet.constituents();
       const int idx = parton.user_index();
       return std::find_if(
           begin(constituents), end(constituents),
           [idx](fastjet::PseudoJet const & con){return con.user_index() == idx;}
       ) != end(constituents);
     }
   }
 
   /**
    * final jet test:
    *   - number of jets must match Born kinematics
    *   - no partons designated as nonjet may end up inside jets
    *   - all other outgoing partons *must* end up inside jets
    *   - the extremal (in rapidity) partons must be inside the extremal jets
    *   - rapidities must be the same (by construction)
    */
   bool PhaseSpacePoint::jets_ok(
       std::vector<fastjet::PseudoJet> const & Born_jets,
       std::vector<fastjet::PseudoJet> const & partons
   ) const{
     fastjet::ClusterSequence cs(partons, param_.jet_param.def);
     const auto jets = sorted_by_rapidity(cs.inclusive_jets(param_.jet_param.min_pt));
     if(jets.size() != Born_jets.size()) return false;
     int in_jet = 0;
     for(size_t i = 0; i < jets.size(); ++i){
       assert(jets[i].has_constituents());
       for(auto && parton: jets[i].constituents()){
         if(is_nonjet_parton(parton)) return false;
       }
       in_jet += jets[i].constituents().size();
     }
     const int expect_in_jet = std::count_if(
         partons.cbegin(), partons.cend(), is_jet_parton
     );
     if(in_jet != expect_in_jet) return false;
     // note that PseudoJet::contains does not work here
     if(! (
            contains_idx(most_backward_FKL(jets), most_backward_FKL(partons))
            &&  contains_idx(most_forward_FKL(jets), most_forward_FKL(partons))
        )) return false;
     if(unob_ && !contains_idx(jets.front(), partons.front())) return false;
     if(unof_ && !contains_idx(jets.back(), partons.back())) return false;
     for(size_t i = 0; i < jets.size(); ++i){
       assert(nearby_ep(jets[i].rapidity(), Born_jets[i].rapidity(), 1e-2));
     }
     return true;
   }
 
   void PhaseSpacePoint::reconstruct_incoming(
       std::array<Particle, 2> const & Born_incoming
   ){
     std::tie(incoming_[0].p, incoming_[1].p) = incoming_momenta(outgoing_);
     for(size_t i = 0; i < incoming_.size(); ++i){
       incoming_[i].type = Born_incoming[i].type;
     }
     assert(momentum_conserved());
   }
 
   double PhaseSpacePoint::phase_space_normalisation(
       int num_Born_jets, int num_out_partons
   ) const{
     return pow(16*pow(M_PI,3), num_Born_jets - num_out_partons);
   }
 
   bool PhaseSpacePoint::momentum_conserved() const{
     fastjet::PseudoJet diff;
     for(auto const & in: incoming()) diff += in.p;
     const double norm = diff.E();
     for(auto const & out: outgoing()) diff -= out.p;
     return nearby(diff, fastjet::PseudoJet{}, norm);
   }
 
 } //namespace RHEJ
diff --git a/src/resummation_jet_momenta.cc b/src/resummation_jet_momenta.cc
index 61206a0..7d36db4 100644
--- a/src/resummation_jet_momenta.cc
+++ b/src/resummation_jet_momenta.cc
@@ -1,218 +1,42 @@
 #include <stdlib.h>
 #include <stdio.h>
 #include <math.h>
 #include <vector>
 #include <array>
 #include <algorithm>
 
 #include "RHEJ/resummation_jet_momenta.hh"
 #include "RHEJ/utility.hh"
 #include "RHEJ/gsl_wrapper.hh"
 
+namespace RHEJ{
 
-namespace {
-  using namespace gsl;
-
-  enum Coordinate{
-    x = 0,
-    y = 1,
-  };
-
-  struct BornParameters{
-    std::vector< std::array<double, 2> > pt_born;
-    std::array<double, 2> q;
-  };
-
-  double pt_abs(double px, double py){
-    return sqrt(px*px + py*py);
-  }
-
-  //! calculate momentum difference for jets
-  /**
-   *  After reshuffling, we have the condition
-   *  Delta = pt_born - pt_res + q* |pt_res|/P_perp = 0
-   *  for each jet, where P_perp is the sum of |pt_res| over all jets
-   *  This function calculates Delta and stores the result in diff
-   *
-   *  Since the gsl_vectors are one-dimensional, indices are a bit funny;
-   *  diff->data[2*i + X]
-   *  corresponds to the X component of the momentum vector for jet i
-   */
-  int calc_jet_diff(const gsl_vector * pt_resum, void *data, gsl_vector * diff){
-    assert(diff->size == pt_resum->size);
-    assert(diff->size % 2 == 0);
-    auto param = static_cast<BornParameters const *>(data);
-    auto const & pt_born = param->pt_born;
-    auto pt_res = pt_resum->data;
-    auto const & q = param->q;
-    const size_t n_jets = pt_resum->size/2;
-
-    double P_perp = 0.;
-    for(size_t jet = 0; jet < n_jets; ++jet){
-      P_perp += pt_abs(pt_res[2*jet + x], pt_res[2*jet + y]);
-    }
-
-    for(size_t jet = 0; jet < n_jets; ++jet){
-      const double pt_res_abs = pt_abs(pt_res[2*jet + x], pt_res[2*jet + y]);
-      for(Coordinate X: {x,y}){
-        diff->data[2*jet + X] =
-          pt_born[jet][X] - pt_res[2*jet + X] - q[X]*pt_res_abs/P_perp;
-      }
-    }
-
-    return GSL_SUCCESS;
-  }
-
-  // computes resummation jet pt from Born jet pt
-  // if this fails an empty vector is returned
-  std::vector< std::array<double ,2> > reshuffle(BornParameters const & p){
-    constexpr int max_iterations = 1000;
-    const size_t n_jets = p.pt_born.size();
-
-    gsl_multiroot_function f = {
-      &calc_jet_diff, 2*n_jets,
-      const_cast<BornParameters *>(&p)
-    };
-    Vector pt_resum{2*n_jets};
-    // initial values for solver - resummation pt = Born pt
-    for (size_t jet = 0; jet < n_jets; ++jet) {
-      pt_resum[2*jet+x] = p.pt_born[jet][x];
-      pt_resum[2*jet+y] = p.pt_born[jet][y];
-    }
-    MultirootFsolver solver{
-      gsl_multiroot_fsolver_hybrids,
-      &f, std::move(pt_resum)
-    };
-
-    // solve equations
-    int status = GSL_CONTINUE;
-    for(
-        int iterations = 1;
-        status == GSL_CONTINUE && iterations < max_iterations;
-        ++iterations
-    ){
-      status = solver.iterate();
-      if(status == GSL_EBADFUNC || status == GSL_ENOPROG) return {};
-      status = solver.test_residual(1e-7);
-    }
-    if(status != GSL_SUCCESS) return {};
-
-    std::vector< std::array<double ,2> > res_pt(n_jets);
-    for(size_t jet = 0; jet < n_jets; ++jet) {
-      res_pt[jet][x] = gsl_vector_get(solver.x(), 2*jet + x);
-      res_pt[jet][y] = gsl_vector_get(solver.x(), 2*jet + y);
-    }
-    return res_pt;
-  }
-
-    // check that pt_i^B == pt_i + qt_i for each jet
-    void assert_pt_conservation(
-        std::vector<fastjet::PseudoJet> const & jetvects,
-        fastjet::PseudoJet const &  qperp,
-        std::vector<fastjet::PseudoJet> const & shuffledmomenta
-    ){
-      RHEJ::ignore(jetvects, qperp, shuffledmomenta);
-#ifndef NDEBUG
-      assert(jetvects.size() == shuffledmomenta.size());
-      double Pperp = 0;
-      for(auto const & p: shuffledmomenta) Pperp += p.perp();
-      for(size_t i = 0; i < jetvects.size(); ++i){
-        const auto qperp_i = qperp*shuffledmomenta[i].perp()/Pperp;
-        const auto pdiff = jetvects[i] - shuffledmomenta[i] - qperp_i;
-        assert(RHEJ::nearby_ep(pdiff.px(), 0, 1e-5));
-        assert(RHEJ::nearby_ep(pdiff.py(), 0, 1e-5));
-      }
-#endif
-    }
-
-  // for "old" reshuffling p^B = p + q*|p|/P
-  std::vector<fastjet::PseudoJet> jet_momenta_linear_in_born(
-      std::vector<fastjet::PseudoJet> const & p_born,
-      fastjet::PseudoJet const & q
-  ) {
-    std::vector<fastjet::PseudoJet> p_res;
-    p_res.reserve(p_born.size());
-
-    BornParameters r;
-    r.q[x] = q.px();
-    r.q[y] = q.py();
-
-    r.pt_born.resize(p_born.size());
-    for (size_t jet = 0; jet < p_born.size(); ++jet) {
-      r.pt_born[jet][x] = p_born[jet].px();
-      r.pt_born[jet][y] = p_born[jet].py();
-    }
-
-    const auto pt_reshuffled = reshuffle(r);
-    if(pt_reshuffled.empty()) return {};
-
-    // Construct the new 4-momenta
-    for (size_t jet = 0; jet < p_born.size(); ++jet) {
-      const double px = pt_reshuffled[jet][x];
-      const double py = pt_reshuffled[jet][y];
-      const double pperp = sqrt(px*px + py*py);
-      // keep the rapidities fixed
-      const double pz = pperp*sinh(p_born[jet].rapidity());
-      const double E = pperp*cosh(p_born[jet].rapidity());
-      p_res.emplace_back(px, py, pz, E);
-      assert(
-          RHEJ::nearby_ep(
-              p_res.back().rapidity(),
-              p_born[jet].rapidity(),
-              1e-5
-          )
-      );
-    }
-
-    assert_pt_conservation(p_born, q, p_res);
-
-    return p_res;
-  }
-
-  // for "new" reshuffling p^B = p + q*|p^B|/P^B
-  std::vector<fastjet::PseudoJet> jet_momenta_linear_in_resummed(
+  std::vector<fastjet::PseudoJet> resummation_jet_momenta(
       std::vector<fastjet::PseudoJet> const & p_born,
       fastjet::PseudoJet const & q
   ) {
+    // for "new" reshuffling p^B = p + q*|p^B|/P^B
     double Pperp_born = 0.;
     for(auto const & p: p_born) Pperp_born += p.perp();
 
     std::vector<fastjet::PseudoJet> p_res;
     p_res.reserve(p_born.size());
     for(auto & pB: p_born) {
       const double px = pB.px() - q.px()*pB.perp()/Pperp_born;
       const double py = pB.py() - q.py()*pB.perp()/Pperp_born;
       const double pperp = sqrt(px*px + py*py);
       // keep the rapidities fixed
       const double pz = pperp*sinh(pB.rapidity());
       const double E = pperp*cosh(pB.rapidity());
       p_res.emplace_back(px, py, pz, E);
       assert(
           RHEJ::nearby_ep(
               p_res.back().rapidity(),
               pB.rapidity(),
               1e-5
           )
       );
     }
     return p_res;
   }
 }
-
-namespace RHEJ{
-
-  std::vector<fastjet::PseudoJet> resummation_jet_momenta(
-      std::vector<fastjet::PseudoJet> const & p_born,
-      fastjet::PseudoJet const & q,
-      ReshufflingAlgorithm algo
-  ) {
-    switch(algo) {
-    case ReshufflingAlgorithm::linear_in_born:
-      return jet_momenta_linear_in_born(p_born, q);
-    case ReshufflingAlgorithm::linear_in_resummed:
-      return jet_momenta_linear_in_resummed(p_born, q);
-    default:;
-    }
-    throw std::logic_error{"unreachable"};
-  }
-}