1#[derive(Debug, Clone)]
5pub struct UffAtomParams {
6 pub label: &'static str,
7 pub element: u8, pub r1: f64, pub theta0: f64, pub x1: f64, pub d1: f64, pub zeta: f64, pub z_star: f64, pub chi: f64, pub v_tors: f64, }
17
18pub fn get_uff_params(label: &str) -> Option<UffAtomParams> {
20 match label {
21 "H_" => Some(UffAtomParams {
23 label: "H_",
24 element: 1,
25 r1: 0.354,
26 theta0: 180.0,
27 x1: 2.886,
28 d1: 0.044,
29 zeta: 0.712,
30 z_star: 0.712,
31 chi: 4.528,
32 v_tors: 0.0,
33 }),
34 "C_3" => Some(UffAtomParams {
36 label: "C_3",
37 element: 6,
38 r1: 0.757,
39 theta0: 109.47,
40 x1: 3.851,
41 d1: 0.105,
42 zeta: 1.912,
43 z_star: 1.912,
44 chi: 5.343,
45 v_tors: 2.119,
46 }),
47 "C_2" => Some(UffAtomParams {
48 label: "C_2",
49 element: 6,
50 r1: 0.732,
51 theta0: 120.0,
52 x1: 3.851,
53 d1: 0.105,
54 zeta: 1.912,
55 z_star: 1.912,
56 chi: 5.343,
57 v_tors: 2.119,
58 }),
59 "C_R" => Some(UffAtomParams {
60 label: "C_R",
61 element: 6,
62 r1: 0.729,
63 theta0: 120.0,
64 x1: 3.851,
65 d1: 0.105,
66 zeta: 1.912,
67 z_star: 1.912,
68 chi: 5.343,
69 v_tors: 2.119,
70 }),
71 "C_1" => Some(UffAtomParams {
72 label: "C_1",
73 element: 6,
74 r1: 0.706,
75 theta0: 180.0,
76 x1: 3.851,
77 d1: 0.105,
78 zeta: 1.912,
79 z_star: 1.912,
80 chi: 5.343,
81 v_tors: 2.119,
82 }),
83 "N_3" => Some(UffAtomParams {
85 label: "N_3",
86 element: 7,
87 r1: 0.700,
88 theta0: 106.7,
89 x1: 3.660,
90 d1: 0.069,
91 zeta: 2.544,
92 z_star: 2.544,
93 chi: 6.899,
94 v_tors: 0.450,
95 }),
96 "N_2" => Some(UffAtomParams {
97 label: "N_2",
98 element: 7,
99 r1: 0.685,
100 theta0: 111.2,
101 x1: 3.660,
102 d1: 0.069,
103 zeta: 2.544,
104 z_star: 2.544,
105 chi: 6.899,
106 v_tors: 0.450,
107 }),
108 "N_R" => Some(UffAtomParams {
109 label: "N_R",
110 element: 7,
111 r1: 0.699,
112 theta0: 120.0,
113 x1: 3.660,
114 d1: 0.069,
115 zeta: 2.544,
116 z_star: 2.544,
117 chi: 6.899,
118 v_tors: 0.450,
119 }),
120 "N_1" => Some(UffAtomParams {
121 label: "N_1",
122 element: 7,
123 r1: 0.656,
124 theta0: 180.0,
125 x1: 3.660,
126 d1: 0.069,
127 zeta: 2.544,
128 z_star: 2.544,
129 chi: 6.899,
130 v_tors: 0.450,
131 }),
132 "O_3" => Some(UffAtomParams {
134 label: "O_3",
135 element: 8,
136 r1: 0.658,
137 theta0: 104.51,
138 x1: 3.500,
139 d1: 0.060,
140 zeta: 2.300,
141 z_star: 2.300,
142 chi: 8.741,
143 v_tors: 2.100,
144 }),
145 "O_2" => Some(UffAtomParams {
146 label: "O_2",
147 element: 8,
148 r1: 0.634,
149 theta0: 120.0,
150 x1: 3.500,
151 d1: 0.060,
152 zeta: 2.300,
153 z_star: 2.300,
154 chi: 8.741,
155 v_tors: 2.100,
156 }),
157 "O_R" => Some(UffAtomParams {
158 label: "O_R",
159 element: 8,
160 r1: 0.680,
161 theta0: 110.0,
162 x1: 3.500,
163 d1: 0.060,
164 zeta: 2.300,
165 z_star: 2.300,
166 chi: 8.741,
167 v_tors: 2.100,
168 }),
169 "O_1" => Some(UffAtomParams {
170 label: "O_1",
171 element: 8,
172 r1: 0.639,
173 theta0: 180.0,
174 x1: 3.500,
175 d1: 0.060,
176 zeta: 2.300,
177 z_star: 2.300,
178 chi: 8.741,
179 v_tors: 2.100,
180 }),
181 "F_" => Some(UffAtomParams {
183 label: "F_",
184 element: 9,
185 r1: 0.668,
186 theta0: 180.0,
187 x1: 3.364,
188 d1: 0.050,
189 zeta: 1.735,
190 z_star: 1.735,
191 chi: 10.874,
192 v_tors: 1.082,
193 }),
194 "Cl" => Some(UffAtomParams {
195 label: "Cl",
196 element: 17,
197 r1: 1.029,
198 theta0: 109.47,
199 x1: 3.947,
200 d1: 0.227,
201 zeta: 2.315,
202 z_star: 2.315,
203 chi: 8.564,
204 v_tors: 1.673,
205 }),
206 "Br" => Some(UffAtomParams {
207 label: "Br",
208 element: 35,
209 r1: 1.137,
210 theta0: 109.47,
211 x1: 4.189,
212 d1: 0.251,
213 zeta: 2.283,
214 z_star: 2.283,
215 chi: 7.790,
216 v_tors: 1.682,
217 }),
218 "I_" => Some(UffAtomParams {
219 label: "I_",
220 element: 53,
221 r1: 1.353,
222 theta0: 109.47,
223 x1: 4.500,
224 d1: 0.339,
225 zeta: 2.650,
226 z_star: 2.650,
227 chi: 6.822,
228 v_tors: 1.530,
229 }),
230 "S_3" => Some(UffAtomParams {
232 label: "S_3",
233 element: 16,
234 r1: 1.020,
235 theta0: 92.1,
236 x1: 4.035,
237 d1: 0.274,
238 zeta: 2.703,
239 z_star: 2.703,
240 chi: 10.000,
241 v_tors: 1.948,
242 }),
243 "S_2" => Some(UffAtomParams {
244 label: "S_2",
245 element: 16,
246 r1: 0.987,
247 theta0: 120.0,
248 x1: 4.035,
249 d1: 0.274,
250 zeta: 2.703,
251 z_star: 2.703,
252 chi: 10.000,
253 v_tors: 1.948,
254 }),
255 "S_R" => Some(UffAtomParams {
256 label: "S_R",
257 element: 16,
258 r1: 0.990,
259 theta0: 120.0,
260 x1: 4.035,
261 d1: 0.274,
262 zeta: 2.703,
263 z_star: 2.703,
264 chi: 10.000,
265 v_tors: 1.948,
266 }),
267 "P_3" => Some(UffAtomParams {
269 label: "P_3",
270 element: 15,
271 r1: 0.930,
272 theta0: 93.8,
273 x1: 4.147,
274 d1: 0.305,
275 zeta: 2.862,
276 z_star: 2.862,
277 chi: 8.000,
278 v_tors: 2.421,
279 }),
280 "B_2" => Some(UffAtomParams {
282 label: "B_2",
283 element: 5,
284 r1: 0.828,
285 theta0: 120.0,
286 x1: 3.637,
287 d1: 0.180,
288 zeta: 1.755,
289 z_star: 1.755,
290 chi: 4.961,
291 v_tors: 0.0,
292 }),
293 "Si3" => Some(UffAtomParams {
295 label: "Si3",
296 element: 14,
297 r1: 1.117,
298 theta0: 109.47,
299 x1: 4.295,
300 d1: 0.402,
301 zeta: 2.323,
302 z_star: 2.323,
303 chi: 4.168,
304 v_tors: 1.225,
305 }),
306 _ => None,
307 }
308}
309
310pub fn get_uff_bond_length(
317 pi: &UffAtomParams,
318 pj: &UffAtomParams,
319 bond_order: &crate::graph::BondOrder,
320) -> f64 {
321 const LAMBDA: f64 = 0.1332;
322
323 let bo_value: f64 = match bond_order {
324 crate::graph::BondOrder::Single => 1.0,
325 crate::graph::BondOrder::Aromatic => 1.5,
326 crate::graph::BondOrder::Double => 2.0,
327 crate::graph::BondOrder::Triple => 3.0,
328 _ => 1.0,
329 };
330
331 let r_bo = if (bo_value - 1.0).abs() < 1e-10 {
332 0.0
333 } else {
334 -LAMBDA * (pi.r1 + pj.r1) * bo_value.ln()
335 };
336
337 let r_en = if (pi.chi - pj.chi).abs() > 1e-6 {
338 let sqrt_diff = pi.chi.sqrt() - pj.chi.sqrt();
339 pi.r1 * pj.r1 * sqrt_diff * sqrt_diff / (pi.chi * pi.r1 + pj.chi * pj.r1)
340 } else {
341 0.0
342 };
343
344 (pi.r1 + pj.r1 + r_bo - r_en).max(0.5)
345}
346
347pub fn get_uff_bond_force_constant(pi: &UffAtomParams, pj: &UffAtomParams, r0: f64) -> f64 {
350 664.12 * pi.z_star * pj.z_star / r0.powi(3)
351}
352
353pub fn get_uff_angle_force_constant(
357 pi: &UffAtomParams,
358 pk: &UffAtomParams,
359 r_ij: f64,
360 r_jk: f64,
361 theta0_rad: f64,
362) -> f64 {
363 let r_ik_sq = r_ij * r_ij + r_jk * r_jk - 2.0 * r_ij * r_jk * theta0_rad.cos();
364 if r_ik_sq < 1e-10 || r_ij < 1e-10 || r_jk < 1e-10 {
365 return 0.0;
366 }
367 332.06 * pi.z_star * pk.z_star / (r_ij * r_jk * r_ik_sq)
368}
369
370pub fn get_uff_torsion_params(
374 hyb_j: &crate::graph::Hybridization,
375 hyb_k: &crate::graph::Hybridization,
376 vj: f64,
377 vk: f64,
378 bond_order: &crate::graph::BondOrder,
379) -> (f64, f64, f64) {
380 use crate::graph::BondOrder::*;
381 use crate::graph::Hybridization::*;
382
383 match (hyb_j, hyb_k, bond_order) {
384 (SP3, SP3, _) => (0.5 * (vj * vk).sqrt(), 3.0, 1.0),
386 (SP3, SP2, _) | (SP2, SP3, _) => (1.0, 6.0, 1.0),
388 (SP2, SP2, Aromatic) | (SP2, SP2, Double) => (5.0, 2.0, -1.0),
390 (SP2, SP2, Single) => (10.0, 2.0, -1.0),
392 (SP, _, _) | (_, SP, _) => (0.0, 1.0, 1.0),
394 _ => (1.0, 3.0, 1.0),
395 }
396}