tparton 0.1.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- tparton-0.1.1/LICENSE +9 -0
- tparton-0.1.1/PKG-INFO +15 -0
- tparton-0.1.1/README.md +3 -0
- tparton-0.1.1/pyproject.toml +18 -0
- tparton-0.1.1/src/tparton/__init__.py +2 -0
- tparton-0.1.1/src/tparton/__main__.py +13 -0
- tparton-0.1.1/src/tparton/m_evolution.py +235 -0
- tparton-0.1.1/src/tparton/t_evolution.py +231 -0
tparton-0.1.1/LICENSE
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
Copyright 2024 Congzhou M Sha (cms6712@psu.edu)
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
4
|
+
|
|
5
|
+
Usage of these programs should cite the publication or preprint associated with this work.
|
|
6
|
+
|
|
7
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
tparton-0.1.1/PKG-INFO
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: tparton
|
|
3
|
+
Version: 0.1.1
|
|
4
|
+
Summary: Evolution of the transversity parton distribution functions via two methods: (1) direct integration of the DGLAP equations along the energy scale and (2) fast Mellin inversion.
|
|
5
|
+
Author-email: Congzhou M Sha <cms6712@psu.edu>
|
|
6
|
+
License-File: LICENSE
|
|
7
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
8
|
+
Classifier: Operating System :: OS Independent
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Requires-Python: >=3.8
|
|
11
|
+
Description-Content-Type: text/markdown
|
|
12
|
+
|
|
13
|
+
# tParton
|
|
14
|
+
|
|
15
|
+
This is an evolution code for the transversity parton distribution functions encountered in hadronic physics.
|
tparton-0.1.1/README.md
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "tparton"
|
|
3
|
+
version = "0.1.1"
|
|
4
|
+
authors = [
|
|
5
|
+
{ name = "Congzhou M Sha", email="cms6712@psu.edu" }
|
|
6
|
+
]
|
|
7
|
+
description = "Evolution of the transversity parton distribution functions via two methods: (1) direct integration of the DGLAP equations along the energy scale and (2) fast Mellin inversion."
|
|
8
|
+
readme = "README.md"
|
|
9
|
+
requires-python = ">=3.8"
|
|
10
|
+
classifiers = [
|
|
11
|
+
"Programming Language :: Python :: 3",
|
|
12
|
+
"License :: OSI Approved :: MIT License",
|
|
13
|
+
"Operating System :: OS Independent",
|
|
14
|
+
]
|
|
15
|
+
[build-system]
|
|
16
|
+
requires = ["hatchling", "numpy>=2.0", "scipy>=1.13"]
|
|
17
|
+
build-backend = "hatchling.build"
|
|
18
|
+
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
method = 'm'
|
|
3
|
+
if len(sys.argv) == 2:
|
|
4
|
+
method = sys.argv[1]
|
|
5
|
+
|
|
6
|
+
if method == 'm':
|
|
7
|
+
print("Vogelsang's moment method")
|
|
8
|
+
from .m_evolution import main
|
|
9
|
+
main()
|
|
10
|
+
else:
|
|
11
|
+
print("Hirai's energy scale method")
|
|
12
|
+
from .t_evolution import main
|
|
13
|
+
main()
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
# Copyright Congzhou M Sha 2024
|
|
2
|
+
import mpmath as mp
|
|
3
|
+
import numpy as np
|
|
4
|
+
from scipy.interpolate import interp1d as interp
|
|
5
|
+
from mpmath import invertlaplace, mpc, pi, zeta, psi, euler as euler_gamma
|
|
6
|
+
|
|
7
|
+
mp.dp = 16
|
|
8
|
+
zeta2 = zeta(2)
|
|
9
|
+
zeta3 = zeta(3)
|
|
10
|
+
|
|
11
|
+
def constants(CG, Nf):
|
|
12
|
+
NC = CG
|
|
13
|
+
CF = (NC * NC - 1) / NC / 2
|
|
14
|
+
TR = 1/2
|
|
15
|
+
Tf= TR * Nf
|
|
16
|
+
beta0 = 11 / 3 * CG - 4 / 3 * TR * Nf
|
|
17
|
+
beta1 = 34 / 3 * CG ** 2 - 10 / 3 * CG * Nf - 2 * CF * Nf
|
|
18
|
+
return NC, CF, TR, Tf, beta0, beta1
|
|
19
|
+
|
|
20
|
+
psi0 = lambda s: psi(0,s)
|
|
21
|
+
psi_p = lambda s: psi(1,s)
|
|
22
|
+
psi_pp = lambda s: psi(2,s)
|
|
23
|
+
|
|
24
|
+
# Special functions which analytically continue the zeta function
|
|
25
|
+
S_1 = lambda n: euler_gamma + psi0(n+1)
|
|
26
|
+
S_2 = lambda n: zeta2 - psi_p(n+1)
|
|
27
|
+
S_3 = lambda n: zeta3 + 0.5 * psi_pp(n+1)
|
|
28
|
+
|
|
29
|
+
etaN = lambda n, eta: 1 if eta == 1 else mp.power(eta, n)
|
|
30
|
+
|
|
31
|
+
def S_p1(n, f):
|
|
32
|
+
return 0.5 * (
|
|
33
|
+
(1 + f) * S_1(n/2) + (1 - f) * S_1((n-1)/2))
|
|
34
|
+
|
|
35
|
+
def S_p2(n, f):
|
|
36
|
+
return 0.5 * (
|
|
37
|
+
(1 + f) * S_2(n/2) + (1 - f) * S_2((n-1)/2))
|
|
38
|
+
|
|
39
|
+
def S_p3(n, f):
|
|
40
|
+
return 0.5 * (
|
|
41
|
+
(1 + f) * S_3(n/2) + (1 - f) * S_3((n-1)/2))
|
|
42
|
+
|
|
43
|
+
G = lambda n: psi0((n+1)/2) - psi0(n/2)
|
|
44
|
+
|
|
45
|
+
def Stilde(n, f):
|
|
46
|
+
temp = -5/8 * zeta3
|
|
47
|
+
term = f
|
|
48
|
+
term *= S_1(n) / n / n - zeta2/2 * G(n) + \
|
|
49
|
+
mp.quad(lambda t: mp.power(t, n-1) * mp.polylog(2, t) / (1 + t), [0, 1])
|
|
50
|
+
return temp + term
|
|
51
|
+
|
|
52
|
+
def mellin(f, s):
|
|
53
|
+
return mp.quad(lambda t: mp.power(t, s-1) * f(t), [0, 1])
|
|
54
|
+
|
|
55
|
+
def inv_mellin(f, x):
|
|
56
|
+
res = invertlaplace(f, -mp.log(x), method='cohen', degree=3)
|
|
57
|
+
print(x, x*res)
|
|
58
|
+
return res
|
|
59
|
+
|
|
60
|
+
def evolve(
|
|
61
|
+
pdf,
|
|
62
|
+
Q0_2=0.16,
|
|
63
|
+
Q2=5.0,
|
|
64
|
+
l_QCD=0.25,
|
|
65
|
+
Nf=5,
|
|
66
|
+
CG=3,
|
|
67
|
+
morp='minus',
|
|
68
|
+
order=2,
|
|
69
|
+
n_x=200,
|
|
70
|
+
splittingMoments=False
|
|
71
|
+
):
|
|
72
|
+
'''
|
|
73
|
+
Evolve the transversity PDF
|
|
74
|
+
***************************
|
|
75
|
+
Parameters:
|
|
76
|
+
pdf: 1D or 2D array-like
|
|
77
|
+
the input first moment. If 1D, assumed to be at x
|
|
78
|
+
evenly distributed on [0, 1] inclusive.
|
|
79
|
+
|
|
80
|
+
Q0_2: float
|
|
81
|
+
initial Q^2
|
|
82
|
+
|
|
83
|
+
Q2: float
|
|
84
|
+
final evolved Q^2
|
|
85
|
+
|
|
86
|
+
l_QCD: float
|
|
87
|
+
QCD energy scale
|
|
88
|
+
|
|
89
|
+
n_f: int
|
|
90
|
+
number of flavors
|
|
91
|
+
|
|
92
|
+
n_t: int
|
|
93
|
+
number of time steps
|
|
94
|
+
|
|
95
|
+
n_z: int
|
|
96
|
+
the number of z steps to take in integral
|
|
97
|
+
|
|
98
|
+
morp: 'plus' or 'minus'
|
|
99
|
+
type of pdf (plus or minus type)
|
|
100
|
+
|
|
101
|
+
order: int
|
|
102
|
+
1: first-order
|
|
103
|
+
2: second-order
|
|
104
|
+
|
|
105
|
+
splittingMoments: bool
|
|
106
|
+
True: return splitting function moments
|
|
107
|
+
False: do not return splitting function moments
|
|
108
|
+
'''
|
|
109
|
+
|
|
110
|
+
# Calculate the color constants
|
|
111
|
+
if pdf.shape[-1] == 1:
|
|
112
|
+
xs = np.linspace(0, 1, len(pdf))
|
|
113
|
+
else:
|
|
114
|
+
xs, pdf = pdf[:, 0], pdf[:, 1]
|
|
115
|
+
pdf = pdf / (xs + 1e-100)
|
|
116
|
+
pdf[0] = 0
|
|
117
|
+
pdf[1] = 0
|
|
118
|
+
pdf_fun = interp(xs, pdf, fill_value=0, assume_sorted=True)
|
|
119
|
+
pdf = lambda x: mp.mpf(pdf_fun(float(x)).item())
|
|
120
|
+
|
|
121
|
+
eta = 1 if morp == 'plus' else -1
|
|
122
|
+
|
|
123
|
+
NC, CF, TR, Tf, beta0, beta1 = constants(CG, Nf)
|
|
124
|
+
|
|
125
|
+
# Corresponds to MDTP_qq_LO
|
|
126
|
+
LO_splitting_function_moment = lambda n: CF * (1.5 - 2 * S_1(n))
|
|
127
|
+
# Corresponds to MDTP_qq_NLO
|
|
128
|
+
def NLO_splitting_function_moment(n):
|
|
129
|
+
f = etaN(n, eta)
|
|
130
|
+
return \
|
|
131
|
+
CF * CF * (
|
|
132
|
+
3 / 8
|
|
133
|
+
+ (1-eta) / (n * (n + 1))
|
|
134
|
+
- 3 * S_2(n)
|
|
135
|
+
- 4 * S_1(n) * (S_2(n) - S_p2(n, f))
|
|
136
|
+
- 8 * Stilde(n, f)
|
|
137
|
+
+ S_p3(n, f)
|
|
138
|
+
) + \
|
|
139
|
+
0.5 * CF * NC * (
|
|
140
|
+
17 / 12
|
|
141
|
+
- (1 - eta) / (n * (n + 1))
|
|
142
|
+
- 134 / 9 * S_1(n)
|
|
143
|
+
+ 22 / 3 * S_2(n)
|
|
144
|
+
+ 4 * S_1(n) * (2 * S_2(n) - S_p2(n, f))
|
|
145
|
+
+ 8 * Stilde(n, f)
|
|
146
|
+
- S_p3(n, f)
|
|
147
|
+
) + \
|
|
148
|
+
2 / 3 * CF * Tf * (
|
|
149
|
+
-1 / 4
|
|
150
|
+
+ 10 / 3 * S_1(n)
|
|
151
|
+
- 2 * S_2(n)
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
def alpha_S(Q2):
|
|
155
|
+
ln_Q2_L_QCD = mp.log(Q2) - 2 * mp.log(l_QCD)
|
|
156
|
+
ln_ln_Q2_L_QCD = mp.log(ln_Q2_L_QCD)
|
|
157
|
+
|
|
158
|
+
alpha_S = 4 * pi / beta0 / ln_Q2_L_QCD
|
|
159
|
+
if order == 2:
|
|
160
|
+
alpha_S -= 4 * pi * beta1 / mp.power(beta0, 3) * ln_ln_Q2_L_QCD / ln_Q2_L_QCD / ln_Q2_L_QCD
|
|
161
|
+
return alpha_S
|
|
162
|
+
|
|
163
|
+
def evolveMoment(n, pdf_m):
|
|
164
|
+
total = 1
|
|
165
|
+
total += (alpha_S(Q0_2) - alpha_S(Q2)) / pi / beta0 * (NLO_splitting_function_moment(n) - beta1 / 2 / beta0 * LO_splitting_function_moment(n))
|
|
166
|
+
total *= mp.power(alpha_S(Q2) / alpha_S(Q0_2), -2 / beta0 * LO_splitting_function_moment(n)) * pdf_m
|
|
167
|
+
return total
|
|
168
|
+
|
|
169
|
+
if n_x > 0:
|
|
170
|
+
xs = np.linspace(0, 1, n_x+2)
|
|
171
|
+
xs = xs[1:-1]
|
|
172
|
+
|
|
173
|
+
# Perform Mellin transform
|
|
174
|
+
pdf_m = lambda s: mellin(pdf, s)
|
|
175
|
+
# Evolve moments
|
|
176
|
+
pdf_evolved_m = lambda s: mpc(evolveMoment(s, pdf_m(s)))
|
|
177
|
+
# Invert Mellin transform
|
|
178
|
+
pdf_evolved = np.array([inv_mellin(pdf_evolved_m, x).__complex__().real for x in xs])
|
|
179
|
+
pdf_evolved[0] = 0
|
|
180
|
+
pdf_evolved[-1] = 0
|
|
181
|
+
xs = np.pad(xs, 1)
|
|
182
|
+
xs[-1] = 1
|
|
183
|
+
pdf_evolved = np.pad(pdf_evolved, 1)
|
|
184
|
+
pdf_evolved = np.stack((xs, np.array(xs) * np.array(pdf_evolved)))
|
|
185
|
+
print('Done!')
|
|
186
|
+
return pdf_evolved
|
|
187
|
+
|
|
188
|
+
def main():
|
|
189
|
+
import argparse, sys
|
|
190
|
+
parser = argparse.ArgumentParser(description='Evolution of the nonsinglet transversity PDF, using Vogelsang\'s moment method.')
|
|
191
|
+
parser.add_argument('input', action='store', type=str,
|
|
192
|
+
help='The CSV file containing (x,x*PDF(x)) pairs on each line. If only a single number on each line, we assume a linear spacing for x between 0 and 1 inclusive')
|
|
193
|
+
parser.add_argument('Q0sq', action='store', type=float, help='The starting energy scale in units of GeV^2')
|
|
194
|
+
parser.add_argument('Qsq', action='store', type=float, help='The ending energy scale in units of GeV^2')
|
|
195
|
+
parser.add_argument('--morp', nargs='?', action='store', type=str, default='plus', help='The plus vs minus type PDF (default is \'plus\')')
|
|
196
|
+
parser.add_argument('-o', action='store', nargs='?', type=str, default='out.dat', help='Output file for the PDF, stored as (x,x*PDF(x)) pairs.')
|
|
197
|
+
parser.add_argument('-l', metavar='l_QCD', nargs='?', action='store', type=float, default=0.25, help='The QCD scale parameter (default 0.25 GeV^2)')
|
|
198
|
+
parser.add_argument('--nf', metavar='n_f', nargs='?', action='store', type=int, default=5, help='The number of flavors (default 5)')
|
|
199
|
+
parser.add_argument('--nc', metavar='n_c', nargs='?', action='store', type=int, default=3, help='The number of colors (default 3)')
|
|
200
|
+
parser.add_argument('--order', metavar='order', nargs='?', action='store', type=int, default=2, help='1: leading order, 2: NLO DGLAP (default 2)')
|
|
201
|
+
parser.add_argument('--nx', metavar='n_x', nargs='?', action='store', type=int, default=-1, help='The number of x values to sample the evolved PDF (default -1). If left at -1, will sample at input xs.')
|
|
202
|
+
parser.add_argument('--delim', nargs='?', action='store', type=str, default=' ', help='Delimiter for the output (default \' \'). If given without an argument, then the delimiter is whitespace (i.e. Mathematica output.)')
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
args = parser.parse_args()
|
|
206
|
+
f = args.input
|
|
207
|
+
if args.delim is None:
|
|
208
|
+
pdf = np.genfromtxt(f)
|
|
209
|
+
args.delim = ' '
|
|
210
|
+
else:
|
|
211
|
+
pdf = np.genfromtxt(f, delimiter=args.delim)
|
|
212
|
+
Q0sq = args.Q0sq
|
|
213
|
+
Qsq = args.Qsq
|
|
214
|
+
morp = args.morp
|
|
215
|
+
l = args.l
|
|
216
|
+
nf = args.nf
|
|
217
|
+
nc = args.nc
|
|
218
|
+
order = args.order
|
|
219
|
+
nx = args.nx
|
|
220
|
+
|
|
221
|
+
res = evolve(pdf,
|
|
222
|
+
Q0_2=Q0sq,
|
|
223
|
+
Q2=Qsq,
|
|
224
|
+
l_QCD=l,
|
|
225
|
+
Nf=nf,
|
|
226
|
+
CG=nc,
|
|
227
|
+
morp=morp,
|
|
228
|
+
order=order,
|
|
229
|
+
n_x=nx
|
|
230
|
+
)
|
|
231
|
+
|
|
232
|
+
np.savetxt(args.o, res.T, delimiter=args.delim)
|
|
233
|
+
|
|
234
|
+
if __name__ == '__main__':
|
|
235
|
+
main()
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
# Copyright Congzhou M Sha 2024
|
|
2
|
+
import numpy as np
|
|
3
|
+
from scipy.integrate import simpson
|
|
4
|
+
from numpy.core.multiarray import interp
|
|
5
|
+
from scipy.special import spence
|
|
6
|
+
|
|
7
|
+
def evolve(
|
|
8
|
+
pdf,
|
|
9
|
+
Q0_2=0.16,
|
|
10
|
+
Q2=5.0,
|
|
11
|
+
l_QCD=0.25,
|
|
12
|
+
n_f=3,
|
|
13
|
+
n_t=100,
|
|
14
|
+
n_z=500,
|
|
15
|
+
morp='plus',
|
|
16
|
+
order=2,
|
|
17
|
+
logScale=False
|
|
18
|
+
):
|
|
19
|
+
'''
|
|
20
|
+
Evolve the transversity PDF
|
|
21
|
+
***************************
|
|
22
|
+
Parameters:
|
|
23
|
+
pdf: array-like
|
|
24
|
+
the input first moment (assumed to be at x
|
|
25
|
+
evenly distributed on [0, 1] inclusive)
|
|
26
|
+
|
|
27
|
+
Q0_2: float
|
|
28
|
+
initial Q^2
|
|
29
|
+
|
|
30
|
+
Q2: float
|
|
31
|
+
final evolved Q^2
|
|
32
|
+
|
|
33
|
+
l_QCD: float
|
|
34
|
+
QCD energy scale
|
|
35
|
+
|
|
36
|
+
n_f: int
|
|
37
|
+
number of flavors
|
|
38
|
+
|
|
39
|
+
n_t: int
|
|
40
|
+
number of time steps
|
|
41
|
+
|
|
42
|
+
n_z: int
|
|
43
|
+
the number of z steps to take in integral
|
|
44
|
+
|
|
45
|
+
morp: 'plus' or 'minus'
|
|
46
|
+
type of pdf (plus or minus type)
|
|
47
|
+
|
|
48
|
+
order: int
|
|
49
|
+
1: first-order
|
|
50
|
+
2: second-order
|
|
51
|
+
|
|
52
|
+
logScale: bool
|
|
53
|
+
z is log scaled if True
|
|
54
|
+
'''
|
|
55
|
+
# Calculate the color constants
|
|
56
|
+
if pdf.shape[-1] == 1:
|
|
57
|
+
xs = np.linspace(0, 1, len(pdf))
|
|
58
|
+
else:
|
|
59
|
+
xs, pdf = pdf[:, 0], pdf[:, 1]
|
|
60
|
+
sign = 1 if morp == 'plus' else -1
|
|
61
|
+
lnlam = 2 * np.log(l_QCD)
|
|
62
|
+
|
|
63
|
+
pi = np.pi
|
|
64
|
+
CF = 4 / 3
|
|
65
|
+
CG = 3
|
|
66
|
+
TR = 1/2
|
|
67
|
+
beta0 = 11 / 3 * CG - 4 / 3 * TR * n_f
|
|
68
|
+
beta1 = 34 / 3 * CG ** 2 - 10 / 3 * CG * n_f - 2 * CF * n_f
|
|
69
|
+
|
|
70
|
+
def alp2pi(t):
|
|
71
|
+
dlnq2 = t - lnlam
|
|
72
|
+
alpha = 4 * pi / beta0 / dlnq2
|
|
73
|
+
alpha_factor = 1 if order == 1 else (1 - beta1 * np.log(dlnq2) / beta0**2 / dlnq2)
|
|
74
|
+
alpha_factor /= (2 * pi)
|
|
75
|
+
return alpha_factor * alpha
|
|
76
|
+
|
|
77
|
+
def splitting(z):
|
|
78
|
+
# Calculate the splitting functions
|
|
79
|
+
p0 = CF * 2 * z / (1 - z+1e-100)
|
|
80
|
+
p0pf = -CF * 2 / (1 - z+1e-100)
|
|
81
|
+
|
|
82
|
+
z1 = 1 / (1 + z)
|
|
83
|
+
z2 = z / (1 + z)
|
|
84
|
+
dln1 = np.log(z1)
|
|
85
|
+
dln2 = np.log(z2)
|
|
86
|
+
# SciPy convention for Spence (aka dilogarithm) differs from paper
|
|
87
|
+
s2 = -spence(z2) + spence(z1) - (dln1 ** 2 - dln2 ** 2) * 0.5
|
|
88
|
+
|
|
89
|
+
if order == 2:
|
|
90
|
+
omz = 1 - z
|
|
91
|
+
lnz = np.log(z)
|
|
92
|
+
lno = np.log(omz+1e-100)
|
|
93
|
+
dP0 = 2 * z / (omz+1e-100)
|
|
94
|
+
pp1 = 1 - z - (3 / 2 + 2 * lno) * lnz * dP0
|
|
95
|
+
pp2 = -omz + (67/9 + 11/3 * lnz + lnz**2 - pi**2 / 3) * dP0
|
|
96
|
+
pp3 = (-lnz - 5/3) * dP0
|
|
97
|
+
pp4 = -omz + 2 * s2 * 2 * -z / (1 + z)
|
|
98
|
+
|
|
99
|
+
# Eq. 43 in Vogelsang
|
|
100
|
+
dpqq = CF * CF * pp1 + CF * CG * 0.5 * pp2 + 2 / 3 * CF * TR * n_f * pp3
|
|
101
|
+
|
|
102
|
+
# Eq. 44 in Vogelsang
|
|
103
|
+
dpqqb = CF * (CF-CG / 2) * pp4
|
|
104
|
+
p1 = dpqq + sign * dpqqb
|
|
105
|
+
p1[0] = 0
|
|
106
|
+
else:
|
|
107
|
+
p1 = 0
|
|
108
|
+
omz = 1 - z
|
|
109
|
+
|
|
110
|
+
# The plus function contributions upon integration for the entire range of z in [x, 1]
|
|
111
|
+
# f(1) in Eq. A.8
|
|
112
|
+
# These terms correspond to -f(1)/(1-z) in Eq. A.8
|
|
113
|
+
p2plus = -(67/9-pi**2/3) * 2 / (omz+1e-100)
|
|
114
|
+
p3plus = 5 / 3 * 2 / (omz+1e-100)
|
|
115
|
+
p1pf = CF * CG / 2 * p2plus + 2 / 3 * CF * TR * n_f * p3plus
|
|
116
|
+
|
|
117
|
+
p0[-1] = 0
|
|
118
|
+
p0pf[-1] = 0
|
|
119
|
+
if order == 2:
|
|
120
|
+
p1[-1] = 0
|
|
121
|
+
p1pf[-1] = 0
|
|
122
|
+
|
|
123
|
+
# The zero order plus and delta function contributions to the integrals
|
|
124
|
+
plus0 = CF * 2
|
|
125
|
+
del0 = CF * 3/2
|
|
126
|
+
|
|
127
|
+
if order == 2:
|
|
128
|
+
zta = 1.2020569031595943
|
|
129
|
+
# The delta function contributions for the entire range of z in [x, 1]
|
|
130
|
+
del1 = CF * CF * (3 / 8 - pi**2 / 2 + 6 * zta) + \
|
|
131
|
+
CF * CG / 2 * (17 / 12 + 11 * pi**2 /9 - 6 * zta) - \
|
|
132
|
+
2 / 3 * CF * TR * n_f * (1 / 4 + pi**2 / 3)
|
|
133
|
+
# p2pl, p3pl correspond to the f(1) in Eq. A.8
|
|
134
|
+
p2pl = (67 / 9 - pi**2/3) * 2
|
|
135
|
+
p3pl = -5 / 3 * 2
|
|
136
|
+
plus1 = CF * CG / 2 * p2pl + 2 / 3 * CF * TR * n_f * p3pl
|
|
137
|
+
else:
|
|
138
|
+
plus1 = 0
|
|
139
|
+
del1 = 0
|
|
140
|
+
return p0, p1, p0pf, p1pf, plus0, del0, plus1, del1
|
|
141
|
+
|
|
142
|
+
tmin = np.log(Q0_2)
|
|
143
|
+
tmax = np.log(Q2)
|
|
144
|
+
ts = np.linspace(tmin, tmax, n_t)
|
|
145
|
+
|
|
146
|
+
def integrate(pdf, i, z, alp):
|
|
147
|
+
p0, p1, p0pf, p1pf, plus0, del0, plus1, del1 = splitting(z)
|
|
148
|
+
p0[-1] = p0pf[-1] = 0
|
|
149
|
+
if order == 2:
|
|
150
|
+
p1[-1] = p1pf[-1] = 0
|
|
151
|
+
|
|
152
|
+
# Implement Eq. A.5 in Hirai
|
|
153
|
+
# The interp function interpolates pdf(x / z)
|
|
154
|
+
# In the FORTRAN code, the first part of this equation is not divided by z
|
|
155
|
+
func = ((p0 + (alp * p1 if order == 2 else 0)) * interp(xs[i] / z, xs, pdf)) + \
|
|
156
|
+
(p0pf + (alp * p1pf if order == 2 else 0)) * pdf[i]
|
|
157
|
+
|
|
158
|
+
lno = np.log(1 - xs[i])
|
|
159
|
+
estimate = simpson(func, x=z) + (plus0 * lno + del0) * pdf[i]
|
|
160
|
+
if order == 2:
|
|
161
|
+
estimate += alp * (plus1 * lno + del1) * pdf[i]
|
|
162
|
+
|
|
163
|
+
return estimate
|
|
164
|
+
|
|
165
|
+
dt = (tmax - tmin) / n_t
|
|
166
|
+
res = np.copy(pdf)
|
|
167
|
+
for i, t in enumerate(ts):
|
|
168
|
+
print(i+1, ' of ', len(ts), 'time steps')
|
|
169
|
+
alp = alp2pi(t)
|
|
170
|
+
inc = np.array([integrate(res, index, \
|
|
171
|
+
np.power(10, np.linspace(np.log10(xs[index]), 0, n_z + 1 - index)) if logScale else np.linspace(xs[index], 1, n_z + 1 - index), \
|
|
172
|
+
alp) for index in range(1, len(xs)-1)])
|
|
173
|
+
inc = np.pad(inc, 1)
|
|
174
|
+
res += dt * inc * alp
|
|
175
|
+
return np.stack((xs, res))
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
def main():
|
|
179
|
+
import argparse, sys
|
|
180
|
+
parser = argparse.ArgumentParser(description='Evolution of the nonsinglet transversity PDF, according to the DGLAP equation.')
|
|
181
|
+
parser.add_argument('input', action='store', type=str,
|
|
182
|
+
help='The CSV file containing (x,x*PDF(x)) pairs on each line. If only a single number on each line, we assume a linear spacing for x between 0 and 1 inclusive')
|
|
183
|
+
parser.add_argument('Q0sq', action='store', type=float, help='The starting energy scale in units of GeV^2')
|
|
184
|
+
parser.add_argument('Qsq', action='store', type=float, help='The ending energy scale in units of GeV^2')
|
|
185
|
+
parser.add_argument('--morp', action='store', nargs='?', type=str, default='plus', help='The plus vs minus type PDF (default \'plus\')')
|
|
186
|
+
parser.add_argument('-o', action='store', nargs='?', type=str, default='out.dat', help='Output file for the PDF, stored as (x,x*PDF(x)) pairs.')
|
|
187
|
+
parser.add_argument('-l', metavar='l_QCD', nargs='?', action='store', type=float, default=0.25, help='The QCD scale parameter (default 0.25 GeV^2)')
|
|
188
|
+
parser.add_argument('--nf', metavar='n_f', nargs='?', action='store', type=int, default=5, help='The number of flavors (default 5)')
|
|
189
|
+
parser.add_argument('--nc', metavar='n_c', nargs='?', action='store', type=int, default=3, help='The number of colors (default 3)')
|
|
190
|
+
parser.add_argument('--order', metavar='order', nargs='?', action='store', type=int, default=2, help='1: leading order, 2: NLO DGLAP (default 2)')
|
|
191
|
+
parser.add_argument('--nt', metavar='n_t', nargs='?', action='store', type=int, default=100, help='Number of steps to numerically integrate the DGLAP equations (default 100)')
|
|
192
|
+
parser.add_argument('--nz', metavar='n_z', nargs='?', action='store', type=int, default=1000, help='Number of steps for numerical integration (default 1000)')
|
|
193
|
+
parser.add_argument('--logScale', nargs='?', action='store', type=bool, default=True, help='True if integration should be done on a log scale (default True)')
|
|
194
|
+
parser.add_argument('--delim', nargs='?', action='store', type=str, default=' ', help='Delimiter for data file (default \' \'). If given without an argument, then the delimiter is whitespace (i.e. Mathematica output.)')
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
args = parser.parse_args()
|
|
198
|
+
args.delim = ' ' if args.delim is None else args.delim
|
|
199
|
+
f = args.input
|
|
200
|
+
if args.delim is None:
|
|
201
|
+
pdf = np.genfromtxt(f)
|
|
202
|
+
args.delim = ' '
|
|
203
|
+
else:
|
|
204
|
+
pdf = np.genfromtxt(f, delimiter=args.delim)
|
|
205
|
+
Q0sq = args.Q0sq
|
|
206
|
+
Qsq = args.Qsq
|
|
207
|
+
morp = args.morp
|
|
208
|
+
l = args.l
|
|
209
|
+
nf = args.nf
|
|
210
|
+
nc = args.nc
|
|
211
|
+
order = args.order
|
|
212
|
+
nt = args.nt
|
|
213
|
+
nz = args.nz
|
|
214
|
+
logScale = args.logScale
|
|
215
|
+
|
|
216
|
+
res = evolve(pdf,
|
|
217
|
+
Q0_2=Q0sq,
|
|
218
|
+
Q2=Qsq,
|
|
219
|
+
l_QCD=l,
|
|
220
|
+
n_f=nf,
|
|
221
|
+
n_t=nt,
|
|
222
|
+
n_z=nz,
|
|
223
|
+
morp=morp,
|
|
224
|
+
order=order,
|
|
225
|
+
logScale=logScale
|
|
226
|
+
)
|
|
227
|
+
|
|
228
|
+
np.savetxt(args.o, res.T, delimiter=args.delim)
|
|
229
|
+
|
|
230
|
+
if __name__ == '__main__':
|
|
231
|
+
main()
|