|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include "boinc_wrapper.h"
|
|
|
#include <iostream>
|
|
|
#include <fstream>
|
|
|
#include <sstream>
|
|
|
#include <chrono>
|
|
|
#include <ctime>
|
|
|
#include <random>
|
|
|
#include <iomanip>
|
|
|
|
|
|
namespace docking_at_home {
|
|
|
namespace boinc {
|
|
|
|
|
|
|
|
|
|
|
|
BOINCWrapper::BOINCWrapper()
|
|
|
: is_initialized_(false), app_name_("DockingAtHOME"), worker_id_("") {
|
|
|
}
|
|
|
|
|
|
BOINCWrapper::~BOINCWrapper() {
|
|
|
if (is_initialized_) {
|
|
|
finalize();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
bool BOINCWrapper::initialize() {
|
|
|
int retval = boinc_init();
|
|
|
if (retval) {
|
|
|
std::cerr << "BOINC initialization failed: " << boincerror(retval) << std::endl;
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
|
|
|
std::random_device rd;
|
|
|
std::mt19937 gen(rd());
|
|
|
std::uniform_int_distribution<> dis(100000, 999999);
|
|
|
worker_id_ = "WORKER_" + std::to_string(dis(gen));
|
|
|
|
|
|
is_initialized_ = true;
|
|
|
std::cout << "BOINC initialized successfully. Worker ID: " << worker_id_ << std::endl;
|
|
|
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
bool BOINCWrapper::register_application(const std::string& app_name, const std::string& version) {
|
|
|
if (!is_initialized_) {
|
|
|
std::cerr << "BOINC not initialized" << std::endl;
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
app_name_ = app_name;
|
|
|
std::cout << "Registered application: " << app_name << " v" << version << std::endl;
|
|
|
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
std::string BOINCWrapper::submit_task(const DockingTask& task) {
|
|
|
if (!is_initialized_) {
|
|
|
std::cerr << "BOINC not initialized" << std::endl;
|
|
|
return "";
|
|
|
}
|
|
|
|
|
|
if (!validate_task(task)) {
|
|
|
std::cerr << "Invalid task" << std::endl;
|
|
|
return "";
|
|
|
}
|
|
|
|
|
|
std::string task_id = generate_task_id();
|
|
|
|
|
|
|
|
|
if (!upload_input_files(task)) {
|
|
|
std::cerr << "Failed to upload input files" << std::endl;
|
|
|
return "";
|
|
|
}
|
|
|
|
|
|
std::cout << "Task submitted successfully: " << task_id << std::endl;
|
|
|
|
|
|
return task_id;
|
|
|
}
|
|
|
|
|
|
bool BOINCWrapper::process_task(const DockingTask& task, DockingResult& result) {
|
|
|
if (!is_initialized_) {
|
|
|
std::cerr << "BOINC not initialized" << std::endl;
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
auto start_time = std::chrono::high_resolution_clock::now();
|
|
|
|
|
|
std::cout << "Processing task: " << task.task_id << std::endl;
|
|
|
std::cout << "Ligand: " << task.ligand_file << std::endl;
|
|
|
std::cout << "Receptor: " << task.receptor_file << std::endl;
|
|
|
std::cout << "GPU enabled: " << (task.use_gpu ? "Yes" : "No") << std::endl;
|
|
|
|
|
|
|
|
|
result.task_id = task.task_id;
|
|
|
result.worker_id = worker_id_;
|
|
|
result.successful_runs = 0;
|
|
|
|
|
|
|
|
|
for (int i = 0; i < task.num_runs; ++i) {
|
|
|
|
|
|
double progress = static_cast<double>(i) / task.num_runs;
|
|
|
update_progress(progress);
|
|
|
|
|
|
|
|
|
if (i > 0 && i % 10 == 0) {
|
|
|
std::string checkpoint_file = task.output_dir + "/checkpoint_" + std::to_string(i);
|
|
|
create_checkpoint(checkpoint_file);
|
|
|
}
|
|
|
|
|
|
|
|
|
boinc_sleep(0.1);
|
|
|
|
|
|
result.successful_runs++;
|
|
|
}
|
|
|
|
|
|
|
|
|
auto end_time = std::chrono::high_resolution_clock::now();
|
|
|
std::chrono::duration<double> elapsed = end_time - start_time;
|
|
|
result.computation_time = elapsed.count();
|
|
|
|
|
|
|
|
|
update_progress(1.0);
|
|
|
report_cpu_time(result.computation_time);
|
|
|
|
|
|
std::cout << "Task completed: " << task.task_id << std::endl;
|
|
|
std::cout << "Computation time: " << result.computation_time << " seconds" << std::endl;
|
|
|
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
double BOINCWrapper::get_task_progress(const std::string& task_id) {
|
|
|
|
|
|
|
|
|
return 0.0;
|
|
|
}
|
|
|
|
|
|
bool BOINCWrapper::get_task_results(const std::string& task_id, DockingResult& result) {
|
|
|
if (!is_initialized_) {
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
|
|
|
return download_output_files(task_id);
|
|
|
}
|
|
|
|
|
|
void BOINCWrapper::update_progress(double fraction_done) {
|
|
|
boinc_fraction_done(fraction_done);
|
|
|
}
|
|
|
|
|
|
void BOINCWrapper::report_cpu_time(double cpu_time) {
|
|
|
boinc_report_app_status(cpu_time, 0, 0);
|
|
|
}
|
|
|
|
|
|
bool BOINCWrapper::create_checkpoint(const std::string& checkpoint_file) {
|
|
|
std::ofstream ckpt(checkpoint_file, std::ios::binary);
|
|
|
if (!ckpt.is_open()) {
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ckpt << "CHECKPOINT_V1" << std::endl;
|
|
|
ckpt << worker_id_ << std::endl;
|
|
|
|
|
|
ckpt.close();
|
|
|
|
|
|
boinc_checkpoint_completed();
|
|
|
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
bool BOINCWrapper::restore_checkpoint(const std::string& checkpoint_file) {
|
|
|
std::ifstream ckpt(checkpoint_file, std::ios::binary);
|
|
|
if (!ckpt.is_open()) {
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
|
|
|
std::string version, worker;
|
|
|
std::getline(ckpt, version);
|
|
|
std::getline(ckpt, worker);
|
|
|
|
|
|
ckpt.close();
|
|
|
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
void BOINCWrapper::finalize() {
|
|
|
if (is_initialized_) {
|
|
|
boinc_finish(0);
|
|
|
is_initialized_ = false;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
bool BOINCWrapper::validate_task(const DockingTask& task) {
|
|
|
if (task.ligand_file.empty() || task.receptor_file.empty()) {
|
|
|
return false;
|
|
|
}
|
|
|
if (task.num_runs <= 0 || task.num_evals <= 0) {
|
|
|
return false;
|
|
|
}
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
std::string BOINCWrapper::generate_task_id() {
|
|
|
auto now = std::chrono::system_clock::now();
|
|
|
auto now_time_t = std::chrono::system_clock::to_time_t(now);
|
|
|
auto now_ms = std::chrono::duration_cast<std::chrono::milliseconds>(
|
|
|
now.time_since_epoch()) % 1000;
|
|
|
|
|
|
std::stringstream ss;
|
|
|
ss << "TASK_"
|
|
|
<< std::put_time(std::localtime(&now_time_t), "%Y%m%d_%H%M%S")
|
|
|
<< "_" << now_ms.count();
|
|
|
|
|
|
return ss.str();
|
|
|
}
|
|
|
|
|
|
bool BOINCWrapper::upload_input_files(const DockingTask& task) {
|
|
|
|
|
|
|
|
|
std::cout << "Uploading input files for task: " << task.task_id << std::endl;
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
bool BOINCWrapper::download_output_files(const std::string& task_id) {
|
|
|
|
|
|
|
|
|
std::cout << "Downloading output files for task: " << task_id << std::endl;
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
BOINCServer::BOINCServer()
|
|
|
: is_initialized_(false), active_work_units_(0), completed_work_units_(0) {
|
|
|
}
|
|
|
|
|
|
BOINCServer::~BOINCServer() {
|
|
|
}
|
|
|
|
|
|
bool BOINCServer::initialize(const std::string& config_file) {
|
|
|
std::cout << "Initializing BOINC server with config: " << config_file << std::endl;
|
|
|
|
|
|
|
|
|
|
|
|
db_host_ = "localhost";
|
|
|
db_name_ = "docking_at_home";
|
|
|
|
|
|
is_initialized_ = true;
|
|
|
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
int BOINCServer::create_work_units(const std::vector<DockingTask>& tasks) {
|
|
|
if (!is_initialized_) {
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
int created = 0;
|
|
|
for (const auto& task : tasks) {
|
|
|
|
|
|
|
|
|
std::cout << "Creating work unit for task: " << task.task_id << std::endl;
|
|
|
created++;
|
|
|
active_work_units_++;
|
|
|
}
|
|
|
|
|
|
return created;
|
|
|
}
|
|
|
|
|
|
bool BOINCServer::process_result(const std::string& result_file) {
|
|
|
if (!is_initialized_) {
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
std::cout << "Processing result file: " << result_file << std::endl;
|
|
|
|
|
|
|
|
|
active_work_units_--;
|
|
|
completed_work_units_++;
|
|
|
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
std::string BOINCServer::get_statistics() {
|
|
|
std::stringstream ss;
|
|
|
ss << "{"
|
|
|
<< "\"active_work_units\": " << active_work_units_ << ", "
|
|
|
<< "\"completed_work_units\": " << completed_work_units_
|
|
|
<< "}";
|
|
|
|
|
|
return ss.str();
|
|
|
}
|
|
|
|
|
|
}
|
|
|
}
|
|
|
|