qlat_utils.lat_data — Lattice Data Container¶
Source: qlat-utils/qlat_utils/lat_data.pyx.in
Note: Update this document when updating the source file.
Outline¶
Overview¶
lat_data is a template module (.pyx.in) that generates LatData container
classes for multi-dimensional arrays with labeled dimensions and named indices.
Each LatData instance stores a ranked array where each dimension has a name
and optional string labels for its indices, making it suitable for
momentum-projected correlator data, per-site observables, and similar
structured lattice QCD datasets.
The generated classes support the NumPy buffer protocol for zero-copy array access, MPI broadcast and global sum operations, and a human-readable text-based file format.
LatData Types¶
Class |
Element Type |
Complex by Default |
|---|---|---|
|
|
Yes |
|
|
Yes |
|
|
No |
|
|
No |
All four classes share the same API. The type is selected based on the precision and integer requirements of the data.
Construction¶
mk_lat_data(info_list, is_complex=True)¶
Factory function to create a LatData with the given dimension layout.
ld = q.mk_lat_data([["t", 8], ["p", 3]])
Parameter |
Description |
|---|---|
|
List of |
|
Whether the last (innermost) dimension is complex (re/im) |
mk_lat_data_real_f(info_list, is_complex=True)¶
Same as mk_lat_data but creates a LatDataRealF (single-precision).
mk_lat_data_int(info_list)¶
Same as mk_lat_data but creates a LatDataInt (integer, non-complex).
mk_lat_data_long(info_list)¶
Same as mk_lat_data but creates a LatDataLong (long integer, non-complex).
LatData.set_info(info_list, is_complex=True)¶
Set the dimension layout on an existing instance.
ld = q.LatData()
ld.set_info([["t", 8], ["mom", 3, ["(0,0,0)", "(1,0,0)", "(1,1,0)"]]])
Dimension Metadata¶
Method |
Description |
|---|---|
|
Number of dimensions (excluding the implicit re/im axis) |
|
Name of dimension |
|
Size of dimension |
|
List of all dimension names |
|
List of all dimension sizes |
|
String labels for dimension |
|
Look up the integer index of a string label |
|
Full info for one dimension, or all dimensions if |
|
Whether the data has a complex (re/im) dimension |
|
Resize (data is lost) |
|
Set name and optional labels for dimension |
Data Access¶
LatData supports standard Python indexing via __getitem__ and
__setitem__, backed by np.asarray:
ld[0, 1] = 3.14
val = ld[0, 1]
Conversion¶
Method |
Description |
|---|---|
|
Copy data to a NumPy array |
|
Load from a NumPy array |
|
Flatten to a Python list |
|
Load from a flat Python list |
|
Convert to an |
I/O Operations¶
Method |
Description |
|---|---|
|
Save from node 0 |
|
Load from node 0 and broadcast |
|
Save on every node |
|
Load on every node (no broadcast) |
|
Serialize to a bytes object |
|
Deserialize from bytes |
load_lat_data(path)¶
Factory function: load a LatData from file.
ld = q.load_lat_data("data/prop.lat")
load_lat_data_real_f(path)¶
Same but returns LatDataRealF.
MPI Operations¶
Method |
Description |
|---|---|
|
Broadcast data from |
|
Return a new |
|
Global-sum in place |
Arithmetic¶
LatData (the double-precision variant) supports arithmetic operations:
Operation |
Description |
|---|---|
|
Element-wise addition |
|
Element-wise subtraction |
|
Scalar multiplication (float or complex) |
|
Negation |
|
In-place addition |
|
In-place subtraction |
|
In-place scalar multiplication |
|
Squared norm of the data vector |
|
Zero all elements |
|
Check if dimensions are identical |
NumPy Buffer Protocol¶
All LatData classes implement the buffer protocol, enabling zero-copy
NumPy array access:
arr = np.asarray(ld) # zero-copy view
The shape is (dim0_size, dim1_size, ...). For complex data, the dtype is
complex128 (or complex64 for LatDataRealF) — the real/imaginary parts
are encoded in the dtype, not as an extra dimension.
Serialization¶
LatData supports Python pickle via __getstate__ / __setstate__. The
serialized form includes dimension metadata (names, sizes, indices) and the
data array, enabling faithful round-tripping through pickle.dumps /
pickle.loads.
Examples¶
Create and populate a LatData¶
import qlat_utils as q
ld = q.mk_lat_data([["t", 8], ["mom", 3]], is_complex=True)
ld.set_dim_name(1, "mom", ["(0,0,0)", "(1,0,0)", "(1,1,0)"])
ld[0, 0] = 1.0 + 0.5j
if q.get_id_node() == 0:
print("shape:", ld.dim_sizes())
print("value:", ld[0, 0])
Query dimension metadata¶
import qlat_utils as q
ld = q.mk_lat_data([["t", 4], ["mom", 3, ["p0", "p1", "p2"]]], is_complex=True)
if q.get_id_node() == 0:
print("ndim:", ld.ndim()) # 2
print("dim_names:", ld.dim_names()) # ['t', 'mom']
print("dim_sizes:", ld.dim_sizes()) # [4, 3]
print("is_complex:", ld.is_complex()) # True
print("dim_indices(1):", ld.dim_indices(1)) # ['p0', 'p1', 'p2']
print("dim_idx(1, 'p1'):", ld.dim_idx(1, "p1")) # 1
Arithmetic operations¶
import qlat_utils as q
ld_a = q.mk_lat_data([["t", 4]])
ld_b = q.mk_lat_data([["t", 4]])
ld_a[0] = 1.0
ld_b[0] = 2.0
ld_sum = ld_a + ld_b # element-wise addition
ld_diff = ld_a - ld_b # element-wise subtraction
ld_scaled = ld_a * 3.0 # scalar multiplication
ld_neg = -ld_a # negation
ld_a += ld_b # in-place addition
ld_a *= 0.5 # in-place scalar multiplication
if q.get_id_node() == 0:
print("qnorm:", ld_a.qnorm()) # squared norm
NumPy buffer protocol (zero-copy)¶
import qlat_utils as q
import numpy as np
ld = q.mk_lat_data([["t", 4], ["x", 3]])
ld[0, 0] = 5.0
arr = np.asarray(ld) # zero-copy view
arr[1, 1] = 7.0 # writes through to LatData
if q.get_id_node() == 0:
print("ld[1,1]:", ld[1, 1]) # 7.0
Pickle round-trip¶
import qlat_utils as q
import pickle
ld = q.mk_lat_data([["t", 4], ["mom", 2, ["p0", "p1"]]])
ld[0, 0] = 1.0 + 0.5j
data = pickle.dumps(ld)
ld_restored = pickle.loads(data)
if q.get_id_node() == 0:
print("dim_names:", ld_restored.dim_names())
print("dim_indices(1):", ld_restored.dim_indices(1))
save_str / load_str round-trip¶
import qlat_utils as q
ld = q.mk_lat_data([["t", 4], ["p", 2]])
ld[0, 0] = 1.5
content = ld.save_str() # serialize to bytes
ld2 = q.LatData()
ld2.load_str(content) # deserialize
Load from file and convert to NumPy¶
import qlat_utils as q
import numpy as np
ld = q.load_lat_data("data/pion_corr.lat")
arr = np.asarray(ld)
if q.get_id_node() == 0:
print("NumPy shape:", arr.shape)
MPI global sum¶
import qlat_utils as q
size_node_list = [[1, 1, 1, 1]]
q.begin_with_mpi(size_node_list)
ld = q.mk_lat_data([["t", 8]])
ld.set_zero()
# ... accumulate local data ...
ld.glb_sum_in_place() # sum across all nodes
q.end_with_mpi()