protein_analysis/
model.rs

1use dihedral::dihedral;
2use protein_core::structure::{Model, Residue};
3
4pub trait ModelAnalysis {
5    fn ramachandran(&self) -> (Vec<f32>, Vec<f32>);
6}
7
8impl ModelAnalysis for Model {
9    fn ramachandran(&self) -> (Vec<f32>, Vec<f32>) {
10        let mut n: Vec<[f32; 3]> = Default::default();
11        let mut ca: Vec<[f32; 3]> = Default::default();
12        let mut c: Vec<[f32; 3]> = Default::default();
13
14        let mut i = 0;
15        while i < self.atoms.len() {
16            if let Residue::AminoAcid(_) = self.atoms[i].residue {
17                if self.atoms[i].name.0 == b"N   "[..]// .is_n()
18                    && self.atoms[i + 1].name.0 == b"CA  "[..] // .is_ca()
19                    && self.atoms[i + 2].name.0 == b"C   "[..]
20                // .is_c()
21                {
22                    n.push(self.atoms[i].coord);
23                    ca.push(self.atoms[i + 1].coord);
24                    c.push(self.atoms[i + 2].coord);
25                    i += 3;
26                    continue;
27                }
28            }
29            i += 1;
30        }
31        assert!(n.len() == ca.len() && n.len() == c.len());
32        let mut phis = Vec::new();
33        let mut psis = Vec::new();
34        for i in 1..n.len() - 1 {
35            let phi = dihedral(&[c[i - 1], n[i], ca[i], c[i]]);
36            let psi = dihedral(&[n[i], ca[i], c[i], n[i + 1]]);
37            phis.push(phi.to_degrees());
38            psis.push(psi.to_degrees());
39        }
40        (phis, psis)
41    }
42}