Input and output

Six formats, each in its own sub-table of qcd. They differ in what they can hold and in how they behave in parallel, and those two differences are the ones to read first.

ModuleHoldsParallel
qcd.affnamed records of strings and flat numeric vectors, in a directory treereader everywhere, writer on the master
qcd.hdf5the same, plus lattice fieldsboth, with a choice of driver
qcd.qdpcQIO records: lattice fields, random states, flat vectors and matricesboth, through QIO
qcd.ddpairssource/propagator pairs in the USQCD DD-pairs layoutthrough QIO
qcd.qdpcca single propagator in the SciDAC/Chroma layoutthrough QIO
qcd.nersc, qcd.milcgauge configurations in their archive formatssee each

AFF

AFF is a small key–value container: a tree of named nodes, each holding a string or a flat vector of ints, doubles or complexes. It is the usual place for correlator output. Paths look like file-system paths, and a reader or a writer has a current directory that chpath moves.

qcd.aff.Reader

qcd.aff.Reader(filename)                          --> aff.reader

Opens an AFF file for reading, on every rank. Raises with the library's own message if it cannot.

qcd.aff.Writer

qcd.aff.Writer(filename)                          --> aff.writer

Opens an AFF file for writing. Only the master node holds a real writer; the other ranks hold a dummy that accepts the calls and does nothing. Success is agreed across ranks, so a failure raises everywhere.

aff.reader:read

r:read(path)                                      --> value

Reads one node. A group node gives true, a character node a string, and the three numeric kinds a vector.int, a vector.real or a vector.complex.

aff.reader:kind

r:kind(path)                                      --> string

One of "Group", "String", "VectorInt", "VectorReal", "VectorComplex" or "Invalid".

aff.reader:list

r:list(path)                                      --> table

The names of the children of a group, as a list of strings.

aff.reader:chpath

r:chpath(path)                                    --> nothing

Changes the current directory. Relative paths are then taken from it.

aff.reader:status

r:status()                                        --> string or nil

The library's last error message, or nil if there was none.

aff.reader:close

r:close()                                         --> nothing

aff.writer:write

w:write(path, value)                              --> nil

Writes one node, creating the path. value is a string, a vector.int, a vector.real or a vector.complex; anything else raises.

aff.writer:mkpath

w:mkpath(path)                                    --> nothing

Creates a group, and any missing groups above it.

aff.writer:chpath

w:chpath(path)                                    --> nothing

aff.writer:status

w:status()                                        --> string or nil

aff.writer:close

w:close()                                         --> nothing

Closing a writer is not optional: the index is written at close time, and a file that was not closed is not readable.

local w = qcd.aff.Writer("out.aff")
w:write("/corr/pion", vector.complex(32))
w:close()

HDF5

The HDF5 module writes the same scalar data AFF does, and lattice fields as well. Both the reader and the writer take an option table that chooses the driver and the on-disk representation.

qcd.hdf5.Reader

qcd.hdf5.Reader(filename [, options])             --> hdf5.reader

qcd.hdf5.Writer

qcd.hdf5.Writer(filename [, options])             --> hdf5.writer

An existing file is opened for update; a missing one is created.

The options, for either:

KeyValuesMeaning
method"posix", "phdf5", "mpio"the driver
transfer"independent", "collective"the MPI-IO transfer mode
metadata"auto", "deferred"the metadata cache policy
precision"double", "float"the on-disk word size
sha256"ignore", "check"whether to verify the stored checksum
kinda record-kind nameforce the interpretation of a record
chunk"contiguous", "natural", or a listthe dataset chunking
alignment, thresholdnumbersH5Pset_alignment
istoreKnumberH5Pset_istore_k, writer only
latticea latticerequired for a lattice-field record, on write and on read

A reader with no method opens the file sequentially on every rank, which is safe and is what reads a parallel-written file without being told to. method="posix" has the master read and broadcast, and then lattice data cannot be read at all. A writer with no method is sequential — master only — and refuses lattice data; phdf5 and mpio make it parallel.

A lattice field is written and read with {lattice = L} in the per-record options, and usually precision as well. Without it the writer does not know the geometry, and the reader answers "no suitable reader". This is a per-call option, not a file-level one, so it goes on write and read, not on Writer and Reader:

local w = qcd.hdf5.Writer("f.h5", {method = "phdf5"})
w:write("/U", U, {lattice = L, precision = "double"})
w:close()

local r = qcd.hdf5.Reader("f.h5")
local V, status = r:read("/U", {lattice = L, precision = "double"})
r:close()

"mpiposix" was removed; asking for it raises rather than silently falling back.

The record kinds, for kind and for what stat reports, are String, Real, Complex, MatrixReal, MatrixComplex, VectorInt, VectorReal, VectorComplex, ColorVector, ColorMatrix, DiracFermion, DiracPropagator, LatticeInt, LatticeReal, LatticeComplex, LatticeColorVector, LatticeColorMatrix, LatticeDiracFermion, LatticeDiracPropagator, and the structural Group, DataSpace, DataSet, DataType, Attribute, File and Unknown.

hdf5.reader:read

r:read(path [, options])                          --> value, status

Reads one dataset and returns it along with a status string — "OK" when the read succeeded. Without kind the reader takes the kind from the record's own metadata. A lattice record needs {lattice = L} in the options.

hdf5.reader:list

r:list(path)                                      --> table

The names of the members of the group at path, as a list of strings in increasing name order. Only the immediate children, not the whole subtree, and the names alone — use stat to find out what each one is. A path that is not a group raises.

Note that a file written by qlua carries its own type descriptors as members of the root group, named with a leading dot, and list reports them along with the data:

r:list("/")   -->   { ".ColorMatrixDouble3", ".ComplexDouble", "U", "s" }

hdf5.reader:stat

r:stat(path)                                      --> table

What is at path, as a table. For a lattice record its fields are kind (one of the record-kind names above), type (the on-disk HDF5 type name), geometry (a table), time and sha256.

hdf5.reader:cwd

r:cwd()                                           --> string

hdf5.reader:chpath

r:chpath(path)                                    --> nothing

hdf5.reader:close

r:close()                                         --> nothing

hdf5.writer:write

w:write(path, value [, options])                  --> nothing

Writes one dataset. value may be a string, a number, a complex, a vector, a matrix, a sequential color object or — on a parallel writer, and with {lattice = L} in the options — a lattice field. Writing lattice data to a sequential writer raises, on every rank, so the job stops cleanly rather than deadlocking.

hdf5.writer:mkpath

w:mkpath(path)                                    --> nothing

hdf5.writer:remove

w:remove(path)                                    --> nothing

hdf5.writer:cwd

w:cwd()                                           --> string

hdf5.writer:chpath

w:chpath(path)                                    --> nothing

hdf5.writer:flush

w:flush()                                         --> nothing

hdf5.writer:close

w:close()                                         --> nothing

QDP/C files (QIO)

A QIO file is a sequence of records, each carrying an XML metadata string and its data. The reader and the writer are strictly sequential in the file: a record is read or written where the cursor is. The method name says what type the record holds, so reading is type-directed — you must know what comes next, or skip it.

qcd.qdpc.Reader

qcd.qdpc.Reader(L, filename [, options])          --> reader, file_xml

Returns the reader and the file-level XML string, or nothing at all if the file could not be opened — so the idiom is

local r, xml = qcd.qdpc.Reader(L, "cfg.lime")
if not r then error("cannot read cfg.lime") end

The options control the I/O-node mapping: rank_stride and master choose which ranks do the writing, and volmap is "natural", "lex" or "rlex".

qcd.qdpc.Writer

qcd.qdpc.Writer(L, filename, file_xml [, volfmt [, options]])  --> writer

volfmt is "single" (the default), "multi", "part" or "part_dir". The options are the reader's.

Reader record methods

Each returns the value and the record's XML string. Given a count n it reads n records of that type and returns them as a table.

MethodReads
r:Int([n])lattice Int
r:Real([n])lattice Real
r:Complex([n])lattice Complex
r:RandomState([n])lattice RandomState
r:ColorVector([n])lattice ColorVector, default colors
r:ColorVectorN(nc [, n])lattice ColorVector
r:ColorMatrix([n])lattice ColorMatrix
r:ColorMatrixN(nc [, n])lattice ColorMatrix
r:DiracFermion([n])lattice DiracFermion
r:DiracFermionN(nc [, n])lattice DiracFermion
r:DiracPropagator([n])lattice DiracPropagator
r:DiracPropagatorN(nc [, n])lattice DiracPropagator
r:generic_Real(...)a real record of unknown color structure
r:int_vector(len)vector.int
r:real_vector(len)vector.real
r:complex_vector(len)vector.complex
r:real_matrix(rows, cols)matrix.real
r:complex_matrix(rows, cols)matrix.complex

A reader also has r:skip(), which steps over the next record without decoding it, and r:close().

The file may be in single precision; the reader converts on the way in, so a script never has to ask.

Writer record methods

Each takes the value and the record's XML string and returns true. For the real and complex types a precision string, "float"/"F" or "double"/"D", may come first; without one the record is written in double. A table in place of a single value writes that many records at once.

MethodWrites
w:Int(I, xml)lattice Int
w:Real([prec,] R, xml)lattice Real
w:Complex([prec,] C, xml)lattice Complex
w:RandomState(S, xml)lattice RandomState
w:ColorVector([prec,] V, xml)lattice ColorVector
w:ColorMatrix([prec,] M, xml)lattice ColorMatrix
w:DiracFermion([prec,] D, xml)lattice DiracFermion
w:DiracPropagator([prec,] P, xml)lattice DiracPropagator
w:int_vector(v, xml)vector.int
w:real_vector(v, xml)vector.real
w:complex_vector(v, xml)vector.complex
w:real_matrix(m, xml)matrix.real
w:complex_matrix(m, xml)matrix.complex

w:close() finishes the file.

The writer has no N-suffixed methods: the number of colors is read from the field.

local w = qcd.qdpc.Writer(L, "gauge.lime", "<cfg/>")
w:ColorMatrix("double", U[1], "<mu>0</mu>")
w:close()

DD-pairs

The USQCD DD-pairs layout stores a source and the propagator solved from it in one file.

qcd.ddpairs.read

qcd.ddpairs.read(L, filename)                     --> source, prop, file_xml

The number of colors is the lattice default.

qcd.ddpairs.readN

qcd.ddpairs.readN(nc, L, filename)                --> source, prop, file_xml

qcd.ddpairs.write

qcd.ddpairs.write(prec, filename, file_xml,
                  source, source_xml, time_slice,
                  prop, prop_xml [, volfmt])      --> nothing

prec is "float"/"F" or "double"/"D". time_slice restricts the source record to one time slice; a value outside the lattice writes the whole volume. volfmt is as for qcd.qdpc.Writer.

Up to and including 2026.10d, volfmt here and in qcd.qdpcc.write_prop was optional only on paper: the binding pushed the lattice before examining the argument, and that landed in the slot an omitted one would have occupied, so leaving it out raised "string expected, got userdata". On such a build, pass "single" explicitly.

SciDAC/Chroma propagators

qcd.qdpcc.read_prop

qcd.qdpcc.read_prop(L, filename)                  --> prop, file_xml, record_xml

qcd.qdpcc.read_propN

qcd.qdpcc.read_propN(nc, L, filename)             --> prop, file_xml, record_xml

qcd.qdpcc.write_prop

qcd.qdpcc.write_prop(prec, filename, file_xml,
                     prop, record_xml [, volfmt]) --> nothing

volfmt defaults to "single"; on 2026.10d and earlier it had to be given, for the reason noted under qcd.ddpairs.write.

NERSC gauge configurations

qcd.nersc.read_gauge

qcd.nersc.read_gauge(L, filename [, {parallel=true}])  --> gauge, header

Returns a list of #L lattice ColorMatrix fields over three colors and a table of the header's key–value pairs. With parallel=false the master node reads and distributes, which is slower but works where the parallel path does not.

qcd.nersc.write_gauge

qcd.nersc.write_gauge(filename, gauge [, options]) --> nothing

gauge is a list of #L three-color ColorMatrix fields. The options set parallel (default false) and the header fields, each a string: HDR_VERSION, STORAGE_FORMAT, ENSEMBLE_ID, ENSEMBLE_LABEL, SEQUENCE_NUMBER, CREATOR, CREATOR_HARDWARE, CREATION_DATE, ARCHIVE_DATE, FLOATING_POINT (default IEEE64BIG) and DATATYPE (default 4D_SU3_GAUGE). The link trace, the plaquette and the checksum are computed and written for you.

MILC gauge configurations

qcd.milc.read_gauge

qcd.milc.read_gauge(L, filename)                  --> gauge, header

Returns the gauge field as a list of #L three-color ColorMatrix fields, and a table whose datetmp field is the configuration's date string. There is no MILC writer.