Skip to content

Commit 4da8c10

Browse files
authored
re-organize code (#66)
1 parent 05915d0 commit 4da8c10

File tree

9 files changed

+619
-679
lines changed

9 files changed

+619
-679
lines changed

src/cli.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
pub fn handle_ti(input: &str, cutoff: &f64, pml: &Option<String>) {
2+
let _ = haddock_restraints::true_interface(input, cutoff, pml);
3+
}
4+
5+
pub fn handle_gen_tbl(input: &str, pml: &Option<String>) {
6+
haddock_restraints::gen_tbl(input, pml)
7+
}
8+
pub fn handle_unambig_ti(input: &str, cutoff: &f64, pml: &Option<String>) {
9+
let _ = haddock_restraints::unambig_ti(input, cutoff, pml);
10+
}
11+
pub fn handle_restraint_bodies(input: &str, pml: &Option<String>) {
12+
let _ = haddock_restraints::restraint_bodies(input, pml);
13+
}
14+
15+
pub fn handle_list_interface(input: &str, cutoff: &f64) {
16+
let _ = haddock_restraints::list_interface(input, cutoff);
17+
}
18+
19+
pub fn handle_generate_z_restraints(
20+
input: &str,
21+
output: &str,
22+
residues: &[Vec<isize>],
23+
grid_size: &usize,
24+
grid_spacing: &f64,
25+
) {
26+
let _ =
27+
haddock_restraints::generate_z_restraints(input, output, residues, grid_size, grid_spacing);
28+
}

src/core/commands/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
pub mod restraint;
2+
pub mod tbl;
3+
pub mod ti;
4+
pub mod z;

src/core/commands/restraint.rs

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
use std::error::Error;
2+
3+
use crate::*;
4+
5+
/// Generates distance restraints between non-contiguous bodies in a protein structure.
6+
///
7+
/// This function analyzes a PDB file to identify separate bodies within the protein structure,
8+
/// calculates gaps between these bodies, and generates Ambiguous Interaction Restraints (AIRs)
9+
/// to maintain the relative positions of these bodies.
10+
///
11+
/// # Arguments
12+
///
13+
/// * `input_file` - A string slice that holds the path to the input PDB file.
14+
///
15+
/// # Returns
16+
///
17+
/// A `Result<(), Box<dyn Error>>` which is Ok(()) if the function completes successfully,
18+
/// or an Error if something goes wrong.
19+
///
20+
/// # Functionality
21+
///
22+
/// 1. Opens and parses the PDB file using a loose strictness level.
23+
/// 2. Identifies separate bodies within the protein structure.
24+
/// 3. Calculates gaps between these bodies.
25+
/// 4. For each gap:
26+
/// a. Creates two interactors, one for each side of the gap.
27+
/// b. Sets up the interactors with appropriate chain, residue, and atom information.
28+
/// c. Configures distance restraints based on the gap distance.
29+
/// 5. Generates AIRs using the created interactors.
30+
/// 6. Prints the generated AIR table to stdout.
31+
///
32+
pub fn restraint_bodies(input_file: &str, pml: &Option<String>) -> Result<String, Box<dyn Error>> {
33+
// Read PDB file
34+
let pdb = match load_pdb(input_file) {
35+
Ok(pdb) => pdb,
36+
Err(e) => {
37+
panic!("Error opening PDB file: {:?}", e);
38+
}
39+
};
40+
41+
// Find in-contiguous chains
42+
let bodies = find_bodies(&pdb);
43+
let mut gaps = create_iter_body_gaps(&bodies);
44+
45+
// Find same-chain ligands
46+
let ligand_gaps = gaps_around_ligand(&pdb);
47+
48+
// NOTE: One restraint per atom of the ligand might be too much, apply some filtering
49+
// - no duplicated atoms in the protein should be used
50+
// - select every-other pair
51+
let filtered_gaps = filter_unique_by_atom_j(ligand_gaps);
52+
let every_other_gaps: Vec<Gap> = filtered_gaps
53+
.into_iter()
54+
.enumerate()
55+
.filter_map(|(idx, g)| {
56+
if idx % 2 == 0 {
57+
// select even
58+
Some(g)
59+
} else {
60+
None
61+
}
62+
})
63+
.collect();
64+
65+
gaps.extend(every_other_gaps);
66+
67+
// Create the interactors
68+
let mut interactors: Vec<Interactor> = Vec::new();
69+
let mut counter = 0;
70+
gaps.iter().for_each(|g| {
71+
// let (chain, res_i, res_j) = g;
72+
let mut interactor_i = Interactor::new(counter);
73+
counter += 1;
74+
let mut interactor_j = Interactor::new(counter);
75+
interactor_j.add_target(counter - 1);
76+
interactor_i.add_target(counter);
77+
counter += 1;
78+
79+
interactor_i.set_chain(g.chain.as_str());
80+
interactor_i.set_active(vec![g.res_i as i16]);
81+
interactor_i.set_active_atoms(vec![g.atom_i.clone()]);
82+
interactor_i.set_target_distance(g.distance);
83+
interactor_i.set_lower_margin(0.0);
84+
interactor_i.set_upper_margin(0.0);
85+
86+
interactor_j.set_chain(g.chain.as_str());
87+
interactor_j.set_passive(vec![g.res_j as i16]);
88+
interactor_j.set_passive_atoms(vec![g.atom_j.clone()]);
89+
90+
interactors.push(interactor_i);
91+
interactors.push(interactor_j);
92+
});
93+
94+
let air = Air::new(interactors);
95+
let tbl = air.gen_tbl().unwrap();
96+
97+
println!("{}", tbl);
98+
99+
if let Some(output_f) = pml {
100+
air.gen_pml(output_f)
101+
};
102+
Ok(tbl)
103+
}
104+
105+
#[cfg(test)]
106+
mod tests {
107+
108+
use super::*;
109+
#[test]
110+
fn test_restraint_bodies() {
111+
let expected_tbl = r"assign ( resid 1 and segid A and name CA ) ( resid 4 and segid A and name CA ) 10.2 0.0 0.0
112+
113+
assign ( resid 2 and segid A and name CA ) ( resid 8 and segid A and name CA ) 14.2 0.0 0.0
114+
115+
";
116+
117+
let opt: Option<String> = None;
118+
match restraint_bodies("tests/data/gaps.pdb", &opt) {
119+
Ok(tbl) => assert_eq!(tbl, expected_tbl),
120+
Err(_e) => (),
121+
}
122+
}
123+
}

src/core/commands/tbl.rs

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
use crate::*;
2+
3+
/// Generates a table of Ambiguous Interaction Restraints (AIRs) based on input data.
4+
///
5+
/// This function reads interactor data from a JSON file, processes the interactors
6+
/// according to specified flags, and generates a table of AIRs.
7+
///
8+
/// # Arguments
9+
///
10+
/// * `input_file` - A string slice that holds the path to the input JSON file.
11+
///
12+
/// # Functionality
13+
///
14+
/// 1. Reads interactor data from the specified JSON file.
15+
/// 2. For each interactor with a non-empty structure:
16+
/// a. If `passive_from_active` is set, derives passive residues from active ones.
17+
/// b. If `surface_as_passive` is set, treats surface residues as passive.
18+
/// c. If `filter_buried` is set, removes buried residues from consideration.
19+
/// 3. Creates an `Air` instance from the processed interactors.
20+
/// 4. Generates a table of AIRs.
21+
/// 5. Prints the generated table to stdout.
22+
///
23+
pub fn gen_tbl(input_file: &str, pml: &Option<String>) {
24+
let mut interactors = read_json_file(input_file).unwrap();
25+
26+
interactors.iter_mut().for_each(|interactor| {
27+
if !interactor.structure().is_empty() {
28+
if interactor.passive_from_active() {
29+
interactor.set_passive_from_active();
30+
}
31+
32+
if interactor.surface_as_passive() {
33+
interactor.set_surface_as_passive();
34+
}
35+
36+
if interactor.filter_buried() {
37+
interactor.remove_buried_residues();
38+
}
39+
}
40+
});
41+
42+
let air = Air::new(interactors);
43+
44+
let tbl = air.gen_tbl().unwrap();
45+
46+
println!("{}", tbl);
47+
48+
if let Some(output_f) = pml {
49+
air.gen_pml(output_f)
50+
};
51+
}
52+
53+
#[cfg(test)]
54+
mod tests {}

0 commit comments

Comments
 (0)