Skip to content

Python API

Python API

PineAPFEL ships a Python package — pineapfel — built with pybind11 and compiled as part of the normal Meson build. It exposes the same card-loading, grid-building, and evolution functions as the C++ library, and returns grids that can be directly handed to PineAPPL for convolution and analysis.

See Building for installation instructions.


Grid creation

Build a PineAPPL grid filled with APFEL++ coefficient functions:

import pineapfel

# 1. Load the three YAML cards
theory  = pineapfel.load_theory_card("runcards/theory.yaml")
op_card = pineapfel.load_operator_card("runcards/operator.yaml")
gdef    = pineapfel.load_grid_def("runcards/grid_dis.yaml")

# 2. Build and fill the grid with coefficient functions
grid = pineapfel.build_grid(gdef, theory, op_card)

# 3. Write to disk
grid.write("dis_f2.pineappl.lz4")

The same build_grid() call works for all supported processes; the relevant flags are read from the grid card:

# SIDIS (PDF ⊗ FF, two convolution functions)
sidis_def = pineapfel.load_grid_def("runcards/grid_sidis.yaml")
sidis_grid = pineapfel.build_grid(sidis_def, theory, op_card)
sidis_grid.write("sidis_f2.pineappl.lz4")

# Polarized DIS g₁
pol_def  = pineapfel.load_grid_def("runcards/grid_dis_pol.yaml")
pol_grid = pineapfel.build_grid(pol_def, theory, op_card)
pol_grid.write("dis_g1.pineappl.lz4")

# Fixed-Flavour Number (FFN) massive scheme
ffn_def  = pineapfel.load_grid_def("runcards/grid_dis_ffn.yaml")
ffn_grid = pineapfel.build_grid(ffn_def, theory, op_card)
ffn_grid.write("dis_f2_ffn.pineappl.lz4")

# FONLL combined scheme
fonll_def  = pineapfel.load_grid_def("runcards/grid_dis_fonll.yaml")
fonll_grid = pineapfel.build_grid(fonll_def, theory, op_card)
fonll_grid.write("dis_f2_fonll.pineappl.lz4")

Evolution

Evolve an existing grid into an FK table:

import pineapfel

theory  = pineapfel.load_theory_card("runcards/theory.yaml")
op_card = pineapfel.load_operator_card("runcards/operator.yaml")

# Read an existing PineAPPL grid
grid = pineapfel.Grid.read("dis_f2.pineappl.lz4")

# Evolve into an FK table
fktable = pineapfel.evolve(grid, theory, op_card)
fktable.write("dis_f2.fk.pineappl.lz4")

Convolution using PineAPPL API

The Grid object returned by build_grid and evolve can be written to disk and read back by PineAPPL for convolution with PDFs:

import lhapdf
import numpy as np
import pineapfel

from pineappl.grid import Grid
from pineappl.convolutions import Conv, ConvType

# ── Build the grid
theory  = pineapfel.load_theory_card("runcards/theory.yaml")
op_card = pineapfel.load_operator_card("runcards/operator.yaml")
gdef    = pineapfel.load_grid_def("runcards/grid_dis.yaml")
grid    = pineapfel.build_grid(gdef, theory, op_card)
grid.write("dis_f2.pineappl.lz4")

# ── Read back with PineAPPL
pg = Grid.read("dis_f2.pineappl.lz4")

# ── Set up the PDF set
pdf = lhapdf.mkPDF("NNPDF40_nnlo_as_01180", 0)

def xfx(pid, x, q2):
    return pdf.xfxQ2(pid, x, q2)

def alphas(q2):
    return pdf.alphasQ2(q2)

# ── Convolve
ct  = ConvType(polarized=False, time_like=False)
c   = Conv(ct, 2212)                             # proton (PDG id 2212)
res = pg.convolve(pdg_convs=[c], xfxs=[xfx], alphas=alphas)
print("F2 per bin:", res)

Programmatic grid definition

Cards can also be constructed in Python without YAML files:

import pineapfel

theory = pineapfel.TheoryCard()
theory.mu0           = 1.0
theory.pert_ord      = 2
theory.q_ref         = 91.2
theory.alpha_qcd_ref = 0.118
theory.quark_thresholds = [0.3, 1.5, 4.5, 100.0, 100.0]
theory.flavors          = [1, 2, 3, 4, 5, 6]
theory.ckm              = [1.0, 0.0, 0.0] * 3   # diagonal CKM
theory.qed              = False
theory.alpha_qed_ref    = 1.0 / 137.0
theory.lepton_thresholds = []
theory.heavy_quark_masses = [0.3, 1.5, 4.5, 100.0, 100.0, 100.0]

op_card = pineapfel.OperatorCard()
op_card.xgrid      = [pineapfel.SubGridDef(100, 1e-7, 3)]
op_card.tabulation = pineapfel.TabulationParams(50, 1.0, 200, 3)
op_card.xi         = [1.0, 1.0, 1.0]

gdef = pineapfel.GridDef()
gdef.process           = pineapfel.ProcessType.DIS
gdef.observable        = pineapfel.Observable.F2
gdef.current           = pineapfel.Current.NC
gdef.mass_scheme       = pineapfel.MassScheme.ZM
gdef.pid_basis         = pineapfel.PidBasis.PDG
gdef.hadron_pids       = [2212]
gdef.convolution_types = [pineapfel.ConvolutionType.UNPOL_PDF]
gdef.orders            = [pineapfel.OrderDef(0, 0, 0, 0, 0),
                          pineapfel.OrderDef(1, 0, 0, 0, 0)]
gdef.bins = [
    pineapfel.BinDef([10.0,  0.001], [100.0,  0.01]),
    pineapfel.BinDef([100.0, 0.01 ], [1000.0, 0.1 ]),
]
gdef.normalizations = [1.0, 1.0]

grid = pineapfel.build_grid(gdef, theory, op_card)
grid.write("my_dis_f2.pineappl.lz4")