1use super::system::System;
26
27#[derive(Debug, Clone, PartialEq)]
38pub struct AtomParam {
39 pub charge: f64,
41 pub mass: f64,
43 pub type_idx: usize,
45}
46
47#[derive(Debug, Clone, PartialEq)]
49pub enum BondPotential {
50 Harmonic {
52 atoms: (usize, usize),
54 k_half: f64,
56 r0: f64,
58 },
59 Morse {
61 atoms: (usize, usize),
63 de: f64,
65 r0: f64,
67 alpha: f64,
69 },
70}
71
72#[derive(Debug, Clone, PartialEq)]
74pub enum AnglePotential {
75 CosineHarmonic {
77 atoms: (usize, usize, usize),
79 c_half: f64,
81 cos0: f64,
83 },
84 CosineLinear {
86 atoms: (usize, usize, usize),
88 c: f64,
90 },
91 ThetaHarmonic {
93 atoms: (usize, usize, usize),
95 k_half: f64,
97 theta0: f64,
99 },
100}
101
102#[derive(Debug, Clone, PartialEq)]
104pub struct TorsionPotential {
105 pub atoms: (usize, usize, usize, usize),
107 pub v_half: f64,
109 pub n: u8,
111 pub cos_n_phi0: f64,
113 pub sin_n_phi0: f64,
115}
116
117#[derive(Debug, Clone, PartialEq)]
119pub enum InversionPotential {
120 Planar {
122 atoms: (usize, usize, usize, usize),
125 c_half: f64,
127 },
128 Umbrella {
130 atoms: (usize, usize, usize, usize),
133 c_half: f64,
135 cos_psi0: f64,
137 },
138}
139
140#[derive(Debug, Clone, PartialEq)]
142pub enum VdwPairPotential {
143 LennardJones {
145 type1_idx: usize,
147 type2_idx: usize,
149 d0: f64,
151 r0_sq: f64,
153 },
154 Buckingham {
156 type1_idx: usize,
158 type2_idx: usize,
160 a: f64,
162 b: f64,
164 c: f64,
166 r_max_sq: f64,
168 two_e_max: f64,
170 },
171}
172
173#[derive(Debug, Clone, PartialEq)]
175pub struct HBondPotential {
176 pub donor_type_idx: usize,
178 pub hydrogen_type_idx: usize,
180 pub acceptor_type_idx: usize,
182 pub d_hb: f64,
184 pub r_hb_sq: f64,
186}
187
188#[derive(Debug, Clone, Default)]
193pub struct Potentials {
194 pub bonds: Vec<BondPotential>,
196 pub angles: Vec<AnglePotential>,
198 pub torsions: Vec<TorsionPotential>,
200 pub inversions: Vec<InversionPotential>,
202 pub vdw_pairs: Vec<VdwPairPotential>,
204 pub h_bonds: Vec<HBondPotential>,
206}
207
208#[derive(Debug, Clone)]
225pub struct ForgedSystem {
226 pub system: System,
228 pub atom_types: Vec<String>,
230 pub atom_properties: Vec<AtomParam>,
232 pub potentials: Potentials,
234}
235
236#[cfg(test)]
237mod tests {
238 use super::*;
239
240 #[test]
241 fn bond_harmonic_construction() {
242 let bond = BondPotential::Harmonic {
243 atoms: (0, 1),
244 k_half: 350.0,
245 r0: 1.54,
246 };
247
248 match bond {
249 BondPotential::Harmonic { atoms, k_half, r0 } => {
250 assert_eq!(atoms.0, 0);
251 assert_eq!(atoms.1, 1);
252 assert_eq!(k_half, 350.0);
253 assert_eq!(r0, 1.54);
254 }
255 _ => panic!("expected Harmonic variant"),
256 }
257 }
258
259 #[test]
260 fn bond_morse_construction() {
261 let bond = BondPotential::Morse {
262 atoms: (2, 3),
263 de: 70.0,
264 r0: 1.10,
265 alpha: 2.0,
266 };
267
268 match bond {
269 BondPotential::Morse {
270 atoms,
271 de,
272 r0,
273 alpha,
274 } => {
275 assert_eq!(atoms.0, 2);
276 assert_eq!(atoms.1, 3);
277 assert_eq!(de, 70.0);
278 assert_eq!(r0, 1.10);
279 assert_eq!(alpha, 2.0);
280 }
281 _ => panic!("expected Morse variant"),
282 }
283 }
284
285 #[test]
286 fn bond_partial_eq() {
287 let b1 = BondPotential::Harmonic {
288 atoms: (0, 1),
289 k_half: 350.0,
290 r0: 1.54,
291 };
292 let b2 = BondPotential::Harmonic {
293 atoms: (0, 1),
294 k_half: 350.0,
295 r0: 1.54,
296 };
297 let b3 = BondPotential::Harmonic {
298 atoms: (0, 1),
299 k_half: 400.0,
300 r0: 1.54,
301 };
302
303 assert_eq!(b1, b2);
304 assert_ne!(b1, b3);
305 }
306
307 #[test]
308 fn bond_clone() {
309 let bond = BondPotential::Harmonic {
310 atoms: (5, 6),
311 k_half: 350.0,
312 r0: 1.09,
313 };
314 let cloned = bond.clone();
315 assert_eq!(bond, cloned);
316 }
317
318 #[test]
319 fn angle_cosine_harmonic_construction() {
320 let angle = AnglePotential::CosineHarmonic {
321 atoms: (0, 1, 2),
322 c_half: 50.0,
323 cos0: 0.5,
324 };
325
326 match angle {
327 AnglePotential::CosineHarmonic {
328 atoms,
329 c_half,
330 cos0,
331 } => {
332 assert_eq!(atoms.0, 0);
333 assert_eq!(atoms.1, 1);
334 assert_eq!(atoms.2, 2);
335 assert_eq!(c_half, 50.0);
336 assert_eq!(cos0, 0.5);
337 }
338 _ => panic!("expected CosineHarmonic variant"),
339 }
340 }
341
342 #[test]
343 fn angle_cosine_linear_construction() {
344 let angle = AnglePotential::CosineLinear {
345 atoms: (6, 7, 8),
346 c: 100.0,
347 };
348
349 match angle {
350 AnglePotential::CosineLinear { atoms, c } => {
351 assert_eq!(atoms.0, 6);
352 assert_eq!(atoms.1, 7);
353 assert_eq!(atoms.2, 8);
354 assert_eq!(c, 100.0);
355 }
356 _ => panic!("expected CosineLinear variant"),
357 }
358 }
359
360 #[test]
361 fn angle_theta_harmonic_construction() {
362 let angle = AnglePotential::ThetaHarmonic {
363 atoms: (3, 4, 5),
364 k_half: 50.0,
365 theta0: 1.911,
366 };
367
368 match angle {
369 AnglePotential::ThetaHarmonic {
370 atoms,
371 k_half,
372 theta0,
373 } => {
374 assert_eq!(atoms.0, 3);
375 assert_eq!(atoms.1, 4);
376 assert_eq!(atoms.2, 5);
377 assert_eq!(k_half, 50.0);
378 assert_eq!(theta0, 1.911);
379 }
380 _ => panic!("expected ThetaHarmonic variant"),
381 }
382 }
383
384 #[test]
385 fn angle_partial_eq() {
386 let a1 = AnglePotential::CosineHarmonic {
387 atoms: (0, 1, 2),
388 c_half: 50.0,
389 cos0: 0.5,
390 };
391 let a2 = AnglePotential::CosineHarmonic {
392 atoms: (0, 1, 2),
393 c_half: 50.0,
394 cos0: 0.5,
395 };
396 assert_eq!(a1, a2);
397 }
398
399 #[test]
400 fn torsion_construction() {
401 let torsion = TorsionPotential {
402 atoms: (0, 1, 2, 3),
403 v_half: 1.0,
404 n: 3,
405 cos_n_phi0: -1.0,
406 sin_n_phi0: 0.0,
407 };
408
409 assert_eq!(torsion.atoms.0, 0);
410 assert_eq!(torsion.atoms.1, 1);
411 assert_eq!(torsion.atoms.2, 2);
412 assert_eq!(torsion.atoms.3, 3);
413 assert_eq!(torsion.v_half, 1.0);
414 assert_eq!(torsion.n, 3);
415 assert_eq!(torsion.cos_n_phi0, -1.0);
416 assert_eq!(torsion.sin_n_phi0, 0.0);
417 }
418
419 #[test]
420 fn torsion_partial_eq() {
421 let t1 = TorsionPotential {
422 atoms: (0, 1, 2, 3),
423 v_half: 1.0,
424 n: 3,
425 cos_n_phi0: -1.0,
426 sin_n_phi0: 0.0,
427 };
428 let t2 = TorsionPotential {
429 atoms: (0, 1, 2, 3),
430 v_half: 1.0,
431 n: 3,
432 cos_n_phi0: -1.0,
433 sin_n_phi0: 0.0,
434 };
435 let t3 = TorsionPotential {
436 atoms: (0, 1, 2, 3),
437 v_half: 2.0,
438 n: 3,
439 cos_n_phi0: -1.0,
440 sin_n_phi0: 0.0,
441 };
442
443 assert_eq!(t1, t2);
444 assert_ne!(t1, t3);
445 }
446
447 #[test]
448 fn torsion_clone() {
449 let torsion = TorsionPotential {
450 atoms: (5, 6, 7, 8),
451 v_half: 22.5,
452 n: 2,
453 cos_n_phi0: 1.0,
454 sin_n_phi0: 0.0,
455 };
456 let cloned = torsion.clone();
457 assert_eq!(torsion, cloned);
458 }
459
460 #[test]
461 fn inversion_planar_construction() {
462 let inversion = InversionPotential::Planar {
463 atoms: (1, 0, 2, 3),
464 c_half: 20.0,
465 };
466
467 match inversion {
468 InversionPotential::Planar { atoms, c_half } => {
469 assert_eq!(atoms.0, 1);
470 assert_eq!(atoms.1, 0);
471 assert_eq!(atoms.2, 2);
472 assert_eq!(atoms.3, 3);
473 assert_eq!(c_half, 20.0);
474 }
475 _ => panic!("expected Planar variant"),
476 }
477 }
478
479 #[test]
480 fn inversion_umbrella_construction() {
481 let inversion = InversionPotential::Umbrella {
482 atoms: (5, 6, 7, 8),
483 c_half: 13.33,
484 cos_psi0: 0.5774,
485 };
486
487 match inversion {
488 InversionPotential::Umbrella {
489 atoms,
490 c_half,
491 cos_psi0,
492 } => {
493 assert_eq!(atoms.0, 5);
494 assert_eq!(atoms.1, 6);
495 assert_eq!(atoms.2, 7);
496 assert_eq!(atoms.3, 8);
497 assert_eq!(c_half, 13.33);
498 assert_eq!(cos_psi0, 0.5774);
499 }
500 _ => panic!("expected Umbrella variant"),
501 }
502 }
503
504 #[test]
505 fn inversion_partial_eq() {
506 let i1 = InversionPotential::Planar {
507 atoms: (1, 0, 2, 3),
508 c_half: 20.0,
509 };
510 let i2 = InversionPotential::Planar {
511 atoms: (1, 0, 2, 3),
512 c_half: 20.0,
513 };
514 assert_eq!(i1, i2);
515 }
516
517 #[test]
518 fn vdw_lennard_jones_construction() {
519 let vdw = VdwPairPotential::LennardJones {
520 type1_idx: 0,
521 type2_idx: 1,
522 d0: 0.0951,
523 r0_sq: 15.195,
524 };
525
526 match vdw {
527 VdwPairPotential::LennardJones {
528 type1_idx,
529 type2_idx,
530 d0,
531 r0_sq,
532 } => {
533 assert_eq!(type1_idx, 0);
534 assert_eq!(type2_idx, 1);
535 assert_eq!(d0, 0.0951);
536 assert_eq!(r0_sq, 15.195);
537 }
538 _ => panic!("expected LennardJones variant"),
539 }
540 }
541
542 #[test]
543 fn vdw_buckingham_construction() {
544 let vdw = VdwPairPotential::Buckingham {
545 type1_idx: 2,
546 type2_idx: 3,
547 a: 1000.0,
548 b: 3.08,
549 c: 500.0,
550 r_max_sq: 16.0,
551 two_e_max: 10.5,
552 };
553
554 match vdw {
555 VdwPairPotential::Buckingham {
556 type1_idx,
557 type2_idx,
558 a,
559 b,
560 c,
561 r_max_sq,
562 two_e_max,
563 } => {
564 assert_eq!(type1_idx, 2);
565 assert_eq!(type2_idx, 3);
566 assert_eq!(a, 1000.0);
567 assert_eq!(b, 3.08);
568 assert_eq!(c, 500.0);
569 assert_eq!(r_max_sq, 16.0);
570 assert_eq!(two_e_max, 10.5);
571 }
572 _ => panic!("expected Buckingham variant"),
573 }
574 }
575
576 #[test]
577 fn vdw_partial_eq() {
578 let v1 = VdwPairPotential::LennardJones {
579 type1_idx: 0,
580 type2_idx: 1,
581 d0: 0.0951,
582 r0_sq: 15.195,
583 };
584 let v2 = VdwPairPotential::LennardJones {
585 type1_idx: 0,
586 type2_idx: 1,
587 d0: 0.0951,
588 r0_sq: 15.195,
589 };
590 let v3 = VdwPairPotential::LennardJones {
591 type1_idx: 0,
592 type2_idx: 1,
593 d0: 0.1000,
594 r0_sq: 15.195,
595 };
596
597 assert_eq!(v1, v2);
598 assert_ne!(v1, v3);
599 }
600
601 #[test]
602 fn hbond_construction() {
603 let hbond = HBondPotential {
604 donor_type_idx: 0,
605 hydrogen_type_idx: 1,
606 acceptor_type_idx: 2,
607 d_hb: 4.0,
608 r_hb_sq: 7.5625,
609 };
610
611 assert_eq!(hbond.donor_type_idx, 0);
612 assert_eq!(hbond.hydrogen_type_idx, 1);
613 assert_eq!(hbond.acceptor_type_idx, 2);
614 assert_eq!(hbond.d_hb, 4.0);
615 assert_eq!(hbond.r_hb_sq, 7.5625);
616 }
617
618 #[test]
619 fn hbond_partial_eq() {
620 let h1 = HBondPotential {
621 donor_type_idx: 0,
622 hydrogen_type_idx: 1,
623 acceptor_type_idx: 2,
624 d_hb: 4.0,
625 r_hb_sq: 7.5625,
626 };
627 let h2 = HBondPotential {
628 donor_type_idx: 0,
629 hydrogen_type_idx: 1,
630 acceptor_type_idx: 2,
631 d_hb: 4.0,
632 r_hb_sq: 7.5625,
633 };
634 let h3 = HBondPotential {
635 donor_type_idx: 0,
636 hydrogen_type_idx: 1,
637 acceptor_type_idx: 2,
638 d_hb: 5.0,
639 r_hb_sq: 7.5625,
640 };
641
642 assert_eq!(h1, h2);
643 assert_ne!(h1, h3);
644 }
645
646 #[test]
647 fn hbond_clone() {
648 let hbond = HBondPotential {
649 donor_type_idx: 3,
650 hydrogen_type_idx: 4,
651 acceptor_type_idx: 5,
652 d_hb: 7.0,
653 r_hb_sq: 7.5625,
654 };
655 let cloned = hbond.clone();
656 assert_eq!(hbond, cloned);
657 }
658
659 #[test]
660 fn atom_param_construction() {
661 let param = AtomParam {
662 charge: -0.5,
663 mass: 12.011,
664 type_idx: 2,
665 };
666
667 assert_eq!(param.charge, -0.5);
668 assert_eq!(param.mass, 12.011);
669 assert_eq!(param.type_idx, 2);
670 }
671
672 #[test]
673 fn atom_param_partial_eq() {
674 let p1 = AtomParam {
675 charge: 0.0,
676 mass: 1.008,
677 type_idx: 0,
678 };
679 let p2 = AtomParam {
680 charge: 0.0,
681 mass: 1.008,
682 type_idx: 0,
683 };
684 let p3 = AtomParam {
685 charge: 0.1,
686 mass: 1.008,
687 type_idx: 0,
688 };
689
690 assert_eq!(p1, p2);
691 assert_ne!(p1, p3);
692 }
693
694 #[test]
695 fn atom_param_clone() {
696 let param = AtomParam {
697 charge: -0.3,
698 mass: 15.999,
699 type_idx: 5,
700 };
701 let cloned = param.clone();
702 assert_eq!(param, cloned);
703 }
704
705 #[test]
706 fn potentials_default() {
707 let pots = Potentials::default();
708
709 assert_eq!(pots.bonds.len(), 0);
710 assert_eq!(pots.angles.len(), 0);
711 assert_eq!(pots.torsions.len(), 0);
712 assert_eq!(pots.inversions.len(), 0);
713 assert_eq!(pots.vdw_pairs.len(), 0);
714 assert_eq!(pots.h_bonds.len(), 0);
715 }
716
717 #[test]
718 fn potentials_add_elements() {
719 let mut pots = Potentials::default();
720
721 pots.bonds.push(BondPotential::Harmonic {
722 atoms: (0, 1),
723 k_half: 350.0,
724 r0: 1.54,
725 });
726
727 pots.angles.push(AnglePotential::CosineHarmonic {
728 atoms: (0, 1, 2),
729 c_half: 50.0,
730 cos0: -0.333,
731 });
732
733 pots.torsions.push(TorsionPotential {
734 atoms: (0, 1, 2, 3),
735 v_half: 1.0,
736 n: 3,
737 cos_n_phi0: -1.0,
738 sin_n_phi0: 0.0,
739 });
740
741 assert_eq!(pots.bonds.len(), 1);
742 assert_eq!(pots.angles.len(), 1);
743 assert_eq!(pots.torsions.len(), 1);
744 }
745
746 #[test]
747 fn potentials_clone() {
748 let mut pots = Potentials::default();
749 pots.bonds.push(BondPotential::Harmonic {
750 atoms: (0, 1),
751 k_half: 350.0,
752 r0: 1.54,
753 });
754
755 let cloned = pots.clone();
756 assert_eq!(pots.bonds.len(), cloned.bonds.len());
757 }
758}