Forward model
Here, we go through an example of simulating the full forward model, from the prior definition to the expected number of events in different bins of the detector response.
using QCDNUM, PartonDensity
using Plots, Printf, NaNMath, Parameters, Random, Distributions
zeus_include_path = string(chop(pathof(PartonDensity), tail=20), "data/ZEUS_I1787035/ZEUS_I1787035.jl")
const MD_DOCS = include(zeus_include_path)
PartonDensity.MetaDataZEUS{Main.var"#f_cross_section_to_counts#1"{Array{Float64, 3}, Array{Float64, 3}, Matrix{Float64}, Matrix{Float64}, Float64, Float64, Vector{Float64}, Vector{Float64}}}("ZEUS_I1787035", 141.44, 185.018, 0.018, 0.018, 318.0, [400.0, 400.0, 400.0, 400.0, 400.0, 400.0, 400.0, 400.0, 400.0, 400.0 … 8000.0, 8000.0, 8000.0, 8000.0, 8000.0, 11000.0, 11000.0, 11000.0, 20000.0, 20000.0], [650.0, 650.0, 650.0, 650.0, 650.0, 650.0, 650.0, 650.0, 650.0, 650.0 … 11000.0, 11000.0, 11000.0, 11000.0, 11000.0, 20000.0, 20000.0, 20000.0, 30000.0, 30000.0], [0.0035, 0.007, 0.01, 0.012, 0.015, 0.017, 0.019, 0.022, 0.024, 0.026 … 0.45, 0.51, 0.57, 0.64, 0.78, 0.13, 0.256, 0.6, 0.25, 0.6], [0.007, 0.01, 0.012, 0.015, 0.017, 0.019, 0.022, 0.024, 0.026, 0.028 … 0.51, 0.57, 0.64, 0.78, 0.99999, 0.256, 0.6, 0.99999, 0.6, 0.99999], [743, 580, 441, 416, 283, 248, 227, 504, 789, 681 … 27, 19, 12, 8, 5, 4, 1, 1, 120, 8], [567, 418, 321, 274, 207, 176, 152, 371, 599, 497 … 15, 14, 9, 8, 7, 2, 0, 0, 41, 3], Main.var"#f_cross_section_to_counts#1"{Array{Float64, 3}, Array{Float64, 3}, Matrix{Float64}, Matrix{Float64}, Float64, Float64, Vector{Float64}, Vector{Float64}}([0.0 0.0 … 0.0 0.0; 0.0 0.0 … 0.0 0.0; … ; 0.0 0.0 … 0.0 0.0; 0.0 0.0 … 0.0 0.0;;; 0.0 0.0 … 0.0 0.0; 0.0 0.0 … 0.0 0.0; … ; 0.0 0.0 … 0.0 0.0; 0.0 0.0 … 0.0 0.0;;; 0.0 0.0 … 0.0 0.0; 0.0 0.0 … 0.0 0.0; … ; 0.0 0.0 … 0.0 0.0; 0.0 0.0 … 0.0 0.0;;; 0.0 0.0 … 0.0 0.0; 0.0 0.0 … 0.0 0.0; … ; 0.0 0.0 … 0.0 0.0; 0.0 0.0 … 0.0 0.0;;; 0.0 0.0 … 0.0 0.0; 0.0 0.0 … 0.0 0.0; … ; 0.0 0.0 … 0.0 0.0; 0.0 0.0 … 0.0 0.0;;; 0.0 0.0 … 0.0 0.0; 0.0 0.0 … 0.0 0.0; … ; 0.0 0.0 … 0.0 0.0; 0.0 0.0 … 0.0 0.0;;; 0.0 0.0 … 0.0 0.0; 0.0 0.0 … 0.0 0.0; … ; 0.0 0.0 … 0.0 0.0; 0.0 0.0 … 0.0 0.0;;; 0.0 0.0 … 0.0 0.0; 0.0 0.0 … 0.0 0.0; … ; 0.0 0.0 … 0.0 0.0; 0.0 0.0 … 0.0 0.0], [0.0 0.0 … 0.0 0.0; 0.0 0.0 … 0.0 0.0; … ; 0.0 0.0 … 0.0 0.0; 0.0 0.0 … 0.0 0.0;;; 0.0 0.0 … 0.0 0.0; 0.0 0.0 … 0.0 0.0; … ; 0.0 0.0 … 0.0 0.0; 0.0 0.0 … 0.0 0.0;;; 0.0 0.0 … 0.0 0.0; 0.0 0.0 … 0.0 0.0; … ; 0.0 0.0 … 0.0 0.0; 0.0 0.0 … 0.0 0.0;;; 0.0 0.0 … 0.0 0.0; 0.0 0.0 … 0.0 0.0; … ; 0.0 0.0 … 0.0 0.0; 0.0 0.0 … 0.0 0.0;;; 0.0 0.0 … 0.0 0.0; 0.0 0.0 … 0.0 0.0; … ; 0.0 0.0 … 0.0 0.0; 0.0 0.0 … 0.0 0.0;;; 0.0 0.0 … 0.0 0.0; 0.0 0.0 … 0.0 0.0; … ; 0.0 0.0 … 0.0 0.0; 0.0 0.0 … 0.0 0.0;;; 0.0 0.0 … 0.0 0.0; 0.0 0.0 … 0.0 0.0; … ; 0.0 0.0 … 0.0 0.0; 0.0 0.0 … 0.0 0.0;;; 0.0 0.0 … 0.0 0.0; 0.0 0.0 … 0.0 0.0; … ; 0.0 0.0 … 0.0 0.0; 0.0 0.0 … 0.0 0.0], [0.0 0.0 … 0.0 0.0; 0.003688148812 0.0018500689892 … 0.0 0.0; … ; 0.0 0.0 … 1.0453516999999999 0.0005606785471999999; 0.0 0.0 … 0.0046826205620000005 0.065218845], [0.0 0.0 … 0.0 0.0; 0.00234097344 0.0 … 0.0 0.0; … ; 0.0 0.0 … 0.94503136 0.000449623616; 0.0 0.0 … 0.08914963199999999 0.0282215232], 185.018, 141.44, [1.07559, 1.00494, 0.997145, 0.994087, 0.991775, 0.990224, 0.98391, 0.991145, 0.993283, 0.976963 … 0.897826, 0.889232, 0.890147, 0.892718, 0.88395, 0.921764, 0.882477, 0.891006, 0.911363, 0.877797], [1.07535, 1.00332, 1.0004, 0.990515, 0.982716, 0.991055, 0.988341, 0.981917, 0.980651, 0.98678 … 0.857518, 0.837175, 0.875777, 0.897924, 0.935441, 0.933215, 0.899119, 0.910332, 1.1251, 1.12007]))
Define input PDFs
We can use DirichletPDFParams
or ValencePDFParams
, as long as we do so according to the PDF parametrisation and priors docs.
random_seed = 42
weights = [3.0, 1.0, 5.0, 5.0, 1.0, 1.0, 1.0, 0.5, 0.5]
θ = rand(MersenneTwister(random_seed), Dirichlet(weights))
pdf_params = DirichletPDFParams(K_u=4.0, K_d=6.0, λ_g1=0.7, λ_g2=-0.4,
K_g=6.0, λ_q=-0.5, K_q=5.0, θ=θ);
Plot the input PDFs
plot_input_pdfs(pdf_params)
Sanity check that sum = 1
int_xtotx(pdf_params) ≈ 1
true
Define QCDNUM grids, weights and settings
grid = QCDNUM.GridParams(x_min=[1.0e-3], x_weights=[1], nx=100,
qq_bounds=[1.0e2, 3.0e4], qq_weights=[1.0, 1.0], nq=50, spline_interp=3)
qcdnum_params = QCDNUM.EvolutionParams(order=2, α_S=0.118, q0=100.0, grid_params=grid,
n_fixed_flav=5, iqc=1, iqb=1, iqt=1, weight_type=1);
Initialise
QCDNUM.init()
+---------------------------------------------------------------------+
| |
| If you use QCDNUM, please refer to: |
| |
| M. Botje, Comput. Phys. Commun. 182(2011)490, arXiV:1005.1481 |
| |
+---------------------------------------------------------------------+
Evolve the PDFs using QCDNUM
Define input PDF function
- See QCDNUM docs under
evolfg
There are functions available to generate the necessary input PDF function in the correct format for QCDNUM.jl
(see get_input_pdf_func()
), along with the mapping between this input function and quark species (see input_pdf_map
).
Get function and PDF input map to fully describe the QCDNUM.InputPDF
my_func = get_input_pdf_func(pdf_params)
input_pdf = QCDNUM.InputPDF(func=my_func, map=input_pdf_map)
QCDNUM.InputPDF
func: _input_pdfs (function of type PartonDensity.var"#_input_pdfs#22"{DirichletPDFParams{Float64, Vector{Float64}}})
cfunc: Base.CFunction
map: Array{Float64}((156,)) [0.0, 0.0, 0.0, 0.0, -1.0, 0.0, 0.0, 0.0, 1.0, 0.0 … 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
Evolve the PDF over the specified grid
ϵ = QCDNUM.evolve(input_pdf, qcdnum_params)
0.0023831637076243695
For splines
nw = QCDNUM.zmfillw()
splint_params = QCDNUM.SPLINTParams();
quark_coeffs = QuarkCoefficients();
ZMFILLW: start weight calculations 4 38 0 0
ZMFILLW: calculations completed
Define initial spline
QCDNUM.ssp_spinit(splint_params.nuser)
ia = QCDNUM.isp_s2make(splint_params.nsteps_x, splint_params.nsteps_q);
xnd = QCDNUM.ssp_unodes(ia, splint_params.nnodes_x, 0);
qnd = QCDNUM.ssp_vnodes(ia, splint_params.nnodes_q, 0);
┌ Warning: SPLINT is already initialised, skipping call to QCDNUM.ssp_spinit()
└ @ QCDNUM /opt/myjulia/packages/QCDNUM/gx4Mo/src/splint/initialisation.jl:36
Check nodes and erase
QCDNUM.ssp_nprint(ia);
QCDNUM.ssp_erase(ia);
N IX XNODE NQMA IQ QNODE NXMI
1 1 0.10000E-02 0 1 0.10000E+03 0
2 5 0.13183E-02 0 2 0.11234E+03 0
3 10 0.18621E-02 0 12 0.35982E+03 0
4 15 0.26303E-02 0 22 0.11525E+04 0
5 20 0.37154E-02 0 32 0.36911E+04 0
6 25 0.52481E-02 0 42 0.11822E+05 0
7 30 0.74131E-02 0 50 0.30000E+05 0
8 35 0.10471E-01 0 - - -
9 40 0.14791E-01 0 - - -
10 45 0.20893E-01 0 - - -
11 50 0.29512E-01 0 - - -
12 55 0.41687E-01 0 - - -
13 60 0.58884E-01 0 - - -
14 65 0.83176E-01 0 - - -
15 70 0.11749E+00 0 - - -
16 75 0.16596E+00 0 - - -
17 80 0.23442E+00 0 - - -
18 85 0.33113E+00 0 - - -
19 90 0.46774E+00 0 - - -
20 95 0.66069E+00 0 - - -
21 100 0.93325E+00 0 - - -
22 101 0.10000E+01 0 - - -
Set nodes and fill spline with structure function
iaFLup = QCDNUM.isp_s2user(xnd, splint_params.nnodes_x, qnd, splint_params.nnodes_q);
QCDNUM.ssp_s2f123(iaFLup, qcdnum_params.output_pdf_loc, quark_coeffs.proup, 1, 0.0);
iaF2up = QCDNUM.isp_s2user(xnd, splint_params.nnodes_x, qnd, splint_params.nnodes_q);
QCDNUM.ssp_s2f123(iaF2up, qcdnum_params.output_pdf_loc, quark_coeffs.proup, 2, 0.0);
iaF3up = QCDNUM.isp_s2user(xnd, splint_params.nnodes_x, qnd, splint_params.nnodes_q);
QCDNUM.ssp_s2f123(iaF3up, qcdnum_params.output_pdf_loc, quark_coeffs.valup, 3, 0.0);
iaFLdn = QCDNUM.isp_s2user(xnd, splint_params.nnodes_x, qnd, splint_params.nnodes_q);
QCDNUM.ssp_s2f123(iaFLdn, qcdnum_params.output_pdf_loc, quark_coeffs.prodn, 1, 0.0);
iaF2dn = QCDNUM.isp_s2user(xnd, splint_params.nnodes_x, qnd, splint_params.nnodes_q);
QCDNUM.ssp_s2f123(iaF2dn, qcdnum_params.output_pdf_loc, quark_coeffs.prodn, 2, 0.0);
iaF3dn = QCDNUM.isp_s2user(xnd, splint_params.nnodes_x, qnd, splint_params.nnodes_q);
QCDNUM.ssp_s2f123(iaF3dn, qcdnum_params.output_pdf_loc, quark_coeffs.valdn, 3, 0.0);
store spline addresses
QCDNUM.ssp_uwrite(splint_params.spline_addresses.F2up, Float64(iaF2up));
QCDNUM.ssp_uwrite(splint_params.spline_addresses.F2dn, Float64(iaF2dn));
QCDNUM.ssp_uwrite(splint_params.spline_addresses.F3up, Float64(iaF3up));
QCDNUM.ssp_uwrite(splint_params.spline_addresses.F3dn, Float64(iaF3dn));
QCDNUM.ssp_uwrite(splint_params.spline_addresses.FLup, Float64(iaFLup));
QCDNUM.ssp_uwrite(splint_params.spline_addresses.FLdn, Float64(iaFLdn));
my_funcp = get_input_xsec_func(1, MD_DOCS) # charge = 1
input_xsecp = @cfunction(my_funcp, Float64, (Ref{Int32}, Ref{Int32}, Ref{UInt8}))
my_funcm = get_input_xsec_func(-1, MD_DOCS) # charge = -1
input_xsecm = @cfunction(my_funcm, Float64, (Ref{Int32}, Ref{Int32}, Ref{UInt8}))
Ptr{Nothing} @0x00007fad241c4e80
plot
g = qcdnum_params.grid_params
xsec_on_grid = zeros(g.nx, g.nq);
for ix = 1:g.nx
for iq = 1:g.nq
xsec_on_grid[ix, iq] = _fun_xsec_i(1, MD_DOCS, ix, iq) # charge = 1
end
end
qcdnum_x_grid = QCDNUM.gxcopy(g.nx)
qcdnum_qq_grid = QCDNUM.gqcopy(g.nq)
p1 = heatmap(qcdnum_x_grid, qcdnum_qq_grid, NaNMath.log10.(xsec_on_grid[:, :]'))
plot(p1, xlabel="x", ylabel="q2",
xaxis=:log, yaxis=:log)
plot(qcdnum_x_grid, NaNMath.log10.(xsec_on_grid[:, 4]),
label="Q2=141 (input scale)", lw=3)
plot!(qcdnum_x_grid, NaNMath.log10.(xsec_on_grid[:, 22]), label="Q2=1152", lw=3)
plot!(qcdnum_x_grid, NaNMath.log10.(xsec_on_grid[:, 35]), label="Q2=5233", lw=3)
plot!(qcdnum_x_grid, NaNMath.log10.(xsec_on_grid[:, 41]), label="Q2=10523", lw=3)
plot!(xaxis=:log, legend=:bottomleft, xlabel="x",
ylabel="log10(cross section spline input)", ylims=(-7, 5))
iaF_eP = QCDNUM.isp_s2make(1, 2);
QCDNUM.ssp_uwrite(splint_params.spline_addresses.F_eP, Float64(iaF_eP));
QCDNUM.ssp_s2fill(iaF_eP, input_xsecp, splint_params.rscut);
iaF_eM = QCDNUM.isp_s2make(1, 2);
QCDNUM.ssp_uwrite(splint_params.spline_addresses.F_eM, Float64(iaF_eM));
QCDNUM.ssp_s2fill(iaF_eM, input_xsecm, splint_params.rscut);
plot spline
spline = zeros(g.nx, g.nq);
for ix = 1:g.nx
for iq = 1:g.nq
spline[ix, iq] = QCDNUM.dsp_funs2(iaF_eP, qcdnum_x_grid[ix],
qcdnum_qq_grid[iq], 1)
end
end
p1 = heatmap(qcdnum_x_grid, qcdnum_qq_grid, NaNMath.log10.(spline[:, :]'))
plot(p1, xlabel="x", ylabel="q2",
xaxis=:log, yaxis=:log)
Integrate over the cross section spline and find expected events numbers
Here, we neglect any possible contribution from systematic errors
nbins = size(MD_DOCS.m_xbins_M_begin)[1]
IntXsec_eP = zeros(nbins);
IntXsec_eM = zeros(nbins);
for i in 1:nbins
IntXsec_eP[i] = QCDNUM.dsp_ints2(iaF_eP, MD_DOCS.m_xbins_M_begin[i], MD_DOCS.m_xbins_M_end[i], MD_DOCS.m_q2bins_M_begin[i], MD_DOCS.m_q2bins_M_end[i], MD_DOCS.sqrtS, 4)
IntXsec_eM[i] = QCDNUM.dsp_ints2(iaF_eM, MD_DOCS.m_xbins_M_begin[i], MD_DOCS.m_xbins_M_end[i], MD_DOCS.m_q2bins_M_begin[i], MD_DOCS.m_q2bins_M_end[i], MD_DOCS.sqrtS, 4)
end
counts_pred_eP, counts_pred_eM = MD_DOCS.f_cross_section_to_counts(MD_DOCS.Ld_ePp, MD_DOCS.Ld_eMp, IntXsec_eP, IntXsec_eM)
counts_pred_eM
153-element Vector{Float64}:
651.6430308810627
462.3474434974716
353.8250890402993
304.3408226976592
200.58796784717183
180.09268590111463
132.68825877655811
276.3002068237758
704.4763532747882
587.3200097391523
⋮
14.133048867826203
8.186102087178547
4.6763201873520055
2.522324578546638
1.5184036052034076
0.9856294574716068
0.1073669154427297
53.9465198773069
2.211269559843675
This page was generated using Literate.jl.