Calling a MadGraph-generated matrix element

MadSpace evaluates matrix elements through the UMAMI interface, a set of C functions every MadGraph7 output exports. This example loads the matrix element for g g > t t~ g, the process from the first example, and evaluates it on sampled momenta.

Generating and compiling the process

At the MadGraph7 prompt:

generate g g > t t~ g
output mg7 PROC_ggttg

Then compile the matrix elements it wrote:

cd PROC_ggttg/SubProcesses
make BACKEND=scalar

launch does the same compilation automatically before starting a run, so this step can be skipped when going through launch instead. BACKEND=scalar picks the portable backend that every machine can compile, which keeps the library name the same everywhere; a plain make instead lets it pick a faster backend suited to the local CPU, at the cost of a machine-dependent name.

This produces one shared library per subprocess under PROC_ggttg/lib/.

Loading the matrix element

import os

import numpy as np
import madspace as ms

proc_dir = "PROC_ggttg"
me_path = os.path.join(proc_dir, "lib", "libmadmatrix_P0_gg_ttxg_scalar.so")
param_card = os.path.join(proc_dir, "Cards", "param_card.dat")

ctx = ms.default_context()
api = ctx.load_matrix_element(me_path, param_card)
print(f"particle count: {api.particle_count()}, diagrams: {api.diagram_count()}")

The library name also appears, alongside every other subprocess of the process, in PROC_ggttg/SubProcesses/subprocesses.json, as me_path with a {device} placeholder for the backend.

Context.load_matrix_element returns a MatrixElementApi, which reads the parameters from param_card.dat when it loads the library:

particle count: 5, diagrams: 16

Building the compute-graph function

MatrixElement wraps the loaded library as a FunctionGenerator. inputs and outputs pick which quantities to pass in and read back. The last argument lets the matrix element draw its own random helicity, color and diagram choices, so none of them need to be supplied here:

MEI = ms.MatrixElement.MatrixElementInput
MEO = ms.MatrixElement.MatrixElementOutput
matrix_element = ms.MatrixElement(
    api, [MEI.momenta_in, MEI.alpha_s_in], [MEO.matrix_element_out], True
)

Evaluating it

The matrix element is a plain function of momenta and \(\alpha_s\), so it takes the output of a PhaseSpaceMapping directly:

mapping = ms.PhaseSpaceMapping([0.0, 0.0, 173.0, 173.0, 0.0], 13000.0, mode="rambo")
rng = np.random.default_rng(0)
r = rng.random((5, mapping.random_dim()))
momenta, x1, x2, det = mapping.map_forward([r])
alpha_s = np.full(5, 0.13)

print(matrix_element(momenta, alpha_s))
[1.18355914e-04 3.54037768e-04 3.24861340e-05 2.72819425e-03 1.46426371e-05]