1use crate::{Atom, AtomKind, Molecule};
15
16const RADII_DATA: [[f64; 4]; 118] = [
24 [0.32, 0.32, 0.32, 1.1],
25 [0.46, 0.46, 0.46, 1.4],
26 [1.33, 1.24, 1.24, 1.82],
27 [1.02, 0.9, 0.85, 1.53],
28 [0.85, 0.78, 0.73, 1.92],
29 [0.75, 0.67, 0.6, 1.7],
30 [0.71, 0.6, 0.54, 1.55],
31 [0.63, 0.57, 0.53, 1.52],
32 [0.64, 0.59, 0.53, 1.47],
33 [0.67, 0.96, 0.96, 1.54],
34 [1.55, 1.6, 1.6, 2.27],
35 [1.39, 1.32, 1.27, 1.73],
36 [1.26, 1.13, 1.11, 1.84],
37 [1.16, 1.07, 1.02, 2.1],
38 [1.11, 1.02, 0.94, 1.8],
39 [1.03, 0.94, 0.95, 1.8],
40 [0.99, 0.95, 0.93, 1.75],
41 [0.96, 1.07, 0.96, 1.88],
42 [1.96, 1.93, 1.93, 2.75],
43 [1.71, 1.47, 1.33, 2.31],
44 [1.48, 1.16, 1.14, 2.15],
45 [1.36, 1.17, 1.08, 2.11],
46 [1.34, 1.12, 1.06, 2.07],
47 [1.22, 1.11, 1.03, 2.06],
48 [1.19, 1.05, 1.03, 2.05],
49 [1.16, 1.09, 1.02, 2.04],
50 [1.11, 1.03, 0.96, 2.0],
51 [1.1, 1.01, 1.01, 1.97],
52 [1.12, 1.15, 1.2, 1.96],
53 [1.18, 1.2, 1.2, 2.01],
54 [1.24, 1.17, 1.21, 1.87],
55 [1.21, 1.11, 1.14, 2.11],
56 [1.21, 1.14, 1.06, 1.85],
57 [1.16, 1.07, 1.07, 1.9],
58 [1.14, 1.09, 1.1, 1.85],
59 [1.17, 1.21, 1.08, 2.02],
60 [2.1, 2.02, 2.02, 3.03],
61 [1.85, 1.57, 1.39, 2.49],
62 [1.63, 1.3, 1.24, 2.32],
63 [1.54, 1.27, 1.21, 2.23],
64 [1.47, 1.25, 1.16, 2.18],
65 [1.38, 1.21, 1.13, 2.17],
66 [1.28, 1.2, 1.1, 2.16],
67 [1.25, 1.14, 1.03, 2.13],
68 [1.25, 1.1, 1.06, 2.1],
69 [1.2, 1.17, 1.12, 2.1],
70 [1.28, 1.39, 1.37, 2.11],
71 [1.36, 1.44, 1.44, 2.18],
72 [1.42, 1.36, 1.46, 1.93],
73 [1.4, 1.3, 1.32, 2.17],
74 [1.4, 1.33, 1.27, 2.06],
75 [1.36, 1.28, 1.21, 2.06],
76 [1.33, 1.29, 1.25, 1.98],
77 [1.31, 1.35, 1.22, 2.16],
78 [2.32, 2.09, 2.09, 3.43],
79 [1.96, 1.61, 1.49, 2.68],
80 [1.8, 1.39, 1.39, 2.43],
81 [1.63, 1.37, 1.31, 2.42],
82 [1.76, 1.38, 1.28, 2.4],
83 [1.74, 1.37, 1.37, 2.39],
84 [1.73, 1.35, 1.35, 2.38],
85 [1.72, 1.34, 1.34, 2.36],
86 [1.68, 1.34, 1.34, 2.35],
87 [1.69, 1.35, 1.32, 2.34],
88 [1.68, 1.35, 1.35, 2.33],
89 [1.67, 1.33, 1.33, 2.31],
90 [1.66, 1.33, 1.33, 2.3],
91 [1.65, 1.33, 1.33, 2.29],
92 [1.64, 1.31, 1.31, 2.27],
93 [1.7, 1.29, 1.29, 2.26],
94 [1.62, 1.31, 1.31, 2.24],
95 [1.52, 1.28, 1.22, 2.23],
96 [1.46, 1.26, 1.19, 2.22],
97 [1.37, 1.2, 1.15, 2.18],
98 [1.31, 1.19, 1.1, 2.16],
99 [1.29, 1.16, 1.09, 2.16],
100 [1.22, 1.15, 1.07, 2.13],
101 [1.23, 1.12, 1.1, 2.13],
102 [1.24, 1.21, 1.23, 2.14],
103 [1.33, 1.42, 1.42, 2.23],
104 [1.44, 1.42, 1.5, 1.96],
105 [1.44, 1.35, 1.37, 2.02],
106 [1.51, 1.41, 1.35, 2.07],
107 [1.45, 1.35, 1.29, 1.97],
108 [1.47, 1.38, 1.38, 2.02],
109 [1.42, 1.45, 1.33, 2.2],
110 [2.23, 2.18, 2.18, 3.48],
111 [2.01, 1.73, 1.59, 2.83],
112 [1.86, 1.53, 1.4, 2.47],
113 [1.75, 1.43, 1.36, 2.45],
114 [1.69, 1.38, 1.29, 2.43],
115 [1.7, 1.34, 1.18, 2.41],
116 [1.71, 1.36, 1.16, 2.39],
117 [1.72, 1.35, 1.35, 2.43],
118 [1.66, 1.35, 1.35, 2.44],
119 [1.66, 1.36, 1.36, 2.45],
120 [1.68, 1.39, 1.39, 2.44],
121 [1.68, 1.4, 1.4, 2.45],
122 [1.65, 1.4, 1.4, 2.45],
123 [1.67, 1.67, 1.67, 2.45],
124 [1.73, 1.39, 1.39, 2.46],
125 [1.76, 1.76, 1.76, 2.46],
126 [1.61, 1.41, 1.41, 2.46],
127 [1.57, 1.4, 1.31, 2.46],
128 [1.49, 1.36, 1.26, 2.46],
129 [1.43, 1.28, 1.21, 2.46],
130 [1.41, 1.28, 1.19, 2.46],
131 [1.34, 1.25, 1.18, 2.46],
132 [1.29, 1.25, 1.13, 2.46],
133 [1.28, 1.16, 1.18, 2.46],
134 [1.21, 1.16, 1.18, 2.46],
135 [1.22, 1.37, 1.3, 2.46],
136 [1.36, 1.36, 1.36, 2.46],
137 [1.43, 1.43, 1.43, 2.46],
138 [1.62, 1.62, 1.62, 2.46],
139 [1.75, 1.75, 1.75, 2.46],
140 [1.65, 1.65, 1.65, 2.46],
141 [1.57, 1.57, 1.57, 2.46],
142];
143
144const BONDING_RADII: [f64; 109] = [
147 0.230, 0.930, 0.680, 0.350, 0.830, 0.680, 0.680, 0.680, 0.640, 1.120, 0.970, 1.100, 1.350, 1.200, 0.750, 1.020, 0.990, 1.570, 1.330,
148 0.990, 1.440, 1.470, 1.330, 1.350, 1.350, 1.340, 1.330, 1.500, 1.520, 1.450, 1.220, 1.170, 1.210, 1.220, 1.210, 1.910, 1.470, 1.120,
149 1.780, 1.560, 1.480, 1.470, 1.350, 1.400, 1.450, 1.500, 1.590, 1.690, 1.630, 1.460, 1.460, 1.470, 1.400, 1.980, 1.670, 1.340, 1.870,
150 1.830, 1.820, 1.810, 1.800, 1.800, 1.990, 1.790, 1.760, 1.750, 1.740, 1.730, 1.720, 1.940, 1.720, 1.570, 1.430, 1.370, 1.350, 1.370,
151 1.320, 1.500, 1.500, 1.700, 1.550, 1.540, 1.540, 1.680, 1.700, 2.400, 2.000, 1.900, 1.880, 1.790, 1.610, 1.580, 1.550, 1.530, 1.510,
152 1.500, 1.500, 1.500, 1.500, 1.500, 1.500, 1.500, 1.500, 1.600, 1.600, 1.600, 1.600, 1.600, 1.600,
153];
154
155fn get_cov_radius(element_number: usize, bond_order: usize) -> Option<f64> {
157 if element_number > 0 && element_number <= RADII_DATA.len() {
158 if bond_order > 0 && bond_order <= 3 {
160 let irow = element_number - 1;
161 let icol = bond_order - 1;
162
163 let r = RADII_DATA[irow][icol];
164 return Some(r);
165 }
166 }
167
168 None
169}
170
171fn get_vdw_radius(element_number: usize) -> Option<f64> {
173 let icol = 3;
175 if element_number > 0 && element_number <= RADII_DATA.len() {
176 let irow = element_number - 1;
177 let r = RADII_DATA[irow][icol];
178 return Some(r);
179 }
180 None
181}
182
183fn get_bonding_radius(element_number: usize) -> Option<f64> {
185 BONDING_RADII.get(element_number - 1).copied()
186}
187
188const MASSES_DATA: [f64; 118] = [
192 1.008000, 4.002602, 6.940000, 9.012183, 10.810000, 12.011000, 14.007000, 15.999000, 18.998403, 20.179700,
193 22.989769, 24.305000, 26.981538, 28.085000, 30.973762, 32.060000, 35.450000, 39.948000, 39.098300, 40.078000,
194 44.955908, 47.867000, 50.941500, 51.996100, 54.938044, 55.845000, 58.933194, 58.693400, 63.546000, 65.380000,
195 69.723000, 72.630000, 74.921595, 78.971000, 79.904000, 83.798000, 85.467800, 87.620000, 88.905840, 91.224000,
196 92.906370, 95.950000, 97.907210, 101.070000, 102.905500, 106.420000, 107.868200, 112.414000, 114.818000,
197 118.710000, 121.760000, 127.600000, 126.904470, 131.293000, 132.905452, 137.327000, 138.905470, 140.116000,
198 140.907660, 144.242000, 144.912760, 150.360000, 151.964000, 157.250000, 158.925350, 162.500000, 164.930330,
199 167.259000, 168.934220, 173.045000, 174.966800, 178.490000, 180.947880, 183.840000, 186.207000, 190.230000,
200 192.217000, 195.084000, 196.966569, 200.592000, 204.380000, 207.200000, 208.980400, 209.000000, 210.000000,
201 222.000000, 223.000000, 226.000000, 227.000000, 232.037700, 231.035880, 238.028910, 237.000000, 244.000000,
202 243.000000, 247.000000, 247.000000, 251.000000, 252.000000, 257.000000, 258.000000, 259.000000, 262.000000,
203 267.000000, 268.000000, 271.000000, 274.000000, 269.000000, 276.000000, 281.000000, 281.000000, 285.000000,
204 286.000000, 289.000000, 288.000000, 293.000000, 294.000000, 294.000000,
205];
206
207fn get_atom_mass(atom: &Atom) -> Option<f64> {
208 match atom.kind() {
209 AtomKind::Element(n) => {
210 assert!(*n > 0, "invalid element number");
211 Some(MASSES_DATA[n - 1])
212 }
213 AtomKind::Dummy(_) => None,
214 }
215}
216
217impl Atom {
222 pub fn get_cov_radius(&self) -> Option<f64> {
224 get_cov_radius(self.number(), 1)
225 }
226
227 pub fn get_vdw_radius(&self) -> Option<f64> {
230 get_vdw_radius(self.number())
231 }
232
233 pub fn get_bonding_radius(&self) -> Option<f64> {
235 get_bonding_radius(self.number())
236 }
237
238 #[deprecated(note = "use get_cov_radius instead")]
239 pub fn cov_radius(&self) -> Option<f64> {
241 self.get_cov_radius()
242 }
243
244 pub fn get_mass(&self) -> Option<f64> {
246 self.mass.or(get_atom_mass(self))
247 }
248
249 #[deprecated(note = "Use get_vdw_radius instead")]
250 pub fn vdw_radius(&self) -> Option<f64> {
253 self.get_vdw_radius()
254 }
255}
256
257impl Molecule {
261 pub fn from_database(name: &str) -> Self {
265 let ch4 = "
266C -0.0000 -0.0000 0.0000
267H 1.0900 -0.0000 0.0000
268H -0.3633 1.0277 0.0000
269H -0.3633 -0.5138 0.8900
270H -0.3633 -0.5138 -0.8900 ";
271
272 let h2o = "
273O -1.4689 2.1375 0.0000
274H -0.5089 2.1375 0.0000
275H -1.7894 3.0424 0.0000
276";
277
278 let hcn = "
279H -2.5671751 1.2900188 0.0000000
280C -1.4971751 1.2900188 0.0000000
281N -0.3505751 1.2900188 0.0000000
282";
283
284 match name {
285 "HCN" => {
286 let atoms = hcn.trim().lines().filter_map(|line| line.parse::<Atom>().ok());
287 Molecule::from_atoms(atoms)
288 }
289 "H2O" => {
290 let atoms = h2o.trim().lines().filter_map(|line| line.parse::<Atom>().ok());
291 Molecule::from_atoms(atoms)
292 }
293 "CH4" => {
294 let atoms = ch4.trim().lines().filter_map(|line| line.parse::<Atom>().ok());
295 Molecule::from_atoms(atoms)
296 }
297 _ => unimplemented!(),
298 }
299 }
300}
301
302#[test]
305fn test_atom_data() {
306 let atom1 = Atom::new("C", [-0.90203687, 0.62555259, 0.0081889]);
308 let atom2 = Atom::new("X", [-0.54538244, -0.38325741, 0.0081889]);
310
311 assert!(atom1.get_cov_radius().is_some());
312 assert!(atom1.get_vdw_radius().is_some());
313 assert!(atom2.get_cov_radius().is_none());
314
315 assert_eq!(atom1.get_mass(), Some(12.011));
317 assert_eq!(atom2.get_mass(), None);
318}