Update Colvars library to version 2020-01-27

One new feature (arithmetic path variables) and several smaller enhancements
or bugfixes.

    Fix error check when loading an old state file
    https://github.com/Colvars/colvars/pull/317

    Get default values for grid boundaries when available
    https://github.com/Colvars/colvars/pull/310

    Allow redefining existing index groups (warn when this happens)
    https://github.com/Colvars/colvars/pull/302

    Simplified replica communication syntax in metadynamics
    https://github.com/Colvars/colvars/pull/301

    Obtain the bias_energy for ABF biases
    https://github.com/Colvars/colvars/pull/294

    Fix reading path file with vector CVCs
    https://github.com/Colvars/colvars/pull/288

    Fix segfault at deleting CVBasedPath
    https://github.com/Colvars/colvars/pull/286

    Parrinello's (arithmetic) pathCV in CV space
    https://github.com/Colvars/colvars/pull/274

    Fix race condition when starting a bundle of walkers
    https://github.com/Colvars/colvars/pull/279
This commit is contained in:
Giacomo Fiorin
2020-01-27 13:39:58 -05:00
parent 5eef3b1828
commit 9427fc50a5
56 changed files with 1876 additions and 1017 deletions

View File

@ -2,7 +2,7 @@
// This file is part of the Collective Variables module (Colvars).
// The original version of Colvars and its updates are located at:
// https://github.com/colvars/colvars
// https://github.com/Colvars/colvars
// Please update all Colvars source files before making any changes.
// If you wish to distribute your changes, please submit them to the
// Colvars repository at GitHub.
@ -38,14 +38,29 @@ colvarbias_meta::colvarbias_meta(char const *key)
new_hills_begin = hills.end();
hills_traj_os = NULL;
use_grids = true;
rebin_grids = false;
hills_energy = NULL;
hills_energy_gradients = NULL;
dump_fes = true;
keep_hills = false;
dump_fes_save = false;
dump_replica_fes = false;
ebmeta_equil_steps = 0L;
replica_update_freq = 0;
replica_id.clear();
}
int colvarbias_meta::init(std::string const &conf)
{
colvarbias::init(conf);
colvarbias_ti::init(conf);
int error_code = COLVARS_OK;
error_code |= colvarbias::init(conf);
error_code |= colvarbias_ti::init(conf);
enable(f_cvb_calc_pmf);
@ -77,21 +92,16 @@ int colvarbias_meta::init(std::string const &conf)
comm = single_replica;
}
// in all cases, the first replica is this bias itself
if (replicas.size() == 0) {
replicas.push_back(this);
}
get_keyval(conf, "useGrids", use_grids, true);
get_keyval(conf, "useGrids", use_grids, use_grids);
if (use_grids) {
get_keyval(conf, "gridsUpdateFrequency", grids_freq, new_hill_freq);
get_keyval(conf, "rebinGrids", rebin_grids, false);
get_keyval(conf, "rebinGrids", rebin_grids, rebin_grids);
expand_grids = false;
size_t i;
for (i = 0; i < num_variables(); i++) {
variables(i)->enable(f_cv_grid);
variables(i)->enable(f_cv_grid); // Could be a child dependency of a f_cvb_use_grids feature
if (variables(i)->expand_boundaries) {
expand_grids = true;
cvm::log("Metadynamics bias \""+this->name+"\""+
@ -101,67 +111,24 @@ int colvarbias_meta::init(std::string const &conf)
}
}
get_keyval(conf, "keepHills", keep_hills, false);
if (! get_keyval(conf, "writeFreeEnergyFile", dump_fes, true))
get_keyval(conf, "dumpFreeEnergyFile", dump_fes, true, colvarparse::parse_silent);
if (get_keyval(conf, "saveFreeEnergyFile", dump_fes_save, false, colvarparse::parse_silent)) {
cvm::log("Option \"saveFreeEnergyFile\" is deprecated, "
"please use \"keepFreeEnergyFiles\" instead.");
}
get_keyval(conf, "writeFreeEnergyFile", dump_fes, dump_fes);
get_keyval(conf, "keepHills", keep_hills, keep_hills);
get_keyval(conf, "keepFreeEnergyFiles", dump_fes_save, dump_fes_save);
hills_energy = new colvar_grid_scalar(colvars);
hills_energy_gradients = new colvar_grid_gradient(colvars);
} else {
rebin_grids = false;
keep_hills = false;
dump_fes = false;
dump_fes_save = false;
dump_replica_fes = false;
hills_energy = NULL;
hills_energy_gradients = NULL;
}
if (comm != single_replica) {
if (expand_grids)
cvm::fatal_error("Error: expandBoundaries is not supported when "
"using more than one replicas; please allocate "
"wide enough boundaries for each colvar"
"ahead of time.\n");
if (get_keyval(conf, "dumpPartialFreeEnergyFile", dump_replica_fes, false)) {
if (dump_replica_fes && (! dump_fes)) {
cvm::log("Enabling \"dumpFreeEnergyFile\".\n");
}
}
get_keyval(conf, "replicaID", replica_id, std::string(""));
if (!replica_id.size())
cvm::error("Error: replicaID must be defined "
"when using more than one replica.\n", INPUT_ERROR);
get_keyval(conf, "replicasRegistry",
replicas_registry_file,
(this->name+".replicas.registry.txt"));
get_keyval(conf, "replicaUpdateFrequency",
replica_update_freq, new_hill_freq);
if (keep_hills)
cvm::log("Warning: in metadynamics bias \""+this->name+"\""+
((comm != single_replica) ? ", replica \""+replica_id+"\"" : "")+
": keepHills with more than one replica can lead to a very "
"large amount of input/output and slow down your calculations. "
"Please consider disabling it.\n");
}
get_keyval(conf, "writeHillsTrajectory", b_hills_traj, false);
init_well_tempered_params(conf);
init_ebmeta_params(conf);
error_code |= init_replicas_params(conf);
error_code |= init_well_tempered_params(conf);
error_code |= init_ebmeta_params(conf);
if (cvm::debug())
cvm::log("Done initializing the metadynamics bias \""+this->name+"\""+
@ -171,6 +138,72 @@ int colvarbias_meta::init(std::string const &conf)
}
int colvarbias_meta::init_replicas_params(std::string const &conf)
{
colvarproxy *proxy = cvm::main()->proxy;
// in all cases, the first replica is this bias itself
if (replicas.size() == 0) {
replicas.push_back(this);
}
if (comm != single_replica) {
if (!get_keyval(conf, "writePartialFreeEnergyFile",
dump_replica_fes, dump_replica_fes)) {
get_keyval(conf, "dumpPartialFreeEnergyFile", dump_replica_fes,
dump_replica_fes, colvarparse::parse_silent);
}
if (dump_replica_fes && (! dump_fes)) {
dump_fes = true;
cvm::log("Enabling \"writeFreeEnergyFile\".\n");
}
get_keyval(conf, "replicaID", replica_id, replica_id);
if (!replica_id.size()) {
if (proxy->replica_enabled() == COLVARS_OK) {
// Obtain replicaID from the communicator
replica_id = cvm::to_str(proxy->replica_index());
cvm::log("Setting replicaID from communication layer: replicaID = "+
replica_id+".\n");
} else {
return cvm::error("Error: using more than one replica, but replicaID "
"could not be obtained.\n", INPUT_ERROR);
}
}
get_keyval(conf, "replicasRegistry", replicas_registry_file,
replicas_registry_file);
if (!replicas_registry_file.size()) {
return cvm::error("Error: the name of the \"replicasRegistry\" file "
"must be provided.\n", INPUT_ERROR);
}
get_keyval(conf, "replicaUpdateFrequency",
replica_update_freq, replica_update_freq);
if (replica_update_freq == 0) {
return cvm::error("Error: replicaUpdateFrequency must be positive.\n",
INPUT_ERROR);
}
if (expand_grids) {
return cvm::error("Error: expandBoundaries is not supported when "
"using more than one replicas; please allocate "
"wide enough boundaries for each colvar"
"ahead of time.\n", INPUT_ERROR);
}
if (keep_hills) {
return cvm::error("Error: multipleReplicas and keepHills are not "
"supported together.\n", INPUT_ERROR);
}
}
return COLVARS_OK;
}
int colvarbias_meta::init_well_tempered_params(std::string const &conf)
{
// for well-tempered metadynamics
@ -379,8 +412,8 @@ int colvarbias_meta::update()
error_code |= replica_share();
}
error_code |= calc_energy();
error_code |= calc_forces();
error_code |= calc_energy(NULL);
error_code |= calc_forces(NULL);
return error_code;
}
@ -418,7 +451,7 @@ int colvarbias_meta::update_grid_params()
int &new_size = new_sizes[i];
bool changed_lb = false, changed_ub = false;
if (!variables(i)->hard_lower_boundary)
if (!variables(i)->is_enabled(f_cv_hard_lower_boundary))
if (curr_bin[i] < min_buffer) {
int const extra_points = (min_buffer - curr_bin[i]);
new_lb -= extra_points * variables(i)->width;
@ -435,7 +468,7 @@ int colvarbias_meta::update_grid_params()
cvm::to_str(new_lower_boundaries[i])+".\n");
}
if (!variables(i)->hard_upper_boundary)
if (!variables(i)->is_enabled(f_cv_hard_upper_boundary))
if (curr_bin[i] > new_size - min_buffer - 1) {
int const extra_points = (curr_bin[i] - (new_size - 1) + min_buffer);
new_ub += extra_points * variables(i)->width;
@ -521,7 +554,7 @@ int colvarbias_meta::update_bias()
std::vector<int> curr_bin = hills_energy->get_colvars_index();
hills_energy_sum_here = hills_energy->value(curr_bin);
} else {
calc_hills(new_hills_begin, hills.end(), hills_energy_sum_here);
calc_hills(new_hills_begin, hills.end(), hills_energy_sum_here, NULL);
}
hills_scale *= cvm::exp(-1.0*hills_energy_sum_here/(bias_temperature*cvm::boltzmann()));
}
@ -578,7 +611,7 @@ int colvarbias_meta::update_grid_data()
}
int colvarbias_meta::calc_energy(std::vector<colvarvalue> const &values)
int colvarbias_meta::calc_energy(std::vector<colvarvalue> const *values)
{
size_t ir = 0;
@ -586,8 +619,8 @@ int colvarbias_meta::calc_energy(std::vector<colvarvalue> const &values)
replicas[ir]->bias_energy = 0.0;
}
std::vector<int> const curr_bin = values.size() ?
hills_energy->get_colvars_index(values) :
std::vector<int> const curr_bin = values ?
hills_energy->get_colvars_index(*values) :
hills_energy->get_colvars_index();
if (hills_energy->index_ok(curr_bin)) {
@ -619,7 +652,8 @@ int colvarbias_meta::calc_energy(std::vector<colvarvalue> const &values)
for (ir = 0; ir < replicas.size(); ir++) {
calc_hills(replicas[ir]->new_hills_begin,
replicas[ir]->hills.end(),
bias_energy);
bias_energy,
values);
if (cvm::debug()) {
cvm::log("Hills energy = "+cvm::to_str(bias_energy)+".\n");
}
@ -629,7 +663,7 @@ int colvarbias_meta::calc_energy(std::vector<colvarvalue> const &values)
}
int colvarbias_meta::calc_forces(std::vector<colvarvalue> const &values)
int colvarbias_meta::calc_forces(std::vector<colvarvalue> const *values)
{
size_t ir = 0, ic = 0;
for (ir = 0; ir < replicas.size(); ir++) {
@ -638,8 +672,8 @@ int colvarbias_meta::calc_forces(std::vector<colvarvalue> const &values)
}
}
std::vector<int> const curr_bin = values.size() ?
hills_energy->get_colvars_index(values) :
std::vector<int> const curr_bin = values ?
hills_energy->get_colvars_index(*values) :
hills_energy->get_colvars_index();
if (hills_energy->index_ok(curr_bin)) {
@ -693,7 +727,7 @@ int colvarbias_meta::calc_forces(std::vector<colvarvalue> const &values)
void colvarbias_meta::calc_hills(colvarbias_meta::hill_iter h_first,
colvarbias_meta::hill_iter h_last,
cvm::real &energy,
std::vector<colvarvalue> const &colvar_values)
std::vector<colvarvalue> const *values)
{
size_t i = 0;
std::vector<colvarvalue> curr_values(num_variables());
@ -701,9 +735,9 @@ void colvarbias_meta::calc_hills(colvarbias_meta::hill_iter h_first,
curr_values[i].type(variables(i)->value());
}
if (colvar_values.size()) {
if (values) {
for (i = 0; i < num_variables(); i++) {
curr_values[i] = colvar_values[i];
curr_values[i] = (*values)[i];
}
} else {
for (i = 0; i < num_variables(); i++) {
@ -738,10 +772,10 @@ void colvarbias_meta::calc_hills_force(size_t const &i,
colvarbias_meta::hill_iter h_first,
colvarbias_meta::hill_iter h_last,
std::vector<colvarvalue> &forces,
std::vector<colvarvalue> const &values)
std::vector<colvarvalue> const *values)
{
// Retrieve the value of the colvar
colvarvalue const x(values.size() ? values[i] : variables(i)->value());
colvarvalue const x(values ? (*values)[i] : variables(i)->value());
// do the type check only once (all colvarvalues in the hills series
// were already saved with their types matching those in the
@ -846,12 +880,12 @@ void colvarbias_meta::project_hills(colvarbias_meta::hill_iter h_first,
// loop over the hills and increment the energy grid locally
hills_energy_here = 0.0;
calc_hills(h_first, h_last, hills_energy_here, colvar_values);
calc_hills(h_first, h_last, hills_energy_here, &colvar_values);
he->acc_value(he_ix, hills_energy_here);
for (i = 0; i < num_variables(); i++) {
hills_forces_here[i].reset();
calc_hills_force(i, h_first, h_last, hills_forces_here, colvar_values);
calc_hills_force(i, h_first, h_last, hills_forces_here, &colvar_values);
colvar_forces_scalar[i] = hills_forces_here[i].real_value;
}
hg->acc_force(hg_ix, &(colvar_forces_scalar.front()));
@ -883,7 +917,7 @@ void colvarbias_meta::project_hills(colvarbias_meta::hill_iter h_first,
}
hills_energy_here = 0.0;
calc_hills(h_first, h_last, hills_energy_here, colvar_values);
calc_hills(h_first, h_last, hills_energy_here, &colvar_values);
he->acc_value(he_ix, hills_energy_here);
he->incr(he_ix);
@ -915,7 +949,7 @@ void colvarbias_meta::project_hills(colvarbias_meta::hill_iter h_first,
void colvarbias_meta::recount_hills_off_grid(colvarbias_meta::hill_iter h_first,
colvarbias_meta::hill_iter h_last,
colvar_grid_scalar *he)
colvar_grid_scalar * /* he */)
{
hills_off_grid.clear();
@ -985,11 +1019,6 @@ void colvarbias_meta::update_replicas_registry()
if (new_replica == this->replica_id) {
// this is the record for this same replica, skip it
if (cvm::debug())
cvm::log("Metadynamics bias \""+this->name+"\""+
((comm != single_replica) ? ", replica \""+replica_id+"\"" : "")+
": skipping this replica's own record: \""+
new_replica+"\", \""+new_replica_file+"\"\n");
new_replica_file.clear();
new_replica.clear();
continue;
@ -1039,11 +1068,12 @@ void colvarbias_meta::update_replicas_registry()
(replicas.back())->enable(f_cvb_calc_ti_samples);
(replicas.back())->colvarbias_ti::init_grids();
}
(replicas.back())->update_status = 1;
}
}
} else {
cvm::fatal_error("Error: cannot read the replicas registry file \""+
replicas_registry+"\".\n");
cvm::error("Error: cannot read the replicas registry file \""+
replicas_registry+"\".\n", FILE_ERROR);
}
// now (re)read the list file of each replica
@ -1068,7 +1098,6 @@ void colvarbias_meta::update_replicas_registry()
cvm::to_str(replica_update_freq)+" steps.\n");
(replicas[ir])->update_status++;
} else {
(replicas[ir])->update_status = 0;
if (new_state_file != (replicas[ir])->replica_state_file) {
cvm::log("Metadynamics bias \""+this->name+"\""+
": replica \""+(replicas[ir])->replica_id+
@ -1092,27 +1121,41 @@ void colvarbias_meta::read_replica_files()
// Note: we start from the 2nd replica.
for (size_t ir = 1; ir < replicas.size(); ir++) {
if (! (replicas[ir])->replica_state_file_in_sync) {
// if a new state file is being read, the hills file is also new
(replicas[ir])->replica_hills_file_pos = 0;
}
// (re)read the state file if necessary
if ( (! (replicas[ir])->has_data) ||
(! (replicas[ir])->replica_state_file_in_sync) ) {
cvm::log("Metadynamics bias \""+this->name+"\""+
": reading the state of replica \""+
(replicas[ir])->replica_id+"\" from file \""+
(replicas[ir])->replica_state_file+"\".\n");
std::ifstream is((replicas[ir])->replica_state_file.c_str());
if ((replicas[ir])->read_state(is)) {
// state file has been read successfully
(replicas[ir])->replica_state_file_in_sync = true;
(replicas[ir])->update_status = 0;
if ((replicas[ir])->replica_state_file.size()) {
cvm::log("Metadynamics bias \""+this->name+"\""+
": reading the state of replica \""+
(replicas[ir])->replica_id+"\" from file \""+
(replicas[ir])->replica_state_file+"\".\n");
std::ifstream is((replicas[ir])->replica_state_file.c_str());
if ((replicas[ir])->read_state(is)) {
// state file has been read successfully
(replicas[ir])->replica_state_file_in_sync = true;
(replicas[ir])->update_status = 0;
} else {
cvm::log("Failed to read the file \""+
(replicas[ir])->replica_state_file+
"\": will try again in "+
cvm::to_str(replica_update_freq)+" steps.\n");
(replicas[ir])->replica_state_file_in_sync = false;
(replicas[ir])->update_status++;
}
is.close();
} else {
cvm::log("Metadynamics bias \""+this->name+"\""+
": the state file of replica \""+
(replicas[ir])->replica_id+"\" is currently undefined: "
"will try again after "+
cvm::to_str(replica_update_freq)+" steps.\n");
(replicas[ir])->update_status++;
}
is.close();
}
if (! (replicas[ir])->replica_state_file_in_sync) {
// if a new state file is being read, the hills file is also new
(replicas[ir])->replica_hills_file_pos = 0;
}
// now read the hills added after writing the state file
@ -1124,14 +1167,16 @@ void colvarbias_meta::read_replica_files()
(replicas[ir])->replica_id+"\" in the file \""+
(replicas[ir])->replica_hills_file+"\".\n");
// read hills from the other replicas' files; for each file, resume
// the position recorded previously
// read hills from the other replicas' files
std::ifstream is((replicas[ir])->replica_hills_file.c_str());
if (is.is_open()) {
// try to resume the previous position
is.seekg((replicas[ir])->replica_hills_file_pos, std::ios::beg);
// try to resume the previous position (if not the beginning)
if ((replicas[ir])->replica_hills_file_pos > 0) {
is.seekg((replicas[ir])->replica_hills_file_pos, std::ios::beg);
}
if (!is.is_open()){
// if fail (the file may have been overwritten), reset this
// position
@ -1149,7 +1194,6 @@ void colvarbias_meta::read_replica_files()
} else {
while ((replicas[ir])->read_hill(is)) {
// if (cvm::debug())
cvm::log("Metadynamics bias \""+this->name+"\""+
": received a hill from replica \""+
(replicas[ir])->replica_id+
@ -1159,11 +1203,13 @@ void colvarbias_meta::read_replica_files()
is.clear();
// store the position for the next read
(replicas[ir])->replica_hills_file_pos = is.tellg();
if (cvm::debug())
if (cvm::debug()) {
cvm::log("Metadynamics bias \""+this->name+"\""+
": stopped reading file \""+(replicas[ir])->replica_hills_file+
": stopped reading file \""+
(replicas[ir])->replica_hills_file+
"\" at position "+
cvm::to_str((replicas[ir])->replica_hills_file_pos)+".\n");
}
// test whether this is the end of the file
is.seekg(0, std::ios::end);
@ -1175,12 +1221,11 @@ void colvarbias_meta::read_replica_files()
}
} else {
cvm::log("Failed to read the file \""+(replicas[ir])->replica_hills_file+
cvm::log("Failed to read the file \""+
(replicas[ir])->replica_hills_file+
"\": will try again in "+
cvm::to_str(replica_update_freq)+" steps.\n");
(replicas[ir])->update_status++;
// cvm::fatal_error ("Error: cannot read from file \""+
// (replicas[ir])->replica_hills_file+"\".\n");
}
is.close();
}
@ -1188,8 +1233,8 @@ void colvarbias_meta::read_replica_files()
size_t const n_flush = (replica_update_freq/new_hill_freq + 1);
if ((replicas[ir])->update_status > 3*n_flush) {
// TODO: suspend the calculation?
cvm::log("WARNING: in metadynamics bias \""+this->name+"\""+
" failed to read completely the output of replica \""+
cvm::log("WARNING: metadynamics bias \""+this->name+"\""+
" could not read information from replica \""+
(replicas[ir])->replica_id+
"\" after more than "+
cvm::to_str((replicas[ir])->update_status * replica_update_freq)+
@ -1712,7 +1757,7 @@ void colvarbias_meta::write_pmf()
cvm:: real target_val=target_dist->value(i);
if (target_val>0) {
pmf_val=pmf->value(i);
pmf_val=pmf_val+cvm::temperature() * cvm::boltzmann() * std::log(target_val);
pmf_val=pmf_val+cvm::temperature() * cvm::boltzmann() * cvm::logn(target_val);
}
pmf->set_value(i,pmf_val);
}
@ -1753,7 +1798,7 @@ void colvarbias_meta::write_pmf()
cvm:: real target_val=target_dist->value(i);
if (target_val>0) {
pmf_val=pmf->value(i);
pmf_val=pmf_val+cvm::temperature() * cvm::boltzmann() * std::log(target_val);
pmf_val=pmf_val+cvm::temperature() * cvm::boltzmann() * cvm::logn(target_val);
}
pmf->set_value(i,pmf_val);
}