diff --git a/Decay/Perturbative/SMTopPOWHEGDecayer.cc b/Decay/Perturbative/SMTopPOWHEGDecayer.cc --- a/Decay/Perturbative/SMTopPOWHEGDecayer.cc +++ b/Decay/Perturbative/SMTopPOWHEGDecayer.cc @@ -1,347 +1,348 @@ // -*- C++ -*- // // This is the implementation of the non-inlined, non-templated member // functions of the SMTopPOWHEGDecayer class. // #include "SMTopPOWHEGDecayer.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Interface/Parameter.h" #include "ThePEG/EventRecord/Particle.h" #include "ThePEG/Repository/UseRandom.h" #include "ThePEG/Repository/EventGenerator.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "Herwig/Shower/RealEmissionProcess.h" #include "Herwig/Shower/QTilde/Couplings/ShowerAlpha.h" using namespace Herwig; SMTopPOWHEGDecayer::SMTopPOWHEGDecayer() : mt_(ZERO), w_(0.), b_(0.), w2_(0.), b2_(0.), pTmin_(GeV), pT_(ZERO) {} IBPtr SMTopPOWHEGDecayer::clone() const { return new_ptr(*this); } IBPtr SMTopPOWHEGDecayer::fullclone() const { return new_ptr(*this); } void SMTopPOWHEGDecayer::persistentOutput(PersistentOStream & os) const { os << ounit(pTmin_,GeV); } void SMTopPOWHEGDecayer::persistentInput(PersistentIStream & is, int) { is >> iunit(pTmin_,GeV); } // The following static variable is needed for the type // description system in ThePEG. DescribeClass<SMTopPOWHEGDecayer,SMTopDecayer> describeHerwigSMTopPOWHEGDecayer("Herwig::SMTopPOWHEGDecayer", "HwPerturbativeDecay.so"); void SMTopPOWHEGDecayer::Init() { static ClassDocumentation<SMTopPOWHEGDecayer> documentation ("There is no documentation for the SMTopPOWHEGDecayer class"); static Parameter<SMTopPOWHEGDecayer,Energy> interfacepTmin ("pTmin", "Minimum transverse momentum from gluon radiation", &SMTopPOWHEGDecayer::pTmin_, GeV, 1.0*GeV, 0.0*GeV, 10.0*GeV, false, false, Interface::limited); } RealEmissionProcessPtr SMTopPOWHEGDecayer::generateHardest(RealEmissionProcessPtr born) { PPtr top = born->bornIncoming()[0]; // get the bottom and W assert(born->bornOutgoing().size()==2); PPtr bottom = born->bornOutgoing()[0]; PPtr Wboson = born->bornOutgoing()[1]; bool order = bottom->id()!=ParticleID::b; if(order) swap(bottom,Wboson); // masses of the particles mt_ = top ->momentum().mass(); w_ = Wboson->momentum().mass() / mt_; b_ = bottom->momentum().mass() / mt_; w2_ = sqr(w_); b2_ = sqr(b_); // find rotation fgrom lab to frame with W along -z LorentzRotation eventFrame( top->momentum().findBoostToCM() ); Lorentz5Momentum pspectator = eventFrame*Wboson->momentum(); eventFrame.rotateZ( -pspectator.phi() ); eventFrame.rotateY( -pspectator.theta() - Constants::pi ); //invert it eventFrame.invert(); //generate the hard emission vector<Lorentz5Momentum> momenta = hardMomenta(); // if no emission return if(momenta.empty()) { born->pT()[ShowerInteraction::QCD] = pTmin_; return born; } // rotate momenta back to the lab for(unsigned int ix=0;ix<momenta.size();++ix) { momenta[ix] *= eventFrame; } // create new Particles PPtr newTop = top ->dataPtr()->produceParticle(top->momentum()); born->incoming().push_back(newTop); PPtr newb = bottom->dataPtr()->produceParticle(momenta[1]); PPtr newW = Wboson->dataPtr()->produceParticle(momenta[2]); PPtr newg = getParticleData(ParticleID::g)->produceParticle(momenta[3]); // colour flow newg->incomingColour(newTop,top->id()<0); newg->colourConnect (newb ,top->id()<0); // outgoing particles if(!order) { born->outgoing().push_back(newb); born->outgoing().push_back(newW); born->emitter(1); } else { born->outgoing().push_back(newW); born->outgoing().push_back(newb); born->emitter(2); } born->outgoing().push_back(newg); // boost for the W LorentzRotation trans(Wboson->momentum().findBoostToCM()); trans.boost(momenta[2].boostVector()); born->transformation(trans); born->spectator(0); born->emitted(3); born->pT()[ShowerInteraction::QCD] = pT_; born->interaction(ShowerInteraction::QCD); return born; } vector<Lorentz5Momentum> SMTopPOWHEGDecayer::hardMomenta() { double C = 6.3; double ymax = 10.; double ymin = -ymax; vector<Lorentz5Momentum> particleMomenta (4); Energy2 lambda = sqr(mt_)* sqrt( 1. + sqr(w2_) + sqr(b2_) - 2.*w2_ - 2.*b2_ - 2.*w2_*b2_); //Calculate A double A = (ymax - ymin) * C * (coupling()->overestimateValue() / (2.*Constants::pi)); Energy pTmax = mt_* (sqr(1.-w_) - b2_) / (2.*(1.-w_)); if (pTmax < pTmin_) particleMomenta.clear(); while (pTmax >= pTmin_) { //Generate pT, y and phi values Energy pT = pTmax * pow(UseRandom::rnd() , (1./A)); if (pT < pTmin_) {particleMomenta.clear(); break;} double phi = UseRandom::rnd() * Constants::twopi; double y = ymin + UseRandom::rnd() * (ymax-ymin); double weight[2] = {0.,0.}; double xw[2], xb[2], xb_z[2], xg; for (unsigned int j=0; j<2; j++) { //Check if the momenta are physical bool physical = calcMomenta(j, pT, y, phi, xg, xw[j], xb[j], xb_z[j], particleMomenta); if (! physical) continue; //Check if point lies within phase space bool inPS = psCheck(xg, xw[j]); if (! inPS) continue; //Calculate the ratio R/B double meRatio = matrixElementRatio(particleMomenta); //Calculate jacobian Energy2 denom = (mt_ - particleMomenta[3].e()) * particleMomenta[2].vect().mag() - particleMomenta[2].e() * particleMomenta[3].z(); InvEnergy2 J = (particleMomenta[2].vect().mag2()) / (2.* lambda * denom); //Calculate weight weight[j] = meRatio * fabs(sqr(pT)*J) * coupling()->ratio(pT*pT) / C; } //Accept point if weight > R if (weight[0] + weight[1] > UseRandom::rnd()) { if (weight[0] > (weight[0] + weight[1])*UseRandom::rnd()) { particleMomenta[1].setE( (mt_/2.)*xb [0]); particleMomenta[1].setZ( (mt_/2.)*xb_z[0]); particleMomenta[2].setE( (mt_/2.)*xw [0]); particleMomenta[2].setZ(-(mt_/2.)*sqrt(sqr(xw[0])-4.*w2_)); } else { particleMomenta[1].setE( (mt_/2.)*xb [1]); particleMomenta[1].setZ( (mt_/2.)*xb_z[1]); particleMomenta[2].setE( (mt_/2.)*xw [1]); particleMomenta[2].setZ(-(mt_/2.)*sqrt(sqr(xw[1])-4.*w2_)); } pT_ = pT; break; } //If there's no splitting lower the pT pTmax = pT; } return particleMomenta; } bool SMTopPOWHEGDecayer::deadZoneCheck(double xw, double xg){ //veto events not in the dead cone double Lambda = sqrt(1. + sqr(w2_) + sqr(b2_) - 2.*w2_ - 2.*b2_ - 2.*w2_*b2_); double kappa = b2_ + 0.5*(1. - w2_ + b2_ + Lambda); //invert xw for z values double A = 1.; double B = -1.; double C = (1.+w2_-b2_-xw)/kappa; if((sqr(B) - 4.*A*C) >= 0.){ double z[2]; z[0] = (-B + sqrt(sqr(B) - 4.*A*C))/(2.*A); z[1] = (-B - sqrt(sqr(B) - 4.*A*C))/(2.*A); double r = 0.5*(1. + b2_/(1. + w2_- xw)); double xg_lims [2]; xg_lims[0] = (2. - xw)*(1.-r) - (z[0]-r)*sqrt(sqr(xw) - 4.*w2_); xg_lims[1] = (2. - xw)*(1.-r) - (z[1]-r)*sqrt(sqr(xw) - 4.*w2_); double xg_low_lim = min(xg_lims[0], xg_lims[1]); double xg_upp_lim = max(xg_lims[0], xg_lims[1]); if (xg>=xg_low_lim && xg<=xg_upp_lim) return false; } double kappa_t = 1. + 0.5*(1. - w2_ + b2_ + Lambda); double z = 1. - xg/kappa_t; double u = 1. + w2_ - b2_ - (1.-z)*kappa_t; double y = 1. - (1.-z)*(kappa_t-1.); if (sqr(u) - 4.*w2_*y*z >= 0.){ double v = sqrt(sqr(u) - 4.*w2_*y*z); double xw_lim = (u + v) / (2.*y) + (u - v) / (2.*z); if (xw <= xw_lim) return false; } else if (sqr(u) - 4.*w2_*y*z < 0.){ double xg_lim = (8.*w2_ -2.*xw*(1-b2_+w2_))/(4.*w2_-2.*xw); if (xg>=xg_lim) return false; } return true; } double SMTopPOWHEGDecayer::matrixElementRatio( vector<Lorentz5Momentum> particleMomenta) { double f = (1. + sqr(b2_) - 2.*sqr(w2_) + w2_ + w2_*b2_ - 2.*b2_); double Nc = standardModel()->Nc(); double Cf = (sqr(Nc) - 1.) / (2.*Nc); double B = f/w2_; Energy2 PbPg = particleMomenta[1]*particleMomenta[3]; Energy2 PtPg = particleMomenta[0]*particleMomenta[3]; Energy2 PtPb = particleMomenta[0]*particleMomenta[1]; double R = Cf *((-4.*sqr(mt_)*f/w2_) * ((sqr(mt_)*b2_/sqr(PbPg)) + (sqr(mt_)/sqr(PtPg)) - 2.*(PtPb/(PtPg*PbPg))) + (16. + 8./w2_ + 8.*b2_/w2_) * ((PtPg/PbPg) + (PbPg/PtPg)) - (16./w2_) * (1. + b2_)); return R/B; } bool SMTopPOWHEGDecayer::calcMomenta(int j, Energy pT, double y, double phi, double& xg, double& xw, double& xb, double& xb_z, vector<Lorentz5Momentum>& particleMomenta){ //Calculate xg xg = 2.*pT*cosh(y) / mt_; if (xg>(1. - sqr(b_ + w_)) || xg<0.) return false; //Calculate xw double xT = 2.*pT / mt_; double A = 4. - 4.*xg + sqr(xT); double B = 4.*(3.*xg - 2. + 2.*b2_ - 2.*w2_ - sqr(xg) - xg*b2_ + xg*w2_); double L = 1. + sqr(w2_) + sqr(b2_) - 2.*w2_ - 2.*b2_ - 2.*w2_*b2_; double det = 16.*( -L*sqr(xT) + pow(xT,4)*w2_ + 2.*xg*sqr(xT)*(1.-w2_-b2_) + L*sqr(xg) - sqr(xg*xT)*(1. + w2_) + pow(xg,4) + 2.*pow(xg,3)*(- 1. + w2_ + b2_) ); if (det<0.) return false; if (j==0) xw = (-B + sqrt(det))/(2.*A); if (j==1) xw = (-B - sqrt(det))/(2.*A); if (xw>(1. + w2_ - b2_) || xw<2.*w_) return false; - //Calculate xb - xb = 2. - xw - xg; - if (xb>(1. + b2_ - w2_) || xb<2.*b_) return false; + //Calculate xb_z + // Due to precision limitations, it is possible for + // sqr(xb)-4.*b2_-s to be very small + // and negative, set to 0 in this case + double xb_z_mod2 = std::max(sqr(xb) - 4.*b2_ - sqr(xT), 0.); - //Calculate xb_z double epsilon_p = -sqrt(sqr(xw) - 4.*w2_) + xT*sinh(y) + - sqrt(sqr(xb) - 4.*b2_ - sqr(xT)); + sqrt(xb_z_mod2); double epsilon_m = -sqrt(sqr(xw) - 4.*w2_) + xT*sinh(y) - - sqrt(sqr(xb) - 4.*b2_ - sqr(xT)); + sqrt(xb_z_mod2); if (fabs(epsilon_p) < 1.e-10){ - xb_z = sqrt(sqr(xb) - 4.*b2_ - sqr(xT)); + xb_z = sqrt(xb_z_mod2); } else if (fabs(epsilon_m) < 1.e-10){ - xb_z = -sqrt(sqr(xb) - 4.*b2_ - sqr(xT)); + xb_z = -sqrt(xb_z_mod2); } else return false; //Check b is on shell if (fabs((sqr(xb) - sqr(xT) - sqr(xb_z) - 4.*b2_))>1.e-10) return false; //Calculate 4 momenta particleMomenta[0].setE ( mt_); particleMomenta[0].setX ( ZERO); particleMomenta[0].setY ( ZERO); particleMomenta[0].setZ ( ZERO); particleMomenta[0].setMass( mt_); particleMomenta[1].setE ( mt_*xb/2.); particleMomenta[1].setX (-pT*cos(phi)); particleMomenta[1].setY (-pT*sin(phi)); particleMomenta[1].setZ ( mt_*xb_z/2.); particleMomenta[1].setMass( mt_*b_); particleMomenta[2].setE ( mt_*xw/2.); particleMomenta[2].setX ( ZERO); particleMomenta[2].setY ( ZERO); particleMomenta[2].setZ (-mt_*sqrt(sqr(xw) - 4.*w2_)/2.); particleMomenta[2].setMass( mt_*w_); particleMomenta[3].setE ( pT*cosh(y)); particleMomenta[3].setX ( pT*cos(phi)); particleMomenta[3].setY ( pT*sin(phi)); particleMomenta[3].setZ ( pT*sinh(y)); particleMomenta[3].setMass( ZERO); return true; } bool SMTopPOWHEGDecayer::psCheck(double xg, double xw) { //Check is point is in allowed region of phase space double xb_star = (1. - w2_ + b2_ - xg) / sqrt(1. - xg); double xg_star = xg / sqrt(1. - xg); if ((sqr(xb_star) - 4.*b2_) < 1e-10) return false; double xw_max = (4. + 4.*w2_ - sqr(xb_star + xg_star) + sqr(sqrt(sqr(xb_star) - 4.*b2_) + xg_star)) / 4.; double xw_min = (4. + 4.*w2_ - sqr(xb_star + xg_star) + sqr(sqrt(sqr(xb_star) - 4.*b2_) - xg_star)) / 4.; if (xw < xw_min || xw > xw_max) return false; return true; } diff --git a/Decay/Perturbative/SMWFermionsPOWHEGDecayer.cc b/Decay/Perturbative/SMWFermionsPOWHEGDecayer.cc --- a/Decay/Perturbative/SMWFermionsPOWHEGDecayer.cc +++ b/Decay/Perturbative/SMWFermionsPOWHEGDecayer.cc @@ -1,627 +1,634 @@ //-*- // // This is the implementation of the non-inlined, non-templated member // functions of the SMWFermionsPOWHEGDecayer class. // #include "SMWFermionsPOWHEGDecayer.h" #include <numeric> #include "Herwig/Models/StandardModel/StandardModel.h" #include "ThePEG/PDF/PolarizedBeamParticleData.h" #include "ThePEG/Helicity/WaveFunction/VectorWaveFunction.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Interface/Parameter.h" #include "ThePEG/Interface/Reference.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "Herwig/Shower/RealEmissionProcess.h" #include "Herwig/Shower/QTilde/Couplings/ShowerAlpha.h" using namespace Herwig; SMWFermionsPOWHEGDecayer::SMWFermionsPOWHEGDecayer() : CF_(4./3.), pTmin_(1.*GeV) { } IBPtr SMWFermionsPOWHEGDecayer::clone() const { return new_ptr(*this); } IBPtr SMWFermionsPOWHEGDecayer::fullclone() const { return new_ptr(*this); } void SMWFermionsPOWHEGDecayer::persistentOutput(PersistentOStream & os) const { os << FFGVertex_ << FFWVertex_ << gluon_ << ounit( pTmin_, GeV ); } void SMWFermionsPOWHEGDecayer::persistentInput(PersistentIStream & is, int) { is >> FFGVertex_ >> FFWVertex_ >> gluon_ >> iunit( pTmin_, GeV ); } ClassDescription<SMWFermionsPOWHEGDecayer> SMWFermionsPOWHEGDecayer::initSMWFermionsPOWHEGDecayer; // Definition of the static class description member. void SMWFermionsPOWHEGDecayer::Init() { static ClassDocumentation<SMWFermionsPOWHEGDecayer> documentation ("There is no documentation for the SMWFermionsPOWHEGDecayer class"); static Parameter<SMWFermionsPOWHEGDecayer, Energy> interfacePtMin ("minpT", "The pt cut on hardest emision generation", &SMWFermionsPOWHEGDecayer::pTmin_, GeV, 1.*GeV, 0*GeV, 100000.0*GeV, false, false, Interface::limited); } RealEmissionProcessPtr SMWFermionsPOWHEGDecayer:: generateHardest(RealEmissionProcessPtr born) { assert(born->bornOutgoing().size()==2); // check coloured if(!born->bornOutgoing()[0]->dataPtr()->coloured()) return RealEmissionProcessPtr(); // extract required info partons_.resize(2); quark_.resize(2); vector<PPtr> hardProcess; wboson_ = born->bornIncoming()[0]; hardProcess.push_back(wboson_); for(unsigned int ix=0;ix<born->bornOutgoing().size();++ix) { partons_[ix] = born->bornOutgoing()[ix]->dataPtr(); quark_[ix] = born->bornOutgoing()[ix]->momentum(); quark_[ix].setMass(partons_[ix]->mass()); hardProcess.push_back(born->bornOutgoing()[ix]); } bool order = partons_[0]->id()<0; if(order) { swap(partons_[0] ,partons_[1] ); swap(quark_[0] ,quark_[1] ); swap(hardProcess[1],hardProcess[2]); } gauge_.setMass(0.*MeV); // Get the W boson mass. mw2_ = (quark_[0] + quark_[1]).m2(); // Generate emission and set _quark[0,1] and _gauge to be the // momenta of q, qbar and g after the hardest emission: if(!getEvent(hardProcess)) { born->pT()[ShowerInteraction::QCD] = pTmin_; return born; } // Ensure the energies are greater than the constituent masses: for (int i=0; i<2; i++) { if (quark_[i].e() < partons_[i]->constituentMass()) return RealEmissionProcessPtr(); } if (gauge_.e() < gluon_ ->constituentMass()) return RealEmissionProcessPtr(); // set masses quark_[0].setMass( partons_[0]->mass() ); quark_[1].setMass( partons_[1]->mass() ); gauge_ .setMass( ZERO ); // // assign the emitter based on evolution scales unsigned int iemitter = quark_[0]*gauge_ > quark_[1]*gauge_ ? 2 : 1; unsigned int ispectator = iemitter==1 ? 1 : 2; // create new partices and insert PPtr wboson = wboson_->dataPtr()->produceParticle(wboson_->momentum()); born->incoming().push_back(wboson); PPtr newq = partons_[0]->produceParticle(quark_[0]); PPtr newa = partons_[1]->produceParticle(quark_[1]); PPtr newg = gluon_->produceParticle(gauge_); // make colour connections newg->colourNeighbour(newq); newa->colourNeighbour(newg); // insert in output structure if(!order) { born->outgoing().push_back(newq); born->outgoing().push_back(newa); } else { born->outgoing().push_back(newa); born->outgoing().push_back(newq); swap(iemitter,ispectator); } born->outgoing().push_back(newg); born->emitter (iemitter ); born->spectator(ispectator); born->emitted (3); born->pT()[ShowerInteraction::QCD] = pT_; // return process born->interaction(ShowerInteraction::QCD); return born; } double SMWFermionsPOWHEGDecayer:: me2(const int ichan, const Particle & part, const ParticleVector & decay, MEOption meopt) const { // leading-order result double output = SMWDecayer::me2(ichan,part,decay,meopt); // check decay products coloured, otherwise return if(!decay[0]->dataPtr()->coloured()) return output; // inital masses, couplings etc // W mass mW_ = part.mass(); // strong coupling aS_ = SM().alphaS(sqr(mW_)); // reduced mass double mu1_ = (decay[0]->dataPtr()->mass())/mW_; double mu2_ = (decay[1]->dataPtr()->mass())/mW_; // scale scale_ = sqr(mW_); // now for the nlo loop correction double virt = CF_*aS_/Constants::pi; // now for the real correction double realFact=0.; for(int iemit=0;iemit<2;++iemit) { double phi = UseRandom::rnd()*Constants::twopi; // set the emitter and the spectator double muj = iemit==0 ? mu1_ : mu2_; double muk = iemit==0 ? mu2_ : mu1_; double muj2 = sqr(muj); double muk2 = sqr(muk); // calculate y double yminus = 0.; double yplus = 1.-2.*muk*(1.-muk)/(1.-muj2-muk2); double y = yminus + UseRandom::rnd()*(yplus-yminus); double v = sqrt(sqr(2.*muk2 + (1.-muj2-muk2)*(1.-y))-4.*muk2) /(1.-muj2-muk2)/(1.-y); double zplus = (1.+v)*(1.-muj2-muk2)*y/2./(muj2+(1.-muj2-muk2)*y); double zminus = (1.-v)*(1.-muj2-muk2)*y/2./(muj2+(1.-muj2-muk2)*y); double z = zminus + UseRandom::rnd()*(zplus-zminus); double jac = (1.-y)*(yplus-yminus)*(zplus-zminus); // calculate x1,x2,x3,xT double x2 = 1.-y*(1.-muj2-muk2)-muj2+muk2; double x1 = 1.+muj2-muk2-z*(x2-2.*muk2); // copy the particle objects over for calculateRealEmission vector<PPtr> hardProcess(3); hardProcess[0] = const_ptr_cast<PPtr>(&part); hardProcess[1] = decay[0]; hardProcess[2] = decay[1]; realFact = 0.25*jac*sqr(1.-muj2-muk2)/ sqrt((1.-sqr(muj-muk))*(1.-sqr(muj+muk)))/Constants::twopi *2.*CF_*aS_*calculateRealEmission(x1, x2, hardProcess, phi, muj, muk, iemit, true); } // the born + virtual + real output = output*(1. + virt + realFact); return output; } double SMWFermionsPOWHEGDecayer::meRatio(vector<cPDPtr> partons, vector<Lorentz5Momentum> momenta, unsigned int iemitter, bool subtract) const { Lorentz5Momentum q = momenta[1]+momenta[2]+momenta[3]; Energy2 Q2=q.m2(); Energy2 lambda = sqrt((Q2-sqr(momenta[1].mass()+momenta[2].mass()))* (Q2-sqr(momenta[1].mass()-momenta[2].mass()))); InvEnergy2 D[2]; double lome[2]; for(unsigned int iemit=0;iemit<2;++iemit) { unsigned int ispect = iemit==0 ? 1 : 0; Energy2 pipj = momenta[3 ] * momenta[1+iemit ]; Energy2 pipk = momenta[3 ] * momenta[1+ispect]; Energy2 pjpk = momenta[1+iemit] * momenta[1+ispect]; double y = pipj/(pipj+pipk+pjpk); double z = pipk/( pipk+pjpk); Energy mij = sqrt(2.*pipj+sqr(momenta[1+iemit].mass())); Energy2 lamB = sqrt((Q2-sqr(mij+momenta[1+ispect].mass()))* (Q2-sqr(mij-momenta[1+ispect].mass()))); Energy2 Qpk = q*momenta[1+ispect]; Lorentz5Momentum pkt = lambda/lamB*(momenta[1+ispect]-Qpk/Q2*q) +0.5/Q2*(Q2+sqr(momenta[1+ispect].mass())-sqr(momenta[1+ispect].mass()))*q; Lorentz5Momentum pijt = q-pkt; double muj = momenta[1+iemit ].mass()/sqrt(Q2); double muk = momenta[1+ispect].mass()/sqrt(Q2); double vt = sqrt((1.-sqr(muj+muk))*(1.-sqr(muj-muk)))/(1.-sqr(muj)-sqr(muk)); double v = sqrt(sqr(2.*sqr(muk)+(1.-sqr(muj)-sqr(muk))*(1.-y))-4.*sqr(muk)) /(1.-y)/(1.-sqr(muj)-sqr(muk)); // dipole term D[iemit] = 0.5/pipj*(2./(1.-(1.-z)*(1.-y)) -vt/v*(2.-z+sqr(momenta[1+iemit].mass())/pipj)); // matrix element vector<Lorentz5Momentum> lomom(3); lomom[0] = momenta[0]; if(iemit==0) { lomom[1] = pijt; lomom[2] = pkt ; } else { lomom[2] = pijt; lomom[1] = pkt ; } lome[iemit] = loME(partons,lomom); } InvEnergy2 ratio = realME(partons,momenta)*abs(D[iemitter]) /(abs(D[0]*lome[0])+abs(D[1]*lome[1])); if(subtract) return Q2*(ratio-2.*D[iemitter]); else return Q2*ratio; } double SMWFermionsPOWHEGDecayer::loME(const vector<cPDPtr> & partons, const vector<Lorentz5Momentum> & momenta) const { // compute the spinors vector<VectorWaveFunction> vin; vector<SpinorWaveFunction> aout; vector<SpinorBarWaveFunction> fout; VectorWaveFunction win (momenta[0],partons[0],incoming); SpinorBarWaveFunction qkout(momenta[1],partons[1],outgoing); SpinorWaveFunction qbout(momenta[2],partons[2],outgoing); for(unsigned int ix=0;ix<2;++ix){ qkout.reset(ix); fout.push_back(qkout); qbout.reset(ix); aout.push_back(qbout); } for(unsigned int ix=0;ix<3;++ix){ win.reset(ix); vin.push_back(win); } // temporary storage of the different diagrams // sum over helicities to get the matrix element double total(0.); for(unsigned int inhel=0;inhel<3;++inhel) { for(unsigned int outhel1=0;outhel1<2;++outhel1) { for(unsigned int outhel2=0;outhel2<2;++outhel2) { Complex diag1 = FFWVertex()->evaluate(scale_,aout[outhel2],fout[outhel1],vin[inhel]); total += norm(diag1); } } } // return the answer return total; } InvEnergy2 SMWFermionsPOWHEGDecayer::realME(const vector<cPDPtr> & partons, const vector<Lorentz5Momentum> & momenta) const { // compute the spinors vector<VectorWaveFunction> vin; vector<SpinorWaveFunction> aout; vector<SpinorBarWaveFunction> fout; vector<VectorWaveFunction> gout; VectorWaveFunction win (momenta[0],partons[0],incoming); SpinorBarWaveFunction qkout(momenta[1],partons[1],outgoing); SpinorWaveFunction qbout(momenta[2],partons[2],outgoing); VectorWaveFunction gluon(momenta[3],partons[3],outgoing); for(unsigned int ix=0;ix<2;++ix){ qkout.reset(ix); fout.push_back(qkout); qbout.reset(ix); aout.push_back(qbout); gluon.reset(2*ix); gout.push_back(gluon); } for(unsigned int ix=0;ix<3;++ix){ win.reset(ix); vin.push_back(win); } vector<Complex> diag(2,0.); double total(0.); for(unsigned int inhel1=0;inhel1<3;++inhel1) { for(unsigned int outhel1=0;outhel1<2;++outhel1) { for(unsigned int outhel2=0;outhel2<2;++outhel2) { for(unsigned int outhel3=0;outhel3<2;++outhel3) { SpinorBarWaveFunction off1 = FFGVertex()->evaluate(scale_,3,partons[1],fout[outhel1],gout[outhel3]); diag[0] = FFWVertex()->evaluate(scale_,aout[outhel2],off1,vin[inhel1]); SpinorWaveFunction off2 = FFGVertex()->evaluate(scale_,3,partons[2],aout[outhel2],gout[outhel3]); diag[1] = FFWVertex()->evaluate(scale_,off2,fout[outhel1],vin[inhel1]); // sum of diagrams Complex sum = std::accumulate(diag.begin(),diag.end(),Complex(0.)); // me2 total += norm(sum); } } } } // divide out the coupling total /= norm(FFGVertex()->norm()); // return the total return total*UnitRemoval::InvE2; } void SMWFermionsPOWHEGDecayer::doinit() { // cast the SM pointer to the Herwig SM pointer tcHwSMPtr hwsm= dynamic_ptr_cast<tcHwSMPtr>(standardModel()); // do the initialisation if(!hwsm) throw InitException() << "Wrong type of StandardModel object in " << "SMWFermionsPOWHEGDecayer::doinit() " << "the Herwig version must be used." << Exception::runerror; // cast the vertices FFWVertex_ = hwsm->vertexFFW(); FFWVertex_->init(); FFGVertex_ = hwsm->vertexFFG(); FFGVertex_->init(); SMWDecayer::doinit(); gluon_ = getParticleData(ParticleID::g); } bool SMWFermionsPOWHEGDecayer::getEvent(vector<PPtr> hardProcess) { vector<Energy> particleMass; for(unsigned int ix=0;ix<hardProcess.size();++ix) { if(abs(hardProcess[ix]->id())==ParticleID::Wplus) { mW_ = hardProcess[ix]->mass(); } else { particleMass.push_back(hardProcess[ix]->mass()); } } if (particleMass.size()!=2) { throw Exception() << "Number of outgoing particles is not equal to 2 in " << "SMWFermionPOWHEGDecayer::getEvent()" << Exception::runerror; } // reduced mass mu1_ = particleMass[0]/mW_; mu2_ = particleMass[1]/mW_; // scale scale_ = sqr(mW_); // max pT Energy pTmax = 0.5*sqrt(mw2_); if(pTmax<pTmin_) return false; // Define over valued y_max & y_min according to the associated pt_min cut. double ymax = acosh(pTmax/pTmin_); double ymin = -ymax; // pt of the emmission pT_ = pTmax; // prefactor double overEst = 4.; double prefactor = overEst*alphaS()->overestimateValue()*CF_* (ymax-ymin)/Constants::twopi; // loop to generate the pt and rapidity bool reject; //arrays to hold the temporary probabilities whilst the for loop progresses double probTemp[2][2]={{0.,0.},{0.,0.}}; probTemp[0][0]=probTemp[0][1]=probTemp[1][0]=probTemp[1][1]=0.; double x1Solution[2][2] = {{0.,0.},{0.,0.}}; double x2Solution[2][2] = {{0.,0.},{0.,0.}}; double x3Solution[2] = {0.,0.}; Energy pT[2] = {pTmax,pTmax}; double yTemp[2] = {0.,0.}; double phi = 0.; // do the competition for(int i=0; i<2; i++) { // set the emitter and the spectator double muj = i==0 ? mu1_ : mu2_; double muk = i==0 ? mu2_ : mu1_; double muj2 = sqr(muj); double muk2 = sqr(muk); do { // generation of phi phi = UseRandom::rnd() * Constants::twopi; // reject the emission reject = true; // generate pt pT[i] *= pow(UseRandom::rnd(),1./prefactor); if(pT[i]<pTmin_) { pT[i] = -GeV; break; } // generate xT double xT2 = sqr(2./mW_*pT[i]); // generate y yTemp[i] = ymin + UseRandom::rnd()*(ymax-ymin); // generate x3 & x1 from pT & y double x1Plus = 1-muk2+muj2; double x1Minus = 2.*muj; x3Solution[i] = 2.*pT[i]*cosh(yTemp[i])/mW_; // prefactor double weightPrefactor = 0.5/sqrt((1.-sqr(muj-muk))*(1.-sqr(muj+muk)))/overEst; // calculate x1 & x2 solutions double discrim2 = (-sqr(x3Solution[i])+xT2)* (xT2*muk2+2.*x3Solution[i]-sqr(muj2)+2.*muk2+2.*muj2-sqr(x3Solution[i])-1. +2.*muj2*muk2-sqr(muk2)-2.*muk2*x3Solution[i]-2.*muj2*x3Solution[i]); // check discrim2 is > 0 if( discrim2 < ZERO) continue; double fact1 =2.*sqr(x3Solution[i])-4.*muk2-6.*x3Solution[i]+4.*muj2-xT2*x3Solution[i] +2.*xT2-2.*muj2*x3Solution[i]+2.*muk2*x3Solution[i]+4.; double fact2 = (4.-4.*x3Solution[i]+xT2); double discriminant = sqrt(discrim2); // two solns for x1 x1Solution[i][0] = (fact1 + 2.*discriminant)/fact2; x1Solution[i][1] = (fact1 - 2.*discriminant)/fact2; bool found = false; for(unsigned int j=0;j<2;++j) { // calculate x2 x2Solution[i][j] = 2.-x3Solution[i]-x1Solution[i][j]; // set limits on x2 double root = max(0.,sqr(x1Solution[i][j])-4.*muj2); root = sqrt(root); double x2Plus = 1.+muk2-muj2 -0.5*(1.-x1Solution[i][j]+muj2-muk2)/(1.-x1Solution[i][j]+muj2) *(x1Solution[i][j]-2.*muj2-root); double x2Minus = 1.+muk2-muj2 -0.5*(1.-x1Solution[i][j]+muj2-muk2)/(1.-x1Solution[i][j]+muj2) *(x1Solution[i][j]-2.*muj2+root); if(x1Solution[i][j]>=x1Minus && x1Solution[i][j]<=x1Plus && x2Solution[i][j]>=x2Minus && x2Solution[i][j]<=x2Plus && checkZMomenta(x1Solution[i][j], x2Solution[i][j], x3Solution[i], yTemp[i], pT[i], muj, muk)) { probTemp[i][j] = weightPrefactor*pT[i]* calculateJacobian(x1Solution[i][j], x2Solution[i][j], pT[i], muj, muk)* calculateRealEmission(x1Solution[i][j], x2Solution[i][j], hardProcess, phi, muj, muk, i, false); found = true; } else { probTemp[i][j] = 0.; } } if(!found) continue; // alpha S piece double wgt = (probTemp[i][0]+probTemp[i][1])*alphaS()->ratio(sqr(pT[i])); // matrix element weight reject = UseRandom::rnd()>wgt; } while(reject); } // end of emitter for loop // no emission if(pT[0]<ZERO&&pT[1]<ZERO) return false; //pick the spectator and x1 x2 values double x1,x2,y; // particle 1 emits, particle 2 spectates unsigned int iemit=0; if(pT[0]>pT[1]){ pT_ = pT[0]; y=yTemp[0]; if(probTemp[0][0]>UseRandom::rnd()*(probTemp[0][0]+probTemp[0][1])) { x1 = x1Solution[0][0]; x2 = x2Solution[0][0]; } else { x1 = x1Solution[0][1]; x2 = x2Solution[0][1]; } } // particle 2 emits, particle 1 spectates else { iemit=1; pT_ = pT[1]; y=yTemp[1]; if(probTemp[1][0]>UseRandom::rnd()*(probTemp[1][0]+probTemp[1][1])) { x1 = x1Solution[1][0]; x2 = x2Solution[1][0]; } else { x1 = x1Solution[1][1]; x2 = x2Solution[1][1]; } } // find spectator unsigned int ispect = iemit == 0 ? 1 : 0; double muk = iemit == 0 ? mu2_ : mu1_; double muk2 = sqr(muk); + double muj = iemit == 0 ? mu1_ : mu2_; + double muj2 = sqr(muj); + double xT2 = sqr(2./mW_*pT_); // Find the boost from the lab to the c.o.m with the spectator // along the -z axis, and then invert it. LorentzRotation eventFrame( ( quark_[0] + quark_[1] ).findBoostToCM() ); Lorentz5Momentum spectator = eventFrame*quark_[ispect]; eventFrame.rotateZ( -spectator.phi() ); eventFrame.rotateY( -spectator.theta() - Constants::pi ); eventFrame.invert(); // spectator quark_[ispect].setT( 0.5*x2*mW_ ); quark_[ispect].setX( ZERO ); quark_[ispect].setY( ZERO ); quark_[ispect].setZ( -sqrt(0.25*mw2_*x2*x2-mw2_*muk2) ); // gluon gauge_.setT( pT_*cosh(y) ); gauge_.setX( pT_*cos(phi) ); gauge_.setY( pT_*sin(phi) ); gauge_.setZ( pT_*sinh(y) ); gauge_.setMass(ZERO); - // emitter reconstructed from gluon & spectator - quark_[iemit] = -gauge_ - quark_[ispect]; + // emitter + quark_[iemit].setX( -pT_*cos(phi) ); + quark_[iemit].setY( -pT_*sin(phi) ); + quark_[iemit].setZ( 0.5*mW_*sqrt(sqr(x1)-xT2-4.*muj2) ); + if(sqrt(0.25*mw2_*x2*x2-mw2_*muk2)-pT_*sinh(y)<ZERO) + quark_[iemit].setZ(-quark_[iemit].z()); quark_[iemit].setT( 0.5*mW_*x1 ); // boost constructed vectors into the event frame quark_[0] = eventFrame * quark_[0]; quark_[1] = eventFrame * quark_[1]; gauge_ = eventFrame * gauge_; // need to reset masses because for whatever reason the boost // touches the mass component of the five-vector and can make // zero mass objects acquire a floating point negative mass(!). gauge_.setMass( ZERO ); quark_[iemit] .setMass(partons_[iemit ]->mass()); quark_[ispect].setMass(partons_[ispect]->mass()); return true; } InvEnergy SMWFermionsPOWHEGDecayer::calculateJacobian(double x1, double x2, Energy pT, double muj, double muk) const{ double xPerp = abs(2.*pT/mW_); Energy jac = mW_/xPerp*fabs((x2*sqr(muj)+2.*sqr(muk)*x1 +sqr(muk)*x2-x1*x2-sqr(x2)+x2)/pow((sqr(x2)-4.*sqr(muk)),1.5)); return 1./jac; //jacobian as defined is dptdy=jac*dx1dx2, therefore we have to divide by it } bool SMWFermionsPOWHEGDecayer::checkZMomenta(double x1, double x2, double x3, double y, Energy pT, double muj, double muk) const { double xPerp2 = 4.*pT*pT/mW_/mW_; double root1 = sqrt(max(0.,sqr(x2)-4.*sqr(muk))); double root2 = sqrt(max(0.,sqr(x1)-xPerp2 - 4.*sqr(muj))); static double tolerance = 1e-6; bool isMomentaReconstructed = false; if(pT*sinh(y) > ZERO) { if(abs(-root1 + sqrt(sqr(x3)-xPerp2) + root2) <= tolerance || abs(-root1 + sqrt(sqr(x3)-xPerp2) - root2) <= tolerance) isMomentaReconstructed=true; } else if(pT*sinh(y) < ZERO){ if(abs(-root1 - sqrt(sqr(x3)-xPerp2) + root2) <= tolerance || abs(-root1 - sqrt(sqr(x3)-xPerp2) - root2) <= tolerance) isMomentaReconstructed=true; } else if(abs(-root1+ sqrt(sqr(x1)-xPerp2 - 4.*(muj))) <= tolerance) isMomentaReconstructed=true; return isMomentaReconstructed; } double SMWFermionsPOWHEGDecayer::calculateRealEmission(double x1, double x2, vector<PPtr> hardProcess, double phi, double muj, double muk, int iemit, bool subtract) const { // make partons data object for meRatio vector<cPDPtr> partons (3); for(int ix=0; ix<3; ++ix) partons[ix] = hardProcess[ix]->dataPtr(); partons.push_back(gluon_); // calculate x3 double x3 = 2.-x1-x2; double xT = sqrt(max(0.,sqr(x3)-0.25*sqr(sqr(x2)+sqr(x3)-sqr(x1)-4.*sqr(muk)+4.*sqr(muj)) /(sqr(x2)-4.*sqr(muk)))); // calculate the momenta Energy M = mW_; Lorentz5Momentum pspect(ZERO,ZERO,-0.5*M*sqrt(max(sqr(x2)-4.*sqr(muk),0.)), 0.5*M*x2,M*muk); Lorentz5Momentum pemit (-0.5*M*xT*cos(phi),-0.5*M*xT*sin(phi), 0.5*M*sqrt(max(sqr(x1)-sqr(xT)-4.*sqr(muj),0.)), 0.5*M*x1,M*muj); Lorentz5Momentum pgluon(0.5*M*xT*cos(phi), 0.5*M*xT*sin(phi), 0.5*M*sqrt(max(sqr(x3)-sqr(xT),0.)),0.5*M*x3,ZERO); if(abs(pspect.z()+pemit.z()-pgluon.z())/M<1e-6) pgluon.setZ(-pgluon.z()); else if(abs(pspect.z()-pemit.z()+pgluon.z())/M<1e-6) pemit .setZ(- pemit.z()); // loop over the possible emitting partons double realwgt(0.); // boost and rotate momenta LorentzRotation eventFrame( ( hardProcess[1]->momentum() + hardProcess[2]->momentum() ).findBoostToCM() ); Lorentz5Momentum spectator = eventFrame*hardProcess[iemit+1]->momentum(); eventFrame.rotateZ( -spectator.phi() ); eventFrame.rotateY( -spectator.theta() ); eventFrame.invert(); vector<Lorentz5Momentum> momenta(3); momenta[0] = hardProcess[0]->momentum(); if(iemit==0) { momenta[2] = eventFrame*pspect; momenta[1] = eventFrame*pemit ; } else { momenta[1] = eventFrame*pspect; momenta[2] = eventFrame*pemit ; } momenta.push_back(eventFrame*pgluon); // calculate the weight if(1.-x1>1e-5 && 1.-x2>1e-5) realwgt += meRatio(partons,momenta,iemit,subtract); return realwgt; } diff --git a/MatrixElement/Matchbox/Phasespace/FFMassiveInvertedTildeKinematics.cc b/MatrixElement/Matchbox/Phasespace/FFMassiveInvertedTildeKinematics.cc --- a/MatrixElement/Matchbox/Phasespace/FFMassiveInvertedTildeKinematics.cc +++ b/MatrixElement/Matchbox/Phasespace/FFMassiveInvertedTildeKinematics.cc @@ -1,304 +1,310 @@ // -*- C++ -*- // // FFMassiveInvertedTildeKinematics.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2012 The Herwig Collaboration // // Herwig is licenced under version 2 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 FFMassiveInvertedTildeKinematics class. // #include "FFMassiveInvertedTildeKinematics.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Repository/EventGenerator.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "Herwig/MatrixElement/Matchbox/Phasespace/RandomHelpers.h" using namespace Herwig; FFMassiveInvertedTildeKinematics::FFMassiveInvertedTildeKinematics() {} FFMassiveInvertedTildeKinematics::~FFMassiveInvertedTildeKinematics() {} IBPtr FFMassiveInvertedTildeKinematics::clone() const { return new_ptr(*this); } IBPtr FFMassiveInvertedTildeKinematics::fullclone() const { return new_ptr(*this); } bool FFMassiveInvertedTildeKinematics::doMap(const double * r) { if ( ptMax() < ptCut() ) { jacobian(0.0); return false; } Lorentz5Momentum emitter = bornEmitterMomentum(); Lorentz5Momentum spectator = bornSpectatorMomentum(); double mapping = 1.0; - pair<Energy,double> ptz = generatePtZ(mapping,r); + vector<double> values; + pair<Energy,double> ptz = generatePtZ(mapping,r, &values); if ( mapping == 0.0 ) { jacobian(0.0); return false; } + // pt and zPrime = qi.nk / (qi+qj).nk are the generated variables Energy pt = ptz.first; - double z = ptz.second; + Energy2 pt2 = sqr(pt); + double zPrime = ptz.second; + + // Define the scale Energy scale = (emitter+spectator).m(); + Energy2 Qijk = sqr(scale); + + // Most of the required values have been calculated in ptzAllowed + double y = values[0]; + double z = values[1]; + double xk = values[3]; + double xij = values[4]; + double suijk = values[5]; + double suijk2 = sqr(values[5]); + // masses double mui2 = sqr( realEmitterData()->hardProcessMass() / scale ); double mu2 = sqr( realEmissionData()->hardProcessMass() / scale ); double muj2 = sqr( realSpectatorData()->hardProcessMass() / scale ); double Mui2 = sqr( bornEmitterData()->hardProcessMass() / scale ); double Muj2 = sqr( bornSpectatorData()->hardProcessMass() / scale ); - - double y = ( sqr( pt / scale ) + sqr(1.-z)*mui2 + z*z*mu2 ) / - (z*(1.-z)*(1.-mui2-mu2-muj2)); - - // now this is done in ptzAllowed!! - // check (y,z) phasespace boundary - // 2011-11-09: never occurred - /** - double bar = 1.-mui2-mu2-muj2; - double ym = 2.*sqrt(mui2)*sqrt(mu2)/bar; - double yp = 1. - 2.*sqrt(muj2)*(1.-sqrt(muj2))/bar; - double zm = ( (2.*mui2+bar*y)*(1.-y) - sqrt(y*y-ym*ym)*sqrt(sqr(2.*muj2+bar-bar*y)-4.*muj2) ) / - ( 2.*(1.-y)*(mui2+mu2+bar*y) ); - double zp = ( (2.*mui2+bar*y)*(1.-y) + sqrt(y*y-ym*ym)*sqrt(sqr(2.*muj2+bar-bar*y)-4.*muj2) ) / - ( 2.*(1.-y)*(mui2+mu2+bar*y) ); - if ( y<ym || y>yp || z<zm || z>zp ) { - cout << "A problem occurred in FFMassiveInvertedTildeKinematics::doMap: "; - if(y<ym) cout << "y<ym " << endl; - if(y>yp) cout << "y>yp " << endl; - if(z<zm) cout << "z<zm " << endl; - if(z>zp) cout << "z>zp " << endl; - jacobian(0.0); - return false; - } - **/ - - mapping /= z*(1.-z); - jacobian( mapping*(1.-y)*(sqr(lastScale())/sHat())/(16.*sqr(Constants::pi)) * - sqr(1.-mui2-mu2-muj2) / rootOfKallen(1.,Mui2,Muj2) ); + + // Construct reference momenta nk, nij, nt + Lorentz5Momentum nij = ( suijk2 / (suijk2-Mui2*Muj2) ) * (emitter - (Mui2/suijk)*spectator); + Lorentz5Momentum nk = ( suijk2 / (suijk2-Mui2*Muj2) ) * (spectator - (Muj2/suijk)*emitter); + + // Following notation in notes, qt = sqrt(wt)*nt double phi = 2.*Constants::pi*r[2]; - /* // not used ??? - Lorentz5Momentum kt - = getKt(emitter,spectator,pt,phi); - */ + Lorentz5Momentum qt = getKt(nij,nk,pt,phi); - subtractionParameters().resize(2); - subtractionParameters()[0] = y; - subtractionParameters()[1] = z; - - // kinematics from FFMassiveKinematics.cc - // updated 2011-08-23 - // updated 2011-11-08 - Energy2 sbar = sqr(scale) * (1.-mui2-mu2-muj2); - // CMF: particle energies - Energy Ei = ( sbar*(1.-(1.-z)*(1.-y)) + 2.*sqr(scale)*mui2 ) / (2.*scale); - Energy E = ( sbar*(1.- z *(1.-y)) + 2.*sqr(scale)*mu2 ) / (2.*scale); - Energy Ej = ( sbar*(1.- y ) + 2.*sqr(scale)*muj2 ) / (2.*scale); - // CMF: momenta in z-direction (axis of pEmitter &pEmitter pSpectator) - Energy qi3 = (2.*Ei*Ej-z*(1.-y)*sbar ) / 2./sqrt(Ej*Ej-sqr(scale)*muj2); - Energy q3 = (2.*E *Ej-(1.-z)*(1.-y)*sbar) / 2./sqrt(Ej*Ej-sqr(scale)*muj2); - Energy qj3 = sqrt( sqr(Ej) - sqr(scale)*muj2 ); - // get z axis in the dipole's CMF which is parallel to pSpectator - Boost toCMF = (emitter+spectator).findBoostToCM(); - Lorentz5Momentum pjAux = spectator; pjAux.boost(toCMF); - ThreeVector<double> pjAxis = pjAux.vect().unit(); - // set the momenta in this special reference frame - // note that pt might in some cases differ from the physical pt! - Energy ptResc = sqrt( sqr(Ei)-sqr(scale)*mui2-sqr(qi3) ); - Lorentz5Momentum em ( ptResc*cos(phi), -ptResc*sin(phi), qi3, Ei ); - Lorentz5Momentum emm ( -ptResc*cos(phi), ptResc*sin(phi), q3, E ); - Lorentz5Momentum spe ( 0.*GeV, 0.*GeV, qj3, Ej ); - // rotate back - em.rotateUz (pjAxis); - emm.rotateUz(pjAxis); - spe.rotateUz(pjAxis); - // boost back - em.boost (-toCMF); - emm.boost(-toCMF); - spe.boost(-toCMF); - // mass shells, rescale energy - em.setMass(scale*sqrt(mui2)); + // Construct qij, qk, qi and qj + Lorentz5Momentum qij = xij*nij + (Mui2/(xij*suijk))*nk; + Lorentz5Momentum spe = xk*nk + (Muj2/(xk*suijk))*nij; + + Lorentz5Momentum em = zPrime*qij + ((pt2/Qijk + mui2 - zPrime*zPrime*Mui2)/(xij*suijk*zPrime))*nk + qt; + Lorentz5Momentum emm = (1.-zPrime)*qij + ((pt2/Qijk + mu2 - sqr(1.-zPrime)*Mui2)/(xij*suijk*(1.-zPrime)))*nk - qt; + + em.setMass(realEmitterData()->hardProcessMass()); em.rescaleEnergy(); - emm.setMass(scale*sqrt(mu2)); + emm.setMass(realEmissionData()->hardProcessMass()); emm.rescaleEnergy(); - spe.setMass(scale*sqrt(muj2)); + spe.setMass(realSpectatorData()->hardProcessMass()); spe.rescaleEnergy(); // book realEmitterMomentum() = em; realEmissionMomentum() = emm; realSpectatorMomentum() = spe; + // Store the jacobian + mapping /= z*(1.-z); + jacobian( mapping*(1.-y)*(sqr(lastScale())/sHat())/(16.*sqr(Constants::pi)) * + sqr(1.-mui2-mu2-muj2) / rootOfKallen(1.,Mui2,Muj2) ); + + // Store the parameters + subtractionParameters().resize(3); + subtractionParameters()[0] = y; + subtractionParameters()[1] = z; + subtractionParameters()[2] = zPrime; + return true; } + Energy FFMassiveInvertedTildeKinematics::lastPt() const { Energy scale = (bornEmitterMomentum()+bornSpectatorMomentum()).m(); // masses double mui2 = sqr( realEmitterData()->hardProcessMass() / scale ); double mu2 = sqr( realEmissionData()->hardProcessMass() / scale ); double muj2 = sqr( realSpectatorData()->hardProcessMass() / scale ); double y = subtractionParameters()[0]; - double z = subtractionParameters()[1]; + double zPrime = subtractionParameters()[2]; - Energy ret = scale * sqrt( y * (1.-mui2-mu2-muj2) * z*(1.-z) - sqr(1.-z)*mui2 - sqr(z)*mu2 ); + Energy ret = scale * sqrt( y * (1.-mui2-mu2-muj2) * zPrime*(1.-zPrime) - sqr(1.-zPrime)*mui2 - sqr(zPrime)*mu2 ); return ret; } double FFMassiveInvertedTildeKinematics::lastZ() const { - return subtractionParameters()[1]; -} - + return subtractionParameters()[2]; +} + Energy FFMassiveInvertedTildeKinematics::ptMax() const { Energy scale = (bornEmitterMomentum()+bornSpectatorMomentum()).m(); // masses double mui2 = sqr( realEmitterData()->hardProcessMass() / scale ); double mu2 = sqr( realEmissionData()->hardProcessMass() / scale ); double muj2 = sqr( realSpectatorData()->hardProcessMass() / scale ); Energy ptmax = rootOfKallen( mui2, mu2, sqr(1.-sqrt(muj2)) ) / ( 2.-2.*sqrt(muj2) ) * scale; return ptmax > 0.*GeV ? ptmax : 0.*GeV; } // NOTE: bounds calculated at this step may be too loose +// These apply to zPrime, which is stored in lastZ() pair<double,double> FFMassiveInvertedTildeKinematics::zBounds(Energy pt, Energy hardPt) const { hardPt = hardPt == ZERO ? ptMax() : min(hardPt,ptMax()); if(pt>hardPt) return make_pair(0.5,0.5); Energy scale = (bornEmitterMomentum()+bornSpectatorMomentum()).m(); // masses double mui2 = sqr( realEmitterData()->hardProcessMass() / scale ); double mu2 = sqr( realEmissionData()->hardProcessMass() / scale ); double muj2 = sqr( realSpectatorData()->hardProcessMass() / scale ); double zp = ( 1.+mui2-mu2+muj2-2.*sqrt(muj2) + rootOfKallen(mui2,mu2,sqr(1-sqrt(muj2))) * sqrt( 1.-sqr(pt/hardPt) ) ) / ( 2.*sqr(1.-sqrt(muj2)) ); double zm = ( 1.+mui2-mu2+muj2-2.*sqrt(muj2) - rootOfKallen(mui2,mu2,sqr(1-sqrt(muj2))) * sqrt( 1.-sqr(pt/hardPt) ) ) / ( 2.*sqr(1.-sqrt(muj2)) ); return make_pair(zm,zp); } -bool FFMassiveInvertedTildeKinematics::ptzAllowed(pair<Energy,double> ptz) const { +bool FFMassiveInvertedTildeKinematics::ptzAllowed(pair<Energy,double> ptz, vector<double>* values) const { + + Energy pt = ptz.first; + Energy2 pt2 = sqr(pt); + double zPrime = ptz.second; + // masses double mui2 = sqr( realEmitterData()->hardProcessMass() / lastScale() ); double mu2 = sqr( realEmissionData()->hardProcessMass() / lastScale() ); double muj2 = sqr( realSpectatorData()->hardProcessMass() / lastScale() ); + double Mui2 = sqr( bornEmitterData()->hardProcessMass() / lastScale() ); + double Muj2 = sqr( bornSpectatorData()->hardProcessMass() / lastScale() ); - Energy pt = ptz.first; - double z = ptz.second; - - double y = ( sqr( pt / lastScale() ) + sqr(1.-z)*mui2 + z*z*mu2 ) / - (z*(1.-z)*(1.-mui2-mu2-muj2)); + // Calculate the scales that we need + Energy2 Qijk = sqr(lastScale()); + double suijk = 0.5*( 1. - Mui2 - Muj2 + sqrt( sqr(1.-Mui2-Muj2) - 4.*Mui2*Muj2 ) ); + double bar = 1.-mui2-mu2-muj2; + + double y = ( pt2/Qijk + sqr(1.-zPrime)*mui2 + zPrime*zPrime*mu2 ) / + (zPrime*(1.-zPrime)*bar); + + // Calculate A:=xij*w + double A = (1./(suijk*zPrime*(1.-zPrime))) * ( pt2/Qijk + zPrime*mu2 + (1.-zPrime)*mui2 - zPrime*(1.-zPrime)*Mui2 ); + + // Calculate the scaling factors, xk and xij + double lambdaK = 1. + (Muj2/suijk); + double lambdaIJ = 1. + (Mui2/suijk); + double xk = (1./(2.*lambdaK)) * ( (lambdaK + (Muj2/suijk)*lambdaIJ - A) + sqrt( sqr(lambdaK + (Muj2/suijk)*lambdaIJ - A) - 4.*lambdaK*lambdaIJ*Muj2/suijk) ); + double xij = 1. - ( (Muj2/suijk) * (1.-xk) / xk ); + + // Calculate z + double z = ( (zPrime*xij*xk*suijk/2.) + (Muj2/ ( 2.*xk*xij*suijk*zPrime))*(pt2/Qijk + mui2) ) / + ( (xij*xk*suijk/2.) + (Muj2/(2.*xk*xij))*(Mui2/suijk + A) ); // check (y,z) phasespace boundary // TODO: is y boundary necessary? - double bar = 1.-mui2-mu2-muj2; double ym = 2.*sqrt(mui2)*sqrt(mu2)/bar; double yp = 1. - 2.*sqrt(muj2)*(1.-sqrt(muj2))/bar; + // These limits apply to z, not zPrime double zm = ( (2.*mui2+bar*y)*(1.-y) - sqrt(y*y-ym*ym)*sqrt(sqr(2.*muj2+bar-bar*y)-4.*muj2) ) / ( 2.*(1.-y)*(mui2+mu2+bar*y) ); double zp = ( (2.*mui2+bar*y)*(1.-y) + sqrt(y*y-ym*ym)*sqrt(sqr(2.*muj2+bar-bar*y)-4.*muj2) ) / ( 2.*(1.-y)*(mui2+mu2+bar*y) ); if ( y<ym || y>yp || z<zm || z>zp ) return false; + + values->push_back(y); + values->push_back(z); + values->push_back(A); + values->push_back(xk); + values->push_back(xij); + values->push_back(suijk); + return true; } -pair<Energy,double> FFMassiveInvertedTildeKinematics::generatePtZ(double& jac, const double * r) const { + +// This is used to generate pt and zPrime +pair<Energy,double> FFMassiveInvertedTildeKinematics::generatePtZ(double& jac, const double * r, vector<double> * values) const { double kappaMin = ptCut() != ZERO ? sqr(ptCut()/ptMax()) : sqr(0.1*GeV/GeV); double kappa; using namespace RandomHelpers; if ( ptCut() > ZERO ) { pair<double,double> kw = generate(inverse(0.,kappaMin,1.),r[0]); kappa = kw.first; jac *= kw.second; } else { pair<double,double> kw = generate((piecewise(), flat(1e-4,kappaMin), match(inverse(0.,kappaMin,1.))),r[0]); kappa = kw.first; jac *= kw.second; } Energy pt = sqrt(kappa)*ptMax(); pair<double,double> zLims = zBounds(pt); pair<double,double> zw = generate(inverse(0.,zLims.first,zLims.second)+ inverse(1.,zLims.first,zLims.second),r[1]); double z = zw.first; jac *= zw.second; jac *= sqr(ptMax()/lastScale()); - if( !ptzAllowed(make_pair(pt,z)) ) jac = 0.; + if( !ptzAllowed(make_pair(pt,z), values )) jac = 0.; return make_pair(pt,z); } // If needed, insert default implementations of virtual function defined // in the InterfacedBase class here (using ThePEG-interfaced-impl in Emacs). void FFMassiveInvertedTildeKinematics::persistentOutput(PersistentOStream &) const { } void FFMassiveInvertedTildeKinematics::persistentInput(PersistentIStream &, int) { } void FFMassiveInvertedTildeKinematics::Init() { static ClassDocumentation<FFMassiveInvertedTildeKinematics> documentation ("FFMassiveInvertedTildeKinematics inverts the final-final tilde " "kinematics."); } // *** Attention *** The following static variable is needed for the type // description system in ThePEG. Please check that the template arguments // are correct (the class and its base class), and that the constructor // arguments are correct (the class name and the name of the dynamically // loadable library where the class implementation can be found). DescribeClass<FFMassiveInvertedTildeKinematics,InvertedTildeKinematics> describeHerwigFFMassiveInvertedTildeKinematics("Herwig::FFMassiveInvertedTildeKinematics", "Herwig.so"); diff --git a/MatrixElement/Matchbox/Phasespace/FFMassiveInvertedTildeKinematics.h b/MatrixElement/Matchbox/Phasespace/FFMassiveInvertedTildeKinematics.h --- a/MatrixElement/Matchbox/Phasespace/FFMassiveInvertedTildeKinematics.h +++ b/MatrixElement/Matchbox/Phasespace/FFMassiveInvertedTildeKinematics.h @@ -1,178 +1,178 @@ // -*- C++ -*- // // FFMassiveInvertedTildeKinematics.h is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2012 The Herwig Collaboration // // Herwig is licenced under version 2 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // #ifndef HERWIG_FFMassiveInvertedTildeKinematics_H #define HERWIG_FFMassiveInvertedTildeKinematics_H // // This is the declaration of the FFMassiveInvertedTildeKinematics class. // #include "Herwig/MatrixElement/Matchbox/Phasespace/InvertedTildeKinematics.h" namespace Herwig { using namespace ThePEG; /** * \ingroup Matchbox * \author Simon Platzer * * \brief FFMassiveInvertedTildeKinematics inverts the final-final tilde * kinematics. * */ class FFMassiveInvertedTildeKinematics: public Herwig::InvertedTildeKinematics { public: /** @name Standard constructors and destructors. */ //@{ /** * The default constructor. */ FFMassiveInvertedTildeKinematics(); /** * The destructor. */ virtual ~FFMassiveInvertedTildeKinematics(); //@} public: /** * Perform the mapping of the tilde kinematics for the * last selected process and store all dimensionless * variables in the subtractionParameters() vector. * Return false, if the calculation of the real * kinematics was impossible for the selected configuration * and true on success. */ virtual bool doMap(const double *); /** * Return the pt associated to the last generated splitting. */ virtual Energy lastPt() const; /** * Return the momentum fraction associated to the last splitting. */ virtual double lastZ() const; /** * Return the upper bound on pt */ virtual Energy ptMax() const; /** * Given a pt, return the boundaries on z * Note that allowing parton masses these bounds may be too loose */ virtual pair<double,double> zBounds(Energy pt, Energy hardPt = ZERO) const; /** * For generated pt and z, check if this point is * kinematically allowed */ - /*virtual*/ bool ptzAllowed(pair<Energy,double>) const; + /*virtual*/ bool ptzAllowed(pair<Energy,double> ptz, vector<double>* values ) const; /** * Generate pt and z */ - virtual pair<Energy,double> generatePtZ(double& jac, const double * r) const; + virtual pair<Energy,double> generatePtZ(double& jac, const double * r, vector<double>* values) const; public: /** * Triangular / Kallen function */ template <class T> inline T rootOfKallen (T a, T b, T c) const { return sqrt( a*a + b*b + c*c - 2.*( a*b+a*c+b*c ) ); } // TODO: remove in both /** * stolen from FFMassiveKinematics.h * Perform a rotation on both momenta such that the first one will * point along the (positive) z axis. Rotate back to the original * reference frame by applying rotateUz(returnedVector) to each momentum. */ ThreeVector<double> rotateToZ (Lorentz5Momentum& pTarget, Lorentz5Momentum& p1) { ThreeVector<double> oldAxis = pTarget.vect().unit(); double ct = oldAxis.z(); double st = sqrt( 1.-sqr(ct) ); // cos,sin(theta) double cp = oldAxis.x()/st; double sp = oldAxis.y()/st; // cos,sin(phi) pTarget.setZ( pTarget.vect().mag() ); pTarget.setX( 0.*GeV ); pTarget.setY( 0.*GeV ); Lorentz5Momentum p1old = p1; p1.setX( sp*p1old.x() - cp*p1old.y() ); p1.setY( ct*cp*p1old.x() + ct*sp*p1old.y() - st*p1old.z() ); p1.setZ( st*cp*p1old.x() + st*sp*p1old.y() + ct*p1old.z() ); return oldAxis; } 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; //@} // If needed, insert declarations of virtual function defined in the // InterfacedBase class here (using ThePEG-interfaced-decl in Emacs). private: /** * The assignment operator is private and must never be called. * In fact, it should not even be implemented. */ FFMassiveInvertedTildeKinematics & operator=(const FFMassiveInvertedTildeKinematics &); }; } #endif /* HERWIG_FFMassiveInvertedTildeKinematics_H */ diff --git a/MatrixElement/Matchbox/Phasespace/InvertedTildeKinematics.cc b/MatrixElement/Matchbox/Phasespace/InvertedTildeKinematics.cc --- a/MatrixElement/Matchbox/Phasespace/InvertedTildeKinematics.cc +++ b/MatrixElement/Matchbox/Phasespace/InvertedTildeKinematics.cc @@ -1,214 +1,214 @@ // -*- C++ -*- // // InvertedTildeKinematics.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2012 The Herwig Collaboration // // Herwig is licenced under version 2 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 InvertedTildeKinematics class. // #include <limits> #include "InvertedTildeKinematics.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Utilities/Rebinder.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "Herwig/MatrixElement/Matchbox/Phasespace/RandomHelpers.h" using namespace Herwig; InvertedTildeKinematics::InvertedTildeKinematics() : HandlerBase(), theJacobian(0.0), thePtCut(0.0*GeV) {} InvertedTildeKinematics::~InvertedTildeKinematics() {} // If needed, insert default implementations of virtual function defined // in the InterfacedBase class here (using ThePEG-interfaced-impl in Emacs). Lorentz5Momentum InvertedTildeKinematics::getKt(const Lorentz5Momentum& p1, const Lorentz5Momentum& p2, Energy pt, double phi, bool spacelike) const { Lorentz5Momentum P; if ( !spacelike ) P = p1 + p2; else P = p1 - p2; Energy2 Q2 = abs(P.m2()); Lorentz5Momentum Q = !spacelike ? Lorentz5Momentum(ZERO,ZERO,ZERO,sqrt(Q2),sqrt(Q2)) : Lorentz5Momentum(ZERO,ZERO,sqrt(Q2),ZERO,-sqrt(Q2)); if ( spacelike && Q.z() < P.z() ) Q.setZ(-Q.z()); bool boost = abs((P-Q).vect().mag2()/GeV2) > 1e-10 || abs((P-Q).t()/GeV) > 1e-5; boost &= (P*Q-Q.mass2())/GeV2 > 1e-8; Lorentz5Momentum inFrame1; if ( boost ) inFrame1 = p1 + ((P*p1-Q*p1)/(P*Q-Q.mass2()))*(P-Q); else inFrame1 = p1; Energy ptx = inFrame1.x(); Energy pty = inFrame1.y(); Energy q = 2.*inFrame1.z(); Energy Qp = sqrt(4.*(sqr(ptx)+sqr(pty))+sqr(q)); Energy Qy = sqrt(4.*sqr(pty)+sqr(q)); double cPhi = cos(phi); double sPhi = sqrt(1.-sqr(cPhi)); if ( phi > Constants::pi ) sPhi = -sPhi; Lorentz5Momentum kt; if ( !spacelike ) { kt.setT(ZERO); kt.setX(pt*Qy*cPhi/Qp); kt.setY(-pt*(4*ptx*pty*cPhi/Qp+q*sPhi)/Qy); kt.setZ(2.*pt*(-ptx*q*cPhi/Qp + pty*sPhi)/Qy); } else { kt.setT(2.*pt*(ptx*q*cPhi+pty*Qp*sPhi)/(q*Qy)); kt.setX(pt*(Qp*q*cPhi+4.*ptx*pty*sPhi)/(q*Qy)); kt.setY(pt*Qy*sPhi/q); kt.setZ(ZERO); } if ( boost ) kt = kt + ((P*kt-Q*kt)/(P*Q-Q.mass2()))*(P-Q); kt.setMass(-pt); kt.rescaleRho(); return kt; } Energy InvertedTildeKinematics::lastScale() const { if ( ( theDipole->bornEmitter() < 2 && theDipole->bornSpectator() > 1 ) || ( theDipole->bornEmitter() > 1 && theDipole->bornSpectator() < 2 ) ) { return -(bornEmitterMomentum()-bornSpectatorMomentum()).m(); } return (bornEmitterMomentum()+bornSpectatorMomentum()).m(); } pair<Energy,double> InvertedTildeKinematics::generatePtZ(double& jac, const double * r, - double pow) const { + double pow, vector<double>* ) const { double kappaMin = ptCut() != ZERO ? sqr(ptCut()/ptMax()) : sqr(0.1*GeV/GeV); double kappa; using namespace RandomHelpers; if ( ptCut() > ZERO ) { pair<double,double> kw = pow==1. ? generate(inverse(0.,kappaMin,1.),r[0]) : generate(power(0.,-pow,kappaMin,1.),r[0]); kappa = kw.first; jac *= kw.second; } else { pair<double,double> kw = generate((piecewise(), flat(1e-4,kappaMin), match(inverse(0.,kappaMin,1.))),r[0]); kappa = kw.first; jac *= kw.second; } Energy pt = sqrt(kappa)*ptMax(); pair<double,double> zLims = zBounds(pt); pair<double,double> zw(0,0);// = // generate(inverse(0.,zLims.first,zLims.second)+ // inverse(1.,zLims.first,zLims.second),r[1]); // FlatZ = 1 if ( theDipole->samplingZ() == 1 ) { zw = generate(flat(zLims.first,zLims.second),r[1]); } // OneOverZ = 2 if ( theDipole->samplingZ() == 2 ) { zw = generate(inverse(0.0,zLims.first,zLims.second),r[1]); } // OneOverOneMinusZ = 3 if ( theDipole->samplingZ() == 3 ) { zw = generate(inverse(1.0,zLims.first,zLims.second),r[1]); } // OneOverZOneMinusZ = 4 if ( theDipole->samplingZ() == 4 ) { zw = generate(inverse(0.0,zLims.first,zLims.second) + inverse(1.0,zLims.first,zLims.second),r[1]); } double z = zw.first; jac *= zw.second; jac *= sqr(ptMax()/lastScale()); return make_pair(pt,z); } void InvertedTildeKinematics::rebind(const TranslationMap & trans) { theDipole = trans.translate(theDipole); HandlerBase::rebind(trans); } IVector InvertedTildeKinematics::getReferences() { IVector ret = HandlerBase::getReferences(); ret.push_back(theDipole); return ret; } void InvertedTildeKinematics::persistentOutput(PersistentOStream & os) const { os << theDipole << theRealXComb << theBornXComb << ounit(theRealEmitterMomentum,GeV) << ounit(theRealEmissionMomentum,GeV) << ounit(theRealSpectatorMomentum,GeV) << theJacobian << ounit(thePtCut,GeV); } void InvertedTildeKinematics::persistentInput(PersistentIStream & is, int) { is >> theDipole >> theRealXComb >> theBornXComb >> iunit(theRealEmitterMomentum,GeV) >> iunit(theRealEmissionMomentum,GeV) >> iunit(theRealSpectatorMomentum,GeV) >> theJacobian >> iunit(thePtCut,GeV); } void InvertedTildeKinematics::Init() { static ClassDocumentation<InvertedTildeKinematics> documentation ("InvertedTildeKinematics is the base class for the inverted 'tilde' " "kinematics being used for subtraction terms in the " "formalism of Catani and Seymour."); } // *** Attention *** The following static variable is needed for the type // description system in ThePEG. Please check that the template arguments // are correct (the class and its base class), and that the constructor // arguments are correct (the class name and the name of the dynamically // loadable library where the class implementation can be found). DescribeAbstractClass<InvertedTildeKinematics,HandlerBase> describeInvertedTildeKinematics("Herwig::InvertedTildeKinematics", "Herwig.so"); diff --git a/MatrixElement/Matchbox/Phasespace/InvertedTildeKinematics.h b/MatrixElement/Matchbox/Phasespace/InvertedTildeKinematics.h --- a/MatrixElement/Matchbox/Phasespace/InvertedTildeKinematics.h +++ b/MatrixElement/Matchbox/Phasespace/InvertedTildeKinematics.h @@ -1,450 +1,450 @@ // -*- C++ -*- // // InvertedTildeKinematics.h is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2012 The Herwig Collaboration // // Herwig is licenced under version 2 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // #ifndef HERWIG_InvertedTildeKinematics_H #define HERWIG_InvertedTildeKinematics_H // // This is the declaration of the InvertedTildeKinematics class. // #include "ThePEG/Handlers/HandlerBase.h" #include "ThePEG/Handlers/StandardXComb.h" #include "ThePEG/Repository/EventGenerator.h" #include "Herwig/MatrixElement/Matchbox/Dipoles/SubtractionDipole.h" namespace Herwig { using namespace ThePEG; /** * \ingroup Matchbox * \author Simon Platzer * * \brief InvertedTildeKinematics is the base class for the inverted 'tilde' * kinematics being used for subtraction terms in the * formalism of Catani and Seymour. * */ class InvertedTildeKinematics: public HandlerBase { public: /** @name Standard constructors and destructors. */ //@{ /** * The default constructor. */ InvertedTildeKinematics(); /** * The destructor. */ virtual ~InvertedTildeKinematics(); //@} public: /** @name Access to kinematic quantities. */ //@{ /** * Return the momentum of the emitter in the real emission process */ const Lorentz5Momentum& realEmitterMomentum() const { return theRealEmitterMomentum; } /** * Return the momentum of the emission in the real emission process */ const Lorentz5Momentum& realEmissionMomentum() const { return theRealEmissionMomentum; } /** * Return the momentum of the spectator in the real emission process */ const Lorentz5Momentum& realSpectatorMomentum() const { return theRealSpectatorMomentum; } /** * Return the momentum of the emitter in the underlying Born process */ const Lorentz5Momentum& bornEmitterMomentum() const { return theBornXComb->meMomenta()[theDipole->bornEmitter()]; } /** * Return the momentum of the spectator in the underlying Born process */ const Lorentz5Momentum& bornSpectatorMomentum() const { return theBornXComb->meMomenta()[theDipole->bornSpectator()]; } /** * Return the momentum fraction of the emitter */ double emitterX() const { return theDipole->bornEmitter() == 0 ? theBornXComb->lastX1() : theBornXComb->lastX2(); } /** * Return the momentum fraction of the spectator */ double spectatorX() const { return theDipole->bornSpectator() == 0 ? theBornXComb->lastX1() : theBornXComb->lastX2(); } /** * Return the vector of dimensionless variables calculated */ const vector<double>& subtractionParameters() const { return theDipole->subtractionParameters(); } /** * Return true, if this InvertedTildeKinematics object needs to transform * all other particles in the process except the emitter, emission and spectator */ virtual bool doesTransform() const { return false; } /** * If this InvertedTildeKinematics object needs to transform all other particles * in the process except the emitter, emission and spectator, return the transformed * momentum. */ virtual Lorentz5Momentum transform(const Lorentz5Momentum& p) const { return p; } /** * Return the centre of mass energy for the underlying Born configuration */ Energy2 sHat() const { return theBornXComb->lastSHat(); } //@} public: /** * Clone this object */ Ptr<InvertedTildeKinematics>::ptr cloneMe() const { return dynamic_ptr_cast<Ptr<InvertedTildeKinematics>::ptr>(clone()); } /** @name Access to process data. */ //@{ /** * Prepare given a dipole, and XCombs describing the real emission * and underlying Born processes, respectively. */ void prepare(tcStdXCombPtr newRealXComb, tcStdXCombPtr newBornXComb) { theRealXComb = newRealXComb; theBornXComb = newBornXComb; } /** * Return the real xcomb */ tcStdXCombPtr realXComb() const { return theRealXComb; } /** * Return the Born xcomb */ tcStdXCombPtr bornXComb() const { return theBornXComb; } /** * Set the current dipole */ void dipole(Ptr<SubtractionDipole>::tptr dip) { theDipole = dip; } /** * Return the current dipole */ Ptr<SubtractionDipole>::tptr dipole() { return theDipole; } /** * Return the current dipole */ Ptr<SubtractionDipole>::tcptr dipole() const { return theDipole; } /** * Return the number of random numbers needed to generate * a real emission configuration off the underlying Born * configuration. */ virtual int nDimRadiation() const { return 3; } /** * Perform the mapping of the tilde kinematics for the * last selected process and store all dimensionless * variables in the subtractionParameters() vector. * Return false, if the calculation of the real * kinematics was impossible for the selected configuration * and true on success. */ virtual bool doMap(const double *) = 0; /** * Set an optional cutoff on the emission's * transverse momentum. */ void ptCut(Energy pt) { thePtCut = pt; } /** * Return the optional cutoff on the emission's * transverse momentum. */ Energy ptCut() const { return thePtCut; } /** * Return the random number index * corresponding to the evolution variable. */ virtual int evolutionVariable() const { return 0; } /** * Return the cutoff on the evolution * random number corresponding to the pt cut. */ virtual double evolutionCutoff() const { return 0.0; } /** * Return the pt associated to the last generated splitting. */ virtual Energy lastPt() const = 0; /** * Return the momentum fraction associated to the last splitting. */ virtual double lastZ() const = 0; /** * Return the relevant dipole scale */ virtual Energy lastScale() const; /** * Return the upper bound on pt */ virtual Energy ptMax() const = 0; /** * Given a pt and a hard pt, return the boundaries on z; if the hard * pt is zero, ptMax() will be used. */ virtual pair<double,double> zBounds(Energy pt, Energy hardPt = ZERO) const = 0; /** * Generate pt and z */ virtual pair<Energy,double> generatePtZ(double& jac, const double * r, - double power=1.) const; + double power=1., vector<double>* values = NULL) const; /** * Return the single particle phasespace weight in units * of sHat() for the last selected configuration. */ double jacobian() const { return theJacobian; } /** * Return the particle type of the emitter in the real emission process */ cPDPtr realEmitterData() const { return (theDipole && theRealXComb) ? theRealXComb->mePartonData()[theDipole->realEmitter()] : cPDPtr(); } /** * Return the particle type of the emission in the real emission process */ cPDPtr realEmissionData() const { return (theDipole && theRealXComb) ? theRealXComb->mePartonData()[theDipole->realEmission()] : cPDPtr(); } /** * Return the particle type of the spectator in the real emission process */ cPDPtr realSpectatorData() const { return (theDipole && theRealXComb) ? theRealXComb->mePartonData()[theDipole->realSpectator()] : cPDPtr(); } /** * Return the particle type of the emitter in the underlying Born process */ cPDPtr bornEmitterData() const { return (theDipole && theBornXComb) ? theBornXComb->mePartonData()[theDipole->bornEmitter()] : cPDPtr(); } /** * Return the particle type of the spectator in the underlying Born process */ cPDPtr bornSpectatorData() const { return (theDipole && theBornXComb) ? theBornXComb->mePartonData()[theDipole->bornSpectator()] : cPDPtr(); } //@} protected: /** * Access the momentum of the emitter in the real emission process */ Lorentz5Momentum& realEmitterMomentum() { return theRealEmitterMomentum; } /** * Access the momentum of the emission in the real emission process */ Lorentz5Momentum& realEmissionMomentum() { return theRealEmissionMomentum; } /** * Access the momentum of the spectator in the real emission process */ Lorentz5Momentum& realSpectatorMomentum() { return theRealSpectatorMomentum; } /** * Access the vector of dimensionless variables calculated */ vector<double>& subtractionParameters() { return theDipole->subtractionParameters(); } /** * Set the single particle phasespace weight in units * of sHat() for the last selected configuration. */ void jacobian(double w) { theJacobian = w; } /** * Calculate a transverse momentum for the given momenta, * invariant pt and azimuth. */ Lorentz5Momentum getKt(const Lorentz5Momentum& p1, const Lorentz5Momentum& p2, Energy pt, double phi, bool spacelike = false) const; 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(); // If needed, insert declarations of virtual function defined in the // InterfacedBase class here (using ThePEG-interfaced-decl in Emacs). protected: /** @name Standard Interfaced functions. */ //@{ /** * Rebind pointer to other Interfaced objects. Called in the setup phase * after all objects used in an EventGenerator has been cloned so that * the pointers will refer to the cloned objects afterwards. * @param trans a TranslationMap relating the original objects to * their respective clones. * @throws RebindException if no cloned object was found for a given * pointer. */ virtual void rebind(const TranslationMap & trans); /** * Return a vector of all pointers to Interfaced objects used in this * object. * @return a vector of pointers. */ virtual IVector getReferences(); //@} private: /** * The last dipole this InvertedTildeKinematics has been selected for */ Ptr<SubtractionDipole>::tptr theDipole; /** * The XComb object describing the real emission process */ tcStdXCombPtr theRealXComb; /** * The XComb object describing the underlying Born process */ tcStdXCombPtr theBornXComb; /** * The momentum of the emitter in the real emission process */ Lorentz5Momentum theRealEmitterMomentum; /** * The momentum of the emission in the real emission process */ Lorentz5Momentum theRealEmissionMomentum; /** * The momentum of the spectator in the real emission process */ Lorentz5Momentum theRealSpectatorMomentum; /** * Return the single particle phasespace weight in units * of sHat() for the last selected configuration. */ double theJacobian; /** * The optional cutoff on the emission's * transverse momentum. */ Energy thePtCut; private: /** * The assignment operator is private and must never be called. * In fact, it should not even be implemented. */ InvertedTildeKinematics & operator=(const InvertedTildeKinematics &); }; } #endif /* HERWIG_InvertedTildeKinematics_H */ diff --git a/Shower/Dipole/Base/DipoleEventRecord.cc b/Shower/Dipole/Base/DipoleEventRecord.cc --- a/Shower/Dipole/Base/DipoleEventRecord.cc +++ b/Shower/Dipole/Base/DipoleEventRecord.cc @@ -1,1516 +1,1498 @@ // -*- C++ -*- // // DipoleEventRecord.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2007 The Herwig Collaboration // // Herwig is licenced under version 2 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 DipoleEventRecord class. // #include "DipoleEventRecord.h" #include "Herwig/Shower/Dipole/Utility/DipolePartonSplitter.h" #include "Herwig/Shower/ShowerHandler.h" #include "ThePEG/PDT/DecayMode.h" #include "Herwig/Decay/HwDecayerBase.h" #include "ThePEG/Repository/EventGenerator.h" #include "ThePEG/PDF/PartonExtractor.h" #include "Herwig/Shower/RealEmissionProcess.h" #include <boost/utility.hpp> #include <algorithm> #include <iterator> using namespace Herwig; PList DipoleEventRecord::colourOrdered(PPair & in, PList & out) { PList colour_ordered; size_t done_size = out.size(); if (in.first->coloured()) ++done_size; if (in.second && in.second->coloured()) ++done_size; while (colour_ordered.size() != done_size) { PPtr current; // start with singlets, as long as we have some if (find(colour_ordered.begin(),colour_ordered.end(),in.first) == colour_ordered.end() && in.first->coloured()) { if (!in.first->hasColour() || !in.first->hasAntiColour()) current = in.first; } if (!current) { for (PList::iterator p = out.begin(); p != out.end(); ++p) { if (find(colour_ordered.begin(),colour_ordered.end(),*p) == colour_ordered.end() && (**p).coloured()) { if (!(**p).hasColour() || !(**p).hasAntiColour()) { current = *p; break; } } } } if (!current) { if (in.second && find(colour_ordered.begin(),colour_ordered.end(),in.second) == colour_ordered.end() && in.second->coloured()) { if (!in.second->hasColour() || !in.second->hasAntiColour()) current = in.second; } } // then go on with anything else if (!current) { if (find(colour_ordered.begin(),colour_ordered.end(),in.first) == colour_ordered.end() && in.first->coloured()) { current = in.first; } } if (!current) { for (PList::iterator p = out.begin(); p != out.end(); ++p) { if (find(colour_ordered.begin(),colour_ordered.end(),*p) == colour_ordered.end() && (**p).coloured()) { current = *p; break; } } } if (!current) { if (in.second && find(colour_ordered.begin(),colour_ordered.end(),in.second) == colour_ordered.end() && in.second->coloured()) { current = in.second; } } assert(current); PPtr next; Ptr<ColourLine>::ptr walk_the_line; while (true) { if (!walk_the_line) { if (current->hasColour()) { walk_the_line = current->colourLine(); } else if (current->hasAntiColour()) { walk_the_line = current->antiColourLine(); } } if (!next) for (tPVector::const_iterator p = walk_the_line->coloured().begin(); p != walk_the_line->coloured().end(); ++p) { if (*p == current) continue; if (find(out.begin(),out.end(),*p) != out.end() || *p == in.first || (in.second && *p == in.second)) { next = *p; if (next->hasColour() && next->hasAntiColour()) { walk_the_line = walk_the_line == next->colourLine() ? next->antiColourLine() : next->colourLine(); } break; } } if (!next) for (tPVector::const_iterator p = walk_the_line->antiColoured().begin(); p != walk_the_line->antiColoured().end(); ++p) { if (*p == current) continue; if (find(out.begin(),out.end(),*p) != out.end() || *p == in.first || (in.second && *p == in.second)) { next = *p; if (next->hasColour() && next->hasAntiColour()) { walk_the_line = walk_the_line == next->colourLine() ? next->antiColourLine() : next->colourLine(); } break; } } assert(next); colour_ordered.push_back(current); current = next; // done if next is not a gluon or next is already in colour_ordered if ((current->hasColour() && !current->hasAntiColour()) || (!current->hasColour() && current->hasAntiColour())) { colour_ordered.push_back(current); break; } if (next->hasColour() && next->hasAntiColour()) { if (find(colour_ordered.begin(),colour_ordered.end(),next) != colour_ordered.end()) break; } next = PPtr(); } } return colour_ordered; } void DipoleEventRecord::popChain() { assert(!theChains.empty()); theDoneChains.push_back(DipoleChain()); theDoneChains.back().dipoles().splice(theDoneChains.back().dipoles().begin(),theChains.front().dipoles()); theChains.pop_front(); } void DipoleEventRecord::popChain(list<DipoleChain>::iterator ch) { assert(!theChains.empty()); theDoneChains.push_back(DipoleChain()); theDoneChains.back().dipoles().splice(theDoneChains.back().dipoles().begin(),ch->dipoles()); theChains.erase(ch); } void DipoleEventRecord::popChains(const list<list<DipoleChain>::iterator>& chs) { assert(!theChains.empty()); for ( list<list<DipoleChain>::iterator>::const_iterator ch = chs.begin(); ch != chs.end(); ++ch ) { theDoneChains.push_back(DipoleChain()); theDoneChains.back().dipoles().splice(theDoneChains.back().dipoles().begin(),(*ch)->dipoles()); } for ( list<list<DipoleChain>::iterator>::const_iterator ch = chs.begin(); ch != chs.end(); ++ch ) theChains.erase(*ch); } DipoleIndex DipoleEventRecord::mergeIndex(list<Dipole>::iterator firstDipole, const pair<bool,bool>& whichFirst, list<Dipole>::iterator secondDipole, const pair<bool,bool>& whichSecond) const { tcPDPtr emitterData = whichFirst.first ? firstDipole->leftParticle()->dataPtr() : firstDipole->rightParticle()->dataPtr(); tcPDPtr spectatorData = whichSecond.first ? secondDipole->leftParticle()->dataPtr() : secondDipole->rightParticle()->dataPtr(); const PDF& emitterPDF = whichFirst.first ? firstDipole->leftPDF() : firstDipole->rightPDF(); const PDF& spectatorPDF = whichSecond.first ? secondDipole->leftPDF() : secondDipole->rightPDF(); return DipoleIndex(emitterData,spectatorData,emitterPDF,spectatorPDF); } SubleadingSplittingInfo DipoleEventRecord::mergeSplittingInfo(list<DipoleChain>::iterator firstChain, list<Dipole>::iterator firstDipole, const pair<bool,bool>& whichFirst, list<DipoleChain>::iterator secondChain, list<Dipole>::iterator secondDipole, const pair<bool,bool>& whichSecond) const { SubleadingSplittingInfo res; res.index(mergeIndex(firstDipole,whichFirst,secondDipole,whichSecond)); res.emitter(whichFirst.first ? firstDipole->leftParticle() : firstDipole->rightParticle()); res.spectator(whichSecond.first ? secondDipole->leftParticle() : secondDipole->rightParticle()); res.emitterX(whichFirst.first ? firstDipole->leftFraction() : firstDipole->rightFraction()); res.spectatorX(whichSecond.first ? secondDipole->leftFraction() : secondDipole->rightFraction()); res.configuration(whichFirst); res.spectatorConfiguration(whichSecond); res.emitterChain(firstChain); res.emitterDipole(firstDipole); res.spectatorChain(secondChain); res.spectatorDipole(secondDipole); return res; } void DipoleEventRecord::getSubleadingSplittings(list<SubleadingSplittingInfo>& res) { static pair<bool,bool> left(true,false); static pair<bool,bool> right(false,true); res.clear(); for ( list<DipoleChain>::iterator cit = theChains.begin(); cit != theChains.end(); ++cit ) { for ( list<Dipole>::iterator dit = cit->dipoles().begin(); dit != cit->dipoles().end(); ++dit ) { for ( list<Dipole>::iterator djt = dit; djt != cit->dipoles().end(); ++djt ) { res.push_back(mergeSplittingInfo(cit,dit,left,cit,djt,left)); res.push_back(mergeSplittingInfo(cit,dit,right,cit,djt,right)); if ( dit != djt ) { res.push_back(mergeSplittingInfo(cit,dit,left,cit,djt,right)); res.push_back(mergeSplittingInfo(cit,dit,right,cit,djt,left)); } } } list<DipoleChain>::iterator cjt = cit; ++cjt; for ( ; cjt != theChains.end(); ++cjt ) { for ( list<Dipole>::iterator dit = cit->dipoles().begin(); dit != cit->dipoles().end(); ++dit ) { for ( list<Dipole>::iterator djt = cjt->dipoles().begin(); djt != cjt->dipoles().end(); ++djt ) { res.push_back(mergeSplittingInfo(cit,dit,left,cjt,djt,left)); res.push_back(mergeSplittingInfo(cit,dit,right,cjt,djt,right)); res.push_back(mergeSplittingInfo(cit,dit,left,cjt,djt,right)); res.push_back(mergeSplittingInfo(cit,dit,right,cjt,djt,left)); } } } } } void DipoleEventRecord::splitSubleading(SubleadingSplittingInfo& dsplit, pair<list<Dipole>::iterator,list<Dipole>::iterator>& childIterators, DipoleChain*& firstChain, DipoleChain*& secondChain) { if ( dsplit.emitterDipole() == dsplit.spectatorDipole() ) { assert(dsplit.emitterChain() == dsplit.spectatorChain()); split(dsplit.emitterDipole(),dsplit.emitterChain(),dsplit, childIterators,firstChain,secondChain,false); } else { // first need to recoil, then split recoil(dsplit.spectatorDipole(),dsplit.spectatorChain(),dsplit); split(dsplit.emitterDipole(),dsplit.emitterChain(),dsplit, childIterators,firstChain,secondChain,true); } } void DipoleEventRecord::findChains(const PList& ordered, const bool decay) { theChains.clear(); theDoneChains.clear(); DipoleChain current_chain; // this whole thing needs to have a more elegant implementation at some point bool startIsTriplet = (ordered.front()->hasColour() && !ordered.front()->hasAntiColour()) || (!ordered.front()->hasColour() && ordered.front()->hasAntiColour()); bool endIsTriplet = (ordered.back()->hasColour() && !ordered.back()->hasAntiColour()) || (!ordered.back()->hasColour() && ordered.back()->hasAntiColour()); if (!( ordered.size() == 2 && startIsTriplet && endIsTriplet)) { PList::const_iterator theStart = ordered.begin(); bool onceMore = false; for (PList::const_iterator p = ordered.begin(); p != ordered.end(); ++p) { PList::const_iterator next_it = p != --ordered.end() ? std::next(p) : ordered.begin(); if (!DipolePartonSplitter::colourConnected(*p,*next_it)) { // it may have happened that we need to close the chain due to another // chain starting right now; see the above global comment for this fix bool startIsOctet = (**theStart).hasColour() && (**theStart).hasAntiColour(); bool endIsOctet = (**p).hasColour() && (**p).hasAntiColour(); if ( DipolePartonSplitter::colourConnected(*p,*theStart) && startIsOctet && endIsOctet ) { swap(next_it,theStart); onceMore = true; } else { theStart = next_it; current_chain.check(); theChains.push_back(current_chain); current_chain.dipoles().clear(); continue; } } pair<bool,bool> initial_state (false,false); initial_state.first = (*p == incoming().first || *p == incoming().second); initial_state.second = (*next_it == incoming().first || *next_it == incoming().second); pair<int,int> which_in (-1,-1); if (initial_state.first) which_in.first = *p == incoming().first ? 0 : 1; if (initial_state.second) which_in.second = *next_it == incoming().first ? 0 : 1; pair<double,double> xs (1.,1.); if (initial_state.first) xs.first = *p == incoming().first ? fractions().first : fractions().second; if (initial_state.second) xs.second = *next_it == incoming().first ? fractions().first : fractions().second; pair<PDF,PDF> pdf; if ( which_in.first == 0 ) pdf.first = pdfs().first; else if ( which_in.first == 1 ) pdf.first = pdfs().second; if ( which_in.second == 0 ) pdf.second = pdfs().first; else if ( which_in.second == 1 ) pdf.second = pdfs().second; // In the case of a decay process register which // parton is incoming to the decay pair<bool,bool> decayed_parton (false,false); if (decay) { decayed_parton.first = (*p == currentDecay()->incoming()[0].first); decayed_parton.second = (*next_it == currentDecay()->incoming()[0].first); - // Should only ever have one incoming parton to a decay process - //assert(!(decayed_parton.first && decayed_parton.second)); } current_chain.dipoles().push_back(Dipole({*p,*next_it},pdf,xs,decayed_parton)); if ( onceMore ) { next_it = theStart; current_chain.check(); theChains.push_back(current_chain); current_chain.dipoles().clear(); onceMore = false; } } } else { // treat 2 -> singlet, singlet -> 2 and 1 + singlet -> 1 + singlet special // to prevent duplicate dipole assert(DipolePartonSplitter::colourConnected(ordered.front(),ordered.back())); pair<bool,bool> initial_state (false,false); initial_state.first = (ordered.front() == incoming().first || ordered.front() == incoming().second); initial_state.second = (ordered.back() == incoming().first || ordered.back() == incoming().second); pair<int,int> which_in (-1,-1); if (initial_state.first) which_in.first = ordered.front() == incoming().first ? 0 : 1; if (initial_state.second) which_in.second = ordered.back() == incoming().first ? 0 : 1; pair<double,double> xs (1.,1.); if (initial_state.first) xs.first = ordered.front() == incoming().first ? fractions().first : fractions().second; if (initial_state.second) xs.second = ordered.back() == incoming().first ? fractions().first : fractions().second; pair<PDF,PDF> pdf; if ( which_in.first == 0 ) pdf.first = pdfs().first; else if ( which_in.first == 1 ) pdf.first = pdfs().second; if ( which_in.second == 0 ) pdf.second = pdfs().first; else if ( which_in.second == 1 ) pdf.second = pdfs().second; // In the case of a decay process register which // parton is incoming to the decay pair<bool,bool> decayed_parton (false,false); if (decay) { decayed_parton.first = (ordered.front() == currentDecay()->incoming()[0].first); decayed_parton.second = (ordered.back() == currentDecay()->incoming()[0].first); - // Should only ever have one incoming parton to a decay process - //assert(!(decayed_parton.first && decayed_parton.second)); } current_chain.dipoles().push_back(Dipole({ordered.front(),ordered.back()},pdf,xs,decayed_parton)); } if (!current_chain.dipoles().empty()) { current_chain.check(); theChains.push_back(current_chain); } } const map<PPtr,PPtr>& DipoleEventRecord::prepare(tSubProPtr subpro, tStdXCombPtr xc, const pair<PDF,PDF>& pdf,tPPair beam, bool dipoles) { // set the subprocess subProcess(subpro); // clear the event record outgoing().clear(); theHard.clear(); theOriginals.clear(); theDecays.clear(); theCurrentDecay = PerturbativeProcessPtr(); // extract incoming particles PPair in = subpro->incoming(); - // get the beam // get the incoming momentum fractions // don't take these from the XComb as it may be null pair<double,double> xs; ThePEG::Direction<0> dir(true); xs.first = in.first->momentum().dirPlus()/beam.first->momentum().dirPlus(); dir.reverse(); xs.second = in.second->momentum().dirPlus()/beam.second->momentum().dirPlus(); xcombPtr(xc); pdfs() = pdf; fractions() = xs; // use ShowerHandler to split up the hard process PerturbativeProcessPtr hard; DecayProcessMap decay; ShowerHandler::currentHandler()->splitHardProcess(tPVector(subpro->outgoing().begin(), subpro->outgoing().end()), hard,decay); // vectors for originals and copies of the particles vector<PPtr> original; vector<PPtr> copies; // fill originals for(unsigned int ix=0;ix<2;++ix) original.push_back(hard->incoming()[ix].first); for(unsigned int ix=0;ix<hard->outgoing().size();++ix) original.push_back(hard->outgoing()[ix].first); for(DecayProcessMap::const_iterator it=decay.begin();it!=decay.end();++it) { fillFromDecays(it->second, original); } // and make copies for ( vector<PPtr>::const_iterator p = original.begin(); p != original.end(); ++p ) { PPtr copy = new_ptr(Particle(**p)); copies.push_back(copy); theOriginals[*p] = copy; } // isolate the colour of the copies from the originals colourIsolate(original,copies); // set the incoming particles incoming().first = copies[0]; ParticleVector children = incoming().first->children(); for ( ParticleVector::const_iterator c = children.begin(); c != children.end(); ++c ) incoming().first->abandonChild(*c); incoming().second = copies[1]; children = incoming().second->children(); for ( ParticleVector::const_iterator c = children.begin(); c != children.end(); ++c ) incoming().second->abandonChild(*c); // set the outgoing particles for the hard process for(unsigned int ix=0;ix<hard->outgoing().size();++ix) { if(hard->outgoing()[ix].first->coloured()) outgoing().push_back(theOriginals[hard->outgoing()[ix].first]); else theHard.push_back(theOriginals[hard->outgoing()[ix].first]); } if ( dipoles ) { PList cordered = colourOrdered(incoming(),outgoing()); findChains(cordered,false); } // sort out the decays - for(DecayProcessMap::const_iterator it=decay.begin();it!=decay.end();++it) { + for(auto const & dec : decay) { // If the decay particle is in original it needs // to be added to the decays and the decay needs to be // changed to the copied particles. - if ( theOriginals.find(it->second->incoming()[0].first) != theOriginals.end() ) { - theDecays[theOriginals[it->second->incoming()[0].first]] = it->second; - PerturbativeProcessPtr decayProc = theDecays[theOriginals[it->second->incoming()[0].first]]; + if ( theOriginals.find(dec.second->incoming()[0].first) != theOriginals.end() ) { + theDecays[theOriginals[dec.second->incoming()[0].first]] = dec.second; + PerturbativeProcessPtr decayProc = theDecays[theOriginals[dec.second->incoming()[0].first]]; separateDecay(decayProc); } else { - assert( find( copies.begin(), copies.end(), it->second->incoming()[0].first ) != copies.end() ); - theDecays[it->second->incoming()[0].first] = it->second; + assert( find( copies.begin(), copies.end(), dec.second->incoming()[0].first ) != copies.end() ); + theDecays[dec.second->incoming()[0].first] = dec.second; } } PList::const_iterator XFirst, XLast; if ( !theHard.empty() ) { XFirst = theHard.begin(); XLast = theHard.end(); } else { XFirst = outgoing().begin(); XLast = outgoing().end(); } thePX = (**XFirst).momentum(); ++XFirst; for ( ; XFirst != XLast; ++XFirst ) thePX += (**XFirst).momentum(); identifyEventType(); return theOriginals; } void DipoleEventRecord::slimprepare(tSubProPtr subpro, tStdXCombPtr xc, const pair<PDF,PDF>& pdf,tPPair beam, bool dipoles) { // set the subprocess subProcess(subpro); // clear the event record outgoing().clear(); theHard.clear(); theOriginals.clear(); theDecays.clear(); theCurrentDecay = PerturbativeProcessPtr(); // extract incoming particles PPair in = subpro->incoming(); // get the beam // get the incoming momentum fractions // don't take these from the XComb as it may be null pair<double,double> xs; ThePEG::Direction<0> dir(true); xs.first = in.first->momentum().dirPlus()/beam.first->momentum().dirPlus(); dir.reverse(); xs.second = in.second->momentum().dirPlus()/beam.second->momentum().dirPlus(); xcombPtr(xc); pdfs() = pdf; fractions() = xs; incoming() = in; for(unsigned int ix=0;ix<subpro->outgoing().size();++ix) { if(subpro->outgoing()[ix]->coloured()) outgoing().push_back(subpro->outgoing()[ix]); } if ( dipoles ) { PList cordered = colourOrdered(incoming(),outgoing()); findChains(cordered,false); } } void DipoleEventRecord::fillFromDecays(PerturbativeProcessPtr decayProc, vector<PPtr>& original) { // Loop over the outgoing of the given perturbative process - for ( vector<pair<PPtr,PerturbativeProcessPtr> >::iterator outIt = decayProc->outgoing().begin(); - outIt != decayProc->outgoing().end(); ++outIt ) { + for ( auto const & outIt : decayProc->outgoing() ) { // Add the outgoing particle to the vector of original particles - original.push_back(outIt->first); + original.push_back(outIt.first); // Iterate through the outgoing - if ( outIt->second ) - fillFromDecays( outIt->second, original); + if ( outIt.second ) + fillFromDecays( outIt.second, original); } } void DipoleEventRecord::separateDecay(PerturbativeProcessPtr decayProc) { // Iteratively replace all entries in the incoming // with their copies. - for ( vector<pair<PPtr,tPerturbativeProcessPtr> >::iterator inIt = decayProc->incoming().begin(); - inIt != decayProc->incoming().end(); ++inIt ) { + for ( auto & inIt : decayProc->incoming() ) { - if ( theOriginals.find( inIt->first ) != theOriginals.end() ) - inIt->first = theOriginals[inIt->first]; + if ( theOriginals.find( inIt.first ) != theOriginals.end() ) + inIt.first = theOriginals[inIt.first]; } // Iteratively replace all entries in the outgoing // with their copies. - for ( vector<pair<PPtr,PerturbativeProcessPtr> >::iterator outIt = decayProc->outgoing().begin(); - outIt!=decayProc->outgoing().end(); ++outIt ) { + for ( auto & outIt : decayProc->outgoing()) { - if ( theOriginals.find( outIt->first ) != theOriginals.end() ) - outIt->first = theOriginals[outIt->first]; + if ( theOriginals.count( outIt.first ) ) + outIt.first = theOriginals[outIt.first]; - if ( outIt->second ) - separateDecay(outIt->second); + if ( outIt.second ) + separateDecay(outIt.second); } } void DipoleEventRecord::clear() { ShowerEventRecord::clear(); theDecays.clear(); theHard.clear(); theChains.clear(); theDoneChains.clear(); theOriginals.clear(); } pair<PVector,PVector> DipoleEventRecord::tmpupdate(DipoleSplittingInfo& dsplit) { PVector inc; PVector out; tcPPtr IF = incoming().first; tcPPtr IS = incoming().second; tcPPtr DE = dsplit.emitter(); tcPPtr DS = dsplit.spectator(); if ( IF != DE && IF != DS ) { PPtr p = IF->data().produceParticle(IF->momentum()); inc.push_back(p); } else if ( IF == DE ) inc.push_back( dsplit.splitEmitter() ); else if ( IF == DS ) inc.push_back( dsplit.splitSpectator() ); if ( IS != DE && IS != DS ) { PPtr p = IS->data().produceParticle(IS->momentum()); inc.push_back(p); } else if ( IS == DE ) inc.push_back( dsplit.splitEmitter() ); else if ( IS == DS ) inc.push_back( dsplit.splitSpectator() ); if ( IF != DE && IS != DE) out.push_back( dsplit.splitEmitter()); if ( IF != DS && IS != DS) out.push_back( dsplit.splitSpectator()); out.push_back( dsplit.emission()); for ( tcPPtr h : theHard ){ PPtr p = h->data().produceParticle(h->momentum()); if ( dsplit.splittingKinematics()->doesTransform() ) { p->set5Momentum( dsplit.splittingKinematics()->transform(p->momentum()) ); } out.push_back(p); } for ( tcPPtr p : outgoing() ) if ( p != DE && p != DS && p != dsplit.emission() ){ PPtr ou = p->data().produceParticle(p->momentum());; if ( dsplit.splittingKinematics()->doesTransform() ){ ou->set5Momentum( dsplit.splittingKinematics()->transform(ou->momentum()) ); } out.push_back(ou); } return {inc,out}; } void DipoleEventRecord::update(DipoleSplittingInfo& dsplit) { if ( incoming().first == dsplit.emitter() ) { intermediates().push_back(dsplit.emitter()); incoming().first = dsplit.splitEmitter(); fractions().first /= dsplit.lastEmitterZ(); } else if ( incoming().first == dsplit.spectator() ) { intermediates().push_back(dsplit.spectator()); incoming().first = dsplit.splitSpectator(); fractions().first /= dsplit.lastSpectatorZ(); } if ( incoming().second == dsplit.emitter() ) { intermediates().push_back(dsplit.emitter()); incoming().second = dsplit.splitEmitter(); fractions().second /= dsplit.lastEmitterZ(); } else if ( incoming().second == dsplit.spectator() ) { intermediates().push_back(dsplit.spectator()); incoming().second = dsplit.splitSpectator(); fractions().second /= dsplit.lastSpectatorZ(); } PList::iterator pos; pos = find(outgoing().begin(), outgoing().end(), dsplit.emitter()); if (pos != outgoing().end()) { intermediates().push_back(*pos); *pos = dsplit.splitEmitter(); } pos = find(outgoing().begin(), outgoing().end(), dsplit.spectator()); if (pos != outgoing().end()) { intermediates().push_back(*pos); *pos = dsplit.splitSpectator(); } outgoing().push_back(dsplit.emission()); if (dsplit.splittingKinematics()->doesTransform()) { for (PList::iterator p = intermediates().begin(); p != intermediates().end(); ++p) { (**p).set5Momentum(dsplit.splittingKinematics()->transform((**p).momentum())); } for (PList::iterator h = theHard.begin(); h != theHard.end(); ++h) { (**h).set5Momentum(dsplit.splittingKinematics()->transform((**h).momentum())); } for (PList::iterator p = outgoing().begin(); p != outgoing().end(); ++p) { if ((*p) != dsplit.splitEmitter() && (*p) != dsplit.splitSpectator() && (*p) != dsplit.emission()) (**p).set5Momentum(dsplit.splittingKinematics()->transform((**p).momentum())); } } // Handle updates related to decays - //if ( !decays().empty() ) { - - // Update decays() while showering the hard process - // NOTE - Actually this is done in constituentRecoil() - - // Showering of decay processes // Treat the evolution of the incoming // decayed particle as in backward evolution - - //else { + if ( dsplit.isDecayProc() ) { // Create a pointer to the decay process PerturbativeProcessPtr decayProc = currentDecay(); // Add the emission to the outgoing of the decay process decayProc->outgoing().push_back( {dsplit.emission(), PerturbativeProcessPtr() }); // Bools to be used throughout const bool decayedEmtr = dsplit.index().incomingDecayEmitter(); const bool decayedSpec = dsplit.index().incomingDecaySpectator(); - // ****************************************************************** - // In the current implementation, **following the hard process** all particles in theDecays evolve independently - // e.g. if we have W -> XYZ where all X, Y and Z need to be showered and decayed, we only identify them as needing decaying (and hence put them in theDecays) AFTER showering the decay of W. Hence, XYZ are not even in theDecays until W has been fully showered and then they are decayed and showered completely independently - // KEY POINT - Never need to update other entries of theDecays + /* + In the current implementation, **following the hard process** + all particles in theDecays evolve independently + e.g. if we have W -> XYZ where all X, Y and Z need to be + showered and decayed, we only identify them as needing decaying + (and hence put them in theDecays) AFTER showering the decay of W. + Hence, XYZ are not even in theDecays until W has been fully + showered and then they are decayed and showered completely independently + KEY POINT - Never need to update other entries of theDecays - // Note: The PPtr in theDecays should remain unchanged and all changes - // should be made to the relative PerturbativeProcess. - // ********************************************************************* - + Note: The PPtr in theDecays should remain unchanged and all changes + should be made to the relative PerturbativeProcess. + */ // Splittings from dipoles in the decay process which // do not have the decayed parton as emitter or spectator. // Update the decay process in theDecays if ( !decayedEmtr && !decayedSpec ) { // Find and replace the old spectator and // emitter in the outgoing of the decay process bool decayProcEm = false; bool decayProcSp = false; - for ( vector<pair<PPtr,PerturbativeProcessPtr> >::iterator outIt = decayProc->outgoing().begin(); outIt!=decayProc->outgoing().end(); ++outIt ) { - if ( !decayProcEm && outIt->first == dsplit.emitter() ) { - *outIt = {dsplit.splitEmitter(), PerturbativeProcessPtr()}; + for ( auto & outIt : decayProc->outgoing() ) { + if ( !decayProcEm && outIt.first == dsplit.emitter() ) { + outIt = {dsplit.splitEmitter(), PerturbativeProcessPtr()}; decayProcEm = true; } - if ( !decayProcSp && outIt->first == dsplit.spectator() ) { - *outIt = {dsplit.splitSpectator(), PerturbativeProcessPtr() }; + if ( !decayProcSp && outIt.first == dsplit.spectator() ) { + outIt = {dsplit.splitSpectator(), PerturbativeProcessPtr() }; decayProcSp = true; } if ( decayProcEm && decayProcSp ) break; } // Test that nothing strange is happening - //assert( (decayProcEm && decayProcSp) ); + assert( (decayProcEm && decayProcSp) ); return; } // The spectator is the decayed particle else if ( decayedSpec ) { // Update the dipole event record intermediates intermediates().push_back(dsplit.splitSpectator()); // Update the the decayProcess incoming decayProc->incoming().clear(); decayProc->incoming().push_back({dsplit.splitSpectator(),decayProc}); // Update the decay process outgoing // Replace the old emitter with the new emitter - vector<pair<PPtr,PerturbativeProcessPtr> >::iterator outEmtrIt = decayProc->outgoing().end(); - for ( outEmtrIt = decayProc->outgoing().begin(); - outEmtrIt != decayProc->outgoing().end(); ++outEmtrIt ) { - if ( outEmtrIt->first == dsplit.emitter() ){ - *outEmtrIt = {dsplit.splitEmitter(), PerturbativeProcessPtr() }; + for ( auto & outEmtrIt : decayProc->outgoing() ) { + if ( outEmtrIt.first == dsplit.emitter() ){ + outEmtrIt = {dsplit.splitEmitter(), PerturbativeProcessPtr() }; break; } } // Perform the recoil transformation - //assert(dsplit.splittingKinematics()->isDecay()); - // Find all particles in the recoil system PList recoilSystem; - for ( vector<pair<PPtr,PerturbativeProcessPtr> >::iterator outIt = decayProc->outgoing().begin(); outIt!=decayProc->outgoing().end(); ++outIt ) { - if ( outIt->first != dsplit.splitEmitter() && outIt->first != dsplit.emission() ) { - recoilSystem.push_back(outIt->first); + for ( auto const & outIt : decayProc->outgoing() ) { + if ( outIt.first != dsplit.splitEmitter() && outIt.first != dsplit.emission() ) { + recoilSystem.push_back(outIt.first); } } dsplit.splittingKinematics()->decayRecoil( recoilSystem ); return; } // The emitter is the decayed particle else { throw Exception() << "DipoleEventRecord: The emitter as a decayed particle is currently not implemented." << Exception::runerror; assert( currentDecay()->incoming()[0].first == dsplit.emitter() && decayedEmtr && !decayedSpec ); // Update the dipole event record intermediates intermediates().push_back(dsplit.splitEmitter()); // Update the the decayProcess incoming decayProc->incoming().clear(); decayProc->incoming().push_back({dsplit.splitEmitter(),decayProc}); // Update the decay process outgoing // Replace the old spectator with the new spectator - vector<pair<PPtr,PerturbativeProcessPtr> >::iterator outSpecIt = decayProc->outgoing().end(); - for ( outSpecIt = decayProc->outgoing().begin(); - outSpecIt!= decayProc->outgoing().end(); ++outSpecIt ) { - if ( outSpecIt->first == dsplit.spectator() ){ - *outSpecIt = { dsplit.splitSpectator(), PerturbativeProcessPtr() }; + for (auto & outSpecIt : decayProc->outgoing() ) { + if ( outSpecIt.first == dsplit.spectator() ){ + outSpecIt = { dsplit.splitSpectator(), PerturbativeProcessPtr() }; break; } } - assert(outSpecIt != decayProc->outgoing().end()); // Perform the recoil transformation assert(dsplit.splittingKinematics()->isDecay()); // Find all particles in the recoil system PList recoilSystem; - for ( vector<pair<PPtr,PerturbativeProcessPtr> >::iterator outIt = decayProc->outgoing().begin(); outIt!=decayProc->outgoing().end(); ++outIt ) { - if ( outIt->first != dsplit.splitSpectator() && outIt->first != dsplit.emission() ) { - recoilSystem.push_back(outIt->first); + for ( auto const & outIt : decayProc->outgoing() ) { + if ( outIt.first != dsplit.splitSpectator() && outIt.first != dsplit.emission() ) { + recoilSystem.push_back(outIt.first); } } dsplit.splittingKinematics()->decayRecoil( recoilSystem ); return; } } } void DipoleEventRecord::split(list<Dipole>::iterator dip, list<DipoleChain>::iterator ch, DipoleSplittingInfo& dsplit, pair<list<Dipole>::iterator,list<Dipole>::iterator>& childIterators, DipoleChain*& firstChain, DipoleChain*& secondChain, bool colourSpectator) { static DipoleChain empty; pair<Dipole,Dipole> children = dip->split(dsplit,colourSpectator); list<Dipole>::iterator breakup = ch->insertSplitting(dip,children,childIterators); if ( breakup == ch->dipoles().end() ) { firstChain = &(*ch); secondChain = ∅ } else { DipoleChain other; other.dipoles().splice(other.dipoles().end(),ch->dipoles(),breakup,ch->dipoles().end()); chains().push_back(other); firstChain = &(*ch); secondChain = &(chains().back()); // explicitly fix iterators in case the splice implementation // at hand does invalidate iterators (the SGI docu says, it doesn't, // but it seems that this behaviour is not part of the standard) childIterators.first = --firstChain->dipoles().end(); childIterators.second = secondChain->dipoles().begin(); } if ( !colourSpectator ) { update(dsplit); // otherwise done by recoil(...) } } pair<PVector,PVector> DipoleEventRecord::tmpsplit(list<Dipole>::iterator dip, list<DipoleChain>::iterator , DipoleSplittingInfo& dsplit, pair<list<Dipole>::iterator,list<Dipole>::iterator>& , DipoleChain*& , DipoleChain*& , bool colourSpectator) { dip->tmpsplit(dsplit,colourSpectator); return tmpupdate(dsplit); // otherwise done by recoil(...) } void DipoleEventRecord::recoil(list<Dipole>::iterator dip, list<DipoleChain>::iterator ch, DipoleSplittingInfo& dsplit) { dip->recoil(dsplit); ch->updateDipole(dip); update(dsplit); } list<pair<list<Dipole>::iterator,list<DipoleChain>::iterator> > DipoleEventRecord::inDipoles() { list<pair<list<Dipole>::iterator,list<DipoleChain>::iterator> > res; for ( list<DipoleChain>::iterator chit = theDoneChains.begin(); chit != theDoneChains.end(); ++chit ) { bool haveOne = false; for ( list<Dipole>::iterator dit = chit->dipoles().begin(); dit != chit->dipoles().end(); ++dit ) { if ( dit->leftPDF().pdf() || dit->rightPDF().pdf() ) { haveOne = true; break; } } if ( haveOne ) { theChains.splice(theChains.begin(),theDoneChains,chit); for ( list<Dipole>::iterator dit = theChains.front().dipoles().begin(); dit != theChains.front().dipoles().end(); ++dit ) { if ( dit->leftPDF().pdf() || dit->rightPDF().pdf() ) { res.push_back({dit,theChains.begin()}); } } } } return res; } void DipoleEventRecord::transform(const SpinOneLorentzRotation& rot) { Lorentz5Momentum tmp; for (PList::iterator p = intermediates().begin(); p != intermediates().end(); ++p) { tmp = (**p).momentum(); tmp = rot * tmp; (**p).set5Momentum(tmp); } for (PList::iterator h = theHard.begin(); h != theHard.end(); ++h) { tmp = (**h).momentum(); tmp = rot * tmp; (**h).set5Momentum(tmp); } for (PList::iterator p = outgoing().begin(); p != outgoing().end(); ++p) { tmp = (**p).momentum(); tmp = rot * tmp; (**p).set5Momentum(tmp); } } tPPair DipoleEventRecord::fillEventRecord(StepPtr step, bool firstInteraction, bool) { PPtr inSubPro = subProcess()->incoming().first; PPtr inParticle; if ( !(inSubPro->parents().empty()) ) inParticle = inSubPro->parents()[0]; else inParticle = inSubPro; PPtr inParton = theOriginals[inSubPro]; theOriginals.erase(inSubPro); updateColour(incoming().first,true); if ( inParticle != inSubPro ) inParticle->abandonChild(inSubPro); inParton->addChild(inSubPro); if ( inParticle != inSubPro ) inParticle->addChild(incoming().first); intermediates().push_back(inSubPro); intermediates().push_back(inParton); // Repeat all the above for the second incoming particle inSubPro = subProcess()->incoming().second; if ( !(inSubPro->parents().empty()) ) inParticle = inSubPro->parents()[0]; else inParticle = inSubPro; inParton = theOriginals[inSubPro]; theOriginals.erase(inSubPro); updateColour(incoming().second,true); if ( inParticle != inSubPro ) inParticle->abandonChild(inSubPro); inParton->addChild(inSubPro); if ( inParticle != inSubPro ) inParticle->addChild(incoming().second); intermediates().push_back(inSubPro); intermediates().push_back(inParton); // theOriginals is populated in ::prepare and contains all of the incoming and outgoing particles of the original hard process // Here outgoing particles from theOriginals are added into the intermediates() while ( !theOriginals.empty() ) { PPtr outSubPro = theOriginals.begin()->first; PPtr outParton = theOriginals.begin()->second; // workaround for OS X Mavericks LLVM libc++ #ifdef _LIBCPP_VERSION map<PPtr,PPtr>::const_iterator beg = theOriginals.begin(); #else map<PPtr,PPtr>::iterator beg = theOriginals.begin(); #endif theOriginals.erase(beg); updateColour(outParton,true); outSubPro->addChild(outParton); intermediates().push_back(outSubPro); } // Update the intermediates of the step step->addIntermediates(intermediates().begin(),intermediates().end()); - for (PList::const_iterator p = outgoing().begin(); - p != outgoing().end(); ++p) - step->addDecayProduct(*p); + for (auto const & p : outgoing()) + step->addDecayProduct( p ); - for (PList::const_iterator p = theHard.begin(); - p != theHard.end(); ++p) - step->addDecayProduct(*p); + for (auto const p : theHard) + step->addDecayProduct( p ); if ( firstInteraction && (incoming().first->coloured() || incoming().second->coloured() ) ) { - ShowerHandler::currentHandler()->lastExtractor()->newRemnants(subProcess()->incoming(),incoming(),step); + ShowerHandler::currentHandler()->lastExtractor() + ->newRemnants(subProcess()->incoming(),incoming(),step); } step->addIntermediate(incoming().first); step->addIntermediate(incoming().second); return incoming(); } bool DipoleEventRecord::prepareDecay( PerturbativeProcessPtr decayProc ) { // Create objects containing the incoming and outgoing partons, // required as inputs for colourOrdered. PList out; - for( unsigned int ix = 0; ix<decayProc->outgoing().size(); ++ix) { - if(decayProc->outgoing()[ix].first->coloured()) { - out.push_back(decayProc->outgoing()[ix].first); + for( auto const & dec : decayProc->outgoing()) { + if(dec.first->coloured()) { + out.push_back(dec.first); } } // Only need to shower if we have coloured outgoing particles if ( out.empty() ) return false; else { // For the incoming, use a PPair containing the incoming and a null pointer PPair in; in.first = decayProc->incoming()[0].first; // Create an ordered list of particles PList cordered; cordered = colourOrdered(in,out); // Find the dipole chains for this decay findChains(cordered,true); return true; } } Energy DipoleEventRecord::decay(PPtr incoming, bool& powhegEmission) { // get the process PerturbativeProcessPtr process = theDecays[incoming]; assert(process); //tDMPtr decayMode = new_ptr(DecayMode()); tDMPtr decayMode = DMPtr(); // Do not decay particles that have already been decayed // Note the herwig decayer deals with colour connections if ( process->outgoing().empty() ) { process->incoming()[0].first = incoming; DecayProcessMap decay; // Decay the particle, returning a pointer to the decay mode decayMode = ShowerHandler::currentHandler()->decay(process,decay); } // Sort out the colour connections of particles already decayed else { // sort out the colour of the incoming map<tColinePtr,tColinePtr> cmap; if(incoming->colourLine()) cmap[process->incoming()[0].first->colourLine()] = incoming->colourLine(); if(incoming->antiColourLine()) cmap[process->incoming()[0].first->antiColourLine()] = incoming->antiColourLine(); // fix colours of outgoing - for(unsigned int ix=0;ix<process->outgoing().size();++ix) { - map<tColinePtr,tColinePtr>::iterator it = cmap.find(process->outgoing()[ix].first->colourLine()); + for(auto const & outg : process->outgoing()) { + map<tColinePtr,tColinePtr>::iterator it = + cmap.find(outg.first->colourLine()); if(it!=cmap.end()) { - ColinePtr c1=process->outgoing()[ix].first->colourLine(); - c1->removeColoured(process->outgoing()[ix].first); - it->second->addColoured(process->outgoing()[ix].first); + ColinePtr c1=outg.first->colourLine(); + c1->removeColoured(outg.first); + it->second->addColoured(outg.first); } - it = cmap.find(process->outgoing()[ix].first->antiColourLine()); + it = cmap.find(outg.first->antiColourLine()); if(it!=cmap.end()) { - ColinePtr c1=process->outgoing()[ix].first->antiColourLine(); - c1->removeAntiColoured(process->outgoing()[ix].first); - it->second->addAntiColoured(process->outgoing()[ix].first); + ColinePtr c1=outg.first->antiColourLine(); + c1->removeAntiColoured(outg.first); + it->second->addAntiColoured(outg.first); } } // swap the incoming process->incoming()[0].first = incoming; } // Set the scale of all particles involved in the decay process to the // mass of the decaying particle // Initialise the scale for the evolution of // the parton shower following the decay Energy showerScale = ZERO; // Set the scale for the evolution of the shower showerScale = process->incoming()[0].first->momentum().m(); Energy2 decayScaleSqr = sqr( showerScale ); process->incoming()[0].first->scale( decayScaleSqr ); - for(unsigned int ix=0;ix<process->outgoing().size();++ix) { - process->outgoing()[ix].first->scale( decayScaleSqr ); + for(auto & outg : process->outgoing()) { + outg.first->scale( decayScaleSqr ); } // Update the decaying particle in the process and the event PList::iterator posOut = find(outgoing().begin(), outgoing().end(), incoming); PList::iterator posHard = find(hard().begin(), hard().end(), incoming); assert((posOut!=outgoing().end() && posHard==hard().end()) || (posOut==outgoing().end() && posHard!=hard().end()) ); if ( posOut!=outgoing().end() ) { outgoing().erase(posOut); } else { hard().erase(posHard); } intermediates().push_back(process->incoming()[0].first); // Populate the children of the incoming - for(unsigned int ix=0;ix<process->outgoing().size();++ix) { - PPtr outgoing = process->outgoing()[ix].first; + for(auto const & outg : process->outgoing()) { + PPtr outgoing = outg.first; process->incoming()[0].first->addChild(outgoing); } // If a decayed particle is not decayed above, // e.g. a W in a 3-body top decay, find its decaymode. if ( powhegEmission && !decayMode ) { string tag = incoming->dataPtr()->name() + "->"; // Must use OrderedParticles for a tag search ShowerHandler::OrderedParticles decayOut; - for(unsigned int ix=0;ix<process->outgoing().size();++ix) { - decayOut.insert(process->outgoing()[ix].first->dataPtr()); + for(auto const & outg : process->outgoing()) { + decayOut.insert(outg.first->dataPtr()); } // Construct the tag for(ShowerHandler::OrderedParticles::const_iterator it=decayOut.begin(); it!=decayOut.end();++it) { if(it!=decayOut.begin()) tag += ","; tag +=(**it).name(); } tag += ";"; // Find the decay mode decayMode = ShowerHandler::currentHandler()->findDecayMode(tag); } // Perform the powheg emission if ( powhegEmission ) { if ( decayMode ) { HwDecayerBasePtr decayer; decayer = dynamic_ptr_cast<HwDecayerBasePtr>(decayMode->decayer()); if ( decayer->hasPOWHEGCorrection() ) { // Construct a real emission process and populate its // incoming and outcoming prior to any powheg emission RealEmissionProcessPtr born = new_ptr( RealEmissionProcess() ); born->bornIncoming().push_back( incoming ); - for(unsigned int ix=0;ix<process->outgoing().size();++ix) { - born->bornOutgoing().push_back(process->outgoing()[ix].first); + for(auto const & outg : process->outgoing()) { + born->bornOutgoing().push_back(outg.first); } // Generate any powheg emission, returning 'real' RealEmissionProcessPtr real = decayer->generateHardest( born ); // If no emission is generated the new incoming and // outgoing containers will be empty. // Only do something if an emission is generated. if ( real && real->incoming().size() != 0 ) { assert ( real->incoming().size() == 1 ); // Update the decay process // Note: Do not use the new incoming particle PPtr oldEmitter; PPtr newEmitter; // Use the name recoiler to avoid confusion with // the spectator in the POWHEGDecayer // i.e. the recoiler can be coloured or non-coloured PPtr oldRecoiler; PPtr newRecoiler; if ( real->emitter() == 1 ) { oldEmitter = real->bornOutgoing()[0]; oldRecoiler = real->bornOutgoing()[1]; newEmitter = real->outgoing()[0]; newRecoiler = real->outgoing()[1]; } else if ( real->emitter() == 2) { oldEmitter = real->bornOutgoing()[1]; oldRecoiler = real->bornOutgoing()[0]; newEmitter = real->outgoing()[1]; newRecoiler = real->outgoing()[0]; } PPtr emitted = real->outgoing()[ real->emitted()-1]; // Update the scales newRecoiler->scale(oldRecoiler->scale()); showerScale = real->pT()[ShowerInteraction::QCD]; newEmitter->scale(sqr(showerScale)); emitted->scale(sqr(showerScale)); // Update the colour flow of the new outgoing particles // Note the emitted and newEmitter are already colour // connected by the powheg emission function emitted->incomingColour(oldEmitter, oldEmitter->id()<0); if ( newRecoiler->coloured() ) newRecoiler->incomingColour(oldRecoiler, oldRecoiler->id()<0); // Update the children of the outgoing oldRecoiler->addChild( newRecoiler ); oldEmitter->addChild( newEmitter ); oldEmitter->addChild( emitted ); // Note: The particles in the pert proc outgoing and both outgoing // vectors of the real emission proc are in the same order for(unsigned int ix=0;ix<real->bornOutgoing().size();++ix) { // Update the decay process assert(process->outgoing()[ix].first == real->bornOutgoing()[ix]); process->outgoing()[ix].first = real->outgoing()[ix]; // Add the outgoing from the born // decay to the event intermediates intermediates().push_back(real->bornOutgoing()[ix]); } // Add the emitted to the outgoing of the decay process process->outgoing().push_back( { emitted, PerturbativeProcessPtr() } ); } // No powheg emission occurred: else powhegEmission = false; } // No powheg emission occurred: else powhegEmission = false; } // No powheg emission occurred: else powhegEmission = false; } // Copy the outgoing from the decay // process to the event record - for(unsigned int ix=0;ix<process->outgoing().size();++ix) { - if ( process->outgoing()[ix].first->coloured() ) - outgoing().push_back(process->outgoing()[ix].first); + for(auto const & outg : process->outgoing()) { + if ( outg.first->coloured() ) + outgoing().push_back(outg.first); else - hard().push_back(process->outgoing()[ix].first); + hard().push_back(outg.first); } return showerScale; } void DipoleEventRecord::updateDecayMom( PPtr decayParent, PerturbativeProcessPtr decayProc ) { // Only particles that have already been decayed // should be passed to this function assert( !(decayProc->outgoing().empty()) ); // Create a list of the children to update their momenta PList children; for ( vector<pair<PPtr,PerturbativeProcessPtr> >::iterator outIt = decayProc->outgoing().begin(); outIt != decayProc->outgoing().end(); ++outIt ) { children.push_back( outIt->first ); } // Boost the children PList::iterator beginChildren = children.begin(); PList::iterator endChildren = children.end(); ThePEG::UtilityBase::setMomentum(beginChildren, endChildren, decayParent->momentum().vect() ); } void DipoleEventRecord::updateDecayChainMom( PPtr decayParent, PerturbativeProcessPtr decayProc ) { // Note - this updates the momenta of the // outgoing of the given decay process // Update the momenta of the outgoing from this decay updateDecayMom( decayParent, decayProc ); // Iteratively update the momenta of the rest of the decay chain for ( vector<pair<PPtr,PerturbativeProcessPtr> >::iterator outIt = decayProc->outgoing().begin(); outIt != decayProc->outgoing().end(); ++outIt ) { // If a child has a corresponding pert proc // then it has decay products if ( outIt->second ) { for(map<PPtr,PerturbativeProcessPtr>::iterator it=theDecays.begin(); it!=theDecays.end();++it) { if(it->second==outIt->second) { it->first->setMomentum(outIt->first->momentum()); break; } } // Iteratively update any decay products if ( !outIt->second->outgoing().empty() ) updateDecayChainMom( outIt->first, outIt->second ); } } } void DipoleEventRecord::updateDecays(PerturbativeProcessPtr decayProc, bool iterate) { // Note - This does not update the momenta of the outgoing // of decayProc. // i.e. it is for use following the (non-)showering // of a decay when the daughter momentum are correct. // With iterate = true, this updates the rest of the decay chain. // Loop over the outgoing from this decay for ( vector<pair<PPtr,PerturbativeProcessPtr> >::iterator outIt = decayProc->outgoing().begin(); outIt!=decayProc->outgoing().end(); ++outIt ) { if ( outIt->second && !outIt->second->outgoing().empty() ) { // Outgoing particles which have already been decayed PPtr newDecayed = outIt->first; PerturbativeProcessPtr newDecayProc = outIt->second; // Update the outgoing momenta from this decay updateDecayMom( newDecayed, newDecayProc); // If this decay is already in theDecays then erase it for(map<PPtr,PerturbativeProcessPtr>::const_iterator it=theDecays.begin(); it!=theDecays.end();++it) { if(it->second==outIt->second) { theDecays.erase(it->first); break; } } // Add to theDecays theDecays[newDecayed] = newDecayProc; //assert(theDecays[newDecayed]->incoming()[0].second==decayProc); // Iteratively update theDecays from the decay chain if ( iterate ) updateDecays( newDecayProc ); } // Deal with any outgoing which need to be decayed else if ( ShowerHandler::currentHandler()->decaysInShower(outIt->first->id()) ) { PerturbativeProcessPtr newDecay=new_ptr(PerturbativeProcess()); newDecay->incoming().push_back({ outIt->first , decayProc } ); theDecays[outIt->first] = newDecay; } } } void DipoleEventRecord::debugLastEvent(ostream& os) const { bool first = ShowerHandler::currentHandler()->firstInteraction(); os << "--- DipoleEventRecord ----------------------------------------------------------\n"; os << " the " << (first ? "hard" : "secondary") << " subprocess is:\n" << (*subProcess()); os << " using PDF's " << pdfs().first.pdf() << " and " << pdfs().second.pdf() << "\n"; os << " chains showering currently:\n"; for ( list<DipoleChain>::const_iterator chit = theChains.begin(); chit != theChains.end(); ++chit ) os << (*chit); os << " chains which finished showering:\n"; for ( list<DipoleChain>::const_iterator chit = theDoneChains.begin(); chit != theDoneChains.end(); ++chit ) os << (*chit); os << "--------------------------------------------------------------------------------\n"; os << flush; } diff --git a/Shower/Dipole/Base/DipoleSplittingGenerator.cc b/Shower/Dipole/Base/DipoleSplittingGenerator.cc --- a/Shower/Dipole/Base/DipoleSplittingGenerator.cc +++ b/Shower/Dipole/Base/DipoleSplittingGenerator.cc @@ -1,780 +1,796 @@ // -*- C++ -*- // // DipoleSplittingGenerator.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2007 The Herwig Collaboration // // Herwig is licenced under version 2 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 DipoleSplittingGenerator class. // #include <config.h> #include "DipoleSplittingGenerator.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Interface/Reference.h" #include "ThePEG/Repository/EventGenerator.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "Herwig/Shower/Dipole/DipoleShowerHandler.h" using namespace Herwig; DipoleSplittingGenerator::DipoleSplittingGenerator() : HandlerBase(), theExponentialGenerator(0), prepared(false), presampling(false), theDoCompensate(false), theSplittingWeight(1.) { if ( ShowerHandler::currentHandler() ) setGenerator(ShowerHandler::currentHandler()->generator()); } DipoleSplittingGenerator::~DipoleSplittingGenerator() { if ( theExponentialGenerator ) { delete theExponentialGenerator; theExponentialGenerator = 0; } } IBPtr DipoleSplittingGenerator::clone() const { return new_ptr(*this); } IBPtr DipoleSplittingGenerator::fullclone() const { return new_ptr(*this); } void DipoleSplittingGenerator::wrap(Ptr<DipoleSplittingGenerator>::ptr other) { assert(!prepared); theOtherGenerator = other; } void DipoleSplittingGenerator::resetVariations() { for ( map<string,double>::iterator w = currentWeights.begin(); w != currentWeights.end(); ++w ) w->second = 1.; } void DipoleSplittingGenerator::veto(const vector<double>&, double p, double r) { double factor = 1.; if ( splittingReweight() ) { - if ( ( ShowerHandler::currentHandler()->firstInteraction() && splittingReweight()->firstInteraction() ) || - ( !ShowerHandler::currentHandler()->firstInteraction() && splittingReweight()->secondaryInteractions() ) ) { + if ( ( ShowerHandler::currentHandler()->firstInteraction() && + splittingReweight()->firstInteraction() ) || + ( !ShowerHandler::currentHandler()->firstInteraction() && + splittingReweight()->secondaryInteractions() ) ) { factor = splittingReweight()->evaluate(generatedSplitting); theSplittingWeight *= (r-factor*p)/(r-p); } } splittingKernel()->veto(generatedSplitting, factor*p, r, currentWeights); } void DipoleSplittingGenerator::accept(const vector<double>&, double p, double r) { double factor = 1.; if ( splittingReweight() ) { - if ( ( ShowerHandler::currentHandler()->firstInteraction() && splittingReweight()->firstInteraction() ) || - ( !ShowerHandler::currentHandler()->firstInteraction() && splittingReweight()->secondaryInteractions() ) ) { + if ( ( ShowerHandler::currentHandler()->firstInteraction() && + splittingReweight()->firstInteraction() ) || + ( !ShowerHandler::currentHandler()->firstInteraction() && + splittingReweight()->secondaryInteractions() ) ) { factor = splittingReweight()->evaluate(generatedSplitting); theSplittingWeight *= factor; } } splittingKernel()->accept(generatedSplitting, factor*p, r, currentWeights); } void DipoleSplittingGenerator::prepare(const DipoleSplittingInfo& sp) { generatedSplitting = sp; generatedSplitting.splittingKinematics(splittingKernel()->splittingKinematics()); generatedSplitting.splittingParameters().resize(splittingKernel()->nDimAdditional()); if ( wrapping() ) { generatedSplitting.emitterData(theSplittingKernel->emitter(generatedSplitting.index())); generatedSplitting.spectatorData(theSplittingKernel->spectator(generatedSplitting.index())); generatedSplitting.emissionData(theSplittingKernel->emission(generatedSplitting.index())); parameters.resize(theOtherGenerator->nDim()); prepared = true; return; } generatedSplitting.emitterData(splittingKernel()->emitter(generatedSplitting.index())); generatedSplitting.spectatorData(splittingKernel()->spectator(generatedSplitting.index())); generatedSplitting.emissionData(splittingKernel()->emission(generatedSplitting.index())); presampledSplitting = generatedSplitting; prepared = true; parameters.resize(nDim()); theExponentialGenerator = new exsample::exponential_generator<DipoleSplittingGenerator,UseRandom>(); theExponentialGenerator->sampling_parameters().maxtry = maxtry(); theExponentialGenerator->sampling_parameters().presampling_points = presamplingPoints(); theExponentialGenerator->sampling_parameters().freeze_grid = freezeGrid(); theExponentialGenerator->detuning(detuning()); theExponentialGenerator->docompensate(theDoCompensate); theExponentialGenerator->function(this); theExponentialGenerator->initialize(); } void DipoleSplittingGenerator::fixParameters(const DipoleSplittingInfo& sp, Energy optHardPt) { assert(generator()); assert(!presampling); assert(prepared); assert(sp.index() == generatedSplitting.index()); generatedSplitting.scale(sp.scale()); // For dipoles containing a decayed particle, // the scale is fixed but the mass of the recoil // system is not so sample over recoilMass(), // so the parameter is related to recoilMass() - if (generatedSplitting.index().incomingDecayEmitter() || generatedSplitting.index().incomingDecaySpectator() ) { + if (generatedSplitting.index().incomingDecayEmitter() || + generatedSplitting.index().incomingDecaySpectator() ) { generatedSplitting.recoilMass(sp.recoilMass()); parameters[3] = sp.recoilMass()/generator()->maximumCMEnergy(); } // If not a decay dipole, sample over the scale of the dipole, // so the parameter is related to scale() else parameters[3] = sp.scale()/generator()->maximumCMEnergy(); generatedSplitting.hardPt(sp.hardPt()); parameters[0] = splittingKinematics()->ptToRandom(optHardPt == ZERO ? generatedSplitting.hardPt() : min(generatedSplitting.hardPt(),optHardPt), sp.scale(), sp.emitterX(), sp.spectatorX(), generatedSplitting.index(), *splittingKernel()); size_t shift = 4; if ( generatedSplitting.index().emitterPDF().pdf() && generatedSplitting.index().spectatorPDF().pdf() ) { generatedSplitting.emitterX(sp.emitterX()); generatedSplitting.spectatorX(sp.spectatorX()); parameters[4] = sp.emitterX(); parameters[5] = sp.spectatorX(); shift += 2; } if ( generatedSplitting.index().emitterPDF().pdf() && !generatedSplitting.index().spectatorPDF().pdf() ) { generatedSplitting.emitterX(sp.emitterX()); parameters[4] = sp.emitterX(); ++shift; } if ( !generatedSplitting.index().emitterPDF().pdf() && generatedSplitting.index().spectatorPDF().pdf() ) { generatedSplitting.spectatorX(sp.spectatorX()); parameters[4] = sp.spectatorX(); ++shift; } if ( splittingKernel()->nDimAdditional() ) - copy(sp.lastSplittingParameters().begin(),sp.lastSplittingParameters().end(),parameters.begin()+shift); + copy(sp.lastSplittingParameters().begin(), + sp.lastSplittingParameters().end(), + parameters.begin()+shift); if ( sp.emitter() ) generatedSplitting.emitter(sp.emitter()); if ( sp.spectator() ) generatedSplitting.spectator(sp.spectator()); } int DipoleSplittingGenerator::nDim() const { assert(!wrapping()); assert(prepared); int ret = 4; // 0 pt, 1 z, 2 phi, 3 scale, 4/5 xs + parameters if ( generatedSplitting.index().emitterPDF().pdf() ) { ++ret; } if ( generatedSplitting.index().spectatorPDF().pdf() ) { ++ret; } ret += splittingKernel()->nDimAdditional(); return ret; } const vector<bool>& DipoleSplittingGenerator::sampleFlags() { assert(!wrapping()); if ( !theFlags.empty() ) return theFlags; theFlags.resize(nDim(),false); theFlags[0] = true; theFlags[1] = true; theFlags[2] = true; // 0 pt, 1 z, 2 phi return theFlags; } const pair<vector<double>,vector<double> >& DipoleSplittingGenerator::support() { assert(!wrapping()); if ( !theSupport.first.empty() ) return theSupport; vector<double> lower(nDim(),0.); vector<double> upper(nDim(),1.); pair<double,double> kSupport = generatedSplitting.splittingKinematics()->kappaSupport(generatedSplitting); pair<double,double> xSupport = generatedSplitting.splittingKinematics()->xiSupport(generatedSplitting); lower[0] = kSupport.first; lower[1] = xSupport.first; upper[0] = kSupport.second; upper[1] = xSupport.second; theSupport.first = lower; theSupport.second = upper; return theSupport; } void DipoleSplittingGenerator::startPresampling() { assert(!wrapping()); splittingKernel()->startPresampling(generatedSplitting.index()); presampling = true; } void DipoleSplittingGenerator::stopPresampling() { assert(!wrapping()); splittingKernel()->stopPresampling(generatedSplitting.index()); presampling = false; } bool DipoleSplittingGenerator::haveOverestimate() const { assert(!wrapping()); assert(prepared); return generatedSplitting.splittingKinematics()->haveOverestimate() && splittingKernel()->haveOverestimate(generatedSplitting); } bool DipoleSplittingGenerator::overestimate(const vector<double>& point) { assert(!wrapping()); assert(prepared); assert(!presampling); assert(haveOverestimate()); if ( ! generatedSplitting.splittingKinematics()->generateSplitting(point[0],point[1],point[2], generatedSplitting, *splittingKernel()) ) return 0.; generatedSplitting.splittingKinematics()->prepareSplitting(generatedSplitting); return ( generatedSplitting.splittingKinematics()->jacobianOverestimate() * splittingKernel()->overestimate(generatedSplitting) ); } double DipoleSplittingGenerator::invertOverestimateIntegral(double value) const { assert(!wrapping()); assert(prepared); assert(!presampling); assert(haveOverestimate()); return splittingKernel()->invertOverestimateIntegral(generatedSplitting,value); } double DipoleSplittingGenerator::evaluate(const vector<double>& point) { assert(!wrapping()); assert(prepared); assert(generator()); DipoleSplittingInfo& split = ( !presampling ? generatedSplitting : presampledSplitting ); split.continuesEvolving(); size_t shift = 4; if ( presampling ) { // For dipoles containing a decayed particle, // the scale is fixed but the mass of the recoil // system is not so sample over recoilMass() if ( split.index().incomingDecaySpectator() ) { split.scale(split.index().spectatorData()->mass()); split.recoilMass(point[3] * generator()->maximumCMEnergy()); } // Currently do not have decaying emitters //else if ( split.index().incomingDecayEmitter() ) { // split.scale(split.index().emitterData()->mass()); // split.recoilMass(point[3] * generator()->maximumCMEnergy()); //} // If not a decay dipole, sample over the scale of the dipole else split.scale(point[3] * generator()->maximumCMEnergy()); if ( split.index().emitterPDF().pdf() && split.index().spectatorPDF().pdf() ) { split.emitterX(point[4]); split.spectatorX(point[5]); shift += 2; } if ( split.index().emitterPDF().pdf() && !split.index().spectatorPDF().pdf() ) { split.emitterX(point[4]); ++shift; } if ( !split.index().emitterPDF().pdf() && split.index().spectatorPDF().pdf() ) { split.spectatorX(point[4]); ++shift; } if ( splittingKernel()->nDimAdditional() ) copy(point.begin()+shift,point.end(),split.splittingParameters().begin()); split.hardPt(split.splittingKinematics()->ptMax(split.scale(), split.emitterX(), split.spectatorX(), split, *splittingKernel())); } - if ( ! split.splittingKinematics()->generateSplitting(point[0],point[1],point[2],split,*splittingKernel()) ) { + if ( ! split.splittingKinematics()->generateSplitting(point[0], + point[1], + point[2], + split, + *splittingKernel()) ) { split.lastValue(0.); return 0.; } split.splittingKinematics()->prepareSplitting(split); if ( split.stoppedEvolving() ) { split.lastValue(0.); return 0.; } if ( !presampling ) splittingKernel()->clearAlphaPDFCache(); double kernel = splittingKernel()->evaluate(split); double jac = split.splittingKinematics()->jacobian(); // multiply in the profile scales when relevant assert(ShowerHandler::currentHandler()); if ( ShowerHandler::currentHandler()->firstInteraction() && ShowerHandler::currentHandler()->profileScales() && !presampling ) { Energy hard = ShowerHandler::currentHandler()->hardScale(); if ( hard > ZERO ) - kernel *= ShowerHandler::currentHandler()->profileScales()->hardScaleProfile(hard,split.lastPt()); + kernel *= ShowerHandler::currentHandler()->profileScales()-> + hardScaleProfile(hard,split.lastPt()); } split.lastValue( abs(jac) * kernel ); if ( ! isfinite(split.lastValue()) ) { - generator()->log() << "DipoleSplittingGenerator:evaluate(): problematic splitting kernel encountered for " + generator()->log() << "DipoleSplittingGenerator:evaluate():" + <<"problematic splitting kernel encountered for " << splittingKernel()->name() << "\n" << flush; split.lastValue(0.0); } if ( kernel < 0. ) return 0.; return split.lastValue(); } void DipoleSplittingGenerator::doGenerate(map<string,double>& variations, Energy optCutoff) { assert(!wrapping()); double res = 0.; Energy startPt = generatedSplitting.hardPt(); double optKappaCutoff = 0.0; if ( optCutoff > splittingKinematics()->IRCutoff() ) { optKappaCutoff = splittingKinematics()->ptToRandom(optCutoff, generatedSplitting.scale(), generatedSplitting.emitterX(), generatedSplitting.spectatorX(), generatedSplitting.index(), *splittingKernel()); } resetVariations(); theSplittingWeight = 1.; while (true) { try { if ( optKappaCutoff == 0.0 ) { res = theExponentialGenerator->generate(); } else { res = theExponentialGenerator->generate(optKappaCutoff); } } catch (exsample::exponential_regenerate&) { resetVariations(); theSplittingWeight = 1.; generatedSplitting.hardPt(startPt); continue; } catch (exsample::hit_and_miss_maxtry&) { throw DipoleShowerHandler::RedoShower(); } catch (exsample::selection_maxtry&) { throw DipoleShowerHandler::RedoShower(); } break; } for ( map<string,double>::const_iterator w = currentWeights.begin(); w != currentWeights.end(); ++w ) { map<string,double>::iterator v = variations.find(w->first); if ( v != variations.end() ) v->second *= w->second; else variations[w->first] = w->second; } if ( res == 0. ) { generatedSplitting.lastPt(0.0*GeV); generatedSplitting.didStopEvolving(); } else { generatedSplitting.continuesEvolving(); if ( theMCCheck ) theMCCheck->book(generatedSplitting.emitterX(), generatedSplitting.spectatorX(), generatedSplitting.scale(), startPt, generatedSplitting.lastPt(), generatedSplitting.lastZ(), 1.); } } Energy DipoleSplittingGenerator::generate(const DipoleSplittingInfo& split, map<string,double>& variations, Energy optHardPt, Energy optCutoff) { fixParameters(split,optHardPt); if ( wrapping() ) { return theOtherGenerator->generateWrapped(generatedSplitting,variations,optHardPt,optCutoff); } doGenerate(variations,optCutoff); return generatedSplitting.lastPt(); } -double DipoleSplittingGenerator::sudakovExpansion(const DipoleSplittingInfo& split,Energy down,Energy fixedScale){ +double DipoleSplittingGenerator::sudakovExpansion(const DipoleSplittingInfo& split, + Energy down,Energy fixedScale){ fixParameters(split); if ( wrapping() ) { return theOtherGenerator->wrappedSudakovExpansion( generatedSplitting, down,fixedScale); } return dosudakovExpansion( split, down,fixedScale); } double DipoleSplittingGenerator::sudakov(const DipoleSplittingInfo& split,Energy down){ fixParameters(split); if ( wrapping() ) { return theOtherGenerator->wrappedSudakov( generatedSplitting, down); } return dosudakov( split, down); } -double DipoleSplittingGenerator::dosudakovExpansion(const DipoleSplittingInfo& ,Energy down,Energy fixedScale){ +double DipoleSplittingGenerator::dosudakovExpansion(const DipoleSplittingInfo& , + Energy down,Energy fixedScale){ assert(down > splittingKinematics()->IRCutoff()); - double optKappaCutoffd = splittingKinematics()->ptToRandom(down, - generatedSplitting.scale(), - generatedSplitting.emitterX(), - generatedSplitting.spectatorX(), - generatedSplitting.index(), - *splittingKernel()); + double optKappaCutoffd = + splittingKinematics()->ptToRandom(down, + generatedSplitting.scale(), + generatedSplitting.emitterX(), + generatedSplitting.spectatorX(), + generatedSplitting.index(), + *splittingKernel()); double optKappaCutoffu = splittingKinematics()->ptToRandom(generatedSplitting.hardPt(), generatedSplitting.scale(), generatedSplitting.emitterX(), generatedSplitting.spectatorX(), generatedSplitting.index(), *splittingKernel()); vector<double> RN; RN.resize(3); double res=0.; double resq=0.; double varx=10.; int k=0; generatedSplitting.setCalcFixedExpansion(true); generatedSplitting.fixedScale(fixedScale); while ( k<500. && k<50000 ){ k+=1.; RN[0]= optKappaCutoffd+(optKappaCutoffu-optKappaCutoffd)*UseRandom::rnd(); //PT RN[1]= UseRandom::rnd(); //Z RN[2]= UseRandom::rnd(); //PHI double tmp=(optKappaCutoffu-optKappaCutoffd)*evaluate(RN); res+= tmp; resq+=pow(tmp,2.); if(k%50==0.){ varx=sqrt((resq/pow(1.*k,2)-pow(res,2)/pow(1.*k,3))); if(varx<0.05)break; } } generatedSplitting.setCalcFixedExpansion(false); return -res/(1.0*k); } double DipoleSplittingGenerator::dosudakov(const DipoleSplittingInfo& ,Energy down){ double optKappaCutoffd = splittingKinematics()->ptToRandom(down, generatedSplitting.scale(), generatedSplitting.emitterX(), generatedSplitting.spectatorX(), generatedSplitting.index(), *splittingKernel()); double optKappaCutoffu = splittingKinematics()->ptToRandom(generatedSplitting.hardPt(), generatedSplitting.scale(), generatedSplitting.emitterX(), generatedSplitting.spectatorX(), generatedSplitting.index(), *splittingKernel()); vector<double> RN; RN.resize(3); double res=0.; double resq=0.; double var=10.; double varx=10.; int k=0; while (((k<40.||var>0.5)&&k<50000)){ k+=1.; RN[0]= optKappaCutoffd+(optKappaCutoffu-optKappaCutoffd)*UseRandom::rnd(); //PT RN[1]=UseRandom::rnd(); //Z RN[2]=UseRandom::rnd(); //PHI double tmp=(optKappaCutoffu-optKappaCutoffd)*evaluate(RN); res+= tmp; resq+=pow(tmp,2.); varx=sqrt((resq/pow(1.*k,2)-pow(res,2)/pow(1.*k,3))); if(k%20==0.)var= (exp(-(res)/(1.0*k)+varx)-exp(-(res)/(1.0*k)-varx))*exp(-res/(1.0*k)); } return exp(-res/(1.0*k)); } double DipoleSplittingGenerator::wrappedSudakovExpansion(DipoleSplittingInfo& split, Energy down,Energy fixedScale) { assert(!wrapping()); DipoleSplittingInfo backup = generatedSplitting; generatedSplitting = split; fixParameters(split); double res=dosudakovExpansion( split, down,fixedScale); split = generatedSplitting; generatedSplitting = backup; return res; } double DipoleSplittingGenerator::wrappedSudakov(DipoleSplittingInfo& split, Energy down) { assert(!wrapping()); DipoleSplittingInfo backup = generatedSplitting; generatedSplitting = split; fixParameters(split); double res=dosudakov( split, down); split = generatedSplitting; generatedSplitting = backup; return res; } Energy DipoleSplittingGenerator::generateWrapped(DipoleSplittingInfo& split, map<string,double>& variations, Energy optHardPt, Energy optCutoff) { assert(!wrapping()); DipoleSplittingInfo backup = generatedSplitting; generatedSplitting = split; fixParameters(split,optHardPt); try { doGenerate(variations,optCutoff); } catch (...) { split = generatedSplitting; generatedSplitting = backup; throw; } Energy pt = generatedSplitting.lastPt(); split = generatedSplitting; generatedSplitting = backup; return pt; } void DipoleSplittingGenerator::completeSplitting(DipoleSplittingInfo& sp) const { pair<bool,bool> conf = sp.configuration(); sp = generatedSplitting; sp.configuration(conf); } Ptr<DipoleSplittingKernel>::tptr DipoleSplittingGenerator::splittingKernel() const { if ( wrapping() ) return theOtherGenerator->splittingKernel(); return theSplittingKernel; } Ptr<DipoleSplittingReweight>::tptr DipoleSplittingGenerator::splittingReweight() const { if ( wrapping() ) return theOtherGenerator->splittingReweight(); return theSplittingReweight; } Ptr<DipoleSplittingKinematics>::tptr DipoleSplittingGenerator::splittingKinematics() const { if ( wrapping() ) return theOtherGenerator->splittingKinematics(); return theSplittingKernel->splittingKinematics(); } void DipoleSplittingGenerator::splittingKernel(Ptr<DipoleSplittingKernel>::tptr sp) { theSplittingKernel = sp; if ( theSplittingKernel->mcCheck() ) theMCCheck = theSplittingKernel->mcCheck(); } void DipoleSplittingGenerator::splittingReweight(Ptr<DipoleSplittingReweight>::tptr sp) { theSplittingReweight = sp; } void DipoleSplittingGenerator::debugGenerator(ostream& os) const { os << "--- DipoleSplittingGenerator ---------------------------------------------------\n"; os << " generating splittings using\n" << " splittingKernel = " << splittingKernel()->name() << " splittingKinematics = " << generatedSplitting.splittingKinematics()->name() << "\n" << " to sample splittings of type:\n"; os << generatedSplitting; os << "--------------------------------------------------------------------------------\n"; } void DipoleSplittingGenerator::debugLastEvent(ostream& os) const { os << "--- DipoleSplittingGenerator ---------------------------------------------------\n"; os << " last generated event:\n"; os << generatedSplitting; os << "--------------------------------------------------------------------------------\n"; } // If needed, insert default implementations of virtual function defined // in the InterfacedBase class here (using ThePEG-interfaced-impl in Emacs). void DipoleSplittingGenerator::persistentOutput(PersistentOStream & os) const { os << theOtherGenerator << theSplittingKernel << theSplittingReweight << theMCCheck << theDoCompensate; } void DipoleSplittingGenerator::persistentInput(PersistentIStream & is, int) { is >> theOtherGenerator >> theSplittingKernel >> theSplittingReweight >> theMCCheck >> theDoCompensate; } ClassDescription<DipoleSplittingGenerator> DipoleSplittingGenerator::initDipoleSplittingGenerator; // Definition of the static class description member. void DipoleSplittingGenerator::Init() { static ClassDocumentation<DipoleSplittingGenerator> documentation ("DipoleSplittingGenerator is used by the dipole shower " "to sample splittings from a given dipole splitting kernel."); static Reference<DipoleSplittingGenerator,DipoleSplittingKernel> interfaceSplittingKernel ("SplittingKernel", "Set the splitting kernel to sample from.", &DipoleSplittingGenerator::theSplittingKernel, false, false, true, false, false); static Reference<DipoleSplittingGenerator,DipoleSplittingReweight> interfaceSplittingReweight ("SplittingReweight", "Set the splitting reweight.", &DipoleSplittingGenerator::theSplittingReweight, false, false, true, true, false); static Reference<DipoleSplittingGenerator,DipoleMCCheck> interfaceMCCheck ("MCCheck", "[debug option] MCCheck", &DipoleSplittingGenerator::theMCCheck, false, false, true, true, false); interfaceMCCheck.rank(-1); } diff --git a/Shower/Dipole/DipoleShowerHandler.cc b/Shower/Dipole/DipoleShowerHandler.cc --- a/Shower/Dipole/DipoleShowerHandler.cc +++ b/Shower/Dipole/DipoleShowerHandler.cc @@ -1,1266 +1,1281 @@ // -*- C++ -*- // // DipoleShowerHandler.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2007 The Herwig Collaboration // // Herwig is licenced under version 2 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 DipoleShowerHandler class. // #include <config.h> #include "DipoleShowerHandler.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Interface/Reference.h" #include "ThePEG/Interface/RefVector.h" #include "ThePEG/Interface/Parameter.h" #include "ThePEG/Interface/Switch.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" // include theses to have complete types #include "Herwig/PDF/MPIPDF.h" #include "Herwig/PDF/MinBiasPDF.h" #include "Herwig/PDF/HwRemDecayer.h" #include "Herwig/Shower/Dipole/Utility/DipolePartonSplitter.h" #include "Herwig/MatrixElement/Matchbox/Base/MergerBase.h" #include "Herwig/MatrixElement/Matchbox/Base/SubtractedME.h" #include "Herwig/MatrixElement/Matchbox/MatchboxFactory.h" #include <queue> using namespace Herwig; bool DipoleShowerHandler::firstWarn = true; DipoleShowerHandler::DipoleShowerHandler() : ShowerHandler(), chainOrderVetoScales(true), nEmissions(0), discardNoEmissions(false), firstMCatNLOEmission(false), thePowhegDecayEmission(true), realignmentScheme(0), verbosity(0), printEvent(0), nTries(0), didRadiate(false), didRealign(false), theRenormalizationScaleFreeze(1.*GeV), theFactorizationScaleFreeze(2.*GeV), theDoCompensate(false), theFreezeGrid(500000), theDetuning(1.0), maxPt(ZERO), muPt(ZERO) {} DipoleShowerHandler::~DipoleShowerHandler() {} IBPtr DipoleShowerHandler::clone() const { return new_ptr(*this); } IBPtr DipoleShowerHandler::fullclone() const { return new_ptr(*this); } void DipoleShowerHandler::cascade(tPVector ) { throw Exception() << "DipoleShowerHandler: Dipoleshower not implemented as second shower." << "Check your setup or contact Herwig authors." << Exception::runerror; } tPPair DipoleShowerHandler::cascade(tSubProPtr sub, XCombPtr, Energy optHardPt, Energy optCutoff) { useMe(); prepareCascade(sub); resetWeights(); if ( !doFSR() && ! doISR() ) return sub->incoming(); eventRecord().clear(); eventRecord().prepare(sub, dynamic_ptr_cast<tStdXCombPtr>(lastXCombPtr()), pdfs(), ShowerHandler::currentHandler()->generator()->currentEvent()->incoming()); if ( eventRecord().outgoing().empty() && !doISR() ) return sub->incoming(); if ( !eventRecord().incoming().first->coloured() && !eventRecord().incoming().second->coloured() && !doFSR() ) return sub->incoming(); nTries = 0; while ( true ) { try { didRadiate = false; didRealign = false; if ( eventRecord().truncatedShower() ) { throw Exception() << "Inconsistent hard emission set-up in DipoleShowerHandler::cascade. " << "No truncated shower needed with DipoleShowerHandler. Add " << "'set MEMatching:TruncatedShower No' to input file." << Exception::runerror; } hardScales(lastXCombPtr()->lastShowerScale()); if ( verbosity > 1 ) { generator()->log() << "DipoleShowerHandler starting off:\n"; eventRecord().debugLastEvent(generator()->log()); generator()->log() << flush; } unsigned int nEmitted = 0; if ( firstMCatNLOEmission ) { if ( !eventRecord().isMCatNLOHEvent() ) nEmissions = 1; else nEmissions = 0; } if ( !firstMCatNLOEmission ) { doCascade(nEmitted,optHardPt,optCutoff); if ( discardNoEmissions ) { if ( !didRadiate ) throw Veto(); if ( nEmissions ) if ( nEmissions < nEmitted ) throw Veto(); } } else { if ( nEmissions == 1 ) doCascade(nEmitted,optHardPt,optCutoff); } if ( intrinsicPtGenerator ) { if ( eventRecord().incoming().first->coloured() && eventRecord().incoming().second->coloured() ) { SpinOneLorentzRotation rot = intrinsicPtGenerator->kick(eventRecord().incoming(), eventRecord().intermediates()); eventRecord().transform(rot); } } didRealign = realign(); constituentReshuffle(); // Decay and shower any particles that require decaying while ( !eventRecord().decays().empty() ) { map<PPtr,PerturbativeProcessPtr>::const_iterator decayIt = eventRecord().decays().begin(); // find the decay to do, one with greatest width and parent showered while(find(eventRecord().outgoing().begin(),eventRecord().outgoing().end(),decayIt->first)== eventRecord().outgoing().end() && find(eventRecord().hard().begin(),eventRecord().hard().end(),decayIt->first)== eventRecord().hard().end()) ++decayIt; assert(decayIt!=eventRecord().decays().end()); PPtr incoming = decayIt->first; eventRecord().currentDecay(decayIt->second); // Use this to record if an emission actually happens bool powhegEmission = thePowhegDecayEmission; // Decay the particle / sort out its pert proc Energy showerScale = eventRecord().decay(incoming, powhegEmission); - // Following the decay, the bool powheg emission is updated to indicate whether or not an emission occurred + // Following the decay, the bool powheg emission is updated + // to indicate whether or not an emission occurred if ( powhegEmission ) nEmitted += 1; // Check that there is only one particle incoming to the decay assert(eventRecord().currentDecay()->incoming().size()==1); // Prepare the event record for the showering of the decay bool needToShower = eventRecord().prepareDecay(eventRecord().currentDecay()); // Only need to shower if we have coloured outgoing particles if ( needToShower ) { // The decays currently considered produce a maximum of 2 chains (with powheg emission) // so all dipole should have the same scale as returned by the decay function. assert( eventRecord().chains().size() <= 2 ); for ( auto & ch : eventRecord().chains()) { for ( auto & dip : ch.dipoles()) { assert ( showerScale > ZERO ); dip.leftScale( showerScale ); dip.rightScale( showerScale ); } } // Perform the cascade doCascade(nEmitted,optHardPt,optCutoff,true); // Do the constituent mass shell reshuffling - decayConstituentReshuffle(eventRecord().currentDecay(), false); + decayConstituentReshuffle(eventRecord().currentDecay()); } // Update the decays, adding any decays and updating momenta eventRecord().updateDecays(eventRecord().currentDecay()); eventRecord().decays().erase(decayIt); } break; } catch (RedoShower&) { resetWeights(); if ( ++nTries > maxtry() ) throw ShowerTriesVeto(maxtry()); eventRecord().clear(); - eventRecord().prepare(sub,dynamic_ptr_cast<tStdXCombPtr>(lastXCombPtr()),pdfs(),ShowerHandler::currentHandler()->generator()->currentEvent()->incoming()); + eventRecord().prepare(sub,dynamic_ptr_cast<tStdXCombPtr>(lastXCombPtr()), + pdfs(), + ShowerHandler::currentHandler()->generator()->currentEvent()->incoming()); continue; } catch (...) { throw; } } tPPair incoming=eventRecord().fillEventRecord(newStep(),firstInteraction(),didRealign); setDidRunCascade(true); return incoming; } // Reshuffle the outgoing partons from the hard process onto their constituent mass shells void DipoleShowerHandler::constituentReshuffle() { if ( constituentReshuffler ) { if ( eventRecord().decays().empty() ) { constituentReshuffler->reshuffle(eventRecord().outgoing(), eventRecord().incoming(), eventRecord().intermediates()); return; } else { PList decaying; for(auto const & dec : eventRecord().decays()) decaying.push_back(dec.first); constituentReshuffler->hardProcDecayReshuffle( decaying, eventRecord().outgoing(), eventRecord().hard(), eventRecord().incoming(), eventRecord().intermediates()); } } // After reshuffling the hard process, the decays need to be updated // as this is not done in reshuffle vector<pair<PPtr,PerturbativeProcessPtr> > decays; for(auto const & dec : eventRecord().decays() ) decays.push_back({dec.first,dec.second}); for(auto const & dec : decays) { PPtr unstable = dec.first; - PList::iterator pos = find(eventRecord().intermediates().begin(),eventRecord().intermediates().end(),dec.first); + PList::iterator pos = find(eventRecord().intermediates().begin(), + eventRecord().intermediates().end(), + dec.first); // Update the PPtr in theDecays if(pos!=eventRecord().intermediates().end()) { unstable = *pos; while(!unstable->children().empty()) { unstable = unstable->children()[0]; } eventRecord().decays().erase(dec.first); eventRecord().decays()[unstable] = dec.second; // Update the momenta of any other particles in the decay chain // (for externally provided events) if ( !(eventRecord().decays()[unstable]->outgoing().empty()) ) eventRecord().updateDecayChainMom( unstable , eventRecord().decays()[unstable]); } else { if ( !(eventRecord().decays()[unstable]->outgoing().empty()) ) { // Update the momenta of any other particles in the decay chain // (for externally provided events) // Note this needs to be done for all decaying particles in the // outgoing/hard regardless of whether that particle radiated // or was involved in the reshuffling, this is due to the // transformation performed for IILightKinematics. if ( (find(eventRecord().outgoing().begin(), eventRecord().outgoing().end(), unstable) != eventRecord().outgoing().end()) || (find(eventRecord().hard().begin(), eventRecord().hard().end(), unstable) != eventRecord().hard().end()) ) eventRecord().updateDecayChainMom( unstable , eventRecord().decays()[unstable]); } } } eventRecord().currentDecay(PerturbativeProcessPtr()); } // Reshuffle outgoing partons from a decay process onto their constituent mass shells -void DipoleShowerHandler::decayConstituentReshuffle(PerturbativeProcessPtr decayProc, const bool test) { +void DipoleShowerHandler::decayConstituentReshuffle(PerturbativeProcessPtr decayProc) { - if ( !test ) { - // decayReshuffle updates both the event record and the decay perturbative process - if ( constituentReshuffler ) { - constituentReshuffler->decayReshuffle(decayProc, - eventRecord().outgoing(), - eventRecord().hard(), - eventRecord().intermediates()); - } - return; - } - if ( test ) { + + if ( Debug::level > 2 ){ + // Test this function by comparing the // invariant mass of the outgoing decay // systems before and after reshuffling Lorentz5Momentum testOutMomBefore (ZERO,ZERO,ZERO,ZERO); Energy testInvMassBefore = ZERO; for ( auto const & testDecayOutItBefore : decayProc->outgoing() ) { testOutMomBefore += testDecayOutItBefore.first->momentum(); } testInvMassBefore = testOutMomBefore.m(); // decayReshuffle updates both the event record and the decay perturbative process if ( constituentReshuffler ) { constituentReshuffler->decayReshuffle(decayProc, eventRecord().outgoing(), eventRecord().hard(), eventRecord().intermediates()); } Lorentz5Momentum testOutMomAfter (ZERO,ZERO,ZERO,ZERO); Energy testInvMassAfter = ZERO; for ( auto const & testDecayOutItAfter : decayProc->outgoing() ) { testOutMomAfter += testDecayOutItAfter.first->momentum(); } testInvMassAfter = testOutMomAfter.m(); Energy incomingMass = decayProc->incoming()[0].first->momentum().m(); assert( abs(testInvMassBefore-incomingMass)/GeV < 1e-5 ); assert( abs(testInvMassBefore-testInvMassAfter)/GeV < 1e-5); + }else{ + // decayReshuffle updates both the event record and the decay perturbative process + if ( constituentReshuffler ) { + constituentReshuffler->decayReshuffle(decayProc, + eventRecord().outgoing(), + eventRecord().hard(), + eventRecord().intermediates()); + } + return; } + } - // Sets the scale of each particle in the dipole chains by finding the smallest of several upper bound energy scales: the CMEnergy of the event, the transverse mass of outgoing particles, the hardScale (maxPT or maxQ) calculated for each dipole (in both configurations) and the veto scale for each particle + // Sets the scale of each particle in the dipole chains by finding the smallest + //of several upper bound energy scales: the CMEnergy of the event, + //the transverse mass of outgoing particles, the hardScale (maxPT or maxQ) + //calculated for each dipole (in both configurations) and the veto scale for each particle void DipoleShowerHandler::hardScales(Energy2 muf) { // Initalise maximum pt as max CMEnergy of the event maxPt = generator()->maximumCMEnergy(); if ( restrictPhasespace() ) { // First interaction == hard collision (i.e. not a MPI collision) if ( !hardScaleIsMuF() || !firstInteraction() ) { if ( !eventRecord().outgoing().empty() ) { for ( auto const & p : eventRecord().outgoing() ) maxPt = min(maxPt,p->momentum().mt()); } //Look at any non-coloured outgoing particles in the current subprocess else { assert(!eventRecord().hard().empty()); Lorentz5Momentum phard(ZERO,ZERO,ZERO,ZERO); for ( auto const & p : eventRecord().hard()) phard += p->momentum(); Energy mhard = phard.m(); maxPt = mhard; } maxPt *= hardScaleFactor(); } else { maxPt = hardScaleFactor()*sqrt(muf); } muPt = maxPt; } else { muPt = hardScaleFactor()*sqrt(muf); } for ( auto & ch : eventRecord().chains()) { // Note that minVetoScale is a value for each DipoleChain, not each dipole // It will contain the minimum veto scale from all of the dipoles in the chain Energy minVetoScale = -1.*GeV; for ( auto & dip : ch.dipoles()) { // max scale per config Energy maxFirst = ZERO; Energy maxSecond = ZERO; // Loop over the kernels for the given dipole. - // For each dipole configuration, calculate ptMax (or QMax if virtuality ordering) for each kernel and find the maximum + // For each dipole configuration, calculate ptMax (or QMax if virtuality ordering) + // for each kernel and find the maximum for ( auto const & k : kernels) { pair<bool,bool> conf = {true,false}; if ( k->canHandle(dip.index(conf)) ) { // Look in DipoleChainOrdering for this Energy scale = evolutionOrdering()->hardScale(dip.emitter(conf),dip.spectator(conf), dip.emitterX(conf),dip.spectatorX(conf), *k,dip.index(conf)); maxFirst = max(maxFirst,scale); } conf = {false,true}; if ( k->canHandle(dip.index(conf)) ) { Energy scale = evolutionOrdering()->hardScale(dip.emitter(conf),dip.spectator(conf), dip.emitterX(conf),dip.spectatorX(conf), *k,dip.index(conf)); maxSecond = max(maxSecond,scale); } } // Find the maximum value from comparing the maxScale found from maxPt and the vetoScale of the particle if ( dip.leftParticle()->vetoScale() >= ZERO ) { maxFirst = min(maxFirst,sqrt(dip.leftParticle()->vetoScale())); // minVetoScale is a value for each DipoleChain, not each dipole // It contains the minimum veto scale for all the dipoles in the entire DipoleChain if ( minVetoScale >= ZERO ) minVetoScale = min(minVetoScale,sqrt(dip.leftParticle()->vetoScale())); else minVetoScale = sqrt(dip.leftParticle()->vetoScale()); } if ( dip.rightParticle()->vetoScale() >= ZERO ) { maxSecond = min(maxSecond,sqrt(dip.rightParticle()->vetoScale())); if ( minVetoScale >= ZERO ) minVetoScale = min(minVetoScale,sqrt(dip.rightParticle()->vetoScale())); else minVetoScale = sqrt(dip.rightParticle()->vetoScale()); } // Set the emitterScale for both members of each dipole maxFirst = min(maxPt,maxFirst); dip.emitterScale({true,false},maxFirst); maxSecond = min(maxPt,maxSecond); dip.emitterScale({false,true},maxSecond); } - // if the smallest veto scale (i.e. from all of the dipoles) is smaller than the scale calculated for a particular particle in a particular dipole, replace the scale with the veto scale + // if the smallest veto scale (i.e. from all of the dipoles) + // is smaller than the scale calculated for a particular + // particle in a particular dipole, + // replace the scale with the veto scale if ( !evolutionOrdering()->independentDipoles() && chainOrderVetoScales && minVetoScale >= ZERO ) { for ( auto & dip : ch.dipoles() ) { dip.leftScale(min(dip.leftScale(),minVetoScale)); dip.rightScale(min(dip.rightScale(),minVetoScale)); } } } } Energy DipoleShowerHandler::getWinner(DipoleSplittingInfo& winner, const Dipole& dip, pair<bool,bool> conf, Energy optHardPt, Energy optCutoff) { return getWinner(winner,dip.index(conf), dip.emitterX(conf),dip.spectatorX(conf), conf,dip.emitter(conf),dip.spectator(conf), dip.emitterScale(conf),optHardPt,optCutoff); } Energy DipoleShowerHandler::getWinner(SubleadingSplittingInfo& winner, Energy optHardPt, Energy optCutoff) { return getWinner(winner,winner.index(), winner.emitterX(),winner.spectatorX(), winner.configuration(), winner.emitter(),winner.spectator(), winner.startScale(),optHardPt,optCutoff); } Energy DipoleShowerHandler::getWinner(DipoleSplittingInfo& winner, const DipoleIndex& index, double emitterX, double spectatorX, pair<bool,bool> conf, tPPtr emitter, tPPtr spectator, Energy startScale, Energy optHardPt, Energy optCutoff) { if ( !index.initialStateEmitter() && !doFSR() ) { winner.didStopEvolving(); return 0.0*GeV; } if ( index.initialStateEmitter() && !doISR() ) { winner.didStopEvolving(); return 0.0*GeV; } // Currently do not split IF dipoles so // don't evaluate them in order to avoid // exceptions in the log if ( index.incomingDecayEmitter() ) { winner.didStopEvolving(); return 0.0*GeV; } DipoleSplittingInfo candidate; candidate.index(index); candidate.configuration(conf); candidate.emitterX(emitterX); candidate.spectatorX(spectatorX); if ( generators().find(candidate.index()) == generators().end() ) getGenerators(candidate.index(),theSplittingReweight); // // NOTE -- needs proper fixing at some point // // For some very strange reason, equal_range gives back // key ranges it hasn't been asked for. This particularly // happens e.g. for FI dipoles of the same kind, but different // PDF (hard vs MPI PDF). I can't see a reason for this, // as DipoleIndex properly implements comparison for equality // and (lexicographic) ordering; for the time being, we // use equal_range, extented by an explicit check for wether // the key is indeed what we wanted. See line after (*) comment // below. // // SW - Update 04/01/2016: Note - This caused a bug for me as I did not // include equality checks on the decay booleans in the == definition pair<GeneratorMap::iterator,GeneratorMap::iterator> gens = generators().equal_range(candidate.index()); Energy winnerScale = 0.0*GeV; GeneratorMap::iterator winnerGen = generators().end(); for ( GeneratorMap::iterator gen = gens.first; gen != gens.second; ++gen ) { // (*) see NOTE above if ( !(gen->first == candidate.index()) ) continue; if ( startScale <= gen->second->splittingKinematics()->IRCutoff() ) continue; Energy dScale = gen->second->splittingKinematics()->dipoleScale(emitter->momentum(), spectator->momentum()); // in very exceptional cases happening in DIS if ( std::isnan( double(dScale/MeV) ) ) throw RedoShower(); candidate.scale(dScale); // Calculate the mass of the recoil system // for decay dipoles if (candidate.index().incomingDecayEmitter() || candidate.index().incomingDecaySpectator() ) { Energy recoilMass = gen->second->splittingKinematics()->recoilMassKin(emitter->momentum(), spectator->momentum()); candidate.recoilMass(recoilMass); } candidate.continuesEvolving(); Energy hardScale = evolutionOrdering()->maxPt(startScale,candidate,*(gen->second->splittingKernel())); Energy maxPossible = gen->second->splittingKinematics()->ptMax(candidate.scale(), candidate.emitterX(), candidate.spectatorX(), candidate, *gen->second->splittingKernel()); Energy ircutoff = optCutoff < gen->second->splittingKinematics()->IRCutoff() ? gen->second->splittingKinematics()->IRCutoff() : optCutoff; if ( maxPossible <= ircutoff ) { continue; } if ( maxPossible >= hardScale ){ candidate.hardPt(hardScale); } else { hardScale = maxPossible; candidate.hardPt(maxPossible); } gen->second->generate(candidate,currentWeights(),optHardPt,optCutoff); - Energy nextScale = evolutionOrdering()->evolutionScale(gen->second->lastSplitting(),*(gen->second->splittingKernel())); + Energy nextScale = evolutionOrdering()->evolutionScale( + gen->second->lastSplitting(),*(gen->second->splittingKernel())); if ( nextScale > winnerScale ) { winner.fill(candidate); gen->second->completeSplitting(winner); winnerGen = gen; winnerScale = nextScale; } reweight(reweight() * gen->second->splittingWeight()); } if ( winnerGen == generators().end() ) { winner.didStopEvolving(); return 0.0*GeV; } if ( winner.stoppedEvolving() ) return 0.0*GeV; return winnerScale; } void DipoleShowerHandler::doCascade(unsigned int& emDone, Energy optHardPt, Energy optCutoff, const bool decay) { if ( nEmissions ) if ( emDone == nEmissions ) return; DipoleSplittingInfo winner; DipoleSplittingInfo dipoleWinner; - //TODO: find a better solution - size_t currentMultiplicity=0; - for(auto i : eventHandler()->currentStep()->getFinalState() ) - if (i->id()!=82)currentMultiplicity++; - - currentMultiplicity+=2; while ( eventRecord().haveChain() ) { if ( verbosity > 2 ) { generator()->log() << "DipoleShowerHandler selecting splittings for the chain:\n" << eventRecord().currentChain() << flush; } list<Dipole>::iterator winnerDip = eventRecord().currentChain().dipoles().end(); Energy winnerScale = 0.0*GeV; Energy nextLeftScale = 0.0*GeV; Energy nextRightScale = 0.0*GeV; for ( list<Dipole>::iterator dip = eventRecord().currentChain().dipoles().begin(); dip != eventRecord().currentChain().dipoles().end(); ++dip ) { nextLeftScale = getWinner(dipoleWinner,*dip,{true,false},optHardPt,optCutoff); if ( nextLeftScale > winnerScale ) { winnerScale = nextLeftScale; winner = dipoleWinner; winnerDip = dip; } nextRightScale = getWinner(dipoleWinner,*dip,{false,true},optHardPt,optCutoff); if ( nextRightScale > winnerScale ) { winnerScale = nextRightScale; winner = dipoleWinner; winnerDip = dip; } if ( evolutionOrdering()->independentDipoles() ) { Energy dipScale = max(nextLeftScale,nextRightScale); if ( dip->leftScale() > dipScale ) dip->leftScale(dipScale); if ( dip->rightScale() > dipScale ) dip->rightScale(dipScale); } } if ( verbosity > 1 ) { if ( winnerDip != eventRecord().currentChain().dipoles().end() ) generator()->log() << "DipoleShowerHandler selected the splitting:\n" << winner << " for the dipole\n" << (*winnerDip) << flush; else generator()->log() << "DipoleShowerHandler could not select a splitting above the IR cutoff\n" << flush; } // pop the chain if no dipole did radiate if ( winnerDip == eventRecord().currentChain().dipoles().end() ) { eventRecord().popChain(); if ( theEventReweight && eventRecord().chains().empty() ) if ( (theEventReweight->firstInteraction() && firstInteraction()) || (theEventReweight->secondaryInteractions() && !firstInteraction()) ) { double w = theEventReweight->weightCascade(eventRecord().incoming(), eventRecord().outgoing(), eventRecord().hard(),theGlobalAlphaS); reweight(reweight()*w); } continue; } // otherwise perform the splitting if (theMergingHelper&&eventHandler()->currentCollision()&&!decay) { - if (theMergingHelper->maxLegs()>currentMultiplicity){ + if (theMergingHelper->maxLegs()>eventRecord().outgoing().size()+ + eventRecord().hard().size() + +2){//incoming if (theMergingHelper->mergingScale()<winnerScale){ const bool transparent=true; if (transparent) { pair<list<Dipole>::iterator,list<Dipole>::iterator> tmpchildren; DipoleSplittingInfo tmpwinner=winner; DipoleChain* tmpfirstChain = nullptr; DipoleChain* tmpsecondChain = nullptr; - auto New=eventRecord().tmpsplit(winnerDip,tmpwinner,tmpchildren,tmpfirstChain,tmpsecondChain); + auto New=eventRecord().tmpsplit(winnerDip,tmpwinner, + tmpchildren,tmpfirstChain, + tmpsecondChain); - if (theMergingHelper->matrixElementRegion(New.first,New.second,winnerScale,theMergingHelper->mergingScale())) { + if (theMergingHelper->matrixElementRegion(New.first, + New.second, + winnerScale, + theMergingHelper->mergingScale())) { optHardPt=winnerScale; continue; } }else{ optHardPt=winnerScale; continue; } } } } didRadiate = true; eventRecord().isMCatNLOSEvent(false); eventRecord().isMCatNLOHEvent(false); pair<list<Dipole>::iterator,list<Dipole>::iterator> children; DipoleChain* firstChain = nullptr; DipoleChain* secondChain = nullptr; // Note: the dipoles are updated in eventRecord().split(....) after the splitting, // hence the entire cascade is handled in doCascade // The dipole scales are updated in dip->split(....) if ( decay ) winner.isDecayProc( true ); eventRecord().split(winnerDip,winner,children,firstChain,secondChain); - currentMultiplicity++; assert(firstChain && secondChain); evolutionOrdering()->setEvolutionScale(winnerScale,winner,*firstChain,children); if ( !secondChain->dipoles().empty() ) evolutionOrdering()->setEvolutionScale(winnerScale,winner,*secondChain,children); if ( verbosity > 1 ) { generator()->log() << "DipoleShowerHandler did split the last selected dipole into:\n" << (*children.first) << (*children.second) << flush; } if ( verbosity > 2 ) { generator()->log() << "After splitting the last selected dipole, " << "DipoleShowerHandler encountered the following chains:\n" << (*firstChain) << (*secondChain) << flush; } if ( theEventReweight ) if ( (theEventReweight->firstInteraction() && firstInteraction()) || (theEventReweight->secondaryInteractions() && !firstInteraction()) ) { double w = theEventReweight->weight(eventRecord().incoming(), eventRecord().outgoing(), eventRecord().hard(),theGlobalAlphaS); reweight(reweight()*w); } if ( nEmissions ) if ( ++emDone == nEmissions ) return; } } bool DipoleShowerHandler::realign() { if ( !didRadiate && !intrinsicPtGenerator ) return false; if ( eventRecord().incoming().first->coloured() || eventRecord().incoming().second->coloured() ) { if ( eventRecord().incoming().first->momentum().perp2()/GeV2 < 1e-10 && eventRecord().incoming().second->momentum().perp2()/GeV2 < 1e-10 ) return false; pair<Lorentz5Momentum,Lorentz5Momentum> inMomenta (eventRecord().incoming().first->momentum(), eventRecord().incoming().second->momentum()); SpinOneLorentzRotation transform((inMomenta.first+inMomenta.second).findBoostToCM()); Axis dir = (transform * inMomenta.first).vect().unit(); Axis rot (-dir.y(),dir.x(),0); double theta = dir.theta(); if ( lastParticles().first->momentum().z() < ZERO ) theta = -theta; transform.rotate(-theta,rot); inMomenta.first = transform*inMomenta.first; inMomenta.second = transform*inMomenta.second; assert(inMomenta.first.z() > ZERO && inMomenta.second.z() < ZERO); Energy2 sHat = (eventRecord().incoming().first->momentum() + eventRecord().incoming().second->momentum()).m2(); pair<Energy,Energy> masses(eventRecord().incoming().first->mass(), eventRecord().incoming().second->mass()); pair<Energy,Energy> qs; if ( !eventRecord().incoming().first->coloured() ) { assert(masses.second == ZERO); qs.first = eventRecord().incoming().first->momentum().z(); qs.second = (sHat-sqr(masses.first))/(2.*(qs.first+sqrt(sqr(masses.first)+sqr(qs.first)))); } else if ( !eventRecord().incoming().second->coloured() ) { assert(masses.first == ZERO); qs.second = eventRecord().incoming().second->momentum().z(); qs.first = (sHat-sqr(masses.second))/(2.*(qs.second+sqrt(sqr(masses.second)+sqr(qs.second)))); } else { assert(masses.first == ZERO && masses.second == ZERO); if ( realignmentScheme == 0 ) { double yX = eventRecord().pX().rapidity(); double yInt = (transform*eventRecord().pX()).rapidity(); double dy = yX-yInt; qs.first = (sqrt(sHat)/2.)*exp(dy); qs.second = (sqrt(sHat)/2.)*exp(-dy); } else if ( realignmentScheme == 1 ) { Energy sS = sqrt((lastParticles().first->momentum() + lastParticles().second->momentum()).m2()); qs.first = eventRecord().fractions().first * sS / 2.; qs.second = eventRecord().fractions().second * sS / 2.; } } double beta = (qs.first-qs.second) / ( sqrt(sqr(masses.first)+sqr(qs.first)) + sqrt(sqr(masses.second)+sqr(qs.second)) ); transform.boostZ(beta); Lorentz5Momentum tmp; if ( eventRecord().incoming().first->coloured() ) { tmp = eventRecord().incoming().first->momentum(); tmp = transform * tmp; eventRecord().incoming().first->set5Momentum(tmp); } if ( eventRecord().incoming().second->coloured() ) { tmp = eventRecord().incoming().second->momentum(); tmp = transform * tmp; eventRecord().incoming().second->set5Momentum(tmp); } eventRecord().transform(transform); return true; } return false; } void DipoleShowerHandler::resetAlphaS(Ptr<AlphaSBase>::tptr as) { for ( auto & k : kernels) { if ( !k->alphaS() ) k->alphaS(as); k->renormalizationScaleFreeze(theRenormalizationScaleFreeze); k->factorizationScaleFreeze(theFactorizationScaleFreeze); } // clear the generators to be rebuild // actually, there shouldn't be any generators // when this happens. generators().clear(); } void DipoleShowerHandler::resetReweight(Ptr<DipoleSplittingReweight>::tptr rw) { for ( auto & g : generators() ) g.second->splittingReweight(rw); } void DipoleShowerHandler::getGenerators(const DipoleIndex& ind, Ptr<DipoleSplittingReweight>::tptr rw) { bool gotone = false; for ( auto & k : kernels ) { if ( k->canHandle(ind) ) { if ( verbosity > 0 ) { generator()->log() << "DipoleShowerHandler encountered the dipole configuration\n" << ind << " in event number " << eventHandler()->currentEvent()->number() << "\nwhich can be handled by the splitting kernel '" << k->name() << "'.\n" << flush; } gotone = true; Ptr<DipoleSplittingGenerator>::ptr nGenerator = new_ptr(DipoleSplittingGenerator()); nGenerator->doCompensate(theDoCompensate); nGenerator->splittingKernel(k); if ( renormalizationScaleFactor() != 1. ) nGenerator->splittingKernel()->renormalizationScaleFactor(renormalizationScaleFactor()); if ( factorizationScaleFactor() != 1. ) nGenerator->splittingKernel()->factorizationScaleFactor(factorizationScaleFactor()); if ( !nGenerator->splittingReweight() ) nGenerator->splittingReweight(rw); nGenerator->splittingKernel()->freezeGrid(theFreezeGrid); nGenerator->splittingKernel()->detuning(theDetuning); GeneratorMap::const_iterator equivalent = generators().end(); for ( GeneratorMap::const_iterator eq = generators().begin(); eq != generators().end(); ++eq ) { if ( !eq->second->wrapping() ) if ( k->canHandleEquivalent(ind,*(eq->second->splittingKernel()),eq->first) ) { equivalent = eq; if ( verbosity > 0 ) { generator()->log() << "The dipole configuration " << ind << " can equivalently be handled by the existing\n" << "generator for configuration " << eq->first << " using the kernel '" << eq->second->splittingKernel()->name() << "'\n" << flush; } break; } } if ( equivalent != generators().end() ) { nGenerator->wrap(equivalent->second); } DipoleSplittingInfo dummy; dummy.index(ind); nGenerator->prepare(dummy); generators().insert({ind,nGenerator}); } } if ( !gotone ) { generator()->logWarning(Exception() << "DipoleShowerHandler could not " << "find a splitting kernel which is able " << "to handle splittings off the dipole " << ind << ".\n" << "Please check the input files." << Exception::warning); } } // If needed, insert default implementations of virtual function defined // in the InterfacedBase class here (using ThePEG-interfaced-impl in Emacs). void DipoleShowerHandler::doinit() { ShowerHandler::doinit(); if ( theGlobalAlphaS ) resetAlphaS(theGlobalAlphaS); } void DipoleShowerHandler::dofinish() { ShowerHandler::dofinish(); } void DipoleShowerHandler::doinitrun() { ShowerHandler::doinitrun(); } void DipoleShowerHandler::persistentOutput(PersistentOStream & os) const { os << kernels << theEvolutionOrdering << constituentReshuffler << intrinsicPtGenerator << theGlobalAlphaS << chainOrderVetoScales << nEmissions << discardNoEmissions << firstMCatNLOEmission << thePowhegDecayEmission << realignmentScheme << verbosity << printEvent << ounit(theRenormalizationScaleFreeze,GeV) << ounit(theFactorizationScaleFreeze,GeV) << theShowerApproximation << theDoCompensate << theFreezeGrid << theDetuning << theEventReweight << theSplittingReweight << ounit(maxPt,GeV) << ounit(muPt,GeV)<< theMergingHelper; } void DipoleShowerHandler::persistentInput(PersistentIStream & is, int) { is >> kernels >> theEvolutionOrdering >> constituentReshuffler >> intrinsicPtGenerator >> theGlobalAlphaS >> chainOrderVetoScales >> nEmissions >> discardNoEmissions >> firstMCatNLOEmission >> thePowhegDecayEmission >> realignmentScheme >> verbosity >> printEvent >> iunit(theRenormalizationScaleFreeze,GeV) >> iunit(theFactorizationScaleFreeze,GeV) >> theShowerApproximation >> theDoCompensate >> theFreezeGrid >> theDetuning >> theEventReweight >> theSplittingReweight >> iunit(maxPt,GeV) >> iunit(muPt,GeV)>>theMergingHelper; } ClassDescription<DipoleShowerHandler> DipoleShowerHandler::initDipoleShowerHandler; // Definition of the static class description member. void DipoleShowerHandler::Init() { static ClassDocumentation<DipoleShowerHandler> documentation ("The DipoleShowerHandler class manages the showering using " "the dipole shower algorithm.", "The shower evolution was performed using the algorithm described in " "\\cite{Platzer:2009jq} and \\cite{Platzer:2011bc}.", "%\\cite{Platzer:2009jq}\n" "\\bibitem{Platzer:2009jq}\n" "S.~Platzer and S.~Gieseke,\n" "``Coherent Parton Showers with Local Recoils,''\n" " JHEP {\\bf 1101}, 024 (2011)\n" "arXiv:0909.5593 [hep-ph].\n" "%%CITATION = ARXIV:0909.5593;%%\n" "%\\cite{Platzer:2011bc}\n" "\\bibitem{Platzer:2011bc}\n" "S.~Platzer and S.~Gieseke,\n" "``Dipole Showers and Automated NLO Matching in Herwig,''\n" "arXiv:1109.6256 [hep-ph].\n" "%%CITATION = ARXIV:1109.6256;%%"); static RefVector<DipoleShowerHandler,DipoleSplittingKernel> interfaceKernels ("Kernels", "Set the splitting kernels to be used by the dipole shower.", &DipoleShowerHandler::kernels, -1, false, false, true, false, false); static Reference<DipoleShowerHandler,DipoleEvolutionOrdering> interfaceEvolutionOrdering ("EvolutionOrdering", "Set the evolution ordering to be used.", &DipoleShowerHandler::theEvolutionOrdering, false, false, true, false, false); static Reference<DipoleShowerHandler,ConstituentReshuffler> interfaceConstituentReshuffler ("ConstituentReshuffler", "The object to be used to reshuffle partons to their constitutent mass shells.", &DipoleShowerHandler::constituentReshuffler, false, false, true, true, false); static Reference<DipoleShowerHandler,IntrinsicPtGenerator> interfaceIntrinsicPtGenerator ("IntrinsicPtGenerator", "Set the object in charge to generate intrinsic pt for incoming partons.", &DipoleShowerHandler::intrinsicPtGenerator, false, false, true, true, false); static Reference<DipoleShowerHandler,AlphaSBase> interfaceGlobalAlphaS ("GlobalAlphaS", "Set a global strong coupling for all splitting kernels.", &DipoleShowerHandler::theGlobalAlphaS, false, false, true, true, false); static Switch<DipoleShowerHandler,int> interfaceRealignmentScheme ("RealignmentScheme", "The realignment scheme to use.", &DipoleShowerHandler::realignmentScheme, 0, false, false); static SwitchOption interfaceRealignmentSchemePreserveRapidity (interfaceRealignmentScheme, "PreserveRapidity", "Preserve the rapidity of non-coloured outgoing system.", 0); static SwitchOption interfaceRealignmentSchemeEvolutionFractions (interfaceRealignmentScheme, "EvolutionFractions", "Use momentum fractions as generated by the evolution.", 1); static SwitchOption interfaceRealignmentSchemeCollisionFrame (interfaceRealignmentScheme, "CollisionFrame", "Determine realignment from collision frame.", 2); static Switch<DipoleShowerHandler,bool> interfaceChainOrderVetoScales ("ChainOrderVetoScales", "[experimental] Switch on or off the chain ordering for veto scales.", &DipoleShowerHandler::chainOrderVetoScales, true, false, false); static SwitchOption interfaceChainOrderVetoScalesOn (interfaceChainOrderVetoScales, "On", "Switch on chain ordering for veto scales.", true); static SwitchOption interfaceChainOrderVetoScalesOff (interfaceChainOrderVetoScales, "Off", "Switch off chain ordering for veto scales.", false); interfaceChainOrderVetoScales.rank(-1); static Parameter<DipoleShowerHandler,unsigned int> interfaceNEmissions ("NEmissions", "[debug option] Limit the number of emissions to be generated. Zero does not limit the number of emissions.", &DipoleShowerHandler::nEmissions, 0, 0, 0, false, false, Interface::lowerlim); interfaceNEmissions.rank(-1); static Switch<DipoleShowerHandler,bool> interfaceDiscardNoEmissions ("DiscardNoEmissions", "[debug option] Discard events without radiation.", &DipoleShowerHandler::discardNoEmissions, false, false, false); static SwitchOption interfaceDiscardNoEmissionsOn (interfaceDiscardNoEmissions, "On", "Discard events without radiation.", true); static SwitchOption interfaceDiscardNoEmissionsOff (interfaceDiscardNoEmissions, "Off", "Do not discard events without radiation.", false); interfaceDiscardNoEmissions.rank(-1); static Switch<DipoleShowerHandler,bool> interfaceFirstMCatNLOEmission ("FirstMCatNLOEmission", "[debug option] Only perform the first MC@NLO emission.", &DipoleShowerHandler::firstMCatNLOEmission, false, false, false); static SwitchOption interfaceFirstMCatNLOEmissionOn (interfaceFirstMCatNLOEmission, "On", "", true); static SwitchOption interfaceFirstMCatNLOEmissionOff (interfaceFirstMCatNLOEmission, "Off", "", false); interfaceFirstMCatNLOEmission.rank(-1); static Parameter<DipoleShowerHandler,int> interfaceVerbosity ("Verbosity", "[debug option] Set the level of debug information provided.", &DipoleShowerHandler::verbosity, 0, 0, 0, false, false, Interface::lowerlim); interfaceVerbosity.rank(-1); static Parameter<DipoleShowerHandler,int> interfacePrintEvent ("PrintEvent", "[debug option] The number of events for which debugging information should be provided.", &DipoleShowerHandler::printEvent, 0, 0, 0, false, false, Interface::lowerlim); interfacePrintEvent.rank(-1); static Parameter<DipoleShowerHandler,Energy> interfaceRenormalizationScaleFreeze ("RenormalizationScaleFreeze", "The freezing scale for the renormalization scale.", &DipoleShowerHandler::theRenormalizationScaleFreeze, GeV, 1.0*GeV, 0.0*GeV, 0*GeV, false, false, Interface::lowerlim); static Parameter<DipoleShowerHandler,Energy> interfaceFactorizationScaleFreeze ("FactorizationScaleFreeze", "The freezing scale for the factorization scale.", &DipoleShowerHandler::theFactorizationScaleFreeze, GeV, 2.0*GeV, 0.0*GeV, 0*GeV, false, false, Interface::lowerlim); static Switch<DipoleShowerHandler,bool> interfaceDoCompensate ("DoCompensate", "", &DipoleShowerHandler::theDoCompensate, false, false, false); static SwitchOption interfaceDoCompensateYes (interfaceDoCompensate, "Yes", "", true); static SwitchOption interfaceDoCompensateNo (interfaceDoCompensate, "No", "", false); static Parameter<DipoleShowerHandler,unsigned long> interfaceFreezeGrid ("FreezeGrid", "", &DipoleShowerHandler::theFreezeGrid, 500000, 1, 0, false, false, Interface::lowerlim); static Parameter<DipoleShowerHandler,double> interfaceDetuning ("Detuning", "A value to detune the overestimate kernel.", &DipoleShowerHandler::theDetuning, 1.0, 1.0, 0, false, false, Interface::lowerlim); static Reference<DipoleShowerHandler,DipoleEventReweight> interfaceEventReweight ("EventReweight", "", &DipoleShowerHandler::theEventReweight, false, false, true, true, false); static Reference<DipoleShowerHandler,DipoleSplittingReweight> interfaceSplittingReweight ("SplittingReweight", "Set the splitting reweight.", &DipoleShowerHandler::theSplittingReweight, false, false, true, true, false); static Switch<DipoleShowerHandler, bool> interfacePowhegDecayEmission ("PowhegDecayEmission", "Use Powheg style emission for the decays", &DipoleShowerHandler::thePowhegDecayEmission, true, false, false); static SwitchOption interfacePowhegDecayEmissionYes (interfacePowhegDecayEmission,"Yes","Powheg decay emission on", true); static SwitchOption interfacePowhegDecayEmissionNo (interfacePowhegDecayEmission,"No","Powheg decay emission off", false); static Reference<DipoleShowerHandler,MergerBase> interfaceMergingHelper ("MergingHelper", "", &DipoleShowerHandler::theMergingHelper, false, false, true, true, false); } diff --git a/Shower/Dipole/DipoleShowerHandler.h b/Shower/Dipole/DipoleShowerHandler.h --- a/Shower/Dipole/DipoleShowerHandler.h +++ b/Shower/Dipole/DipoleShowerHandler.h @@ -1,544 +1,544 @@ // -*- C++ -*- // // DipoleShowerHandler.h is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2007 The Herwig Collaboration // // Herwig is licenced under version 2 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // #ifndef HERWIG_DipoleShowerHandler_H #define HERWIG_DipoleShowerHandler_H // // This is the declaration of the DipoleShowerHandler class. // #include "Herwig/Shower/ShowerHandler.h" #include "Herwig/Shower/Dipole/DipoleShowerHandler.fh" #include "Herwig/Shower/Dipole/Base/DipoleSplittingInfo.h" #include "Herwig/Shower/Dipole/Base/DipoleSplittingReweight.h" #include "Herwig/Shower/Dipole/Kernels/DipoleSplittingKernel.h" #include "Herwig/Shower/Dipole/Base/DipoleSplittingGenerator.h" #include "Herwig/Shower/Dipole/Base/DipoleEventRecord.h" #include "Herwig/Shower/Dipole/Base/DipoleEvolutionOrdering.h" #include "Herwig/Shower/Dipole/Base/DipoleEventReweight.h" #include "Herwig/Shower/Dipole/Utility/ConstituentReshuffler.h" #include "Herwig/Shower/Dipole/Utility/IntrinsicPtGenerator.h" #include "Herwig/MatrixElement/Matchbox/Base/MergerBase.h" #include "Herwig/MatrixElement/Matchbox/Matching/ShowerApproximation.h" namespace Herwig { using namespace ThePEG; /** * \ingroup DipoleShower * \author Simon Platzer * * \brief The DipoleShowerHandler class manages the showering using * the dipole shower algorithm. * * @see \ref DipoleShowerHandlerInterfaces "The interfaces" * defined for DipoleShowerHandler. */ class DipoleShowerHandler: public ShowerHandler { friend class Merger; public: /** @name Standard constructors and destructors. */ //@{ /** * The default constructor. */ DipoleShowerHandler(); /** * The destructor. */ virtual ~DipoleShowerHandler(); //@} public: inline void colourPrint(); /** * Indicate a problem in the shower. */ struct RedoShower {}; /** * Insert an additional splitting kernel. */ void addSplitting(Ptr<DipoleSplittingKernel>::ptr sp) { kernels.push_back(sp); } /** * Reset the alpha_s for all splitting kernels. */ void resetAlphaS(Ptr<AlphaSBase>::tptr); virtual void cascade(tPVector); /** * Reset the splitting reweight for all splitting kernels. */ void resetReweight(Ptr<DipoleSplittingReweight>::tptr); /** * Return true, if the shower handler can generate a truncated * shower for POWHEG style events generated using Matchbox */ virtual bool canHandleMatchboxTrunc() const { return false; } /** * Return true, if this cascade handler will perform reshuffling from hard * process masses. */ virtual bool isReshuffling() const { return false; } /** * Return the relevant hard scale to be used in the profile scales */ virtual Energy hardScale() const { return muPt; } /** * Calculate the alpha_s value the shower uses for Q. */ double as(Energy Q)const{return theGlobalAlphaS->value(sqr(Q));} /** * */ double Nf(Energy Q)const{return theGlobalAlphaS->Nf(sqr(Q));} protected: typedef multimap<DipoleIndex,Ptr<DipoleSplittingGenerator>::ptr> GeneratorMap; /** * The main method which manages the showering of a subprocess. */ virtual tPPair cascade(tSubProPtr sub, XCombPtr xcomb) { return cascade(sub,xcomb,ZERO,ZERO); } /** * The main method which manages the showering of a subprocess. */ tPPair cascade(tSubProPtr sub, XCombPtr xcomb, Energy optHardPt, Energy optCutoff); /** * Build splitting generators for the given * dipole index. */ void getGenerators(const DipoleIndex&, Ptr<DipoleSplittingReweight>::tptr rw = Ptr<DipoleSplittingReweight>::tptr()); /** * Setup the hard scales. */ void hardScales(Energy2 scale); /** * Return the evolution ordering */ Ptr<DipoleEvolutionOrdering>::tptr evolutionOrdering() const { return theEvolutionOrdering; } /** * Reshuffle to constituent mass shells */ void constituentReshuffle(); /** * Reshuffle to constituent mass shells */ - void decayConstituentReshuffle( PerturbativeProcessPtr decayProc, const bool test = false); + void decayConstituentReshuffle( PerturbativeProcessPtr decayProc); /** * Access the generator map */ GeneratorMap& generators() { return theGenerators; } /** * Access the event record */ DipoleEventRecord& eventRecord() { return theEventRecord; } /** * Return the event record */ const DipoleEventRecord& eventRecord() const { return theEventRecord; } /** * Return the splitting kernels. */ const vector<Ptr<DipoleSplittingKernel>::ptr>& splittingKernels() const { return kernels; } /** * Realign the event such as to have the incoming partons along thre * beam axes. */ bool realign(); protected: /** * Perform the cascade. */ void doCascade(unsigned int& emDone, Energy optHardPt = ZERO, Energy optCutoff = ZERO, const bool decay = false); /** * Set the number of emissions **/ void setNEmissions(unsigned int n){nEmissions=n;} /** * Get the winning splitting for the * given dipole and configuration. */ Energy getWinner(DipoleSplittingInfo& winner, const Dipole& dip, pair<bool,bool> conf, Energy optHardPt = ZERO, Energy optCutoff = ZERO); /** * Get the winning splitting for the * given dipole and configuration. */ Energy getWinner(SubleadingSplittingInfo& winner, Energy optHardPt = ZERO, Energy optCutoff = ZERO); /** * Get the winning splitting for the * given dipole and configuration. */ Energy getWinner(DipoleSplittingInfo& winner, const DipoleIndex& index, double emitterX, double spectatorX, pair<bool,bool> conf, tPPtr emitter, tPPtr spectator, Energy startScale, Energy optHardPt = ZERO, Energy optCutoff = ZERO); 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; //@} // If needed, insert declarations of virtual function defined in the // InterfacedBase class here (using ThePEG-interfaced-decl in Emacs). protected: /** @name Standard Interfaced functions. */ //@{ /** * Initialize this object after the setup phase before saving an * EventGenerator to disk. * @throws InitException if object could not be initialized properly. */ virtual void doinit(); /** * Initialize this object. Called in the run phase just before * a run begins. */ virtual void doinitrun(); /** * Finalize this object. Called in the run phase just after a * run has ended. Used eg. to write out statistics. */ virtual void dofinish(); //@} private: /** * The splitting kernels to be used. */ vector<Ptr<DipoleSplittingKernel>::ptr> kernels; /** * The evolution ordering considered */ Ptr<DipoleEvolutionOrdering>::ptr theEvolutionOrdering; /** * The ConstituentReshuffler to be used */ Ptr<ConstituentReshuffler>::ptr constituentReshuffler; /** * The intrinsic pt generator to be used. */ Ptr<IntrinsicPtGenerator>::ptr intrinsicPtGenerator; /** * A global alpha_s to be used for all splitting kernels. */ Ptr<AlphaSBase>::ptr theGlobalAlphaS; /** * Apply chain ordering to events from matrix * element corrections. */ bool chainOrderVetoScales; /** * Limit the number of emissions. * Limit applied if > 0. */ unsigned int nEmissions; /** * Discard events which did not radiate. */ bool discardNoEmissions; /** * Perform the first MC@NLO emission only. */ bool firstMCatNLOEmission; /** * True if powheg style emissions are to be used in the decays */ bool thePowhegDecayEmission; /** * The realignment scheme */ int realignmentScheme; private: /** * The verbosity level. * 0 - print no info * 1 - print diagnostic information on setting up * splitting generators etc. * 2 - print detailed event information for up to * printEvent events. * 3 - print dipole chains after each splitting. */ int verbosity; /** * See verbosity. */ int printEvent; private: /** * The splitting generators indexed by the dipole * indices they can work on. */ GeneratorMap theGenerators; /** * The evnt record used. */ DipoleEventRecord theEventRecord; /** * The number of shoer tries so far. */ unsigned int nTries; /** * Whether or not we did radiate anything */ bool didRadiate; /** * Whether or not we did realign the event */ bool didRealign; private: /** * A freezing value for the renormalization scale */ Energy theRenormalizationScaleFreeze; /** * A freezing value for the factorization scale */ Energy theFactorizationScaleFreeze; /** * The matching subtraction, if appropriate */ Ptr<ShowerApproximation>::tptr theShowerApproximation; /** * True, if sampler should apply compensation */ bool theDoCompensate; /** * Return the number of accepted points after which the grid should * be frozen */ unsigned long theFreezeGrid; /** * The detuning factor applied to the sampling overestimate kernel */ double theDetuning; /** * A pointer to the dipole event reweight object */ Ptr<DipoleEventReweight>::ptr theEventReweight; /** * A pointer to a global dipole splitting reweight */ Ptr<DipoleSplittingReweight>::ptr theSplittingReweight; /** * True if no warnings have been issued yet */ static bool firstWarn; /** * The shower starting scale for the last event encountered */ Energy maxPt; /** * The shower hard scale for the last event encountered */ Energy muPt; /** * The merging helper takes care of merging multiple LO and NLO * cross sections. Here we need to check if an emission would * radiate in the matrix element region of an other multipicity. * If so, the emission is vetoed. */ Ptr<MergerBase>::ptr theMergingHelper; private: /** * The static object used to initialize the description of this class. * Indicates that this is a concrete class with persistent data. */ static ClassDescription<DipoleShowerHandler> initDipoleShowerHandler; /** * The assignment operator is private and must never be called. * In fact, it should not even be implemented. */ DipoleShowerHandler & operator=(const DipoleShowerHandler &); }; } #include "ThePEG/Utilities/ClassTraits.h" namespace ThePEG { /** @cond TRAITSPECIALIZATIONS */ /** This template specialization informs ThePEG about the * base classes of DipoleShowerHandler. */ template <> struct BaseClassTrait<Herwig::DipoleShowerHandler,1> { /** Typedef of the first base class of DipoleShowerHandler. */ typedef Herwig::ShowerHandler NthBase; }; /** This template specialization informs ThePEG about the name of * the DipoleShowerHandler class and the shared object where it is defined. */ template <> struct ClassTraits<Herwig::DipoleShowerHandler> : public ClassTraitsBase<Herwig::DipoleShowerHandler> { /** Return a platform-independent class name */ static string className() { return "Herwig::DipoleShowerHandler"; } /** * The name of a file containing the dynamic library where the class * DipoleShowerHandler is implemented. It may also include several, space-separated, * libraries if the class DipoleShowerHandler depends on other classes (base classes * excepted). In this case the listed libraries will be dynamically * linked in the order they are specified. */ static string library() { return "HwDipoleShower.so"; } }; /** @endcond */ } #endif /* HERWIG_DipoleShowerHandler_H */ diff --git a/Shower/Dipole/Kinematics/FFMassiveKinematics.cc b/Shower/Dipole/Kinematics/FFMassiveKinematics.cc --- a/Shower/Dipole/Kinematics/FFMassiveKinematics.cc +++ b/Shower/Dipole/Kinematics/FFMassiveKinematics.cc @@ -1,363 +1,363 @@ // -*- C++ -*- // // FFMassiveKinematics.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2007 The Herwig Collaboration // // Herwig is licenced under version 2 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 FFMassiveKinematics class. // #include "FFMassiveKinematics.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/Repository/UseRandom.h" #include "ThePEG/Repository/EventGenerator.h" #include "Herwig/Shower/Dipole/Base/DipoleSplittingInfo.h" #include "Herwig/Shower/Dipole/Kernels/DipoleSplittingKernel.h" // TODO: remove after verification // only for checking for NaN or inf #include <gsl/gsl_math.h> using namespace Herwig; FFMassiveKinematics::FFMassiveKinematics() : DipoleSplittingKinematics() {} FFMassiveKinematics::~FFMassiveKinematics() {} IBPtr FFMassiveKinematics::clone() const { return new_ptr(*this); } IBPtr FFMassiveKinematics::fullclone() const { return new_ptr(*this); } pair<double,double> FFMassiveKinematics::kappaSupport(const DipoleSplittingInfo&) const { return {0.0,1.0}; } pair<double,double> FFMassiveKinematics::xiSupport(const DipoleSplittingInfo& split) const { double c = sqrt(1.-4.*sqr(IRCutoff()/generator()->maximumCMEnergy())); if ( split.index().emitterData()->id() == ParticleID::g ) { if ( split.emissionData()->id() != ParticleID::g ) return {0.5*(1.-c),0.5*(1.+c)}; double b = log((1.+c)/(1.-c)); return {-b,b}; } return {-log(0.5*(1.+c)),-log(0.5*(1.-c))}; } Energy FFMassiveKinematics::dipoleScale(const Lorentz5Momentum& pEmitter, const Lorentz5Momentum& pSpectator) const { return (pEmitter+pSpectator).m(); } Energy FFMassiveKinematics::ptMax(Energy dScale, double, double, const DipoleIndex& ind, const DipoleSplittingKernel& split) const { double mui = split.emitter(ind)->mass() / dScale; double mu = split.emission(ind)->mass() / dScale; double muj = split.spectator(ind)->mass() / dScale; - double mui2 = sqr( mui ), mu2 = sqr( mu ), muj2 = sqr( muj ); - return rootOfKallen( mui2, mu2, sqr(1.-muj) ) / ( 2.-2.*sqrt(muj2) ) * dScale; + double mui2 = sqr( mui ), mu2 = sqr( mu ); + return rootOfKallen( mui2, mu2, sqr(1.-muj) ) / ( 2.-2.*muj ) * dScale; } Energy FFMassiveKinematics::QMax(Energy dScale, double, double, const DipoleIndex& ind, const DipoleSplittingKernel&) const { assert(false && "implementation missing"); double Muj = ind.spectatorData()->mass() / dScale; return dScale * ( 1.-2.*Muj+sqr(Muj) ); } // The name of this function is misleading // scale here is defined as sqr(scale) = sqr(qi+qj) // Here, scale is Q Energy FFMassiveKinematics::PtFromQ(Energy scale, const DipoleSplittingInfo& split) const { double zPrime=split.lastSplittingParameters()[0]; Energy mi = split.emitterData()->mass(); Energy m = split.emissionData()->mass(); Energy2 pt2 = zPrime*(1.-zPrime)*sqr(scale) - (1-zPrime)*sqr(mi) - zPrime*sqr(m); assert(pt2 >= ZERO); return sqrt(pt2); } // The name of this function is misleading // scale here is the transverse momentum // Q2 is sqr(qi+qj) // This is simply the inverse of PtFromQ Energy FFMassiveKinematics::QFromPt(Energy scale, const DipoleSplittingInfo& split) const { double zPrime=split.lastSplittingParameters()[0]; Energy mi = split.emitterData()->mass(); Energy m = split.emissionData()->mass(); Energy2 Q2 = (sqr(scale) + (1-zPrime)*sqr(mi) + zPrime*sqr(m))/(zPrime*(1.-zPrime)); return sqrt(Q2); } double FFMassiveKinematics::ptToRandom(Energy pt, Energy, double,double, const DipoleIndex&, const DipoleSplittingKernel&) const { return log(pt/IRCutoff()) / log(0.5 * generator()->maximumCMEnergy()/IRCutoff()); } bool FFMassiveKinematics::generateSplitting(double kappa, double xi, double rphi, DipoleSplittingInfo& info, const DipoleSplittingKernel&) { // scaled masses double mui2 = sqr( info.emitterData()->mass() / info.scale() ); double mu2 = sqr( info.emissionData()->mass() / info.scale() ); double muj2 = sqr( info.spectatorData()->mass() / info.scale() ); double Mui2 = 0.; if ( info.emitterData()->id() + info.emissionData()->id() == 0 ) Mui2 = 0.; // gluon else Mui2 = mui2; // (anti)quark double Muj2 = muj2; // To solve issue with scale during presampling // need to enforce that Qijk-mij2-mk2 = 2*pij.pk > 0, // so combine checks by comparing against square root. if ( 1.-Mui2-Muj2 < sqrt(4.*Mui2*Muj2) ) { jacobian(0.0); return false; } Energy2 Qijk = sqr(info.scale()); double suijk = 0.5*( 1. - Mui2 - Muj2 + sqrt( sqr(1.-Mui2-Muj2) - 4.*Mui2*Muj2 ) ); // Calculate pt Energy pt = IRCutoff() * pow(0.5 * generator()->maximumCMEnergy()/IRCutoff(),kappa); Energy2 pt2 = sqr(pt); if ( pt > info.hardPt() || pt < IRCutoff() ) { jacobian(0.0); return false; } // Generate zPrime (i.e. the new definition of z specific to massive FF) double zPrime; if ( info.index().emitterData()->id() == ParticleID::g ) { if ( info.emissionData()->id() != ParticleID::g ) { zPrime = xi; } else { zPrime = exp(xi)/(1.+exp(xi)); } } else { zPrime = 1.-exp(-xi); } // Check limit on pt Energy ptmax1 = rootOfKallen( mui2, mu2, sqr(1.-sqrt(muj2)) ) / ( 2.-2.*sqrt(muj2) ) * info.scale(); Energy auxHardPt = ptmax1 > info.hardPt() ? info.hardPt() : ptmax1; // 24/05/2015: Moved this check from the zPrime limit checks if ( pt > auxHardPt ){ jacobian(0.0); return false; } // 2011-11-09 // assert(ptmax1>info.hardPt()); // 24/05/2015: // The simple >= assert above is triggered // during sampling due to precision. // Have added a tolerance to deal with this. assert( abs(ptmax1 - info.hardPt()) <= 1e-8*GeV || ptmax1>=info.hardPt() ); // new: 2011-08-31 // 2011-11-08: this does happen if( sqrt(mui2)+sqrt(mu2)+sqrt(muj2) > 1. ){ jacobian(0.0); return false; } // These apply to zPrime // phasespace constraint to incorporate ptMax double zp1 = ( 1.+mui2-mu2+muj2-2.*sqrt(muj2) + rootOfKallen(mui2,mu2,sqr(1-sqrt(muj2))) * sqrt( 1.-sqr(pt/auxHardPt) ) ) / ( 2.*sqr(1.-sqrt(muj2)) ); double zm1 = ( 1.+mui2-mu2+muj2-2.*sqrt(muj2) - rootOfKallen(mui2,mu2,sqr(1-sqrt(muj2))) * sqrt( 1.-sqr(pt/auxHardPt) ) ) / ( 2.*sqr(1.-sqrt(muj2)) ); if ( zPrime > zp1 || zPrime < zm1 ) { jacobian(0.0); return false; } // Calculate A:=xij*w double A = (1./(suijk*zPrime*(1.-zPrime))) * ( pt2/Qijk + zPrime*mu2 + (1.-zPrime)*mui2 - zPrime*(1.-zPrime)*Mui2 ); // Calculate y from A (can also write explicitly in terms of qt, zPrime and masses however we need A anyway) double bar = 1.-mui2-mu2-muj2; double y = (1./bar) * (A*suijk + Mui2 - mui2 - mu2 ); // kinematic phasespace boundaries for y // same as in Dittmaier hep-ph/9904440v2 (equivalent to CS) double ym = 2.*sqrt(mui2)*sqrt(mu2)/bar; double yp = 1. - 2.*sqrt(muj2)*(1.-sqrt(muj2))/bar; if ( y < ym || y > yp ) { jacobian(0.0); return false; } // Calculate xk and xij double lambdaK = 1. + (Muj2/suijk); double lambdaIJ = 1. + (Mui2/suijk); double xk = (1./(2.*lambdaK)) * ( (lambdaK + (Muj2/suijk)*lambdaIJ - A) + sqrt( sqr(lambdaK + (Muj2/suijk)*lambdaIJ - A) - 4.*lambdaK*lambdaIJ*Muj2/suijk) ); double xij = 1. - ( (Muj2/suijk) * (1.-xk) / xk ); // Transform to standard z definition as used in the kernels (i.e. that used in CS and standard sudakov parametrisations) double z = ( (zPrime*xij*xk*suijk/2.) + (Muj2/ ( 2.*xk*xij*suijk*zPrime))*(pt2/Qijk + mui2) ) / ( (xij*xk*suijk/2.) + (Muj2/(2.*xk*xij))*(Mui2/suijk + A) ); // These apply to z, not zPrime double zm = ( (2.*mui2+bar*y)*(1.-y) - sqrt(y*y-ym*ym)*sqrt(sqr(2.*muj2+bar-bar*y)-4.*muj2) ) / ( 2.*(1.-y)*(mui2+mu2+bar*y) ); double zp = ( (2.*mui2+bar*y)*(1.-y) + sqrt(y*y-ym*ym)*sqrt(sqr(2.*muj2+bar-bar*y)-4.*muj2) ) / ( 2.*(1.-y)*(mui2+mu2+bar*y) ); if ( z < zm || z > zp ) { jacobian(0.0); return false; } double phi = 2.*Constants::pi*rphi; // TODO: This may need changing due to different definitions of z double mapZJacobian; if ( info.index().emitterData()->id() == ParticleID::g ) { if ( info.emissionData()->id() != ParticleID::g ) { mapZJacobian = 1.; } else { mapZJacobian = z*(1.-z); } } else { mapZJacobian = 1.-z; } jacobian( 2. * mapZJacobian * (1.-y) * log(0.5 * generator()->maximumCMEnergy()/IRCutoff()) * bar / rootOfKallen(1.,Mui2,Muj2) ); // Record the physical variables, as used by the CS kernel definitions lastPt(pt); lastZ(z); lastPhi(phi); // Record zPrime for use in kinematics generation and kernel evaluation splittingParameters().clear(); splittingParameters().push_back(zPrime); if ( theMCCheck ) { theMCCheck->book(1.,1.,info.scale(),info.hardPt(),pt,z,jacobian()); } return true; } // revised 2011-08-22 // revised 2011-11-06 // revised with new FF kinematics in 2016 - SW void FFMassiveKinematics::generateKinematics(const Lorentz5Momentum& pEmitter, const Lorentz5Momentum& pSpectator, const DipoleSplittingInfo& dInfo) { // The only value stored in dInfo.lastSplittingParameters() should be zPrime assert(dInfo.lastSplittingParameters().size() == 1 ); double zPrime = dInfo.lastSplittingParameters()[0]; Energy pt = dInfo.lastPt(); Energy2 pt2 = sqr(pt); // scaled masses double mui2 = sqr( dInfo.emitterData()->mass() / dInfo.scale() ); double mu2 = sqr( dInfo.emissionData()->mass() / dInfo.scale() ); double muj2 = sqr( dInfo.spectatorData()->mass() / dInfo.scale() ); double Mui2 = 0.; if ( dInfo.emitterData()->id() + dInfo.emissionData()->id() == 0 ) Mui2 = 0.; // gluon else Mui2 = mui2; // (anti)quark double Muj2 = muj2; Energy2 Qijk = sqr(dInfo.scale()); double suijk = 0.5*( 1. - Mui2 - Muj2 + sqrt( sqr(1.-Mui2-Muj2) - 4.*Mui2*Muj2 ) ); double suijk2 = sqr(suijk); // Calculate A:=xij*w double A = (1./(suijk*zPrime*(1.-zPrime))) * ( pt2/Qijk + zPrime*mu2 + (1.-zPrime)*mui2 - zPrime*(1.-zPrime)*Mui2 ); // Calculate the scaling factors, xk and xij double lambdaK = 1. + (Muj2/suijk); double lambdaIJ = 1. + (Mui2/suijk); double xk = (1./(2.*lambdaK)) * ( (lambdaK + (Muj2/suijk)*lambdaIJ - A) + sqrt( sqr(lambdaK + (Muj2/suijk)*lambdaIJ - A) - 4.*lambdaK*lambdaIJ*Muj2/suijk) ); double xij = 1. - ( (Muj2/suijk) * (1.-xk) / xk ); // Construct reference momenta nk, nij, nt Lorentz5Momentum nij = ( suijk2 / (suijk2-Mui2*Muj2) ) * (pEmitter - (Mui2/suijk)*pSpectator); Lorentz5Momentum nk = ( suijk2 / (suijk2-Mui2*Muj2) ) * (pSpectator - (Muj2/suijk)*pEmitter); // Following notation in notes, qt = sqrt(wt)*nt Lorentz5Momentum qt = getKt(nij,nk,pt,dInfo.lastPhi()); // Construct qij, qk, qi and qj Lorentz5Momentum qij = xij*nij + (Mui2/(xij*suijk))*nk; Lorentz5Momentum qk = xk*nk + (Muj2/(xk*suijk))*nij; // For clarity, following notation in notes: //Lorentz5Momentum qi = zPrime*qij + ((pt2 + mi2 - zPrime*zPrime*mij2)/(xij*sijk*zPrime))*nk + sqrt(wt)*nt; //Lorentz5Momentum qj = (1.-zPrime)*qij + ((pt2 + mj2 - sqr(1.-zPrime)*mij2)/(xij*sijk*(1.-zPrime)))*nk - sqrt(wt)*nt; // No need to actually calculate nt and wt: Lorentz5Momentum qi = zPrime*qij + ((pt2/Qijk + mui2 - zPrime*zPrime*Mui2)/(xij*suijk*zPrime))*nk + qt; Lorentz5Momentum qj = (1.-zPrime)*qij + ((pt2/Qijk + mu2 - sqr(1.-zPrime)*Mui2)/(xij*suijk*(1.-zPrime)))*nk - qt; emitterMomentum(qi); emissionMomentum(qj); spectatorMomentum(qk); } // If needed, insert default implementations of function defined // in the InterfacedBase class here (using ThePEG-interfaced-impl in Emacs). void FFMassiveKinematics::persistentOutput(PersistentOStream & ) const { } void FFMassiveKinematics::persistentInput(PersistentIStream & , int) { } ClassDescription<FFMassiveKinematics> FFMassiveKinematics::initFFMassiveKinematics; // Definition of the static class description member. void FFMassiveKinematics::Init() { static ClassDocumentation<FFMassiveKinematics> documentation ("FFMassiveKinematics implements massive splittings " "off a final-final dipole."); } diff --git a/Shower/QTilde/QTildeShowerHandler.cc b/Shower/QTilde/QTildeShowerHandler.cc --- a/Shower/QTilde/QTildeShowerHandler.cc +++ b/Shower/QTilde/QTildeShowerHandler.cc @@ -1,3817 +1,3788 @@ // -*- C++ -*- // // QTildeShowerHandler.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2011 The Herwig Collaboration // // Herwig is licenced under version 2 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 QTildeShowerHandler class. // #include "QTildeShowerHandler.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Interface/Switch.h" #include "ThePEG/Interface/Reference.h" #include "ThePEG/Interface/RefVector.h" #include "ThePEG/Interface/Parameter.h" #include "ThePEG/EventRecord/Particle.h" #include "ThePEG/Repository/UseRandom.h" #include "ThePEG/Repository/EventGenerator.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/Utilities/EnumIO.h" #include "Herwig/Shower/QTilde/Base/ShowerParticle.h" #include "Herwig/PDF/MPIPDF.h" #include "Herwig/PDF/MinBiasPDF.h" #include "Herwig/Shower/QTilde/Base/ShowerTree.h" +#include "Herwig/Shower/QTilde/Base/HardTree.h" #include "Herwig/Shower/QTilde/Base/KinematicsReconstructor.h" #include "Herwig/Shower/QTilde/Base/PartnerFinder.h" #include "Herwig/PDF/HwRemDecayer.h" #include "Herwig/Shower/QTilde/Base/ShowerVertex.h" #include "ThePEG/Repository/CurrentGenerator.h" #include "Herwig/MatrixElement/Matchbox/Base/SubtractedME.h" #include "Herwig/MatrixElement/Matchbox/MatchboxFactory.h" #include "ThePEG/PDF/PartonExtractor.h" #include "Herwig/Shower/RealEmissionProcess.h" using namespace Herwig; -namespace { - - /** - * A struct to order the particles in the same way as in the DecayMode's - */ - struct ParticleOrdering { - /** - * Operator for the ordering - * @param p1 The first ParticleData object - * @param p2 The second ParticleData object - */ - bool operator() (tcPDPtr p1, tcPDPtr p2) { - return abs(p1->id()) > abs(p2->id()) || - ( abs(p1->id()) == abs(p2->id()) && p1->id() > p2->id() ) || - ( p1->id() == p2->id() && p1->fullName() > p2->fullName() ); - } - }; - typedef multiset<tcPDPtr,ParticleOrdering> OrderedParticles; - - /** - * Cached lookup of decay modes. - * Generator::findDecayMode() is not efficient. - */ - tDMPtr findDecayMode(const string & tag) { - static map<string,DMPtr> cache; - map<string,DMPtr>::const_iterator pos = cache.find(tag); - - if ( pos != cache.end() ) - return pos->second; - - tDMPtr dm = CurrentGenerator::current().findDecayMode(tag); - cache[tag] = dm; - return dm; - } -} - bool QTildeShowerHandler::_hardEmissionWarn = true; bool QTildeShowerHandler::_missingTruncWarn = true; QTildeShowerHandler::QTildeShowerHandler() : _maxtry(100), _meCorrMode(1), _reconOpt(0), _hardVetoReadOption(false), _iptrms(ZERO), _beta(0.), _gamma(ZERO), _iptmax(), _limitEmissions(0), _initialenhance(1.), _finalenhance(1.), _nReWeight(100), _reWeight(false), interaction_(ShowerInteraction::Both), _trunc_Mode(true), _hardEmission(1), _spinOpt(1), _softOpt(2), _hardPOWHEG(false), muPt(ZERO), _maxTryFSR(100000), _maxFailFSR(100), _fracFSR(0.001), _nFSR(0), _nFailedFSR(0) {} QTildeShowerHandler::~QTildeShowerHandler() {} IBPtr QTildeShowerHandler::clone() const { return new_ptr(*this); } IBPtr QTildeShowerHandler::fullclone() const { return new_ptr(*this); } void QTildeShowerHandler::persistentOutput(PersistentOStream & os) const { os << _model << _splittingGenerator << _maxtry << _meCorrMode << _hardVetoReadOption << _limitEmissions << _spinOpt << _softOpt << _hardPOWHEG << ounit(_iptrms,GeV) << _beta << ounit(_gamma,GeV) << ounit(_iptmax,GeV) << _vetoes << _fullShowerVetoes << _nReWeight << _reWeight << _trunc_Mode << _hardEmission << _reconOpt << ounit(muPt,GeV) << oenum(interaction_) << _maxTryFSR << _maxFailFSR << _fracFSR; } void QTildeShowerHandler::persistentInput(PersistentIStream & is, int) { is >> _model >> _splittingGenerator >> _maxtry >> _meCorrMode >> _hardVetoReadOption >> _limitEmissions >> _spinOpt >> _softOpt >> _hardPOWHEG >> iunit(_iptrms,GeV) >> _beta >> iunit(_gamma,GeV) >> iunit(_iptmax,GeV) >> _vetoes >> _fullShowerVetoes >> _nReWeight >> _reWeight >> _trunc_Mode >> _hardEmission >> _reconOpt >> iunit(muPt,GeV) >> ienum(interaction_) >> _maxTryFSR >> _maxFailFSR >> _fracFSR; } // The following static variable is needed for the type // description system in ThePEG. DescribeClass<QTildeShowerHandler,ShowerHandler> describeHerwigQTildeShowerHandler("Herwig::QTildeShowerHandler", "HwShower.so"); void QTildeShowerHandler::Init() { static ClassDocumentation<QTildeShowerHandler> documentation ("TheQTildeShowerHandler class is the main class" " for the angular-ordered parton shower", "The Shower evolution was performed using an algorithm described in " "\\cite{Marchesini:1983bm,Marchesini:1987cf,Gieseke:2003rz,Bahr:2008pv}.", "%\\cite{Marchesini:1983bm}\n" "\\bibitem{Marchesini:1983bm}\n" " G.~Marchesini and B.~R.~Webber,\n" " ``Simulation Of QCD Jets Including Soft Gluon Interference,''\n" " Nucl.\\ Phys.\\ B {\\bf 238}, 1 (1984).\n" " %%CITATION = NUPHA,B238,1;%%\n" "%\\cite{Marchesini:1987cf}\n" "\\bibitem{Marchesini:1987cf}\n" " G.~Marchesini and B.~R.~Webber,\n" " ``Monte Carlo Simulation of General Hard Processes with Coherent QCD\n" " Radiation,''\n" " Nucl.\\ Phys.\\ B {\\bf 310}, 461 (1988).\n" " %%CITATION = NUPHA,B310,461;%%\n" "%\\cite{Gieseke:2003rz}\n" "\\bibitem{Gieseke:2003rz}\n" " S.~Gieseke, P.~Stephens and B.~Webber,\n" " ``New formalism for QCD parton showers,''\n" " JHEP {\\bf 0312}, 045 (2003)\n" " [arXiv:hep-ph/0310083].\n" " %%CITATION = JHEPA,0312,045;%%\n" ); static Reference<QTildeShowerHandler,SplittingGenerator> interfaceSplitGen("SplittingGenerator", "A reference to the SplittingGenerator object", &Herwig::QTildeShowerHandler::_splittingGenerator, false, false, true, false); static Reference<QTildeShowerHandler,ShowerModel> interfaceShowerModel ("ShowerModel", "The pointer to the object which defines the shower evolution model.", &QTildeShowerHandler::_model, false, false, true, false, false); static Parameter<QTildeShowerHandler,unsigned int> interfaceMaxTry ("MaxTry", "The maximum number of attempts to generate the shower from a" " particular ShowerTree", &QTildeShowerHandler::_maxtry, 100, 1, 100000, false, false, Interface::limited); static Parameter<QTildeShowerHandler,unsigned int> interfaceNReWeight ("NReWeight", "The number of attempts for the shower when reweighting", &QTildeShowerHandler::_nReWeight, 100, 10, 10000, false, false, Interface::limited); static Switch<QTildeShowerHandler, unsigned int> ifaceMECorrMode ("MECorrMode", "Choice of the ME Correction Mode", &QTildeShowerHandler::_meCorrMode, 1, false, false); static SwitchOption on (ifaceMECorrMode,"HardPlusSoft","hard+soft on", 1); static SwitchOption hard (ifaceMECorrMode,"Hard","only hard on", 2); static SwitchOption soft (ifaceMECorrMode,"Soft","only soft on", 3); static Switch<QTildeShowerHandler, bool> ifaceHardVetoReadOption ("HardVetoReadOption", "Apply read-in scale veto to all collisions or just the primary one?", &QTildeShowerHandler::_hardVetoReadOption, false, false, false); static SwitchOption AllCollisions (ifaceHardVetoReadOption, "AllCollisions", "Read-in pT veto applied to primary and secondary collisions.", false); static SwitchOption PrimaryCollision (ifaceHardVetoReadOption, "PrimaryCollision", "Read-in pT veto applied to primary but not secondary collisions.", true); static Parameter<QTildeShowerHandler, Energy> ifaceiptrms ("IntrinsicPtGaussian", "RMS of intrinsic pT of Gaussian distribution:\n" "2*(1-Beta)*exp(-sqr(intrinsicpT/RMS))/sqr(RMS)", &QTildeShowerHandler::_iptrms, GeV, ZERO, ZERO, 1000000.0*GeV, false, false, Interface::limited); static Parameter<QTildeShowerHandler, double> ifacebeta ("IntrinsicPtBeta", "Proportion of inverse quadratic distribution in generating intrinsic pT.\n" "(1-Beta) is the proportion of Gaussian distribution", &QTildeShowerHandler::_beta, 0, 0, 1, false, false, Interface::limited); static Parameter<QTildeShowerHandler, Energy> ifacegamma ("IntrinsicPtGamma", "Parameter for inverse quadratic:\n" "2*Beta*Gamma/(sqr(Gamma)+sqr(intrinsicpT))", &QTildeShowerHandler::_gamma,GeV, ZERO, ZERO, 100000.0*GeV, false, false, Interface::limited); static Parameter<QTildeShowerHandler, Energy> ifaceiptmax ("IntrinsicPtIptmax", "Upper bound on intrinsic pT for inverse quadratic", &QTildeShowerHandler::_iptmax,GeV, ZERO, ZERO, 100000.0*GeV, false, false, Interface::limited); static RefVector<QTildeShowerHandler,ShowerVeto> ifaceVetoes ("Vetoes", "The vetoes to be checked during showering", &QTildeShowerHandler::_vetoes, -1, false,false,true,true,false); static RefVector<QTildeShowerHandler,FullShowerVeto> interfaceFullShowerVetoes ("FullShowerVetoes", "The vetos to be appliede on the full final state of the shower", &QTildeShowerHandler::_fullShowerVetoes, -1, false, false, true, false, false); static Switch<QTildeShowerHandler,unsigned int> interfaceLimitEmissions ("LimitEmissions", "Limit the number and type of emissions for testing", &QTildeShowerHandler::_limitEmissions, 0, false, false); static SwitchOption interfaceLimitEmissionsNoLimit (interfaceLimitEmissions, "NoLimit", "Allow an arbitrary number of emissions", 0); static SwitchOption interfaceLimitEmissionsOneInitialStateEmission (interfaceLimitEmissions, "OneInitialStateEmission", "Allow one emission in the initial state and none in the final state", 1); static SwitchOption interfaceLimitEmissionsOneFinalStateEmission (interfaceLimitEmissions, "OneFinalStateEmission", "Allow one emission in the final state and none in the initial state", 2); static SwitchOption interfaceLimitEmissionsHardOnly (interfaceLimitEmissions, "HardOnly", "Only allow radiation from the hard ME correction", 3); static SwitchOption interfaceLimitEmissionsOneEmission (interfaceLimitEmissions, "OneEmission", "Allow one emission in either the final state or initial state, but not both", 4); static Switch<QTildeShowerHandler,bool> interfaceTruncMode ("TruncatedShower", "Include the truncated shower?", &QTildeShowerHandler::_trunc_Mode, 1, false, false); static SwitchOption interfaceTruncMode0 (interfaceTruncMode,"No","Truncated Shower is OFF", 0); static SwitchOption interfaceTruncMode1 (interfaceTruncMode,"Yes","Truncated Shower is ON", 1); static Switch<QTildeShowerHandler,int> interfaceHardEmission ("HardEmission", "Whether to use ME corrections or POWHEG for the hardest emission", &QTildeShowerHandler::_hardEmission, 0, false, false); static SwitchOption interfaceHardEmissionNone (interfaceHardEmission, "None", "No Corrections", 0); static SwitchOption interfaceHardEmissionMECorrection (interfaceHardEmission, "MECorrection", "Old fashioned ME correction", 1); static SwitchOption interfaceHardEmissionPOWHEG (interfaceHardEmission, "POWHEG", "Powheg style hard emission", 2); static Switch<QTildeShowerHandler,ShowerInteraction> interfaceInteractions ("Interactions", "The interactions to be used in the shower", &QTildeShowerHandler::interaction_, ShowerInteraction::Both, false, false); static SwitchOption interfaceInteractionsQCD (interfaceInteractions, "QCD", "Only QCD radiation", ShowerInteraction::QCD); static SwitchOption interfaceInteractionsQED (interfaceInteractions, "QED", "Only QEd radiation", ShowerInteraction::QED); static SwitchOption interfaceInteractionsQCDandQED (interfaceInteractions, "QCDandQED", "Both QED and QCD radiation", ShowerInteraction::Both); static Switch<QTildeShowerHandler,unsigned int> interfaceReconstructionOption ("ReconstructionOption", "Treatment of the reconstruction of the transverse momentum of " "a branching from the evolution scale.", &QTildeShowerHandler::_reconOpt, 0, false, false); static SwitchOption interfaceReconstructionOptionCutOff (interfaceReconstructionOption, "CutOff", "Use the cut-off masses in the calculation", 0); static SwitchOption interfaceReconstructionOptionOffShell (interfaceReconstructionOption, "OffShell", "Use the off-shell masses in the calculation veto the emission of the parent," " no veto in generation of emissions from children", 1); static SwitchOption interfaceReconstructionOptionOffShell2 (interfaceReconstructionOption, "OffShell2", "Use the off-shell masses in the calculation veto the emissions from the children." " no veto in generation of emissions from children", 2); static SwitchOption interfaceReconstructionOptionOffShell3 (interfaceReconstructionOption, "OffShell3", "Use the off-shell masses in the calculation veto the emissions from the children." " veto in generation of emissions from children using cut-off for second parton", 3); static SwitchOption interfaceReconstructionOptionOffShell4 (interfaceReconstructionOption, "OffShell4", "Ass OffShell3 but with a restriction on the mass of final-state" " jets produced via backward evolution.", 4); static Switch<QTildeShowerHandler,unsigned int> interfaceSpinCorrelations ("SpinCorrelations", "Treatment of spin correlations in the parton shower", &QTildeShowerHandler::_spinOpt, 1, false, false); static SwitchOption interfaceSpinCorrelationsOff (interfaceSpinCorrelations, "No", "No spin correlations", 0); static SwitchOption interfaceSpinCorrelationsSpin (interfaceSpinCorrelations, "Yes", "Include the azimuthal spin correlations only", 1); static Switch<QTildeShowerHandler,unsigned int> interfaceSoftCorrelations ("SoftCorrelations", "Option for the treatment of soft correlations in the parton shower", &QTildeShowerHandler::_softOpt, 2, false, false); static SwitchOption interfaceSoftCorrelationsNone (interfaceSoftCorrelations, "No", "No soft correlations", 0); static SwitchOption interfaceSoftCorrelationsFull (interfaceSoftCorrelations, "Full", "Use the full eikonal", 1); static SwitchOption interfaceSoftCorrelationsSingular (interfaceSoftCorrelations, "Singular", "Use original Webber-Marchisini form", 2); static Switch<QTildeShowerHandler,bool> interfaceHardPOWHEG ("HardPOWHEG", "Treatment of powheg emissions which are too hard to have a shower interpretation", &QTildeShowerHandler::_hardPOWHEG, false, false, false); static SwitchOption interfaceHardPOWHEGAsShower (interfaceHardPOWHEG, "AsShower", "Still interpret as shower emissions", false); static SwitchOption interfaceHardPOWHEGRealEmission (interfaceHardPOWHEG, "RealEmission", "Generate shower from the real emmission configuration", true); static Parameter<QTildeShowerHandler,unsigned int> interfaceMaxTryFSR ("MaxTryFSR", "The maximum number of attempted FSR emissions in" " the generation of the FSR", &QTildeShowerHandler::_maxTryFSR, 100000, 10, 100000000, false, false, Interface::limited); static Parameter<QTildeShowerHandler,unsigned int> interfaceMaxFailFSR ("MaxFailFSR", "Maximum number of failures generating the FSR", &QTildeShowerHandler::_maxFailFSR, 100, 1, 100000000, false, false, Interface::limited); static Parameter<QTildeShowerHandler,double> interfaceFSRFailureFraction ("FSRFailureFraction", "Maximum fraction of events allowed to fail due to too many FSR emissions", &QTildeShowerHandler::_fracFSR, 0.001, 1e-10, 1, false, false, Interface::limited); } void QTildeShowerHandler::cascade(tPVector finalstate) { hard_=ShowerTreePtr(); decay_.clear(); done_.clear(); tStdXCombPtr xcomb; StepPtr pstep = newStep(); unsigned int countFailures=0; while (countFailures<maxtry()) { try { decay_.clear(); done_.clear(); DecayProcessMap decay; PerturbativeProcessPtr hard=new_ptr(PerturbativeProcess()); PPtr p1,p2,p1tmp,p2tmp; for(tPVector::iterator it=finalstate.begin();it!=finalstate.end();++it){ PPtr p=(*it); while (!p->parents().empty()) { if (p->parents().size()==2&&((!p1&&!p2)||p1==p2)) { p1=p->parents()[1]; p2=p->parents()[0]; while (!p2->parents().empty()) { p2=p2->parents()[0]; } while (!p1->parents().empty()) { p1=p1->parents()[0]; } } p=p->parents()[0]; } } assert(p1!=p2); hard->incoming().push_back(make_pair(p1,PerturbativeProcessPtr())); hard->incoming().push_back(make_pair(p2,PerturbativeProcessPtr())); for(tPVector::iterator it=finalstate.begin();it!=finalstate.end();++it){ PPtr p=(*it); PerturbativeProcessPtr newDecay=new_ptr(PerturbativeProcess()); if((decaysInShower((**it).id())&&!(**it).dataPtr()->stable())){ createDecayProcess(*it,hard,decay); }else{ hard->outgoing().push_back(make_pair(*it,PerturbativeProcessPtr())); } } setCurrentHandler(); ShowerTree::constructTrees(hard_,decay_,hard,decay); done_.push_back(hard_); if(decay_.empty()) return; while(!decay_.empty()) { ShowerDecayMap::iterator dit = decay_.begin(); if (!dit->second->parent()) { decay_.erase(dit); continue; } ShowerTreePtr decayingTree = dit->second; decay_.erase(dit); QTildeShowerHandler::decay(decayingTree,decay_); currentTree(decayingTree); showerDecay(decayingTree); done_.push_back(decayingTree); decayingTree->updateAfterShower(decay_); } break; } catch (KinematicsReconstructionVeto) { resetWeights(); ++countFailures; } } fillEventRecord(); setDidRunCascade(true); hard_=ShowerTreePtr(); decay_.clear(); done_.clear(); return; } tPPair QTildeShowerHandler::cascade(tSubProPtr sub, XCPtr xcomb) { // use me for reference in tex file etc useMe(); prepareCascade(sub); // set things up in the base class resetWeights(); hard_=ShowerTreePtr(); decay_.clear(); done_.clear(); // check if anything needs doing if ( !doFSR() && ! doISR() ) return sub->incoming(); // start of the try block for the whole showering process unsigned int countFailures=0; while (countFailures<maxtry()) { try { decay_.clear(); done_.clear(); PerturbativeProcessPtr hard; DecayProcessMap decay; splitHardProcess(firstInteraction() ? tagged() : tPVector(currentSubProcess()->outgoing().begin(), currentSubProcess()->outgoing().end()), hard,decay); ShowerTree::constructTrees(hard_,decay_,hard,decay); // if no hard process if(!hard_) throw Exception() << "Shower starting with a decay" << "is not implemented" << Exception::runerror; // perform the shower for the hard process showerHardProcess(hard_,xcomb); done_.push_back(hard_); hard_->updateAfterShower(decay_); // if no decaying particles to shower break out of the loop if(decay_.empty()) break; // shower the decay products while(!decay_.empty()) { // find particle whose production process has been showered ShowerDecayMap::iterator dit = decay_.begin(); while(!dit->second->parent()->hasShowered() && dit!=decay_.end()) ++dit; assert(dit!=decay_.end()); // get the particle ShowerTreePtr decayingTree = dit->second; // remove it from the multimap decay_.erase(dit); // make sure the particle has been decayed QTildeShowerHandler::decay(decayingTree,decay_); // now shower the decay showerDecay(decayingTree); done_.push_back(decayingTree); decayingTree->updateAfterShower(decay_); } // suceeded break out of the loop break; } catch (KinematicsReconstructionVeto) { resetWeights(); ++countFailures; } + catch ( ... ) { + hard_=ShowerTreePtr(); + decay_.clear(); + done_.clear(); + throw; + } } // if loop exited because of too many tries, throw event away if (countFailures >= maxtry()) { resetWeights(); hard_=ShowerTreePtr(); decay_.clear(); done_.clear(); throw Exception() << "Too many tries for main while loop " - << "in ShowerHandler::cascade()." + << "in QTildeShowerHandler::cascade()." << Exception::eventerror; } //enter the particles in the event record fillEventRecord(); // clear storage hard_=ShowerTreePtr(); decay_.clear(); done_.clear(); // non hadronic case return if (!isResolvedHadron(incomingBeams().first ) && !isResolvedHadron(incomingBeams().second) ) return incomingBeams(); // remake the remnants (needs to be after the colours are sorted // out in the insertion into the event record) if ( firstInteraction() ) return remakeRemnant(sub->incoming()); //Return the new pair of incoming partons. remakeRemnant is not //necessary here, because the secondary interactions are not yet //connected to the remnants. return make_pair(findFirstParton(sub->incoming().first ), findFirstParton(sub->incoming().second)); } void QTildeShowerHandler::fillEventRecord() { // create a new step StepPtr pstep = newStep(); assert(!done_.empty()); assert(done_[0]->isHard()); // insert the steps for(unsigned int ix=0;ix<done_.size();++ix) { done_[ix]->fillEventRecord(pstep,doISR(),doFSR()); } } HardTreePtr QTildeShowerHandler::generateCKKW(ShowerTreePtr ) const { return HardTreePtr(); } void QTildeShowerHandler::doinit() { ShowerHandler::doinit(); // interactions may have been changed through a setup file so we // clear it up here // calculate max no of FSR vetos _maxFailFSR = max(int(_maxFailFSR), int(_fracFSR*double(generator()->N()))); // check on the reweighting for(unsigned int ix=0;ix<_fullShowerVetoes.size();++ix) { if(_fullShowerVetoes[ix]->behaviour()==1) { _reWeight = true; break; } } if(_reWeight && maximumTries()<_nReWeight) { throw Exception() << "Reweight being performed in the shower but the number of attempts for the" << "shower is less than that for the reweighting.\n" << "Maximum number of attempt for the shower " << fullName() << ":MaxTry is " << maximumTries() << "\nand for reweighting is " << fullName() << ":NReWeight is " << _nReWeight << "\n" << "we recommend the number of attempts is 10 times the number for reweighting\n" << Exception::runerror; } } void QTildeShowerHandler::generateIntrinsicpT(vector<ShowerProgenitorPtr> particlesToShower) { _intrinsic.clear(); if ( !ipTon() || !doISR() ) return; // don't do anything for the moment for secondary scatters if( !firstInteraction() ) return; // generate intrinsic pT for(unsigned int ix=0;ix<particlesToShower.size();++ix) { // only consider initial-state particles if(particlesToShower[ix]->progenitor()->isFinalState()) continue; if(!particlesToShower[ix]->progenitor()->dataPtr()->coloured()) continue; Energy ipt; if(UseRandom::rnd() > _beta) { ipt=_iptrms*sqrt(-log(UseRandom::rnd())); } else { ipt=_gamma*sqrt(pow(1.+sqr(_iptmax/_gamma), UseRandom::rnd())-1.); } pair<Energy,double> pt = make_pair(ipt,UseRandom::rnd(Constants::twopi)); _intrinsic[particlesToShower[ix]] = pt; } } void QTildeShowerHandler::setupMaximumScales(const vector<ShowerProgenitorPtr> & p, XCPtr xcomb) { // let POWHEG events radiate freely if(_hardEmission==2&&hardTree()) { vector<ShowerProgenitorPtr>::const_iterator ckt = p.begin(); for (; ckt != p.end(); ckt++) (*ckt)->maxHardPt(Constants::MaxEnergy); return; } // return if no vetos if (!restrictPhasespace()) return; // find out if hard partonic subprocess. bool isPartonic(false); map<ShowerProgenitorPtr,ShowerParticlePtr>::const_iterator cit = _currenttree->incomingLines().begin(); Lorentz5Momentum pcm; for(; cit!=currentTree()->incomingLines().end(); ++cit) { pcm += cit->first->progenitor()->momentum(); isPartonic |= cit->first->progenitor()->coloured(); } // find minimum pt from hard process, the maximum pt from all outgoing // coloured lines (this is simpler and more general than // 2stu/(s^2+t^2+u^2)). Maximum scale for scattering processes will // be transverse mass. Energy ptmax = generator()->maximumCMEnergy(); // general case calculate the scale if ( !hardScaleIsMuF() || (hardVetoReadOption()&&!firstInteraction()) ) { // scattering process if(currentTree()->isHard()) { assert(xcomb); // coloured incoming particles if (isPartonic) { map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator cjt = currentTree()->outgoingLines().begin(); for(; cjt!=currentTree()->outgoingLines().end(); ++cjt) { if (cjt->first->progenitor()->coloured()) ptmax = min(ptmax,cjt->first->progenitor()->momentum().mt()); } } if (ptmax == generator()->maximumCMEnergy() ) ptmax = pcm.m(); if(hardScaleIsMuF()&&hardVetoReadOption()&& !firstInteraction()) { ptmax=min(ptmax,sqrt(xcomb->lastShowerScale())); } } // decay, incoming() is the decaying particle. else { ptmax = currentTree()->incomingLines().begin()->first ->progenitor()->momentum().mass(); } } // hepeup.SCALUP is written into the lastXComb by the // LesHouchesReader itself - use this by user's choice. // Can be more general than this. else { if(currentTree()->isHard()) { assert(xcomb); ptmax = sqrt( xcomb->lastShowerScale() ); } else { ptmax = currentTree()->incomingLines().begin()->first ->progenitor()->momentum().mass(); } } ptmax *= hardScaleFactor(); // set maxHardPt for all progenitors. For partonic processes this // is now the max pt in the FS, for non-partonic processes or // processes with no coloured FS the invariant mass of the IS vector<ShowerProgenitorPtr>::const_iterator ckt = p.begin(); for (; ckt != p.end(); ckt++) (*ckt)->maxHardPt(ptmax); } void QTildeShowerHandler::setupHardScales(const vector<ShowerProgenitorPtr> & p, XCPtr xcomb) { if ( hardScaleIsMuF() && (!hardVetoReadOption() || firstInteraction()) ) { Energy hardScale = ZERO; if(currentTree()->isHard()) { assert(xcomb); hardScale = sqrt( xcomb->lastShowerScale() ); } else { hardScale = currentTree()->incomingLines().begin()->first ->progenitor()->momentum().mass(); } hardScale *= hardScaleFactor(); vector<ShowerProgenitorPtr>::const_iterator ckt = p.begin(); for (; ckt != p.end(); ckt++) (*ckt)->hardScale(hardScale); muPt = hardScale; } } void QTildeShowerHandler::showerHardProcess(ShowerTreePtr hard, XCPtr xcomb) { _hardme = HwMEBasePtr(); // extract the matrix element tStdXCombPtr lastXC = dynamic_ptr_cast<tStdXCombPtr>(xcomb); if(lastXC) { _hardme = dynamic_ptr_cast<HwMEBasePtr>(lastXC->matrixElement()); } _decayme = HwDecayerBasePtr(); // set the current tree currentTree(hard); hardTree(HardTreePtr()); // work out the type of event currentTree()->xcombPtr(dynamic_ptr_cast<StdXCombPtr>(xcomb)); currentTree()->identifyEventType(); checkFlags(); // generate the showering doShowering(true,xcomb); } RealEmissionProcessPtr QTildeShowerHandler::hardMatrixElementCorrection(bool hard) { // set the initial enhancement factors for the soft correction _initialenhance = 1.; _finalenhance = 1.; // see if we can get the correction from the matrix element // or decayer RealEmissionProcessPtr real; if(hard) { if(_hardme&&_hardme->hasMECorrection()) { _hardme->initializeMECorrection(_currenttree->perturbativeProcess(), _initialenhance,_finalenhance); if(hardMEC()) real = _hardme->applyHardMatrixElementCorrection(_currenttree->perturbativeProcess()); } } else { if(_decayme&&_decayme->hasMECorrection()) { _decayme->initializeMECorrection(_currenttree->perturbativeProcess(), _initialenhance,_finalenhance); if(hardMEC()) real = _decayme->applyHardMatrixElementCorrection(_currenttree->perturbativeProcess()); } } return real; } ShowerParticleVector QTildeShowerHandler::createTimeLikeChildren(tShowerParticlePtr, IdList ids) { // Create the ShowerParticle objects for the two children of // the emitting particle; set the parent/child relationship // if same as definition create particles, otherwise create cc ShowerParticleVector children; for(unsigned int ix=0;ix<2;++ix) { children.push_back(new_ptr(ShowerParticle(ids[ix+1],true))); if(children[ix]->id()==_progenitor->id()&&!ids[ix+1]->stable()) children[ix]->set5Momentum(Lorentz5Momentum(_progenitor->progenitor()->mass())); else children[ix]->set5Momentum(Lorentz5Momentum(ids[ix+1]->mass())); } return children; } bool QTildeShowerHandler::timeLikeShower(tShowerParticlePtr particle, ShowerInteraction type, Branching fb, bool first) { // don't do anything if not needed if(_limitEmissions == 1 || hardOnly() || ( _limitEmissions == 2 && _nfs != 0) || ( _limitEmissions == 4 && _nfs + _nis != 0) ) { if(particle->spinInfo()) particle->spinInfo()->develop(); return false; } // too many tries if(_nFSR>=_maxTryFSR) { ++_nFailedFSR; // too many failed events if(_nFailedFSR>=_maxFailFSR) throw Exception() << "Too many events have failed due to too many shower emissions, in\n" << "QTildeShowerHandler::timeLikeShower(). Terminating run\n" << Exception::runerror; throw Exception() << "Too many attempted emissions in QTildeShowerHandler::timeLikeShower()\n" << Exception::eventerror; } // generate the emission ShowerParticleVector children; int ntry=0; // generate the emission if(!fb.kinematics) fb = selectTimeLikeBranching(particle,type,HardBranchingPtr()); // no emission, return if(!fb.kinematics) { if(particle->spinInfo()) particle->spinInfo()->develop(); return false; } Branching fc[2]; bool setupChildren = true; while (ntry<50) { fc[0] = Branching(); fc[1] = Branching(); ++ntry; assert(fb.kinematics); // has emitted // Assign the shower kinematics to the emitting particle. if(setupChildren) { ++_nFSR; particle->showerKinematics(fb.kinematics); // check highest pT if(fb.kinematics->pT()>progenitor()->highestpT()) progenitor()->highestpT(fb.kinematics->pT()); // create the children children = createTimeLikeChildren(particle,fb.ids); // update the children particle->showerKinematics()-> updateChildren(particle, children,fb.type,_reconOpt>=3); // update number of emissions ++_nfs; if(_limitEmissions!=0) { if(children[0]->spinInfo()) children[0]->spinInfo()->develop(); if(children[1]->spinInfo()) children[1]->spinInfo()->develop(); if(particle->spinInfo()) particle->spinInfo()->develop(); return true; } setupChildren = false; } // select branchings for children fc[0] = selectTimeLikeBranching(children[0],type,HardBranchingPtr()); fc[1] = selectTimeLikeBranching(children[1],type,HardBranchingPtr()); // old default if(_reconOpt==0) { // shower the first particle if(fc[0].kinematics) timeLikeShower(children[0],type,fc[0],false); if(children[0]->spinInfo()) children[0]->spinInfo()->develop(); // shower the second particle if(fc[1].kinematics) timeLikeShower(children[1],type,fc[1],false); if(children[1]->spinInfo()) children[1]->spinInfo()->develop(); break; } // Herwig default else if(_reconOpt==1) { // shower the first particle if(fc[0].kinematics) timeLikeShower(children[0],type,fc[0],false); if(children[0]->spinInfo()) children[0]->spinInfo()->develop(); // shower the second particle if(fc[1].kinematics) timeLikeShower(children[1],type,fc[1],false); if(children[1]->spinInfo()) children[1]->spinInfo()->develop(); // branching has happened particle->showerKinematics()->updateParent(particle, children,fb.type); // clean up the vetoed emission if(particle->virtualMass()==ZERO) { particle->showerKinematics(ShoKinPtr()); for(unsigned int ix=0;ix<children.size();++ix) particle->abandonChild(children[ix]); children.clear(); if(particle->spinInfo()) particle->spinInfo()->decayVertex(VertexPtr()); particle->vetoEmission(fb.type,fb.kinematics->scale()); // generate the new emission fb = selectTimeLikeBranching(particle,type,HardBranchingPtr()); // no emission, return if(!fb.kinematics) { if(particle->spinInfo()) particle->spinInfo()->develop(); return false; } setupChildren = true; continue; } else break; } // veto children else if(_reconOpt>=2) { // cut-off masses for the branching const vector<Energy> & virtualMasses = fb.sudakov->virtualMasses(fb.ids); // compute the masses of the children Energy masses[3]; for(unsigned int ix=0;ix<2;++ix) { if(fc[ix].kinematics) { const vector<Energy> & vm = fc[ix].sudakov->virtualMasses(fc[ix].ids); Energy2 q2 = fc[ix].kinematics->z()*(1.-fc[ix].kinematics->z())*sqr(fc[ix].kinematics->scale()); if(fc[ix].ids[0]->id()!=ParticleID::g) q2 += sqr(vm[0]); masses[ix+1] = sqrt(q2); } else { masses[ix+1] = virtualMasses[ix+1]; } } masses[0] = fb.ids[0]->id()!=ParticleID::g ? virtualMasses[0] : ZERO; double z = fb.kinematics->z(); Energy2 pt2 = z*(1.-z)*(z*(1.-z)*sqr(fb.kinematics->scale()) + sqr(masses[0])) - sqr(masses[1])*(1.-z) - sqr(masses[2])*z; if(pt2>=ZERO) { break; } else { // reset the scales for the children for(unsigned int ix=0;ix<2;++ix) { if(fc[ix].kinematics) children[ix]->vetoEmission(fc[ix].type,fc[ix].kinematics->scale()); else children[ix]->vetoEmission(ShowerPartnerType::QCDColourLine,ZERO); children[ix]->virtualMass(ZERO); } } } }; if(_reconOpt>=2) { // shower the first particle if(fc[0].kinematics) timeLikeShower(children[0],type,fc[0],false); if(children[0]->spinInfo()) children[0]->spinInfo()->develop(); // shower the second particle if(fc[1].kinematics) timeLikeShower(children[1],type,fc[1],false); if(children[1]->spinInfo()) children[1]->spinInfo()->develop(); // branching has happened particle->showerKinematics()->updateParent(particle, children,fb.type); } if(first&&!children.empty()) particle->showerKinematics()->resetChildren(particle,children); if(particle->spinInfo()) particle->spinInfo()->develop(); return true; } bool QTildeShowerHandler::spaceLikeShower(tShowerParticlePtr particle, PPtr beam, ShowerInteraction type) { //using the pdf's associated with the ShowerHandler assures, that //modified pdf's are used for the secondary interactions via //CascadeHandler::resetPDFs(...) tcPDFPtr pdf; if(firstPDF().particle() == _beam) pdf = firstPDF().pdf(); if(secondPDF().particle() == _beam) pdf = secondPDF().pdf(); Energy freeze = pdfFreezingScale(); // don't do anything if not needed if(_limitEmissions == 2 || hardOnly() || ( _limitEmissions == 1 && _nis != 0 ) || ( _limitEmissions == 4 && _nis + _nfs != 0 ) ) { if(particle->spinInfo()) particle->spinInfo()->develop(); return false; } Branching bb; // generate branching while (true) { bb=_splittingGenerator->chooseBackwardBranching(*particle,beam, _initialenhance, _beam,type, pdf,freeze); // return if no emission if(!bb.kinematics) { if(particle->spinInfo()) particle->spinInfo()->develop(); return false; } // if not vetoed break if(!spaceLikeVetoed(bb,particle)) break; // otherwise reset scale and continue particle->vetoEmission(bb.type,bb.kinematics->scale()); if(particle->spinInfo()) particle->spinInfo()->decayVertex(VertexPtr()); } // assign the splitting function and shower kinematics particle->showerKinematics(bb.kinematics); if(bb.kinematics->pT()>progenitor()->highestpT()) progenitor()->highestpT(bb.kinematics->pT()); // For the time being we are considering only 1->2 branching // particles as in Sudakov form factor tcPDPtr part[2]={bb.ids[0],bb.ids[2]}; // Now create the actual particles, make the otherChild a final state // particle, while the newParent is not ShowerParticlePtr newParent = new_ptr(ShowerParticle(part[0],false)); ShowerParticlePtr otherChild = new_ptr(ShowerParticle(part[1],true,true)); ShowerParticleVector theChildren; theChildren.push_back(particle); theChildren.push_back(otherChild); //this updates the evolution scale particle->showerKinematics()-> updateParent(newParent, theChildren,bb.type); // update the history if needed _currenttree->updateInitialStateShowerProduct(_progenitor,newParent); _currenttree->addInitialStateBranching(particle,newParent,otherChild); // for the reconstruction of kinematics, parent/child // relationships are according to the branching process: // now continue the shower ++_nis; bool emitted = _limitEmissions==0 ? spaceLikeShower(newParent,beam,type) : false; if(newParent->spinInfo()) newParent->spinInfo()->develop(); // now reconstruct the momentum if(!emitted) { if(_intrinsic.find(_progenitor)==_intrinsic.end()) { bb.kinematics->updateLast(newParent,ZERO,ZERO); } else { pair<Energy,double> kt=_intrinsic[_progenitor]; bb.kinematics->updateLast(newParent, kt.first*cos(kt.second), kt.first*sin(kt.second)); } } particle->showerKinematics()-> updateChildren(newParent, theChildren,bb.type,_reconOpt>=4); if(_limitEmissions!=0) { if(particle->spinInfo()) particle->spinInfo()->develop(); return true; } // perform the shower of the final-state particle timeLikeShower(otherChild,type,Branching(),true); updateHistory(otherChild); if(theChildren[1]->spinInfo()) theChildren[1]->spinInfo()->develop(); // return the emitted if(particle->spinInfo()) particle->spinInfo()->develop(); return true; } void QTildeShowerHandler::showerDecay(ShowerTreePtr decay) { // work out the type of event currentTree()->xcombPtr(StdXCombPtr()); currentTree()->identifyEventType(); _decayme = HwDecayerBasePtr(); _hardme = HwMEBasePtr(); // find the decayer // try the normal way if possible tDMPtr dm = decay->incomingLines().begin()->first->original() ->decayMode(); if(!dm) dm = decay->incomingLines().begin()->first->copy() ->decayMode(); if(!dm) dm = decay->incomingLines().begin()->first->progenitor()->decayMode(); // otherwise make a string and look it up if(!dm) { string tag = decay->incomingLines().begin()->first->original()->dataPtr()->name() + "->"; OrderedParticles outgoing; for(map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator it=decay->outgoingLines().begin();it!=decay->outgoingLines().end();++it) { if(abs(decay->incomingLines().begin()->first->original()->id()) == ParticleID::t && abs(it->first->original()->id())==ParticleID::Wplus && decay->treelinks().size() == 1) { ShowerTreePtr Wtree = decay->treelinks().begin()->first; for(map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator it2=Wtree->outgoingLines().begin();it2!=Wtree->outgoingLines().end();++it2) { outgoing.insert(it2->first->original()->dataPtr()); } } else { outgoing.insert(it->first->original()->dataPtr()); } } for(OrderedParticles::const_iterator it=outgoing.begin(); it!=outgoing.end();++it) { if(it!=outgoing.begin()) tag += ","; tag +=(**it).name(); } tag += ";"; dm = findDecayMode(tag); } if(dm) _decayme = dynamic_ptr_cast<HwDecayerBasePtr>(dm->decayer()); // set the ShowerTree to be showered currentTree(decay); decay->applyTransforms(); hardTree(HardTreePtr()); // generate the showering doShowering(false,XCPtr()); // if no vetos // force calculation of spin correlations SpinPtr spInfo = decay->incomingLines().begin()->first->progenitor()->spinInfo(); if(spInfo) { if(!spInfo->developed()) spInfo->needsUpdate(); spInfo->develop(); } } bool QTildeShowerHandler::spaceLikeDecayShower(tShowerParticlePtr particle, const ShowerParticle::EvolutionScales & maxScales, Energy minmass,ShowerInteraction type, Branching fb) { // too many tries if(_nFSR>=_maxTryFSR) { ++_nFailedFSR; // too many failed events if(_nFailedFSR>=_maxFailFSR) throw Exception() << "Too many events have failed due to too many shower emissions, in\n" << "QTildeShowerHandler::timeLikeShower(). Terminating run\n" << Exception::runerror; throw Exception() << "Too many attempted emissions in QTildeShowerHandler::timeLikeShower()\n" << Exception::eventerror; } // generate the emission ShowerParticleVector children; int ntry=0; // generate the emission if(!fb.kinematics) fb = selectSpaceLikeDecayBranching(particle,maxScales,minmass,type, HardBranchingPtr()); // no emission, return if(!fb.kinematics) return false; Branching fc[2]; bool setupChildren = true; while (ntry<50) { if(particle->virtualMass()==ZERO) particle->virtualMass(_progenitor->progenitor()->mass()); fc[0] = Branching(); fc[1] = Branching(); ++ntry; assert(fb.kinematics); // has emitted // Assign the shower kinematics to the emitting particle. if(setupChildren) { ++_nFSR; // Assign the shower kinematics to the emitting particle. particle->showerKinematics(fb.kinematics); if(fb.kinematics->pT()>progenitor()->highestpT()) progenitor()->highestpT(fb.kinematics->pT()); // create the ShowerParticle objects for the two children children = createTimeLikeChildren(particle,fb.ids); // updateChildren the children particle->showerKinematics()-> updateChildren(particle, children, fb.type,_reconOpt>=3); setupChildren = false; } // select branchings for children fc[0] = selectSpaceLikeDecayBranching(children[0],maxScales,minmass, type,HardBranchingPtr()); fc[1] = selectTimeLikeBranching (children[1],type,HardBranchingPtr()); // old default if(_reconOpt==0) { // shower the first particle _currenttree->updateInitialStateShowerProduct(_progenitor,children[0]); _currenttree->addInitialStateBranching(particle,children[0],children[1]); if(fc[0].kinematics) spaceLikeDecayShower(children[0],maxScales,minmass,type,Branching()); // shower the second particle if(fc[1].kinematics) timeLikeShower(children[1],type,fc[1],true); updateHistory(children[1]); // branching has happened break; } // Herwig default else if(_reconOpt==1) { // shower the first particle _currenttree->updateInitialStateShowerProduct(_progenitor,children[0]); _currenttree->addInitialStateBranching(particle,children[0],children[1]); if(fc[0].kinematics) spaceLikeDecayShower(children[0],maxScales,minmass,type,Branching()); // shower the second particle if(fc[1].kinematics) timeLikeShower(children[1],type,fc[1],true); updateHistory(children[1]); // branching has happened particle->showerKinematics()->updateParent(particle, children,fb.type); // clean up the vetoed emission if(particle->virtualMass()==ZERO) { particle->showerKinematics(ShoKinPtr()); for(unsigned int ix=0;ix<children.size();++ix) particle->abandonChild(children[ix]); children.clear(); particle->vetoEmission(fb.type,fb.kinematics->scale()); // generate the new emission fb = selectSpaceLikeDecayBranching(particle,maxScales,minmass,type, HardBranchingPtr()); // no emission, return if(!fb.kinematics) { return false; } setupChildren = true; continue; } else break; } else if(_reconOpt>=2) { // cut-off masses for the branching const vector<Energy> & virtualMasses = fb.sudakov->virtualMasses(fb.ids); // compute the masses of the children Energy masses[3]; // space-like children masses[1] = children[0]->virtualMass(); // time-like child if(fc[1].kinematics) { const vector<Energy> & vm = fc[1].sudakov->virtualMasses(fc[1].ids); Energy2 q2 = fc[1].kinematics->z()*(1.-fc[1].kinematics->z())*sqr(fc[1].kinematics->scale()); if(fc[1].ids[0]->id()!=ParticleID::g) q2 += sqr(vm[0]); masses[2] = sqrt(q2); } else { masses[2] = virtualMasses[2]; } masses[0]=particle->virtualMass(); double z = fb.kinematics->z(); Energy2 pt2 = (1.-z)*(z*sqr(masses[0])-sqr(masses[1])-z/(1.-z)*sqr(masses[2])); if(pt2>=ZERO) { break; } else { // reset the scales for the children for(unsigned int ix=0;ix<2;++ix) { if(fc[ix].kinematics) children[ix]->vetoEmission(fc[ix].type,fc[ix].kinematics->scale()); else { if(ix==0) children[ix]->vetoEmission(ShowerPartnerType::QCDColourLine,Constants::MaxEnergy); else children[ix]->vetoEmission(ShowerPartnerType::QCDColourLine,ZERO); } } children[0]->virtualMass(_progenitor->progenitor()->mass()); children[1]->virtualMass(ZERO); } } }; if(_reconOpt>=2) { // In the case of splittings which involves coloured particles, // set properly the colour flow of the branching. // update the history if needed _currenttree->updateInitialStateShowerProduct(_progenitor,children[0]); _currenttree->addInitialStateBranching(particle,children[0],children[1]); // shower the first particle if(fc[0].kinematics) spaceLikeDecayShower(children[0],maxScales,minmass,type,Branching()); // shower the second particle if(fc[1].kinematics) timeLikeShower(children[1],type,fc[1],true); updateHistory(children[1]); // branching has happened particle->showerKinematics()->updateParent(particle, children,fb.type); } // branching has happened return true; } vector<ShowerProgenitorPtr> QTildeShowerHandler::setupShower(bool hard) { RealEmissionProcessPtr real; // generate hard me if needed if(_hardEmission==1) { real = hardMatrixElementCorrection(hard); if(real&&!real->outgoing().empty()) setupMECorrection(real); } // generate POWHEG hard emission if needed else if(_hardEmission==2) hardestEmission(hard); // set the initial colour partners setEvolutionPartners(hard,interaction_,false); // get the particles to be showered vector<ShowerProgenitorPtr> particlesToShower = currentTree()->extractProgenitors(); // return the answer return particlesToShower; } void QTildeShowerHandler::setEvolutionPartners(bool hard,ShowerInteraction type, bool clear) { // match the particles in the ShowerTree and hardTree if(hardTree() && !hardTree()->connect(currentTree())) throw Exception() << "Can't match trees in " << "QTildeShowerHandler::setEvolutionPartners()" << Exception::eventerror; // extract the progenitors vector<ShowerParticlePtr> particles = currentTree()->extractProgenitorParticles(); // clear the partners if needed if(clear) { for(unsigned int ix=0;ix<particles.size();++ix) { particles[ix]->partner(ShowerParticlePtr()); particles[ix]->clearPartners(); } } // sort out the colour partners if(hardTree()) { // find the partner for(unsigned int ix=0;ix<particles.size();++ix) { tShowerParticlePtr partner = hardTree()->particles()[particles[ix]]->branchingParticle()->partner(); if(!partner) continue; for(map<ShowerParticlePtr,tHardBranchingPtr>::const_iterator it=hardTree()->particles().begin(); it!=hardTree()->particles().end();++it) { if(it->second->branchingParticle()==partner) { particles[ix]->partner(it->first); break; } } if(!particles[ix]->partner()) throw Exception() << "Can't match partners in " << "QTildeShowerHandler::setEvolutionPartners()" << Exception::eventerror; } } // Set the initial evolution scales showerModel()->partnerFinder()-> setInitialEvolutionScales(particles,!hard,interaction_,!_hardtree); if(hardTree() && _hardPOWHEG) { bool tooHard=false; map<ShowerParticlePtr,tHardBranchingPtr>::const_iterator eit=hardTree()->particles().end(); for(unsigned int ix=0;ix<particles.size();++ix) { map<ShowerParticlePtr,tHardBranchingPtr>::const_iterator mit = hardTree()->particles().find(particles[ix]); Energy hardScale(ZERO); ShowerPartnerType type(ShowerPartnerType::Undefined); // final-state if(particles[ix]->isFinalState()) { if(mit!= eit && !mit->second->children().empty()) { hardScale = mit->second->scale(); type = mit->second->type(); } } // initial-state else { if(mit!= eit && mit->second->parent()) { hardScale = mit->second->parent()->scale(); type = mit->second->parent()->type(); } } if(type!=ShowerPartnerType::Undefined) { if(type==ShowerPartnerType::QED) { tooHard |= particles[ix]->scales().QED_noAO<hardScale; } else if(type==ShowerPartnerType::QCDColourLine) { tooHard |= particles[ix]->scales().QCD_c_noAO<hardScale; } else if(type==ShowerPartnerType::QCDAntiColourLine) { tooHard |= particles[ix]->scales().QCD_ac_noAO<hardScale; } } } if(tooHard) convertHardTree(hard,type); } } void QTildeShowerHandler::updateHistory(tShowerParticlePtr particle) { if(!particle->children().empty()) { ShowerParticleVector theChildren; for(unsigned int ix=0;ix<particle->children().size();++ix) { ShowerParticlePtr part = dynamic_ptr_cast<ShowerParticlePtr> (particle->children()[ix]); theChildren.push_back(part); } // update the history if needed if(particle==_currenttree->getFinalStateShowerProduct(_progenitor)) _currenttree->updateFinalStateShowerProduct(_progenitor, particle,theChildren); _currenttree->addFinalStateBranching(particle,theChildren); for(unsigned int ix=0;ix<theChildren.size();++ix) updateHistory(theChildren[ix]); } } bool QTildeShowerHandler::startTimeLikeShower(ShowerInteraction type) { _nFSR = 0; // initialize basis vectors etc if(!progenitor()->progenitor()->partner()) return false; progenitor()->progenitor()->initializeFinalState(); if(hardTree()) { map<ShowerParticlePtr,tHardBranchingPtr>::const_iterator eit=hardTree()->particles().end(), mit = hardTree()->particles().find(progenitor()->progenitor()); if( mit != eit && !mit->second->children().empty() ) { bool output=truncatedTimeLikeShower(progenitor()->progenitor(), mit->second ,type,Branching(),true); if(output) updateHistory(progenitor()->progenitor()); return output; } } // do the shower bool output = hardOnly() ? false : timeLikeShower(progenitor()->progenitor() ,type,Branching(),true) ; if(output) updateHistory(progenitor()->progenitor()); return output; } bool QTildeShowerHandler::startSpaceLikeShower(PPtr parent, ShowerInteraction type) { // initialise the basis vectors if(!progenitor()->progenitor()->partner()) return false; progenitor()->progenitor()->initializeInitialState(parent); if(hardTree()) { map<ShowerParticlePtr,tHardBranchingPtr>::const_iterator eit =hardTree()->particles().end(), mit = hardTree()->particles().find(progenitor()->progenitor()); if( mit != eit && mit->second->parent() ) { return truncatedSpaceLikeShower( progenitor()->progenitor(), parent, mit->second->parent(), type ); } } // perform the shower return hardOnly() ? false : spaceLikeShower(progenitor()->progenitor(),parent,type); } bool QTildeShowerHandler:: startSpaceLikeDecayShower(const ShowerParticle::EvolutionScales & maxScales, Energy minimumMass,ShowerInteraction type) { _nFSR = 0; // set up the particle basis vectors if(!progenitor()->progenitor()->partner()) return false; progenitor()->progenitor()->initializeDecay(); if(hardTree()) { map<ShowerParticlePtr,tHardBranchingPtr>::const_iterator eit =hardTree()->particles().end(), mit = hardTree()->particles().find(progenitor()->progenitor()); if( mit != eit && mit->second->parent() ) { HardBranchingPtr branch=mit->second; while(branch->parent()) branch=branch->parent(); return truncatedSpaceLikeDecayShower(progenitor()->progenitor(),maxScales, minimumMass, branch ,type, Branching()); } } // perform the shower return hardOnly() ? false : spaceLikeDecayShower(progenitor()->progenitor(),maxScales,minimumMass,type,Branching()); } bool QTildeShowerHandler::timeLikeVetoed(const Branching & fb, ShowerParticlePtr particle) { // work out type of interaction ShowerInteraction type = convertInteraction(fb.type); // check whether emission was harder than largest pt of hard subprocess if ( restrictPhasespace() && fb.kinematics->pT() > _progenitor->maxHardPt() ) return true; // soft matrix element correction veto if( softMEC()) { if(_hardme && _hardme->hasMECorrection()) { if(_hardme->softMatrixElementVeto(_progenitor,particle,fb)) return true; } else if(_decayme && _decayme->hasMECorrection()) { if(_decayme->softMatrixElementVeto(_progenitor,particle,fb)) return true; } } // veto on maximum pt if(fb.kinematics->pT()>_progenitor->maximumpT(type)) return true; // general vetos if (fb.kinematics && !_vetoes.empty()) { bool vetoed=false; for (vector<ShowerVetoPtr>::iterator v = _vetoes.begin(); v != _vetoes.end(); ++v) { bool test = (**v).vetoTimeLike(_progenitor,particle,fb); switch((**v).vetoType()) { case ShowerVeto::Emission: vetoed |= test; break; case ShowerVeto::Shower: if(test) throw VetoShower(); break; case ShowerVeto::Event: if(test) throw Veto(); break; } } if(vetoed) return true; } if ( firstInteraction() && profileScales() ) { double weight = profileScales()-> hardScaleProfile(_progenitor->hardScale(),fb.kinematics->pT()); if ( UseRandom::rnd() > weight ) return true; } return false; } bool QTildeShowerHandler::spaceLikeVetoed(const Branching & bb, ShowerParticlePtr particle) { // work out type of interaction ShowerInteraction type = convertInteraction(bb.type); // check whether emission was harder than largest pt of hard subprocess if (restrictPhasespace() && bb.kinematics->pT() > _progenitor->maxHardPt()) return true; // apply the soft correction if( softMEC() && _hardme && _hardme->hasMECorrection() ) { if(_hardme->softMatrixElementVeto(_progenitor,particle,bb)) return true; } // the more general vetos // check vs max pt for the shower if(bb.kinematics->pT()>_progenitor->maximumpT(type)) return true; if (!_vetoes.empty()) { bool vetoed=false; for (vector<ShowerVetoPtr>::iterator v = _vetoes.begin(); v != _vetoes.end(); ++v) { bool test = (**v).vetoSpaceLike(_progenitor,particle,bb); switch ((**v).vetoType()) { case ShowerVeto::Emission: vetoed |= test; break; case ShowerVeto::Shower: if(test) throw VetoShower(); break; case ShowerVeto::Event: if(test) throw Veto(); break; } } if (vetoed) return true; } if ( firstInteraction() && profileScales() ) { double weight = profileScales()-> hardScaleProfile(_progenitor->hardScale(),bb.kinematics->pT()); if ( UseRandom::rnd() > weight ) return true; } return false; } bool QTildeShowerHandler::spaceLikeDecayVetoed( const Branching & fb, ShowerParticlePtr particle) { // work out type of interaction ShowerInteraction type = convertInteraction(fb.type); // apply the soft correction if( softMEC() && _decayme && _decayme->hasMECorrection() ) { if(_decayme->softMatrixElementVeto(_progenitor,particle,fb)) return true; } // veto on hardest pt in the shower if(fb.kinematics->pT()> _progenitor->maximumpT(type)) return true; // general vetos if (!_vetoes.empty()) { bool vetoed=false; for (vector<ShowerVetoPtr>::iterator v = _vetoes.begin(); v != _vetoes.end(); ++v) { bool test = (**v).vetoSpaceLike(_progenitor,particle,fb); switch((**v).vetoType()) { case ShowerVeto::Emission: vetoed |= test; break; case ShowerVeto::Shower: if(test) throw VetoShower(); break; case ShowerVeto::Event: if(test) throw Veto(); break; } if (vetoed) return true; } } return false; } void QTildeShowerHandler::hardestEmission(bool hard) { HardTreePtr ISRTree; // internal POWHEG in production or decay if( (( _hardme && _hardme->hasPOWHEGCorrection()!=0 ) || ( _decayme && _decayme->hasPOWHEGCorrection()!=0 ) ) ) { RealEmissionProcessPtr real; unsigned int type(0); // production if(_hardme) { assert(hard); real = _hardme->generateHardest( currentTree()->perturbativeProcess(), interaction_); type = _hardme->hasPOWHEGCorrection(); } // decay else { assert(!hard); real = _decayme->generateHardest( currentTree()->perturbativeProcess() ); type = _decayme->hasPOWHEGCorrection(); } if(real) { // set up ther hard tree if(!real->outgoing().empty()) _hardtree = new_ptr(HardTree(real)); // set up the vetos currentTree()->setVetoes(real->pT(),type); } // store initial state POWHEG radiation if(_hardtree && _hardme && _hardme->hasPOWHEGCorrection()==1) ISRTree = _hardtree; } else if (hard) { // Get minimum pT cutoff used in shower approximation Energy maxpt = 1.*GeV; if ( currentTree()->showerApproximation() ) { int colouredIn = 0; int colouredOut = 0; for( map< ShowerProgenitorPtr, tShowerParticlePtr >::iterator it = currentTree()->outgoingLines().begin(); it != currentTree()->outgoingLines().end(); ++it ) { if( it->second->coloured() ) ++colouredOut; } for( map< ShowerProgenitorPtr, ShowerParticlePtr >::iterator it = currentTree()->incomingLines().begin(); it != currentTree()->incomingLines().end(); ++it ) { if( it->second->coloured() ) ++colouredIn; } if ( currentTree()->showerApproximation()->ffPtCut() == currentTree()->showerApproximation()->fiPtCut() && currentTree()->showerApproximation()->ffPtCut() == currentTree()->showerApproximation()->iiPtCut() ) maxpt = currentTree()->showerApproximation()->ffPtCut(); else if ( colouredIn == 2 && colouredOut == 0 ) maxpt = currentTree()->showerApproximation()->iiPtCut(); else if ( colouredIn == 0 && colouredOut > 1 ) maxpt = currentTree()->showerApproximation()->ffPtCut(); else if ( colouredIn == 2 && colouredOut == 1 ) maxpt = min(currentTree()->showerApproximation()->iiPtCut(), currentTree()->showerApproximation()->fiPtCut()); else if ( colouredIn == 1 && colouredOut > 1 ) maxpt = min(currentTree()->showerApproximation()->ffPtCut(), currentTree()->showerApproximation()->fiPtCut()); else maxpt = min(min(currentTree()->showerApproximation()->iiPtCut(), currentTree()->showerApproximation()->fiPtCut()), currentTree()->showerApproximation()->ffPtCut()); } // Generate hardtree from born and real emission subprocesses _hardtree = generateCKKW(currentTree()); // Find transverse momentum of hardest emission if (_hardtree){ for(set<HardBranchingPtr>::iterator it=_hardtree->branchings().begin(); it!=_hardtree->branchings().end();++it) { if ((*it)->parent() && (*it)->status()==HardBranching::Incoming) maxpt=(*it)->branchingParticle()->momentum().perp(); if ((*it)->children().size()==2 && (*it)->status()==HardBranching::Outgoing){ if ((*it)->branchingParticle()->id()!=21 && abs((*it)->branchingParticle()->id())>5 ){ if ((*it)->children()[0]->branchingParticle()->id()==21 || abs((*it)->children()[0]->branchingParticle()->id())<6) maxpt=(*it)->children()[0]->branchingParticle()->momentum().perp(); else if ((*it)->children()[1]->branchingParticle()->id()==21 || abs((*it)->children()[1]->branchingParticle()->id())<6) maxpt=(*it)->children()[1]->branchingParticle()->momentum().perp(); } else { if ( abs((*it)->branchingParticle()->id())<6){ if (abs((*it)->children()[0]->branchingParticle()->id())<6) maxpt = (*it)->children()[1]->branchingParticle()->momentum().perp(); else maxpt = (*it)->children()[0]->branchingParticle()->momentum().perp(); } else maxpt = (*it)->children()[1]->branchingParticle()->momentum().perp(); } } } } // Hardest (pt) emission should be the first powheg emission. maxpt=min(sqrt(lastXCombPtr()->lastShowerScale()),maxpt); // set maximum pT for subsequent emissions from S events if ( currentTree()->isPowhegSEvent() ) { for( map< ShowerProgenitorPtr, tShowerParticlePtr >::iterator it = currentTree()->outgoingLines().begin(); it != currentTree()->outgoingLines().end(); ++it ) { if( ! it->second->coloured() ) continue; it->first->maximumpT(maxpt, ShowerInteraction::QCD ); } for( map< ShowerProgenitorPtr, ShowerParticlePtr >::iterator it = currentTree()->incomingLines().begin(); it != currentTree()->incomingLines().end(); ++it ) { if( ! it->second->coloured() ) continue; it->first->maximumpT(maxpt, ShowerInteraction::QCD ); } } } else _hardtree = generateCKKW(currentTree()); // if hard me doesn't have a FSR powheg // correction use decay powheg correction if (_hardme && _hardme->hasPOWHEGCorrection()<2) { addFSRUsingDecayPOWHEG(ISRTree); } // connect the trees if(_hardtree) { connectTrees(currentTree(),_hardtree,hard); } } void QTildeShowerHandler::addFSRUsingDecayPOWHEG(HardTreePtr ISRTree) { // check for intermediate colour singlet resonance const ParticleVector inter = _hardme->subProcess()->intermediates(); if (inter.size()!=1 || inter[0]->momentum().m2()/GeV2 < 0 || inter[0]->dataPtr()->iColour()!=PDT::Colour0) { return; } // ignore cases where outgoing particles are not coloured map<ShowerProgenitorPtr, tShowerParticlePtr > out = currentTree()->outgoingLines(); if (out.size() != 2 || out. begin()->second->dataPtr()->iColour()==PDT::Colour0 || out.rbegin()->second->dataPtr()->iColour()==PDT::Colour0) { return; } // look up decay mode tDMPtr dm; string tag; string inParticle = inter[0]->dataPtr()->name() + "->"; vector<string> outParticles; outParticles.push_back(out.begin ()->first->progenitor()->dataPtr()->name()); outParticles.push_back(out.rbegin()->first->progenitor()->dataPtr()->name()); for (int it=0; it<2; ++it){ tag = inParticle + outParticles[it] + "," + outParticles[(it+1)%2] + ";"; dm = generator()->findDecayMode(tag); if(dm) break; } // get the decayer HwDecayerBasePtr decayer; if(dm) decayer = dynamic_ptr_cast<HwDecayerBasePtr>(dm->decayer()); // check if decayer has a FSR POWHEG correction if (!decayer || decayer->hasPOWHEGCorrection()<2) { return; } // generate the hardest emission // create RealEmissionProcess PPtr in = new_ptr(*inter[0]); RealEmissionProcessPtr newProcess(new_ptr(RealEmissionProcess())); newProcess->bornIncoming().push_back(in); newProcess->bornOutgoing().push_back(out.begin ()->first->progenitor()); newProcess->bornOutgoing().push_back(out.rbegin()->first->progenitor()); // generate the FSR newProcess = decayer->generateHardest(newProcess); HardTreePtr FSRTree; if(newProcess) { // set up ther hard tree if(!newProcess->outgoing().empty()) FSRTree = new_ptr(HardTree(newProcess)); // set up the vetos currentTree()->setVetoes(newProcess->pT(),2); } if(!FSRTree) return; // if there is no ISRTree make _hardtree from FSRTree if (!ISRTree){ vector<HardBranchingPtr> inBranch,hardBranch; for(map<ShowerProgenitorPtr,ShowerParticlePtr>::const_iterator cit =currentTree()->incomingLines().begin(); cit!=currentTree()->incomingLines().end();++cit ) { inBranch.push_back(new_ptr(HardBranching(cit->second,SudakovPtr(), HardBranchingPtr(), HardBranching::Incoming))); inBranch.back()->beam(cit->first->original()->parents()[0]); hardBranch.push_back(inBranch.back()); } if(inBranch[0]->branchingParticle()->dataPtr()->coloured()) { inBranch[0]->colourPartner(inBranch[1]); inBranch[1]->colourPartner(inBranch[0]); } for(set<HardBranchingPtr>::iterator it=FSRTree->branchings().begin(); it!=FSRTree->branchings().end();++it) { if((**it).branchingParticle()->id()!=in->id()) hardBranch.push_back(*it); } hardBranch[2]->colourPartner(hardBranch[3]); hardBranch[3]->colourPartner(hardBranch[2]); HardTreePtr newTree = new_ptr(HardTree(hardBranch,inBranch, ShowerInteraction::QCD)); _hardtree = newTree; } // Otherwise modify the ISRTree to include the emission in FSRTree else { vector<tShowerParticlePtr> FSROut, ISROut; set<HardBranchingPtr>::iterator itFSR, itISR; // get outgoing particles for(itFSR =FSRTree->branchings().begin(); itFSR!=FSRTree->branchings().end();++itFSR){ if ((**itFSR).status()==HardBranching::Outgoing) FSROut.push_back((*itFSR)->branchingParticle()); } for(itISR =ISRTree->branchings().begin(); itISR!=ISRTree->branchings().end();++itISR){ if ((**itISR).status()==HardBranching::Outgoing) ISROut.push_back((*itISR)->branchingParticle()); } // find COM frame formed by outgoing particles LorentzRotation eventFrameFSR, eventFrameISR; eventFrameFSR = ((FSROut[0]->momentum()+FSROut[1]->momentum()).findBoostToCM()); eventFrameISR = ((ISROut[0]->momentum()+ISROut[1]->momentum()).findBoostToCM()); // find rotation between ISR and FSR frames int j=0; if (ISROut[0]->id()!=FSROut[0]->id()) j=1; eventFrameISR.rotateZ( (eventFrameFSR*FSROut[0]->momentum()).phi()- (eventFrameISR*ISROut[j]->momentum()).phi() ); eventFrameISR.rotateY( (eventFrameFSR*FSROut[0]->momentum()).theta()- (eventFrameISR*ISROut[j]->momentum()).theta() ); eventFrameISR.invert(); for (itFSR=FSRTree->branchings().begin(); itFSR!=FSRTree->branchings().end();++itFSR){ if ((**itFSR).branchingParticle()->id()==in->id()) continue; for (itISR =ISRTree->branchings().begin(); itISR!=ISRTree->branchings().end();++itISR){ if ((**itISR).status()==HardBranching::Incoming) continue; if ((**itFSR).branchingParticle()->id()== (**itISR).branchingParticle()->id()){ // rotate FSRTree particle to ISRTree event frame (**itISR).branchingParticle()->setMomentum(eventFrameISR* eventFrameFSR* (**itFSR).branchingParticle()->momentum()); (**itISR).branchingParticle()->rescaleMass(); // add the children of the FSRTree particles to the ISRTree if(!(**itFSR).children().empty()){ (**itISR).addChild((**itFSR).children()[0]); (**itISR).addChild((**itFSR).children()[1]); // rotate momenta to ISRTree event frame (**itISR).children()[0]->branchingParticle()->setMomentum(eventFrameISR* eventFrameFSR* (**itFSR).children()[0]->branchingParticle()->momentum()); (**itISR).children()[1]->branchingParticle()->setMomentum(eventFrameISR* eventFrameFSR* (**itFSR).children()[1]->branchingParticle()->momentum()); } } } } _hardtree = ISRTree; } } bool QTildeShowerHandler::truncatedTimeLikeShower(tShowerParticlePtr particle, HardBranchingPtr branch, ShowerInteraction type, Branching fb, bool first) { // select a branching if we don't have one if(!fb.kinematics) fb = selectTimeLikeBranching(particle,type,branch); // must be an emission, the forced one it not a truncated one assert(fb.kinematics); ShowerParticleVector children; int ntry=0; Branching fc[2]; bool setupChildren = true; while (ntry<50) { if(!fc[0].hard) fc[0] = Branching(); if(!fc[1].hard) fc[1] = Branching(); ++ntry; // Assign the shower kinematics to the emitting particle. if(setupChildren) { ++_nFSR; // Assign the shower kinematics to the emitting particle. particle->showerKinematics(fb.kinematics); if(fb.kinematics->pT()>progenitor()->highestpT()) progenitor()->highestpT(fb.kinematics->pT()); // create the children children = createTimeLikeChildren(particle,fb.ids); // update the children particle->showerKinematics()-> updateChildren(particle, children,fb.type,_reconOpt>=3); setupChildren = false; } // select branchings for children if(!fc[0].kinematics) { // select branching for first particle if(!fb.hard && fb.iout ==1 ) fc[0] = selectTimeLikeBranching(children[0],type,branch); else if(fb.hard && !branch->children()[0]->children().empty() ) fc[0] = selectTimeLikeBranching(children[0],type,branch->children()[0]); else fc[0] = selectTimeLikeBranching(children[0],type,HardBranchingPtr()); } // select branching for the second particle if(!fc[1].kinematics) { // select branching for first particle if(!fb.hard && fb.iout ==2 ) fc[1] = selectTimeLikeBranching(children[1],type,branch); else if(fb.hard && !branch->children()[1]->children().empty() ) fc[1] = selectTimeLikeBranching(children[1],type,branch->children()[1]); else fc[1] = selectTimeLikeBranching(children[1],type,HardBranchingPtr()); } // old default if(_reconOpt==0 || (_reconOpt==1 && fb.hard) ) { // shower the first particle if(fc[0].kinematics) { // the parent has truncated emission and following line if(!fb.hard && fb.iout == 1) truncatedTimeLikeShower(children[0],branch,type,fc[0],false); // hard emission and subsquent hard emissions else if(fb.hard && !branch->children()[0]->children().empty() ) truncatedTimeLikeShower(children[0],branch->children()[0],type,fc[0],false); // normal shower else timeLikeShower(children[0],type,fc[0],false); } if(children[0]->spinInfo()) children[0]->spinInfo()->develop(); // shower the second particle if(fc[1].kinematics) { // the parent has truncated emission and following line if(!fb.hard && fb.iout == 2) truncatedTimeLikeShower(children[1],branch,type,fc[1],false); // hard emission and subsquent hard emissions else if(fb.hard && !branch->children()[1]->children().empty() ) truncatedTimeLikeShower(children[1],branch->children()[1],type,fc[1],false); else timeLikeShower(children[1],type,fc[1],false); } if(children[1]->spinInfo()) children[1]->spinInfo()->develop(); // branching has happened particle->showerKinematics()->updateParent(particle, children,fb.type); break; } // H7 default else if(_reconOpt==1) { // shower the first particle if(fc[0].kinematics) { // the parent has truncated emission and following line if(!fb.hard && fb.iout == 1) truncatedTimeLikeShower(children[0],branch,type,fc[0],false); else timeLikeShower(children[0],type,fc[0],false); } if(children[0]->spinInfo()) children[0]->spinInfo()->develop(); // shower the second particle if(fc[1].kinematics) { // the parent has truncated emission and following line if(!fb.hard && fb.iout == 2) truncatedTimeLikeShower(children[1],branch,type,fc[1],false); else timeLikeShower(children[1],type,fc[1],false); } if(children[1]->spinInfo()) children[1]->spinInfo()->develop(); // branching has happened particle->showerKinematics()->updateParent(particle, children,fb.type); // clean up the vetoed emission if(particle->virtualMass()==ZERO) { particle->showerKinematics(ShoKinPtr()); for(unsigned int ix=0;ix<children.size();++ix) particle->abandonChild(children[ix]); children.clear(); if(particle->spinInfo()) particle->spinInfo()->decayVertex(VertexPtr()); particle->vetoEmission(fb.type,fb.kinematics->scale()); // generate the new emission fb = selectTimeLikeBranching(particle,type,branch); // must be at least hard emission assert(fb.kinematics); setupChildren = true; continue; } else break; } else if(_reconOpt>=2) { // cut-off masses for the branching const vector<Energy> & virtualMasses = fb.sudakov->virtualMasses(fb.ids); // compute the masses of the children Energy masses[3]; for(unsigned int ix=0;ix<2;++ix) { if(fc[ix].kinematics) { const vector<Energy> & vm = fc[ix].sudakov->virtualMasses(fc[ix].ids); Energy2 q2 = fc[ix].kinematics->z()*(1.-fc[ix].kinematics->z())*sqr(fc[ix].kinematics->scale()); if(fc[ix].ids[0]->id()!=ParticleID::g) q2 += sqr(vm[0]); masses[ix+1] = sqrt(q2); } else { masses[ix+1] = virtualMasses[ix+1]; } } masses[0] = fb.ids[0]->id()!=ParticleID::g ? virtualMasses[0] : ZERO; double z = fb.kinematics->z(); Energy2 pt2 = z*(1.-z)*(z*(1.-z)*sqr(fb.kinematics->scale()) + sqr(masses[0])) - sqr(masses[1])*(1.-z) - sqr(masses[2])*z; if(pt2>=ZERO) { break; } // if only the hard emission have to accept it else if ((fc[0].hard && !fc[1].kinematics) || (fc[1].hard && !fc[0].kinematics) ) { break; } else { // reset the scales for the children for(unsigned int ix=0;ix<2;++ix) { if(fc[ix].hard) continue; if(fc[ix].kinematics && ! fc[ix].hard ) children[ix]->vetoEmission(fc[ix].type,fc[ix].kinematics->scale()); else children[ix]->vetoEmission(ShowerPartnerType::QCDColourLine,ZERO); children[ix]->virtualMass(ZERO); } } } }; if(_reconOpt>=2) { // shower the first particle if(fc[0].kinematics) { // the parent has truncated emission and following line if(!fb.hard && fb.iout == 1) truncatedTimeLikeShower(children[0],branch,type,fc[0],false); // hard emission and subsquent hard emissions else if(fb.hard && !branch->children()[0]->children().empty() ) truncatedTimeLikeShower(children[0],branch->children()[0],type,fc[0],false); // normal shower else timeLikeShower(children[0],type,fc[0],false); } if(children[0]->spinInfo()) children[0]->spinInfo()->develop(); // shower the second particle if(fc[1].kinematics) { // the parent has truncated emission and following line if(!fb.hard && fb.iout == 2) truncatedTimeLikeShower(children[1],branch,type,fc[1],false); // hard emission and subsquent hard emissions else if(fb.hard && !branch->children()[1]->children().empty() ) truncatedTimeLikeShower(children[1],branch->children()[1],type,fc[1],false); else timeLikeShower(children[1],type,fc[1],false); } if(children[1]->spinInfo()) children[1]->spinInfo()->develop(); // branching has happened particle->showerKinematics()->updateParent(particle, children,fb.type); } if(first&&!children.empty()) particle->showerKinematics()->resetChildren(particle,children); if(particle->spinInfo()) particle->spinInfo()->develop(); return true; } bool QTildeShowerHandler::truncatedSpaceLikeShower(tShowerParticlePtr particle, PPtr beam, HardBranchingPtr branch, ShowerInteraction type) { tcPDFPtr pdf; if(firstPDF().particle() == beamParticle()) pdf = firstPDF().pdf(); if(secondPDF().particle() == beamParticle()) pdf = secondPDF().pdf(); Energy freeze = pdfFreezingScale(); Branching bb; // parameters of the force branching double z(0.); HardBranchingPtr timelike; for( unsigned int ix = 0; ix < branch->children().size(); ++ix ) { if( branch->children()[ix]->status() ==HardBranching::Outgoing) { timelike = branch->children()[ix]; } if( branch->children()[ix]->status() ==HardBranching::Incoming ) z = branch->children()[ix]->z(); } // generate truncated branching tcPDPtr part[2]; if(z>=0.&&z<=1.) { while (true) { if( !isTruncatedShowerON() || hardOnly() ) break; bb = splittingGenerator()->chooseBackwardBranching( *particle, beam, 1., beamParticle(), type , pdf,freeze); if( !bb.kinematics || bb.kinematics->scale() < branch->scale() ) { bb = Branching(); break; } // particles as in Sudakov form factor part[0] = bb.ids[0]; part[1] = bb.ids[2]; double zsplit = bb.kinematics->z(); // apply the vetos for the truncated shower // if doesn't carry most of momentum ShowerInteraction type2 = convertInteraction(bb.type); if(type2==branch->sudakov()->interactionType() && zsplit < 0.5) { particle->vetoEmission(bb.type,bb.kinematics->scale()); continue; } // others if( part[0]->id() != particle->id() || // if particle changes type bb.kinematics->pT() > progenitor()->maximumpT(type2) || // pt veto bb.kinematics->scale() < branch->scale()) { // angular ordering veto particle->vetoEmission(bb.type,bb.kinematics->scale()); continue; } // and those from the base class if(spaceLikeVetoed(bb,particle)) { particle->vetoEmission(bb.type,bb.kinematics->scale()); continue; } break; } } if( !bb.kinematics ) { //do the hard emission ShoKinPtr kinematics = branch->sudakov()->createInitialStateBranching( branch->scale(), z, branch->phi(), branch->children()[0]->pT() ); // assign the splitting function and shower kinematics particle->showerKinematics( kinematics ); if(kinematics->pT()>progenitor()->highestpT()) progenitor()->highestpT(kinematics->pT()); // For the time being we are considering only 1->2 branching // Now create the actual particles, make the otherChild a final state // particle, while the newParent is not ShowerParticlePtr newParent = new_ptr( ShowerParticle( branch->branchingParticle()->dataPtr(), false ) ); ShowerParticlePtr otherChild = new_ptr( ShowerParticle( timelike->branchingParticle()->dataPtr(), true, true ) ); ShowerParticleVector theChildren; theChildren.push_back( particle ); theChildren.push_back( otherChild ); particle->showerKinematics()-> updateParent( newParent, theChildren, branch->type()); // update the history if needed currentTree()->updateInitialStateShowerProduct( progenitor(), newParent ); currentTree()->addInitialStateBranching( particle, newParent, otherChild ); // for the reconstruction of kinematics, parent/child // relationships are according to the branching process: // now continue the shower bool emitted=false; if(!hardOnly()) { if( branch->parent() ) { emitted = truncatedSpaceLikeShower( newParent, beam, branch->parent() , type); } else { emitted = spaceLikeShower( newParent, beam , type); } } if( !emitted ) { if( intrinsicpT().find( progenitor() ) == intrinsicpT().end() ) { kinematics->updateLast( newParent, ZERO, ZERO ); } else { pair<Energy,double> kt = intrinsicpT()[progenitor()]; kinematics->updateLast( newParent, kt.first*cos( kt.second ), kt.first*sin( kt.second ) ); } } particle->showerKinematics()-> updateChildren( newParent, theChildren,bb.type,false); if(hardOnly()) return true; // perform the shower of the final-state particle if( timelike->children().empty() ) { timeLikeShower( otherChild , type,Branching(),true); } else { truncatedTimeLikeShower( otherChild, timelike , type,Branching(), true); } updateHistory(otherChild); // return the emitted return true; } // assign the splitting function and shower kinematics particle->showerKinematics( bb.kinematics ); if(bb.kinematics->pT()>progenitor()->highestpT()) progenitor()->highestpT(bb.kinematics->pT()); // For the time being we are considering only 1->2 branching // Now create the actual particles, make the otherChild a final state // particle, while the newParent is not ShowerParticlePtr newParent = new_ptr( ShowerParticle( part[0], false ) ); ShowerParticlePtr otherChild = new_ptr( ShowerParticle( part[1], true, true ) ); ShowerParticleVector theChildren; theChildren.push_back( particle ); theChildren.push_back( otherChild ); particle->showerKinematics()-> updateParent( newParent, theChildren, bb.type); // update the history if needed currentTree()->updateInitialStateShowerProduct( progenitor(), newParent ); currentTree()->addInitialStateBranching( particle, newParent, otherChild ); // for the reconstruction of kinematics, parent/child // relationships are according to the branching process: // now continue the shower bool emitted = truncatedSpaceLikeShower( newParent, beam, branch,type); // now reconstruct the momentum if( !emitted ) { if( intrinsicpT().find( progenitor() ) == intrinsicpT().end() ) { bb.kinematics->updateLast( newParent, ZERO, ZERO ); } else { pair<Energy,double> kt = intrinsicpT()[ progenitor() ]; bb.kinematics->updateLast( newParent, kt.first*cos( kt.second ), kt.first*sin( kt.second ) ); } } particle->showerKinematics()-> updateChildren( newParent, theChildren, bb.type,false); // perform the shower of the final-state particle timeLikeShower( otherChild , type,Branching(),true); updateHistory(otherChild); // return the emitted return true; } bool QTildeShowerHandler:: truncatedSpaceLikeDecayShower(tShowerParticlePtr particle, const ShowerParticle::EvolutionScales & maxScales, Energy minmass, HardBranchingPtr branch, ShowerInteraction type, Branching fb) { // select a branching if we don't have one if(!fb.kinematics) fb = selectSpaceLikeDecayBranching(particle,maxScales,minmass,type,branch); // must be an emission, the forced one it not a truncated one assert(fb.kinematics); ShowerParticleVector children; int ntry=0; Branching fc[2]; bool setupChildren = true; while (ntry<50) { if(!fc[0].hard) fc[0] = Branching(); if(!fc[1].hard) fc[1] = Branching(); ++ntry; if(setupChildren) { ++_nFSR; // Assign the shower kinematics to the emitting particle. particle->showerKinematics(fb.kinematics); if(fb.kinematics->pT()>progenitor()->highestpT()) progenitor()->highestpT(fb.kinematics->pT()); // create the ShowerParticle objects for the two children children = createTimeLikeChildren(particle,fb.ids); // updateChildren the children particle->showerKinematics()-> updateChildren(particle, children, fb.type,_reconOpt>=3); setupChildren = false; } // select branchings for children if(!fc[0].kinematics) { if(children[0]->id()==particle->id()) { // select branching for first particle if(!fb.hard) fc[0] = selectSpaceLikeDecayBranching(children[0],maxScales,minmass,type,branch); else if(fb.hard && ! branch->children()[0]->children().empty() ) fc[0] = selectSpaceLikeDecayBranching(children[0],maxScales,minmass,type, branch->children()[0]); else fc[0] = selectSpaceLikeDecayBranching(children[0],maxScales,minmass,type, HardBranchingPtr()); } else { // select branching for first particle if(fb.hard && !branch->children()[0]->children().empty() ) fc[0] = selectTimeLikeBranching(children[0],type,branch->children()[0]); else fc[0] = selectTimeLikeBranching(children[0],type,HardBranchingPtr()); } } // select branching for the second particle if(!fc[1].kinematics) { if(children[1]->id()==particle->id()) { // select branching for first particle if(!fb.hard) fc[1] = selectSpaceLikeDecayBranching(children[1],maxScales,minmass,type,branch); else if(fb.hard && ! branch->children()[1]->children().empty() ) fc[1] = selectSpaceLikeDecayBranching(children[1],maxScales,minmass,type, branch->children()[1]); else fc[1] = selectSpaceLikeDecayBranching(children[1],maxScales,minmass,type, HardBranchingPtr()); } else { if(fb.hard && !branch->children()[1]->children().empty() ) fc[1] = selectTimeLikeBranching(children[1],type,branch->children()[1]); else fc[1] = selectTimeLikeBranching(children[1],type,HardBranchingPtr()); } } // old default if(_reconOpt==0 || (_reconOpt==1 && fb.hard) ) { // update the history if needed currentTree()->updateInitialStateShowerProduct(progenitor(),children[0]); currentTree()->addInitialStateBranching(particle,children[0],children[1]); // shower the first particle if(fc[0].kinematics) { if(children[0]->id()==particle->id()) { if(!fb.hard) truncatedSpaceLikeDecayShower( children[0],maxScales,minmass, branch,type,fc[0]); else if(fb.hard && ! branch->children()[0]->children().empty() ) truncatedSpaceLikeDecayShower( children[0],maxScales,minmass, branch->children()[0],type,fc[0]); else spaceLikeDecayShower( children[0],maxScales,minmass,type,fc[0]); } else { if(fb.hard && !branch->children()[0]->children().empty() ) truncatedTimeLikeShower(children[0],branch->children()[0],type,fc[0],false); // normal shower else timeLikeShower(children[0],type,fc[0],false); } } // shower the second particle if(fc[1].kinematics) { if(children[0]->id()==particle->id()) { if(!fb.hard) truncatedSpaceLikeDecayShower( children[0],maxScales,minmass, branch,type,fc[1]); else if(fb.hard && ! branch->children()[0]->children().empty() ) truncatedSpaceLikeDecayShower( children[0],maxScales,minmass, branch->children()[0],type,fc[1]); else spaceLikeDecayShower( children[0],maxScales,minmass,type,fc[1]); } else { if(fb.hard && !branch->children()[0]->children().empty() ) truncatedTimeLikeShower(children[0],branch->children()[0],type,fc[1],false); // normal shower else timeLikeShower(children[0],type,fc[1],false); } } updateHistory(children[1]); // branching has happened break; } // H7 default else if(_reconOpt==1) { // update the history if needed currentTree()->updateInitialStateShowerProduct(progenitor(),children[0]); currentTree()->addInitialStateBranching(particle,children[0],children[1]); // shower the first particle if(fc[0].kinematics) { if(children[0]->id()==particle->id()) { if(!fb.hard) truncatedSpaceLikeDecayShower( children[0],maxScales,minmass, branch,type,fc[0]); else if(fb.hard && ! branch->children()[0]->children().empty() ) truncatedSpaceLikeDecayShower( children[0],maxScales,minmass, branch->children()[0],type,fc[0]); else spaceLikeDecayShower( children[0],maxScales,minmass,type,fc[0]); } else { if(fb.hard && !branch->children()[0]->children().empty() ) truncatedTimeLikeShower(children[0],branch->children()[0],type,fc[0],false); // normal shower else timeLikeShower(children[0],type,fc[0],false); } } // shower the second particle if(fc[1].kinematics) { if(children[0]->id()==particle->id()) { if(!fb.hard) truncatedSpaceLikeDecayShower( children[0],maxScales,minmass, branch,type,fc[1]); else if(fb.hard && ! branch->children()[0]->children().empty() ) truncatedSpaceLikeDecayShower( children[0],maxScales,minmass, branch->children()[0],type,fc[1]); else spaceLikeDecayShower( children[0],maxScales,minmass,type,fc[1]); } else { if(fb.hard && !branch->children()[0]->children().empty() ) truncatedTimeLikeShower(children[0],branch->children()[0],type,fc[1],false); // normal shower else timeLikeShower(children[0],type,fc[1],false); } } // clean up the vetoed emission if(particle->virtualMass()==ZERO) { particle->showerKinematics(ShoKinPtr()); for(unsigned int ix=0;ix<children.size();++ix) particle->abandonChild(children[ix]); children.clear(); particle->vetoEmission(fb.type,fb.kinematics->scale()); // generate the new emission fb = selectSpaceLikeDecayBranching(particle,maxScales,minmass,type,branch); // must be at least hard emission assert(fb.kinematics); setupChildren = true; continue; } else { updateHistory(children[1]); break; } } else if(_reconOpt>=2) { // cut-off masses for the branching const vector<Energy> & virtualMasses = fb.sudakov->virtualMasses(fb.ids); // compute the masses of the children Energy masses[3]; // space-like children masses[1] = children[0]->virtualMass(); // time-like child if(fc[1].kinematics) { const vector<Energy> & vm = fc[1].sudakov->virtualMasses(fc[1].ids); Energy2 q2 = fc[1].kinematics->z()*(1.-fc[1].kinematics->z())*sqr(fc[1].kinematics->scale()); if(fc[1].ids[0]->id()!=ParticleID::g) q2 += sqr(vm[0]); masses[2] = sqrt(q2); } else { masses[2] = virtualMasses[2]; } masses[0]=particle->virtualMass(); double z = fb.kinematics->z(); Energy2 pt2 = (1.-z)*(z*sqr(masses[0])-sqr(masses[1])-z/(1.-z)*sqr(masses[2])); if(pt2>=ZERO) { break; } else { // reset the scales for the children for(unsigned int ix=0;ix<2;++ix) { if(fc[ix].kinematics) children[ix]->vetoEmission(fc[ix].type,fc[ix].kinematics->scale()); else { if(ix==0) children[ix]->vetoEmission(ShowerPartnerType::QCDColourLine,Constants::MaxEnergy); else children[ix]->vetoEmission(ShowerPartnerType::QCDColourLine,ZERO); } } children[0]->virtualMass(_progenitor->progenitor()->mass()); children[1]->virtualMass(ZERO); } } }; if(_reconOpt>=2) { // update the history if needed currentTree()->updateInitialStateShowerProduct(progenitor(),children[0]); currentTree()->addInitialStateBranching(particle,children[0],children[1]); // shower the first particle if(fc[0].kinematics) { if(children[0]->id()==particle->id()) { if(!fb.hard) truncatedSpaceLikeDecayShower( children[0],maxScales,minmass, branch,type,fc[0]); else if(fb.hard && ! branch->children()[0]->children().empty() ) truncatedSpaceLikeDecayShower( children[0],maxScales,minmass, branch->children()[0],type,fc[0]); else spaceLikeDecayShower( children[0],maxScales,minmass,type,fc[0]); } else { if(fb.hard && !branch->children()[0]->children().empty() ) truncatedTimeLikeShower(children[0],branch->children()[0],type,fc[0],false); // normal shower else timeLikeShower(children[0],type,fc[0],false); } } // shower the second particle if(fc[1].kinematics) { if(children[0]->id()==particle->id()) { if(!fb.hard) truncatedSpaceLikeDecayShower( children[0],maxScales,minmass, branch,type,fc[1]); else if(fb.hard && ! branch->children()[0]->children().empty() ) truncatedSpaceLikeDecayShower( children[0],maxScales,minmass, branch->children()[0],type,fc[1]); else spaceLikeDecayShower( children[0],maxScales,minmass,type,fc[1]); } else { if(fb.hard && !branch->children()[0]->children().empty() ) truncatedTimeLikeShower(children[0],branch->children()[0],type,fc[1],false); // normal shower else timeLikeShower(children[0],type,fc[1],false); } } updateHistory(children[1]); } return true; } void QTildeShowerHandler::connectTrees(ShowerTreePtr showerTree, HardTreePtr hardTree, bool hard ) { ShowerParticleVector particles; // find the Sudakovs for(set<HardBranchingPtr>::iterator cit=hardTree->branchings().begin(); cit!=hardTree->branchings().end();++cit) { // Sudakovs for ISR if((**cit).parent()&&(**cit).status()==HardBranching::Incoming) { ++_nis; vector<long> br(3); br[0] = (**cit).parent()->branchingParticle()->id(); br[1] = (**cit). branchingParticle()->id(); br[2] = (**cit).parent()->children()[0]==*cit ? (**cit).parent()->children()[1]->branchingParticle()->id() : (**cit).parent()->children()[0]->branchingParticle()->id(); BranchingList branchings = splittingGenerator()->initialStateBranchings(); if(br[1]<0&&br[0]==br[1]) { br[0] = abs(br[0]); br[1] = abs(br[1]); } else if(br[1]<0) { br[1] = -br[1]; br[2] = -br[2]; } long index = abs(br[1]); SudakovPtr sudakov; for(BranchingList::const_iterator cjt = branchings.lower_bound(index); cjt != branchings.upper_bound(index); ++cjt ) { IdList ids = cjt->second.particles; if(ids[0]->id()==br[0]&&ids[1]->id()==br[1]&&ids[2]->id()==br[2]) { sudakov=cjt->second.sudakov; break; } } if(!sudakov) throw Exception() << "Can't find Sudakov for the hard emission in " << "QTildeShowerHandler::connectTrees() for ISR" << Exception::runerror; (**cit).parent()->sudakov(sudakov); } // Sudakovs for FSR else if(!(**cit).children().empty()) { ++_nfs; vector<long> br(3); br[0] = (**cit) .branchingParticle()->id(); br[1] = (**cit).children()[0]->branchingParticle()->id(); br[2] = (**cit).children()[1]->branchingParticle()->id(); BranchingList branchings = splittingGenerator()->finalStateBranchings(); if(br[0]<0) { br[0] = abs(br[0]); br[1] = abs(br[1]); br[2] = abs(br[2]); } long index = br[0]; SudakovPtr sudakov; for(BranchingList::const_iterator cjt = branchings.lower_bound(index); cjt != branchings.upper_bound(index); ++cjt ) { IdList ids = cjt->second.particles; if(ids[0]->id()==br[0]&&ids[1]->id()==br[1]&&ids[2]->id()==br[2]) { sudakov=cjt->second.sudakov; break; } } if(!sudakov) { throw Exception() << "Can't find Sudakov for the hard emission in " << "QTildeShowerHandler::connectTrees()" << Exception::runerror; } (**cit).sudakov(sudakov); } } // calculate the evolution scale for(set<HardBranchingPtr>::iterator cit=hardTree->branchings().begin(); cit!=hardTree->branchings().end();++cit) { particles.push_back((*cit)->branchingParticle()); } showerModel()->partnerFinder()-> setInitialEvolutionScales(particles,!hard,interaction_,true); hardTree->partnersSet(true); // inverse reconstruction if(hard) { showerModel()->kinematicsReconstructor()-> deconstructHardJets(hardTree,interaction_); } else showerModel()->kinematicsReconstructor()-> deconstructDecayJets(hardTree,interaction_); // now reset the momenta of the showering particles vector<ShowerProgenitorPtr> particlesToShower=showerTree->extractProgenitors(); // match them map<ShowerProgenitorPtr,HardBranchingPtr> partners; for(set<HardBranchingPtr>::const_iterator bit=hardTree->branchings().begin(); bit!=hardTree->branchings().end();++bit) { Energy2 dmin( 1e30*GeV2 ); ShowerProgenitorPtr partner; for(vector<ShowerProgenitorPtr>::const_iterator pit=particlesToShower.begin(); pit!=particlesToShower.end();++pit) { if(partners.find(*pit)!=partners.end()) continue; if( (**bit).branchingParticle()->id() != (**pit).progenitor()->id() ) continue; if( (**bit).branchingParticle()->isFinalState() != (**pit).progenitor()->isFinalState() ) continue; if( (**pit).progenitor()->isFinalState() ) { Energy2 dtest = sqr( (**pit).progenitor()->momentum().x() - (**bit).showerMomentum().x() ) + sqr( (**pit).progenitor()->momentum().y() - (**bit).showerMomentum().y() ) + sqr( (**pit).progenitor()->momentum().z() - (**bit).showerMomentum().z() ) + sqr( (**pit).progenitor()->momentum().t() - (**bit).showerMomentum().t() ); // add mass difference for identical particles (e.g. Z0 Z0 production) dtest += 1e10*sqr((**pit).progenitor()->momentum().m()-(**bit).showerMomentum().m()); if( dtest < dmin ) { partner = *pit; dmin = dtest; } } else { // ensure directions are right if((**pit).progenitor()->momentum().z()/(**bit).showerMomentum().z()>ZERO) { partner = *pit; break; } } } if(!partner) throw Exception() << "Failed to match shower and hard trees in QTildeShowerHandler::hardestEmission" << Exception::eventerror; partners[partner] = *bit; } for(vector<ShowerProgenitorPtr>::const_iterator pit=particlesToShower.begin(); pit!=particlesToShower.end();++pit) { HardBranchingPtr partner = partners[*pit]; if((**pit).progenitor()->dataPtr()->stable()) { (**pit).progenitor()->set5Momentum(partner->showerMomentum()); (**pit).copy()->set5Momentum(partner->showerMomentum()); } else { Lorentz5Momentum oldMomentum = (**pit).progenitor()->momentum(); Lorentz5Momentum newMomentum = partner->showerMomentum(); LorentzRotation boost( oldMomentum.findBoostToCM(),oldMomentum.e()/oldMomentum.mass()); (**pit).progenitor()->transform(boost); (**pit).copy() ->transform(boost); boost = LorentzRotation(-newMomentum.findBoostToCM(),newMomentum.e()/newMomentum.mass()); (**pit).progenitor()->transform(boost); (**pit).copy() ->transform(boost); } } // correction boosts for daughter trees for(map<tShowerTreePtr,pair<tShowerProgenitorPtr,tShowerParticlePtr> >::const_iterator tit = showerTree->treelinks().begin(); tit != showerTree->treelinks().end();++tit) { ShowerTreePtr decayTree = tit->first; map<ShowerProgenitorPtr,ShowerParticlePtr>::const_iterator cit = decayTree->incomingLines().begin(); // reset the momentum of the decay particle Lorentz5Momentum oldMomentum = cit->first->progenitor()->momentum(); Lorentz5Momentum newMomentum = tit->second.second->momentum(); LorentzRotation boost( oldMomentum.findBoostToCM(),oldMomentum.e()/oldMomentum.mass()); decayTree->transform(boost,true); boost = LorentzRotation(-newMomentum.findBoostToCM(),newMomentum.e()/newMomentum.mass()); decayTree->transform(boost,true); } } void QTildeShowerHandler::doShowering(bool hard,XCPtr xcomb) { // zero number of emissions _nis = _nfs = 0; // if MC@NLO H event and limited emissions // indicate both final and initial state emission if ( currentTree()->isMCatNLOHEvent() && _limitEmissions != 0 ) { _nis = _nfs = 1; } // extract particles to shower vector<ShowerProgenitorPtr> particlesToShower(setupShower(hard)); // check if we should shower bool colCharge = false; for(unsigned int ix=0;ix<particlesToShower.size();++ix) { if(particlesToShower[ix]->progenitor()->dataPtr()->coloured() || particlesToShower[ix]->progenitor()->dataPtr()->charged()) { colCharge = true; break; } } if(!colCharge) { _currenttree->hasShowered(true); return; } // setup the maximum scales for the shower if (restrictPhasespace()) setupMaximumScales(particlesToShower,xcomb); // set the hard scales for the profiles setupHardScales(particlesToShower,xcomb); // specific stuff for hard processes and decays Energy minmass(ZERO), mIn(ZERO); // hard process generate the intrinsic p_T once and for all if(hard) { generateIntrinsicpT(particlesToShower); } // decay compute the minimum mass of the final-state else { for(unsigned int ix=0;ix<particlesToShower.size();++ix) { if(particlesToShower[ix]->progenitor()->isFinalState()) { if(particlesToShower[ix]->progenitor()->dataPtr()->stable()) minmass += particlesToShower[ix]->progenitor()->dataPtr()->constituentMass(); else minmass += particlesToShower[ix]->progenitor()->mass(); } else { mIn = particlesToShower[ix]->progenitor()->mass(); } } // throw exception if decay can't happen if ( minmass > mIn ) { throw Exception() << "QTildeShowerHandler.cc: Mass of decaying particle is " << "below constituent masses of decay products." << Exception::eventerror; } } // setup for reweighted bool reWeighting = _reWeight && hard && ShowerHandler::currentHandler()->firstInteraction(); double eventWeight=0.; unsigned int nTryReWeight(0); // create random particle vector (only need to do once) vector<ShowerProgenitorPtr> tmp; unsigned int nColouredIncoming = 0; while(particlesToShower.size()>0){ unsigned int xx=UseRandom::irnd(particlesToShower.size()); tmp.push_back(particlesToShower[xx]); particlesToShower.erase(particlesToShower.begin()+xx); } particlesToShower=tmp; for(unsigned int ix=0;ix<particlesToShower.size();++ix) { if(!particlesToShower[ix]->progenitor()->isFinalState() && particlesToShower[ix]->progenitor()->coloured()) ++nColouredIncoming; } bool switchRecon = hard && nColouredIncoming !=1; // main shower loop unsigned int ntry(0); bool reconstructed = false; do { // clear results of last attempt if needed if(ntry!=0) { currentTree()->clear(); setEvolutionPartners(hard,interaction_,true); _nis = _nfs = 0; // if MC@NLO H event and limited emissions // indicate both final and initial state emission if ( currentTree()->isMCatNLOHEvent() && _limitEmissions != 0 ) { _nis = _nfs = 1; } for(unsigned int ix=0; ix<particlesToShower.size();++ix) { SpinPtr spin = particlesToShower[ix]->progenitor()->spinInfo(); if(spin && spin->decayVertex() && dynamic_ptr_cast<tcSVertexPtr>(spin->decayVertex())) { spin->decayVertex(VertexPtr()); } } } // loop over particles for(unsigned int ix=0;ix<particlesToShower.size();++ix) { // extract the progenitor progenitor(particlesToShower[ix]); // final-state radiation if(progenitor()->progenitor()->isFinalState()) { if(!doFSR()) continue; // perform shower progenitor()->hasEmitted(startTimeLikeShower(interaction_)); } // initial-state radiation else { if(!doISR()) continue; // hard process if(hard) { // get the PDF setBeamParticle(_progenitor->beam()); assert(beamParticle()); // perform the shower // set the beam particle tPPtr beamparticle=progenitor()->original(); if(!beamparticle->parents().empty()) beamparticle=beamparticle->parents()[0]; // generate the shower progenitor()->hasEmitted(startSpaceLikeShower(beamparticle, interaction_)); } // decay else { // skip colour and electrically neutral particles if(!progenitor()->progenitor()->dataPtr()->coloured() && !progenitor()->progenitor()->dataPtr()->charged()) { progenitor()->hasEmitted(false); continue; } // perform shower // set the scales correctly. The current scale is the maximum scale for // emission not the starting scale ShowerParticle::EvolutionScales maxScales(progenitor()->progenitor()->scales()); progenitor()->progenitor()->scales() = ShowerParticle::EvolutionScales(); if(progenitor()->progenitor()->dataPtr()->charged()) { progenitor()->progenitor()->scales().QED = progenitor()->progenitor()->mass(); progenitor()->progenitor()->scales().QED_noAO = progenitor()->progenitor()->mass(); } if(progenitor()->progenitor()->hasColour()) { progenitor()->progenitor()->scales().QCD_c = progenitor()->progenitor()->mass(); progenitor()->progenitor()->scales().QCD_c_noAO = progenitor()->progenitor()->mass(); } if(progenitor()->progenitor()->hasAntiColour()) { progenitor()->progenitor()->scales().QCD_ac = progenitor()->progenitor()->mass(); progenitor()->progenitor()->scales().QCD_ac_noAO = progenitor()->progenitor()->mass(); } // perform the shower progenitor()->hasEmitted(startSpaceLikeDecayShower(maxScales,minmass, interaction_)); } } } // do the kinematic reconstruction, checking if it worked reconstructed = hard ? showerModel()->kinematicsReconstructor()-> reconstructHardJets (currentTree(),intrinsicpT(),interaction_, switchRecon && ntry>maximumTries()/2) : showerModel()->kinematicsReconstructor()-> reconstructDecayJets(currentTree(),interaction_); if(!reconstructed) continue; // apply vetos on the full shower for(vector<FullShowerVetoPtr>::const_iterator it=_fullShowerVetoes.begin(); it!=_fullShowerVetoes.end();++it) { int veto = (**it).applyVeto(currentTree()); if(veto<0) continue; // veto the shower if(veto==0) { reconstructed = false; break; } // veto the shower and reweight else if(veto==1) { reconstructed = false; break; } // veto the event else if(veto==2) { throw Veto(); } } if(reWeighting) { if(reconstructed) eventWeight += 1.; reconstructed=false; ++nTryReWeight; if(nTryReWeight==_nReWeight) { reWeighting = false; if(eventWeight==0.) throw Veto(); } } } while(!reconstructed&&maximumTries()>++ntry); // check if failed to generate the shower if(ntry==maximumTries()) { if(hard) throw ShowerHandler::ShowerTriesVeto(ntry); else throw Exception() << "Failed to generate the shower after " << ntry << " attempts in QTildeShowerHandler::showerDecay()" << Exception::eventerror; } // handle the weights and apply any reweighting required if(nTryReWeight>0) { tStdEHPtr seh = dynamic_ptr_cast<tStdEHPtr>(generator()->currentEventHandler()); static bool first = true; if(seh) { seh->reweight(eventWeight/double(nTryReWeight)); } else if(first) { generator()->log() << "Reweighting the shower only works with internal Herwig7 processes" << "Presumably you are showering Les Houches Events. These will not be" << "reweighted\n"; first = false; } } // tree has now showered _currenttree->hasShowered(true); hardTree(HardTreePtr()); } void QTildeShowerHandler:: convertHardTree(bool hard,ShowerInteraction type) { map<ColinePtr,ColinePtr> cmap; // incoming particles for(map<ShowerProgenitorPtr,ShowerParticlePtr>::const_iterator cit=currentTree()->incomingLines().begin();cit!=currentTree()->incomingLines().end();++cit) { map<ShowerParticlePtr,tHardBranchingPtr>::const_iterator mit = hardTree()->particles().find(cit->first->progenitor()); // put the colour lines in the map ShowerParticlePtr oldParticle = cit->first->progenitor(); ShowerParticlePtr newParticle = mit->second->branchingParticle(); ColinePtr cLine = oldParticle-> colourLine(); ColinePtr aLine = oldParticle->antiColourLine(); if(newParticle->colourLine() && cmap.find(newParticle-> colourLine())==cmap.end()) cmap[newParticle-> colourLine()] = cLine; if(newParticle->antiColourLine() && cmap.find(newParticle->antiColourLine())==cmap.end()) cmap[newParticle->antiColourLine()] = aLine; // check whether or not particle emits bool emission = mit->second->parent(); if(emission) { if(newParticle->colourLine()) { ColinePtr ctemp = newParticle-> colourLine(); ctemp->removeColoured(newParticle); } if(newParticle->antiColourLine()) { ColinePtr ctemp = newParticle->antiColourLine(); ctemp->removeAntiColoured(newParticle); } newParticle = mit->second->parent()->branchingParticle(); } // get the new colour lines ColinePtr newCLine,newALine; // sort out colour lines if(newParticle->colourLine()) { ColinePtr ctemp = newParticle-> colourLine(); ctemp->removeColoured(newParticle); if(cmap.find(ctemp)!=cmap.end()) { newCLine = cmap[ctemp]; } else { newCLine = new_ptr(ColourLine()); cmap[ctemp] = newCLine; } } // and anticolour lines if(newParticle->antiColourLine()) { ColinePtr ctemp = newParticle->antiColourLine(); ctemp->removeAntiColoured(newParticle); if(cmap.find(ctemp)!=cmap.end()) { newALine = cmap[ctemp]; } else { newALine = new_ptr(ColourLine()); cmap[ctemp] = newALine; } } // remove colour lines from old particle if(aLine) { aLine->removeAntiColoured(cit->first->copy()); aLine->removeAntiColoured(cit->first->progenitor()); } if(cLine) { cLine->removeColoured(cit->first->copy()); cLine->removeColoured(cit->first->progenitor()); } // add particle to colour lines if(newCLine) newCLine->addColoured (newParticle); if(newALine) newALine->addAntiColoured(newParticle); // insert new particles cit->first->copy(newParticle); ShowerParticlePtr sp(new_ptr(ShowerParticle(*newParticle,1,false))); cit->first->progenitor(sp); currentTree()->incomingLines()[cit->first]=sp; cit->first->perturbative(!emission); // and the emitted particle if needed if(emission) { ShowerParticlePtr newOut = mit->second->parent()->children()[1]->branchingParticle(); if(newOut->colourLine()) { ColinePtr ctemp = newOut-> colourLine(); ctemp->removeColoured(newOut); assert(cmap.find(ctemp)!=cmap.end()); cmap[ctemp]->addColoured (newOut); } if(newOut->antiColourLine()) { ColinePtr ctemp = newOut->antiColourLine(); ctemp->removeAntiColoured(newOut); assert(cmap.find(ctemp)!=cmap.end()); cmap[ctemp]->addAntiColoured(newOut); } ShowerParticlePtr sout=new_ptr(ShowerParticle(*newOut,1,true)); ShowerProgenitorPtr out=new_ptr(ShowerProgenitor(cit->first->original(),newOut,sout)); out->perturbative(false); currentTree()->outgoingLines().insert(make_pair(out,sout)); } if(hard) { // sort out the value of x if(mit->second->beam()->momentum().z()>ZERO) { sp->x(newParticle->momentum(). plus()/mit->second->beam()->momentum(). plus()); } else { sp->x(newParticle->momentum().minus()/mit->second->beam()->momentum().minus()); } } } // outgoing particles for(map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator cit=currentTree()->outgoingLines().begin();cit!=currentTree()->outgoingLines().end();++cit) { map<tShowerTreePtr,pair<tShowerProgenitorPtr, tShowerParticlePtr> >::const_iterator tit; for(tit = currentTree()->treelinks().begin(); tit != currentTree()->treelinks().end();++tit) { if(tit->second.first && tit->second.second==cit->first->progenitor()) break; } map<ShowerParticlePtr,tHardBranchingPtr>::const_iterator mit = hardTree()->particles().find(cit->first->progenitor()); if(mit==hardTree()->particles().end()) continue; // put the colour lines in the map ShowerParticlePtr oldParticle = cit->first->progenitor(); ShowerParticlePtr newParticle = mit->second->branchingParticle(); ShowerParticlePtr newOut; ColinePtr cLine = oldParticle-> colourLine(); ColinePtr aLine = oldParticle->antiColourLine(); if(newParticle->colourLine() && cmap.find(newParticle-> colourLine())==cmap.end()) cmap[newParticle-> colourLine()] = cLine; if(newParticle->antiColourLine() && cmap.find(newParticle->antiColourLine())==cmap.end()) cmap[newParticle->antiColourLine()] = aLine; // check whether or not particle emits bool emission = !mit->second->children().empty(); if(emission) { if(newParticle->colourLine()) { ColinePtr ctemp = newParticle-> colourLine(); ctemp->removeColoured(newParticle); } if(newParticle->antiColourLine()) { ColinePtr ctemp = newParticle->antiColourLine(); ctemp->removeAntiColoured(newParticle); } newParticle = mit->second->children()[0]->branchingParticle(); newOut = mit->second->children()[1]->branchingParticle(); if(newParticle->id()!=oldParticle->id()&&newParticle->id()==newOut->id()) swap(newParticle,newOut); } // get the new colour lines ColinePtr newCLine,newALine; // sort out colour lines if(newParticle->colourLine()) { ColinePtr ctemp = newParticle-> colourLine(); ctemp->removeColoured(newParticle); if(cmap.find(ctemp)!=cmap.end()) { newCLine = cmap[ctemp]; } else { newCLine = new_ptr(ColourLine()); cmap[ctemp] = newCLine; } } // and anticolour lines if(newParticle->antiColourLine()) { ColinePtr ctemp = newParticle->antiColourLine(); ctemp->removeAntiColoured(newParticle); if(cmap.find(ctemp)!=cmap.end()) { newALine = cmap[ctemp]; } else { newALine = new_ptr(ColourLine()); cmap[ctemp] = newALine; } } // remove colour lines from old particle if(aLine) { aLine->removeAntiColoured(cit->first->copy()); aLine->removeAntiColoured(cit->first->progenitor()); } if(cLine) { cLine->removeColoured(cit->first->copy()); cLine->removeColoured(cit->first->progenitor()); } // special for unstable particles if(newParticle->id()==oldParticle->id() && (tit!=currentTree()->treelinks().end()||!oldParticle->dataPtr()->stable())) { Lorentz5Momentum oldMomentum = oldParticle->momentum(); Lorentz5Momentum newMomentum = newParticle->momentum(); LorentzRotation boost( oldMomentum.findBoostToCM(),oldMomentum.e()/oldMomentum.mass()); if(tit!=currentTree()->treelinks().end()) tit->first->transform(boost,false); oldParticle->transform(boost); boost = LorentzRotation(-newMomentum.findBoostToCM(),newMomentum.e()/newMomentum.mass()); oldParticle->transform(boost); if(tit!=currentTree()->treelinks().end()) tit->first->transform(boost,false); newParticle=oldParticle; } // add particle to colour lines if(newCLine) newCLine->addColoured (newParticle); if(newALine) newALine->addAntiColoured(newParticle); // insert new particles cit->first->copy(newParticle); ShowerParticlePtr sp(new_ptr(ShowerParticle(*newParticle,1,true))); cit->first->progenitor(sp); currentTree()->outgoingLines()[cit->first]=sp; cit->first->perturbative(!emission); // and the emitted particle if needed if(emission) { if(newOut->colourLine()) { ColinePtr ctemp = newOut-> colourLine(); ctemp->removeColoured(newOut); assert(cmap.find(ctemp)!=cmap.end()); cmap[ctemp]->addColoured (newOut); } if(newOut->antiColourLine()) { ColinePtr ctemp = newOut->antiColourLine(); ctemp->removeAntiColoured(newOut); assert(cmap.find(ctemp)!=cmap.end()); cmap[ctemp]->addAntiColoured(newOut); } ShowerParticlePtr sout=new_ptr(ShowerParticle(*newOut,1,true)); ShowerProgenitorPtr out=new_ptr(ShowerProgenitor(cit->first->original(),newOut,sout)); out->perturbative(false); currentTree()->outgoingLines().insert(make_pair(out,sout)); } // update any decay products if(tit!=currentTree()->treelinks().end()) currentTree()->updateLink(tit->first,make_pair(cit->first,sp)); } // reset the tree currentTree()->resetShowerProducts(); // reextract the particles and set the colour partners vector<ShowerParticlePtr> particles = currentTree()->extractProgenitorParticles(); // clear the partners for(unsigned int ix=0;ix<particles.size();++ix) { particles[ix]->partner(ShowerParticlePtr()); particles[ix]->clearPartners(); } // clear the tree hardTree(HardTreePtr()); // Set the initial evolution scales showerModel()->partnerFinder()-> setInitialEvolutionScales(particles,!hard,type,!_hardtree); } Branching QTildeShowerHandler::selectTimeLikeBranching(tShowerParticlePtr particle, ShowerInteraction type, HardBranchingPtr branch) { Branching fb; unsigned int iout=0; while (true) { // break if doing truncated shower and no truncated shower needed if(branch && (!isTruncatedShowerON()||hardOnly())) break; fb=_splittingGenerator->chooseForwardBranching(*particle,_finalenhance,type); // no emission break if(!fb.kinematics) break; // special for truncated shower if(branch) { // check haven't evolved too far if(fb.kinematics->scale() < branch->scale()) { fb=Branching(); break; } // find the truncated line iout=0; if(fb.ids[1]->id()!=fb.ids[2]->id()) { if(fb.ids[1]->id()==particle->id()) iout=1; else if (fb.ids[2]->id()==particle->id()) iout=2; } else if(fb.ids[1]->id()==particle->id()) { if(fb.kinematics->z()>0.5) iout=1; else iout=2; } // apply the vetos for the truncated shower // no flavour changing branchings if(iout==0) { particle->vetoEmission(fb.type,fb.kinematics->scale()); continue; } double zsplit = iout==1 ? fb.kinematics->z() : 1-fb.kinematics->z(); // only if same interaction for forced branching ShowerInteraction type2 = convertInteraction(fb.type); // and evolution if(type2==branch->sudakov()->interactionType()) { if(zsplit < 0.5 || // hardest line veto fb.kinematics->scale()*zsplit < branch->scale() ) { // angular ordering veto particle->vetoEmission(fb.type,fb.kinematics->scale()); continue; } } // pt veto if(fb.kinematics->pT() > progenitor()->maximumpT(type2)) { particle->vetoEmission(fb.type,fb.kinematics->scale()); continue; } } // standard vetos for all emissions if(timeLikeVetoed(fb,particle)) { particle->vetoEmission(fb.type,fb.kinematics->scale()); if(particle->spinInfo()) particle->spinInfo()->decayVertex(VertexPtr()); continue; } // special for already decayed particles // don't allow flavour changing branchings bool vetoDecay = false; for(map<tShowerTreePtr,pair<tShowerProgenitorPtr, tShowerParticlePtr> >::const_iterator tit = currentTree()->treelinks().begin(); tit != currentTree()->treelinks().end();++tit) { if(tit->second.first == progenitor()) { map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator it = currentTree()->outgoingLines().find(progenitor()); if(it!=currentTree()->outgoingLines().end() && particle == it->second && fb.ids[0]!=fb.ids[1] && fb.ids[1]!=fb.ids[2]) { vetoDecay = true; break; } } } if(vetoDecay) { particle->vetoEmission(fb.type,fb.kinematics->scale()); if(particle->spinInfo()) particle->spinInfo()->decayVertex(VertexPtr()); continue; } break; } // normal case if(!branch) { if(fb.kinematics) fb.hard = false; return fb; } // truncated emission if(fb.kinematics) { fb.hard = false; fb.iout = iout; return fb; } // otherwise need to return the hard emission // construct the kinematics for the hard emission ShoKinPtr showerKin= branch->sudakov()->createFinalStateBranching(branch->scale(), branch->children()[0]->z(), branch->phi(), branch->children()[0]->pT()); IdList idlist(3); idlist[0] = particle->dataPtr(); idlist[1] = branch->children()[0]->branchingParticle()->dataPtr(); idlist[2] = branch->children()[1]->branchingParticle()->dataPtr(); fb = Branching( showerKin, idlist, branch->sudakov(),branch->type() ); fb.hard = true; fb.iout=0; // return it return fb; } Branching QTildeShowerHandler::selectSpaceLikeDecayBranching(tShowerParticlePtr particle, const ShowerParticle::EvolutionScales & maxScales, Energy minmass,ShowerInteraction type, HardBranchingPtr branch) { Branching fb; unsigned int iout=0; while (true) { // break if doing truncated shower and no truncated shower needed if(branch && (!isTruncatedShowerON()||hardOnly())) break; // select branching fb=_splittingGenerator->chooseDecayBranching(*particle,maxScales,minmass, _initialenhance,type); // return if no radiation if(!fb.kinematics) break; // special for truncated shower if(branch) { // check haven't evolved too far if(fb.kinematics->scale() < branch->scale()) { fb=Branching(); break; } // find the truncated line iout=0; if(fb.ids[1]->id()!=fb.ids[2]->id()) { if(fb.ids[1]->id()==particle->id()) iout=1; else if (fb.ids[2]->id()==particle->id()) iout=2; } else if(fb.ids[1]->id()==particle->id()) { if(fb.kinematics->z()>0.5) iout=1; else iout=2; } // apply the vetos for the truncated shower // no flavour changing branchings if(iout==0) { particle->vetoEmission(fb.type,fb.kinematics->scale()); continue; } ShowerInteraction type2 = convertInteraction(fb.type); double zsplit = iout==1 ? fb.kinematics->z() : 1-fb.kinematics->z(); if(type2==branch->sudakov()->interactionType()) { if(zsplit < 0.5 || // hardest line veto fb.kinematics->scale()*zsplit < branch->scale() ) { // angular ordering veto particle->vetoEmission(fb.type,fb.kinematics->scale()); continue; } } // pt veto if(fb.kinematics->pT() > progenitor()->maximumpT(type2)) { particle->vetoEmission(fb.type,fb.kinematics->scale()); continue; } } // if not vetoed break if(spaceLikeDecayVetoed(fb,particle)) { // otherwise reset scale and continue particle->vetoEmission(fb.type,fb.kinematics->scale()); continue; } break; } // normal case if(!branch) { if(fb.kinematics) fb.hard = false; return fb; } // truncated emission if(fb.kinematics) { fb.hard = false; fb.iout = iout; return fb; } // otherwise need to return the hard emission // construct the kinematics for the hard emission ShoKinPtr showerKin= branch->sudakov()->createDecayBranching(branch->scale(), branch->children()[0]->z(), branch->phi(), branch->children()[0]->pT()); IdList idlist(3); idlist[0] = particle->dataPtr(); idlist[1] = branch->children()[0]->branchingParticle()->dataPtr(); idlist[2] = branch->children()[1]->branchingParticle()->dataPtr(); // create the branching fb = Branching( showerKin, idlist, branch->sudakov(),ShowerPartnerType::QCDColourLine ); fb.hard=true; fb.iout=0; // return it return fb; } void QTildeShowerHandler::checkFlags() { string error = "Inconsistent hard emission set-up in QTildeShowerHandler::showerHardProcess(). "; if ( ( currentTree()->isMCatNLOSEvent() || currentTree()->isMCatNLOHEvent() ) ) { if (_hardEmission ==2 ) throw Exception() << error << "Cannot generate POWHEG matching with MC@NLO shower " << "approximation. Add 'set QTildeShowerHandler:HardEmission 0' to input file." << Exception::runerror; if ( canHandleMatchboxTrunc() ) throw Exception() << error << "Cannot use truncated qtilde shower with MC@NLO shower " << "approximation. Set LHCGenerator:EventHandler" << ":CascadeHandler to '/Herwig/Shower/ShowerHandler' or " << "'/Herwig/Shower/Dipole/DipoleShowerHandler'." << Exception::runerror; } else if ( ((currentTree()->isPowhegSEvent() || currentTree()->isPowhegHEvent()) ) && _hardEmission != 2){ if ( canHandleMatchboxTrunc()) throw Exception() << error << "Unmatched events requested for POWHEG shower " << "approximation. Set QTildeShowerHandler:HardEmission to " << "'POWHEG'." << Exception::runerror; else if (_hardEmissionWarn) { _hardEmissionWarn = false; _hardEmission=2; throw Exception() << error << "Unmatched events requested for POWHEG shower " << "approximation. Changing QTildeShowerHandler:HardEmission from " << _hardEmission << " to 2" << Exception::warning; } } if ( currentTree()->isPowhegSEvent() || currentTree()->isPowhegHEvent()) { if (currentTree()->showerApproximation()->needsTruncatedShower() && !canHandleMatchboxTrunc() ) throw Exception() << error << "Current shower handler cannot generate truncated shower. " << "Set Generator:EventHandler:CascadeHandler to " << "'/Herwig/Shower/PowhegShowerHandler'." << Exception::runerror; } else if ( currentTree()->truncatedShower() && _missingTruncWarn) { _missingTruncWarn=false; throw Exception() << "Warning: POWHEG shower approximation used without " << "truncated shower. Set Generator:EventHandler:" << "CascadeHandler to '/Herwig/Shower/PowhegShowerHandler' and " << "'MEMatching:TruncatedShower Yes'." << Exception::warning; } // else if ( !dipme && _hardEmissionMode > 1 && // firstInteraction()) // throw Exception() << error // << "POWHEG matching requested for LO events. Include " // << "'set Factory:ShowerApproximation MEMatching' in input file." // << Exception::runerror; } tPPair QTildeShowerHandler::remakeRemnant(tPPair oldp){ // get the parton extractor PartonExtractor & pex = *lastExtractor(); // get the new partons tPPair newp = make_pair(findFirstParton(oldp.first ), findFirstParton(oldp.second)); // if the same do nothing if(newp == oldp) return oldp; // Creates the new remnants and returns the new PartonBinInstances // ATTENTION Broken here for very strange configuration PBIPair newbins = pex.newRemnants(oldp, newp, newStep()); newStep()->addIntermediate(newp.first); newStep()->addIntermediate(newp.second); // return the new partons return newp; } PPtr QTildeShowerHandler::findFirstParton(tPPtr seed) const{ if(seed->parents().empty()) return seed; tPPtr parent = seed->parents()[0]; //if no parent there this is a loose end which will //be connected to the remnant soon. if(!parent || parent == incomingBeams().first || parent == incomingBeams().second ) return seed; else return findFirstParton(parent); } void QTildeShowerHandler::decay(ShowerTreePtr tree, ShowerDecayMap & decay) { // must be one incoming particle assert(tree->incomingLines().size()==1); // apply any transforms tree->applyTransforms(); // if already decayed return if(!tree->outgoingLines().empty()) return; // now we need to replace the particle with a new copy after the shower // find particle after the shower map<tShowerTreePtr,pair<tShowerProgenitorPtr,tShowerParticlePtr> >::const_iterator tit = tree->parent()->treelinks().find(tree); assert(tit!=tree->parent()->treelinks().end()); ShowerParticlePtr newparent=tit->second.second; PerturbativeProcessPtr newProcess = new_ptr(PerturbativeProcess()); newProcess->incoming().push_back(make_pair(newparent,PerturbativeProcessPtr())); DecayProcessMap decayMap; ShowerHandler::decay(newProcess,decayMap); ShowerTree::constructTrees(tree,decay,newProcess,decayMap); } namespace { ShowerProgenitorPtr findFinalStateLine(ShowerTreePtr tree, long id, Lorentz5Momentum momentum) { map<ShowerProgenitorPtr,tShowerParticlePtr>::iterator partner; Energy2 dmin(1e30*GeV2); for(map<ShowerProgenitorPtr,tShowerParticlePtr>::iterator cit =tree->outgoingLines().begin(); cit!=tree->outgoingLines().end(); ++cit) { if(cit->second->id()!=id) continue; Energy2 test = sqr(cit->second->momentum().x()-momentum.x())+ sqr(cit->second->momentum().y()-momentum.y())+ sqr(cit->second->momentum().z()-momentum.z())+ sqr(cit->second->momentum().t()-momentum.t()); if(test<dmin) { dmin = test; partner = cit; } } return partner->first; } ShowerProgenitorPtr findInitialStateLine(ShowerTreePtr tree, long id, Lorentz5Momentum momentum) { map<ShowerProgenitorPtr,ShowerParticlePtr>::iterator partner; Energy2 dmin(1e30*GeV2); for(map<ShowerProgenitorPtr,ShowerParticlePtr>::iterator cit =tree->incomingLines().begin(); cit!=tree->incomingLines().end(); ++cit) { if(cit->second->id()!=id) continue; Energy2 test = sqr(cit->second->momentum().x()-momentum.x())+ sqr(cit->second->momentum().y()-momentum.y())+ sqr(cit->second->momentum().z()-momentum.z())+ sqr(cit->second->momentum().t()-momentum.t()); if(test<dmin) { dmin = test; partner = cit; } } return partner->first; } void fixSpectatorColours(PPtr newSpect,ShowerProgenitorPtr oldSpect, ColinePair & cline,ColinePair & aline, bool reconnect) { cline.first = oldSpect->progenitor()->colourLine(); cline.second = newSpect->colourLine(); aline.first = oldSpect->progenitor()->antiColourLine(); aline.second = newSpect->antiColourLine(); if(!reconnect) return; if(cline.first) { cline.first ->removeColoured(oldSpect->copy()); cline.first ->removeColoured(oldSpect->progenitor()); cline.second->removeColoured(newSpect); cline.first ->addColoured(newSpect); } if(aline.first) { aline.first ->removeAntiColoured(oldSpect->copy()); aline.first ->removeAntiColoured(oldSpect->progenitor()); aline.second->removeAntiColoured(newSpect); aline.first ->addAntiColoured(newSpect); } } void fixInitialStateEmitter(ShowerTreePtr tree, PPtr newEmit,PPtr emitted, ShowerProgenitorPtr emitter, ColinePair cline,ColinePair aline,double x) { // sort out the colours if(emitted->dataPtr()->iColour()==PDT::Colour8) { // emitter if(cline.first && cline.first == emitter->progenitor()->antiColourLine() && cline.second !=newEmit->antiColourLine()) { // sort out not radiating line ColinePtr col = emitter->progenitor()->colourLine(); if(col) { col->removeColoured(emitter->copy()); col->removeColoured(emitter->progenitor()); newEmit->colourLine()->removeColoured(newEmit); col->addColoured(newEmit); } } else if(aline.first && aline.first == emitter->progenitor()->colourLine() && aline.second !=newEmit->colourLine()) { // sort out not radiating line ColinePtr anti = emitter->progenitor()->antiColourLine(); if(anti) { anti->removeAntiColoured(emitter->copy()); anti->removeAntiColoured(emitter->progenitor()); newEmit->colourLine()->removeAntiColoured(newEmit); anti->addAntiColoured(newEmit); } } else assert(false); // emitted if(cline.first && cline.second==emitted->colourLine()) { cline.second->removeColoured(emitted); cline.first->addColoured(emitted); } else if(aline.first && aline.second==emitted->antiColourLine()) { aline.second->removeAntiColoured(emitted); aline.first->addAntiColoured(emitted); } else assert(false); } else { if(emitter->progenitor()->antiColourLine() ) { ColinePtr col = emitter->progenitor()->antiColourLine(); col->removeAntiColoured(emitter->copy()); col->removeAntiColoured(emitter->progenitor()); if(newEmit->antiColourLine()) { newEmit->antiColourLine()->removeAntiColoured(newEmit); col->addAntiColoured(newEmit); } else if (emitted->colourLine()) { emitted->colourLine()->removeColoured(emitted); col->addColoured(emitted); } else assert(false); } if(emitter->progenitor()->colourLine() ) { ColinePtr col = emitter->progenitor()->colourLine(); col->removeColoured(emitter->copy()); col->removeColoured(emitter->progenitor()); if(newEmit->colourLine()) { newEmit->colourLine()->removeColoured(newEmit); col->addColoured(newEmit); } else if (emitted->antiColourLine()) { emitted->antiColourLine()->removeAntiColoured(emitted); col->addAntiColoured(emitted); } else assert(false); } } // update the emitter emitter->copy(newEmit); ShowerParticlePtr sp = new_ptr(ShowerParticle(*newEmit,1,false)); sp->x(x); emitter->progenitor(sp); tree->incomingLines()[emitter]=sp; emitter->perturbative(false); // add emitted sp=new_ptr(ShowerParticle(*emitted,1,true)); ShowerProgenitorPtr gluon=new_ptr(ShowerProgenitor(emitter->original(),emitted,sp)); gluon->perturbative(false); tree->outgoingLines().insert(make_pair(gluon,sp)); } void fixFinalStateEmitter(ShowerTreePtr tree, PPtr newEmit,PPtr emitted, ShowerProgenitorPtr emitter, ColinePair cline,ColinePair aline) { map<tShowerTreePtr,pair<tShowerProgenitorPtr,tShowerParticlePtr> >::const_iterator tit; // special case if decayed for(tit = tree->treelinks().begin(); tit != tree->treelinks().end();++tit) { if(tit->second.first && tit->second.second==emitter->progenitor()) break; } // sort out the colour lines if(cline.first && cline.first == emitter->progenitor()->antiColourLine() && cline.second !=newEmit->antiColourLine()) { // sort out not radiating line ColinePtr col = emitter->progenitor()->colourLine(); if(col) { col->removeColoured(emitter->copy()); col->removeColoured(emitter->progenitor()); newEmit->colourLine()->removeColoured(newEmit); col->addColoured(newEmit); } } else if(aline.first && aline.first == emitter->progenitor()->colourLine() && aline.second !=newEmit->colourLine()) { // sort out not radiating line ColinePtr anti = emitter->progenitor()->antiColourLine(); if(anti) { anti->removeAntiColoured(emitter->copy()); anti->removeAntiColoured(emitter->progenitor()); newEmit->colourLine()->removeAntiColoured(newEmit); anti->addAntiColoured(newEmit); } } else assert(false); // update the emitter emitter->copy(newEmit); ShowerParticlePtr sp = new_ptr(ShowerParticle(*newEmit,1,true)); emitter->progenitor(sp); tree->outgoingLines()[emitter]=sp; emitter->perturbative(false); // update for decaying particles if(tit!=tree->treelinks().end()) tree->updateLink(tit->first,make_pair(emitter,sp)); // add the emitted particle // sort out the colour if(cline.first && cline.second==emitted->antiColourLine()) { cline.second->removeAntiColoured(emitted); cline.first->addAntiColoured(emitted); } else if(aline.first && aline.second==emitted->colourLine()) { aline.second->removeColoured(emitted); aline.first->addColoured(emitted); } else assert(false); sp=new_ptr(ShowerParticle(*emitted,1,true)); ShowerProgenitorPtr gluon=new_ptr(ShowerProgenitor(emitter->original(), emitted,sp)); gluon->perturbative(false); tree->outgoingLines().insert(make_pair(gluon,sp)); } } void QTildeShowerHandler::setupMECorrection(RealEmissionProcessPtr real) { assert(real); currentTree()->hardMatrixElementCorrection(true); // II emission if(real->emitter() < real->incoming().size() && real->spectator() < real->incoming().size()) { // recoiling system for( map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator cjt= currentTree()->outgoingLines().begin(); cjt != currentTree()->outgoingLines().end();++cjt ) { cjt->first->progenitor()->transform(real->transformation()); cjt->first->copy()->transform(real->transformation()); } // the the radiating system ShowerProgenitorPtr emitter,spectator; unsigned int iemit = real->emitter(); unsigned int ispect = real->spectator(); int ig = int(real->emitted())-int(real->incoming().size()); emitter = findInitialStateLine(currentTree(), real->bornIncoming()[iemit]->id(), real->bornIncoming()[iemit]->momentum()); spectator = findInitialStateLine(currentTree(), real->bornIncoming()[ispect]->id(), real->bornIncoming()[ispect]->momentum()); // sort out the colours ColinePair cline,aline; fixSpectatorColours(real->incoming()[ispect],spectator,cline,aline,true); // update the spectator spectator->copy(real->incoming()[ispect]); ShowerParticlePtr sp(new_ptr(ShowerParticle(*real->incoming()[ispect],1,false))); sp->x(ispect ==0 ? real->x().first :real->x().second); spectator->progenitor(sp); currentTree()->incomingLines()[spectator]=sp; spectator->perturbative(true); // now for the emitter fixInitialStateEmitter(currentTree(),real->incoming()[iemit],real->outgoing()[ig], emitter,cline,aline,iemit ==0 ? real->x().first :real->x().second); } // FF emission else if(real->emitter() >= real->incoming().size() && real->spectator() >= real->incoming().size()) { assert(real->outgoing()[real->emitted()-real->incoming().size()]->id()==ParticleID::g); // find the emitter and spectator in the shower tree ShowerProgenitorPtr emitter,spectator; int iemit = int(real->emitter())-int(real->incoming().size()); emitter = findFinalStateLine(currentTree(), real->bornOutgoing()[iemit]->id(), real->bornOutgoing()[iemit]->momentum()); int ispect = int(real->spectator())-int(real->incoming().size()); spectator = findFinalStateLine(currentTree(), real->bornOutgoing()[ispect]->id(), real->bornOutgoing()[ispect]->momentum()); map<tShowerTreePtr,pair<tShowerProgenitorPtr,tShowerParticlePtr> >::const_iterator tit; // first the spectator // special case if decayed for(tit = currentTree()->treelinks().begin(); tit != currentTree()->treelinks().end();++tit) { if(tit->second.first && tit->second.second==spectator->progenitor()) break; } // sort out the colours ColinePair cline,aline; fixSpectatorColours(real->outgoing()[ispect],spectator,cline,aline,true); // update the spectator spectator->copy(real->outgoing()[ispect]); ShowerParticlePtr sp(new_ptr(ShowerParticle(*real->outgoing()[ispect],1,true))); spectator->progenitor(sp); currentTree()->outgoingLines()[spectator]=sp; spectator->perturbative(true); // update for decaying particles if(tit!=currentTree()->treelinks().end()) currentTree()->updateLink(tit->first,make_pair(spectator,sp)); // now the emitting particle int ig = int(real->emitted())-int(real->incoming().size()); fixFinalStateEmitter(currentTree(),real->outgoing()[iemit], real->outgoing()[ig], emitter,cline,aline); } // IF emission else { // scattering process if(real->incoming().size()==2) { ShowerProgenitorPtr emitter,spectator; unsigned int iemit = real->emitter(); unsigned int ispect = real->spectator(); int ig = int(real->emitted())-int(real->incoming().size()); ColinePair cline,aline; // incoming spectator if(ispect<2) { spectator = findInitialStateLine(currentTree(), real->bornIncoming()[ispect]->id(), real->bornIncoming()[ispect]->momentum()); fixSpectatorColours(real->incoming()[ispect],spectator,cline,aline,true); // update the spectator spectator->copy(real->incoming()[ispect]); ShowerParticlePtr sp(new_ptr(ShowerParticle(*real->incoming()[ispect],1,false))); sp->x(ispect ==0 ? real->x().first :real->x().second); spectator->progenitor(sp); currentTree()->incomingLines()[spectator]=sp; spectator->perturbative(true); } // outgoing spectator else { spectator = findFinalStateLine(currentTree(), real->bornOutgoing()[ispect-real->incoming().size()]->id(), real->bornOutgoing()[ispect-real->incoming().size()]->momentum()); // special case if decayed map<tShowerTreePtr,pair<tShowerProgenitorPtr,tShowerParticlePtr> >::const_iterator tit; for(tit = currentTree()->treelinks().begin(); tit != currentTree()->treelinks().end();++tit) { if(tit->second.first && tit->second.second==spectator->progenitor()) break; } fixSpectatorColours(real->outgoing()[ispect-real->incoming().size()],spectator,cline,aline,true); // update the spectator spectator->copy(real->outgoing()[ispect-real->incoming().size()]); ShowerParticlePtr sp(new_ptr(ShowerParticle(*real->outgoing()[ispect-real->incoming().size()],1,true))); spectator->progenitor(sp); currentTree()->outgoingLines()[spectator]=sp; spectator->perturbative(true); // update for decaying particles if(tit!=currentTree()->treelinks().end()) currentTree()->updateLink(tit->first,make_pair(spectator,sp)); } // incoming emitter if(iemit<2) { emitter = findInitialStateLine(currentTree(), real->bornIncoming()[iemit]->id(), real->bornIncoming()[iemit]->momentum()); fixInitialStateEmitter(currentTree(),real->incoming()[iemit],real->outgoing()[ig], emitter,aline,cline,iemit ==0 ? real->x().first :real->x().second); } // outgoing emitter else { emitter = findFinalStateLine(currentTree(), real->bornOutgoing()[iemit-real->incoming().size()]->id(), real->bornOutgoing()[iemit-real->incoming().size()]->momentum()); fixFinalStateEmitter(currentTree(),real->outgoing()[iemit-real->incoming().size()], real->outgoing()[ig],emitter,aline,cline); } } // decay process else { assert(real->spectator()==0); unsigned int iemit = real->emitter()-real->incoming().size(); int ig = int(real->emitted())-int(real->incoming().size()); ColinePair cline,aline; // incoming spectator ShowerProgenitorPtr spectator = findInitialStateLine(currentTree(), real->bornIncoming()[0]->id(), real->bornIncoming()[0]->momentum()); fixSpectatorColours(real->incoming()[0],spectator,cline,aline,false); // find the emitter ShowerProgenitorPtr emitter = findFinalStateLine(currentTree(), real->bornOutgoing()[iemit]->id(), real->bornOutgoing()[iemit]->momentum()); // recoiling system for( map<ShowerProgenitorPtr,tShowerParticlePtr>::const_iterator cjt= currentTree()->outgoingLines().begin(); cjt != currentTree()->outgoingLines().end();++cjt ) { if(cjt->first==emitter) continue; cjt->first->progenitor()->transform(real->transformation()); cjt->first->copy()->transform(real->transformation()); } // sort out the emitter fixFinalStateEmitter(currentTree(),real->outgoing()[iemit], real->outgoing()[ig],emitter,aline,cline); } } // clean up the shower tree _currenttree->resetShowerProducts(); } diff --git a/Shower/QTilde/QTildeShowerHandler.h b/Shower/QTilde/QTildeShowerHandler.h --- a/Shower/QTilde/QTildeShowerHandler.h +++ b/Shower/QTilde/QTildeShowerHandler.h @@ -1,859 +1,859 @@ // -*- C++ -*- #ifndef Herwig_QTildeShowerHandler_H #define Herwig_QTildeShowerHandler_H // // This is the declaration of the QTildeShowerHandler class. // #include "QTildeShowerHandler.fh" #include "Herwig/Shower/ShowerHandler.h" #include "Herwig/Shower/QTilde/Base/ShowerModel.h" #include "Herwig/Shower/QTilde/SplittingFunctions/SplittingGenerator.h" #include "Herwig/Shower/QTilde/Base/ShowerTree.h" #include "Herwig/Shower/QTilde/Base/ShowerProgenitor.fh" #include "Herwig/Shower/QTilde/Base/HardTree.h" #include "Herwig/Shower/QTilde/Base/Branching.h" #include "Herwig/Shower/QTilde/Base/ShowerVeto.h" #include "Herwig/Shower/QTilde/Base/FullShowerVeto.h" #include "Herwig/MatrixElement/HwMEBase.h" #include "Herwig/Decay/HwDecayerBase.h" #include "Herwig/MatrixElement/Matchbox/Matching/ShowerApproximation.h" #include "Herwig/Shower/RealEmissionProcess.h" #include "Herwig/Utilities/Statistic.h" namespace Herwig { using namespace ThePEG; /** * The QTildeShowerHandler class. * * @see \ref QTildeShowerHandlerInterfaces "The interfaces" * defined for QTildeShowerHandler. */ class QTildeShowerHandler: public ShowerHandler { public: /** * Pointer to an XComb object */ typedef Ptr<XComb>::pointer XCPtr; public: /** @name Standard constructors and destructors. */ //@{ /** * The default constructor. */ QTildeShowerHandler(); /** * The destructor. */ virtual ~QTildeShowerHandler(); //@} public: /** * At the end of the Showering, transform ShowerParticle objects * into ThePEG particles and fill the event record with them. * Notice that the parent/child relationships and the * transformation from ShowerColourLine objects into ThePEG * ColourLine ones must be properly handled. */ void fillEventRecord(); /** * Return the relevant hard scale to be used in the profile scales */ virtual Energy hardScale() const { return muPt; } /** * Hook to allow vetoing of event after showering hard sub-process * as in e.g. MLM merging. */ virtual bool showerHardProcessVeto() { return false; } /** * Generate hard emissions for CKKW etc */ virtual HardTreePtr generateCKKW(ShowerTreePtr tree) const; /** * Members to perform the shower */ //@{ /** * Perform the shower of the hard process */ virtual void showerHardProcess(ShowerTreePtr,XCPtr); /** * Perform the shower of a decay */ virtual void showerDecay(ShowerTreePtr); //@} /** * Access to the flags and shower variables */ //@{ /** * Get the ShowerModel */ ShowerModelPtr showerModel() const {return _model;} /** * Get the SplittingGenerator */ tSplittingGeneratorPtr splittingGenerator() const { return _splittingGenerator; } /** * Mode for hard emissions */ int hardEmission() const {return _hardEmission;} //@} /** * Connect the Hard and Shower trees */ virtual void connectTrees(ShowerTreePtr showerTree, HardTreePtr hardTree, bool hard ); /** * Access to switches for spin correlations */ //@{ /** * Spin Correlations */ unsigned int spinCorrelations() const { return _spinOpt; } /** * Soft correlations */ unsigned int softCorrelations() const { return _softOpt; } /** * Any correlations */ bool correlations() const { return _spinOpt!=0||_softOpt!=0; } //@} protected: /** * Perform the shower */ void doShowering(bool hard,XCPtr); /** * Generate the hard matrix element correction */ virtual RealEmissionProcessPtr hardMatrixElementCorrection(bool); /** * Generate the hardest emission */ virtual void hardestEmission(bool hard); /** * Set up for applying a matrix element correction */ void setupMECorrection(RealEmissionProcessPtr real); /** * Extract the particles to be showered, set the evolution scales * and apply the hard matrix element correction * @param hard Whether this is a hard process or decay * @return The particles to be showered */ virtual vector<ShowerProgenitorPtr> setupShower(bool hard); /** * set the colour partners */ virtual void setEvolutionPartners(bool hard,ShowerInteraction, bool clear); /** * Methods to perform the evolution of an individual particle, including * recursive calling on the products */ //@{ /** * It does the forward evolution of the time-like input particle * (and recursively for all its radiation products). * accepting only emissions which conforms to the showerVariables * and soft matrix element correction. * If at least one emission has occurred then the method returns true. * @param particle The particle to be showered */ virtual bool timeLikeShower(tShowerParticlePtr particle, ShowerInteraction, Branching fb, bool first); /** * It does the backward evolution of the space-like input particle * (and recursively for all its time-like radiation products). * accepting only emissions which conforms to the showerVariables. * If at least one emission has occurred then the method returns true * @param particle The particle to be showered * @param beam The beam particle */ virtual bool spaceLikeShower(tShowerParticlePtr particle,PPtr beam, ShowerInteraction); /** * If does the forward evolution of the input on-shell particle * involved in a decay * (and recursively for all its time-like radiation products). * accepting only emissions which conforms to the showerVariables. * @param particle The particle to be showered * @param maxscale The maximum scale for the shower. * @param minimumMass The minimum mass of the final-state system */ virtual bool spaceLikeDecayShower(tShowerParticlePtr particle, const ShowerParticle::EvolutionScales & maxScales, Energy minimumMass,ShowerInteraction, Branching fb); /** * Truncated shower from a time-like particle */ virtual bool truncatedTimeLikeShower(tShowerParticlePtr particle, HardBranchingPtr branch, ShowerInteraction type, Branching fb, bool first); /** * Truncated shower from a space-like particle */ virtual bool truncatedSpaceLikeShower(tShowerParticlePtr particle,PPtr beam, HardBranchingPtr branch, ShowerInteraction type); /** * Truncated shower from a time-like particle */ virtual bool truncatedSpaceLikeDecayShower(tShowerParticlePtr particle, const ShowerParticle::EvolutionScales & maxScales, Energy minimumMass, HardBranchingPtr branch, ShowerInteraction type, Branching fb); //@} /** * Switches for matrix element corrections */ //@{ /** * Any ME correction? */ bool MECOn() const { return _hardEmission == 1; } /** * Any hard ME correction? */ bool hardMEC() const { return _hardEmission == 1 && (_meCorrMode == 1 || _meCorrMode == 2); } /** * Any soft ME correction? */ bool softMEC() const { return _hardEmission == 1 && (_meCorrMode == 1 || _meCorrMode > 2); } //@} /** * Is the truncated shower on? */ bool isTruncatedShowerON() const {return _trunc_Mode;} /** * Switch for intrinsic pT */ //@{ /** * Any intrinsic pT? */ bool ipTon() const { return _iptrms != ZERO || ( _beta == 1.0 && _gamma != ZERO && _iptmax !=ZERO ); } //@} /**@name Additional shower vetoes */ //@{ /** * Insert a veto. */ void addVeto (ShowerVetoPtr v) { _vetoes.push_back(v); } /** * Remove a veto. */ void removeVeto (ShowerVetoPtr v) { vector<ShowerVetoPtr>::iterator vit = find(_vetoes.begin(),_vetoes.end(),v); if (vit != _vetoes.end()) _vetoes.erase(vit); } //@} /** * Switches for vetoing hard emissions */ //@{ /** * Returns true if the hard veto read-in is to be applied to only * the primary collision and false otherwise. */ bool hardVetoReadOption() const {return _hardVetoReadOption;} //@} /** * Enhancement factors for radiation needed to generate the soft matrix * element correction. */ //@{ /** * Access the enhancement factor for initial-state radiation */ double initialStateRadiationEnhancementFactor() const { return _initialenhance; } /** * Access the enhancement factor for final-state radiation */ double finalStateRadiationEnhancementFactor() const { return _finalenhance; } /** * Set the enhancement factor for initial-state radiation */ void initialStateRadiationEnhancementFactor(double in) { _initialenhance=in; } /** * Set the enhancement factor for final-state radiation */ void finalStateRadiationEnhancementFactor(double in) { _finalenhance=in; } //@} /** * Access to set/get the HardTree currently beinging showered */ //@{ /** * The HardTree currently being showered */ tHardTreePtr hardTree() {return _hardtree;} /** * The HardTree currently being showered */ void hardTree(tHardTreePtr in) {_hardtree = in;} //@} /** * Access/set the beam particle for the current initial-state shower */ //@{ /** * Get the beam particle data */ Ptr<BeamParticleData>::const_pointer beamParticle() const { return _beam; } /** * Set the beam particle data */ void setBeamParticle(Ptr<BeamParticleData>::const_pointer in) { _beam=in; } //@} /** - * Set/Get the current tree being evolverd for inheriting classes + * Set/Get the current tree being evolver for inheriting classes */ //@{ /** * Get the tree */ tShowerTreePtr currentTree() { return _currenttree; } /** * Set the tree */ void currentTree(tShowerTreePtr tree) { _currenttree=tree; } //@} /** * Access the maximum number of attempts to generate the shower */ unsigned int maximumTries() const { return _maxtry; } /** * Set/Get the ShowerProgenitor for the current shower */ //@{ /** * Access the progenitor */ ShowerProgenitorPtr progenitor() { return _progenitor; } /** * Set the progenitor */ void progenitor(ShowerProgenitorPtr in) { _progenitor=in; } //@} /** * Calculate the intrinsic \f$p_T\f$. */ virtual void generateIntrinsicpT(vector<ShowerProgenitorPtr>); /** * Access to the intrinsic \f$p_T\f$ for inheriting classes */ map<tShowerProgenitorPtr,pair<Energy,double> > & intrinsicpT() { return _intrinsic; } /** * find the maximally allowed pt acc to the hard process. */ void setupMaximumScales(const vector<ShowerProgenitorPtr> &,XCPtr); /** * find the relevant hard scales for profile scales. */ void setupHardScales(const vector<ShowerProgenitorPtr> &,XCPtr); /** * Convert the HardTree into an extra shower emission */ void convertHardTree(bool hard,ShowerInteraction type); protected: /** * Find the parton extracted from the incoming particle after ISR */ PPtr findFirstParton(tPPtr seed) const; /** * Fix Remnant connections after ISR */ tPPair remakeRemnant(tPPair oldp); protected: /** * Start the shower of a timelike particle */ virtual bool startTimeLikeShower(ShowerInteraction); /** * Update of the time-like stuff */ void updateHistory(tShowerParticlePtr particle); /** * Start the shower of a spacelike particle */ virtual bool startSpaceLikeShower(PPtr,ShowerInteraction); /** * Start the shower of a spacelike particle */ virtual bool startSpaceLikeDecayShower(const ShowerParticle::EvolutionScales & maxScales, Energy minimumMass,ShowerInteraction); /** * Select the branching for the next time-like emission */ Branching selectTimeLikeBranching(tShowerParticlePtr particle, ShowerInteraction type, HardBranchingPtr branch); /** * Select the branching for the next space-like emission in a decay */ Branching selectSpaceLikeDecayBranching(tShowerParticlePtr particle, const ShowerParticle::EvolutionScales & maxScales, Energy minmass,ShowerInteraction type, HardBranchingPtr branch); /** * Create the timelike child of a branching */ ShowerParticleVector createTimeLikeChildren(tShowerParticlePtr particle, IdList ids); /** * Vetos for the timelike shower */ virtual bool timeLikeVetoed(const Branching &,ShowerParticlePtr); /** * Vetos for the spacelike shower */ virtual bool spaceLikeVetoed(const Branching &,ShowerParticlePtr); /** * Vetos for the spacelike shower */ virtual bool spaceLikeDecayVetoed(const Branching &,ShowerParticlePtr); /** * Only generate the hard emission, for testing only. */ bool hardOnly() const {return _limitEmissions==3;} /** * Check the flags */ void checkFlags(); /** * */ void addFSRUsingDecayPOWHEG(HardTreePtr ISRTree); 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: /** * The main method which manages the showering of a subprocess. */ virtual tPPair cascade(tSubProPtr sub, XCPtr xcomb); /** * If cascade was called before, but there are still decaying partialces * in the DecayInShower list to be showered. Also possible with another shower * like combining Dipole and Qtilde. */ virtual void cascade(tPVector) ; /** * Decay a ShowerTree */ void decay(ShowerTreePtr tree, ShowerDecayMap & decay); 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; //@} protected: /** @name Standard Interfaced functions. */ //@{ /** * Initialize this object after the setup phase before saving an * EventGenerator to disk. * @throws InitException if object could not be initialized properly. */ virtual void doinit(); //@} private: /** * The assignment operator is private and must never be called. * In fact, it should not even be implemented. */ QTildeShowerHandler & operator=(const QTildeShowerHandler &); private: /** * Stuff from the ShowerHandler */ //@{ /** * The ShowerTree for the hard process */ ShowerTreePtr hard_; /** * The ShowerTree for the decays */ ShowerDecayMap decay_; /** * The ShowerTrees for which the initial shower */ vector<ShowerTreePtr> done_; //@} private : /** * Pointer to the model for the shower evolution model */ ShowerModelPtr _model; /** * Pointer to the splitting generator */ SplittingGeneratorPtr _splittingGenerator; /** * Maximum number of tries to generate the shower of a particular tree */ unsigned int _maxtry; /** * Matrix element correction switch */ unsigned int _meCorrMode; /** * Control of the reconstruction option */ unsigned int _reconOpt; /** * If hard veto pT scale is being read-in this determines * whether the read-in value is applied to primary and * secondary (MPI) scatters or just the primary one, with * the usual computation of the veto being performed for * the secondary (MPI) scatters. */ bool _hardVetoReadOption; /** * rms intrinsic pT of Gaussian distribution */ Energy _iptrms; /** * Proportion of inverse quadratic intrinsic pT distribution */ double _beta; /** * Parameter for inverse quadratic: 2*Beta*Gamma/(sqr(Gamma)+sqr(intrinsicpT)) */ Energy _gamma; /** * Upper bound on intrinsic pT for inverse quadratic */ Energy _iptmax; /** * Limit the number of emissions for testing */ unsigned int _limitEmissions; /** * The progenitor of the current shower */ ShowerProgenitorPtr _progenitor; /** * Matrix element */ HwMEBasePtr _hardme; /** * Decayer */ HwDecayerBasePtr _decayme; /** * The ShowerTree currently being showered */ ShowerTreePtr _currenttree; /** * The HardTree currently being showered */ HardTreePtr _hardtree; /** * Radiation enhancement factors for use with the veto algorithm * if needed by the soft matrix element correction */ //@{ /** * Enhancement factor for initial-state radiation */ double _initialenhance; /** * Enhancement factor for final-state radiation */ double _finalenhance; //@} /** * The beam particle data for the current initial-state shower */ Ptr<BeamParticleData>::const_pointer _beam; /** * Storage of the intrinsic \f$p_t\f$ of the particles */ map<tShowerProgenitorPtr,pair<Energy,double> > _intrinsic; /** * Vetoes */ vector<ShowerVetoPtr> _vetoes; /** * Full Shower Vetoes */ vector<FullShowerVetoPtr> _fullShowerVetoes; /** * Number of iterations for reweighting */ unsigned int _nReWeight; /** * Whether or not we are reweighting */ bool _reWeight; /** * number of IS emissions */ unsigned int _nis; /** * Number of FS emissions */ unsigned int _nfs; /** * The option for wqhich interactions to use */ ShowerInteraction interaction_; /** * Truncated shower switch */ bool _trunc_Mode; /** * Count of the number of truncated emissions */ unsigned int _truncEmissions; /** * Mode for the hard emissions */ int _hardEmission; /** * Option to include spin correlations */ unsigned int _spinOpt; /** * Option for the kernal for soft correlations */ unsigned int _softOpt; /** * Option for hard radiation in POWHEG events */ bool _hardPOWHEG; /** * True if no warnings about incorrect hard emission * mode setting have been issued yet */ static bool _hardEmissionWarn; /** * True if no warnings about missing truncated shower * have been issued yet */ static bool _missingTruncWarn; /** * The relevant hard scale to be used in the profile scales */ Energy muPt; /** * Maximum number of emission attempts for FSR */ unsigned int _maxTryFSR; /** * Maximum number of failures for FSR generation */ unsigned int _maxFailFSR; /** * Failure fraction for FSR generation */ double _fracFSR; /** * Counter for number of FSR emissions */ unsigned int _nFSR; /** * Counter for the number of failed events due to FSR emissions */ unsigned int _nFailedFSR; }; } -#endif /* Herwig_QTildeShowerHandler_H */ +#endif /* HERWIG_QTildeShowerHandler_H */ diff --git a/src/Matchbox/FiveFlavourNoBMassScheme.in b/src/Matchbox/FiveFlavourNoBMassScheme.in --- a/src/Matchbox/FiveFlavourNoBMassScheme.in +++ b/src/Matchbox/FiveFlavourNoBMassScheme.in @@ -1,102 +1,76 @@ # -*- ThePEG-repository -*- cd /Herwig/MatrixElements/Matchbox do Factory:StartParticleGroup p insert Factory:ParticleGroup 0 /Herwig/Particles/b insert Factory:ParticleGroup 0 /Herwig/Particles/bbar insert Factory:ParticleGroup 0 /Herwig/Particles/c insert Factory:ParticleGroup 0 /Herwig/Particles/cbar insert Factory:ParticleGroup 0 /Herwig/Particles/s insert Factory:ParticleGroup 0 /Herwig/Particles/sbar insert Factory:ParticleGroup 0 /Herwig/Particles/d insert Factory:ParticleGroup 0 /Herwig/Particles/dbar insert Factory:ParticleGroup 0 /Herwig/Particles/u insert Factory:ParticleGroup 0 /Herwig/Particles/ubar insert Factory:ParticleGroup 0 /Herwig/Particles/g do Factory:EndParticleGroup do Factory:StartParticleGroup pbar insert Factory:ParticleGroup 0 /Herwig/Particles/b insert Factory:ParticleGroup 0 /Herwig/Particles/bbar insert Factory:ParticleGroup 0 /Herwig/Particles/c insert Factory:ParticleGroup 0 /Herwig/Particles/cbar insert Factory:ParticleGroup 0 /Herwig/Particles/s insert Factory:ParticleGroup 0 /Herwig/Particles/sbar insert Factory:ParticleGroup 0 /Herwig/Particles/d insert Factory:ParticleGroup 0 /Herwig/Particles/dbar insert Factory:ParticleGroup 0 /Herwig/Particles/u insert Factory:ParticleGroup 0 /Herwig/Particles/ubar insert Factory:ParticleGroup 0 /Herwig/Particles/g do Factory:EndParticleGroup cd /Herwig/Merging/ do MergingFactory:StartParticleGroup p insert MergingFactory:ParticleGroup 0 /Herwig/Particles/b insert MergingFactory:ParticleGroup 0 /Herwig/Particles/bbar insert MergingFactory:ParticleGroup 0 /Herwig/Particles/c insert MergingFactory:ParticleGroup 0 /Herwig/Particles/cbar insert MergingFactory:ParticleGroup 0 /Herwig/Particles/s insert MergingFactory:ParticleGroup 0 /Herwig/Particles/sbar insert MergingFactory:ParticleGroup 0 /Herwig/Particles/d insert MergingFactory:ParticleGroup 0 /Herwig/Particles/dbar insert MergingFactory:ParticleGroup 0 /Herwig/Particles/u insert MergingFactory:ParticleGroup 0 /Herwig/Particles/ubar insert MergingFactory:ParticleGroup 0 /Herwig/Particles/g do MergingFactory:EndParticleGroup do MergingFactory:StartParticleGroup pbar insert MergingFactory:ParticleGroup 0 /Herwig/Particles/b insert MergingFactory:ParticleGroup 0 /Herwig/Particles/bbar insert MergingFactory:ParticleGroup 0 /Herwig/Particles/c insert MergingFactory:ParticleGroup 0 /Herwig/Particles/cbar insert MergingFactory:ParticleGroup 0 /Herwig/Particles/s insert MergingFactory:ParticleGroup 0 /Herwig/Particles/sbar insert MergingFactory:ParticleGroup 0 /Herwig/Particles/d insert MergingFactory:ParticleGroup 0 /Herwig/Particles/dbar insert MergingFactory:ParticleGroup 0 /Herwig/Particles/u insert MergingFactory:ParticleGroup 0 /Herwig/Particles/ubar insert MergingFactory:ParticleGroup 0 /Herwig/Particles/g do MergingFactory:EndParticleGroup cd /Herwig/Particles do b:UnsetHardProcessMass do bbar:UnsetHardProcessMass do c:UnsetHardProcessMass do cbar:UnsetHardProcessMass set b:NominalMass 0*GeV set bbar:NominalMass 0*GeV set c:NominalMass 0*GeV set cbar:NominalMass 0*GeV -cd /Herwig/DipoleShower/Kernels - -cp IFgx2qqxDipoleKernel IFgx2bbbarxDipoleKernel -set IFgx2bbbarxDipoleKernel:Flavour /Herwig/Particles/b -insert /Herwig/DipoleShower/DipoleShowerHandler:Kernels 0 IFgx2bbbarxDipoleKernel - -cp IFgx2qqxDipoleKernel IFgx2bbarbxDipoleKernel -set IFgx2bbarbxDipoleKernel:Flavour /Herwig/Particles/bbar -insert /Herwig/DipoleShower/DipoleShowerHandler:Kernels 0 IFgx2bbarbxDipoleKernel - -cp IFMgx2qqxDipoleKernel IFMgx2bbbarxDipoleKernel -set IFMgx2bbbarxDipoleKernel:Flavour /Herwig/Particles/b -insert /Herwig/DipoleShower/DipoleShowerHandler:Kernels 0 IFMgx2bbbarxDipoleKernel - -cp IFMgx2qqxDipoleKernel IFMgx2bbarbxDipoleKernel -set IFMgx2bbarbxDipoleKernel:Flavour /Herwig/Particles/bbar -insert /Herwig/DipoleShower/DipoleShowerHandler:Kernels 0 IFMgx2bbarbxDipoleKernel - -cp IIgx2qqxDipoleKernel IIgx2bbbarxDipoleKernel -set IIgx2bbbarxDipoleKernel:Flavour /Herwig/Particles/b -insert /Herwig/DipoleShower/DipoleShowerHandler:Kernels 0 IIgx2bbbarxDipoleKernel - -cp IIgx2qqxDipoleKernel IIgx2bbarbxDipoleKernel -set IIgx2bbarbxDipoleKernel:Flavour /Herwig/Particles/bbar -insert /Herwig/DipoleShower/DipoleShowerHandler:Kernels 0 IIgx2bbarbxDipoleKernel - diff --git a/src/Merging/1LO-0NLO-LHC-T.in b/src/Merging/1LO-0NLO-LHC-T.in --- a/src/Merging/1LO-0NLO-LHC-T.in +++ b/src/Merging/1LO-0NLO-LHC-T.in @@ -1,172 +1,172 @@ # -*- ThePEG-repository -*- ################################################## ## Herwig/Merging example input file ################################################## ################################################## ## Collider type ################################################## read Matchbox/PPCollider.in read Merging/Merging.in ################################################## ## Beam energy sqrt(s) ################################################## cd /Herwig/EventHandlers set EventHandler:LuminosityFunction:Energy 7000*GeV ################################################## ## Process selection ################################################## ## Note that event generation may fail if no matching matrix element has ## been found. Coupling orders are with respect to the Born process, ## i.e. NLO QCD does not require an additional power of alphas. ## Model assumptions read Matchbox/StandardModelLike.in read Matchbox/DiagonalCKM.in ## Set the order of the couplings cd /Herwig/Merging set MergingFactory:OrderInAlphaS 2 set MergingFactory:OrderInAlphaEW 0 ## Select the process ## You may use identifiers such as p, pbar, j, l, mu+, h0 etc. do MergingFactory:Process p p -> t tbar [ ] set MergingFactory:NLOProcesses 0 set Merger:MergingScale 10.*GeV set Merger:MergingScaleSmearing 0.1 set Merger:gamma 1. set MPreWeight:HTPower 0 set MPreWeight:MaxPTPower 0 set MPreWeight:OnlyColoured False -read Matchbox/PQCDLevel.in +#read Matchbox/PQCDLevel.in ## Special settings required for on-shell production of unstable particles ## enable for on-shell top production read Matchbox/OnShellTopProduction.in ## enable for on-shell W, Z or h production # read Matchbox/OnShellWProduction.in # read Matchbox/OnShellZProduction.in # read Matchbox/OnShellHProduction.in # Special settings for the VBF approximation # read Matchbox/VBFDiagramsOnly.in ################################################## ## Matrix element library selection ################################################## ## Select a generic tree/loop combination or a ## specialized NLO package # read Matchbox/MadGraph-GoSam.in read Matchbox/MadGraph-MadGraph.in # read Matchbox/MadGraph-NJet.in # read Matchbox/MadGraph-OpenLoops.in # read Matchbox/HJets.in # read Matchbox/VBFNLO.in ## Uncomment this to use ggh effective couplings ## currently only supported by MadGraph-GoSam # read Matchbox/HiggsEffective.in ################################################## ## Cut selection ## See the documentation for more options ################################################## set /Herwig/Cuts/ChargedLeptonPairMassCut:MinMass 60*GeV set /Herwig/Cuts/ChargedLeptonPairMassCut:MaxMass 120*GeV cd /Herwig/MatrixElements/Matchbox/Utility insert DiagramGenerator:ExcludeInternal 0 /Herwig/Particles/gamma ## cuts on additional jets # read Matchbox/DefaultPPJets.in # insert JetCuts:JetRegions 0 FirstJet # insert JetCuts:JetRegions 1 SecondJet # insert JetCuts:JetRegions 2 ThirdJet # insert JetCuts:JetRegions 3 FourthJet ################################################## ## Scale choice ## See the documentation for more options ################################################## cd /Herwig/MatrixElements/Matchbox/Scales/ set /Herwig/Merging/MergingFactory:ScaleChoice TopPairMassScale ################################################## ## Scale uncertainties ################################################## # read Matchbox/MuDown.in # read Matchbox/MuUp.in ################################################## ## Shower scale uncertainties ################################################## # read Matchbox/MuQDown.in # read Matchbox/MuQUp.in ################################################## ## PDF choice ################################################## read Matchbox/FiveFlavourNoBMassScheme.in read Matchbox/MMHT2014.in ################################################## ## CMW - Scheme ################################################## ### Use factor in alpha_s argument: alpha_s(q) -> alpha_s(fac*q) ### with fac=exp(-(67-3pi^2-10/3*Nf)/(33-2Nf)) read Merging/FactorCMWScheme.in ### Linear CMW multiplication: ### alpha_s(q) -> alpha_s(q)(1+K_g*alpha_s(q)/2pi ) # read Merging/LinearCMWScheme.in ### Same for 4 flavours # read Merging/FactorCMWScheme_4fl.in # read Merging/LinearCMWScheme_4fl.in ################################################## ## Analyses ################################################## cd /Herwig/Analysis insert /Herwig/Generators/EventGenerator:AnalysisHandlers 0 Rivet # insert /Herwig/Generators/EventGenerator:AnalysisHandlers 0 HepMC read Merging/LHC7-T-Analysis.in ################################################## ## Save the generator ################################################## do /Herwig/Merging/MergingFactory:ProductionMode set /Herwig/Generators/EventGenerator:IntermediateOutput Yes cd /Herwig/Generators saverun 1LO-0NLO-LHC-T EventGenerator diff --git a/src/defaults/DipoleShowerDefaults.in b/src/defaults/DipoleShowerDefaults.in --- a/src/defaults/DipoleShowerDefaults.in +++ b/src/defaults/DipoleShowerDefaults.in @@ -1,569 +1,599 @@ # -*- ThePEG-repository -*- ################################################################################ # # Default setup for the dipole shower. # ################################################################################ ################################################################################ # Load libraries ################################################################################ library HwDipoleShower.so mkdir /Herwig/DipoleShower cd /Herwig/DipoleShower create Herwig::DipoleShowerHandler DipoleShowerHandler set DipoleShowerHandler:FreezeGrid 100000 newdef DipoleShowerHandler:PDFA /Herwig/Partons/ShowerLOPDF newdef DipoleShowerHandler:PDFB /Herwig/Partons/ShowerLOPDF newdef DipoleShowerHandler:PDFARemnant /Herwig/Partons/RemnantPDF newdef DipoleShowerHandler:PDFBRemnant /Herwig/Partons/RemnantPDF ################################################################################ # Setup the underlying event and fix missing reference. ################################################################################ set DipoleShowerHandler:MPIHandler /Herwig/UnderlyingEvent/MPIHandler set DipoleShowerHandler:RemDecayer /Herwig/Partons/RemnantDecayer ################################################################################ # Setup the ordering. ################################################################################ create Herwig::DipoleChainOrdering ChainPtOrdering ################################################################################ # Setup the reshuffler. ################################################################################ create Herwig::ConstituentReshuffler ConstituentReshuffler set DipoleShowerHandler:ConstituentReshuffler ConstituentReshuffler ################################################################################ # Setup intrinsic pt. ################################################################################ create Herwig::IntrinsicPtGenerator IntrinsicPtGenerator set DipoleShowerHandler:IntrinsicPtGenerator IntrinsicPtGenerator cd /Herwig/DipoleShower ################################################################################ # Setup the alphas ################################################################################ cp /Herwig/Couplings/NLOAlphaS NLOAlphaS ################################################################################ # Setup the splitting kinematics. ################################################################################ mkdir /Herwig/DipoleShower/Kinematics cd /Herwig/DipoleShower/Kinematics create Herwig::FFLightKinematics FFLightKinematics create Herwig::FILightKinematics FILightKinematics create Herwig::IFLightKinematics IFLightKinematics create Herwig::IILightKinematics IILightKinematics create Herwig::FFMassiveKinematics FFMassiveKinematics create Herwig::FIMassiveKinematics FIMassiveKinematics create Herwig::IFMassiveKinematics IFMassiveKinematics create Herwig::FIMassiveDecayKinematics FIMassiveDecayKinematics ################################################################################ # Setup the kernels. ################################################################################ mkdir /Herwig/DipoleShower/Kernels cd /Herwig/DipoleShower/Kernels ################################################################################ # FF ################################################################################ create Herwig::FFgx2ggxDipoleKernel FFgx2ggxDipoleKernel set FFgx2ggxDipoleKernel:SplittingKinematics /Herwig/DipoleShower/Kinematics/FFLightKinematics insert /Herwig/DipoleShower/DipoleShowerHandler:Kernels 0 FFgx2ggxDipoleKernel create Herwig::FFqx2qgxDipoleKernel FFqx2qgxDipoleKernel set FFqx2qgxDipoleKernel:SplittingKinematics /Herwig/DipoleShower/Kinematics/FFLightKinematics insert /Herwig/DipoleShower/DipoleShowerHandler:Kernels 0 FFqx2qgxDipoleKernel create Herwig::FFgx2qqxDipoleKernel FFgx2qqxDipoleKernel set FFgx2qqxDipoleKernel:SplittingKinematics /Herwig/DipoleShower/Kinematics/FFLightKinematics cp FFgx2qqxDipoleKernel FFgx2ddxDipoleKernel set FFgx2ddxDipoleKernel:Flavour /Herwig/Particles/d insert /Herwig/DipoleShower/DipoleShowerHandler:Kernels 0 FFgx2ddxDipoleKernel cp FFgx2qqxDipoleKernel FFgx2uuxDipoleKernel set FFgx2uuxDipoleKernel:Flavour /Herwig/Particles/u insert /Herwig/DipoleShower/DipoleShowerHandler:Kernels 0 FFgx2uuxDipoleKernel cp FFgx2qqxDipoleKernel FFgx2ccxDipoleKernel set FFgx2ccxDipoleKernel:Flavour /Herwig/Particles/c insert /Herwig/DipoleShower/DipoleShowerHandler:Kernels 0 FFgx2ccxDipoleKernel cp FFgx2qqxDipoleKernel FFgx2ssxDipoleKernel set FFgx2ssxDipoleKernel:Flavour /Herwig/Particles/s insert /Herwig/DipoleShower/DipoleShowerHandler:Kernels 0 FFgx2ssxDipoleKernel cp FFgx2qqxDipoleKernel FFgx2bbxDipoleKernel set FFgx2bbxDipoleKernel:Flavour /Herwig/Particles/b insert /Herwig/DipoleShower/DipoleShowerHandler:Kernels 0 FFgx2bbxDipoleKernel ### massive dipoles create Herwig::FFMgx2ggxDipoleKernel FFMgx2ggxDipoleKernel set FFMgx2ggxDipoleKernel:SplittingKinematics /Herwig/DipoleShower/Kinematics/FFMassiveKinematics insert /Herwig/DipoleShower/DipoleShowerHandler:Kernels 0 FFMgx2ggxDipoleKernel create Herwig::FFMqx2qgxDipoleKernel FFMqx2qgxDipoleKernel set FFMqx2qgxDipoleKernel:SplittingKinematics /Herwig/DipoleShower/Kinematics/FFMassiveKinematics cp FFMqx2qgxDipoleKernel FFMdx2dgxDipoleKernel set FFMdx2dgxDipoleKernel:Flavour /Herwig/Particles/d insert /Herwig/DipoleShower/DipoleShowerHandler:Kernels 0 FFMdx2dgxDipoleKernel cp FFMqx2qgxDipoleKernel FFMux2ugxDipoleKernel set FFMux2ugxDipoleKernel:Flavour /Herwig/Particles/u insert /Herwig/DipoleShower/DipoleShowerHandler:Kernels 0 FFMux2ugxDipoleKernel cp FFMqx2qgxDipoleKernel FFMcx2cgxDipoleKernel set FFMcx2cgxDipoleKernel:Flavour /Herwig/Particles/c insert /Herwig/DipoleShower/DipoleShowerHandler:Kernels 0 FFMcx2cgxDipoleKernel cp FFMqx2qgxDipoleKernel FFMsx2sgxDipoleKernel set FFMsx2sgxDipoleKernel:Flavour /Herwig/Particles/s insert /Herwig/DipoleShower/DipoleShowerHandler:Kernels 0 FFMsx2sgxDipoleKernel cp FFMqx2qgxDipoleKernel FFMbx2bgxDipoleKernel set FFMbx2bgxDipoleKernel:Flavour /Herwig/Particles/b insert /Herwig/DipoleShower/DipoleShowerHandler:Kernels 0 FFMbx2bgxDipoleKernel cp FFMqx2qgxDipoleKernel FFMtx2tgxDipoleKernel set FFMtx2tgxDipoleKernel:Flavour /Herwig/Particles/t insert /Herwig/DipoleShower/DipoleShowerHandler:Kernels 0 FFMtx2tgxDipoleKernel create Herwig::FFMgx2qqxDipoleKernel FFMgx2qqxDipoleKernel set FFMgx2qqxDipoleKernel:SplittingKinematics /Herwig/DipoleShower/Kinematics/FFMassiveKinematics cp FFMgx2qqxDipoleKernel FFMgx2ddxDipoleKernel set FFMgx2ddxDipoleKernel:Flavour /Herwig/Particles/d insert /Herwig/DipoleShower/DipoleShowerHandler:Kernels 0 FFMgx2ddxDipoleKernel cp FFMgx2qqxDipoleKernel FFMgx2uuxDipoleKernel set FFMgx2uuxDipoleKernel:Flavour /Herwig/Particles/u insert /Herwig/DipoleShower/DipoleShowerHandler:Kernels 0 FFMgx2uuxDipoleKernel cp FFMgx2qqxDipoleKernel FFMgx2ccxDipoleKernel set FFMgx2ccxDipoleKernel:Flavour /Herwig/Particles/c insert /Herwig/DipoleShower/DipoleShowerHandler:Kernels 0 FFMgx2ccxDipoleKernel cp FFMgx2qqxDipoleKernel FFMgx2ssxDipoleKernel set FFMgx2ssxDipoleKernel:Flavour /Herwig/Particles/s insert /Herwig/DipoleShower/DipoleShowerHandler:Kernels 0 FFMgx2ssxDipoleKernel cp FFMgx2qqxDipoleKernel FFMgx2bbxDipoleKernel set FFMgx2bbxDipoleKernel:Flavour /Herwig/Particles/b insert /Herwig/DipoleShower/DipoleShowerHandler:Kernels 0 FFMgx2bbxDipoleKernel ################################################################################ # create the pdf ratio object ################################################################################ create Herwig::PDFRatio PDFRatio +cd /Herwig/DipoleShower/Kernels + + ################################################################################ # FI ################################################################################ create Herwig::FIgx2ggxDipoleKernel FIgx2ggxDipoleKernel set FIgx2ggxDipoleKernel:PDFRatio PDFRatio set FIgx2ggxDipoleKernel:SplittingKinematics /Herwig/DipoleShower/Kinematics/FILightKinematics insert /Herwig/DipoleShower/DipoleShowerHandler:Kernels 0 FIgx2ggxDipoleKernel create Herwig::FIqx2qgxDipoleKernel FIqx2qgxDipoleKernel set FIqx2qgxDipoleKernel:PDFRatio PDFRatio set FIqx2qgxDipoleKernel:SplittingKinematics /Herwig/DipoleShower/Kinematics/FILightKinematics insert /Herwig/DipoleShower/DipoleShowerHandler:Kernels 0 FIqx2qgxDipoleKernel create Herwig::FIgx2qqxDipoleKernel FIgx2qqxDipoleKernel set FIgx2qqxDipoleKernel:PDFRatio PDFRatio set FIgx2qqxDipoleKernel:SplittingKinematics /Herwig/DipoleShower/Kinematics/FILightKinematics cp FIgx2qqxDipoleKernel FIgx2ddxDipoleKernel set FIgx2ddxDipoleKernel:Flavour /Herwig/Particles/d insert /Herwig/DipoleShower/DipoleShowerHandler:Kernels 0 FIgx2ddxDipoleKernel cp FIgx2qqxDipoleKernel FIgx2uuxDipoleKernel set FIgx2uuxDipoleKernel:Flavour /Herwig/Particles/u insert /Herwig/DipoleShower/DipoleShowerHandler:Kernels 0 FIgx2uuxDipoleKernel cp FIgx2qqxDipoleKernel FIgx2ccxDipoleKernel set FIgx2ccxDipoleKernel:Flavour /Herwig/Particles/c insert /Herwig/DipoleShower/DipoleShowerHandler:Kernels 0 FIgx2ccxDipoleKernel cp FIgx2qqxDipoleKernel FIgx2ssxDipoleKernel set FIgx2ssxDipoleKernel:Flavour /Herwig/Particles/s insert /Herwig/DipoleShower/DipoleShowerHandler:Kernels 0 FIgx2ssxDipoleKernel cp FIgx2qqxDipoleKernel FIgx2bbxDipoleKernel set FIgx2bbxDipoleKernel:Flavour /Herwig/Particles/b insert /Herwig/DipoleShower/DipoleShowerHandler:Kernels 0 FIgx2bbxDipoleKernel ### massive dipoles create Herwig::FIMqx2qgxDipoleKernel FIMqx2qgxDipoleKernel set FIMqx2qgxDipoleKernel:PDFRatio PDFRatio set FIMqx2qgxDipoleKernel:SplittingKinematics /Herwig/DipoleShower/Kinematics/FIMassiveKinematics cp FIMqx2qgxDipoleKernel FIMdx2dgxDipoleKernel set FIMdx2dgxDipoleKernel:Flavour /Herwig/Particles/d insert /Herwig/DipoleShower/DipoleShowerHandler:Kernels 0 FIMdx2dgxDipoleKernel cp FIMqx2qgxDipoleKernel FIMux2ugxDipoleKernel set FIMux2ugxDipoleKernel:Flavour /Herwig/Particles/u insert /Herwig/DipoleShower/DipoleShowerHandler:Kernels 0 FIMux2ugxDipoleKernel cp FIMqx2qgxDipoleKernel FIMcx2cgxDipoleKernel set FIMcx2cgxDipoleKernel:Flavour /Herwig/Particles/c insert /Herwig/DipoleShower/DipoleShowerHandler:Kernels 0 FIMcx2cgxDipoleKernel cp FIMqx2qgxDipoleKernel FIMsx2sgxDipoleKernel set FIMsx2sgxDipoleKernel:Flavour /Herwig/Particles/s insert /Herwig/DipoleShower/DipoleShowerHandler:Kernels 0 FIMsx2sgxDipoleKernel cp FIMqx2qgxDipoleKernel FIMbx2bgxDipoleKernel set FIMbx2bgxDipoleKernel:Flavour /Herwig/Particles/b insert /Herwig/DipoleShower/DipoleShowerHandler:Kernels 0 FIMbx2bgxDipoleKernel cp FIMqx2qgxDipoleKernel FIMtx2tgxDipoleKernel set FIMtx2tgxDipoleKernel:Flavour /Herwig/Particles/t insert /Herwig/DipoleShower/DipoleShowerHandler:Kernels 0 FIMtx2tgxDipoleKernel create Herwig::FIMgx2qqxDipoleKernel FIMgx2qqxDipoleKernel set FIMgx2qqxDipoleKernel:PDFRatio PDFRatio set FIMgx2qqxDipoleKernel:SplittingKinematics /Herwig/DipoleShower/Kinematics/FIMassiveKinematics cp FIMgx2qqxDipoleKernel FIMgx2ddxDipoleKernel set FIMgx2ddxDipoleKernel:Flavour /Herwig/Particles/d insert /Herwig/DipoleShower/DipoleShowerHandler:Kernels 0 FIMgx2ddxDipoleKernel cp FIMgx2qqxDipoleKernel FIMgx2uuxDipoleKernel set FIMgx2uuxDipoleKernel:Flavour /Herwig/Particles/u insert /Herwig/DipoleShower/DipoleShowerHandler:Kernels 0 FIMgx2uuxDipoleKernel cp FIMgx2qqxDipoleKernel FIMgx2ccxDipoleKernel set FIMgx2ccxDipoleKernel:Flavour /Herwig/Particles/c insert /Herwig/DipoleShower/DipoleShowerHandler:Kernels 0 FIMgx2ccxDipoleKernel cp FIMgx2qqxDipoleKernel FIMgx2ssxDipoleKernel set FIMgx2ssxDipoleKernel:Flavour /Herwig/Particles/s insert /Herwig/DipoleShower/DipoleShowerHandler:Kernels 0 FIMgx2ssxDipoleKernel cp FIMgx2qqxDipoleKernel FIMgx2bbxDipoleKernel set FIMgx2bbxDipoleKernel:Flavour /Herwig/Particles/b insert /Herwig/DipoleShower/DipoleShowerHandler:Kernels 0 FIMgx2bbxDipoleKernel #cp FIMgx2qqxDipoleKernel FIMgx2ttxDipoleKernel #set FIMgx2ttxDipoleKernel:Flavour /Herwig/Particles/t #insert /Herwig/DipoleShower/DipoleShowerHandler:Kernels 0 FIMgx2ttxDipoleKernel ################################################################################ # IF ################################################################################ create Herwig::IFgx2ggxDipoleKernel IFgx2ggxDipoleKernel set IFgx2ggxDipoleKernel:PDFRatio PDFRatio set IFgx2ggxDipoleKernel:SplittingKinematics /Herwig/DipoleShower/Kinematics/IFLightKinematics insert /Herwig/DipoleShower/DipoleShowerHandler:Kernels 0 IFgx2ggxDipoleKernel create Herwig::IFqx2qgxDipoleKernel IFqx2qgxDipoleKernel set IFqx2qgxDipoleKernel:PDFRatio PDFRatio set IFqx2qgxDipoleKernel:SplittingKinematics /Herwig/DipoleShower/Kinematics/IFLightKinematics insert /Herwig/DipoleShower/DipoleShowerHandler:Kernels 0 IFqx2qgxDipoleKernel create Herwig::IFqx2gqxDipoleKernel IFqx2gqxDipoleKernel set IFqx2gqxDipoleKernel:PDFRatio PDFRatio set IFqx2gqxDipoleKernel:SplittingKinematics /Herwig/DipoleShower/Kinematics/IFLightKinematics insert /Herwig/DipoleShower/DipoleShowerHandler:Kernels 0 IFqx2gqxDipoleKernel create Herwig::IFgx2qqxDipoleKernel IFgx2qqxDipoleKernel set IFgx2qqxDipoleKernel:PDFRatio PDFRatio set IFgx2qqxDipoleKernel:SplittingKinematics /Herwig/DipoleShower/Kinematics/IFLightKinematics cp IFgx2qqxDipoleKernel IFgx2ddbarxDipoleKernel set IFgx2ddbarxDipoleKernel:Flavour /Herwig/Particles/d insert /Herwig/DipoleShower/DipoleShowerHandler:Kernels 0 IFgx2ddbarxDipoleKernel cp IFgx2qqxDipoleKernel IFgx2dbardxDipoleKernel set IFgx2dbardxDipoleKernel:Flavour /Herwig/Particles/dbar insert /Herwig/DipoleShower/DipoleShowerHandler:Kernels 0 IFgx2dbardxDipoleKernel cp IFgx2qqxDipoleKernel IFgx2uubarxDipoleKernel set IFgx2uubarxDipoleKernel:Flavour /Herwig/Particles/u insert /Herwig/DipoleShower/DipoleShowerHandler:Kernels 0 IFgx2uubarxDipoleKernel cp IFgx2qqxDipoleKernel IFgx2ubaruxDipoleKernel set IFgx2ubaruxDipoleKernel:Flavour /Herwig/Particles/ubar insert /Herwig/DipoleShower/DipoleShowerHandler:Kernels 0 IFgx2ubaruxDipoleKernel cp IFgx2qqxDipoleKernel IFgx2ccbarxDipoleKernel set IFgx2ccbarxDipoleKernel:Flavour /Herwig/Particles/c insert /Herwig/DipoleShower/DipoleShowerHandler:Kernels 0 IFgx2ccbarxDipoleKernel cp IFgx2qqxDipoleKernel IFgx2cbarcxDipoleKernel set IFgx2cbarcxDipoleKernel:Flavour /Herwig/Particles/cbar insert /Herwig/DipoleShower/DipoleShowerHandler:Kernels 0 IFgx2cbarcxDipoleKernel cp IFgx2qqxDipoleKernel IFgx2ssbarxDipoleKernel set IFgx2ssbarxDipoleKernel:Flavour /Herwig/Particles/s insert /Herwig/DipoleShower/DipoleShowerHandler:Kernels 0 IFgx2ssbarxDipoleKernel cp IFgx2qqxDipoleKernel IFgx2sbarsxDipoleKernel set IFgx2sbarsxDipoleKernel:Flavour /Herwig/Particles/sbar insert /Herwig/DipoleShower/DipoleShowerHandler:Kernels 0 IFgx2sbarsxDipoleKernel +cp IFgx2qqxDipoleKernel IFgx2bbbarxDipoleKernel +set IFgx2bbbarxDipoleKernel:Flavour /Herwig/Particles/b +insert /Herwig/DipoleShower/DipoleShowerHandler:Kernels 0 IFgx2bbbarxDipoleKernel + +cp IFgx2qqxDipoleKernel IFgx2bbarbxDipoleKernel +set IFgx2bbarbxDipoleKernel:Flavour /Herwig/Particles/bbar +insert /Herwig/DipoleShower/DipoleShowerHandler:Kernels 0 IFgx2bbarbxDipoleKernel + + + ### massive dipoles create Herwig::IFMgx2ggxDipoleKernel IFMgx2ggxDipoleKernel set IFMgx2ggxDipoleKernel:PDFRatio PDFRatio set IFMgx2ggxDipoleKernel:SplittingKinematics /Herwig/DipoleShower/Kinematics/IFMassiveKinematics insert /Herwig/DipoleShower/DipoleShowerHandler:Kernels 0 IFMgx2ggxDipoleKernel create Herwig::IFMqx2qgxDipoleKernel IFMqx2qgxDipoleKernel set IFMqx2qgxDipoleKernel:PDFRatio PDFRatio set IFMqx2qgxDipoleKernel:SplittingKinematics /Herwig/DipoleShower/Kinematics/IFMassiveKinematics insert /Herwig/DipoleShower/DipoleShowerHandler:Kernels 0 IFMqx2qgxDipoleKernel create Herwig::IFMqx2gqxDipoleKernel IFMqx2gqxDipoleKernel set IFMqx2gqxDipoleKernel:PDFRatio PDFRatio set IFMqx2gqxDipoleKernel:SplittingKinematics /Herwig/DipoleShower/Kinematics/IFMassiveKinematics insert /Herwig/DipoleShower/DipoleShowerHandler:Kernels 0 IFMqx2gqxDipoleKernel create Herwig::IFMgx2qqxDipoleKernel IFMgx2qqxDipoleKernel set IFMgx2qqxDipoleKernel:PDFRatio PDFRatio set IFMgx2qqxDipoleKernel:SplittingKinematics /Herwig/DipoleShower/Kinematics/IFMassiveKinematics +cp IFMgx2qqxDipoleKernel IFMgx2bbbarxDipoleKernel +set IFMgx2bbbarxDipoleKernel:Flavour /Herwig/Particles/b +insert /Herwig/DipoleShower/DipoleShowerHandler:Kernels 0 IFMgx2bbbarxDipoleKernel + +cp IFMgx2qqxDipoleKernel IFMgx2bbarbxDipoleKernel +set IFMgx2bbarbxDipoleKernel:Flavour /Herwig/Particles/bbar +insert /Herwig/DipoleShower/DipoleShowerHandler:Kernels 0 IFMgx2bbarbxDipoleKernel + cp IFMgx2qqxDipoleKernel IFMgx2ddbarxDipoleKernel set IFMgx2ddbarxDipoleKernel:Flavour /Herwig/Particles/d insert /Herwig/DipoleShower/DipoleShowerHandler:Kernels 0 IFMgx2ddbarxDipoleKernel cp IFMgx2qqxDipoleKernel IFMgx2dbardxDipoleKernel set IFMgx2dbardxDipoleKernel:Flavour /Herwig/Particles/dbar insert /Herwig/DipoleShower/DipoleShowerHandler:Kernels 0 IFMgx2dbardxDipoleKernel cp IFMgx2qqxDipoleKernel IFMgx2uubarxDipoleKernel set IFMgx2uubarxDipoleKernel:Flavour /Herwig/Particles/u insert /Herwig/DipoleShower/DipoleShowerHandler:Kernels 0 IFMgx2uubarxDipoleKernel cp IFMgx2qqxDipoleKernel IFMgx2ubaruxDipoleKernel set IFMgx2ubaruxDipoleKernel:Flavour /Herwig/Particles/ubar insert /Herwig/DipoleShower/DipoleShowerHandler:Kernels 0 IFMgx2ubaruxDipoleKernel cp IFMgx2qqxDipoleKernel IFMgx2ccbarxDipoleKernel set IFMgx2ccbarxDipoleKernel:Flavour /Herwig/Particles/c insert /Herwig/DipoleShower/DipoleShowerHandler:Kernels 0 IFMgx2ccbarxDipoleKernel cp IFMgx2qqxDipoleKernel IFMgx2cbarcxDipoleKernel set IFMgx2cbarcxDipoleKernel:Flavour /Herwig/Particles/cbar insert /Herwig/DipoleShower/DipoleShowerHandler:Kernels 0 IFMgx2cbarcxDipoleKernel cp IFMgx2qqxDipoleKernel IFMgx2ssbarxDipoleKernel set IFMgx2ssbarxDipoleKernel:Flavour /Herwig/Particles/s insert /Herwig/DipoleShower/DipoleShowerHandler:Kernels 0 IFMgx2ssbarxDipoleKernel cp IFMgx2qqxDipoleKernel IFMgx2sbarsxDipoleKernel set IFMgx2sbarsxDipoleKernel:Flavour /Herwig/Particles/sbar insert /Herwig/DipoleShower/DipoleShowerHandler:Kernels 0 IFMgx2sbarsxDipoleKernel ################################################################################ # II ################################################################################ create Herwig::IIgx2ggxDipoleKernel IIgx2ggxDipoleKernel set IIgx2ggxDipoleKernel:PDFRatio PDFRatio set IIgx2ggxDipoleKernel:SplittingKinematics /Herwig/DipoleShower/Kinematics/IILightKinematics insert /Herwig/DipoleShower/DipoleShowerHandler:Kernels 0 IIgx2ggxDipoleKernel create Herwig::IIqx2qgxDipoleKernel IIqx2qgxDipoleKernel set IIqx2qgxDipoleKernel:PDFRatio PDFRatio set IIqx2qgxDipoleKernel:SplittingKinematics /Herwig/DipoleShower/Kinematics/IILightKinematics insert /Herwig/DipoleShower/DipoleShowerHandler:Kernels 0 IIqx2qgxDipoleKernel create Herwig::IIqx2gqxDipoleKernel IIqx2gqxDipoleKernel set IIqx2gqxDipoleKernel:PDFRatio PDFRatio set IIqx2gqxDipoleKernel:SplittingKinematics /Herwig/DipoleShower/Kinematics/IILightKinematics insert /Herwig/DipoleShower/DipoleShowerHandler:Kernels 0 IIqx2gqxDipoleKernel create Herwig::IIgx2qqxDipoleKernel IIgx2qqxDipoleKernel set IIgx2qqxDipoleKernel:PDFRatio PDFRatio set IIgx2qqxDipoleKernel:SplittingKinematics /Herwig/DipoleShower/Kinematics/IILightKinematics cp IIgx2qqxDipoleKernel IIgx2ddbarxDipoleKernel set IIgx2ddbarxDipoleKernel:Flavour /Herwig/Particles/d insert /Herwig/DipoleShower/DipoleShowerHandler:Kernels 0 IIgx2ddbarxDipoleKernel cp IIgx2qqxDipoleKernel IIgx2dbardxDipoleKernel set IIgx2dbardxDipoleKernel:Flavour /Herwig/Particles/dbar insert /Herwig/DipoleShower/DipoleShowerHandler:Kernels 0 IIgx2dbardxDipoleKernel cp IIgx2qqxDipoleKernel IIgx2uubarxDipoleKernel set IIgx2uubarxDipoleKernel:Flavour /Herwig/Particles/u insert /Herwig/DipoleShower/DipoleShowerHandler:Kernels 0 IIgx2uubarxDipoleKernel cp IIgx2qqxDipoleKernel IIgx2ubaruxDipoleKernel set IIgx2ubaruxDipoleKernel:Flavour /Herwig/Particles/ubar insert /Herwig/DipoleShower/DipoleShowerHandler:Kernels 0 IIgx2ubaruxDipoleKernel cp IIgx2qqxDipoleKernel IIgx2ccbarxDipoleKernel set IIgx2ccbarxDipoleKernel:Flavour /Herwig/Particles/c insert /Herwig/DipoleShower/DipoleShowerHandler:Kernels 0 IIgx2ccbarxDipoleKernel cp IIgx2qqxDipoleKernel IIgx2cbarcxDipoleKernel set IIgx2cbarcxDipoleKernel:Flavour /Herwig/Particles/cbar insert /Herwig/DipoleShower/DipoleShowerHandler:Kernels 0 IIgx2cbarcxDipoleKernel cp IIgx2qqxDipoleKernel IIgx2ssbarxDipoleKernel set IIgx2ssbarxDipoleKernel:Flavour /Herwig/Particles/s insert /Herwig/DipoleShower/DipoleShowerHandler:Kernels 0 IIgx2ssbarxDipoleKernel cp IIgx2qqxDipoleKernel IIgx2sbarsxDipoleKernel set IIgx2sbarsxDipoleKernel:Flavour /Herwig/Particles/sbar insert /Herwig/DipoleShower/DipoleShowerHandler:Kernels 0 IIgx2sbarsxDipoleKernel +cp IIgx2qqxDipoleKernel IIgx2bbbarxDipoleKernel +set IIgx2bbbarxDipoleKernel:Flavour /Herwig/Particles/b +insert /Herwig/DipoleShower/DipoleShowerHandler:Kernels 0 IIgx2bbbarxDipoleKernel + +cp IIgx2qqxDipoleKernel IIgx2bbarbxDipoleKernel +set IIgx2bbarbxDipoleKernel:Flavour /Herwig/Particles/bbar +insert /Herwig/DipoleShower/DipoleShowerHandler:Kernels 0 IIgx2bbarbxDipoleKernel + + ################################################################################ # Decays ################################################################################ # Currently only tested for top-quark decays ################################################################################ # q -> qg + t -> tg ################################################################################ create Herwig::FIMDecayqx2qgxDipoleKernelFull FIMDecayqx2qgxDipoleKernelFull set FIMDecayqx2qgxDipoleKernelFull:SplittingKinematics /Herwig/DipoleShower/Kinematics/FIMassiveDecayKinematics cp FIMDecayqx2qgxDipoleKernelFull FIMDecaybx2bgxDipoleKernelFull set FIMDecaybx2bgxDipoleKernelFull:Flavour /Herwig/Particles/b insert /Herwig/DipoleShower/DipoleShowerHandler:Kernels 0 FIMDecaybx2bgxDipoleKernelFull cp FIMDecayqx2qgxDipoleKernelFull FIMDecaydx2dgxDipoleKernelFull set FIMDecaydx2dgxDipoleKernelFull:Flavour /Herwig/Particles/d insert /Herwig/DipoleShower/DipoleShowerHandler:Kernels 0 FIMDecaydx2dgxDipoleKernelFull cp FIMDecayqx2qgxDipoleKernelFull FIMDecayux2ugxDipoleKernelFull set FIMDecayux2ugxDipoleKernelFull:Flavour /Herwig/Particles/u insert /Herwig/DipoleShower/DipoleShowerHandler:Kernels 0 FIMDecayux2ugxDipoleKernelFull cp FIMDecayqx2qgxDipoleKernelFull FIMDecaysx2sgxDipoleKernelFull set FIMDecaysx2sgxDipoleKernelFull:Flavour /Herwig/Particles/s insert /Herwig/DipoleShower/DipoleShowerHandler:Kernels 0 FIMDecaysx2sgxDipoleKernelFull cp FIMDecayqx2qgxDipoleKernelFull FIMDecaycx2cgxDipoleKernelFull set FIMDecaycx2cgxDipoleKernelFull:Flavour /Herwig/Particles/c insert /Herwig/DipoleShower/DipoleShowerHandler:Kernels 0 FIMDecaycx2cgxDipoleKernelFull ################################################################################ ## g -> gg + t -> tg ################################################################################ create Herwig::FIMDecaygx2ggxDipoleKernelFull FIMDecaygx2ggxDipoleKernelFull set FIMDecaygx2ggxDipoleKernelFull:SplittingKinematics /Herwig/DipoleShower/Kinematics/FIMassiveDecayKinematics insert /Herwig/DipoleShower/DipoleShowerHandler:Kernels 0 FIMDecaygx2ggxDipoleKernelFull ############# ## g -> qq ## ############# create Herwig::FIMDecaygx2qqxDipoleKernel FIMDecaygx2qqxDipoleKernel set FIMDecaygx2qqxDipoleKernel:SplittingKinematics /Herwig/DipoleShower/Kinematics/FIMassiveDecayKinematics cp FIMDecaygx2qqxDipoleKernel FIMDecaygx2ddxDipoleKernel set FIMDecaygx2ddxDipoleKernel:Flavour /Herwig/Particles/d insert /Herwig/DipoleShower/DipoleShowerHandler:Kernels 0 FIMDecaygx2ddxDipoleKernel cp FIMDecaygx2qqxDipoleKernel FIMDecaygx2uuxDipoleKernel set FIMDecaygx2uuxDipoleKernel:Flavour /Herwig/Particles/u insert /Herwig/DipoleShower/DipoleShowerHandler:Kernels 0 FIMDecaygx2uuxDipoleKernel cp FIMDecaygx2qqxDipoleKernel FIMDecaygx2ssxDipoleKernel set FIMDecaygx2ssxDipoleKernel:Flavour /Herwig/Particles/s insert /Herwig/DipoleShower/DipoleShowerHandler:Kernels 0 FIMDecaygx2ssxDipoleKernel cp FIMDecaygx2qqxDipoleKernel FIMDecaygx2ccxDipoleKernel set FIMDecaygx2ccxDipoleKernel:Flavour /Herwig/Particles/c insert /Herwig/DipoleShower/DipoleShowerHandler:Kernels 0 FIMDecaygx2ccxDipoleKernel cp FIMDecaygx2qqxDipoleKernel FIMDecaygx2bbxDipoleKernel set FIMDecaygx2bbxDipoleKernel:Flavour /Herwig/Particles/b insert /Herwig/DipoleShower/DipoleShowerHandler:Kernels 0 FIMDecaygx2bbxDipoleKernel cd / ################################################################################ # Setup the dipole shower parameters ################################################################################ cd /Herwig/DipoleShower ################################################################################ # matching parameters ################################################################################ set /Herwig/MatrixElements/Matchbox/MEMatching:FFPtCut 1.0*GeV set /Herwig/MatrixElements/Matchbox/MEMatching:FFScreeningScale 0.0*GeV set /Herwig/MatrixElements/Matchbox/MEMatching:FIPtCut 1.0*GeV set /Herwig/MatrixElements/Matchbox/MEMatching:FIScreeningScale 0.0*GeV set /Herwig/MatrixElements/Matchbox/MEMatching:IIPtCut 1.0*GeV set /Herwig/MatrixElements/Matchbox/MEMatching:IIScreeningScale 0.0*GeV set /Herwig/MatrixElements/Matchbox/DipoleMatching:ShowerHandler /Herwig/DipoleShower/DipoleShowerHandler set /Herwig/MatrixElements/Matchbox/DipoleMatching:FFPtCut 1.0*GeV set /Herwig/MatrixElements/Matchbox/DipoleMatching:FFScreeningScale 0.0*GeV set /Herwig/MatrixElements/Matchbox/DipoleMatching:FIPtCut 1.0*GeV set /Herwig/MatrixElements/Matchbox/DipoleMatching:FIScreeningScale 0.0*GeV set /Herwig/MatrixElements/Matchbox/DipoleMatching:IIPtCut 1.0*GeV set /Herwig/MatrixElements/Matchbox/DipoleMatching:IIScreeningScale 0.0*GeV ################################################################################ # shower parameters ################################################################################ set DipoleShowerHandler:GlobalAlphaS NLOAlphaS set DipoleShowerHandler:EvolutionOrdering ChainPtOrdering set IntrinsicPtGenerator:ValenceIntrinsicPtScale 1.26905*GeV set IntrinsicPtGenerator:SeaIntrinsicPtScale 1.1613*GeV cd /Herwig/DipoleShower/Kinematics set FFLightKinematics:IRCutoff 1.014259*GeV set FILightKinematics:IRCutoff 1.0*GeV set IFLightKinematics:IRCutoff 1.0*GeV set IILightKinematics:IRCutoff 1.0*GeV set FFMassiveKinematics:IRCutoff 1.014259*GeV set FIMassiveKinematics:IRCutoff 1.0*GeV set IFMassiveKinematics:IRCutoff 1.0*GeV set FIMassiveDecayKinematics:IRCutoff 1.0*GeV cd /