#include "REMNANTS/Main/Hadron_Remnant.H" #include "REMNANTS/Tools/Colour_Generator.H" #include "BEAM/Main/Beam_Base.H" #include "ATOOLS/Org/Run_Parameter.H" #include "ATOOLS/Org/Exception.H" #include "ATOOLS/Math/Random.H" #include using namespace REMNANTS; using namespace ATOOLS; Hadron_Remnant::Hadron_Remnant(PDF::PDF_Base * pdf,const unsigned int beam): Remnant_Base(rtp::hadron,beam), p_pdf(pdf), p_partons(&(p_pdf->Partons())), m_beamflav(pdf->Bunch()), p_valence(NULL), p_remnant(NULL), p_recoiler(NULL), m_alpha(0.), m_gamma(1.), m_beta(-1.5), m_invb(1./(m_beta+1)), m_LambdaQCD(0.25) { m_scale2 = Max(4.0,p_pdf->Q2Min()); ConstructConstituentFlavours(); } void Hadron_Remnant::ConstructConstituentFlavours() { if (m_constituents.size()>0) return; int hadint=(m_beamflav.Kfcode()-(m_beamflav.Kfcode()/10000)*10000)/10; if ((hadint>100)&&(hadint<1000)) { m_constituents.push_back(Flavour((kf_code)(hadint)/100)); m_constituents.push_back(Flavour((kf_code)((hadint-(hadint/100)*100)/10))); m_constituents.push_back(Flavour((kf_code)(hadint-(hadint/10)*10))); } else if ((hadint>10)&&(hadint<100)) { m_constituents.push_back(Flavour((kf_code)(hadint)/10)); m_constituents.push_back(Flavour((kf_code)(hadint-(hadint/10)*10))); } else THROW(critical_error,"Cannot determine constituents."); if (m_beamflav.IsAnti()) { for(FlavourList::iterator flit=m_constituents.begin(); flit!=m_constituents.end();flit++) (*flit) = (*flit).Bar(); } } bool Hadron_Remnant::IsValence(Particle * part) { // only one valence parton. if (m_valence) return false; // assume valence(q) = pdf(q) - pdf(qbar) Flavour flav = part->Flav(); for (FlavourList::iterator flit=m_constituents.begin(); flit!=m_constituents.end();flit++) { if (flav==(*flit)) { Vec4D mom = part->Momentum(); m_x = mom[0]/m_residualE; p_pdf->Calculate(m_x,sqr(flav.Mass())+m_scale2); double val = p_pdf->GetXPDF(flav)-p_pdf->GetXPDF(flav.Bar()); double tot = p_pdf->GetXPDF(flav); m_valence = (val/tot > ran->Get()); if (m_valence) p_valence = part; return m_valence; } } return false; } void Hadron_Remnant::MakeSpectator(Particle * parton) { // If a shower initiator is a sea-quark or antiquark, a corresponding // antiflavour has to be added to the spectators. p_spectator = NULL; if (IsValence(parton)) return; Flavour flav = parton->Flav(); if (flav.IsQuark()) { p_spectator = MakeParticle(flav.Bar()); p_spectator->SetFlow((flav.Bar().IsAnti()?2:1),-1); p_colours->AddColour(m_beam,(flav.Bar().IsAnti()?1:0),p_spectator); m_spectators.push_front(p_spectator); } } Particle * Hadron_Remnant::MakeParticle(const Flavour & flav) { Particle * part = new Particle(-1,flav,Vec4D(0.,0.,0.,0.),'B'); part->SetNumber(); part->SetBeam(m_beam); return part; } bool Hadron_Remnant::FillBlob(ParticleMomMap *ktmap,const bool & copy) { m_residualE = p_beam->OutMomentum()[0]; // Add remnants, diquark and quark, if necessary. if (!p_valence || !p_remnant) MakeRemnants(); // Possibly adjust final pending colours with extra gluons - in prinicple one may have // to check that they are not singlets .... CompensateColours(); // Assume all remnant bases already produced a beam blob = p_beamblob MakeLongitudinalMomenta(ktmap,copy); bool colourconserved = p_beamblob->CheckColour(true); if (!colourconserved) { msg_Error()<<"Error in "<Output(); return false; } return true; } void Hadron_Remnant::CompensateColours() { while (p_colours->Colours(m_beam,0).size()>0 && p_colours->Colours(m_beam,1).size()>0) { Particle * gluon = MakeParticle(Flavour(kf_gluon)); int col[2]; for (size_t i=0;i<2;i++) gluon->SetFlow(i+1,p_colours->NextColour(m_beam,i)); //msg_Out()<<"Add new particle to beam blob ["<Get()*m_constituents.size()); FlavourList::iterator flit=m_constituents.begin(); for (size_t i=0;iSetFlow(index+1,p_colours->NextColour(m_beam,index)); m_spectators.push_back(p_valence); } else { valflav = p_valence->Flav(); index = ((valflav.IsQuark() && !valflav.IsAnti()) || (valflav.IsDiQuark() && valflav.IsAnti()))?0:1; } p_remnant = p_recoiler = MakeParticle(RemnantFlavour(valflav)); p_remnant->SetFlow(2-index,p_colours->NextColour(m_beam,1-index)); m_spectators.push_front(p_recoiler); return true; } Flavour Hadron_Remnant::RemnantFlavour(const Flavour & flav) { // Counter taken to make sure only two flavours are used // to construct diquark - either qq'_0 or qq_1. bool taken = false; std::vector kfs; for (FlavourList::iterator flit=m_constituents.begin(); flit!=m_constituents.end();flit++) { if (taken && flav==(*flit)) continue; kfs.push_back((flit->IsAnti()?-1:1)*flit->Kfcode()); taken = true; } int kfcode = 1 + (kfs.size()==2 && kfs[0]==kfs[1]?2:0); for (size_t i=0;iOutMomentum(); for (Part_Iterator pmit=m_extracted.begin(); pmit!=m_extracted.end();pmit++) { availMom -= (*pmit)->Momentum(); if (copy) { Particle * pcopy = new Particle(**pmit); pcopy->SetNumber(); pcopy->SetBeam(m_beam); p_beamblob->AddToOutParticles(pcopy); } else p_beamblob->AddToOutParticles(*pmit); (*ktmap)[(*pmit)] = Vec4D(); } for (Part_Iterator pmit=m_spectators.begin(); pmit!=m_spectators.end();pmit++) { Particle * part = (*pmit); if (part==m_spectators.back()) part->SetMomentum(availMom); else { double z = SelectZ(part->Flav(),true); part->SetMomentum(z*availMom); availMom -= part->Momentum(); } if (copy) { Particle * pcopy = new Particle(*part); pcopy->SetNumber(); pcopy->SetBeam(m_beam); p_beamblob->AddToOutParticles(pcopy); } else p_beamblob->AddToOutParticles(part); (*ktmap)[part] = Vec4D(); } } double Hadron_Remnant::SelectZ(const Flavour & flav,const bool & isvalence) { double zmin = Max(m_LambdaQCD,flav.HadMass())/m_residualE, z(zmin), zmax(1.-1./m_residualE); double wt = 1.; if (!isvalence) { zmax -= double(m_spectators.size()-1)*0.3/m_residualE; // Assume functional from of z^beta with beta = -1.5 (default) // Maybe beta_gluon != beta_quark, but leave it for the time being if (m_beta!=-1) { double rand = ran->Get(); z = pow(rand*pow(zmax,m_beta+1.)+(1.-rand)*pow(zmin,m_beta+1.),m_invb); } else z = zmin * pow(zmax/zmin,ran->Get()); } else { // If di-quark assume form peaking at 1, something like // exp(-gamma/z)*(1-z)^alpha -> realised by hit-or-miss double wtmax = pow((1.-zmin),m_alpha)*exp(-m_gamma/zmax); do { z = zmin + (zmax-zmin)*ran->Get(); wt = pow((1.-z),m_alpha)*exp(-m_gamma/z); } while (wt < wtmax*ran->Get()); if (!flav.IsDiQuark()) z = 1.-z; } return z; } void Hadron_Remnant::Reset(const bool & DIS) { Remnant_Base::Reset(); while (!m_spectators.empty()) { Particle * part = m_spectators.front(); if (part->ProductionBlob()) part->ProductionBlob()->RemoveOutParticle(part); if (part->DecayBlob()) part->DecayBlob()->RemoveInParticle(part); delete part; m_spectators.pop_front(); } m_spectators.clear(); m_residualE = p_beam->OutMomentum()[0]; m_valence = false; p_valence = p_remnant = p_recoiler = NULL; } bool Hadron_Remnant::TestExtract(const Flavour &flav,const Vec4D &mom) { // Is flavour element of flavours allowed by PDF? if (p_partons->find(flav)==p_partons->end()) { msg_Error()<m_residualE) { msg_Error()< E = "<OutMomentum()[0]); if (m_xXMin() || m_x>p_pdf->XMax()) { msg_Error()<begin(); flit!=p_partons->end();flit++) { msg_Out()<<" "<<(*flit); } msg_Out()<<"}.\n"; }