|
1 | 1 | # DreidTyper |
2 | 2 |
|
3 | | -**DreidTyper** is a high-performance, foundational software library for the automated assignment of DREIDING force field atom types and the perception of molecular topologies. It provides a modern, robust solution for translating simple chemical connectivity (a molecular graph) into a complete, engine-agnostic topological description essential for molecular simulations. This library is engineered from the ground up in **Rust** for exceptional performance, memory safety, and strict adherence to the principles of modular software design. |
| 3 | +**DreidTyper** is a Rust library that turns a minimal `MolecularGraph` (atoms + bonds) into a fully typed, DREIDING-compatible topology. The pipeline is deterministic, aggressively validated, and designed for integrators who need trustworthy chemistry without shipping their own perception code. |
4 | 4 |
|
5 | | -The core mission of DreidTyper is to provide a reliable, predictable, and easy-to-integrate tool for developers and researchers building the next generation of simulation tools for general chemistry, materials science, and drug discovery. |
| 5 | +At a high level the library walks through: |
| 6 | + |
| 7 | +1. **Perception:** six ordered passes (rings → Kekulé expansion → electron bookkeeping → aromaticity → resonance → hybridization) that upgrade raw connectivity into a rich `AnnotatedMolecule`. |
| 8 | +2. **Typing:** an iterative, priority-sorted rule engine that resolves the final DREIDING atom label for every atom. |
| 9 | +3. **Building:** a pure graph traversal that emits canonical bonds, angles, and torsions as a `MolecularTopology`. |
6 | 10 |
|
7 | 11 | ## Features |
8 | 12 |
|
9 | | -- **DREIDING Atom Typing**: Assigns canonical DREIDING atom types from molecular connectivity. |
10 | | -- **Full Topology Perception**: Identifies bonds, angles, and proper/improper dihedrals. |
11 | | -- **Memory Safe & Fast**: Built in Rust for guaranteed memory safety and high performance. |
12 | | -- **Rule-Based Engine**: Uses a clear TOML-based rule system for atom typing logic. |
13 | | -- **Engine-Agnostic**: Produces a pure topological representation independent of any MD engine. |
| 13 | +- **Chemically faithful perception:** built-in algorithms cover SSSR ring search, strict Kekulé expansion, charge/lone pair templates for heteroatoms, aromaticity categorization (including anti-aromatic detection), resonance propagation, and hybridization inference. |
| 14 | +- **Deterministic typing engine:** TOML rules are sorted by priority and evaluated until a fixed point, making neighbor-dependent rules (e.g., `H_HB`) converge without guesswork. |
| 15 | +- **Engine-agnostic topology:** outputs canonicalized bonds, angles, proper and improper dihedrals ready for any simulator that consumes DREIDING-style terms. |
| 16 | +- **Extensible ruleset:** ship with curated defaults (`resources/default.rules.toml`) and load or merge custom rule files at runtime. |
| 17 | +- **Rust-first ergonomics:** zero `unsafe`, comprehensive unit/integration tests, and precise error variants for validation, perception, and typing failures. |
14 | 18 |
|
15 | 19 | ## Getting Started |
16 | 20 |
|
17 | | -To get started with DreidTyper, add it as a dependency in your `Cargo.toml`: |
| 21 | +Add the crate to your `Cargo.toml`: |
18 | 22 |
|
19 | 23 | ```toml |
20 | 24 | [dependencies] |
21 | | -dreid-typer = "0.2.0" |
| 25 | +dreid-typer = "0.2.1" |
22 | 26 | ``` |
23 | 27 |
|
24 | | -Then, you can use it in your Rust code as follows: |
| 28 | +Run the full pipeline from connectivity to topology: |
25 | 29 |
|
26 | 30 | ```rust |
27 | | -use dreid_typer::{ |
28 | | - assign_topology, MolecularGraph, MolecularTopology, |
29 | | - Element, BondOrder, |
30 | | -}; |
| 31 | +use dreid_typer::{assign_topology, Element, MolecularGraph, MolecularTopology, BondOrder}; |
31 | 32 |
|
32 | | -// 1. Define the molecule's connectivity using a `MolecularGraph`. |
33 | 33 | let mut graph = MolecularGraph::new(); |
34 | | -let c1 = graph.add_atom(Element::C); // CH3 |
35 | | -let c2 = graph.add_atom(Element::C); // CH2 |
| 34 | +let c1 = graph.add_atom(Element::C); |
| 35 | +let c2 = graph.add_atom(Element::C); |
36 | 36 | let o = graph.add_atom(Element::O); |
37 | | -let h_c1_1 = graph.add_atom(Element::H); |
38 | | -let h_c1_2 = graph.add_atom(Element::H); |
39 | | -let h_c1_3 = graph.add_atom(Element::H); |
40 | | -let h_c2_1 = graph.add_atom(Element::H); |
41 | | -let h_c2_2 = graph.add_atom(Element::H); |
42 | 37 | let h_o = graph.add_atom(Element::H); |
| 38 | +let h_atoms: Vec<_> = (0..6).map(|_| graph.add_atom(Element::H)).collect(); |
43 | 39 |
|
44 | 40 | graph.add_bond(c1, c2, BondOrder::Single).unwrap(); |
45 | 41 | graph.add_bond(c2, o, BondOrder::Single).unwrap(); |
46 | | -graph.add_bond(c1, h_c1_1, BondOrder::Single).unwrap(); |
47 | | -graph.add_bond(c1, h_c1_2, BondOrder::Single).unwrap(); |
48 | | -graph.add_bond(c1, h_c1_3, BondOrder::Single).unwrap(); |
49 | | -graph.add_bond(c2, h_c2_1, BondOrder::Single).unwrap(); |
50 | | -graph.add_bond(c2, h_c2_2, BondOrder::Single).unwrap(); |
51 | 42 | graph.add_bond(o, h_o, BondOrder::Single).unwrap(); |
52 | | - |
53 | | -// 2. Call the main function to perceive the topology. |
54 | | -let topology: MolecularTopology = assign_topology(&graph).unwrap(); |
55 | | - |
56 | | -// 3. Inspect the results. |
57 | | -assert_eq!(topology.atoms.len(), 9); |
58 | | -assert_eq!(topology.bonds.len(), 8); |
59 | | -assert_eq!(topology.angles.len(), 13); |
60 | | -assert_eq!(topology.proper_dihedrals.len(), 12); |
61 | | - |
62 | | -// Check the assigned DREIDING atom types. |
63 | | -assert_eq!(topology.atoms[c1].atom_type, "C_3"); // sp3 Carbon |
64 | | -assert_eq!(topology.atoms[c2].atom_type, "C_3"); // sp3 Carbon |
65 | | -assert_eq!(topology.atoms[o].atom_type, "O_3"); // sp3 Oxygen |
66 | | -assert_eq!(topology.atoms[h_o].atom_type, "H_HB"); // Hydrogen-bonding Hydrogen |
67 | | -assert_eq!(topology.atoms[h_c1_1].atom_type, "H_"); // Standard Hydrogen |
| 43 | +for (carbon, chunk) in [c1, c2].into_iter().zip(h_atoms.chunks(3)) { |
| 44 | + for &hydrogen in chunk { |
| 45 | + graph.add_bond(carbon, hydrogen, BondOrder::Single).unwrap(); |
| 46 | + } |
| 47 | +} |
| 48 | + |
| 49 | +let topology: MolecularTopology = assign_topology(&graph).expect("perception + typing succeed"); |
| 50 | + |
| 51 | +assert_eq!(topology.atoms[c1].atom_type, "C_3"); |
| 52 | +assert_eq!(topology.atoms[c2].atom_type, "C_3"); |
| 53 | +assert_eq!(topology.atoms[o].atom_type, "O_3"); |
| 54 | +assert_eq!(topology.atoms[h_o].atom_type, "H_HB"); |
68 | 55 | ``` |
69 | 56 |
|
70 | | -> **Note**: This is a simplified example. For more complex molecules and edge cases, please refer to the [API Documentation](https://docs.rs/dreid-typer). |
| 57 | +Need custom chemistry? Parse a TOML file and run the same API: |
| 58 | + |
| 59 | +```rust |
| 60 | +use dreid_typer::{assign_topology_with_rules, rules, MolecularGraph}; |
| 61 | + |
| 62 | +let mut ruleset = rules::get_default_rules().to_vec(); |
| 63 | +let extra = std::fs::read_to_string("my_metals.rules.toml")?; |
| 64 | +ruleset.extend(rules::parse_rules(&extra)?); |
| 65 | + |
| 66 | +let topology = assign_topology_with_rules(&graph, &ruleset)?; |
| 67 | +``` |
71 | 68 |
|
72 | 69 | ## Documentation |
73 | 70 |
|
|
0 commit comments