diff --git a/FixedOrderGen/src/PhaseSpacePoint.cc b/FixedOrderGen/src/PhaseSpacePoint.cc
index 50548f4..09b787b 100644
--- a/FixedOrderGen/src/PhaseSpacePoint.cc
+++ b/FixedOrderGen/src/PhaseSpacePoint.cc
@@ -1,591 +1,605 @@
 #include "PhaseSpacePoint.hh"
 
 #include <random>
 #include <algorithm>
 
 #include "RHEJ/kinematics.hh"
 #include "RHEJ/utility.hh"
 #include "RHEJ/exceptions.hh"
 
 #include "Process.hh"
 
 #include <CLHEP/Random/Randomize.h>
 #include <CLHEP/Random/RanluxEngine.h>
 
 using namespace RHEJ;
 
 namespace HEJFOG{
 
   static_assert(
       std::numeric_limits<double>::has_quiet_NaN,
       "no quiet NaN for double"
   );
   constexpr double NaN = std::numeric_limits<double>::quiet_NaN();
   RHEJ::UnclusteredEvent to_UnclusteredEvent(PhaseSpacePoint const & psp){
     RHEJ::UnclusteredEvent result;
     result.incoming = psp.incoming();
     std::sort(
         begin(result.incoming), end(result.incoming),
         [](Particle o1, Particle o2){return o1.p.pz()<o2.p.pz();}
     );
     assert(result.incoming.size() == 2);
     result.outgoing = psp.outgoing();
     assert(
         std::is_sorted(
             begin(result.outgoing), end(result.outgoing),
             RHEJ::rapidity_less{}
         )
     );
     assert(result.outgoing.size() >= 2);
     result.decays = psp.decays();
     result.central.mur = NaN;
     result.central.muf = NaN;
     result.central.weight = psp.weight();
     return result;
   }
 
   namespace{
     bool can_swap_to_uno(
         RHEJ::Particle const & p1, RHEJ::Particle const & p2
     ){
       return is_parton(p1)
         && p1.type != pid::gluon
         && p2.type == pid::gluon;
     }
 
     /** assumes FKL configurations between first and last,
      * else there can be a quark in a non-extreme position
      * e.g. uno configuration gqg would pass
      */
     bool can_change_to_qqx(
       std::vector<RHEJ::Particle>::const_iterator first,
       std::vector<RHEJ::Particle>::const_iterator last){
       return 1 < std::count_if(first, last, [](Particle const & p)
         {return p.type == pid::gluon;});
     }
   }
 
   void PhaseSpacePoint::maybe_turn_to_subl(
       double chance,
       Process const & proc,
       RHEJ::RNG & ran
   ){
     if(proc.njets <= 2) return;
     assert(outgoing_.size() >= 2);
 
     // decide what kind of subleading process is allowed
     bool allow_uno = false;
     const size_t nout = outgoing_.size();
     const bool can_be_uno_backward = can_swap_to_uno(
       outgoing_[0], outgoing_[1]
     );
     const bool can_be_uno_forward = can_swap_to_uno(
       outgoing_[nout-1], outgoing_[nout-2]
     );
     allow_uno = can_be_uno_backward || can_be_uno_forward;
 
     bool allow_qqx = false;
     if(proc.boson && is_AWZ_boson(*(proc.boson))) {
       allow_qqx = can_change_to_qqx(outgoing_.cbegin(), outgoing_.cend());
       if(incoming_[0].type == pid::gluon && incoming_[1].type == pid::gluon) {
         /// enforce qqx for initial gg
         allow_uno = false;
         chance = 1.;
       }
     }
 
     if(!allow_uno && !allow_qqx) return;
     if(ran.flat() < chance){
       weight_ /= chance;
       if(allow_uno && !allow_qqx){
           turn_to_uno(can_be_uno_backward, can_be_uno_forward, ran);
       } else if (!allow_uno && allow_qqx) {
         std::cout << "only qqx" << std::endl;
         turn_to_qqx(ran);
       } else {
         assert( allow_uno && allow_qqx);
         std::cout << "both qqx and uno" << std::endl;
         if(ran.flat() < 0.5) turn_to_uno(can_be_uno_backward, can_be_uno_forward, ran);
         else turn_to_qqx(ran);
         weight_ *= 2.;
       }
     } else weight_ /= 1 - chance;
 
   }
 
   void PhaseSpacePoint::turn_to_uno(
       const bool can_be_uno_backward, const bool can_be_uno_forward,
       RHEJ::RNG & ran
   ){
     if(!can_be_uno_backward && !can_be_uno_forward) return;
     const size_t nout = outgoing_.size();
     if(can_be_uno_backward && can_be_uno_forward){
       if(ran.flat() < 0.5){
         std::swap(outgoing_[0].type, outgoing_[1].type);
       } else {
         std::swap(outgoing_[nout-1].type, outgoing_[nout-2].type);
       }
       weight_ *= 2.;
     } else if(can_be_uno_backward){
       std::swap(outgoing_[0].type, outgoing_[1].type);
     } else {
       assert(can_be_uno_forward);
       std::swap(outgoing_[nout-1].type, outgoing_[nout-2].type);
     }
   }
 
   void PhaseSpacePoint::turn_to_qqx(RHEJ::RNG & ran){
     /// @TODO implement
     std::cerr << "turn_to_qqx not implemented yet. Here is a random number instead "
       << ran.flat() <<".\n";
   }
 
   template<class ParticleMomenta>
   fastjet::PseudoJet PhaseSpacePoint::gen_last_momentum(
       ParticleMomenta const & other_momenta,
       const double mass_square, const double y
   ) const {
     std::array<double,2> pt{0.,0.};
     for (auto const & p: other_momenta) {
       pt[0]-= p.px();
       pt[1]-= p.py();
     }
 
     const double mperp = sqrt(pt[0]*pt[0]+pt[1]*pt[1]+mass_square);
     const double pz=mperp*sinh(y);
     const double E=mperp*cosh(y);
 
     return {pt[0], pt[1], pz, E};
   }
 
   PhaseSpacePoint::PhaseSpacePoint(
     Process const & proc,
     JetParameters const & jet_param,
     RHEJ::PDF & pdf, double E_beam,
     double subl_chance,
     HiggsProperties const & h,
     RHEJ::RNG & ran
   )
   {
     assert(proc.njets >= 2);
     status_ = good;
     weight_ = 1;
 
     const int nout = proc.njets + (proc.boson?1:0);
     outgoing_.reserve(nout);
 
     // generate parton momenta
     const bool is_pure_jets = !proc.boson;
     auto partons = gen_LO_partons(
         proc.njets, is_pure_jets, jet_param, E_beam, ran
     );
     // pre fill flavour with gluons
     for(auto&& p_out: partons) {
       outgoing_.emplace_back(Particle{pid::gluon, std::move(p_out)});
     }
     if(status_ != good) return;
 
     if(proc.boson){
       switch (*proc.boson) {
       case pid::Higgs:{
         auto Hparticle=gen_boson(pid::higgs, h.mass, h.width, ran);
         auto pos=std::upper_bound(
             begin(outgoing_),end(outgoing_),Hparticle,rapidity_less{}
         );
         outgoing_.insert(pos, Hparticle);
         if(! h.decays.empty()){
           const int boson_idx = std::distance(begin(outgoing_), pos);
           decays_.emplace(
               boson_idx,
               decay_boson(outgoing_[boson_idx], h.decays, ran)
           );
         }
         break;
       }
       case pid::Wp:{
         /// @TODO implement, currently this is just a relabel Higgs
         ///@{
         std::cout << "Emission of Wp not implemented yet.\nThis is just a place holder" << std::endl;
         auto Hparticle=gen_boson(pid::Wp, h.mass, h.width, ran);
         auto pos=std::upper_bound(
             begin(outgoing_),end(outgoing_),Hparticle,rapidity_less{}
         );
         outgoing_.insert(pos, Hparticle);
         if(! h.decays.empty()){
           const int boson_idx = std::distance(begin(outgoing_), pos);
           decays_.emplace(
               boson_idx,
               decay_boson(outgoing_[boson_idx], h.decays, ran)
           );
         }
         ///@}
         break;
       }
       case pid::Wm:{
         /// @TODO implement, currently this is just a relabel Higgs
         ///@{
         std::cout << "Emission of Wm not implemented yet.\nThis is just a place holder" << std::endl;
         auto Hparticle=gen_boson(pid::higgs, h.mass, h.width, ran);
         auto pos=std::upper_bound(
             begin(outgoing_),end(outgoing_),Hparticle,rapidity_less{}
         );
         outgoing_.insert(pos, Hparticle);
         if(! h.decays.empty()){
           const int boson_idx = std::distance(begin(outgoing_), pos);
           decays_.emplace(
               boson_idx,
               decay_boson(outgoing_[boson_idx], h.decays, ran)
           );
         }
         ///@}
         break;
       }
       case pid::photon:
       case pid::Z:
       default:
         throw std::logic_error("Emission of boson of unsupported type");
       }
     }
     // normalisation of momentum-conserving delta function
     weight_ *= pow(2*M_PI, 4);
 
+    /// @TODO currently gg->Wgg allowed, change this!
     reconstruct_incoming(proc.incoming, pdf, E_beam, jet_param.min_pt, ran);
     if(status_ != good) return;
     // set outgoing states
     most_backward_FKL(outgoing_).type = incoming_[0].type;
     most_forward_FKL(outgoing_).type = incoming_[1].type;
 
-    /// @TODO if W && only gluon: subl_change = 1
-
     maybe_turn_to_subl(subl_chance, proc, ran);
+
+    #ifndef NDEBUG
+    if(proc.boson && is_AWZ_boson(*proc.boson)){
+      // check that W has a quark to couple to
+      auto const partons = filter_partons(outgoing_);
+      /// @TODO extend assert to also check flavour? Maybe easier in separate cmake test
+      assert(partons.front().type != pid::gluon
+        || partons.back().type != pid::gluon  // extremal quark
+        || ( (partons.size() > 3 )            // or central qqx
+          && ( 1<std::count_if(partons.cbegin()+1, partons.cend()-1,
+                [](Particle const & p) {return p.type != pid::gluon;})
+              ))
+      );
+    }
+    #endif
   }
 
   double PhaseSpacePoint::gen_hard_pt(
       int np , double ptmin, double ptmax, double y,
       RHEJ::RNG & ran
   ) {
     // heuristic parameters for pt sampling
     const double ptpar = ptmin + np/5.;
     const double arg_small_y = atan((ptmax - ptmin)/ptpar);
     const double y_cut = 3.;
 
     const double r1 = ran.flat();
     if(y < y_cut){
       const double pt = ptmin + ptpar*tan(r1*arg_small_y);
       const double temp = cos(r1*arg_small_y);
       weight_ *= pt*ptpar*arg_small_y/(temp*temp);
       return pt;
     }
 
     const double ptpar2 = ptpar/(1 + 5*(y-y_cut));
     const double temp = 1. - std::exp((ptmin-ptmax)/ptpar2);
     const double pt = ptmin - ptpar2*std::log(1-r1*temp);
     weight_ *= pt*ptpar2*temp/(1-r1*temp);
     return pt;
   }
 
   double PhaseSpacePoint::gen_soft_pt(int np, double max_pt, RHEJ::RNG & ran) {
     constexpr double ptpar = 4.;
 
     const double r = ran.flat();
     const double pt = max_pt + ptpar/np*std::log(r);
     weight_ *= pt*ptpar/(np*r);
     return pt;
   }
 
   double PhaseSpacePoint::gen_parton_pt(
       int count, JetParameters const & jet_param, double max_pt, double y,
       RHEJ::RNG & ran
   ) {
     constexpr double p_small_pt = 0.02;
 
     if(! jet_param.peak_pt) {
        return gen_hard_pt(count, jet_param.min_pt, max_pt, y, ran);
     }
     const double r = ran.flat();
     if(r > p_small_pt) {
       weight_ /= 1. - p_small_pt;
       return gen_hard_pt(count, *jet_param.peak_pt, max_pt, y, ran);
     }
     weight_ /= p_small_pt;
     const double pt =  gen_soft_pt(count, *jet_param.peak_pt, ran);
     if(pt < jet_param.min_pt) {
       weight_=0.0;
       status_ = not_enough_jets;
       return jet_param.min_pt;
     }
     return pt;
   }
 
   std::vector<fastjet::PseudoJet> PhaseSpacePoint::gen_LO_partons(
       int np, bool is_pure_jets,
       JetParameters const & jet_param,
       double max_pt,
       RHEJ::RNG & ran
   ){
     if (np<2) throw std::invalid_argument{"Not enough partons in gen_LO_partons"};
 
     weight_ /= pow(16.*pow(M_PI,3),np);
     weight_ /= std::tgamma(np+1); //remove rapidity ordering
     std::vector<fastjet::PseudoJet> partons;
     partons.reserve(np);
     for(int i = 0; i < np; ++i){
       const double y = -jet_param.max_y + 2*jet_param.max_y*ran.flat();
       weight_ *= 2*jet_param.max_y;
 
       const bool is_last_parton = i+1 == np;
       if(is_pure_jets && is_last_parton) {
         constexpr double parton_mass_sq = 0.;
         partons.emplace_back(gen_last_momentum(partons, parton_mass_sq, y));
         break;
       }
 
       const double phi = 2*M_PI*ran.flat();
       weight_ *= 2.0*M_PI;
 
       const double pt = gen_parton_pt(np, jet_param, max_pt, y, ran);
       if(weight_ == 0.0) return {};
 
       partons.emplace_back(fastjet::PtYPhiM(pt, y, phi));
       assert(jet_param.min_pt <= partons[i].pt());
       assert(partons[i].pt() <= max_pt+1e-5);
     }
     // Need to check that at LO, the number of jets = number of partons;
     fastjet::ClusterSequence cs(partons, jet_param.def);
     auto cluster_jets=cs.inclusive_jets(jet_param.min_pt);
     if (cluster_jets.size()!=unsigned(np)){
       weight_=0.0;
       status_ = not_enough_jets;
       return {};
     }
 
     std::sort(begin(partons), end(partons), rapidity_less{});
 
     return partons;
   }
 
   Particle PhaseSpacePoint::gen_boson(
       RHEJ::ParticleID bosonid, double mass, double width,
       RHEJ::RNG & ran
   ){
     // Usual phase space measure
     weight_ /= 16.*pow(M_PI, 3);
 
     // Generate a y Gaussian distributed around 0
     // TODO: magic number only for Higgs
     const double y = random_normal(1.6, ran);
     const double r1 = ran.flat();
     const double sH = mass*(
         mass + width*tan(M_PI/2.*r1 + (r1-1.)*atan(mass/width))
     );
 
     auto p = gen_last_momentum(outgoing_, sH, y);
 
     return Particle{bosonid, std::move(p)};
   }
 
   Particle const & PhaseSpacePoint::most_backward_FKL(
       std::vector<Particle> const & partons
   ) const{
     if(!RHEJ::is_parton(partons[0])) return partons[1];
     return partons[0];
   }
 
   Particle const & PhaseSpacePoint::most_forward_FKL(
       std::vector<Particle> const & partons
   ) const{
     const size_t last_idx = partons.size() - 1;
     if(!RHEJ::is_parton(partons[last_idx])) return partons[last_idx-1];
     return partons[last_idx];
   }
 
   Particle & PhaseSpacePoint::most_backward_FKL(
       std::vector<Particle> & partons
   ) const{
     if(!RHEJ::is_parton(partons[0])) return partons[1];
     return partons[0];
   }
 
   Particle & PhaseSpacePoint::most_forward_FKL(
       std::vector<Particle> & partons
   ) const{
     const size_t last_idx = partons.size() - 1;
     if(!RHEJ::is_parton(partons[last_idx])) return partons[last_idx-1];
     return partons[last_idx];
   }
 
   void PhaseSpacePoint::reconstruct_incoming(
       std::array<RHEJ::ParticleID, 2> const & ids,
       RHEJ::PDF & pdf, double E_beam,
       double uf,
       RHEJ::RNG & ran
   ){
     std::tie(incoming_[0].p, incoming_[1].p) = incoming_momenta(outgoing_);
     // calculate xa, xb
     const double sqrts=2*E_beam;
     const double xa=(incoming_[0].p.e()-incoming_[0].p.pz())/sqrts;
     const double xb=(incoming_[1].p.e()+incoming_[1].p.pz())/sqrts;
     // abort if phase space point is outside of collider energy reach
     if (xa>1. || xb>1.){
       weight_=0;
       status_ = too_much_energy;
       return;
     }
     // pick pdfs
     /** @TODO
      *  ufa, ufb don't correspond to our final scale choice.
      *  The reversed HEJ scale generators currently expect a full event as input,
      *  so fixing this is not completely trivial
      */
     if(ids[0] == pid::proton || ids[0] == pid::p_bar){
       const double ufa=uf;
       incoming_[0].type = generate_incoming_id(xa, ufa, pdf, ran);
     }
     else {
       incoming_[0].type = ids[0];
     }
     if(ids[1] == pid::proton || ids[1] == pid::p_bar){
       const double ufb=uf;
       incoming_[1].type = generate_incoming_id(xb, ufb, pdf, ran);
     }
     else {
       incoming_[1].type = ids[1];
     }
     assert(momentum_conserved(1e-7));
   }
 
   RHEJ::ParticleID PhaseSpacePoint::generate_incoming_id(
       double x, double uf, RHEJ::PDF & pdf,
       RHEJ::RNG & ran
   ){
     const double pdfg=fabs(pdf.pdfpt(0,x,uf,pid::gluon));
     const double pdfu=fabs(pdf.pdfpt(0,x,uf,pid::up));
     const double pdfd=fabs(pdf.pdfpt(0,x,uf,pid::down));
     const double pdfux=fabs(pdf.pdfpt(0,x,uf,pid::u_bar));
     const double pdfdx=fabs(pdf.pdfpt(0,x,uf,pid::d_bar));
     const double pdfc=fabs(pdf.pdfpt(0,x,uf,pid::charm));
     const double pdfs=fabs(pdf.pdfpt(0,x,uf,pid::strange));
     const double pdfsx=fabs(pdf.pdfpt(0,x,uf,pid::s_bar));
     const double pdfb=fabs(pdf.pdfpt(0,x,uf,pid::b));
 
     const double pdftot=pdfg+4.0/9.0*(pdfu + pdfd + pdfux + pdfdx +pdfs +pdfsx + 2.0*(pdfc +pdfb ));
     const double r1=pdftot*ran.flat();
     double sum;
 
     if (r1<(sum=pdfg)) {
       weight_*=pdftot/pdfg;
       return pid::gluon;
     }
     if (r1<(sum+=(4./9.)*pdfu)) {
       weight_*=pdftot/((4./9.)*pdfu);
       return pid::up;
     }
     else if (r1<(sum+=(4./9.)*pdfd)) {
       weight_*=pdftot/((4./9.)*pdfd);
       return pid::down;
     }
     else if (r1<(sum+=(4./9.)*pdfux)) {
       weight_*=pdftot/((4./9.)*pdfux);
       return pid::u_bar;
     }
     else if (r1<(sum+=(4./9.)*pdfdx)) {
       weight_*=pdftot/((4./9.)*pdfdx);
       return pid::d_bar;
     }
     else if (r1<(sum+=(4./9.)*pdfc)) {
       weight_*=pdftot/((4./9.)*pdfc);
       return pid::c;
     }
     else if (r1<(sum+=(4./9.)*pdfc)){
       weight_*=pdftot/((4./9.)*pdfc);
       return pid::c_bar;
     }
     else if (r1<(sum+=(4./9.)*pdfs)) {
       weight_*=pdftot/((4./9.)*pdfs);
       return pid::s;
     }
     else if (r1<(sum+=(4./9.)*pdfsx)) {
       weight_*=pdftot/((4./9.)*pdfsx);
       return pid::s_bar;
     }
     else if (r1<(sum+=(4./9.)*pdfb)) {
       weight_*=pdftot/((4./9.)*pdfb);
       return pid::b;
     }
     else if (r1<=(sum+=(4./9.)*pdfb)) {
       weight_*=pdftot/((4./9.)*pdfb);
       return pid::b_bar;
     }
     std::cerr << "Error in choosing incoming parton: "<<x<<" "<<uf<<" "<<sum<<" "<<pdftot<<" "<<r1
       <<" "<<pdfg+4./9.*(pdfu+pdfux+pdfd+pdfdx+pdfs+pdfsx+2.*(pdfc+pdfb))<<std::endl;
     throw std::logic_error{"Failed to choose parton flavour"};
   }
 
   double PhaseSpacePoint::random_normal(
       double stddev,
       RHEJ::RNG & ran
   ){
     const double r1 = ran.flat();
     const double r2 = ran.flat();
     const double lninvr1 = -log(r1);
     const double result = stddev*sqrt(2.*lninvr1)*cos(2.*M_PI*r2);
     weight_ *= exp(result*result/(2*stddev*stddev))*sqrt(2.*M_PI)*stddev;
     return result;
   }
 
   bool PhaseSpacePoint::momentum_conserved(double ep) const{
     fastjet::PseudoJet diff;
     for(auto const & in: incoming()) diff += in.p;
     for(auto const & out: outgoing()) diff -= out.p;
     return nearby_ep(diff, fastjet::PseudoJet{}, ep);
   }
 
   Decay PhaseSpacePoint::select_decay_channel(
       std::vector<Decay> const & decays,
       RHEJ::RNG & ran
   ){
     double br_total = 0.;
     for(auto const & decay: decays) br_total += decay.branching_ratio;
     // adjust weight
     // this is given by (channel branching ratio)/(chance to pick channel)
     // where (chance to pick channel) =
     //       (channel branching ratio)/(total branching ratio)
     weight_ *= br_total;
     const double r1 = br_total*ran.flat();
     double br_sum = 0.;
     for(auto const & decay: decays){
       br_sum += decay.branching_ratio;
       if(r1 < br_sum) return decay;
     }
     throw std::logic_error{"unreachable"};
   }
 
   std::vector<Particle> PhaseSpacePoint::decay_boson(
       RHEJ::Particle const & parent,
       std::vector<Decay> const & decays,
       RHEJ::RNG & ran
   ){
     const auto channel = select_decay_channel(decays, ran);
     if(channel.products.size() != 2){
       throw RHEJ::not_implemented{
         "only decays into two particles are implemented"
       };
     }
     std::vector<Particle> decay_products(channel.products.size());
     for(size_t i = 0; i < channel.products.size(); ++i){
       decay_products[i].type = channel.products[i];
     }
     // choose polar and azimuth angle in parent rest frame
     const double E = parent.m()/2;
     const double theta = 2.*M_PI*ran.flat();
     const double cos_phi = 2.*ran.flat()-1.;
     const double sin_phi = sqrt(1. - cos_phi*cos_phi);  // Know 0 < phi < pi
     const double px = E*cos(theta)*sin_phi;
     const double py = E*sin(theta)*sin_phi;
     const double pz = E*cos_phi;
     decay_products[0].p.reset(px, py, pz, E);
     decay_products[1].p.reset(-px, -py, -pz, E);
     for(auto & particle: decay_products) particle.p.boost(parent.p);
     return decay_products;
   }
 }