Skip to content

Commit

Permalink
Merge pull request #16 from lightdock/0.3.1
Browse files Browse the repository at this point in the history
0.3.1
  • Loading branch information
brianjimenez authored Apr 19, 2024
2 parents 07c2def + ce5bfbf commit 93747b6
Show file tree
Hide file tree
Showing 11 changed files with 879 additions and 531 deletions.
11 changes: 10 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
[package]
name = "lightdock"
version = "0.3.0"
version = "0.3.1"
authors = ["Brian Jimenez Garcia <[email protected]>"]
edition = "2021"
license = "GPL-3.0-only"
description = "Macromolecular docking software based on the GSO algorithm"
homepage = "https://lightdock.org"

[dependencies]
rand = "0.7.3"
Expand All @@ -13,3 +16,9 @@ lazy_static = "1.4.0"
npyz = "0.8.3"
log = "0.4.21"
env_logger = "0.11.3"

[lints.clippy]
borrowed_box = "allow"
needless_range_loop = "allow"
too_many_arguments = "allow"
new_ret_no_self = "allow"
213 changes: 142 additions & 71 deletions src/bin/lightdock-rust.rs
Original file line number Diff line number Diff line change
@@ -1,45 +1,47 @@
extern crate npyz;
extern crate serde;
extern crate serde_json;
extern crate npyz;

use lightdock::GSO;
use lightdock::constants::{DEFAULT_LIGHTDOCK_PREFIX, DEFAULT_SEED, DEFAULT_REC_NM_FILE, DEFAULT_LIG_NM_FILE};
use lightdock::scoring::{Score, Method};
use lightdock::constants::{
DEFAULT_LIGHTDOCK_PREFIX, DEFAULT_LIG_NM_FILE, DEFAULT_REC_NM_FILE, DEFAULT_SEED,
};
use lightdock::dfire::DFIRE;
use lightdock::dna::DNA;
use lightdock::pydock::PYDOCK;
use lightdock::scoring::{Method, Score};
use lightdock::GSO;
use npyz::NpyFile;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::env;
use std::fs;
use serde::{Serialize, Deserialize};
use std::error::Error;
use std::fs;
use std::fs::File;
use std::io::{Read, BufReader};
use std::io::BufReader;
use std::path::Path;
use std::collections::HashMap;
use std::thread;
use npyz::NpyData;

// Use 8MB as binary stack
const STACK_SIZE: usize = 8 * 1024 * 1024;

#[derive(Serialize, Deserialize, Debug)]
struct SetupFile {
seed: Option<u64>,
anm_seed: u64,
ftdock_file: Option<String>,
noh: bool,
anm_rec: usize,
anm_lig: usize,
swarms: u32,
starting_points_seed: u32,
verbose_parser: bool,
noxt: bool,
seed: Option<u64>,
anm_seed: u64,
ftdock_file: Option<String>,
noh: bool,
anm_rec: usize,
anm_lig: usize,
swarms: u32,
starting_points_seed: u32,
verbose_parser: bool,
noxt: bool,
now: bool,
restraints: Option<String>,
use_anm: bool,
glowworms: u32,
membrane: bool,
receptor_pdb: String,
restraints: Option<String>,
use_anm: bool,
glowworms: u32,
membrane: bool,
receptor_pdb: String,
ligand_pdb: String,
receptor_restraints: Option<HashMap<String, Vec<String>>>,
ligand_restraints: Option<HashMap<String, Vec<String>>>,
Expand All @@ -57,15 +59,14 @@ fn read_setup_from_file<P: AsRef<Path>>(path: P) -> Result<SetupFile, Box<dyn Er

fn parse_input_coordinates(swarm_filename: &str) -> Vec<Vec<f64>> {
// Parse swarm filename content
let contents = fs::read_to_string(swarm_filename)
.expect("Error reading the input file");
let contents = fs::read_to_string(swarm_filename).expect("Error reading the input file");

let mut positions: Vec<Vec<f64>> = Vec::new();
for s in contents.lines() {
let vector_raw: String = String::from(s);
let vector: Vec<&str> = vector_raw.split(' ').collect();
let mut position: Vec<f64> = Vec::new();
for pos in vector.iter() {
for pos in vector.iter() {
position.push(pos.trim().parse::<f64>().unwrap());
}
positions.push(position);
Expand Down Expand Up @@ -95,13 +96,11 @@ fn run() {
let num_steps = &args[3];
// parse the number
let steps: u32 = match num_steps.parse() {
Ok(n) => {
n
},
Ok(n) => n,
Err(_) => {
eprintln!("Error: steps argument must be a number");
return;
},
}
};
let method_type = &args[4].to_lowercase();
// parse the type
Expand All @@ -112,7 +111,7 @@ fn run() {
_ => {
eprintln!("Error: method not supported");
return;
},
}
};

// Load setup
Expand All @@ -121,10 +120,19 @@ fn run() {
// Simulation path
let simulation_path = Path::new(setup_filename).parent().unwrap();

simulate(simulation_path.to_str().unwrap(), &setup, swarm_filename, steps, method);
simulate(
simulation_path.to_str().unwrap(),
&setup,
swarm_filename,
steps,
method,
);
}
_ => {
println!("Wrong command line. Usage: {} setup_filename swarm_filename steps method", args[0]);
println!(
"Wrong command line. Usage: {} setup_filename swarm_filename steps method",
args[0]
);
}
}
}
Expand All @@ -137,15 +145,16 @@ fn parse_swarm_id(path: &Path) -> Option<i32> {
.and_then(|s| s.parse::<i32>().ok())
}

fn simulate(simulation_path: &str, setup: &SetupFile, swarm_filename: &str, steps: u32, method: Method) {

let seed:u64 = match setup.seed {
Some(seed) => {
seed
},
None => {
DEFAULT_SEED
},
fn simulate(
simulation_path: &str,
setup: &SetupFile,
swarm_filename: &str,
steps: u32,
method: Method,
) {
let seed: u64 = match setup.seed {
Some(seed) => seed,
None => DEFAULT_SEED,
};

println!("Reading starting positions from {:?}", swarm_filename);
Expand All @@ -154,47 +163,76 @@ fn simulate(simulation_path: &str, setup: &SetupFile, swarm_filename: &str, step
println!("Swarm ID {:?}", swarm_id);
let swarm_directory = format!("swarm_{}", swarm_id);

if !fs::metadata(&swarm_directory).map(|m| m.is_dir()).unwrap_or(false) {
if !fs::metadata(&swarm_directory)
.map(|m| m.is_dir())
.unwrap_or(false)
{
panic!("Output directory does not exist for swarm {:?}", swarm_id);
}

println!("Writing to swarm dir {:?}", swarm_directory);
let positions = parse_input_coordinates(swarm_filename);

let receptor_filename = if simulation_path == "" {
let receptor_filename = if simulation_path.is_empty() {
format!("{}{}", DEFAULT_LIGHTDOCK_PREFIX, setup.receptor_pdb)
} else {
format!("{}/{}{}", simulation_path, DEFAULT_LIGHTDOCK_PREFIX, setup.receptor_pdb)
format!(
"{}/{}{}",
simulation_path, DEFAULT_LIGHTDOCK_PREFIX, setup.receptor_pdb
)
};
// Parse receptor input PDB structure
println!("Reading receptor input structure: {}", receptor_filename);
let (receptor, _errors) = pdbtbx::open(&receptor_filename, pdbtbx::StrictnessLevel::Medium).unwrap();
let (receptor, _errors) =
pdbtbx::open(&receptor_filename, pdbtbx::StrictnessLevel::Medium).unwrap();

let ligand_filename = if simulation_path == "" {
let ligand_filename = if simulation_path.is_empty() {
format!("{}{}", DEFAULT_LIGHTDOCK_PREFIX, setup.ligand_pdb)
} else {
format!("{}/{}{}", simulation_path, DEFAULT_LIGHTDOCK_PREFIX, setup.ligand_pdb)
format!(
"{}/{}{}",
simulation_path, DEFAULT_LIGHTDOCK_PREFIX, setup.ligand_pdb
)
};
// Parse ligand input PDB structure
println!("Reading ligand input structure: {}", ligand_filename);
let (ligand, _errors) = pdbtbx::open(&ligand_filename, pdbtbx::StrictnessLevel::Medium).unwrap();
let (ligand, _errors) =
pdbtbx::open(&ligand_filename, pdbtbx::StrictnessLevel::Medium).unwrap();

// Read ANM data if activated
let mut rec_nm: Vec<f64> = Vec::new();
let mut lig_nm: Vec<f64> = Vec::new();
if setup.use_anm {
let mut buf = vec![];
if setup.anm_rec > 0 {
std::fs::File::open(DEFAULT_REC_NM_FILE).unwrap().read_to_end(&mut buf).unwrap();
rec_nm = NpyData::from_bytes(&buf).unwrap().to_vec();
let bytes = match std::fs::read(DEFAULT_REC_NM_FILE) {
Ok(bytes) => bytes,
Err(e) => {
panic!(
"Error reading receptor ANM file [{:?}]: {:?}",
DEFAULT_REC_NM_FILE,
e.to_string()
);
}
};
let reader = NpyFile::new(&bytes[..]).unwrap();
rec_nm = reader.into_vec::<f64>().unwrap();
if rec_nm.len() != receptor.atom_count() * 3 * setup.anm_rec {
panic!("Number of read ANM in receptor does not correspond to the number of atoms");
}
}
if setup.anm_lig > 0 {
buf = vec![];
std::fs::File::open(DEFAULT_LIG_NM_FILE).unwrap().read_to_end(&mut buf).unwrap();
lig_nm = NpyData::from_bytes(&buf).unwrap().to_vec();
let bytes = match std::fs::read(DEFAULT_LIG_NM_FILE) {
Ok(bytes) => bytes,
Err(e) => {
panic!(
"Error reading ligand ANM file [{:?}]: {:?}",
DEFAULT_LIG_NM_FILE,
e.to_string()
);
}
};
let reader = NpyFile::new(&bytes[..]).unwrap();
lig_nm = reader.into_vec::<f64>().unwrap();
if lig_nm.len() != ligand.atom_count() * 3 * setup.anm_lig {
panic!("Number of read ANM in ligand does not correspond to the number of atoms");
}
Expand All @@ -203,31 +241,64 @@ fn simulate(simulation_path: &str, setup: &SetupFile, swarm_filename: &str, step

// Restraints
let rec_active_restraints: Vec<String> = match &setup.receptor_restraints {
Some(restraints) => { restraints["active"].clone() },
None => { Vec::new() },
Some(restraints) => restraints["active"].clone(),
None => Vec::new(),
};
let rec_passive_restraints: Vec<String> = match &setup.receptor_restraints {
Some(restraints) => { restraints["passive"].clone() },
None => { Vec::new() },
Some(restraints) => restraints["passive"].clone(),
None => Vec::new(),
};
let lig_active_restraints: Vec<String> = match &setup.ligand_restraints {
Some(restraints) => { restraints["active"].clone() },
None => { Vec::new() },
Some(restraints) => restraints["active"].clone(),
None => Vec::new(),
};
let lig_passive_restraints: Vec<String> = match &setup.ligand_restraints {
Some(restraints) => { restraints["passive"].clone() },
None => { Vec::new() },
Some(restraints) => restraints["passive"].clone(),
None => Vec::new(),
};

// Scoring function
println!("Loading {:?} scoring function", method);
let scoring = match method {
Method::DFIRE => DFIRE::new(receptor, rec_active_restraints, rec_passive_restraints, rec_nm, setup.anm_rec,
ligand, lig_active_restraints, lig_passive_restraints, lig_nm, setup.anm_lig, setup.use_anm) as Box<dyn Score>,
Method::DNA => DNA::new(receptor, rec_active_restraints, rec_passive_restraints, rec_nm, setup.anm_rec,
ligand, lig_active_restraints, lig_passive_restraints, lig_nm, setup.anm_lig, setup.use_anm) as Box<dyn Score>,
Method::PYDOCK => PYDOCK::new(receptor, rec_active_restraints, rec_passive_restraints, rec_nm, setup.anm_rec,
ligand, lig_active_restraints, lig_passive_restraints, lig_nm, setup.anm_lig, setup.use_anm) as Box<dyn Score>,
Method::DFIRE => DFIRE::new(
receptor,
rec_active_restraints,
rec_passive_restraints,
rec_nm,
setup.anm_rec,
ligand,
lig_active_restraints,
lig_passive_restraints,
lig_nm,
setup.anm_lig,
setup.use_anm,
) as Box<dyn Score>,
Method::DNA => DNA::new(
receptor,
rec_active_restraints,
rec_passive_restraints,
rec_nm,
setup.anm_rec,
ligand,
lig_active_restraints,
lig_passive_restraints,
lig_nm,
setup.anm_lig,
setup.use_anm,
) as Box<dyn Score>,
Method::PYDOCK => PYDOCK::new(
receptor,
rec_active_restraints,
rec_passive_restraints,
rec_nm,
setup.anm_rec,
ligand,
lig_active_restraints,
lig_passive_restraints,
lig_nm,
setup.anm_lig,
setup.use_anm,
) as Box<dyn Score>,
};

// Glowworm Swarm Optimization algorithm
Expand All @@ -239,7 +310,7 @@ fn simulate(simulation_path: &str, setup: &SetupFile, swarm_filename: &str, step
setup.use_anm,
setup.anm_rec,
setup.anm_lig,
swarm_directory
swarm_directory,
);

// Simulate for the given steps
Expand Down
2 changes: 1 addition & 1 deletion src/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,4 @@ pub const DEFAULT_NMODES_STEP: f64 = 0.5;

// 1D NumPy arrays containing calculated ANM from ProDy
pub const DEFAULT_REC_NM_FILE: &str = "rec_nm.npy";
pub const DEFAULT_LIG_NM_FILE: &str = "lig_nm.npy";
pub const DEFAULT_LIG_NM_FILE: &str = "lig_nm.npy";
Loading

0 comments on commit 93747b6

Please sign in to comment.