diff --git a/Models/General/TwoBodyDecayConstructor.cc b/Models/General/TwoBodyDecayConstructor.cc --- a/Models/General/TwoBodyDecayConstructor.cc +++ b/Models/General/TwoBodyDecayConstructor.cc @@ -1,432 +1,446 @@ // -*- C++ -*- // // TwoBodyDecayConstructor.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2019 The Herwig Collaboration // // Herwig is licenced under version 3 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // // // This is the implementation of the non-inlined, non-templated member // functions of the TwoBodyDecayConstructor class. // #include "TwoBodyDecayConstructor.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Interface/Reference.h" #include "ThePEG/Interface/Switch.h" #include "Herwig/Decay/General/GeneralTwoBodyDecayer.h" #include "Herwig/Models/StandardModel/StandardModel.h" #include "ThePEG/PDT/EnumParticles.h" #include "DecayConstructor.h" #include "ThePEG/Utilities/Throw.h" #include "ThePEG/Utilities/EnumIO.h" #include "ThePEG/Helicity/Vertex/AbstractFFVVertex.fh" #include "ThePEG/Helicity/Vertex/AbstractFFSVertex.fh" #include "ThePEG/Helicity/Vertex/AbstractVVSVertex.fh" #include "ThePEG/Helicity/Vertex/AbstractVSSVertex.fh" #include "ThePEG/Helicity/Vertex/AbstractVVTVertex.fh" #include "ThePEG/Helicity/Vertex/AbstractFFTVertex.fh" #include "ThePEG/Helicity/Vertex/AbstractSSTVertex.fh" #include "ThePEG/Helicity/Vertex/AbstractSSSVertex.fh" #include "ThePEG/Helicity/Vertex/AbstractVVVVertex.fh" #include "ThePEG/Helicity/Vertex/AbstractRFSVertex.fh" #include "ThePEG/Helicity/Vertex/AbstractRFVVertex.fh" +#include "VectorCurrentDecayConstructor.h" using namespace Herwig; using ThePEG::Helicity::VertexBasePtr; IBPtr TwoBodyDecayConstructor::clone() const { return new_ptr(*this); } IBPtr TwoBodyDecayConstructor::fullclone() const { return new_ptr(*this); } void TwoBodyDecayConstructor::persistentOutput(PersistentOStream & os) const { os << alphaQCD_ << alphaQED_ << oenum(inter_); } void TwoBodyDecayConstructor::persistentInput(PersistentIStream & is, int) { is >> alphaQCD_ >> alphaQED_>> ienum(inter_); } // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeHerwigTwoBodyDecayConstructor("Herwig::TwoBodyDecayConstructor", "Herwig.so"); void TwoBodyDecayConstructor::Init() { static ClassDocumentation documentation ("The TwoBodyDecayConstructor implements to creation of 2 body decaymodes " "and decayers that do not already exist for the given set of vertices."); static Reference interfaceShowerAlphaQCD ("AlphaQCD", "The coupling for QCD corrections", &TwoBodyDecayConstructor::alphaQCD_, false, false, true, false, false); static Reference interfaceShowerAlphaQED ("AlphaQED", "The coupling for QED corrections", &TwoBodyDecayConstructor::alphaQED_, false, false, true, false, false); static Switch interfaceInteractions ("Interactions", "which interactions to include for the hard corrections", &TwoBodyDecayConstructor::inter_, ShowerInteraction::QCD, false, false); static SwitchOption interfaceInteractionsQCD (interfaceInteractions, "QCD", "QCD Only", ShowerInteraction::QCD); static SwitchOption interfaceInteractionsQED (interfaceInteractions, "QED", "QED only", ShowerInteraction::QED); static SwitchOption interfaceInteractionsQCDandQED (interfaceInteractions, "QCDandQED", "Both QCD and QED", ShowerInteraction::Both); } void TwoBodyDecayConstructor::DecayList(const set & particles) { + // special for weak decays + for(unsigned int ix=0;ixdecayConstructors().size();++ix) { + Ptr::pointer + weak = dynamic_ptr_cast::pointer > + (decayConstructor()->decayConstructors()[ix]); + if(!weak) continue; + weakMassCut_ = max(weakMassCut_,weak->massCut()); + } if( particles.empty() ) return; tHwSMPtr model = dynamic_ptr_cast(generator()->standardModel()); unsigned int nv(model->numberOfVertices()); for(set::const_iterator ip=particles.begin(); ip!=particles.end();++ip) { tPDPtr parent = *ip; if ( Debug::level > 0 ) Repository::cout() << "Constructing 2-body decays for " << parent->PDGName() << '\n'; multiset decays; for(unsigned int iv = 0; iv < nv; ++iv) { if(excluded(model->vertex(iv)) || model->vertex(iv)->getNpoint()>3) continue; for(unsigned int il = 0; il < 3; ++il) createModes(parent, model->vertex(iv), il,decays); } if( !decays.empty() ) createDecayMode(decays); } } void TwoBodyDecayConstructor:: createModes(tPDPtr inpart, VertexBasePtr vertex, unsigned int list, multiset & modes) { if( !vertex->isIncoming(inpart) || vertex->getNpoint() != 3 ) return; Energy m1(inpart->mass()); tPDPtr ccpart = inpart->CC() ? inpart->CC() : inpart; long id = ccpart->id(); tPDVector decaylist = vertex->search(list, ccpart); tPDVector::size_type nd = decaylist.size(); for( tPDVector::size_type i = 0; i < nd; i += 3 ) { tPDPtr pa(decaylist[i]), pb(decaylist[i + 1]), pc(decaylist[i + 2]); if( pb->id() == id ) swap(pa, pb); if( pc->id() == id ) swap(pa, pc); //allowed on-shell decay? if( m1 <= pb->mass() + pc->mass() ) continue; + // double counting with current decays? + if(inpart->iSpin()==PDT::Spin1 && inpart->iCharge()==0 && + pb->id()==-pc->id() && abs(pb->id())<=3 && inpart->mass() <= weakMassCut_ ) { + continue; + } //vertices are defined with all particles incoming modes.insert( TwoBodyDecay(inpart,pb, pc, vertex) ); } } GeneralTwoBodyDecayerPtr TwoBodyDecayConstructor::createDecayer(TwoBodyDecay decay, vector vertices) { string name; using namespace Helicity::VertexType; PDT::Spin in = decay.parent_->iSpin(); // PDT::Spin out1 = decay.children_.first ->iSpin(); PDT::Spin out2 = decay.children_.second->iSpin(); switch(decay.vertex_->getName()) { case FFV : if(in == PDT::Spin1Half) { name = "FFVDecayer"; if(out2==PDT::Spin1Half) swap(decay.children_.first,decay.children_.second); } else { name = "VFFDecayer"; } break; case FFS : if(in == PDT::Spin1Half) { name = "FFSDecayer"; if(out2==PDT::Spin1Half) swap(decay.children_.first,decay.children_.second); } else { name = "SFFDecayer"; } break; case VVS : if(in == PDT::Spin1) { name = "VVSDecayer"; if(out2==PDT::Spin1) swap(decay.children_.first,decay.children_.second); } else { name = "SVVDecayer"; } break; case VSS : if(in == PDT::Spin1) { name = "VSSDecayer"; } else { name = "SSVDecayer"; if(out2==PDT::Spin0) swap(decay.children_.first,decay.children_.second); } break; case VVT : name = in==PDT::Spin2 ? "TVVDecayer" : "Unknown"; break; case FFT : name = in==PDT::Spin2 ? "TFFDecayer" : "Unknown"; break; case SST : name = in==PDT::Spin2 ? "TSSDecayer" : "Unknown"; break; case SSS : name = "SSSDecayer"; break; case VVV : name = "VVVDecayer"; break; case RFS : if(in==PDT::Spin1Half) { name = "FRSDecayer"; if(out2==PDT::Spin3Half) swap(decay.children_.first,decay.children_.second); } else if(in==PDT::Spin0) { name = "SRFDecayer"; if(out2==PDT::Spin3Half) swap(decay.children_.first,decay.children_.second); } else { name = "Unknown"; } break; case RFV : if(in==PDT::Spin1Half) { name = "FRVDecayer"; if(out2==PDT::Spin3Half) swap(decay.children_.first,decay.children_.second); } else name = "Unknown"; break; default : Throw() << "Error: Cannot assign " << decay.vertex_->fullName() << " to a decayer. " << "Decay is " << decay.parent_->PDGName() << " -> " << decay.children_.first ->PDGName() << " " << decay.children_.second->PDGName() << Exception::runerror; } if(name=="Unknown") Throw() << "Error: Cannot assign " << decay.vertex_->fullName() << " to a decayer. " << "Decay is " << decay.parent_->PDGName() << " -> " << decay.children_.first ->PDGName() << " " << decay.children_.second->PDGName() << Exception::runerror; ostringstream fullname; fullname << "/Herwig/Decays/" << name << "_" << decay.parent_->PDGName() << "_" << decay.children_.first ->PDGName() << "_" << decay.children_.second->PDGName(); string classname = "Herwig::" + name; GeneralTwoBodyDecayerPtr decayer; decayer = dynamic_ptr_cast (generator()->preinitCreate(classname,fullname.str())); if(!decayer) Throw() << "Error: Cannot assign " << decay.vertex_->fullName() << " to a decayer. " << "Decay is " << decay.parent_->PDGName() << " -> " << decay.children_.first ->PDGName() << " " << decay.children_.second->PDGName() << Exception::runerror; // set the strong coupling for radiation generator()->preinitInterface(decayer, "AlphaS" , "set", alphaQCD_->fullName()); // set the EM coupling for radiation generator()->preinitInterface(decayer, "AlphaEM", "set", alphaQED_->fullName()); // set the type of interactions for the correction if(inter_==ShowerInteraction::QCD) generator()->preinitInterface(decayer, "Interactions", "set", "QCD"); else if(inter_==ShowerInteraction::QED) generator()->preinitInterface(decayer, "Interactions", "set", "QED"); else generator()->preinitInterface(decayer, "Interactions", "set", "QCDandQED"); // get the vertices for radiation from the external legs map inRad,fourRad; vector > outRad(2); vector itemp={ShowerInteraction::QCD,ShowerInteraction::QED}; for(auto & inter : itemp) { inRad[inter] = radiationVertex(decay.parent_,inter); outRad[0][inter] = radiationVertex(decay.children_.first ,inter); outRad[1][inter] = radiationVertex(decay.children_.second,inter); // get any contributing 4 point vertices fourRad[inter] = radiationVertex(decay.parent_,inter, decay.children_); } // set info on decay decayer->setDecayInfo(decay.parent_,decay.children_,vertices, inRad,outRad,fourRad); // initialised the decayer setDecayerInterfaces(fullname.str()); decayer->init(); return decayer; } void TwoBodyDecayConstructor:: createDecayMode(multiset & decays) { tPDPtr inpart = decays.begin()->parent_; for( multiset::iterator dit = decays.begin(); dit != decays.end(); ) { TwoBodyDecay mode = *dit; // get all the moees with the same in and outgoing particles pair::iterator, multiset::iterator> range = decays.equal_range(mode); // construct the decay mode tPDPtr pb((mode).children_.first), pc((mode).children_.second); string tag = inpart->name() + "->" + pb->name() + "," + pc->name() + ";"; // Does it exist already ? tDMPtr dm = generator()->findDecayMode(tag); // find the vertices vector vertices; for ( multiset::iterator dit2 = range.first; dit2 != range.second; ++dit2) { vertices.push_back(dit2->vertex_); } dit=range.second; // now create DecayMode objects that do not already exist if( createDecayModes() && (!dm || inpart->id() == ParticleID::h0) ) { tDMPtr ndm = generator()->preinitCreateDecayMode(tag); if(ndm) { inpart->stable(false); GeneralTwoBodyDecayerPtr decayer=createDecayer(mode,vertices); if(!decayer) continue; generator()->preinitInterface(ndm, "Decayer", "set", decayer->fullName()); generator()->preinitInterface(ndm, "Active", "set", "Yes"); Energy width = decayer->partialWidth(make_pair(inpart,inpart->mass()), make_pair(pb,pb->mass()) , make_pair(pc,pc->mass())); setBranchingRatio(ndm, width); if(width==ZERO || ndm->brat()minimumBR()) { generator()->preinitInterface(decayer->fullName(), "Initialize", "set","0"); } } else Throw() << "TwoBodyDecayConstructor::createDecayMode - Needed to create " << "new decaymode but one could not be created for the tag " << tag << Exception::warning; } else if( dm ) { if(dm->brat()minimumBR()) { continue; } if((dm->decayer()->fullName()).find("Mambo") != string::npos) { inpart->stable(false); GeneralTwoBodyDecayerPtr decayer=createDecayer(mode,vertices); if(!decayer) continue; generator()->preinitInterface(dm, "Decayer", "set", decayer->fullName()); Energy width = decayer->partialWidth(make_pair(inpart,inpart->mass()), make_pair(pb,pb->mass()) , make_pair(pc,pc->mass())); if(width/(dm->brat()*inpart->width())<1e-10) { string message = "Herwig calculation of the partial width for the decay mode " + inpart->PDGName() + " -> " + pb->PDGName() + " " + pc->PDGName() + " is zero.\n This will cause problems with the calculation of" + " spin correlations.\n It is probably due to inconsistent parameters" + " and decay modes being passed to Herwig via the SLHA file.\n" + " Zeroing the branching ratio for this mode."; setBranchingRatio(dm,ZERO); generator()->logWarning(NBodyDecayConstructorError(message,Exception::warning)); } } } } // update CC mode if it exists if( inpart->CC() ) inpart->CC()->synchronize(); } VertexBasePtr TwoBodyDecayConstructor::radiationVertex(tPDPtr particle, ShowerInteraction inter, tPDPair children) { tHwSMPtr model = dynamic_ptr_cast(generator()->standardModel()); map::iterator rit = radiationVertices_[inter].find(particle); tPDPtr cc = particle->CC() ? particle->CC() : particle; if(children==tPDPair() && rit!=radiationVertices_[inter].end()) return rit->second; unsigned int nv(model->numberOfVertices()); long bosonID = inter==ShowerInteraction::QCD ? ParticleID::g : ParticleID::gamma; tPDPtr gluon = getParticleData(bosonID); // look for radiation vertices for incoming and outgoing particles for(unsigned int iv=0;ivvertex(iv); // look for 3 point vertices if (children==tPDPair()){ if( !vertex->isIncoming(particle) || vertex->getNpoint() != 3 || !vertex->isOutgoing(particle) || !vertex->isOutgoing(gluon)) continue; for(unsigned int list=0;list<3;++list) { tPDVector decaylist = vertex->search(list, particle); for( tPDVector::size_type i = 0; i < decaylist.size(); i += 3 ) { tPDPtr pa(decaylist[i]), pb(decaylist[i + 1]), pc(decaylist[i + 2]); if( pb->id() == bosonID ) swap(pa, pb); if( pc->id() == bosonID ) swap(pa, pc); if( pb->id() != particle->id()) swap(pb, pc); if( pa->id() != bosonID) continue; if( pb != particle) continue; if( pc != cc) continue; radiationVertices_[inter][particle] = vertex; return vertex; } } } // look for 4 point vertex including a gluon else { if( !vertex->isIncoming(particle) || vertex->getNpoint()!=4 || !vertex->isOutgoing(children.first) || !vertex->isOutgoing(children.second) || !vertex->isOutgoing(gluon)) continue; for(unsigned int list=0;list<4;++list) { tPDVector decaylist = vertex->search(list, particle); for( tPDVector::size_type i = 0; i < decaylist.size(); i += 4 ) { tPDPtr pa(decaylist[i]), pb(decaylist[i+1]), pc(decaylist[i+2]), pd(decaylist[i+3]); // order so that a = g, b = parent if( pb->id() == bosonID ) swap(pa, pb); if( pc->id() == bosonID ) swap(pa, pc); if( pd->id() == bosonID ) swap(pa, pd); if( pc->id() == particle->id()) swap(pb, pc); if( pd->id() == particle->id()) swap(pb, pd); if( pa->id() != bosonID) continue; if( pb->id() != particle->id()) continue; if( !((abs(pd->id()) == abs(children. first->id()) && abs(pc->id()) == abs(children.second->id())) || (abs(pc->id()) == abs(children. first->id()) && abs(pd->id()) == abs(children.second->id())))) continue; return vertex; } } } } return VertexBasePtr(); } diff --git a/Models/General/TwoBodyDecayConstructor.h b/Models/General/TwoBodyDecayConstructor.h --- a/Models/General/TwoBodyDecayConstructor.h +++ b/Models/General/TwoBodyDecayConstructor.h @@ -1,177 +1,182 @@ // -*- C++ -*- // // TwoBodyDecayConstructor.h is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2019 The Herwig Collaboration // // Herwig is licenced under version 3 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // #ifndef HERWIG_TwoBodyDecayConstructor_H #define HERWIG_TwoBodyDecayConstructor_H // // This is the declaration of the TwoBodyDecayConstructor class. // #include "NBodyDecayConstructorBase.h" #include "ThePEG/Helicity/Vertex/VertexBase.h" #include "Herwig/Decay/General/GeneralTwoBodyDecayer.fh" #include "Herwig/Shower/ShowerAlpha.h" #include "TwoBodyDecay.h" namespace Herwig { using namespace ThePEG; using Helicity::VertexBasePtr; using Helicity::tVertexBasePtr; /** * The TwoBodyDecayConstructor class inherits from the dummy base class * NBodyDecayConstructorBase and implements the necessary functions in * order to create the 2 body decay modes for a given set of vertices * stored in a Model class. * * @see \ref TwoBodyDecayConstructorInterfaces "The interfaces" * defined for TwoBodyDecayConstructor. * @see NBodyDecayConstructor **/ class TwoBodyDecayConstructor: public NBodyDecayConstructorBase { public: /** * The default constructor. */ - TwoBodyDecayConstructor() : inter_(ShowerInteraction::Both) { + TwoBodyDecayConstructor() : inter_(ShowerInteraction::Both), weakMassCut_(-GeV) { radiationVertices_[ShowerInteraction::QCD] = map(); radiationVertices_[ShowerInteraction::QED] = map(); } /** * Function used to determine allowed decaymodes *@param part vector of ParticleData pointers containing particles in model */ virtual void DecayList(const set & part); /** * Number of outgoing lines. Required for correct ordering. */ virtual unsigned int numBodies() const { return 2; } public: /** @name Functions used by the persistent I/O system. */ //@{ /** * Function used to write out object persistently. * @param os the persistent output stream written to. */ void persistentOutput(PersistentOStream & os) const; /** * Function used to read in object persistently. * @param is the persistent input stream read from. * @param version the version number of the object when written. */ void persistentInput(PersistentIStream & is, int version); //@} /** * The standard Init function used to initialize the interfaces. * Called exactly once for each class by the class description system * before the main function starts or * when this class is dynamically loaded. */ static void Init(); protected: /** @name Clone Methods. */ //@{ /** * Make a simple clone of this object. * @return a pointer to the new object. */ virtual IBPtr clone() const; /** Make a clone of this object, possibly modifying the cloned object * to make it sane. * @return a pointer to the new object. */ virtual IBPtr fullclone() const; //@} private: /** * The assignment operator is private and must never be called. * In fact, it should not even be implemented. */ TwoBodyDecayConstructor & operator=(const TwoBodyDecayConstructor &) = delete; private: /** @name Functions to create decayers and decaymodes. */ //@{ /** * Function to create decays * @param inpart Incoming particle * @param vert The vertex to create decays for * @param ilist Which list to search * @param iv Row number in _theExistingDecayers member * @return A vector a decay modes */ void createModes(tPDPtr inpart, VertexBasePtr vert, unsigned int ilist, multiset & modes); /** * Function to create decayer for specific vertex * @param decay decay mode for this decay * member variable */ GeneralTwoBodyDecayerPtr createDecayer(TwoBodyDecay decay, vector ); /** * Create decay mode(s) from given part and decay modes * @param decays The vector of decay modes * @param decayer The decayer responsible for this decay */ void createDecayMode(multiset & decays); //@} /** * Get the vertex for QED/QCD radiation */ VertexBasePtr radiationVertex(tPDPtr particle,ShowerInteraction inter, tPDPair children = tPDPair ()); private: /** * Map of particles and the vertices which generate their QCD * radiation */ map > radiationVertices_; /** * Default choice for the strong coupling object for hard QCD radiation */ ShowerAlphaPtr alphaQCD_; /** * Default choice for the strong coupling object for hard QED radiation */ ShowerAlphaPtr alphaQED_; /** * Which type of corrections to the decays to include */ ShowerInteraction inter_; + + /** + * Cut off or decays via the weak current + */ + Energy weakMassCut_; }; } #endif /* HERWIG_TwoBodyDecayConstructor_H */