forked from lightdock/lightdock-rust
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlightdock-rust.rs
222 lines (200 loc) · 7.88 KB
/
lightdock-rust.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
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
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
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::dfire::DFIRE;
use lightdock::dna::DNA;
use lightdock::pydock::PYDOCK;
use std::env;
use std::fs;
use serde::{Serialize, Deserialize};
use std::error::Error;
use std::fs::File;
use std::io::{Read, 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,
now: bool,
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>>>,
}
fn read_setup_from_file<P: AsRef<Path>>(path: P) -> Result<SetupFile, Box<dyn Error>> {
// Open the file in read-only mode with buffer.
let file = File::open(path)?;
let reader = BufReader::new(file);
// Read the JSON contents of the file as an instance of `SetupFile`.
let u = serde_json::from_reader(reader)?;
// Return the `SetupFile`.
Ok(u)
}
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 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() {
position.push(pos.trim().parse::<f64>().unwrap());
}
positions.push(position);
}
positions
}
fn main() {
// Spawn thread with explicit stack size
let child = thread::Builder::new()
.stack_size(STACK_SIZE)
.spawn(run)
.unwrap();
// Wait for thread to join
child.join().unwrap();
}
fn run() {
env_logger::init();
// Parse command line
let args: Vec<String> = env::args().collect();
match args.len() {
5 => {
let setup_filename = &args[1];
let swarm_filename = &args[2];
let num_steps = &args[3];
// parse the number
let steps: u32 = match num_steps.parse() {
Ok(n) => {
n
},
Err(_) => {
eprintln!("Error: steps argument must be a number");
return;
},
};
let method_type = &args[4].to_lowercase();
// parse the type
let method = match &method_type[..] {
"dfire" => Method::DFIRE,
"dna" => Method::DNA,
"pydock" => Method::PYDOCK,
_ => {
eprintln!("Error: method not supported");
return;
},
};
// Load setup
let setup = read_setup_from_file(setup_filename).unwrap();
// Simulation path
let simulation_path = Path::new(setup_filename).parent().unwrap();
simulate(simulation_path.to_str().unwrap(), &setup, swarm_filename, steps, method);
}
_ => {
println!("Wrong command line. Usage: {} setup_filename swarm_filename steps method", args[0]);
}
}
}
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);
let positions = parse_input_coordinates(swarm_filename);
let receptor_filename = if simulation_path == "" {
format!("{}{}", DEFAULT_LIGHTDOCK_PREFIX, setup.receptor_pdb)
} else {
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 ligand_filename = if simulation_path == "" {
format!("{}{}", DEFAULT_LIGHTDOCK_PREFIX, setup.ligand_pdb)
} else {
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();
// 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();
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();
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");
}
}
}
// Restraints
let rec_active_restraints: Vec<String> = match &setup.receptor_restraints {
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() },
};
let lig_active_restraints: Vec<String> = match &setup.ligand_restraints {
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() },
};
// 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>,
};
// Glowworm Swarm Optimization algorithm
println!("Creating GSO with {} glowworms", positions.len());
let mut gso = GSO::new(&positions, seed, &scoring, setup.use_anm, setup.anm_rec, setup.anm_lig);
// Simulate for the given steps
println!("Starting optimization ({} steps)", steps);
gso.run(steps);
}