diff --git a/FixedOrderGen/src/PhaseSpacePoint.cc b/FixedOrderGen/src/PhaseSpacePoint.cc
index a8381bd..31b00b3 100644
--- a/FixedOrderGen/src/PhaseSpacePoint.cc
+++ b/FixedOrderGen/src/PhaseSpacePoint.cc
@@ -1,456 +1,457 @@
 #include "PhaseSpacePoint.hh"
 
 #include <random>
 
 #include "HEJ/kinematics.hh"
 #include "HEJ/utility.hh"
 #include "HEJ/exceptions.hh"
 
 #include "Process.hh"
 
 #include <CLHEP/Random/Randomize.h>
 #include <CLHEP/Random/RanluxEngine.h>
 
 using namespace HEJ;
 
 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();
   HEJ::UnclusteredEvent to_UnclusteredEvent(PhaseSpacePoint const & psp){
     HEJ::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),
             HEJ::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(
         HEJ::Particle const & p1, HEJ::Particle const & p2
     ){
       return is_parton(p1)
         && p1.type != HEJ::pid::gluon
         && p2.type == HEJ::pid::gluon;
     }
   }
 
   void PhaseSpacePoint::maybe_turn_to_uno(
       double chance,
       HEJ::RNG & ran
   ){
     assert(outgoing_.size() >= 2);
     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]
     );
     if(!can_be_uno_backward && !can_be_uno_forward) return;
     if(ran.flat() < chance){
       weight_ /= chance;
       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);
       }
     }
     else weight_ /= 1 - chance;
   }
 
   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,
     HEJ::PDF & pdf, double E_beam,
     double uno_chance,
     ParticlesPropMap const & particles_properties,
     HEJ::RNG & ran
   )
   {
     assert(proc.njets >= 2);
     if(proc.boson
       && particles_properties.find(*(proc.boson))
         == particles_properties.end())
       throw HEJ::missing_option("Boson "
         +std::to_string(*(proc.boson))+" can't be generated: missing properties");
     status_ = good;
     weight_ = 1;
 
     const int nout = proc.njets + (proc.boson?1:0);
     outgoing_.reserve(nout);
 
     const bool is_pure_jets = !proc.boson;
     auto partons = gen_LO_partons(
         proc.njets, is_pure_jets, jet_param, E_beam, ran
     );
     for(auto&& p_out: partons) {
       outgoing_.emplace_back(Particle{pid::gluon, std::move(p_out)});
     }
     if(status_ != good) return;
 
+    // create boson
     if(proc.boson){
       const auto & boson_prop = particles_properties.at(*proc.boson);
-      auto boson=gen_boson(*proc.boson, boson_prop.mass, boson_prop.width, ran);
-      auto pos=std::upper_bound(
+      auto boson(gen_boson(*proc.boson, boson_prop.mass, boson_prop.width, ran));
+      const auto pos = std::upper_bound(
           begin(outgoing_),end(outgoing_),boson,rapidity_less{}
       );
-      outgoing_.insert(pos, boson);
+      outgoing_.insert(pos, std::move(boson));
       if(! boson_prop.decays.empty()){
         const int boson_idx = std::distance(begin(outgoing_), pos);
         decays_.emplace(
             boson_idx,
             decay_boson(outgoing_[boson_idx], boson_prop.decays, ran)
         );
       }
     }
     // normalisation of momentum-conserving delta function
     weight_ *= pow(2*M_PI, 4);
 
     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;
 
     if(proc.njets > 2) maybe_turn_to_uno(uno_chance, ran);
   }
 
   double PhaseSpacePoint::gen_hard_pt(
       int np , double ptmin, double ptmax, double y,
       HEJ::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, HEJ::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,
       HEJ::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,
       HEJ::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(
       HEJ::ParticleID bosonid, double mass, double width,
       HEJ::RNG & ran
   ){
     if(bosonid != HEJ::pid::Higgs)
       throw HEJ::not_implemented("Production of boson "+std::to_string(bosonid)
         +" not implemented yet.");
     // 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(!HEJ::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(!HEJ::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(!HEJ::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(!HEJ::is_parton(partons[last_idx])) return partons[last_idx-1];
     return partons[last_idx];
   }
 
   void PhaseSpacePoint::reconstruct_incoming(
       std::array<HEJ::ParticleID, 2> const & ids,
       HEJ::PDF & pdf, double E_beam,
       double uf,
       HEJ::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 HEJ scale generators currently expect a full event as input,
      *  so fixing this is not completely trivial
      */
     for(size_t i = 0; i < 2; ++i){
       if(ids[i] == pid::proton || ids[i] == pid::p_bar){
         incoming_[i].type = generate_incoming_id(i, i?xb:xa, uf, pdf, ran);
       }
       else {
         incoming_[i].type = ids[i];
       }
     }
     assert(momentum_conserved(1e-7));
   }
 
   namespace {
     /// particles are ordered, odd = anti
     ParticleID index_to_pid(size_t i){
       if(!i) return pid::gluon;
       return static_cast<ParticleID>(i%2?(i+1)/2:-i/2);
     }
   }
 
   HEJ::ParticleID PhaseSpacePoint::generate_incoming_id(
       size_t const beam_idx, double const x, double const uf,
       HEJ::PDF & pdf, HEJ::RNG & ran
   ){
     std::array<double,11> pdf_wt;
     pdf_wt[0] = fabs(pdf.pdfpt(beam_idx,x,uf,pid::gluon));
     double pdftot = pdf_wt[0];
       for(size_t i = 1; i < pdf_wt.size(); ++i){
       pdf_wt[i] = 4./9.*fabs(pdf.pdfpt(beam_idx,x,uf,index_to_pid(i)));
       pdftot += pdf_wt[i];
     }
     const double r1 = pdftot * ran.flat();
     double sum = 0;
     for(size_t i=0; i < pdf_wt.size(); ++i){
       if (r1 < (sum+=pdf_wt[i])){
         weight_*= pdftot/pdf_wt[i];
         return index_to_pid(i);
       }
     }
     std::cerr << "Error in choosing incoming parton: "<<x<<" "<<uf<<" "
       <<sum<<" "<<pdftot<<" "<<r1<<std::endl;
     throw std::logic_error{"Failed to choose parton flavour"};
   }
 
   double PhaseSpacePoint::random_normal(
       double stddev,
       HEJ::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,
       HEJ::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(
       HEJ::Particle const & parent,
       std::vector<Decay> const & decays,
       HEJ::RNG & ran
   ){
     const auto channel = select_decay_channel(decays, ran);
     if(channel.products.size() != 2){
       throw HEJ::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;
   }
 }
diff --git a/include/HEJ/PDG_codes.hh b/include/HEJ/PDG_codes.hh
index 01dc521..be9a45f 100644
--- a/include/HEJ/PDG_codes.hh
+++ b/include/HEJ/PDG_codes.hh
@@ -1,97 +1,98 @@
 /** \file PDG_codes.hh
  *  \brief Contains the Particle IDs of all relevant SM particles.
  *
  *  Large enumeration included which has multiple entries for potential
  *  alternative names of different particles. There are also functions
  *  which can be used to determine if a particle is a parton or if
  *  it is a non-gluon boson.
  */
 
 #pragma once
 
 #include <string>
 
 namespace HEJ {
 
   //! particle ids according to PDG
   namespace pid {
     //! The possible particle identities. We use PDG IDs as standard.
     enum ParticleID{
       d = 1,                          /*!< Down Quark */
       down = d,                       /*!< Down Quark */
       u = 2,                          /*!< Up Quark */
       up = u,                         /*!< Up Quark */
       s = 3,                          /*!< Strange Quark */
       strange = s,                    /*!< Strange Quark */
       c = 4,                          /*!< Charm Quark */
       charm = c,                      /*!< Charm Quark */
       b = 5,                          /*!< Bottom Quark */
       bottom = b,                     /*!< Bottom Quark */
       t = 6,                          /*!< Top Quark */
       top = t,                        /*!< Top Quark */
       e = 11,                         /*!< Electron */
       electron = e,                   /*!< Electron */
       nu_e = 12,                      /*!< Electron Neutrino */
       electron_neutrino = nu_e,       /*!< Electron neutrino */
       mu = 13,                        /*!< Muon */
       muon = mu,                      /*!< Muon */
       nu_mu = 14,                     /*!< Muon Neutrino */
       muon_neutrino = nu_mu,          /*!< Muon Neutrino */
       tau = 15,                       /*!< Tau */
       nu_tau = 16,                    /*!< Tau Neutrino */
       tau_neutrino = nu_tau,          /*!< Tau Neutrino */
       d_bar = -d,                     /*!< Anti-Down Quark */
       u_bar = -u,                     /*!< Anti-Up quark */
       s_bar = -s,                     /*!< Anti-Strange Quark */
       c_bar = -c,                     /*!< Anti-Charm Quark */
       b_bar = -b,                     /*!< Anti-Bottom Quark */
       t_bar = -t,                     /*!< Anti-Top Quark */
       e_bar = -e,                     /*!< Positron */
+      positron = e_bar,               /*!< Positron */
       nu_e_bar = -nu_e,               /*!< Anti-Electron Neutrino */
       mu_bar = -mu,                   /*!< Anti-Muon */
       nu_mu_bar = -nu_mu,             /*!< Anti-Muon Neutrino */
       tau_bar = -tau,                 /*!< Anti-Tau */
       nu_tau_bar = -nu_tau,           /*!< Anti-Tau Neutrino */
       gluon = 21,                     /*!< Gluon */
       g = gluon,                      /*!< Gluon */
       photon = 22,                    /*!< Photon */
       gamma = photon,                 /*!< Photon */
       Z = 23,                         /*!< Z Boson */
       Wp = 24,                        /*!< W- Boson */
       Wm = -Wp,                        /*!< W+ Boson */
       h = 25,                         /*!< Higgs Boson */
       Higgs = h,                      /*!< Higgs Boson */
       higgs = h,                      /*!< Higgs Boson */
       p = 2212,                       /*!< Proton */
       proton = p,                     /*!< Proton */
       p_bar = -p,                     /*!< Anti-Proton */
     };
 
   }
 
   using ParticleID = pid::ParticleID;
 
   //! Convert a particle name to the corresponding PDG particle ID
   ParticleID to_ParticleID(std::string const & name);
 
   /**
    * \brief Function to determine if particle is a parton
    * @param p              PDG ID of particle
    * @returns              true if the particle is a parton, false otherwise
    */
   inline
   constexpr bool is_parton(ParticleID p){
     return p == pid::gluon || std::abs(p) <= pid::top;
   }
 
   /**
    * \brief function to determine if the particle is a photon, W, Z, or Higgs boson
    * @param id             PDG ID of particle
    * @returns              true if the partice is a A,W,Z, or H, false otherwise
    */
   inline
   constexpr bool is_AWZH_boson(ParticleID id){
     return id == pid::Wm || (id >= pid::photon && id <= pid::Higgs);
   }
 
 }
diff --git a/src/PDG_codes.cc b/src/PDG_codes.cc
index 3dfc576..6dc9379 100644
--- a/src/PDG_codes.cc
+++ b/src/PDG_codes.cc
@@ -1,48 +1,48 @@
 #include "HEJ/PDG_codes.hh"
 
 #include <map>
 #include <iostream>
 
 namespace HEJ{
   ParticleID to_ParticleID(std::string const & name){
     using namespace HEJ::pid;
     static const std::map<std::string, ParticleID> known = {
       {"d", d}, {"down", down}, {"1",static_cast<ParticleID>(1)},
       {"u", u}, {"up", up}, {"2",static_cast<ParticleID>(2)},
       {"s", s}, {"strange", strange}, {"3",static_cast<ParticleID>(3)},
       {"c", c}, {"charm", charm}, {"4",static_cast<ParticleID>(4)},
       {"b", b}, {"bottom", bottom}, {"5",static_cast<ParticleID>(5)},
       {"t", t}, {"top", top}, {"6",static_cast<ParticleID>(6)},
-      {"e", e}, {"electron", electron}, {"11",static_cast<ParticleID>(11)},
+      {"e", e}, {"electron", electron}, {"e-", e}, {"11",static_cast<ParticleID>(11)},
       {"nu_e", nu_e}, {"electron_neutrino", electron_neutrino}, {"12",static_cast<ParticleID>(12)},
-      {"mu", mu}, {"muon", muon}, {"13",static_cast<ParticleID>(13)},
+      {"mu", mu}, {"muon", muon}, {"mu-", mu}, {"13",static_cast<ParticleID>(13)},
       {"nu_mu", nu_mu}, {"muon_neutrino", muon_neutrino}, {"14",static_cast<ParticleID>(14)},
-      {"tau", tau}, {"15",static_cast<ParticleID>(15)},
+      {"tau", tau}, {"tau-", tau}, {"15",static_cast<ParticleID>(15)},
       {"nu_tau", nu_tau}, {"tau_neutrino", tau_neutrino}, {"16",static_cast<ParticleID>(16)},
       {"d_bar", d_bar}, {"-1",static_cast<ParticleID>(-1)},
       {"u_bar", u_bar}, {"-2",static_cast<ParticleID>(-2)},
       {"s_bar", s_bar}, {"-3",static_cast<ParticleID>(-3)},
       {"c_bar", c_bar}, {"-4",static_cast<ParticleID>(-4)},
       {"b_bar", b_bar}, {"-5",static_cast<ParticleID>(-5)},
       {"t_bar", t_bar}, {"-6",static_cast<ParticleID>(-6)},
-      {"e_bar", e_bar}, {"-11",static_cast<ParticleID>(-11)},
+      {"e_bar", e_bar}, {"positron", positron}, {"e+", e_bar}, {"-11",static_cast<ParticleID>(-11)},
       {"nu_e_bar", nu_e_bar}, {"-12",static_cast<ParticleID>(-12)},
-      {"mu_bar", mu_bar}, {"-13",static_cast<ParticleID>(-13)},
+      {"mu_bar", mu_bar}, {"mu+", mu_bar}, {"-13",static_cast<ParticleID>(-13)},
       {"nu_mu_bar", nu_mu_bar}, {"-14",static_cast<ParticleID>(-14)},
-      {"tau_bar", tau_bar}, {"-15",static_cast<ParticleID>(-15)},
+      {"tau_bar", tau_bar}, {"tau+", tau_bar}, {"-15",static_cast<ParticleID>(-15)},
       {"nu_tau_bar", nu_tau_bar}, {"-16",static_cast<ParticleID>(-16)},
       {"gluon", gluon}, {"g", g}, {"21",static_cast<ParticleID>(21)},
       {"photon", photon}, {"gamma", gamma}, {"22",static_cast<ParticleID>(22)},
       {"Z", Z}, {"23",static_cast<ParticleID>(23)},
       {"Wp", Wp}, {"W+", Wp}, {"24",static_cast<ParticleID>(24)},
       {"Wm", Wm}, {"W-", Wm}, {"-24",static_cast<ParticleID>(-24)},
       {"h", h}, {"H", h}, {"Higgs", Higgs}, {"higgs", higgs}, {"25",static_cast<ParticleID>(25)},
       {"p", p}, {"proton", proton}, {"p_bar", p_bar}, {"2212",static_cast<ParticleID>(2212)}
     };
     const auto res = known.find(name);
     if(res == known.end()){
       throw std::invalid_argument("Unknown particle " + name);
     }
     return res->second;
   }
 }