1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
//! A high-performance Rust library for calculating dynamic partial atomic charges
//! using the Charge Equilibration (QEq) method.
//!
//! # Cheq: Charge Equilibration for Molecular Dynamics
//!
//! **Cheq** implements the robust and general Charge Equilibration (QEq) method
//! proposed by Rappé and Goddard (1991) to predict the self-consistent,
//! geometry-dependent partial charges of atoms in a molecular system.
//!
//! Unlike fixed-charge force fields, QEq allows atomic charges to dynamically
//! respond to changes in molecular geometry and external fields, which is
//! essential for accurate molecular dynamics (MD) simulations, particularly
//! for systems like ceramics, polymers, and biological molecules where
//! charge transfer is significant.
//!
//! The method relies solely on atomic properties (electronegativity, hardness,
//! and radius) and the molecular geometry to achieve charge neutrality.
//!
//! # Quickstart
//!
//! The primary entry point is the [`QEqSolver`], which requires a set of [`Parameters`]
//! (atomic data) and a slice of atoms with coordinates.
//!
//! ```
//! use cheq::{get_default_parameters, QEqSolver, Atom, SolverOptions};
//! use approx::assert_relative_eq;
//!
//! // 1. Set up the parameters and solver.
//! // (Parameters include chi, J, radius, and n for each element)
//! let params = get_default_parameters();
//! let options = SolverOptions::default(); // Use default convergence criteria
//! let solver = QEqSolver::new(params).with_options(options);
//!
//! // 2. Define the molecular system (Water molecule geometry).
//! let bond_length = 0.9575;
//! let angle = 104.45f64.to_radians();
//!
//! let atoms = vec![
//! Atom { atomic_number: 8, position: [0.0, 0.0, 0.0] }, // Oxygen
//! Atom { atomic_number: 1, position: [bond_length, 0.0, 0.0] }, // Hydrogen 1
//! Atom { atomic_number: 1, position: [
//! bond_length * angle.cos(),
//! bond_length * angle.sin(),
//! 0.0,
//! ]}, // Hydrogen 2
//! ];
//!
//! // 3. Solve for partial charges (total charge Q_tot = 0.0).
//! let result = solver.solve(&atoms, 0.0).unwrap();
//!
//! // 4. Inspect the results.
//! let q_o = result.charges[0];
//! let q_h1 = result.charges[1];
//!
//! assert!(q_o < 0.0); // Oxygen is negative
//! assert!(q_h1 > 0.0); // Hydrogen is positive
//! assert_relative_eq!(q_o + 2.0 * q_h1, 0.0, epsilon = 1e-9); // Charge conservation
//! println!("Charges (O, H1, H2): ({:.3}, {:.3}, {:.3})", q_o, q_h1, result.charges[2]);
//! ```
//!
//! # External Electrostatic Fields
//!
//! Cheq supports hybrid QEq/MM calculations where a molecular fragment (e.g., a ligand)
//! undergoes charge equilibration in the presence of an external electrostatic environment
//! (e.g., a protein binding pocket). This is achieved using [`ExternalPotential`]:
//!
//! ```
//! use cheq::{get_default_parameters, QEqSolver, Atom, ExternalPotential, PointCharge};
//!
//! let params = get_default_parameters();
//! let solver = QEqSolver::new(params);
//!
//! // Define the QEq subsystem (e.g., a ligand).
//! let ligand = vec![
//! Atom { atomic_number: 6, position: [0.0, 0.0, 0.0] },
//! Atom { atomic_number: 8, position: [1.2, 0.0, 0.0] },
//! ];
//!
//! // Define the external environment (e.g., protein pocket atoms with force field charges).
//! let external = ExternalPotential::from_point_charges(vec![
//! PointCharge::new(7, [3.0, 0.0, 0.0], -0.42), // Backbone nitrogen
//! PointCharge::new(8, [4.0, 1.0, 0.0], -0.57), // Carbonyl oxygen
//! ]);
//!
//! // Solve with external field.
//! let result = solver.solve_in_field(&ligand, 0.0, &external).unwrap();
//! ```
// Internal modules are private to enforce encapsulation.
// Re-export public components at the crate root for easy access.
pub use CheqError;
pub use ;
pub use ;
pub use ;
// Provide access to default parameters.
use OnceLock;
static DEFAULT_PARAMETERS: = new;
/// Provides a thread-safe, cached reference to the default atomic parameters.
///
/// These parameters are statically compiled into the library from the `resources/qeq.data.toml`
/// file and include data for a wide range of elements, following the conventions
/// derived from the Rappé & Goddard QEq formalism.
///
/// This function ensures that the parameters are loaded only once, improving
/// performance for repeated calls.
///
/// # Returns
///
/// A static reference (`&'static Parameters`) to the default parameter set.
///
/// # Panics
///
/// Panics only if the embedded default TOML file cannot be parsed, which indicates
/// a bug in the library distribution.