protein.rs 7.05 KB
Newer Older
1
use super::atom::Atom;
NOEL Philippe's avatar
NOEL Philippe committed
2
use super::chain::Chain;
3 4
use super::residue::Residue;

5 6 7 8
use super::selection_atom;

use std::char;

NOEL Philippe's avatar
NOEL Philippe committed
9 10

#[derive(Debug)]
NOEL Philippe's avatar
NOEL Philippe committed
11
pub struct Protein {
12 13
    pub name: String,
    pub lst_chain: Vec<Chain>,
14
    last_chain_added: char,
NOEL Philippe's avatar
NOEL Philippe committed
15 16
}

NOEL Philippe's avatar
NOEL Philippe committed
17
impl<'a> Protein {
18 19 20 21 22 23 24 25 26 27 28

    /// Create a new protein structure
    ///
    /// # Examples
    /// 
    /// ````
    /// use pdbparser;
    /// 
    /// let my_prot = pdbparser::Protein::new(String::from("my_prot"));
    /// 
    /// ````
NOEL Philippe's avatar
NOEL Philippe committed
29
    pub fn new(n : String) -> Protein {
NOEL Philippe's avatar
NOEL Philippe committed
30
        Protein {
NOEL Philippe's avatar
NOEL Philippe committed
31 32
            name: n,
            lst_chain: Vec::new(),
33
            last_chain_added: ' ',
NOEL Philippe's avatar
NOEL Philippe committed
34 35 36
        }
    }

37 38 39 40 41 42 43 44 45 46 47 48 49 50
    /// Return True if the chain is in the protein
    ///
    /// # Examples
    /// 
    /// ````
    /// use pdbparser;
    /// 
    /// let mut my_prot = pdbparser::Protein::new(String::from("my_prot"));
    /// let my_chain_a = pdbparser::Chain::new('n');
    /// my_prot.add_chain(my_chain_a);
    /// 
    /// assert!(my_prot.is_chain('n'));
    /// 
    /// ````
NOEL Philippe's avatar
NOEL Philippe committed
51 52 53 54 55
    pub fn is_chain(&self, c: char) -> bool {
        for ii in &self.lst_chain {
            if ii.get_name() == c {
                return true
            }
NOEL Philippe's avatar
NOEL Philippe committed
56
        }
57
        false
NOEL Philippe's avatar
NOEL Philippe committed
58 59
    }

60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
    /// Return a mutable reference of a chaine with its name. Return None if the
    /// chain does not exist
    ///
    /// # Examples
    /// 
    /// ````
    /// use pdbparser;
    /// 
    /// let mut my_prot = pdbparser::Protein::new(String::from("my_prot"));
    /// my_prot.add_chain(pdbparser::Chain::new('n'));
    /// assert_eq!('n', my_prot.lst_chain[0].get_name());
    /// {    
    ///     let mut reference = my_prot.get_chain_ref('n').unwrap();
    ///     reference.name = 'a';
    /// }
    /// assert_eq!('a', my_prot.lst_chain[0].get_name());
    /// ````
    pub fn get_chain_ref(&mut self, c: char) -> Option<&mut Chain> {
        for chain in &mut self.lst_chain {
            if chain.name == c {
                return Some(chain)
            }
        }
        None
    }

86 87 88 89 90 91 92 93 94 95 96 97
    /// Get the number of chain in the protein
    ///
    /// # Examples
    /// 
    /// ````
    /// use pdbparser;
    /// 
    /// let my_prot = pdbparser::Protein::new(String::from("my_prot"));
    /// 
    /// assert_eq!(0, my_prot.get_number_chain());
    /// ````
    pub fn get_number_chain(&self) -> u32 {
NOEL Philippe's avatar
NOEL Philippe committed
98
        self.lst_chain.len() as u32
NOEL Philippe's avatar
NOEL Philippe committed
99
    }
100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120


    /// Add a new chain structure in the protein
    ///
    /// # Examples
    /// 
    /// ````
    /// use pdbparser;
    /// 
    /// let mut my_prot = pdbparser::Protein::new(String::from("my_prot"));
    /// let my_chain_a = pdbparser::Chain::new('n');
    /// 
    /// my_prot.add_chain(my_chain_a);
    /// 
    /// assert_eq!(1, my_prot.get_number_chain());
    /// 
    /// ````
    pub fn add_chain(&mut self, c: Chain) {
        self.last_chain_added = c.get_name();
        self.lst_chain.push(c);
    }
121

122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143

    /// Return the number of residue in the protein
    ///
    /// # Examples
    /// 
    /// ````
    /// use pdbparser;
    /// 
    /// let mut my_prot = pdbparser::Protein::new(String::from("my_prot"));
    /// let mut my_chain = pdbparser::Chain::new('n');
    /// let lys = pdbparser::Residue::new(String::from("lysine"), 1);
    /// let pro = pdbparser::Residue::new(String::from("proline"), 2);
    /// 
    /// my_chain.add_res(lys);
    /// my_chain.add_res(pro);
    /// 
    /// my_prot.add_chain(my_chain);
    /// 
    /// 
    /// assert_eq!(2, my_prot.get_number_residue());
    /// 
    /// ````
144 145 146 147 148 149 150 151 152 153
    pub fn get_number_residue(&self) -> u64 {
        let mut n: u64 = 0;
        for chain in self.lst_chain.iter() {
            for _ in chain.lst_res.iter() {
                n+= 1;
            }
        }
        n
    }

154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
    /// Return the number of atom in the protein
    ///
    /// # Examples
    /// 
    /// ````
    /// use pdbparser;
    /// 
    /// let my_prot = pdbparser::parse_pdb("src/tests_file/f2.pdb");
    /// assert_eq!(1085, my_prot.get_number_atom());
    /// ````
    pub fn get_number_atom(&self) -> u64 {
        let mut n: u64 = 0;
        for chain in self.lst_chain.iter() {
            for res in chain.lst_res.iter() {
                for _ in res.lst_atom.iter() {
                    n += 1;
                }
            }
        }
        n
    }
175 176 177 178

    /// Function that add information on the protein (used in the parsing)
    /// /!\Change this to a macro!
    /// 
179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202
    pub fn update_protein(&mut self, chain: char, res_name: String, res_number: u64, atom_name: String, atom_number: u64, coord: [f32; 3]) {
        // Get a chain reference. If the chain exist, return a mutable reference to it. If not,
        // create a new chain an return the mutable reference 
        let chain = match self.get_chain_ref(chain) {
            Some(c) => c,
            None => {
                self.add_chain(Chain::new(chain));
                self.get_chain_ref(chain).unwrap()
            },
        };
        
        // Get a residue reference. If the residue exist, return a mutable reference to it. If not,
        // create a new residue and return it as mutable reference
        let residue = match chain.get_residue_ref(res_number as u64) {
            Some(r) => r,
            None => {
                chain.add_res(Residue::new(res_name, res_number));
                chain.get_residue_ref(res_number).unwrap()
            },
        };
        
        let atom = Atom::new(atom_name, atom_number, coord);
        residue.add_atom(atom);
    }
NOEL Philippe's avatar
NOEL Philippe committed
203 204 205 206 207 208 209 210

    /// function that return a vector for atom index
    /// Can be used in other program like rrmsd_map to select specific atom
    /// 
    /// # Examples
    /// ```
    /// use pdbparser;
    /// 
211
    /// let my_prot = pdbparser::parse_pdb("src/tests_file/f2_adn.pdb");
NOEL Philippe's avatar
NOEL Philippe committed
212 213
    /// let atom_index = my_prot.get_atom_index();
    /// 
214 215
    /// assert_eq!(atom_index[0], 1);
    /// assert_eq!(atom_index[1], 2);
NOEL Philippe's avatar
NOEL Philippe committed
216 217 218 219 220 221 222 223 224 225 226 227 228
    /// 
    /// ```
    pub fn get_atom_index(&self) -> Vec<u64> {
        let mut lst: Vec<u64> = Vec::new();
        for chain in &self.lst_chain {
            for res in &chain.lst_res {
                for atom in &res.lst_atom {
                    lst.push(atom.number);
                }
            }
        }
        lst
    }
229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256

    /// Select atom from a pattern and return a new protein structure
    /// 
    /// TODO: The methode is idiot and need to be improve.
    /// ex: don't parse the chain if it's not selected
    /// 

    pub fn select_atoms(&self, pattern: &str) -> Protein {

        let mut n_prot = Protein::new(String::from("toto"));

        let select = match selection_atom::parse_select(&pattern) {
            Some(x) => x,
            None => panic!("tutu"),
        };
        for chain in &self.lst_chain {
            let c_chain = chain.name;
            for residue in &chain.lst_res {
                let c_res = residue.res_num;
                for atom in &residue.lst_atom {
                    if selection_atom::atom_match(&select, c_chain, c_res) {
                        n_prot.update_protein(c_chain, residue.name.clone(), c_res, atom.name.clone(), atom.number, atom.coord)
                    }
                }
            }
        }
        n_prot
    }
NOEL Philippe's avatar
NOEL Philippe committed
257
}