Convert other formats into CON¶
Note
Executable Org Babel source (Python only) is Executable Chemfiles notebook.
CI runs scripts/run-chemfiles-notebook.sh (tangle + drift check +
python3 docs/notebooks/chemfiles_ingress.py). Rust and other language
snippets on this page are prose only — they are not Babel-run in CI.
Do not hand-edit the tangled .py; update the notebook Org source and
re-tangle with READCON_TANGLE_UPDATE=1.
Diátaxis companions: How-to — Chemfiles conversion and selection (tasks), Explanation — Chemfiles ingress and CON topology (why), Reference — Chemfiles conversion and selection (API tables).
flowchart LR
subgraph Foreign["Foreign trajectories"]
XYZ[XYZ]
PDB[PDB]
GRO[GRO]
OTH[…]
end
CF[chemfiles reader]
RC[readcon ConFrame]
CON[".con / .convel"]
SEL[selection grammar]
XYZ --> CF
PDB --> CF
GRO --> CF
OTH --> CF
CF -->|read_chemfiles*| RC
RC --> CON
RC --> SEL
SEL -->|atom_data indices| RC
This tutorial is learning-oriented: one successful path from a non-CON file
into CON. Prefer pip install readcon-chemfiles (or Rust --features chemfiles).
For native CON files without conversion, start with Tutorial — your first CON checkpoint instead.
What you will build¶
Install a chemfiles-linked build.
Drive conversion from another format (we use XYZ; the same APIs accept PDB, GRO, LAMMPS dump, and other chemfiles formats).
Inspect geometry, line-2 units (Å / ps from chemfiles), and optional bonds / residues.
Run a selection (
name O,angles: all) in CONatom_dataorder.Write a
.con(and optionally multi-frame) file for eOn / amsel / CON consumers.
You do not need a pre-existing .con file. The point is ingress from the wider ecosystem into CON.
Foreign trajectory to chemfiles to
ConFrame(optional bonds) to.con. chemparseplot and rgpycrumbs then plot that CON file.
Choose one install path¶
Pick one environment. Do not install both readcon and readcon-chemfiles
in the same venv (both provide import readcon).
Path A — Python full wheel (recommended)¶
python -m venv .venv && source .venv/bin/activate
pip install -U 'readcon-chemfiles==0.16.1'
python -c "import readcon; print(readcon.has_chemfiles_support())" # True
Path B — Rust with chemfiles¶
cargo build --features chemfiles
cargo test --features chemfiles --lib chemfiles
Path C — Editable Python from this repo¶
maturin develop --features python,chemfiles
python -c "import readcon; assert readcon.has_chemfiles_support()"
A small XYZ to convert¶
Create water.xyz:
3
water demo for readcon-core chemfiles tutorial
O 0.000 0.000 0.000
H 0.957 0.000 0.000
H -0.240 0.927 0.000
Any chemfiles-readable file works the same way (structure.pdb, conf.gro, …).
Convert XYZ → CON (Rust)¶
use readcon_core::chemfiles_import::{
chemfiles_enabled, con_frame_from_trajectory_path, con_frames_from_trajectory_path,
};
use readcon_core::writer::ConFrameWriter;
fn main() -> Result<(), Box<dyn std::error::Error>> {
assert!(chemfiles_enabled(), "rebuild with --features chemfiles");
let frame = con_frame_from_trajectory_path("water.xyz")?;
println!(
"atoms={} has_bonds={} bonds={}",
frame.atom_data.len(),
frame.has_bonds(),
frame.bonds().len()
);
let mut w = ConFrameWriter::from_path("water_from_xyz.con")?;
w.write_frame(&frame)?;
let all = con_frames_from_trajectory_path("water.xyz")?;
println!("trajectory frames: {}", all.len());
Ok(())
}
Build with --features chemfiles. Line 2 of the CON file is JSON
(con_spec_version 2). Topology, if present in the source format, becomes
metadata["bonds"] (indices in atom_data order; see :doc:`chemfiles-explain`).
Convert XYZ → CON (Python)¶
With readcon-chemfiles, Python mirrors the Rust ingress APIs:
import readcon
assert readcon.has_chemfiles_support(), "pip install readcon-chemfiles"
frame = readcon.read_chemfiles_first("water.xyz")
# or: frames = readcon.read_chemfiles("water.xyz")
print("atoms", len(frame.atoms), "has_bonds", frame.has_bonds)
for i, a in enumerate(frame.atoms):
print(f" [{i}] {a.symbol} id={a.atom_id} ({a.x:.3f},{a.y:.3f},{a.z:.3f})")
frame.write_con("water_from_xyz.con")
data = open("water.xyz", encoding="utf-8").read()
mem_frames = readcon.read_chemfiles_memory(data, "XYZ")
assert len(mem_frames) == 1
print("oxygens", frame.select_atoms("name O"))
Plain XYZ usually has no bonds. Geometry still converts; use PDB (or the
next section) for angles: / bonds:.
Drive topology¶
Prefer a bonded source format¶
let frame = con_frame_from_trajectory_path("ligand.pdb")?;
// has_bonds() often true → angles: / is_bonded work after projection
Or attach bonds after ingress (indices = atom_data order)¶
use readcon_core::chemfiles_import::con_frame_from_trajectory_path;
use readcon_core::chemfiles_selection::evaluate_selection_on_con_frame;
use readcon_core::types::{Bond, ConFrameBuilder};
use readcon_core::writer::ConFrameWriter;
let imported = con_frame_from_trajectory_path("water.xyz")?;
let mut b = ConFrameBuilder::new(imported.header.boxl, imported.header.angles);
for a in &imported.atom_data {
b.add_atom(
a.symbol.as_ref(),
a.x, a.y, a.z,
[a.fixed_x, a.fixed_y, a.fixed_z],
a.atom_id,
a.mass,
);
}
b.set_bonds(&[Bond::new(0, 1), Bond::new(0, 2)]);
let frame = b.build()?;
let angles = evaluate_selection_on_con_frame("angles: all", &frame)?;
assert_eq!(angles.context_size, 3);
let mut w = ConFrameWriter::from_path("water_with_bonds.con")?;
w.write_frame(&frame)?;
Python selection on bonded CON¶
import readcon
frame = readcon.read_first_frame("water_with_bonds.con")
assert frame.has_bonds
print(frame.select_atoms("type H"))
print(frame.select("bonds: all")["matches"])
print(frame.select("angles: all")["matches"])
frame.write_con("water_selected_roundtrip.con")
Multi-format conversion habit¶
Treat chemfiles as the format router; CON as the on-disk checkpoint store.
use readcon_core::chemfiles_import::con_frames_from_trajectory_path;
use readcon_core::writer::ConFrameWriter;
for path in ["conf.gro", "system.pdb", "dump.lammpstrj", "traj.xyz"] {
if !std::path::Path::new(path).exists() {
continue;
}
let frames = con_frames_from_trajectory_path(path)?;
let out = format!("{path}.converted.con");
let mut w = ConFrameWriter::from_path(&out)?;
for f in &frames {
w.write_frame(f)?;
}
}
In-memory:
use readcon_core::chemfiles_import::con_frames_from_memory;
let xyz = std::fs::read_to_string("water.xyz")?;
let frames = con_frames_from_memory(&xyz, "XYZ")?;
Checkpoint¶
You succeeded if:
has_chemfiles_support()/chemfiles_enabled()is true for your build.You produced a
.confrom a non-CON file.You know XYZ may lack bonds; PDB or
set_bondsenables topology selectors.You ran at least one selection and saw CON
atom_dataindices.
Next: :doc:`chemfiles-howto`, :doc:`chemfiles-explain`, :doc:`chemfiles-reference`.