qlat.hlbl_contract — Hadronic Light-by-Light Contractions¶
Source: qlat/qlat/hlbl_contract.pyx
Note: Update this document when updating the source file.
Outline¶
Overview¶
hlbl_contract implements the hadronic light-by-light (HLbL) scattering
contraction routines needed for the muon anomalous magnetic moment (g-2)
calculation on the lattice. The module provides:
Muon-line fields (
mk_m_z_field_tag) — the electromagnetic vertex kernel at a point z, used to connect the muon line to the hadronic vacuum polarization.Local currents (
mk_local_current_from_props) — the electromagnetic current J_mu(x) constructed from quark propagator pairs.CurrentMoments— moments of the current distribution used in the multipole expansion of the HLbL tensor.Four-pair contractions (
contract_four_pair_no_glb_sum) — the dominant HLbL diagram where two photon propagators connect to a single quark loop.Two-plus-two pair contractions (
contract_two_plus_two_pair_no_glb_sum) — the subdominant HLbL diagram with two separate quark loops connected by two photon propagators.
All contraction functions return results as NumPy arrays with shape
(n_labels, s_limit, l_limit) where s and l are angular momentum
quantum numbers in the multipole expansion. Global sums over MPI ranks
are not performed inside these functions; the caller must sum the returned
arrays.
import qlat as q
q.begin_with_mpi([[1, 1, 1, 1]])
# ... (see examples below)
q.end_with_mpi()
Muon-Line Field¶
mk_m_z_field_tag(psel_d, xg_x, xg_y, a, tag) -> SelectedPointsRealD¶
Compute the muon-line field at vertex z for sampled source point x and sink point y.
Parameter |
Type |
Description |
|---|---|---|
|
|
Point selection for the d (detector) sites |
|
|
Global coordinate of source point x |
|
|
Global coordinate of sink point y |
|
|
Lattice spacing (in muon-mass units; use |
|
|
|
Returns a SelectedPointsRealD containing the muon-line field values at
the selected points.
Pair Label Generators¶
contract_two_plus_two_pair_labels() -> list¶
Generate the contraction labels for the two-plus-two pair HLbL diagram.
Local Current from Propagators¶
mk_local_current_from_props(sprop1, sprop2) -> SelectedPointsWilsonMatrix¶
Construct the local electromagnetic current from a pair of point-selected propagators:
J(x) = gamma5 * sprop2^+ * gamma5 * gamma_mu * sprop1
Parameter |
Type |
Description |
|---|---|---|
|
|
First propagator (forward) |
|
|
Second propagator (conjugated with gamma5) |
Returns a SelectedPointsWilsonMatrix containing the current at each
selected point.
Point-Selected Probability Fields¶
mk_psel_d_prob_xy(psel_prob, psel_d_prob, idx_xg_x, idx_xg_y) -> tuple¶
Compute the probability-weighted field for a pair of source/sink points.
Parameter |
Type |
Description |
|---|---|---|
|
|
Probability weights for the primary point selection |
|
|
Probability weights for the detector point selection |
|
|
Index of source point x in |
|
|
Index of sink point y in |
Returns (prob_pair, psel_d_prob_xy) where prob_pair is the combined
probability for the (x, y) pair and psel_d_prob_xy is the per-detector-point
probability field.
CurrentMoments Class¶
CurrentMoments stores the multipole moments of the electromagnetic current
distribution, used in the HLbL tensor decomposition.
Constructor¶
CurrentMoments()¶
Create an uninitialized instance.
CurrentMoments(current: SelectedPointsWilsonMatrix, psel_d_prob_xy: SelectedPointsRealD)¶
Create and compute moments from a local current field weighted by detector-point probabilities.
Copy and Assignment¶
copy(is_copying_data: bool = True) -> CurrentMoments¶
Return a copy. If is_copying_data is False, return an uninitialized
instance.
__imatmul__(v1: CurrentMoments)¶
In-place assignment: self @= v1.
Compute Moments¶
set_from_current(current: SelectedPointsWilsonMatrix, psel_d_prob_xy: SelectedPointsRealD)¶
Compute moments from the given current and probability fields.
Global Sum¶
glb_sum() -> CurrentMoments¶
Return a new CurrentMoments with all entries summed across MPI ranks.
Does not modify self.
Four-Pair Contraction¶
Two-Plus-Two Pair Contraction¶
contract_two_plus_two_pair_no_glb_sum(coef, psel_prob, psel_lps_prob, idx_xg_x, lps_hvp_x, edl_list_c, r_sq_limit, muon_mass, z_v) -> tuple¶
Perform the two-plus-two pair HLbL contraction. This diagram involves two quark loops connected by two photon propagators.
Returns (n_points_selected, n_points_computed, lsl_arr) where lsl_arr
has shape (n_labels, s_limit, l_limit).
Parameter |
Type |
Description |
|---|---|---|
|
|
Overall coefficient |
|
|
Probability weights for primary point selection |
|
|
Probability weights for the loop point selection |
|
|
Index of source point x in |
|
|
HVP tensor at point x |
|
|
External double-line list |
|
|
Maximum r^2 cutoff |
|
|
Muon mass |
|
|
Vector coupling constant |
Note: The returned array has not been globally summed; the caller must sum across MPI ranks.
Examples¶
Compute Muon-Line Field¶
import qlat as q
import os
import tempfile
size_node_list = [[1, 1, 1, 1]]
q.begin_with_mpi(size_node_list)
total_site = q.Coordinate([4, 4, 4, 8])
geo = q.Geometry(total_site)
psel = q.PointsSelection(total_site, [[0, 0, 0, 0]])
psel_d = q.PointsSelection(total_site, [[1, 0, 0, 0],
[0, 1, 0, 0]])
xg_x = q.Coordinate([0, 0, 0, 0])
xg_y = q.Coordinate([2, 0, 0, 0])
a = 0.1 # lattice spacing in muon-mass units
tag = 0 # subtraction (preferred)
# Compute muon-line interpolation data (required by mk_m_z_field_tag).
# In production, use precomputed tables loaded via
# load_multiple_muonline_interpolations. Here we compute a small test
# sample for demonstration purposes.
# Note: compute_save_muonline_interpolation requires at least 2 MPI ranks.
interp_path = os.path.join(tempfile.gettempdir(), "muon-line-interp")
q.compute_save_muonline_interpolation(
f"{interp_path}/0000000000",
[3, 2, 2, 2, 2],
(1e-8, 1e-3, 1024 * 16, 1024 * 1024 * 16),
)
# Set extrapolation weights to use only the single interpolation table
# at index 0. The default weights reference multiple tables at different
# grid resolutions that are not available in this standalone example.
q.set_muon_line_m_extra_weights([[1.0], [1.0]])
smf_d = q.hlbl_contract.mk_m_z_field_tag(psel_d, xg_x, xg_y, a, tag)
print(f"muon-line field shape: {smf_d.n_points}")
q.end_with_mpi()
Local Current from Propagators¶
import qlat as q
size_node_list = [[1, 1, 1, 1]]
q.begin_with_mpi(size_node_list)
total_site = q.Coordinate([4, 4, 4, 8])
geo = q.Geometry(total_site)
psel = q.PointsSelection(total_site, [[0, 0, 0, 0]])
sprop1 = q.PselProp(psel)
sprop2 = q.PselProp(psel)
sprop1.set_zero()
sprop2.set_zero()
scf = q.hlbl_contract.mk_local_current_from_props(sprop1, sprop2)
print(f"local current computed at {scf.n_points} points")
q.end_with_mpi()
Four-Pair Contraction Workflow¶
import qlat as q
import numpy as np
size_node_list = [[1, 1, 1, 1]]
q.begin_with_mpi(size_node_list)
total_site = q.Coordinate([4, 4, 4, 8])
geo = q.Geometry(total_site)
# Create minimal selections
psel = q.PointsSelection(total_site, [[0, 0, 0, 0],
[1, 0, 0, 0]])
psel_d = q.PointsSelection(total_site, [[0, 0, 0, 0]])
# Probability weights (uniform for demonstration)
psel_prob = q.SelectedPointsRealD(psel, 1)
psel_d_prob = q.SelectedPointsRealD(psel_d, 1)
psel_prob.set_zero()
psel_d_prob.set_zero()
# Generate pair labels
tags = ["ref-far", "ref-center"]
labels = q.hlbl_contract.contract_four_pair_labels(tags)
print(f"number of labels: {len(labels)}")
# Generate two-plus-two labels
labels_22 = q.hlbl_contract.contract_two_plus_two_pair_labels()
print(f"number of 2+2 labels: {len(labels_22)}")
q.end_with_mpi()
CurrentMoments¶
import qlat as q
size_node_list = [[1, 1, 1, 1]]
q.begin_with_mpi(size_node_list)
total_site = q.Coordinate([4, 4, 4, 8])
geo = q.Geometry(total_site)
psel = q.PointsSelection(total_site, [[0, 0, 0, 0]])
psel_d = q.PointsSelection(total_site, [[0, 0, 0, 0]])
# Build a current and probability field
sprop1 = q.PselProp(psel)
sprop2 = q.PselProp(psel)
sprop1.set_zero()
sprop2.set_zero()
scf = q.hlbl_contract.mk_local_current_from_props(sprop1, sprop2)
psel_d_prob = q.SelectedPointsRealD(psel_d, 1)
psel_d_prob.set_zero()
cm = q.hlbl_contract.CurrentMoments(scf, psel_d_prob)
cm_glb = cm.glb_sum()
print("CurrentMoments computed and globally summed")
q.end_with_mpi()