Skip to content

Commit 5cda4af

Browse files
authored
Merge branch 'master' into patch-1
2 parents 008df99 + 93747b6 commit 5cda4af

11 files changed

+879
-531
lines changed

Diff for: Cargo.toml

+10-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
[package]
22
name = "lightdock"
3-
version = "0.3.0"
3+
version = "0.3.1"
44
authors = ["Brian Jimenez Garcia <[email protected]>"]
55
edition = "2021"
6+
license = "GPL-3.0-only"
7+
description = "Macromolecular docking software based on the GSO algorithm"
8+
homepage = "https://lightdock.org"
69
repository = "https://github.com/lightdock/lightdock-rust"
710

811
[dependencies]
@@ -14,3 +17,9 @@ lazy_static = "1.4.0"
1417
npyz = "0.8.3"
1518
log = "0.4.21"
1619
env_logger = "0.11.3"
20+
21+
[lints.clippy]
22+
borrowed_box = "allow"
23+
needless_range_loop = "allow"
24+
too_many_arguments = "allow"
25+
new_ret_no_self = "allow"

Diff for: src/bin/lightdock-rust.rs

+142-71
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,47 @@
1+
extern crate npyz;
12
extern crate serde;
23
extern crate serde_json;
3-
extern crate npyz;
44

5-
use lightdock::GSO;
6-
use lightdock::constants::{DEFAULT_LIGHTDOCK_PREFIX, DEFAULT_SEED, DEFAULT_REC_NM_FILE, DEFAULT_LIG_NM_FILE};
7-
use lightdock::scoring::{Score, Method};
5+
use lightdock::constants::{
6+
DEFAULT_LIGHTDOCK_PREFIX, DEFAULT_LIG_NM_FILE, DEFAULT_REC_NM_FILE, DEFAULT_SEED,
7+
};
88
use lightdock::dfire::DFIRE;
99
use lightdock::dna::DNA;
1010
use lightdock::pydock::PYDOCK;
11+
use lightdock::scoring::{Method, Score};
12+
use lightdock::GSO;
13+
use npyz::NpyFile;
14+
use serde::{Deserialize, Serialize};
15+
use std::collections::HashMap;
1116
use std::env;
12-
use std::fs;
13-
use serde::{Serialize, Deserialize};
1417
use std::error::Error;
18+
use std::fs;
1519
use std::fs::File;
16-
use std::io::{Read, BufReader};
20+
use std::io::BufReader;
1721
use std::path::Path;
18-
use std::collections::HashMap;
1922
use std::thread;
20-
use npyz::NpyData;
2123

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

2527
#[derive(Serialize, Deserialize, Debug)]
2628
struct SetupFile {
27-
seed: Option<u64>,
28-
anm_seed: u64,
29-
ftdock_file: Option<String>,
30-
noh: bool,
31-
anm_rec: usize,
32-
anm_lig: usize,
33-
swarms: u32,
34-
starting_points_seed: u32,
35-
verbose_parser: bool,
36-
noxt: bool,
29+
seed: Option<u64>,
30+
anm_seed: u64,
31+
ftdock_file: Option<String>,
32+
noh: bool,
33+
anm_rec: usize,
34+
anm_lig: usize,
35+
swarms: u32,
36+
starting_points_seed: u32,
37+
verbose_parser: bool,
38+
noxt: bool,
3739
now: bool,
38-
restraints: Option<String>,
39-
use_anm: bool,
40-
glowworms: u32,
41-
membrane: bool,
42-
receptor_pdb: String,
40+
restraints: Option<String>,
41+
use_anm: bool,
42+
glowworms: u32,
43+
membrane: bool,
44+
receptor_pdb: String,
4345
ligand_pdb: String,
4446
receptor_restraints: Option<HashMap<String, Vec<String>>>,
4547
ligand_restraints: Option<HashMap<String, Vec<String>>>,
@@ -57,15 +59,14 @@ fn read_setup_from_file<P: AsRef<Path>>(path: P) -> Result<SetupFile, Box<dyn Er
5759

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

6364
let mut positions: Vec<Vec<f64>> = Vec::new();
6465
for s in contents.lines() {
6566
let vector_raw: String = String::from(s);
6667
let vector: Vec<&str> = vector_raw.split(' ').collect();
6768
let mut position: Vec<f64> = Vec::new();
68-
for pos in vector.iter() {
69+
for pos in vector.iter() {
6970
position.push(pos.trim().parse::<f64>().unwrap());
7071
}
7172
positions.push(position);
@@ -95,13 +96,11 @@ fn run() {
9596
let num_steps = &args[3];
9697
// parse the number
9798
let steps: u32 = match num_steps.parse() {
98-
Ok(n) => {
99-
n
100-
},
99+
Ok(n) => n,
101100
Err(_) => {
102101
eprintln!("Error: steps argument must be a number");
103102
return;
104-
},
103+
}
105104
};
106105
let method_type = &args[4].to_lowercase();
107106
// parse the type
@@ -112,7 +111,7 @@ fn run() {
112111
_ => {
113112
eprintln!("Error: method not supported");
114113
return;
115-
},
114+
}
116115
};
117116

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

124-
simulate(simulation_path.to_str().unwrap(), &setup, swarm_filename, steps, method);
123+
simulate(
124+
simulation_path.to_str().unwrap(),
125+
&setup,
126+
swarm_filename,
127+
steps,
128+
method,
129+
);
125130
}
126131
_ => {
127-
println!("Wrong command line. Usage: {} setup_filename swarm_filename steps method", args[0]);
132+
println!(
133+
"Wrong command line. Usage: {} setup_filename swarm_filename steps method",
134+
args[0]
135+
);
128136
}
129137
}
130138
}
@@ -137,15 +145,16 @@ fn parse_swarm_id(path: &Path) -> Option<i32> {
137145
.and_then(|s| s.parse::<i32>().ok())
138146
}
139147

140-
fn simulate(simulation_path: &str, setup: &SetupFile, swarm_filename: &str, steps: u32, method: Method) {
141-
142-
let seed:u64 = match setup.seed {
143-
Some(seed) => {
144-
seed
145-
},
146-
None => {
147-
DEFAULT_SEED
148-
},
148+
fn simulate(
149+
simulation_path: &str,
150+
setup: &SetupFile,
151+
swarm_filename: &str,
152+
steps: u32,
153+
method: Method,
154+
) {
155+
let seed: u64 = match setup.seed {
156+
Some(seed) => seed,
157+
None => DEFAULT_SEED,
149158
};
150159

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

157-
if !fs::metadata(&swarm_directory).map(|m| m.is_dir()).unwrap_or(false) {
166+
if !fs::metadata(&swarm_directory)
167+
.map(|m| m.is_dir())
168+
.unwrap_or(false)
169+
{
158170
panic!("Output directory does not exist for swarm {:?}", swarm_id);
159171
}
160172

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

164-
let receptor_filename = if simulation_path == "" {
176+
let receptor_filename = if simulation_path.is_empty() {
165177
format!("{}{}", DEFAULT_LIGHTDOCK_PREFIX, setup.receptor_pdb)
166178
} else {
167-
format!("{}/{}{}", simulation_path, DEFAULT_LIGHTDOCK_PREFIX, setup.receptor_pdb)
179+
format!(
180+
"{}/{}{}",
181+
simulation_path, DEFAULT_LIGHTDOCK_PREFIX, setup.receptor_pdb
182+
)
168183
};
169184
// Parse receptor input PDB structure
170185
println!("Reading receptor input structure: {}", receptor_filename);
171-
let (receptor, _errors) = pdbtbx::open(&receptor_filename, pdbtbx::StrictnessLevel::Medium).unwrap();
186+
let (receptor, _errors) =
187+
pdbtbx::open(&receptor_filename, pdbtbx::StrictnessLevel::Medium).unwrap();
172188

173-
let ligand_filename = if simulation_path == "" {
189+
let ligand_filename = if simulation_path.is_empty() {
174190
format!("{}{}", DEFAULT_LIGHTDOCK_PREFIX, setup.ligand_pdb)
175191
} else {
176-
format!("{}/{}{}", simulation_path, DEFAULT_LIGHTDOCK_PREFIX, setup.ligand_pdb)
192+
format!(
193+
"{}/{}{}",
194+
simulation_path, DEFAULT_LIGHTDOCK_PREFIX, setup.ligand_pdb
195+
)
177196
};
178197
// Parse ligand input PDB structure
179198
println!("Reading ligand input structure: {}", ligand_filename);
180-
let (ligand, _errors) = pdbtbx::open(&ligand_filename, pdbtbx::StrictnessLevel::Medium).unwrap();
199+
let (ligand, _errors) =
200+
pdbtbx::open(&ligand_filename, pdbtbx::StrictnessLevel::Medium).unwrap();
181201

182202
// Read ANM data if activated
183203
let mut rec_nm: Vec<f64> = Vec::new();
184204
let mut lig_nm: Vec<f64> = Vec::new();
185205
if setup.use_anm {
186-
let mut buf = vec![];
187206
if setup.anm_rec > 0 {
188-
std::fs::File::open(DEFAULT_REC_NM_FILE).unwrap().read_to_end(&mut buf).unwrap();
189-
rec_nm = NpyData::from_bytes(&buf).unwrap().to_vec();
207+
let bytes = match std::fs::read(DEFAULT_REC_NM_FILE) {
208+
Ok(bytes) => bytes,
209+
Err(e) => {
210+
panic!(
211+
"Error reading receptor ANM file [{:?}]: {:?}",
212+
DEFAULT_REC_NM_FILE,
213+
e.to_string()
214+
);
215+
}
216+
};
217+
let reader = NpyFile::new(&bytes[..]).unwrap();
218+
rec_nm = reader.into_vec::<f64>().unwrap();
190219
if rec_nm.len() != receptor.atom_count() * 3 * setup.anm_rec {
191220
panic!("Number of read ANM in receptor does not correspond to the number of atoms");
192221
}
193222
}
194223
if setup.anm_lig > 0 {
195-
buf = vec![];
196-
std::fs::File::open(DEFAULT_LIG_NM_FILE).unwrap().read_to_end(&mut buf).unwrap();
197-
lig_nm = NpyData::from_bytes(&buf).unwrap().to_vec();
224+
let bytes = match std::fs::read(DEFAULT_LIG_NM_FILE) {
225+
Ok(bytes) => bytes,
226+
Err(e) => {
227+
panic!(
228+
"Error reading ligand ANM file [{:?}]: {:?}",
229+
DEFAULT_LIG_NM_FILE,
230+
e.to_string()
231+
);
232+
}
233+
};
234+
let reader = NpyFile::new(&bytes[..]).unwrap();
235+
lig_nm = reader.into_vec::<f64>().unwrap();
198236
if lig_nm.len() != ligand.atom_count() * 3 * setup.anm_lig {
199237
panic!("Number of read ANM in ligand does not correspond to the number of atoms");
200238
}
@@ -203,31 +241,64 @@ fn simulate(simulation_path: &str, setup: &SetupFile, swarm_filename: &str, step
203241

204242
// Restraints
205243
let rec_active_restraints: Vec<String> = match &setup.receptor_restraints {
206-
Some(restraints) => { restraints["active"].clone() },
207-
None => { Vec::new() },
244+
Some(restraints) => restraints["active"].clone(),
245+
None => Vec::new(),
208246
};
209247
let rec_passive_restraints: Vec<String> = match &setup.receptor_restraints {
210-
Some(restraints) => { restraints["passive"].clone() },
211-
None => { Vec::new() },
248+
Some(restraints) => restraints["passive"].clone(),
249+
None => Vec::new(),
212250
};
213251
let lig_active_restraints: Vec<String> = match &setup.ligand_restraints {
214-
Some(restraints) => { restraints["active"].clone() },
215-
None => { Vec::new() },
252+
Some(restraints) => restraints["active"].clone(),
253+
None => Vec::new(),
216254
};
217255
let lig_passive_restraints: Vec<String> = match &setup.ligand_restraints {
218-
Some(restraints) => { restraints["passive"].clone() },
219-
None => { Vec::new() },
256+
Some(restraints) => restraints["passive"].clone(),
257+
None => Vec::new(),
220258
};
221259

222260
// Scoring function
223261
println!("Loading {:?} scoring function", method);
224262
let scoring = match method {
225-
Method::DFIRE => DFIRE::new(receptor, rec_active_restraints, rec_passive_restraints, rec_nm, setup.anm_rec,
226-
ligand, lig_active_restraints, lig_passive_restraints, lig_nm, setup.anm_lig, setup.use_anm) as Box<dyn Score>,
227-
Method::DNA => DNA::new(receptor, rec_active_restraints, rec_passive_restraints, rec_nm, setup.anm_rec,
228-
ligand, lig_active_restraints, lig_passive_restraints, lig_nm, setup.anm_lig, setup.use_anm) as Box<dyn Score>,
229-
Method::PYDOCK => PYDOCK::new(receptor, rec_active_restraints, rec_passive_restraints, rec_nm, setup.anm_rec,
230-
ligand, lig_active_restraints, lig_passive_restraints, lig_nm, setup.anm_lig, setup.use_anm) as Box<dyn Score>,
263+
Method::DFIRE => DFIRE::new(
264+
receptor,
265+
rec_active_restraints,
266+
rec_passive_restraints,
267+
rec_nm,
268+
setup.anm_rec,
269+
ligand,
270+
lig_active_restraints,
271+
lig_passive_restraints,
272+
lig_nm,
273+
setup.anm_lig,
274+
setup.use_anm,
275+
) as Box<dyn Score>,
276+
Method::DNA => DNA::new(
277+
receptor,
278+
rec_active_restraints,
279+
rec_passive_restraints,
280+
rec_nm,
281+
setup.anm_rec,
282+
ligand,
283+
lig_active_restraints,
284+
lig_passive_restraints,
285+
lig_nm,
286+
setup.anm_lig,
287+
setup.use_anm,
288+
) as Box<dyn Score>,
289+
Method::PYDOCK => PYDOCK::new(
290+
receptor,
291+
rec_active_restraints,
292+
rec_passive_restraints,
293+
rec_nm,
294+
setup.anm_rec,
295+
ligand,
296+
lig_active_restraints,
297+
lig_passive_restraints,
298+
lig_nm,
299+
setup.anm_lig,
300+
setup.use_anm,
301+
) as Box<dyn Score>,
231302
};
232303

233304
// Glowworm Swarm Optimization algorithm
@@ -239,7 +310,7 @@ fn simulate(simulation_path: &str, setup: &SetupFile, swarm_filename: &str, step
239310
setup.use_anm,
240311
setup.anm_rec,
241312
setup.anm_lig,
242-
swarm_directory
313+
swarm_directory,
243314
);
244315

245316
// Simulate for the given steps

Diff for: src/constants.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,4 @@ pub const DEFAULT_NMODES_STEP: f64 = 0.5;
2525

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

0 commit comments

Comments
 (0)