How-to — Chemfiles conversion and selection¶
Note
Diátaxis how-to guides. Learning path: Convert other formats into CON.
Executable Org: Executable Chemfiles notebook (scripts/run-chemfiles-notebook.sh).
(How-to — CON I/O by language) or finish Convert other formats into CON once.
How to convert a single structure file (XYZ, PDB, GRO, …) to CON¶
Goal: one file on disk → one .con.
Rust (requires --features chemfiles):
use readcon_core::chemfiles_import::con_frame_from_trajectory_path;
use readcon_core::writer::ConFrameWriter;
let frame = con_frame_from_trajectory_path("input.pdb")?; // or .xyz, .gro, …
let mut w = ConFrameWriter::from_path("output.con")?;
w.write_frame(&frame)?;
Chemfiles selects the reader from the path. If the format has topology, CON
line-2 JSON may include bonds (0-based atom_data indices after import
remap).
Python (readcon-chemfiles):
import readcon
frame = readcon.read_chemfiles_first("input.pdb") # or .xyz, .gro, …
frame.write_con("output.con")
# multi-frame:
for i, f in enumerate(readcon.read_chemfiles("traj.xyz")):
f.write_con(f"frame_{i}.con")
# or one multi-frame CON via write_con(list) — use readcon.write_con(path, frames)
frames = readcon.read_chemfiles("traj.xyz")
readcon.write_con("traj.con", frames)
How to convert a multi-frame trajectory into multi-frame CON¶
Goal: every chemfiles step becomes a CON frame in one file.
use readcon_core::chemfiles_import::con_frames_from_trajectory_path;
use readcon_core::writer::ConFrameWriter;
let frames = con_frames_from_trajectory_path("traj.xyz")?;
let mut w = ConFrameWriter::from_path("traj.con")?;
for f in &frames {
w.write_frame(f)?;
}
How to convert from an in-memory buffer¶
Goal: bytes already in memory (HTTP download, archive member).
use readcon_core::chemfiles_import::con_frames_from_memory;
let data = std::fs::read_to_string("snippet.xyz")?;
// Second argument is a chemfiles format name, e.g. "XYZ", "PDB", "GRO"
let frames = con_frames_from_memory(&data, "XYZ")?;
How to select atoms by name or type on a CON frame¶
Goal: indices in CON atom_data order (not atom_id column unless they
coincide).
Python (readcon-chemfiles):
import readcon
frame = readcon.read_first_frame("structure.con")
print(readcon.select_atom_indices(frame, "name O"))
print(readcon.select_atom_indices(frame, "type H"))
print(readcon.select_atom_indices(frame, "all"))
Rust:
use readcon_core::chemfiles_selection::select_atom_indices;
// frame: &ConFrame
let oxygens = select_atom_indices("name O", frame)?;
Works without bonds for atom selectors. On lean builds / lean wheels,
APIs exist but return FeatureDisabled / RuntimeError — install full
chemfiles support.
How to select bonds and angles¶
Goal: topology-aware matches.
Requires metadata["bonds"] on the frame (from chemfiles import of a bonded
format, or ConFrameBuilder::set_bonds / header.set_bonds).
import readcon
frame = readcon.read_first_frame("with_bonds.con")
assert frame.has_bonds
print(readcon.select_on_frame(frame, "bonds: all")["matches"])
print(readcon.select_on_frame(frame, "angles: all")["matches"])
print(readcon.select_on_frame(frame, "is_bonded")) # pair context
use readcon_core::chemfiles_selection::evaluate_selection_on_con_frame;
let r = evaluate_selection_on_con_frame("angles: all", frame)?;
assert_eq!(r.context_size, 3);
Angles/dihedrals are derived by chemfiles from bonds at projection time; you do not store angle arrays on disk in v0.13.
How to use the C API for selection¶
Build libreadcon_core with --features chemfiles for real evaluation;
without it, rkr_has_chemfiles_support() is 0 and rkr_frame_select returns
RKR_STATUS_SELECTION_ERROR.
#include "readcon-core.h"
if (!rkr_has_chemfiles_support()) { /* rebuild with chemfiles */ }
RKRConFrame *frame = /* from iterator */;
RKRSelectionResult *sel = NULL;
if (rkr_frame_select(frame, "bonds: all", &sel) == RKR_STATUS_SUCCESS) {
uint64_t n = rkr_selection_result_match_count(sel);
/* ... rkr_selection_result_match_at ... */
rkr_selection_result_free(sel);
}
C++: readcon::ConFrame::select / readcon::has_chemfiles_support() in
readcon-core.hpp.
How to install lean CON I/O only (no libchemfiles)¶
pip install 'readcon==0.13.0' # has_chemfiles_support() is False
cargo build # stubs; FeatureDisabled on import/select
Selection symbols still import in Python/Rust; they error clearly. Use this for CI that must not compile CMake/chemfiles.
How to install full chemfiles support¶
pip install 'readcon-chemfiles==0.13.0' # preferred PyPI
# or: pip install 'readcon[chemfiles]' # depends on readcon-chemfiles==X.Y.Z
cargo build --features chemfiles
maturin develop --features python,chemfiles
Do not install readcon and readcon-chemfiles together (module clash).
How to batch-convert a directory of foreign trajectories¶
use readcon_core::chemfiles_import::con_frames_from_trajectory_path;
use readcon_core::writer::ConFrameWriter;
use std::fs;
use std::path::Path;
fn convert_tree(dir: &Path) -> std::io::Result<()> {
for entry in fs::read_dir(dir)? {
let path = entry?.path();
let ext = path.extension().and_then(|e| e.to_str()).unwrap_or("");
if !matches!(ext, "xyz" | "pdb" | "gro" | "lammpstrj" | "mol2") {
continue;
}
let Ok(frames) = con_frames_from_trajectory_path(&path) else {
eprintln!("skip (chemfiles failed): {}", path.display());
continue;
};
let out = path.with_extension("con");
let mut w = ConFrameWriter::from_path(&out).expect("writer");
for f in &frames {
w.write_frame(f).expect("write");
}
println!("{} -> {} ({} frames)", path.display(), out.display(), frames.len());
}
Ok(())
}
Run under a chemfiles-enabled build. Extend the extension list for formats your chemfiles build supports.
How to batch-convert in Python¶
from pathlib import Path
import readcon
assert readcon.has_chemfiles_support()
exts = {".xyz", ".pdb", ".gro", ".lammpstrj", ".mol2"}
for path in Path("incoming").iterdir():
if path.suffix.lower() not in exts:
continue
try:
frames = readcon.read_chemfiles(str(path))
except (OSError, ValueError, RuntimeError) as e:
print("skip", path, e)
continue
out = path.with_suffix(".con")
readcon.write_con(str(out), frames)
print(path, "->", out, len(frames), "frames")