diff --git a/Hadronization/HadronSelector.cc b/Hadronization/HadronSelector.cc --- a/Hadronization/HadronSelector.cc +++ b/Hadronization/HadronSelector.cc @@ -1,1030 +1,1134 @@ // -*- C++ -*- // // HadronSelector.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 HadronSelector class. // #include "HadronSelector.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Interface/Parameter.h" #include "ThePEG/Interface/Switch.h" #include "ThePEG/Interface/ParVector.h" #include "ThePEG/Interface/RefVector.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include <ThePEG/PDT/EnumParticles.h> #include <ThePEG/Repository/EventGenerator.h> #include <ThePEG/Repository/CurrentGenerator.h> #include <ThePEG/Repository/Repository.h> #include "CheckId.h" #include <ThePEG/Utilities/DescribeClass.h> +#include "Herwig/Utilities/Kinematics.h" using namespace Herwig; DescribeAbstractClass<HadronSelector,Interfaced> describeHadronSelector("Herwig::HadronSelector","Herwig.so"); namespace { // debug helper void dumpTable(const HadronTable & tbl) { typedef HadronTable::const_iterator TableIter; for (TableIter it = tbl.begin(); it != tbl.end(); ++it) { cerr << it->first.first << ' ' << it->first.second << '\n'; for (KupcoData::const_iterator jt = it->second.begin(); jt != it->second.end(); ++jt) { cerr << '\t' << *jt << '\n'; } } } bool weightIsLess (pair<long,double> a, pair<long,double> b) { return a.second < b.second; } } HadronSelector::HadronSelector(unsigned int opt) : _weight1S0(Nmax,1.),_weight3S1(Nmax,1.),_weight1P1(Nmax,1.),_weight3P0(Nmax,1.), _weight3P1(Nmax,1.),_weight3P2(Nmax,1.),_weight1D2(Nmax,1.),_weight3D1(Nmax,1.), _weight3D2(Nmax,1.),_weight3D3(Nmax,1.), _repwt(Lmax,vector<vector<double> >(Jmax,vector<double>(Nmax))), _topt(opt),_trial(0), _limBottom(), _limCharm(), _limExotic(), belowThreshold_(0) { // The mixing angles // the ideal mixing angle const double idealAngleMix = atan( sqrt(0.5) ) * 180.0 / Constants::pi; // \eta-\eta' mixing angle _etamix = -23.0; // phi-omega mixing angle _phimix = +36.0; // h_1'-h_1 mixing angle _h1mix = idealAngleMix; // f_0(1710)-f_0(1370) mixing angle _f0mix = idealAngleMix; // f_1(1420)-f_1(1285)\f$ mixing angle _f1mix = idealAngleMix; // f'_2-f_2\f$ mixing angle _f2mix = +26.0; // eta_2(1870)-eta_2(1645) mixing angle _eta2mix = idealAngleMix; // phi(???)-omega(1650) mixing angle _omhmix = idealAngleMix; // phi_3-omega_3 mixing angle _ph3mix = +28.0; // eta(1475)-eta(1295) mixing angle _eta2Smix = idealAngleMix; // phi(1680)-omega(1420) mixing angle _phi2Smix = idealAngleMix; } void HadronSelector::persistentOutput(PersistentOStream & os) const { os << _partons << _etamix << _phimix << _h1mix << _f0mix << _f1mix << _f2mix << _eta2mix << _omhmix << _ph3mix << _eta2Smix << _phi2Smix << _weight1S0 << _weight3S1 << _weight1P1 << _weight3P0 << _weight3P1 << _weight3P2 << _weight1D2 << _weight3D1 << _weight3D2 << _weight3D3 << _forbidden << _repwt << _pwt << _limBottom << _limCharm << _limExotic << belowThreshold_ << _table; } void HadronSelector::persistentInput(PersistentIStream & is, int) { is >> _partons >> _etamix >> _phimix >> _h1mix >> _f0mix >> _f1mix >> _f2mix >> _eta2mix >> _omhmix >> _ph3mix >> _eta2Smix >> _phi2Smix >> _weight1S0 >> _weight3S1 >> _weight1P1 >> _weight3P0 >> _weight3P1 >> _weight3P2 >> _weight1D2 >> _weight3D1 >> _weight3D2 >> _weight3D3 >> _forbidden >> _repwt >> _pwt >> _limBottom >> _limCharm >> _limExotic >> belowThreshold_ >> _table; } void HadronSelector::Init() { static ClassDocumentation<HadronSelector> documentation ("There is no documentation for the HadronSelector class"); static RefVector<HadronSelector,ParticleData> interfacePartons ("Partons", "The partons which are to be considered as the consistuents of the hadrons.", &HadronSelector::_partons, -1, false, false, true, false, false); static RefVector<HadronSelector,ParticleData> interfaceForbidden ("Forbidden", "The PDG codes of the particles which cannot be produced in the hadronization.", &HadronSelector::_forbidden, -1, false, false, true, false, false); // // mixing angles // // the ideal mixing angle const double idealAngleMix = atan( sqrt(0.5) ) * 180.0 / Constants::pi; static Parameter<HadronSelector,double> interface11S0Mixing ("11S0Mixing", "The mixing angle for the I=0 mesons from the 1 1S0 multiplet," " i.e. eta and etaprime.", &HadronSelector::_etamix, -23., -180., 180., false, false, Interface::limited); static Parameter<HadronSelector,double> interface13S1Mixing ("13S1Mixing", "The mixing angle for the I=0 mesons from the 1 3S1 multiplet," " i.e. phi and omega.", &HadronSelector::_phimix, +36., -180., 180., false, false, Interface::limited); static Parameter<HadronSelector,double> interface11P1Mixing ("11P1Mixing", "The mixing angle for the I=0 mesons from the 1 1P1 multiplet," " i.e. h_1' and h_1.", &HadronSelector::_h1mix, idealAngleMix, -180., 180., false, false, Interface::limited); static Parameter<HadronSelector,double> interface13P0Mixing ("13P0Mixing", "The mixing angle for the I=0 mesons from the 1 3P0 multiplet," " i.e. f_0(1710) and f_0(1370).", &HadronSelector::_f0mix, idealAngleMix, -180., 180., false, false, Interface::limited); static Parameter<HadronSelector,double> interface13P1Mixing ("13P1Mixing", "The mixing angle for the I=0 mesons from the 1 3P1 multiplet," " i.e. f_1(1420) and f_1(1285).", &HadronSelector::_f1mix, idealAngleMix, -180., 180., false, false, Interface::limited); static Parameter<HadronSelector,double> interface13P2Mixing ("13P2Mixing", "The mixing angle for the I=0 mesons from the 1 3P2 multiplet," " i.e. f'_2 and f_2.", &HadronSelector::_f2mix, 26.0, -180., 180., false, false, Interface::limited); static Parameter<HadronSelector,double> interface11D2Mixing ("11D2Mixing", "The mixing angle for the I=0 mesons from the 1 1D2 multiplet," " i.e. eta_2(1870) and eta_2(1645).", &HadronSelector::_eta2mix, idealAngleMix, -180., 180., false, false, Interface::limited); static Parameter<HadronSelector,double> interface13D0Mixing ("13D0Mixing", "The mixing angle for the I=0 mesons from the 1 3D0 multiplet," " i.e. eta_2(1870) phi(?) and omega(1650).", &HadronSelector::_omhmix, idealAngleMix, -180., 180., false, false, Interface::limited); static Parameter<HadronSelector,double> interface13D1Mixing ("13D1Mixing", "The mixing angle for the I=0 mesons from the 1 3D1 multiplet," " i.e. phi_3 and omega_3.", &HadronSelector::_ph3mix, 28.0, -180., 180., false, false, Interface::limited); static Parameter<HadronSelector,double> interface21S0Mixing ("21S0Mixing", "The mixing angle for the I=0 mesons from the 2 1S0 multiplet," " i.e. eta(1475) and eta(1295).", &HadronSelector::_eta2Smix, idealAngleMix, -180., 180., false, false, Interface::limited); static Parameter<HadronSelector,double> interface23S1Mixing ("23S1Mixing", "The mixing angle for the I=0 mesons from the 1 3S1 multiplet," " i.e. phi(1680) and omega(1420).", &HadronSelector::_phi2Smix, idealAngleMix, -180., 180., false, false, Interface::limited); // // the meson weights // static ParVector<HadronSelector,double> interface1S0Weights ("1S0Weights", "The weights for the 1S0 multiplets start with n=1.", &HadronSelector::_weight1S0, Nmax, 1.0, 0.0, 100.0, false, false, Interface::limited); static ParVector<HadronSelector,double> interface3S1Weights ("3S1Weights", "The weights for the 3S1 multiplets start with n=1.", &HadronSelector::_weight3S1, Nmax, 1.0, 0.0, 100.0, false, false, Interface::limited); static ParVector<HadronSelector,double> interface1P1Weights ("1P1Weights", "The weights for the 1P1 multiplets start with n=1.", &HadronSelector::_weight1P1, Nmax, 1.0, 0.0, 100.0, false, false, Interface::limited); static ParVector<HadronSelector,double> interface3P0Weights ("3P0Weights", "The weights for the 3P0 multiplets start with n=1.", &HadronSelector::_weight3P0, Nmax, 1.0, 0.0, 100.0, false, false, Interface::limited); static ParVector<HadronSelector,double> interface3P1Weights ("3P1Weights", "The weights for the 3P1 multiplets start with n=1.", &HadronSelector::_weight3P1, Nmax, 1.0, 0.0, 100.0, false, false, Interface::limited); static ParVector<HadronSelector,double> interface3P2Weights ("3P2Weights", "The weights for the 3P2 multiplets start with n=1.", &HadronSelector::_weight3P2, Nmax, 1.0, 0.0, 100.0, false, false, Interface::limited); static ParVector<HadronSelector,double> interface1D2Weights ("1D2Weights", "The weights for the 1D2 multiplets start with n=1.", &HadronSelector::_weight1D2, Nmax, 1.0, 0.0, 100.0, false, false, Interface::limited); static ParVector<HadronSelector,double> interface3D1Weights ("3D1Weights", "The weights for the 3D1 multiplets start with n=1.", &HadronSelector::_weight3D1, Nmax, 1.0, 0.0, 100.0, false, false, Interface::limited); static ParVector<HadronSelector,double> interface3D2Weights ("3D2Weights", "The weights for the 3D2 multiplets start with n=1.", &HadronSelector::_weight3D2, Nmax, 1.0, 0.0, 100.0, false, false, Interface::limited); static ParVector<HadronSelector,double> interface3D3Weights ("3D3Weights", "The weights for the 3D3 multiplets start with n=1.", &HadronSelector::_weight3D3, Nmax, 1.0, 0.0, 100.0, false, false, Interface::limited); static Switch<HadronSelector,unsigned int> interfaceTrial ("Trial", "A Debugging option to only produce certain types of hadrons", &HadronSelector::_trial, 0, false, false); static SwitchOption interfaceTrialAll (interfaceTrial, "All", "Produce all the hadrons", 0); static SwitchOption interfaceTrialPions (interfaceTrial, "Pions", "Only produce pions", 1); static SwitchOption interfaceTrialSpin2 (interfaceTrial, "Spin2", "Only mesons with spin less than or equal to two are produced", 2); static SwitchOption interfaceTrialSpin3 (interfaceTrial, "Spin3", "Only hadrons with spin less than or equal to three are produced", 3); static Parameter<HadronSelector,double> interfaceSingleHadronLimitBottom ("SingleHadronLimitBottom", "Threshold for one-hadron decay of b-cluster", &HadronSelector::_limBottom, 0, 0.0, 0.0, 100.0,false,false,false); static Parameter<HadronSelector,double> interfaceSingleHadronLimitCharm ("SingleHadronLimitCharm", "threshold for one-hadron decay of c-cluster", &HadronSelector::_limCharm, 0, 0.0, 0.0, 100.0,false,false,false); static Parameter<HadronSelector,double> interfaceSingleHadronLimitExotic ("SingleHadronLimitExotic", "threshold for one-hadron decay of exotic cluster", &HadronSelector::_limExotic, 0, 0.0, 0.0, 100.0,false,false,false); static Switch<HadronSelector,unsigned int> interfaceBelowThreshold ("BelowThreshold", "Option fo the selection of the hadrons if the cluster is below the pair threshold", &HadronSelector::belowThreshold_, 0, false, false); static SwitchOption interfaceBelowThresholdLightest (interfaceBelowThreshold, "Lightest", "Force cluster to decay to the lightest hadron with the appropriate flavours", 0); static SwitchOption interfaceBelowThresholdAll (interfaceBelowThreshold, "All", "Select from all the hadrons below the two hadron threshold according to their spin weights", 1); } double HadronSelector::mixingStateWeight(long id) const { switch(id) { case ParticleID::eta: return 0.5*probabilityMixing(_etamix ,1); case ParticleID::etaprime: return 0.5*probabilityMixing(_etamix ,2); case ParticleID::phi: return 0.5*probabilityMixing(_phimix ,1); case ParticleID::omega: return 0.5*probabilityMixing(_phimix ,2); case ParticleID::hprime_1: return 0.5*probabilityMixing(_h1mix ,1); case ParticleID::h_1: return 0.5*probabilityMixing(_h1mix ,2); case 10331: return 0.5*probabilityMixing(_f0mix ,1); case 10221: return 0.5*probabilityMixing(_f0mix ,2); case ParticleID::fprime_1: return 0.5*probabilityMixing(_f1mix ,1); case ParticleID::f_1: return 0.5*probabilityMixing(_f1mix ,2); case ParticleID::fprime_2: return 0.5*probabilityMixing(_f2mix ,1); case ParticleID::f_2: return 0.5*probabilityMixing(_f2mix ,2); case 10335: return 0.5*probabilityMixing(_eta2mix ,1); case 10225: return 0.5*probabilityMixing(_eta2mix ,2); // missing phi member of 13D1 should be here case 30223: return 0.5*probabilityMixing(_omhmix ,2); case 337: return 0.5*probabilityMixing(_ph3mix ,1); case 227: return 0.5*probabilityMixing(_ph3mix ,2); case 100331: return 0.5*probabilityMixing(_eta2mix ,1); case 100221: return 0.5*probabilityMixing(_eta2mix ,2); case 100333: return 0.5*probabilityMixing(_phi2Smix,1); case 100223: return 0.5*probabilityMixing(_phi2Smix,2); default: return 1./3.; } } void HadronSelector::doinit() { Interfaced::doinit(); // set the weights for the various excited mesons // set all to one to start with for (int l = 0; l < Lmax; ++l ) { for (int j = 0; j < Jmax; ++j) { for (int n = 0; n < Nmax; ++n) { _repwt[l][j][n] = 1.0; } } } // set the others from the relevant vectors for( int ix=0;ix<max(int(_weight1S0.size()),int(Nmax));++ix) _repwt[0][0][ix]=_weight1S0[ix]; for( int ix=0;ix<max(int(_weight3S1.size()),int(Nmax));++ix) _repwt[0][1][ix]=_weight3S1[ix]; for( int ix=0;ix<max(int(_weight1P1.size()),int(Nmax));++ix) _repwt[1][1][ix]=_weight1P1[ix]; for( int ix=0;ix<max(int(_weight3P0.size()),int(Nmax));++ix) _repwt[1][0][ix]=_weight3P0[ix]; for( int ix=0;ix<max(int(_weight3P1.size()),int(Nmax));++ix) _repwt[1][1][ix]=_weight3P1[ix]; for( int ix=0;ix<max(int(_weight3P2.size()),int(Nmax));++ix) _repwt[1][2][ix]=_weight3P2[ix]; for( int ix=0;ix<max(int(_weight1D2.size()),int(Nmax));++ix) _repwt[2][2][ix]=_weight1D2[ix]; for( int ix=0;ix<max(int(_weight3D1.size()),int(Nmax));++ix) _repwt[2][1][ix]=_weight3D1[ix]; for( int ix=0;ix<max(int(_weight3D2.size()),int(Nmax));++ix) _repwt[2][2][ix]=_weight3D2[ix]; for( int ix=0;ix<max(int(_weight3D3.size()),int(Nmax));++ix) _repwt[2][3][ix]=_weight3D3[ix]; // find the maximum map<long,double>::iterator pit = max_element(_pwt.begin(),_pwt.end(),weightIsLess); const double pmax = pit->second; for(pit=_pwt.begin(); pit!=_pwt.end(); ++pit) { pit->second/=pmax; } // construct the hadron tables constructHadronTable(); // for debugging if(Debug::level >= 10 ) dumpTable(table()); } void HadronSelector::insertToHadronTable(tPDPtr &particle, int flav1, int flav2) { // inserting a new Hadron in the hadron table. long pid = particle->id(); int pspin = particle->iSpin(); double maxdd(0.),maxss(0.),maxrest(0.); HadronInfo a(pid, particle,specialWeight(pid),particle->mass()); // set the weight to the number of spin states a.overallWeight = pspin; // identical light flavours if(flav1 == flav2 && flav1<=3) { // ddbar> uubar> admixture states if(flav1==1) { if(_topt != 0) a.overallWeight *= 0.5*a.swtef; _table[make_pair(1,1)].insert(a); _table[make_pair(2,2)].insert(a); if(_topt == 0 && a.overallWeight > maxdd) maxdd = a.overallWeight; } // load up ssbar> uubar> ddbar> admixture states else { a.wt = mixingStateWeight(pid); a.overallWeight *= a.wt; if(_topt != 0) a.overallWeight *= a.swtef; _table[make_pair(1,1)].insert(a); _table[make_pair(2,2)].insert(a); if(_topt == 0 && a.overallWeight > maxdd) maxdd = a.overallWeight; a.wt = (_topt != 0) ? 1.- 2.*a.wt : 1 - a.wt; if(a.wt > 0) { a.overallWeight = a.wt * a.swtef * pspin; _table[make_pair(3,3)].insert(a); if(_topt == 0 && a.overallWeight > maxss) maxss = a.overallWeight; } } } // spin-1/2 baryons else if(pspin==2) { // octet bit assert(DiquarkMatcher::Check(flav1)); long iq1 = flav1/1000; long iq2 = (flav1/100)%10; if(_topt != 0) a.overallWeight *= a.swtef; if(iq1==iq2) { assert(flav2!=iq1); // first the uu1 d type piece a.wt = 1./3.; a.overallWeight *= a.wt; _table[make_pair(flav1,flav2)].insert(a); _table[make_pair(flav2,flav1)].insert(a); if(_topt == 0 && a.overallWeight > maxrest) maxrest = a.overallWeight; // also need ud1 u type long f3 = CheckId::makeDiquarkID(iq1,flav2,3); a.overallWeight /= a.wt; a.wt = 1./6.; a.overallWeight *= a.wt; _table[make_pair(iq1,f3 )].insert(a); _table[make_pair(f3 ,iq1)].insert(a); if(_topt == 0 && a.overallWeight > maxrest) maxrest = a.overallWeight; // and ud0 u type f3 = CheckId::makeDiquarkID(iq1,flav2,1); a.overallWeight /= a.wt; a.wt = 0.5; a.overallWeight *= a.wt; _table[make_pair(iq1,f3 )].insert(a); _table[make_pair(f3 ,iq1)].insert(a); if(_topt == 0 && a.overallWeight > maxrest) maxrest = a.overallWeight; } else if(iq1==flav2) { // ud1 u type a.wt = 1./6.; a.overallWeight *= a.wt; _table[make_pair(flav1,flav2)].insert(a); _table[make_pair(flav2,flav1)].insert(a); if(_topt == 0 && a.overallWeight > maxrest) maxrest = a.overallWeight; // also need ud0 u type long f3 = CheckId::makeDiquarkID(iq1,iq2,1); a.overallWeight /= a.wt; a.wt = 0.5; a.overallWeight *= a.wt; _table[make_pair(f3 ,flav2)].insert(a); _table[make_pair(flav2 ,f3 )].insert(a); if(_topt == 0 && a.overallWeight > maxrest) maxrest = a.overallWeight; // and uu1 d type f3 = CheckId::makeDiquarkID(iq1,iq1,3); a.overallWeight /= a.wt; a.wt = 1./3.; a.overallWeight *= a.wt; _table[make_pair(f3 ,iq2)].insert(a); _table[make_pair(iq2, f3)].insert(a); if(_topt == 0 && a.overallWeight > maxrest) maxrest = a.overallWeight; } else if(iq2==flav2) assert(false); else { // determine if light quarks in spin 0 or spin 1 long it1 = (pid/100)%10; long it2 = (pid/10 )%10; // first perm double wgt0(1./4.),wgt1(1./12.); // only spin-0 if(it1<it2) { long f3 = CheckId::makeDiquarkID(iq1,iq2,1); a.wt = 1./3.; a.overallWeight *= a.wt; _table[make_pair(f3,flav2)].insert(a); _table[make_pair(flav2,f3)].insert(a); if(_topt == 0 && a.overallWeight > maxrest) maxrest = a.overallWeight; swap(wgt0,wgt1); } // only spin-1 else { a.wt = 1./3.; a.overallWeight *= a.wt; _table[make_pair(flav1,flav2)].insert(a); _table[make_pair(flav2,flav1)].insert(a); if(_topt == 0 && a.overallWeight > maxrest) maxrest = a.overallWeight; } // not sure here // spin 0 a.overallWeight /= a.wt; a.wt = wgt0; a.overallWeight *= a.wt; // second perm long f3 = CheckId::makeDiquarkID(iq1,flav2,1); _table[make_pair(iq2,f3)].insert(a); _table[make_pair(f3,iq2)].insert(a); if(_topt == 0 && a.overallWeight > maxrest) maxrest = a.overallWeight; // 3rd perm f3 = CheckId::makeDiquarkID(iq2,flav2,1); _table[make_pair(iq1,f3)].insert(a); _table[make_pair(f3,iq1)].insert(a); if(_topt == 0 && a.overallWeight > maxrest) maxrest = a.overallWeight; // spin 1 a.overallWeight /= a.wt; a.wt = wgt1; a.overallWeight *= a.wt; // second perm f3 = CheckId::makeDiquarkID(iq1,flav2,3); _table[make_pair(iq2,f3)].insert(a); _table[make_pair(f3,iq2)].insert(a); if(_topt == 0 && a.overallWeight > maxrest) maxrest = a.overallWeight; // 3rd perm f3 = CheckId::makeDiquarkID(iq2,flav2,3); _table[make_pair(iq1,f3)].insert(a); _table[make_pair(f3,iq1)].insert(a); if(_topt == 0 && a.overallWeight > maxrest) maxrest = a.overallWeight; } } // spin -3/2 baryons else if(pspin==4) { long iq1 = flav1/1000; long iq2 = (flav1/100)%10; if(_topt != 0) a.overallWeight *= a.swtef; // all the same if(iq1==iq2 && iq1==flav2) { a.wt = 1.; a.overallWeight *= a.wt; _table[make_pair(flav1,flav2)].insert(a); _table[make_pair(flav2,flav1)].insert(a); if(_topt == 0 && a.overallWeight > maxrest) maxrest = a.overallWeight; } else if(iq1==iq2) { // first option uu1 d a.wt = 1./3.; a.overallWeight *= a.wt; _table[make_pair(flav1,flav2)].insert(a); _table[make_pair(flav2,flav1)].insert(a); if(_topt == 0 && a.overallWeight > maxrest) maxrest = a.overallWeight; // also need ud1 u type long f3 = CheckId::makeDiquarkID(iq1,flav2,3); a.overallWeight /= a.wt; a.wt = 2./3.; a.overallWeight *= a.wt; _table[make_pair(iq1,f3 )].insert(a); _table[make_pair(f3 ,iq1)].insert(a); if(_topt == 0 && a.overallWeight > maxrest) maxrest = a.overallWeight; } else if(iq1==flav2) { // also need ud1 u type a.wt = 2./3.; a.overallWeight *= a.wt; _table[make_pair(flav1,flav2)].insert(a); _table[make_pair(flav2,flav1)].insert(a); if(_topt == 0 && a.overallWeight > maxrest) maxrest = a.overallWeight; // and uu1 d type long f3 = CheckId::makeDiquarkID(iq1,iq1,3); a.overallWeight /= a.wt; a.wt = 1./3.; a.overallWeight *= a.wt; _table[make_pair(iq2,f3)].insert(a); _table[make_pair(f3,iq2)].insert(a); if(_topt == 0 && a.overallWeight > maxrest) maxrest = a.overallWeight; } else if(iq2==flav2) assert(false); else { // just need the three different combinations // first perm a.wt = 1./3.; a.overallWeight *= a.wt; _table[make_pair(flav1,flav2)].insert(a); _table[make_pair(flav2,flav1)].insert(a); if(_topt == 0 && a.overallWeight > maxrest) maxrest = a.overallWeight; // 2nd perm long f3 = CheckId::makeDiquarkID(iq1,flav2,3); _table[make_pair(iq2,f3)].insert(a); _table[make_pair(f3,iq2)].insert(a); if(_topt == 0 && a.overallWeight > maxrest) maxrest = a.overallWeight; // 3rd perm f3 = CheckId::makeDiquarkID(iq2,flav2,3); _table[make_pair(iq1,f3)].insert(a); _table[make_pair(f3,iq1)].insert(a); if(_topt == 0 && a.overallWeight > maxrest) maxrest = a.overallWeight; } } // all other cases else { if(_topt != 0) a.overallWeight *=a.swtef; _table[make_pair(flav1,flav2)].insert(a); if(flav1 != flav2) _table[make_pair(flav2,flav1)].insert(a); if(_topt == 0 && a.overallWeight > maxrest) maxrest = a.overallWeight; } // normalise weights to one for first option if(_topt == 0) { HadronTable::const_iterator tit; KupcoData::iterator it; for(tit=_table.begin();tit!=_table.end();++tit) { double weight; if(tit->first.first==tit->first.second) { if(tit->first.first==1||tit->first.first==2) weight=1./maxdd; else if (tit->first.first==3) weight=1./maxss; else weight=1./maxrest; } else weight=1./maxrest; for(it = tit->second.begin(); it!=tit->second.end(); ++it) { it->rescale(weight); } } } } void HadronSelector::constructHadronTable() { // initialise the table _table.clear(); for(unsigned int ix=0; ix<_partons.size(); ++ix) { for(unsigned int iy=0; iy<_partons.size(); ++iy) { if (!(DiquarkMatcher::Check(_partons[ix]->id()) && DiquarkMatcher::Check(_partons[iy]->id()))) _table[make_pair(_partons[ix]->id(),_partons[iy]->id())] = KupcoData(); } } // get the particles from the event generator ParticleMap particles = generator()->particles(); // loop over the particles for(ParticleMap::iterator it=particles.begin(); it!=particles.end(); ++it) { long pid = it->first; tPDPtr particle = it->second; int pspin = particle->iSpin(); // Don't include hadrons which are explicitly forbidden if(find(_forbidden.begin(),_forbidden.end(),particle)!=_forbidden.end()) continue; // Don't include non-hadrons or antiparticles if(pid < 100) continue; // remove diffractive particles if(pspin == 0) continue; // K_0S and K_0L not made make K0 and Kbar0 if(pid==ParticleID::K_S0||pid==ParticleID::K_L0) continue; // Debugging options // Only include those with 2J+1 less than...5 if(_trial==2 && pspin >= 5) continue; // Only include those with 2J+1 less than...7 if(_trial==3 && pspin >= 7) continue; // Only include pions if(_trial==1 && pid!=111 && pid!=211) continue; // shouldn't be coloured if(particle->coloured()) continue; // Get the flavours const int x4 = (pid/1000)%10; const int x3 = (pid/100 )%10; const int x2 = (pid/10 )%10; const int x7 = (pid/1000000)%10; const bool wantSusy = x7 == 1 || x7 == 2; // Skip non-hadrons (susy particles, etc...) if(x3 == 0 || x2 == 0) continue; int flav1,flav2; // meson if(x4 == 0) { flav1 = x2; flav2 = x3; if (wantSusy) flav2 += 1000000 * x7; } // baryon else { flav2 = x4; if (wantSusy) flav2 += 1000000 * x7; // insert the spin 1 diquark, sort out the rest later flav1 = CheckId::makeDiquarkID(x2,x3,3); } insertToHadronTable(particle,flav1,flav2); } } double HadronSelector::mesonWeight(long id) const { // Total angular momentum int j = ((id % 10) - 1) / 2; // related to Orbital angular momentum l int nl = (id/10000 )%10; int l = -999; int n = (id/100000)%10; // Radial excitation if(j == 0) l = nl; else if(nl == 0) l = j - 1; else if(nl == 1 || nl == 2) l = j; else if(nl == 3) l = j + 1; // Angular or Radial excited meson if((l||j||n) && l>=0 && l<Lmax && j<Jmax && n<Nmax) { return sqr(_repwt[l][j][n]); } // rest is not excited or // has spin >= 5/2 (ispin >= 6), haven't got those else return 1.0; } int HadronSelector::signHadron(tcPDPtr idQ1, tcPDPtr idQ2, tcPDPtr hadron) const { // This method receives in input three PDG ids, whose the // first two have proper signs (corresponding to particles, id > 0, // or antiparticles, id < 0 ), whereas the third one must // be always positive (particle not antiparticle), // corresponding to: // --- quark-antiquark, or antiquark-quark, or // quark-diquark, or diquark-quark, or // antiquark-antidiquark, or antidiquark-antiquark // for the first two input (idQ1, idQ2); // --- meson or baryon for the third input (idHad): // The method returns: // --- + 1 if the two partons (idQ1, idQ2) are exactly // the constituents for the hadron idHad; // --- - 1 if the two partons (idQ1, idQ2) are exactly // the constituents for the anti-hadron -idHad; // --- + 0 otherwise. // The method it is therefore useful to decide the // sign of the id of the produced hadron as appeared // in the vector _vecHad (where only hadron idHad > 0 are present) // given the two constituent partons. int sign = 0; long idHad = hadron->id(); assert(idHad > 0); int chargeIn = idQ1->iCharge() + idQ2->iCharge(); int chargeOut = hadron->iCharge(); // same charge if( chargeIn == chargeOut && chargeIn !=0 ) sign = +1; else if(chargeIn == -chargeOut && chargeIn !=0 ) sign = -1; else if(chargeIn == 0 && chargeOut == 0 ) { // In the case of same null charge, there are four cases: // i) K0-like mesons, B0-like mesons, Bs-like mesons // the PDG convention is to consider them "antiparticle" (idHad < 0) // if the "dominant" (heavier) flavour (respectively, s, b) // is a quark (idQ > 0): for instance, B0s = (b, sbar) has id < 0 // Remember that there is an important exception for K0L (id=130) and // K0S (id=310): they don't have antiparticles, therefore idHad > 0 // always. We use below the fact that K0L and K0S are the unique // hadrons having 0 the first (less significant) digit of their id. // 2) D0-like mesons: the PDG convention is to consider them "particle" // (idHad > 0) if the charm flavour is carried by a c: (c,ubar) has id>0 // 3) the remaining mesons should not have antiparticle, therefore their // sign is always positive. // 4) for baryons, that is when one of idQ1 and idQ2 is a (anti-) quark and // the other one is a (anti-) diquark the sign is negative when both // constituents are "anti", that is both with id < 0; positive otherwise. // meson if(abs(int(idQ1->iColour()))== 3 && abs(int(idQ2->iColour())) == 3 && !DiquarkMatcher::Check(idQ1->id()) && !DiquarkMatcher::Check(idQ2->id())) { int idQa = abs(idQ1->id()); int idQb = abs(idQ2->id()); int dominant = idQ2->id(); if(idQa > idQb) { swap(idQa,idQb); dominant = idQ1->id(); } if((idQa==ParticleID::d && idQb==ParticleID::s) || (idQa==ParticleID::d && idQb==ParticleID::b) || (idQa==ParticleID::s && idQb==ParticleID::b)) { // idHad%10 is zero for K0L,K0S if (dominant < 0 || idHad%10 == 0) sign = +1; else if(dominant > 0) sign = -1; } else if((idQa==ParticleID::u && idQb==ParticleID::c) || (idQa==ParticleID::u && idQb==ParticleID::t) || (idQa==ParticleID::c && idQb==ParticleID::t)) { if (dominant > 0) sign = +1; else if(dominant < 0) sign = -1; } else if(idQa==idQb) sign = +1; // sets sign for Susy particles else sign = (dominant > 0) ? +1 : -1; } // baryon else if(DiquarkMatcher::Check(idQ1->id()) || DiquarkMatcher::Check(idQ2->id())) { if (idQ1->id() > 0 && idQ2->id() > 0) sign = +1; else if(idQ1->id() < 0 && idQ2->id() < 0) sign = -1; } } if (sign == 0) { cerr << "Could not work out sign for " << idQ1->PDGName() << ' ' << idQ2->PDGName() << " => " << hadron->PDGName() << '\n'; assert(false); } return sign; } pair<tcPDPtr,tcPDPtr> HadronSelector::lightestHadronPair(tcPDPtr ptr1, tcPDPtr ptr2, tcPDPtr ptr3) const { // throw exception of id3!=0 as doesn't work if ( ptr3 ) throw Exception() << "ptr3!=0 not yet implemented in HadronSelector::lightestHadronPair" << Exception::abortnow; // charge int totalcharge = ptr1->iCharge() + ptr2->iCharge(); if ( ptr3 ) totalcharge += ptr3->iCharge(); tcPDPtr vIdHad1[2]={tcPDPtr(),tcPDPtr()},vIdHad2[2]={tcPDPtr(),tcPDPtr()}; bool vOk[2] = {false, false}; Energy vMassPair[2] = { ZERO, ZERO }; for (int i = 0; i < 2; i++) { tcPDPtr idPartner = i==0 ? getParticleData(ParticleID::d) : getParticleData(ParticleID::u); // Change sign to idPartner (transform it into a anti-quark) if it is not // possible to form a meson or a baryon. assert (ptr1 && idPartner); if (!CheckId::canBeHadron(ptr1, idPartner)) idPartner = idPartner->CC(); vIdHad1[i] = lightestHadron(ptr1, idPartner); vIdHad2[i] = lightestHadron(ptr2, idPartner->CC()); if ( vIdHad1[i] && vIdHad2[i] && vIdHad1[i]->iCharge() + vIdHad2[i]->iCharge() == totalcharge ) { vOk[i] = true; vMassPair[i] = vIdHad1[i]->mass() + vIdHad2[i]->mass(); } } // Take the lightest pair compatible with charge conservation. if ( vOk[0] && ( ! vOk[1] || vMassPair[0] <= vMassPair[1] ) ) { return make_pair(vIdHad1[0],vIdHad2[0]); } else if ( vOk[1] && ( ! vOk[0] || vMassPair[1] < vMassPair[0] ) ) { return make_pair(vIdHad1[1],vIdHad2[1]); } else { return make_pair(tcPDPtr(),tcPDPtr()); } } Energy HadronSelector::massLightestBaryonPair(tcPDPtr ptr1, tcPDPtr ptr2) const { // Make sure that we don't have any diquarks as input, return arbitrarily // large value if we do Energy currentSum = Constants::MaxEnergy; for(unsigned int ix=0; ix<_partons.size(); ++ix) { if(!DiquarkMatcher::Check(_partons[ix]->id())) continue; HadronTable::const_iterator tit1=_table.find(make_pair(abs(ptr1->id()),_partons[ix]->id())), tit2=_table.find(make_pair(_partons[ix]->id(),abs(ptr2->id()))); if( tit1==_table.end() || tit2==_table.end()) continue; if(tit1->second.empty()||tit2->second.empty()) continue; Energy s = tit1->second.begin()->mass + tit2->second.begin()->mass; if(currentSum > s) currentSum = s; } return currentSum; } tcPDPtr HadronSelector::lightestHadron(tcPDPtr ptr1, tcPDPtr ptr2, #ifndef NDEBUG tcPDPtr ptr3) const { #else tcPDPtr ) const { #endif // The method assumes ptr3 == 0 rest not implemented assert(ptr1 && ptr2 && !ptr3); // find entry in the table pair<long,long> ids = make_pair(abs(ptr1->id()),abs(ptr2->id())); HadronTable::const_iterator tit=_table.find(ids); // throw exception if flavours wrong if (tit==_table.end()) throw Exception() << "Could not find " << ids.first << ' ' << ids.second << " in _table. " << "In HadronSelector::lightestHadron()" << Exception::eventerror; if(tit->second.empty()) throw Exception() << "HadronSelector::lightestHadron " << "could not find any hadrons containing " << ptr1->id() << ' ' << ptr2->id() << '\n' << tit->first.first << ' ' << tit->first.second << Exception::eventerror; // find the lightest hadron int sign = signHadron(ptr1,ptr2,tit->second.begin()->ptrData); tcPDPtr candidate = sign > 0 ? tit->second.begin()->ptrData : tit->second.begin()->ptrData->CC(); // \todo 20 GeV limit is temporary fudge to let SM particles go through. // \todo Use isExotic instead? if (candidate->mass() > 20*GeV && candidate->mass() < ptr1->constituentMass() + ptr2->constituentMass()) { generator()->log() << "HadronSelector::lightestHadron: " << "chosen candidate " << candidate->PDGName() << " is lighter than its constituents " << ptr1->PDGName() << ", " << ptr2->PDGName() << '\n' << candidate->mass()/GeV << " < " << ptr1->constituentMass()/GeV << " + " << ptr2->constituentMass()/GeV << '\n' << "Check your particle data tables.\n"; assert(false); } return candidate; } vector<pair<tcPDPtr,double> > HadronSelector::hadronsBelowThreshold(Energy threshold, tcPDPtr ptr1, tcPDPtr ptr2, #ifndef NDEBUG tcPDPtr ptr3) const { #else tcPDPtr ) const { #endif // The method assumes ptr3 == 0 rest not implemented assert(ptr1 && ptr2 && !ptr3); // find entry in the table pair<long,long> ids = make_pair(abs(ptr1->id()),abs(ptr2->id())); HadronTable::const_iterator tit=_table.find(ids); // throw exception if flavours wrong if (tit==_table.end()) throw Exception() << "Could not find " << ids.first << ' ' << ids.second << " in _table. " << "In HadronSelector::hadronsBelowThreshold()" << Exception::eventerror; if(tit->second.empty()) throw Exception() << "HadronSelector::hadronsBelowThreshold() " << "could not find any hadrons containing " << ptr1->id() << ' ' << ptr2->id() << '\n' << tit->first.first << ' ' << tit->first.second << Exception::eventerror; vector<pair<tcPDPtr,double> > candidates; KupcoData::const_iterator hit = tit->second.begin(); // find the hadrons while(hit!=tit->second.end()&&hit->mass<threshold) { // find the hadron int sign = signHadron(ptr1,ptr2,hit->ptrData); tcPDPtr candidate = sign > 0 ? hit->ptrData : hit->ptrData->CC(); // \todo 20 GeV limit is temporary fudge to let SM particles go through. // \todo Use isExotic instead? if (candidate->mass() > 20*GeV && candidate->mass() < ptr1->constituentMass() + ptr2->constituentMass()) { generator()->log() << "HadronSelector::hadronsBelowTheshold: " << "chosen candidate " << candidate->PDGName() << " is lighter than its constituents " << ptr1->PDGName() << ", " << ptr2->PDGName() << '\n' << candidate->mass()/GeV << " < " << ptr1->constituentMass()/GeV << " + " << ptr2->constituentMass()/GeV << '\n' << "Check your particle data tables.\n"; assert(false); } candidates.push_back(make_pair(candidate,hit->overallWeight)); ++hit; } return candidates; } tcPDPtr HadronSelector::chooseSingleHadron(tcPDPtr par1, tcPDPtr par2, Energy mass) const { // Determine the sum of the nominal masses of the two lightest hadrons // with the right flavour numbers as the cluster under consideration. // Notice that we don't need real masses (drawn by a Breit-Wigner // distribution) because the lightest pair of hadrons does not involve // any broad resonance. Energy threshold = massLightestHadronPair(par1,par2); // Special: it allows one-hadron decays also above threshold. if (CheckId::isExotic(par1,par2)) threshold *= (1.0 + UseRandom::rnd()*_limExotic); else if (CheckId::hasBottom(par1,par2)) threshold *= (1.0 + UseRandom::rnd()*_limBottom); else if (CheckId::hasCharm(par1,par2)) threshold *= (1.0 + UseRandom::rnd()*_limCharm); // only do one hadron decay is mass less than the threshold if(mass>=threshold) return tcPDPtr(); // select the hadron tcPDPtr hadron; // old option pick the lightest hadron if(belowThreshold_ == 0) { hadron= lightestHadron(par1,par2); } // new option select from those available else if(belowThreshold_ == 1) { vector<pair<tcPDPtr,double> > hadrons = hadronsBelowThreshold(threshold,par1,par2); if(hadrons.size()==1) { hadron = hadrons[0].first; } else if(hadrons.empty()) { hadron= lightestHadron(par1,par2); } else { double totalWeight=0.; for(unsigned int ix=0;ix<hadrons.size();++ix) { totalWeight += hadrons[ix].second; } totalWeight *= UseRandom::rnd(); for(unsigned int ix=0;ix<hadrons.size();++ix) { if(totalWeight<=hadrons[ix].second) { hadron = hadrons[ix].first; break; } else totalWeight -= hadrons[ix].second; } assert(hadron); } } else assert(false); return hadron; } + +pair<tcPDPtr,tcPDPtr> HadronSelector::chooseHadronPair(const Energy cluMass, + tcPDPtr par1, tcPDPtr par2) const { + useMe(); + // if either of the input partons is a diquark don't allow diquarks to be + // produced + bool diquark = !(DiquarkMatcher::Check(par1->id()) || DiquarkMatcher::Check(par2->id())); + bool quark = true; + // decide is baryon or meson production + if(diquark) std::tie(quark,diquark) = selectBaryon(cluMass,par1,par2); + // weights for the different possibilities + Energy weight, wgtsum(ZERO); + // loop over all hadron pairs with the allowed flavours + static vector<Kupco> hadrons; + hadrons.clear(); + for(unsigned int ix=0;ix<partons().size();++ix) { + tcPDPtr quarktopick = partons()[ix]; + if(!quark && abs(int(quarktopick->iColour())) == 3 + && !DiquarkMatcher::Check(quarktopick->id())) continue; + if(!diquark && abs(int(quarktopick->iColour())) == 3 + && DiquarkMatcher::Check(quarktopick->id())) continue; + HadronTable::const_iterator + tit1 = table().find(make_pair(abs(par1->id()),quarktopick->id())); + HadronTable::const_iterator + tit2 = table().find(make_pair(quarktopick->id(),abs(par2->id()))); + // If not in table skip + if(tit1 == table().end()||tit2==table().end()) continue; + // tables empty skip + const KupcoData & T1 = tit1->second; + const KupcoData & T2 = tit2->second; + if(T1.empty()||T2.empty()) continue; + // if too massive skip + if(cluMass <= T1.begin()->mass + + T2.begin()->mass) continue; + // quark weight + double quarkWeight = pwt(quarktopick->id()); + // special for strange + if(abs(quarktopick->id()) == 3) + quarkWeight = strangeWeight(cluMass,par1,par2); + // loop over the hadrons + KupcoData::const_iterator H1,H2; + for(H1 = T1.begin();H1 != T1.end(); ++H1) { + for(H2 = T2.begin();H2 != T2.end(); ++H2) { + // break if cluster too light + if(cluMass < H1->mass + H2->mass) break; + weight = quarkWeight * H1->overallWeight * H2->overallWeight * + Kinematics::pstarTwoBodyDecay(cluMass, H1->mass, H2->mass); + int signQ = 0; + assert (par1 && quarktopick); + assert (par2); + + assert(quarktopick->CC()); + + if(CheckId::canBeHadron(par1, quarktopick->CC()) + && CheckId::canBeHadron(quarktopick, par2)) + signQ = +1; + else if(CheckId::canBeHadron(par1, quarktopick) + && CheckId::canBeHadron(quarktopick->CC(), par2)) + signQ = -1; + else { + cerr << "Could not make sign for" << par1->id()<< " " << quarktopick->id() + << " " << par2->id() << "\n"; + assert(false); + } + + if (signQ == -1) + quarktopick = quarktopick->CC(); + // construct the object with the info + Kupco a(quarktopick, H1->ptrData, H2->ptrData, weight); + hadrons.push_back(a); + wgtsum += weight; + } + } + } + if (hadrons.empty()) + return make_pair(tcPDPtr(),tcPDPtr()); + // select the hadron + wgtsum *= UseRandom::rnd(); + unsigned int ix=0; + do { + wgtsum-= hadrons[ix].weight; + ++ix; + } + while(wgtsum > ZERO && ix < hadrons.size()); + if(ix == hadrons.size() && wgtsum > ZERO) + return make_pair(tcPDPtr(),tcPDPtr()); + --ix; + assert(hadrons[ix].idQ); + int signHad1 = signHadron(par1, hadrons[ix].idQ->CC(), hadrons[ix].hadron1); + int signHad2 = signHadron(par2, hadrons[ix].idQ, hadrons[ix].hadron2); + assert( signHad1 != 0 && signHad2 != 0 ); + return make_pair + ( signHad1 > 0 ? hadrons[ix].hadron1 : tcPDPtr(hadrons[ix].hadron1->CC()), + signHad2 > 0 ? hadrons[ix].hadron2 : tcPDPtr(hadrons[ix].hadron2->CC())); +} + +pair<bool,bool> HadronSelector::selectBaryon(const Energy, tcPDPtr, tcPDPtr ) const { + assert(false); +} + +double HadronSelector::strangeWeight(const Energy, tcPDPtr, tcPDPtr) const { + assert(false); +} diff --git a/Hadronization/HadronSelector.h b/Hadronization/HadronSelector.h --- a/Hadronization/HadronSelector.h +++ b/Hadronization/HadronSelector.h @@ -1,592 +1,603 @@ // -*- C++ -*- // // HadronSelector.h is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2019 The Herwig Collaboration // // Herwig is licenced under version 3 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // #ifndef HERWIG_HadronSelector_H #define HERWIG_HadronSelector_H // // This is the declaration of the HadronSelector class. // #include "ThePEG/Interface/Interfaced.h" #include <ThePEG/Persistency/PersistentOStream.h> #include <ThePEG/Persistency/PersistentIStream.h> #include <ThePEG/PDT/ParticleData.h> #include <ThePEG/PDT/StandardMatchers.h> #include <ThePEG/Repository/EventGenerator.h> #include "HadronSelector.fh" #include "HadronInfo.h" #include "Kupco.h" namespace Herwig { using namespace ThePEG; /**\ingroup Hadronization * \class HadronSelector * \brief This class selects the hadron flavours of a cluster decay. * \author Philip Stephens * \author Alberto Ribon * \author Peter Richardson * * This is the base class for the selection of either a pair of hadrons, or * in some cases a single hadron. The different approaches which were * previously implemented in this class are now implemented in the * HwppSelector and Hw64Selector which inherit from this class. * * This class implements a number of methods which are needed by all models * and in addition contains the weights for the different meson multiplets and * mixing of the light \f$I=0\f$ mesons. * * @see \ref HadronSelectorInterfaces "The interfaces" * defined for HadronSelector. * @see HwppSelector * @see Hw64Selector */ class HadronSelector: public Interfaced { public: /** * The default constructor. */ HadronSelector(unsigned int); /** * Method to return a pair of hadrons given the PDG codes of * two or three constituents * @param cluMass The mass of the cluster * @param par1 The first constituent * @param par2 The second constituent * @param par3 The third constituent */ - virtual pair<tcPDPtr,tcPDPtr> chooseHadronPair(const Energy cluMass, tcPDPtr par1, - tcPDPtr par2,tcPDPtr par3 = PDPtr()) const = 0; + virtual pair<tcPDPtr,tcPDPtr> chooseHadronPair(const Energy cluMass, + tcPDPtr par1, tcPDPtr par2) const; /** * Select the single hadron for a cluster decay * return null pointer if not a single hadron decay * @param par1 1st constituent * @param par2 2nd constituent * @param mass Mass of the cluster */ tcPDPtr chooseSingleHadron(tcPDPtr par1, tcPDPtr par2, Energy mass) const; /** * This returns the lightest pair of hadrons given by the flavours. * * Given the two (or three) constituents of a cluster, it returns * the two lightest hadrons with proper flavour numbers. * Furthermore, the first of the two hadrons must have the constituent with * par1, and the second must have the constituent with par2. * \todo At the moment it does *nothing* in the case that also par3 is present. * * The method is implemented by calling twice lightestHadron, * once with (par1,quarktopick->CC()) ,and once with (par2,quarktopick) * where quarktopick is either the pointer to * d or u quarks . In fact, the idea is that whatever the flavour of par1 * and par2, no matter if (anti-)quark or (anti-)diquark, the lightest * pair of hadrons containing flavour par1 and par2 will have either * flavour d or u, being the lightest quarks. * The method returns the pair (PDPtr(),PDPtr()) if anything goes wrong. * * \todo The method assumes par3 == PDPtr() (otherwise we don't know how to proceed: a * possible, trivial way would be to randomly select two of the three * (anti-)quarks and treat them as a (anti-)diquark, reducing the problem * to two components as treated below. * In the normal (two components) situation, the strategy is the following: * treat in the same way the two possibilities: (d dbar) (i=0) and * (u ubar) (i=1) as the pair quark-antiquark necessary to form a * pair of hadrons containing the input flavour par1 and par2; finally, * select the one that produces the lightest pair of hadrons, compatible * with the charge conservation constraint. */ pair<tcPDPtr,tcPDPtr> lightestHadronPair(tcPDPtr ptr1, tcPDPtr ptr2, tcPDPtr ptr3 = PDPtr ()) const; /** * Returns the mass of the lightest pair of hadrons with the given particles * @param ptr1 is the first constituent * @param ptr2 is the second constituent * @param ptr3 is the third constituent */ Energy massLightestHadronPair(tcPDPtr ptr1, tcPDPtr ptr2, tcPDPtr ptr3 = PDPtr ()) const { pair<tcPDPtr,tcPDPtr> pairData = lightestHadronPair(ptr1, ptr2, ptr3); if ( ! pairData.first || ! pairData.second ) return ZERO; return ( pairData.first->mass() + pairData.second->mass() ); } /** * Returns the lightest hadron formed by the given particles. * * Given the id of two (or three) constituents of a cluster, it returns * the lightest hadron with proper flavour numbers. * At the moment it does *nothing* in the case that also 'ptr3' present. * @param ptr1 is the first constituent * @param ptr2 is the second constituent * @param ptr3 is the third constituent */ tcPDPtr lightestHadron(tcPDPtr ptr1, tcPDPtr ptr2, tcPDPtr ptr3 = PDPtr ()) const; /** * Returns the hadrons below the constituent mass threshold formed by the given particles, * together with their total weight * * Given the id of two (or three) constituents of a cluster, it returns * the lightest hadron with proper flavour numbers. * At the moment it does *nothing* in the case that also 'ptr3' present. * @param threshold The theshold * @param ptr1 is the first constituent * @param ptr2 is the second constituent * @param ptr3 is the third constituent */ vector<pair<tcPDPtr,double> > hadronsBelowThreshold(Energy threshold, tcPDPtr ptr1, tcPDPtr ptr2, tcPDPtr ptr3 = PDPtr ()) const; /** * Return the nominal mass of the hadron returned by lightestHadron() * @param ptr1 is the first constituent * @param ptr2 is the second constituent * @param ptr3 is the third constituent */ Energy massLightestHadron(tcPDPtr ptr1, tcPDPtr ptr2, #ifndef NDEBUG tcPDPtr ptr3 = PDPtr ()) const { #else tcPDPtr = PDPtr ()) const { #endif // The method assumes ptr3 == empty assert(!(ptr3)); // find entry in the table pair<long,long> ids(abs(ptr1->id()),abs(ptr2->id())); HadronTable::const_iterator tit=_table.find(ids); // throw exception if flavours wrong if(tit==_table.end()||tit->second.empty()) throw Exception() << "HadronSelector::massLightestHadron " << "failed for particle" << ptr1->id() << " " << ptr2->id() << Exception::eventerror; // return the mass return tit->second.begin()->mass; } /** * Returns the mass of the lightest pair of baryons. * @param ptr1 is the first constituent * @param ptr2 is the second constituent */ Energy massLightestBaryonPair(tcPDPtr ptr1, tcPDPtr ptr2) const; /** * Access the parton weights */ double pwt(long pid) const { map<long,double>::const_iterator it = _pwt.find(abs(pid)); assert( it != _pwt.end() ); return it->second; } + /** + * Force baryon/meson selection + */ + virtual pair<bool,bool> selectBaryon(const Energy cluMass, tcPDPtr par1, tcPDPtr par2) const; + + /** + * Strange quark weight + */ + virtual double strangeWeight(const Energy cluMass, tcPDPtr par1, tcPDPtr par2) const; + + public: /** @name Functions used by the persistent I/O system. */ //@{ /** * Function used to write out object persistently. * @param os the persistent output stream written to. */ void persistentOutput(PersistentOStream & os) const; /** * Function used to read in object persistently. * @param is the persistent input stream read from. * @param version the version number of the object when written. */ void persistentInput(PersistentIStream & is, int version); //@} /** * The standard Init function used to initialize the interfaces. * Called exactly once for each class by the class description system * before the main function starts or * when this class is dynamically loaded. */ static void Init(); protected: /** @name Standard Interfaced functions. */ //@{ /** * Initialize this object after the setup phase before saving an * EventGenerator to disk. * * The array _repwt is initialized using the interfaces to set different * weights for different meson multiplets and the constructHadronTable() * method called to complete the construction of the hadron tables. * * @throws InitException if object could not be initialized properly. */ virtual void doinit(); //@} protected: /** * A sub-function of HadronSelector::constructHadronTable(). * It receives the information of a prospective Hadron and inserts it * into the hadron table construct. * @param particle is a particle data pointer to the hadron * @param flav1 is the first constituent of the hadron * @param flav2 is the second constituent of the hadron */ void insertToHadronTable(tPDPtr &particle, int flav1, int flav2); /** * Construct the table of hadron data * This is the main method to initialize the hadron data (mainly the * weights associated to each hadron, taking into account its spin, * eventual isoscalar-octect mixing, singlet-decuplet factor). This is * the method that one should update when new or updated hadron data is * available. * * This class implements the construction of the basic table but can be * overridden if needed in inheriting classes. * * The rationale for factors used for diquarks involving different quarks can * be can be explained by taking a prototype example that in the exact SU(2) limit, * in which: * \f[m_u=m_d\f] * \f[M_p=M_n=M_\Delta\f] * and we will have equal numbers of u and d quarks produced. * Suppose that we weight 1 the diquarks made of the same * quark and 1/2 those made of different quarks, the fractions * of u and d baryons (p, n, Delta) we get are the following: * - \f$\Delta^{++}\f$: 1 possibility only u uu with weight 1 * - \f$\Delta^- \f$: 1 possibility only d dd with weight 1 * - \f$p,\Delta^+ \f$: 2 possibilities u ud with weight 1/2 * d uu with weight 1 * - \f$n,\Delta^0 \f$: 2 possibilities d ud with weight 1/2 * u dd with weight 1 * In the latter two cases, we have to take into account the * fact that p and n have spin 1/2 whereas Delta+ and Delta0 * have spin 3/2 therefore from phase space we get a double weight * for Delta+ and Delta0 relative to p and n respectively. * Therefore the relative amount of these baryons that is * produced is the following: * # p = # n = ( 1/2 + 1 ) * 1/3 = 1/2 * # Delta++ = # Delta- = 1 = ( 1/2 + 1) * 2/3 # Delta+ = # Delta0 * which is correct, and therefore the weight 1/2 for the * diquarks of different types of quarks is justified (at least * in this limit of exact SU(2) ). */ virtual void constructHadronTable(); /** * Access to the table of hadrons */ const HadronTable & table() const { return _table; } /** * Access to the list of partons */ const vector<PDPtr> & partons() const { return _partons; } /** * Access to the list of partons */ vector<PDPtr> & partons() { return _partons; } /** * Access the parton weights */ map<long,double> & pwt() { return _pwt; } /** * Methods for the mixing of \f$I=0\f$ mesons */ //@{ /** * Return the probability of mixing for Octet-Singlet isoscalar mixing, * the probability of the * \f$\frac1{\sqrt{2}}(|u\bar{u}\rangle + |d\bar{d}\rangle)\f$ component * is returned. * @param angleMix The mixing angle in degrees (not radians) * @param order is 0 for no mixing, 1 for the first resonance of a pair, * 2 for the second one. * The mixing is defined so that for example with \f$\eta-\eta'\f$ mixing where * the mixing angle is \f$\theta=-23^0$ with $\eta\f$ as the first particle * and \f$\eta'\f$ the second one. * The convention used is * \f[\eta = \cos\theta|\eta_{\rm octet }\rangle * -\sin\theta|\eta_{\rm singlet}\rangle\f] * \f[\eta' = \sin\theta|\eta_{\rm octet }\rangle * -\cos\theta|\eta_{\rm singlet}\rangle\f] * with * \f[|\eta_{\rm singlet}\rangle = \frac1{\sqrt{3}} * \left[|u\bar{u}\rangle + |d\bar{d}\rangle + |s\bar{s}\rangle\right]\f] * \f[|\eta_{\rm octet }\rangle = \frac1{\sqrt{6}} * \left[|u\bar{u}\rangle + |d\bar{d}\rangle - 2|s\bar{s}\rangle\right]\f] */ double probabilityMixing(const double angleMix, const int order) const { static double convert=Constants::pi/180.0; if (order == 1) return sqr( cos( angleMix*convert + atan( sqrt(2.0) ) ) ); else if (order == 2) return sqr( sin( angleMix*convert + atan( sqrt(2.0) ) ) ); else return 1.; } /** * Returns the weight of given mixing state. * @param id The PDG code of the meson */ virtual double mixingStateWeight(long id) const; //@} /** * Calculates a special weight specific to a given hadron. * @param id The PDG code of the hadron */ double specialWeight(long id) const { const int pspin = id % 10; // Only K0L and K0S have pspin == 0, should // not get them until Decay step assert( pspin != 0 ); // Baryon : J = 1/2 or 3/2 if(pspin%2==0) return baryonWeight(id); // Meson else return mesonWeight(id); } /** * Weights for mesons */ virtual double mesonWeight(long id) const; /** * Weights for baryons */ virtual double baryonWeight(long id) const = 0; /** * This method returns the proper sign ( > 0 hadron; < 0 anti-hadron ) * for the input PDG id idHad > 0, suppose to be made by the * two constituent particle pointers: par1 and par2 (both with proper sign). */ int signHadron(tcPDPtr ptr1, tcPDPtr ptr2, tcPDPtr hadron) const; private: /** * The assignment operator is private and must never be called. * In fact, it should not even be implemented. */ HadronSelector & operator=(const HadronSelector &) = delete; private: /** * The PDG codes of the constituent particles allowed */ vector<PDPtr> _partons; /** * The PDG codes of the hadrons which cannot be produced in the hadronization */ vector<PDPtr> _forbidden; /** * Weights for quarks and diquarks. */ map<long,double> _pwt; /** * The mixing angles for the \f$I=0\f$ mesons containing light quarks */ //@{ /** * The \f$\eta-\eta'\f$ mixing angle */ double _etamix; /** * The \f$\phi-\omega\f$ mixing angle */ double _phimix; /** * The \f$h_1'-h_1\f$ mixing angle */ double _h1mix; /** * The \f$f_0(1710)-f_0(1370)\f$ mixing angle */ double _f0mix; /** * The \f$f_1(1420)-f_1(1285)\f$ mixing angle */ double _f1mix; /** * The \f$f'_2-f_2\f$ mixing angle */ double _f2mix; /** * The \f$\eta_2(1870)-\eta_2(1645)\f$ mixing angle */ double _eta2mix; /** * The \f$\phi(???)-\omega(1650)\f$ mixing angle */ double _omhmix; /** * The \f$\phi_3-\omega_3\f$ mixing angle */ double _ph3mix; /** * The \f$\eta(1475)-\eta(1295)\f$ mixing angle */ double _eta2Smix; /** * The \f$\phi(1680)-\omega(1420)\f$ mixing angle */ double _phi2Smix; //@} /** * The weights for the various meson multiplets to be used to supress the * production of particular states */ //@{ /** * The weights for the \f$\phantom{1}^1S_0\f$ multiplets */ vector<double> _weight1S0; /** * The weights for the \f$\phantom{1}^3S_1\f$ multiplets */ vector<double> _weight3S1; /** * The weights for the \f$\phantom{1}^1P_1\f$ multiplets */ vector<double> _weight1P1; /** * The weights for the \f$\phantom{1}^3P_0\f$ multiplets */ vector<double> _weight3P0; /** * The weights for the \f$\phantom{1}^3P_1\f$ multiplets */ vector<double> _weight3P1; /** * The weights for the \f$\phantom{1}^3P_2\f$ multiplets */ vector<double> _weight3P2; /** * The weights for the \f$\phantom{1}^1D_2\f$ multiplets */ vector<double> _weight1D2; /** * The weights for the \f$\phantom{1}^3D_1\f$ multiplets */ vector<double> _weight3D1; /** * The weights for the \f$\phantom{1}^3D_2\f$ multiplets */ vector<double> _weight3D2; /** * The weights for the \f$\phantom{1}^3D_3\f$ multiplets */ vector<double> _weight3D3; //@} /** * The weights for the excited meson multiplets */ vector<vector<vector<double> > > _repwt; /** * The table of hadron data */ HadronTable _table; /** * Enums so arrays can be statically allocated */ //@{ /** * Defines values for array sizes. L,J,N max values for excited mesons. */ enum MesonMultiplets { Lmax = 3, Jmax = 4, Nmax = 4}; //@} /** * Option for the construction of the tables */ unsigned int _topt; /** * Which particles to produce for debugging purposes */ unsigned int _trial; /** * @name A parameter used for determining when clusters are too light. * * This parameter is used for setting the lower threshold, \f$ t \f$ as * \f[ t' = t(1 + r B^1_{\rm lim}) \f] * where \f$ r \f$ is a random number [0,1]. */ //@{ double _limBottom; double _limCharm; double _limExotic; //@} /** * Option for the selection of hadrons below the pair threshold */ unsigned int belowThreshold_; }; } #endif /* HERWIG_HadronSelector_H */ diff --git a/Hadronization/Hw64Selector.cc b/Hadronization/Hw64Selector.cc --- a/Hadronization/Hw64Selector.cc +++ b/Hadronization/Hw64Selector.cc @@ -1,212 +1,212 @@ // -*- C++ -*- // // Hw64Selector.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 Hw64Selector class. // #include "Hw64Selector.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Interface/Parameter.h" #include "ThePEG/Repository/UseRandom.h" #include "CheckId.h" #include "Herwig/Utilities/Kinematics.h" #include <ThePEG/Utilities/DescribeClass.h> using namespace Herwig; DescribeClass<Hw64Selector,HadronSelector> describeHw64Selector("Herwig::Hw64Selector","Herwig.so"); IBPtr Hw64Selector::clone() const { return new_ptr(*this); } IBPtr Hw64Selector::fullclone() const { return new_ptr(*this); } void Hw64Selector::persistentOutput(PersistentOStream & os) const { os << _pwtDquark << _pwtUquark << _pwtSquark << _pwtCquark << _pwtBquark << _pwtDIquarkS0 << _pwtDIquarkS1 << _sngWt << _decWt ; } void Hw64Selector::persistentInput(PersistentIStream & is, int) { is >> _pwtDquark >> _pwtUquark >> _pwtSquark >> _pwtCquark >> _pwtBquark >> _pwtDIquarkS0 >> _pwtDIquarkS1 >> _sngWt >> _decWt ; } void Hw64Selector::doinit() { // the default partons allowed // the quarks for ( int ix=1; ix<=5; ++ix ) { partons().push_back(getParticleData(ix)); } // the diquarks for(unsigned int ix=1;ix<=5;++ix) { for(unsigned int iy=1; iy<=ix;++iy) { partons().push_back(getParticleData(CheckId::makeDiquarkID(ix,iy,long(3)))); if(ix!=iy) partons().push_back(getParticleData(CheckId::makeDiquarkID(ix,iy,long(1)))); } } // weights for the different quarks etc for(unsigned int ix=0; ix<partons().size(); ++ix) { pwt()[partons()[ix]->id()]=0.; } pwt()[1] = _pwtDquark; pwt()[2] = _pwtUquark; pwt()[3] = _pwtSquark; pwt()[4] = _pwtCquark; pwt()[5] = _pwtBquark; pwt()[1103] = _pwtDIquarkS1 * _pwtDquark * _pwtDquark; pwt()[2101] = _pwtDIquarkS0 * _pwtUquark * _pwtDquark; pwt()[2103] = _pwtDIquarkS1 * _pwtUquark * _pwtDquark; pwt()[2203] = _pwtDIquarkS1 * _pwtUquark * _pwtUquark; pwt()[3101] = _pwtDIquarkS0 * _pwtSquark * _pwtDquark; pwt()[3103] = _pwtDIquarkS1 * _pwtSquark * _pwtDquark; pwt()[3201] = _pwtDIquarkS0 * _pwtSquark * _pwtUquark; pwt()[3203] = _pwtDIquarkS1 * _pwtSquark * _pwtUquark; pwt()[3303] = _pwtDIquarkS1 * _pwtSquark * _pwtSquark; HadronSelector::doinit(); } void Hw64Selector::Init() { static ClassDocumentation<Hw64Selector> documentation ("The Hw64Selector class implements the hadron selection algorithm of Hw6"); static Parameter<Hw64Selector,double> interfacePwtDquark("PwtDquark","Weight for choosing a quark D", &Hw64Selector::_pwtDquark, 0, 1.0, 0.0, 10.0, false,false,false); static Parameter<Hw64Selector,double> interfacePwtUquark("PwtUquark","Weight for choosing a quark U", &Hw64Selector::_pwtUquark, 0, 1.0, 0.0, 10.0, false,false,false); static Parameter<Hw64Selector,double> interfacePwtSquark("PwtSquark","Weight for choosing a quark S", &Hw64Selector::_pwtSquark, 0, 1.0, 0.0, 10.0, false,false,false); static Parameter<Hw64Selector,double> interfacePwtCquark("PwtCquark","Weight for choosing a quark C", &Hw64Selector::_pwtCquark, 0, 0.0, 0.0, 10.0, false,false,false); static Parameter<Hw64Selector,double> interfacePwtBquark("PwtBquark","Weight for choosing a quark B", &Hw64Selector::_pwtBquark, 0, 0.0, 0.0, 10.0, false,false,false); static Parameter<Hw64Selector,double> interfacePwtDIquarkS0("PwtDIquarkS0","Weight for choosing a spin-0 DIquark", &Hw64Selector::_pwtDIquarkS0, 0, 1.0, 0.0, 100.0, false,false,false); static Parameter<Hw64Selector,double> interfacePwtDIquarkS1("PwtDIquarkS1","Weight for choosing a spin-1 DIquark", &Hw64Selector::_pwtDIquarkS1, 0, 1.0, 0.0, 100.0, false,false,false); static Parameter<Hw64Selector,double> interfaceSngWt("SngWt","Weight for singlet baryons", &Hw64Selector::_sngWt, 0, 1.0, 0.0, 10.0, false,false,false); static Parameter<Hw64Selector,double> interfaceDecWt("DecWt","Weight for decuplet baryons", &Hw64Selector::_decWt, 0, 1.0, 0.0, 10.0, false,false,false); } -pair<tcPDPtr,tcPDPtr> Hw64Selector::chooseHadronPair(const Energy cluMass,tcPDPtr par1, - tcPDPtr par2,tcPDPtr) const { +pair<tcPDPtr,tcPDPtr> Hw64Selector::chooseHadronPair(const Energy cluMass, + tcPDPtr par1, tcPDPtr par2) const { bool diquark = !(DiquarkMatcher::Check(par1->id()) || DiquarkMatcher::Check(par2->id())); pair<tcPDPtr,tcPDPtr> lighthad = lightestHadronPair(par1, par2); if(!lighthad.first || !lighthad.second) throw Exception() << "Hw64Selector::chooseHadronPair " << "We have 0's! First id = " << par1->id() << " second = " << par2->id() << ". This is probably a problem with either" << " undecayed heavy particles or colour connections" << Exception::eventerror; // calculate maximum momentum Energy PCMax = Kinematics::pstarTwoBodyDecay(cluMass,lighthad.first->mass(), lighthad.second->mass()); tcPDPtr had1 = tcPDPtr(); tcPDPtr had2 = tcPDPtr(); int ntry = 0; tcPDPtr quark = tcPDPtr(); const int nmax = 5000; Energy p; do { quark = partons()[UseRandom::irnd(partons().size())]; if(diquark && DiquarkMatcher::Check(quark->id())) continue; if(pwt(quark->id()) <= UseRandom::rnd()) continue; pair<long,long> pid(abs(par1->id()),quark->id()); KupcoData::const_iterator it1,it2; const HadronTable::const_iterator tit = table().find(pid); assert(tit != table().end()); const KupcoData & hdata = tit->second; do { it1 = hdata.begin(); advance(it1,int(hdata.size()*UseRandom::rnd())); } while(it1 != hdata.end() && it1->overallWeight < UseRandom::rnd()); had1 = it1->ptrData; pid = make_pair(quark->id(),abs(par2->id())); do { it2 = hdata.begin(); advance(it2,int(hdata.size()*UseRandom::rnd())); } while(it2 != hdata.end() && it2->overallWeight < UseRandom::rnd()); had2 = it2->ptrData; if(had1 && had2) { p = Kinematics::pstarTwoBodyDecay(cluMass, it1->mass, it2->mass); if(p/PCMax < UseRandom::rnd()) { had1 = had2 = tcPDPtr(); ntry++; } } } while((!had1|| !had2) && ntry < nmax); if(ntry >= nmax) return lighthad; int signHad1 = 0; int signHad2 = 0; if(CheckId::canBeHadron(par1,quark->CC()) && CheckId::canBeHadron(quark,par2)) { signHad1 = signHadron(par1, quark->CC(), had1); signHad2 = signHadron(par2, quark, had2); } else if(CheckId::canBeHadron(par1,quark) && CheckId::canBeHadron(quark->CC(),par2)) { signHad1 = signHadron(par1, quark, had1); signHad2 = signHadron(par2, quark->CC(), had2); } else throw Exception() << "Hw64Selector::chooseHadronPair()" << Exception::abortnow; return make_pair( signHad1 > 0 ? had1 : tcPDPtr(had1->CC()), signHad2 > 0 ? had2 : tcPDPtr(had2->CC())); } double Hw64Selector::baryonWeight(long id) const { const int pspin = id % 10; if(pspin == 2) { // Singlet (Lambda-like) baryon if( (id/100)%10 < (id/10 )%10 ) return sqr(_sngWt); } // Decuplet baryon else if (pspin == 4) return sqr(_decWt); return 1.; } diff --git a/Hadronization/Hw64Selector.h b/Hadronization/Hw64Selector.h --- a/Hadronization/Hw64Selector.h +++ b/Hadronization/Hw64Selector.h @@ -1,184 +1,184 @@ // -*- C++ -*- // // Hw64Selector.h is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2019 The Herwig Collaboration // // Herwig is licenced under version 3 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // #ifndef HERWIG_Hw64Selector_H #define HERWIG_Hw64Selector_H // // This is the declaration of the Hw64Selector class. // #include "HadronSelector.h" #include "Hw64Selector.fh" namespace Herwig { using namespace ThePEG; /** \ingroup hadronization * The Hw64Selector class selects the hadrons produced in cluster decay using * the FORTRAN HERWIG variant of the cluster model. * * @see \ref Hw64SelectorInterfaces "The interfaces" * defined for Hw64Selector. */ class Hw64Selector: public HadronSelector { public: /** * The default constructor. */ Hw64Selector() : HadronSelector(0), _pwtDquark( 1.0 ),_pwtUquark( 1.0 ),_pwtSquark( 1.0 ),_pwtCquark( 0.0 ), _pwtBquark( 0.0 ),_pwtDIquarkS0( 1.0 ),_pwtDIquarkS1( 1.0 ), _sngWt( 1.0 ), _decWt( 1.0 ) {} /** * Method to return a pair of hadrons given the PDG codes of * two or three constituents * @param cluMass The mass of the cluster * @param par1 The particle pointer of the first constituent * @param par2 The particle pointer of the second constituent * @param par3 The particle pointer of the third constituent */ - virtual pair<tcPDPtr,tcPDPtr> chooseHadronPair(const Energy cluMass,tcPDPtr par1, - tcPDPtr par2,tcPDPtr par3 = PDPtr()) const; + virtual pair<tcPDPtr,tcPDPtr> chooseHadronPair(const Energy cluMass, + tcPDPtr par1, tcPDPtr par2) const; public: /** @name Functions used by the persistent I/O system. */ //@{ /** * Function used to write out object persistently. * @param os the persistent output stream written to. */ void persistentOutput(PersistentOStream & os) const; /** * Function used to read in object persistently. * @param is the persistent input stream read from. * @param version the version number of the object when written. */ void persistentInput(PersistentIStream & is, int version); //@} /** * The standard Init function used to initialize the interfaces. * Called exactly once for each class by the class description system * before the main function starts or * when this class is dynamically loaded. */ static void Init(); protected : /** * Weights for baryons */ virtual double baryonWeight(long id) const; protected: /** @name Clone Methods. */ //@{ /** * Make a simple clone of this object. * @return a pointer to the new object. */ virtual IBPtr clone() const; /** Make a clone of this object, possibly modifying the cloned object * to make it sane. * @return a pointer to the new object. */ virtual IBPtr fullclone() const; //@} protected: /** @name Standard Interfaced functions. */ //@{ /** * Initialize this object after the setup phase before saving an * EventGenerator to disk. * @throws InitException if object could not be initialized properly. */ virtual void doinit(); //@} private: /** * The assignment operator is private and must never be called. * In fact, it should not even be implemented. */ Hw64Selector & operator=(const Hw64Selector &) = delete; private: /** * The weights for the different quarks and diquarks */ //@{ /** * The probability of producting a down quark. */ double _pwtDquark; /** * The probability of producting an up quark. */ double _pwtUquark; /** * The probability of producting a strange quark. */ double _pwtSquark; /** * The probability of producting a charm quark. */ double _pwtCquark; /** * The probability of producting a bottom quark. */ double _pwtBquark; /** * The probability of producting a spin-0 diquark. */ double _pwtDIquarkS0; /** * The probability of producting a spin-1 diquark. */ double _pwtDIquarkS1; //@} /** * Singlet and Decuplet weights */ //@{ /** * The singlet weight */ double _sngWt; /** * The decuplet weight */ double _decWt; //@} }; } #endif /* HERWIG_Hw64Selector_H */ diff --git a/Hadronization/HwppSelector.cc b/Hadronization/HwppSelector.cc --- a/Hadronization/HwppSelector.cc +++ b/Hadronization/HwppSelector.cc @@ -1,364 +1,281 @@ // -*- C++ -*- // // HwppSelector.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 HwppSelector class. // #include "HwppSelector.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Interface/Switch.h" #include "ThePEG/Interface/Parameter.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "Herwig/Utilities/Kinematics.h" #include "ThePEG/Utilities/Selector.h" #include "ThePEG/Repository/UseRandom.h" #include "CheckId.h" #include <cassert> #include <ThePEG/Utilities/DescribeClass.h> using namespace Herwig; DescribeClass<HwppSelector,HadronSelector> describeHwppSelector("Herwig::HwppSelector","Herwig.so"); IBPtr HwppSelector::clone() const { return new_ptr(*this); } IBPtr HwppSelector::fullclone() const { return new_ptr(*this); } void HwppSelector::doinit() { // the default partons allowed // the quarks for ( int ix=1; ix<=5; ++ix ) { partons().push_back(getParticleData(ix)); } // the diquarks for(unsigned int ix=1;ix<=5;++ix) { for(unsigned int iy=1; iy<=ix;++iy) { partons().push_back(getParticleData(CheckId::makeDiquarkID(ix,iy,long(3)))); if(ix!=iy) partons().push_back(getParticleData(CheckId::makeDiquarkID(ix,iy,long(1)))); } } // weights for the different quarks etc for(unsigned int ix=0; ix<partons().size(); ++ix) { pwt()[partons()[ix]->id()]=0.; } pwt()[1] = _pwtDquark; pwt()[2] = _pwtUquark; pwt()[3] = _pwtSquark; pwt()[4] = _pwtCquark; pwt()[5] = _pwtBquark; pwt()[1103] = _pwtDIquarkS1 * _pwtDquark * _pwtDquark; pwt()[2101] = _pwtDIquarkS0 * _pwtUquark * _pwtDquark; pwt()[2103] = _pwtDIquarkS1 * _pwtUquark * _pwtDquark; pwt()[2203] = _pwtDIquarkS1 * _pwtUquark * _pwtUquark; pwt()[3101] = _pwtDIquarkS0 * _pwtSquark * _pwtDquark; pwt()[3103] = _pwtDIquarkS1 * _pwtSquark * _pwtDquark; pwt()[3201] = _pwtDIquarkS0 * _pwtSquark * _pwtUquark; pwt()[3203] = _pwtDIquarkS1 * _pwtSquark * _pwtUquark; pwt()[3303] = _pwtDIquarkS1 * _pwtSquark * _pwtSquark; HadronSelector::doinit(); } void HwppSelector::persistentOutput(PersistentOStream & os) const { os << _pwtDquark << _pwtUquark << _pwtSquark << _pwtCquark << _pwtBquark << _pwtDIquarkS0 << _pwtDIquarkS1 << _sngWt << _decWt << _mode << _enhanceSProb << ounit(_m0Decay,GeV) << _massMeasure << _scHadronWtFactor << _sbHadronWtFactor; } void HwppSelector::persistentInput(PersistentIStream & is, int) { is >> _pwtDquark >> _pwtUquark >> _pwtSquark >> _pwtCquark >> _pwtBquark >> _pwtDIquarkS0 >> _pwtDIquarkS1 >> _sngWt >> _decWt >> _mode >> _enhanceSProb >> iunit(_m0Decay,GeV) >> _massMeasure >> _scHadronWtFactor >> _sbHadronWtFactor; } void HwppSelector::Init() { static ClassDocumentation<HwppSelector> documentation ("The HwppSelector class implements the Herwig algorithm for selecting" " the hadrons", "The hadronization used the selection algorithm described in \\cite{Kupco:1998fx}.", "%\\cite{Kupco:1998fx}\n" "\\bibitem{Kupco:1998fx}\n" " A.~Kupco,\n" " ``Cluster hadronization in HERWIG 5.9,''\n" " arXiv:hep-ph/9906412.\n" " %%CITATION = HEP-PH/9906412;%%\n" ); static Parameter<HwppSelector,double> interfacePwtDquark("PwtDquark","Weight for choosing a quark D", &HwppSelector::_pwtDquark, 0, 1.0, 0.0, 10.0, false,false,false); static Parameter<HwppSelector,double> interfacePwtUquark("PwtUquark","Weight for choosing a quark U", &HwppSelector::_pwtUquark, 0, 1.0, 0.0, 10.0, false,false,false); static Parameter<HwppSelector,double> interfacePwtSquark("PwtSquark","Weight for choosing a quark S", &HwppSelector::_pwtSquark, 0, 1.0, 0.0, 10.0, false,false,false); static Parameter<HwppSelector,double> interfacePwtCquark("PwtCquark","Weight for choosing a quark C", &HwppSelector::_pwtCquark, 0, 0.0, 0.0, 10.0, false,false,false); static Parameter<HwppSelector,double> interfacePwtBquark("PwtBquark","Weight for choosing a quark B", &HwppSelector::_pwtBquark, 0, 0.0, 0.0, 10.0, false,false,false); static Parameter<HwppSelector,double> interfacePwtDIquarkS0("PwtDIquarkS0","Weight for choosing a spin-0 DIquark", &HwppSelector::_pwtDIquarkS0, 0, 1.0, 0.0, 100.0, false,false,false); static Parameter<HwppSelector,double> interfacePwtDIquarkS1("PwtDIquarkS1","Weight for choosing a spin-1 DIquark", &HwppSelector::_pwtDIquarkS1, 0, 1.0, 0.0, 100.0, false,false,false); static Parameter<HwppSelector,double> interfaceSngWt("SngWt","Weight for singlet baryons", &HwppSelector::_sngWt, 0, 1.0, 0.0, 10.0, false,false,false); static Parameter<HwppSelector,double> interfaceDecWt("DecWt","Weight for decuplet baryons", &HwppSelector::_decWt, 0, 1.0, 0.0, 10.0, false,false,false); static Switch<HwppSelector,unsigned int> interfaceMode ("Mode", "Which algorithm to use", &HwppSelector::_mode, 1, false, false); static SwitchOption interfaceModeKupco (interfaceMode, "Kupco", "Use the Kupco approach", 0); static SwitchOption interfaceModeHwpp (interfaceMode, "Hwpp", "Use the Herwig approach", 1); static Switch<HwppSelector,int> interfaceEnhanceSProb ("EnhanceSProb", "Option for enhancing strangeness", &HwppSelector::_enhanceSProb, 0, false, false); static SwitchOption interfaceEnhanceSProbNo (interfaceEnhanceSProb, "No", "No strangeness enhancement.", 0); static SwitchOption interfaceEnhanceSProbScaled (interfaceEnhanceSProb, "Scaled", "Scaled strangeness enhancement", 1); static SwitchOption interfaceEnhanceSProbExponential (interfaceEnhanceSProb, "Exponential", "Exponential strangeness enhancement", 2); static Switch<HwppSelector,int> interfaceMassMeasure ("MassMeasure", "Option to use different mass measures", &HwppSelector::_massMeasure,0,false,false); static SwitchOption interfaceMassMeasureMass (interfaceMassMeasure, "Mass", "Mass Measure", 0); static SwitchOption interfaceMassMeasureLambda (interfaceMassMeasure, "Lambda", "Lambda Measure", 1); static Parameter<HwppSelector,double> interfacescHadronWtFactor ("scHadronWtFactor", "Wight factor for strenge-charm heavy hadrns", &HwppSelector::_scHadronWtFactor, 1., 0., 10., false, false, Interface::limited); static Parameter<HwppSelector,double> interfacesbHadronWtFactor ("sbHadronWtFactor", "Wight factor for strenge-bottom heavy hadrns", &HwppSelector::_sbHadronWtFactor, 1., 0., 10., false, false, Interface::limited); static Parameter<HwppSelector,Energy> interfaceDecayMassScale ("DecayMassScale", "Cluster decay mass scale", &HwppSelector::_m0Decay, GeV, 1.0*GeV, 0.1*GeV, 50.*GeV, false, false, Interface::limited); } -pair<tcPDPtr,tcPDPtr> HwppSelector::chooseHadronPair(const Energy cluMass,tcPDPtr par1, - tcPDPtr par2,tcPDPtr ) const { - // if either of the input partons is a diquark don't allow diquarks to be - // produced - bool diquark = !(DiquarkMatcher::Check(par1->id()) || DiquarkMatcher::Check(par2->id())); - bool quark = true; - // if the Herwig algorithm +double HwppSelector::baryonWeight(long id) const { + const int pspin = id % 10; + if(pspin == 2) { + // Singlet (Lambda-like) baryon + if( (id/100)%10 < (id/10 )%10 ) return sqr(_sngWt); + } + // Decuplet baryon + else if (pspin == 4) return sqr(_decWt); + return 1.; +} + +pair<bool,bool> HwppSelector::selectBaryon(const Energy cluMass, tcPDPtr par1, tcPDPtr par2) const { + bool quark=true, diquark=true; + useMe(); if(_mode ==1) { if(UseRandom::rnd() > 1./(1.+_pwtDIquarkS0+_pwtDIquarkS1) && cluMass > massLightestBaryonPair(par1,par2)) { diquark = true; quark = false; } else { useMe(); diquark = false; quark = true; } } - // weights for the different possibilities - Energy weight, wgtsum(ZERO); - // loop over all hadron pairs with the allowed flavours - static vector<Kupco> hadrons; - hadrons.clear(); - for(unsigned int ix=0;ix<partons().size();++ix) { - tcPDPtr quarktopick = partons()[ix]; - if(!quark && abs(int(quarktopick->iColour())) == 3 - && !DiquarkMatcher::Check(quarktopick->id())) continue; - if(!diquark && abs(int(quarktopick->iColour())) == 3 - && DiquarkMatcher::Check(quarktopick->id())) continue; - HadronTable::const_iterator - tit1 = table().find(make_pair(abs(par1->id()),quarktopick->id())); - HadronTable::const_iterator - tit2 = table().find(make_pair(quarktopick->id(),abs(par2->id()))); - // If not in table skip - if(tit1 == table().end()||tit2==table().end()) continue; - // tables empty skip - const KupcoData & T1 = tit1->second; - const KupcoData & T2 = tit2->second; - if(T1.empty()||T2.empty()) continue; - // if too massive skip - if(cluMass <= T1.begin()->mass + - T2.begin()->mass) continue; - // quark weight - double quarkWeight = pwt(quarktopick->id()); - if(abs(quarktopick->id()) == 3) { - // Decoupling the weight of heavy strenge hadrons - if(_enhanceSProb == 0 && abs(par1->id()) == 4) { - quarkWeight = pwt(quarktopick->id())*_scHadronWtFactor; - } - else if(_enhanceSProb == 0 && abs(par1->id()) == 5) { - quarkWeight = pwt(quarktopick->id())*_sbHadronWtFactor; - } - // Scaling strangeness enhancement - else if(_enhanceSProb == 1) { - double scale = double(sqr(_m0Decay/cluMass)); - quarkWeight = (_maxScale < scale) ? 0. : pow(quarkWeight,scale); - } - // Exponential strangeness enhancement - else if(_enhanceSProb == 2) { - Energy2 mass2; - Energy endpointmass = par1->mass() + par2->mass(); - // Choose to use either the cluster mass - // or to use the lambda measure - mass2 = (_massMeasure == 0) ? sqr(cluMass) : - sqr(cluMass) - sqr(endpointmass); - double scale = double(sqr(_m0Decay)/mass2); - quarkWeight = (_maxScale < scale) ? 0. : exp(-scale); - } - } - // loop over the hadrons - KupcoData::const_iterator H1,H2; - for(H1 = T1.begin();H1 != T1.end(); ++H1) { - for(H2 = T2.begin();H2 != T2.end(); ++H2) { - // break if cluster too light - if(cluMass < H1->mass + H2->mass) break; - weight = quarkWeight * H1->overallWeight * H2->overallWeight * - Kinematics::pstarTwoBodyDecay(cluMass, H1->mass, H2->mass); - //cerr<<H1->id<<" "<<H2->id<<" "<<weight/GeV<<"\n"; - int signQ = 0; - assert (par1 && quarktopick); - assert (par2); - - assert(quarktopick->CC()); - - if(CheckId::canBeHadron(par1, quarktopick->CC()) - && CheckId::canBeHadron(quarktopick, par2)) - signQ = +1; - else if(CheckId::canBeHadron(par1, quarktopick) - && CheckId::canBeHadron(quarktopick->CC(), par2)) - signQ = -1; - else { - cerr << "Could not make sign for" << par1->id()<< " " << quarktopick->id() - << " " << par2->id() << "\n"; - assert(false); - } - - if (signQ == -1) - quarktopick = quarktopick->CC(); - // construct the object with the info - Kupco a(quarktopick, H1->ptrData, H2->ptrData, weight); - hadrons.push_back(a); - wgtsum += weight; - } - } - } - if (hadrons.empty()) - return make_pair(tcPDPtr(),tcPDPtr()); - // select the hadron - wgtsum *= UseRandom::rnd(); - unsigned int ix=0; - do { - wgtsum-= hadrons[ix].weight; - ++ix; - } - while(wgtsum > ZERO && ix < hadrons.size()); - if(ix == hadrons.size() && wgtsum > ZERO) - return make_pair(tcPDPtr(),tcPDPtr()); - --ix; - assert(hadrons[ix].idQ); - int signHad1 = signHadron(par1, hadrons[ix].idQ->CC(), hadrons[ix].hadron1); - int signHad2 = signHadron(par2, hadrons[ix].idQ, hadrons[ix].hadron2); - assert( signHad1 != 0 && signHad2 != 0 ); - return make_pair - ( signHad1 > 0 ? hadrons[ix].hadron1 : tcPDPtr(hadrons[ix].hadron1->CC()), - signHad2 > 0 ? hadrons[ix].hadron2 : tcPDPtr(hadrons[ix].hadron2->CC())); + return make_pair(quark,diquark); } -double HwppSelector::baryonWeight(long id) const { - const int pspin = id % 10; - if(pspin == 2) { - // Singlet (Lambda-like) baryon - if( (id/100)%10 < (id/10 )%10 ) return sqr(_sngWt); +double HwppSelector::strangeWeight(const Energy cluMass, tcPDPtr par1, tcPDPtr par2) const { + // Decoupling the weight of heavy strenge hadrons + if(_enhanceSProb == 0 && abs(par1->id()) == 4) { + return pwt(3)*_scHadronWtFactor; } - // Decuplet baryon - else if (pspin == 4) return sqr(_decWt); - return 1.; + else if(_enhanceSProb == 0 && abs(par1->id()) == 5) { + return pwt(3)*_sbHadronWtFactor; + } + // Scaling strangeness enhancement + else if(_enhanceSProb == 1) { + double scale = double(sqr(_m0Decay/cluMass)); + return (_maxScale < scale) ? 0. : pow(pwt(3),scale); + } + // Exponential strangeness enhancement + else if(_enhanceSProb == 2) { + Energy2 mass2; + Energy endpointmass = par1->mass() + par2->mass(); + // Choose to use either the cluster mass + // or to use the lambda measure + mass2 = (_massMeasure == 0) ? sqr(cluMass) : + sqr(cluMass) - sqr(endpointmass); + double scale = double(sqr(_m0Decay)/mass2); + return (_maxScale < scale) ? 0. : exp(-scale); + } + return pwt(3); } diff --git a/Hadronization/HwppSelector.h b/Hadronization/HwppSelector.h --- a/Hadronization/HwppSelector.h +++ b/Hadronization/HwppSelector.h @@ -1,247 +1,225 @@ // -*- C++ -*- // // HwppSelector.h is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2019 The Herwig Collaboration // // Herwig is licenced under version 3 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // #ifndef HERWIG_HwppSelector_H #define HERWIG_HwppSelector_H // // This is the declaration of the HwppSelector class. // #include "HadronSelector.h" #include "HwppSelector.fh" namespace Herwig { using namespace ThePEG; /** \ingroup hadronization * The HwppSelector class selects the hadrons produced in cluster decay using * the Herwig variant of the cluster model. * * @see \ref HwppSelectorInterfaces "The interfaces" * defined for HwppSelector. */ class HwppSelector: public HadronSelector { public: /** * The default constructor. */ HwppSelector() : HadronSelector(1), _pwtDquark( 1.0 ),_pwtUquark( 1.0 ),_pwtSquark( 1.0 ),_pwtCquark( 0.0 ), _pwtBquark( 0.0 ),_pwtDIquarkS0( 1.0 ),_pwtDIquarkS1( 1.0 ), _sngWt( 1.0 ), _decWt( 1.0 ), _mode(1), _enhanceSProb(0), _m0Decay(1.*GeV), _scHadronWtFactor(1.), _sbHadronWtFactor(1.) {} - /** - * - * This method is used to choose a pair of hadrons. - * - * Given the mass of a cluster and the particle pointers of its - * two (or three) constituents, this returns the pair of particle pointers of - * the two hadrons with proper flavour numbers. - * Furthermore, the first of the two hadron must have the - * constituent with par1, and the second must have the constituent with par2. - * At the moment it does *nothing* in the case that also par3 is present. - * - * Kupco's method is used, rather than one used in FORTRAN HERWIG - * The idea is to build on the fly a table of all possible pairs - * of hadrons (Had1,Had2) (that we can call "cluster decay channels") - * which are kinematically above threshold and have flavour - * Had1=(par1,quarktopick->CC()), Had2=(quarktopick,par2), where quarktopick - * is the poniter of: - * --- d, u, s, c, b - * if either par1 or par2 is a diquark; - * --- d, u, s, c, b, dd, ud, uu, sd, su, ss, - * cd, cu, cs, cc, bd, bu, bs, bc, bb - * if both par1 and par2 are quarks. - * The weight associated with each channel is given by the product - * of: the phase space available including the spin factor 2*J+1, - * the constant weight factor for chosen idQ, - * the octet-singlet isoscalar mixing factor, and finally - * the singlet-decuplet weight factor. - */ - pair<tcPDPtr,tcPDPtr> chooseHadronPair(const Energy cluMass,tcPDPtr par1, - tcPDPtr par2,tcPDPtr par3 = PDPtr()) const - ; - public: /** @name Functions used by the persistent I/O system. */ //@{ /** * Function used to write out object persistently. * @param os the persistent output stream written to. */ void persistentOutput(PersistentOStream & os) const; /** * Function used to read in object persistently. * @param is the persistent input stream read from. * @param version the version number of the object when written. */ void persistentInput(PersistentIStream & is, int version); //@} /** * The standard Init function used to initialize the interfaces. * Called exactly once for each class by the class description system * before the main function starts or * when this class is dynamically loaded. */ static void Init(); protected: /** * Weights for baryons */ virtual double baryonWeight(long id) const; + /** + * Whether to select a meson or a baryon + */ + pair<bool,bool> selectBaryon(const Energy cluMass, tcPDPtr par1, tcPDPtr par2) const; + + /** + * Strange quark weight + */ + virtual double strangeWeight(const Energy cluMass, tcPDPtr par1, tcPDPtr par2) const; + protected: /** @name Clone Methods. */ //@{ /** * Make a simple clone of this object. * @return a pointer to the new object. */ virtual IBPtr clone() const; /** Make a clone of this object, possibly modifying the cloned object * to make it sane. * @return a pointer to the new object. */ virtual IBPtr fullclone() const; //@} protected: /** @name Standard Interfaced functions. */ //@{ /** * Initialize this object after the setup phase before saving an * EventGenerator to disk. * @throws InitException if object could not be initialized properly. */ virtual void doinit(); //@} private: /** * The assignment operator is private and must never be called. * In fact, it should not even be implemented. */ HwppSelector & operator=(const HwppSelector &) = delete; private: /** * The weights for the different quarks and diquarks */ //@{ /** * The probability of producting a down quark. */ double _pwtDquark; /** * The probability of producting an up quark. */ double _pwtUquark; /** * The probability of producting a strange quark. */ double _pwtSquark; /** * The probability of producting a charm quark. */ double _pwtCquark; /** * The probability of producting a bottom quark. */ double _pwtBquark; /** * The probability of producting a spin-0 diquark. */ double _pwtDIquarkS0; /** * The probability of producting a spin-1 diquark. */ double _pwtDIquarkS1; //@} /** * Singlet and Decuplet weights */ //@{ /** * The singlet weight */ double _sngWt; /** * The decuplet weight */ double _decWt; //@} private: /** * Which algorithm to use */ unsigned int _mode; /** * Flag that switches between no strangeness enhancement, scaling enhancement, * and exponential enhancement (in numerical order) */ int _enhanceSProb; /** * Parameter that governs the strangeness enhancement scaling */ Energy _m0Decay; /** * Flag that switches between mass measures used in strangeness enhancement: * cluster mass, or the lambda measure - ( m_{clu}^2 - (m_q + m_{qbar})^2 ) */ int _massMeasure; /** * Constant variable that stops the scale in strangeness enhancement from * becoming too large */ const double _maxScale = 20.; /** * Heavy strange-charm hadron wight coefficient */ double _scHadronWtFactor; /** * Heavy strange-bottom hadron wight coefficient */ double _sbHadronWtFactor; }; } #endif /* HERWIG_HwppSelector_H */ diff --git a/src/defaults/Hadronization.in b/src/defaults/Hadronization.in --- a/src/defaults/Hadronization.in +++ b/src/defaults/Hadronization.in @@ -1,102 +1,101 @@ # -*- ThePEG-repository -*- ############################################################ # Setup of default hadronization # # There are no user servicable parts inside. # # Anything that follows below should only be touched if you # know what you're doing. ############################################################# cd /Herwig/Particles create ThePEG::ParticleData Cluster setup Cluster 81 Cluster 0.00990 0.0 0.0 0.0 0 0 0 1 create ThePEG::ParticleData Remnant setup Remnant 82 Remnant 0.00990 0.0 0.0 0.0 0 0 0 1 mkdir /Herwig/Hadronization cd /Herwig/Hadronization create Herwig::ClusterHadronizationHandler ClusterHadHandler create Herwig::PartonSplitter PartonSplitter create Herwig::ClusterFinder ClusterFinder create Herwig::ColourReconnector ColourReconnector create Herwig::ClusterFissioner ClusterFissioner create Herwig::LightClusterDecayer LightClusterDecayer create Herwig::ClusterDecayer ClusterDecayer create Herwig::HwppSelector HadronSelector newdef ClusterHadHandler:PartonSplitter PartonSplitter newdef ClusterHadHandler:ClusterFinder ClusterFinder newdef ClusterHadHandler:ColourReconnector ColourReconnector newdef ClusterHadHandler:ClusterFissioner ClusterFissioner newdef ClusterHadHandler:LightClusterDecayer LightClusterDecayer newdef ClusterHadHandler:ClusterDecayer ClusterDecayer newdef ClusterHadHandler:MinVirtuality2 0.1*GeV2 newdef ClusterHadHandler:MaxDisplacement 1.0e-10*millimeter newdef ClusterHadHandler:UnderlyingEventHandler NULL newdef ClusterFissioner:HadronSelector HadronSelector newdef LightClusterDecayer:HadronSelector HadronSelector newdef ClusterDecayer:HadronSelector HadronSelector newdef ColourReconnector:ColourReconnection Yes newdef ColourReconnector:ReconnectionProbabilityBaryonic 0.7 newdef ColourReconnector:ReconnectionProbability 0.95 newdef ColourReconnector:Algorithm Baryonic newdef ColourReconnector:OctetTreatment All # Clustering parameters for light quarks newdef ClusterFissioner:ClMaxLight 3.649 newdef ClusterFissioner:ClPowLight 2.780 newdef ClusterFissioner:PSplitLight 0.899 newdef ClusterDecayer:ClDirLight 1 newdef ClusterDecayer:ClSmrLight 0.78 # Clustering parameters for b-quarks newdef ClusterFissioner:ClMaxBottom 3.757 newdef ClusterFissioner:ClPowBottom 0.547 newdef ClusterFissioner:PSplitBottom 0.625 newdef ClusterDecayer:ClDirBottom 1 newdef ClusterDecayer:ClSmrBottom 0.078 newdef HadronSelector:SingleHadronLimitBottom 0.000 # Clustering parameters for c-quarks newdef ClusterFissioner:ClMaxCharm 3.950 newdef ClusterFissioner:ClPowCharm 2.559 newdef ClusterFissioner:PSplitCharm 0.994 newdef ClusterDecayer:ClDirCharm 1 newdef ClusterDecayer:ClSmrCharm 0.163 newdef HadronSelector:SingleHadronLimitCharm 0.000 # Clustering parameters for exotic quarks # (e.g. hadronizing Susy particles) newdef ClusterFissioner:ClMaxExotic 2.7*GeV newdef ClusterFissioner:ClPowExotic 1.46 newdef ClusterFissioner:PSplitExotic 1.00 newdef ClusterDecayer:ClDirExotic 1 newdef ClusterDecayer:ClSmrExotic 0. newdef HadronSelector:SingleHadronLimitExotic 0. # newdef PartonSplitter:SplitPwtSquark 0.824135 newdef PartonSplitter:Split uds # newdef HadronSelector:PwtDquark 1.0 newdef HadronSelector:PwtUquark 1.0 newdef HadronSelector:PwtSquark 0.291717 newdef HadronSelector:PwtCquark 0.0 newdef HadronSelector:PwtBquark 0.0 newdef HadronSelector:PwtDIquarkS0 0.2 newdef HadronSelector:PwtDIquarkS1 0.1 newdef HadronSelector:SngWt 0.75 -newdef HadronSelector:OctWt 0.60 newdef HadronSelector:DecWt 0.50 newdef HadronSelector:Mode 1 newdef HadronSelector:BelowThreshold All newdef HadronSelector:scHadronWtFactor 2.5 newdef HadronSelector:sbHadronWtFactor 2.5 create Herwig::SpinHadronizer SpinHadronizer