Update Colvars to version 2020-07-07
This update contains several fixes and small new features or usability improvements. Descriptions and authorship information can be accessed from the pull requests listed below. Skip the zero-step also when multiple run commands are executed in sequence (@giacomofiorin) https://github.com/Colvars/colvars/pull/357 Do not accumulate data at step 0 (@giacomofiorin) https://github.com/Colvars/colvars/pull/345 Support for symmetry permutations of atoms in RMSD (@jhenin) https://github.com/Colvars/colvars/pull/344 Detect new grid parameters (@jhenin) https://github.com/Colvars/colvars/pull/341 Only access the output streams in non-threaded regions (@giacomofiorin) https://github.com/Colvars/colvars/pull/338 Fix incomplete setting of default colvarsRestartFrequency (@giacomofiorin) https://github.com/Colvars/colvars/pull/334 Fix typo (@e-kwsm) https://github.com/Colvars/colvars/pull/333 Convert the input keyword to lowercase in read_state_data_key (@HanatoK) https://github.com/Colvars/colvars/pull/332 Implement reflecting b.c. for ext Lagrangian (@jhenin) https://github.com/Colvars/colvars/pull/329
This commit is contained in:
@ -8,7 +8,6 @@
|
||||
// Colvars repository at GitHub.
|
||||
|
||||
#include "colvarmodule.h"
|
||||
#include "colvarproxy.h"
|
||||
#include "colvar.h"
|
||||
#include "colvarbias_abf.h"
|
||||
|
||||
@ -29,8 +28,14 @@ colvarbias_abf::colvarbias_abf(char const *key)
|
||||
last_gradients(NULL),
|
||||
last_samples(NULL)
|
||||
{
|
||||
colvarproxy *proxy = cvm::main()->proxy;
|
||||
if (!proxy->total_forces_same_step()) {
|
||||
// Samples at step zero can not be collected
|
||||
feature_states[f_cvb_step_zero_data].available = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int colvarbias_abf::init(std::string const &conf)
|
||||
{
|
||||
colvarbias::init(conf);
|
||||
@ -71,8 +76,19 @@ int colvarbias_abf::init(std::string const &conf)
|
||||
// full_samples - min_samples >= 1 is guaranteed
|
||||
|
||||
get_keyval(conf, "inputPrefix", input_prefix, std::vector<std::string>());
|
||||
get_keyval(conf, "outputFreq", output_freq, cvm::restart_out_freq);
|
||||
|
||||
get_keyval(conf, "historyFreq", history_freq, 0);
|
||||
if (history_freq != 0) {
|
||||
if (output_freq == 0) {
|
||||
cvm::error("Error: historyFreq must be a multiple of outputFreq.\n",
|
||||
INPUT_ERROR);
|
||||
} else {
|
||||
if ((history_freq % output_freq) != 0) {
|
||||
cvm::error("Error: historyFreq must be a multiple of outputFreq.\n",
|
||||
INPUT_ERROR);
|
||||
}
|
||||
}
|
||||
}
|
||||
b_history_files = (history_freq > 0);
|
||||
|
||||
// shared ABF
|
||||
@ -146,6 +162,7 @@ int colvarbias_abf::init(std::string const &conf)
|
||||
for (i = 0; i < num_variables(); i++) {
|
||||
if (max_force[i] < 0.0) {
|
||||
cvm::error("Error: maxForce should be non-negative.");
|
||||
return COLVARS_ERROR;
|
||||
}
|
||||
}
|
||||
cap_force = true;
|
||||
@ -184,25 +201,24 @@ int colvarbias_abf::init(std::string const &conf)
|
||||
czar_gradients = new colvar_grid_gradient(colvars);
|
||||
}
|
||||
|
||||
// For now, we integrate on-the-fly iff the grid is < 3D
|
||||
if ( num_variables() <= 3 ) {
|
||||
get_keyval(conf, "integrate", b_integrate, num_variables() <= 3); // Integrate for output if d<=3
|
||||
if (b_integrate) {
|
||||
// For now, we integrate on-the-fly iff the grid is < 3D
|
||||
if ( num_variables() > 3 ) {
|
||||
cvm::error("Error: cannot integrate free energy in dimension > 3.\n");
|
||||
return COLVARS_ERROR;
|
||||
}
|
||||
pmf = new integrate_potential(colvars, gradients);
|
||||
if ( b_CZAR_estimator ) {
|
||||
czar_pmf = new integrate_potential(colvars, czar_gradients);
|
||||
}
|
||||
get_keyval(conf, "integrate", b_integrate, true); // Integrate for output
|
||||
if ( num_variables() > 1 ) {
|
||||
// Projected ABF
|
||||
get_keyval(conf, "pABFintegrateFreq", pabf_freq, 0);
|
||||
// Parameters for integrating initial (and final) gradient data
|
||||
get_keyval(conf, "integrateInitMaxIterations", integrate_initial_iterations, 1e4);
|
||||
get_keyval(conf, "integrateInitTol", integrate_initial_tol, 1e-6);
|
||||
// for updating the integrated PMF on the fly
|
||||
get_keyval(conf, "integrateMaxIterations", integrate_iterations, 100);
|
||||
get_keyval(conf, "integrateTol", integrate_tol, 1e-4);
|
||||
}
|
||||
} else {
|
||||
b_integrate = false;
|
||||
// Parameters for integrating initial (and final) gradient data
|
||||
get_keyval(conf, "integrateMaxIterations", integrate_iterations, 1e4, colvarparse::parse_silent);
|
||||
get_keyval(conf, "integrateTol", integrate_tol, 1e-6, colvarparse::parse_silent);
|
||||
// Projected ABF, updating the integrated PMF on the fly
|
||||
get_keyval(conf, "pABFintegrateFreq", pabf_freq, 0, colvarparse::parse_silent);
|
||||
get_keyval(conf, "pABFintegrateMaxIterations", pabf_integrate_iterations, 100, colvarparse::parse_silent);
|
||||
get_keyval(conf, "pABFintegrateTol", pabf_integrate_tol, 1e-4, colvarparse::parse_silent);
|
||||
}
|
||||
|
||||
// For shared ABF, we store a second set of grids.
|
||||
@ -330,7 +346,7 @@ int colvarbias_abf::update()
|
||||
force_bin = bin;
|
||||
}
|
||||
|
||||
if (cvm::step_relative() > 0 || cvm::proxy->total_forces_same_step()) {
|
||||
if (cvm::step_relative() > 0 || is_enabled(f_cvb_step_zero_data)) {
|
||||
|
||||
if (update_bias) {
|
||||
// if (b_adiabatic_reweighting) {
|
||||
@ -346,10 +362,10 @@ int colvarbias_abf::update()
|
||||
// and subtract previous ABF force if necessary
|
||||
update_system_force(i);
|
||||
}
|
||||
gradients->acc_force(force_bin, system_force);
|
||||
if ( b_integrate ) {
|
||||
pmf->update_div_neighbors(force_bin);
|
||||
}
|
||||
gradients->acc_force(force_bin, system_force);
|
||||
if ( b_integrate ) {
|
||||
pmf->update_div_neighbors(force_bin);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -370,10 +386,10 @@ int colvarbias_abf::update()
|
||||
if ( b_integrate ) {
|
||||
if ( pabf_freq && cvm::step_relative() % pabf_freq == 0 ) {
|
||||
cvm::real err;
|
||||
int iter = pmf->integrate(integrate_iterations, integrate_tol, err);
|
||||
if ( iter == integrate_iterations ) {
|
||||
cvm::log("Warning: PMF integration did not converge to " + cvm::to_str(integrate_tol)
|
||||
+ " in " + cvm::to_str(integrate_iterations)
|
||||
int iter = pmf->integrate(pabf_integrate_iterations, pabf_integrate_tol, err);
|
||||
if ( iter == pabf_integrate_iterations ) {
|
||||
cvm::log("Warning: PMF integration did not converge to " + cvm::to_str(pabf_integrate_tol)
|
||||
+ " in " + cvm::to_str(pabf_integrate_iterations)
|
||||
+ " steps. Residual error: " + cvm::to_str(err));
|
||||
}
|
||||
pmf->set_zero_minimum(); // TODO: do this only when necessary
|
||||
@ -448,17 +464,6 @@ int colvarbias_abf::update()
|
||||
output_prefix = cvm::output_prefix() + "." + this->name;
|
||||
}
|
||||
|
||||
if (output_freq && (cvm::step_absolute() % output_freq) == 0) {
|
||||
if (cvm::debug()) cvm::log("ABF bias trying to write gradients and samples to disk");
|
||||
write_gradients_samples(output_prefix);
|
||||
}
|
||||
|
||||
if (b_history_files && (cvm::step_absolute() % history_freq) == 0) {
|
||||
// file already exists iff cvm::step_relative() > 0
|
||||
// otherwise, backup and replace
|
||||
write_gradients_samples(output_prefix + ".hist", (cvm::step_relative() > 0));
|
||||
}
|
||||
|
||||
if (shared_on && shared_last_step >= 0 && cvm::step_absolute() % shared_freq == 0) {
|
||||
// Share gradients and samples for shared ABF.
|
||||
replica_share();
|
||||
@ -487,10 +492,10 @@ int colvarbias_abf::update()
|
||||
eabf_UI.update(cvm::step_absolute(), x, y);
|
||||
}
|
||||
|
||||
/// Add the bias energy for 1D ABF
|
||||
bias_energy = calc_energy(NULL);
|
||||
/// Compute the bias energy
|
||||
int error_code = calc_energy(NULL);
|
||||
|
||||
return COLVARS_OK;
|
||||
return error_code;
|
||||
}
|
||||
|
||||
|
||||
@ -570,83 +575,71 @@ int colvarbias_abf::replica_share() {
|
||||
last_samples->copy_grid(*samples);
|
||||
shared_last_step = cvm::step_absolute();
|
||||
|
||||
if (b_integrate) {
|
||||
// Update divergence to account for newly shared gradients
|
||||
pmf->set_div();
|
||||
}
|
||||
return COLVARS_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void colvarbias_abf::write_gradients_samples(const std::string &prefix, bool append)
|
||||
{
|
||||
std::string samples_out_name = prefix + ".count";
|
||||
std::string gradients_out_name = prefix + ".grad";
|
||||
std::ios::openmode mode = (append ? std::ios::app : std::ios::out);
|
||||
|
||||
std::ostream *samples_os =
|
||||
cvm::proxy->output_stream(samples_out_name, mode);
|
||||
if (!samples_os) return;
|
||||
samples->write_multicol(*samples_os);
|
||||
cvm::proxy->close_output_stream(samples_out_name);
|
||||
|
||||
// In dimension higher than 2, dx is easier to handle and visualize
|
||||
if (num_variables() > 2) {
|
||||
std::string samples_dx_out_name = prefix + ".count.dx";
|
||||
std::ostream *samples_dx_os = cvm::proxy->output_stream(samples_dx_out_name, mode);
|
||||
if (!samples_os) return;
|
||||
samples->write_opendx(*samples_dx_os);
|
||||
*samples_dx_os << std::endl;
|
||||
cvm::proxy->close_output_stream(samples_dx_out_name);
|
||||
template <class T> int colvarbias_abf::write_grid_to_file(T const *grid,
|
||||
std::string const &filename,
|
||||
bool close) {
|
||||
std::ostream *os = cvm::proxy->output_stream(filename);
|
||||
if (!os) {
|
||||
return cvm::error("Error opening file " + filename + " for writing.\n", COLVARS_ERROR | FILE_ERROR);
|
||||
}
|
||||
grid->write_multicol(*os);
|
||||
if (close) {
|
||||
cvm::proxy->close_output_stream(filename);
|
||||
} else {
|
||||
// Insert empty line between frames in history files
|
||||
*os << std::endl;
|
||||
cvm::proxy->flush_output_stream(os);
|
||||
}
|
||||
|
||||
std::ostream *gradients_os =
|
||||
cvm::proxy->output_stream(gradients_out_name, mode);
|
||||
if (!gradients_os) return;
|
||||
gradients->write_multicol(*gradients_os);
|
||||
cvm::proxy->close_output_stream(gradients_out_name);
|
||||
// In dimension higher than 2, dx is easier to handle and visualize
|
||||
// but we cannot write multiple frames in a dx file now
|
||||
// (could be implemented as multiple dx files)
|
||||
if (num_variables() > 2 && close) {
|
||||
std::string dx = filename + ".dx";
|
||||
std::ostream *dx_os = cvm::proxy->output_stream(dx);
|
||||
if (!dx_os) {
|
||||
return cvm::error("Error opening file " + dx + " for writing.\n", COLVARS_ERROR | FILE_ERROR);
|
||||
}
|
||||
grid->write_opendx(*dx_os);
|
||||
// if (close) {
|
||||
cvm::proxy->close_output_stream(dx);
|
||||
// }
|
||||
// else {
|
||||
// // TODO, decide convention for multiple datasets in dx file
|
||||
// *dx_os << std::endl;
|
||||
// dx_os->flush();
|
||||
// }
|
||||
}
|
||||
return COLVARS_OK;
|
||||
}
|
||||
|
||||
|
||||
void colvarbias_abf::write_gradients_samples(const std::string &prefix, bool close)
|
||||
{
|
||||
write_grid_to_file<colvar_grid_count>(samples, prefix + ".count", close);
|
||||
write_grid_to_file<colvar_grid_gradient>(gradients, prefix + ".grad", close);
|
||||
|
||||
if (b_integrate) {
|
||||
// Do numerical integration (to high precision) and output a PMF
|
||||
cvm::real err;
|
||||
pmf->integrate(integrate_initial_iterations, integrate_initial_tol, err);
|
||||
pmf->integrate(integrate_iterations, integrate_tol, err);
|
||||
pmf->set_zero_minimum();
|
||||
|
||||
std::string pmf_out_name = prefix + ".pmf";
|
||||
std::ostream *pmf_os = cvm::proxy->output_stream(pmf_out_name, mode);
|
||||
if (!pmf_os) return;
|
||||
pmf->write_multicol(*pmf_os);
|
||||
|
||||
// In dimension higher than 2, dx is easier to handle and visualize
|
||||
if (num_variables() > 2) {
|
||||
std::string pmf_dx_out_name = prefix + ".pmf.dx";
|
||||
std::ostream *pmf_dx_os = cvm::proxy->output_stream(pmf_dx_out_name, mode);
|
||||
if (!pmf_dx_os) return;
|
||||
pmf->write_opendx(*pmf_dx_os);
|
||||
*pmf_dx_os << std::endl;
|
||||
cvm::proxy->close_output_stream(pmf_dx_out_name);
|
||||
}
|
||||
|
||||
*pmf_os << std::endl;
|
||||
cvm::proxy->close_output_stream(pmf_out_name);
|
||||
write_grid_to_file<colvar_grid_scalar>(pmf, prefix + ".pmf", close);
|
||||
}
|
||||
|
||||
if (b_CZAR_estimator) {
|
||||
// Write eABF CZAR-related quantities
|
||||
|
||||
std::string z_samples_out_name = prefix + ".zcount";
|
||||
|
||||
std::ostream *z_samples_os =
|
||||
cvm::proxy->output_stream(z_samples_out_name, mode);
|
||||
if (!z_samples_os) return;
|
||||
z_samples->write_multicol(*z_samples_os);
|
||||
cvm::proxy->close_output_stream(z_samples_out_name);
|
||||
|
||||
write_grid_to_file<colvar_grid_count>(z_samples, prefix + ".zcount", close);
|
||||
if (b_czar_window_file) {
|
||||
std::string z_gradients_out_name = prefix + ".zgrad";
|
||||
|
||||
std::ostream *z_gradients_os =
|
||||
cvm::proxy->output_stream(z_gradients_out_name, mode);
|
||||
if (!z_gradients_os) return;
|
||||
z_gradients->write_multicol(*z_gradients_os);
|
||||
cvm::proxy->close_output_stream(z_gradients_out_name);
|
||||
write_grid_to_file<colvar_grid_gradient>(z_gradients, prefix + ".zgrad", close);
|
||||
}
|
||||
|
||||
// Calculate CZAR estimator of gradients
|
||||
@ -657,39 +650,15 @@ void colvarbias_abf::write_gradients_samples(const std::string &prefix, bool app
|
||||
- cvm::temperature() * cvm::boltzmann() * z_samples->log_gradient_finite_diff(ix, n), n);
|
||||
}
|
||||
}
|
||||
|
||||
std::string czar_gradients_out_name = prefix + ".czar.grad";
|
||||
|
||||
std::ostream *czar_gradients_os =
|
||||
cvm::proxy->output_stream(czar_gradients_out_name, mode);
|
||||
if (!czar_gradients_os) return;
|
||||
czar_gradients->write_multicol(*czar_gradients_os);
|
||||
cvm::proxy->close_output_stream(czar_gradients_out_name);
|
||||
write_grid_to_file<colvar_grid_gradient>(czar_gradients, prefix + ".czar.grad", close);
|
||||
|
||||
if (b_integrate) {
|
||||
// Do numerical integration (to high precision) and output a PMF
|
||||
cvm::real err;
|
||||
czar_pmf->set_div();
|
||||
czar_pmf->integrate(integrate_initial_iterations, integrate_initial_tol, err);
|
||||
czar_pmf->integrate(integrate_iterations, integrate_tol, err);
|
||||
czar_pmf->set_zero_minimum();
|
||||
|
||||
std::string czar_pmf_out_name = prefix + ".czar.pmf";
|
||||
std::ostream *czar_pmf_os = cvm::proxy->output_stream(czar_pmf_out_name, mode);
|
||||
if (!czar_pmf_os) return;
|
||||
czar_pmf->write_multicol(*czar_pmf_os);
|
||||
|
||||
// In dimension higher than 2, dx is easier to handle and visualize
|
||||
if (num_variables() > 2) {
|
||||
std::string czar_pmf_dx_out_name = prefix + ".czar.pmf.dx";
|
||||
std::ostream *czar_pmf_dx_os = cvm::proxy->output_stream(czar_pmf_dx_out_name, mode);
|
||||
if (!czar_pmf_dx_os) return;
|
||||
czar_pmf->write_opendx(*czar_pmf_dx_os);
|
||||
*czar_pmf_dx_os << std::endl;
|
||||
cvm::proxy->close_output_stream(czar_pmf_dx_out_name);
|
||||
}
|
||||
|
||||
*czar_pmf_os << std::endl;
|
||||
cvm::proxy->close_output_stream(czar_pmf_out_name);
|
||||
write_grid_to_file<colvar_grid_scalar>(czar_pmf, prefix + ".czar.pmf", close);
|
||||
}
|
||||
}
|
||||
return;
|
||||
@ -836,25 +805,56 @@ std::istream & colvarbias_abf::read_state_data(std::istream& is)
|
||||
return is;
|
||||
}
|
||||
|
||||
|
||||
int colvarbias_abf::write_output_files()
|
||||
{
|
||||
if (cvm::debug()) {
|
||||
cvm::log("ABF bias trying to write gradients and samples to disk");
|
||||
}
|
||||
|
||||
if (shared_on && cvm::main()->proxy->replica_index() > 0) {
|
||||
// No need to report the same data as replica 0, let it do the I/O job
|
||||
return COLVARS_OK;
|
||||
}
|
||||
|
||||
write_gradients_samples(output_prefix);
|
||||
if (b_history_files) {
|
||||
if ((cvm::step_absolute() % history_freq) == 0) {
|
||||
write_gradients_samples(output_prefix + ".hist", false);
|
||||
}
|
||||
}
|
||||
|
||||
if (b_UI_estimator) {
|
||||
eabf_UI.calc_pmf();
|
||||
eabf_UI.write_files();
|
||||
}
|
||||
|
||||
return COLVARS_OK;
|
||||
}
|
||||
|
||||
|
||||
int colvarbias_abf::calc_energy(std::vector<colvarvalue> const *values)
|
||||
{
|
||||
if (values) {
|
||||
return cvm::error("colvarbias_abf::calc_energy() with an argument "
|
||||
"is currently not implemented.\n",
|
||||
COLVARS_NOT_IMPLEMENTED);
|
||||
}
|
||||
bias_energy = 0.0; // default value, overridden if a value can be calculated
|
||||
|
||||
if (num_variables() != 1) return 0.0;
|
||||
if (num_variables() > 1 || values != NULL) {
|
||||
// Use simple estimate: neglect effect of fullSamples,
|
||||
// return value at center of bin
|
||||
if (pmf != NULL) {
|
||||
std::vector<int> const curr_bin = values ?
|
||||
pmf->get_colvars_index(*values) :
|
||||
pmf->get_colvars_index();
|
||||
|
||||
if (pmf->index_ok(curr_bin)) {
|
||||
bias_energy = pmf->value(curr_bin);
|
||||
}
|
||||
}
|
||||
return COLVARS_OK;
|
||||
}
|
||||
|
||||
// Get the home bin.
|
||||
int home0 = gradients->current_bin_scalar(0);
|
||||
if (home0 < 0) return 0.0;
|
||||
if (home0 < 0) return COLVARS_OK;
|
||||
int gradient_len = (int)(gradients->number_of_points(0));
|
||||
int home = (home0 < gradient_len) ? home0 : (gradient_len-1);
|
||||
|
||||
@ -886,5 +886,6 @@ int colvarbias_abf::calc_energy(std::vector<colvarvalue> const *values)
|
||||
sum += fact*gradients->value(ix)/count*gradients->widths[0]*frac;
|
||||
|
||||
// The applied potential is the negative integral of force samples.
|
||||
return -sum;
|
||||
bias_energy = -sum;
|
||||
return COLVARS_OK;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user