Language bindings¶
Tip
Install: Getting started. Rust crate API:
docs.rs/readcon-core
(includes index_proj). Campaign store:
readcon-db docs ·
docs.rs/readcon-db.
This page is the multi-language reference (parity matrix + examples).
Feature parity matrix¶
The surfaces (Rust, Python, Julia, Fortran, C, C++) share the same core read/write/build functionality. The table below maps coarse features to bindings; multi-language panels follow for the common “read first frame” task.
Feature |
Rust |
Python |
Julia |
Fortran |
C |
C++ |
|---|---|---|---|---|---|---|
Lazy frame iterator |
yes |
yes (streaming |
yes |
|
yes |
yes |
Read-all-frames helper |
|
|
|
|
|
|
Count frames (skip walk) |
|
|
n/a |
n/a |
n/a |
n/a |
Coordinates on a loaded frame |
SoA on |
|
via frame fields |
via frame accessors |
via frame accessors |
via frame accessors |
Parallel multi-frame parse |
yes ( |
yes (via |
no |
no |
no |
no |
Builder API |
|
|
|
|
|
|
Writer API |
|
|
|
|
|
|
Velocity / force sections |
yes |
yes |
yes |
yes |
yes |
yes |
Per-axis fixed mask |
yes |
yes |
yes |
yes |
yes |
yes |
Typed metadata getters (energy, time, frame_index, neb_*) |
yes |
yes |
yes |
yes |
yes |
yes |
Typed metadata setters (set_energy, set_frame_index, …) |
yes |
yes |
yes |
yes |
yes |
yes |
Raw JSON metadata getter |
|
|
|
|
|
|
Strict validation ( |
yes |
yes |
yes |
yes |
yes |
yes |
RPC server |
yes ( |
no |
no |
no |
no |
no |
Cap’n Proto serialization |
yes ( |
no |
no |
no |
no |
no |
gzip / .gz round-trip |
yes |
yes |
yes |
yes |
yes |
yes |
zstd / .zst round-trip |
yes ( |
yes ( |
yes ( |
yes ( |
yes ( |
yes ( |
Per-atom |
yes |
yes |
yes |
yes |
yes |
yes |
Symbol <-> Z helpers |
yes |
derived from Atom |
yes |
|
|
|
|
|
|
|
|
|
|
Coords / forces / velocities / energies as NumPy ndarray |
n/a (use AoS) |
yes ( |
n/a |
n/a |
n/a |
n/a |
Builder DLPack 1.0 export (owned |
yes ( |
via NumPy |
n/a |
yes (all six sections + |
yes ( |
yes (same C ABI) |
metatensor |
yes ( |
n/a |
n/a |
yes (opaque |
yes (gated C ABI) |
yes (same C ABI) |
Optional frame |
yes |
|
|
|
|
|
Chemfiles import / selection |
yes ( |
|
|
|
|
|
Selection (shared evaluator). One evaluator core; every
surface is a pass-through (evaluate_selection_on_con_frame → chemfiles
Selection after projecting the frame). Build with --features chemfiles;
probe with rkr_has_chemfiles_support() / has_chemfiles_support() (Julia) /
feature at build time (Rust/Python).
Documentation map (Diátaxis): core tutorial tutorial.org; multi-language
how-to howto.org; chemfiles track chemfiles-tutorial.org /
chemfiles-howto.org / chemfiles-explain.org / chemfiles-reference.org.
This page is reference. Release cutting: contributing.org
Release process.
Multi-language: read first frame + metadata¶
Same task in each user-facing language (paths are examples).
use readcon_core::iterators::read_first_frame;
let frame = read_first_frame(std::path::Path::new("structure.con"))?;
println!("{} atoms, meta={:?}", frame.atom_data.len(), frame.header.metadata);
println!("energy={:?}", frame.header.energy());
import readcon
# Prefer first-frame / streaming / skip count when full materialization
# is unnecessary (see also count_frames, iter_con).
frame = readcon.read_first_frame("structure.con")
print(len(frame.atoms), frame.metadata)
print("energy", frame.energy) # typed accessor when present
use readcon
type(frame_t) :: fr
type(catom_t) :: a
fr = read_first_frame("structure.con")
if (fr%valid()) then
print *, "natoms", fr%natoms()
print *, "metadata_json", fr%metadata_json()
print *, "energy", fr%energy()
a = fr%atom(1)
print *, "atom1 fixed_x/y/z", a%fixed_x, a%fixed_y, a%fixed_z
call fr%free()
end if
#include "readcon-core.h"
RKRConFrame *f = rkr_read_first_frame("structure.con");
CFrame *cf = rkr_frame_to_c_frame(f);
char *meta = rkr_frame_metadata_json(f);
printf("natoms=%zu meta=%s\n", (size_t)cf->num_atoms, meta ? meta : "");
printf("fixed_x=%d\n", cf->atoms[0].fixed_x);
rkr_free_string(meta);
free_c_frame(cf);
free_rkr_frame(f);
#include "readcon-core.hpp"
// Prefer C API or C++ wrappers in include/readcon-core.hpp
auto *f = rkr_read_first_frame("structure.con");
auto *cf = rkr_frame_to_c_frame(f);
char *meta = rkr_frame_metadata_json(f);
// ... use cf->atoms[i].fixed_x/y/z ...
rkr_free_string(meta);
free_c_frame(cf);
free_rkr_frame(f);
Selection on CON frames. With metadata["bonds"] (0-based atom_data
pairs): bonds: / angles: / dihedrals: / pairs: / two: / three: /
four:, and is_bonded / is_angle / is_dihedral. Without bonds,
name / type / all / none still work. Matches are always in CON
atom_data order (type-grouped; import remaps bond endpoints via atom_id).
Name vs type after foreign import. On disk: one symbol column. Optional
sidecars chemfiles_atom_names / chemfiles_atom_types let name H1 and
type H differ after conversion. Hand-built frames use symbol for both.
Format limits. No residues, pair bonds only, thin property sidecars—so
resname, impropers, and most external property maps are not selectable.
Explanation — Chemfiles ingress and CON topology.
Python (PyO3)¶
Installation¶
# From PyPI
pip install readcon
# From source with maturin
maturin develop --features python
# Or via pixi
pixi r -e python python-build
Version and spec queries¶
import readcon
print(readcon.__version__) # e.g. "0.5.0"
print(readcon.CON_SPEC_VERSION) # 2
Usage¶
import readcon
# Read frames
frames = readcon.read_con("path/to/file.con")
first = readcon.read_first_frame("path/to/file.con")
for frame in readcon.iter_con("path/to/file.con"):
pass
frames = readcon.read_con_string(contents)
# Access data
for frame in frames:
print(frame.cell) # [f64, f64, f64]
print(frame.angles) # [f64, f64, f64]
print(frame.has_velocities)
for atom in frame.atoms:
print(atom.symbol, atom.x, atom.y, atom.z, atom.mass)
if atom.has_velocity:
print(atom.vx, atom.vy, atom.vz)
# Construct frames (v0.4.0+)
atom = readcon.Atom(symbol="Cu", x=0.0, y=0.0, z=0.0,
fixed=[False, False, False], atom_id=1)
frame = readcon.ConFrame(cell=[10.0, 10.0, 10.0],
angles=[90.0, 90.0, 90.0],
atoms=[atom])
frame.metadata["generator"] = "my-tool 1.0"
frame.atoms.append(readcon.Atom(symbol="H", x=1.0, y=0.0, z=0.0))
# Write frames (with optional precision)
readcon.write_con("output.con", frames)
readcon.write_con("precise.con", frames, precision=17)
output_str = readcon.write_con_string(frames)
# ASE conversion (v0.4.0+, requires ase)
ase_atoms = frame.to_ase()
frame2 = readcon.ConFrame.from_ase(ase_atoms)
Types¶
readcon.AtomConstructable with keyword arguments (v0.4.0+). Properties: symbol, x, y, z, fixed, is_fixed, atom_id, mass (v0.4.2+), vx, vy, vz, has_velocity, fx, fy, fz, has_forces, energy (v0.10.0+), has_energy (v0.10.0+). Data fields are writable.
readcon.ConFrameConstructable with cell, angles, atoms, and optional headers and metadata (v0.4.0+). Properties: cell, angles, atoms (live list), has_velocities, has_forces, has_energies (v0.10.0+), prebox_header, postbox_header, spec_version (v0.6.0+), metadata (v0.6.0+, live dict of native JSON-compatible values), energy, frame_index, time, timestep, neb_bead, neb_band. Methods: to_ase(), from_ase() (v0.4.0+), set_metadata_json(), set_scalar_metadata(), set_string_metadata(), set_energy(), set_frame_index(), set_time(), set_timestep(), set_neb_bead(), set_neb_band(), atom_index_by_id(id) (v0.10.0+), build_atom_id_index() (v0.10.0+), coords_array() (v0.10.0+), velocities_array() (v0.10.0+), forces_array() (v0.10.0+), energies_array() (v0.10.0+), atom_ids_array() (v0.10.0+).
readcon.read_first_frame(path)Parse and return only the first frame.
readcon.iter_con(path)Return a Python iterator over frames. The iterator API avoids indexing into
read_con(path)for first-frame and loop-based workflows.
NumPy array views and DLPack interop (v0.10.0+)¶
Every per-atom quantity has a contiguous NumPy ndarray accessor (type-grouped
atom_data order). Prefer DLPack for cross-framework hand-off: read
ndim, shape, and dtype (code/bits) from the tensor—do not assume the
host language must allocate f64 / real64 copies. On-disk CON numerics are
IEEE binary64 today, and current exports report kDLFloat / 64 for vectors and
scalars (kDLUInt / 64 for atom_id), but consumers should branch on the
tensor metadata so a future dtype change does not force a host f64 ABI.
C / C++ / Fortran: rkr_frame_*_dlpack / builder \*_dlpack (and
rkr_dlpack_delete) are the portable path. Choose output dtype and device
with RKRDlpackExportOptions on \*_dlpack_ex — fields are DLPack
DLDataType (code / bits / lanes) and DLDevice (device_type /
device_id), layout-compatible with <dlpack/dlpack.h>.
On CPU, float sections accept the DLPack host types we can fill from CON
binary64 storage: kDLFloat 32/64, kDLInt / kDLUInt 8/16/32/64, kDLBool
(8-bit). Complex / bfloat / float8 / opaque / lanes≠1 → validation error
until implemented. Non-CPU device_type without --features cuda →
RKR_STATUS_FEATURE_DISABLED (or validation error on Rust as_dlpack). With
optional cuda, kDLCUDA / RKR_DL_CUDA allocates real device memory and
frame/FFI export uses H2D for CPU-resident SoA (not host pointers labeled as
CUDA). Legacy
\*_dlpack exports 64-bit kDLFloat on CPU. rkr_frame_copy_* still fills double*.
import numpy as np
import torch
import readcon
frame = readcon.read_first_frame("trajectory.con")
coords = frame.coords_array() # ndarray (N, 3); inspect .dtype
forces = frame.forces_array() # Optional; None if absent
velocities = frame.velocities_array()
energies = frame.energies_array() # Optional shape (N,)
atom_ids = frame.atom_ids_array() # typically uint64
# Zero-copy hand-off into torch via DLPack (dtype follows the tensor).
coords_torch = torch.from_dlpack(coords)
assert coords_torch.shape == (len(frame), 3)
# atom_id reverse index for O(1) lookup by file column-5 id.
idx = frame.build_atom_id_index() # dict[int, int]
position = idx.get(42) # Optional[int]
ASE conversion preserves
atom_idthrough anatom_idarray, velocities through ASE velocities, forces through aSinglePointCalculator, and per-axis fixed masks throughFixCartesian/FixAtomsconstraints.
Typed metadata accessors¶
Every reserved JSON key has a typed setter in addition to the live
metadata dict. The setters validate the input type up front so
authoring with bad metadata fails immediately, while the dict path
remains available for raw escape-hatch use.
import readcon
frame = readcon.read_first_frame("traj.con")
# Read: typed getter returns None when absent
print(frame.energy) # Optional[float]
print(frame.frame_index) # Optional[int]
print(frame.neb_bead) # Optional[int]
# Write: typed setters validate input shape
frame.set_energy(-42.5)
frame.set_frame_index(7)
frame.set_neb_bead(3)
# Object-shaped keys still go through the dict
frame.metadata["potential"] = {"type": "EMT", "cutoff": 6.0}
frame.metadata["units"] = {"length": "angstrom", "energy": "eV"}
# Bulk-replace metadata from a JSON string (validated against the schema)
frame.set_metadata_json('{"con_spec_version": 2, "energy": -1.0}')
Julia (ccall)¶
Installation¶
Set READCON_LIB_PATH to the shared library path, or build with
cargo build --release and the Julia package will find it
automatically.
export READCON_LIB_PATH=/path/to/libreadcon_core.so
Usage¶
using ReadCon
frames = read_con("path/to/file.con")
for frame in frames
println(frame.cell)
println(frame.angles)
println(frame.has_velocities)
println(frame.spec_version)
println(frame.energy)
for atom in frame.atoms
println(atom.x, " ", atom.y, " ", atom.z)
end
end
write_con("roundtrip.con", frames)
Types¶
ReadCon.Atomatomic_number, x, y, z, atom_id, mass, is_fixed, fixed, vx, vy, vz, has_velocity, fx, fy, fz, has_forces
ReadCon.ConFramecell, angles, atoms, has_velocities, has_forces, prebox_header, postbox_header, spec_version, metadata_json, energy, frame_index, time, timestep, neb_bead, neb_band
ReadCon.write_con(path, frames; precision=6)Writes Julia frames through the C FFI builder/writer path, preserving velocities, forces, per-axis fixed masks, atom ids, masses, and JSON metadata.
Typed metadata accessors¶
Mirrors the Rust and Python typed-setter helpers. Reserved keys are
addressable by named getters and setters; arbitrary keys go through
metadata_json.
using ReadCon
frames = read_con("traj.con")
frame = first(frames)
# Read: typed getters return Union{Nothing, T}
println(frame.energy) # Union{Nothing, Float64}
println(frame.frame_index) # Union{Nothing, UInt64}
println(frame.time) # Union{Nothing, Float64}
# Write: typed setters
ReadCon.set_energy!(frame, -42.5)
ReadCon.set_frame_index!(frame, 7)
ReadCon.set_neb_bead!(frame, 3)
# Bulk: replace from a JSON string (validated against the schema)
ReadCon.set_metadata_json!(
frame,
"{\"con_spec_version\": 2, \"sections\": [\"velocities\"], \"energy\": -1.0}",
)
C/C++ (FFI)¶
Version and spec queries¶
#include "readcon-core.h"
// Compile-time check
#if RKR_CON_SPEC_VERSION < 2
#error "readcon-core spec v2 required for atom_id support"
#endif
// Runtime queries
printf("Spec version: %u\n", rkr_con_spec_version());
printf("Library version: %s\n", rkr_library_version());
C API¶
Include readcon-core.h and link against libreadcon_core.
#include "readcon-core.h"
CConFrameIterator *iter = read_con_file_iterator("file.con");
RKRConFrame *handle;
while ((handle = con_frame_iterator_next(iter)) != NULL) {
CFrame *frame = rkr_frame_to_c_frame(handle);
printf("Atoms: %zu, Velocities: %s\n",
frame->num_atoms, frame->has_velocities ? "yes" : "no");
for (size_t i = 0; i < frame->num_atoms; i++) {
CAtom *a = &frame->atoms[i];
if (a->has_velocity) {
printf(" vel=(%.6f, %.6f, %.6f)\n", a->vx, a->vy, a->vz);
}
}
free_c_frame(frame);
free_rkr_frame(handle);
}
free_con_frame_iterator(iter);
Path iterator + compression + in-memory buffers¶
read_con_file_iterator(path) routes through compression::read_file_contents:
plain .con, gzip (.con.gz / magic 1f 8b), and zstd (.con.zst, requires
--features zstd) all work without a temp file. Prefer these when the consumer
already holds text in memory (no temp file bridge):
Entry |
Input |
Notes |
|---|---|---|
|
filesystem path |
transparent gzip/zstd |
|
null-terminated CON UTF-8 |
caller-decompressed buffer |
|
byte slice (not necessarily NUL-terminated) |
same ownership as path iterator |
Free with free_con_frame_iterator; frames from con_frame_iterator_next with
free_rkr_frame. Bulk path: rkr_read_all_frames / free_rkr_frame_array or
free_rkr_frame_ptr_array (outer pointer array only).
Frame section buffers (no AoS required)¶
C |
C++ ( |
Meaning |
|---|---|---|
|
|
|
|
|
row-major xyz; always present |
|
matching |
|
|
|
owned DLPack share (dlpk |
Fortran: fr%atom_count(), fr%copy_positions(pbuf), fr%copy_velocities,
fr%copy_forces, fr%copy_masses (same status codes). Builder: bd%copy_positions,
bd%copy_masses, plus \*_dlpack helpers in fortran/README.md.
Multi-frame chemfiles selection (Rust + Python)¶
Atom-context trajectory positions (e.g. name H) without re-selecting in user code:
Rust:
evaluate_selection_on_frames/select_atom_positions_on_framesinchemfiles_selection(featurechemfiles; lean builds returnChemfilesImportError::FeatureDisabled).Python:
readcon.evaluate_selection_on_frames(sel, frames)andreadcon.select_atom_positions_on_frames("name H", frames)→{"selection", "frames": [{"frame_index", "result", "atom_indices", "positions"}, ...]}. Single-frame:select_on_frame/select_atom_indices/ConFrame.select/select_atomsremain. Indices are CONatom_dataorder (species-contiguous).
No C ABI multi-frame selection entry in this cut (call per-frame rkr_frame_select
or use Rust/Python). Lean builds: gated selection / metatensor return
RKR_STATUS_FEATURE_DISABLED (-11), never confused with internal error (-7).
Metadata builder helpers:
RKRConFrameBuilder *builder = rkr_frame_new(cell, angles, "", "", "", "");
if (rkr_frame_builder_set_energy(builder, -42.5) != RKR_STATUS_SUCCESS) {
free_rkr_frame_builder(builder);
return 1;
}
if (rkr_frame_builder_set_frame_index(builder, 7) != RKR_STATUS_SUCCESS) {
free_rkr_frame_builder(builder);
return 1;
}
rkr_frame_builder_set_time(builder, 3.5);
rkr_frame_builder_set_timestep(builder, 0.2);
rkr_frame_builder_set_neb_bead(builder, 4);
rkr_frame_builder_set_neb_band(builder, 1);
rkr_frame_builder_set_scalar_metadata(builder, "convergence", 1.0e-3);
rkr_frame_builder_set_string_metadata(builder, "generator", "eon");
rkr_frame_add_atom_with_velocity_and_forces_fixed_mask(
builder, "Cu", 0.0, 0.0, 0.0,
true, false, true,
0, 63.546,
0.1, 0.2, 0.3,
-0.1, -0.2, -0.3);
printf("status: %s\n", rkr_status_message(RKR_STATUS_SUCCESS));
C++ API¶
Include readcon-core.hpp for RAII wrappers.
#include "readcon-core.hpp"
readcon::ConFrameIterator frames("file.con");
for (auto&& frame : frames) {
auto& cell = frame.cell();
auto& atoms = frame.atoms();
bool has_vel = frame.has_velocities();
for (const auto& atom : atoms) {
if (atom.has_velocity) {
std::cout << atom.vx << " " << atom.vy << " " << atom.vz << "\n";
}
}
}
Builder metadata helpers:
readcon::ConFrameBuilder builder({10.0, 10.0, 10.0}, {90.0, 90.0, 90.0});
builder.set_energy(-42.5);
builder.set_frame_index(7);
builder.set_time(3.5);
builder.set_timestep(0.2);
builder.set_neb_bead(4);
builder.set_neb_band(1);
builder.set_scalar_metadata("convergence", 1.0e-3);
builder.set_string_metadata("generator", "eon");
builder.set_metadata_json(R"({"custom_key":"custom_value"})");
builder.add_atom_with_velocity_and_forces(
"Cu", 0.0, 0.0, 0.0,
{true, false, true},
0, 63.546,
0.1, 0.2, 0.3,
-0.1, -0.2, -0.3);
Build system integration¶
Meson wrap¶
readcon_dep = dependency('readcon-core')
executable('my_app', 'main.c', dependencies: readcon_dep)
CMake FetchContent¶
include(FetchContent)
FetchContent_Declare(
readcon-core
URL https://github.com/lode-org/readcon-core/releases/download/v0.14.1/readcon-core-cxx-0.14.1.tar.gz
URL_HASH SHA256=<sha256 from the .sha256 sidecar on the GitHub Release>
)
FetchContent_MakeAvailable(readcon-core)
target_link_libraries(my_app PRIVATE readcon-core::shared)
metatensor TensorBlock export (v0.10.0+; C/Fortran ABI v0.13.1+)¶
Design (option A): high-level construction in Rust
(metatensor_export / TensorBlock); C boundary = metatensor-sys only
(mts_block_t *, mts_block_data / mts_block_labels / mts_block_free from
metatensor.h). Single ownership transfer in Rust
(tensor_block_into_raw_mts → rkr_* out-param; free with rkr_mts_block_free
or mts_block_free, not both). We do not merge metatensor’s cbindgen
header into readcon-core.h; two headers, one pointer ABI.
Lean vs fat builds
Variant |
Cargo |
|
C header |
Fortran module |
Link |
|---|---|---|---|---|---|
Lean |
default / |
symbols always linked (stubs) |
|
C decls always present; runtime **``RKR_STATUS_FEATURE_DISABLED`` (``-11``)** |
no real blocks |
Fat |
|
export all four blocks + |
|
full TensorBlock transfer |
yes |
After a fat cargo build --features metatensor, build.rs writes
target/<profile>/readcon-metatensor.env (READCON_METATENSOR_INCLUDE,
READCON_METATENSOR_LIB_DIR) and adds link-search / -lmetatensor / rpath.
scripts/run_fortran_tests.sh sources that file (with a glob fallback).
Headers
File |
When |
|---|---|
|
Always; metatensor + zstd entry points always declared (lean stubs |
|
Prefer for C consumers: includes ``metatensor.h`` first, then defines the gate and |
|
Values/labels/free via sys C API; required to interpret the pointer |
Regenerate readcon-core.h with scripts/regen-capi-headers.sh (CI --check).
Status codes (C/Fortran)
Code |
Meaning |
|---|---|
|
Owned non-null |
|
null pointer arg |
|
API not in this build (lean Fortran metatensor; never aliases internal error |
|
Optional velocities/forces/energies missing on frame; out null |
other non-zero |
internal / metatensor error |
Exports
Quantity |
Shape |
C ABI |
Fortran (fat / |
|---|---|---|---|
positions |
|
|
|
velocities |
|
|
|
forces |
|
|
|
atom energies |
|
|
|
free |
— |
|
|
Sample labels atom_id; properties xyz (0/1/2) or single energy. No full
TensorMap keyed by species (callers build that). Example C consumer:
examples/c_metatensor_sample.c.
[dependencies]
readcon-core = { version = "0.13", features = ["metatensor"] }
use readcon_core::metatensor_export::{
frame_positions_block, frame_velocities_block,
frame_forces_block, frame_energies_block,
tensor_block_into_raw_mts, // FFI transfer; prefer rkr_* from C
};
let frame = /* ... */;
let positions = frame_positions_block(&frame)?; // [N, 3] f64
let velocities = frame_velocities_block(&frame)?; // Option<TensorBlock>
// C path: tensor_block_into_raw_mts(block) then mts_block_free only
cargo build --release --features chemfiles,metatensor
set -a && source target/release/readcon-metatensor.env && set +a
gcc -I include -I "$READCON_METATENSOR_INCLUDE" examples/c_metatensor_sample.c \
-L target/release -L "$READCON_METATENSOR_LIB_DIR" \
-Wl,-rpath,"$READCON_METATENSOR_LIB_DIR" -Wl,-rpath,$PWD/target/release \
-lreadcon_core -lmetatensor -o /tmp/c_mts
#include "readcon-metatensor.h"
/* rkr_frame_metatensor_positions_block(frame, &block);
mts_block_data(block, &array); mts_block_labels(block, 0);
rkr_mts_block_free(block); */
CI / tests: Rust metatensor_ lib tests (C ABI + transfer). Fortran workflow
runs lean (chemfiles) and fat (chemfiles,metatensor) via
scripts/run_fortran_tests.sh. Fortran suite does not call chemfiles C++
on CI (SIGFPE under gfortran traps); chemfiles stays on Rust CI. Python/Julia:
no first-class TensorBlock helpers (matrix n/a); use C or Rust.
Builder and frame DLPack export (C / Fortran)¶
Owned DLManagedTensorVersioned tensors (mirror of dlpack.h). Fortran binds
struct fields for dlpack_inspect (ndim, shape, dtype bits) and
dlpack_data_ptr. *Inspect dtype before casting the data pointer*—do not
require host real64 solely because CON text uses binary64; use the bits field
(64 for float sections today; 64 uint for atom ids).
Section |
C (builder / frame) |
Fortran |
|---|---|---|
positions |
|
|
velocities |
|
|
forces |
|
|
atom energies |
|
|
masses |
|
|
atom ids |
|
|
free |
|
|
Absent optional sections return RKR_STATUS_SECTION_ABSENT. Builder exports are
owned clones, not live views of internal storage. Frame copy_* helpers still
take double* for hosts that already use f64; prefer DLPack when interoperating.
Compression formats¶
Extension |
Magic bytes |
Feature |
Reader |
Writer |
|---|---|---|---|---|
|
|
always |
transparent decode on read |
|
|
|
|
transparent decode on read |
|
Builds without the zstd feature still detect zstd magic bytes on
read and return io::ErrorKind::Unsupported pointing at the feature
flag, so consumers never see a corrupt parse on a zstd file produced
by another tool.
Fortran (fpm ReadCon, ISO_C_BINDING)¶
Wrappers in fortran/ReadCon/src/readcon.f90 over include/readcon-core.h
(issue #6). Link libreadcon_core (Meson wrap, CMake FetchContent / find_package, or pkg-config --libs readcon-core).
# Lean (chemfiles only): metatensor Fortran helpers return RKR_STATUS_FEATURE_DISABLED (-11)
READCON_FORTRAN_FEATURES=chemfiles scripts/run_fortran_tests.sh
# Fat: real mts_block_t* path (-cpp -DREADCON_HAS_METATENSOR + libmetatensor)
READCON_FORTRAN_FEATURES=chemfiles,metatensor scripts/run_fortran_tests.sh
use readcon
use, intrinsic :: iso_c_binding
type(frame_t) :: fr
type(builder_t) :: bd
type(c_ptr) :: tensor, block
integer :: st, ndim, bits
integer(int64) :: s0, s1
logical :: ok
fr = read_first_frame("structure.con")
st = bd%positions_dlpack(tensor)
call dlpack_inspect(tensor, ndim, s0, s1, bits, ok)
call bd%dlpack_delete(tensor)
st = frame_metatensor_positions_block(fr, block) ! fat lib
call mts_block_free_rkr(block)
call fr%free()
Per-axis fixed_x / fixed_y / fixed_z are on catom_t (issue #19).
Full API: frame_t, iterator_t, builder_t, writer_t, all six DLPack
exports, four metatensor block exports (when linked), symbol_to_z /
z_to_symbol, has_chemfiles_support. Details: fortran/README.md.
CI: .github/workflows/ci_fortran.yml (lean and fat jobs).