Index: trunk/src/DglapEvolution.cpp
===================================================================
--- trunk/src/DglapEvolution.cpp (revision 420)
+++ trunk/src/DglapEvolution.cpp (revision 421)
@@ -1,510 +1,524 @@
//==============================================================================
// DglapEvolution.h
//
// Copyright (C) 2010-2019 Tobias Toll and Thomas Ullrich
//
// This file is part of Sartre.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation.
// This program is distributed in the hope that it will be useful,
// but without any warranty; without even the implied warranty of
// merchantability or fitness for a particular purpose. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see .
//
// Author: Thomas Ullrich
// $Date$
// $Author$
//==============================================================================
#include "DglapEvolution.h"
#include "TableGeneratorSettings.h"
#include "DipoleModelParameters.h"
#include
#include
#include
using namespace std;
#define PR(x) cout << #x << " = " << (x) << endl;
DglapEvolution* DglapEvolution::mInstance = 0;
DglapEvolution::DglapEvolution()
{
DipoleModelParameters parameters(TableGeneratorSettings::instance());
//
// For speed purposes the key parameters are held as data member.
// Here we assign the proper ones depending on the model and the
// parameters set choosen.
//
mAg = parameters.Ag();
mLambdaG = parameters.lambdaG();
mMu02 = parameters.mu02();
//
// Define alpha_s functor
//
mAlphaStrong = new AlphaStrong;
//
// Set alpha_s at c, b, t mass
//
mMC = mAlphaStrong->massCharm();
mMB = mAlphaStrong->massBottom();
mMT = mAlphaStrong->massTop();
const double FourPi = 4.*M_PI;
mALPC = mAlphaStrong->at(mMC*mMC)/FourPi;
mALPB = mAlphaStrong->at(mMB*mMB)/FourPi;
mALPT = mAlphaStrong->at(mMT*mMT)/FourPi;
mALPS = mAlphaStrong->at(mMu02)/FourPi;
//
// Initialization of support points in n-space and weights for the
// Gauss quadrature and of the anomalous dimensions for the RG
// evolution at these n-values.
//
//
// Weights and support points for nomalized 8 point gauss quadrature
//
double wz[9] = {0, 0.101228536290376,0.222381034453374,0.313706645877887,
0.362683783378362,0.362683783378362,0.313706645877887,
0.222381034453374,0.101228536290376};
double zs[9] = {0, -0.960289856497536,-0.796666477413627,-0.525532409916329,
-0.183434642495650,0.183434642495650,0.525532409916329,
0.796666477413627,0.960289856497536};
//
// Integration contour parameters
//
double down[18] = {0, 0., 0.5, 1., 2., 3., 4., 6., 8.,
1.e1, 1.2e1, 1.5e1, 1.8e1, 2.1e1, 2.4e1, 2.7e1, 3.e1, 3.3e1};
double up[18];
mC = 0.8;
double phi = M_PI * 3./4.;
double co = cos(phi);
double si = sin(phi);
mCC = complex(co, si);
for (int i=1; i <=16; i++) up[i] = down[i+1];
up[17] = 36.;
//
// Support points and weights for the gauss integration
// (the factor (up-down)/2 is included in the weights)
//
int k = 0;
double sum, diff, z;
for (int i=1; i <=17; i++) {
sum = up[i] + down[i];
diff = up[i] - down[i];
for (int j=1; j <=8; j++) {
k++;
z = 0.5 * (sum + diff * zs[j]);
mWN[k] = diff / 2.* wz[j];
mN[k] = complex(mC+co*z+1.,si*z);
}
}
anom();
//
// Defaults for lookup table
//
mTableMinX = 1.e-10;
mTableMaxX = 1;
mTableMinQ2 = 1.;
mTableMaxQ2 = 1e6;
mLookupTableIsFilled = false;
mUseLookupTable = false;
mNumberOfNodesInX = mNumberOfNodesInQ2 = 0;
}
DglapEvolution::~DglapEvolution()
{
if (mAlphaStrong) delete mAlphaStrong;
if (mLookupTableIsFilled) {
for (unsigned int i = 0; i < mNumberOfNodesInQ2; ++i)
delete [] mLookupTable[i];
delete [] mLookupTable;
}
}
double DglapEvolution::alphaSxG(double x, double Q2)
{
double val = xG(x, Q2);
return val*mAlphaStrong->at(Q2);
}
double DglapEvolution::xG(double x, double Q2)
{
double result = 0;
if (!mUseLookupTable) {
result = xG_Engine(x, Q2);
}
else if (mUseLookupTable && !mLookupTableIsFilled) {
cout << "DglapEvolution::xG(): Warning, use of lookup table requested\n"
<< " but table is not setup. First use \n"
<< " generateLookupTable() to fill table.\n"
<< " Will fall back to numeric calculation."
<< endl;
result = xG_Engine(x, Q2);
}
else
result = xG_Interpolator(x, Q2);
return result;
}
double DglapEvolution::xG_Engine(double x, double Q2)
{
//
// These are provided by AlphaStrong ensuring
// consistency between evolution and alpha_s.
//
if (mAlphaStrong->order() != 0) {
cout << "DglapEvolution::xG_Engine(): Fatal error, alpha_s is in order "
<< mAlphaStrong->order()
<< " but DglapEvolution only support order = 0. Stop here." << endl;
exit(1);
}
double alpq = mAlphaStrong->at(Q2)/(4*M_PI);
//
// Q2 and x dependent quantities
//
double ax = log(x);
double ex = exp(-mC * ax);
//
// integration length parameter for the mellin inversion
//
const int nmax = 136;
//
// Gluon density and output
//
complex fn[137];
reno(fn, alpq, nmax, mAg, mLambdaG);
long double fun = 0; // long double is needed
long double fz;
complex xnm,cex;
for (int i=1; i <= nmax; i++) {
xnm = (mC - mN[i]+1.) * ax;
cex = exp(xnm) / M_PI * mCC;
fz = imag(fn[i]*cex);
fun = fun + mWN[i] * fz;
}
double pa = fun * ex;
return pa;
}
void DglapEvolution::generateLookupTable(int nx, int nq2)
{
//
// Delete old lookup table (if it exists)
//
if (mLookupTableIsFilled) {
for (unsigned int i = 0; i < mNumberOfNodesInQ2; ++i)
delete [] mLookupTable[i];
delete [] mLookupTable;
}
mNumberOfNodesInX = nx;
mNumberOfNodesInQ2 = nq2;
//
// Create new table
//
mLookupTable = new double*[mNumberOfNodesInQ2];
for(unsigned int i = 0; i < mNumberOfNodesInQ2; ++i)
mLookupTable[i] = new double[mNumberOfNodesInX];
//
// Fill lookup table
//
int printEach = mNumberOfNodesInQ2*mNumberOfNodesInX/10;
int nCount = 0;
cout << "DglapEvolution: generating lookup table "; cout.flush();
for (unsigned int i = 0; i < mNumberOfNodesInQ2; i++) {
double Q2 = pow(mTableMaxQ2/mTableMinQ2,i*1./(mNumberOfNodesInQ2-1.))*mTableMinQ2;
for (unsigned int j = 0; j < mNumberOfNodesInX; j++) {
double x = pow(mTableMaxX/mTableMinX,j*1./(mNumberOfNodesInX-1.))*mTableMinX;
mLookupTable[i][j] = xG_Engine(x, Q2);
nCount++;
if (nCount%printEach == 0) cout << '.'; cout.flush();
}
}
cout << " done" << endl;
mLookupTableIsFilled = true;
}
double DglapEvolution::luovi(double f[4], double arg[4], double z)
{
double cof[4];
for (int i=0; i < 4; i++ ) cof[i]=f[i];
for (int i=0; i < 3 ; i++) {
for (int j=i; j < 3 ; j++) {
int jndex = 2 - j;
int index = jndex + 1 + i;
cof[index]= (cof[index]-cof[index-1])/(arg[index]-arg[jndex]);
}
}
double sum=cof[3];
for (int i=0; i < 3; i++ ) {
int index = 2 - i;
sum = (z-arg[index])*sum + cof[index];
}
return sum;
}
double DglapEvolution::xG_Interpolator(double x, double Q2)
{
int q2steps = mNumberOfNodesInQ2-1;
int xsteps = mNumberOfNodesInX-1;
//
// Position in the Q2 grid
//
double realq = q2steps * log(Q2/mTableMinQ2)/log(mTableMaxQ2/mTableMinQ2);
int n_q2 = static_cast(realq);
if (n_q2 <= 0) {n_q2 = 1;}
if (n_q2 > q2steps-2) {n_q2 = n_q2-2;}
//
// Position in the x grid
//
double realx = xsteps * log(x/mTableMinX)/log(mTableMaxX/mTableMinX);
int n_x = static_cast(realx);
if (n_x <= 0) { n_x = 1;}
if (n_x > xsteps-2){ n_x = n_x-2;}
//
// Starting the interpolation
//
double arg[4];
for (int i=0; i < 4; i++) { arg[i] = n_x-1+i;}
double fu[4], fg[4];
for (int i=0; i < 4; i++) {
fu[0] = mLookupTable[n_q2-1+i][n_x-1];
fu[1] = mLookupTable[n_q2-1+i][n_x];
fu[2] = mLookupTable[n_q2-1+i][n_x+1];
fu[3] = mLookupTable[n_q2-1+i][n_x+2];
fg[i] = luovi(fu,arg,realx);
}
for (int i=0; i < 4; i++) { arg[i] = n_q2-1+i;}
return luovi(fg, arg, realq);
}
void DglapEvolution::reno(complex *fn, double alpq, int nmax, double ag, double lambdag)
{
//
// Mellin-n space Q**2 - evolution of the gluon at LO
//
// The moments are calculated on an array of moments, mN, suitable
// for a (non-adaptive) Gauss quadrature.
//
// Currently this takes the simplest possible fit form:
// xg = A_g x^(-lambdag) (1-x)^(5.6), following Amir&Raju
//
for (int k1 = 1; k1 <= nmax; k1++) {
//
// Input moments of the parton densities
// at the low scale
//
complex xn = mN[k1];
complex gln = ag * (1.0 / (xn + 5.0 - lambdag)
- 6.0 / (xn + 4.0 - lambdag)
+ 15.0 / (xn + 3.0 - lambdag)
- 20.0 / (xn + 2.0 -lambdag)
+ 15.0 / (xn + 1.0 - lambdag)
- 6.0 / (xn - lambdag)
+ 1.0 / (xn - lambdag - 1.0));
int f;
double xl, s, alp;
complex ep, gl;
if (alpq >= mALPC) { // evolution below the charm threshold
f = 3;
xl = mALPS / alpq;
s = log(xl);
ep = exp(-mAP[k1][f]*s);
gl = gln;
gln = ep * gl;
}
else if ((alpq < mALPC) && (alpq >= mALPB)) { // between thresholds
f = 3;
xl = mALPS / mALPC;
s = log(xl);
ep = exp(-mAP[k1][f]*s);
gl = gln;
gln = ep * gl;
f = 4;
xl = mALPC / alpq;
s = log(xl);
ep = exp(-mAP[k1][f]*s);
gl = gln;
gln = ep * gl;
}
else if (alpq < mALPB) { // above bottom threshold
f = 3;
xl = mALPS / mALPC;
s = log (xl);
ep = exp (- mAP[k1][f]*s);
gl = gln;
gln = ep * gl;
f = 4;
alp = mALPB;
xl = mALPC / mALPB;
s = log (xl);
ep = exp(-mAP[k1][f]*s);
gl = gln;
gln = ep * gl;
f = 5;
xl = mALPB / alpq;
s = log(xl);
ep = exp(-mAP[k1][f]*s);
gl = gln;
gln = ep * gl;
}
fn[k1] = gln;
}
}
void DglapEvolution::anom() {
//
// Anomalous dimensions for leading order evolution of parton densities.
// The moments are calculated on an externally given array of mellin
// moments, mN, suitable for a (non-adaptive) quadrature.
//
// Present version: the number of active flavours in the factorization
// is fixed to ff=3, in the beta-function it varies between f=3 and
// f=5. The dimension of the moment array is 136.
//
double b0, b02;
complex ggi, ggf;
complex xn, xap;
complex gg;
for (int k1=1; k1 <= 136; k1++) {
xn = mN[k1];
anCalc(ggi, ggf, xn);
for (int k2=3; k2 <= 5; k2++) {
double f = k2;
// anomalous dimensions and related quantities in leading order
b0 = 11.- 2./3.* f;
b02 = 2.* b0;
gg = ggi + f * ggf;
xap = gg / b02;
mAP[k1][k2] = xap;
}
}
}
void DglapEvolution::anCalc(complex& ggi,
complex& ggf, complex& xn)
{
complex xn1 = xn + 1.;
complex xn2 = xn + 2.;
complex xnm = xn - 1.;
//
// Leading order
//
complex cpsi = psiFunction(xn1) + 0.577216;
ggi = -22.- 24./(xn * xnm) - 24./(xn1 * xn2) + 24.* cpsi;
ggf = 4./3.;
}
complex DglapEvolution::psiFunction(complex z)
{
//
// psi - function for complex argument
//
complex sub;
while (real(z) < 10) {
sub = sub - 1./z;
z += 1.;
}
complex rz = 1./z;
complex dz = rz * rz;
complex result = sub + log(z) - rz/2.- dz/2520. * ( 210.+ dz * (-21.+10.*dz ));
return result;
}
double DglapEvolution::logDerivative(double x, double Q2)
{
double alpq = mAlphaStrong->at(Q2)/(4*M_PI);
//
// Q2 and x dependent quantities
//
double ax = log(x);
double ex = exp(-mC * ax);
//
// integration length parameter for the mellin inversion
//
const int nmax = 136;
//
// Gluon density and output
//
complex fn[137];
reno(fn, alpq, nmax, mAg, mLambdaG);
long double fun = 0; // long double is needed
long double fz;
complex xnm,cex;
for (int i=1; i <= nmax; i++) {
xnm = (mC - mN[i]+1.) * ax;
cex = exp(xnm) / M_PI * mCC;
fz = imag(fn[i]*cex);
fun = fun + mWN[i] * fz;
}
double glue = fun * ex;
fun = 0;
for (int i=1; i <= nmax; i++) {
xnm = (mC - mN[i]+1.) * ax;
cex = exp(xnm) / M_PI * mCC;
fz = imag(fn[i]*cex*mN[i]);
fun = fun + mWN[i] * fz;
}
double pa = fun * ex;
double lambda = -(1-pa/glue);
return lambda;
}
+void DglapEvolution::list(ostream& os)
+{
+ os << "DglapEvolution parameters:" << endl;
+ os << " Ag = " << mAg << endl;
+ os << " lambdaG = " << mLambdaG << endl;
+ os << " mu02 = " << mMu02 << endl;
+ os << " m_c = " << mMC << " (from AlphaStrong)" << endl;
+ os << " m_b = " << mMB << " (from AlphaStrong)" << endl;
+ os << " m_t = " << mMT << " (from AlphaStrong)" << endl;
+ if (mUseLookupTable)
+ os << " Lookup table in use" << endl;
+ else
+ os << " Lookup table not used" << endl;
+}
Index: trunk/src/DglapEvolution.h
===================================================================
--- trunk/src/DglapEvolution.h (revision 420)
+++ trunk/src/DglapEvolution.h (revision 421)
@@ -1,145 +1,147 @@
//==============================================================================
// DglapEvolution.h
//
// Copyright (C) 2010-2019 Tobias Toll and Thomas Ullrich
//
// This file is part of Sartre.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation.
// This program is distributed in the hope that it will be useful,
// but without any warranty; without even the implied warranty of
// merchantability or fitness for a particular purpose. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see .
//
// Author: Thomas Ullrich
// $Date$
// $Author$
//==============================================================================
// LO DGLAP evolution
//
// This class is a singleton.
//
// The evolution functions xG() and alphasxG()
// take as arguments:
//
// x : Bjorken momentum fraction
// Q2: Virtuality in GeV^2
//
// DglapEvolution::xG() returns x*G(x, Q^2)
// DglapEvolution::alphaSxG() returns alpha_s(Q^2)*x*G(x,Q^2)
//
// This is a rewrite of code written in F77. The documentation is
// largely left as provided in the Fortran version but includes
// the updated variable and function names. Data originally stored
// in common blocks and several static variables turned into data members.
// Some relics of the original F77 code remained such as array
// indexing starting at 1 (arrays are size +1 here).
// The code was substantially simplified and is limited to work
// only in LO.
//
// Lookup Table:
// To speed up things the class features a lookup table mechanism.
// Lookup tables are generated by calling:
//
// DglapEvolution::generateLookupTable(int nx = 200, int nq2 = 200);
//
// where nx and nq2 is the granularity in x and Q2. Loopkup tables
// are kept in memory. The method generateLookupTable() can be called
// multiple times with different sized if needed. The use of the lookup
// table is switched on or off at any time via:
//
// DglapEvolution::useLookupTable(bool val);
//
// If switched off the lookup table is *not* deleted. It just instructs
// xG() to not use the lookup table.
// The current state can be checked via lookupTableIsUsed().
//==============================================================================
#ifndef DglapEvolution_h
#define DglapEvolution_h
#include
#include
#include "AlphaStrong.h"
using namespace std;
class DglapEvolution {
public:
static DglapEvolution& instance();
~DglapEvolution();
double xG(double x, double Q2);
double alphaSxG(double x, double Q2);
double logDerivative(double x, double Q2); // dlog(xG)/dlog(1/x)
void generateLookupTable(int nx = 200, int nq2 = 200);
void useLookupTable(bool);
bool lookupTableIsUsed() const;
-
+
+ void list(ostream& = cout);
+
private:
DglapEvolution();
private:
void anom();
void anCalc(complex& ggi, complex& ggf, complex& xn);
complex psiFunction(complex);
complex lngam(complex X);
complex beta(complex, complex);
void reno(complex* fn, double alpq, int nmax, double ag, double lambdag);
double xG_Interpolator(double x, double Q2);
double xG_Engine(double x, double Q2);
double luovi( double f[4], double arg[4], double z);
private:
static DglapEvolution* mInstance;
double mMu02;
double mAg;
double mLambdaG;
complex mCC;
complex mAP[137][6];
complex mN[137];
double mWN[137];
double mC;
double mALPS;
double mALPC;
double mALPB;
double mALPT;
double mMUR;
double mMC;
double mMB;
double mMT;
bool mLookupTableIsFilled;
bool mUseLookupTable;
unsigned int mNumberOfNodesInX;
unsigned int mNumberOfNodesInQ2;
double mTableMinX;
double mTableMaxX;
double mTableMinQ2;
double mTableMaxQ2;
double **mLookupTable;
AlphaStrong *mAlphaStrong;
};
inline void DglapEvolution::useLookupTable(bool val) {mUseLookupTable = val;}
inline bool DglapEvolution::lookupTableIsUsed() const
{
return mUseLookupTable && mLookupTableIsFilled;
}
inline DglapEvolution& DglapEvolution::instance()
{
if (!mInstance) mInstance = new DglapEvolution;
return *mInstance;
}
#endif