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 "Ti3+4" => Some(UffAtomParams {
308 label: "Ti3+4",
309 element: 22,
310 r1: 1.412,
311 theta0: 109.47,
312 x1: 3.175,
313 d1: 0.017,
314 zeta: 2.659,
315 z_star: 2.659,
316 chi: 3.470,
317 v_tors: 0.0,
318 }),
319 "V_3+5" => Some(UffAtomParams {
320 label: "V_3+5",
321 element: 23,
322 r1: 1.402,
323 theta0: 109.47,
324 x1: 3.144,
325 d1: 0.016,
326 zeta: 2.679,
327 z_star: 2.679,
328 chi: 3.650,
329 v_tors: 0.0,
330 }),
331 "Cr6+3" => Some(UffAtomParams {
332 label: "Cr6+3",
333 element: 24,
334 r1: 1.345,
335 theta0: 90.0,
336 x1: 3.023,
337 d1: 0.015,
338 zeta: 2.463,
339 z_star: 2.463,
340 chi: 3.415,
341 v_tors: 0.0,
342 }),
343 "Mn6+2" => Some(UffAtomParams {
344 label: "Mn6+2",
345 element: 25,
346 r1: 1.382,
347 theta0: 90.0,
348 x1: 2.961,
349 d1: 0.013,
350 zeta: 2.430,
351 z_star: 2.430,
352 chi: 3.325,
353 v_tors: 0.0,
354 }),
355 "Fe3+2" | "Fe6+2" => Some(UffAtomParams {
356 label: "Fe3+2",
357 element: 26,
358 r1: 1.335,
359 theta0: 109.47,
360 x1: 2.912,
361 d1: 0.013,
362 zeta: 2.430,
363 z_star: 2.430,
364 chi: 3.760,
365 v_tors: 0.0,
366 }),
367 "Co6+3" => Some(UffAtomParams {
368 label: "Co6+3",
369 element: 27,
370 r1: 1.241,
371 theta0: 90.0,
372 x1: 2.872,
373 d1: 0.014,
374 zeta: 2.430,
375 z_star: 2.430,
376 chi: 4.105,
377 v_tors: 0.0,
378 }),
379 "Ni4+2" => Some(UffAtomParams {
380 label: "Ni4+2",
381 element: 28,
382 r1: 1.164,
383 theta0: 90.0,
384 x1: 2.834,
385 d1: 0.015,
386 zeta: 2.430,
387 z_star: 2.430,
388 chi: 4.465,
389 v_tors: 0.0,
390 }),
391 "Cu3+1" => Some(UffAtomParams {
392 label: "Cu3+1",
393 element: 29,
394 r1: 1.302,
395 theta0: 109.47,
396 x1: 3.495,
397 d1: 0.005,
398 zeta: 1.756,
399 z_star: 1.756,
400 chi: 4.200,
401 v_tors: 0.0,
402 }),
403 "Zn3+2" => Some(UffAtomParams {
404 label: "Zn3+2",
405 element: 30,
406 r1: 1.193,
407 theta0: 109.47,
408 x1: 2.763,
409 d1: 0.124,
410 zeta: 1.308,
411 z_star: 1.308,
412 chi: 5.106,
413 v_tors: 0.0,
414 }),
415 "Ge3" => Some(UffAtomParams {
417 label: "Ge3",
418 element: 32,
419 r1: 1.197,
420 theta0: 109.47,
421 x1: 4.280,
422 d1: 0.379,
423 zeta: 2.789,
424 z_star: 2.789,
425 chi: 4.051,
426 v_tors: 0.701,
427 }),
428 "As3" => Some(UffAtomParams {
429 label: "As3",
430 element: 33,
431 r1: 1.211,
432 theta0: 92.1,
433 x1: 4.230,
434 d1: 0.309,
435 zeta: 2.864,
436 z_star: 2.864,
437 chi: 5.188,
438 v_tors: 1.476,
439 }),
440 "Se3" => Some(UffAtomParams {
441 label: "Se3",
442 element: 34,
443 r1: 1.190,
444 theta0: 90.6,
445 x1: 4.205,
446 d1: 0.291,
447 zeta: 2.764,
448 z_star: 2.764,
449 chi: 6.428,
450 v_tors: 0.335,
451 }),
452 "Sn3" => Some(UffAtomParams {
453 label: "Sn3",
454 element: 50,
455 r1: 1.399,
456 theta0: 109.47,
457 x1: 4.392,
458 d1: 0.567,
459 zeta: 3.198,
460 z_star: 3.198,
461 chi: 4.000,
462 v_tors: 0.199,
463 }),
464 "Sb3" => Some(UffAtomParams {
465 label: "Sb3",
466 element: 51,
467 r1: 1.404,
468 theta0: 91.6,
469 x1: 4.420,
470 d1: 0.449,
471 zeta: 3.510,
472 z_star: 3.510,
473 chi: 4.899,
474 v_tors: 1.100,
475 }),
476 "Te3" => Some(UffAtomParams {
477 label: "Te3",
478 element: 52,
479 r1: 1.386,
480 theta0: 90.25,
481 x1: 4.470,
482 d1: 0.398,
483 zeta: 3.526,
484 z_star: 3.526,
485 chi: 5.816,
486 v_tors: 0.300,
487 }),
488 "Mo3+6" => Some(UffAtomParams {
489 label: "Mo3+6",
490 element: 42,
491 r1: 1.386,
492 theta0: 109.47,
493 x1: 3.052,
494 d1: 0.056,
495 zeta: 3.056,
496 z_star: 3.056,
497 chi: 3.465,
498 v_tors: 0.0,
499 }),
500 "Pd4+2" => Some(UffAtomParams {
501 label: "Pd4+2",
502 element: 46,
503 r1: 1.338,
504 theta0: 90.0,
505 x1: 2.899,
506 d1: 0.048,
507 zeta: 2.899,
508 z_star: 2.899,
509 chi: 4.320,
510 v_tors: 0.0,
511 }),
512 "Ag1+1" => Some(UffAtomParams {
513 label: "Ag1+1",
514 element: 47,
515 r1: 1.386,
516 theta0: 180.0,
517 x1: 3.148,
518 d1: 0.036,
519 zeta: 1.956,
520 z_star: 1.956,
521 chi: 4.436,
522 v_tors: 0.0,
523 }),
524 "Pt4+2" => Some(UffAtomParams {
525 label: "Pt4+2",
526 element: 78,
527 r1: 1.364,
528 theta0: 90.0,
529 x1: 2.754,
530 d1: 0.080,
531 zeta: 2.754,
532 z_star: 2.754,
533 chi: 4.790,
534 v_tors: 0.0,
535 }),
536 "Au4+3" => Some(UffAtomParams {
537 label: "Au4+3",
538 element: 79,
539 r1: 1.255,
540 theta0: 90.0,
541 x1: 3.293,
542 d1: 0.039,
543 zeta: 2.309,
544 z_star: 2.309,
545 chi: 5.770,
546 v_tors: 0.0,
547 }),
548 _ => None,
549 }
550}
551
552pub fn get_uff_bond_length(
559 pi: &UffAtomParams,
560 pj: &UffAtomParams,
561 bond_order: &crate::graph::BondOrder,
562) -> f64 {
563 const LAMBDA: f64 = 0.1332;
564
565 let bo_value: f64 = match bond_order {
566 crate::graph::BondOrder::Single => 1.0,
567 crate::graph::BondOrder::Aromatic => 1.5,
568 crate::graph::BondOrder::Double => 2.0,
569 crate::graph::BondOrder::Triple => 3.0,
570 _ => 1.0,
571 };
572
573 let r_bo = if (bo_value - 1.0).abs() < 1e-10 {
574 0.0
575 } else {
576 -LAMBDA * (pi.r1 + pj.r1) * bo_value.ln()
577 };
578
579 let r_en = if (pi.chi - pj.chi).abs() > 1e-6 {
580 let sqrt_diff = pi.chi.sqrt() - pj.chi.sqrt();
581 pi.r1 * pj.r1 * sqrt_diff * sqrt_diff / (pi.chi * pi.r1 + pj.chi * pj.r1)
582 } else {
583 0.0
584 };
585
586 (pi.r1 + pj.r1 + r_bo - r_en).max(0.5)
587}
588
589pub fn get_uff_bond_force_constant(pi: &UffAtomParams, pj: &UffAtomParams, r0: f64) -> f64 {
592 664.12 * pi.z_star * pj.z_star / r0.powi(3)
593}
594
595pub fn get_uff_angle_force_constant(
599 pi: &UffAtomParams,
600 pk: &UffAtomParams,
601 r_ij: f64,
602 r_jk: f64,
603 theta0_rad: f64,
604) -> f64 {
605 let r_ik_sq = r_ij * r_ij + r_jk * r_jk - 2.0 * r_ij * r_jk * theta0_rad.cos();
606 if r_ik_sq < 1e-10 || r_ij < 1e-10 || r_jk < 1e-10 {
607 return 0.0;
608 }
609 332.06 * pi.z_star * pk.z_star / (r_ij * r_jk * r_ik_sq)
610}
611
612pub fn get_uff_torsion_params(
616 hyb_j: &crate::graph::Hybridization,
617 hyb_k: &crate::graph::Hybridization,
618 vj: f64,
619 vk: f64,
620 bond_order: &crate::graph::BondOrder,
621) -> (f64, f64, f64) {
622 use crate::graph::BondOrder::*;
623 use crate::graph::Hybridization::*;
624
625 match (hyb_j, hyb_k, bond_order) {
626 (SP3, SP3, _) => (0.5 * (vj * vk).sqrt(), 3.0, 1.0),
628 (SP3, SP2, _) | (SP2, SP3, _) => (1.0, 6.0, 1.0),
630 (SP2, SP2, Aromatic) | (SP2, SP2, Double) => (5.0, 2.0, -1.0),
632 (SP2, SP2, Single) => (10.0, 2.0, -1.0),
634 (SP, _, _) | (_, SP, _) => (0.0, 1.0, 1.0),
636 _ => (1.0, 3.0, 1.0),
637 }
638}