diff --git a/Decay/Baryon/BaryonFactorizedDecayer.cc b/Decay/Baryon/BaryonFactorizedDecayer.cc --- a/Decay/Baryon/BaryonFactorizedDecayer.cc +++ b/Decay/Baryon/BaryonFactorizedDecayer.cc @@ -1,809 +1,809 @@ // -*- C++ -*- // // This is the implementation of the non-inlined, non-templated member // functions of the BaryonFactorizedDecayer class. // #include "BaryonFactorizedDecayer.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Interface/Parameter.h" #include "ThePEG/Interface/ParVector.h" #include "ThePEG/Interface/Reference.h" #include "ThePEG/PDT/DecayMode.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/Interface/Parameter.h" #include "ThePEG/Helicity/WaveFunction/SpinorWaveFunction.h" #include "ThePEG/Helicity/WaveFunction/SpinorBarWaveFunction.h" #include "ThePEG/Helicity/WaveFunction/RSSpinorWaveFunction.h" #include "ThePEG/Helicity/WaveFunction/RSSpinorBarWaveFunction.h" #include "Herwig/Decay/DecayVertex.h" #include "ThePEG/Helicity/FermionSpinInfo.h" #include "ThePEG/Helicity/RSFermionSpinInfo.h" #include "ThePEG/StandardModel/StandardModelBase.h" #include "Herwig/Decay/GeneralDecayMatrixElement.h" using namespace Herwig; using namespace ThePEG::Helicity; BaryonFactorizedDecayer::BaryonFactorizedDecayer() { // default values taken from PRD56, 2799 _a1c= 1.1; _a2c=-0.5; _a1b= 1.0; _a2b= 0.28; // intermediates generateIntermediates(true); } void BaryonFactorizedDecayer::doinitrun() { _current->initrun(); _form->initrun(); DecayIntegrator::doinitrun(); _weights.clear();_wgtloc.clear();_wgtmax.clear(); for(unsigned int ix=0;ixmaxWeight()); _wgtloc.push_back(_weights.size()); for(unsigned int iy=0;iychannels().size();++iy) _weights.push_back(mode(ix)->channels()[iy].weight()); } } void BaryonFactorizedDecayer::doinit() { DecayIntegrator::doinit(); // get the CKM matrix (unsquared for interference) Complex ckmmat[3][3]; vector< vector > CKM(_theCKM->getUnsquaredMatrix(SM().families())); for(unsigned int ix=0;ix<3;++ix) { for(unsigned int iy=0;iy<3;++iy) { ckmmat[ix][iy]=CKM[ix][iy]; } } // make sure the current and form factor got initialised _current->init(); _form->init(); // find all the possible modes vector tformmap,tcurrmap; vector inquark,outquark,currq,curra; tPDVector incoming; vector outgoing; for(unsigned int iform=0;iform<_form->numberOfFactors();++iform) { // particles from the form factor int id0,id1; _form->particleID (iform,id0,id1); int spect1,spect2,inq,outq,ispin,ospin; _form->formFactorInfo(iform,ispin,ospin,spect1,spect2,inq,outq); // particles from the form factor tPDPtr in = getParticleData(id0); tPDPtr out = getParticleData(id1); // the charge of the decay products int Wcharge = in->iCharge()-out->iCharge(); // max mass for the particles in the current Energy min = in->massMax()-out->massMin(); for(unsigned int icurr=0;icurr<_current->numberOfModes();++icurr) { // get the particles from the current int iq,ia; _current->decayModeInfo(icurr,iq,ia); tPDVector ptemp=_current->particles(Wcharge,icurr,iq,ia); tPDVector outV = {out}; outV.insert(std::end(outV), std::begin(ptemp), std::end(ptemp)); Energy minb=ZERO; for(unsigned int iz=0;izmassMin(); // valid mode if(outV.size()>1&&minb0&&inq%2!=iq%2)|| (inq<0&&abs(inq)%2!=abs(ia)%2))))) { tformmap.push_back(iform);tcurrmap.push_back(icurr); incoming.push_back(in); outgoing.push_back(outV); inquark.push_back(inq);outquark.push_back(outq); currq.push_back(iq);curra.push_back(ia); } // if the meson is neutral try the CC mode if(Wcharge==0&&iq!=-ia&&((inq>0&&inq%2!=iq%2)|| (inq<0&&abs(inq)%2!=abs(ia)%2))) { ptemp=_current->particles(Wcharge,icurr,-ia,-iq); tPDVector outV = {out}; outV.insert(std::end(outV), std::begin(ptemp), std::end(ptemp)); Energy minb=ZERO; for(unsigned int iz=0;izmassMin(); if(outV.size()>1&&minb modeloc; vector modecc; findModes(ix,incoming,outgoing,modeloc,modecc); // if more than two outgoing particles only allow one diagram if ( outgoing[ix].size() > 2 && !modeloc.empty() ) {break;} // create the mode and set the particles as for the first instance PhaseSpaceModePtr mode=new_ptr(PhaseSpaceMode(incoming[ix],outgoing[ix],1.)); PhaseSpaceChannel channel((PhaseSpaceChannel(mode),0,1)); Energy min = incoming[ix]->massMax()-outgoing[ix][0]->massMin(); int Wcharge = incoming[ix]->iCharge()-outgoing[ix][0]->iCharge(); bool done = _current->createMode(Wcharge,tcPDPtr(),FlavourInfo(), tcurrmap[ix],mode,1,0,channel,min); if(!done){throw InitException() << "Failed to construct mode in " << "BaryonFactorizedDecayer::doinit()." << Exception::abortnow;} // set the parameters for the additional modes vectorttform,ttcurr; ttform.push_back(tformmap[ix]);ttcurr.push_back(tcurrmap[ix]); for(unsigned int iy=0;iy tCKM; Complex ckm; + vector tCKM; for(unsigned int iy=0;iyparticleID(ttform[iy],id0,id1); int Wcharge = getParticleData(id0)->iCharge()-getParticleData(id1)->iCharge(); Complex ckm=1.; if(Wcharge!=0) { if(abs(iq)%2==0){ckm *= conj(ckmmat[abs(iq)/2-1][(abs(ia)-1)/2]);} else{ckm *= conj(ckmmat[abs(ia)/2-1][(abs(iq)-1)/2]);} if(abs(inq)%2==0){ckm *= ckmmat[abs(inq)/2-1][(abs(outq)-1)/2];} else{ckm *= ckmmat[abs(outq)/2-1][(abs(inq)-1)/2];} if(abs(inq)==5){ckm*=_a1b;} else{ckm*=_a1c;} } else { if(inq>0) { if(abs(inq)%2==0){ckm *= ckmmat[abs(inq)/2-1][(abs(iq)-1)/2];} else{ckm *= ckmmat[abs(iq)/2-1][(abs(inq)-1)/2];} if(abs(outq)%2==0) {ckm *= conj(ckmmat[abs(outq)/2-1][(abs(ia)-1)/2]);} else{ckm *= conj(ckmmat[abs(ia)/2-1][(abs(outq)-1)/2]);} } else { if(abs(inq)%2==0){ckm *= ckmmat[abs(inq)/2-1][(abs(ia)-1)/2];} else{ckm *= ckmmat[abs(ia)/2-1][(abs(inq)-1)/2];} if(abs(outq)%2==0) {ckm *= conj(ckmmat[abs(outq)/2-1][(abs(iq)-1)/2]);} else{ckm *= conj(ckmmat[abs(iq)/2-1][(abs(outq)-1)/2]);} } if(abs(inq)==5){ckm*=_a2b;} else{ckm*=_a2c;} } if((abs(inq)%2==0&&inq<0)||(abs(inq)%2!=0&&inq>0)){ckm=conj(ckm);} tCKM.push_back(ckm); } // add the parameters for the mode to the list _currentmap.push_back(ttcurr); _formmap.push_back(ttform); _factCKM.push_back(tCKM); double maxweight(0.); // add the mode to the list if(_wgtmax.size()>numberModes()) maxweight=_wgtmax[numberModes()]; // the weights for the channel vector channelwgts; if(_wgtloc.size()>numberModes()&& _wgtloc[numberModes()]+mode->channels().size()<=_weights.size()) { vector::iterator start=_weights.begin()+_wgtloc[numberModes()]; vector::iterator end = start+mode->channels().size(); channelwgts=vector(start,end); } else { channelwgts.resize(mode->channels().size(),1./(mode->channels().size())); } // don't need channels for two body decays if(outgoing[ix].size()==2) { channelwgts.clear(); mode = new_ptr(PhaseSpaceMode(incoming[ix],outgoing[ix],maxweight)); } else { mode->maxWeight(maxweight); mode->setWeights(channelwgts); } addMode(mode); // resize the duplicate modes to remove them for(unsigned int iy=0;iyid()),ibaryon,foundb,id0,id1; vector idall,idother; tPDVector::const_iterator pit = children.begin(); tPDVector::const_iterator pend = children.end(); for( ; pit!=pend;++pit){idall.push_back((**pit).id());} // loop over the particles in the form factor do { _form->particleID(iform,id0,id1); ibaryon=0; if(id0==idin){ibaryon=id1;} else if(id0==-idin){ibaryon=-id1;} if(ibaryon!=0) { foundb=false; idother.clear(); for(ix=0;ixaccept(idother);} } ++iform; } while(!allowed&&iform<_form->numberOfFactors()); return allowed; } int BaryonFactorizedDecayer::modeNumber(bool & cc,tcPDPtr parent, const tPDVector & children) const { unsigned int ix,iy; int idin(parent->id()),ibaryon,foundb,id0,id1,icurr(-1),iform(0); vector idall,idother; tPDVector::const_iterator pit = children.begin(); tPDVector::const_iterator pend = children.end(); for( ; pit!=pend;++pit){idall.push_back((**pit).id());} // loop over the particles in the form factor do { _form->particleID(iform,id0,id1); ibaryon=0; if(id0==idin){ibaryon=id1;} else if(id0==-idin){ibaryon=-id1;} ++iform; foundb=false; idother.clear(); for(ix=0;ixdecayMode(idother);} } while(icurr<0&&iformnumberOfFactors())); // now find the mode int imode=-1; ix=0; --iform; do { for(iy=0;iy<_currentmap[ix].size();++iy) {if(int(_currentmap[ix][iy])==icurr&&int(_formmap[ix][iy])==iform){imode=ix;}} ++ix; } while(imode<0&&ix> _current >> _form >> _a1b >> _a2b >>_a1c >>_a2c >> _currentmap >> _formmap >> _factCKM >> _wgtloc >> _wgtmax >> _weights >> _theCKM; } // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeHerwigBaryonFactorizedDecayer("Herwig::BaryonFactorizedDecayer", "HwBaryonDecay.so"); void BaryonFactorizedDecayer::Init() { static ClassDocumentation documentation ("The BaryonFactorizedDecayer class combines the baryon form factor and a" " weak current to perform a decay in the naive factorization approximation."); static Reference interfaceWeakCurrent ("Current", "The reference for the decay current to be used.", &BaryonFactorizedDecayer::_current, false, false, true, false, false); static ParVector interfaceWeightLocation ("WeightLocation", "The locations of the weights for a given channel in the vector", &BaryonFactorizedDecayer::_wgtloc, 0, 0, 0, 0, 10000, false, false, true); static ParVector interfaceWeightMax ("MaximumWeight", "The maximum weight for a given channel.", &BaryonFactorizedDecayer::_wgtmax, 0, 0, 0, 0., 100., false, false, true); static ParVector interfaceWeights ("Weights", "The weights for the integration.", &BaryonFactorizedDecayer::_weights, 0, 0, 0, 0., 1., false, false, true); static Reference interfaceFormFactor ("FormFactor", "The form-factor", &BaryonFactorizedDecayer::_form, true, true, true, false, false); static Parameter interfacea1Bottom ("a1Bottom", "The factorization paramter a_1 for decays of bottom baryons", &BaryonFactorizedDecayer::_a1b, 1., -10.0, 10.0, false, false, true); static Parameter interfacea2Bottom ("a2Bottom", "The factorization paramter a_2 for decays of bottom baryons", &BaryonFactorizedDecayer::_a2b, 0.28, -10.0, 10.0, false, false, true); static Parameter interfacea1Charm ("a1Charm", "The factorization paramter a_1 for decays of charm baryons", &BaryonFactorizedDecayer::_a1c, 1.1, -10.0, 10.0, false, false, true); static Parameter interfacea2Charm ("a2Charm", "The factorization paramter a_2 for decays of charm baryons", &BaryonFactorizedDecayer::_a2c, -0.5, -10.0, 10.0, false, false, true); static Reference interfaceCKM ("CKM", "Reference to the Standard Model object", &BaryonFactorizedDecayer::_theCKM, false, false, true, false); } void BaryonFactorizedDecayer:: constructSpinInfo(const Particle & part, ParticleVector decay) const { // for the decaying particle if(part.id()>0) { SpinorWaveFunction:: constructSpinInfo(_inHalf,const_ptr_cast(&part),incoming,true); } else { SpinorBarWaveFunction:: constructSpinInfo(_inHalfBar,const_ptr_cast(&part),incoming,true); } // decay product // spin 1/2 if(decay[0]->dataPtr()->iSpin()==PDT::Spin1Half) { if(part.id()>0) { SpinorBarWaveFunction::constructSpinInfo(_inHalfBar,decay[0],outgoing,true); } else { SpinorWaveFunction::constructSpinInfo(_inHalf,decay[0],outgoing,true); } } // spin 3/2 else if(decay[0]->dataPtr()->iSpin()==PDT::Spin3Half) { if(part.id()>0) { RSSpinorBarWaveFunction::constructSpinInfo(_inThreeHalfBar, decay[0],outgoing,true); } else { RSSpinorWaveFunction::constructSpinInfo(_inThreeHalf, decay[0],outgoing,true); } } else assert(false); // and the stuff from the current _current->constructSpinInfo(ParticleVector(decay.begin()+1,decay.end())); } double BaryonFactorizedDecayer::me2(const int ichan, const Particle & part, const tPDVector & outgoing, const vector & momenta, MEOption meopt) const { double me(0.); assert(part.dataPtr()->iSpin()==PDT::Spin1Half); if(outgoing[0]->iSpin()==PDT::Spin1Half) me=halfHalf(ichan,part,outgoing,momenta,meopt); else if(outgoing[0]->iSpin()==PDT::Spin3Half) me=halfThreeHalf(ichan,part,outgoing,momenta,meopt); else assert(false); return me; } // matrix element for a 1/2 -> 1/2 decay double BaryonFactorizedDecayer::halfHalf(const int ichan, const Particle & part, const tPDVector & outgoing, const vector & momenta, MEOption meopt) const { Energy scale; // extract the spins of the particles vector spin; for(unsigned ix=0;ixiSpin()); if(!ME()) ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin1Half,spin))); if(meopt==Initialize) { // spinors and rho if(part.id()>0) SpinorWaveFunction ::calculateWaveFunctions(_inHalf,_rho, const_ptr_cast(&part), incoming); else SpinorBarWaveFunction::calculateWaveFunctions(_inHalfBar,_rho, const_ptr_cast(&part), incoming); } ME()->zero(); // spinors for the decay product if(part.id()>0) { _inHalfBar.resize(2); for(unsigned int ihel=0;ihel<2;++ihel) _inHalfBar[ihel] = HelicityFunctions::dimensionedSpinorBar(-momenta[0],ihel,Helicity::outgoing); } else { _inHalf.resize(2); for(unsigned int ihel=0;ihel<2;++ihel) _inHalf[ihel] = HelicityFunctions::dimensionedSpinor (-momenta[0],ihel,Helicity::outgoing); } // get the information on the form-factor int id0(part.id()),id1(outgoing[0]->id()); // work out the value of q and calculate the form factors Lorentz5Momentum q(part.momentum()-momenta[0]); q.rescaleMass(); Energy m0(part.mass()),m1(momenta[0].mass()); Energy2 q2(q.mass2()); Lorentz5Momentum sum(part.momentum()+momenta[0]); // calculate the baryonic part of the current for the decay double pre(0.); for(unsigned int mode=0;mode<_formmap[imode()].size();++mode) { Complex f1v,f2v,f3v,f1a,f2a,f3a; // calculate the form factor piece _form->SpinHalfSpinHalfFormFactor(q2,_formmap[imode()][mode],id0,id1,m0,m1, f1v,f2v,f3v,f1a,f2a,f3a,FlavourInfo()); Complex left = f1v-f1a-f2v-double((m0-m1)/(m0+m1))*f2a; Complex right = f1v+f1a-f2v+double((m0-m1)/(m0+m1))*f2a; vector baryon(4); for(unsigned int ix=0;ix<2;++ix) { for(unsigned int iy=0;iy<2;++iy) { LorentzPolarizationVectorE vtemp = _inHalf[ix].generalCurrent(_inHalfBar[iy],left,right); complex vspin=_inHalf[ix].scalar(_inHalfBar[iy]); complex aspin=_inHalf[ix].pseudoScalar(_inHalfBar[iy]); // the momentum like pieces if(part.id()>0) { vtemp+= (f2v*vspin+f2a*aspin)/(m0+m1)*sum; vtemp+= (f3v*vspin+f3a*aspin)/(m0+m1)*q; } else { vtemp+= (f2v*vspin-f2a*aspin)/(m0+m1)*sum; vtemp+= (f3v*vspin-f3a*aspin)/(m0+m1)*q; } if(part.id()>0) baryon[2*ix+iy]=vtemp; else baryon[2*iy+ix]=vtemp; } } // construct the weak current vector hadron = _current->current(tcPDPtr(),FlavourInfo(), _currentmap[imode()][mode],ichan,scale, tPDVector(outgoing.begin()+1,outgoing.end()), vector(momenta.begin()+1,momenta.end()),meopt); pre=pow(part.mass()/scale,int(outgoing.size()-3));pre*=pre; vector constants(outgoing.size()+1),ihel(outgoing.size()+1); int itemp=1; unsigned int ibar=0; for(int iz=int(outgoing.size()-1);iz>=0;--iz) { if(abs(outgoing[iz]->id())!=id1) { itemp *= outgoing[iz]->iSpin(); constants[iz]=itemp; } else ibar=iz; constants[outgoing.size()]=1; constants[ibar]=constants[ibar+1]; } for(unsigned int mhel=0;mhel0;--ix) { if(ix-1!=ibar){ihel[ix]=(lhel%constants[ix-1])/constants[ix];}} (*ME())(ihel) += Complex(hadron[lhel].dot(baryon[mhel])* _factCKM[imode()][mode]*SM().fermiConstant()); } } } // return the answer return 0.5*pre*(ME()->contract(_rho)).real(); } // matrix element for a 1/2 -> 3/2 decay double BaryonFactorizedDecayer::halfThreeHalf(const int ichan, const Particle & part, const tPDVector & outgoing, const vector & momenta, MEOption meopt) const { // spins Energy scale; vector spin(outgoing.size()); for(unsigned int ix=0;ixiSpin(); if(!ME()) ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin1Half,spin))); // spinors etc for the decaying particle if(meopt==Initialize) { // spinors and rho if(part.id()>0) SpinorWaveFunction ::calculateWaveFunctions(_inHalf,_rho, const_ptr_cast(&part), incoming); else SpinorBarWaveFunction::calculateWaveFunctions(_inHalfBar,_rho, const_ptr_cast(&part), incoming); } ME()->zero(); // spinors for the decay product LorentzPolarizationVector in=UnitRemoval::InvE*part.momentum(); if(part.id()>0) { RSSpinorBarWaveFunction swave(momenta[0],outgoing[0],Helicity::outgoing); _inThreeHalfBar.resize(4); _inHalfBar.resize(4); for(unsigned int ihel=0;ihel<4;++ihel) { swave.reset(ihel); _inThreeHalfBar[ihel]=swave.dimensionedWf(); _inHalfBar[ihel] = _inThreeHalfBar[ihel].dot(in); } } else { RSSpinorWaveFunction swave(momenta[0],outgoing[0],Helicity::outgoing); _inThreeHalf.resize(4); _inHalf.resize(4); for(unsigned int ihel=0;ihel<4;++ihel) { swave.reset(ihel); _inThreeHalf[ihel]=swave.dimensionedWf(); _inHalf[ihel] = _inThreeHalf[ihel].dot(in); } } // get the information on the form-factor int id0(part.id()),id1(outgoing[0]->id()); // work out the value of q and calculate the form factors Lorentz5Momentum q(part.momentum()-momenta[0]); q.rescaleMass(); Energy m0(part.mass()),m1(momenta[0].mass()); Energy2 q2(q.mass2()); Lorentz5Momentum sum(part.momentum()+momenta[0]); InvEnergy ms(1./(m0+m1)); InvEnergy2 ms2(ms*ms); double pre(0.); for(unsigned int mode=0;mode<_formmap[imode()].size();++mode) { // calculate the form factors Complex f1v,f2v,f3v,f4v,f1a,f2a,f3a,f4a; _form->SpinHalfSpinThreeHalfFormFactor(q2,_formmap[imode()][mode],id0,id1,m0,m1, f1v,f2v,f3v,f4v,f1a,f2a,f3a,f4a,FlavourInfo()); complex lS1,lS2,rS1,rS2; Complex left,right; complex lV,rV; if(part.id()>0) { left = f1a-f1v; right = f1a+f1v; lS1 = ms2*(f3a-f4a-f3v+f4v); rS1 = ms2*(f3a-f4a+f3v-f4v); lS2 = ms2*(f4a-f4v); rS2 = ms2*(f4a+f4v); lV = ms*(f2a-f2v); rV = ms*(f2a+f2v); } else { left = conj(f1a+f1v); right = conj(f1a-f1v); lS1 = ms2*conj(f3a-f4a+f3v-f4v); rS1 = ms2*conj(f3a-f4a-f3v+f4v); lS2 = ms2*conj(f4a-f4v); rS2 = ms2*conj(f4a+f4v); lV = ms *conj(f2a-f2v); rV = ms *conj(f2a+f2v); } // construct the vectors for the decay LorentzPolarizationVectorE baryon[4][2]; for(unsigned int iya=0;iya<4;++iya) { for(unsigned int ixa=0;ixa<2;++ixa) { unsigned int ix,iy; if(outgoing[0]->id()>0) { ix=iya; iy=ixa; } else { ix=ixa; iy=iya; } // scalar like terms complex lfact = _inHalf[iy].leftScalar( _inHalfBar[ix]); complex rfact = _inHalf[iy].rightScalar(_inHalfBar[ix]); Complex scalar1 = (lS1*lfact+rS1*rfact)*UnitRemoval::E; Complex scalar2 = (lS2*lfact+rS2*rfact)*UnitRemoval::E; LorentzPolarizationVector svec = _inHalf[iy].generalCurrent(_inHalfBar[ix],lV/ms,rV/ms)*ms; LorentzPolarizationVectorE tvec; if(part.id()>0) { tvec=_inThreeHalfBar[ix].generalCurrent(_inHalf[iy],left,right); } else { tvec=_inThreeHalf[iy].generalCurrent(_inHalfBar[ix],left,right); } baryon[iya][ixa] = tvec+svec*UnitRemoval::E +scalar1*momenta[0]+scalar2*part.momentum(); } } vector hadron = _current->current(tcPDPtr(),FlavourInfo(),_currentmap[imode()][mode],ichan,scale, tPDVector(outgoing.begin()+1,outgoing.end()), vector(momenta.begin()+1,momenta.end()),meopt); // prefactor pre = pow(part.mass()/scale,int(outgoing.size()-3)); pre *= pre; // work out the mapping for the hadron vector vector constants(outgoing.size()+1),ihel(outgoing.size()+1); int itemp = 1; int ibar = 0; for(int ix=int(outgoing.size()-1);ix>=0;--ix) { if(abs(outgoing[ix]->id())!=id1) { itemp*=outgoing[ix]->iSpin(); constants[ix]=itemp; } else{ibar=ix;} } constants[outgoing.size()]=1; constants[ibar]=constants[ibar+1]; for(unsigned int iya=0;iya<4;++iya) { ihel[1]=iya; for(unsigned int ixa=0;ixa<2;++ixa) { ihel[0]=ixa; for(unsigned int lhel=0;lhel0;--ix) {if(ix-1!=ibar){ihel[ix]=(lhel%constants[ix-1])/constants[ix];}} (*ME())(ihel) += Complex(hadron[lhel].dot(baryon[iya][ixa])* _factCKM[imode()][mode]*SM().fermiConstant()); } } } } // return the answer return 0.5*pre*(ME()->contract(_rho)).real(); } void BaryonFactorizedDecayer::findModes(unsigned int imode, tPDVector & incoming, vector & outgoing, vector & loc, vector & cc) { // get the id's for the mode // incoming int id_in = incoming[imode]->id(); int idbar_in = incoming[imode]->CC() ? incoming[imode]->CC()->id() : incoming[imode]->id(); // outgoing vector id_out,idbar_out; for(unsigned int ix=0;ixid()); if(outgoing[imode][ix]->CC()) idbar_out.push_back(outgoing[imode][ix]->CC()->id()); else idbar_out.push_back(id_out[ix]); } // loop over the modes for(unsigned int ix=0;ixid()==id_in&&outgoing[ix].size()==id_out.size()) { vector done(id_out.size(),false); unsigned int nfound = 0; for(unsigned int iy=0;iyid(); unsigned int iz = 0; bool found = false; do { if(idtemp==id_out[iz]&&!done[iz]) { done[iz]=true; found=true; } ++iz; } while(izid()==idbar_in&&outgoing[ix].size()==idbar_out.size()) { vector done(id_out.size(),false); unsigned int nfound=0; for(unsigned int iy=0;iyid(); unsigned int iz=0; bool found = false; do { if(idtemp==idbar_out[iz]&&!done[iz]) { done[iz]=true; found=true; } ++iz; } while(izname() << " \n"; for(ix=0;ix<_wgtloc.size();++ix) {output << "insert " << name() << ":WeightLocation " << ix << " " << _wgtloc[ix] << "\n";} for(ix=0;ix<_wgtmax.size();++ix) {output << "insert " << name() << ":MaximumWeight " << ix << " " << _wgtmax[ix] << "\n";} for(ix=0;ix<_weights.size();++ix) {output << "insert " << name() << ":Weights " << ix << " " << _weights[ix] << "\n";} _current->dataBaseOutput(output,false,true); output << "newdef " << name() << ":Current " << _current->name() << " \n"; _form->dataBaseOutput(output,false,true); output << "newdef " << name() << ":FormFactor " << _form->name() << " \n"; if(header){output << "\n\" where BINARY ThePEGName=\"" << fullName() << "\";" << endl;} } diff --git a/Decay/Dalitz/ScalarTo3ScalarDalitz.cc b/Decay/Dalitz/ScalarTo3ScalarDalitz.cc --- a/Decay/Dalitz/ScalarTo3ScalarDalitz.cc +++ b/Decay/Dalitz/ScalarTo3ScalarDalitz.cc @@ -1,174 +1,173 @@ // -*- C++ -*- // // This is the implementation of the non-inlined, non-templated member // functions of the ScalarTo3ScalarDalitz class. // #include "ScalarTo3ScalarDalitz.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Interface/Parameter.h" #include "ThePEG/Interface/Switch.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/Helicity/WaveFunction/ScalarWaveFunction.h" #include "Herwig/Decay/GeneralDecayMatrixElement.h" using namespace Herwig; using namespace ThePEG::Helicity; IBPtr ScalarTo3ScalarDalitz::clone() const { return new_ptr(*this); } IBPtr ScalarTo3ScalarDalitz::fullclone() const { return new_ptr(*this); } void ScalarTo3ScalarDalitz::persistentOutput(PersistentOStream & os) const { os << useResonanceMass_ ; } void ScalarTo3ScalarDalitz::persistentInput(PersistentIStream & is, int) { is >> useResonanceMass_; } // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeHerwigScalarTo3ScalarDalitz("Herwig::ScalarTo3ScalarDalitz", "HwDalitzDecay.so"); void ScalarTo3ScalarDalitz::Init() { static ClassDocumentation documentation ("The ScalarTo3ScalarDalitz class provides a base class for " "weak three-body decays of bottom and charm mesons"); static Switch interfaceResonanceMass ("ResonanceMass", "Whether to use the kinematic mass or the resonance pole mass for the denominator in kinematic expressions", &ScalarTo3ScalarDalitz::useResonanceMass_, false, false, false); static SwitchOption interfaceResonanceMassYes (interfaceResonanceMass, "Yes", "Use the resonance mass, to be avoided only use if do in experimental fit", true); static SwitchOption interfaceResonanceMassNo (interfaceResonanceMass, "No", "Use the correct kinematic mass", false); } void ScalarTo3ScalarDalitz:: constructSpinInfo(const Particle & part, ParticleVector decay) const { // set up the spin information for the decay products ScalarWaveFunction::constructSpinInfo(const_ptr_cast(&part), incoming,true); for(unsigned int ix=0;ix<3;++ix) ScalarWaveFunction::constructSpinInfo(decay[ix],outgoing,true); } double ScalarTo3ScalarDalitz::me2(const int ichan, const Particle & part, const tPDVector & , const vector & momenta, MEOption meopt) const { - static const Complex ii(0.,1.); if(!ME()) ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin0,PDT::Spin0,PDT::Spin0,PDT::Spin0))); useMe(); if(meopt==Initialize) { ScalarWaveFunction:: calculateWaveFunctions(rho_,const_ptr_cast(&part),incoming); } // set the kinematics mD_ = part.mass(); for(unsigned int ix=0;ixamp; if (resonances()[i]->type==ResonanceType::NonResonant) return output; // mass of the resonance const Energy & mR = resonances()[i]->mass ; // locations of the outgoing particles const unsigned int &d1 = resonances()[i]->daughter1; const unsigned int &d2 = resonances()[i]->daughter2; const unsigned int &sp = resonances()[i]->spectator; // compute the Breit-Wigner times resonance form factor piece output *= resonances()[i]->BreitWigner(m2_[d1][d2],mOut_[d1],mOut_[d2]); // angular piece // mass for the denominator Energy mDen = useResonanceMass_ ? resonances()[i]->mass : m2_[d1][d2]; // denominator for the older form of the amplitude Energy2 denom = GeV2; if (resonances()[i]->type/10 == 1 ) { Energy2 pa2 = 0.25*(sqr(m2_[d1][d2])-2.*(sqr(mOut_[d1])+sqr(mOut_[d2])) + sqr(sqr(mOut_[d1])-sqr(mOut_[d2]))/sqr(m2_[d1][d2])); Energy2 pc2 = 0.25*(sqr(m2_[d1][d2])-2.*(sqr(mD_ )+sqr(mOut_[sp])) + sqr(sqr(mD_ )-sqr(mOut_[sp]))/sqr(m2_[d1][d2])); denom = 4.*sqrt(pa2*pc2); } // vectors if(abs(resonances()[i]->type)%10==3) { output *= (sqr(m2_[d2][sp])-sqr(m2_[d1][sp]) + ( sqr(mD_)-sqr(mOut_[sp]))*(sqr(mOut_[d1])-sqr(mOut_[d2]))/sqr(mDen) )/denom; } else if(abs(resonances()[i]->type)%10==5) { output *= 1./sqr(denom)*( sqr( sqr(m2_[d2][sp]) - sqr(m2_[d1][sp]) +(sqr(mD_)-sqr(mOut_[sp]))*(sqr(mOut_[d1])-sqr(mOut_[d2]))/(sqr(mDen))) - (sqr(m2_[d1][d2])-2* sqr(mD_)-2*sqr(mOut_[sp]) + sqr((sqr( mD_) - sqr(mOut_[sp]))/mDen))* (sqr(m2_[d1][d2])-2*sqr(mOut_[d1])-2*sqr(mOut_[d2]) + sqr((sqr(mOut_[d1]) - sqr(mOut_[d2]))/mDen))/3.); } // spin zero and non-resonant is done now if((abs(resonances()[i]->type)%10==1 && resonances()[i]->type != ResonanceType::Spin0Gauss ) || abs(resonances()[i]->type/10)==10) { return output; } // spin piece x Blatt-Weisskopf for parent else { double fD=1.; // for the D decay Energy pD = sqrt(max(ZERO,(0.25*sqr(sqr(mD_)-sqr(mR)-sqr(mOut_[sp])) - sqr(mR*mOut_[sp]))/sqr(mD_))); Energy pDAB= sqrt( 0.25*sqr(sqr(mD_)-sqr(m2_[d1][d2])-sqr(mOut_[sp])) - sqr(m2_[d1][d2]*mOut_[sp]))/mD_; double r2A(parentRadius() *pD),r2B(parentRadius() *pDAB); // Blatt-Weisskopf factors and spin piece switch (resonances()[i]->type) { case ResonanceType::Spin0Gauss: fD = exp(-(r2B-r2A)/12.); break; case ResonanceType::Spin1: case ResonanceType::Spin1E691 : case ResonanceType::Spin1GS : fD=sqrt( (1. + sqr(r2A)) / (1. + sqr(r2B)) ); break; case ResonanceType::Spin2: case ResonanceType::Spin2E691: fD = sqrt( (9. + sqr(r2A)*(3.+sqr(r2A))) / (9. + sqr(r2B)*(3.+sqr(r2B)))); break; default : assert(false); } output *= fD; return output; } } void ScalarTo3ScalarDalitz::dataBaseOutput(ofstream & output, bool header) const { if(header) output << "update decayers set parameters=\""; // parameters for the DalitzBase base class DalitzBase::dataBaseOutput(output,false); output << "newdef " << name() << ":ResonanceMass " << useResonanceMass_ << "\n"; output << "\n"; if(header) { output << "\n\" where BINARY ThePEGName=\"" << fullName() << "\";" << endl; } } diff --git a/Decay/General/VectorCurrentDecayer.cc b/Decay/General/VectorCurrentDecayer.cc --- a/Decay/General/VectorCurrentDecayer.cc +++ b/Decay/General/VectorCurrentDecayer.cc @@ -1,273 +1,272 @@ // -*- C++ -*- // // VectorCurrentDecayer.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2019 The Herwig Collaboration // // Herwig is licenced under version 3 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // // // This is the implementation of the non-inlined, non-templated member // functions of the VectorCurrentDecayer class. // #include "VectorCurrentDecayer.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Interface/Parameter.h" #include "ThePEG/Interface/ParVector.h" #include "ThePEG/Interface/Reference.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "Herwig/Decay/GeneralDecayMatrixElement.h" #include "Herwig/Models/General/BSMModel.h" using namespace Herwig; IBPtr VectorCurrentDecayer::clone() const { return new_ptr(*this); } IBPtr VectorCurrentDecayer::fullclone() const { return new_ptr(*this); } void VectorCurrentDecayer::persistentOutput(PersistentOStream & os) const { os << inpart_ << currentOut_ << current_ << mode_ << wgtloc_ << wgtmax_ << weights_ << cSMmed_; } void VectorCurrentDecayer::persistentInput(PersistentIStream & is, int) { is >> inpart_ >> currentOut_ >> current_ >> mode_ >> wgtloc_ >> wgtmax_ >> weights_ >> cSMmed_; } // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeHerwigVectorCurrentDecayer("Herwig::VectorCurrentDecayer", "Herwig.so"); void VectorCurrentDecayer::Init() { static ClassDocumentation documentation ("The VectorCurrentDecayer class is designed for the decays of low mass vector bosons"); } void VectorCurrentDecayer::setDecayInfo(PDPtr in, const vector & outCurrent, WeakCurrentPtr current) { inpart_ = in; currentOut_ = outCurrent; current_ = current; // cast the model Ptr::ptr model = dynamic_ptr_cast::ptr>(generator()->standardModel()); bool foundU(false),foundD(false),foundS(false); // find the vertices we need and extract the couplings for(unsigned int ix = 0; ix < model->numberOfVertices(); ++ix ) { VertexBasePtr vertex = model->vertex(ix); if(vertex->getNpoint()!=3) continue; for(unsigned int iloc = 0;iloc < 3; ++iloc) { vector ext = vertex->search(iloc, in->id()); if(ext.empty()) continue; for(unsigned int ioff=0;ioffsetCoupling(sqr(in->mass()),getParticleData(1),getParticleData(-1),in); cSMmed_[0] = vertex->norm(); } else if(abs(ext[ioff])==2 && abs(ext[ioff+1])==2 && ext[ioff]==-ext[ioff+1]) { foundU = true; vertex->setCoupling(sqr(in->mass()),getParticleData(2),getParticleData(-2),in); cSMmed_[1] = vertex->norm(); } else if(abs(ext[ioff])==3 && abs(ext[ioff+1])==3 && ext[ioff]==-ext[ioff+1]) { foundS = true; vertex->setCoupling(sqr(in->mass()),getParticleData(3),getParticleData(-3),in); cSMmed_[2] = vertex->norm(); } } } } if(!foundD) { throw InitException() << "Cannot find down quark coupling in VectorCurrentDecayer::doinit()"; } if(!foundU) { throw InitException() << "Cannot find up quark coupling in VectorCurrentDecayer::doinit()"; } if(!foundS) { throw InitException() << "Cannot find strange quark coupling in VectorCurrentDecayer::doinit()"; } } int VectorCurrentDecayer::modeNumber(bool & cc, tcPDPtr parent, const tPDVector & children) const { vector id; id.push_back(parent->id()); for(unsigned int ix=0;ixid()); return modeNumber(cc,id); } void VectorCurrentDecayer::doinitrun() { current_->initrun(); DecayIntegrator::doinitrun(); } void VectorCurrentDecayer::doinit() { DecayIntegrator::doinit(); // make sure the current got initialised current_->init(); // find the mode for(unsigned int ix=0;ixnumberOfModes();++ix) { // get the external particles for this mode int iq(0),ia(0); tPDVector ptemp = current_->particles(inpart_->iCharge(),ix,iq,ia); // check this is the right mode if(ptemp.size()!=currentOut_.size()) continue; vector matched(ptemp.size(),false); bool match = true; for(unsigned int iy=0;iycreateMode(inpart_->iCharge(),tcPDPtr(),FlavourInfo(), ix,mode,0,-1,channel,inpart_->mass()); if(done) { // the maximum weight and the channel weights // the weights for the channel if(weights_.empty()) { weights_.resize(mode->channels().size(),1./(mode->channels().size())); } mode_ = ix; // special for the two body modes if(out.size()==2) { weights_.clear(); mode=new_ptr(PhaseSpaceMode(inpart_,out,1.)); } mode->maxWeight(wgtmax_); mode->setWeights(weights_); addMode(mode); } break; } } int VectorCurrentDecayer::modeNumber(bool & cc, vector id) const { // incoming particle long idtemp; tPDPtr p0=getParticleData(id[0]); idtemp = p0->CC() ? -id[0] : id[0]; if( id[0] ==inpart_->id()) cc=false; else if(idtemp==inpart_->id()) cc=true ; else return -1; vector idout; for(vector::iterator it=++id.begin();it!=id.end();++it) { idout.push_back(*it); } unsigned int icurr=current_->decayMode(idout); if(mode_==icurr) return 0; else return -1; } void VectorCurrentDecayer:: constructSpinInfo(const Particle & part, ParticleVector decay) const { VectorWaveFunction::constructSpinInfo(vectors_,const_ptr_cast(&part), Helicity::incoming,true,false); weakCurrent()->constructSpinInfo(ParticleVector(decay.begin(),decay.end())); } double VectorCurrentDecayer::me2(const int ichan, const Particle & part, const tPDVector & outgoing, const vector & momenta, MEOption meopt) const { using namespace ThePEG::Helicity; // polarization vectors for the incoming particle if(meopt==Initialize) { VectorWaveFunction::calculateWaveFunctions(vectors_,rho_, const_ptr_cast(&part), incoming,false); // fix rho if no correlations fixRho(rho_); } // work out the mapping for the hadron vector int nOut = momenta.size(); vector constants(nOut+1); vector iSpin(nOut); vector hadrons(nOut); int itemp(1); int ix(nOut); do { --ix; iSpin[ix] = outgoing[ix]->iSpin(); itemp *= iSpin[ix]; constants[ix] = itemp; hadrons[ix] = outgoing[ix]->id(); } while(ix>0); constants[nOut] = 1; - Energy2 scale(sqr(part.mass())); // calculate the hadron current Energy q = part.mass(); // currents for the different flavour components vector hadronI0(current_->current(tcPDPtr(), FlavourInfo(IsoSpin::IZero, IsoSpin::I3Zero,Strangeness::Zero), mode(),ichan,q,outgoing,momenta,DecayIntegrator::Calculate)); vector hadronI1(current_->current(tcPDPtr(), FlavourInfo(IsoSpin::IOne, IsoSpin::I3Zero,Strangeness::Zero), mode(),ichan,q,outgoing,momenta,DecayIntegrator::Calculate)); vector hadronssbar(current_->current(tcPDPtr(), FlavourInfo(IsoSpin::IZero, IsoSpin::I3Zero,Strangeness::ssbar), mode(),ichan,q,outgoing,momenta,DecayIntegrator::Calculate)); // compute the matrix element GeneralDecayMEPtr newME(new_ptr(GeneralDecayMatrixElement(PDT::Spin1,iSpin))); vector ihel(momenta.size()+1); unsigned int hI0_size = hadronI0.size(); unsigned int hI1_size = hadronI1.size(); unsigned int hss_size = hadronssbar.size(); unsigned int maxsize = max(max(hadronI0.size(),hadronI1.size()),hss_size); for(unsigned int hhel=0;hhel0;--ix) { ihel[ix]=(hhel%constants[ix-1])/constants[ix]; } for(ihel[0]=0;ihel[0]<3;++ihel[0]) { Complex amp = 0.; // work on coefficients for the I1 and I0 bits if(hI0_size != 0 ) amp += Complex((cSMmed_[0]+cSMmed_[1])/sqrt(2.)/q*(vectors_[ihel[0]].wave().dot(hadronI0[hhel]))); if(hI1_size !=0) amp += Complex((cSMmed_[0]-cSMmed_[1])/sqrt(2.)/q*(vectors_[ihel[0]].wave().dot(hadronI1[hhel]))); if(hss_size !=0) amp += Complex(cSMmed_[2] /q*(vectors_[ihel[0]].wave().dot(hadronssbar[hhel]))); (*newME)(ihel) = amp; } } // store the matrix element ME(newME); // return the answer double output = (ME()->contract(rho_)).real(); return output; } Energy VectorCurrentDecayer::partialWidth(tPDPtr part, vector out) { vector id; id.push_back(part->id()); for(unsigned int ix=0;ixid()); bool cc; int mode=modeNumber(cc,id); imode(mode); return initializePhaseSpaceMode(mode,true,true); } diff --git a/Decay/Perturbative/SMWDecayer.cc b/Decay/Perturbative/SMWDecayer.cc --- a/Decay/Perturbative/SMWDecayer.cc +++ b/Decay/Perturbative/SMWDecayer.cc @@ -1,740 +1,740 @@ // -*- C++ -*- // // SMWDecayer.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2019 The Herwig Collaboration // // Herwig is licenced under version 3 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // // // This is the implementation of the non-inlined, non-templated member // functions of the SMWDecayer class. // #include "SMWDecayer.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Interface/ParVector.h" #include "ThePEG/Interface/Reference.h" #include "ThePEG/Interface/Switch.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/PDT/DecayMode.h" #include "Herwig/Decay/DecayVertex.h" #include "ThePEG/Helicity/VectorSpinInfo.h" #include "ThePEG/Helicity/FermionSpinInfo.h" #include "ThePEG/Helicity/WaveFunction/VectorWaveFunction.h" #include "Herwig/Models/StandardModel/StandardModel.h" #include "Herwig/Shower/RealEmissionProcess.h" #include "Herwig/Decay/GeneralDecayMatrixElement.h" #include using namespace Herwig; using namespace ThePEG::Helicity; const double SMWDecayer::EPS_=0.00000001; SMWDecayer::SMWDecayer() : quarkWeight_(6,0.), leptonWeight_(3,0.), CF_(4./3.), NLO_(false) { quarkWeight_[0] = 1.01596; quarkWeight_[1] = 0.0537308; quarkWeight_[2] = 0.0538085; quarkWeight_[3] = 1.01377; quarkWeight_[4] = 1.45763e-05; quarkWeight_[5] = 0.0018143; leptonWeight_[0] = 0.356594; leptonWeight_[1] = 0.356593; leptonWeight_[2] = 0.356333; // intermediates generateIntermediates(false); } void SMWDecayer::doinit() { PerturbativeDecayer::doinit(); // get the vertices from the Standard Model object tcHwSMPtr hwsm=dynamic_ptr_cast(standardModel()); if(!hwsm) throw InitException() << "Must have Herwig StandardModel object in" << "SMWDecayer::doinit()" << Exception::runerror; FFWVertex_ = hwsm->vertexFFW(); FFGVertex_ = hwsm->vertexFFG(); WWWVertex_ = hwsm->vertexWWW(); FFPVertex_ = hwsm->vertexFFP(); // make sure they are initialized FFGVertex_->init(); FFWVertex_->init(); WWWVertex_->init(); FFPVertex_->init(); // now set up the decay modes // W modes tPDPtr Wp = getParticleData(ParticleID::Wplus); // loop for the quarks unsigned int iz=0; for(int ix=1;ix<6;ix+=2) { for(int iy=2;iy<6;iy+=2) { // check that the combination of particles is allowed if(!FFWVertex_->allowed(-ix,iy,ParticleID::Wminus)) throw InitException() << "SMWDecayer::doinit() the W vertex" << "cannot handle all the quark modes" << Exception::abortnow; tPDVector out = {getParticleData(-ix), getParticleData( iy)}; PhaseSpaceModePtr mode = new_ptr(PhaseSpaceMode(Wp,out,quarkWeight_[iz])); addMode(mode); ++iz; } } // loop for the leptons for(int ix=11;ix<17;ix+=2) { tPDVector out = {getParticleData(-ix ), getParticleData( ix+1)}; PhaseSpaceModePtr mode = new_ptr(PhaseSpaceMode(Wp,out,leptonWeight_[(ix-11)/2])); addMode(mode); } gluon_ = getParticleData(ParticleID::g); } int SMWDecayer::modeNumber(bool & cc,tcPDPtr parent, const tPDVector & children) const { int imode(-1); if(children.size()!=2) return imode; int id0=parent->id(); tPDVector::const_iterator pit = children.begin(); int id1=(**pit).id(); ++pit; int id2=(**pit).id(); if(abs(id0)!=ParticleID::Wplus) return imode; int idd(0),idu(0); if(abs(id1)%2==1&&abs(id2)%2==0) { idd=abs(id1); idu=abs(id2); } else if(abs(id1)%2==0&&abs(id2)%2==1) { idd=abs(id2); idu=abs(id1); } if(idd==0&&idu==0) { return imode; } else if(idd<=5) { imode=idd+idu/2-2; } else { imode=(idd-1)/2+1; } cc= (id0==ParticleID::Wminus); return imode; } ParticleVector SMWDecayer::decay(const Particle & parent, const tPDVector & children) const { // generate the decay bool cc; unsigned int imode = modeNumber(cc,parent.dataPtr(),children); ParticleVector output = generate(false,cc,imode,parent); if(output[0]->hasColour()) output[0]->antiColourNeighbour(output[1]); else if(output[1]->hasColour()) output[1]->antiColourNeighbour(output[0]); return output; } void SMWDecayer::persistentOutput(PersistentOStream & os) const { os << FFWVertex_ << quarkWeight_ << leptonWeight_ << FFGVertex_ << gluon_ << NLO_ << WWWVertex_ << FFPVertex_; } void SMWDecayer::persistentInput(PersistentIStream & is, int) { is >> FFWVertex_ >> quarkWeight_ >> leptonWeight_ >> FFGVertex_ >> gluon_ >> NLO_ >> WWWVertex_ >> FFPVertex_; } // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeHerwigSMWDecayer("Herwig::SMWDecayer", "HwPerturbativeDecay.so"); void SMWDecayer::Init() { static ClassDocumentation documentation ("The SMWDecayer class is the implementation of the decay" " of the W boson to the Standard Model fermions."); static ParVector interfaceWquarkMax ("QuarkMax", "The maximum weight for the decay of the W to quarks", &SMWDecayer::quarkWeight_, 0, 0, 0, -10000, 10000, false, false, true); static ParVector interfaceWleptonMax ("LeptonMax", "The maximum weight for the decay of the W to leptons", &SMWDecayer::leptonWeight_, 0, 0, 0, -10000, 10000, false, false, true); static Switch interfaceNLO ("NLO", "Whether to return the LO or NLO result", &SMWDecayer::NLO_, false, false, false); static SwitchOption interfaceNLOLO (interfaceNLO, "No", "Leading-order result", false); static SwitchOption interfaceNLONLO (interfaceNLO, "Yes", "NLO result", true); } void SMWDecayer:: constructSpinInfo(const Particle & part, ParticleVector decay) const { int iferm(1),ianti(0); if(decay[0]->id()>0) swap(iferm,ianti); VectorWaveFunction::constructSpinInfo(vectors_,const_ptr_cast(&part), incoming,true,false); SpinorBarWaveFunction:: constructSpinInfo(wavebar_,decay[iferm],outgoing,true); SpinorWaveFunction:: constructSpinInfo(wave_ ,decay[ianti],outgoing,true); } // return the matrix element squared double SMWDecayer::me2(const int,const Particle & part, const tPDVector & outgoing, const vector & momenta, MEOption meopt) const { if(!ME()) ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin1,PDT::Spin1Half,PDT::Spin1Half))); int iferm(1),ianti(0); if(outgoing[0]->id()>0) swap(iferm,ianti); if(meopt==Initialize) { VectorWaveFunction::calculateWaveFunctions(vectors_,rho_, const_ptr_cast(&part), incoming,false); // fix rho if no correlations fixRho(rho_); } SpinorBarWaveFunction wbar(momenta[iferm],outgoing[iferm],Helicity::outgoing); SpinorWaveFunction w (momenta[ianti],outgoing[ianti],Helicity::outgoing); wavebar_.resize(2); wave_ .resize(2); for(unsigned int ihel=0;ihel<2;++ihel) { wbar.reset(ihel); wavebar_[ihel] = wbar; w.reset(ihel); wave_ [ihel] = w; } // compute the matrix element Energy2 scale(sqr(part.mass())); for(unsigned int ifm=0;ifm<2;++ifm) { for(unsigned int ia=0;ia<2;++ia) { for(unsigned int vhel=0;vhel<3;++vhel) { if(iferm>ianti) (*ME())(vhel,ia,ifm)= FFWVertex_->evaluate(scale,wave_[ia],wavebar_[ifm],vectors_[vhel]); else (*ME())(vhel,ifm,ia)= FFWVertex_->evaluate(scale,wave_[ia],wavebar_[ifm],vectors_[vhel]); } } } double output=(ME()->contract(rho_)).real()*UnitRemoval::E2/scale; if(abs(outgoing[0]->id())<=6) output*=3.; // // leading-order result if(!NLO_) return output; // check decay products coloured, otherwise return if(!outgoing[0]->coloured()) return output; // inital masses, couplings etc // W mass mW_ = part.mass(); // strong coupling aS_ = SM().alphaS(sqr(mW_)); // reduced mass double mu1 = outgoing[0]->mass()/mW_; double mu2 = outgoing[1]->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 - tcPDVector outgoing = {part.dataPtr(),outgoing[0],outgoing[1],gluon_}; + tcPDVector oTemp = {part.dataPtr(),outgoing[0],outgoing[1],gluon_}; vector mom = {part.momentum(),momenta[0],momenta[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, outgoing,mom, phi, + *2.*CF_*aS_*calculateRealEmission(x1, x2, oTemp, mom, phi, muj, muk, iemit, true); } // the born + virtual + real output *= (1. + virt + realFact); return output; } void SMWDecayer::doinitrun() { PerturbativeDecayer::doinitrun(); if(initialize()) { for(unsigned int ix=0;ixmaxWeight(); else leptonWeight_[ix-6]=mode(ix)->maxWeight(); } } } void SMWDecayer::dataBaseOutput(ofstream & output, bool header) const { if(header) output << "update decayers set parameters=\""; for(unsigned int ix=0;ixbornOutgoing().size();++ix) qq.push_back(born->bornOutgoing()[ix]); // ensure quark first if(qq[0]->id()<0) swap(qq[0],qq[1]); // centre of mass energy d_Q_ = (qq[0]->momentum() + qq[1]->momentum()).m(); // quark mass d_m_ = 0.5*(qq[0]->momentum().m()+qq[1]->momentum().m()); // set the other parameters setRho(sqr(d_m_/d_Q_)); setKtildeSymm(); // otherwise can do it initial=1.; final =1.; } bool SMWDecayer::softMatrixElementVeto(PPtr parent, PPtr progenitor, const bool & , const Energy & highestpT, const vector & ids, const double & d_z, const Energy & d_qt, const Energy & ) { // check we should be applying the veto if(parent->id()!=progenitor->id()|| ids[0]!=ids[1]|| ids[2]->id()!=ParticleID::g) return false; // calculate pt Energy2 d_m2 = parent->momentum().m2(); Energy2 pPerp2 = sqr(d_z*d_qt) - d_m2; if(pPerp2id()>0) weight = qWeightX(d_qt, d_z); else weight = qbarWeightX(d_qt, d_z); // compute veto from weight and return return !UseRandom::rndbool(weight); } void SMWDecayer::setRho(double r) { d_rho_ = r; d_v_ = sqrt(1.-4.*d_rho_); } void SMWDecayer::setKtildeSymm() { d_kt1_ = (1. + sqrt(1. - 4.*d_rho_))/2.; setKtilde2(); } void SMWDecayer::setKtilde2() { double num = d_rho_ * d_kt1_ + 0.25 * d_v_ *(1.+d_v_)*(1.+d_v_); double den = d_kt1_ - d_rho_; d_kt2_ = num/den; } double SMWDecayer::getZfromX(double x1, double x2) { double uval = u(x2); double num = x1 - (2. - x2)*uval; double den = sqrt(x2*x2 - 4.*d_rho_); return uval + num/den; } double SMWDecayer::getKfromX(double x1, double x2) { double zval = getZfromX(x1, x2); return (1.-x2)/(zval*(1.-zval)); } double SMWDecayer::MEV(double x1, double x2) { // Vector part double num = (x1+2.*d_rho_)*(x1+2.*d_rho_) + (x2+2.*d_rho_)*(x2+2.*d_rho_) - 8.*d_rho_*(1.+2.*d_rho_); double den = (1.+2.*d_rho_)*(1.-x1)*(1.-x2); return (num/den - 2.*d_rho_/((1.-x1)*(1.-x1)) - 2*d_rho_/((1.-x2)*(1.-x2)))/d_v_; } double SMWDecayer::MEA(double x1, double x2) { // Axial part double num = (x1+2.*d_rho_)*(x1+2.*d_rho_) + (x2+2.*d_rho_)*(x2+2.*d_rho_) + 2.*d_rho_*((5.-x1-x2)*(5.-x1-x2) - 19.0 + 4*d_rho_); double den = d_v_*d_v_*(1.-x1)*(1.-x2); return (num/den - 2.*d_rho_/((1.-x1)*(1.-x1)) - 2*d_rho_/((1.-x2)*(1.-x2)))/d_v_; } double SMWDecayer::u(double x2) { return 0.5*(1. + d_rho_/(1.-x2+d_rho_)); } void SMWDecayer:: getXXbar(double kti, double z, double &x, double &xbar) { double w = sqr(d_v_) + kti*(-1. + z)*z*(2. + kti*(-1. + z)*z); if (w < 0) { x = -1.; xbar = -1; } else { x = (1. + sqr(d_v_)*(-1. + z) + sqr(kti*(-1. + z))*z*z*z + z*sqrt(w) - kti*(-1. + z)*z*(2. + z*(-2 + sqrt(w))))/ (1. - kti*(-1. + z)*z + sqrt(w)); xbar = 1. + kti*(-1. + z)*z; } } double SMWDecayer::qWeight(double x, double xbar) { double rval; double xg = 2. - xbar - x; // always return one in the soft gluon region if(xg < EPS_) return 1.0; // check it is in the phase space if((1.-x)*(1.-xbar)*(1.-xg) < d_rho_*xg*xg) return 0.0; double k1 = getKfromX(x, xbar); double k2 = getKfromX(xbar, x); // Is it in the quark emission zone? if(k1 < d_kt1_) { rval = MEV(x, xbar)/PS(x, xbar); // is it also in the anti-quark emission zone? if(k2 < d_kt2_) rval *= 0.5; return rval; } return 1.0; } double SMWDecayer::qbarWeight(double x, double xbar) { double rval; double xg = 2. - xbar - x; // always return one in the soft gluon region if(xg < EPS_) return 1.0; // check it is in the phase space if((1.-x)*(1.-xbar)*(1.-xg) < d_rho_*xg*xg) return 0.0; double k1 = getKfromX(x, xbar); double k2 = getKfromX(xbar, x); // Is it in the antiquark emission zone? if(k2 < d_kt2_) { rval = MEV(x, xbar)/PS(xbar, x); // is it also in the quark emission zone? if(k1 < d_kt1_) rval *= 0.5; return rval; } return 1.0; } double SMWDecayer::qWeightX(Energy qtilde, double z) { double x, xb; getXXbar(sqr(qtilde/d_Q_), z, x, xb); // if exceptionally out of phase space, leave this emission, as there // is no good interpretation for the soft ME correction. if (x < 0 || xb < 0) return 1.0; return qWeight(x, xb); } double SMWDecayer::qbarWeightX(Energy qtilde, double z) { double x, xb; getXXbar(sqr(qtilde/d_Q_), z, xb, x); // see above in qWeightX. if (x < 0 || xb < 0) return 1.0; return qbarWeight(x, xb); } double SMWDecayer::PS(double x, double xbar) { double u = 0.5*(1. + d_rho_ / (1.-xbar+d_rho_)); double z = u + (x - (2.-xbar)*u)/sqrt(xbar*xbar - 4.*d_rho_); double brack = (1.+z*z)/(1.-z)- 2.*d_rho_/(1-xbar); // interesting: the splitting function without the subtraction // term. Actually gives a much worse approximation in the collinear // limit. double brack = (1.+z*z)/(1.-z); double den = (1.-xbar)*sqrt(xbar*xbar - 4.*d_rho_); return brack/den; } double SMWDecayer::matrixElementRatio(const Particle & inpart, const ParticleVector & decay2, const ParticleVector & decay3, MEOption, ShowerInteraction inter) { // extract partons and LO momentas vector partons(1,inpart.dataPtr()); vector lomom(1,inpart.momentum()); for(unsigned int ix=0;ix<2;++ix) { partons.push_back(decay2[ix]->dataPtr()); lomom.push_back(decay2[ix]->momentum()); } vector realmom(1,inpart.momentum()); for(unsigned int ix=0;ix<3;++ix) { if(ix==2) partons.push_back(decay3[ix]->dataPtr()); realmom.push_back(decay3[ix]->momentum()); } if(partons[0]->id()<0) { swap(partons[1],partons[2]); swap(lomom[1],lomom[2]); swap(realmom[1],realmom[2]); } scale_ = sqr(inpart.mass()); double lome = loME(partons,lomom); InvEnergy2 reme = realME(partons,realmom,inter); double ratio = reme/lome*sqr(inpart.mass())*4.*Constants::pi; if(inter==ShowerInteraction::QCD) ratio *= CF_; return ratio; } double SMWDecayer::meRatio(tcPDVector partons, vector 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(0.); 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 lomom(3); lomom[0] = momenta[0]; if(iemit==0) { lomom[1] = pijt; lomom[2] = pkt ; } else { lomom[2] = pijt; lomom[1] = pkt ; } if(iemit==0) lome = loME(partons,lomom); } InvEnergy2 ratio = realME(partons,momenta,ShowerInteraction::QCD)/lome*abs(D[iemitter]) /(abs(D[0])+abs(D[1])); if(subtract) return Q2*(ratio-2.*D[iemitter]); else return Q2*ratio; } double SMWDecayer::loME(const vector & partons, const vector & momenta) const { // compute the spinors vector vin; vector aout; vector 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 SMWDecayer::realME(const vector & partons, const vector & momenta, ShowerInteraction inter) const { // compute the spinors vector vin; vector aout; vector fout; vector 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 diag(3,0.); double total(0.); AbstractFFVVertexPtr vertex = inter==ShowerInteraction::QCD ? FFGVertex_ : FFPVertex_; 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 = vertex->evaluate(scale_,3,partons[1]->CC(),fout[outhel1],gout[outhel3]); diag[0] = FFWVertex_->evaluate(scale_,aout[outhel2],off1,vin[inhel1]); SpinorWaveFunction off2 = vertex->evaluate(scale_,3,partons[2]->CC(),aout[outhel2],gout[outhel3]); diag[1] = FFWVertex_->evaluate(scale_,off2,fout[outhel1],vin[inhel1]); if(inter==ShowerInteraction::QED) { VectorWaveFunction off3 = WWWVertex_->evaluate(scale_,3,partons[0],vin[inhel1],gout[outhel3]); diag[2] = FFWVertex_->evaluate(scale_,aout[outhel2],fout[outhel1],off3); } // sum of diagrams Complex sum = std::accumulate(diag.begin(),diag.end(),Complex(0.)); // me2 total += norm(sum); } } } } // divide out the coupling total /= norm(vertex->norm()); // double g = sqrt(2.)*abs(FFWVertex_->norm()); // double xg = 2.*momenta[3].t()/momenta[0].mass(); // double xe,mue2; // if(abs(partons[1]->id())==ParticleID::eminus) { // xe = 2.*momenta[1].t()/momenta[0].mass(); // mue2 = sqr(momenta[1].mass()/momenta[0].mass()); // } // else { // xe = 2.*momenta[2].t()/momenta[0].mass(); // mue2 = sqr(momenta[2].mass()/momenta[0].mass()); // } // double cg = -4. * g * g * (-pow(mue2, 3.) / 2. + (xg * xg / 4. + (xe / 2. + 1.) * xg + 5. / 2. * xe - 2.) * mue2 * mue2 // + (pow(xg, 3.) / 4. + (xe / 4. - 5. / 4.) * xg * xg + (-7. / 2. * xe + 3.) * xg - 3. * xe * xe // + 11. / 2. * xe - 7. / 2.) * mue2 + (xg * xg / 2. + (xe - 2.) * xg + xe * xe - 2. * xe + 2.) * (-1. + xg + xe)) * (xe - mue2 - 1.) * // pow(xg, -2.) * pow(-1. + xg + xe - mue2, -2.); // cerr << "real " << cg/total << "\n"; // return the total return total*UnitRemoval::InvE2; } double SMWDecayer::calculateRealEmission(double x1, double x2, tcPDVector partons, vector pin, double phi, double muj, double muk, int iemit, bool subtract) const { // 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()); // boost and rotate momenta LorentzRotation eventFrame( ( pin[1] + pin[2] ).findBoostToCM() ); unsigned int ispect = iemit==0 ? 2 : 1; Lorentz5Momentum spectator = eventFrame*pin[ispect]; eventFrame.rotateZ( -spectator.phi() ); eventFrame.rotateY( -spectator.theta() ); eventFrame.invert(); vector momenta(3); momenta[0] = pin[0]; momenta[ispect ] = eventFrame*pspect; momenta[iemit+1] = eventFrame*pemit ; momenta.push_back(eventFrame*pgluon); // calculate the weight double realwgt(0.); if(1.-x1>1e-5 && 1.-x2>1e-5) realwgt = meRatio(partons,momenta,iemit,subtract); return realwgt; } diff --git a/Decay/Perturbative/SMZDecayer.cc b/Decay/Perturbative/SMZDecayer.cc --- a/Decay/Perturbative/SMZDecayer.cc +++ b/Decay/Perturbative/SMZDecayer.cc @@ -1,1122 +1,1122 @@ // -*- C++ -*- // // SMZDecayer.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2019 The Herwig Collaboration // // Herwig is licenced under version 3 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // // // This is the implementation of the non-inlined, non-templated member // functions of the SMZDecayer class. // #include "SMZDecayer.h" #include "Herwig/Utilities/Maths.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Interface/ParVector.h" #include "ThePEG/Interface/Reference.h" #include "ThePEG/Interface/Switch.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/PDT/DecayMode.h" #include "Herwig/Decay/DecayVertex.h" #include "ThePEG/Helicity/VectorSpinInfo.h" #include "ThePEG/Helicity/FermionSpinInfo.h" #include "ThePEG/Helicity/WaveFunction/VectorWaveFunction.h" #include "Herwig/Models/StandardModel/StandardModel.h" #include "Herwig/Shower/RealEmissionProcess.h" #include "Herwig/Decay/GeneralDecayMatrixElement.h" #include using namespace Herwig; using namespace ThePEG::Helicity; const double SMZDecayer::EPS_=0.00000001; SMZDecayer::SMZDecayer() : quarkWeight_(5,0.), leptonWeight_(6,0.), CF_(4./3.), NLO_(false) { quarkWeight_[0] = 0.488029; quarkWeight_[1] = 0.378461; quarkWeight_[2] = 0.488019; quarkWeight_[3] = 0.378027; quarkWeight_[4] = 0.483207; leptonWeight_[0] = 0.110709; leptonWeight_[1] = 0.220276; leptonWeight_[2] = 0.110708; leptonWeight_[3] = 0.220276; leptonWeight_[4] = 0.110458; leptonWeight_[5] = 0.220276; // intermediates generateIntermediates(false); // QED corrections hasRealEmissionME(true); hasOneLoopME(true); } void SMZDecayer::doinit() { PerturbativeDecayer::doinit(); // get the vertices from the Standard Model object tcHwSMPtr hwsm=dynamic_ptr_cast(standardModel()); if(!hwsm) throw InitException() << "Must have Herwig StandardModel object in" << "SMZDecayer::doinit()" << Exception::runerror; // cast the vertices FFZVertex_ = dynamic_ptr_cast(hwsm->vertexFFZ()); FFZVertex_->init(); FFGVertex_ = hwsm->vertexFFG(); FFGVertex_->init(); FFPVertex_ = hwsm->vertexFFP(); FFPVertex_->init(); gluon_ = getParticleData(ParticleID::g); // now set up the decay modes tPDPtr Z0 = getParticleData(ParticleID::Z0); // loop over the quarks and the leptons for(int istep=0;istep<11;istep+=10) { for(int ix=1;ix<7;++ix) { int iy=istep+ix; if(iy==6) continue; double maxWeight = iy<=6 ? quarkWeight_.at(ix-1) : leptonWeight_.at(iy-11); tPDVector out = {getParticleData(-iy),getParticleData( iy)}; PhaseSpaceModePtr mode = new_ptr(PhaseSpaceMode(Z0,out,maxWeight)); addMode(mode); } } } int SMZDecayer::modeNumber(bool & cc,tcPDPtr parent, const tPDVector & children) const { int imode(-1); if(children.size()!=2) return imode; int id0=parent->id(); tPDVector::const_iterator pit = children.begin(); int id1=(**pit).id(); ++pit; int id2=(**pit).id(); // Z to quarks or leptons cc =false; if(id0!=ParticleID::Z0) return imode; if(abs(id1)<6&&id1==-id2) { imode=abs(id1)-1; } else if(abs(id1)>=11&&abs(id1)<=16&&id1==-id2) { imode=abs(id1)-6; } cc = false; return imode; } void SMZDecayer::persistentOutput(PersistentOStream & os) const { os << FFZVertex_ << FFPVertex_ << FFGVertex_ << quarkWeight_ << leptonWeight_ << NLO_ << gluon_; } void SMZDecayer::persistentInput(PersistentIStream & is, int) { is >> FFZVertex_ >> FFPVertex_ >> FFGVertex_ >> quarkWeight_ >> leptonWeight_ >> NLO_ >> gluon_; } // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeHerwigSMZDecayer("Herwig::SMZDecayer", "HwPerturbativeDecay.so"); void SMZDecayer::Init() { static ClassDocumentation documentation ("The SMZDecayer class is the implementation of the decay" " Z boson to the Standard Model fermions."); static ParVector interfaceZquarkMax ("QuarkMax", "The maximum weight for the decay of the Z to quarks", &SMZDecayer::quarkWeight_, 0, 0, 0, -10000, 10000, false, false, true); static ParVector interfaceZleptonMax ("LeptonMax", "The maximum weight for the decay of the Z to leptons", &SMZDecayer::leptonWeight_, 0, 0, 0, -10000, 10000, false, false, true); static Switch interfaceNLO ("NLO", "Whether to return the LO or NLO result", &SMZDecayer::NLO_, false, false, false); static SwitchOption interfaceNLOLO (interfaceNLO, "No", "Leading-order result", false); static SwitchOption interfaceNLONLO (interfaceNLO, "Yes", "NLO result", true); } ParticleVector SMZDecayer::decay(const Particle & parent, const tPDVector & children) const { // generate the decay bool cc; unsigned int imode = modeNumber(cc,parent.dataPtr(),children); ParticleVector output = generate(false,false,imode,parent); if(output[0]->hasColour()) output[0]->antiColourNeighbour(output[1]); else if(output[1]->hasColour()) output[1]->antiColourNeighbour(output[0]); return output; } void SMZDecayer:: constructSpinInfo(const Particle & part, ParticleVector decay) const { int iferm(1),ianti(0); if(decay[0]->id()>0) swap(iferm,ianti); VectorWaveFunction::constructSpinInfo(_vectors,const_ptr_cast(&part), incoming,true,false); SpinorBarWaveFunction:: constructSpinInfo(_wavebar,decay[iferm],outgoing,true); SpinorWaveFunction:: constructSpinInfo(_wave ,decay[ianti],outgoing,true); } // return the matrix element squared double SMZDecayer::me2(const int,const Particle & part, const tPDVector & outgoing, const vector & momenta, MEOption meopt) const { if(!ME()) ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin1,PDT::Spin1Half,PDT::Spin1Half))); int iferm(1),ianti(0); if(outgoing[0]->id()>0) swap(iferm,ianti); if(meopt==Initialize) { VectorWaveFunction::calculateWaveFunctions(_vectors,_rho, const_ptr_cast(&part), incoming,false); // fix rho if no correlations fixRho(_rho); } SpinorBarWaveFunction wbar(momenta[iferm],outgoing[iferm],Helicity::outgoing); SpinorWaveFunction w (momenta[ianti],outgoing[ianti],Helicity::outgoing); _wavebar.resize(2); _wave .resize(2); for(unsigned int ihel=0;ihel<2;++ihel) { wbar.reset(ihel); _wavebar[ihel] = wbar; w.reset(ihel); _wave [ihel] = w; } // compute the matrix element Energy2 scale(sqr(part.mass())); unsigned int ifm,ia,vhel; for(ifm=0;ifm<2;++ifm) { for(ia=0;ia<2;++ia) { for(vhel=0;vhel<3;++vhel) { if(iferm>ianti) (*ME())(vhel,ia,ifm)= FFZVertex_->evaluate(scale,_wave[ia],_wavebar[ifm],_vectors[vhel]); else (*ME())(vhel,ifm,ia)= FFZVertex_->evaluate(scale,_wave[ia],_wavebar[ifm],_vectors[vhel]); } } } double output=(ME()->contract(_rho)).real()*UnitRemoval::E2/scale; if(abs(outgoing[0]->id())<=6) output*=3.; // if LO return if(!NLO_) return output; // check decay products coloured, otherwise return if(!outgoing[0]->coloured()) return output; // inital masses, couplings etc // fermion mass Energy particleMass = outgoing[0]->mass(); // Z mass mZ_ = part.mass(); // strong coupling aS_ = SM().alphaS(sqr(mZ_)); // reduced mass mu_ = particleMass/mZ_; mu2_ = sqr(mu_); // scale scale_ = sqr(mZ_); // compute the spinors vector aout; vector fout; vector vin; SpinorBarWaveFunction qkout(momenta[0],outgoing[0],Helicity::outgoing); SpinorWaveFunction qbout(momenta[1],outgoing[1],Helicity::outgoing); VectorWaveFunction zin (part.momentum() ,part.dataPtr() ,incoming); 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){ zin.reset(ix); vin.push_back(zin); } // temporary storage of the different diagrams // sum over helicities to get the matrix element double total=0.; if(mu_!=0.) { LorentzPolarizationVector momDiff = (momenta[0]-momenta[1])/2./(momenta[0].mass()+momenta[1].mass()); // scalars Complex scalar1 = zin.wave().dot(momDiff); for(unsigned int outhel1=0;outhel1<2;++outhel1) { for(unsigned int outhel2=0;outhel2<2;++outhel2) { for(unsigned int inhel=0;inhel<3;++inhel) { // first the LO bit Complex diag1 = FFZVertex_->evaluate(scale_,aout[outhel2], fout[outhel1],vin[inhel]); // extra stuff for NLO LorentzPolarizationVector left = aout[outhel2].wave().leftCurrent(fout[outhel1].wave()); LorentzPolarizationVector right = aout[outhel2].wave().rightCurrent(fout[outhel1].wave()); Complex scalar = aout[outhel2].wave().scalar(fout[outhel1].wave()); // nlo specific pieces Complex diag3 = Complex(0.,1.)*FFZVertex_->norm()* (FFZVertex_->right()*( left.dot(zin.wave())) + FFZVertex_-> left()*(right.dot(zin.wave())) - ( FFZVertex_-> left()+FFZVertex_->right())*scalar1*scalar); // nlo piece total += real(diag1*conj(diag3) + diag3*conj(diag1)); } } } // rescale total *= UnitRemoval::E2/scale_; } else { total = ZERO; } // now for the NLO bit double mu4 = sqr(mu2_); double lmu = mu_!=0. ? log(mu_) : 0.; double v = sqrt(1.-4.*mu2_),v2(sqr(v)); double omv = 4.*mu2_/(1.+v); double f1,f2,fNS,VNS; double r = omv/(1.+v); double lr = mu_!=0. ? log(r) : 0.; // normal form if(mu_>1e-4) { f1 = CF_*aS_/Constants::pi* ( +1. + 3.*log(0.5*(1.+v)) - 1.5*log(0.5*(1.+v2)) + sqr(Constants::pi)/6. - 0.5*sqr(lr) - (1.+v2)/v*(lr*log(1.+v2) + sqr(Constants::pi)/12. -0.5*log(4.*mu2_)*lr + 0.25*sqr(lr))); fNS = -0.5*(1.+2.*v2)*lr/v + 1.5*lr - 2./3.*sqr(Constants::pi) + 0.5*sqr(lr) + (1.+v2)/v*(Herwig::Math::ReLi2(r) + sqr(Constants::pi)/3. - 0.25*sqr(lr) + lr*log((2.*v/ (1.+v)))); VNS = 1.5*log(0.5*(1.+v2)) + 0.5*(1.+v2)/v*( 2.*lr*log(2.*(1.+v2)/sqr(1.+v)) + 2.*Herwig::Math::ReLi2(sqr(r)) - 2.*Herwig::Math::ReLi2(2.*v/(1.+v)) - sqr(Constants::pi)/6.) + log(1.-mu_) - 2.*log(1.-2.*mu_) - 4.*mu2_/(1.+v2)*log(mu_/(1.-mu_)) - mu_/(1.-mu_) + 4.*(2.*mu2_-mu_)/(1.+v2) + 0.5*sqr(Constants::pi); f2 = CF_*aS_/Constants::pi*mu2_*lr/v; } // small mass limit else { f1 = -CF_*aS_/Constants::pi/6.* ( - 6. - 24.*lmu*mu2_ - 15.*mu4 - 12.*mu4*lmu - 24.*mu4*sqr(lmu) + 2.*mu4*sqr(Constants::pi) - 12.*mu2_*mu4 - 96.*mu2_*mu4*sqr(lmu) + 8.*mu2_*mu4*sqr(Constants::pi) - 80.*mu2_*mu4*lmu); fNS = - mu2_/18.*( + 36.*lmu - 36. - 45.*mu2_ + 216.*lmu*mu2_ - 24.*mu2_*sqr(Constants::pi) + 72.*mu2_*sqr(lmu) - 22.*mu4 + 1032.*mu4 * lmu - 96.*mu4*sqr(Constants::pi) + 288.*mu4*sqr(lmu)); VNS = - mu2_/1260.*(-6930. + 7560.*lmu + 2520.*mu_ - 16695.*mu2_ + 1260.*mu2_*sqr(Constants::pi) + 12600.*lmu*mu2_ + 1344.*mu_*mu2_ - 52780.*mu4 + 36960.*mu4*lmu + 5040.*mu4*sqr(Constants::pi) - 12216.*mu_*mu4); f2 = CF_*aS_*mu2_/Constants::pi*( 2.*lmu + 4.*mu2_*lmu + 2.*mu2_ + 12.*mu4*lmu + 7.*mu4); } // add up bits for f1 f1 += CF_*aS_/Constants::pi*(fNS+VNS); double realFact(0.); for(int iemit=0;iemit<2;++iemit) { // now for the real correction double phi = UseRandom::rnd()*Constants::twopi; // calculate y double yminus = 0.; double yplus = 1.-2.*mu_*(1.-mu_)/(1.-2*mu2_); double y = yminus + UseRandom::rnd()*(yplus-yminus); // calculate z double v1 = sqrt(sqr(2.*mu2_+(1.-2.*mu2_)*(1.-y))-4.*mu2_)/(1.-2.*mu2_)/(1.-y); double zplus = (1.+v1)*(1.-2.*mu2_)*y/2./(mu2_ +(1.-2.*mu2_)*y); double zminus = (1.-v1)*(1.-2.*mu2_)*y/2./(mu2_ +(1.-2.*mu2_)*y); double z = zminus + UseRandom::rnd()*(zplus-zminus); double jac = (1.-y)*(yplus-yminus)*(zplus-zminus); // calculate x1,x2 double x2 = 1. - y*(1.-2.*mu2_); double x1 = 1. - z*(x2-2.*mu2_); // copy the particle objects over for calculateRealEmission - tcPDVector outgoing = {part.dataPtr(),outgoing[0],outgoing[1],gluon_}; + tcPDVector oTemp = {part.dataPtr(),outgoing[0],outgoing[1],gluon_}; vector mom = {part.momentum(),momenta[0],momenta[1]}; // total real emission contribution realFact += 0.25*jac*sqr(1.-2.*mu2_)/ sqrt(1.-4.*mu2_)/Constants::twopi - *2.*CF_*aS_*calculateRealEmission(x1, x2, outgoing, mom, phi, + *2.*CF_*aS_*calculateRealEmission(x1, x2, oTemp, mom, phi, iemit, true); } // the born + virtual + real output = output*(1. + f1 + realFact) + f2*total; return output; } void SMZDecayer::doinitrun() { PerturbativeDecayer::doinitrun(); if(initialize()) { for(unsigned int ix=0;ixmaxWeight(); else if(ix<11) leptonWeight_[ix-5 ]=mode(ix)->maxWeight(); } } } void SMZDecayer::dataBaseOutput(ofstream & output, bool header) const { if(header) output << "update decayers set parameters=\""; for(unsigned int ix=0;ixmomentum().phi(); // wavefunctions for the decaying particle in the rotated dipole frame vector vec1 = _vectors; for(unsigned int ix=0;ix vec2 = _vectors; for(unsigned int ix=0;ixid()<0) swap(iferm,ianti); // wavefunctions for the particles before the radiation // wavefunctions for the outgoing fermion SpinorBarWaveFunction wavebartemp; Lorentz5Momentum ptemp = - _wavebar[0].momentum(); ptemp *= rot2; if(ptemp.perp()/ptemp.e()<1e-10) { ptemp.setX(ZERO); ptemp.setY(ZERO); } wavebartemp = SpinorBarWaveFunction(ptemp,_wavebar[0].particle(),outgoing); // wavefunctions for the outgoing antifermion SpinorWaveFunction wavetemp; ptemp = - _wave[0].momentum(); ptemp *= rot2; if(ptemp.perp()/ptemp.e()<1e-10) { ptemp.setX(ZERO); ptemp.setY(ZERO); } wavetemp = SpinorWaveFunction(ptemp,_wave[0].particle(),outgoing); // loop over helicities vector wf_old; vector wfb_old; for(unsigned int ihel=0;ihel<2;++ihel) { wavetemp.reset(ihel); wf_old.push_back(wavetemp); wavebartemp.reset(ihel); wfb_old.push_back(wavebartemp); } // calculate the wave functions for the new fermions // ensure the momenta have pT=0 for(unsigned int ix=0;ix<2;++ix) { Lorentz5Momentum ptemp = children[ix]->momentum(); if(ptemp.perp()/ptemp.e()<1e-10) { ptemp.setX(ZERO); ptemp.setY(ZERO); children[ix]->set5Momentum(ptemp); } } // calculate the wavefunctions vector wfb; SpinorBarWaveFunction::calculateWaveFunctions(wfb,children[iferm],outgoing); vector wf; SpinorWaveFunction::calculateWaveFunctions (wf ,children[ianti],outgoing); // wave functions for the photons vector photon; VectorWaveFunction::calculateWaveFunctions(photon,children[2],outgoing,true); // loop to calculate the matrix elements Complex lome[3][2][2],diffme[3][2][2][2],summe[3][2][2][2]; Energy2 scale(sqr(parent.mass())); Complex diff[2]={0.,0.}; Complex sum [2]={0.,0.}; for(unsigned int ifm=0;ifm<2;++ifm) { for(unsigned int ia=0;ia<2;++ia) { for(unsigned int vhel=0;vhel<3;++vhel) { // calculation of the leading-order matrix element Complex loamp = FFZVertex_->evaluate(scale,wf_old[ia], wfb_old[ifm],vec2[vhel]); Complex lotemp = FFZVertex_->evaluate(scale,wf[ia], wfb[ifm],vec1[vhel]); if(iferm>ianti) lome[vhel][ia][ifm] = loamp; else lome[vhel][ifm][ia] = loamp; // photon loop for the real emmision terms for(unsigned int phel=0;phel<2;++phel) { // radiation from the antifermion // normal case with small angle treatment if(children[2 ]->momentum().z()/ children[iferm]->momentum().z()>=ZERO && iemitter == iferm ) { Complex dipole = e*double(children[iferm]->dataPtr()->iCharge())/3.* UnitRemoval::E*loamp* (children[iferm]->momentum()*photon[2*phel].wave())/ (children[iferm]->momentum()*children[2]->momentum()); // sum and difference SpinorBarWaveFunction foff = FFPVertex_->evaluateSmall(ZERO,3,children[iferm]->dataPtr()->CC(), wfb[ifm],photon[2*phel], ifm,2*phel,ctheta,phi,stheta,false); diff[0] = FFZVertex_->evaluate(scale,wf[ia],foff,vec1[vhel]) + e*double(children[iferm]->dataPtr()->iCharge())/3.* UnitRemoval::E*(lotemp-loamp)* (children[iferm]->momentum()*photon[2*phel].wave())/ (children[iferm]->momentum()*children[2]->momentum()); sum [0] = diff[0]+2.*dipole; } // special if fermion backwards else { SpinorBarWaveFunction foff = FFPVertex_->evaluate(ZERO,3,children[iferm]->dataPtr()->CC(), wfb[ifm],photon[2*phel]); Complex diag = FFZVertex_->evaluate(scale,wf[ia],foff,vec1[vhel]); Complex dipole = e*double(children[iferm]->dataPtr()->iCharge())/3.* UnitRemoval::E*loamp* (children[iferm]->momentum()*photon[2*phel].wave())/ (children[iferm]->momentum()*children[2]->momentum()); diff[0] = diag-dipole; sum [0] = diag+dipole; } // radiation from the anti fermion // small angle case in general if(children[2 ]->momentum().z()/ children[ianti]->momentum().z()>=ZERO && iemitter == ianti ) { Complex dipole = e*double(children[ianti]->dataPtr()->iCharge())/3.* UnitRemoval::E*loamp* (children[ianti]->momentum()*photon[2*phel].wave())/ (children[ianti]->momentum()*children[2]->momentum()); // sum and difference SpinorWaveFunction foff = FFPVertex_->evaluateSmall(ZERO,3,children[ianti]->dataPtr()->CC(), wf[ia],photon[2*phel], ia,2*phel,ctheta,phi,stheta,false); diff[1] = FFZVertex_->evaluate(scale,foff ,wfb[ifm],vec1[vhel]) + e*double(children[ianti]->dataPtr()->iCharge())/3.* UnitRemoval::E*(lotemp-loamp)* (children[ianti]->momentum()*photon[2*phel].wave())/ (children[ianti]->momentum()*children[2]->momentum()); sum [1] = diff[1]+2.*dipole; } // special if fermion backwards after radiation else { SpinorWaveFunction foff = FFPVertex_->evaluate(ZERO,3,children[ianti]->dataPtr()->CC(), wf[ia],photon[2*phel]); Complex diag = FFZVertex_->evaluate(scale,foff ,wfb[ifm],vec1[vhel]); Complex dipole = e*double(children[ianti]->dataPtr()->iCharge())/3.* UnitRemoval::E*loamp* (children[ianti]->momentum()*photon[2*phel].wave())/ (children[ianti]->momentum()*children[2]->momentum()); // sum and difference diff[1] = diag - dipole; sum [1] = diag + dipole; } // add to me if(iferm>ianti) { diffme[vhel][ia][ifm][phel] = diff[0] + diff[1]; summe [vhel][ia][ifm][phel] = sum[0] + sum[1] ; } else { diffme [vhel][ifm][ia][phel] = diff[0] + diff[1]; summe [vhel][ifm][ia][phel] = sum[0] + sum[1] ; } } } } } // cerr << parent << "\n"; // for(unsigned int ix=0;ixdataPtr()->iCharge()* // children[1]->dataPtr()->iCharge()/9.; // Energy2 ubar = 2.*children[0]->momentum()*children[2]->momentum(); // Energy2 tbar = 2.*children[1]->momentum()*children[2]->momentum(); // double mu2 = sqr(children[1]->mass()/parent.mass()); // double gL = (FFZVertex_->left() *FFZVertex_->norm()).real(); // double gR = (FFZVertex_->right()*FFZVertex_->norm()).real(); // Energy2 den = sqr(parent.mass())*(((sqr(gL)+sqr(gR))*(1-mu2)+6.*mu2*gL*gR)); // InvEnergy2 anal = -iCharge*( 2.*(ubar/tbar+tbar/ubar)/sqr(parent.mass())+ // 4.*mu2/den*((sqr(gL)+sqr(gR))*(1+ubar/tbar+tbar/ubar) // -2.*gL*gR*(1.+2.*(ubar/tbar+tbar/ubar)))); // cerr << "testing ratio " << parent.PDGName() // << " " << difference.real()/sqr(e)/lo.real()*UnitRemoval::InvE2/(anal) << "\n" // << stheta << " " << ctheta << "\n"; return difference.real()/sqr(e)/lo.real()*UnitRemoval::InvE2; } double SMZDecayer::oneLoopVirtualME(unsigned int, const Particle & parent, const ParticleVector & children) { assert(children.size()==2); // velocities of the particles double beta = sqrt(1.-4.*sqr(children[0]->mass()/parent.mass())); double opb = 1.+beta; double omb = 4.*sqr(children[0]->mass()/parent.mass())/opb; // couplings double gL = (FFZVertex_->left() *FFZVertex_->norm()).real(); double gR = (FFZVertex_->right()*FFZVertex_->norm()).real(); double gA = 0.5*(gL-gR); double gV = 0.5*(gL+gR); // correction terms double ln = log(omb/opb); double f1 = 1. + ln*beta; double fA = 1. + ln/beta; InvEnergy f2 = 0.5*sqrt(omb*opb)/parent.mass()/beta*ln; // momentum difference for the loop Lorentz5Momentum q = children[0]->momentum()-children[1]->momentum(); if(children[0]->id()<0) q *= -1.; // spinors vector > sp; vector > sbar; for(unsigned int ix=0;ix<2;++ix) { sp .push_back( _wave[ix].dimensionedWave()); sbar.push_back(_wavebar[ix].dimensionedWave()); } // polarization vectors vector pol; for(unsigned int ix=0;ix<3;++ix) pol.push_back(_vectors[ix].wave()); // matrix elements complex lome[3][2][2],loopme[3][2][2]; for(unsigned int vhel=0;vhel<3;++vhel) { for(unsigned int ihel1=0;ihel1<2;++ihel1) { for(unsigned int ihel2=0;ihel2<2;++ihel2) { complex vector = sp[ihel1].generalCurrent(sbar[ihel2], 1.,1.).dot(pol[vhel]); complex axial = sp[ihel1].generalCurrent(sbar[ihel2],-1.,1.).dot(pol[vhel]); complex scalar = sp[ihel1].scalar(sbar[ihel2])*(q*pol[vhel]); lome [vhel][ihel1][ihel2] = gV* vector-gA* axial; loopme[vhel][ihel1][ihel2] = gV*f1*vector-gA*fA*axial+scalar*f2*gV; } } } // sum sums complex den(ZERO),num(ZERO); for(unsigned int vhel1=0;vhel1<3;++vhel1) { for(unsigned int vhel2=0;vhel2<3;++vhel2) { for(unsigned int ihel1=0;ihel1<2;++ihel1) { for(unsigned int ihel2=0;ihel2<2;++ihel2) { num += _rho(vhel1,vhel2)* ( lome[vhel1][ihel1][ihel2]*conj(loopme[vhel2][ihel1][ihel2])+ loopme[vhel1][ihel1][ihel2]*conj( lome[vhel2][ihel1][ihel2])); den += _rho(vhel1,vhel2)* lome[vhel1][ihel1][ihel2]*conj(lome[vhel2][ihel1][ihel2]); } } } } // prefactor double iCharge = children[0]->dataPtr()->iCharge()* children[1]->dataPtr()->iCharge()/9.; double pre = 0.5*SM().alphaEM()*iCharge/Constants::pi; // output return pre*num.real()/den.real(); } void SMZDecayer:: initializeMECorrection(RealEmissionProcessPtr born, double & initial, double & final) { // get the quark and antiquark ParticleVector qq; for(unsigned int ix=0;ixbornOutgoing().size();++ix) qq.push_back(born->bornOutgoing()[ix]); // ensure quark first if(qq[0]->id()<0) swap(qq[0],qq[1]); // centre of mass energy d_Q_ = (qq[0]->momentum() + qq[1]->momentum()).m(); // quark mass d_m_ = 0.5*(qq[0]->momentum().m()+qq[1]->momentum().m()); // set the other parameters setRho(sqr(d_m_/d_Q_)); setKtildeSymm(); // otherwise can do it initial=1.; final =1.; } bool SMZDecayer::softMatrixElementVeto(PPtr parent, PPtr progenitor, const bool & , const Energy & highestpT, const vector & ids, const double & d_z, const Energy & d_qt, const Energy &) { // check we should be applying the veto if(parent->id()!=progenitor->id()|| ids[0]->id()!=ids[1]->id()|| ids[2]->id()!=ParticleID::g) return false; // calculate pt Energy2 d_m2 = parent->momentum().m2(); Energy pPerp = (1.-d_z)*sqrt( sqr(d_z*d_qt) - d_m2); // if not hardest so far don't apply veto if(pPerpid()>0) weight = qWeightX(d_qt, d_z); else weight = qbarWeightX(d_qt, d_z); // compute veto from weight and return return !UseRandom::rndbool(weight); } void SMZDecayer::setRho(double r) { d_rho_ = r; d_v_ = sqrt(1.-4.*d_rho_); } void SMZDecayer::setKtildeSymm() { d_kt1_ = (1. + sqrt(1. - 4.*d_rho_))/2.; setKtilde2(); } void SMZDecayer::setKtilde2() { double num = d_rho_ * d_kt1_ + 0.25 * d_v_ *(1.+d_v_)*(1.+d_v_); double den = d_kt1_ - d_rho_; d_kt2_ = num/den; } double SMZDecayer::getZfromX(double x1, double x2) { double uval = u(x2); double num = x1 - (2. - x2)*uval; double den = sqrt(x2*x2 - 4.*d_rho_); return uval + num/den; } double SMZDecayer::getKfromX(double x1, double x2) { double zval = getZfromX(x1, x2); return (1.-x2)/(zval*(1.-zval)); } double SMZDecayer::MEV(double x1, double x2) { // Vector part double num = (x1+2.*d_rho_)*(x1+2.*d_rho_) + (x2+2.*d_rho_)*(x2+2.*d_rho_) - 8.*d_rho_*(1.+2.*d_rho_); double den = (1.+2.*d_rho_)*(1.-x1)*(1.-x2); return (num/den - 2.*d_rho_/((1.-x1)*(1.-x1)) - 2*d_rho_/((1.-x2)*(1.-x2)))/d_v_; } double SMZDecayer::MEA(double x1, double x2) { // Axial part double num = (x1+2.*d_rho_)*(x1+2.*d_rho_) + (x2+2.*d_rho_)*(x2+2.*d_rho_) + 2.*d_rho_*((5.-x1-x2)*(5.-x1-x2) - 19.0 + 4*d_rho_); double den = d_v_*d_v_*(1.-x1)*(1.-x2); return (num/den - 2.*d_rho_/((1.-x1)*(1.-x1)) - 2*d_rho_/((1.-x2)*(1.-x2)))/d_v_; } double SMZDecayer::u(double x2) { return 0.5*(1. + d_rho_/(1.-x2+d_rho_)); } void SMZDecayer:: getXXbar(double kti, double z, double &x, double &xbar) { double w = sqr(d_v_) + kti*(-1. + z)*z*(2. + kti*(-1. + z)*z); if (w < 0) { x = -1.; xbar = -1; } else { x = (1. + sqr(d_v_)*(-1. + z) + sqr(kti*(-1. + z))*z*z*z + z*sqrt(w) - kti*(-1. + z)*z*(2. + z*(-2 + sqrt(w))))/ (1. - kti*(-1. + z)*z + sqrt(w)); xbar = 1. + kti*(-1. + z)*z; } } double SMZDecayer::qWeight(double x, double xbar) { double rval; double xg = 2. - xbar - x; // always return one in the soft gluon region if(xg < EPS_) return 1.0; // check it is in the phase space if((1.-x)*(1.-xbar)*(1.-xg) < d_rho_*xg*xg) return 0.0; double k1 = getKfromX(x, xbar); double k2 = getKfromX(xbar, x); // Is it in the quark emission zone? if(k1 < d_kt1_) { rval = MEV(x, xbar)/PS(x, xbar); // is it also in the anti-quark emission zone? if(k2 < d_kt2_) rval *= 0.5; return rval; } return 1.0; } double SMZDecayer::qbarWeight(double x, double xbar) { double rval; double xg = 2. - xbar - x; // always return one in the soft gluon region if(xg < EPS_) return 1.0; // check it is in the phase space if((1.-x)*(1.-xbar)*(1.-xg) < d_rho_*xg*xg) return 0.0; double k1 = getKfromX(x, xbar); double k2 = getKfromX(xbar, x); // Is it in the antiquark emission zone? if(k2 < d_kt2_) { rval = MEV(x, xbar)/PS(xbar, x); // is it also in the quark emission zone? if(k1 < d_kt1_) rval *= 0.5; return rval; } return 1.0; } double SMZDecayer::qWeightX(Energy qtilde, double z) { double x, xb; getXXbar(sqr(qtilde/d_Q_), z, x, xb); // if exceptionally out of phase space, leave this emission, as there // is no good interpretation for the soft ME correction. if (x < 0 || xb < 0) return 1.0; return qWeight(x, xb); } double SMZDecayer::qbarWeightX(Energy qtilde, double z) { double x, xb; getXXbar(sqr(qtilde/d_Q_), z, xb, x); // see above in qWeightX. if (x < 0 || xb < 0) return 1.0; return qbarWeight(x, xb); } double SMZDecayer::PS(double x, double xbar) { double u = 0.5*(1. + d_rho_ / (1.-xbar+d_rho_)); double z = u + (x - (2.-xbar)*u)/sqrt(xbar*xbar - 4.*d_rho_); double brack = (1.+z*z)/(1.-z)- 2.*d_rho_/(1-xbar); // interesting: the splitting function without the subtraction // term. Actually gives a much worse approximation in the collinear // limit. double brack = (1.+z*z)/(1.-z); double den = (1.-xbar)*sqrt(xbar*xbar - 4.*d_rho_); return brack/den; } double SMZDecayer::matrixElementRatio(const Particle & part, const ParticleVector & decay2, const ParticleVector & decay3, MEOption, ShowerInteraction inter) { // extract partons and LO momentas tcPDVector partons(1,part.dataPtr()); vector lomom(1,part.momentum()); for(unsigned int ix=0;ix<2;++ix) { partons.push_back(decay2[ix]->dataPtr()); lomom.push_back(decay2[ix]->momentum()); } vector realmom(1,part.momentum()); for(unsigned int ix=0;ix<3;++ix) { if(ix==2) partons.push_back(decay3[ix]->dataPtr()); realmom.push_back(decay3[ix]->momentum()); } if(partons[0]->id()<0) { swap(partons[1],partons[2]); swap(lomom[1],lomom[2]); swap(realmom[1],realmom[2]); } scale_ = sqr(part.mass()); double lome = loME(partons,lomom); InvEnergy2 reme = realME(partons,realmom,inter); double ratio = reme/lome*sqr(part.mass())*4.*Constants::pi; if(inter==ShowerInteraction::QCD) ratio *= CF_; return ratio; } double SMZDecayer::meRatio(tcPDVector partons, vector 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 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,ShowerInteraction::QCD)*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 SMZDecayer::loME(const tcPDVector & partons, const vector & momenta) const { // compute the spinors vector vin; vector aout; vector fout; VectorWaveFunction zin (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){ zin.reset(ix); vin.push_back(zin); } // 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 = FFZVertex_->evaluate(scale_,aout[outhel2],fout[outhel1],vin[inhel]); total += norm(diag1); } } } // return the answer return total; } InvEnergy2 SMZDecayer::realME(const tcPDVector & partons, const vector & momenta, ShowerInteraction inter) const { AbstractFFVVertexPtr vertex = inter==ShowerInteraction::QCD ? FFGVertex_ : FFPVertex_; // compute the spinors vector vin; vector aout; vector fout; vector gout; VectorWaveFunction zin (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){ zin.reset(ix); vin.push_back(zin); } vector 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 = vertex->evaluate(scale_,3,partons[1]->CC(),fout[outhel1],gout[outhel3]); diag[0] = FFZVertex_->evaluate(scale_,aout[outhel2],off1,vin[inhel1]); SpinorWaveFunction off2 = vertex->evaluate(scale_,3,partons[2]->CC(),aout[outhel2],gout[outhel3]); diag[1] = FFZVertex_->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(vertex->norm()); // return the total return total*UnitRemoval::InvE2; } double SMZDecayer::calculateRealEmission(double x1, double x2, vector hardProcess, double phi, bool subtract) const { // make partons data object for meRatio tcPDVector 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))/(sqr(x2)-4.*mu2_))); // calculate the momenta Energy M = mZ_; Lorentz5Momentum pspect(ZERO,ZERO,-0.5*M*sqrt(max(sqr(x2)-4.*mu2_,0.)),0.5*M*x2,M*mu_); Lorentz5Momentum pemit (-0.5*M*xT*cos(phi),-0.5*M*xT*sin(phi), 0.5*M*sqrt(max(sqr(x1)-sqr(xT)-4.*mu2_,0.)),0.5*M*x1,M*mu_); 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.); for(unsigned int iemit=0;iemit<2;++iemit) { // 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 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); } // total real emission contribution return realwgt; } double SMZDecayer::calculateRealEmission(double x1, double x2, tcPDVector partons, vector pin, double phi, bool subtract, int emitter) const { // calculate x3 double x3 = 2.-x1-x2; double xT = sqrt(max(0.,sqr(x3) -0.25*sqr(sqr(x2)+sqr(x3)-sqr(x1))/(sqr(x2)-4.*mu2_))); // calculate the momenta Energy M = mZ_; Lorentz5Momentum pspect(ZERO,ZERO,-0.5*M*sqrt(max(sqr(x2)-4.*mu2_,0.)),0.5*M*x2,M*mu_); Lorentz5Momentum pemit (-0.5*M*xT*cos(phi),-0.5*M*xT*sin(phi), 0.5*M*sqrt(max(sqr(x1)-sqr(xT)-4.*mu2_,0.)),0.5*M*x1,M*mu_); 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()); // boost and rotate momenta LorentzRotation eventFrame( ( pin[1]+pin[2] ).findBoostToCM() ); unsigned int ispect = emitter==0 ? 2 : 1; Lorentz5Momentum spectator = eventFrame*pin[ispect]; eventFrame.rotateZ( -spectator.phi() ); eventFrame.rotateY( -spectator.theta() ); eventFrame.invert(); vector momenta(3); momenta[0] = pin[0]; momenta[ispect ] = eventFrame*pspect; momenta[emitter+1] = eventFrame*pemit ; momenta.push_back(eventFrame*pgluon); // calculate the weight double realwgt(0.); if(1.-x1>1e-5 && 1.-x2>1e-5) realwgt = meRatio(partons,momenta,emitter,subtract); // total real emission contribution return realwgt; } diff --git a/Decay/TensorMeson/TensorMesonSpin3VectorDecayer.cc b/Decay/TensorMeson/TensorMesonSpin3VectorDecayer.cc --- a/Decay/TensorMeson/TensorMesonSpin3VectorDecayer.cc +++ b/Decay/TensorMeson/TensorMesonSpin3VectorDecayer.cc @@ -1,285 +1,285 @@ // -*- C++ -*- // // Spin3MesonTensorPScalarDecayer.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2019 The Herwig Collaboration // // Herwig is licenced under version 3 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // // // This is the implementation of the non-inlined, non-templated member // functions of the TensorMesonSpin3VectorDecayer class. // #include "TensorMesonSpin3VectorDecayer.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Interface/Command.h" #include "ThePEG/Helicity/WaveFunction/Rank3TensorWaveFunction.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/PDT/DecayMode.h" #include "Herwig/Decay/GeneralDecayMatrixElement.h" using namespace Herwig; using namespace ThePEG::Helicity; void TensorMesonSpin3VectorDecayer::doinitrun() { DecayIntegrator::doinitrun(); if(initialize()) { for(unsigned int ix=0;ixmaxWeight(); } } void TensorMesonSpin3VectorDecayer::doinit() { DecayIntegrator::doinit(); // check consistence of the parameters unsigned int isize=incoming_.size(); if(isize!=outgoing_.size()||isize!=maxWeight_.size()||isize!=coupling_.size()) throw InitException() << "Inconsistent parameters TensorMesonSpin3VectorDecayer" << Exception::abortnow; // set up the integration channels vector wgt(0); PhaseSpaceModePtr mode; for(unsigned int ix=0;ixid()); int idbar = parent->CC() ? parent->CC()->id() : id; int id1(children[0]->id()); int id1bar = children[0]->CC() ? children[0]->CC()->id() : id1; int id2(children[1]->id()); int id2bar = children[1]->CC() ? children[1]->CC()->id() : id2; int imode(-1); unsigned int ix(0); cc=false; do { if(id ==incoming_[ix]) { if((id1 ==outgoing_[ix].first&&id2 ==outgoing_[ix].second)|| (id2 ==outgoing_[ix].first&&id1 ==outgoing_[ix].second)) imode=ix; } if(idbar==incoming_[ix]) { if((id1bar==outgoing_[ix].first&&id2bar==outgoing_[ix].second)|| (id2bar==outgoing_[ix].first&&id1bar==outgoing_[ix].second)) { imode=ix; cc=true; } } ++ix; } while(ix> incoming_ >> outgoing_ >> maxWeight_ >> iunit(coupling_,GeV); } // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeHerwigTensorMesonSpin3VectorDecayer("Herwig::TensorMesonSpin3VectorDecayer", "HwTMDecay.so"); void TensorMesonSpin3VectorDecayer::Init() { static ClassDocumentation documentation ("The TensorMesonSpin3VectorDecayer class is designed for the decay" " of a tensor meson to a tensor and pseudoscalar mesons."); static Command interfaceSetUpDecayMode ("SetUpDecayMode", "Set up the particles, coupling(GeV) and max weight for a decay", &TensorMesonSpin3VectorDecayer::setUpDecayMode, false); } string TensorMesonSpin3VectorDecayer::setUpDecayMode(string arg) { // parse first bit of the string string stype = StringUtils::car(arg); arg = StringUtils::cdr(arg); // extract PDG code for the incoming particle long in = stoi(stype); tcPDPtr pData = getParticleData(in); if(!pData) return "Incoming particle with id " + std::to_string(in) + "does not exist"; if(pData->iSpin()!=PDT::Spin2) return "Incoming particle with id " + std::to_string(in) + "does not have spin 2"; // and outgoing particles stype = StringUtils::car(arg); arg = StringUtils::cdr(arg); pair out; out.first = stoi(stype); pData = getParticleData(out.first); if(!pData) return "First outgoing particle with id " + std::to_string(out.first) + "does not exist"; if(pData->iSpin()!=PDT::Spin3) return "First outgoing particle with id " + std::to_string(out.first) + "does not have spin 3"; out.first = stoi(stype); stype = StringUtils::car(arg); arg = StringUtils::cdr(arg); out.second = stoi(stype); pData = getParticleData(out.second); if(!pData) return "Second outgoing particle with id " + std::to_string(out.second) + "does not exist"; if(pData->iSpin()!=PDT::Spin1) return "Second outgoing particle with id " + std::to_string(out.second) + "does not have spin 1"; // get the coupling stype = StringUtils::car(arg); arg = StringUtils::cdr(arg); Energy g = stof(stype)*GeV; // and the maximum weight stype = StringUtils::car(arg); arg = StringUtils::cdr(arg); double wgt = stof(stype); // store the information incoming_.push_back(in); outgoing_.push_back(out); coupling_.push_back(g); maxWeight_.push_back(wgt); // success return ""; } void TensorMesonSpin3VectorDecayer:: constructSpinInfo(const Particle & part, ParticleVector decay) const { TensorWaveFunction::constructSpinInfo(tensors_,const_ptr_cast(&part), incoming,true,false); // set up the spin information for the decay products Rank3TensorWaveFunction::constructSpinInfo(rank3_,decay[0], outgoing,true,false); VectorWaveFunction::constructSpinInfo(vectors_,decay[1],outgoing,true, decay[1]->id()==ParticleID::gamma); } // matrix elememt for the process double TensorMesonSpin3VectorDecayer::me2(const int,const Particle & part, const tPDVector & outgoing, const vector & momenta, MEOption meopt) const { if(!ME()) ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin2,PDT::Spin3,PDT::Spin1))); // check for photons bool photon(outgoing[1]->id()==ParticleID::gamma); // stuff for incoming particle if(meopt==Initialize) { rho_ = RhoDMatrix(PDT::Spin2); TensorWaveFunction:: calculateWaveFunctions(tensors_,rho_,const_ptr_cast(&part), incoming,false); } rank3_.resize(7); Rank3TensorWaveFunction twave(momenta[0],outgoing[0],Helicity::outgoing); for(unsigned int ihel=0;ihel<7;++ihel) { twave.reset(ihel); rank3_[ihel] = twave.wave(); } vectors_.resize(3); for(unsigned int ix=0;ix<3;++ix) { if(photon && ix==1) continue; vectors_[ix] = HelicityFunctions::polarizationVector(-momenta[1],ix,Helicity::outgoing); } // calculate the matrix element Energy2 denom[2] = {part.momentum()*momenta[0]-part.mass() *momenta[0].mass(), momenta[0] *momenta[1]-momenta[0].mass()*momenta[1].mass()}; double fact(coupling_[imode()]/part.mass()); for(unsigned int ih1=0;ih1<7;++ih1) { for(unsigned int ih2=0;ih2<3;++ih2) { if(ih2==1 && photon) { for(unsigned int ih0=0;ih0<5;++ih0) (*ME())(ih0,ih1,ih2)=0.; } else { LorentzPolarizationVector v0 = vectors_[ih2] - momenta[1]*momenta[0].dot(vectors_[ih2])/denom[1]; LorentzTensor t0 = rank3_[ih1].dot(v0,0); LorentzPolarizationVectorE v1 = t0.postDot(momenta[1]); Complex d1 = v1*momenta[1]/denom[0]; for(unsigned int ih0=0;ih0<5;++ih0) { LorentzPolarizationVectorE v2 = tensors_[ih0].postDot(momenta[0]); Complex d2 = v2*momenta[0]/denom[0]; (*ME())(ih0,ih1,ih2) = fact*(t0*tensors_[ih0] - 2.*v1.dot(v2)/denom[0]+d1*d2); } } } } double output = ME()->contract(rho_).real(); // test of the answer - double test = 7./5.*sqr(fact); - if(photon) test *=2./3.; + // double test = 7./5.*sqr(fact); + // if(photon) test *=2./3.; // cout << "testing matrix element for " << part.PDGName() << " -> " // << outgoing[0]->PDGName() << " " << outgoing[1]->PDGName() << " " // << output << " " << test << " " << (output-test)/(output+test) << endl; // return the answer return output; } bool TensorMesonSpin3VectorDecayer::twoBodyMEcode(const DecayMode & dm,int & mecode, double & coupling) const { int imode(-1); int id(dm.parent()->id()); int idbar = dm.parent()->CC() ? dm.parent()->CC()->id() : id; ParticleMSet::const_iterator pit(dm.products().begin()); int id1((**pit).id()); int id1bar = (**pit).CC() ? (**pit).CC()->id() : id1; ++pit; int id2((**pit).id()); int id2bar = (**pit).CC() ? (**pit).CC()->id() : id2; unsigned int ix(0); bool order(false); do { if(id ==incoming_[ix]) { if(id1==outgoing_[ix].first&&id2==outgoing_[ix].second) { imode=ix; order=true; } if(id2==outgoing_[ix].first&&id1==outgoing_[ix].second) { imode=ix; order=false; } } if(idbar==incoming_[ix]&&imode<0) { if(id1bar==outgoing_[ix].first&&id2bar==outgoing_[ix].second) { imode=ix; order=true; } if(id2bar==outgoing_[ix].first&&id1bar==outgoing_[ix].second) { imode=ix; order=false; } } ++ix; } while(ixmass(); mecode=22; return order; } void TensorMesonSpin3VectorDecayer::dataBaseOutput(ofstream & output, bool header) const { if(header) output << "update decayers set parameters=\""; // parameters for the DecayIntegrator base class DecayIntegrator::dataBaseOutput(output,false); // the rest of the parameters for(unsigned int ix=0;ixconstituentMass(); } /** * Generate a list of n gluon masses, with a maximum available energy */ list generateMany(size_t n, Energy QMax) const { list res; - Energy m0, mu, md, ms, mg, mgmax, summg; + Energy m0, mu, md, ms, mg, summg; mu=getParticleData(ThePEG::ParticleID::u)->constituentMass(); md=getParticleData(ThePEG::ParticleID::d)->constituentMass(); ms=getParticleData(ThePEG::ParticleID::s)->constituentMass(); m0=md; if(mu QMax - 2.0*m0*(n-k-1) ){ repeat=true; break; } } } return res; } public: /** @name Functions used by the persistent I/O system. */ //@{ /** * Function used to write out object persistently. * @param os the persistent output stream written to. */ void persistentOutput(PersistentOStream & os) const; /** * Function used to read in object persistently. * @param is the persistent input stream read from. * @param version the version number of the object when written. */ void persistentInput(PersistentIStream & is, int version); //@} /** * The standard Init function used to initialize the interfaces. * Called exactly once for each class by the class description system * before the main function starts or * when this class is dynamically loaded. */ static void Init(); protected: /** @name Clone Methods. */ //@{ /** * Make a simple clone of this object. * @return a pointer to the new object. */ virtual IBPtr clone() const; /** Make a clone of this object, possibly modifying the cloned object * to make it sane. * @return a pointer to the new object. */ virtual IBPtr fullclone() const; //@} private: /** * The assignment operator is private and must never be called. * In fact, it should not even be implemented. */ GluonMassGenerator & operator=(const GluonMassGenerator &) = delete; }; } #endif /* Herwig_GluonMassGenerator_H */ diff --git a/MatrixElement/FxFx/FxFxReader.cc b/MatrixElement/FxFx/FxFxReader.cc --- a/MatrixElement/FxFx/FxFxReader.cc +++ b/MatrixElement/FxFx/FxFxReader.cc @@ -1,1605 +1,1605 @@ // -*- C++ -*- // // FxFxReader.cc is a part of ThePEG - Toolkit for HEP Event Generation // Copyright (C) 1999-2019 Leif Lonnblad // // ThePEG is licenced under version 3 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // // // This is the implementation of the non-inlined, non-templated member // functions of the FxFxReader class. // #include "FxFxReader.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Interface/Parameter.h" #include "ThePEG/Interface/Reference.h" #include "ThePEG/Interface/RefVector.h" #include "ThePEG/Interface/Switch.h" #include "ThePEG/Interface/Command.h" //#include "config.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/PDF/PartonExtractor.h" #include "ThePEG/PDF/NoPDF.h" #include "ThePEG/Cuts/Cuts.h" #include "ThePEG/EventRecord/TmpTransform.h" #include "ThePEG/Utilities/UtilityBase.h" #include "ThePEG/Handlers/XComb.h" #include "ThePEG/Handlers/CascadeHandler.h" #include "FxFxEventHandler.h" #include "ThePEG/Utilities/Throw.h" #include "ThePEG/Utilities/HoldFlag.h" #include "ThePEG/Utilities/Debug.h" #include "ThePEG/Helicity/WaveFunction/SpinorWaveFunction.h" using namespace ThePEG; FxFxReader::FxFxReader(bool active) : theNEvents(0), position(0), reopened(0), theMaxScan(-1), scanning(false), isActive(active), theCacheFileName(""), doCutEarly(true), preweight(1.0), reweightPDF(false), doInitPDFs(false), theMaxMultCKKW(0), theMinMultCKKW(0), lastweight(1.0), maxFactor(1.0), optionalnpLO(0), optionalnpNLO(0), weightScale(1.0*picobarn), skipping(false), theMomentumTreatment(0), useWeightWarnings(true),theReOpenAllowed(true), theIncludeSpin(true) {} FxFxReader::FxFxReader(const FxFxReader & x) : HandlerBase(x), LastXCombInfo<>(x), heprup(x.heprup), hepeup(x.hepeup), inData(x.inData), inPDF(x.inPDF), outPDF(x.outPDF), thePartonExtractor(x.thePartonExtractor), thePartonBins(x.thePartonBins), theXCombs(x.theXCombs), theCuts(x.theCuts), theNEvents(x.theNEvents), position(x.position), reopened(x.reopened), theMaxScan(x.theMaxScan), scanning(false), isActive(x.isActive), theCacheFileName(x.theCacheFileName), doCutEarly(x.doCutEarly), stats(x.stats), statmap(x.statmap), thePartonBinInstances(x.thePartonBinInstances), reweights(x.reweights), preweights(x.preweights), preweight(x.preweight), reweightPDF(x.reweightPDF), doInitPDFs(x.doInitPDFs), theMaxMultCKKW(x.theMaxMultCKKW), theMinMultCKKW(x.theMinMultCKKW), lastweight(x.lastweight), maxFactor(x.maxFactor), weightScale(x.weightScale), xSecWeights(x.xSecWeights), maxWeights(x.maxWeights), skipping(x.skipping), theMomentumTreatment(x.theMomentumTreatment), useWeightWarnings(x.useWeightWarnings), theReOpenAllowed(x.theReOpenAllowed), theIncludeSpin(x.theIncludeSpin) {} FxFxReader::~FxFxReader() {} void FxFxReader::doinitrun() { HandlerBase::doinitrun(); stats.reset(); for ( StatMap::iterator i = statmap.begin(); i != statmap.end(); ++i ) i->second.reset(); open(); if ( cacheFileName().length() ) openReadCacheFile(); position = 0; reopened = 0; } bool FxFxReader::preInitialize() const { if ( HandlerBase::preInitialize() ) return true; if ( doInitPDFs && ! ( inPDF.first && inPDF.second ) ) return true; return false; } void FxFxReader::doinit() { HandlerBase::doinit(); open(); close(); if ( !heprup.IDBMUP.first || !heprup.IDBMUP.second ) Throw() << "No information about incoming particles were found in " << "FxFxReader '" << name() << "'." << Exception::warning; inData = make_pair(getParticleData(heprup.IDBMUP.first), getParticleData(heprup.IDBMUP.second)); if ( heprup.EBMUP.first <= 0.0 || heprup.EBMUP.second <= 0.0 ) Throw() << "No information about the energy of incoming particles were found in " << "FxFxReader '" << name() << "'." << Exception::warning; if ( doInitPDFs && ! ( inPDF.first && inPDF.second ) ) { initPDFs(); if ( ! ( inPDF.first && inPDF.second ) ) Throw() << "FxFxReader '" << name() << "' could not create PDFBase objects in pre-initialization." << Exception::warning; } else if ( !inPDF.first || !inPDF.second ) Throw() << "No information about the PDFs of incoming particles were found in " << "FxFxReader '" << name() << "'." << Exception::warning; } void FxFxReader::initPDFs() { if ( inPDF.first && inPDF.second ) return; string remhname; if ( heprup.PDFSUP.first && !inPDF.first) { inPDF.first = dynamic_ptr_cast (generator()->preinitCreate("ThePEG::LHAPDF", fullName() + "/PDFA", "ThePEGLHAPDF.so")); if ( !inPDF.first ) { Throw() << "FxFxReader '" << name() << "' could not use information " << "about the PDFs used because the LHAPDF library was not properly " "defined." << Exception::warning; return; } remhname = fullName() + "/DummyRemH"; generator()->preinitCreate("ThePEG::NoRemnants", remhname); generator()->preinitInterface(inPDF.first, "RemnantHandler", "set", remhname); if ( heprup.PDFGUP.first > 0 && heprup.PDFGUP.first < 10 ) { ostringstream os; os << heprup.PDFGUP.first << " " << heprup.PDFSUP.first; generator()->preinitInterface(inPDF.first, "PDFLIBNumbers", "set", os.str()); } else { ostringstream os; os << heprup.PDFGUP.first*1000 + heprup.PDFSUP.first; generator()->preinitInterface(inPDF.first, "PDFNumber", "set", os.str()); } generator()->preinitInterface(inPDF.first, "RangeException", "newdef", "Freeze"); } if ( heprup.PDFSUP.second && !inPDF.second) { inPDF.second = dynamic_ptr_cast (generator()->preinitCreate("ThePEG::LHAPDF", fullName() + "/PDFB", "ThePEGLHAPDF.so")); if ( !inPDF.second ) { Throw() << "FxFxReader '" << name() << "' could not use information " << "about the PDFs used because the LHAPDF library was not properly " "defined." << Exception::warning; return; } if ( remhname == "" ) { remhname = fullName() + "/DummyRemH"; generator()->preinitCreate("ThePEG::NoRemnants", remhname); } generator()->preinitInterface(inPDF.second, "RemnantHandler", "set", remhname); if ( heprup.PDFGUP.second > 0 && heprup.PDFGUP.second < 10 ) { ostringstream os; os << heprup.PDFGUP.second << " " << heprup.PDFSUP.second; generator()->preinitInterface(inPDF.second, "PDFLIBNumbers", "set", os.str()); } else { ostringstream os; os << heprup.PDFGUP.second*1000 + heprup.PDFSUP.second; generator()->preinitInterface(inPDF.second, "PDFNumber", "set", os.str()); } generator()->preinitInterface(inPDF.second, "RangeException", "newdef", "Freeze"); } if ( ! ( inPDF.first && inPDF.second ) ) Throw() << "FxFxReader '" << name() << "' could not find information about the PDFs used." << Exception::warning; } void FxFxReader::initialize(FxFxEventHandler & eh) { Energy2 Smax = ZERO; double Y = 0.0; if ( !theCuts ) { theCuts = eh.cuts(); if ( !theCuts ) Throw() << "No Cuts object was assigned to the FxFxReader '" << name() << "' nor was one\nassigned to the controlling " << "FxFxEventHandler '" << eh.name() << "'.\nAt least one of them " << "needs to have a Cuts object." << Exception::runerror; Smax = cuts().SMax(); Y = cuts().Y(); } theCKKW = eh.CKKWHandler(); if ( !partonExtractor() ) { thePartonExtractor = eh.partonExtractor(); if ( !partonExtractor() ) Throw() << "No PartonExtractor object was assigned to the FxFxReader '" << name() << "' nor was one\nassigned to the controlling " << "FxFxEventHandler '" << eh.name() << "'.\nAt least one of them " << "needs to have a PartonExtractor object." << Exception::runerror; } open(); Energy emax = 2.0*sqrt(heprup.EBMUP.first*heprup.EBMUP.second)*GeV; theCuts->initialize(sqr(emax), 0.5*log(heprup.EBMUP.first/heprup.EBMUP.second)); if ( Smax > ZERO && ( Smax != cuts().SMax() || Y != cuts().Y() ) ) Throw() << "The FxFxReader '" << name() << "' uses the same Cuts object " << "as another FxFxReader which has not got the same energies of " << "the colliding particles. For the generation to work properly " << "different FxFxReader object with different colliding particles " << "must be assigned different (although possibly identical) Cuts " << "objects." << Exception::warning; thePartonBins = partonExtractor()->getPartons(emax, inData, cuts()); for ( int i = 0, N = partonBins().size(); i < N; ++i ) { theXCombs[partonBins()[i]] = new_ptr(XComb(emax, inData, &eh, partonExtractor(), CKKWHandler(), partonBins()[i], theCuts)); partonExtractor()->nDims(partonBins()[i]); } outPDF = make_pair(partonExtractor()->getPDF(inData.first), partonExtractor()->getPDF(inData.second)); close(); if ( !heprup.IDWTUP && useWeightWarnings ) Throw() << "No information about the weighting scheme was found. The events " << "produced by FxFxReader " << name() << " may not be sampled correctly." << Exception::warning; if ( abs(heprup.IDWTUP) > 1 && !eh.weighted() && useWeightWarnings ) Throw() << "FxFxReader " << name() << " has the IDWTUP flag set to " << heprup.IDWTUP << " which is not supported by this reader, the " << "produced events may not be sampled correctly. It is up to " << "sub-classes of FxFxReader to correctly convert to match IDWTUP " << "+/- 1. Will try to make intelligent guesses to get " << "correct statistics.\nIn most cases this should be sufficient. " << "Unset WeightWarnings to avoid this message," << "or set Weighted to on." << Exception::warning; if ( heprup.IDWTUP != eh.weightOption() && abs(heprup.IDWTUP) < 3 && useWeightWarnings ) Throw() << "FxFxReader " << name() << " has the IDWTUP flag set to " << heprup.IDWTUP << ", which does not correspond\nto the weight option " << eh.weightOption() << " set in " << "the FxFxEventHandler " << eh.name() << ".\n\n" << "Use the following handler setting instead:\n" << " set " << eh.name() << ":WeightOption " << heprup.IDWTUP << "\nWill try to make intelligent guesses to get " << "correct statistics. In most cases this should be sufficient. " << "Unset WeightWarnings to avoid this message" << Exception::warning; scan(); initStat(); } long FxFxReader::scan() { open(); // Shall we write the events to a cache file for fast reading? If so // we write to a temporary file if the caches events should be // randomized. if ( cacheFileName().length() ) openWriteCacheFile(); // Keep track of the number of events scanned. long neve = 0; long cuteve = 0; bool negw = false; // If the open() has not already gotten information about subprocesses // and cross sections we have to scan through the events. if ( !heprup.NPRUP || cacheFile() || abs(heprup.IDWTUP) != 1 ) { // why scan if IDWTUP != 1? HoldFlag<> isScanning(scanning); - double oldsum = 0.0; + // double oldsum = 0.0; vector lprup; vector newmax; vector oldeve; vector neweve; vector sumlprup; vector sumsqlprup; vector nscanned; for ( int i = 0; ( maxScan() < 0 || i < maxScan() ) && readEvent(); ++i ) { if ( !checkPartonBin() ) Throw() << "Found event in LesHouchesReader '" << name() << "' which cannot be handeled by the assigned PartonExtractor '" << partonExtractor()->name() << "'." << Exception::runerror; vector::iterator idit = find(lprup.begin(), lprup.end(), hepeup.IDPRUP); int id = lprup.size(); if ( idit == lprup.end() ) { lprup.push_back(hepeup.IDPRUP); newmax.push_back(0.0); neweve.push_back(0); oldeve.push_back(0); sumlprup.push_back(0.); sumsqlprup.push_back(0.); nscanned.push_back(0); } else { id = idit - lprup.begin(); } ++neve; ++oldeve[id]; - oldsum += hepeup.XWGTUP; + // oldsum += hepeup.XWGTUP; sumlprup[id] += hepeup.XWGTUP; sumsqlprup[id] += sqr(hepeup.XWGTUP); ++nscanned[id]; if ( cacheFile() ) { if ( eventWeight() == 0.0 ) { ++cuteve; continue; } cacheEvent(); } ++neweve[id]; newmax[id] = max(newmax[id], abs(eventWeight())); if ( eventWeight() < 0.0 ) negw = true; } //end of scanning events xSecWeights.resize(oldeve.size(), 1.0); for ( int i = 0, N = oldeve.size(); i < N; ++i ) if ( oldeve[i] ) xSecWeights[i] = double(neweve[i])/double(oldeve[i]); if ( maxScan() < 0 || neve > NEvents() ) NEvents(neve - cuteve); if ( lprup.size() == heprup.LPRUP.size() ) { for ( int id = 0, N = lprup.size(); id < N; ++id ) { vector::iterator idit = find(heprup.LPRUP.begin(), heprup.LPRUP.end(), hepeup.IDPRUP); if ( idit == heprup.LPRUP.end() ) { Throw() << "When scanning events, the LesHouschesReader '" << name() << "' found undeclared processes." << Exception::warning; heprup.NPRUP = 0; break; } int idh = idit - heprup.LPRUP.begin(); heprup.XMAXUP[idh] = newmax[id]; } } if ( heprup.NPRUP == 0 ) { // No heprup block was supplied or something went wrong. heprup.NPRUP = lprup.size(); heprup.LPRUP.resize(lprup.size()); heprup.XMAXUP.resize(lprup.size()); for ( int id = 0, N = lprup.size(); id < N; ++id ) { heprup.LPRUP[id] = lprup[id]; heprup.XMAXUP[id] = newmax[id]; } } if ( abs(heprup.IDWTUP) != 1 ) { // Try to fix things if abs(heprup.IDWTUP) != 1. - double sumxsec = 0.0; + // double sumxsec = 0.0; if(abs(heprup.IDWTUP)==3) { - for ( int id = 0; id < heprup.NPRUP; ++id ) sumxsec += heprup.XSECUP[id]; + // for ( int id = 0; id < heprup.NPRUP; ++id ) sumxsec += heprup.XSECUP[id]; } else { for ( int id = 0; id < heprup.NPRUP; ++id ) { //set the cross section directly from the event weights read heprup.XSECUP[id] = sumlprup[id]/nscanned[id]; heprup.XERRUP[id] = (sumsqlprup[id]/nscanned[id] - sqr(sumlprup[id]/nscanned[id])) / nscanned[id]; if(fabs(heprup.XERRUP[id]) < 1e-10) { heprup.XERRUP[id] = 0; } if(fabs(newmax[id]) < 1e-10) { newmax[id] = 0; } if(heprup.XERRUP[id] < 0.) { if( heprup.XERRUP[id]/(sumsqlprup[id]/nscanned[id])>-1e-10) heprup.XERRUP[id] = 0.; else { Throw() << "Negative error when scanning events in LesHouschesReader '" << name() << Exception::warning; heprup.XERRUP[id] = 0.; } } heprup.XERRUP[id] = sqrt( heprup.XERRUP[id] ); heprup.XMAXUP[id] = newmax[id]; //cout << "heprup.XMAXUP[id] = " << heprup.XMAXUP[id] << endl; - sumxsec += heprup.XSECUP[id]; + // sumxsec += heprup.XSECUP[id]; } } //cout << "sumxsec = " << sumxsec << endl; //weightScale = picobarn*neve*sumxsec/oldsum; weightScale = 1.0*picobarn; // temporary fix? // cout << "weightscale = " << weightScale/picobarn << endl; } } if ( cacheFile() ) closeCacheFile(); if ( negw ) heprup.IDWTUP = min(-abs(heprup.IDWTUP), -1); return neve; } void FxFxReader::setWeightScale(long) {} void FxFxReader::initStat() { stats.reset(); statmap.clear(); if ( heprup.NPRUP <= 0 ) return; double sumx = 0.0; xSecWeights.resize(heprup.NPRUP, 1.0); maxWeights.clear(); for ( int ip = 0; ip < heprup.NPRUP; ++ip ) { sumx = max(heprup.XMAXUP[ip]*xSecWeights[ip], sumx); statmap[heprup.LPRUP[ip]] = XSecStat(heprup.XMAXUP[ip]*weightScale*xSecWeights[ip]); maxWeights[heprup.LPRUP[ip]] = heprup.XMAXUP[ip]; } stats.maxXSec(sumx*weightScale); maxFactor = 1.0; } void FxFxReader::increaseMaxXSec(CrossSection maxxsec) { for ( int i = 0; i < heprup.NPRUP; ++i ) statmap[heprup.LPRUP[i]].maxXSec(statmap[heprup.LPRUP[i]].maxXSec()* maxxsec/stats.maxXSec()); maxFactor *= maxxsec/stats.maxXSec(); stats.maxXSec(maxxsec); } tXCombPtr FxFxReader::getXComb() { if ( lastXCombPtr() ) return lastXCombPtr(); fillEvent(); connectMothers(); tcPBPair sel = createPartonBinInstances(); tXCombPtr lastXC = xCombs()[sel]; // clean up the old XComb object before switching to a new one if ( theLastXComb && theLastXComb != lastXC ) theLastXComb->clean(); theLastXComb = lastXC; lastXCombPtr()->subProcess(SubProPtr()); lastXCombPtr()->setPartonBinInstances(partonBinInstances(), sqr(hepeup.SCALUP)*GeV2); lastXCombPtr()->lastAlphaS(hepeup.AQCDUP); lastXCombPtr()->lastAlphaEM(hepeup.AQEDUP); return lastXCombPtr(); } tSubProPtr FxFxReader::getSubProcess() { getXComb(); if ( subProcess() ) return subProcess(); lastXCombPtr()->subProcess(new_ptr(SubProcess(lastPartons(), tCollPtr(), this))); subProcess()->setOutgoing(outgoing().begin(), outgoing().end()); subProcess()->setIntermediates(intermediates().begin(), intermediates().end()); return subProcess(); } void FxFxReader::fillEvent() { if ( !particleIndex.empty() ) return; particleIndex.clear(); colourIndex.clear(); colourIndex(0, tColinePtr()); createParticles(); createBeams(); } void FxFxReader::reopen() { // If we didn't know how many events there were, we know now. if ( NEvents() <= 0 ) NEvents(position); ++reopened; // How large fraction of the events have we actually used? And how // large will we have used if we go through the file again? double frac = double(stats.attempts())/double(NEvents()); if ( frac*double(reopened + 1)/double(reopened) > 1.0 && NEvents() - stats.attempts() < generator()->N() - generator()->currentEventNumber() ) { if(theReOpenAllowed) generator()->logWarning(FxFxReopenWarning() << "Reopening FxFxReader '" << name() << "' after accessing " << stats.attempts() << " events out of " << NEvents() << Exception::warning); else throw FxFxReopenWarning() << "More events requested than available in FxFxReader " << name() << Exception::runerror; } if ( cacheFile() ) { closeCacheFile(); openReadCacheFile(); if ( !uncacheEvent() ) Throw() << "Could not reopen FxFxReader '" << name() << "'." << Exception::runerror; } else { close(); open(); if ( !readEvent() ) Throw() << "Could not reopen FxFxReader '" << name() << "'." << Exception::runerror; } } void FxFxReader::reset() { particleIndex.clear(); colourIndex.clear(); if ( theLastXComb ) theLastXComb->clean(); theLastXComb = tXCombPtr(); } bool FxFxReader::readEvent() { reset(); if ( !doReadEvent() ) return false; // If we are just skipping event we do not need to reweight or do // anything fancy. if ( skipping ) return true; if ( cacheFile() && !scanning ) return true; // Reweight according to the re- and pre-weights objects in the // FxFxReader base class. lastweight = reweight(); if ( !reweightPDF && !cutEarly() ) return true; // We should try to reweight the PDFs or make early cuts here. fillEvent(); double x1 = incoming().first->momentum().plus()/ beams().first->momentum().plus(); if ( reweightPDF && inPDF.first && outPDF.first && inPDF.first != outPDF.first ) { if ( hepeup.XPDWUP.first <= 0.0 ) hepeup.XPDWUP.first = inPDF.first->xfx(inData.first, incoming().first->dataPtr(), sqr(hepeup.SCALUP*GeV), x1); double xf = outPDF.first->xfx(inData.first, incoming().first->dataPtr(), sqr(hepeup.SCALUP*GeV), x1); lastweight *= xf/hepeup.XPDWUP.first; hepeup.XPDWUP.first = xf; } double x2 = incoming().second->momentum().minus()/ beams().second->momentum().minus(); if ( reweightPDF && inPDF.second && outPDF.second && inPDF.second != outPDF.second ) { if ( hepeup.XPDWUP.second <= 0.0 ) hepeup.XPDWUP.second = inPDF.second->xfx(inData.second, incoming().second->dataPtr(), sqr(hepeup.SCALUP*GeV), x2); double xf = outPDF.second->xfx(inData.second, incoming().second->dataPtr(), sqr(hepeup.SCALUP*GeV), x2); lastweight *= xf/hepeup.XPDWUP.second; hepeup.XPDWUP.second = xf; } if ( cutEarly() ) { if ( !cuts().initSubProcess((incoming().first->momentum() + incoming().second->momentum()).m2(), 0.5*log(x1/x2)) ) lastweight = 0.0; tSubProPtr sub = getSubProcess(); TmpTransform tmp(sub, Utilities::getBoostToCM(sub->incoming())); if ( !cuts().passCuts(*sub) ) lastweight = 0.0; } return true; } double FxFxReader::getEvent() { if ( cacheFile() ) { if ( !uncacheEvent() ) reopen(); } else { if ( !readEvent() ) reopen(); } ++position; double max = maxWeights[hepeup.IDPRUP]*maxFactor; // cout << "maxFactor = " << maxFactor << " maxWeights[hepeup.IDPRUP] = " << maxWeights[hepeup.IDPRUP] << endl; // normalize all the weights to the max weight for(map::iterator it=optionalWeights.begin(); it!=optionalWeights.end();++it) { if(it->first!="ecom" && it->second!=-999 && it->second!=-111 && it->second!=-222 && it->second!=-333) { it->second = (max != 0.0) ? it->second/max : 0.0; } } //cout << "hepeup.XWGTUP = " << hepeup.XWGTUP << endl; //cout << "max = " << max << " " << eventWeight() << endl; return max != 0.0? eventWeight()/max: 0.0; } void FxFxReader::skip(long n) { HoldFlag<> skipflag(skipping); while ( n-- ) getEvent(); } double FxFxReader::reweight() { preweight = 1.0; if ( reweights.empty() && preweights.empty() && !( CKKWHandler() && maxMultCKKW() > 0 && maxMultCKKW() > minMultCKKW() ) ) return 1.0; fillEvent(); getSubProcess(); for ( int i = 0, N = preweights.size(); i < N; ++i ) { preweights[i]->setXComb(lastXCombPtr()); preweight *= preweights[i]->weight(); } double weight = preweight; for ( int i = 0, N = reweights.size(); i < N; ++i ) { reweights[i]->setXComb(lastXCombPtr()); weight *= reweights[i]->weight(); } // If we are caching events we do not want to do CKKW reweighting. if ( cacheFile() ) return weight; if ( CKKWHandler() && maxMultCKKW() > 0 && maxMultCKKW() > minMultCKKW() ) { CKKWHandler()->setXComb(lastXCombPtr()); weight *= CKKWHandler()->reweightCKKW(minMultCKKW(), maxMultCKKW()); } return weight; } bool FxFxReader::checkPartonBin() { // First find the positions of the incoming partons. pair< vector, vector > inc; for ( int i = 0; i < hepeup.NUP; ++i ) { if ( hepeup.ISTUP[i] == -9 ) { if ( inc.first.empty() ) inc.first.push_back(i); else if ( inc.second.empty() ) inc.second.push_back(i); } else if ( hepeup.ISTUP[i] == -1 ) { if ( inc.first.size() && hepeup.MOTHUP[i].first == inc.first.back() + 1 ) inc.first.push_back(i); else if ( inc.second.size() && hepeup.MOTHUP[i].first == inc.second.back() + 1 ) inc.second.push_back(i); else if ( inc.first.empty() ) { inc.first.push_back(-1); inc.first.push_back(i); } else if ( inc.second.empty() ) { inc.second.push_back(-1); inc.second.push_back(i); } else if ( inc.first.size() <= inc.second.size() ) inc.first.push_back(i); else inc.second.push_back(i); } } // Now store the corresponding id numbers pair< vector, vector > ids; ids.first.push_back(inc.first[0] < 0? heprup.IDBMUP.first: hepeup.IDUP[inc.first[0]]); for ( int i = 1, N = inc.first.size(); i < N; ++i ) ids.first.push_back(hepeup.IDUP[inc.first[i]]); ids.second.push_back(inc.second[0] < 0? heprup.IDBMUP.second: hepeup.IDUP[inc.second[0]]); for ( int i = 1, N = inc.second.size(); i < N; ++i ) ids.second.push_back(hepeup.IDUP[inc.second[i]]); // Find the correct pair of parton bins. PBPair pbp; for ( int i = 0, N = partonBins().size(); i < N; ++i ) { tcPBPtr curr = partonBins()[i].first; int icurr = inc.first.size() - 1; while ( curr && icurr >= 0 ) { if ( curr->parton()->id () != ids.first[icurr] ) break; curr = curr->incoming(); --icurr; } if(!(!partonBins()[i].first->incoming() && !partonBins()[i].first->particle() && partonBins()[i].first->parton()->id () == ids.first[0] && ( inc.first.size()==1 || (inc.first.size()==2 && ids.first[0]==ids.first[1]))) && ( curr || icurr >= 0 ) ) continue; curr = partonBins()[i].second; icurr = inc.second.size() - 1; while ( curr && icurr >= 0 ) { if ( curr->parton()->id () != ids.second[icurr] ) break; curr = curr->incoming(); --icurr; } if(!(!partonBins()[i].second->incoming() && !partonBins()[i].second->particle() && partonBins()[i].second->parton()->id () == ids.second[0] && ( inc.second.size()==1 || (inc.second.size()==2 && ids.second[0]==ids.second[1]))) && ( curr || icurr >= 0 ) ) continue; pbp = partonBins()[i]; } // If we are only checking we return here. return ( pbp.first && pbp.second ); } namespace { bool recursionNotNull(tcPBPtr bin, tcPPtr p) { while ( bin && p ) { if ( p->dataPtr() != bin->parton() ) break; bin = bin->incoming(); p = p->parents().size()? p->parents()[0]: tPPtr(); } return bin || p; } } tcPBPair FxFxReader::createPartonBinInstances() { tcPBPair sel; for ( int i = 0, N = partonBins().size(); i < N; ++i ) { tcPBPtr bin = partonBins()[i].first; tcPPtr p = incoming().first; if ( recursionNotNull(bin,p) ) continue; bin = partonBins()[i].second; p = incoming().second; if ( recursionNotNull(bin,p) ) continue; sel = partonBins()[i]; break; } if ( !sel.first || !sel.second ) Throw() << "Could not find appropriate PartonBin objects for event produced by " << "FxFxReader '" << name() << "'." << Exception::runerror; Direction<0> dir(true); thePartonBinInstances.first = new_ptr(PartonBinInstance(incoming().first, sel.first, -sqr(hepeup.SCALUP*GeV))); if ( thePartonBinInstances.first->xi() > 1.00001 ) { Throw() << "Found an event with momentum fraction larger than unity (x1=" << thePartonBinInstances.first->xi() << "). The event will be skipped." << Exception::warning; throw Veto(); } dir.reverse(); thePartonBinInstances.second = new_ptr(PartonBinInstance(incoming().second, sel.second, -sqr(hepeup.SCALUP*GeV))); if ( thePartonBinInstances.second->xi() > 1.00001 ) { Throw() << "Found an event with momentum fraction larger than unity (x2=" << thePartonBinInstances.second->xi() << "). The event will be skipped." << Exception::warning; throw Veto(); } return sel; } void FxFxReader::createParticles() { theBeams = PPair(); theIncoming = PPair(); theOutgoing = PVector(); theIntermediates = PVector(); for ( int i = 0, N = hepeup.IDUP.size(); i < N; ++i ) { if ( !hepeup.IDUP[i] ) continue; Lorentz5Momentum mom(hepeup.PUP[i][0]*GeV, hepeup.PUP[i][1]*GeV, hepeup.PUP[i][2]*GeV, hepeup.PUP[i][3]*GeV, hepeup.PUP[i][4]*GeV); if(theMomentumTreatment == 1) mom.rescaleEnergy(); else if(theMomentumTreatment == 2) mom.rescaleMass(); PDPtr pd = getParticleData(hepeup.IDUP[i]); if (!pd) { Throw() << "FxFxReader '" << name() << "' found unknown particle ID " << hepeup.IDUP[i] << " in Les Houches common block structure.\n" << "You need to define the new particle in an input file.\n" << Exception::runerror; } if ( ! pd->coloured() && ( hepeup.ICOLUP[i].first != 0 || hepeup.ICOLUP[i].second != 0 ) ) { Throw() << "FxFxReader " << name() << ": " << pd->PDGName() << " is not a coloured particle.\nIt should not have " << "(anti-)colour lines " << hepeup.ICOLUP[i].first << ' ' << hepeup.ICOLUP[i].second << " set; the event file needs to be fixed." << Exception::runerror; } PPtr p = pd->produceParticle(mom); if(hepeup.ICOLUP[i].first>=0 && hepeup.ICOLUP[i].second >=0) { tColinePtr c = colourIndex(hepeup.ICOLUP[i].first); if ( c ) c->addColoured(p); c = colourIndex(hepeup.ICOLUP[i].second); if ( c ) c->addAntiColoured(p); } else { tColinePtr c1 = colourIndex(abs(hepeup.ICOLUP[i].first )); tColinePtr c2 = colourIndex(abs(hepeup.ICOLUP[i].second)); if(pd->hasColour()) { c1->addColouredIndexed(p,1); c2->addColouredIndexed(p,2); } else { c1->addAntiColouredIndexed(p,1); c2->addAntiColouredIndexed(p,2); } } particleIndex(i + 1, p); switch ( hepeup.ISTUP[i] ) { case -9: if ( !theBeams.first ) theBeams.first = p; else if ( !theBeams.second ) theBeams.second = p; else Throw() << "To many incoming beam particles in the FxFxReader '" << name() << "'." << Exception::runerror; break; case -1: if ( !theIncoming.first ) theIncoming.first = p; else if ( !theIncoming.second ) theIncoming.second = p; else if ( particleIndex(theIncoming.first) == hepeup.MOTHUP[i].first ) theIncoming.first = p; else if ( particleIndex(theIncoming.second) == hepeup.MOTHUP[i].first ) theIncoming.second = p; else Throw() << "To many incoming particles to hard subprocess in the " << "FxFxReader '" << name() << "'." << Exception::runerror; p->scale(sqr(hepeup.SCALUP*GeV)); break; case 1: theOutgoing.push_back(p); p->scale(sqr(hepeup.SCALUP*GeV)); break; case -2: case 2: case 3: theIntermediates.push_back(p); break; default: Throw() << "Unknown status code (" << hepeup.ISTUP[i] << ") in the FxFxReader '" << name() << "'." << Exception::runerror; } // value 9 is defined as "Unknown or unpolarized particles" double spinup = hepeup.SPINUP[i]; if ( abs(spinup - 9) < 1.0e-3 ) spinup = 0.; if ( spinup < -1. || spinup > 1. ) { Throw() << "Polarization must be between -1 and 1, not " << spinup << " as found in the " << "FxFx event file.\nThe event file needs to be fixed." << Exception::runerror; } if( theIncludeSpin && abs(pd->id()) == ParticleID::tauminus && spinup !=0) { if(pd->iSpin() == PDT::Spin1Half ) { vector wave; Helicity::SpinorWaveFunction(wave,p,Helicity::outgoing,true); RhoDMatrix rho(pd->iSpin(),true); rho(0,0) = 0.5*(1.-spinup); rho(1,1) = 0.5*(1.+spinup); p->spinInfo()->rhoMatrix() = rho; p->spinInfo()-> DMatrix() = rho; } } } // check the colour flows, and if necessary create any sources/sinks // hard process // get the particles in the hard process PVector external; for ( int i = 0, N = hepeup.IDUP.size(); i < N; ++i ) { unsigned int moth; switch ( hepeup.ISTUP[i] ) { case -1: external.push_back(particleIndex.find(i+1)); break; case 1: case 2: case 3: moth = hepeup.MOTHUP[i].first; if(moth!=0 && (hepeup.ISTUP[moth]==-1||hepeup.ISTUP[moth]==-2|| hepeup.ISTUP[moth]==-9)) external.push_back(particleIndex.find(i+1)); moth = hepeup.MOTHUP[i].second; if(moth!=0 && (hepeup.ISTUP[moth]==-1||hepeup.ISTUP[moth]==-2|| hepeup.ISTUP[moth]==-9)) external.push_back(particleIndex.find(i+1)); break; case -2: case -9: default: break; } } // check the incoming/outgoing lines match vector unMatchedColour,unMatchedAntiColour; for(unsigned int ix=0;ix col = external[ix]->colourInfo()-> colourLines(); vector anti = external[ix]->colourInfo()->antiColourLines(); if(hepeup.ISTUP[particleIndex(external[ix])-1]<0) swap(col,anti); if(!col.empty()) { for(unsigned int ic1=0;ic1 col2; if(hepeup.ISTUP[particleIndex(external[iy])-1]<0) { if(external[iy]->colourInfo()->colourLines().empty()) continue; col2 = external[iy]->colourInfo()->colourLines(); } else if(hepeup.ISTUP[particleIndex(external[iy])-1]>0) { if(external[iy]->colourInfo()->antiColourLines().empty()) continue; col2 = external[iy]->colourInfo()->antiColourLines(); } for(unsigned int ic2=0;ic2(col[ic1])); } } if(!anti.empty()) { for(unsigned int ic1=0;ic1 anti2; if(hepeup.ISTUP[particleIndex(external[iy])-1]<0) { if(external[iy]->colourInfo()->antiColourLines().empty()) continue; anti2 = external[iy]->colourInfo()->antiColourLines(); } else if(hepeup.ISTUP[particleIndex(external[iy])-1]>0) { if(external[iy]->colourInfo()->colourLines().empty()) continue; anti2 = external[iy]->colourInfo()->colourLines(); } for(unsigned int ic2=0;ic2(anti[ic1])); } } } // might have source/sink if( unMatchedColour.size() + unMatchedAntiColour.size() != 0) { if(unMatchedColour.size() == 3 ) { unMatchedColour[0]->setSourceNeighbours(unMatchedColour[1], unMatchedColour[2]); } else if(unMatchedColour.size() != 0 && ThePEG_DEBUG_LEVEL) { Throw() << "FxFxReader '" << name() << "' found inconsistent colour " << "flow in Les Houches common block structure for hard process.\n" << hepeup << Exception::runerror; } if(unMatchedAntiColour.size() == 3 ) { unMatchedAntiColour[0]->setSinkNeighbours(unMatchedAntiColour[1], unMatchedAntiColour[2]); } else if(unMatchedAntiColour.size() != 0 && ThePEG_DEBUG_LEVEL) { Throw() << "FxFxReader '" << name() << "' found inconsistent colour " << "flow in Les Houches common block structure for hard process.\n" << hepeup << Exception::runerror; } } // any subsequent decays for ( int i = 0, N = hepeup.IDUP.size(); i < N; ++i ) { if(hepeup.ISTUP[i] !=2 && hepeup.ISTUP[i] !=3) continue; PVector external; external.push_back(particleIndex.find(i+1)); for ( int j = 0; j < N; ++j ) { if(hepeup.MOTHUP[j].first==i+1|| hepeup.MOTHUP[j].second==i+1) external.push_back(particleIndex.find(j+1)); } // check the incoming/outgoing lines match vector unMatchedColour,unMatchedAntiColour; for(unsigned int ix=0;ix col = external[ix]->colourInfo()-> colourLines(); vector anti = external[ix]->colourInfo()->antiColourLines(); if(ix==0) swap(col,anti); if(!col.empty()) { for(unsigned int ic1=0;ic1 col2; if(iy==0) { if(external[iy]->colourInfo()->colourLines().empty()) continue; col2 = external[iy]->colourInfo()->colourLines(); } else { if(external[iy]->colourInfo()->antiColourLines().empty()) continue; col2 = external[iy]->colourInfo()->antiColourLines(); } for(unsigned int ic2=0;ic2(col[ic1])); } } if(!anti.empty()) { for(unsigned int ic1=0;ic1 anti2; if(iy==0) { if(external[iy]->colourInfo()->antiColourLines().empty()) continue; anti2 = external[iy]->colourInfo()->antiColourLines(); } else { if(external[iy]->colourInfo()->colourLines().empty()) continue; anti2 = external[iy]->colourInfo()->colourLines(); } for(unsigned int ic2=0;ic2(anti[ic1])); } } } // might have source/sink if( unMatchedColour.size() + unMatchedAntiColour.size() != 0) { if(unMatchedColour.size() == 3 ) { unMatchedColour[0]->setSourceNeighbours(unMatchedColour[1], unMatchedColour[2]); } else if(unMatchedColour.size() != 0 && ThePEG_DEBUG_LEVEL) { Throw() << "FxFxReader '" << name() << "' found inconsistent colour " << "flow in Les Houches common block structure for decay of \n" << *external[0] << "\n" << hepeup << Exception::runerror; } if(unMatchedAntiColour.size() == 3 ) { unMatchedAntiColour[0]->setSinkNeighbours(unMatchedAntiColour[1], unMatchedAntiColour[2]); } else if(unMatchedAntiColour.size() != 0 && ThePEG_DEBUG_LEVEL) { Throw() << "FxFxReader '" << name() << "' found inconsistent colour " << "flow in Les Houches common block structure for decay of\n" << *external[0] << "\n" << hepeup << Exception::runerror; } } } } void FxFxReader::createBeams() { if ( !theBeams.first && dynamic_ptr_cast::tcp>(inPDF.first) ) { theBeams.first = theIncoming.first; } else if ( !theBeams.first ) { theBeams.first = getParticleData(heprup.IDBMUP.first)->produceParticle(); double m = theBeams.first->mass()/GeV; theBeams.first->set5Momentum (Lorentz5Momentum(ZERO, ZERO, sqrt(sqr(heprup.EBMUP.first) - sqr(m))*GeV, heprup.EBMUP.first*GeV, m*GeV)); hepeup.IDUP.push_back(heprup.IDBMUP.first); hepeup.ISTUP.push_back(-9); hepeup.MOTHUP.push_back(make_pair(0, 0)); hepeup.ICOLUP.push_back(make_pair(0, 0)); hepeup.VTIMUP.push_back(0.0); hepeup.SPINUP.push_back(0.0); particleIndex(hepeup.IDUP.size(), theBeams.first); hepeup.MOTHUP[particleIndex(theIncoming.first) - 1].first = hepeup.IDUP.size(); } if ( !theBeams.second && dynamic_ptr_cast::tcp>(inPDF.second) ) { theBeams.second = theIncoming.second; } else if ( !theBeams.second ) { theBeams.second = getParticleData(heprup.IDBMUP.second)->produceParticle(); double m = theBeams.second->mass()/GeV; theBeams.second->set5Momentum (Lorentz5Momentum(ZERO, ZERO, -sqrt(sqr(heprup.EBMUP.second) - sqr(m))*GeV, heprup.EBMUP.second*GeV, m*GeV)); hepeup.IDUP.push_back(heprup.IDBMUP.second); hepeup.ISTUP.push_back(-9); hepeup.MOTHUP.push_back(make_pair(0, 0)); hepeup.ICOLUP.push_back(make_pair(0, 0)); hepeup.VTIMUP.push_back(0.0); hepeup.SPINUP.push_back(0.0); particleIndex(hepeup.IDUP.size(), theBeams.second); hepeup.MOTHUP[particleIndex(theIncoming.second) - 1].first = hepeup.IDUP.size(); } } void FxFxReader::connectMothers() { const ObjectIndexer & pi = particleIndex; for ( int i = 0, N = hepeup.IDUP.size(); i < N; ++i ) { if ( pi(hepeup.MOTHUP[i].first) ) pi(hepeup.MOTHUP[i].first)->addChild(pi(i + 1)); if ( pi(hepeup.MOTHUP[i].second) && hepeup.MOTHUP[i].second != hepeup.MOTHUP[i].first ) pi(hepeup.MOTHUP[i].second)->addChild(pi(i + 1)); } } void FxFxReader::openReadCacheFile() { if ( cacheFile() ) closeCacheFile(); cacheFile().open(cacheFileName(), "r"); position = 0; } void FxFxReader::openWriteCacheFile() { if ( cacheFile() ) closeCacheFile(); cacheFile().open(cacheFileName(), "w"); } void FxFxReader::closeCacheFile() { cacheFile().close(); } void FxFxReader::cacheEvent() const { static vector buff; cacheFile().write(&hepeup.NUP, sizeof(hepeup.NUP)); buff.resize(eventSize(hepeup.NUP)); char * pos = &buff[0]; pos = mwrite(pos, hepeup.IDPRUP); pos = mwrite(pos, hepeup.XWGTUP); pos = mwrite(pos, hepeup.XPDWUP); pos = mwrite(pos, hepeup.SCALUP); pos = mwrite(pos, hepeup.AQEDUP); pos = mwrite(pos, hepeup.AQCDUP); pos = mwrite(pos, hepeup.IDUP[0], hepeup.NUP); pos = mwrite(pos, hepeup.ISTUP[0], hepeup.NUP); pos = mwrite(pos, hepeup.MOTHUP[0], hepeup.NUP); pos = mwrite(pos, hepeup.ICOLUP[0], hepeup.NUP); for ( int i = 0; i < hepeup.NUP; ++i ) pos = mwrite(pos, hepeup.PUP[i][0], 5); pos = mwrite(pos, hepeup.VTIMUP[0], hepeup.NUP); pos = mwrite(pos, hepeup.SPINUP[0], hepeup.NUP); pos = mwrite(pos, lastweight); pos = mwrite(pos, optionalWeights); pos = mwrite(pos, LHEeventnum); for(size_t ff = 0; ff < optionalWeightsNames.size(); ff++) { pos = mwrite(pos, optionalWeightsNames[ff]); } /* for(int f = 0; f < optionalWeightsNames.size(); f++) { cout << "optionalWeightsNames = " << optionalWeightsNames[f] << endl; }*/ pos = mwrite(pos, optionalnpLO); pos = mwrite(pos, optionalnpNLO); pos = mwrite(pos, preweight); cacheFile().write(&buff[0], buff.size(), 1); } bool FxFxReader::uncacheEvent() { reset(); static vector buff; if ( cacheFile().read(&hepeup.NUP, sizeof(hepeup.NUP)) != 1 ) return false; buff.resize(eventSize(hepeup.NUP)); if ( cacheFile().read(&buff[0], buff.size()) != 1 ) return false; const char * pos = &buff[0]; pos = mread(pos, hepeup.IDPRUP); pos = mread(pos, hepeup.XWGTUP); pos = mread(pos, hepeup.XPDWUP); pos = mread(pos, hepeup.SCALUP); pos = mread(pos, hepeup.AQEDUP); pos = mread(pos, hepeup.AQCDUP); hepeup.IDUP.resize(hepeup.NUP); pos = mread(pos, hepeup.IDUP[0], hepeup.NUP); hepeup.ISTUP.resize(hepeup.NUP); pos = mread(pos, hepeup.ISTUP[0], hepeup.NUP); hepeup.MOTHUP.resize(hepeup.NUP); pos = mread(pos, hepeup.MOTHUP[0], hepeup.NUP); hepeup.ICOLUP.resize(hepeup.NUP); pos = mread(pos, hepeup.ICOLUP[0], hepeup.NUP); hepeup.PUP.resize(hepeup.NUP); for ( int i = 0; i < hepeup.NUP; ++i ) pos = mread(pos, hepeup.PUP[i][0], 5); hepeup.VTIMUP.resize(hepeup.NUP); pos = mread(pos, hepeup.VTIMUP[0], hepeup.NUP); hepeup.SPINUP.resize(hepeup.NUP); pos = mread(pos, hepeup.SPINUP[0], hepeup.NUP); pos = mread(pos, lastweight); pos = mread(pos, optionalWeights); for(size_t ff = 0; ff < optionalWeightsNames.size(); ff++) { pos = mread(pos, optionalWeightsNames[ff]); } pos = mread(pos, optionalnpLO); pos = mread(pos, optionalnpNLO); pos = mread(pos, preweight); pos = mread(pos, LHEeventnum); // If we are skipping, we do not have to do anything else. if ( skipping ) return true; if ( CKKWHandler() && maxMultCKKW() > 0 && maxMultCKKW() > minMultCKKW() ) { // The cached event has not been submitted to CKKW reweighting, so // we do that now. fillEvent(); getSubProcess(); CKKWHandler()->setXComb(lastXCombPtr()); lastweight *= CKKWHandler()->reweightCKKW(minMultCKKW(), maxMultCKKW()); } return true; } void FxFxReader::persistentOutput(PersistentOStream & os) const { os << heprup.IDBMUP << heprup.EBMUP << heprup.PDFGUP << heprup.PDFSUP << heprup.IDWTUP << heprup.NPRUP << heprup.XSECUP << heprup.XERRUP << heprup.XMAXUP << heprup.LPRUP << hepeup.NUP << hepeup.IDPRUP << hepeup.XWGTUP << hepeup.XPDWUP << hepeup.SCALUP << hepeup.AQEDUP << hepeup.AQCDUP << hepeup.IDUP << hepeup.ISTUP << hepeup.MOTHUP << hepeup.ICOLUP << hepeup.PUP << hepeup.VTIMUP << hepeup.SPINUP << inData << inPDF << outPDF << thePartonExtractor << theCKKW << thePartonBins << theXCombs << theCuts << theNEvents << position << reopened << theMaxScan << isActive << theCacheFileName << doCutEarly << stats << statmap << thePartonBinInstances << theBeams << theIncoming << theOutgoing << theIntermediates << reweights << preweights << preweight << reweightPDF << doInitPDFs << theLastXComb << theMaxMultCKKW << theMinMultCKKW << lastweight << optionalWeights << optionalnpLO << optionalnpNLO << LHEeventnum << maxFactor << ounit(weightScale, picobarn) << xSecWeights << maxWeights << theMomentumTreatment << useWeightWarnings << theReOpenAllowed << theIncludeSpin; } void FxFxReader::persistentInput(PersistentIStream & is, int) { if ( cacheFile() ) closeCacheFile(); is >> heprup.IDBMUP >> heprup.EBMUP >> heprup.PDFGUP >> heprup.PDFSUP >> heprup.IDWTUP >> heprup.NPRUP >> heprup.XSECUP >> heprup.XERRUP >> heprup.XMAXUP >> heprup.LPRUP >> hepeup.NUP >> hepeup.IDPRUP >> hepeup.XWGTUP >> hepeup.XPDWUP >> hepeup.SCALUP >> hepeup.AQEDUP >> hepeup.AQCDUP >> hepeup.IDUP >> hepeup.ISTUP >> hepeup.MOTHUP >> hepeup.ICOLUP >> hepeup.PUP >> hepeup.VTIMUP >> hepeup.SPINUP >> inData >> inPDF >> outPDF >> thePartonExtractor >> theCKKW >> thePartonBins >> theXCombs >> theCuts >> theNEvents >> position >> reopened >> theMaxScan >> isActive >> theCacheFileName >> doCutEarly >> stats >> statmap >> thePartonBinInstances >> theBeams >> theIncoming >> theOutgoing >> theIntermediates >> reweights >> preweights >> preweight >> reweightPDF >> doInitPDFs >> theLastXComb >> theMaxMultCKKW >> theMinMultCKKW >> lastweight >> optionalWeights >> optionalnpLO >> optionalnpNLO >> LHEeventnum >> maxFactor >> iunit(weightScale, picobarn) >> xSecWeights >> maxWeights >> theMomentumTreatment >> useWeightWarnings >> theReOpenAllowed >> theIncludeSpin; } AbstractClassDescription FxFxReader::initFxFxReader; // Definition of the static class description member. void FxFxReader::setBeamA(long id) { heprup.IDBMUP.first = id; } long FxFxReader::getBeamA() const { return heprup.IDBMUP.first; } void FxFxReader::setBeamB(long id) { heprup.IDBMUP.second = id; } long FxFxReader::getBeamB() const { return heprup.IDBMUP.second; } void FxFxReader::setEBeamA(Energy e) { heprup.EBMUP.first = e/GeV; } Energy FxFxReader::getEBeamA() const { return heprup.EBMUP.first*GeV; } void FxFxReader::setEBeamB(Energy e) { heprup.EBMUP.second = e/GeV; } Energy FxFxReader::getEBeamB() const { return heprup.EBMUP.second*GeV; } void FxFxReader::setPDFA(PDFPtr pdf) { inPDF.first = pdf; } PDFPtr FxFxReader::getPDFA() const { return inPDF.first; } void FxFxReader::setPDFB(PDFPtr pdf) { inPDF.second = pdf; } PDFPtr FxFxReader::getPDFB() const { return inPDF.second; } void FxFxReader::Init() { static ClassDocumentation documentation ("ThePEG::FxFxReader is an abstract base class to be used " "for objects which reads event files or streams from matrix element " "generators."); static Parameter interfaceBeamA ("BeamA", "The PDG id of the incoming particle along the positive z-axis. " "If zero the corresponding information is to be deduced from the " "event stream/file.", 0, 0, 0, 0, true, false, false, &FxFxReader::setBeamA, &FxFxReader::getBeamA, 0, 0, 0); static Parameter interfaceBeamB ("BeamB", "The PDG id of the incoming particle along the negative z-axis. " "If zero the corresponding information is to be deduced from the " "event stream/file.", 0, 0, 0, 0, true, false, false, &FxFxReader::setBeamB, &FxFxReader::getBeamB, 0, 0, 0); static Parameter interfaceEBeamA ("EBeamA", "The energy of the incoming particle along the positive z-axis. " "If zero the corresponding information is to be deduced from the " "event stream/file.", 0, GeV, ZERO, ZERO, 1000000000.0*GeV, true, false, true, &FxFxReader::setEBeamA, &FxFxReader::getEBeamA, 0, 0, 0); static Parameter interfaceEBeamB ("EBeamB", "The energy of the incoming particle along the negative z-axis. " "If zero the corresponding information is to be deduced from the " "event stream/file.", 0, GeV, ZERO, ZERO, 1000000000.0*GeV, true, false, true, &FxFxReader::setEBeamB, &FxFxReader::getEBeamB, 0, 0, 0); static Reference interfacePDFA ("PDFA", "The PDF used for incoming particle along the positive z-axis. " "If null the corresponding information is to be deduced from the " "event stream/file.", 0, true, false, true, true, false, &FxFxReader::setPDFA, &FxFxReader::getPDFA, 0); static Reference interfacePDFB ("PDFB", "The PDF used for incoming particle along the negative z-axis. " "If null the corresponding information is to be deduced from the " "event stream/file.", 0, true, false, true, true, false, &FxFxReader::setPDFB, &FxFxReader::getPDFB, 0); static Parameter interfaceMaxScan ("MaxScan", "The maximum number of events to scan to obtain information about " "processes and cross section in the intialization.", &FxFxReader::theMaxScan, -1, 0, 0, true, false, false); static Parameter interfaceCacheFileName ("CacheFileName", "Name of file used to cache the events form the reader in a fast-readable " "form. If empty, no cache file will be generated.", &FxFxReader::theCacheFileName, "", true, false); interfaceCacheFileName.fileType(); static Switch interfaceCutEarly ("CutEarly", "Determines whether to apply cuts to events before converting to " "ThePEG format.", &FxFxReader::doCutEarly, true, true, false); static SwitchOption interfaceCutEarlyYes (interfaceCutEarly, "Yes", "Event are cut before converted.", true); static SwitchOption interfaceCutEarlyNo (interfaceCutEarly, "No", "Events are not cut before converted.", false); static Reference interfacePartonExtractor ("PartonExtractor", "The PartonExtractor object used to construct remnants. If no object is " "provided the FxFxEventHandler object must provide one instead.", &FxFxReader::thePartonExtractor, true, false, true, true, false); static Reference interfaceCuts ("Cuts", "The Cuts object to be used for this reader. Note that these " "must not be looser cuts than those used in the actual generation. " "If no object is provided the FxFxEventHandler object must " "provide one instead.", &FxFxReader::theCuts, true, false, true, true, false); static RefVector interfaceReweights ("Reweights", "A list of ThePEG::ReweightBase objects to modify this the weight of " "this reader.", &FxFxReader::reweights, 0, false, false, true, false); static RefVector interfacePreweights ("Preweights", "A list of ThePEG::ReweightBase objects to bias the phase space for this " "reader without influencing the actual cross section.", &FxFxReader::preweights, 0, false, false, true, false); static Switch interfaceReweightPDF ("ReweightPDF", "If the PDFs used in the generation for this reader is different " "from the ones assumed by the associated PartonExtractor object, " "should the events be reweighted to fit the latter?", &FxFxReader::reweightPDF, false, true, false); static SwitchOption interfaceReweightPDFNo (interfaceReweightPDF, "No", "The event weights are kept as they are.", false); static SwitchOption interfaceReweightPDFYes (interfaceReweightPDF, "Yes", "The events are reweighted.", true); static Switch interfaceInitPDFs ("InitPDFs", "If no PDFs were specified in PDFA or " "PDFBfor this reader, try to extract the " "information from the event file and assign the relevant PDFBase" "objects when the reader is initialized.", &FxFxReader::doInitPDFs, false, true, false); static SwitchOption interfaceInitPDFsYes (interfaceInitPDFs, "Yes", "Extract PDFs during initialization.", true); static SwitchOption interfaceInitPDFsNo (interfaceInitPDFs, "No", "Do not extract PDFs during initialization.", false); static Parameter interfaceMaxMultCKKW ("MaxMultCKKW", "If this reader is to be used (possibly together with others) for CKKW-" "reweighting and veto, this should give the multiplicity of outgoing " "particles in the highest multiplicity matrix element in the group. " "If set to zero, no CKKW procedure should be applied.", &FxFxReader::theMaxMultCKKW, 0, 0, 0, true, false, Interface::lowerlim); static Parameter interfaceMinMultCKKW ("MinMultCKKW", "If this reader is to be used (possibly together with others) for CKKW-" "reweighting and veto, this should give the multiplicity of outgoing " "particles in the lowest multiplicity matrix element in the group. If " "larger or equal to MaxMultCKKW, no CKKW " "procedure should be applied.", &FxFxReader::theMinMultCKKW, 0, 0, 0, true, false, Interface::lowerlim); static Switch interfaceMomentumTreatment ("MomentumTreatment", "Treatment of the momenta supplied by the interface", &FxFxReader::theMomentumTreatment, 0, false, false); static SwitchOption interfaceMomentumTreatmentAccept (interfaceMomentumTreatment, "Accept", "Just accept the momenta given", 0); static SwitchOption interfaceMomentumTreatmentRescaleEnergy (interfaceMomentumTreatment, "RescaleEnergy", "Rescale the energy supplied so it is consistent with the mass", 1); static SwitchOption interfaceMomentumTreatmentRescaleMass (interfaceMomentumTreatment, "RescaleMass", "Rescale the mass supplied so it is consistent with the" " energy and momentum", 2); static Switch interfaceWeightWarnings ("WeightWarnings", "Determines if warnings about possible weight incompatibilities should " "be issued when this reader is initialized.", &FxFxReader::useWeightWarnings, true, true, false); static SwitchOption interfaceWeightWarningsWarnAboutWeights (interfaceWeightWarnings, "WarnAboutWeights", "Warn about possible incompatibilities with the weight option in the " "Les Houches common block and the requested weight treatment.", true); static SwitchOption interfaceWeightWarningsDontWarnAboutWeights (interfaceWeightWarnings, "DontWarnAboutWeights", "Do not warn about possible incompatibilities with the weight option " "in the Les Houches common block and the requested weight treatment.", false); static Switch interfaceAllowedTopReOpen ("AllowedToReOpen", "Can the file be reopened if more events are requested than the file contains?", &FxFxReader::theReOpenAllowed, true, false, false); static SwitchOption interfaceAllowedTopReOpenYes (interfaceAllowedTopReOpen, "Yes", "Allowed to reopen the file", true); static SwitchOption interfaceAllowedTopReOpenNo (interfaceAllowedTopReOpen, "No", "Not allowed to reopen the file", false); static Switch interfaceIncludeSpin ("IncludeSpin", "Use the spin information present in the event file, for tau leptons" " only as this is the only case which makes any sense", &FxFxReader::theIncludeSpin, true, false, false); static SwitchOption interfaceIncludeSpinYes (interfaceIncludeSpin, "Yes", "Use the spin information", true); static SwitchOption interfaceIncludeSpinNo (interfaceIncludeSpin, "No", "Don't use the spin information", false); interfaceCuts.rank(8); interfacePartonExtractor.rank(7); interfaceBeamA.rank(5); interfaceBeamB.rank(4); interfaceEBeamA.rank(3); interfaceEBeamB.rank(2); interfaceMaxMultCKKW.rank(1.5); interfaceMinMultCKKW.rank(1.0); interfaceBeamA.setHasDefault(false); interfaceBeamB.setHasDefault(false); interfaceEBeamA.setHasDefault(false); interfaceEBeamB.setHasDefault(false); interfaceMaxMultCKKW.setHasDefault(false); interfaceMinMultCKKW.setHasDefault(false); } namespace ThePEG { ostream & operator<<(ostream & os, const HEPEUP & h) { os << "\n" << " " << setw(4) << h.NUP << " " << setw(6) << h.IDPRUP << " " << setw(14) << h.XWGTUP << " " << setw(14) << h.SCALUP << " " << setw(14) << h.AQEDUP << " " << setw(14) << h.AQCDUP << "\n"; for ( int i = 0; i < h.NUP; ++i ) os << " " << setw(8) << h.IDUP[i] << " " << setw(2) << h.ISTUP[i] << " " << setw(4) << h.MOTHUP[i].first << " " << setw(4) << h.MOTHUP[i].second << " " << setw(4) << h.ICOLUP[i].first << " " << setw(4) << h.ICOLUP[i].second << " " << setw(14) << h.PUP[i][0] << " " << setw(14) << h.PUP[i][1] << " " << setw(14) << h.PUP[i][2] << " " << setw(14) << h.PUP[i][3] << " " << setw(14) << h.PUP[i][4] << " " << setw(1) << h.VTIMUP[i] << " " << setw(1) << h.SPINUP[i] << std::endl; os << "" << std::endl; return os; } } diff --git a/MatrixElement/Gamma/MEGammaGamma2PiPi.cc b/MatrixElement/Gamma/MEGammaGamma2PiPi.cc --- a/MatrixElement/Gamma/MEGammaGamma2PiPi.cc +++ b/MatrixElement/Gamma/MEGammaGamma2PiPi.cc @@ -1,176 +1,174 @@ // -*- C++ -*- // // This is the implementation of the non-inlined, non-templated member // functions of the MEGammaGamma2PiPi class. // #include "MEGammaGamma2PiPi.h" #include "ThePEG/Interface/ClassDocumentation.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/PDT/EnumParticles.h" #include "ThePEG/MatrixElement/Tree2toNDiagram.h" #include "ThePEG/StandardModel/StandardModelBase.h" #include "Herwig/MatrixElement/HardVertex.h" using namespace Herwig; using ThePEG::Helicity::incoming; MEGammaGamma2PiPi::MEGammaGamma2PiPi() { massOption(vector(2,1)); } void MEGammaGamma2PiPi::getDiagrams() const { tcPDPtr gamma = getParticleData(ParticleID::gamma); tcPDPtr pip = getParticleData(ParticleID::piplus); tcPDPtr pim = pip->CC(); // first t-channel add(new_ptr((Tree2toNDiagram(3),gamma,pip,gamma,1,pip, 2,pim,-1))); // interchange add(new_ptr((Tree2toNDiagram(3),gamma,pip,gamma,2,pip, 1,pim,-2))); } Energy2 MEGammaGamma2PiPi::scale() const { return 2.*sHat()*tHat()*uHat()/(sqr(sHat())+sqr(tHat())+sqr(uHat())); } double MEGammaGamma2PiPi::me2() const { VectorWaveFunction p1w(rescaledMomenta()[0],mePartonData()[0],incoming); VectorWaveFunction p2w(rescaledMomenta()[1],mePartonData()[1],incoming); vector p1,p2; for(unsigned int ix=0;ix<2;++ix) { p1w.reset(2*ix);p1.push_back(p1w); p2w.reset(2*ix);p2.push_back(p2w); } // calculate the matrix element return helicityME(p1,p2,rescaledMomenta(),false); } unsigned int MEGammaGamma2PiPi::orderInAlphaS() const { return 0; } unsigned int MEGammaGamma2PiPi::orderInAlphaEW() const { return 2; } Selector MEGammaGamma2PiPi::diagrams(const DiagramVector & diags) const { Selector sel; for ( DiagramIndex i = 0; i < diags.size(); ++i ) if ( diags[i]->id() == -1 ) sel.insert(meInfo()[0], i); else if ( diags[i]->id() == -2 ) sel.insert(meInfo()[1], i); return sel; } Selector MEGammaGamma2PiPi::colourGeometries(tcDiagPtr ) const { static ColourLines c1(""); Selector sel; sel.insert(1.0, &c1); return sel; } IBPtr MEGammaGamma2PiPi::clone() const { return new_ptr(*this); } IBPtr MEGammaGamma2PiPi::fullclone() const { return new_ptr(*this); } // The following static variable is needed for the type // description system in ThePEG. DescribeNoPIOClass describeHerwigMEGammaGamma2PiPi("Herwig::MEGammaGamma2PiPi", "HwMEGammaGamma.so"); void MEGammaGamma2PiPi::Init() { static ClassDocumentation documentation ("The MEGammaGamma2PiPi class provides a simple matrix element for gamma gamma -> pi+pi-"); } void MEGammaGamma2PiPi::constructVertex(tSubProPtr sub) { // extract the particles in the hard process ParticleVector hard; hard.push_back(sub->incoming().first); hard.push_back(sub->incoming().second); hard.push_back(sub->outgoing()[0]); hard.push_back(sub->outgoing()[1]); // order of particles unsigned int order[4]={0,1,2,3}; // identify the process and calculate matrix element vector p1,p2; if(hard[order[2]]->id()<0) swap(order[2],order[3]); VectorWaveFunction (p1 ,hard[order[0]],incoming,false,true); VectorWaveFunction (p2 ,hard[order[1]],incoming,false,true); p1[1]=p1[2]; p2[1]=p2[2]; vector momenta; for(unsigned int ix=0;ix<4;++ix) momenta.push_back(hard[order[ix]]->momentum()); helicityME(p1,p2,momenta,true); // construct the vertex HardVertexPtr hardvertex=new_ptr(HardVertex()); // set the matrix element for the vertex hardvertex->ME(me_); // set the pointers and to and from the vertex for(unsigned int ix=0;ix<4;++ix) { if(hard[order[ix]]->spinInfo()) hard[order[ix]]->spinInfo()->productionVertex(hardvertex); } } double MEGammaGamma2PiPi::helicityME(vector &p1, vector &p2, const vector & momenta, bool calc) const { // for(unsigned int ix=0;ix<4;++ix) // cerr << mePartonData()[ix]->PDGName() <<" " << meMomenta()[ix]/GeV << " " << meMomenta()[ix].mass()/GeV << "\n"; // double beta = meMomenta()[2].vect().mag()/meMomenta()[2].t(); // double ct = meMomenta()[2].cosTheta(); // double phi = meMomenta()[2].phi(); - // scale (external photons so scale in couplings is 0) - Energy2 mt(0.*GeV2); // matrix element to be stored if(calc) me_.reset(ProductionMatrixElement(PDT::Spin1,PDT::Spin1, PDT::Spin0,PDT::Spin0)); // calculate the matrix element double output(0.),sumdiag[2]={0.,0.}; Complex diag[2]; Energy2 d1 = momenta[0]*momenta[2], d2 = momenta[1]*momenta[2]; for(unsigned int ihel1=0;ihel1<2;++ihel1) { complex a1 = momenta[2]*p1[ihel1].wave(); complex a2 = momenta[3]*p1[ihel1].wave(); for(unsigned int ihel2=0;ihel2<2;++ihel2) { complex b1 = momenta[2]*p2[ihel2].wave(); complex b2 = momenta[3]*p2[ihel2].wave(); // t-channel diagram diag[0] = a1*b2/d1; // u-channel diagram diag[1] = a2*b1/d2; sumdiag[0] += norm(diag[0]); sumdiag[1] += norm(diag[1]); Complex amp = p1[ihel1].wave()*p2[ihel2].wave()-diag[0]-diag[1]; output += norm(amp); // store the me if needed if(calc) me_(2*ihel1,2*ihel2,0,0) = amp; } } // diagrams DVector save; save.push_back(sumdiag[0]); save.push_back(sumdiag[1]); meInfo(save); // code to test vs the analytic result // Energy2 m2 = sqr(momenta[2].mass()); // double test = 2. + ((d1 + d2)*m2*(-2*d1*d2 + (d1 + d2)*m2))/(sqr(d1)*sqr(d2)); // cerr << "testing ME " << (output-test)/(output+test) << " " << output << " " << test << " " << output/test << "\n"; // coupling factors return output*sqr(SM().alphaEM()*4.*Constants::pi); } diff --git a/MatrixElement/Matchbox/External/GoSam/GoSamAmplitude.cc b/MatrixElement/Matchbox/External/GoSam/GoSamAmplitude.cc --- a/MatrixElement/Matchbox/External/GoSam/GoSamAmplitude.cc +++ b/MatrixElement/Matchbox/External/GoSam/GoSamAmplitude.cc @@ -1,1067 +1,1067 @@ // -*- C++ -*- // // GoSamAmplitude.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2019 The Herwig Collaboration // // Herwig is licenced under version 3 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // // // This is the implementation of the non-inlined, non-templated member // functions of the GoSamAmplitude class. // #include "GoSamAmplitude.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/EventRecord/Particle.h" #include "ThePEG/Repository/UseRandom.h" #include "ThePEG/Repository/EventGenerator.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Interface/Reference.h" #include "ThePEG/Interface/RefVector.h" #include "ThePEG/Interface/Parameter.h" #include "ThePEG/Interface/Switch.h" #include "ThePEG/Interface/Command.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/Utilities/StringUtils.h" #include "Herwig/MatrixElement/Matchbox/MatchboxFactory.h" #include "Herwig/API/Filesystem.h" #include #include #include #include #include namespace bfs = Herwig::filesystem; using namespace Herwig; #ifndef HERWIG_BINDIR #error Makefile.am needs to define HERWIG_BINDIR #endif #ifndef HERWIG_PKGDATADIR #error Makefile.am needs to define HERWIG_PKGDATADIR #endif #ifndef GOSAM_PREFIX #error Makefile.am needs to define GOSAM_PREFIX #endif //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// GoSamAmplitude::GoSamAmplitude() : theAccuracyTarget(6),theCodeExists(false),theFormOpt(true),theNinja(true), theHiggsEff(false),theMassiveLeptons(false),theLoopInducedOption(0), isitDR(false),doneGoSamInit(false),doneGoSamInitRun(false), bindir_(HERWIG_BINDIR), pkgdatadir_(HERWIG_PKGDATADIR), GoSamPrefix_(GOSAM_PREFIX) {} IBPtr GoSamAmplitude::clone() const { return new_ptr(*this); } IBPtr GoSamAmplitude::fullclone() const { return new_ptr(*this); } //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// void GoSamAmplitude::doinit() { optionalContractFile() = name() + ".OLPContract.lh"; MatchboxOLPME::doinit(); doneGoSamInit = true; } void GoSamAmplitude::doinitrun() { optionalContractFile() = name() + ".OLPContract.lh"; MatchboxOLPME::doinitrun(); doneGoSamInitRun = true; } //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// extern "C" void OLP_Start(const char*, int* i); extern "C" void OLP_Polvec(double*, double*, double*); extern "C" void OLP_SetParameter(char*, double*, double*, int*); extern "C" void OLP_PrintParameter(char*); extern "C" void OLP_EvalSubProcess2(int*, double*, double*, double*, double*); //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// bool GoSamAmplitude::startOLP(const map, int>& procs) { char char_cwd[256]; getcwd(char_cwd, sizeof(char_cwd)); string cwd = string(char_cwd); string folderMatchboxBuild = factory()->buildStorage(); folderMatchboxBuild.erase(folderMatchboxBuild.begin()); // set all necessary path and file names gosamPath = gosamPathInterface == "" ? cwd + folderMatchboxBuild + "GoSam" : gosamPathInterface; // When transitioning to C++ 11 this length()-1 workaround can be replaced by string.back() if (gosamPath.at(gosamPath.length()-1) != '/') gosamPath.append("/"); gosamSourcePath = gosamPath + "source/"; gosamInstallPath = gosamPath + "build/"; // create all the directories if (!bfs::is_directory(gosamPath)){ try { bfs::create_directory(gosamPath); } catch (exception& e) { throw Exception() << "--------------------------------------------------------------------------------\n" << "The following exception occured:\n\n" << " " << e.what() << "\n\n" << " -> Please create the parent directory of\n" << " " << gosamPath << "\n" << " manually!\n" << "--------------------------------------------------------------------------------\n" << Exception::runerror; } } if (!bfs::is_directory(gosamSourcePath)) bfs::create_directory(gosamSourcePath); if (!bfs::is_directory(gosamInstallPath)) bfs::create_directory(gosamInstallPath); contractFileTitle = name() + ".OLPContract.lh"; contractFileName = gosamPath + "/" + contractFileTitle; string orderFileName = gosamPath + "/" + name() + ".OLPOrder.lh"; // Set the path variable (plus file name) where to find the GoSam specific input file gosamSetupInFileName = gosamSetupInFileNameInterface == "" ? gosamPath + "/setup.gosam.in" : gosamSetupInFileNameInterface; // Use the python script gosam2herwig to make replacements in the GoSam // specific input file at gosamSetupInFileName. If the GoSam input file // does not exist yet at gosamSetupInFileName the python script will get // it from src/defaults/ before making the replacements. string cmd = "python "+bindir_+"/gosam2herwig "; cmd+=" --usrinfile="+gosamSetupInFileNameInterface; cmd+=" --infile="+gosamSetupInFileName+".tbu"; cmd+=" --definfile="+pkgdatadir_+"/defaults/setup.gosam.in"; cmd+=" --formtempdir="+StringUtils::replace(gosamSourcePath, string("/"), string("\\/")); //@FORMTEMPDIR@ cmd+=" --reduction="+(theNinja ? string("ninja,golem95") : string("samurai,golem95")); //@REDUCTIONPROGRAMS@ cmd+=" --formopt="+(theFormOpt ? string("") : string(", noformopt")); //@FORMOPT@ cmd+=" --higgseff="+(theHiggsEff ? string("smehc") : string("smdiag")); //@MODEL@ std::system(cmd.c_str()); if ( factory()->initVerbose() ) { generator()->log() << "\n\n>>> NOTE: According to the repository settings for the GoSam interface:\n" << flush; if (theHiggsEff) generator()->log() << "\n -- GoSam will use a model with an effective ggH coupling (model=smehc).\n" << flush; else if (!theHiggsEff) generator()->log() << "\n -- GoSam will use its default model (model=smdiag).\n" << flush; if (theNinja) generator()->log() << " -- GoSam will use Ninja as reduction program (reduction_programs=ninja,golem95).\n" << flush; else if (!theNinja) generator()->log() << " -- GoSam will use Samurai as reduction program (reduction_programs=samurai,golem95).\n" << flush; if (theFormOpt) generator()->log() << " -- Form optimization switched on (extensions=autotools).\n" << flush; else if (!theFormOpt) generator()->log() << " -- Form optimization switched off (extensions=autotools, noformopt).\n" << flush; if (theNinja && !theFormOpt) throw Exception() << "GoSamAmplitude: Ninja reduction needs form optimization!\n" << Exception::runerror; if (gosamSetupInFileNameInterface == "") { generator()->log() << "\n Please be aware that you are using a copy of the default GoSam input file!\n" << " Please note that if you need special options to be considered for the specific\n" << " process you are looking at (diagram filtering, etc.) these are not automatically\n" << " set for you. In that case please consider to specify your own GoSam input file\n" << " via 'set " << name() << ":SetupInFilename' in the input file.\n\n" << flush; } // If one uses a custom GoSam input file at gosamSetupInFileName = gosamSetupInFileNameInterface // then please note that not all options in there might match the corresponding Herwig repository // options if (gosamSetupInFileNameInterface != "") { generator()->log() << "\n Please be aware that you are using a custom GoSam input file!\n" << " Please note that if you have set the options for model, reduction_programs,\n" << " extensions and/or form.tempdir manually these will of course not be replaced\n" << " by the corresponding repository settings mentioned above.\n\n" << flush; } generator()->log() << "\n>>> NOTE: GoSam may return the set of used parameters for this process via the OLP_PrintParameter() function:\n\n" << " -- If Debug::level > 1, the OLP parameters are being written to file: at " << factory()->runStorage() + name() + ".OLPParameters.lh.\n\n" << flush; } double accuracyTarget = 1.0/pow(10.0,accuracyTargetNegExp()); time_t rawtime; time (&rawtime); accuracyFileTitle = name() + ".OLPAccuracy.lh"; accuracyFile = factory()->buildStorage() + accuracyFileTitle; ofstream accuracyFileStream; if ( Debug::level > 1 ) { accuracyFileStream.open(accuracyFile.c_str()); // Opening accuracyFile once here removes all previous content before the read step accuracyFileStream << "\nFile to contain those PSPs for which GoSam evaluated one-loop interference terms or loop induced ME2s\n" << "with acc > target accuracy = " << accuracyTarget << ". Date/Time: " << ctime(&rawtime) << endl; } if ( factory()->initVerbose() ) { generator()->log() << "\n>>> NOTE: GoSam will return the accuracy of one-loop interference terms or loop induced ME2s\n" << " at every PSP via the BLHA2 acc parameter:\n\n" << " -- In cases where acc > 10^-AccuracyTarget = " << accuracyTarget << " the corresponding PSPs are being dis-\n" << " carded.\n" << " -- The default value for AccuracyTarget is 6, but you may consider setting it otherwise\n" << " via 'set " << name() << ":AccuracyTarget' in the input file.\n" << " -- Currently the value for AccuracyTarget is set to " << accuracyTargetNegExp() << ".\n" << " -- If Debug::level > 1, the discarded PSPs are being written to file: at " + accuracyFile << ".\n" << " -- If the amount of PSPs with acc > " << accuracyTarget << " is significant, please consider to re-evaluate\n" << " your process setup (accuracy target, masses, cuts, etc.)!\n\n\n" << flush; } // check for old order file and create it if it doesn't already exist fillOrderFile(procs, orderFileName); ifstream ifile(contractFileName.c_str()); if(!ifile){ signOLP(orderFileName, contractFileName); } if ( !checkOLPContract(contractFileName) ) { throw Exception() << "GoSamAmplitude: failed to start GoSam" << Exception::runerror; } if (!( DynamicLoader::load(gosamInstallPath+"/lib/libgolem_olp.so") || DynamicLoader::load(gosamInstallPath+"/lib64/libgolem_olp.so") || DynamicLoader::load(gosamInstallPath+"/lib/libgolem_olp.dylib") || DynamicLoader::load(gosamInstallPath+"/lib64/libgolem_olp.dylib"))) buildGoSam(); int status = -1; startOLP(contractFileTitle, status); if ( status != 1 ) return false; return true; } void GoSamAmplitude::startOLP(const string& contract, int& status) { string tempcontract = contract; char char_cwd[256]; getcwd(char_cwd, sizeof(char_cwd)); string cwd = string(char_cwd); string folderMatchboxBuild = factory()->buildStorage(); folderMatchboxBuild.erase(folderMatchboxBuild.begin()); gosamPath = gosamPathInterface == "" ? cwd + folderMatchboxBuild + "GoSam" : gosamPathInterface; // When transitioning to C++ 11 this length()-1 workaround can be replaced by string.back() if (gosamPath.at(gosamPath.length()-1) != '/') gosamPath.append("/"); if (!( DynamicLoader::load(gosamPath+"build/lib/libgolem_olp.so") || DynamicLoader::load(gosamPath+"build/lib64/libgolem_olp.so") || DynamicLoader::load(gosamPath+"build/lib/libgolem_olp.dylib") || DynamicLoader::load(gosamPath+"build/lib64/libgolem_olp.dylib"))) throw Exception() << "GoSamAmplitude: Failed to load GoSam. Please check the log file.\n" << Exception::runerror; tempcontract = gosamPath + tempcontract; OLP_Start(tempcontract.c_str(), &status); // hand over input parameters for EW scheme considered int pStatus = 0; double zero = 0.0; if ( SM().ewScheme() == 0 || SM().ewScheme() == 6 ) { // EW/Scheme Default and EW/Scheme Independent throw Exception() << "GoSamAmplitude: `Best value' schemes are not supported by GoSam" << Exception::runerror; } else if ( SM().ewScheme() == 4 ) { // EW/Scheme mW (uses mW,GF,sin2thetaW) seems not to be supported by GoSam throw Exception() << "GoSamAmplitude: `mW' scheme is not supported by GoSam" << Exception::runerror; } else if ( SM().ewScheme() == 1 ) { // EW/Scheme GMuScheme (uses mW,mZ,GF) double in1=getParticleData(ParticleID::Z0)->hardProcessMass()/GeV; double in2=getParticleData(ParticleID::Wplus)->hardProcessMass()/GeV; double in3=SM().fermiConstant()*GeV2; OLP_SetParameter((char *)"mass(23)",&in1,&zero,&pStatus); OLP_SetParameter((char *)"mass(24)",&in2,&zero,&pStatus); OLP_SetParameter((char *)"Gf",&in3,&zero,&pStatus); } else if ( SM().ewScheme() == 2 ) { // EW/Scheme alphaMZScheme (uses mW,mZ,alpha(mZ)) double in1=getParticleData(ParticleID::Z0)->hardProcessMass()/GeV; double in2=getParticleData(ParticleID::Wplus)->hardProcessMass()/GeV; double in3=SM().alphaEMMZ(); OLP_SetParameter((char *)"mass(23)",&in1,&zero,&pStatus); OLP_SetParameter((char *)"mass(24)",&in2,&zero,&pStatus); OLP_SetParameter((char *)"alpha",&in3,&zero,&pStatus); } else if ( SM().ewScheme() == 3 ) { // EW/Scheme NoMass (uses alpha(mZ),GF,sin2thetaW) double in1=SM().fermiConstant()*GeV2; double in2=SM().alphaEMMZ(); double in3=SM().sin2ThetaW(); OLP_SetParameter((char *)"Gf",&in1,&zero,&pStatus); OLP_SetParameter((char *)"alpha",&in2,&zero,&pStatus); OLP_SetParameter((char *)"sw2",&in3,&zero,&pStatus); } else if ( SM().ewScheme() == 5 ) { // EW/Scheme mZ (uses mZ,alphaEM,sin2thetaW) double in1=getParticleData(ParticleID::Z0)->hardProcessMass()/GeV; double in2=SM().alphaEMMZ(); double in3=SM().sin2ThetaW(); OLP_SetParameter((char *)"mass(23)",&in1,&zero,&pStatus); OLP_SetParameter((char *)"alpha",&in2,&zero,&pStatus); OLP_SetParameter((char *)"sw2",&in3,&zero,&pStatus); } else if ( SM().ewScheme() == 7 ) { // EW/Scheme FeynRulesUFO (uses mZ,GF,alpha(mZ)) double in1=getParticleData(ParticleID::Z0)->hardProcessMass()/GeV; double in2=SM().alphaEMMZ(); double in3=SM().fermiConstant()*GeV2; OLP_SetParameter((char *)"mass(23)",&in1,&zero,&pStatus); OLP_SetParameter((char *)"alpha",&in2,&zero,&pStatus); OLP_SetParameter((char *)"Gf",&in3,&zero,&pStatus); } // hand over widths of Z and W double wZ = getParticleData(23)->hardProcessWidth()/GeV; double wW = getParticleData(24)->hardProcessWidth()/GeV; OLP_SetParameter((char*)"width(23)",&wZ,&zero,&pStatus); OLP_SetParameter((char*)"width(24)",&wW,&zero,&pStatus); // hand over mass and width of the Higgs double wH = getParticleData(25)->hardProcessWidth()/GeV; double mH = getParticleData(25)->hardProcessMass()/GeV; OLP_SetParameter((char*)"width(25)",&wH,&zero,&pStatus); OLP_SetParameter((char*)"mass(25)",&mH,&zero,&pStatus); // hand over initial input parameter for alphaS double as = SM().alphaS(); OLP_SetParameter((char *)"alphaS", &as, &zero, &pStatus); // fill massive Particle vector if (massiveParticles.empty()) { // with quark masses for (int i=1; i<=6; ++i) if (getParticleData(i)->hardProcessMass()/GeV > 0.0) massiveParticles.push_back(i); // with lepton masses - if (theMassiveLeptons && getParticleData(11)->hardProcessMass()/GeV > 0.0) massiveParticles.push_back(11); - if (theMassiveLeptons && getParticleData(13)->hardProcessMass()/GeV > 0.0) massiveParticles.push_back(13); - if (theMassiveLeptons && getParticleData(15)->hardProcessMass()/GeV > 0.0) massiveParticles.push_back(15); + if (theMassiveLeptons && getParticleData(11)->hardProcessMass()/GeV > 0.0) massiveParticles.push_back(11); + if (theMassiveLeptons && getParticleData(13)->hardProcessMass()/GeV > 0.0) massiveParticles.push_back(13); + if (theMassiveLeptons && getParticleData(15)->hardProcessMass()/GeV > 0.0) massiveParticles.push_back(15); } // hand over quark (and possibly lepton) masses and widths (iff massive) if ( massiveParticles.size() != 0 ) { for ( vector::const_iterator mID = massiveParticles.begin(); mID != massiveParticles.end(); ++mID ) { string mstr; string wstr; int mInt = *mID; double mass=getParticleData(mInt)->hardProcessMass()/GeV; double width=getParticleData(mInt)->hardProcessWidth()/GeV; std::stringstream ss; ss << mInt; string str = ss.str(); mstr="mass("+str+")"; wstr="width("+str+")"; char * mchar = new char[mstr.size()+1]; char * wchar = new char[wstr.size()+1]; std::copy(mstr.begin(),mstr.end(),mchar); std::copy(wstr.begin(),wstr.end(),wchar); mchar[mstr.size()] = '\0'; wchar[wstr.size()] = '\0'; OLP_SetParameter( mchar, &mass, &zero, &pStatus ); OLP_SetParameter( wchar, &width, &zero, &pStatus ); delete[] mchar; delete[] wchar; // Nicer but not working properly: // double mass=getParticleData(*mID)->hardProcessMass()/GeV; // double width=getParticleData(*mID)->hardProcessWidth()/GeV; // string mstr="mass("+static_cast(&(ostringstream()<<(*mID)))->str()+")"; // string wstr="width("+static_cast(&(ostringstream()<<(*mID)))->str()+")"; // cout<<"\n massiv "< 1 ) { string ppstr = factory()->runStorage() + name() + ".OLPParameters.lh"; OLP_PrintParameter(const_cast(ppstr.c_str())); } didStartOLP() = true; } //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// void GoSamAmplitude::fillOrderFile(const map, int>& procs, string orderFileName) { for ( map, int>::const_iterator p = procs.begin() ; p != procs.end() ; ++p ) { std::stringstream Processstr; std::stringstream Typestr; Processstr << (*p).first.first.legs[0]->id() << " " << (*p).first.first.legs[1]->id() << " -> "; for ( PDVector::const_iterator o = (*p).first.first.legs.begin() + 2 ; o != (*p).first.first.legs.end() ; ++o ) Processstr << (**o).id() << " "; if ( (*p).first.second == ProcessType::treeME2 ) { Typestr << "Tree"; } else if ( (*p).first.second == ProcessType::loopInducedME2 ) { Typestr << "LoopInduced"; } else if ( (*p).first.second == ProcessType::colourCorrelatedME2 ) { Typestr << "ccTree"; } else if ( (*p).first.second == ProcessType::spinColourCorrelatedME2 ) { Typestr << "scTree"; } else if ( (*p).first.second == ProcessType::oneLoopInterference ) { Typestr << "Loop"; } gosamprocinfo pro = gosamprocinfo((*p).second, -1, Processstr.str(), Typestr.str()); pro.setOAs(p->first.first.orderInAlphaS); pro.setOAew(p->first.first.orderInAlphaEW); processmap[(*p).second] = pro; } ifstream oldOrderFileStream(orderFileName.c_str()); if (oldOrderFileStream){ oldOrderFileStream.close(); return; } ofstream orderFile(orderFileName.c_str()); int asPower = 100; int minlegs = 100; int maxlegs = -1; int maxasPower = -1; int aewPower = 100; int maxaewPower = -1; for ( map, int>::const_iterator t = procs.begin() ; t != procs.end() ; ++t ) { asPower = min(asPower, static_cast(t->first.first.orderInAlphaS)); minlegs = min(minlegs, static_cast(t->first.first.legs.size())); maxlegs = max(maxlegs, static_cast(t->first.first.legs.size())); maxasPower = max(maxasPower, static_cast(t->first.first.orderInAlphaS)); aewPower = min(aewPower, static_cast(t->first.first.orderInAlphaEW)); maxaewPower = max(maxaewPower, static_cast(t->first.first.orderInAlphaEW)); } orderFile << "# OLP order file created by Herwig/Matchbox for GoSam\n\n"; orderFile << "InterfaceVersion BLHA2\n"; orderFile << "MatrixElementSquareType CHsummed\n"; orderFile << "CorrectionType QCD\n"; orderFile << "IRregularisation " << (isDR() ? "DRED" : "CDR") << "\n"; // loop over quarks to check if they have non-zero masses for (int i=1; i<=6; ++i) if (getParticleData(i)->hardProcessMass()/GeV > 0.0) massiveParticles.push_back(i); // check if leptons have non-zero masses (iff theMassiveLeptons==true) if (theMassiveLeptons && getParticleData(11)->hardProcessMass()/GeV > 0.0) massiveParticles.push_back(11); if (theMassiveLeptons && getParticleData(13)->hardProcessMass()/GeV > 0.0) massiveParticles.push_back(13); if (theMassiveLeptons && getParticleData(15)->hardProcessMass()/GeV > 0.0) massiveParticles.push_back(15); if ( massiveParticles.size() != 0 ) { orderFile << "MassiveParticles "; for ( vector::const_iterator mID = massiveParticles.begin(); mID != massiveParticles.end(); ++mID ) { int mInt = *mID; orderFile << mInt << " "; } orderFile << "\n"; } orderFile << "\n"; vector < string > types; types.push_back("Tree"); types.push_back("LoopInduced"); types.push_back("ccTree"); types.push_back("scTree"); types.push_back("Loop"); for ( int i = asPower ; i != maxasPower + 1 ; i++ ) { for ( int j = aewPower ; j != maxaewPower + 1 ; j++ ) { orderFile << "\nAlphasPower " << i << "\n"; orderFile << "AlphaPower " << j << "\n"; for ( vector::iterator it = types.begin() ; it != types.end() ; it++ ) { if ( *it == "LoopInduced" ) continue; for ( map::iterator p = processmap.begin() ; p != processmap.end() ; ++p ) if ( (*p).second.Tstr() == *it && i == (*p).second.orderAs() && j == (*p).second.orderAew() ) { orderFile << "\nAmplitudeType " << *it << "\n"; break; } for ( map::iterator p = processmap.begin() ; p != processmap.end() ; ++p ) if ( (*p).second.Tstr() == *it && i == (*p).second.orderAs() && j == (*p).second.orderAew() ) { orderFile << (*p).second.Pstr() << "\n"; } } } } // Write out the loop induced processes separately int asPowerLI = 100; int aewPowerLI = 100; for ( map::iterator p = processmap.begin() ; p != processmap.end() ; ++p ) { if ( (*p).second.Tstr() != "LoopInduced" ) continue; if ( (*p).second.orderAs() != asPowerLI || (*p).second.orderAew() != aewPowerLI ) { asPowerLI = (*p).second.orderAs(); aewPowerLI = (*p).second.orderAew(); // At the moment GoSam requires for qcd loop induced processes the as coupling power // which would correspond to an associated fictitious Born process orderFile << "\nAlphasPower " << (asPowerLI-2) << "\n"; orderFile << "AlphaPower " << aewPowerLI << "\n"; orderFile << "\nAmplitudeType " << "LoopInduced" << "\n"; } orderFile << (*p).second.Pstr() << "\n"; } orderFile << flush; } void GoSamAmplitude::signOLP(const string& order, const string& contract) { if(!theCodeExists){ char char_cwd[256]; getcwd(char_cwd, sizeof(char_cwd)); string cwd = string(char_cwd); string folderMatchboxBuild = factory()->buildStorage(); folderMatchboxBuild.erase(folderMatchboxBuild.begin()); generator()->log() << "\n>>> generating GoSam amplitudes. This may take some time, please be patient.\n" << ">>> see " + cwd + folderMatchboxBuild + "gosam-amplitudes.log for details.\n" << flush; string cmd = GoSamPrefix_+"/bin/gosam.py --olp --output-file=" + contract + " --config=" + gosamSetupInFileName+".tbu" + " --destination=" + gosamSourcePath + " " + order + " > " + cwd + folderMatchboxBuild + "gosam-amplitudes.log 2>&1"; std::system(cmd.c_str()); cmd = "python "+bindir_+"/gosam2herwig "; cmd += " --makelink "; // cmd += " --makelinkfrom=contract "; cmd += " --makelinkfrom="+gosamPath+"/"+name()+".OLPContract.lh"; cmd += " --makelinkto="+factory()->buildStorage() + name() + ".OLPContract.lh"; std::system(cmd.c_str()); } } bool GoSamAmplitude::checkOLPContract(string contractFileName) { ifstream infile(contractFileName.c_str()); string line; vector < string > contractfile; while (std::getline(infile, line)) contractfile.push_back(line); for ( map::iterator p = processmap.begin() ; p != processmap.end() ; p++ ) { bool righttype = false; for ( vector::iterator linex = contractfile.begin() ; linex != contractfile.end() ; ++linex ) { if ( (*linex).find("AmplitudeType ")!= std::string::npos ) { if ( (*linex).find(" " + (*p).second.Tstr() + " ")!= std::string::npos ) { righttype = true; } else { righttype = false; } } if ( righttype ) { if ( (*linex).find((*p).second.Pstr()) != std::string::npos && (*p).second.Pstr().length() == (*linex).find("|") ) { string sub = (*linex).substr((*linex).find("|") + 1, (*linex).find("#") - (*linex).find("|") - 1); // | 1 23 # buggy?? if ( sub.find(" 1 ") != 0 ) throw Exception() << "GoSamAmplitude: Failed to check contractfile. Please check the logfile.\n" << Exception::runerror; string subx = sub.substr(3); int subint; istringstream(subx) >> subint; (*p).second.setGID(subint); } } } } string ids = factory()->buildStorage() + "GoSam.ids.dat"; ofstream IDS(ids.c_str()); idpair.clear(); for ( map::iterator p = processmap.begin() ; p != processmap.end() ; p++ ) idpair.push_back(-1); idpair.push_back(-1); for ( map::iterator p = processmap.begin() ; p != processmap.end() ; p++ ) { idpair[(*p).second.HID()]=(*p).second.GID(); IDS << (*p).second.HID() << " " << (*p).second.GID() << " " << (*p).second.Tstr() << "\n"; if ( (*p).second.GID() == -1 ) return 0; } IDS << flush; return 1; } bool GoSamAmplitude::buildGoSam() { if(!theCodeExists){ generator()->log() << "\n>>> compiling GoSam amplitudes. This may take some time, please be patient.\n" << ">>> see " + gosamSourcePath + "gosam-build.log for details.\n\n" << flush; string cmd = "cd " + gosamSourcePath + " && sh autogen.sh FCFLAGS=-g --prefix=" + gosamInstallPath + " --disable-static > gosam-build.log 2>&1"; std::system(cmd.c_str()); if (!gosamBuildScript.empty()) { cmd = "cd " + gosamSourcePath + " && " + gosamBuildScript + " >> gosam-build.log 2>&1"; std::system(cmd.c_str()); } std::system(cmd.c_str()); cmd = "cd " + gosamSourcePath + " && make install >> gosam-build.log 2>&1"; std::system(cmd.c_str()); } theCodeExists=true; return 1; } void GoSamAmplitude::getids() const { string line = factory()->buildStorage() + "GoSam.ids.dat"; ifstream infile(line.c_str()); int hid; int gid; string type; while (std::getline(infile, line)) { idpair.push_back(-1); idtypepair.push_back(" "); } infile.close(); string line2 = factory()->buildStorage() + "GoSam.ids.dat"; ifstream infile2(line2.c_str()); idpair.push_back(-1); idtypepair.push_back(" "); while (std::getline(infile2, line2)) { istringstream(line2) >> hid >> gid >> type; idpair[hid]=gid; idtypepair[hid]=type; } infile.close(); } //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// void GoSamAmplitude::evalSubProcess() const { useMe(); double units = pow(lastSHat() / GeV2, int(mePartonData().size()) - 4.); fillOLPMomenta(lastXComb().meMomenta(),mePartonData(),reshuffleMasses()); double scale = sqrt(mu2() / GeV2); if (hasRunningAlphaS()) { int pStatus = 0; double zero = 0.0; double as; as = lastAlphaS(); OLP_SetParameter((char *)"alphaS", &as, &zero, &pStatus); } double out[7] = { }; double acc; if ( idpair.size() == 0 ){ getids(); } int id = -99; if ( olpId()[ProcessType::loopInducedME2] ) id = olpId()[ProcessType::loopInducedME2]; else if ( olpId()[ProcessType::oneLoopInterference] ) id = olpId()[ProcessType::oneLoopInterference]; else id = olpId()[ProcessType::treeME2]; int callid(idpair[id]); // If id denotes the Herwig ID, this returns the GoSam ID string calltype(idtypepair[id]); // If id denotes the Herwig ID, this returns the amplitude type OLP_EvalSubProcess2(&(callid), olpMomenta(), &scale, out, &acc); double accuracyTarget = 1.0/pow(10.0,accuracyTargetNegExp()); accuracyFileTitle = name() + ".OLPAccuracy.lh"; accuracyFile = factory()->buildStorage() + accuracyFileTitle; ofstream accuracyFileStream; if ( (olpId()[ProcessType::oneLoopInterference]||olpId()[ProcessType::loopInducedME2]) && acc > accuracyTarget ) { if ( Debug::level > 1 ) { accuracyFileStream.open(accuracyFile.c_str(),ios::app); vector currentpsp = lastXComb().meMomenta(); time_t rawtime; time (&rawtime); if (doneGoSamInit) accuracyFileStream << "READ phase: "; else if (doneGoSamInitRun) accuracyFileStream << "RUN phase: "; accuracyFileStream << "Sub-process with Herwig ID = " << id << " and GoSam ID = " << callid << ", " << ctime(&rawtime); accuracyFileStream << "GoSam evaluated one-loop interference or loop induced ME2 with acc = " << acc << " > target accuracy = " << accuracyTarget << ", at PSP [in units of GeV]:" << endl; for (size_t i=0; i!=currentpsp.size(); ++i) { accuracyFileStream << "(t,x,y,z,mass;m)[" << i << "]=(" << currentpsp[i].t()/GeV << "," << currentpsp[i].x()/GeV << "," << currentpsp[i].y()/GeV << "," << currentpsp[i].z()/GeV << "," << currentpsp[i].mass()/GeV << ";" << currentpsp[i].m()/GeV << ")" << endl; } accuracyFileStream << endl; } throw Veto(); // Dispose of PSP } if ( olpId()[ProcessType::oneLoopInterference] ) { if (calculateTreeME2()) lastTreeME2(out[3] * units); lastOneLoopInterference((out[2])* units); lastOneLoopPoles(pair(out[0] * units, out[1] * units)); } else if ( olpId()[ProcessType::treeME2] ) { lastTreeME2(out[3] * units); } else if ( olpId()[ProcessType::loopInducedME2] ) { lastTreeME2(out[2] * units); } } void GoSamAmplitude::evalColourCorrelator(pair ) const { double units = pow(lastSHat() / GeV2, int(mePartonData().size()) - 4.); fillOLPMomenta(lastXComb().meMomenta(),mePartonData(),reshuffleMasses()); double scale = sqrt(mu2() / GeV2); if (hasRunningAlphaS()) { int pStatus = 0; double zero = 0.0; double as; as = lastAlphaS(); OLP_SetParameter((char *)"alphaS", &as, &zero, &pStatus); } int n = lastXComb().meMomenta().size(); colourCorrelatorResults.resize(n * (n - 1) / 2); if ( idpair.size() == 0 ) getids(); int callid(idpair[olpId()[ProcessType::colourCorrelatedME2]]); double acc; OLP_EvalSubProcess2(&(callid), olpMomenta(), &scale, &colourCorrelatorResults[0], &acc); cPDVector particles = lastXComb().matrixElement()->mePartonData(); for ( int i = 0 ; i < n ; ++i ) { for ( int j = i + 1 ; j < n ; ++j ) { lastColourCorrelator(make_pair(i, j), colourCorrelatorResults[i+j*(j-1)/2] * units); } } } void GoSamAmplitude::evalSpinColourCorrelator(pair ) const { double units = pow(lastSHat() / GeV2, int(mePartonData().size()) - 4.); fillOLPMomenta(lastXComb().meMomenta(),mePartonData(),reshuffleMasses()); double scale = sqrt(mu2() / GeV2); if (hasRunningAlphaS()) { int pStatus = 0; double zero = 0.0; double as; as = lastAlphaS(); OLP_SetParameter((char *)"alphaS", &as, &zero, &pStatus); } int n = lastXComb().meMomenta().size(); spinColourCorrelatorResults.resize(2*n*n); if ( idpair.size() == 0 ) getids(); double acc; int callid(idpair[olpId()[ProcessType::spinColourCorrelatedME2]]); OLP_EvalSubProcess2(&(callid), olpMomenta(), &scale, &spinColourCorrelatorResults[0], &acc); for ( int i = 0; i < n; ++i ) { for ( int j = 0; j < n; ++j ) { Complex scc(spinColourCorrelatorResults[2*i+2*n*j]*units, spinColourCorrelatorResults[2*i+2*n*j+1]*units); lastColourSpinCorrelator(make_pair(i,j),scc); } } } LorentzVector GoSamAmplitude::plusPolarization(const Lorentz5Momentum& p, const Lorentz5Momentum& n, int inc) const { double pvec[4] = {p.t()/GeV,p.x()/GeV,p.y()/GeV,p.z()/GeV}; double nvec[4] = {n.t()/GeV,n.x()/GeV,n.y()/GeV,n.z()/GeV}; double out[8] ={ }; OLP_Polvec(pvec,nvec,out); LorentzVector res; Complex a(out[0],out[1]); res.setT(a); Complex b(out[2],out[3]); res.setX(b); Complex c(out[4],out[5]); res.setY(c); Complex d(out[6],out[7]); res.setZ(d); if (inc<2) return res.conjugate(); else return res; } //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// // If needed, insert default implementations of virtual function defined // in the InterfacedBase class here (using ThePEG-interfaced-impl in Emacs). void GoSamAmplitude::persistentOutput(PersistentOStream & os) const { os << idpair << idtypepair << processmap << gosamPathInterface << gosamSetupInFileNameInterface << gosamBuildScript << gosamPath << gosamSourcePath << gosamInstallPath << gosamSetupInFileName << orderFileTitle << contractFileTitle << contractFileName << orderFileName << theCodeExists << theFormOpt << theNinja << isitDR << massiveParticles << theHiggsEff << theAccuracyTarget << theMassiveLeptons << theLoopInducedOption << doneGoSamInit << doneGoSamInitRun << bindir_ << pkgdatadir_ << GoSamPrefix_; } void GoSamAmplitude::persistentInput(PersistentIStream & is, int) { is >> idpair >> idtypepair >> processmap >> gosamPathInterface >> gosamSetupInFileNameInterface >> gosamBuildScript >> gosamPath >> gosamSourcePath >> gosamInstallPath >> gosamSetupInFileName >> orderFileTitle >> contractFileTitle >> contractFileName >> orderFileName >> theCodeExists >> theFormOpt >> theNinja >> isitDR >> massiveParticles >> theHiggsEff >> theAccuracyTarget >> theMassiveLeptons >> theLoopInducedOption >> doneGoSamInit >> doneGoSamInitRun >> bindir_ >> pkgdatadir_ >> GoSamPrefix_; } // *** 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 describeHerwigGoSamAmplitude("Herwig::GoSamAmplitude", "HwMatchboxGoSam.so"); void GoSamAmplitude::Init() { static ClassDocumentation documentation("GoSamAmplitude implements an interface to GoSam.", "Matrix elements have been calculated using GoSam \\cite{Cullen:2011xs}, \\cite{Cullen:2014yla}", "%\\cite{Cullen:2011xs}\n" "\\bibitem{Cullen:2011xs}\n" "G.~Cullen et al.,\n" "``GoSam: A Program for Automated One-Loop Calculations,''\n" "arXiv:1111.6534 [hep-ph].\n" "%%CITATION = ARXIV:1111.6534;%%\n" "%\\cite{Cullen:2014yla}\n" "\\bibitem{Cullen:2014yla}\n" "G.~Cullen et al.,\n" "``GoSaam-2.0: a tool for automated one-loop calculations within the Standard Model and beyond,''\n" "arXiv:1404.7096 [hep-ph].\n" "%%CITATION = ARXIV:1404.7096;%%"); static Parameter interfaceProcessPath ("ProcessPath", "Prefix for the process source code, include files and library produced by GoSam.", &GoSamAmplitude::gosamPathInterface, "", false, false); static Parameter interfaceSetupInFilename ("SetupInFilename", "File name of the GoSam infile (typically setup.gosam.in) to be used. If left empty a new setup.gosam.in is created in the location specified in Path", &GoSamAmplitude::gosamSetupInFileNameInterface, "", false, false); static Switch interfaceCodeExists ("CodeExists", "Switch on or off if Code already exists/not exists.", &GoSamAmplitude::theCodeExists, true, false, false); static SwitchOption interfaceCodeExistsYes (interfaceCodeExists, "Yes", "Switch True if Code already exists.", true); static SwitchOption interfaceCodeExistsNo (interfaceCodeExists, "No", "Switch False if Code has to be build.", false); static Switch interfaceisitDR ("isDR", "Switch on or off DR.", &GoSamAmplitude::isitDR, false, false, false); static SwitchOption interfaceisitDRYes (interfaceisitDR, "Yes", "Switch True.", true); static SwitchOption interfaceisitDRNo (interfaceisitDR, "No", "Switch False.", false); static Switch interfaceFormOpt ("FormOpt", "Switch On/Off formopt", &GoSamAmplitude::theFormOpt, true, false, false); static SwitchOption interfaceFormOptYes (interfaceFormOpt, "Yes", "Yes", true); static SwitchOption interfaceFormOptNo (interfaceFormOpt, "No", "No", false); static Switch interfaceNinja ("Ninja", "Switch On/Off for reduction with Ninja. If Off then Samurai is used.", &GoSamAmplitude::theNinja, true, false, false); static SwitchOption interfaceNinjaYes (interfaceNinja, "Yes", "Yes", true); static SwitchOption interfaceNinjaNo (interfaceNinja, "No", "No", false); static Switch interfaceHiggsEff ("HiggsEff", "Switch On/Off for effective higgs model.", &GoSamAmplitude::theHiggsEff, false, false, false); static SwitchOption interfaceHiggsEffYes (interfaceHiggsEff, "Yes", "Yes", true); static SwitchOption interfaceHiggsEffNo (interfaceHiggsEff, "No", "No", false); static Parameter interfaceBuildScript ("BuildScript", "File name of a custom build script, which is called between 'autogen.sh'" "and 'make install'. It can be used for parallelization.", &GoSamAmplitude::gosamBuildScript, "", false, false); static Parameter interfaceAccuracyTarget ("AccuracyTarget", "Integer to parametrize the threshold value for the BLHA2 acc parameter, returned by GoSam in the case of " "sub-processes with one-loop intereference terms or loop induced sub-processes." "If acc > 10^-AccuracyTarget the corresponding PSP is being discarded. Discarded PSPs are written to file " "if Debug::level > 1.", &GoSamAmplitude::theAccuracyTarget, 6, 0, 0, false, false, Interface::lowerlim); static Switch interfaceMassiveLeptons ("MassiveLeptons", "If set to Yes, then pass on the light lepton masses - as well as the tau mass - to GoSam." "Otherwise GoSam will use light leptons of zero mass as default, as well as its own default tau mass.", &GoSamAmplitude::theMassiveLeptons, false, false, false); static SwitchOption interfaceMassiveLeptonsNo (interfaceMassiveLeptons, "No", "No", false); static SwitchOption interfaceMassiveLeptonsYes (interfaceMassiveLeptons, "Yes", "Yes", true); static Switch interfaceLoopInducedOption ("LoopInducedOption", "Options for the GoSam interface, in the case that a loop induced process is being considered. The default " "option is 0, for which only the squared one-loop amplitude in the Standard Model is being considered. All " "other options consider additional contributions from a model with an effective interaction, which lead to " "the same final state, such as the squared effective amplitude, or the interference term between the one- " "loop amplitude in the Standard Model and the effective amplitude, or any additive combinations therefrom. " "In order to use those options an appropriate model has to be used.", &GoSamAmplitude::theLoopInducedOption, 0, false, false); static SwitchOption interfaceLoopInducedOptionLI2 (interfaceLoopInducedOption, "LI2", "Only consider the squared one-loop amplitude in the Standard Model.", 0); static SwitchOption interfaceLoopInducedOptionEff2 (interfaceLoopInducedOption, "Eff2", "Only consider the squared effective amplitude.", 1); static SwitchOption interfaceLoopInducedOptionLIEffInterference (interfaceLoopInducedOption, "LIEffInterference", "Only consider the interference term between the one-loop amplitude " "in the Standard Model and the effective amplitude.", 2); static SwitchOption interfaceLoopInducedOptionLI2plusEff2 (interfaceLoopInducedOption, "LI2plusEff2", "Consider the sum of the squared one-loop amplitude in the Standard " "Model plus the squared effective amplitude.", 3); static SwitchOption interfaceLoopInducedOptionLI2plusLIEffInterference (interfaceLoopInducedOption, "LI2plusEffInterference", "Consider the sum of the squared one-loop amplitude in the Standard " "Model plus the interference term between the one-loop amplitude in " "the Standard Model and the effective amplitude.", 4); static SwitchOption interfaceLoopInducedOptionEff2plusLIEffInterference (interfaceLoopInducedOption, "Eff2plusEffInterference", "Consider the sum of the squared effective amplitude plus the inter- " "ference term between the one-loop amplitude in the Standard Model " "and the effective amplitude.", 5); static SwitchOption interfaceLoopInducedOptionAllAdditions (interfaceLoopInducedOption, "AllAdditions", "Consider the sum of the squared one-loop amplitude in the Standard " "Model plus all other contributions, which come with the effective " "Model.", 6); static Parameter interfaceBinDir ("BinDir", "The location for the installed executable", &GoSamAmplitude::bindir_, string(HERWIG_BINDIR), false, false); static Parameter interfacePKGDATADIR ("DataDir", "The location for the installed Herwig data files", &GoSamAmplitude::pkgdatadir_, string(HERWIG_PKGDATADIR), false, false); static Parameter interfaceGoSamPrefix ("GoSamPrefix", "The prefix for the location of GoSam", &GoSamAmplitude::GoSamPrefix_, string(GOSAM_PREFIX), false, false); } diff --git a/Models/General/HardProcessConstructor.cc b/Models/General/HardProcessConstructor.cc --- a/Models/General/HardProcessConstructor.cc +++ b/Models/General/HardProcessConstructor.cc @@ -1,958 +1,958 @@ // -*- C++ -*- // // This is the implementation of the non-inlined, non-templated member // functions of the HardProcessConstructor class. // #include "HardProcessConstructor.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Interface/Switch.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" using namespace Herwig; void HardProcessConstructor::persistentOutput(PersistentOStream & os) const { os << debug_ << subProcess_ << model_; } void HardProcessConstructor::persistentInput(PersistentIStream & is, int) { is >> debug_ >> subProcess_ >> model_; } // The following static variable is needed for the type // description system in ThePEG. DescribeAbstractClass describeHerwigHardProcessConstructor("Herwig::HardProcessConstructor", "Herwig.so"); void HardProcessConstructor::Init() { static ClassDocumentation documentation ("Base class for implementation of the automatic generation of hard processes"); static Switch interfaceDebugME ("DebugME", "Print comparison with analytical ME", &HardProcessConstructor::debug_, false, false, false); static SwitchOption interfaceDebugMEYes (interfaceDebugME, "Yes", "Print the debug information", true); static SwitchOption interfaceDebugMENo (interfaceDebugME, "No", "Do not print the debug information", false); } void HardProcessConstructor::doinit() { Interfaced::doinit(); EGPtr eg = generator(); model_ = dynamic_ptr_cast(eg->standardModel()); if(!model_) throw InitException() << "HardProcessConstructor:: doinit() - " << "The model pointer is null!" << Exception::abortnow; if(!eg->eventHandler()) { throw InitException() << "HardProcessConstructor:: doinit() - " << "The eventHandler pointer was null therefore " << "could not get SubProcessHandler pointer " << Exception::abortnow; } string subProcessName = eg->preinitInterface(eg->eventHandler(), "SubProcessHandlers", "get",""); subProcess_ = eg->getObject(subProcessName); if(!subProcess_) { ostringstream s; s << "HardProcessConstructor:: doinit() - " << "There was an error getting the SubProcessHandler " << "from the current event handler. "; generator()->logWarning( Exception(s.str(), Exception::warning) ); } } GeneralHardME::ColourStructure HardProcessConstructor:: colourFlow(const tcPDVector & extpart) const { PDT::Colour ina = extpart[0]->iColour(); PDT::Colour inb = extpart[1]->iColour(); PDT::Colour outa = extpart[2]->iColour(); PDT::Colour outb = extpart[3]->iColour(); // incoming colour neutral if(ina == PDT::Colour0 && inb == PDT::Colour0) { if( outa == PDT::Colour0 && outb == PDT::Colour0 ) { return GeneralHardME::Colour11to11; } else if( outa == PDT::Colour3 && outb == PDT::Colour3bar ) { return GeneralHardME::Colour11to33bar; } else if( outa == PDT::Colour8 && outb == PDT::Colour8 ) { return GeneralHardME::Colour11to88; } else assert(false); } // incoming 3 3 else if(ina == PDT::Colour3 && inb == PDT::Colour3 ) { if( outa == PDT::Colour3 && outb == PDT::Colour3 ) { return GeneralHardME::Colour33to33; } else if( outa == PDT::Colour6 && outb == PDT::Colour0 ) { return GeneralHardME::Colour33to61; } else if( outa == PDT::Colour0 && outb == PDT::Colour6 ) { return GeneralHardME::Colour33to16; } else if ( outa == PDT::Colour0 && outb == PDT::Colour3bar) { return GeneralHardME::Colour33to13bar; } else if ( outb == PDT::Colour0 && outa == PDT::Colour3bar) { return GeneralHardME::Colour33to3bar1; } else if ( outa == PDT::Colour8 && outb == PDT::Colour3bar) { return GeneralHardME::Colour33to83bar; } else if ( outb == PDT::Colour8 && outa == PDT::Colour3bar) { return GeneralHardME::Colour33to3bar8; } else assert(false); } // incoming 3bar 3bar else if(ina == PDT::Colour3bar && inb == PDT::Colour3bar ) { if( outa == PDT::Colour3bar && outb == PDT::Colour3bar ) { return GeneralHardME::Colour3bar3barto3bar3bar; } else if( outa == PDT::Colour6bar && outb == PDT::Colour0) { return GeneralHardME::Colour3bar3barto6bar1; } else if ( outa == PDT::Colour0 && outb == PDT::Colour6bar ) { return GeneralHardME::Colour3bar3barto16bar; } else if ( outa == PDT::Colour0 && outb == PDT::Colour3) { return GeneralHardME::Colour3bar3barto13; } else if ( outb == PDT::Colour0 && outa == PDT::Colour3) { return GeneralHardME::Colour3bar3barto31; } else if ( outa == PDT::Colour8 && outb == PDT::Colour3) { return GeneralHardME::Colour3bar3barto83; } else if ( outb == PDT::Colour8 && outa == PDT::Colour3) { return GeneralHardME::Colour3bar3barto38; } else assert(false); } // incoming 3 3bar else if(ina == PDT::Colour3 && inb == PDT::Colour3bar ) { if( outa == PDT::Colour0 && outb == PDT::Colour0 ) { return GeneralHardME::Colour33barto11; } else if( outa == PDT::Colour3 && outb == PDT::Colour3bar ) { return GeneralHardME::Colour33barto33bar; } else if( outa == PDT::Colour8 && outb == PDT::Colour8 ) { return GeneralHardME::Colour33barto88; } else if( outa == PDT::Colour8 && outb == PDT::Colour0 ) { return GeneralHardME::Colour33barto81; } else if( outa == PDT::Colour0 && outb == PDT::Colour8 ) { return GeneralHardME::Colour33barto18; } else if( outa == PDT::Colour6 && outb == PDT::Colour6bar) { return GeneralHardME::Colour33barto66bar; } else if( outa == PDT::Colour6bar && outb == PDT::Colour6) { return GeneralHardME::Colour33barto6bar6; } else assert(false); } // incoming 88 else if(ina == PDT::Colour8 && inb == PDT::Colour8 ) { if( outa == PDT::Colour0 && outb == PDT::Colour0 ) { return GeneralHardME::Colour88to11; } else if( outa == PDT::Colour3 && outb == PDT::Colour3bar ) { return GeneralHardME::Colour88to33bar; } else if( outa == PDT::Colour8 && outb == PDT::Colour8 ) { return GeneralHardME::Colour88to88; } else if( outa == PDT::Colour8 && outb == PDT::Colour0 ) { return GeneralHardME::Colour88to81; } else if( outa == PDT::Colour0 && outb == PDT::Colour8 ) { return GeneralHardME::Colour88to18; } else if( outa == PDT::Colour6 && outb == PDT::Colour6bar ) { return GeneralHardME::Colour88to66bar; } else assert(false); } // incoming 38 else if(ina == PDT::Colour3 && inb == PDT::Colour8 ) { if(outa == PDT::Colour3 && outb == PDT::Colour0) { return GeneralHardME::Colour38to31; } else if(outa == PDT::Colour0 && outb == PDT::Colour3) { return GeneralHardME::Colour38to13; } else if(outa == PDT::Colour3 && outb == PDT::Colour8) { return GeneralHardME::Colour38to38; } else if(outa == PDT::Colour8 && outb == PDT::Colour3) { return GeneralHardME::Colour38to83; } else if(outa == PDT::Colour3bar && outb == PDT::Colour6){ return GeneralHardME::Colour38to3bar6; } else if(outa == PDT::Colour6 && outb == PDT::Colour3bar) { return GeneralHardME::Colour38to63bar; } else if(outa == PDT::Colour3bar && outb == PDT::Colour3bar) { return GeneralHardME::Colour38to3bar3bar; } else assert(false); } // incoming 3bar8 else if(ina == PDT::Colour3bar && inb == PDT::Colour8 ) { if(outa == PDT::Colour3bar && outb == PDT::Colour0 ) { return GeneralHardME::Colour3bar8to3bar1; } else if(outa == PDT::Colour0 && outb == PDT::Colour3bar) { return GeneralHardME::Colour3bar8to13bar; } else if(outa == PDT::Colour3bar && outb == PDT::Colour8 ) { return GeneralHardME::Colour3bar8to3bar8; } else if(outa == PDT::Colour8 && outb == PDT::Colour3bar) { return GeneralHardME::Colour3bar8to83bar; } else if(outa == PDT::Colour3 && outb == PDT::Colour3) { return GeneralHardME::Colour3bar8to33; } else assert(false); } // unknown colour flow else assert(false); return GeneralHardME::UNDEFINED; } void HardProcessConstructor::fixFSOrder(HPDiagram & diag) { tcPDPtr psa = getParticleData(diag.incoming.first); tcPDPtr psb = getParticleData(diag.incoming.second); tcPDPtr psc = getParticleData(diag.outgoing.first); tcPDPtr psd = getParticleData(diag.outgoing.second); //fix a spin order if( psc->iSpin() < psd->iSpin() ) { swap(diag.outgoing.first, diag.outgoing.second); if(diag.channelType == HPDiagram::tChannel) { diag.ordered.second = !diag.ordered.second; } return; } if( psc->iSpin() == psd->iSpin() && psc->id() < 0 && psd->id() > 0 ) { swap(diag.outgoing.first, diag.outgoing.second); if(diag.channelType == HPDiagram::tChannel) { diag.ordered.second = !diag.ordered.second; } return; } } void HardProcessConstructor::assignToCF(HPDiagram & diag) { if(diag.channelType == HPDiagram::tChannel) { if(diag.ordered.second) tChannelCF(diag); else uChannelCF(diag); } else if(diag.channelType == HPDiagram::sChannel) { sChannelCF(diag); } else if (diag.channelType == HPDiagram::fourPoint) { fourPointCF(diag); } else assert(false); } void HardProcessConstructor::tChannelCF(HPDiagram & diag) { tcPDPtr ia = getParticleData(diag.incoming.first ); tcPDPtr ib = getParticleData(diag.incoming.second); tcPDPtr oa = getParticleData(diag.outgoing.first ); tcPDPtr ob = getParticleData(diag.outgoing.second); PDT::Colour ina = ia->iColour(); PDT::Colour inb = ib->iColour(); PDT::Colour outa = oa->iColour(); PDT::Colour outb = ob->iColour(); vector cfv(1, make_pair(0, 1.)); if(diag.intermediate->iColour() == PDT::Colour0) { if(ina==PDT::Colour0) { cfv[0] = make_pair(0, 1); } else if(ina==PDT::Colour3 || ina==PDT::Colour3bar) { if( inb == PDT::Colour0 ) { cfv[0] = make_pair(0, 1); } else if(inb==PDT::Colour3 || outb==PDT::Colour3bar) { cfv[0] = make_pair(2, 1); } else if(inb==PDT::Colour8) { cfv[0] = make_pair(2, 1); } } else if(ina==PDT::Colour8) { if( inb == PDT::Colour0 ) { cfv[0] = make_pair(0, 1); } else if(inb==PDT::Colour3 || outb==PDT::Colour3bar) { cfv[0] = make_pair(2, 1); } else if(inb==PDT::Colour8) { cfv[0] = make_pair(7, -1); } } } else if(diag.intermediate->iColour() == PDT::Colour8) { if(ina==PDT::Colour8&&outa==PDT::Colour8&& inb==PDT::Colour8&&outb==PDT::Colour8) { cfv[0]=make_pair(2, 2.); cfv.push_back(make_pair(3, -2.)); cfv.push_back(make_pair(1, -2.)); cfv.push_back(make_pair(4, 2.)); } else if(ina==PDT::Colour8&&outa==PDT::Colour0&& inb==PDT::Colour8&&outb==PDT::Colour8&& (oa->iSpin()==PDT::Spin0||oa->iSpin()==PDT::Spin1Half|| oa->iSpin()==PDT::Spin3Half)) { cfv[0] = make_pair(0,-1); } else if(ina==PDT::Colour8&&outa==PDT::Colour8&& inb==PDT::Colour8&&outb==PDT::Colour0&& (ob->iSpin()==PDT::Spin0||ob->iSpin()==PDT::Spin1Half|| ob->iSpin()==PDT::Spin3Half)) { cfv[0] = make_pair(0,-1); } } else if(diag.intermediate->iColour() == PDT::Colour3 || diag.intermediate->iColour() == PDT::Colour3bar) { if(outa == PDT::Colour0 || outb == PDT::Colour0) { if( outa == PDT::Colour6 || outb == PDT::Colour6 || outa == PDT::Colour6bar || outb == PDT::Colour6bar) { cfv[0] = make_pair(0,0.5); cfv.push_back(make_pair(1,0.5)); } else if ((ina==PDT::Colour3 && inb == PDT::Colour3 && (outa == PDT::Colour3bar || outb == PDT::Colour3bar))|| (ina==PDT::Colour3bar && inb == PDT::Colour3bar && (outa == PDT::Colour3 || outb == PDT::Colour3 ))) { cfv[0] = make_pair(0,1.); } else { cfv[0] = make_pair(0,1.); } } else if(outa==PDT::Colour6 && outb==PDT::Colour3bar) { cfv[0] = make_pair(4,1.); cfv.push_back(make_pair(5,1.)); } else if(outa==PDT::Colour6 && outb==PDT::Colour6bar) { cfv[0] = make_pair(4, 1.); for(unsigned int ix=5;ix<8;++ix) cfv.push_back(make_pair(ix,1.)); } else if(outa==PDT::Colour6 || outa ==PDT::Colour6bar || outb==PDT::Colour6 || outb ==PDT::Colour6bar ) { assert(false); } else if(ina==PDT::Colour3 && inb==PDT::Colour3 ) { if((outa==PDT::Colour0 && outb==PDT::Colour3bar)|| (outb==PDT::Colour0 && outa==PDT::Colour3bar)) cfv[0] = make_pair(0,1.); else if((outa==PDT::Colour8 && outb==PDT::Colour3bar)|| (outb==PDT::Colour8 && outa==PDT::Colour3bar)) { cfv[0] = make_pair(1,1.); } } else if(ina==PDT::Colour3bar && inb==PDT::Colour3bar ) { if((outa==PDT::Colour0 && outb==PDT::Colour3)|| (outb==PDT::Colour0 && outa==PDT::Colour3)) cfv[0] = make_pair(0,1.); else if((outa==PDT::Colour8 && outb==PDT::Colour3)|| (outb==PDT::Colour8 && outa==PDT::Colour3)) { double sign = diag.intermediate->iSpin()==PDT::Spin0 ? -1. : 1.; cfv[0] = make_pair(1,sign); } } else if((ina==PDT::Colour3 && inb==PDT::Colour8) || (ina==PDT::Colour3bar && inb==PDT::Colour8) || (inb==PDT::Colour3 && ina==PDT::Colour8) || (inb==PDT::Colour3bar && ina==PDT::Colour8) ) { if((outa==PDT::Colour3 && outb==PDT::Colour3 ) || (outa==PDT::Colour3bar && outb==PDT::Colour3bar)) { cfv[0] = make_pair(1,1.); } } } else if(diag.intermediate->iColour() == PDT::Colour6 || diag.intermediate->iColour() == PDT::Colour6bar) { if(ina==PDT::Colour8 && inb==PDT::Colour8) { cfv[0] = make_pair(0, 1.); for(unsigned int ix=1;ix<4;++ix) cfv.push_back(make_pair(ix,1.)); for(unsigned int ix=4;ix<8;++ix) cfv.push_back(make_pair(ix,1.)); } else if(outa==PDT::Colour3bar && outb==PDT::Colour6) { cfv[0] = make_pair(0,1.); for(unsigned int ix=1;ix<4;++ix) cfv.push_back(make_pair(ix,1.)); } else if(outa==PDT::Colour6 && outb==PDT::Colour3bar) { cfv[0] = make_pair(4,1.); cfv.push_back(make_pair(5,1.)); } } diag.colourFlow = cfv; } void HardProcessConstructor::uChannelCF(HPDiagram & diag) { tcPDPtr ia = getParticleData(diag.incoming.first ); tcPDPtr ib = getParticleData(diag.incoming.second); tcPDPtr oa = getParticleData(diag.outgoing.first ); tcPDPtr ob = getParticleData(diag.outgoing.second); PDT::Colour ina = ia->iColour(); PDT::Colour inb = ib->iColour(); PDT::Colour outa = oa->iColour(); PDT::Colour outb = ob->iColour(); PDT::Colour offshell = diag.intermediate->iColour(); vector cfv(1, make_pair(1, 1.)); if(offshell == PDT::Colour8) { if(outa == PDT::Colour0 && outb == PDT::Colour0) { cfv[0].first = 0; } else if( outa != outb ) { if(outa == PDT::Colour0 || outb == PDT::Colour0) { cfv[0].first = 0; } else if(ina == PDT::Colour3 && inb == PDT::Colour8 && outb == PDT::Colour3 && outa == PDT::Colour8) { tPDPtr off = diag.intermediate; if(off->CC()) off=off->CC(); if(off->iSpin()!=PDT::Spin1Half || diag.vertices.second->allowed(off->id(),diag.outgoing.first,diag.incoming.second)) { cfv[0].first = 0; cfv.push_back(make_pair(1, -1.)); } else { cfv[0].first = 1; cfv.push_back(make_pair(0, -1.)); } } else if(ina == PDT::Colour3bar && inb == PDT::Colour8 && outb == PDT::Colour3bar && outa == PDT::Colour8) { tPDPtr off = diag.intermediate; if(off->CC()) off=off->CC(); if(off->iSpin()!=PDT::Spin1Half || diag.vertices.second->allowed(diag.outgoing.first,off->id(),diag.incoming.second)) { cfv[0].first = 0; cfv.push_back(make_pair(1, -1.)); } else { cfv[0].first = 1; cfv.push_back(make_pair(0, -1.)); } } else { cfv[0].first = 0; cfv.push_back(make_pair(1, -1.)); } } else if(outa==PDT::Colour8&&ina==PDT::Colour8) { cfv[0]=make_pair(4, 2.); cfv.push_back(make_pair(5, -2.)); cfv.push_back(make_pair(0, -2.)); cfv.push_back(make_pair(2, 2.)); } } else if(offshell == PDT::Colour3 || offshell == PDT::Colour3bar) { if( outa == PDT::Colour0 || outb == PDT::Colour0 ) { if( outa == PDT::Colour6 || outb == PDT::Colour6 || outa == PDT::Colour6bar || outb == PDT::Colour6bar) { cfv[0] = make_pair(0,0.5); cfv.push_back(make_pair(1,0.5)); } else if ((ina==PDT::Colour3 && inb == PDT::Colour3 && (outa == PDT::Colour3bar || outb == PDT::Colour3bar))|| (ina==PDT::Colour3bar && inb == PDT::Colour3bar && (outa == PDT::Colour3 || outb == PDT::Colour3 ))) { double sign = diag.intermediate->iSpin()==PDT::Spin0 ? -1. : 1.; cfv[0] = make_pair(0,sign); } else { cfv[0] = make_pair(0,1.); } } else if(outa==PDT::Colour3bar && outb==PDT::Colour6) { cfv[0] = make_pair(4,1.); cfv.push_back(make_pair(5,1.)); } else if(outa==PDT::Colour6 && outb==PDT::Colour3bar) { cfv[0] = make_pair(0,1.); for(int ix=0; ix<4;++ix) cfv.push_back(make_pair(ix,1.)); } else if(outa==PDT::Colour6bar && outb==PDT::Colour6) { cfv[0] = make_pair(4,1.); for(int ix=5; ix<8;++ix) cfv.push_back(make_pair(ix,1.)); } else if(ina==PDT::Colour0 && inb==PDT::Colour0) { cfv[0] = make_pair(0,1.); } else if(ina==PDT::Colour3 && inb==PDT::Colour3 ) { if((outa==PDT::Colour0 && outb==PDT::Colour3bar)|| (outb==PDT::Colour0 && outa==PDT::Colour3bar)) cfv[0] = make_pair(0,1.); else if((outa==PDT::Colour8 && outb==PDT::Colour3bar)|| (outb==PDT::Colour8 && outa==PDT::Colour3bar)) { double sign = diag.intermediate->iSpin()==PDT::Spin0 ? -1. : 1.; cfv[0] = make_pair(2,sign); } } else if(ina==PDT::Colour3bar && inb==PDT::Colour3bar ) { if((outa==PDT::Colour0 && outb==PDT::Colour3)|| (outb==PDT::Colour0 && outa==PDT::Colour3)) cfv[0] = make_pair(0,1.); else if((outa==PDT::Colour8 && outb==PDT::Colour3)|| (outb==PDT::Colour8 && outa==PDT::Colour3)) { cfv[0] = make_pair(2,1.); } } else if(((ina==PDT::Colour3 && inb==PDT::Colour8) || (ina==PDT::Colour3bar && inb==PDT::Colour8) || (inb==PDT::Colour3 && ina==PDT::Colour8) || (inb==PDT::Colour3bar && ina==PDT::Colour8)) && ((outa==PDT::Colour3 && outb==PDT::Colour3 ) || (outa==PDT::Colour3bar && outb==PDT::Colour3bar))) { cfv[0] = make_pair(2, 1.); } else if(( ina==PDT::Colour3 && inb==PDT::Colour3bar && outa==PDT::Colour3 && outb==PDT::Colour3bar)) { cfv[0] = make_pair(2, 1.); cfv.push_back(make_pair(3,-1.)); } } else if( offshell == PDT::Colour0 ) { if(ina==PDT::Colour0) { cfv[0] = make_pair(0, 1); } else if(ina==PDT::Colour3 || ina==PDT::Colour3bar) { if( inb == PDT::Colour0 ) { cfv[0] = make_pair(0, 1); } else if(inb==PDT::Colour3 || inb==PDT::Colour3bar) { cfv[0] = make_pair(3, 1); } else if(inb==PDT::Colour8) { cfv[0] = make_pair(2, 1); } } else if(ina==PDT::Colour8) { if( inb == PDT::Colour0 ) { cfv[0] = make_pair(0, 1); } else if(inb==PDT::Colour3 || outb==PDT::Colour3bar) { cfv[0] = make_pair(2, 1); } else if(inb==PDT::Colour8) { cfv[0] = make_pair(8, -1); } } } else if(diag.intermediate->iColour() == PDT::Colour6 || diag.intermediate->iColour() == PDT::Colour6bar) { if(ina==PDT::Colour8 && inb==PDT::Colour8) { cfv[0] = make_pair(0, 1.); for(unsigned int ix=1;ix<4;++ix) cfv.push_back(make_pair(ix,1.)); for(unsigned int ix=8;ix<12;++ix) cfv.push_back(make_pair(ix,1.)); } - else if(outa==PDT::Colour3bar && outa==PDT::Colour6) { + else if(outa==PDT::Colour3bar && outb==PDT::Colour6) { cfv[0] = make_pair(4, 1.); cfv.push_back(make_pair(5,1.)); } - else if(outa==PDT::Colour6 && outa==PDT::Colour3bar) { + else if(outa==PDT::Colour6 && outb==PDT::Colour3bar) { cfv[0] = make_pair(0, 1.); for(unsigned int ix=1;ix<4;++ix) cfv.push_back(make_pair(ix,1.)); } } diag.colourFlow = cfv; } void HardProcessConstructor::sChannelCF(HPDiagram & diag) { tcPDPtr pa = getParticleData(diag.incoming.first); tcPDPtr pb = getParticleData(diag.incoming.second); PDT::Colour ina = pa->iColour(); PDT::Colour inb = pb->iColour(); PDT::Colour offshell = diag.intermediate->iColour(); tcPDPtr pc = getParticleData(diag.outgoing.first); tcPDPtr pd = getParticleData(diag.outgoing.second); PDT::Colour outa = pc->iColour(); PDT::Colour outb = pd->iColour(); vector cfv(1); if(offshell == PDT::Colour8) { if(ina == PDT::Colour0 || inb == PDT::Colour0 || outa == PDT::Colour0 || outb == PDT::Colour0) { cfv[0] = make_pair(0, 1); } else { bool incol = ina == PDT::Colour8 && inb == PDT::Colour8; bool outcol = outa == PDT::Colour8 && outb == PDT::Colour8; bool intrip = ina == PDT::Colour3 && inb == PDT::Colour3bar; bool outtrip = outa == PDT::Colour3 && outb == PDT::Colour3bar; bool outsex = outa == PDT::Colour6 && outb == PDT::Colour6bar; bool outsexb = outa == PDT::Colour6bar && outb == PDT::Colour6; if(incol || outcol) { // Require an additional minus sign for a scalar/fermion // 33bar final state due to the way the vertex rules are defined. int prefact(1); if( ((pc->iSpin() == PDT::Spin1Half && pd->iSpin() == PDT::Spin1Half) || (pc->iSpin() == PDT::Spin0 && pd->iSpin() == PDT::Spin0 ) || (pc->iSpin() == PDT::Spin1 && pd->iSpin() == PDT::Spin1 )) && (outa == PDT::Colour3 && outb == PDT::Colour3bar) ) prefact = -1; if(incol && outcol) { cfv[0] = make_pair(0, -2.); cfv.push_back(make_pair(1, 2.)); cfv.push_back(make_pair(3, 2.)); cfv.push_back(make_pair(5, -2.)); } else if(incol && outsex) { cfv[0].first = 4; cfv[0].second = prefact; for(unsigned int ix=1;ix<4;++ix) cfv.push_back(make_pair(4+ix, prefact)); for(unsigned int ix=0;ix<4;++ix) cfv.push_back(make_pair(8+ix,-prefact)); } else { cfv[0].first = 0; cfv[0].second = -prefact; cfv.push_back(make_pair(1, prefact)); } } else if( ( intrip && !outtrip ) || ( !intrip && outtrip ) ) { if(!outsex) cfv[0] = make_pair(0, 1); else { cfv[0] = make_pair(0, 1.); for(unsigned int ix=0;ix<3;++ix) cfv.push_back(make_pair(ix+1, 1.)); } } else if((intrip && outsex) || (intrip && outsexb)) { cfv[0] = make_pair(0,1.); for(int ix=1; ix<4; ++ix) cfv.push_back(make_pair(ix,1.)); } else cfv[0] = make_pair(1, 1); } } else if(offshell == PDT::Colour0) { if( ina == PDT::Colour0 ) { cfv[0] = make_pair(0, 1); } else if(ina==PDT::Colour3 || ina==PDT::Colour3bar) { if( outa == PDT::Colour0 ) { cfv[0] = make_pair(0, 1); } else if(outa==PDT::Colour3 || outa==PDT::Colour3bar) { cfv[0] = make_pair(3, 1); } else if(outa==PDT::Colour8) { cfv[0] = make_pair(2, 1); } else if(outa==PDT::Colour6 || outa==PDT::Colour6bar) { cfv[0] = make_pair(8, 1.); cfv.push_back(make_pair(9,1.)); } else assert(false); } else if(ina==PDT::Colour8) { if( outa == PDT::Colour0 ) { cfv[0] = make_pair(0, 1); } else if(outa==PDT::Colour3 || outb==PDT::Colour3bar) { cfv[0] = make_pair(2, 1); } else if(outa==PDT::Colour8) { cfv[0] = make_pair(6, 1); } } } else if(offshell == PDT::Colour3 || offshell == PDT::Colour3bar) { if(outa == PDT::Colour6 || outa == PDT::Colour6bar || outb == PDT::Colour6bar || outb == PDT::Colour6) { cfv[0] = make_pair(6, 1.); cfv.push_back(make_pair(7,1.)); } else if((ina == PDT::Colour3 && inb == PDT::Colour3) || (ina == PDT::Colour3bar && inb == PDT::Colour3bar)) { if((outa == PDT::Colour3 && outb == PDT::Colour3 ) || (outa == PDT::Colour3bar && outb == PDT::Colour3bar)) { cfv[0] = make_pair(2, 1.); cfv.push_back(make_pair(3,-1.)); } else cfv[0] = make_pair(0,1.); } else if(((ina==PDT::Colour3 && inb==PDT::Colour8) || (ina==PDT::Colour3bar && inb==PDT::Colour8) || (inb==PDT::Colour3 && ina==PDT::Colour8) || (inb==PDT::Colour3bar && ina==PDT::Colour8) ) && ((outa==PDT::Colour3 && outb==PDT::Colour3 ) || (outa==PDT::Colour3bar && outb==PDT::Colour3bar))) { cfv[0] = make_pair(0,1.); } else { if(outa == PDT::Colour0 || outb == PDT::Colour0) cfv[0] = make_pair(0, 1); else cfv[0] = make_pair(1, 1); } } else if( offshell == PDT::Colour6 || offshell == PDT::Colour6bar) { if((ina == PDT::Colour3 && inb == PDT::Colour3 && outa == PDT::Colour3 && outb == PDT::Colour3 ) || (ina == PDT::Colour3bar && inb == PDT::Colour3bar && outa == PDT::Colour3bar && outb == PDT::Colour3bar)) { cfv[0] = make_pair(2,0.5); cfv.push_back(make_pair(3,0.5)); } else if((ina == PDT::Colour3 && inb == PDT::Colour3 && ((outa == PDT::Colour6 && outb == PDT::Colour0)|| (outb == PDT::Colour6 && outa == PDT::Colour0))) || (ina == PDT::Colour3bar && inb == PDT::Colour3bar && ((outa == PDT::Colour6bar && outb == PDT::Colour0)|| (outb == PDT::Colour6bar && outa == PDT::Colour0)))) { cfv[0] = make_pair(0,0.5); cfv.push_back(make_pair(1,0.5)); } else assert(false); } else { if(outa == PDT::Colour0 || outb == PDT::Colour0) cfv[0] = make_pair(0, 1); else cfv[0] = make_pair(1, 1); } diag.colourFlow = cfv; } void HardProcessConstructor::fourPointCF(HPDiagram & diag) { using namespace ThePEG::Helicity; // count the colours unsigned int noct(0),ntri(0),nsng(0),nsex(0),nf(0); vector particles; for(unsigned int ix=0;ix<4;++ix) { particles.push_back(getParticleData(diag.ids[ix])); PDT::Colour col = particles.back()->iColour(); if(col==PDT::Colour0) ++nsng; else if(col==PDT::Colour3||col==PDT::Colour3bar) ++ntri; else if(col==PDT::Colour8) ++noct; else if(col==PDT::Colour6||col==PDT::Colour6bar) ++nsex; if(particles.back()->iSpin()==2) nf+=1; } if(nsng==4 || (ntri==2&&nsng==2) || (noct==3 && nsng==1) || (ntri==2 && noct==1 && nsng==1) || (noct == 2 && nsng == 2) ) { vector cfv(1,make_pair(0,1)); diag.colourFlow = cfv; } else if(noct==4) { // flows for SSVV, VVVV is handled in me class vector cfv(6); cfv[0] = make_pair(0, -2.); cfv[1] = make_pair(1, -2.); cfv[2] = make_pair(2, +4.); cfv[3] = make_pair(3, -2.); cfv[4] = make_pair(4, +4.); cfv[5] = make_pair(5, -2.); diag.colourFlow = cfv; } else if(ntri==2&&noct==2) { vector cfv(2); cfv[0] = make_pair(0, 1); cfv[1] = make_pair(1, 1); if(nf==2) cfv[1].second = -1.; diag.colourFlow = cfv; } else if(nsex==2&&noct==2) { vector cfv; for(unsigned int ix=0;ix<4;++ix) cfv.push_back(make_pair(ix ,2.)); for(unsigned int ix=0;ix<8;++ix) cfv.push_back(make_pair(4+ix,1.)); diag.colourFlow = cfv; } else if(ntri==4) { // get the order from the vertex vector temp; for(unsigned int ix=0;ix<4;++ix) { temp = diag.vertices.first->search(ix,diag.outgoing.first); if(!temp.empty()) break; } // compute the mapping vector ids; ids.push_back( particles[0]->CC() ? -diag.incoming.first : diag.incoming.first ); ids.push_back( particles[1]->CC() ? -diag.incoming.second : diag.incoming.second); ids.push_back( diag.outgoing.first ); ids.push_back( diag.outgoing.second); vector order = {0,1,2,3}; vector matched(4,false); for(unsigned int ix=0;ix 3 3 if((particles[0]->iColour()==PDT::Colour3 && particles[1]->iColour()==PDT::Colour3) || (particles[0]->iColour()==PDT::Colour3bar && particles[1]->iColour()==PDT::Colour3bar) ) { if(diag.vertices.first->colourStructure()==ColourStructure::SU3I12I34) { if( (order[0]==0 && order[1]==2) || (order[2]==0 && order[3]==2) || (order[0]==2 && order[1]==0) || (order[2]==2 && order[3]==0)) diag.colourFlow = vector(1,make_pair(2,1.)); else diag.colourFlow = vector(1,make_pair(3,1.)); } else if(diag.vertices.first->colourStructure()==ColourStructure::SU3I14I23) { if( (order[0]==0 && order[3]==2) || (order[1]==0 && order[2]==2) || (order[0]==2 && order[3]==0) || (order[1]==2 && order[2]==0)) diag.colourFlow = vector(1,make_pair(2,1.)); else diag.colourFlow = vector(1,make_pair(3,1.)); } else if(diag.vertices.first->colourStructure()==ColourStructure::SU3T21T43) { if( (order[1]==0 && order[0]==2) || (order[3]==0 && order[2]==2) || (order[1]==2 && order[0]==0) || (order[3]==2 && order[2]==0)) diag.colourFlow = vector(1,make_pair(0,1.)); else diag.colourFlow = vector(1,make_pair(1,1.)); } else if(diag.vertices.first->colourStructure()==ColourStructure::SU3T23T41) { if( (order[1]==0 && order[2]==2) || (order[3]==0 && order[0]==2) || (order[1]==2 && order[2]==0) || (order[3]==2 && order[0]==0)) diag.colourFlow = vector(1,make_pair(0,1.)); else diag.colourFlow = vector(1,make_pair(1,1.)); } else assert(false); } else if((particles[0]->iColour()==PDT::Colour3 && particles[1]->iColour()==PDT::Colour3bar) | (particles[0]->iColour()==PDT::Colour3bar && particles[1]->iColour()==PDT::Colour3)) { if(diag.vertices.first->colourStructure()==ColourStructure::SU3I12I34) { if( (order[0]==0 && order[1]==1) || (order[2]==0 && order[3]==0) || (order[0]==1 && order[1]==0) || (order[2]==1 && order[3]==1)) diag.colourFlow = vector(1,make_pair(3,1.)); else diag.colourFlow = vector(1,make_pair(2,1.)); } else if(diag.vertices.first->colourStructure()==ColourStructure::SU3I14I23) { if( (order[0]==0 && order[3]==1) || (order[0]==2 && order[3]==3) || (order[0]==1 && order[3]==0) || (order[0]==3 && order[3]==2)) diag.colourFlow = vector(1,make_pair(3,1.)); else diag.colourFlow = vector(1,make_pair(2,1.)); } else if(diag.vertices.first->colourStructure()==ColourStructure::SU3T21T43) { if( (order[1]==0 && order[0]==1) || (order[3]==0 && order[2]==1) || (order[1]==1 && order[0]==0) || (order[3]==1 && order[2]==0)) diag.colourFlow = vector(1,make_pair(1,1.)); else diag.colourFlow = vector(1,make_pair(0,1.)); } else if(diag.vertices.first->colourStructure()==ColourStructure::SU3T23T41) { if( (order[1]==0 && order[2]==1) || (order[1]==1 && order[2]==0) || (order[1]==3 && order[2]==2) || (order[1]==2 && order[2]==3)) diag.colourFlow = vector(1,make_pair(1,1.)); else diag.colourFlow = vector(1,make_pair(2,1.)); } else assert(false); } else { assert(false); } } else { assert(false); } } namespace { // Helper functor for find_if in duplicate function. class SameDiagramAs { public: SameDiagramAs(const HPDiagram & diag) : a(diag) {} bool operator()(const HPDiagram & b) const { return a == b; } private: HPDiagram a; }; } bool HardProcessConstructor::duplicate(const HPDiagram & diag, const HPDVector & group) const { //find if a duplicate diagram exists HPDVector::const_iterator it = find_if(group.begin(), group.end(), SameDiagramAs(diag)); return it != group.end(); } bool HardProcessConstructor::checkOrder(const HPDiagram & diag) const { for(map >::const_iterator it=model_->couplings().begin(); it!=model_->couplings().end();++it) { int order=0; if(diag.vertices.first ) order += diag.vertices.first ->orderInCoupling(it->second.first); if(diag.vertices.second&&diag.vertices.first->getNpoint()==3) order += diag.vertices.second->orderInCoupling(it->second.first); if(order>it->second.second) return false; } return true; } diff --git a/Models/Sextet/SextetFFSVertex.cc b/Models/Sextet/SextetFFSVertex.cc --- a/Models/Sextet/SextetFFSVertex.cc +++ b/Models/Sextet/SextetFFSVertex.cc @@ -1,215 +1,215 @@ // -*- C++ -*- // // This is the implementation of the non-inlined, non-templated member // functions of the SextetFFSVertex class. // #include "SextetFFSVertex.h" #include "SextetModel.h" #include "SextetParticles.h" #include "ThePEG/Interface/ClassDocumentation.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" using namespace Herwig; IBPtr SextetFFSVertex::clone() const { return new_ptr(*this); } IBPtr SextetFFSVertex::fullclone() const { return new_ptr(*this); } void SextetFFSVertex::persistentOutput(PersistentOStream & os) const { os << g1L_ << g1R_ << g1pR_ << g1ppR_ << g3L_; } void SextetFFSVertex::persistentInput(PersistentIStream & is, int) { is >> g1L_ >> g1R_ >> g1pR_ >> g1ppR_ >> g3L_; } // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeSextetFFSVertex("Herwig::SextetFFSVertex", "HwSextetModel.so"); void SextetFFSVertex::Init() { static ClassDocumentation documentation ("The SextetFFSVertex class implements the coupling of two " "fermions to a scalar sextet particle."); } void SextetFFSVertex::doinit() { orderInGs (0); orderInGem(1); SextetModelPtr model = dynamic_ptr_cast(generator()->standardModel()); if(!model) throw Exception() << "Must be using the SextetModel" << " in SextetGSSVertex::doinit()" << Exception::runerror; // extract the couplings g1L_ = model->g1L(); g1R_ = model->g1R(); g1pR_ = model->g1pR(); g1ppR_ = model->g1ppR(); g3L_ = model->g3L(); // add the enabled particles if(model->ScalarSingletY43Enabled()) { for(long ix=0;ix<3;++ix) { long iu = 2*ix + 2; if(g1ppR_[ix]!=0.) { addToList( iu, iu, ParticleID::ScalarDQSingletY43bar); addToList( -iu, -iu, ParticleID::ScalarDQSingletY43); } } } if(model->ScalarSingletY13Enabled()) { for(long ix=0;ix<3;++ix) { long iu = 2*ix + 2; long id = 2*ix + 1; if(g1L_[ix]!=0. || g1R_[ix]!=0.) { addToList( id, iu, ParticleID::ScalarDQSingletY13bar); addToList( -id, -iu, ParticleID::ScalarDQSingletY13); } } } if(model->ScalarSingletY23Enabled()) { for(long ix=0;ix<3;++ix) { long id = 2*ix + 1; if(g1pR_[ix]!=0. ) { addToList( id, id,ParticleID::ScalarDQSingletY23bar); addToList(-id,-id,ParticleID::ScalarDQSingletY23); } } } if(model->ScalarTripletY13Enabled()) { for(long ix=0;ix<3;++ix) { long iu = 2*ix + 2; long id = 2*ix + 1; if(g3L_[ix]!=0. ) { addToList( iu, iu, ParticleID::ScalarDQTripletPbar); addToList( -iu, -iu, ParticleID::ScalarDQTripletP); addToList( iu, id, ParticleID::ScalarDQTriplet0bar); addToList( -iu, -id, ParticleID::ScalarDQTriplet0); addToList( id, id, ParticleID::ScalarDQTripletMbar); addToList( -id, -id, ParticleID::ScalarDQTripletM); } } } Helicity::FFSVertex::doinit(); } void SextetFFSVertex::setCoupling(Energy2,tcPDPtr part1, tcPDPtr part2,tcPDPtr part3) { long q1ID=(abs(part1->id())), q2ID=(abs(part2->id())), sDQID=(abs(part3->id())); //check scalar diquark assert( sDQID == ParticleID::ScalarDQSingletY43 || sDQID == ParticleID::ScalarDQSingletY13 || sDQID == ParticleID::ScalarDQSingletY23 || sDQID == ParticleID::ScalarDQTripletP || sDQID == ParticleID::ScalarDQTriplet0 || sDQID == ParticleID::ScalarDQTripletM); //check quarks assert(!(q1ID>6) && !(q2ID>6)); bool part1Up = (q1ID==2 || q1ID==4 || q1ID==6); #ifndef NDEBUG bool part2Up = (q2ID==2 || q2ID==4 || q2ID==6); #endif Complex cRight, cLeft, prefactor(1.); if(sDQID==ParticleID::ScalarDQSingletY43){ //should both be up type assert(part1Up && part2Up); if(q1ID==2) cRight=Complex(g1ppR_[0]); else if(q1ID==4) cRight=Complex(g1ppR_[1]); else cRight=Complex(g1ppR_[2]); cLeft=Complex(0.); } if(sDQID==ParticleID::ScalarDQSingletY13){ //should be one up one down type assert((part1Up && !part2Up) || (!part1Up && part2Up)); long upType; if(part1Up) upType=q1ID; else upType=q2ID; if(upType==2){ cRight=Complex(g1R_[0]); cLeft=Complex(2.*g1L_[0]); } else if(upType==4){ cRight=Complex(g1R_[1]); cLeft=Complex(2.*g1L_[1]); } - else - cRight=Complex(g1R_[2]);{ + else { + cRight=Complex(g1R_[2]); cLeft=Complex(2.*g1L_[2]); } } if(sDQID==ParticleID::ScalarDQSingletY23){ //should both be down type assert(!part1Up && !part2Up); if(q1ID==1) cRight=Complex(g1pR_[0]); else if(q1ID==3) cRight=Complex(g1pR_[1]); else cRight=Complex(g1pR_[2]); cLeft=Complex(0.); } if(sDQID==ParticleID::ScalarDQTripletP){ //should both be up type assert(part1Up && part2Up); if(q1ID==2) cLeft=Complex(g3L_[0]); else if(q1ID==4) cLeft=Complex(g3L_[1]); else cLeft=Complex(g3L_[2]); cRight=Complex(0.); } if(sDQID==ParticleID::ScalarDQTriplet0){ //should both one up and down type assert((part1Up && !part2Up) || (!part1Up && part2Up)); //possibly doesn't couple long upType; if(part1Up) upType=q1ID; else upType=q2ID; if(upType==2) cLeft=Complex(g3L_[0]); else if(upType==4) cLeft=Complex(g3L_[1]); else cLeft=Complex(g3L_[2]); cRight=Complex(0.); } if(sDQID==ParticleID::ScalarDQTripletM){ //should one both be down type assert(!part1Up && !part2Up); if(q1ID==1) cLeft=Complex(g3L_[0]); else if(q1ID==3) cLeft=Complex(g3L_[1]); else cLeft=Complex(g3L_[2]); cRight=Complex(0.); prefactor=Complex(-1.); } left(cLeft); right(cRight); norm(prefactor); } diff --git a/PDT/HeavyMesonWidthGenerator.cc b/PDT/HeavyMesonWidthGenerator.cc --- a/PDT/HeavyMesonWidthGenerator.cc +++ b/PDT/HeavyMesonWidthGenerator.cc @@ -1,252 +1,252 @@ // -*- C++ -*- // // This is the implementation of the non-inlined, non-templated member // functions of the HeavyMesonWidthGenerator class. // #include "HeavyMesonWidthGenerator.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/Decay/HeavyMeson/HQETStrongDecayer.h" using namespace Herwig; HeavyMesonWidthGenerator::HeavyMesonWidthGenerator() : fPi_(130.2*MeV), g_(0.566), gp_(0.189), h_(0.544), hp_(0.413), k_(0.407), kp_(0.242), gtilde_(0.283), psiL_(0.), psiS_(0.041), Lambda_(1.*GeV), couplingsSet_(false) {} IBPtr HeavyMesonWidthGenerator::clone() const { return new_ptr(*this); } IBPtr HeavyMesonWidthGenerator::fullclone() const { return new_ptr(*this); } void HeavyMesonWidthGenerator::persistentOutput(PersistentOStream & os) const { os << ounit(fPi_,MeV) << g_ << gp_ << h_ << hp_ << k_ << kp_ << gtilde_ << psiL_ << psiS_ << ounit(Lambda_,GeV) << couplingsSet_; } void HeavyMesonWidthGenerator::persistentInput(PersistentIStream & is, int) { is >> iunit(fPi_,MeV) >> g_ >> gp_ >> h_ >> hp_ >> k_ >> kp_ >> gtilde_ >> psiL_ >> psiS_ >> iunit(Lambda_,GeV) >> couplingsSet_; } // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeHerwigHeavyMesonWidthGenerator("Herwig::HeavyMesonWidthGenerator", "HwHMDecay.so"); void HeavyMesonWidthGenerator::Init() { static ClassDocumentation documentation ("The HeavyMesonWidthGenerator class calculates the width for heavy meson decays"); static Parameter interfacefPi ("fPi", "The pion decay constant", &HeavyMesonWidthGenerator::fPi_, MeV, 130.2*MeV, 100.0*MeV, 200.0*MeV, false, false, Interface::limited); static Parameter interfaceg ("g", "The coupling for 1S (0-,1-) decays", &HeavyMesonWidthGenerator::g_, 0.566, 0.0, 1.0, false, false, Interface::limited); static Parameter interfacegp ("gp", "The coupling for 1S (0+,1+) decays", &HeavyMesonWidthGenerator::gp_, 0.189, 0.0, 1.0, false, false, Interface::limited); static Parameter interfaceh ("h", "The coupling for 1P (0+,1+) decays", &HeavyMesonWidthGenerator::h_, 0.544, 0.0, 1.0, false, false, Interface::limited); static Parameter interfacehp ("hp", "The coupling for 1P (1+,2+) decays", &HeavyMesonWidthGenerator::hp_, 0.413, 0.0, 1.0, false, false, Interface::limited); static Parameter interfacek ("k", "The coupling for 1D (2-,3-) decays", &HeavyMesonWidthGenerator::k_, 0.407, 0.0, 1.0, false, false, Interface::limited); static Parameter interfacekp ("kp", "The coupling for 1D (1-,2-) decays", &HeavyMesonWidthGenerator::kp_, 0.242, 0.0, 1.0, false, false, Interface::limited); static Parameter interfacegtilde ("gtilde", "The coupling for 2S (0-,1-) decays", &HeavyMesonWidthGenerator::gtilde_, 0.283, 0.0, 1.0, false, false, Interface::limited); static Parameter interfacefLambda ("Lambda", "Strong decays momentum scale", &HeavyMesonWidthGenerator::Lambda_, GeV, 1.*GeV, .1*GeV, 2.*GeV, false, false, Interface::limited); static Parameter interfacefpsiL ("psiL", "D_1 mixing angle for up and down heavy mesons", &HeavyMesonWidthGenerator::psiL_, 0., -M_PI/2., M_PI/2., false, false, Interface::limited); static Parameter interfacefpsiS ("psiS", "D_1 mixing angle for strange heavy mesons", &HeavyMesonWidthGenerator::psiS_, 0.041, -M_PI/2., M_PI/2., false, false, Interface::limited); } void HeavyMesonWidthGenerator::setupMode(tcDMPtr, tDecayIntegratorPtr decayer, unsigned int) { // cast the decayer Ptr::tcptr strong = dynamic_ptr_cast::tcptr >(decayer); if(strong) { if(!couplingsSet_) { fPi_ = strong->fPi_ ; g_ = strong->g_ ; gp_ = strong->gp_ ; h_ = strong->h_ ; hp_ = strong->hp_ ; k_ = strong->k_ ; kp_ = strong->kp_ ; gtilde_ = strong->gtilde_; psiL_ = strong->psiL_ ; psiS_ = strong->psiS_ ; Lambda_ = strong->Lambda_; couplingsSet_ = true; } } } void HeavyMesonWidthGenerator::dataBaseOutput(ofstream & output, bool header) { if(header) output << "update Width_Generators set parameters=\""; // info from the base class GenericWidthGenerator::dataBaseOutput(output,false); // info from this class output << "newdef " << name() << ":fPi " << fPi_/MeV << "\n"; output << "newdef " << name() << ":g " << g_ << "\n"; output << "newdef " << name() << ":gp " << gp_ << "\n"; output << "newdef " << name() << ":h " << h_ << "\n"; output << "newdef " << name() << ":hp " << hp_ << "\n"; output << "newdef " << name() << ":k " << k_ << "\n"; output << "newdef " << name() << ":kp " << kp_ << "\n"; output << "newdef " << name() << ":gtilde " << gtilde_ << "\n"; output << "newdef " << name() << ":Lambda " << Lambda_/GeV << "\n"; output << "newdef " << name() << ":psiL " << psiL_ << "\n"; output << "newdef " << name() << ":psiS " << psiS_ << "\n"; if(header) output << "\n\" where BINARY ThePEGName=\"" << name() << "\";" << endl; } Energy HeavyMesonWidthGenerator::partial2BodyWidth(int imode, Energy q,Energy m1, Energy m2) const { if(qid()); double psi = (id%100)/10!=3 ? psiL_ : psiS_; unsigned int itemp = abs(id)-abs(id)%1000; double mix1(cos(psi)),mix2(sin(psi)); if(itemp==20000) { swap(mix1,mix2); mix1 *=-1.; } InvEnergy2 A = -2.*sqrt(2.*m1/3./q)*hp_*mix1/fPi_/Lambda_; double B = -h_*mix2/1/fPi_*sqrt(m1/q)/q*(sqr(q)-sqr(m1)+sqr(m2)); B += A*sqr(pcm); test = (3.*sqr(A*q*sqr(pcm)) +sqr(B)/3.*(3.*sqr(m1)+sqr(pcm)) -A*B*sqr(pcm)*(sqr(q)+sqr(m1)-sqr(m2)))/sqr(m1); } else if(mecode==105) { test = 32.*sqr(hp_)*m1*sqr(sqr(pcm))/15./sqr(fPi_)/sqr(Lambda_)/q; } else if(mecode==106) { test = 16.*sqr(hp_)*m1*sqr(sqr(pcm))/5./sqr(fPi_)/sqr(Lambda_)/q; } else if(mecode==107) { test = sqr(h_)/sqr(fPi_)*m1/pow<3,1>(q)*sqr(sqr(q)-sqr(m1)+sqr(m2)); } else if(mecode==108) { test = 8.*m1*sqr(kp_*pcm*(sqr(q)-sqr(m1)+sqr(m2)))/9./sqr(fPi_*Lambda_*q)/q; } else if(mecode==109) { test = 4.*m1*sqr(kp_*pcm*(sqr(q)-sqr(m1)+sqr(m2)))/9./sqr(fPi_*Lambda_*q)/q; } else if(mecode==110) { test = 2.*sqr(kp_*pcm*(sqr(q)-sqr(m1)+sqr(m2)))/15./sqr(fPi_*Lambda_)/m2/pow<5,1>(q)* (sqr(q)*(sqr(q)+8.*sqr(m1)-2.*sqr(m2))+sqr(sqr(m1)-sqr(m2))); } else if(mecode==111) { test = 32.*sqr(k_)*pow<6,1>(pcm)/225./sqr(fPi_*sqr(Lambda_))/m1/pow<3,1>(q)* (sqr(q)*(16.*sqr(q)-2.*sqr(m1)+8.*sqr(m2))+sqr(sqr(m1)-sqr(m2))); } else if(mecode==112) { test = 32.*sqr(k_)*m1/35./q*pow<6,1>(pcm)/sqr(fPi_*sqr(Lambda_)); } else if(mecode==113) { test = 128.*sqr(k_)*m1/q*pow<6,1>(pcm)/105./sqr(fPi_*sqr(Lambda_)); } else if(mecode==114) { test = 4.*sqr(gtilde_)*q/m1*sqr(pcm)/sqr(fPi_); } else if(mecode==115) { test = 4.*sqr(gtilde_)*m1*sqr(pcm)/3./sqr(fPi_)/q; } else if(mecode==116) { test = 8.*sqr(gtilde_)*m1*sqr(pcm)/3./sqr(fPi_)/q; } else if(mecode==117) { long id = abs(particle()->id()); double psi = (id%100)/10!=3 ? psiL_ : psiS_; unsigned int itemp = abs(id)-abs(id)%1000; double mix1(cos(psi)),mix2(sin(psi)); if(itemp==20000) { swap(mix1,mix2); mix1 *=-1.; } test = 4.*sqr(gp_*mix2)*m1*sqr(pcm)/3./sqr(fPi_)/q; } else assert(false); return test*pcm/8./Constants::pi*MEcoupling(imode)*MEcoupling(imode); } diff --git a/Shower/QTilde/Matching/PowhegShowerHandler.cc b/Shower/QTilde/Matching/PowhegShowerHandler.cc --- a/Shower/QTilde/Matching/PowhegShowerHandler.cc +++ b/Shower/QTilde/Matching/PowhegShowerHandler.cc @@ -1,1104 +1,1103 @@ // -*- C++ -*- // // PowhegShowerHandler.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2019 The Herwig Collaboration // // Herwig is licenced under version 3 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // // // This is the implementation of the non-inlined, non-templated member // functions of the PowhegShowerHandler class. // #include #include "PowhegShowerHandler.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 "ThePEG/Utilities/DescribeClass.h" // include theses to have complete types #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/Kinematics/KinematicsReconstructor.h" #include "Herwig/Shower/QTilde/Base/PartnerFinder.h" #include "Herwig/PDF/HwRemDecayer.h" #include "Herwig/Shower/QTilde/Base/ShowerProgenitor.h" #include "Herwig/Shower/QTilde/Base/HardBranching.h" #include "Herwig/Shower/QTilde/Base/HardTree.h" #include "Herwig/MatrixElement/HwMEBase.h" #include "ThePEG/MatrixElement/MEBase.h" #include "ThePEG/MatrixElement/DiagramBase.fh" #include "ThePEG/PDF/PartonExtractor.h" #include "Herwig/MatrixElement/Matchbox/MatchboxFactory.h" #include "Herwig/MatrixElement/Matchbox/Utility/DiagramDrawer.h" using namespace Herwig; namespace { struct ParticleOrdering { 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() ); } }; } IBPtr PowhegShowerHandler::clone() const { return new_ptr(*this); } IBPtr PowhegShowerHandler::fullclone() const { return new_ptr(*this); } HardTreePtr PowhegShowerHandler::generateCKKW(ShowerTreePtr showerTree) const { // hard subprocess tSubProPtr sub = lastXCombPtr()->subProcess(); // real emission sub-process tSubProPtr real = Factory()->hardTreeSubprocess(); // born emitter emitter_ = Factory()->hardTreeEmitter(); spectator_ = Factory()->hardTreeSpectator(); // if no hard emission return if ( !(real && emitter_>-1) ) return HardTreePtr(); // check emission if(sub->outgoing().size()>=real->outgoing().size()) return HardTreePtr(); // check if decay has radiated don't add it if(showerTree->outgoingLines().size() != sub->outgoing().size()) { // loop over the decay trees for(map >::const_iterator tit=showerTree->treelinks().begin(); tit != showerTree->treelinks().end(); ++tit) { if(tit->first->outgoingLines().empty()) continue; // match the particles set decayProducts; set outgoing(real->outgoing().begin(),real->outgoing().end()); for(map::const_iterator oit=tit->first->outgoingLines().begin(); oit!=tit->first->outgoingLines().end();++oit) { tPPtr decayProd; Energy2 dmin( 1e30*GeV2 ); tPPtr part = oit->second->original(); for( set::const_iterator it = outgoing.begin(); it != outgoing.end(); ++it ) { if((**it).id()!=part->id()) continue; Energy2 dtest = sqr( part->momentum().x() - (**it).momentum().x() ) + sqr( part->momentum().y() - (**it).momentum().y() ) + sqr( part->momentum().z() - (**it).momentum().z() ) + sqr( part->momentum().t() - (**it).momentum().t() ); dtest += 1e10*sqr(part->momentum().m()-(**it).momentum().m()); if( dtest < dmin ) { decayProd = *it; dmin = dtest; } } if(!decayProd) { throw Exception() << "PowhegShowerHandler::generateCKKW(). Can't match shower and hard trees." << Exception::eventerror; } outgoing .erase (decayProd); decayProducts.insert(decayProd); } - bool coloured = false, foundParent = true; + bool foundParent = true; tPPtr parent,emitted; unsigned int nprod(0); for( set::const_iterator it = decayProducts.begin(); it != decayProducts.end(); ++it ) { - coloured |= (**it).dataPtr()->coloured(); tPPtr newParent = !(**it).parents().empty() ? (**it).parents()[0] : tPPtr(); ++nprod; // check if from emission if(newParent->id()==(**it).id()) { if(newParent->children().size()!=2) foundParent=false; bool foundChild(false), foundGluon(false); for(unsigned int ix=0;ixchildren().size();++ix) { if(newParent->children()[ix]==*it) { foundChild = true; continue; } else if(newParent->children()[ix]->id()==ParticleID::g) { foundGluon = true; continue; } } if(foundChild && foundGluon) { newParent = !newParent->parents().empty() ? newParent->parents()[0] : tPPtr(); ++nprod; } else foundParent = false; } if(!newParent) { foundParent = false; } else if(!parent) { parent = newParent; } else { if(parent!=newParent) foundParent = false; } } if(nprod!=tit->first->outgoingLines().size()&&foundParent) { if(decayRadiation_==0) { throw Exception() << "The radiation generated in this event\n " << *real << "\n has been interepted as occuring in the " << "decay \nof a colour-singlet object and cannot be handled " << "you can either not simulated this process, " << "veto this class of events by using\n" << "set " << fullName() << ":DecayRadiation VetoEvent\n" << "or throw the hard radiation away using \n" << "set " << fullName() << ":DecayRadiation VetoRadiation\n" << "Please contact us at herwig@hepforge.org for advice\n" << "on how to simulate this process\n" << Exception::runerror; } else if(decayRadiation_==1) { throw Exception() << "The radiation generated in this event\n " << *real << "\n has been interepted as occuring in the " << "decay \nof a colour-singlet object and cannot be handled " << "vetoing event\n" << Exception::eventerror; } else if(decayRadiation_==2) { generator()->log() << "The radiation generated in this event\n " << *real << "\n has been interepted as occuring in the " << "decay \nof a colour-singlet object and cannot be handled " << "vetoing radiation\n"; return HardTreePtr(); } else assert(false); } } } tStdXCombPtr lastXC = dynamic_ptr_cast(lastXCombPtr()); tStdXCombPtr headXC = lastXC->head(); if (headXC) matrixElement_ = dynamic_ptr_cast(headXC->matrixElement()); else if (lastXC) matrixElement_ = dynamic_ptr_cast(lastXC->matrixElement()); if (lastXC){ tStdXCombPtr projector= lastXC->lastProjector(); if (projector){ matrixElement_ = dynamic_ptr_cast(projector->matrixElement()); setSubtractionIntegral(true); } else setSubtractionIntegral(false); } assert(matrixElement_); // create a hard tree by clustering the event try { hardTree(doClustering(real,showerTree)); } catch(exception &e) { throw Exception() << "Caught a problem in PowhegShowerHandler::doClustering " << e.what() << Exception::eventerror; } // Get the HardTree from the CKKW handler. CKKWTreePtr hardtree = hardTree().tree(); // zero to avoid MPI problems Factory()->setHardTreeEmitter(-1); Factory()->setHardTreeSubprocess(SubProPtr()); return hardtree; } PotentialTree PowhegShowerHandler::doClustering(tSubProPtr real,ShowerTreePtr showerTree) const { // clear storage of the protoTrees protoBranchings().clear(); protoTrees().clear(); hardTrees_.clear(); assert( matrixElement() ); // extract the XComb for the Born process tStdXCombPtr lastXC; if (subtractionIntegral()){ tStdXCombPtr lastXCReal = dynamic_ptr_cast(lastXCombPtr()); lastXC = lastXCReal->lastProjector(); } else lastXC = dynamic_ptr_cast(lastXCombPtr()); const StandardXComb xc= *lastXC; // get the particles for the born process PPair incomingBorn = xc.subProcess()->incoming(); ParticleVector outgoingBorn = xc.subProcess()->outgoing(); // get particles from the XComb object for the real process ParticleVector outgoing = real->outgoing(); PPair incoming = real->incoming(); // loop through the FS particles and create ProtoBranchings for( unsigned int i = 0; i < outgoing.size(); ++i) { tPPtr parent = outgoing[i]->parents()[0]; ProtoBranchingPtr currentBranching = new_ptr(ProtoBranching(outgoing[i]->dataPtr(),HardBranching::Outgoing, outgoing[i]->momentum(),tSudakovPtr())); currentBranching-> colourLine(outgoing[i]-> colourLine()); currentBranching->antiColourLine(outgoing[i]->antiColourLine()); protoBranchings().insert(currentBranching); } // add IS hardBranchings ProtoBranchingPtr currentBranching = new_ptr(ProtoBranching(incoming.first ->dataPtr(),HardBranching::Incoming, incoming.first ->momentum(),tSudakovPtr())); currentBranching-> colourLine(incoming.first-> colourLine()); currentBranching->antiColourLine(incoming.first->antiColourLine()); protoBranchings().insert(currentBranching); currentBranching = new_ptr(ProtoBranching(incoming.second->dataPtr(),HardBranching::Incoming, incoming.second->momentum(),tSudakovPtr())); currentBranching-> colourLine(incoming.second-> colourLine()); currentBranching->antiColourLine(incoming.second->antiColourLine()); protoBranchings().insert(currentBranching); // create and initialise the first tree ProtoTreePtr initialProtoTree = new_ptr( ProtoTree() ); for(set::const_iterator it=protoBranchings().begin(); it!=protoBranchings().end();++it) { initialProtoTree->addBranching(*it); } // fill _proto_trees with all possible trees protoTrees().insert(initialProtoTree ); fillProtoTrees( initialProtoTree , xc.mePartonData()[emitter_]->id() ); // create a HardTree from each ProtoTree and fill hardTrees() for( set< ProtoTreePtr >::const_iterator cit = protoTrees().begin(); cit != protoTrees().end(); ++cit ) { set bornParticles(outgoingBorn.begin(),outgoingBorn.end()); bornParticles.insert(incomingBorn.first ); bornParticles.insert(incomingBorn.second); PotentialTree newTree; newTree.tree((**cit).createHardTree()); // new check based on the colour structure map cmap; // make the colour connections in the tree ShowerParticleVector branchingParticles; map branchingMap; bool matched(true); int iemitter(-1); HardBranchingPtr emitter; map locMap; for( set< HardBranchingPtr >::iterator it = newTree.tree()->branchings().begin(); it != newTree.tree()->branchings().end(); ++it ) { matched = true; // map the particle to the branching for future use branchingParticles.push_back((**it).branchingParticle()); branchingMap.insert(make_pair((**it).branchingParticle(),*it)); tPPtr bornPartner; if((**it).status()==HardBranching::Incoming) { HardBranchingPtr parent=*it; while(parent->parent()) { parent = parent->parent(); }; if(parent->branchingParticle()->momentum().z()/incomingBorn.first->momentum().z()>0.) { bornPartner = incomingBorn.first; if(!parent->children().empty()) { iemitter = 0; emitter = *it; } locMap[0] = *it; } else { bornPartner = incomingBorn.second; if(!parent->children().empty()) { iemitter = 1; emitter = *it; } locMap[1] = *it; } } else { Energy2 dmin( 1e30*GeV2 ); for(set::const_iterator bit=bornParticles.begin();bit!=bornParticles.end(); ++bit) { if((**it).branchingParticle()->id()!=(**bit).id()) continue; if(*bit==incomingBorn.first||*bit==incomingBorn.second) continue; Energy2 dtest = sqr( (**bit).momentum().x() - (**it).branchingParticle()->momentum().x() ) + sqr( (**bit).momentum().y() - (**it).branchingParticle()->momentum().y() ) + sqr( (**bit).momentum().z() - (**it).branchingParticle()->momentum().z() ) + sqr( (**bit).momentum().t() - (**it).branchingParticle()->momentum().t() ); dtest += 1e10*sqr((**bit).momentum().m()-(**it).branchingParticle()->momentum().m()); if( dtest < dmin ) { bornPartner = *bit; dmin = dtest; } } // find the map int iloc(-1); for(unsigned int ix=0;ixcolourLine()) { if(cmap.find((**it).branchingParticle()->colourLine())!=cmap.end()) { if(cmap[(**it).branchingParticle()->colourLine()]!=bornPartner->colourLine()) { matched=false; } } else { cmap[(**it).branchingParticle()->colourLine()] = bornPartner->colourLine(); } } if((**it).branchingParticle()->antiColourLine()) { if(cmap.find((**it).branchingParticle()->antiColourLine())!=cmap.end()) { if(cmap[(**it).branchingParticle()->antiColourLine()]!=bornPartner->antiColourLine()) { matched=false; } } else { cmap[(**it).branchingParticle()->antiColourLine()] = bornPartner->antiColourLine(); } } // require a match if(!matched) break; } // if no match continue if(!matched) continue; // now sort out any decays if(showerTree->outgoingLines().size()+showerTree->incomingLines().size() != newTree.tree()->branchings().size()) { if(showerTree->treelinks().empty()) { matched = false; continue; } // loop over the decay trees for(map >::const_iterator tit=showerTree->treelinks().begin(); tit != showerTree->treelinks().end(); ++tit) { if(tit->first->outgoingLines().empty()) continue; set decayProducts; set branchings = newTree.tree()->branchings(); // match the particles for(map::const_iterator oit=tit->first->outgoingLines().begin(); oit!=tit->first->outgoingLines().end();++oit) { HardBranchingPtr decayProd; Energy2 dmin( 1e30*GeV2 ); tPPtr part = oit->second->original(); for( set< HardBranchingPtr >::iterator it = branchings.begin(); it != branchings.end(); ++it ) { if((**it).status()==HardBranching::Incoming ) continue; if((**it).branchingParticle()->id()!=part->id()) continue; Energy2 dtest = sqr( part->momentum().x() - (**it).branchingParticle()->momentum().x() ) + sqr( part->momentum().y() - (**it).branchingParticle()->momentum().y() ) + sqr( part->momentum().z() - (**it).branchingParticle()->momentum().z() ) + sqr( part->momentum().t() - (**it).branchingParticle()->momentum().t() ); dtest += 1e10*sqr(part->momentum().m()-(**it).branchingParticle()->momentum().m()); if( dtest < dmin ) { decayProd = *it; dmin = dtest; } } if(!decayProd) { throw Exception() << "PowhegShowerHandler::generateCKKW(). Can't match shower and hard trees." << Exception::eventerror; } branchings .erase (decayProd); decayProducts.insert(decayProd); } // erase the decay products Lorentz5Momentum pnew,pshower; for(set::iterator it = decayProducts.begin(); it!=decayProducts.end(); ++it) { newTree.tree()->branchings().erase(*it); pnew += (**it).branchingParticle()->momentum(); pshower += (**it).showerMomentum(); } pnew .setMass(tit->second.second->mass()); pshower.setMass(tit->second.second->mass()); pnew .rescaleEnergy(); pshower.rescaleEnergy(); // create the decaying particle ShowerParticlePtr particle = new_ptr( ShowerParticle( tit->second.second->dataPtr() , true ) ); particle->set5Momentum( pnew ); HardBranchingPtr newBranch = new_ptr( HardBranching( particle, tSudakovPtr(), HardBranchingPtr(), HardBranching::Outgoing ) ); newBranch->showerMomentum(pshower); newTree.tree()->branchings().insert(newBranch); } } // if no match continue if(!matched) continue; // find the colour partners try { partnerFinder() ->setInitialEvolutionScales(branchingParticles,false, ShowerInteraction::QCD,true); } catch( Exception & e ) { generator()->log() << "Problem in set evolution scales in " << "PowhegShowerHandler::doClustering(). Exception was" << e.what(); continue; } for(unsigned int ix=0;ixpartner()) { HardBranchingPtr partner = branchingMap[branchingParticles[ix]->partner()]; branchingMap[branchingParticles[ix]]->colourPartner(partner); } } if(forcePartners_) { locMap[emitter_ ]->colourPartner(locMap[spectator_]); locMap[spectator_]->colourPartner(locMap[emitter_ ]); locMap[emitter_ ]->branchingParticle()->partner(locMap[spectator_]->branchingParticle()); locMap[spectator_]->branchingParticle()->partner(locMap[emitter_ ]->branchingParticle()); } newTree.tree()->partnersSet(true); // set the beam particles PPair beams = lastXCombPtr()->lastParticles(); // remove children of beams PVector beam_children = beams.first->children(); if( (**newTree.tree()->incoming().begin()).branchingParticle()->momentum().z() / beams.first->momentum().z() < 0.) swap( beams.first, beams.second ); set::iterator it = newTree.tree()->incoming().begin(); HardBranchingPtr br = *it; br->beam( beams.first ); while ( !br->children().empty() ) { for(unsigned int ix = 0; ix < br->children().size(); ++ix ) { if( br->children()[ix]->status() == HardBranching::Incoming ) { br = br->children()[ix]; break; } } br->beam( beams.first ); } ++it; br = *it; br->beam( beams.second ); while ( !br->children().empty() ) { for( unsigned int ix = 0; ix < br->children().size(); ++ix ) { if( br->children()[ix]->status() == HardBranching::Incoming ) { br = br->children()[ix]; break; } } br->beam( beams.second ); } // check the emitter and the spectator some how if(iemitter!=emitter_) continue; //do inverse momentum reconstruction if( !kinematicsReconstructor() ->deconstructHardJets( newTree.tree(), ShowerInteraction::QCD ) ) continue; newTree.tree()->findNodes(); newTree.weight(1.); hardTrees_.push_back( make_pair( newTree, 1. ) ); } // select the tree PotentialTree chosen_hardTree; if (hardTrees_.size()==1) { chosen_hardTree = hardTrees_[0].first; } else { // if multiple trees pick the one with matching // intermediate particle momenta for (unsigned int il=0; il > particles; PotentialTree testTree = hardTrees_[il].first; CKKWTreePtr check = testTree.tree(); // get id and momenta of particles in hard tree for (set< HardBranchingPtr >::iterator it=check->branchings().begin(); it!=check->branchings().end(); ++it) { particles.push_back(make_pair((*it)->branchingParticle()->id(), (*it)->branchingParticle()->momentum())); if (!(*it)->children().empty()){ for (unsigned int ic=0; ic<(*it)->children().size(); ++ic) particles.push_back(make_pair((*it)->children()[ic]->branchingParticle()->id(), (*it)->children()[ic]->branchingParticle()->momentum())); } if ((*it)->parent()){ particles.push_back(make_pair((*it)->parent()->branchingParticle()->id(), (*it)->parent()->branchingParticle()->momentum())); if (!(*it)->parent()->children().empty()) { for (unsigned int ic=0; ic<(*it)->parent()->children().size(); ++ic) { if(*it==(*it)->parent()->children()[ic]) continue; particles.push_back(make_pair((*it)->parent()->children()[ic]->branchingParticle()->id(), (*it)->parent()->children()[ic]->branchingParticle()->momentum())); } } } } // loop through and match to particles in real subprocess vector >::iterator part = particles.begin(); // incoming for (; part!=particles.end(); ++part){ if ((*part).first==real->incoming().first->id() && fuzzyEqual((*part).second, real->incoming().first->momentum())) break; } if (part!=particles.end()) particles.erase(part); part = particles.begin(); for (; part!=particles.end(); ++part){ if ((*part).first==real->incoming().second->id() && fuzzyEqual((*part).second, real->incoming().second->momentum())) break; } if (part!=particles.end()) particles.erase(part); // outgoing for (unsigned int io=0; iooutgoing().size(); ++io){ part = particles.begin(); for (; part!=particles.end(); ++part){ if ((*part).first==real->outgoing()[io]->id() && fuzzyEqual((*part).second, real->outgoing()[io]->momentum())) break; } if (part!=particles.end()) particles.erase(part); } // intermediate for (unsigned int ii=0; iiintermediates().size(); ++ii){ part = particles.begin(); for (; part!=particles.end(); ++part){ if ((*part).first==real->intermediates()[ii]->id() && fuzzyEqual((*part).second, real->intermediates()[ii]->momentum())) break; } if (part!=particles.end()) particles.erase(part); } // intermediate CC with -1*momentum for (unsigned int ii=0; iiintermediates().size(); ++ii){ part = particles.begin(); for (; part!=particles.end(); ++part){ if (!real->intermediates()[ii]->coloured() || (real->intermediates()[ii]->hasColour() && real->intermediates()[ii]->hasAntiColour())){ if ((*part).first==real->intermediates()[ii]->id() && fuzzyEqual((*part).second, -1.*real->intermediates()[ii]->momentum()) ) break; } else { if ((*part).first==-1.*real->intermediates()[ii]->id() && fuzzyEqual((*part).second, -1.*real->intermediates()[ii]->momentum()) ) break; } } if (part!=particles.end()) particles.erase(part); } // if all particles match, set as hardtree if (particles.empty()){ chosen_hardTree = testTree; break; } } } protoBranchings().clear(); protoTrees().clear(); hardTrees_.clear(); if(! chosen_hardTree.tree() ) { return PotentialTree(); } else return chosen_hardTree; } bool PowhegShowerHandler::checkDiagram(PotentialTree & tree, tcDiagPtr loDiagram) const { set::const_iterator cit; tcPDPair incoming; multiset outgoing; //get the incoming and outgoing partons involved in hard process for( cit = tree.tree()->branchings().begin(); cit != tree.tree()->branchings().end(); ++cit ){ if( (*cit)->status() ==HardBranching::Incoming) { HardBranchingPtr parent = *cit; while(parent->parent()) parent = parent->parent(); if( parent->branchingParticle()->momentum().z()>ZERO ) incoming.first = (*cit)->branchingParticle()->dataPtr(); else incoming.second = (*cit)->branchingParticle()->dataPtr(); } else { outgoing.insert( (*cit)->branchingParticle()->dataPtr() ); } } if(!incoming.first || !incoming.second) return 0.; pair tag; tag.first = incoming.first ->PDGName() + "," + incoming.second->PDGName() + "->"; tag.second = incoming.second ->PDGName() + "," + incoming.first ->PDGName() + "->"; string tag_out; for ( multiset::iterator i = outgoing.begin(); i != outgoing.end(); ++i ) { if ( i != outgoing.begin() ) tag_out += ","; tag_out += (**i).PDGName(); } tag.first += tag_out; tag.second += tag_out; // find the diagrams if( tag.first == loDiagram->getTag() || tag.second == loDiagram->getTag() ) tree.diagram(loDiagram); // check this is allowed return tree.diagram(); } void PowhegShowerHandler::fillProtoTrees( ProtoTreePtr currentProtoTree,long id ) const { if(currentProtoTree->branchings().size()==(lastXCombPtr()->subProcess()->outgoing().size()+2)) return; for( set::const_iterator ita = currentProtoTree->branchings().begin(); ita!=currentProtoTree->branchings().end();++ita) { for( set::const_iterator itb = currentProtoTree->branchings().begin(); itb!=ita;++itb) { // can't merge two incoming branchings if( (**ita).status() == HardBranching::Incoming && (**itb).status() == HardBranching::Incoming ) continue; // if branching must be outgoing, skip incoming if(emitter_>=2 && ( (**ita).status() == HardBranching::Incoming || (**itb).status() == HardBranching::Incoming )) continue; // if branching must be incoming, skip outgoing if(emitter_<2 && ( (**ita).status() != HardBranching::Incoming && (**itb).status() != HardBranching::Incoming )) continue; // get a new branching for this pair ProtoBranchingPtr currentBranching = getCluster(*ita,*itb); // check branching with the right PID if( ! currentBranching || currentBranching->id() != id) continue; // branching allowed so make a new Tree out of these branchings set< tProtoBranchingPtr > newTreeBranchings = currentProtoTree->branchings(); newTreeBranchings.erase(*ita); newTreeBranchings.erase(*itb); newTreeBranchings.insert(currentBranching); ProtoTreePtr newProtoTree = new_ptr( ProtoTree( newTreeBranchings ) ); // remove duplicate trees if( ! repeatProtoTree( newProtoTree ) ) protoTrees().insert( newProtoTree ); // remove the current tree if it hasn't already been removed if( protoTrees().find( currentProtoTree ) != protoTrees().end() ) protoTrees().erase( currentProtoTree ); // do recursion fillProtoTrees( newProtoTree , id); } } } bool PowhegShowerHandler::repeatProtoTree( ProtoTreePtr currentProtoTree ) const { // loop over all prototrees and see // how many ProtoBranchings of current ProtoTree are found in each for( set< ProtoTreePtr >::const_iterator cit = protoTrees().begin(); cit != protoTrees().end(); ++cit ) { unsigned int no_matches = 0; for( set< tProtoBranchingPtr >::const_iterator ckt = currentProtoTree->branchings().begin(); ckt != currentProtoTree->branchings().end(); ckt++ ) { if( (*cit)->branchings().find( *ckt ) != (*cit)->branchings().end() ) ++no_matches; } // return true if all match if( no_matches == currentProtoTree->branchings().size() ) return true; } return false; } tProtoBranchingPtr PowhegShowerHandler::getCluster( tProtoBranchingPtr b1, tProtoBranchingPtr b2 ) const { // look for the clustered pair in protoBranchings_ for(set::const_iterator cit = protoBranchings().begin(); cit != protoBranchings().end(); ++cit) { // both outgoing if(b1->status()==HardBranching::Outgoing && b2->status()==HardBranching::Outgoing) { if((**cit).status()!=HardBranching::Outgoing|| (**cit).children().empty()) continue; if( ( b1 == (**cit).children()[0] && b2 == (**cit).children()[1] ) || ( b1 == (**cit).children()[1] && b2 == (**cit).children()[0] ) ) return *cit; } // first incoming else if(b1->status()==HardBranching::Incoming) { if((**cit).backChildren().empty() ) continue; if(b1!=(**cit).backChildren()[0]) continue; if(b2==(**cit).backChildren()[1]) return *cit; } // second incoming else if(b2->status()==HardBranching::Incoming) { if((**cit).backChildren().empty() ) continue; if(b2!=(**cit).backChildren()[0]) continue; if(b1==(**cit).backChildren()[1]) return *cit; } } // is branching incoming or outgoing bool incoming = b1->status()==HardBranching::Incoming || b2->status()==HardBranching::Incoming; // get the branching BranchingElement theBranching; if( !incoming ) theBranching = allowedFinalStateBranching( b1, b2 ); else theBranching = allowedInitialStateBranching( b1, b2 ); //if branching is not allowed return null ProtoBrancing if( !theBranching.sudakov ) return ProtoBranchingPtr(); // get the ParticleData object for the new branching tcPDPtr particle_data = incoming ? theBranching.particles[1] : theBranching.particles[0]; // create clustered ProtoBranching ProtoBranchingPtr clusteredBranch; // outgoing if( !incoming ) { Lorentz5Momentum pairMomentum = b1->momentum() + b2->momentum(); pairMomentum.setMass(ZERO); clusteredBranch = new_ptr(ProtoBranching(particle_data,HardBranching::Outgoing, pairMomentum, theBranching.sudakov)); if(particle_data->iColour()==PDT::Colour0) return ProtoBranchingPtr(); else if(particle_data->iColour()==PDT::Colour3) { if(b1->particle()->iColour()==PDT::Colour3 && b2->particle()->iColour()==PDT::Colour8) { if(b1->colourLine()!=b2->antiColourLine()) return ProtoBranchingPtr(); clusteredBranch->colourLine(b2->colourLine()); } else if(b2->particle()->iColour()==PDT::Colour3 && b1->particle()->iColour()==PDT::Colour8) { if(b2->colourLine()!=b1->antiColourLine()) return ProtoBranchingPtr(); clusteredBranch->antiColourLine(b1->colourLine()); } else assert(false); clusteredBranch->type(ShowerPartnerType::QCDColourLine); } else if(particle_data->iColour()==PDT::Colour3bar) { if(b1->particle()->iColour()==PDT::Colour3bar && b2->particle()->iColour()==PDT::Colour8) { if(b1->antiColourLine()!=b2->colourLine()) return ProtoBranchingPtr(); clusteredBranch->antiColourLine(b2->antiColourLine()); } else if(b2->particle()->iColour()==PDT::Colour3bar && b1->particle()->iColour()==PDT::Colour8) { if(b2->antiColourLine()!=b1->colourLine()) return ProtoBranchingPtr(); clusteredBranch->antiColourLine(b1->antiColourLine()); } else assert(false); clusteredBranch->type(ShowerPartnerType::QCDAntiColourLine); } else if(particle_data->iColour()==PDT::Colour8) { tProtoBranchingPtr coloured,antiColoured; if(b1->particle()->iColour()==PDT::Colour3 && b2->particle()->iColour()==PDT::Colour3bar) { coloured = b1; antiColoured = b2; } else if(b2->particle()->iColour()==PDT::Colour3 && b1->particle()->iColour()==PDT::Colour3bar) { coloured = b2; antiColoured = b1; } else if(b1->particle()->iColour()==PDT::Colour8 && b2->particle()->iColour()==PDT::Colour8 ) { if(b1->colourLine()==b2->antiColourLine()) { coloured = b2; antiColoured = b1; } else if(b2->colourLine()==b1->antiColourLine()) { coloured = b1; antiColoured = b2; } else return ProtoBranchingPtr(); } else assert(false); // can't have colour self connected gluons if(coloured-> colourLine()==antiColoured->antiColourLine()) return ProtoBranchingPtr(); clusteredBranch-> colourLine( coloured-> colourLine()); clusteredBranch->antiColourLine(antiColoured->antiColourLine()); // softest particle is the emitted if(coloured->momentum().t()>antiColoured->momentum().t()) { clusteredBranch->type(ShowerPartnerType::QCDAntiColourLine); } else { clusteredBranch->type(ShowerPartnerType::QCDColourLine); } } else assert(false); } // incoming else { Lorentz5Momentum pairMomentum = b1->momentum() - b2->momentum(); pairMomentum.setMass( ZERO ); // check for CC if( particle_data->CC() && ( b1->id() != theBranching.particles[0]->id() || b2->id() != theBranching.particles[2]->id() ) ) { particle_data = particle_data->CC(); } clusteredBranch = new_ptr(ProtoBranching(particle_data,HardBranching::Incoming, pairMomentum,theBranching.sudakov)); // work out the type of branching if(b1->particle()->iColour()==PDT::Colour3) { b1->type(ShowerPartnerType::QCDColourLine); if(b2->particle()->iColour()==PDT::Colour3 && particle_data->iColour()==PDT::Colour8) { if(b1->colourLine()==b2->colourLine()) return ProtoBranchingPtr(); clusteredBranch-> colourLine(b1->colourLine()); clusteredBranch->antiColourLine(b2->colourLine()); } else if(b2->particle()->iColour()==PDT::Colour8 && particle_data->iColour()==PDT::Colour3) { if(b1->colourLine()!=b2->colourLine()) return ProtoBranchingPtr(); clusteredBranch->colourLine(b2->antiColourLine()); } else assert(false); } else if(b1->particle()->iColour()==PDT::Colour3bar) { b1->type(ShowerPartnerType::QCDAntiColourLine); if(b2->particle()->iColour()==PDT::Colour3bar && particle_data->iColour()==PDT::Colour8) { if(b1->antiColourLine()==b2->antiColourLine()) return ProtoBranchingPtr(); clusteredBranch-> colourLine(b2->antiColourLine()); clusteredBranch->antiColourLine(b1->antiColourLine()); } else if(b2->particle()->iColour()==PDT::Colour8 && particle_data->iColour()==PDT::Colour3bar) { if(b1->antiColourLine()!=b2->antiColourLine()) return ProtoBranchingPtr(); clusteredBranch->antiColourLine(b2->colourLine()); } else assert(false); } else if(b1->particle()->iColour()==PDT::Colour8) { if(b2->particle()->iColour()==PDT::Colour3) { if(b1->colourLine()!=b2->colourLine()) return ProtoBranchingPtr(); clusteredBranch->antiColourLine(b1->antiColourLine()); b1->type(ShowerPartnerType::QCDColourLine); } else if(b2->particle()->iColour()==PDT::Colour3bar) { if(b1->antiColourLine()!=b2->antiColourLine()) return ProtoBranchingPtr(); clusteredBranch-> colourLine(b1->colourLine()); b1->type(ShowerPartnerType::QCDAntiColourLine); } else if(b2->particle()->iColour()==PDT::Colour8) { if(b1->colourLine()==b2->colourLine()) { b1->type(ShowerPartnerType::QCDColourLine); clusteredBranch->antiColourLine(b1->antiColourLine()); clusteredBranch->colourLine(b2->antiColourLine()); } else if(b1->antiColourLine()==b2->antiColourLine()) { b1->type(ShowerPartnerType::QCDAntiColourLine); clusteredBranch-> colourLine(b1->colourLine()); clusteredBranch->antiColourLine(b2->colourLine()); } else { return ProtoBranchingPtr(); } } else assert(false); } else assert(false); } protoBranchings().insert(clusteredBranch); //set children relations // outgoing if( !incoming ){ clusteredBranch->addChild( b1 ); clusteredBranch->addChild( b2 ); } else { clusteredBranch->addBackChild( b1 ); clusteredBranch->addBackChild( b2 ); } return clusteredBranch; } BranchingElement PowhegShowerHandler:: allowedFinalStateBranching( tProtoBranchingPtr & b1, tProtoBranchingPtr & b2) const { // check with normal ID's pair< long, long > ptest = make_pair( b1->id(), b2->id() ); map< pair< long, long >, BranchingElement >::const_iterator split = allowedFinal_.find(ptest); if( split != allowedFinal_.end() ) { if( split->second.particles[1]->id() != ptest.first ) swap( b1, b2 ); return split->second; } // check with CC if( b1->particle()->CC() ) ptest.first *= -1; if( b2->particle()->CC() ) ptest.second *= -1; split = allowedFinal_.find( ptest ); if( split != allowedFinal_.end() ) { // cc the idlist only be for qbar g clusterings BranchingElement ccBranch = split->second; swap(ccBranch.particles,ccBranch.conjugateParticles); if( split->second.particles[1]->id() != ptest.first ) swap( b1, b2); return ccBranch; } // not found found null pointer return BranchingElement(); } BranchingElement PowhegShowerHandler::allowedInitialStateBranching( tProtoBranchingPtr & b1, tProtoBranchingPtr & b2) const { if(b2->status()==HardBranching::Incoming) swap(b1,b2); // is initial parton an antiparticle bool cc = b1->id() < 0; //gives range of allowedInitial_ with matching first abs( id ) pair< multimap< long, BranchingElement >::const_iterator, multimap< long, BranchingElement >::const_iterator > location = allowedInitial_.equal_range( abs( b1->id() ) ); //iterates over this range for( multimap< long, BranchingElement >::const_iterator it = location.first; it != location.second; ++it ) { //test id for second particle in pair long idtest = cc ? it->second.conjugateParticles[2]->id() : it->second.particles[2]->id(); // does second id match the test if( idtest == b2->id() ) return it->second; //if the the IS parton is a gluon and charge conjugate of second parton mathes accept if( idtest == -b2->id() && ! b1->particle()->CC() ) return it->second; } // not found found null pointer return BranchingElement(); } bool PowhegShowerHandler::fuzzyEqual(Lorentz5Momentum a, Lorentz5Momentum b) const{ // check momenta are within 1% of each other if ( (a.e()==ZERO && b.e()==ZERO) || (a.e()/b.e()>0.99 && a.e()/b.e()<1.01) ){ if ((a.x()==ZERO && b.x()==ZERO) || (a.x()/b.x()>0.99 && a.x()/b.x()<1.01) ){ if ((a.y()==ZERO && b.y()==ZERO) || (a.y()/b.y()>0.99 && a.y()/b.y()<1.01) ){ if ((a.z()==ZERO && b.z()==ZERO) || (a.z()/b.z()>0.99 && a.z()/b.z()<1.01) ) return true; } } } return false; } void PowhegShowerHandler::doinit() { QTildeShowerHandler::doinit(); // extract the allowed branchings // final-state for(BranchingList::const_iterator it = splittingGenerator()->finalStateBranchings().begin(); it != splittingGenerator()->finalStateBranchings().end(); ++it) { pair prod(make_pair(it->second.particles[1]->id(), it->second.particles[2]->id())); allowedFinal_.insert(make_pair(prod,it->second)); swap(prod.first,prod.second); allowedFinal_.insert(make_pair(prod,it->second)); } // initial-state for(BranchingList::const_iterator it = splittingGenerator()->initialStateBranchings().begin(); it != splittingGenerator()->initialStateBranchings().end(); ++it) { allowedInitial_.insert(make_pair(it->second.particles[0]->id(),it->second)); } } void PowhegShowerHandler::persistentOutput(PersistentOStream & os) const { os << allowedInitial_ << allowedFinal_ << subtractionIntegral_ << enforceColourConsistency_ << forcePartners_ << decayRadiation_; } void PowhegShowerHandler::persistentInput(PersistentIStream & is, int) { is >> allowedInitial_ >> allowedFinal_ >> subtractionIntegral_ >> enforceColourConsistency_ >> forcePartners_ >> decayRadiation_; } // Static variable needed for the type description system in ThePEG. DescribeClass describeHerwigPowhegShowerHandler("Herwig::PowhegShowerHandler", "HwMatchbox.so HwMatching.so"); void PowhegShowerHandler::Init() { static ClassDocumentation documentation ("The PowhegShowerHandler class"); static Switch interfaceEnforceColourConsistency ("EnforceColourConsistency", "Force the Born and real emission colour flows to be consistent", &PowhegShowerHandler::enforceColourConsistency_, false, false, false); static SwitchOption interfaceEnforceColourConsistencyYes (interfaceEnforceColourConsistency, "Yes", "Enforce the consistency", true); static SwitchOption interfaceEnforceColourConsistencyNo (interfaceEnforceColourConsistency, "No", "Don't enforce consistency", false); static Switch interfaceForcePartners ("ForcePartners", "Whether or not to force the partners to be those from the kinematic generation", &PowhegShowerHandler::forcePartners_, false, false, false); static SwitchOption interfaceForcePartnersYes (interfaceForcePartners, "Yes", "Force them", true); static SwitchOption interfaceForcePartnersNo (interfaceForcePartners, "No", "Don't force them", false); static Switch interfaceDecayRadiation ("DecayRadiation", "Handling of radiation which is interpretted as having come from decays", &PowhegShowerHandler::decayRadiation_, 0, false,false); static SwitchOption interfaceDecayRadiationNotAllowed (interfaceDecayRadiation, "NotAllowed", "Not allowed at all, run error will be thrown", 0); static SwitchOption interfaceDecayRadiationVetoEvent (interfaceDecayRadiation, "VetoEvent", "Veto the whole event", 1); static SwitchOption interfaceDecayRadiationVetoRadiation (interfaceDecayRadiation, "VetoRadiation", "Throw the radiation away but keep the event", 2); } diff --git a/Shower/QTilde/SplittingFunctions/OneOneOneQEDSplitFn.cc b/Shower/QTilde/SplittingFunctions/OneOneOneQEDSplitFn.cc --- a/Shower/QTilde/SplittingFunctions/OneOneOneQEDSplitFn.cc +++ b/Shower/QTilde/SplittingFunctions/OneOneOneQEDSplitFn.cc @@ -1,236 +1,235 @@ // -*- C++ -*- // // This is the implementation of the non-inlined, non-templated member // functions of the OneOneOneQEDSplitFn class. // #include "OneOneOneQEDSplitFn.h" #include "ThePEG/StandardModel/StandardModelBase.h" #include "ThePEG/Repository/EventGenerator.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/PDT/ParticleData.h" #include "Herwig/Decay/TwoBodyDecayMatrixElement.h" #include "Herwig/Models/StandardModel/SMFFHVertex.h" using namespace Herwig; IBPtr OneOneOneQEDSplitFn::clone() const { return new_ptr(*this); } IBPtr OneOneOneQEDSplitFn::fullclone() const { return new_ptr(*this); } void OneOneOneQEDSplitFn::persistentOutput(PersistentOStream & os) const { os << gWWG_ << _theSM; } void OneOneOneQEDSplitFn::persistentInput(PersistentIStream & is, int) { is >> gWWG_ >> _theSM; } // The following static variable is needed for the type description system in ThePEG. DescribeClass describeHerwigOneOneOneQEDSplitFn("Herwig::OneOneOneQEDSplitFn", "HwShower.so"); void OneOneOneQEDSplitFn::Init() { static ClassDocumentation documentation ("The OneOneOneQEDSplitFn class implements the gamma->WW EW splitting."); } void OneOneOneQEDSplitFn::doinit() { SplittingFunction::doinit(); tcSMPtr sm = generator()->standardModel(); - double sw2 = sm->sin2ThetaW(); // WWG coupling gWWG_ = 1.; // to employ running masses, wherever needed _theSM = dynamic_ptr_cast(generator()->standardModel()); } void OneOneOneQEDSplitFn::getCouplings(double & gvvv, const IdList & ids) const { // G > WW if(ids[0]->id()==ParticleID::gamma && abs(ids[1]->id())==ParticleID::Wplus && abs(ids[2]->id())==ParticleID::Wplus){ gvvv = gWWG_; } else assert(false); } double OneOneOneQEDSplitFn::P(const double z, const Energy2 t, const IdList &ids, const bool mass, const RhoDMatrix & rho) const { double gvvv(0.); getCouplings(gvvv,ids); double abs_rho_00 = abs(rho(0,0)); double abs_rho_11 = abs(rho(1,1)); double abs_rho_22 = abs(rho(2,2)); // massless limit double val = ((2.*sqr(1.-(1.-z)*z))/((1.-z)*z))*(abs_rho_00+abs_rho_22); // massive limits if(mass) { double m0t2 = sqr(ids[0]->mass())/t; double m1t2 = sqr(ids[1]->mass())/t; double m2t2 = sqr(ids[2]->mass())/t; val += (-2.*(m2t2*(1.-sqr(1.-z)*z)+m1t2*(1.-(1.-z)*sqr(z)))*(abs_rho_00+abs_rho_22))/((1.-z)*z) + (2.*m0t2*(2.*pow(1.-z,3)*z*abs_rho_11+sqr(1.-(1.-z)*z)*(abs_rho_00+abs_rho_22)))/((1.-z)*z); } return sqr(gvvv)*val; } double OneOneOneQEDSplitFn::overestimateP(const double z, const IdList & ids) const { double gvvv(0.); getCouplings(gvvv,ids); return sqr(gvvv)*(2./(z*(1.-z))); } double OneOneOneQEDSplitFn::ratioP(const double z, const Energy2 t, const IdList & ids, const bool mass, const RhoDMatrix & rho) const { double val(0.); double abs_rho_00 = abs(rho(0,0)); double abs_rho_11 = abs(rho(1,1)); double abs_rho_22 = abs(rho(2,2)); // massless limit val = sqr(1.-(1.-z)*z)*(abs_rho_00+abs_rho_22); // massive limit if(mass) { double m0t2 = sqr(ids[0]->mass())/t; double m1t2 = sqr(ids[1]->mass())/t; double m2t2 = sqr(ids[2]->mass())/t; val += -(m2t2*(1.-sqr(1.-z)*z) + m1t2*(1.-(1.-z)*sqr(z)))*(abs_rho_00+abs_rho_22) + m0t2*(2.*pow(1.-z,3)*z*abs_rho_11+sqr(1.-(1.-z)*z)*(abs_rho_00+abs_rho_22)); } return val; } double OneOneOneQEDSplitFn::integOverP(const double z, const IdList & ids, unsigned int PDFfactor) const { double gvvv(0.); getCouplings(gvvv,ids); double pre = sqr(gvvv); switch (PDFfactor) { case 0: return 2.*pre*(log(z)-log(1.-z)); case 1: //return -2.*pre*(1./z+log(1.-z)-log(z)); case 2: //return 2.*pre*(2.*log(z)+(2.*z-1.)/(z*(1.-z))-2.*log(1.-z)); case 3: //return 2.*pre*(1./(1.-z)-1./z-2.*log(1.-z)+2.*log(z)); default: throw Exception() << "OneOneOneQEDSplitFn::integOverP() invalid PDFfactor = " << PDFfactor << Exception::runerror; } } double OneOneOneQEDSplitFn::invIntegOverP(const double r, const IdList & ids, unsigned int PDFfactor) const { double gvvv(0.); getCouplings(gvvv,ids); double pre = sqr(gvvv); switch (PDFfactor) { case 0: return exp(0.5*r/pre)/(1.+exp(0.5*r/pre)); case 1: case 2: case 3: default: throw Exception() << "OneOneOneQEDSplitFn::invIntegOverP() invalid PDFfactor = " << PDFfactor << Exception::runerror; } } bool OneOneOneQEDSplitFn::accept(const IdList &ids) const { if(ids.size()!=3) return false; if(ids[0]->id()==ParticleID::gamma && abs(ids[1]->id())==ParticleID::Wplus && ids[1]->id()==-ids[2]->id()) return true; return false; } vector > OneOneOneQEDSplitFn::generatePhiForward(const double, const Energy2, const IdList & , const RhoDMatrix &) { // no dependence on the spin density matrix, dependence on off-diagonal terms cancels // and rest = splitting function for Tr(rho)=1 as required by defn return vector >(1,make_pair(0,1.)); } vector > OneOneOneQEDSplitFn::generatePhiBackward(const double, const Energy2, const IdList & , const RhoDMatrix &) { // no dependence on the spin density matrix, dependence on off-diagonal terms cancels // and rest = splitting function for Tr(rho)=1 as required by defn return vector >(1,make_pair(0,1.)); } DecayMEPtr OneOneOneQEDSplitFn::matrixElement(const double z, const Energy2 t, const IdList & ids, const double phi, bool) { // calculate the kernal DecayMEPtr kernal(new_ptr(TwoBodyDecayMatrixElement(PDT::Spin1,PDT::Spin1,PDT::Spin1))); double gvvv(0.); getCouplings(gvvv,ids); // defining dummies double m0t = ids[0]->mass()/sqrt(t); double m1t = ids[1]->mass()/sqrt(t); double m2t = ids[2]->mass()/sqrt(t); Complex phase = exp(Complex(0.,1.)*phi); Complex cphase = conj(phase); double z1_z = z*(1.-z); double sqrtmass = sqrt(sqr(m0t)-sqr(m1t)/z-sqr(m2t)/(1.-z)+1.); double r2 = sqrt(2.); // assign kernel (*kernal)(0,0,0) = gvvv*phase*(1./sqrt(z1_z))*sqrtmass; (*kernal)(0,0,1) = gvvv*r2*m2t*(z/(1.-z)); //2>4 (*kernal)(0,0,2) = -gvvv*cphase*sqrt(z/(1.-z))*sqrtmass; (*kernal)(0,1,0) = -gvvv*r2*m1t*(1.-z)/z; //2>4 (*kernal)(0,1,1) = 0.; (*kernal)(0,1,2) = 0.; (*kernal)(0,2,0) = -gvvv*(1.-z)*cphase*sqrt((1.-z)/z)*sqrtmass; (*kernal)(0,2,1) = 0.; (*kernal)(0,2,2) = 0.; (*kernal)(1,0,0) = 0.; (*kernal)(1,0,1) = 0.; //2>4 (*kernal)(1,0,2) = -gvvv*r2*m0t*(1.-z); //2>4 (*kernal)(1,1,0) = 0.; //221>441 (*kernal)(1,1,1) = 0.; //222>444 (*kernal)(1,1,2) = 0.; //223>443 (*kernal)(1,2,0) = -gvvv*r2*m0t*(1.-z); //2>4 (*kernal)(1,2,1) = 0.; //2>4 (*kernal)(1,2,2) = 0.; //2>4 (*kernal)(2,0,0) = 0.; (*kernal)(2,0,1) = 0.; (*kernal)(2,0,2) = gvvv*(1.-z)*phase*sqrt((1.-z)/z)*sqrtmass; (*kernal)(2,1,0) = 0.; (*kernal)(2,1,1) = 0.; //2>4 (*kernal)(2,1,2) = -gvvv*r2*m1t*((1.-z)/z);//2>4 (*kernal)(2,2,0) = gvvv*phase*sqrt(z/(1.-z))*sqrtmass; (*kernal)(2,2,1) = gvvv*r2*m2t*(z/(1.-z)); //2>4 (*kernal)(2,2,2) = -gvvv*cphase*(1./sqrt(z1_z))*sqrtmass; // return the answer return kernal; }