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.
@ -29,6 +29,10 @@ colvar::colvar()
kinetic_energy = 0.0;
potential_energy = 0.0;
#ifdef LEPTON
dev_null = 0.0;
#endif
description = "uninitialized colvar";
init_dependencies();
}
@ -194,23 +198,32 @@ int colvar::init(std::string const &conf)
{
bool homogeneous = is_enabled(f_cv_linear);
for (i = 0; i < cvcs.size(); i++) {
if ((cvm::fabs(cvcs[i]->sup_coeff) - 1.0) > 1.0e-10) {
if (cvm::fabs(cvm::fabs(cvcs[i]->sup_coeff) - 1.0) > 1.0e-10) {
homogeneous = false;
}
}
set_enabled(f_cv_homogeneous, homogeneous);
}
// A single-component variable almost concides with its CVC object
if ((cvcs.size() == 1) && is_enabled(f_cv_homogeneous)) {
if ( !is_enabled(f_cv_scripted) && !is_enabled(f_cv_custom_function) &&
(cvm::fabs(cvcs[0]->sup_coeff - 1.0) < 1.0e-10) &&
(cvcs[0]->sup_np == 1) ) {
enable(f_cv_single_cvc);
}
}
// Colvar is deemed periodic if:
// - it is homogeneous
// - all cvcs are periodic
// - all cvcs have the same period
if (is_enabled(f_cv_homogeneous) && cvcs[0]->b_periodic) { // TODO make this a CVC feature
if (is_enabled(f_cv_homogeneous) && cvcs[0]->is_enabled(f_cvc_periodic)) {
bool b_periodic = true;
period = cvcs[0]->period;
wrap_center = cvcs[0]->wrap_center;
for (i = 1; i < cvcs.size(); i++) {
if (!cvcs[i]->b_periodic || cvcs[i]->period != period) {
if (!cvcs[i]->is_enabled(f_cvc_periodic) || cvcs[i]->period != period) {
b_periodic = false;
period = 0.0;
cvm::log("Warning: although one component is periodic, this colvar will "
@ -296,13 +309,13 @@ int colvar::init(std::string const &conf)
#ifdef LEPTON
int colvar::init_custom_function(std::string const &conf)
{
std::string expr;
std::string expr, expr_in; // expr_in is a buffer to remember expr after unsuccessful parsing
std::vector<Lepton::ParsedExpression> pexprs;
Lepton::ParsedExpression pexpr;
size_t pos = 0; // current position in config string
double *ref;
if (!key_lookup(conf, "customFunction", &expr, &pos)) {
if (!key_lookup(conf, "customFunction", &expr_in, &pos)) {
return COLVARS_OK;
}
@ -310,6 +323,7 @@ int colvar::init_custom_function(std::string const &conf)
cvm::log("This colvar uses a custom function.\n");
do {
expr = expr_in;
if (cvm::debug())
cvm::log("Parsing expression \"" + expr + "\".\n");
try {
@ -337,8 +351,7 @@ int colvar::init_custom_function(std::string const &conf)
// To keep the same workflow, we use a pointer to a double here
// that will receive CVC values - even though none was allocated by Lepton
ref = &dev_null;
if (cvm::debug())
cvm::log("Variable " + vn + " is absent from expression \"" + expr + "\".\n");
cvm::log("Warning: Variable " + vn + " is absent from expression \"" + expr + "\".\n");
}
value_eval_var_refs.push_back(ref);
}
@ -348,7 +361,7 @@ int colvar::init_custom_function(std::string const &conf)
cvm::error("Error compiling expression \"" + expr + "\".\n", INPUT_ERROR);
return INPUT_ERROR;
}
} while (key_lookup(conf, "customFunction", &expr, &pos));
} while (key_lookup(conf, "customFunction", &expr_in, &pos));
// Now define derivative with respect to each scalar sub-component
@ -373,8 +386,7 @@ int colvar::init_custom_function(std::string const &conf)
catch (...) { // Variable is absent from derivative
// To keep the same workflow, we use a pointer to a double here
// that will receive CVC values - even though none was allocated by Lepton
if (cvm::debug())
cvm::log("Variable " + vvn + " is absent from derivative of \"" + expr + "\" wrt " + vn + ".\n");
cvm::log("Warning: Variable " + vvn + " is absent from derivative of \"" + expr + "\" wrt " + vn + ".\n");
ref = &dev_null;
}
grad_eval_var_refs.push_back(ref);
@ -439,6 +451,21 @@ int colvar::init_custom_function(std::string const &conf)
int colvar::init_custom_function(std::string const &conf)
{
std::string expr;
size_t pos = 0;
if (key_lookup(conf, "customFunction", &expr, &pos)) {
std::string msg("Error: customFunction requires the Lepton library.");
#if (__cplusplus < 201103L)
// NOTE: this is not ideal; testing for the Lepton library's version would
// be more accurate, but also less portable
msg +=
std::string(" Note also that recent versions of Lepton require C++11: "
"please see https://colvars.github.io/README-c++11.html.");
#endif
return cvm::error(msg, COLVARS_NOT_IMPLEMENTED);
}
return COLVARS_OK;
}
@ -449,7 +476,19 @@ int colvar::init_grid_parameters(std::string const &conf)
{
colvarmodule *cv = cvm::main();
get_keyval(conf, "width", width, 1.0);
cvm::real default_width = width;
if (!key_already_set("width")) {
// The first time, check if the CVC has a width to provide
default_width = 1.0;
if (is_enabled(f_cv_single_cvc) && cvcs[0]->is_enabled(f_cvc_width)) {
cvm::real const cvc_width = cvcs[0]->get_param("width");
default_width = cvc_width;
}
}
get_keyval(conf, "width", width, default_width);
if (width <= 0.0) {
cvm::error("Error: \"width\" must be positive.\n", INPUT_ERROR);
return INPUT_ERROR;
@ -460,12 +499,32 @@ int colvar::init_grid_parameters(std::string const &conf)
if (is_enabled(f_cv_scalar)) {
if (is_enabled(f_cv_single_cvc)) {
// Get the default boundaries from the component
if (cvcs[0]->is_enabled(f_cvc_lower_boundary)) {
enable(f_cv_lower_boundary);
enable(f_cv_hard_lower_boundary);
lower_boundary =
*(reinterpret_cast<colvarvalue const *>(cvcs[0]->get_param_ptr("lowerBoundary")));
}
if (cvcs[0]->is_enabled(f_cvc_upper_boundary)) {
enable(f_cv_upper_boundary);
enable(f_cv_hard_upper_boundary);
upper_boundary =
*(reinterpret_cast<colvarvalue const *>(cvcs[0]->get_param_ptr("upperBoundary")));
}
}
if (get_keyval(conf, "lowerBoundary", lower_boundary, lower_boundary)) {
enable(f_cv_lower_boundary);
// Because this is the user's choice, we cannot assume it is a true
// physical boundary
disable(f_cv_hard_lower_boundary);
}
if (get_keyval(conf, "upperBoundary", upper_boundary, upper_boundary)) {
enable(f_cv_upper_boundary);
disable(f_cv_hard_upper_boundary);
}
std::string lw_conf, uw_conf;
@ -520,12 +579,11 @@ harmonicWalls {\n\
}
}
if (is_enabled(f_cv_lower_boundary)) {
get_keyval(conf, "hardLowerBoundary", hard_lower_boundary, false);
}
if (is_enabled(f_cv_upper_boundary)) {
get_keyval(conf, "hardUpperBoundary", hard_upper_boundary, false);
}
get_keyval_feature(this, conf, "hardLowerBoundary", f_cv_hard_lower_boundary,
is_enabled(f_cv_hard_lower_boundary));
get_keyval_feature(this, conf, "hardUpperBoundary", f_cv_hard_upper_boundary,
is_enabled(f_cv_hard_upper_boundary));
// consistency checks for boundaries and walls
if (is_enabled(f_cv_lower_boundary) && is_enabled(f_cv_upper_boundary)) {
@ -546,7 +604,8 @@ harmonicWalls {\n\
INPUT_ERROR);
return INPUT_ERROR;
}
if (expand_boundaries && hard_lower_boundary && hard_upper_boundary) {
if (expand_boundaries && is_enabled(f_cv_hard_lower_boundary) &&
is_enabled(f_cv_hard_upper_boundary)) {
cvm::error("Error: inconsistent configuration "
"(trying to expand boundaries with both "
"hardLowerBoundary and hardUpperBoundary enabled).\n",
@ -568,7 +627,8 @@ int colvar::init_extended_Lagrangian(std::string const &conf)
cvm::log("Enabling the extended Lagrangian term for colvar \""+
this->name+"\".\n");
x_ext.type(value());
// Mark x_ext as uninitialized so we can initialize it to the colvar value when updating
x_ext.type(colvarvalue::type_notset);
v_ext.type(value());
fr.type(value());
@ -646,7 +706,7 @@ int colvar::init_output_flags(std::string const &conf)
bool temp;
if (get_keyval(conf, "outputSystemForce", temp, false, colvarparse::parse_silent)) {
cvm::error("Option outputSystemForce is deprecated: only outputTotalForce is supported instead.\n"
"The two are NOT identical: see http://colvars.github.io/totalforce.html.\n", INPUT_ERROR);
"The two are NOT identical: see https://colvars.github.io/totalforce.html.\n", INPUT_ERROR);
return INPUT_ERROR;
}
}
@ -664,7 +724,7 @@ int colvar::init_output_flags(std::string const &conf)
// read the configuration and set up corresponding instances, for
// each type of component implemented
template<typename def_class_name> int colvar::init_components_type(std::string const &conf,
char const *def_desc,
char const * /* def_desc */,
char const *def_config_key)
{
size_t def_count = 0;
@ -744,6 +804,7 @@ template<typename def_class_name> int colvar::init_components_type(std::string c
int colvar::init_components(std::string const &conf)
{
int error_code = COLVARS_OK;
size_t i = 0, j = 0;
error_code |= init_components_type<distance>(conf, "distance", "distance");
error_code |= init_components_type<distance_vec>(conf, "distance vector", "distanceVec");
@ -793,9 +854,11 @@ int colvar::init_components(std::string const &conf)
error_code |= init_components_type<eigenvector>(conf, "eigenvector", "eigenvector");
error_code |= init_components_type<gspath>(conf, "geometrical path collective variables (s)", "gspath");
error_code |= init_components_type<gzpath>(conf, "geometrical path collective variables (z)", "gzpath");
error_code |= init_components_type<linearCombination>(conf, "linear combination of other collective variables", "subColvar");
error_code |= init_components_type<linearCombination>(conf, "linear combination of other collective variables", "linearCombination");
error_code |= init_components_type<gspathCV>(conf, "geometrical path collective variables (s) for other CVs", "gspathCV");
error_code |= init_components_type<gzpathCV>(conf, "geometrical path collective variables (z) for other CVs", "gzpathCV");
error_code |= init_components_type<aspathCV>(conf, "arithmetic path collective variables (s) for other CVs", "aspathCV");
error_code |= init_components_type<azpathCV>(conf, "arithmetic path collective variables (s) for other CVs", "azpathCV");
if (!cvcs.size() || (error_code != COLVARS_OK)) {
cvm::error("Error: no valid components were provided "
@ -804,15 +867,26 @@ int colvar::init_components(std::string const &conf)
return INPUT_ERROR;
}
// Check for uniqueness of CVC names (esp. if user-provided)
for (i = 0; i < cvcs.size(); i++) {
for (j = i+1; j < cvcs.size(); j++) {
if (cvcs[i]->name == cvcs[j]->name) {
cvm::error("Components " + cvm::to_str(i) + " and " + cvm::to_str(j) +\
" cannot have the same name \"" + cvcs[i]->name+ "\".\n", INPUT_ERROR);
return INPUT_ERROR;
}
}
}
n_active_cvcs = cvcs.size();
cvm::log("All components initialized.\n");
// Store list of children cvcs for dependency checking purposes
for (size_t i = 0; i < cvcs.size(); i++) {
for (i = 0; i < cvcs.size(); i++) {
add_child(cvcs[i]);
}
cvm::log("All components initialized.\n");
return COLVARS_OK;
}
@ -921,7 +995,7 @@ int colvar::parse_analysis(std::string const &conf)
return cvm::error("Error: collective variable \""+acf_colvar_name+
"\" is not defined at this time.\n", INPUT_ERROR);
}
cv2->enable(f_cv_fdiff_velocity);
cv2->enable(f_cv_fdiff_velocity); // Manual dependency to object of same type
} else if (acf_type_str == to_lower_cppstr(std::string("coordinate_p2"))) {
acf_type = acf_p2coor;
} else {
@ -998,6 +1072,8 @@ int colvar::init_dependencies() {
init_feature(f_cv_Langevin, "Langevin dynamics", f_type_user);
require_feature_self(f_cv_Langevin, f_cv_extended_Lagrangian);
init_feature(f_cv_single_cvc, "single component", f_type_static);
init_feature(f_cv_linear, "linear", f_type_static);
init_feature(f_cv_scalar, "scalar", f_type_static);
@ -1023,6 +1099,12 @@ int colvar::init_dependencies() {
init_feature(f_cv_upper_boundary, "upper boundary", f_type_user);
require_feature_self(f_cv_upper_boundary, f_cv_scalar);
init_feature(f_cv_hard_lower_boundary, "hard lower boundary", f_type_user);
require_feature_self(f_cv_hard_lower_boundary, f_cv_lower_boundary);
init_feature(f_cv_hard_upper_boundary, "hard upper boundary", f_type_user);
require_feature_self(f_cv_hard_upper_boundary, f_cv_upper_boundary);
init_feature(f_cv_grid, "grid", f_type_dynamic);
require_feature_self(f_cv_grid, f_cv_lower_boundary);
require_feature_self(f_cv_grid, f_cv_upper_boundary);
@ -1227,7 +1309,7 @@ int colvar::collect_cvc_data()
}
int colvar::check_cvc_range(int first_cvc, size_t num_cvcs)
int colvar::check_cvc_range(int first_cvc, size_t /* num_cvcs */)
{
if ((first_cvc < 0) || (first_cvc >= ((int) cvcs.size()))) {
cvm::error("Error: trying to address a component outside the "
@ -1512,7 +1594,7 @@ int colvar::calc_colvar_properties()
// initialize the restraint center in the first step to the value
// just calculated from the cvcs
if (cvm::step_relative() == 0 && !after_restart) {
if ((cvm::step_relative() == 0 && !after_restart) || x_ext.type() == colvarvalue::type_notset) {
x_ext = x;
v_ext.reset(); // (already 0; added for clarity)
}
@ -1859,6 +1941,59 @@ int colvar::update_cvc_config(std::vector<std::string> const &confs)
}
int colvar::cvc_param_exists(std::string const &param_name)
{
if (is_enabled(f_cv_single_cvc)) {
return cvcs[0]->param_exists(param_name);
}
return cvm::error("Error: calling colvar::cvc_param_exists() for a variable "
"with more than one component.\n", COLVARS_NOT_IMPLEMENTED);
}
cvm::real colvar::get_cvc_param(std::string const &param_name)
{
if (is_enabled(f_cv_single_cvc)) {
return cvcs[0]->get_param(param_name);
}
cvm::error("Error: calling colvar::get_cvc_param() for a variable "
"with more than one component.\n", COLVARS_NOT_IMPLEMENTED);
return 0.0;
}
void const *colvar::get_cvc_param_ptr(std::string const &param_name)
{
if (is_enabled(f_cv_single_cvc)) {
return cvcs[0]->get_param_ptr(param_name);
}
cvm::error("Error: calling colvar::get_cvc_param() for a variable "
"with more than one component.\n", COLVARS_NOT_IMPLEMENTED);
return NULL;
}
colvarvalue const *colvar::get_cvc_param_grad(std::string const &param_name)
{
if (is_enabled(f_cv_single_cvc)) {
return cvcs[0]->get_param_grad(param_name);
}
cvm::error("Error: calling colvar::get_cvc_param_grad() for a variable "
"with more than one component.\n", COLVARS_NOT_IMPLEMENTED);
return NULL;
}
int colvar::set_cvc_param(std::string const &param_name, void const *new_value)
{
if (is_enabled(f_cv_single_cvc)) {
return cvcs[0]->set_param(param_name, new_value);
}
return cvm::error("Error: calling colvar::set_cvc_param() for a variable "
"with more than one component.\n", COLVARS_NOT_IMPLEMENTED);
}
// ******************** METRIC FUNCTIONS ********************
// Use the metrics defined by \link colvar::cvc \endlink objects