Page Menu
Home
HEPForge
Search
Configure Global Search
Log In
Files
F10881109
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
58 KB
Subscribers
None
View Options
diff --git a/Hadronization/DynamicClusterFissioner.cc b/Hadronization/DynamicClusterFissioner.cc
new file mode 100644
--- /dev/null
+++ b/Hadronization/DynamicClusterFissioner.cc
@@ -0,0 +1,404 @@
+// -*- C++ -*-
+//
+// ClusterFissioner.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.
+//
+//
+// Thisk is the implementation of the non-inlined, non-templated member
+// functions of the ClusterFissioner class.
+//
+
+#include "DynamicClusterFissioner.h"
+#include <ThePEG/Interface/ClassDocumentation.h>
+#include <ThePEG/Interface/Reference.h>
+#include <ThePEG/Interface/Parameter.h>
+#include <ThePEG/Interface/Switch.h>
+#include <ThePEG/Persistency/PersistentOStream.h>
+#include <ThePEG/Persistency/PersistentIStream.h>
+#include <ThePEG/PDT/EnumParticles.h>
+#include "Herwig/Utilities/Kinematics.h"
+#include "ThePEG/Repository/UseRandom.h"
+#include "ThePEG/Repository/EventGenerator.h"
+#include <ThePEG/Utilities/DescribeClass.h>
+
+using namespace Herwig;
+
+DescribeClass<DynamicClusterFissioner,ClusterFissioner>
+describeDynamicClusterFissioner("Herwig::DynamicClusterFissioner","Herwig.so");
+
+DynamicClusterFissioner::DynamicClusterFissioner() :
+ _Qqtilde(4*GeV),
+ _Qg2tilde(4*GeV),
+ _AngOrdFission(1),
+ _restrictGluon(1)
+{}
+
+IBPtr DynamicClusterFissioner::clone() const {
+ return new_ptr(*this);
+}
+
+IBPtr DynamicClusterFissioner::fullclone() const {
+ return new_ptr(*this);
+}
+
+void DynamicClusterFissioner::persistentOutput(PersistentOStream & os) const {
+ os << _AngOrdFission << _restrictGluon << ounit(_Qqtilde,GeV) << ounit(_Qg2tilde,GeV) << _dynamicGluonMassGenerator << _dynamicPartonSplitter;
+}
+
+void DynamicClusterFissioner::persistentInput(PersistentIStream & is, int) {
+ is >> _AngOrdFission >> _restrictGluon >> iunit(_Qqtilde,GeV) >> iunit(_Qg2tilde,GeV) >> _dynamicGluonMassGenerator >> _dynamicPartonSplitter;
+}
+
+void DynamicClusterFissioner::Init() {
+
+ static Parameter<DynamicClusterFissioner,Energy> interfaceQqtilde
+ ("Qqtilde",
+ "Scale of the non-pert. quark splitting in the cluster fission",
+ &DynamicClusterFissioner::_Qqtilde, GeV, 4.0*GeV, 1.5*GeV, 10000.0*GeV,false,false,false); //Set upper/lower bound and default later
+
+ static Parameter<DynamicClusterFissioner,Energy> interfaceQg2tilde
+ ("Qg2tilde",
+ "Upper scale for the Sudakov for the non-pert. gluon splitting in the cluster fission",
+ &DynamicClusterFissioner::_Qg2tilde, GeV, 4.0*GeV, 0.5*GeV, 10000.0*GeV,false,false,false); //Set upper/lower bound and default later
+
+ static Switch<DynamicClusterFissioner,int> interfaceAngOrdFission
+ ("AngularOrderedFission",
+ "Option to switch on angular ordering in the dynamic fission model",
+ &DynamicClusterFissioner::_AngOrdFission,0,false,false);
+ static SwitchOption interfaceAngOrdFissionNo
+ (interfaceAngOrdFission,
+ "No",
+ "No (Qqtilde and Qg2tilde independent)",
+ 0);
+ static SwitchOption interfaceAngOrdFissionYes
+ (interfaceAngOrdFission,
+ "Yes",
+ "Qg2tilde=(1-z)*Qqtilde",
+ 1);
+
+
+ static Switch<DynamicClusterFissioner,int> interfacerestrictGluon
+ ("restrictGluon",
+ "Option to restrict the gluon virtuality in the dynamic fission in order to make sure that the splitting works out kinematically",
+ &DynamicClusterFissioner::_restrictGluon,0,false,false);
+ static SwitchOption interfacerestrictGluonNo
+ (interfacerestrictGluon,
+ "No",
+ "Gluon can have virtuality up to Qg2tilde. Might be necessary to start fission again with new z and qtilde for the quark",
+ 0);
+ static SwitchOption interfacerestrictGluonYes
+ (interfacerestrictGluon,
+ "Yes",
+ "Gluon virtuality is restricted to the range that the kinematics allow once that z and qitlde are fixed for the quark",
+ 1);
+
+ static Reference<DynamicClusterFissioner,DynamicGluonMassGenerator> interfaceDynamicGluonMassGenerator
+ ("GluonMassGenerator",
+ "Set a reference to a gluon mass generator.",
+ &DynamicClusterFissioner::_dynamicGluonMassGenerator, false, false, true, true, false);
+
+ static Reference<DynamicClusterFissioner,DynamicPartonSplitter> interfaceDynamicPartonSplitter
+ ("PartonSplitter",
+ "Set a reference to a parton splitter",
+ &DynamicClusterFissioner::_dynamicPartonSplitter, false, false, true, true, false);
+
+}
+
+
+
+
+InvEnergy DynamicClusterFissioner::Pqzproposal(double z,Energy qtilde, Energy Qqtilde, Energy mq) const{
+ return _dynamicGluonMassGenerator->ClusterAlphaS(0.*GeV2)*2.*(1.-sqr(mq/Qqtilde))/(qtilde*(1.-z));
+}
+
+InvEnergy DynamicClusterFissioner::Pqz(double z, Energy qtilde, Energy mq) const {
+ if ( z*qtilde > mq){
+ return _dynamicGluonMassGenerator->ClusterAlphaS(sqr(z*(1.0-z)*qtilde))*( (1.+z*z)/(1.-z) - ((2.*sqr(mq))/( z*(1.-z)*sqr(qtilde) )))/qtilde;}
+ else {
+ return 0./(1.*GeV);
+ }
+}
+
+
+void DynamicClusterFissioner::dynamicFission(tPPtr ptrP, tPPtr ptrPbar, PPtr& ptrQ, PPtr& ptrQbar) const {
+
+ LorentzMomentum P1, P2;
+ bool fromcolor;
+
+ Energy mq2, mg, MP1, Qqtilde, Qgtilde, qtilde, mq;
+
+ double z;
+
+ //minimal quark mass
+ Energy m0, mu, ms, md;
+ mu=getParticleData(ThePEG::ParticleID::u)->constituentMass();
+ md=getParticleData(ThePEG::ParticleID::d)->constituentMass();
+ ms=getParticleData(ThePEG::ParticleID::s)->constituentMass();
+ m0=md;
+ if(mu<m0){m0=mu;}
+ if(ms<m0){m0=ms;}
+
+
+ bool repeat2=true;
+
+
+ LorentzMomentum Pcl(ptrP->momentum()+ptrPbar->momentum());
+ Energy Mcl = Pcl.m();
+ //boost to rest frame of the cluster
+ Boost bv = Pcl.boostVector();
+
+
+ //upper scale of the quark splitting
+ Qqtilde = _Qqtilde;
+
+
+while(repeat2){
+
+ //choose from which constituent we radiate the gluon
+ if ( UseRandom::rnd(0.0, 1.0)<0.5 ){
+ P1 = ptrP->momentum();
+ P2 = ptrPbar->momentum();
+ mq = ptrP->data().constituentMass();
+ mq2 = ptrPbar->data().constituentMass();
+ fromcolor=true;
+ }
+ else{
+ P2 = ptrP->momentum();
+ P1 = ptrPbar->momentum();
+ mq = ptrPbar->data().constituentMass();
+ mq2 = ptrP->data().constituentMass();
+ fromcolor=false;
+ }
+
+
+
+ //and check if it is kinematically possible for that constituent
+ if (!canSplitMinimally(Mcl,mq,mq2,m0)){
+ swap(P1,P2);
+ swap(mq,mq2);
+ fromcolor=(!fromcolor);
+ }
+
+
+ P1.boost(-bv);
+ P2.boost(-bv);
+
+
+
+ //Qqtilde = Qqtilde + mq;
+ //get z and qtilde
+ double zmin=mq/Qqtilde;
+ double zmax=1-(4*sqr(m0)/( sqr(Mcl-mq2)-sqr(mq) ));
+ //if ((_AngOrdFission==1) && (1-(4*m0/Qqtilde)<zmax)){
+ // zmax=1-(4*m0/Qqtilde);
+// }
+
+
+
+
+ double rzmin=-log(1-zmin);
+ double rzmax=-log(1-zmax);
+
+ bool repeat = true;
+ while (repeat){
+ //generate z and qtilde from a proposal distribution and check that at least with minimal quark mass the kinematics can work out
+ bool repeat3 = true;
+ double ymin, ymax;
+ while (repeat3){
+ z = 1.0 - exp(-UseRandom::rnd(rzmin,rzmax));
+
+ ymin =mq/(z*Qqtilde);
+ if ((_AngOrdFission==1)&&(4*m0/((1.-z)*Qqtilde)>ymin)){
+ ymin=4*m0/((1.-z)*Qqtilde);
+ }
+ ymax =sqrt( ( sqr(Mcl-mq2) -sqr(mq) -(4*sqr(m0)/(1-z)) )/( z*(1-z) ) )/Qqtilde;
+ if (ymax >1.){
+ ymax=1.;
+ }
+ if (ymin<ymax){
+ repeat3=false;
+ }
+ }
+
+ double rymin=-log(ymax);
+ double rymax=-log(ymin);
+
+ qtilde=Qqtilde*exp(-UseRandom::rnd(rymin,rymax));
+
+ //compare with actual distrubition
+ if (Pqzproposal(z,qtilde,Qqtilde,mq)*UseRandom::rnd(0.0,1.0)<Pqz(z,qtilde,mq)){
+ repeat = false;
+ }
+ }
+
+
+ //scale for the Sudakov in the gluon splitting
+ if (_AngOrdFission==1){
+ Qgtilde=(1.-z)*qtilde;
+ }
+ else{
+ Qgtilde=_Qg2tilde;
+ }
+
+
+ //gluon virtuality
+ if (_restrictGluon==1){
+ //restirct the gluon virtuality to the range where kinematic reconstruction is possible, i.e. Mcl>MP1+mq2 is always true
+ Energy mgmax=sqrt((1.-z)*(sqr(Mcl-mq2) - sqr(mq) -z*(1.-z)*sqr(qtilde)));
+ mg=_dynamicGluonMassGenerator->generate(Qgtilde,mgmax);
+ }
+ else{
+ //no additional restriction on gluon virtuality. Mcl>MP1+mq2 might fail and new z and qtilde for the quark are generated
+ mg=_dynamicGluonMassGenerator->generate(Qgtilde);
+ }
+
+
+
+
+
+
+
+ //kinematic reconstruction / get momenta P1prime and P2prime before radiating
+ //invariant mass of quark before radiating
+ MP1 = sqrt(sqr(mq)+z*(1.0-z)*sqr(qtilde)+(sqr(mg)/(1.-z)));
+
+
+
+ if(Mcl>MP1+mq2){
+ repeat2 = false;
+ }
+
+ }//end while(repeat2)
+
+
+
+
+ Energy absP = sqrt(sqr(sqr(Mcl))+sqr(sqr(MP1))+sqr(sqr(mq2))-2.0*(sqr(Mcl*MP1)+sqr(Mcl*mq2)+sqr(MP1*mq2)))/(2.0*Mcl);
+
+
+
+ Lorentz5Momentum P1prime(absP*P1.vect().unit(),sqrt(sqr(absP)+sqr(MP1)),MP1);
+ Lorentz5Momentum P2prime(absP*P2.vect().unit(),sqrt(sqr(absP)+sqr(mq2)),mq2);
+
+
+
+
+
+ //splitting
+ //construct the backwards light-like vector
+ LorentzVector<double> nbar(-P1prime.vect().unit(),1.0);
+
+ //construct the transverse momentum with random azimuthal angle
+ //construct an orthonormal basis of transverse 4-vectors
+ ThreeVector<double> Three_qperp1 = nbar.vect().orthogonal().unit();
+ ThreeVector<double> Three_qperp2 = nbar.vect().unit().cross(Three_qperp1);
+ LorentzVector<double> qperp1(Three_qperp1,0.0);
+ LorentzVector<double> qperp2(Three_qperp2,0.0);
+
+
+
+ using Constants::pi;
+ double phi = UseRandom::rnd( -pi , pi );
+ Energy gperpabs=sqrt(sqr(1.-z)*(sqr(z*qtilde)-sqr(mq)) );
+
+ LorentzMomentum gperp = gperpabs*cos(phi)*qperp1+gperpabs*sin(phi)*qperp2;
+
+ //quark and gluon momenta
+ Lorentz5Momentum k(z*P1prime + ((sqr(mq)-sqr(z*MP1)+sqr(gperpabs))/(2.0*z*P1prime.dot(nbar)))*nbar - gperp,mq);
+ Lorentz5Momentum g((1.-z)*P1prime + ((sqr(mg)-sqr((1.-z)*MP1)+sqr(gperpabs))/(2.0*(1.-z)*P1prime.dot(nbar)))*nbar +gperp,mg);
+
+
+
+
+ //create particles and give them to PartonSplitter
+
+
+ PPtr ptrPprime = PPtr();
+ PPtr ptrG = PPtr();
+ ptrG = getParticle(ThePEG::ParticleID::g);
+ ptrG->set5Momentum(g);
+ if (fromcolor){
+ ptrP->set5Momentum(k);
+ ptrPbar->set5Momentum(P2prime);
+ ptrPprime = getParticle(ptrP->id());
+ ptrPprime->set5Momentum(P1prime);
+ //_dynamicPartonSplitter->splitTimeLikeGluon(ptrG,ptrPprime,ptrPbar,ptrQ,ptrQbar,Qgtilde,nbar,fromcolor);
+ _dynamicPartonSplitter->splitTimeLikeGluon(ptrG,ptrQ, ptrQbar, ptrPprime, ptrPbar,Qgtilde,nbar,fromcolor);
+ }
+ else{
+ ptrP->set5Momentum(P2prime);
+ ptrPbar->set5Momentum(k);
+ ptrPprime = getParticle(ptrPbar->id());
+ ptrPprime->set5Momentum(P1prime);
+ //_dynamicPartonSplitter->splitTimeLikeGluon(ptrG,ptrP,ptrPprime,ptrQ,ptrQbar,Qgtilde,nbar,fromcolor);
+ _dynamicPartonSplitter->splitTimeLikeGluon(ptrG,ptrQ, ptrQbar, ptrP, ptrPprime,Qgtilde,nbar,fromcolor);
+ }
+
+
+
+
+ //boost back to lab frame
+ //(this must be possible in a nicer way)
+ Lorentz5Momentum temp;
+ temp = ptrP->momentum();
+ temp.boost(bv);
+ ptrP->set5Momentum(temp);
+
+ temp = ptrPbar->momentum();
+ temp.boost(bv);
+ ptrPbar->set5Momentum(temp);
+
+ temp = ptrQ->momentum();
+ temp.boost(bv);
+ ptrQ->set5Momentum(temp);
+
+ temp = ptrQbar->momentum();
+ temp.boost(bv);
+ ptrQbar->set5Momentum(temp);
+
+}
+
+
+bool DynamicClusterFissioner::canSplitMinimally(Energy Mcl, Energy m1, Energy m2, Energy m0) const {
+
+ if (Mcl<m1+m2+2*m0){ return false; }
+
+ Energy Qtilde=_Qqtilde;
+
+
+ if (Qtilde>m1){
+
+ if (_AngOrdFission==0){
+ if (Qtilde>2*m0+m1){
+ return Mcl>m2+m1+2*m0;
+ }
+ else{
+ return Mcl>m2+sqrt(Qtilde*(m1- (4*sqr(m0)/(Qtilde-m1)) ));
+ }
+ }
+ else{
+ if (Qtilde>4*m0+m1){
+ return Mcl>m2+sqrt((m0+m1)*(4*m0+m1));
+ }
+ else{
+ return Mcl<m2+sqrt( sqr(m1) + (4*sqr(m0)*(4*m1+Qtilde))/(Qtilde-m1) );
+ }
+ }
+
+ }
+ else{
+ return false;
+ }
+
+
+}
+
+bool DynamicClusterFissioner::canSplitMinimally(tcClusterPtr clu, Energy minmass) const {
+ Energy Mcl=clu->mass();
+ Energy m1 = clu->particle(0)->data().constituentMass();
+ Energy m2 = clu->particle(1)->data().constituentMass();
+ return ((canSplitMinimally(Mcl,m1,m2,minmass))||(canSplitMinimally(Mcl,m2,m1,minmass)));
+}
diff --git a/Hadronization/DynamicClusterFissioner.h b/Hadronization/DynamicClusterFissioner.h
new file mode 100644
--- /dev/null
+++ b/Hadronization/DynamicClusterFissioner.h
@@ -0,0 +1,210 @@
+// -*- C++ -*-
+//
+// ClusterFissioner.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_DynamicClusterFissioner_H
+#define HERWIG_DynamicClusterFissioner_H
+
+#include <ThePEG/Interface/Interfaced.h>
+#include "CluHadConfig.h"
+#include "ClusterFissioner.h"
+#include "DynamicPartonSplitter.h"
+#include "DynamicGluonMassGenerator.h"
+
+namespace Herwig {
+using namespace ThePEG;
+
+
+class DynamicClusterFissioner: public ClusterFissioner {
+
+public:
+
+ /** @name Standard constructors and destructors. */
+ //@{
+ /**
+ * Default constructor.
+ */
+ DynamicClusterFissioner();
+
+ //@}
+
+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);
+ //@}
+
+ /**
+ * Standard Init function used to initialize the interfaces.
+ */
+ static void Init();
+
+protected:
+
+ /** @name Clone Methods. */
+ //@{
+ /**
+ * Make a simple clone of this object.
+ * @return a pointer to the new object.
+ */
+ virtual IBPtr clone() const;
+
+ /** Make a clone of this object, possibly modifying the cloned object
+ * to make it sane.
+ * @return a pointer to the new object.
+ */
+ virtual IBPtr fullclone() const;
+ //@}
+
+private:
+
+ /**
+ * Private and non-existent assignment operator.
+ */
+ DynamicClusterFissioner & operator=(const DynamicClusterFissioner &) = delete;
+
+
+
+public:
+
+ //@{
+
+ /**
+ * Split three-component cluster
+ */
+ virtual cutType cutThree(ClusterPtr &, tPVector & finalhadrons, bool softUEisOn){
+ assert(false);//implementation missing
+ }
+ //@}
+
+protected:
+
+
+
+
+ InvEnergy Pqzproposal(double z, Energy qtilde, Energy Qqtilde, Energy mq) const;
+ InvEnergy Pqz(double z, Energy Qqtilde, Energy mq) const;
+
+
+ /**
+ * The actual implementation of the dynamic fission
+ */
+ virtual void dynamicFission(tPPtr ptrP, tPPtr ptrPbar, PPtr & ptrQ, PPtr & ptrQbar) const;
+
+
+ /**
+ * call the dynamic fission function here
+ */
+ virtual void drawNewFlavour(PPtr& newPtr1, PPtr& newPtr2,const ClusterPtr& cluster) const {
+ if(!cluster->particle(0)->hasAntiColour()){
+ dynamicFission(cluster->particle(0), cluster->particle(1) ,newPtr2,newPtr1);
+ }
+ else{
+ dynamicFission(cluster->particle(1), cluster->particle(0) ,newPtr1,newPtr2);
+ }
+ }
+
+
+
+ bool canSplitMinimally(tcClusterPtr clu, Energy minmass) const;
+ bool canSplitMinimally(Energy Mcl, Energy m1, Energy m2, Energy m0) const;
+
+
+ /**
+ * set the momenta here
+ */
+ virtual pair<Energy,Energy> drawNewMasses(Energy Mc, bool soft1, bool soft2,
+ Lorentz5Momentum& pClu1, Lorentz5Momentum& pClu2,
+ tPPtr ptrQ1, Lorentz5Momentum& pQ1,
+ tPPtr newPtr1, Lorentz5Momentum& pQone,
+ tPPtr newPtr2, Lorentz5Momentum& pQtwo,
+ tPPtr ptrQ2, Lorentz5Momentum& pQ2) const
+ {
+ pQ1 = ptrQ1->momentum();
+ pQ2 = ptrQ2->momentum();
+ pQone = newPtr1->momentum();
+ pQtwo = newPtr2->momentum();
+ pClu1 = pQ1+pQone;
+ pClu2 = pQ2 + pQtwo;
+
+ pClu1.setMass(pClu1.m());
+ pClu2.setMass(pClu2.m());
+
+ pQ1.setMass(ptrQ1->data().constituentMass());
+ pQ2.setMass(ptrQ2->data().constituentMass());
+ pQone.setMass(newPtr1->data().constituentMass());
+ pQtwo.setMass(newPtr2->data().constituentMass());
+
+ pair<Energy,Energy> result;
+ result.first = pClu1.m();
+ result.second = pClu2.m();
+ return result;
+ }
+
+ /**
+ * does nothing
+ * kinematics already done in drawNewMasses
+ */
+ virtual void calculateKinematics(const Lorentz5Momentum &pClu,
+ const Lorentz5Momentum &p0Q1,
+ const bool toHadron1, const bool toHadron2,
+ Lorentz5Momentum &pClu1, Lorentz5Momentum &pClu2,
+ Lorentz5Momentum &pQ1, Lorentz5Momentum &pQb,
+ Lorentz5Momentum &pQ2, Lorentz5Momentum &pQ2b) const {}
+
+
+
+ /**
+ * pointer to the dynamic parton splitter
+ */
+ /*Ptr<DynamicPartonSplitter>::tptr partonSplitter() const {
+ Ptr<DynamicPartonSplitter>::tptr partonSplitter_ = dynamic_ptr_cast<Ptr<DynamicPartonSplitter>::tptr>(ClusterHadronizationHandler::currentHandler()->partonSplitter());
+ return partonSplitter_;
+ }*/
+
+ /**
+ * pointer to the dynamic gluon mass generator
+ */
+ /*Ptr<DynamicGluonMassGenerator>::tptr gluonMassGenerator() const {
+ Ptr<DynamicGluonMassGenerator>::tptr gluonMassGenerator_ = dynamic_ptr_cast<Ptr<DynamicGluonMassGenerator>::tptr>(ClusterHadronizationHandler::currentHandler()->gluonMassGenerator());
+ return gluonMassGenerator_;
+ }*/
+
+
+private:
+
+ //scales for quark and gluon splitting in the fission
+ Energy _Qqtilde;
+ Energy _Qg2tilde;
+
+ //switch for angular ordering in dynamic fission
+ int _AngOrdFission;
+
+ //switch for restricting the gluon virtuality in dynamic fission
+ int _restrictGluon;
+
+ Ptr<DynamicGluonMassGenerator>::ptr _dynamicGluonMassGenerator;
+ Ptr<DynamicPartonSplitter>::ptr _dynamicPartonSplitter;
+
+
+
+};
+}
+
+#endif /* HERWIG_DynamicClusterFissioner_H */
diff --git a/Hadronization/DynamicGluonMassGenerator.cc b/Hadronization/DynamicGluonMassGenerator.cc
new file mode 100644
--- /dev/null
+++ b/Hadronization/DynamicGluonMassGenerator.cc
@@ -0,0 +1,153 @@
+// -*- C++ -*-
+//
+// This is the implementation of the non-inlined, non-templated member
+// functions of the GluonMassGenerator class.
+//
+
+#include "DynamicGluonMassGenerator.h"
+#include "ThePEG/Interface/ClassDocumentation.h"
+#include "ThePEG/EventRecord/Particle.h"
+#include "ThePEG/Repository/UseRandom.h"
+#include "ThePEG/Repository/EventGenerator.h"
+#include "ThePEG/Utilities/DescribeClass.h"
+#include "ThePEG/StandardModel/StandardModelBase.h"
+#include "ClusterHadronizationHandler.h"
+#include "ThePEG/Persistency/PersistentOStream.h"
+#include "ThePEG/Persistency/PersistentIStream.h"
+#include <ThePEG/Interface/Parameter.h>
+
+using namespace Herwig;
+
+DynamicGluonMassGenerator::DynamicGluonMassGenerator() {}
+
+DynamicGluonMassGenerator::~DynamicGluonMassGenerator() {}
+
+IBPtr DynamicGluonMassGenerator::clone() const {
+ return new_ptr(*this);
+}
+
+IBPtr DynamicGluonMassGenerator::fullclone() const {
+ return new_ptr(*this);
+}
+
+
+
+InvEnergy DynamicGluonMassGenerator::PmgProposal(Energy, Energy mq) const {
+ return (ClusterAlphaS(4*mq*mq)*0.32/mq);
+}
+
+
+InvEnergy DynamicGluonMassGenerator::PmgProposal(Energy mg) const {
+ Energy mu, ms, md;
+ mu=getParticleData(ThePEG::ParticleID::u)->constituentMass();
+ md=getParticleData(ThePEG::ParticleID::d)->constituentMass();
+ ms=getParticleData(ThePEG::ParticleID::s)->constituentMass();
+ return PmgProposal(mg, mu)+PmgProposal(mg, md)+PmgProposal(mg, ms);
+}
+
+
+
+InvEnergy DynamicGluonMassGenerator::Pmg(Energy mg, Energy mq, Energy Qtilde) const {
+ if((2*mq<mg) && (mg <= sqrt(mq*Qtilde))){
+ return (ClusterAlphaS(mg*mg)/mg)*sqrt(1-pow(2*mq/mg,2))*(1+(2*pow(mq/mg,2)));
+ }
+ else if ((sqrt(mq*Qtilde)<mg) &&(mg<=Qtilde/2.0)){
+ return (ClusterAlphaS(mg*mg)/mg)*sqrt(1-pow(2*mg/Qtilde,2))*(1+(3*pow(mq/mg,2))-pow(mg/Qtilde,2) );
+ }
+ else{
+ return 0.0*InvGeV;
+ }
+}
+
+InvEnergy DynamicGluonMassGenerator::Pmg(Energy mg,Energy Qtilde) const {
+ Energy mu, ms, md;
+ mu=getParticleData(ThePEG::ParticleID::u)->constituentMass();
+ md=getParticleData(ThePEG::ParticleID::d)->constituentMass();
+ ms=getParticleData(ThePEG::ParticleID::s)->constituentMass();
+ return Pmg(mg,mu,Qtilde)+Pmg(mg,md,Qtilde)+Pmg(mg,ms,Qtilde);
+}
+
+
+
+Energy DynamicGluonMassGenerator::generateProposal(Energy mgmax) const {
+ Energy m0, mu, ms, md;
+ mu=getParticleData(ThePEG::ParticleID::u)->constituentMass();
+ md=getParticleData(ThePEG::ParticleID::d)->constituentMass();
+ ms=getParticleData(ThePEG::ParticleID::s)->constituentMass();
+ m0=md;
+ if(mu<m0){m0=mu;}
+ if(ms<m0){m0=ms;}
+ return UseRandom::rnd(2.*m0,mgmax);
+}
+
+Energy DynamicGluonMassGenerator::generate(Energy Qtilde, Energy mgmax) const {
+ Energy mg;
+ double r;
+ bool repeat;
+ Energy max=mgmax;
+ if(0.5*Qtilde<max){max=0.5*Qtilde;};
+ repeat=true;
+ while(repeat){
+ mg=generateProposal(max);
+ r=UseRandom::rnd(0.0, 1.0);
+ if(r*PmgProposal(mg)<Pmg(mg,Qtilde)){
+ repeat=false;
+ }
+ }
+ return mg;
+}
+
+
+Energy DynamicGluonMassGenerator::generate(Energy Qtilde) const {
+ return generate(Qtilde,Qtilde);
+}
+
+
+Energy DynamicGluonMassGenerator::generate() const {
+ return generate(Qgtilde());
+}
+
+
+
+// If needed, insert default implementations of virtual function defined
+// in the InterfacedBase class here (using ThePEG-interfaced-impl in Emacs).
+
+
+
+void DynamicGluonMassGenerator::persistentOutput(PersistentOStream & os) const {
+ // *** ATTENTION *** os << ; // Add all member variable which should be written persistently here.
+ os << ounit(_Qgtilde,GeV) << ounit(_clusteralphasfreeze,GeV);
+}
+
+void DynamicGluonMassGenerator::persistentInput(PersistentIStream & is, int) {
+ // *** ATTENTION *** is >> ; // Add all member variable which should be read persistently here.
+ is >> iunit(_Qgtilde,GeV) >> iunit(_clusteralphasfreeze,GeV);
+}
+
+
+// *** Attention *** The following static variable is needed for the type
+// description system in ThePEG. Please check that the template arguments
+// are correct (the class and its base class), and that the constructor
+// arguments are correct (the class name and the name of the dynamically
+// loadable library where the class implementation can be found).
+DescribeClass<DynamicGluonMassGenerator,GluonMassGenerator>
+ describeHerwigDynamicGluonMassGenerator("Herwig::DynamicGluonMassGenerator", "");
+
+void DynamicGluonMassGenerator::Init() {
+
+ static ClassDocumentation<DynamicGluonMassGenerator> documentation
+ ("There is no documentation for the DynamicGluonMassGenerator class");
+
+
+ static Parameter<DynamicGluonMassGenerator,Energy> interfaceQgtilde
+ ("Qgtilde",
+ "Upper scale for the Sudakov for the non-pert. gluon splitting",
+ &DynamicGluonMassGenerator::_Qgtilde, GeV, 4.0*GeV, 0.5*GeV, 10000.0*GeV,false,false,false);
+
+ static Parameter<DynamicGluonMassGenerator,Energy> interfaceClusterAlphaSFreeze
+ ("ClusterAlphaSFreeze",
+ "Freeze-out scale for the non-pert. coupling in gluon splitting and cluster fission",
+ &DynamicGluonMassGenerator::_clusteralphasfreeze, GeV, 1.0*GeV, 0.1*GeV, 10.0*GeV,false,false,false);
+
+}
+
diff --git a/Hadronization/DynamicGluonMassGenerator.h b/Hadronization/DynamicGluonMassGenerator.h
new file mode 100644
--- /dev/null
+++ b/Hadronization/DynamicGluonMassGenerator.h
@@ -0,0 +1,174 @@
+// -*- C++ -*-
+#ifndef Herwig_DynamicGluonMassGenerator_H
+#define Herwig_DynamicGluonMassGenerator_H
+//
+// This is the declaration of the DynamicGluonMassGenerator class.
+//
+
+
+
+#include "Herwig/Hadronization/GluonMassGenerator.h"
+#include "ClusterHadronizationHandler.h"
+#include "ThePEG/StandardModel/StandardModelBase.h"
+#include "Cluster.h"
+
+
+namespace Herwig {
+
+using namespace ThePEG;
+
+/**
+ * Here is the documentation of the GluonMassGenerator class.
+ *
+ * @see \ref GluonMassGeneratorInterfaces "The interfaces"
+ * defined for GluonMassGenerator.
+ */
+class DynamicGluonMassGenerator: public GluonMassGenerator {
+
+public:
+
+ /** @name Standard constructors and destructors. */
+ //@{
+ /**
+ * The default constructor.
+ */
+ DynamicGluonMassGenerator();
+
+ /**
+ * The destructor.
+ */
+ virtual ~DynamicGluonMassGenerator();
+ //@}
+
+public:
+
+
+ /**
+ * Returns the scale Qgtilde of the Sudakov in the gluon splitting
+ */
+ virtual Energy Qgtilde() const {
+ return _Qgtilde;
+ }
+
+ /**
+ * Returns the minimum mass of a gluon that can by generated
+ */
+ virtual Energy minGluonMass() const { //ToDo: get it from hadron spectrum
+ Energy m0, mu, md, ms;
+ mu=getParticleData(ThePEG::ParticleID::u)->constituentMass();
+ md=getParticleData(ThePEG::ParticleID::d)->constituentMass();
+ ms=getParticleData(ThePEG::ParticleID::s)->constituentMass();
+ m0=md;
+ if(mu<m0){m0=mu;}
+ if(ms<m0){m0=ms;}
+ return m0;
+ }
+
+
+ /**
+ * Generate a gluon mass drawn from the proposal distribution (overestimate)
+ */
+ virtual Energy generateProposal(Energy Qtilde) const;
+
+ /**
+ * The proposal distributions for the gluon mass (overestimate)
+ */
+ virtual InvEnergy PmgProposal(Energy mg, Energy mq) const;
+ virtual InvEnergy PmgProposal(Energy mg) const;
+
+
+ /**
+ * The gluon mass distribution
+ */
+ virtual InvEnergy Pmg(Energy mg, Energy mq, Energy Qtilde) const;
+ virtual InvEnergy Pmg(Energy mg, Energy Qtilde) const;
+
+
+ /**
+ * Generate a single gluon mass
+ */
+ virtual Energy generate(Energy Qtilde, Energy mgmax) const;
+ virtual Energy generate(Energy Qtilde) const;
+ virtual Energy generate() const;
+
+
+ /**
+ * Return the the strong coupling used in ClusterFission
+ */
+ double ClusterAlphaS(Energy2 q2) const {
+ if(q2>sqr(_clusteralphasfreeze)){return ClusterHadronizationHandler::currentHandler()->SM().alphaS(q2);}
+ else{return ClusterHadronizationHandler::currentHandler()->SM().alphaS(sqr(_clusteralphasfreeze));}
+ }
+
+
+
+public:
+
+ /** @name Functions used by the persistent I/O system. */
+ //@{
+ /**
+ * Function used to write out object persistently.
+ * @param os the persistent output stream written to.
+ */
+ void persistentOutput(PersistentOStream & os) const;
+
+ /**
+ * Function used to read in object persistently.
+ * @param is the persistent input stream read from.
+ * @param version the version number of the object when written.
+ */
+ void persistentInput(PersistentIStream & is, int version);
+ //@}
+
+ /**
+ * The standard Init function used to initialize the interfaces.
+ * Called exactly once for each class by the class description system
+ * before the main function starts or
+ * when this class is dynamically loaded.
+ */
+ static void Init();
+
+protected:
+
+ /** @name Clone Methods. */
+ //@{
+ /**
+ * Make a simple clone of this object.
+ * @return a pointer to the new object.
+ */
+ virtual IBPtr clone() const;
+
+ /** Make a clone of this object, possibly modifying the cloned object
+ * to make it sane.
+ * @return a pointer to the new object.
+ */
+ virtual IBPtr fullclone() const;
+ //@}
+
+
+// If needed, insert declarations of virtual function defined in the
+// InterfacedBase class here (using ThePEG-interfaced-decl in Emacs).
+
+
+private:
+
+ /**
+ * Private and non-existent assignment operator.
+ */
+ DynamicGluonMassGenerator & operator=(const DynamicGluonMassGenerator &) = delete;
+
+ /**
+ * Scale of the Sudakov in the gluon splitting
+ */
+ Energy _Qgtilde = 4.0*GeV;
+
+ /**
+ * freezing scale for the non-pert. alphas
+ */
+ Energy _clusteralphasfreeze = 1.0*GeV;
+
+};
+
+}
+
+#endif /* Herwig_DynamicGluonMassGenerator_H */
diff --git a/Hadronization/DynamicPartonSplitter.cc b/Hadronization/DynamicPartonSplitter.cc
new file mode 100644
--- /dev/null
+++ b/Hadronization/DynamicPartonSplitter.cc
@@ -0,0 +1,312 @@
+// -*- C++ -*-
+//
+// PartonSplitter.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 PartonSplitter class.
+//
+
+#include "DynamicPartonSplitter.h"
+#include <ThePEG/Interface/ClassDocumentation.h>
+#include <ThePEG/Interface/Reference.h>
+#include <ThePEG/Interface/Switch.h>
+#include <ThePEG/Persistency/PersistentOStream.h>
+#include <ThePEG/Persistency/PersistentIStream.h>
+#include <ThePEG/PDT/EnumParticles.h>
+#include <ThePEG/EventRecord/Step.h>
+#include "ThePEG/Interface/Parameter.h"
+#include <ThePEG/Repository/EventGenerator.h>
+#include <ThePEG/Repository/CurrentGenerator.h>
+#include "ThePEG/Repository/UseRandom.h"
+#include "Herwig/Utilities/Kinematics.h"
+#include <ThePEG/Utilities/DescribeClass.h>
+#include "ClusterHadronizationHandler.h"
+#include <ThePEG/EventRecord/Particle.h>
+#include <ThePEG/PDT/PDT.h>
+
+
+using namespace Herwig;
+
+IBPtr DynamicPartonSplitter::clone() const {
+ return new_ptr(*this);
+}
+
+IBPtr DynamicPartonSplitter::fullclone() const {
+ return new_ptr(*this);
+}
+
+void DynamicPartonSplitter::persistentOutput(PersistentOStream & os) const {
+ os << _findProgenitor << _restrictZ << _dynamicGluonMassGenerator;
+}
+
+void DynamicPartonSplitter::persistentInput(PersistentIStream & is, int) {
+ is >> _findProgenitor >> _restrictZ >> _dynamicGluonMassGenerator;
+}
+
+DescribeClass<DynamicPartonSplitter,PartonSplitter>
+describeDynamicPartonSplitter("Herwig::DynamicPartonSplitter","Herwig.so");
+
+
+void DynamicPartonSplitter::Init() {
+
+ static ClassDocumentation<DynamicPartonSplitter> documentation
+ ("This class is reponsible of the nonperturbative splitting of partons");
+
+
+ static Switch<DynamicPartonSplitter,int> interfaceRestrictZ
+ ("RestrictZ",
+ "Option to restrict z in gluon splitting to z > 0.5",
+ &DynamicPartonSplitter::_restrictZ,0,false,false);
+ static SwitchOption interfaceRestrictZNo
+ (interfaceRestrictZ,
+ "No",
+ "No restriction",
+ 0);
+ static SwitchOption interfaceRestrictZYes
+ (interfaceRestrictZ,
+ "Yes",
+ "Restric z > 0.5",
+ 1);
+
+
+ static Switch<DynamicPartonSplitter,int> interfaceFindProgenitor
+ ("FindProgenitor",
+ "Option for how to choose which color partner is the progenitor of the gluon",
+ &DynamicPartonSplitter::_findProgenitor,0,false,false);
+ static SwitchOption interfaceFindProgenitorAngle
+ (interfaceFindProgenitor,
+ "Angle",
+ "choose color partner with maximum cos(theta)",
+ 0);
+ static SwitchOption interfaceFindProgenitorMomentum
+ (interfaceFindProgenitor,
+ "Momentum",
+ "choose color partner with maximum |p|*cos(theta)",
+ 1);
+ static SwitchOption interfaceFindProgenitorpT
+ (interfaceFindProgenitor,
+ "pT",
+ "choose color partner with maximum cos^2(theta) as backwards direction",
+ 2);
+ static SwitchOption interfaceFindProgenitorpTforward
+ (interfaceFindProgenitor,
+ "pTforward",
+ "choose color partner with maximum cos^2(theta), gluon always in forward direction",
+ 3);
+ static SwitchOption interfaceFindProgenitorGluon
+ (interfaceFindProgenitor,
+ "Gluon",
+ "Gluon as progenitor",
+ 4);
+ static SwitchOption interfaceFindProgenitorIsotropic
+ (interfaceFindProgenitor,
+ "Isotropic",
+ "Isotropic gluon decay",
+ 5);
+
+ static Reference<DynamicPartonSplitter,DynamicGluonMassGenerator> interfaceDynamicGluonMassGenerator
+ ("GluonMassGenerator",
+ "Set a reference to a gluon mass generator.",
+ &DynamicPartonSplitter::_dynamicGluonMassGenerator, false, false, true, true, false);
+}
+
+
+void DynamicPartonSplitter::drawNewFlavour(PPtr & ptrQ, PPtr & ptrQbar, Energy mg, Energy Qtilde){
+ static const Energy md = getParticleData(ThePEG::ParticleID::d)->constituentMass();
+ static const Energy mu = getParticleData(ThePEG::ParticleID::u)->constituentMass();
+ static const Energy ms = getParticleData(ThePEG::ParticleID::s)->constituentMass();
+
+ double prob_d=_dynamicGluonMassGenerator->Pmg(mg,md,Qtilde)*UnitRemoval::E;
+ double prob_u=_dynamicGluonMassGenerator->Pmg(mg,mu,Qtilde)*UnitRemoval::E;
+ double prob_s=_dynamicGluonMassGenerator->Pmg(mg,ms,Qtilde)*UnitRemoval::E;
+
+
+ long idNew=0;
+ int choice = UseRandom::rnd3(prob_u, prob_d, prob_s);
+ switch(choice) {
+ case 0: idNew = ThePEG::ParticleID::u; break;
+ case 1: idNew = ThePEG::ParticleID::d; break;
+ case 2: idNew = ThePEG::ParticleID::s; break;
+ }
+ ptrQ = getParticle(idNew);
+ ptrQbar = getParticle(-idNew);
+ assert (ptrQ);
+ assert(ptrQbar);
+ assert (ptrQ->dataPtr());
+ assert(ptrQbar->dataPtr());
+
+}
+
+
+void DynamicPartonSplitter::splitTimeLikeGluon(tcPPtr ptrGluon, PPtr & ptrQ, PPtr & ptrQbar, tcPPtr ptrP, tcPPtr ptrPbar, Energy Qtilde, LorentzVector<double> nbar, bool ProgenitorHasColor){
+
+ LorentzMomentum momentumG = ptrGluon->momentum();
+ LorentzMomentum momentumP = ptrP->momentum();
+ LorentzMomentum momentumPbar = ptrPbar->momentum();
+ Energy mg = momentumG.m();
+
+ drawNewFlavour(ptrQ,ptrQbar,mg,Qtilde);
+
+ Energy mQ = ptrQ->data().constituentMass();
+ LorentzMomentum momentumQ, momentumQbar;
+
+ if(_findProgenitor == 5){
+
+ Lorentz5Momentum momentum5Qtemp, momentum5Qbartemp;
+ double cosThetaStar = UseRandom::rnd( -1.0 , 1.0 );
+ using Constants::pi;
+ double phiStar = UseRandom::rnd( -pi , pi );
+ Kinematics::twoBodyDecay(momentumG, mQ,
+ mQ, cosThetaStar, phiStar, momentum5Qtemp,
+ momentum5Qbartemp );
+ momentumQ = momentum5Qtemp;
+ momentumQbar = momentum5Qbartemp;
+ }
+ else{
+ //construct an orthonormal basis of transverse 4-vectors
+ ThreeVector<double> Three_qperp1 = nbar.vect().orthogonal().unit();
+ ThreeVector<double> Three_qperp2 = nbar.vect().unit().cross(Three_qperp1);
+ LorentzVector<double> qperp1(Three_qperp1,0.0);
+ LorentzVector<double> qperp2(Three_qperp2,0.0);
+
+ //get the z-value from the gluon splitting function
+ bool repeat;
+ double z,r,x;
+ if (mg < sqrt(mQ*Qtilde)){x = pow(mQ/mg,2);}
+ else {x = pow(mg/Qtilde,2);}
+ repeat = true;
+ while(repeat){
+ r = UseRandom::rnd(0.0, 1.0);
+ z = (r-0.5)*sqrt(1-4*x)+0.5;
+ r = UseRandom::rnd(0.0, 1.0-2.0*x+2.0*pow(mQ/mg,2));
+ if( r < (1-(2*z*(1-z))+2*pow(mQ/mg,2)) ){
+ repeat = false;
+ }
+ }
+
+ if (_restrictZ==1){//without this ProgenitorHasColor would not be necessary
+ if (ProgenitorHasColor){
+ if (z>0.5){z = 1.-z;} //anti-quark in direction of progenitor
+ }
+ else{
+ if (z<0.5){z = 1.-z;} //quark in direction of progenitor
+ }
+ }
+
+ //magniuted of relative transverse momentum
+ Energy qT = sqrt(sqr(mg)*z*(1.-z)-sqr(mQ));
+ //azimuthal angle of relative tranverse momentum
+ using Constants::pi;
+ double phi = UseRandom::rnd( -pi , pi );
+
+ //set the relative transverse momentum
+ LorentzMomentum qperp = qT*cos(phi)*qperp1+qT*sin(phi)*qperp2;
+
+ //calculate the quarks' momenta
+ momentumQ = z*momentumG + ( ( (mg*mg)*(1-2.*z) -2*momentumG.dot(qperp) )/( 2.*momentumG.dot(nbar) ) )*nbar + qperp;
+ momentumQbar = momentumG - momentumQ;
+
+ } //else _findProgenitor Isotropic
+
+ //without this I would not need to give also P and Pbar
+ if (((_findProgenitor == 4)||(_findProgenitor==5))&&(_restrictZ==1)){
+ LorentzMomentum c1 = momentumQ+momentumP;
+ LorentzMomentum c2 = momentumQbar+momentumPbar;
+ LorentzMomentum c3 = momentumQ+momentumPbar;
+ LorentzMomentum c4 = momentumQbar+momentumP;
+
+ //linear
+ Energy M12=c1.m()+c2.m();
+ Energy M34=c3.m()+c4.m();
+
+ //quadratic
+ //Energy2 M12 = c1.m()*c1.m() + c2.m()*c2.m();
+ //Energy2 M34 = c3.m()*c3.m() + c4.m()*c4.m();
+
+ //product
+ //Energy2 M12=c1.m()*c2.m();
+ //Energy2 M34=c3.m()*c4.m();
+
+ //maximum
+ //Energy M12 = std::max(c1.m(),c2.m());
+ //Energy M34 = std::max(c3.m(),c4.m());
+
+ if (M12 < M34){
+ swap(momentumQ,momentumQbar);
+ }
+ }
+
+ Lorentz5Momentum momentum5Q(momentumQ,mQ);
+ Lorentz5Momentum momentum5Qbar(momentumQbar,mQ);
+
+ ptrQ ->set5Momentum( momentum5Q );
+ ptrQbar ->set5Momentum( momentum5Qbar );
+
+}
+
+
+
+void DynamicPartonSplitter::splitTimeLikeGluon(tcPPtr ptrGluon, PPtr & ptrQ, PPtr & ptrQbar){
+ LorentzVector<double> nbar;
+ bool ProgenitorHasColor;
+
+ tPPtr ColorPartner = ptrGluon->antiColourLine()->endParticle();
+ tPPtr AntiColorPartner = ptrGluon->colourLine()->startParticle();
+ Findnbar(ptrGluon,ColorPartner,AntiColorPartner,nbar,ProgenitorHasColor);
+
+ splitTimeLikeGluon(ptrGluon,ptrQ,ptrQbar,ColorPartner,AntiColorPartner,_dynamicGluonMassGenerator->Qgtilde(),nbar,ProgenitorHasColor);
+}
+
+
+
+void DynamicPartonSplitter::Findnbar(tcPPtr ptrGluon, tcPPtr ptrP, tcPPtr ptrPbar, LorentzVector<double> & nbarfinal, bool & ProgenitorHasColor){
+
+ LorentzMomentum momentumG = ptrGluon->momentum();
+ LorentzMomentum momentumP = ptrP->momentum();
+ LorentzMomentum momentumPbar = ptrPbar->momentum();
+
+ LorentzMomentum nbar = momentumP;
+ ProgenitorHasColor = true;
+
+ if (_findProgenitor==0){
+ if( momentumG.vect().unit().dot( momentumPbar.vect().unit() ) > momentumG.vect().unit().dot( momentumP.vect().unit() )){
+ nbar = momentumPbar; //minimum angle theta
+ ProgenitorHasColor = false; //has anticolor
+ }
+ nbar.setVect( (-1.)*nbar.vect() );
+ }
+ else if (_findProgenitor==1){
+ if ( momentumG.vect().dot( momentumPbar.vect() ) > momentumG.vect().dot( momentumP.vect() ) ){
+ nbar = momentumPbar; //maximum |p|*cos(theta)
+ ProgenitorHasColor = false; //has anticolor
+ }
+ nbar.setVect( (-1.)*nbar.vect() );
+ }
+ else if ((_findProgenitor==2)||(_findProgenitor==3)){
+ ProgenitorHasColor = false;
+ if( pow(momentumG.vect().unit().dot( momentumPbar.vect().unit()),2) > pow(momentumG.vect().unit().dot( momentumP.vect().unit() ),2)){
+ nbar = momentumPbar; //maximum cos^2(theta) --> minimum gluon transverse momentum
+ ProgenitorHasColor = true;
+ }
+ if (_findProgenitor==3){
+ if ( momentumG.vect().unit().dot( nbar.vect().unit() ) > 0. ){
+ nbar.setVect( (-1.)*nbar.vect() ); //gluon always in forward direction
+ ProgenitorHasColor = !ProgenitorHasColor;
+ }
+ }
+ }
+ else if (_findProgenitor==4){
+ nbar = momentumG;
+ nbar.setVect( (-1.)*nbar.vect() );
+ }
+
+ nbarfinal.setT(1.0);
+ nbarfinal.setVect(nbar.vect().unit());
+}
+
+
diff --git a/Hadronization/DynamicPartonSplitter.h b/Hadronization/DynamicPartonSplitter.h
new file mode 100644
--- /dev/null
+++ b/Hadronization/DynamicPartonSplitter.h
@@ -0,0 +1,180 @@
+// -*- C++ -*-
+//
+// PartonSplitter.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_DynamicPartonSplitter_H
+#define HERWIG_DynamicPartonSplitter_H
+
+#include "CluHadConfig.h"
+#include <ThePEG/Interface/Interfaced.h>
+#include <ThePEG/Utilities/Selector.h>
+#include "PartonSplitter.h"
+#include "DynamicGluonMassGenerator.h"
+
+namespace Herwig {
+
+
+using namespace ThePEG;
+
+
+/** \ingroup Hadronization
+ * \class PartonSplitter
+ * \brief This class splits the gluons from the end of the shower.
+ * \author Philip Stephens
+ * \author Alberto Ribon
+ *
+ * This class does all of the nonperturbative parton splittings needed
+ * immediately after the end of the showering (both initial and final),
+ * as very first step of the cluster hadronization.
+ *
+ * the quarks are attributed with different weights for the splitting
+ * by default only the splitting in u and d quarks is allowed
+ * the option "set /Herwig/Hadronization/PartonSplitter:Split 1"
+ * allows for additional splitting into s quarks based on some weight
+ * in order for that to work the mass of the strange quark has to be changed
+ * from the default value s.t. m_g > 2m_s
+ *
+ *
+ * * @see \ref PartonSplitterInterfaces "The interfaces"
+ * defined for PartonSplitter.
+ */
+class DynamicPartonSplitter: public PartonSplitter {
+
+public:
+
+ /**
+ * Default constructor
+ */
+ DynamicPartonSplitter() :
+ PartonSplitter(),
+ _findProgenitor(0),
+ _restrictZ(0)
+ {}
+
+
+public:
+
+ /** @name Functions used by the persistent I/O system. */
+ //@{
+ /**
+ * Function used to write out object persistently.
+ * @param os the persistent output stream written to.
+ */
+ void persistentOutput(PersistentOStream & os) const;
+
+ /**
+ * Function used to read in object persistently.
+ * @param is the persistent input stream read from.
+ * @param version the version number of the object when written.
+ */
+ void persistentInput(PersistentIStream & is, int version);
+ //@}
+
+ /**
+ * The standard Init function used to initialize the interfaces.
+ * Called exactly once for each class by the class description system
+ * before the main function starts or
+ * when this class is dynamically loaded.
+ */
+ static void Init();
+
+protected:
+
+ /** @name Clone Methods. */
+ //@{
+ /**
+ * Make a simple clone of this object.
+ * @return a pointer to the new object.
+ */
+ virtual IBPtr clone() const;
+
+ /** Make a clone of this object, possibly modifying the cloned object
+ * to make it sane.
+ * @return a pointer to the new object.
+ */
+ virtual IBPtr fullclone() const;
+ //@}
+
+private:
+
+ /**
+ * Private and non-existent assignment operator.
+ */
+ DynamicPartonSplitter & operator=(const DynamicPartonSplitter &) = delete;
+
+
+public:
+ /**
+ * Non-perturbatively split a time-like gluon,
+ * if something goes wrong null pointers are returned.
+ * @param gluon The gluon to be split
+ * @param quark The quark produced in the splitting
+ * @param anti The antiquark produced in the splitting
+ */
+ virtual void splitTimeLikeGluon(tcPPtr gluon, PPtr & quark, PPtr & anti);
+
+
+ /**
+ * Non-perturbatively split a time-like gluon,
+ * if something goes wrong null pointers are returned.
+ * @param gluon The gluon to be split
+ * @param quark The quark produced in the splitting
+ * @param anti The antiquark produced in the splitting
+ * @colorpartner1 The color partner of the gluon
+ * @colorpartner2 The anticolor partner of the gluon
+ * @Qtilde The scale of the Sudakov in the splitting
+ * @nbar Backwards lightlike direction of the splitting
+ * @ProgenitorHasColor If the (anti)quark that is identified as the "progenitor" of the gluon has color or anticolor
+ * @
+ */
+ void splitTimeLikeGluon(tcPPtr gluon, PPtr & quark, PPtr & anti, tcPPtr colorpartner1, tcPPtr colorpartner2, Energy Qtilde, LorentzVector<double> nbar, bool ProgenitorHasColor);
+
+private:
+ /**
+ * Finding the backwards light like direction for the splitting and defining the gluon "progenitor"
+ * @gluon The gluon to be split
+ * @colorpartner1 The color partner of the gluon
+ * @colorpartner2 The anticolor partner of the gluon
+ * @nbar The lightlike vector that will be defined
+ * @ProgenitorHasColor Returns whether the "progenitor" of the gluon has color or anticolor
+ * */
+ void Findnbar(tcPPtr gluon, tcPPtr colorpartner1, tcPPtr colorpartner2, LorentzVector<double> & nbar, bool & ProgenitorHasColor);
+
+
+ /**
+ * draw the new light flavour according to probabilities given by gluon mass distribution
+ */
+ void drawNewFlavour(PPtr & ptrQ, PPtr & ptrQbar, Energy mg, Energy Qtilde);
+
+
+
+
+private:
+
+ /**
+ * switch for different options for choosing the gluon's progenitor
+ */
+ int _findProgenitor;
+
+
+ /**
+ * switch for restricting z > 0.5
+ */
+ int _restrictZ;
+
+
+ /**
+ * pointer to the dynamic gluon mass generator
+ */
+ Ptr<DynamicGluonMassGenerator>::ptr _dynamicGluonMassGenerator;
+
+
+};
+
+}
+
+#endif /* HERWIG_DynamicPartonSplitter_H */
diff --git a/Hadronization/Makefile.am b/Hadronization/Makefile.am
--- a/Hadronization/Makefile.am
+++ b/Hadronization/Makefile.am
@@ -1,23 +1,26 @@
noinst_LTLIBRARIES = libHwHadronization.la
libHwHadronization_la_SOURCES = \
CluHadConfig.h \
Cluster.h Cluster.cc Cluster.fh \
ClusterDecayer.cc ClusterDecayer.h ClusterDecayer.fh \
ClusterFinder.cc ClusterFinder.h ClusterFinder.fh \
ClusterFissioner.cc ClusterFissioner.h ClusterFissioner.fh \
MatrixElementClusterFissioner.cc MatrixElementClusterFissioner.h \
ClusterHadronizationHandler.cc ClusterHadronizationHandler.h \
ClusterHadronizationHandler.fh \
ColourReconnector.cc ColourReconnector.h ColourReconnector.fh \
+DynamicGluonMassGenerator.h DynamicGluonMassGenerator.cc \
+DynamicPartonSplitter.h DynamicPartonSplitter.cc \
+DynamicClusterFissioner.h DynamicClusterFissioner.cc \
GluonMassGenerator.h GluonMassGenerator.cc \
Hw64Selector.cc Hw64Selector.h \
HwppSelector.cc HwppSelector.h \
Hw7Selector.cc Hw7Selector.h \
LightClusterDecayer.cc LightClusterDecayer.h LightClusterDecayer.fh \
PartonSplitter.cc PartonSplitter.h PartonSplitter.fh \
SpinHadronizer.h SpinHadronizer.cc \
HadronSpectrum.h HadronSpectrum.fh HadronSpectrum.cc \
StandardModelHadronSpectrum.h StandardModelHadronSpectrum.cc \
DarkHadronSpectrum.h DarkHadronSpectrum.cc \
DarkHwppSelector.cc DarkHwppSelector.h
diff --git a/Shower/QTilde/Couplings/ShowerAlphaQCDNP.cc b/Shower/QTilde/Couplings/ShowerAlphaQCDNP.cc
--- a/Shower/QTilde/Couplings/ShowerAlphaQCDNP.cc
+++ b/Shower/QTilde/Couplings/ShowerAlphaQCDNP.cc
@@ -1,419 +1,422 @@
// -*- C++ -*-
//
// ShowerAlphaQCDNP.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 ShowerAlphaQCDNP class.
//
#include "ShowerAlphaQCDNP.h"
#include "ThePEG/PDT/ParticleData.h"
#include "ThePEG/Interface/ClassDocumentation.h"
#include "ThePEG/Interface/Switch.h"
#include "ThePEG/Interface/Parameter.h"
#include "ThePEG/Interface/ParVector.h"
#include "ThePEG/Interface/Command.h"
#include "ThePEG/Interface/Deleted.h"
#include "ThePEG/Persistency/PersistentOStream.h"
#include "ThePEG/Persistency/PersistentIStream.h"
#include "ThePEG/Utilities/Throw.h"
#include "ThePEG/Utilities/DescribeClass.h"
#include "ThePEG/Config/Constants.h"
#include "Herwig/Utilities/AlphaS.h"
#include "gsl/gsl_sf_lambert.h"
using namespace Herwig;
using Herwig::Math::alphaS;
using Herwig::Math::derivativeAlphaS;
DescribeClass<ShowerAlphaQCDNP,ShowerAlpha>
describeShowerAlphaQCDNP("Herwig::ShowerAlphaQCDNP","HwShower.so");
IBPtr ShowerAlphaQCDNP::clone() const {
return new_ptr(*this);
}
IBPtr ShowerAlphaQCDNP::fullclone() const {
return new_ptr(*this);
}
void ShowerAlphaQCDNP::persistentOutput(PersistentOStream & os) const {
os << ounit(_qmin,GeV) << _asMaxNP << _nfMaxNP
<< ounit(_thresholds,GeV) << ounit(_lambda,GeV)
<< _nloop << _thresopt
<< _alphain << _tolerance << _maxtry
<< _npPower << ounit(_optInputScale,GeV) << _quarkBranching
<< ounit(_quarkMasses,GeV);
}
void ShowerAlphaQCDNP::persistentInput(PersistentIStream & is, int) {
is >> iunit(_qmin,GeV) >> _asMaxNP >> _nfMaxNP
>> iunit(_thresholds,GeV) >> iunit(_lambda,GeV)
>> _nloop >> _thresopt
>> _alphain >> _tolerance >> _maxtry
>> _npPower >> iunit(_optInputScale,GeV) >> _quarkBranching
>> iunit(_quarkMasses,GeV);
}
void ShowerAlphaQCDNP::Init() {
static ClassDocumentation<ShowerAlphaQCDNP> documentation
("This (concrete) class describes the QCD alpha running.");
// default such that as(qmin) = 1 in the current parametrization.
- static Parameter<ShowerAlphaQCDNP,Energy> intQmin
+ static Parameter<ShowerAlphaQCDNP,Energy> interfaceQmin
("Qmin", "Q < Qmin is treated with NP parametrization as of (unit [GeV])",
- &ShowerAlphaQCDNP::_qmin, GeV, 1*GeV, 1*GeV,
+ &ShowerAlphaQCDNP::_qmin, GeV, 1*GeV, 0*GeV,
100.0*GeV,false,false,false);
static Parameter<ShowerAlphaQCDNP,unsigned int> interfaceNumberOfLoops
("NumberOfLoops",
"The number of loops to use in the alpha_S calculation",
&ShowerAlphaQCDNP::_nloop, 3, 1, 3,
false, false, Interface::limited);
static Parameter<ShowerAlphaQCDNP,double> interfaceAlphaMZ
("AlphaIn",
"The input value of the strong coupling at the chosen InputScale (default: MZ)",
&ShowerAlphaQCDNP::_alphain, 0.118, 0.1, 0.2,
false, false, Interface::limited);
static Parameter<ShowerAlphaQCDNP,double> interfaceTolerance
("Tolerance",
"The tolerance for discontinuities in alphaS at thresholds.",
&ShowerAlphaQCDNP::_tolerance, 1e-10, 1e-20, 1e-4,
false, false, Interface::limited);
static Parameter<ShowerAlphaQCDNP,unsigned int> interfaceMaximumIterations
("MaximumIterations",
"The maximum number of iterations for the Newton-Raphson method to converge.",
&ShowerAlphaQCDNP::_maxtry, 100, 10, 1000,
false, false, Interface::limited);
static Switch<ShowerAlphaQCDNP,bool> interfaceThresholdOption
("ThresholdOption",
"Whether to use the consistuent or normal masses for the thresholds",
&ShowerAlphaQCDNP::_thresopt, true, false, false);
static SwitchOption interfaceThresholdOptionCurrent
(interfaceThresholdOption,
"Current",
"Use the current masses",
true);
static SwitchOption interfaceThresholdOptionConstituent
(interfaceThresholdOption,
"Constituent",
"Use the constitent masses.",
false);
static Command<ShowerAlphaQCDNP> interfaceValue
("Value",
"",
&ShowerAlphaQCDNP::value, false);
static Command<ShowerAlphaQCDNP> interfacecheck
("check",
"check",
&ShowerAlphaQCDNP::check, false);
static Command<ShowerAlphaQCDNP> interfacecheckNf
("checkNf",
"checkNf",
&ShowerAlphaQCDNP::checkNf, false);
static Command<ShowerAlphaQCDNP> interfacecheckscaleNP
("checkscaleNP",
"checkscaleNP",
&ShowerAlphaQCDNP::checkscaleNP, false);
static Parameter<ShowerAlphaQCDNP,Energy> interfaceInputScale
("InputScale",
"An optional input scale. MZ will be used if not set.",
&ShowerAlphaQCDNP::_optInputScale, GeV, 91.1876_GeV, ZERO, 0*GeV,
false, false, Interface::lowerlim);
static ParVector<ShowerAlphaQCDNP,Energy> interfaceQuarkMasses
("QuarkMasses",
"The quark masses to be used instead of the masses set in the particle data.",
&ShowerAlphaQCDNP::_quarkMasses, GeV, -1, 0.0*GeV, 0.0*GeV, 0*GeV,
false, false, Interface::lowerlim);
static Switch<ShowerAlphaQCDNP,bool> interfaceQuarkBranching
("QuarkBranching",
"True, if this coupling is used in a gluon to qqbar branching.",
&ShowerAlphaQCDNP::_quarkBranching, false, false, false);
static SwitchOption interfaceQuarkBranchingYes
(interfaceQuarkBranching,
"Yes",
"Use in gluon to qqbar branching.",
true);
static SwitchOption interfaceQuarkBranchingNo
(interfaceQuarkBranching,
"No",
"Use in gluon emission.",
false);
static Parameter<ShowerAlphaQCDNP,double> interfaceNPPower
("NPPower",
"The non-perturbative power law",
- &ShowerAlphaQCDNP::_npPower, 2.0, 1.0, 0,
- false, false, Interface::lowerlim);
+ &ShowerAlphaQCDNP::_npPower, 2.0, 1.0, 10.,
+ false, false, false);
+
}
void ShowerAlphaQCDNP::doinit() {
ShowerAlpha::doinit();
// calculate the value of 5-flavour lambda
// evaluate the initial
// value of Lambda from alphas if needed using Newton-Raphson
_lambda[2]=computeLambda(_optInputScale,_alphain,5);
// compute the threshold matching
// top threshold
for(int ix=1;ix<4;++ix) {
if ( _quarkMasses.empty() ) {
if(_thresopt)
_thresholds[ix]=getParticleData(ix+3)->mass();
else
_thresholds[ix]=getParticleData(ix+3)->constituentMass();
} else {
// starting at zero rather than one, cf the other alphas's
_thresholds[ix] = _quarkMasses[ix+2];
}
}
// compute 6 flavour lambda by matching at top mass using Newton Raphson
_lambda[3]=computeLambda(_thresholds[3],alphaS(_thresholds[3],_lambda[2],5,_nloop),6);
// bottom threshold
// compute 4 flavour lambda by matching at bottom mass using Newton Raphson
_lambda[1]=computeLambda(_thresholds[2],alphaS(_thresholds[2],_lambda[2],5,_nloop),4);
// charm threshold
// compute 3 flavour lambda by matching at charm mass using Newton Raphson
_lambda[0]=computeLambda(_thresholds[1],alphaS(_thresholds[1],_lambda[1],4,_nloop),3);
//Energy q = scaleNPMin();
//auto nflam = getLamNf(q);
//_asMaxNP = alphaS(q, nflam.second, nflam.first, _nloop);
Energy q = scaleThatmMinimizesScaleNP() ;
_asMaxNP = value(q*q)*1.05;
//_absoluteCutoff=_qmin*pow(100.*log(10.),-1./_npPower);
- _absoluteCutoff=2.0*GeV;
+ _absoluteCutoff=_qmin*pow(log(10e100*GeV/_qmin),-1./_npPower);
_nfMaxNP = nfNP(sqr(_absoluteCutoff));
}
string ShowerAlphaQCDNP::check(string args) {
doinit();
istringstream argin(args);
double Q_low, Q_high;
long n_steps;
argin >> Q_low >> Q_high >> n_steps;
string fname;
argin >> fname;
Repository::clog() << "checking alpha_s in range [" << Q_low << "," << Q_high << "] GeV in "
<< n_steps << " steps.\nResults are written to " << fname << "\n";
double step_width = (Q_high-Q_low)/n_steps;
ofstream out (fname.c_str());
for (long k = 0; k <= n_steps; ++k) {
Energy Q = Q_low*GeV + k*step_width*GeV;
//out << (Q/GeV) << " " << value(Q*Q) << " " << _asMaxNP << "\n";
out << (Q/GeV) << " " << value(Q*Q) << "\n";
}
return "alpha_s check finished";
}
string ShowerAlphaQCDNP::checkNf(string args) {
doinit();
istringstream argin(args);
double Q_low, Q_high;
long n_steps;
argin >> Q_low >> Q_high >> n_steps;
string fname;
argin >> fname;
Repository::clog() << "checking nfNP in range [" << Q_low << "," << Q_high << "] GeV in "
<< n_steps << " steps.\nResults are written to " << fname << "\n";
double step_width = (Q_high-Q_low)/n_steps;
ofstream out (fname.c_str());
for (long k = 0; k <= n_steps; ++k) {
Energy Q = Q_low*GeV + k*step_width*GeV;
//out << (Q/GeV) << " " << nfNP(Q*Q) << " " << _nfMaxNP << "\n";
out << (Q/GeV) << " " << nfNP(Q*Q) << "\n";
}
return "nfNP check finished";
}
string ShowerAlphaQCDNP::checkscaleNP(string args) {
doinit();
istringstream argin(args);
double Q_low, Q_high;
long n_steps;
argin >> Q_low >> Q_high >> n_steps;
string fname;
argin >> fname;
Repository::clog() << "checking scaleNP (in GeV) in range [" << Q_low << "," << Q_high << "] GeV in "
<< n_steps << " steps.\nResults are written to " << fname << "\n";
double step_width = (Q_high-Q_low)/n_steps;
ofstream out (fname.c_str());
for (long k = 0; k <= n_steps; ++k) {
Energy Q = Q_low*GeV + k*step_width*GeV;
out << (Q/GeV) << " " << scaleNP(scaleFactor()*Q)/(1.*GeV) << "\n";
}
return "scaleNP check finished";
}
double ShowerAlphaQCDNP::value(const Energy2 scale) const {
Energy q = scaleFactor()*sqrt(scale);
+
+ if (q<_absoluteCutoff){
+ auto nflam = getLamNf(_absoluteCutoff);
+ double as = alphaS(scaleNP(_absoluteCutoff), nflam.second, nflam.first, _nloop);
+ return as*pow(q/_absoluteCutoff,_npPower);
+ } else {
+ auto nflam = getLamNf(q);
+ return alphaS(scaleNP(q), nflam.second, nflam.first, _nloop);
+ }
- if ( q > _absoluteCutoff ) {
- auto nflam = getLamNf(q);
- return alphaS(scaleNP(q), nflam.second, nflam.first, _nloop);
- }
-
-
- return 0.;
}
string ShowerAlphaQCDNP::value(string scale) {
istringstream readscale(scale);
double inScale; readscale >> inScale;
Energy theScale = inScale * GeV;
initialize();
ostringstream showvalue ("");
showvalue << "alpha_s (" << theScale/GeV << " GeV) = "
<< value (sqr(theScale));
return showvalue.str();
}
pair<short, Energy> ShowerAlphaQCDNP::getLamNf(Energy q) const {
short nf = 6;
// get lambda and nf according to the thresholds
if (q < _thresholds[1]) nf = 3;
else if (q < _thresholds[2]) nf = 4;
else if (q < _thresholds[3]) nf = 5;
return pair<short,Energy>(nf, _lambda[nf-3]);
}
Energy ShowerAlphaQCDNP::computeLambda(Energy match,
double alpha,
unsigned int nflav) const {
Energy lamtest=200.0*MeV;
double xtest;
unsigned int ntry=0;
do {
++ntry;
xtest = log(sqr(match/lamtest));
xtest += (alpha-alphaS(match,lamtest,nflav,_nloop))/derivativeAlphaS(match,lamtest,nflav,_nloop);
Energy newLambda = match/exp(0.5 *xtest);
lamtest = newLambda<match ? newLambda : 0.5*(lamtest+match);
}
while(abs(alpha-alphaS(match,lamtest,nflav,_nloop)) > _tolerance && ntry < _maxtry);
return lamtest;
}
// --------------------------------------------------------------------------------
// main modification for nonperturbative running in terms of changed argument and
// nonperturbative number of flavours
// --------------------------------------------------------------------------------
double ShowerAlphaQCDNP::nfNP(const Energy2 q2) const {
Energy q=sqrt(q2);
if (q<_absoluteCutoff){
- return 0.;
+ return nfNP(_absoluteCutoff*_absoluteCutoff)*pow(_absoluteCutoff/q,_npPower);
}
else{
//get p-nf
double nf=getLamNf(q).first;
//beta function coefficients; b=sum_i (alphaS/(4Pi))^i * sum_j b_ij *nf^j
using Constants::pi;
double b00 = 11.;
double b01 = - 2./3.;
double b10 = 51.;
double b11 = - 19./3.;
double c = (b00+b10*value(q2)/(4.*pi))/(b01+b11*value(q2)/(4.*pi));
//absolute number of np-flavors
double nfNPabs=(c+nf)*(q*scaleNPDerivative(q)/scaleNP(q))-c;
//return ratio of np-flavors over p-flavors
return nfNPabs/nf;
}
}
Energy ShowerAlphaQCDNP::scaleNP(const Energy q) const {
return q*(1.+(_qmin/q)*(exp(pow(_qmin/q,_npPower))-1.));
}
double ShowerAlphaQCDNP::scaleNPDerivative(const Energy q) const {
return 1.-exp(pow(_qmin/q,_npPower))*_npPower*pow(_qmin/q,1.+_npPower);
}
Energy ShowerAlphaQCDNP::scaleThatmMinimizesScaleNP() const {
double x=(1./_npPower)*gsl_sf_lambert_W0(pow(_npPower,1./(1.+_npPower))/(1.+_npPower));
return _qmin*exp(x)*pow(_npPower,1./(1.+_npPower));
}
Energy ShowerAlphaQCDNP::scaleNPMin() const {
double x=((1.+_npPower)/_npPower)*gsl_sf_lambert_W0(pow(_npPower,1./(1.+_npPower))/(1.+_npPower));
return _qmin*(-1.+exp(x)+pow(x,-1./_npPower));
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Sat, May 3, 5:53 AM (17 h, 31 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
4972828
Default Alt Text
(58 KB)
Attached To
rHERWIGHG herwighg
Event Timeline
Log In to Comment