Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pad lines before parsing pdb #16

Merged
merged 4 commits into from
Aug 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,4 @@ kd-tree = "0.6.0"
clap = { version = "4.5", features = ["derive"] }
nalgebra = "0.33.0"
itertools = "0.13.0"
pdb-handler = "0.1.0"
33 changes: 12 additions & 21 deletions src/interactor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,17 +137,14 @@ impl Interactor {
///
/// # Dependencies
///
/// This method relies on external functions from the `pdbtbx` and `structure` modules:
/// - `pdbtbx::open_pdb`
/// This method relies on external functions from the `structure` module:
/// - `structure::get_residues`
/// - `structure::neighbor_search`
/// - `structure::load_pdb`
///
pub fn set_passive_from_active(&mut self) {
match pdbtbx::open_pdb(
self.structure.clone().unwrap(),
pdbtbx::StrictnessLevel::Loose,
) {
Ok((pdb, _warnings)) => {
match structure::load_pdb(self.structure.clone().unwrap().as_str()) {
Ok(pdb) => {
let residues = structure::get_residues(
&pdb,
self.active.iter().map(|x| *x as isize).collect(),
Expand Down Expand Up @@ -187,20 +184,17 @@ impl Interactor {
///
/// # Dependencies
///
/// This method relies on external functions from the `pdbtbx` and `sasa` modules:
/// - `pdbtbx::open_pdb`
/// This method relies on external functions from the `sasa` and `structure` modules:
/// - `sasa::calculate_sasa`
/// - `structure::load_pdb`
///
/// # Note
///
/// The threshold for considering a residue as "surface" is set to 0.7 relative SASA.
/// This value may need to be adjusted based on specific requirements.
pub fn set_surface_as_passive(&mut self) {
match pdbtbx::open_pdb(
self.structure.clone().unwrap(),
pdbtbx::StrictnessLevel::Loose,
) {
Ok((pdb, _warnings)) => {
match structure::load_pdb(self.structure.clone().unwrap().as_str()) {
Ok(pdb) => {
let sasa = sasa::calculate_sasa(pdb.clone());

// Add these neighbors to the passive set
Expand Down Expand Up @@ -238,20 +232,17 @@ impl Interactor {
///
/// # Dependencies
///
/// This method relies on external functions from the `pdbtbx` and `sasa` modules:
/// - `pdbtbx::open_pdb`
/// This method relies on external functions from the `sasa` and `structure` module:
/// - `sasa::calculate_sasa`
/// - `structure::load_pdb`
///
/// # Note
///
/// The default threshold for considering a residue as "buried" is set to 0.7 relative SASA.
/// This can be customized by setting the `filter_buried_cutoff` field of the `Interactor`.
pub fn remove_buried_residues(&mut self) {
match pdbtbx::open_pdb(
self.structure.clone().unwrap(),
pdbtbx::StrictnessLevel::Loose,
) {
Ok((pdb, _warnings)) => {
match structure::load_pdb(self.structure.clone().unwrap().as_str()) {
Ok(pdb) => {
let sasa = sasa::calculate_sasa(pdb.clone());

let sasa_cutoff = self.filter_buried_cutoff.unwrap_or(0.7);
Expand Down
21 changes: 11 additions & 10 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ fn gen_tbl(input_file: &str) {
///
/// # Arguments
///
/// * `input_pdb` - A string slice that holds the path to the input PDB file.
/// * `input_file` - A string slice that holds the path to the input PDB file.
/// * `cutoff` - A reference to a f64 value specifying the distance cutoff (in Angstroms) for determining interfaces.
///
/// # Returns
Expand Down Expand Up @@ -213,9 +213,10 @@ fn gen_tbl(input_file: &str) {
/// - `structure::get_true_interface` and `structure::get_chains_in_contact` for interface analysis.
/// - `Interactor` struct for representing protein chains and their interactions.
/// - `Air` struct for generating the AIR table.
fn true_interface(input_pdb: &str, cutoff: &f64) -> Result<(), Box<dyn Error>> {
let pdb = match pdbtbx::open_pdb(input_pdb, pdbtbx::StrictnessLevel::Loose) {
Ok((pdb, _warnings)) => pdb,
fn true_interface(input_file: &str, cutoff: &f64) -> Result<(), Box<dyn Error>> {
// Read PDB file
let pdb = match structure::load_pdb(input_file) {
Ok(pdb) => pdb,
Err(e) => {
panic!("Error opening PDB file: {:?}", e);
}
Expand Down Expand Up @@ -307,8 +308,8 @@ fn true_interface(input_pdb: &str, cutoff: &f64) -> Result<(), Box<dyn Error>> {
/// - `Air` struct for generating the AIR table.
fn restraint_bodies(input_file: &str) -> Result<(), Box<dyn Error>> {
// Read PDB file
let pdb = match pdbtbx::open_pdb(input_file, pdbtbx::StrictnessLevel::Loose) {
Ok((pdb, _warnings)) => pdb,
let pdb = match structure::load_pdb(input_file) {
Ok(pdb) => pdb,
Err(e) => {
panic!("Error opening PDB file: {:?}", e);
}
Expand Down Expand Up @@ -404,8 +405,8 @@ fn restraint_bodies(input_file: &str) -> Result<(), Box<dyn Error>> {
/// - `pdbtbx` for opening and parsing PDB files.
/// - `structure::get_true_interface` for identifying interface residues.
fn list_interface(input_file: &str, cutoff: &f64) -> Result<(), Box<dyn Error>> {
let pdb = match pdbtbx::open_pdb(input_file, pdbtbx::StrictnessLevel::Loose) {
Ok((pdb, _warnings)) => pdb,
let pdb = match structure::load_pdb(input_file) {
Ok(pdb) => pdb,
Err(e) => {
panic!("Error opening PDB file: {:?}", e);
}
Expand All @@ -430,8 +431,8 @@ fn generate_z_restraints(
grid_size: &usize,
grid_spacing: &f64,
) -> Result<(), Box<dyn Error>> {
let pdb = match pdbtbx::open_pdb(input_file, pdbtbx::StrictnessLevel::Loose) {
Ok((pdb, _warnings)) => pdb,
let pdb = match structure::load_pdb(input_file) {
Ok(pdb) => pdb,
Err(e) => {
panic!("Error opening PDB file: {:?}", e);
}
Expand Down
8 changes: 3 additions & 5 deletions src/sasa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -564,17 +564,15 @@ pub const REL_ASA: &[(&str, AsaValues)] = &[
#[cfg(test)]
mod test {

use crate::structure;

use super::*;
use std::env;

// TODO: Add more tests

#[test]
fn test_calculate_sasa() {
let pdb_path = env::current_dir().unwrap().join("tests/data/complex.pdb");
let pdb = pdbtbx::open_pdb(pdb_path.to_str().unwrap(), pdbtbx::StrictnessLevel::Loose)
.unwrap()
.0;
let pdb = structure::load_pdb("tests/data/complex.pdb").unwrap();
let extended_residues = calculate_sasa(pdb);

assert_eq!(extended_residues.len(), 116);
Expand Down
62 changes: 56 additions & 6 deletions src/structure.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ use std::collections::{HashMap, HashSet};
use itertools::Itertools;
use kd_tree::KdTree;
use nalgebra::Vector3;
use pdbtbx::Residue;
use pdbtbx::{Atom, PDB};
use pdbtbx::{PDBError, Residue};
use rand::rngs::StdRng;
use rand::seq::SliceRandom;
use rand::SeedableRng;
Expand Down Expand Up @@ -543,6 +543,42 @@ pub fn get_atoms_from_resnumbers(pdb: &PDB, selection: &[isize]) -> Vec<Atom> {
.collect()
}

/// Loads a PDB (Protein Data Bank) file from a file path.
///
/// This function takes a PDB file content as a string, pads the lines,
/// and then attempts to parse it into a PDB structure using the pdbtbx library.
///
/// # Arguments
///
/// * `input_pdb` - A string slice containing the file path of a PDB file.
///
/// # Returns
///
/// * `Result<PDB, Vec<PDBError>>` - On success, returns the parsed PDB structure.
/// On failure, returns a vector of PDBError describing what went wrong during parsing.
///
/// # Notes
///
/// - This function uses `pdb_handler::pad_lines` to preprocess the input string.
/// - The PDB is parsed with `pdbtbx::StrictnessLevel::Loose` to allow for some flexibility in the input format.
/// - Any warnings generated during parsing are discarded. If you need to handle warnings,
/// consider modifying the function to return them along with the PDB structure.
pub fn load_pdb(input_pdb: &str) -> Result<PDB, Vec<PDBError>> {
// Pad lines before reading the PDB file
let padded_reader = pdb_handler::pad_lines(input_pdb);

let pdb = pdbtbx::open_pdb_raw(
padded_reader,
pdbtbx::Context::None,
pdbtbx::StrictnessLevel::Loose,
);

match pdb {
Ok((pdb, _)) => Ok(pdb),
Err(e) => Err(e),
}
}

#[cfg(test)]
mod tests {

Expand All @@ -552,11 +588,7 @@ mod tests {

#[test]
fn test_get_true_interface() {
let pdb_path = env::current_dir().unwrap().join("tests/data/complex.pdb");

let pdb = pdbtbx::open_pdb(pdb_path.to_str().unwrap(), pdbtbx::StrictnessLevel::Loose)
.unwrap()
.0;
let pdb = load_pdb("tests/data/complex.pdb").unwrap();

let observed_true_interface = get_true_interface(&pdb, 5.0);

Expand All @@ -575,4 +607,22 @@ mod tests {

assert_eq!(observed_true_interface, expected_true_interface);
}

#[test]
fn test_load_pdb_short_lines() {
let pdb_path = env::current_dir()
.unwrap()
.join("tests/data/leu_short_lines.pdb");
let pdb = load_pdb(pdb_path.to_str().unwrap()).unwrap();
assert_eq!(pdb.atoms().count(), 8);
}

#[test]
fn test_load_pdb_normal_lines() {
let pdb_path = env::current_dir()
.unwrap()
.join("tests/data/leu_normal_lines.pdb");
let pdb = load_pdb(pdb_path.to_str().unwrap()).unwrap();
assert_eq!(pdb.atoms().count(), 8);
}
}
8 changes: 8 additions & 0 deletions tests/data/leu_normal_lines.pdb
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
ATOM 1 N LEU A 929 26.117 -5.693 15.769 1.00 29.81 A N
ATOM 2 CA LEU A 929 27.153 -4.857 15.061 1.00 29.93 A C
ATOM 3 C LEU A 929 26.486 -3.835 14.143 1.00 29.74 A C
ATOM 4 O LEU A 929 26.790 -2.625 14.181 1.00 29.50 A O
ATOM 5 CB LEU A 929 28.096 -5.742 14.248 1.00 30.37 A C
ATOM 6 CG LEU A 929 29.617 -5.471 14.154 1.00 28.52 A C
ATOM 7 CD1 LEU A 929 30.109 -5.719 12.711 1.00 27.72 A C
ATOM 8 CD2 LEU A 929 30.111 -4.134 14.702 1.00 25.22 A C
8 changes: 8 additions & 0 deletions tests/data/leu_short_lines.pdb
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
ATOM 1 N LEU A 929 26.117 -5.693 15.769 1.00 29.81 A
ATOM 2 CA LEU A 929 27.153 -4.857 15.061 1.00 29.93 A
ATOM 3 C LEU A 929 26.486 -3.835 14.143 1.00 29.74 A
ATOM 4 O LEU A 929 26.790 -2.625 14.181 1.00 29.50 A
ATOM 5 CB LEU A 929 28.096 -5.742 14.248 1.00 30.37 A
ATOM 6 CG LEU A 929 29.617 -5.471 14.154 1.00 28.52 A
ATOM 7 CD1 LEU A 929 30.109 -5.719 12.711 1.00 27.72 A
ATOM 8 CD2 LEU A 929 30.111 -4.134 14.702 1.00 25.22 A