version 1.19 | version 1.20 |
---|
| |
/// -*- c++ -*- | // -*- c++ -*- |
| |
#include "colvarmodule.h" | #include "colvarmodule.h" |
#include "colvar.h" | #include "colvar.h" |
#include "colvarbias_abf.h" | #include "colvarbias_abf.h" |
| |
/// ABF bias constructor; parses the config file | |
| |
colvarbias_abf::colvarbias_abf(std::string const &conf, char const *key) | colvarbias_abf::colvarbias_abf(char const *key) |
: colvarbias(conf, key), | : colvarbias(key), |
| system_force(NULL), |
gradients(NULL), | gradients(NULL), |
samples(NULL) | samples(NULL), |
| z_gradients(NULL), |
| z_samples(NULL), |
| czar_gradients(NULL), |
| last_gradients(NULL), |
| last_samples(NULL) |
{ | { |
| } |
| |
| |
| int colvarbias_abf::init(std::string const &conf) |
| { |
| colvarbias::init(conf); |
| |
| provide(f_cvb_history_dependent); |
| |
// TODO relax this in case of VMD plugin | // TODO relax this in case of VMD plugin |
if (cvm::temperature() == 0.0) | if (cvm::temperature() == 0.0) |
cvm::log("WARNING: ABF should not be run without a thermostat or at 0 Kelvin!\n"); | cvm::log("WARNING: ABF should not be run without a thermostat or at 0 Kelvin!\n"); |
| |
// ************* parsing general ABF options *********************** | // ************* parsing general ABF options *********************** |
| |
get_keyval(conf, "applyBias", apply_bias, true); | get_keyval_feature((colvarparse *)this, conf, "applyBias", f_cvb_apply_force, true); |
if (!apply_bias) cvm::log("WARNING: ABF biases will *not* be applied!\n"); | if (!is_enabled(f_cvb_apply_force)){ |
| cvm::log("WARNING: ABF biases will *not* be applied!\n"); |
| } |
| |
get_keyval(conf, "updateBias", update_bias, true); | get_keyval(conf, "updateBias", update_bias, true); |
if (!update_bias) cvm::log("WARNING: ABF biases will *not* be updated!\n"); | if (update_bias) { |
| enable(f_cvb_history_dependent); |
| } else { |
| cvm::log("WARNING: ABF biases will *not* be updated!\n"); |
| } |
| |
get_keyval(conf, "hideJacobian", hide_Jacobian, false); | get_keyval(conf, "hideJacobian", hide_Jacobian, false); |
if (hide_Jacobian) { | if (hide_Jacobian) { |
| |
cvm::error("Error: no collective variables specified for the ABF bias.\n"); | cvm::error("Error: no collective variables specified for the ABF bias.\n"); |
} | } |
| |
| if (update_bias) { |
| // Request calculation of total force (which also checks for availability) |
| if(enable(f_cvb_get_total_force)) return cvm::get_error(); |
| } |
| |
| bool b_extended = false; |
for (size_t i = 0; i < colvars.size(); i++) { | for (size_t i = 0; i < colvars.size(); i++) { |
| |
if (colvars[i]->value().type() != colvarvalue::type_scalar) { | if (colvars[i]->value().type() != colvarvalue::type_scalar) { |
cvm::error("Error: ABF bias can only use scalar-type variables.\n"); | cvm::error("Error: ABF bias can only use scalar-type variables.\n"); |
} | } |
| colvars[i]->enable(f_cv_grid); |
colvars[i]->enable(colvar::task_gradients); | |
| |
if (update_bias) { | |
// Request calculation of system force (which also checks for availability) | |
colvars[i]->enable(colvar::task_system_force); | |
| |
if (!colvars[i]->tasks[colvar::task_extended_lagrangian]) { | |
// request computation of Jacobian force | |
// ultimately, will be done regardless of extended Lagrangian | |
// and colvar should then just report zero Jacobian force | |
colvars[i]->enable(colvar::task_Jacobian_force); | |
| |
// request Jacobian force as part as system force | |
// except if the user explicitly requires the "silent" Jacobian | |
// correction AND the colvar has a single component | |
if (hide_Jacobian) { | if (hide_Jacobian) { |
if (colvars[i]->n_components() > 1) { | colvars[i]->enable(f_cv_hide_Jacobian); |
cvm::log("WARNING: colvar \"" + colvars[i]->name | |
+ "\" has multiple components; reporting its Jacobian forces\n"); | |
colvars[i]->enable(colvar::task_report_Jacobian_force); | |
} | |
} else { | |
colvars[i]->enable(colvar::task_report_Jacobian_force); | |
} | |
} | |
} | } |
| |
| // If any colvar is extended-system, we need to collect the extended |
| // system gradient |
| if (colvars[i]->is_enabled(f_cv_extended_Lagrangian)) |
| b_extended = true; |
| |
// Here we could check for orthogonality of the Cartesian coordinates | // Here we could check for orthogonality of the Cartesian coordinates |
// and make it just a warning if some parameter is set? | // and make it just a warning if some parameter is set? |
} | } |
| |
| |
bin.assign(colvars.size(), 0); | bin.assign(colvars.size(), 0); |
force_bin.assign(colvars.size(), 0); | force_bin.assign(colvars.size(), 0); |
force = new cvm::real [colvars.size()]; | system_force = new cvm::real [colvars.size()]; |
| |
// Construct empty grids based on the colvars | // Construct empty grids based on the colvars |
if (cvm::debug()) { | if (cvm::debug()) { |
| |
gradients->samples = samples; | gradients->samples = samples; |
samples->has_parent_data = true; | samples->has_parent_data = true; |
| |
| // Data for eABF z-based estimator |
| if (b_extended) { |
| // CZAR output files for stratified eABF |
| get_keyval(conf, "writeCZARwindowFile", b_czar_window_file, false, |
| colvarparse::parse_silent); |
| |
| z_bin.assign(colvars.size(), 0); |
| z_samples = new colvar_grid_count(colvars); |
| z_samples->request_actual_value(); |
| z_gradients = new colvar_grid_gradient(colvars); |
| z_gradients->request_actual_value(); |
| z_gradients->samples = z_samples; |
| z_samples->has_parent_data = true; |
| czar_gradients = new colvar_grid_gradient(colvars); |
| } |
| |
// For shared ABF, we store a second set of grids. | // For shared ABF, we store a second set of grids. |
// This used to be only if "shared" was defined, | // This used to be only if "shared" was defined, |
// but now we allow calling share externally (e.g. from Tcl). | // but now we allow calling share externally (e.g. from Tcl). |
| |
} | } |
| |
cvm::log("Finished ABF setup.\n"); | cvm::log("Finished ABF setup.\n"); |
| |
| return COLVARS_OK; |
} | } |
| |
/// Destructor | /// Destructor |
| |
gradients = NULL; | gradients = NULL; |
} | } |
| |
| if (z_samples) { |
| delete z_samples; |
| z_samples = NULL; |
| } |
| |
| if (z_gradients) { |
| delete z_gradients; |
| z_gradients = NULL; |
| } |
| |
| if (czar_gradients) { |
| delete czar_gradients; |
| czar_gradients = NULL; |
| } |
| |
// shared ABF | // shared ABF |
// We used to only do this if "shared" was defined, | // We used to only do this if "shared" was defined, |
// but now we can call shared externally | // but now we can call shared externally |
| |
last_gradients = NULL; | last_gradients = NULL; |
} | } |
| |
delete [] force; | if (system_force) { |
| delete [] system_force; |
| system_force = NULL; |
| } |
| |
if (cvm::n_abf_biases > 0) | if (cvm::n_abf_biases > 0) |
cvm::n_abf_biases -= 1; | cvm::n_abf_biases -= 1; |
| |
/// Update the FE gradient, compute and apply biasing force | /// Update the FE gradient, compute and apply biasing force |
/// also output data to disk if needed | /// also output data to disk if needed |
| |
cvm::real colvarbias_abf::update() | int colvarbias_abf::update() |
{ | { |
if (cvm::debug()) cvm::log("Updating ABF bias " + this->name); | if (cvm::debug()) cvm::log("Updating ABF bias " + this->name); |
| |
| |
if ( update_bias && samples->index_ok(force_bin) ) { | if ( update_bias && samples->index_ok(force_bin) ) { |
// Only if requested and within bounds of the grid... | // Only if requested and within bounds of the grid... |
| |
for (size_t i=0; i<colvars.size(); i++) { // get forces(lagging by 1 timestep) from colvars | for (size_t i = 0; i < colvars.size(); i++) { |
force[i] = colvars[i]->system_force(); | // get total forces (lagging by 1 timestep) from colvars |
| // and subtract previous ABF force |
| update_system_force(i); |
| } |
| gradients->acc_force(force_bin, system_force); |
| } |
| if ( z_gradients && update_bias ) { |
| for (size_t i = 0; i < colvars.size(); i++) { |
| z_bin[i] = z_samples->current_bin_scalar(i); |
| } |
| if ( z_samples->index_ok(z_bin) ) { |
| for (size_t i = 0; i < colvars.size(); i++) { |
| // If we are outside the range of xi, the force has not been obtained above |
| // the function is just an accessor, so cheap to call again anyway |
| update_system_force(i); |
| } |
| z_gradients->acc_force(z_bin, system_force); |
} | } |
gradients->acc_force(force_bin, force); | |
} | } |
} | } |
| |
| |
} | } |
| |
// Compute and apply the new bias, if applicable | // Compute and apply the new bias, if applicable |
if ( apply_bias && samples->index_ok(bin) ) { | if (is_enabled(f_cvb_apply_force) && samples->index_ok(bin)) { |
| |
size_t count = samples->value(bin); | size_t count = samples->value(bin); |
cvm::real fact = 1.0; | cvm::real fact = 1.0; |
| |
} | } |
| |
if (b_history_files && (cvm::step_absolute() % history_freq) == 0) { | if (b_history_files && (cvm::step_absolute() % history_freq) == 0) { |
cvm::log("ABFHISTORYFILE "+cvm::to_str(cvm::step_absolute())); | |
// file already exists iff cvm::step_relative() > 0 | // file already exists iff cvm::step_relative() > 0 |
// otherwise, backup and replace | // otherwise, backup and replace |
write_gradients_samples(output_prefix + ".hist", (cvm::step_relative() > 0)); | write_gradients_samples(output_prefix + ".hist", (cvm::step_relative() > 0)); |
| |
cvm::log("Prepared sample and gradient buffers at step "+cvm::to_str(cvm::step_absolute())+"."); | cvm::log("Prepared sample and gradient buffers at step "+cvm::to_str(cvm::step_absolute())+"."); |
} | } |
| |
return 0.0; | return COLVARS_OK; |
} | } |
| |
| |
int colvarbias_abf::replica_share() { | int colvarbias_abf::replica_share() { |
int p; | int p; |
| |
| |
pmf_os << std::endl; | pmf_os << std::endl; |
pmf_os.close(); | pmf_os.close(); |
} | } |
| |
| if (z_gradients) { |
| // Write eABF-related quantities |
| |
| std::string z_samples_out_name = prefix + ".zcount"; |
| cvm::ofstream z_samples_os; |
| |
| if (!append) cvm::backup_file(z_samples_out_name.c_str()); |
| z_samples_os.open(z_samples_out_name.c_str(), mode); |
| if (!z_samples_os.is_open()) { |
| cvm::error("Error opening eABF z-histogram file " + z_samples_out_name + " for writing"); |
| } |
| z_samples->write_multicol(z_samples_os); |
| z_samples_os.close(); |
| |
| if (b_czar_window_file) { |
| std::string z_gradients_out_name = prefix + ".zgrad"; |
| cvm::ofstream z_gradients_os; |
| |
| if (!append) cvm::backup_file(z_gradients_out_name.c_str()); |
| z_gradients_os.open(z_gradients_out_name.c_str(), mode); |
| if (!z_gradients_os.is_open()) { |
| cvm::error("Error opening eABF z-gradient file " + z_gradients_out_name + " for writing"); |
| } |
| z_gradients->write_multicol(z_gradients_os); |
| z_gradients_os.close(); |
| } |
| |
| // Calculate CZAR estimator of gradients |
| for (std::vector<int> ix = czar_gradients->new_index(); |
| czar_gradients->index_ok(ix); czar_gradients->incr(ix)) { |
| for (size_t n = 0; n < czar_gradients->multiplicity(); n++) { |
| czar_gradients->set_value(ix, z_gradients->value_output(ix, n) |
| - cvm::temperature() * cvm::boltzmann() * z_samples->log_gradient_finite_diff(ix, n), |
| n); |
| } |
| } |
| |
| std::string czar_gradients_out_name = prefix + ".czar.grad"; |
| cvm::ofstream czar_gradients_os; |
| |
| if (!append) cvm::backup_file(czar_gradients_out_name.c_str()); |
| czar_gradients_os.open(czar_gradients_out_name.c_str(), mode); |
| if (!czar_gradients_os.is_open()) { |
| cvm::error("Error opening CZAR gradient file " + czar_gradients_out_name + " for writing"); |
| } |
| czar_gradients->write_multicol(czar_gradients_os); |
| czar_gradients_os.close(); |
| |
| if (colvars.size() == 1) { |
| std::string czar_pmf_out_name = prefix + ".czar.pmf"; |
| if (!append) cvm::backup_file(czar_pmf_out_name.c_str()); |
| cvm::ofstream czar_pmf_os; |
| // Do numerical integration and output a PMF |
| czar_pmf_os.open(czar_pmf_out_name.c_str(), mode); |
| if (!czar_pmf_os.is_open()) cvm::error("Error opening CZAR pmf file " + czar_pmf_out_name + " for writing"); |
| czar_gradients->write_1D_integral(czar_pmf_os); |
| czar_pmf_os << std::endl; |
| czar_pmf_os.close(); |
| } |
| } |
return; | return; |
} | } |
| |
| |
| |
void colvarbias_abf::read_gradients_samples() | void colvarbias_abf::read_gradients_samples() |
{ | { |
std::string samples_in_name, gradients_in_name; | std::string samples_in_name, gradients_in_name, z_samples_in_name, z_gradients_in_name; |
| |
for ( size_t i = 0; i < input_prefix.size(); i++ ) { | for ( size_t i = 0; i < input_prefix.size(); i++ ) { |
samples_in_name = input_prefix[i] + ".count"; | samples_in_name = input_prefix[i] + ".count"; |
gradients_in_name = input_prefix[i] + ".grad"; | gradients_in_name = input_prefix[i] + ".grad"; |
| z_samples_in_name = input_prefix[i] + ".zcount"; |
| z_gradients_in_name = input_prefix[i] + ".zgrad"; |
// For user-provided files, the per-bias naming scheme may not apply | // For user-provided files, the per-bias naming scheme may not apply |
| |
std::ifstream is; | std::ifstream is; |
| |
cvm::log("Reading sample count from " + samples_in_name + " and gradients from " + gradients_in_name); | cvm::log("Reading sample count from " + samples_in_name + " and gradient from " + gradients_in_name); |
is.open(samples_in_name.c_str()); | is.open(samples_in_name.c_str()); |
if (!is.is_open()) cvm::error("Error opening ABF samples file " + samples_in_name + " for reading"); | if (!is.is_open()) cvm::error("Error opening ABF samples file " + samples_in_name + " for reading"); |
samples->read_multicol(is, true); | samples->read_multicol(is, true); |
| |
if (!is.is_open()) cvm::error("Error opening ABF gradient file " + gradients_in_name + " for reading"); | if (!is.is_open()) cvm::error("Error opening ABF gradient file " + gradients_in_name + " for reading"); |
gradients->read_multicol(is, true); | gradients->read_multicol(is, true); |
is.close(); | is.close(); |
| |
| if (z_gradients) { |
| // Read eABF z-averaged data for CZAR |
| cvm::log("Reading z-histogram from " + z_samples_in_name + " and z-gradient from " + z_gradients_in_name); |
| |
| is.clear(); |
| is.open(z_samples_in_name.c_str()); |
| if (!is.is_open()) cvm::error("Error opening eABF z-histogram file " + z_samples_in_name + " for reading"); |
| z_samples->read_multicol(is, true); |
| is.close(); |
| is.clear(); |
| |
| is.open(z_gradients_in_name.c_str()); |
| if (!is.is_open()) cvm::error("Error opening eABF z-gradient file " + z_gradients_in_name + " for reading"); |
| z_gradients->read_multicol(is, true); |
| is.close(); |
| } |
} | } |
return; | return; |
} | } |
| |
{ | { |
| |
std::ios::fmtflags flags(os.flags()); | std::ios::fmtflags flags(os.flags()); |
os.setf(std::ios::fmtflags(0), std::ios::floatfield); // default floating-point format | |
| |
os << "abf {\n" | os << "abf {\n" |
<< " configuration {\n" | << " configuration {\n" |
<< " name " << this->name << "\n"; | << " name " << this->name << "\n"; |
os << " }\n"; | os << " }\n"; |
| |
os << "samples\n"; | os.setf(std::ios::fmtflags(0), std::ios::floatfield); // default floating-point format |
| os << "\nsamples\n"; |
samples->write_raw(os, 8); | samples->write_raw(os, 8); |
| os.flags(flags); |
| |
os << "\ngradient\n"; | os << "\ngradient\n"; |
gradients->write_raw(os); | gradients->write_raw(os, 8); |
| |
| if (z_gradients) { |
| os.setf(std::ios::fmtflags(0), std::ios::floatfield); // default floating-point format |
| os << "\nz_samples\n"; |
| z_samples->write_raw(os, 8); |
| os.flags(flags); |
| os << "\nz_gradient\n"; |
| z_gradients->write_raw(os, 8); |
| } |
| |
os << "}\n\n"; | os << "}\n\n"; |
| |
| |
std::istream & colvarbias_abf::read_restart(std::istream& is) | std::istream & colvarbias_abf::read_restart(std::istream& is) |
{ | { |
if ( input_prefix.size() > 0 ) { | if ( input_prefix.size() > 0 ) { |
cvm::error("ERROR: cannot provide both inputPrefix and restart information(colvarsInput)"); | cvm::error("ERROR: cannot provide both inputPrefix and a colvars state file.\n", INPUT_ERROR); |
} | } |
| |
size_t const start_pos = is.tellg(); | size_t const start_pos = is.tellg(); |
| |
return is; | return is; |
} | } |
| |
| if (z_gradients) { |
| if ( !(is >> key) || !(key == "z_samples")) { |
| cvm::log("Error: in reading restart configuration for ABF bias \""+ |
| this->name+"\" at position "+ |
| cvm::to_str(is.tellg())+" in stream.\n"); |
| is.clear(); |
| is.seekg(start_pos, std::ios::beg); |
| is.setstate(std::ios::failbit); |
| return is; |
| } |
| if (! z_samples->read_raw(is)) { |
| is.clear(); |
| is.seekg(start_pos, std::ios::beg); |
| is.setstate(std::ios::failbit); |
| return is; |
| } |
| |
| if ( !(is >> key) || !(key == "z_gradient")) { |
| cvm::log("Error: in reading restart configuration for ABF bias \""+ |
| this->name+"\" at position "+ |
| cvm::to_str(is.tellg())+" in stream.\n"); |
| is.clear(); |
| is.seekg(start_pos, std::ios::beg); |
| is.setstate(std::ios::failbit); |
| return is; |
| } |
| if (! z_gradients->read_raw(is)) { |
| is.clear(); |
| is.seekg(start_pos, std::ios::beg); |
| is.setstate(std::ios::failbit); |
| return is; |
| } |
| } |
is >> brace; | is >> brace; |
if (brace != "}") { | if (brace != "}") { |
cvm::error("Error: corrupt restart information for ABF bias \""+ | cvm::error("Error: corrupt restart information for ABF bias \""+ |