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 and optional bonds on the resulting CON frame.
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 → chemfiles →
ConFrame(optional bonds) →.con.After ingress, geometries are first-class for chemparseplot / rgpycrumbs /
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.14.0'
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`.