Rust API
Installation
Add sci-form to your Cargo.toml:
[dependencies]
sci-form = "0.9"For parallel batch processing, enable the parallel feature:
[dependencies]
sci-form = { version = "0.9", features = ["parallel"] }For GPU acceleration (experimental):
[dependencies]
sci-form = { version = "0.9", features = ["experimental-gpu"] }Core Types
ConformerResult
The result of a 3D conformer generation.
pub struct ConformerResult {
/// Input SMILES string
pub smiles: String,
/// Number of atoms
pub num_atoms: usize,
/// Flat coordinates: [x₀, y₀, z₀, x₁, y₁, z₁, ...]
pub coords: Vec<f64>,
/// Atomic numbers in the same order as coordinates
pub elements: Vec<u8>,
/// Bonds as (atom_a, atom_b, order_string)
pub bonds: Vec<(usize, usize, String)>,
/// Error message (None if successful)
pub error: Option<String>,
/// Generation time in milliseconds
pub time_ms: f64,
}Bond order strings: "SINGLE", "DOUBLE", "TRIPLE", "AROMATIC".
ConformerConfig
Configuration for batch generation.
pub struct ConformerConfig {
/// RNG seed for reproducibility (default: 42)
pub seed: u64,
/// Number of threads, 0 = auto-detect (default: 0)
pub num_threads: usize,
}Functions
embed(smiles, seed) → ConformerResult
Generate a single 3D conformer.
let result = sci_form::embed("CCO", 42);
assert!(result.error.is_none());
assert_eq!(result.num_atoms, 9); // 2C + 1O + 6HThe same seed always produces the same coordinates (deterministic).
embed_batch(smiles_list, config) → Vec<ConformerResult>
Generate conformers for multiple molecules, optionally in parallel.
let smiles = vec!["CCO", "c1ccccc1", "CC(=O)O"];
let config = sci_form::ConformerConfig { seed: 42, num_threads: 4 };
let results = sci_form::embed_batch(&smiles, &config);
for r in &results {
println!("{}: {} atoms, {:.1}ms", r.smiles, r.num_atoms, r.time_ms);
}Requires the parallel feature for multi-threaded execution. Without it, molecules are processed sequentially.
parse(smiles) → Result<Molecule, String>
Parse a SMILES string into a molecular graph without generating 3D coordinates.
let mol = sci_form::parse("c1ccccc1").unwrap();
println!("Atoms: {}, Bonds: {}", mol.graph.node_count(), mol.graph.edge_count());version() → String
println!("{}", sci_form::version()); // "sci-form 0.9.1"Working with Coordinates
let result = sci_form::embed("CC(=O)O", 42);
if result.error.is_none() {
// Access individual atom coordinates
for i in 0..result.num_atoms {
let x = result.coords[i * 3];
let y = result.coords[i * 3 + 1];
let z = result.coords[i * 3 + 2];
let elem = result.elements[i];
println!("Atom {} (Z={}): ({:.3}, {:.3}, {:.3})", i, elem, x, y, z);
}
}Serialization
ConformerResult implements Serialize and Deserialize (serde), so you can convert to/from JSON:
let result = sci_form::embed("CCO", 42);
let json = serde_json::to_string_pretty(&result).unwrap();
println!("{}", json);Quantum Chemistry Pipeline
let conf = sci_form::embed("c1ccccc1", 42);
let pos: Vec<[f64;3]> = conf.coords.chunks(3).map(|c| [c[0],c[1],c[2]]).collect();
// PM3 semi-empirical (supports transition metals via PM3(tm))
let pm3 = sci_form::compute_pm3(&conf.elements, &pos).unwrap();
println!("PM3 HOF: {:.2} kcal/mol, gap: {:.3} eV", pm3.heat_of_formation, pm3.gap);
// GFN-xTB family
let xtb = sci_form::compute_xtb(&conf.elements, &pos).unwrap();
let gfn1 = sci_form::xtb::gfn1::solve_gfn1(&conf.elements, &pos).unwrap();
let gfn2 = sci_form::xtb::gfn2::solve_gfn2(&conf.elements, &pos).unwrap();
println!("GFN2 gap: {:.3} eV, D4: {:.4} eV", gfn2.gap, gfn2.dispersion_energy);
// HF-3c with CISD excited states
let hf = sci_form::solve_hf3c(&conf.elements, &pos, &Default::default()).unwrap();
println!("HF-3c energy: {:.4} eV, converged: {}", hf.energy, hf.converged);3D Descriptors & ML Models
use sci_form::ml::whim::{compute_whim, WhimWeighting};
use sci_form::ml::advanced_models::*;
let whim = compute_whim(&conf.elements, &pos, WhimWeighting::Mass);
println!("WHIM spread: {:.3}", whim.total_spread);
// Train a Random Forest
let rf_config = RandomForestConfig { n_trees: 100, ..Default::default() };
let rf = train_random_forest(&features, &targets, &rf_config);
let pred = rf.predict(&new_sample);Crystallographic Materials
use sci_form::materials::space_groups::space_group_by_number;
let sg = space_group_by_number(225).unwrap(); // Fm-3m
println!("{}: {} ({})", sg.number, sg.symbol, sg.crystal_system);
let equiv = sg.generate_equivalent_positions(&[0.0, 0.0, 0.0]);→ See the Rust API reference for all functions and types.