Update Colvars to version 2022-05-09

This update includes one new feature (neural-network based collective
variables), several small enhancements (including an automatic definition of
grid boundaries for angle-based CVs, and a normalization option for
eigenvector-based CVs), bugfixes and documentation improvements.

Usage information for specific features included in the Colvars library
(i.e. not just the library as a whole) is now also reported to the screen or
LAMMPS logfile (as is done already in other LAMMPS classes).

Notable to LAMMPS code development are the removals of duplicated code and of
ambiguously-named preprocessor defines in the Colvars headers.  Since the
last PR, the existing regression tests have also been running automatically
via GitHub Actions.

The following pull requests in the Colvars repository are relevant to LAMMPS:

- 475 Remove fatal error condition
  https://github.com/Colvars/colvars/pull/475 (@jhenin, @giacomofiorin)

- 474 Allow normalizing eigenvector vector components to deal with unit change
  https://github.com/Colvars/colvars/pull/474 (@giacomofiorin, @jhenin)

- 470 Better error handling in the initialization of NeuralNetwork CV
  https://github.com/Colvars/colvars/pull/470 (@HanatoK)

- 468 Add examples of histogram configuration, with and without explicit grid parameters
  https://github.com/Colvars/colvars/pull/468 (@giacomofiorin)

- 464 Fix #463 using more fine-grained features
  https://github.com/Colvars/colvars/pull/464 (@jhenin, @giacomofiorin)

- 447 [RFC] New option "scaledBiasingForce" for colvarbias
  https://github.com/Colvars/colvars/pull/447 (@HanatoK, @jhenin)

- 444 [RFC] Implementation of dense neural network as CV
  https://github.com/Colvars/colvars/pull/444 (@HanatoK, @giacomofiorin, @jhenin)

- 443 Fix explicit gradient dependency of sub-CVs
  https://github.com/Colvars/colvars/pull/443 (@HanatoK, @jhenin)

- 442 Persistent bias count
  https://github.com/Colvars/colvars/pull/442 (@jhenin, @giacomofiorin)

- 437 Return type of bias from scripting interface
  https://github.com/Colvars/colvars/pull/437 (@giacomofiorin)

- 434 More flexible use of boundaries from colvars by grids
  https://github.com/Colvars/colvars/pull/434 (@jhenin)

- 433 Prevent double-free in linearCombination
  https://github.com/Colvars/colvars/pull/433 (@HanatoK)

- 428 More complete documentation for index file format (NDX)
  https://github.com/Colvars/colvars/pull/428 (@giacomofiorin)

- 426 Integrate functional version of backup_file() into base proxy class
  https://github.com/Colvars/colvars/pull/426 (@giacomofiorin)

- 424 Track CVC inheritance when documenting feature usage
  https://github.com/Colvars/colvars/pull/424 (@giacomofiorin)

- 419 Generate citation report while running computations
  https://github.com/Colvars/colvars/pull/419 (@giacomofiorin, @jhenin)

- 415 Rebin metadynamics bias from explicit hills when available
  https://github.com/Colvars/colvars/pull/415 (@giacomofiorin)

- 312 Ignore a keyword if it has content to the left of it (regardless of braces)
  https://github.com/Colvars/colvars/pull/312 (@giacomofiorin)

Authors: @giacomofiorin, @HanatoK, @jhenin
This commit is contained in:
Giacomo Fiorin
2022-05-10 11:24:54 -04:00
parent 4737b9efb7
commit 1220bea011
66 changed files with 4040 additions and 1221 deletions

View File

@ -28,6 +28,7 @@ COLVARS_SRCS = \
colvarbias_alb.cpp \ colvarbias_alb.cpp \
colvarbias.cpp \ colvarbias.cpp \
colvarbias_histogram.cpp \ colvarbias_histogram.cpp \
colvarbias_histogram_reweight_amd.cpp \
colvarbias_meta.cpp \ colvarbias_meta.cpp \
colvarbias_restraint.cpp \ colvarbias_restraint.cpp \
colvarcomp_alchlambda.cpp \ colvarcomp_alchlambda.cpp \
@ -37,6 +38,8 @@ COLVARS_SRCS = \
colvarcomp.cpp \ colvarcomp.cpp \
colvarcomp_distances.cpp \ colvarcomp_distances.cpp \
colvarcomp_gpath.cpp \ colvarcomp_gpath.cpp \
colvarcomp_neuralnetwork.cpp \
colvarcomp_combination.cpp \
colvarcomp_protein.cpp \ colvarcomp_protein.cpp \
colvarcomp_rotations.cpp \ colvarcomp_rotations.cpp \
colvarcomp_volmaps.cpp \ colvarcomp_volmaps.cpp \
@ -55,7 +58,8 @@ COLVARS_SRCS = \
colvarscript_commands_bias.cpp \ colvarscript_commands_bias.cpp \
colvarscript_commands_colvar.cpp \ colvarscript_commands_colvar.cpp \
colvartypes.cpp \ colvartypes.cpp \
colvarvalue.cpp colvarvalue.cpp \
colvar_neuralnetworkcompute.cpp
LEPTON_SRCS = \ LEPTON_SRCS = \
lepton/src/CompiledExpression.cpp lepton/src/ExpressionTreeNode.cpp \ lepton/src/CompiledExpression.cpp lepton/src/ExpressionTreeNode.cpp \

View File

@ -58,6 +58,21 @@ $(COLVARS_OBJ_DIR)colvarbias_histogram.o: colvarbias_histogram.cpp \
lepton/include/lepton/Exception.h \ lepton/include/lepton/Exception.h \
lepton/include/lepton/ParsedExpression.h lepton/include/lepton/Parser.h \ lepton/include/lepton/ParsedExpression.h lepton/include/lepton/Parser.h \
colvarbias_histogram.h colvarbias.h colvargrid.h colvarbias_histogram.h colvarbias.h colvargrid.h
$(COLVARS_OBJ_DIR)colvarbias_histogram_reweight_amd.o: \
colvarbias_histogram_reweight_amd.cpp \
colvarbias_histogram_reweight_amd.h colvarbias_histogram.h colvarbias.h \
colvar.h colvarmodule.h colvars_version.h colvarvalue.h colvartypes.h \
colvarparse.h colvarparams.h colvardeps.h lepton/include/Lepton.h \
lepton/include/lepton/CompiledExpression.h \
lepton/include/lepton/ExpressionTreeNode.h \
lepton/include/lepton/windowsIncludes.h \
lepton/include/lepton/CustomFunction.h \
lepton/include/lepton/ExpressionProgram.h \
lepton/include/lepton/ExpressionTreeNode.h \
lepton/include/lepton/Operation.h lepton/include/lepton/CustomFunction.h \
lepton/include/lepton/Exception.h \
lepton/include/lepton/ParsedExpression.h lepton/include/lepton/Parser.h \
colvargrid.h colvarproxy.h colvarproxy_tcl.h colvarproxy_volmaps.h
$(COLVARS_OBJ_DIR)colvarbias_meta.o: colvarbias_meta.cpp colvarmodule.h \ $(COLVARS_OBJ_DIR)colvarbias_meta.o: colvarbias_meta.cpp colvarmodule.h \
colvars_version.h colvarproxy.h colvartypes.h colvarvalue.h \ colvars_version.h colvarproxy.h colvartypes.h colvarvalue.h \
colvarproxy_tcl.h colvarproxy_volmaps.h colvar.h colvarparse.h \ colvarproxy_tcl.h colvarproxy_volmaps.h colvar.h colvarparse.h \
@ -87,9 +102,9 @@ $(COLVARS_OBJ_DIR)colvarbias_restraint.o: colvarbias_restraint.cpp \
lepton/include/lepton/Exception.h \ lepton/include/lepton/Exception.h \
lepton/include/lepton/ParsedExpression.h lepton/include/lepton/Parser.h lepton/include/lepton/ParsedExpression.h lepton/include/lepton/Parser.h
$(COLVARS_OBJ_DIR)colvarcomp_alchlambda.o: colvarcomp_alchlambda.cpp \ $(COLVARS_OBJ_DIR)colvarcomp_alchlambda.o: colvarcomp_alchlambda.cpp \
colvarmodule.h colvars_version.h colvar.h colvarvalue.h colvartypes.h \ colvarmodule.h colvars_version.h colvarvalue.h colvartypes.h \
colvarparse.h colvarparams.h colvardeps.h lepton/include/Lepton.h \ colvarparse.h colvarparams.h colvar.h colvardeps.h \
lepton/include/lepton/CompiledExpression.h \ lepton/include/Lepton.h lepton/include/lepton/CompiledExpression.h \
lepton/include/lepton/ExpressionTreeNode.h \ lepton/include/lepton/ExpressionTreeNode.h \
lepton/include/lepton/windowsIncludes.h \ lepton/include/lepton/windowsIncludes.h \
lepton/include/lepton/CustomFunction.h \ lepton/include/lepton/CustomFunction.h \
@ -184,6 +199,36 @@ $(COLVARS_OBJ_DIR)colvarcomp_gpath.o: colvarcomp_gpath.cpp colvarmodule.h \
lepton/include/lepton/ParsedExpression.h lepton/include/lepton/Parser.h \ lepton/include/lepton/ParsedExpression.h lepton/include/lepton/Parser.h \
colvarcomp.h colvaratoms.h colvarproxy.h colvarproxy_tcl.h \ colvarcomp.h colvaratoms.h colvarproxy.h colvarproxy_tcl.h \
colvarproxy_volmaps.h colvar_arithmeticpath.h colvar_geometricpath.h colvarproxy_volmaps.h colvar_arithmeticpath.h colvar_geometricpath.h
$(COLVARS_OBJ_DIR)colvarcomp_neuralnetwork.o: \
colvarcomp_neuralnetwork.cpp colvarmodule.h colvars_version.h \
colvarvalue.h colvartypes.h colvarparse.h colvarparams.h colvar.h \
colvardeps.h lepton/include/Lepton.h \
lepton/include/lepton/CompiledExpression.h \
lepton/include/lepton/ExpressionTreeNode.h \
lepton/include/lepton/windowsIncludes.h \
lepton/include/lepton/CustomFunction.h \
lepton/include/lepton/ExpressionProgram.h \
lepton/include/lepton/ExpressionTreeNode.h \
lepton/include/lepton/Operation.h lepton/include/lepton/CustomFunction.h \
lepton/include/lepton/Exception.h \
lepton/include/lepton/ParsedExpression.h lepton/include/lepton/Parser.h \
colvarcomp.h colvaratoms.h colvarproxy.h colvarproxy_tcl.h \
colvarproxy_volmaps.h colvar_arithmeticpath.h colvar_geometricpath.h \
colvar_neuralnetworkcompute.h
$(COLVARS_OBJ_DIR)colvarcomp_combination.o: colvarcomp_combination.cpp \
colvarcomp.h colvarmodule.h colvars_version.h colvar.h colvarvalue.h \
colvartypes.h colvarparse.h colvarparams.h colvardeps.h \
lepton/include/Lepton.h lepton/include/lepton/CompiledExpression.h \
lepton/include/lepton/ExpressionTreeNode.h \
lepton/include/lepton/windowsIncludes.h \
lepton/include/lepton/CustomFunction.h \
lepton/include/lepton/ExpressionProgram.h \
lepton/include/lepton/ExpressionTreeNode.h \
lepton/include/lepton/Operation.h lepton/include/lepton/CustomFunction.h \
lepton/include/lepton/Exception.h \
lepton/include/lepton/ParsedExpression.h lepton/include/lepton/Parser.h \
colvaratoms.h colvarproxy.h colvarproxy_tcl.h colvarproxy_volmaps.h \
colvar_arithmeticpath.h colvar_geometricpath.h
$(COLVARS_OBJ_DIR)colvarcomp_protein.o: colvarcomp_protein.cpp \ $(COLVARS_OBJ_DIR)colvarcomp_protein.o: colvarcomp_protein.cpp \
colvarmodule.h colvars_version.h colvarvalue.h colvartypes.h \ colvarmodule.h colvars_version.h colvarvalue.h colvartypes.h \
colvarparse.h colvarparams.h colvar.h colvardeps.h \ colvarparse.h colvarparams.h colvar.h colvardeps.h \
@ -275,11 +320,12 @@ $(COLVARS_OBJ_DIR)colvarmodule.o: colvarmodule.cpp colvarmodule.h \
lepton/include/lepton/Exception.h \ lepton/include/lepton/Exception.h \
lepton/include/lepton/ParsedExpression.h lepton/include/lepton/Parser.h \ lepton/include/lepton/ParsedExpression.h lepton/include/lepton/Parser.h \
colvarbias.h colvarbias_abf.h colvargrid.h colvar_UIestimator.h \ colvarbias.h colvarbias_abf.h colvargrid.h colvar_UIestimator.h \
colvarbias_alb.h colvarbias_histogram.h colvarbias_meta.h \ colvarbias_alb.h colvarbias_histogram.h \
colvarbias_histogram_reweight_amd.h colvarbias_meta.h \
colvarbias_restraint.h colvarscript.h colvarscript_commands.h \ colvarbias_restraint.h colvarscript.h colvarscript_commands.h \
colvarscript_commands_colvar.h colvarscript_commands_bias.h \ colvarscript_commands_colvar.h colvarscript_commands_bias.h \
colvaratoms.h colvarcomp.h colvar_arithmeticpath.h \ colvaratoms.h colvarcomp.h colvar_arithmeticpath.h \
colvar_geometricpath.h colvar_geometricpath.h colvarmodule_refs.h
$(COLVARS_OBJ_DIR)colvarparams.o: colvarparams.cpp colvarmodule.h \ $(COLVARS_OBJ_DIR)colvarparams.o: colvarparams.cpp colvarmodule.h \
colvars_version.h colvarvalue.h colvartypes.h colvarparams.h colvars_version.h colvarvalue.h colvartypes.h colvarparams.h
$(COLVARS_OBJ_DIR)colvarparse.o: colvarparse.cpp colvarmodule.h \ $(COLVARS_OBJ_DIR)colvarparse.o: colvarparse.cpp colvarmodule.h \
@ -374,6 +420,19 @@ $(COLVARS_OBJ_DIR)colvarscript_commands_colvar.o: \
colvarscript_commands_bias.h colvarscript_commands_bias.h
$(COLVARS_OBJ_DIR)colvartypes.o: colvartypes.cpp colvarmodule.h \ $(COLVARS_OBJ_DIR)colvartypes.o: colvartypes.cpp colvarmodule.h \
colvars_version.h colvartypes.h colvarparse.h colvarvalue.h \ colvars_version.h colvartypes.h colvarparse.h colvarvalue.h \
colvarparams.h ../../src/math_eigen.h colvarparams.h ../../src/math_eigen_impl.h
$(COLVARS_OBJ_DIR)colvarvalue.o: colvarvalue.cpp colvarmodule.h \ $(COLVARS_OBJ_DIR)colvarvalue.o: colvarvalue.cpp colvarmodule.h \
colvars_version.h colvarvalue.h colvartypes.h colvars_version.h colvarvalue.h colvartypes.h
$(COLVARS_OBJ_DIR)colvar_neuralnetworkcompute.o: \
colvar_neuralnetworkcompute.cpp colvar_neuralnetworkcompute.h \
lepton/include/Lepton.h lepton/include/lepton/CompiledExpression.h \
lepton/include/lepton/ExpressionTreeNode.h \
lepton/include/lepton/windowsIncludes.h \
lepton/include/lepton/CustomFunction.h \
lepton/include/lepton/ExpressionProgram.h \
lepton/include/lepton/ExpressionTreeNode.h \
lepton/include/lepton/Operation.h lepton/include/lepton/CustomFunction.h \
lepton/include/lepton/Exception.h \
lepton/include/lepton/ParsedExpression.h lepton/include/lepton/Parser.h \
colvarparse.h colvarmodule.h colvars_version.h colvarvalue.h \
colvartypes.h colvarparams.h

View File

@ -38,24 +38,22 @@ colvar::colvar()
expand_boundaries = false; expand_boundaries = false;
description = "uninitialized colvar"; description = "uninitialized colvar";
init_dependencies(); colvar::init_dependencies();
} }
namespace { /// Compare two cvcs using their names
/// Compare two cvcs using their names /// Used to sort CVC array in scripted coordinates
/// Used to sort CVC array in scripted coordinates bool colvar::compare_cvc(const colvar::cvc* const i, const colvar::cvc* const j)
bool compare(colvar::cvc *i, colvar::cvc *j) {
{ return i->name < j->name;
return i->name < j->name;
}
} }
int colvar::init(std::string const &conf) int colvar::init(std::string const &conf)
{ {
cvm::log("Initializing a new collective variable.\n"); cvm::log("Initializing a new collective variable.\n");
colvarparse::init(conf); colvarparse::set_string(conf);
int error_code = COLVARS_OK; int error_code = COLVARS_OK;
@ -68,8 +66,8 @@ int colvar::init(std::string const &conf)
(cvm::colvar_by_name(this->name) != this)) { (cvm::colvar_by_name(this->name) != this)) {
cvm::error("Error: this colvar cannot have the same name, \""+this->name+ cvm::error("Error: this colvar cannot have the same name, \""+this->name+
"\", as another colvar.\n", "\", as another colvar.\n",
INPUT_ERROR); COLVARS_INPUT_ERROR);
return INPUT_ERROR; return COLVARS_INPUT_ERROR;
} }
// Initialize dependency members // Initialize dependency members
@ -97,6 +95,7 @@ int colvar::init(std::string const &conf)
enable(f_cv_scripted); enable(f_cv_scripted);
cvm::log("This colvar uses scripted function \"" + scripted_function + "\".\n"); cvm::log("This colvar uses scripted function \"" + scripted_function + "\".\n");
cvm::main()->cite_feature("Scripted functions (Tcl)");
std::string type_str; std::string type_str;
get_keyval(conf, "scriptedFunctionType", type_str, "scalar"); get_keyval(conf, "scriptedFunctionType", type_str, "scalar");
@ -110,8 +109,8 @@ int colvar::init(std::string const &conf)
} }
} }
if (x.type() == colvarvalue::type_notset) { if (x.type() == colvarvalue::type_notset) {
cvm::error("Could not parse scripted colvar type.", INPUT_ERROR); cvm::error("Could not parse scripted colvar type.", COLVARS_INPUT_ERROR);
return INPUT_ERROR; return COLVARS_INPUT_ERROR;
} }
cvm::log(std::string("Expecting colvar value of type ") cvm::log(std::string("Expecting colvar value of type ")
@ -121,8 +120,8 @@ int colvar::init(std::string const &conf)
int size; int size;
if (!get_keyval(conf, "scriptedFunctionVectorSize", size)) { if (!get_keyval(conf, "scriptedFunctionVectorSize", size)) {
cvm::error("Error: no size specified for vector scripted function.", cvm::error("Error: no size specified for vector scripted function.",
INPUT_ERROR); COLVARS_INPUT_ERROR);
return INPUT_ERROR; return COLVARS_INPUT_ERROR;
} }
x.vector1d_value.resize(size); x.vector1d_value.resize(size);
} }
@ -131,7 +130,7 @@ int colvar::init(std::string const &conf)
// Sort array of cvcs based on their names // Sort array of cvcs based on their names
// Note: default CVC names are in input order for same type of CVC // Note: default CVC names are in input order for same type of CVC
std::sort(cvcs.begin(), cvcs.end(), compare); std::sort(cvcs.begin(), cvcs.end(), colvar::compare_cvc);
if(cvcs.size() > 1) { if(cvcs.size() > 1) {
cvm::log("Sorted list of components for this scripted colvar:\n"); cvm::log("Sorted list of components for this scripted colvar:\n");
@ -257,8 +256,8 @@ int colvar::init(std::string const &conf)
cvm::error("ERROR: you are defining this collective variable " cvm::error("ERROR: you are defining this collective variable "
"by using components of different types. " "by using components of different types. "
"You must use the same type in order to " "You must use the same type in order to "
"sum them together.\n", INPUT_ERROR); "sum them together.\n", COLVARS_INPUT_ERROR);
return INPUT_ERROR; return COLVARS_INPUT_ERROR;
} }
} }
@ -295,14 +294,14 @@ int colvar::init(std::string const &conf)
// TODO use here information from the CVCs' own natural boundaries // TODO use here information from the CVCs' own natural boundaries
error_code |= init_grid_parameters(conf); error_code |= init_grid_parameters(conf);
error_code |= init_extended_Lagrangian(conf); // Detect if we have a single component that is an alchemical lambda
error_code |= init_output_flags(conf); if (is_enabled(f_cv_single_cvc) && cvcs[0]->function_type == "alchLambda") {
// Detect if we have one component that is an alchemical lambda
if (is_enabled(f_cv_single_cvc) && cvcs[0]->function_type == "alch_lambda") {
enable(f_cv_external); enable(f_cv_external);
} }
error_code |= init_extended_Lagrangian(conf);
error_code |= init_output_flags(conf);
// Now that the children are defined we can solve dependencies // Now that the children are defined we can solve dependencies
enable(f_cv_active); enable(f_cv_active);
@ -328,6 +327,8 @@ int colvar::init_custom_function(std::string const &conf)
return COLVARS_OK; return COLVARS_OK;
} }
cvm::main()->cite_feature("Custom functions (Lepton)");
enable(f_cv_custom_function); enable(f_cv_custom_function);
cvm::log("This colvar uses a custom function.\n"); cvm::log("This colvar uses a custom function.\n");
@ -340,8 +341,8 @@ int colvar::init_custom_function(std::string const &conf)
pexprs.push_back(pexpr); pexprs.push_back(pexpr);
} }
catch (...) { catch (...) {
cvm::error("Error parsing expression \"" + expr + "\".\n", INPUT_ERROR); cvm::error("Error parsing expression \"" + expr + "\".\n", COLVARS_INPUT_ERROR);
return INPUT_ERROR; return COLVARS_INPUT_ERROR;
} }
try { try {
@ -367,8 +368,8 @@ int colvar::init_custom_function(std::string const &conf)
} }
} }
catch (...) { catch (...) {
cvm::error("Error compiling expression \"" + expr + "\".\n", INPUT_ERROR); cvm::error("Error compiling expression \"" + expr + "\".\n", COLVARS_INPUT_ERROR);
return INPUT_ERROR; return COLVARS_INPUT_ERROR;
} }
} while (key_lookup(conf, "customFunction", &expr_in, &pos)); } while (key_lookup(conf, "customFunction", &expr_in, &pos));
@ -395,7 +396,9 @@ int colvar::init_custom_function(std::string const &conf)
catch (...) { // Variable is absent from derivative catch (...) { // Variable is absent from derivative
// To keep the same workflow, we use a pointer to a double here // 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 // that will receive CVC values - even though none was allocated by Lepton
cvm::log("Warning: Variable " + vvn + " is absent from derivative of \"" + expr + "\" wrt " + vn + ".\n"); if (cvm::debug()) {
cvm::log("Warning: Variable " + vvn + " is absent from derivative of \"" + expr + "\" wrt " + vn + ".\n");
}
ref = &dev_null; ref = &dev_null;
} }
grad_eval_var_refs.push_back(ref); grad_eval_var_refs.push_back(ref);
@ -407,8 +410,8 @@ int colvar::init_custom_function(std::string const &conf)
if (value_evaluators.size() == 0) { if (value_evaluators.size() == 0) {
cvm::error("Error: no custom function defined.\n", INPUT_ERROR); cvm::error("Error: no custom function defined.\n", COLVARS_INPUT_ERROR);
return INPUT_ERROR; return COLVARS_INPUT_ERROR;
} }
std::string type_str; std::string type_str;
@ -423,8 +426,8 @@ int colvar::init_custom_function(std::string const &conf)
} }
} }
if (x.type() == colvarvalue::type_notset) { if (x.type() == colvarvalue::type_notset) {
cvm::error("Could not parse custom colvar type.", INPUT_ERROR); cvm::error("Could not parse custom colvar type.", COLVARS_INPUT_ERROR);
return INPUT_ERROR; return COLVARS_INPUT_ERROR;
} }
// Guess type based on number of expressions // Guess type based on number of expressions
@ -450,7 +453,7 @@ int colvar::init_custom_function(std::string const &conf)
cvm::error("Error: based on custom function type, expected " cvm::error("Error: based on custom function type, expected "
+ cvm::to_str(x.size()) + " scalar expressions, but " + cvm::to_str(x.size()) + " scalar expressions, but "
+ cvm::to_str(value_evaluators.size()) + " were found.\n"); + cvm::to_str(value_evaluators.size()) + " were found.\n");
return INPUT_ERROR; return COLVARS_INPUT_ERROR;
} }
return COLVARS_OK; return COLVARS_OK;
@ -501,12 +504,14 @@ int colvar::init_grid_parameters(std::string const &conf)
get_keyval(conf, "width", width, default_width); get_keyval(conf, "width", width, default_width);
if (width <= 0.0) { if (width <= 0.0) {
cvm::error("Error: \"width\" must be positive.\n", INPUT_ERROR); cvm::error("Error: \"width\" must be positive.\n", COLVARS_INPUT_ERROR);
return INPUT_ERROR; return COLVARS_INPUT_ERROR;
} }
lower_boundary.type(value()); lower_boundary.type(value());
upper_boundary.type(value()); upper_boundary.type(value());
lower_boundary.real_value = 0.0;
upper_boundary.real_value = width; // Default to 1-wide grids
if (is_enabled(f_cv_scalar)) { if (is_enabled(f_cv_scalar)) {
@ -549,7 +554,7 @@ int colvar::init_grid_parameters(std::string const &conf)
"consider using a harmonicWalls restraint (caution: force constant would then be scaled by width^2).\n"); "consider using a harmonicWalls restraint (caution: force constant would then be scaled by width^2).\n");
if (!get_keyval(conf, "lowerWall", lower_wall)) { if (!get_keyval(conf, "lowerWall", lower_wall)) {
error_code |= cvm::error("Error: the value of lowerWall must be set " error_code |= cvm::error("Error: the value of lowerWall must be set "
"explicitly.\n", INPUT_ERROR); "explicitly.\n", COLVARS_INPUT_ERROR);
} }
lw_conf = std::string("\n\ lw_conf = std::string("\n\
lowerWallConstant "+cvm::to_str(lower_wall_k*width*width)+"\n\ lowerWallConstant "+cvm::to_str(lower_wall_k*width*width)+"\n\
@ -562,7 +567,7 @@ int colvar::init_grid_parameters(std::string const &conf)
"consider using a harmonicWalls restraint (caution: force constant would then be scaled by width^2).\n"); "consider using a harmonicWalls restraint (caution: force constant would then be scaled by width^2).\n");
if (!get_keyval(conf, "upperWall", upper_wall)) { if (!get_keyval(conf, "upperWall", upper_wall)) {
error_code |= cvm::error("Error: the value of upperWall must be set " error_code |= cvm::error("Error: the value of upperWall must be set "
"explicitly.\n", INPUT_ERROR); "explicitly.\n", COLVARS_INPUT_ERROR);
} }
uw_conf = std::string("\n\ uw_conf = std::string("\n\
upperWallConstant "+cvm::to_str(upper_wall_k*width*width)+"\n\ upperWallConstant "+cvm::to_str(upper_wall_k*width*width)+"\n\
@ -575,7 +580,7 @@ int colvar::init_grid_parameters(std::string const &conf)
cvm::to_str(upper_wall)+ cvm::to_str(upper_wall)+
", is not higher than the lower wall, "+ ", is not higher than the lower wall, "+
cvm::to_str(lower_wall)+".\n", cvm::to_str(lower_wall)+".\n",
INPUT_ERROR); COLVARS_INPUT_ERROR);
} }
} }
@ -604,7 +609,7 @@ harmonicWalls {\n\
cvm::to_str(upper_boundary)+ cvm::to_str(upper_boundary)+
", is not higher than the lower boundary, "+ ", is not higher than the lower boundary, "+
cvm::to_str(lower_boundary)+".\n", cvm::to_str(lower_boundary)+".\n",
INPUT_ERROR); COLVARS_INPUT_ERROR);
} }
} }
@ -612,7 +617,7 @@ harmonicWalls {\n\
if (expand_boundaries && periodic_boundaries()) { if (expand_boundaries && periodic_boundaries()) {
error_code |= cvm::error("Error: trying to expand boundaries that already " error_code |= cvm::error("Error: trying to expand boundaries that already "
"cover a whole period of a periodic colvar.\n", "cover a whole period of a periodic colvar.\n",
INPUT_ERROR); COLVARS_INPUT_ERROR);
} }
if (expand_boundaries && is_enabled(f_cv_hard_lower_boundary) && if (expand_boundaries && is_enabled(f_cv_hard_lower_boundary) &&
@ -620,7 +625,7 @@ harmonicWalls {\n\
error_code |= cvm::error("Error: inconsistent configuration " error_code |= cvm::error("Error: inconsistent configuration "
"(trying to expand boundaries, but both " "(trying to expand boundaries, but both "
"hardLowerBoundary and hardUpperBoundary " "hardLowerBoundary and hardUpperBoundary "
"are enabled).\n", INPUT_ERROR); "are enabled).\n", COLVARS_INPUT_ERROR);
} }
return error_code; return error_code;
@ -641,33 +646,40 @@ int colvar::init_extended_Lagrangian(std::string const &conf)
x_ext.type(colvarvalue::type_notset); x_ext.type(colvarvalue::type_notset);
v_ext.type(value()); v_ext.type(value());
fr.type(value()); fr.type(value());
const bool found = get_keyval(conf, "extendedTemp", temp, cvm::temperature()); const bool temp_provided = get_keyval(conf, "extendedTemp", temp, cvm::temperature());
if (temp <= 0.0) { if (is_enabled(f_cv_external)) {
if (found) // In the case of an "external" coordinate, there is no coupling potential:
cvm::error("Error: \"extendedTemp\" must be positive.\n", INPUT_ERROR); // only the fictitious mass is meaningful
else get_keyval(conf, "extendedMass", ext_mass);
cvm::error("Error: a positive temperature must be provided, either " // Ensure that the computed restraint energy term is zero
"by enabling a thermostat, or through \"extendedTemp\".\n", ext_force_k = 0.0;
INPUT_ERROR); } else {
return INPUT_ERROR; // Standard case of coupling to a geometric colvar
} if (temp <= 0.0) { // Then a finite temperature is required
if (temp_provided)
cvm::error("Error: \"extendedTemp\" must be positive.\n", COLVARS_INPUT_ERROR);
else
cvm::error("Error: a positive temperature must be provided, either "
"by enabling a thermostat, or through \"extendedTemp\".\n",
COLVARS_INPUT_ERROR);
return COLVARS_INPUT_ERROR;
}
get_keyval(conf, "extendedFluctuation", tolerance);
if (tolerance <= 0.0) {
cvm::error("Error: \"extendedFluctuation\" must be positive.\n", COLVARS_INPUT_ERROR);
return COLVARS_INPUT_ERROR;
}
ext_force_k = cvm::boltzmann() * temp / (tolerance * tolerance);
cvm::log("Computed extended system force constant: " + cvm::to_str(ext_force_k) + " [E]/U^2\n");
get_keyval(conf, "extendedFluctuation", tolerance); get_keyval(conf, "extendedTimeConstant", extended_period, 200.0);
if (tolerance <= 0.0) { if (extended_period <= 0.0) {
cvm::error("Error: \"extendedFluctuation\" must be positive.\n", INPUT_ERROR); cvm::error("Error: \"extendedTimeConstant\" must be positive.\n", COLVARS_INPUT_ERROR);
return INPUT_ERROR; }
ext_mass = (cvm::boltzmann() * temp * extended_period * extended_period)
/ (4.0 * PI * PI * tolerance * tolerance);
cvm::log("Computed fictitious mass: " + cvm::to_str(ext_mass) + " [E]/(U/fs)^2 (U: colvar unit)\n");
} }
ext_force_k = cvm::boltzmann() * temp / (tolerance * tolerance);
cvm::log("Computed extended system force constant: " + cvm::to_str(ext_force_k) + " [E]/U^2\n");
get_keyval(conf, "extendedTimeConstant", extended_period, 200.0);
if (extended_period <= 0.0) {
cvm::error("Error: \"extendedTimeConstant\" must be positive.\n", INPUT_ERROR);
}
ext_mass = (cvm::boltzmann() * temp * extended_period * extended_period)
/ (4.0 * PI * PI * tolerance * tolerance);
cvm::log("Computed fictitious mass: " + cvm::to_str(ext_mass) + " [E]/(U/fs)^2 (U: colvar unit)\n");
{ {
bool b_output_energy; bool b_output_energy;
get_keyval(conf, "outputEnergy", b_output_energy, false); get_keyval(conf, "outputEnergy", b_output_energy, false);
@ -678,8 +690,8 @@ int colvar::init_extended_Lagrangian(std::string const &conf)
get_keyval(conf, "extendedLangevinDamping", ext_gamma, 1.0); get_keyval(conf, "extendedLangevinDamping", ext_gamma, 1.0);
if (ext_gamma < 0.0) { if (ext_gamma < 0.0) {
cvm::error("Error: \"extendedLangevinDamping\" may not be negative.\n", INPUT_ERROR); cvm::error("Error: \"extendedLangevinDamping\" may not be negative.\n", COLVARS_INPUT_ERROR);
return INPUT_ERROR; return COLVARS_INPUT_ERROR;
} }
if (ext_gamma != 0.0) { if (ext_gamma != 0.0) {
enable(f_cv_Langevin); enable(f_cv_Langevin);
@ -718,8 +730,8 @@ int colvar::init_output_flags(std::string const &conf)
bool temp; bool temp;
if (get_keyval(conf, "outputSystemForce", temp, false, colvarparse::parse_silent)) { if (get_keyval(conf, "outputSystemForce", temp, false, colvarparse::parse_silent)) {
cvm::error("Option outputSystemForce is deprecated: only outputTotalForce is supported instead.\n" cvm::error("Option outputSystemForce is deprecated: only outputTotalForce is supported instead.\n"
"The two are NOT identical: see https://colvars.github.io/totalforce.html.\n", INPUT_ERROR); "The two are NOT identical: see https://colvars.github.io/totalforce.html.\n", COLVARS_INPUT_ERROR);
return INPUT_ERROR; return COLVARS_INPUT_ERROR;
} }
} }
@ -730,14 +742,23 @@ int colvar::init_output_flags(std::string const &conf)
return COLVARS_OK; return COLVARS_OK;
} }
// 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_config_key)
{
#if (__cplusplus >= 201103L) #if (__cplusplus >= 201103L)
// C++11
template<typename def_class_name> int colvar::init_components_type(std::string const &,
char const * /* def_desc */,
char const *def_config_key) {
// global_cvc_map is only supported in the C++11 case
global_cvc_map[def_config_key] = [](const std::string& cvc_conf){return new def_class_name(cvc_conf);}; global_cvc_map[def_config_key] = [](const std::string& cvc_conf){return new def_class_name(cvc_conf);};
// TODO: maybe it is better to do more check to avoid duplication in the map?
return COLVARS_OK;
}
int colvar::init_components_type_from_global_map(const std::string& conf,
const char* def_config_key) {
#else
template<typename def_class_name> int colvar::init_components_type(std::string const & conf,
char const * /* def_desc */,
char const *def_config_key) {
#endif #endif
size_t def_count = 0; size_t def_count = 0;
std::string def_conf = ""; std::string def_conf = "";
@ -752,39 +773,41 @@ template<typename def_class_name> int colvar::init_components_type(std::string c
(cvm::debug() ? ", with configuration:\n"+def_conf (cvm::debug() ? ", with configuration:\n"+def_conf
: ".\n")); : ".\n"));
cvm::increase_depth(); cvm::increase_depth();
// only the following line is different from init_components_type
// in the non-C++11 case
#if (__cplusplus >= 201103L)
cvc *cvcp = global_cvc_map.at(def_config_key)(def_conf);
#else
cvc *cvcp = new def_class_name(def_conf); cvc *cvcp = new def_class_name(def_conf);
#endif
if (cvcp != NULL) { if (cvcp != NULL) {
cvcs.push_back(cvcp); cvcs.push_back(cvcp);
cvcp->check_keywords(def_conf, def_config_key); cvcp->check_keywords(def_conf, def_config_key);
cvcp->config_key = def_config_key; cvcp->set_function_type(def_config_key);
if (cvm::get_error()) { if (cvm::get_error()) {
cvm::error("Error: in setting up component \""+ cvm::error("Error: in setting up component \""+
std::string(def_config_key)+"\".\n", INPUT_ERROR); std::string(def_config_key)+"\".\n", COLVARS_INPUT_ERROR);
return INPUT_ERROR; return COLVARS_INPUT_ERROR;
} }
cvm::decrease_depth(); cvm::decrease_depth();
} else { } else {
cvm::decrease_depth();
cvm::error("Error: in allocating component \""+ cvm::error("Error: in allocating component \""+
std::string(def_config_key)+"\".\n", std::string(def_config_key)+"\".\n",
MEMORY_ERROR); COLVARS_MEMORY_ERROR);
return MEMORY_ERROR; return COLVARS_MEMORY_ERROR;
} }
if ( (cvcp->period != 0.0) || (cvcp->wrap_center != 0.0) ) { if ( (cvcp->period != 0.0) || (cvcp->wrap_center != 0.0) ) {
if ( (cvcp->function_type != std::string("distance_z")) && if (! cvcp->is_enabled(f_cvc_periodic)) {
(cvcp->function_type != std::string("dihedral")) &&
(cvcp->function_type != std::string("polar_phi")) &&
(cvcp->function_type != std::string("spin_angle")) &&
(cvcp->function_type != std::string("euler_phi")) &&
(cvcp->function_type != std::string("euler_psi"))) {
cvm::error("Error: invalid use of period and/or " cvm::error("Error: invalid use of period and/or "
"wrapAround in a \""+ "wrapAround in a \""+
std::string(def_config_key)+ std::string(def_config_key)+
"\" component.\n"+ "\" component.\n"+
"Period: "+cvm::to_str(cvcp->period) + "Period: "+cvm::to_str(cvcp->period) +
" wrapAround: "+cvm::to_str(cvcp->wrap_center), " wrapAround: "+cvm::to_str(cvcp->wrap_center),
INPUT_ERROR); COLVARS_INPUT_ERROR);
return INPUT_ERROR; return COLVARS_INPUT_ERROR;
} }
} }
@ -814,12 +837,14 @@ template<typename def_class_name> int colvar::init_components_type(std::string c
return COLVARS_OK; return COLVARS_OK;
} }
int colvar::init_components(std::string const &conf) int colvar::init_components(std::string const &conf)
{ {
int error_code = COLVARS_OK; int error_code = COLVARS_OK;
size_t i = 0, j = 0; size_t i = 0, j = 0;
// in the non-C++11 case, the components are initialized directly by init_components_type;
// in the C++11 case, the components are stored in the global_cvc_map at first
// by init_components_type, and then the map is iterated to initialize all components.
error_code |= init_components_type<distance>(conf, "distance", "distance"); error_code |= init_components_type<distance>(conf, "distance", "distance");
error_code |= init_components_type<distance_vec>(conf, "distance vector", "distanceVec"); error_code |= init_components_type<distance_vec>(conf, "distance vector", "distanceVec");
error_code |= init_components_type<cartesian>(conf, "Cartesian coordinates", "cartesian"); error_code |= init_components_type<cartesian>(conf, "Cartesian coordinates", "cartesian");
@ -867,6 +892,7 @@ int colvar::init_components(std::string const &conf)
error_code |= init_components_type<inertia_z>(conf, "moment of inertia around an axis", "inertiaZ"); error_code |= init_components_type<inertia_z>(conf, "moment of inertia around an axis", "inertiaZ");
error_code |= init_components_type<eigenvector>(conf, "eigenvector", "eigenvector"); error_code |= init_components_type<eigenvector>(conf, "eigenvector", "eigenvector");
error_code |= init_components_type<alch_lambda>(conf, "alchemical coupling parameter", "alchLambda"); error_code |= init_components_type<alch_lambda>(conf, "alchemical coupling parameter", "alchLambda");
error_code |= init_components_type<alch_Flambda>(conf, "force on alchemical coupling parameter", "alchFLambda");
error_code |= init_components_type<gspath>(conf, "geometrical path collective variables (s)", "gspath"); 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<gzpath>(conf, "geometrical path collective variables (z)", "gzpath");
error_code |= init_components_type<linearCombination>(conf, "linear combination of other collective variables", "linearCombination"); error_code |= init_components_type<linearCombination>(conf, "linear combination of other collective variables", "linearCombination");
@ -877,14 +903,29 @@ int colvar::init_components(std::string const &conf)
error_code |= init_components_type<euler_phi>(conf, "euler phi angle of the optimal orientation", "eulerPhi"); error_code |= init_components_type<euler_phi>(conf, "euler phi angle of the optimal orientation", "eulerPhi");
error_code |= init_components_type<euler_psi>(conf, "euler psi angle of the optimal orientation", "eulerPsi"); error_code |= init_components_type<euler_psi>(conf, "euler psi angle of the optimal orientation", "eulerPsi");
error_code |= init_components_type<euler_theta>(conf, "euler theta angle of the optimal orientation", "eulerTheta"); error_code |= init_components_type<euler_theta>(conf, "euler theta angle of the optimal orientation", "eulerTheta");
#ifdef LEPTON
error_code |= init_components_type<customColvar>(conf, "CV with support of the lepton custom function", "customColvar");
#endif
error_code |= init_components_type<neuralNetwork>(conf, "neural network CV for other CVs", "NeuralNetwork");
error_code |= init_components_type<map_total>(conf, "total value of atomic map", "mapTotal"); error_code |= init_components_type<map_total>(conf, "total value of atomic map", "mapTotal");
#if (__cplusplus >= 201103L)
// iterate over all available CVC in the map
for (auto it = global_cvc_map.begin(); it != global_cvc_map.end(); ++it) {
error_code |= init_components_type_from_global_map(conf, it->first.c_str());
// TODO: is it better to check the error code here?
if (error_code != COLVARS_OK) {
cvm::log("Failed to initialize " + it->first + " with the following configuration:\n");
cvm::log(conf);
// TODO: should it stop here?
}
}
#endif
if (!cvcs.size() || (error_code != COLVARS_OK)) { if (!cvcs.size() || (error_code != COLVARS_OK)) {
cvm::error("Error: no valid components were provided " cvm::error("Error: no valid components were provided "
"for this collective variable.\n", "for this collective variable.\n",
INPUT_ERROR); COLVARS_INPUT_ERROR);
return INPUT_ERROR; return COLVARS_INPUT_ERROR;
} }
// Check for uniqueness of CVC names (esp. if user-provided) // Check for uniqueness of CVC names (esp. if user-provided)
@ -892,8 +933,8 @@ int colvar::init_components(std::string const &conf)
for (j = i+1; j < cvcs.size(); j++) { for (j = i+1; j < cvcs.size(); j++) {
if (cvcs[i]->name == cvcs[j]->name) { if (cvcs[i]->name == cvcs[j]->name) {
cvm::error("Components " + cvm::to_str(i) + " and " + cvm::to_str(j) +\ cvm::error("Components " + cvm::to_str(i) + " and " + cvm::to_str(j) +\
" cannot have the same name \"" + cvcs[i]->name+ "\".\n", INPUT_ERROR); " cannot have the same name \"" + cvcs[i]->name+ "\".\n", COLVARS_INPUT_ERROR);
return INPUT_ERROR; return COLVARS_INPUT_ERROR;
} }
} }
} }
@ -917,7 +958,9 @@ void colvar::do_feature_side_effects(int id)
case f_cv_total_force_calc: case f_cv_total_force_calc:
cvm::request_total_force(); cvm::request_total_force();
break; break;
case f_cv_collect_gradient: case f_cv_collect_atom_ids:
// Needed for getting gradients vias collect_gradients
// or via atomic forces e.g. in Colvars Dashboard in VMD
if (atom_ids.size() == 0) { if (atom_ids.size() == 0) {
build_atom_list(); build_atom_list();
} }
@ -983,7 +1026,7 @@ int colvar::parse_analysis(std::string const &conf)
get_keyval(conf, "runAveStride", runave_stride, 1); get_keyval(conf, "runAveStride", runave_stride, 1);
if ((cvm::restart_out_freq % runave_stride) != 0) { if ((cvm::restart_out_freq % runave_stride) != 0) {
cvm::error("Error: runAveStride must be commensurate with the restart frequency.\n", INPUT_ERROR); cvm::error("Error: runAveStride must be commensurate with the restart frequency.\n", COLVARS_INPUT_ERROR);
} }
get_keyval(conf, "runAveOutputFile", runave_outfile, runave_outfile); get_keyval(conf, "runAveOutputFile", runave_outfile, runave_outfile);
@ -1013,7 +1056,7 @@ int colvar::parse_analysis(std::string const &conf)
colvar *cv2 = cvm::colvar_by_name(acf_colvar_name); colvar *cv2 = cvm::colvar_by_name(acf_colvar_name);
if (cv2 == NULL) { if (cv2 == NULL) {
return cvm::error("Error: collective variable \""+acf_colvar_name+ return cvm::error("Error: collective variable \""+acf_colvar_name+
"\" is not defined at this time.\n", INPUT_ERROR); "\" is not defined at this time.\n", COLVARS_INPUT_ERROR);
} }
cv2->enable(f_cv_fdiff_velocity); // Manual dependency to object of same type 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"))) { } else if (acf_type_str == to_lower_cppstr(std::string("coordinate_p2"))) {
@ -1021,7 +1064,7 @@ int colvar::parse_analysis(std::string const &conf)
} else { } else {
cvm::log("Unknown type of correlation function, \""+ cvm::log("Unknown type of correlation function, \""+
acf_type_str+"\".\n"); acf_type_str+"\".\n");
cvm::set_error_bits(INPUT_ERROR); cvm::set_error_bits(COLVARS_INPUT_ERROR);
} }
get_keyval(conf, "corrFuncOffset", acf_offset, 0); get_keyval(conf, "corrFuncOffset", acf_offset, 0);
@ -1029,7 +1072,7 @@ int colvar::parse_analysis(std::string const &conf)
get_keyval(conf, "corrFuncStride", acf_stride, 1); get_keyval(conf, "corrFuncStride", acf_stride, 1);
if ((cvm::restart_out_freq % acf_stride) != 0) { if ((cvm::restart_out_freq % acf_stride) != 0) {
cvm::error("Error: corrFuncStride must be commensurate with the restart frequency.\n", INPUT_ERROR); cvm::error("Error: corrFuncStride must be commensurate with the restart frequency.\n", COLVARS_INPUT_ERROR);
} }
get_keyval(conf, "corrFuncNormalize", acf_normalize, true); get_keyval(conf, "corrFuncNormalize", acf_normalize, true);
@ -1060,10 +1103,15 @@ int colvar::init_dependencies() {
init_feature(f_cv_collect_gradient, "collect_gradient", f_type_dynamic); init_feature(f_cv_collect_gradient, "collect_gradient", f_type_dynamic);
require_feature_self(f_cv_collect_gradient, f_cv_gradient); require_feature_self(f_cv_collect_gradient, f_cv_gradient);
require_feature_self(f_cv_collect_gradient, f_cv_scalar); require_feature_self(f_cv_collect_gradient, f_cv_scalar);
// The following exlusion could be lifted by implementing the feature require_feature_self(f_cv_collect_gradient, f_cv_collect_atom_ids);
// The following exclusions could be lifted by implementing the feature
exclude_feature_self(f_cv_collect_gradient, f_cv_scripted); exclude_feature_self(f_cv_collect_gradient, f_cv_scripted);
exclude_feature_self(f_cv_collect_gradient, f_cv_custom_function);
require_feature_children(f_cv_collect_gradient, f_cvc_explicit_gradient); require_feature_children(f_cv_collect_gradient, f_cvc_explicit_gradient);
init_feature(f_cv_collect_atom_ids, "collect_atom_ids", f_type_dynamic);
require_feature_children(f_cv_collect_atom_ids, f_cvc_collect_atom_ids);
init_feature(f_cv_fdiff_velocity, "velocity_from_finite_differences", f_type_dynamic); init_feature(f_cv_fdiff_velocity, "velocity_from_finite_differences", f_type_dynamic);
// System force: either trivial (spring force); through extended Lagrangian, or calculated explicitly // System force: either trivial (spring force); through extended Lagrangian, or calculated explicitly
@ -1138,8 +1186,7 @@ int colvar::init_dependencies() {
require_feature_self(f_cv_reflecting_upper_boundary, f_cv_extended_Lagrangian); require_feature_self(f_cv_reflecting_upper_boundary, f_cv_extended_Lagrangian);
init_feature(f_cv_grid, "grid", f_type_dynamic); 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_scalar);
require_feature_self(f_cv_grid, f_cv_upper_boundary);
init_feature(f_cv_runave, "running_average", f_type_user); init_feature(f_cv_runave, "running_average", f_type_user);
@ -1371,8 +1418,8 @@ int colvar::check_cvc_range(int first_cvc, size_t /* num_cvcs */)
{ {
if ((first_cvc < 0) || (first_cvc >= ((int) cvcs.size()))) { if ((first_cvc < 0) || (first_cvc >= ((int) cvcs.size()))) {
cvm::error("Error: trying to address a component outside the " cvm::error("Error: trying to address a component outside the "
"range defined for colvar \""+name+"\".\n", BUG_ERROR); "range defined for colvar \""+name+"\".\n", COLVARS_BUG_ERROR);
return BUG_ERROR; return COLVARS_BUG_ERROR;
} }
return COLVARS_OK; return COLVARS_OK;
} }
@ -1471,8 +1518,8 @@ int colvar::collect_cvc_values()
"last read from the state file:\n"+cvm::to_str(x_restart)+ "last read from the state file:\n"+cvm::to_str(x_restart)+
"\nPossible causes are changes in configuration, " "\nPossible causes are changes in configuration, "
"wrong state file, or how PBC wrapping is handled.\n", "wrong state file, or how PBC wrapping is handled.\n",
INPUT_ERROR); COLVARS_INPUT_ERROR);
return INPUT_ERROR; return COLVARS_INPUT_ERROR;
} }
} }
} }
@ -1651,10 +1698,10 @@ int colvar::calc_colvar_properties()
} }
if (is_enabled(f_cv_extended_Lagrangian)) { if (is_enabled(f_cv_extended_Lagrangian)) {
// initialize the restraint center in the first step to the value // initialize the restraint center in the first step to the value
// just calculated from the cvcs // just calculated from the cvcs
if ((cvm::step_relative() == 0 && !after_restart) || x_ext.type() == colvarvalue::type_notset) { // Do the same if no simulation is running (eg. VMD postprocessing)
if ((cvm::step_relative() == 0 && !after_restart) || x_ext.type() == colvarvalue::type_notset || !cvm::proxy->simulation_running()) {
x_ext = x; x_ext = x;
if (is_enabled(f_cv_reflecting_lower_boundary) && x_ext < lower_boundary) { if (is_enabled(f_cv_reflecting_lower_boundary) && x_ext < lower_boundary) {
cvm::log("Warning: initializing extended coordinate to reflective lower boundary, as colvar value is below."); cvm::log("Warning: initializing extended coordinate to reflective lower boundary, as colvar value is below.");
@ -1732,121 +1779,8 @@ cvm::real colvar::update_forces_energy()
// At this point f is the force f from external biases that will be applied to the // At this point f is the force f from external biases that will be applied to the
// extended variable if there is one // extended variable if there is one
if (is_enabled(f_cv_extended_Lagrangian) && cvm::proxy->simulation_running()) {
if (is_enabled(f_cv_extended_Lagrangian)) { update_extended_Lagrangian();
if (cvm::proxy->simulation_running()) {
// Only integrate the extended equations of motion in running MD simulations
if (cvm::debug()) {
cvm::log("Updating extended-Lagrangian degree of freedom.\n");
}
if (prev_timestep > -1L) {
// Keep track of slow timestep to integrate MTS colvars
// the colvar checks the interval after waking up twice
cvm::step_number n_timesteps = cvm::step_relative() - prev_timestep;
if (n_timesteps != 0 && n_timesteps != time_step_factor) {
cvm::error("Error: extended-Lagrangian " + description + " has timeStepFactor " +
cvm::to_str(time_step_factor) + ", but was activated after " + cvm::to_str(n_timesteps) +
" steps at timestep " + cvm::to_str(cvm::step_absolute()) + " (relative step: " +
cvm::to_str(cvm::step_relative()) + ").\n" +
"Make sure that this colvar is requested by biases at multiples of timeStepFactor.\n");
return 0.;
}
}
// Integrate with slow timestep (if time_step_factor != 1)
cvm::real dt = cvm::dt() * cvm::real(time_step_factor);
colvarvalue f_ext(fr.type()); // force acting on the extended variable
f_ext.reset();
if (is_enabled(f_cv_external)) {
// There are no forces on the "actual colvar" bc there is no gradient wrt atomic coordinates
// So we apply this to the extended DOF
f += fb_actual;
}
fr = f;
// External force has been scaled for a 1-timestep impulse, scale it back because we will
// integrate it with the colvar's own timestep factor
f_ext = f / cvm::real(time_step_factor);
colvarvalue f_system(fr.type()); // force exterted by the system on the extended DOF
if (is_enabled(f_cv_external)) {
// Add "alchemical" force from external variable
f_system = cvcs[0]->total_force();
// f is now irrelevant because we are not applying atomic forces in the simulation
// just driving the external variable lambda
} else {
// the total force is applied to the fictitious mass, while the
// atoms only feel the harmonic force + wall force
// fr: bias force on extended variable (without harmonic spring), for output in trajectory
// f_ext: total force on extended variable (including harmonic spring)
// f: - initially, external biasing force
// - after this code block, colvar force to be applied to atomic coordinates
// ie. spring force (fb_actual will be added just below)
f_system = (-0.5 * ext_force_k) * this->dist2_lgrad(x_ext, x);
f = -1.0 * f_system;
// Coupling force is a slow force, to be applied to atomic coords impulse-style
// over a single MD timestep
f *= cvm::real(time_step_factor);
}
f_ext += f_system;
if (is_enabled(f_cv_subtract_applied_force)) {
// Report a "system" force without the biases on this colvar
// that is, just the spring force (or alchemical force)
ft_reported = f_system;
} else {
// The total force acting on the extended variable is f_ext
// This will be used in the next timestep
ft_reported = f_ext;
}
// backup in case we need to revert this integration timestep
// if the same MD timestep is re-run
prev_x_ext = x_ext;
prev_v_ext = v_ext;
// leapfrog: starting from x_i, f_i, v_(i-1/2)
v_ext += (0.5 * dt) * f_ext / ext_mass;
// Because of leapfrog, kinetic energy at time i is approximate
kinetic_energy = 0.5 * ext_mass * v_ext * v_ext;
potential_energy = 0.5 * ext_force_k * this->dist2(x_ext, x);
// leap to v_(i+1/2)
if (is_enabled(f_cv_Langevin)) {
v_ext -= dt * ext_gamma * v_ext;
colvarvalue rnd(x);
rnd.set_random();
v_ext += dt * ext_sigma * rnd / ext_mass;
}
v_ext += (0.5 * dt) * f_ext / ext_mass;
x_ext += dt * v_ext;
cvm::real delta = 0; // Length of overshoot past either reflecting boundary
if ((is_enabled(f_cv_reflecting_lower_boundary) && (delta = x_ext - lower_boundary) < 0) ||
(is_enabled(f_cv_reflecting_upper_boundary) && (delta = x_ext - upper_boundary) > 0)) {
x_ext -= 2.0 * delta;
v_ext *= -1.0;
if ((is_enabled(f_cv_reflecting_lower_boundary) && (delta = x_ext - lower_boundary) < 0) ||
(is_enabled(f_cv_reflecting_upper_boundary) && (delta = x_ext - upper_boundary) > 0)) {
cvm::error("Error: extended coordinate value " + cvm::to_str(x_ext) + " is still outside boundaries after reflection.\n");
}
}
x_ext.apply_constraints();
this->wrap(x_ext);
if (is_enabled(f_cv_external)) {
// Colvar value is constrained to the extended value
x = x_ext;
cvcs[0]->set_value(x_ext);
}
} else {
// If this is a postprocessing run (eg. in VMD), the extended DOF
// is equal to the actual coordinate
x_ext = x;
}
} }
if (!is_enabled(f_cv_external)) { if (!is_enabled(f_cv_external)) {
@ -1861,6 +1795,117 @@ cvm::real colvar::update_forces_energy()
} }
void colvar::update_extended_Lagrangian()
{
if (cvm::debug()) {
cvm::log("Updating extended-Lagrangian degree of freedom.\n");
}
if (prev_timestep > -1L) {
// Keep track of slow timestep to integrate MTS colvars
// the colvar checks the interval after waking up twice
cvm::step_number n_timesteps = cvm::step_relative() - prev_timestep;
if (n_timesteps != 0 && n_timesteps != time_step_factor) {
cvm::error("Error: extended-Lagrangian " + description + " has timeStepFactor " +
cvm::to_str(time_step_factor) + ", but was activated after " + cvm::to_str(n_timesteps) +
" steps at timestep " + cvm::to_str(cvm::step_absolute()) + " (relative step: " +
cvm::to_str(cvm::step_relative()) + ").\n" +
"Make sure that this colvar is requested by biases at multiples of timeStepFactor.\n");
return;
}
}
// Integrate with slow timestep (if time_step_factor != 1)
cvm::real dt = cvm::dt() * cvm::real(time_step_factor);
colvarvalue f_ext(fr.type()); // force acting on the extended variable
f_ext.reset();
if (is_enabled(f_cv_external)) {
// There are no forces on the "actual colvar" bc there is no gradient wrt atomic coordinates
// So we apply this to the extended DOF
f += fb_actual;
}
fr = f;
// External force has been scaled for a 1-timestep impulse, scale it back because we will
// integrate it with the colvar's own timestep factor
f_ext = f / cvm::real(time_step_factor);
colvarvalue f_system(fr.type()); // force exterted by the system on the extended DOF
if (is_enabled(f_cv_external)) {
// Add "alchemical" force from external variable
f_system = cvcs[0]->total_force();
// f is now irrelevant because we are not applying atomic forces in the simulation
// just driving the external variable lambda
} else {
// the total force is applied to the fictitious mass, while the
// atoms only feel the harmonic force + wall force
// fr: bias force on extended variable (without harmonic spring), for output in trajectory
// f_ext: total force on extended variable (including harmonic spring)
// f: - initially, external biasing force
// - after this code block, colvar force to be applied to atomic coordinates
// ie. spring force (fb_actual will be added just below)
f_system = (-0.5 * ext_force_k) * this->dist2_lgrad(x_ext, x);
f = -1.0 * f_system;
// Coupling force is a slow force, to be applied to atomic coords impulse-style
// over a single MD timestep
f *= cvm::real(time_step_factor);
}
f_ext += f_system;
if (is_enabled(f_cv_subtract_applied_force)) {
// Report a "system" force without the biases on this colvar
// that is, just the spring force (or alchemical force)
ft_reported = f_system;
} else {
// The total force acting on the extended variable is f_ext
// This will be used in the next timestep
ft_reported = f_ext;
}
// backup in case we need to revert this integration timestep
// if the same MD timestep is re-run
prev_x_ext = x_ext;
prev_v_ext = v_ext;
// leapfrog: starting from x_i, f_i, v_(i-1/2)
v_ext += (0.5 * dt) * f_ext / ext_mass;
// Because of leapfrog, kinetic energy at time i is approximate
kinetic_energy = 0.5 * ext_mass * v_ext * v_ext;
potential_energy = 0.5 * ext_force_k * this->dist2(x_ext, x);
// leap to v_(i+1/2)
if (is_enabled(f_cv_Langevin)) {
v_ext -= dt * ext_gamma * v_ext;
colvarvalue rnd(x);
rnd.set_random();
v_ext += dt * ext_sigma * rnd / ext_mass;
}
v_ext += (0.5 * dt) * f_ext / ext_mass;
x_ext += dt * v_ext;
cvm::real delta = 0; // Length of overshoot past either reflecting boundary
if ((is_enabled(f_cv_reflecting_lower_boundary) && (delta = x_ext - lower_boundary) < 0) ||
(is_enabled(f_cv_reflecting_upper_boundary) && (delta = x_ext - upper_boundary) > 0)) {
x_ext -= 2.0 * delta;
v_ext *= -1.0;
if ((is_enabled(f_cv_reflecting_lower_boundary) && (delta = x_ext - lower_boundary) < 0) ||
(is_enabled(f_cv_reflecting_upper_boundary) && (delta = x_ext - upper_boundary) > 0)) {
cvm::error("Error: extended coordinate value " + cvm::to_str(x_ext) + " is still outside boundaries after reflection.\n");
}
}
x_ext.apply_constraints();
this->wrap(x_ext);
if (is_enabled(f_cv_external)) {
// Colvar value is constrained to the extended value
x = x_ext;
cvcs[0]->set_value(x_ext);
}
}
int colvar::end_of_step() int colvar::end_of_step()
{ {
if (cvm::debug()) if (cvm::debug())
@ -1922,7 +1967,7 @@ void colvar::communicate_forces()
size_t r = 0; // index in the vector of variable references size_t r = 0; // index in the vector of variable references
size_t e = 0; // index of the gradient evaluator size_t e = 0; // index of the gradient evaluator
for (size_t i = 0; i < cvcs.size(); i++) { // gradient with respect to cvc i for (i = 0; i < cvcs.size(); i++) { // gradient with respect to cvc i
cvm::matrix2d<cvm::real> jacobian (x.size(), cvcs[i]->value().size()); cvm::matrix2d<cvm::real> jacobian (x.size(), cvcs[i]->value().size());
for (size_t j = 0; j < cvcs[i]->value().size(); j++) { // j-th element for (size_t j = 0; j < cvcs[i]->value().size(); j++) { // j-th element
for (size_t c = 0; c < x.size(); c++) { // derivative of scalar element c of the colvarvalue for (size_t c = 0; c < x.size(); c++) { // derivative of scalar element c of the colvarvalue
@ -2021,7 +2066,7 @@ int colvar::update_cvc_config(std::vector<std::string> const &confs)
if (confs.size() != cvcs.size()) { if (confs.size() != cvcs.size()) {
return cvm::error("Error: Wrong number of CVC config strings. " return cvm::error("Error: Wrong number of CVC config strings. "
"For those CVCs that are not being changed, try passing " "For those CVCs that are not being changed, try passing "
"an empty string.", INPUT_ERROR); "an empty string.", COLVARS_INPUT_ERROR);
} }
int error_code = COLVARS_OK; int error_code = COLVARS_OK;
@ -2108,12 +2153,6 @@ int colvar::set_cvc_param(std::string const &param_name, void const *new_value)
bool colvar::periodic_boundaries(colvarvalue const &lb, colvarvalue const &ub) const bool colvar::periodic_boundaries(colvarvalue const &lb, colvarvalue const &ub) const
{ {
if ( (!is_enabled(f_cv_lower_boundary)) || (!is_enabled(f_cv_upper_boundary)) ) {
cvm::log("Error: checking periodicity for collective variable \""+this->name+"\" "
"requires lower and upper boundaries to be defined.\n");
cvm::set_error_bits(INPUT_ERROR);
}
if (period > 0.0) { if (period > 0.0) {
if ( ((cvm::sqrt(this->dist2(lb, ub))) / this->width) if ( ((cvm::sqrt(this->dist2(lb, ub))) / this->width)
< 1.0E-10 ) { < 1.0E-10 ) {
@ -2127,8 +2166,8 @@ bool colvar::periodic_boundaries(colvarvalue const &lb, colvarvalue const &ub) c
bool colvar::periodic_boundaries() const bool colvar::periodic_boundaries() const
{ {
if ( (!is_enabled(f_cv_lower_boundary)) || (!is_enabled(f_cv_upper_boundary)) ) { if ( (!is_enabled(f_cv_lower_boundary)) || (!is_enabled(f_cv_upper_boundary)) ) {
cvm::log("Error: checking periodicity for collective variable \""+this->name+"\" " // Return false if answer is unknown at this time
"requires lower and upper boundaries to be defined.\n"); return false;
} }
return periodic_boundaries(lower_boundary, upper_boundary); return periodic_boundaries(lower_boundary, upper_boundary);
@ -2231,7 +2270,7 @@ std::istream & colvar::read_state(std::istream &is)
std::string(""), colvarparse::parse_silent); std::string(""), colvarparse::parse_silent);
if (check_name.size() == 0) { if (check_name.size() == 0) {
cvm::error("Error: Collective variable in the " cvm::error("Error: Collective variable in the "
"restart file without any identifier.\n", INPUT_ERROR); "restart file without any identifier.\n", COLVARS_INPUT_ERROR);
is.clear(); is.clear();
is.seekg(start_pos, std::ios::beg); is.seekg(start_pos, std::ios::beg);
is.setstate(std::ios::failbit); is.setstate(std::ios::failbit);
@ -2556,7 +2595,7 @@ int colvar::calc_acf()
colvar const *cfcv = cvm::colvar_by_name(acf_colvar_name); colvar const *cfcv = cvm::colvar_by_name(acf_colvar_name);
if (cfcv == NULL) { if (cfcv == NULL) {
return cvm::error("Error: collective variable \""+acf_colvar_name+ return cvm::error("Error: collective variable \""+acf_colvar_name+
"\" is not defined at this time.\n", INPUT_ERROR); "\" is not defined at this time.\n", COLVARS_INPUT_ERROR);
} }
if (acf_x_history.empty() && acf_v_history.empty()) { if (acf_x_history.empty() && acf_v_history.empty()) {
@ -2567,7 +2606,7 @@ int colvar::calc_acf()
cvm::error("Error: correlation function between \""+cfcv->name+ cvm::error("Error: correlation function between \""+cfcv->name+
"\" and \""+this->name+"\" cannot be calculated, " "\" and \""+this->name+"\" cannot be calculated, "
"because their value types are different.\n", "because their value types are different.\n",
INPUT_ERROR); COLVARS_INPUT_ERROR);
} }
acf_nframes = 0; acf_nframes = 0;
@ -2761,7 +2800,7 @@ int colvar::write_acf(std::ostream &os)
(*acf_i)/(cvm::real(acf_nframes)) ) << "\n"; (*acf_i)/(cvm::real(acf_nframes)) ) << "\n";
} }
return os.good() ? COLVARS_OK : FILE_ERROR; return os.good() ? COLVARS_OK : COLVARS_FILE_ERROR;
} }

View File

@ -272,9 +272,16 @@ public:
private: private:
/// Parse the CVC configuration for all components of a certain type /// Parse the CVC configuration for all components of a certain type
template<typename def_class_name> int init_components_type(std::string const &conf, template<typename def_class_name> int init_components_type(std::string const & conf,
char const *def_desc, char const *def_desc,
char const *def_config_key); char const *def_config_key);
#if (__cplusplus >= 201103L)
/// For the C++11 case, the names of all available components are
/// registered in the global map at first, and then the CVC configuration
/// is parsed by this function
int init_components_type_from_global_map(const std::string& conf,
const char* def_config_key);
#endif
public: public:
@ -346,6 +353,9 @@ public:
/// return colvar energy if extended Lagrandian active /// return colvar energy if extended Lagrandian active
cvm::real update_forces_energy(); cvm::real update_forces_energy();
/// \brief Integrate equations of motion of extended Lagrangian coordinate if needed
void update_extended_Lagrangian();
/// \brief Communicate forces (previously calculated in /// \brief Communicate forces (previously calculated in
/// colvar::update()) to the external degrees of freedom /// colvar::update()) to the external degrees of freedom
void communicate_forces(); void communicate_forces();
@ -592,6 +602,7 @@ public:
class alpha_angles; class alpha_angles;
class dihedPC; class dihedPC;
class alch_lambda; class alch_lambda;
class alch_Flambda;
class componentDisabled; class componentDisabled;
class CartesianBasedPath; class CartesianBasedPath;
class gspath; class gspath;
@ -605,6 +616,8 @@ public:
class euler_phi; class euler_phi;
class euler_psi; class euler_psi;
class euler_theta; class euler_theta;
class neuralNetwork;
class customColvar;
// non-scalar components // non-scalar components
class distance_vec; class distance_vec;
@ -623,6 +636,9 @@ public:
} }
#endif #endif
/// \brief function for sorting cvcs by their names
static bool compare_cvc(const colvar::cvc* const i, const colvar::cvc* const j);
protected: protected:
/// \brief Array of \link colvar::cvc \endlink objects /// \brief Array of \link colvar::cvc \endlink objects

View File

@ -63,15 +63,15 @@ namespace UIestimator {
temp.resize(dimension); temp.resize(dimension);
} }
int inline get_value(const std::vector<double> & x, const std::vector<double> & y) { int get_value(const std::vector<double> & x, const std::vector<double> & y) {
return matrix[convert_x(x)][convert_y(x, y)]; return matrix[convert_x(x)][convert_y(x, y)];
} }
void inline set_value(const std::vector<double> & x, const std::vector<double> & y, const int value) { void set_value(const std::vector<double> & x, const std::vector<double> & y, const int value) {
matrix[convert_x(x)][convert_y(x,y)] = value; matrix[convert_x(x)][convert_y(x,y)] = value;
} }
void inline increase_value(const std::vector<double> & x, const std::vector<double> & y, const int value) { void increase_value(const std::vector<double> & x, const std::vector<double> & y, const int value) {
matrix[convert_x(x)][convert_y(x,y)] += value; matrix[convert_x(x)][convert_y(x,y)] += value;
} }
@ -164,17 +164,18 @@ namespace UIestimator {
temp.resize(dimension); temp.resize(dimension);
} }
const T inline get_value(const std::vector<double> & x) { T & get_value(const std::vector<double> & x) {
return vector[convert_x(x)]; return vector[convert_x(x)];
} }
void inline set_value(const std::vector<double> & x, const T value) { void set_value(const std::vector<double> & x, const T value) {
vector[convert_x(x)] = value; vector[convert_x(x)] = value;
} }
void inline increase_value(const std::vector<double> & x, const T value) { void increase_value(const std::vector<double> & x, const T value) {
vector[convert_x(x)] += value; vector[convert_x(x)] += value;
} }
private: private:
std::vector<double> lowerboundary; std::vector<double> lowerboundary;
std::vector<double> upperboundary; std::vector<double> upperboundary;
@ -301,7 +302,8 @@ namespace UIestimator {
~UIestimator() {} ~UIestimator() {}
// called from MD engine every step // called from MD engine every step
bool update(cvm::step_number step, std::vector<double> x, std::vector<double> y) { bool update(cvm::step_number /* step */,
std::vector<double> x, std::vector<double> y) {
int i; int i;

View File

@ -0,0 +1,298 @@
#if (__cplusplus >= 201103L)
#include "colvar_neuralnetworkcompute.h"
#include "colvarparse.h"
namespace neuralnetworkCV {
std::map<std::string, std::pair<std::function<double(double)>, std::function<double(double)>>> activation_function_map
{
{"tanh", {[](double x){return std::tanh(x);},
[](double x){return 1.0 - std::tanh(x) * std::tanh(x);}}},
{"sigmoid", {[](double x){return 1.0 / (1.0 + std::exp(-x));},
[](double x){return std::exp(-x) / ((1.0 + std::exp(-x)) * (1.0 + std::exp(-x)));}}},
{"linear", {[](double x){return x;},
[](double /*x*/){return 1.0;}}},
{"relu", {[](double x){return x < 0. ? 0. : x;},
[](double x){return x < 0. ? 0. : 1.;}}},
{"lrelu100", {[](double x){return x < 0. ? 0.01 * x : x;},
[](double x){return x < 0. ? 0.01 : 1.;}}},
{"elu", {[](double x){return x < 0. ? std::exp(x)-1. : x;},
[](double x){return x < 0. ? std::exp(x) : 1.;}}}
};
#ifdef LEPTON
customActivationFunction::customActivationFunction():
expression(), value_evaluator(nullptr), gradient_evaluator(nullptr),
input_reference(nullptr), derivative_reference(nullptr) {}
customActivationFunction::customActivationFunction(const std::string& expression_string):
expression(), value_evaluator(nullptr), gradient_evaluator(nullptr),
input_reference(nullptr), derivative_reference(nullptr) {
setExpression(expression_string);
}
customActivationFunction::customActivationFunction(const customActivationFunction& source):
expression(), value_evaluator(nullptr), gradient_evaluator(nullptr),
input_reference(nullptr), derivative_reference(nullptr) {
// check if the source object is initialized
if (source.value_evaluator != nullptr) {
this->setExpression(source.expression);
}
}
customActivationFunction& customActivationFunction::operator=(const customActivationFunction& source) {
if (source.value_evaluator != nullptr) {
this->setExpression(source.expression);
} else {
expression = std::string();
value_evaluator = nullptr;
gradient_evaluator = nullptr;
input_reference = nullptr;
derivative_reference = nullptr;
}
return *this;
}
void customActivationFunction::setExpression(const std::string& expression_string) {
expression = expression_string;
Lepton::ParsedExpression parsed_expression;
// the variable must be "x" for the input of an activation function
const std::string activation_input_variable{"x"};
// parse the expression
try {
parsed_expression = Lepton::Parser::parse(expression);
} catch (...) {
cvm::error("Error parsing or compiling expression \"" + expression + "\".\n", COLVARS_INPUT_ERROR);
}
// compile the expression
try {
value_evaluator = std::unique_ptr<Lepton::CompiledExpression>(new Lepton::CompiledExpression(parsed_expression.createCompiledExpression()));
} catch (...) {
cvm::error("Error compiling expression \"" + expression + "\".\n", COLVARS_INPUT_ERROR);
}
// create a compiled expression for the derivative
try {
gradient_evaluator = std::unique_ptr<Lepton::CompiledExpression>(new Lepton::CompiledExpression(parsed_expression.differentiate(activation_input_variable).createCompiledExpression()));
} catch (...) {
cvm::error("Error creating compiled expression for variable \"" + activation_input_variable + "\".\n", COLVARS_INPUT_ERROR);
}
// get the reference to the input variable in the compiled expression
try {
input_reference = &(value_evaluator->getVariableReference(activation_input_variable));
} catch (...) {
cvm::error("Error on getting the reference to variable \"" + activation_input_variable + "\" in the compiled expression.\n", COLVARS_INPUT_ERROR);
}
// get the reference to the input variable in the compiled derivative expression
try {
derivative_reference = &(gradient_evaluator->getVariableReference(activation_input_variable));
} catch (...) {
cvm::error("Error on getting the reference to variable \"" + activation_input_variable + "\" in the compiled derivative exprssion.\n", COLVARS_INPUT_ERROR);
}
}
std::string customActivationFunction::getExpression() const {
return expression;
}
double customActivationFunction::evaluate(double x) const {
*input_reference = x;
return value_evaluator->evaluate();
}
double customActivationFunction::derivative(double x) const {
*derivative_reference = x;
return gradient_evaluator->evaluate();
}
#endif
denseLayer::denseLayer(const std::string& weights_file, const std::string& biases_file, const std::function<double(double)>& f, const std::function<double(double)>& df): m_activation_function(f), m_activation_function_derivative(df) {
#ifdef LEPTON
m_use_custom_activation = false;
#endif
readFromFile(weights_file, biases_file);
}
#ifdef LEPTON
denseLayer::denseLayer(const std::string& weights_file, const std::string& biases_file, const std::string& custom_activation_expression) {
m_use_custom_activation = true;
m_custom_activation_function = customActivationFunction(custom_activation_expression);
readFromFile(weights_file, biases_file);
}
#endif
void denseLayer::readFromFile(const std::string& weights_file, const std::string& biases_file) {
// parse weights file
m_weights.clear();
m_biases.clear();
std::string line;
std::ifstream ifs_weights(weights_file.c_str());
if (!ifs_weights) {
throw std::runtime_error("Cannot open file " + weights_file);
}
while (std::getline(ifs_weights, line)) {
if (ifs_weights.bad()) {
throw std::runtime_error("I/O error while reading " + weights_file);
}
std::vector<std::string> splitted_data;
colvarparse::split_string(line, std::string{" "}, splitted_data);
if (splitted_data.size() > 0) {
std::vector<double> weights_tmp(splitted_data.size());
for (size_t i = 0; i < splitted_data.size(); ++i) {
try {
weights_tmp[i] = std::stod(splitted_data[i]);
} catch (...) {
throw std::runtime_error("Cannot convert " + splitted_data[i] + " to a number while reading file " + weights_file);
}
}
m_weights.push_back(weights_tmp);
}
}
// parse biases file
std::ifstream ifs_biases(biases_file.c_str());
if (!ifs_biases) {
throw std::runtime_error("Cannot open file " + biases_file);
}
while (std::getline(ifs_biases, line)) {
if (ifs_biases.bad()) {
throw std::runtime_error("I/O error while reading " + biases_file);
}
std::vector<std::string> splitted_data;
colvarparse::split_string(line, std::string{" "}, splitted_data);
if (splitted_data.size() > 0) {
double bias = 0;
try {
bias = std::stod(splitted_data[0]);
} catch (...) {
throw std::runtime_error("Cannot convert " + splitted_data[0] + " to a number while reading file " + biases_file);
}
m_biases.push_back(bias);
}
}
m_input_size = m_weights[0].size();
m_output_size = m_weights.size();
}
void denseLayer::setActivationFunction(const std::function<double(double)>& f, const std::function<double(double)>& df) {
m_activation_function = f;
m_activation_function_derivative = df;
}
void denseLayer::compute(const std::vector<double>& input, std::vector<double>& output) const {
for (size_t i = 0; i < m_output_size; ++i) {
output[i] = 0;
for (size_t j = 0; j < m_input_size; ++j) {
output[i] += input[j] * m_weights[i][j];
}
output[i] += m_biases[i];
#ifdef LEPTON
if (m_use_custom_activation) {
output[i] = m_custom_activation_function.evaluate(output[i]);
} else {
#endif
output[i] = m_activation_function(output[i]);
#ifdef LEPTON
}
#endif
}
}
double denseLayer::computeGradientElement(const std::vector<double>& input, const size_t i, const size_t j) const {
double sum_with_bias = 0;
for (size_t j_in = 0; j_in < m_input_size; ++j_in) {
sum_with_bias += input[j_in] * m_weights[i][j_in];
}
sum_with_bias += m_biases[i];
#ifdef LEPTON
if (m_use_custom_activation) {
const double grad_ij = m_custom_activation_function.derivative(sum_with_bias) * m_weights[i][j];
return grad_ij;
} else {
#endif
const double grad_ij = m_activation_function_derivative(sum_with_bias) * m_weights[i][j];
return grad_ij;
#ifdef LEPTON
}
#endif
}
void denseLayer::computeGradient(const std::vector<double>& input, std::vector<std::vector<double>>& output_grad) const {
for (size_t j = 0; j < m_input_size; ++j) {
for (size_t i = 0; i < m_output_size; ++i) {
output_grad[i][j] = computeGradientElement(input, i, j);
}
}
}
neuralNetworkCompute::neuralNetworkCompute(const std::vector<denseLayer>& dense_layers): m_dense_layers(dense_layers) {
m_layers_output.resize(m_dense_layers.size());
m_grads_tmp.resize(m_dense_layers.size());
for (size_t i_layer = 0; i_layer < m_layers_output.size(); ++i_layer) {
m_layers_output[i_layer].assign(m_dense_layers[i_layer].getOutputSize(), 0);
m_grads_tmp[i_layer].assign(m_dense_layers[i_layer].getOutputSize(), std::vector<double>(m_dense_layers[i_layer].getInputSize(), 0));
}
}
bool neuralNetworkCompute::addDenseLayer(const denseLayer& layer) {
if (m_dense_layers.empty()) {
// add layer to this ann directly if m_dense_layers is empty
m_dense_layers.push_back(layer);
m_layers_output.push_back(std::vector<double>(layer.getOutputSize()));
m_grads_tmp.push_back(std::vector<std::vector<double>>(layer.getOutputSize(), std::vector<double>(layer.getInputSize(), 0)));
return true;
} else {
// otherwise, we need to check if the output of last layer in m_dense_layers matches the input of layer to be added
if (m_dense_layers.back().getOutputSize() == layer.getInputSize()) {
m_dense_layers.push_back(layer);
m_layers_output.push_back(std::vector<double>(layer.getOutputSize()));
m_grads_tmp.push_back(std::vector<std::vector<double>>(layer.getOutputSize(), std::vector<double>(layer.getInputSize(), 0)));
return true;
} else {
return false;
}
}
}
std::vector<std::vector<double>> neuralNetworkCompute::multiply_matrix(const std::vector<std::vector<double>>& A, const std::vector<std::vector<double>>& B) {
const size_t m = A.size();
const size_t n = B.size();
if (A[0].size() != n) {
std::cerr << "Error on multiplying matrices!\n";
}
const size_t t = B[0].size();
std::vector<std::vector<double>> C(m, std::vector<double>(t, 0.0));
for (size_t i = 0; i < m; ++i) {
for (size_t j = 0; j < t; ++j) {
for (size_t k = 0; k < n; ++k) {
C[i][j] += A[i][k] * B[k][j];
}
}
}
return C;
}
void neuralNetworkCompute::compute() {
if (m_dense_layers.empty()) {
return;
}
size_t i_layer;
m_dense_layers[0].compute(m_input, m_layers_output[0]);
for (i_layer = 1; i_layer < m_dense_layers.size(); ++i_layer) {
m_dense_layers[i_layer].compute(m_layers_output[i_layer - 1], m_layers_output[i_layer]);
}
// gradients of each layer
m_dense_layers[0].computeGradient(m_input, m_grads_tmp[0]);
for (i_layer = 1; i_layer < m_dense_layers.size(); ++i_layer) {
m_dense_layers[i_layer].computeGradient(m_layers_output[i_layer - 1], m_grads_tmp[i_layer]);
}
// chain rule
if (m_dense_layers.size() > 1) {
m_chained_grad = multiply_matrix(m_grads_tmp[1], m_grads_tmp[0]);
for (i_layer = 2; i_layer < m_dense_layers.size(); ++i_layer) {
m_chained_grad = multiply_matrix(m_grads_tmp[i_layer], m_chained_grad);
}
} else {
m_chained_grad = m_grads_tmp[0];
}
}
}
#endif

View File

@ -0,0 +1,140 @@
#if (__cplusplus >= 201103L)
#ifndef NEURALNETWORKCOMPUTE_H
#define NEURALNETWORKCOMPUTE_H
#include <vector>
#include <functional>
#include <string>
#include <iostream>
#include <cmath>
#include <memory>
#include <map>
#ifdef LEPTON
#include "Lepton.h"
#endif
namespace neuralnetworkCV {
/// mapping from a string to the activation function and its derivative
extern std::map<std::string, std::pair<std::function<double(double)>, std::function<double(double)>>> activation_function_map;
#ifdef LEPTON
// allow to define a custom activation function
class customActivationFunction {
public:
/// empty constructor
customActivationFunction();
/// construct by an mathematical expression
customActivationFunction(const std::string& expression_string);
/// copy constructor
customActivationFunction(const customActivationFunction& source);
/// overload assignment operator
customActivationFunction& operator=(const customActivationFunction& source);
/// setter for the custom expression
void setExpression(const std::string& expression_string);
/// getter for the custom expression
std::string getExpression() const;
/// evaluate the value of an expression
double evaluate(double x) const;
/// evaluate the gradient of an expression
double derivative(double x) const;
private:
std::string expression;
std::unique_ptr<Lepton::CompiledExpression> value_evaluator;
std::unique_ptr<Lepton::CompiledExpression> gradient_evaluator;
double* input_reference;
double* derivative_reference;
};
#endif
class denseLayer {
private:
size_t m_input_size;
size_t m_output_size;
std::function<double(double)> m_activation_function;
std::function<double(double)> m_activation_function_derivative;
#ifdef LEPTON
bool m_use_custom_activation;
customActivationFunction m_custom_activation_function;
#else
static const bool m_use_custom_activation = false;
#endif
/// weights[i][j] is the weight of the i-th output and the j-th input
std::vector<std::vector<double>> m_weights;
/// bias of each node
std::vector<double> m_biases;
public:
/// empty constructor
denseLayer() {}
/*! @param[in] weights_file filename of the weights file
* @param[in] biases_file filename of the biases file
* @param[in] f activation function
* @param[in] df derivative of the activation function
*/
denseLayer(const std::string& weights_file, const std::string& biases_file, const std::function<double(double)>& f, const std::function<double(double)>& df);
#ifdef LEPTON
/*! @param[in] weights_file filename of the weights file
* @param[in] biases_file filename of the biases file
* @param[in] custom_activation_expression the expression of the custom activation function
*/
denseLayer(const std::string& weights_file, const std::string& biases_file, const std::string& custom_activation_expression);
#endif
/// read data from file
void readFromFile(const std::string& weights_file, const std::string& biases_file);
/// setup activation function
void setActivationFunction(const std::function<double(double)>& f, const std::function<double(double)>& df);
/// compute the value of this layer
void compute(const std::vector<double>& input, std::vector<double>& output) const;
/// compute the gradient of i-th output wrt j-th input
double computeGradientElement(const std::vector<double>& input, const size_t i, const size_t j) const;
/// output[i][j] is the gradient of i-th output wrt j-th input
void computeGradient(const std::vector<double>& input, std::vector<std::vector<double>>& output_grad) const;
/// get the input size
size_t getInputSize() const {
return m_input_size;
}
/// get the output size
size_t getOutputSize() const {
return m_output_size;
}
/// getter for weights and biases
double getWeight(size_t i, size_t j) const {
return m_weights[i][j];
}
double getBias(size_t i) const {
return m_biases[i];
}
~denseLayer() {}
};
class neuralNetworkCompute {
private:
std::vector<denseLayer> m_dense_layers;
std::vector<double> m_input;
/// temporary output for each layer, useful to speedup the gradients' calculation
std::vector<std::vector<double>> m_layers_output;
std::vector<std::vector<std::vector<double>>> m_grads_tmp;
std::vector<std::vector<double>> m_chained_grad;
private:
/// helper function: multiply two matrix constructed from 2D vector
static std::vector<std::vector<double>> multiply_matrix(const std::vector<std::vector<double>>& A, const std::vector<std::vector<double>>& B);
public:
neuralNetworkCompute(): m_dense_layers(0), m_layers_output(0) {}
neuralNetworkCompute(const std::vector<denseLayer>& dense_layers);
bool addDenseLayer(const denseLayer& layer);
// for faster computation
const std::vector<double>& input() const {return m_input;}
std::vector<double>& input() {return m_input;}
/// compute the values and the gradients of all output nodes
void compute();
double getOutput(const size_t i) const {return m_layers_output.back()[i];}
double getGradient(const size_t i, const size_t j) const {return m_chained_grad[i][j];}
/// get a specified layer
const denseLayer& getLayer(const size_t i) const {return m_dense_layers[i];}
/// get the number of layers
size_t getNumberOfLayers() const {return m_dense_layers.size();}
};
}
#endif
#endif

View File

@ -77,6 +77,17 @@ cvm::atom::~atom()
} }
cvm::atom & cvm::atom::operator = (cvm::atom const &a)
{
index = a.index;
id = (cvm::proxy)->get_atom_id(index);
update_mass();
update_charge();
reset_data();
return *this;
}
cvm::atom_group::atom_group() cvm::atom_group::atom_group()
{ {
@ -163,12 +174,12 @@ int cvm::atom_group::add_atom_id(int aid)
int cvm::atom_group::remove_atom(cvm::atom_iter ai) int cvm::atom_group::remove_atom(cvm::atom_iter ai)
{ {
if (is_enabled(f_ag_scalable)) { if (is_enabled(f_ag_scalable)) {
cvm::error("Error: cannot remove atoms from a scalable group.\n", INPUT_ERROR); cvm::error("Error: cannot remove atoms from a scalable group.\n", COLVARS_INPUT_ERROR);
return COLVARS_ERROR; return COLVARS_ERROR;
} }
if (!this->size()) { if (!this->size()) {
cvm::error("Error: trying to remove an atom from an empty group.\n", INPUT_ERROR); cvm::error("Error: trying to remove an atom from an empty group.\n", COLVARS_INPUT_ERROR);
return COLVARS_ERROR; return COLVARS_ERROR;
} else { } else {
total_mass -= ai->mass; total_mass -= ai->mass;
@ -186,7 +197,7 @@ int cvm::atom_group::set_dummy()
if (atoms_ids.size() > 0) { if (atoms_ids.size() > 0) {
return cvm::error("Error: setting group with keyword \""+key+ return cvm::error("Error: setting group with keyword \""+key+
"\" and name \""+name+"\" as dummy, but it already " "\" and name \""+name+"\" as dummy, but it already "
"contains atoms.\n", INPUT_ERROR); "contains atoms.\n", COLVARS_INPUT_ERROR);
} }
b_dummy = true; b_dummy = true;
return COLVARS_OK; return COLVARS_OK;
@ -200,7 +211,7 @@ int cvm::atom_group::set_dummy_pos(cvm::atom_pos const &pos)
} else { } else {
return cvm::error("Error: setting dummy position for group with keyword \""+ return cvm::error("Error: setting dummy position for group with keyword \""+
key+"\" and name \""+name+ key+"\" and name \""+name+
"\", but it is not dummy.\n", INPUT_ERROR); "\", but it is not dummy.\n", COLVARS_INPUT_ERROR);
} }
return COLVARS_OK; return COLVARS_OK;
} }
@ -213,7 +224,7 @@ int cvm::atom_group::init()
// These may be overwritten by parse(), if a name is provided // These may be overwritten by parse(), if a name is provided
atoms.clear(); atoms.clear();
init_dependencies(); atom_group::init_dependencies();
index = -1; index = -1;
b_dummy = false; b_dummy = false;
@ -253,9 +264,12 @@ int cvm::atom_group::init_dependencies() {
// parallel calculation implies that we have at least a scalable center of mass, // parallel calculation implies that we have at least a scalable center of mass,
// but f_ag_scalable is kept as a separate feature to deal with future dependencies // but f_ag_scalable is kept as a separate feature to deal with future dependencies
init_feature(f_ag_scalable, "scalable_group", f_type_static); init_feature(f_ag_scalable, "scalable_group", f_type_dynamic);
init_feature(f_ag_scalable_com, "scalable_group_center_of_mass", f_type_static); init_feature(f_ag_scalable_com, "scalable_group_center_of_mass", f_type_static);
require_feature_self(f_ag_scalable, f_ag_scalable_com); require_feature_self(f_ag_scalable_com, f_ag_scalable);
init_feature(f_ag_collect_atom_ids, "collect_atom_ids", f_type_dynamic);
exclude_feature_self(f_ag_collect_atom_ids, f_ag_scalable);
// check that everything is initialized // check that everything is initialized
for (i = 0; i < colvardeps::f_ag_ntot; i++) { for (i = 0; i < colvardeps::f_ag_ntot; i++) {
@ -280,11 +294,11 @@ int cvm::atom_group::init_dependencies() {
// f_ag_scalable_com is provided by the CVC iff it is COM-based // f_ag_scalable_com is provided by the CVC iff it is COM-based
feature_states[f_ag_scalable_com].available = false; feature_states[f_ag_scalable_com].available = false;
// TODO make f_ag_scalable depend on f_ag_scalable_com (or something else)
feature_states[f_ag_scalable].available = true; feature_states[f_ag_scalable].available = true;
feature_states[f_ag_fit_gradients].available = true; feature_states[f_ag_fit_gradients].available = true;
feature_states[f_ag_fitting_group].available = true; feature_states[f_ag_fitting_group].available = true;
feature_states[f_ag_explicit_gradient].available = true; feature_states[f_ag_explicit_gradient].available = true;
feature_states[f_ag_collect_atom_ids].available = true;
return COLVARS_OK; return COLVARS_OK;
} }
@ -381,8 +395,8 @@ int cvm::atom_group::parse(std::string const &group_conf)
(cvm::atom_group_by_name(this->name) != this)) { (cvm::atom_group_by_name(this->name) != this)) {
cvm::error("Error: this atom group cannot have the same name, \""+this->name+ cvm::error("Error: this atom group cannot have the same name, \""+this->name+
"\", as another atom group.\n", "\", as another atom group.\n",
INPUT_ERROR); COLVARS_INPUT_ERROR);
return INPUT_ERROR; return COLVARS_INPUT_ERROR;
} }
cvm::main()->register_named_atom_group(this); cvm::main()->register_named_atom_group(this);
description = "atom group " + name; description = "atom group " + name;
@ -396,18 +410,23 @@ int cvm::atom_group::parse(std::string const &group_conf)
b_defined_center |= get_keyval_feature(this, group_conf, "centerToReference", f_ag_center, is_enabled(f_ag_center)); b_defined_center |= get_keyval_feature(this, group_conf, "centerToReference", f_ag_center, is_enabled(f_ag_center));
if (is_enabled(f_ag_center_origin) && ! is_enabled(f_ag_center)) { if (is_enabled(f_ag_center_origin) && ! is_enabled(f_ag_center)) {
return cvm::error("centerToReference may not be disabled if centerToOrigin is enabled.\n"); return cvm::error("centerToReference may not be disabled if centerToOrigin"
"is enabled.\n", COLVARS_INPUT_ERROR);
} }
// Legacy alias // Legacy alias
bool b_defined_rotate = get_keyval_feature(this, group_conf, "rotateReference", f_ag_rotate, false, parse_deprecated); bool b_defined_rotate = get_keyval_feature(this, group_conf, "rotateReference", f_ag_rotate, false, parse_deprecated);
b_defined_rotate |= get_keyval_feature(this, group_conf, "rotateToReference", f_ag_rotate, is_enabled(f_ag_rotate)); b_defined_rotate |= get_keyval_feature(this, group_conf, "rotateToReference", f_ag_rotate, is_enabled(f_ag_rotate));
if (is_enabled(f_ag_rotate) || is_enabled(f_ag_center) ||
is_enabled(f_ag_center_origin)) {
cvm::main()->cite_feature("Moving frame of reference");
}
// is the user setting explicit options? // is the user setting explicit options?
b_user_defined_fit = b_defined_center || b_defined_rotate; b_user_defined_fit = b_defined_center || b_defined_rotate;
if (is_available(f_ag_scalable_com) && !is_enabled(f_ag_rotate) && !is_enabled(f_ag_center)) { if (is_available(f_ag_scalable_com) && !is_enabled(f_ag_rotate) && !is_enabled(f_ag_center)) {
enable(f_ag_scalable_com); enable(f_ag_scalable_com);
enable(f_ag_scalable);
} }
{ {
@ -462,7 +481,7 @@ int cvm::atom_group::parse(std::string const &group_conf)
for (psii = psf_segids.begin(); psii < psf_segids.end(); ++psii) { for (psii = psf_segids.begin(); psii < psf_segids.end(); ++psii) {
if ( (psii->size() == 0) || (psii->size() > 4) ) { if ( (psii->size() == 0) || (psii->size() > 4) ) {
cvm::error("Error: invalid PSF segment identifier provided, \""+ cvm::error("Error: invalid PSF segment identifier provided, \""+
(*psii)+"\".\n", INPUT_ERROR); (*psii)+"\".\n", COLVARS_INPUT_ERROR);
} }
} }
@ -475,7 +494,7 @@ int cvm::atom_group::parse(std::string const &group_conf)
range_count++; range_count++;
if (psf_segids.size() && (range_count > psf_segids.size())) { if (psf_segids.size() && (range_count > psf_segids.size())) {
cvm::error("Error: more instances of \"atomNameResidueRange\" than " cvm::error("Error: more instances of \"atomNameResidueRange\" than "
"values of \"psfSegID\".\n", INPUT_ERROR); "values of \"psfSegID\".\n", COLVARS_INPUT_ERROR);
} else { } else {
parse_error |= add_atom_name_residue_range(psf_segids.size() ? parse_error |= add_atom_name_residue_range(psf_segids.size() ?
*psii : std::string(""), range_conf); *psii : std::string(""), range_conf);
@ -493,13 +512,13 @@ int cvm::atom_group::parse(std::string const &group_conf)
std::string atoms_col; std::string atoms_col;
if (!get_keyval(group_conf, "atomsCol", atoms_col, std::string(""))) { if (!get_keyval(group_conf, "atomsCol", atoms_col, std::string(""))) {
cvm::error("Error: parameter atomsCol is required if atomsFile is set.\n", cvm::error("Error: parameter atomsCol is required if atomsFile is set.\n",
INPUT_ERROR); COLVARS_INPUT_ERROR);
} }
double atoms_col_value; double atoms_col_value;
bool const atoms_col_value_defined = get_keyval(group_conf, "atomsColValue", atoms_col_value, 0.0); bool const atoms_col_value_defined = get_keyval(group_conf, "atomsColValue", atoms_col_value, 0.0);
if (atoms_col_value_defined && (!atoms_col_value)) { if (atoms_col_value_defined && (!atoms_col_value)) {
cvm::error("Error: atomsColValue, if provided, must be non-zero.\n", INPUT_ERROR); cvm::error("Error: atomsColValue, if provided, must be non-zero.\n", COLVARS_INPUT_ERROR);
} }
// NOTE: calls to add_atom() and/or add_atom_id() are in the proxy-implemented function // NOTE: calls to add_atom() and/or add_atom_id() are in the proxy-implemented function
@ -521,7 +540,7 @@ int cvm::atom_group::parse(std::string const &group_conf)
if (!(atoms_ids.size())) { if (!(atoms_ids.size())) {
parse_error |= cvm::error("Error: no atoms defined for atom group \""+ parse_error |= cvm::error("Error: no atoms defined for atom group \""+
key+"\".\n", INPUT_ERROR); key+"\".\n", COLVARS_INPUT_ERROR);
} }
// whether these atoms will ever receive forces or not // whether these atoms will ever receive forces or not
@ -595,7 +614,7 @@ int cvm::atom_group::add_atoms_of_group(atom_group const *ag)
if (cvm::get_error()) return COLVARS_ERROR; if (cvm::get_error()) return COLVARS_ERROR;
} else { } else {
cvm::error("Error: source atom group contains no atoms\".\n", INPUT_ERROR); cvm::error("Error: source atom group contains no atoms\".\n", COLVARS_INPUT_ERROR);
return COLVARS_ERROR; return COLVARS_ERROR;
} }
@ -633,7 +652,7 @@ int cvm::atom_group::add_atom_numbers(std::string const &numbers_conf)
if (cvm::get_error()) return COLVARS_ERROR; if (cvm::get_error()) return COLVARS_ERROR;
} else { } else {
cvm::error("Error: no numbers provided for \"" cvm::error("Error: no numbers provided for \""
"atomNumbers\".\n", INPUT_ERROR); "atomNumbers\".\n", COLVARS_INPUT_ERROR);
return COLVARS_ERROR; return COLVARS_ERROR;
} }
@ -657,7 +676,7 @@ int cvm::atom_group::add_index_group(std::string const &index_group_name)
if (i_group >= index_group_names.size()) { if (i_group >= index_group_names.size()) {
return cvm::error("Error: could not find index group "+ return cvm::error("Error: could not find index group "+
index_group_name+" among those already provided.\n", index_group_name+" among those already provided.\n",
INPUT_ERROR); COLVARS_INPUT_ERROR);
} }
int error_code = COLVARS_OK; int error_code = COLVARS_OK;
@ -709,7 +728,7 @@ int cvm::atom_group::add_atom_numbers_range(std::string const &range_conf)
if (cvm::get_error()) return COLVARS_ERROR; if (cvm::get_error()) return COLVARS_ERROR;
} else { } else {
cvm::error("Error: no valid definition for \"atomNumbersRange\", \""+ cvm::error("Error: no valid definition for \"atomNumbersRange\", \""+
range_conf+"\".\n", INPUT_ERROR); range_conf+"\".\n", COLVARS_INPUT_ERROR);
return COLVARS_ERROR; return COLVARS_ERROR;
} }
@ -795,16 +814,16 @@ int cvm::atom_group::parse_fitting_options(std::string const &group_conf)
key+"\" has already a reference group " key+"\" has already a reference group "
"for the rototranslational fit, which was communicated by the " "for the rototranslational fit, which was communicated by the "
"colvar component. You should not use fittingGroup " "colvar component. You should not use fittingGroup "
"in this case.\n", INPUT_ERROR); "in this case.\n", COLVARS_INPUT_ERROR);
return INPUT_ERROR; return COLVARS_INPUT_ERROR;
} }
cvm::log("Within atom group \""+key+"\":\n"); cvm::log("Within atom group \""+key+"\":\n");
fitting_group = new atom_group("fittingGroup"); fitting_group = new atom_group("fittingGroup");
if (fitting_group->parse(fitting_group_conf) == COLVARS_OK) { if (fitting_group->parse(fitting_group_conf) == COLVARS_OK) {
fitting_group->check_keywords(fitting_group_conf, "fittingGroup"); fitting_group->check_keywords(fitting_group_conf, "fittingGroup");
if (cvm::get_error()) { if (cvm::get_error()) {
cvm::error("Error setting up atom group \"fittingGroup\".", INPUT_ERROR); cvm::error("Error setting up atom group \"fittingGroup\".", COLVARS_INPUT_ERROR);
return INPUT_ERROR; return COLVARS_INPUT_ERROR;
} }
} }
enable(f_ag_fitting_group); enable(f_ag_fitting_group);
@ -830,7 +849,7 @@ int cvm::atom_group::parse_fitting_options(std::string const &group_conf)
bool found = get_keyval(group_conf, "refPositionsColValue", ref_pos_col_value, 0.0); bool found = get_keyval(group_conf, "refPositionsColValue", ref_pos_col_value, 0.0);
if (found && ref_pos_col_value == 0.0) { if (found && ref_pos_col_value == 0.0) {
cvm::error("Error: refPositionsColValue, " cvm::error("Error: refPositionsColValue, "
"if provided, must be non-zero.\n", INPUT_ERROR); "if provided, must be non-zero.\n", COLVARS_INPUT_ERROR);
return COLVARS_ERROR; return COLVARS_ERROR;
} }
} }
@ -850,14 +869,14 @@ int cvm::atom_group::parse_fitting_options(std::string const &group_conf)
key+ key+
"\" ("+cvm::to_str(group_for_fit->size())+ "\" ("+cvm::to_str(group_for_fit->size())+
"): to perform a rotational fit, "+ "): to perform a rotational fit, "+
"these numbers should be equal.\n", INPUT_ERROR); "these numbers should be equal.\n", COLVARS_INPUT_ERROR);
} }
// save the center of geometry of ref_pos and subtract it // save the center of geometry of ref_pos and subtract it
center_ref_pos(); center_ref_pos();
} else { } else {
cvm::error("Error: no reference positions provided.\n", INPUT_ERROR); cvm::error("Error: no reference positions provided.\n", COLVARS_INPUT_ERROR);
return COLVARS_ERROR; return COLVARS_ERROR;
} }
@ -921,7 +940,7 @@ int cvm::atom_group::create_sorted_ids()
return cvm::error("Error: duplicate atom IDs in atom group? (found " + return cvm::error("Error: duplicate atom IDs in atom group? (found " +
cvm::to_str(sorted_atoms_ids_list.size()) + cvm::to_str(sorted_atoms_ids_list.size()) +
" unique atom IDs instead of " + " unique atom IDs instead of " +
cvm::to_str(atoms_ids.size()) + ").\n", BUG_ERROR); cvm::to_str(atoms_ids.size()) + ").\n", COLVARS_BUG_ERROR);
} }
// Compute map between sorted and unsorted elements // Compute map between sorted and unsorted elements
@ -1059,12 +1078,12 @@ void cvm::atom_group::calc_apply_roto_translation()
void cvm::atom_group::apply_translation(cvm::rvector const &t) void cvm::atom_group::apply_translation(cvm::rvector const &t)
{ {
if (b_dummy) { if (b_dummy) {
cvm::error("Error: cannot translate the coordinates of a dummy atom group.\n", INPUT_ERROR); cvm::error("Error: cannot translate the coordinates of a dummy atom group.\n", COLVARS_INPUT_ERROR);
return; return;
} }
if (is_enabled(f_ag_scalable)) { if (is_enabled(f_ag_scalable)) {
cvm::error("Error: cannot translate the coordinates of a scalable atom group.\n", INPUT_ERROR); cvm::error("Error: cannot translate the coordinates of a scalable atom group.\n", COLVARS_INPUT_ERROR);
return; return;
} }
@ -1124,7 +1143,7 @@ int cvm::atom_group::calc_center_of_geometry()
for (cvm::atom_const_iter ai = this->begin(); ai != this->end(); ai++) { for (cvm::atom_const_iter ai = this->begin(); ai != this->end(); ai++) {
cog += ai->pos; cog += ai->pos;
} }
cog /= this->size(); cog /= cvm::real(this->size());
} }
return COLVARS_OK; return COLVARS_OK;
} }
@ -1154,7 +1173,7 @@ int cvm::atom_group::calc_dipole(cvm::atom_pos const &dipole_center)
{ {
if (b_dummy) { if (b_dummy) {
return cvm::error("Error: trying to compute the dipole " return cvm::error("Error: trying to compute the dipole "
"of a dummy group.\n", INPUT_ERROR); "of a dummy group.\n", COLVARS_INPUT_ERROR);
} }
dip.reset(); dip.reset();
for (cvm::atom_const_iter ai = this->begin(); ai != this->end(); ai++) { for (cvm::atom_const_iter ai = this->begin(); ai != this->end(); ai++) {
@ -1235,12 +1254,12 @@ std::vector<cvm::atom_pos> cvm::atom_group::positions() const
{ {
if (b_dummy) { if (b_dummy) {
cvm::error("Error: positions are not available " cvm::error("Error: positions are not available "
"from a dummy atom group.\n", INPUT_ERROR); "from a dummy atom group.\n", COLVARS_INPUT_ERROR);
} }
if (is_enabled(f_ag_scalable)) { if (is_enabled(f_ag_scalable)) {
cvm::error("Error: atomic positions are not available " cvm::error("Error: atomic positions are not available "
"from a scalable atom group.\n", INPUT_ERROR); "from a scalable atom group.\n", COLVARS_INPUT_ERROR);
} }
std::vector<cvm::atom_pos> x(this->size(), 0.0); std::vector<cvm::atom_pos> x(this->size(), 0.0);
@ -1256,12 +1275,12 @@ std::vector<cvm::atom_pos> cvm::atom_group::positions_shifted(cvm::rvector const
{ {
if (b_dummy) { if (b_dummy) {
cvm::error("Error: positions are not available " cvm::error("Error: positions are not available "
"from a dummy atom group.\n", INPUT_ERROR); "from a dummy atom group.\n", COLVARS_INPUT_ERROR);
} }
if (is_enabled(f_ag_scalable)) { if (is_enabled(f_ag_scalable)) {
cvm::error("Error: atomic positions are not available " cvm::error("Error: atomic positions are not available "
"from a scalable atom group.\n", INPUT_ERROR); "from a scalable atom group.\n", COLVARS_INPUT_ERROR);
} }
std::vector<cvm::atom_pos> x(this->size(), 0.0); std::vector<cvm::atom_pos> x(this->size(), 0.0);
@ -1277,12 +1296,12 @@ std::vector<cvm::rvector> cvm::atom_group::velocities() const
{ {
if (b_dummy) { if (b_dummy) {
cvm::error("Error: velocities are not available " cvm::error("Error: velocities are not available "
"from a dummy atom group.\n", INPUT_ERROR); "from a dummy atom group.\n", COLVARS_INPUT_ERROR);
} }
if (is_enabled(f_ag_scalable)) { if (is_enabled(f_ag_scalable)) {
cvm::error("Error: atomic velocities are not available " cvm::error("Error: atomic velocities are not available "
"from a scalable atom group.\n", INPUT_ERROR); "from a scalable atom group.\n", COLVARS_INPUT_ERROR);
} }
std::vector<cvm::rvector> v(this->size(), 0.0); std::vector<cvm::rvector> v(this->size(), 0.0);
@ -1298,12 +1317,12 @@ std::vector<cvm::rvector> cvm::atom_group::total_forces() const
{ {
if (b_dummy) { if (b_dummy) {
cvm::error("Error: total forces are not available " cvm::error("Error: total forces are not available "
"from a dummy atom group.\n", INPUT_ERROR); "from a dummy atom group.\n", COLVARS_INPUT_ERROR);
} }
if (is_enabled(f_ag_scalable)) { if (is_enabled(f_ag_scalable)) {
cvm::error("Error: atomic total forces are not available " cvm::error("Error: atomic total forces are not available "
"from a scalable atom group.\n", INPUT_ERROR); "from a scalable atom group.\n", COLVARS_INPUT_ERROR);
} }
std::vector<cvm::rvector> f(this->size(), 0.0); std::vector<cvm::rvector> f(this->size(), 0.0);
@ -1321,7 +1340,7 @@ cvm::rvector cvm::atom_group::total_force() const
{ {
if (b_dummy) { if (b_dummy) {
cvm::error("Error: total total forces are not available " cvm::error("Error: total total forces are not available "
"from a dummy atom group.\n", INPUT_ERROR); "from a dummy atom group.\n", COLVARS_INPUT_ERROR);
} }
if (is_enabled(f_ag_scalable)) { if (is_enabled(f_ag_scalable)) {

View File

@ -90,6 +90,9 @@ public:
/// Destructor /// Destructor
~atom(); ~atom();
/// Assignment operator (added to appease LGTM)
atom & operator = (atom const &a);
/// Set mutable data (everything except id and mass) to zero /// Set mutable data (everything except id and mass) to zero
inline void reset_data() inline void reset_data()
{ {

View File

@ -19,12 +19,13 @@
colvarbias::colvarbias(char const *key) colvarbias::colvarbias(char const *key)
{ {
bias_type = to_lower_cppstr(key); bias_type = colvarparse::to_lower_cppstr(key);
state_keyword = bias_type; state_keyword = bias_type;
description = "uninitialized " + cvm::to_str(key) + " bias"; rank = -1;
init_dependencies(); description = "uninitialized " + bias_type + " bias";
rank = 1;
colvarbias::init_dependencies();
time_step_factor = 1; time_step_factor = 1;
@ -32,38 +33,37 @@ colvarbias::colvarbias(char const *key)
b_output_energy = false; b_output_energy = false;
output_freq = cvm::restart_out_freq; output_freq = cvm::restart_out_freq;
reset(); colvarbias::reset();
state_file_step = 0L; state_file_step = 0L;
matching_state = false; matching_state = false;
biasing_force_scaling_factors = NULL;
} }
int colvarbias::init(std::string const &conf) int colvarbias::init(std::string const &conf)
{ {
colvarparse::init(conf); name = bias_type + cvm::to_str(rank);
colvarparse::set_string(conf);
size_t i = 0; size_t i = 0;
if (name.size() == 0) { if (num_variables() == 0) {
// First initialization
// first initialization
cvm::log("Initializing a new \""+bias_type+"\" instance.\n"); cvm::log("Initializing a new \""+bias_type+"\" instance.\n");
rank = cvm::main()->num_biases_type(bias_type);
get_keyval(conf, "name", name, bias_type+cvm::to_str(rank));
{ // Only allow setting a non-default name on first init
colvarbias *bias_with_name = cvm::bias_by_name(this->name); get_keyval(conf, "name", name, name);
if (bias_with_name != NULL) {
if ((bias_with_name->rank != this->rank) || colvarbias *bias_with_name = cvm::bias_by_name(this->name);
(bias_with_name->bias_type != this->bias_type)) { if (bias_with_name != NULL) {
cvm::error("Error: this bias cannot have the same name, \""+this->name+ if ((bias_with_name->rank != this->rank) ||
"\", as another bias.\n", INPUT_ERROR); (bias_with_name->bias_type != this->bias_type)) {
return INPUT_ERROR; cvm::error("Error: this bias cannot have the same name, \""+this->name+
} "\", as another bias.\n", COLVARS_INPUT_ERROR);
return COLVARS_INPUT_ERROR;
} }
} }
description = "bias " + name; description = "bias " + name;
{ {
@ -72,8 +72,8 @@ int colvarbias::init(std::string const &conf)
if (get_keyval(conf, "colvars", colvar_names)) { if (get_keyval(conf, "colvars", colvar_names)) {
if (num_variables()) { if (num_variables()) {
cvm::error("Error: cannot redefine the colvars that a bias was already defined on.\n", cvm::error("Error: cannot redefine the colvars that a bias was already defined on.\n",
INPUT_ERROR); COLVARS_INPUT_ERROR);
return INPUT_ERROR; return COLVARS_INPUT_ERROR;
} }
for (i = 0; i < colvar_names.size(); i++) { for (i = 0; i < colvar_names.size(); i++) {
add_colvar(colvar_names[i]); add_colvar(colvar_names[i]);
@ -82,8 +82,8 @@ int colvarbias::init(std::string const &conf)
} }
if (!num_variables()) { if (!num_variables()) {
cvm::error("Error: no collective variables specified.\n", INPUT_ERROR); cvm::error("Error: no collective variables specified.\n", COLVARS_INPUT_ERROR);
return INPUT_ERROR; return COLVARS_INPUT_ERROR;
} }
} else { } else {
@ -91,7 +91,6 @@ int colvarbias::init(std::string const &conf)
} }
colvar_values.resize(num_variables()); colvar_values.resize(num_variables());
for (i = 0; i < num_variables(); i++) { for (i = 0; i < num_variables(); i++) {
colvar_values[i].type(colvars[i]->value().type()); colvar_values[i].type(colvars[i]->value().type());
colvar_forces[i].type(colvar_values[i].type()); colvar_forces[i].type(colvar_values[i].type());
@ -117,6 +116,28 @@ int colvarbias::init(std::string const &conf)
return COLVARS_ERROR; return COLVARS_ERROR;
} }
// Use the scaling factors from a grid?
get_keyval_feature(this, conf, "scaledBiasingForce",
f_cvb_scale_biasing_force,
is_enabled(f_cvb_scale_biasing_force), parse_echo);
if (is_enabled(f_cvb_scale_biasing_force)) {
std::string biasing_force_scaling_factors_in_filename;
get_keyval(conf, "scaledBiasingForceFactorsGrid",
biasing_force_scaling_factors_in_filename, std::string());
std::ifstream is;
cvm::log("Reading scaling factors for the forces of bias " +
name + " from " + biasing_force_scaling_factors_in_filename);
is.open(biasing_force_scaling_factors_in_filename.c_str());
if (!is.is_open()) {
cvm::error("Error opening the grid file " +
biasing_force_scaling_factors_in_filename + " for reading");
}
biasing_force_scaling_factors = new colvar_grid_scalar(colvars);
biasing_force_scaling_factors->read_multicol(is, true);
biasing_force_scaling_factors_bin.assign(num_variables(), 0);
is.close();
}
// Now that children are defined, we can solve dependencies // Now that children are defined, we can solve dependencies
enable(f_cvb_active); enable(f_cvb_active);
if (cvm::debug()) print_state(); if (cvm::debug()) print_state();
@ -174,6 +195,9 @@ int colvarbias::init_dependencies() {
init_feature(f_cvb_write_ti_pmf, "write_TI_PMF", f_type_user); init_feature(f_cvb_write_ti_pmf, "write_TI_PMF", f_type_user);
require_feature_self(f_cvb_write_ti_pmf, f_cvb_calc_ti_samples); require_feature_self(f_cvb_write_ti_pmf, f_cvb_calc_ti_samples);
init_feature(f_cvb_scale_biasing_force, "scale_biasing_force", f_type_user);
require_feature_children(f_cvb_scale_biasing_force, f_cv_grid);
// check that everything is initialized // check that everything is initialized
for (i = 0; i < colvardeps::f_cvb_ntot; i++) { for (i = 0; i < colvardeps::f_cvb_ntot; i++) {
if (is_not_set(i)) { if (is_not_set(i)) {
@ -253,6 +277,12 @@ int colvarbias::clear()
} }
} }
if (biasing_force_scaling_factors != NULL) {
delete biasing_force_scaling_factors;
biasing_force_scaling_factors = NULL;
biasing_force_scaling_factors_bin.clear();
}
cv->config_changed(); cv->config_changed();
return COLVARS_OK; return COLVARS_OK;
@ -290,8 +320,8 @@ int colvarbias::add_colvar(std::string const &cv_name)
} else { } else {
cvm::error("Error: cannot find a colvar named \""+ cvm::error("Error: cannot find a colvar named \""+
cv_name+"\".\n", INPUT_ERROR); cv_name+"\".\n", COLVARS_INPUT_ERROR);
return INPUT_ERROR; return COLVARS_INPUT_ERROR;
} }
return COLVARS_OK; return COLVARS_OK;
@ -352,7 +382,16 @@ void colvarbias::communicate_forces()
if (! is_enabled(f_cvb_apply_force)) { if (! is_enabled(f_cvb_apply_force)) {
return; return;
} }
cvm::real biasing_force_factor = 1.0;
size_t i = 0; size_t i = 0;
if (is_enabled(f_cvb_scale_biasing_force)) {
for (i = 0; i < num_variables(); i++) {
biasing_force_scaling_factors_bin[i] = biasing_force_scaling_factors->current_bin_scalar(i);
}
if (biasing_force_scaling_factors->index_ok(biasing_force_scaling_factors_bin)) {
biasing_force_factor *= biasing_force_scaling_factors->value(biasing_force_scaling_factors_bin);
}
}
for (i = 0; i < num_variables(); i++) { for (i = 0; i < num_variables(); i++) {
if (cvm::debug()) { if (cvm::debug()) {
cvm::log("Communicating a force to colvar \""+ cvm::log("Communicating a force to colvar \""+
@ -364,9 +403,9 @@ void colvarbias::communicate_forces()
// which is why rescaling has to happen now: the colvar is not // which is why rescaling has to happen now: the colvar is not
// aware of this bias' time_step_factor // aware of this bias' time_step_factor
if (is_enabled(f_cvb_bypass_ext_lagrangian)) { if (is_enabled(f_cvb_bypass_ext_lagrangian)) {
variables(i)->add_bias_force_actual_value(cvm::real(time_step_factor) * colvar_forces[i]); variables(i)->add_bias_force_actual_value(cvm::real(time_step_factor) * colvar_forces[i] * biasing_force_factor);
} else { } else {
variables(i)->add_bias_force(cvm::real(time_step_factor) * colvar_forces[i]); variables(i)->add_bias_force(cvm::real(time_step_factor) * colvar_forces[i] * biasing_force_factor);
} }
previous_colvar_forces[i] = colvar_forces[i]; previous_colvar_forces[i] = colvar_forces[i];
} }
@ -437,7 +476,7 @@ int colvarbias::set_state_params(std::string const &conf)
if (check_name.size() == 0) { if (check_name.size() == 0) {
cvm::error("Error: \""+bias_type+"\" block within the restart file " cvm::error("Error: \""+bias_type+"\" block within the restart file "
"has no identifiers.\n", INPUT_ERROR); "has no identifiers.\n", COLVARS_INPUT_ERROR);
} }
if (check_name != this->name) { if (check_name != this->name) {
@ -491,7 +530,7 @@ std::istream & colvarbias::read_state(std::istream &is)
"\" bias \""+ "\" bias \""+
this->name+"\" at position "+ this->name+"\" at position "+
cvm::to_str(static_cast<size_t>(is.tellg()))+ cvm::to_str(static_cast<size_t>(is.tellg()))+
" in stream.\n", INPUT_ERROR); " in stream.\n", COLVARS_INPUT_ERROR);
is.clear(); is.clear();
is.seekg(start_pos, std::ios::beg); is.seekg(start_pos, std::ios::beg);
is.setstate(std::ios::failbit); is.setstate(std::ios::failbit);
@ -511,7 +550,7 @@ std::istream & colvarbias::read_state(std::istream &is)
cvm::error("Error: in reading state data for \""+bias_type+"\" bias \""+ cvm::error("Error: in reading state data for \""+bias_type+"\" bias \""+
this->name+"\" at position "+ this->name+"\" at position "+
cvm::to_str(static_cast<size_t>(is.tellg()))+ cvm::to_str(static_cast<size_t>(is.tellg()))+
" in stream.\n", INPUT_ERROR); " in stream.\n", COLVARS_INPUT_ERROR);
is.clear(); is.clear();
is.seekg(start_pos, std::ios::beg); is.seekg(start_pos, std::ios::beg);
is.setstate(std::ios::failbit); is.setstate(std::ios::failbit);
@ -538,9 +577,9 @@ int colvarbias::write_state_prefix(std::string const &prefix)
int error_code = COLVARS_OK; int error_code = COLVARS_OK;
if (os != NULL) { if (os != NULL) {
os->setf(std::ios::scientific, std::ios::floatfield); os->setf(std::ios::scientific, std::ios::floatfield);
error_code = write_state(*os).good() ? COLVARS_OK : FILE_ERROR; error_code = write_state(*os).good() ? COLVARS_OK : COLVARS_FILE_ERROR;
} else { } else {
error_code = FILE_ERROR; error_code = COLVARS_FILE_ERROR;
} }
cvm::proxy->close_output_stream(filename.c_str()); cvm::proxy->close_output_stream(filename.c_str());
return error_code; return error_code;
@ -552,7 +591,7 @@ int colvarbias::write_state_string(std::string &output)
std::ostringstream os; std::ostringstream os;
if (!write_state(os)) { if (!write_state(os)) {
return cvm::error("Error: in writing state of bias \""+name+ return cvm::error("Error: in writing state of bias \""+name+
"\" to buffer.\n", FILE_ERROR); "\" to buffer.\n", COLVARS_FILE_ERROR);
} }
output = os.str(); output = os.str();
return COLVARS_OK; return COLVARS_OK;
@ -571,7 +610,7 @@ int colvarbias::read_state_prefix(std::string const &prefix)
} }
return read_state(is).good() ? COLVARS_OK : return read_state(is).good() ? COLVARS_OK :
cvm::error("Error: in reading state for \""+name+"\" from input file \""+ cvm::error("Error: in reading state for \""+name+"\" from input file \""+
std::string(filename)+"\".\n", FILE_ERROR); std::string(filename)+"\".\n", COLVARS_FILE_ERROR);
} }
@ -589,12 +628,12 @@ int colvarbias::read_state_string(char const *buffer)
is.rdbuf()->pubsetbuf(const_cast<char *>(buffer), buffer_size); is.rdbuf()->pubsetbuf(const_cast<char *>(buffer), buffer_size);
return read_state(is).good() ? COLVARS_OK : return read_state(is).good() ? COLVARS_OK :
cvm::error("Error: in reading state for \""+name+"\" from buffer.\n", cvm::error("Error: in reading state for \""+name+"\" from buffer.\n",
FILE_ERROR); COLVARS_FILE_ERROR);
} }
return COLVARS_OK; return COLVARS_OK;
} }
return cvm::error("Error: NULL pointer for colvarbias::read_state_string()", return cvm::error("Error: NULL pointer for colvarbias::read_state_string()",
BUG_ERROR); COLVARS_BUG_ERROR);
} }
@ -607,7 +646,7 @@ std::istream & colvarbias::read_state_data_key(std::istream &is, char const *key
cvm::error("Error: in reading restart configuration for "+ cvm::error("Error: in reading restart configuration for "+
bias_type+" bias \""+this->name+"\" at position "+ bias_type+" bias \""+this->name+"\" at position "+
cvm::to_str(static_cast<size_t>(is.tellg()))+ cvm::to_str(static_cast<size_t>(is.tellg()))+
" in stream.\n", INPUT_ERROR); " in stream.\n", COLVARS_INPUT_ERROR);
is.clear(); is.clear();
is.seekg(start_pos, std::ios::beg); is.seekg(start_pos, std::ios::beg);
is.setstate(std::ios::failbit); is.setstate(std::ios::failbit);
@ -710,13 +749,17 @@ int colvarbias_ti::init(std::string const &conf)
return cvm::error("Error: cannot collect TI samples while other " return cvm::error("Error: cannot collect TI samples while other "
"time-dependent biases are active and not all " "time-dependent biases are active and not all "
"variables have subtractAppliedForces on.\n", "variables have subtractAppliedForces on.\n",
INPUT_ERROR); COLVARS_INPUT_ERROR);
} }
} }
} }
} }
} }
if (is_enabled(f_cvb_write_ti_pmf) || is_enabled(f_cvb_write_ti_samples)) {
cvm::main()->cite_feature("Internal-forces free energy estimator");
}
return error_code; return error_code;
} }

View File

@ -14,6 +14,7 @@
#include "colvarparse.h" #include "colvarparse.h"
#include "colvardeps.h" #include "colvardeps.h"
class colvar_grid_scalar;
/// \brief Collective variable bias, base class /// \brief Collective variable bias, base class
class colvarbias class colvarbias
@ -29,7 +30,7 @@ public:
/// Keyword used in state files (== bias_type most of the time) /// Keyword used in state files (== bias_type most of the time)
std::string state_keyword; std::string state_keyword;
/// If there is more than one bias of this type, record its rank /// Track how many times a bias of this type was defined
int rank; int rank;
/// Add a new collective variable to this bias /// Add a new collective variable to this bias
@ -256,6 +257,10 @@ protected:
/// Flag used to tell if the state string being read is for this bias /// Flag used to tell if the state string being read is for this bias
bool matching_state; bool matching_state;
/// \brief The biasing forces will be scaled by the factor in this grid
/// if b_bias_force_scaled is true
colvar_grid_scalar* biasing_force_scaling_factors;
std::vector<int> biasing_force_scaling_factors_bin;
}; };

View File

@ -39,6 +39,7 @@ colvarbias_abf::colvarbias_abf(char const *key)
int colvarbias_abf::init(std::string const &conf) int colvarbias_abf::init(std::string const &conf)
{ {
colvarbias::init(conf); colvarbias::init(conf);
cvm::main()->cite_feature("ABF colvar bias implementation");
colvarproxy *proxy = cvm::main()->proxy; colvarproxy *proxy = cvm::main()->proxy;
@ -81,11 +82,11 @@ int colvarbias_abf::init(std::string const &conf)
if (history_freq != 0) { if (history_freq != 0) {
if (output_freq == 0) { if (output_freq == 0) {
cvm::error("Error: historyFreq must be a multiple of outputFreq.\n", cvm::error("Error: historyFreq must be a multiple of outputFreq.\n",
INPUT_ERROR); COLVARS_INPUT_ERROR);
} else { } else {
if ((history_freq % output_freq) != 0) { if ((history_freq % output_freq) != 0) {
cvm::error("Error: historyFreq must be a multiple of outputFreq.\n", cvm::error("Error: historyFreq must be a multiple of outputFreq.\n",
INPUT_ERROR); COLVARS_INPUT_ERROR);
} }
} }
} }
@ -94,10 +95,11 @@ int colvarbias_abf::init(std::string const &conf)
// shared ABF // shared ABF
get_keyval(conf, "shared", shared_on, false); get_keyval(conf, "shared", shared_on, false);
if (shared_on) { if (shared_on) {
cvm::main()->cite_feature("Multiple-walker ABF implementation");
if ((proxy->replica_enabled() != COLVARS_OK) || if ((proxy->replica_enabled() != COLVARS_OK) ||
(proxy->num_replicas() <= 1)) { (proxy->num_replicas() <= 1)) {
return cvm::error("Error: shared ABF requires more than one replica.", return cvm::error("Error: shared ABF requires more than one replica.",
INPUT_ERROR); COLVARS_INPUT_ERROR);
} }
cvm::log("shared ABF will be applied among "+ cvm::log("shared ABF will be applied among "+
cvm::to_str(proxy->num_replicas()) + " replicas.\n"); cvm::to_str(proxy->num_replicas()) + " replicas.\n");
@ -156,6 +158,12 @@ int colvarbias_abf::init(std::string const &conf)
// and make it just a warning if some parameter is set? // and make it just a warning if some parameter is set?
} }
if (b_extended) {
cvm::main()->cite_feature("eABF implementation");
} else {
cvm::main()->cite_feature("Internal-forces free energy estimator");
}
if (get_keyval(conf, "maxForce", max_force)) { if (get_keyval(conf, "maxForce", max_force)) {
if (max_force.size() != num_variables()) { if (max_force.size() != num_variables()) {
cvm::error("Error: Number of parameters to maxForce does not match number of colvars."); cvm::error("Error: Number of parameters to maxForce does not match number of colvars.");
@ -188,6 +196,9 @@ int colvarbias_abf::init(std::string const &conf)
// Data for eAB F z-based estimator // Data for eAB F z-based estimator
if ( b_extended ) { if ( b_extended ) {
get_keyval(conf, "CZARestimator", b_CZAR_estimator, true); get_keyval(conf, "CZARestimator", b_CZAR_estimator, true);
if ( b_CZAR_estimator ) {
cvm::main()->cite_feature("CZAR eABF estimator");
}
// CZAR output files for stratified eABF // CZAR output files for stratified eABF
get_keyval(conf, "writeCZARwindowFile", b_czar_window_file, false, get_keyval(conf, "writeCZARwindowFile", b_czar_window_file, false,
colvarparse::parse_silent); colvarparse::parse_silent);
@ -214,7 +225,7 @@ int colvarbias_abf::init(std::string const &conf)
czar_pmf = new integrate_potential(colvars, czar_gradients); czar_pmf = new integrate_potential(colvars, czar_gradients);
} }
// Parameters for integrating initial (and final) gradient data // Parameters for integrating initial (and final) gradient data
get_keyval(conf, "integrateMaxIterations", integrate_iterations, 1e4, colvarparse::parse_silent); get_keyval(conf, "integrateMaxIterations", integrate_iterations, 10000, colvarparse::parse_silent);
get_keyval(conf, "integrateTol", integrate_tol, 1e-6, colvarparse::parse_silent); get_keyval(conf, "integrateTol", integrate_tol, 1e-6, colvarparse::parse_silent);
// Projected ABF, updating the integrated PMF on the fly // Projected ABF, updating the integrated PMF on the fly
get_keyval(conf, "pABFintegrateFreq", pabf_freq, 0, colvarparse::parse_silent); get_keyval(conf, "pABFintegrateFreq", pabf_freq, 0, colvarparse::parse_silent);
@ -243,20 +254,21 @@ int colvarbias_abf::init(std::string const &conf)
get_keyval(conf, "UIestimator", b_UI_estimator, false); get_keyval(conf, "UIestimator", b_UI_estimator, false);
if (b_UI_estimator) { if (b_UI_estimator) {
std::vector<double> UI_lowerboundary;
std::vector<double> UI_upperboundary;
std::vector<double> UI_width;
std::vector<double> UI_krestr;
bool UI_restart = (input_prefix.size() > 0); cvm::main()->cite_feature("Umbrella-integration eABF estimator");
std::vector<double> UI_lowerboundary;
std::vector<double> UI_upperboundary;
std::vector<double> UI_width;
std::vector<double> UI_krestr;
for (i = 0; i < num_variables(); i++) bool UI_restart = (input_prefix.size() > 0);
{
UI_lowerboundary.push_back(colvars[i]->lower_boundary); for (i = 0; i < num_variables(); i++) {
UI_upperboundary.push_back(colvars[i]->upper_boundary); UI_lowerboundary.push_back(colvars[i]->lower_boundary);
UI_width.push_back(colvars[i]->width); UI_upperboundary.push_back(colvars[i]->upper_boundary);
UI_krestr.push_back(colvars[i]->force_constant()); UI_width.push_back(colvars[i]->width);
} UI_krestr.push_back(colvars[i]->force_constant());
}
eabf_UI = UIestimator::UIestimator(UI_lowerboundary, eabf_UI = UIestimator::UIestimator(UI_lowerboundary,
UI_upperboundary, UI_upperboundary,
UI_width, UI_width,
@ -412,7 +424,7 @@ int colvarbias_abf::update()
// Compute and apply the new bias, if applicable // Compute and apply the new bias, if applicable
if (is_enabled(f_cvb_apply_force) && samples->index_ok(bin)) { if (is_enabled(f_cvb_apply_force) && samples->index_ok(bin)) {
cvm::real count = samples->value(bin); cvm::real count = cvm::real(samples->value(bin));
cvm::real fact = 1.0; cvm::real fact = 1.0;
// Factor that ensures smooth introduction of the force // Factor that ensures smooth introduction of the force
@ -442,13 +454,13 @@ int colvarbias_abf::update()
// This is enforced naturally if using integrated PMF // This is enforced naturally if using integrated PMF
colvar_forces[0].real_value = fact * (grad[0] - gradients->average ()); colvar_forces[0].real_value = fact * (grad[0] - gradients->average ());
} else { } else {
for (size_t i = 0; i < num_variables(); i++) { for (i = 0; i < num_variables(); i++) {
// subtracting the mean force (opposite of the FE gradient) means adding the gradient // subtracting the mean force (opposite of the FE gradient) means adding the gradient
colvar_forces[i].real_value = fact * grad[i]; colvar_forces[i].real_value = fact * grad[i];
} }
} }
if (cap_force) { if (cap_force) {
for (size_t i = 0; i < num_variables(); i++) { for (i = 0; i < num_variables(); i++) {
if ( colvar_forces[i].real_value * colvar_forces[i].real_value > max_force[i] * max_force[i] ) { if ( colvar_forces[i].real_value * colvar_forces[i].real_value > max_force[i] * max_force[i] ) {
colvar_forces[i].real_value = (colvar_forces[i].real_value > 0 ? max_force[i] : -1.0 * max_force[i]); colvar_forces[i].real_value = (colvar_forces[i].real_value > 0 ? max_force[i] : -1.0 * max_force[i]);
} }
@ -484,7 +496,7 @@ int colvarbias_abf::update()
{ {
std::vector<double> x(num_variables(),0); std::vector<double> x(num_variables(),0);
std::vector<double> y(num_variables(),0); std::vector<double> y(num_variables(),0);
for (size_t i = 0; i < num_variables(); i++) for (i = 0; i < num_variables(); i++)
{ {
x[i] = colvars[i]->actual_value(); x[i] = colvars[i]->actual_value();
y[i] = colvars[i]->value(); y[i] = colvars[i]->value();
@ -589,7 +601,7 @@ template <class T> int colvarbias_abf::write_grid_to_file(T const *grid,
bool close) { bool close) {
std::ostream *os = cvm::proxy->output_stream(filename); std::ostream *os = cvm::proxy->output_stream(filename);
if (!os) { if (!os) {
return cvm::error("Error opening file " + filename + " for writing.\n", COLVARS_ERROR | FILE_ERROR); return cvm::error("Error opening file " + filename + " for writing.\n", COLVARS_ERROR | COLVARS_FILE_ERROR);
} }
grid->write_multicol(*os); grid->write_multicol(*os);
if (close) { if (close) {
@ -607,7 +619,7 @@ template <class T> int colvarbias_abf::write_grid_to_file(T const *grid,
std::string dx = filename + ".dx"; std::string dx = filename + ".dx";
std::ostream *dx_os = cvm::proxy->output_stream(dx); std::ostream *dx_os = cvm::proxy->output_stream(dx);
if (!dx_os) { if (!dx_os) {
return cvm::error("Error opening file " + dx + " for writing.\n", COLVARS_ERROR | FILE_ERROR); return cvm::error("Error opening file " + dx + " for writing.\n", COLVARS_ERROR | COLVARS_FILE_ERROR);
} }
grid->write_opendx(*dx_os); grid->write_opendx(*dx_os);
// if (close) { // if (close) {
@ -709,7 +721,7 @@ void colvarbias_abf::read_gradients_samples()
is.open(gradients_in_name.c_str()); is.open(gradients_in_name.c_str());
if (!is.is_open()) { if (!is.is_open()) {
cvm::error("Error opening ABF gradient file " + cvm::error("Error opening ABF gradient file " +
gradients_in_name + " for reading", INPUT_ERROR); gradients_in_name + " for reading", COLVARS_INPUT_ERROR);
} else { } else {
gradients->read_multicol(is, true); gradients->read_multicol(is, true);
is.close(); is.close();
@ -765,7 +777,7 @@ std::ostream & colvarbias_abf::write_state_data(std::ostream& os)
std::istream & colvarbias_abf::read_state_data(std::istream& is) std::istream & colvarbias_abf::read_state_data(std::istream& is)
{ {
if ( input_prefix.size() > 0 ) { if ( input_prefix.size() > 0 ) {
cvm::error("ERROR: cannot provide both inputPrefix and a colvars state file.\n", INPUT_ERROR); cvm::error("ERROR: cannot provide both inputPrefix and a colvars state file.\n", COLVARS_INPUT_ERROR);
} }
if (! read_state_data_key(is, "samples")) { if (! read_state_data_key(is, "samples")) {

View File

@ -37,6 +37,7 @@ colvarbias_alb::colvarbias_alb(char const *key)
int colvarbias_alb::init(std::string const &conf) int colvarbias_alb::init(std::string const &conf)
{ {
colvarbias::init(conf); colvarbias::init(conf);
cvm::main()->cite_feature("ALB colvar bias implementation");
enable(f_cvb_scalar_variables); enable(f_cvb_scalar_variables);
@ -73,21 +74,21 @@ int colvarbias_alb::init(std::string const &conf)
} }
} else { } else {
colvar_centers.clear(); colvar_centers.clear();
cvm::fatal_error("Error: must define the initial centers of adaptive linear bias .\n"); cvm::error("Error: must define the initial centers of adaptive linear bias .\n");
} }
if (colvar_centers.size() != num_variables()) if (colvar_centers.size() != num_variables())
cvm::fatal_error("Error: number of centers does not match " cvm::error("Error: number of centers does not match "
"that of collective variables.\n"); "that of collective variables.\n");
if (!get_keyval(conf, "UpdateFrequency", update_freq, 0)) if (!get_keyval(conf, "UpdateFrequency", update_freq, 0))
cvm::fatal_error("Error: must set updateFrequency for adaptive linear bias.\n"); cvm::error("Error: must set updateFrequency for adaptive linear bias.\n");
//we split the time between updating and equilibrating //we split the time between updating and equilibrating
update_freq /= 2; update_freq /= 2;
if (update_freq <= 1) if (update_freq <= 1)
cvm::fatal_error("Error: must set updateFrequency to greater than 2.\n"); cvm::error("Error: must set updateFrequency to greater than 2.\n");
enable(f_cvb_history_dependent); enable(f_cvb_history_dependent);
@ -253,31 +254,31 @@ int colvarbias_alb::set_state_params(std::string const &conf)
} }
if (!get_keyval(conf, "setCoupling", set_coupling)) if (!get_keyval(conf, "setCoupling", set_coupling))
cvm::fatal_error("Error: current setCoupling is missing from the restart.\n"); cvm::error("Error: current setCoupling is missing from the restart.\n");
if (!get_keyval(conf, "currentCoupling", current_coupling)) if (!get_keyval(conf, "currentCoupling", current_coupling))
cvm::fatal_error("Error: current setCoupling is missing from the restart.\n"); cvm::error("Error: current setCoupling is missing from the restart.\n");
if (!get_keyval(conf, "maxCouplingRange", max_coupling_range)) if (!get_keyval(conf, "maxCouplingRange", max_coupling_range))
cvm::fatal_error("Error: maxCouplingRange is missing from the restart.\n"); cvm::error("Error: maxCouplingRange is missing from the restart.\n");
if (!get_keyval(conf, "couplingRate", coupling_rate)) if (!get_keyval(conf, "couplingRate", coupling_rate))
cvm::fatal_error("Error: current setCoupling is missing from the restart.\n"); cvm::error("Error: current setCoupling is missing from the restart.\n");
if (!get_keyval(conf, "couplingAccum", coupling_accum)) if (!get_keyval(conf, "couplingAccum", coupling_accum))
cvm::fatal_error("Error: couplingAccum is missing from the restart.\n"); cvm::error("Error: couplingAccum is missing from the restart.\n");
if (!get_keyval(conf, "mean", means)) if (!get_keyval(conf, "mean", means))
cvm::fatal_error("Error: current mean is missing from the restart.\n"); cvm::error("Error: current mean is missing from the restart.\n");
if (!get_keyval(conf, "ssd", ssd)) if (!get_keyval(conf, "ssd", ssd))
cvm::fatal_error("Error: current ssd is missing from the restart.\n"); cvm::error("Error: current ssd is missing from the restart.\n");
if (!get_keyval(conf, "updateCalls", update_calls)) if (!get_keyval(conf, "updateCalls", update_calls))
cvm::fatal_error("Error: current updateCalls is missing from the restart.\n"); cvm::error("Error: current updateCalls is missing from the restart.\n");
if (!get_keyval(conf, "b_equilibration", b_equilibration)) if (!get_keyval(conf, "b_equilibration", b_equilibration))
cvm::fatal_error("Error: current updateCalls is missing from the restart.\n"); cvm::error("Error: current updateCalls is missing from the restart.\n");
return COLVARS_OK; return COLVARS_OK;
} }

View File

@ -24,6 +24,7 @@ colvarbias_histogram::colvarbias_histogram(char const *key)
int colvarbias_histogram::init(std::string const &conf) int colvarbias_histogram::init(std::string const &conf)
{ {
colvarbias::init(conf); colvarbias::init(conf);
cvm::main()->cite_feature("Histogram colvar bias implementation");
enable(f_cvb_scalar_variables); enable(f_cvb_scalar_variables);
enable(f_cvb_history_dependent); enable(f_cvb_history_dependent);
@ -48,27 +49,27 @@ int colvarbias_histogram::init(std::string const &conf)
if (colvar_array) { if (colvar_array) {
for (i = 0; i < num_variables(); i++) { // should be all vector for (i = 0; i < num_variables(); i++) { // should be all vector
if (colvars[i]->value().type() != colvarvalue::type_vector) { if (colvars[i]->value().type() != colvarvalue::type_vector) {
cvm::error("Error: used gatherVectorColvars with non-vector colvar.\n", INPUT_ERROR); cvm::error("Error: used gatherVectorColvars with non-vector colvar.\n", COLVARS_INPUT_ERROR);
return INPUT_ERROR; return COLVARS_INPUT_ERROR;
} }
if (i == 0) { if (i == 0) {
colvar_array_size = colvars[i]->value().size(); colvar_array_size = colvars[i]->value().size();
if (colvar_array_size < 1) { if (colvar_array_size < 1) {
cvm::error("Error: vector variable has dimension less than one.\n", INPUT_ERROR); cvm::error("Error: vector variable has dimension less than one.\n", COLVARS_INPUT_ERROR);
return INPUT_ERROR; return COLVARS_INPUT_ERROR;
} }
} else { } else {
if (colvar_array_size != colvars[i]->value().size()) { if (colvar_array_size != colvars[i]->value().size()) {
cvm::error("Error: trying to combine vector colvars of different lengths.\n", INPUT_ERROR); cvm::error("Error: trying to combine vector colvars of different lengths.\n", COLVARS_INPUT_ERROR);
return INPUT_ERROR; return COLVARS_INPUT_ERROR;
} }
} }
} }
} else { } else {
for (i = 0; i < num_variables(); i++) { // should be all scalar for (i = 0; i < num_variables(); i++) { // should be all scalar
if (colvars[i]->value().type() != colvarvalue::type_scalar) { if (colvars[i]->value().type() != colvarvalue::type_scalar) {
cvm::error("Error: only scalar colvars are supported when gatherVectorColvars is off.\n", INPUT_ERROR); cvm::error("Error: only scalar colvars are supported when gatherVectorColvars is off.\n", COLVARS_INPUT_ERROR);
return INPUT_ERROR; return COLVARS_INPUT_ERROR;
} }
} }
} }
@ -184,7 +185,7 @@ int colvarbias_histogram::write_output_files()
std::ostream *grid_os = cvm::proxy->output_stream(out_name); std::ostream *grid_os = cvm::proxy->output_stream(out_name);
if (!grid_os) { if (!grid_os) {
return cvm::error("Error opening histogram file "+out_name+ return cvm::error("Error opening histogram file "+out_name+
" for writing.\n", FILE_ERROR); " for writing.\n", COLVARS_FILE_ERROR);
} }
grid->write_multicol(*grid_os); grid->write_multicol(*grid_os);
cvm::proxy->close_output_stream(out_name); cvm::proxy->close_output_stream(out_name);
@ -196,7 +197,7 @@ int colvarbias_histogram::write_output_files()
std::ostream *grid_os = cvm::proxy->output_stream(out_name_dx); std::ostream *grid_os = cvm::proxy->output_stream(out_name_dx);
if (!grid_os) { if (!grid_os) {
return cvm::error("Error opening histogram file "+out_name_dx+ return cvm::error("Error opening histogram file "+out_name_dx+
" for writing.\n", FILE_ERROR); " for writing.\n", COLVARS_FILE_ERROR);
} }
grid->write_opendx(*grid_os); grid->write_opendx(*grid_os);
cvm::proxy->close_output_stream(out_name_dx); cvm::proxy->close_output_stream(out_name_dx);

View File

@ -0,0 +1,393 @@
// -*- c++ -*-
// 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
// 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.
#include "colvarbias_histogram_reweight_amd.h"
#include "colvarproxy.h"
colvarbias_reweightaMD::colvarbias_reweightaMD(char const *key)
: colvarbias_histogram(key), grid_count(NULL), grid_dV(NULL),
grid_dV_square(NULL), pmf_grid_exp_avg(NULL), pmf_grid_cumulant(NULL),
grad_grid_exp_avg(NULL), grad_grid_cumulant(NULL)
{
}
colvarbias_reweightaMD::~colvarbias_reweightaMD() {
if (grid_dV) {
delete grid_dV;
grid_dV = NULL;
}
if (grid_dV_square) {
delete grid_dV_square;
grid_dV_square = NULL;
}
if (grid_count) {
delete grid_count;
grid_count = NULL;
}
if (pmf_grid_exp_avg) {
delete pmf_grid_exp_avg;
pmf_grid_exp_avg = NULL;
}
if (pmf_grid_cumulant) {
delete pmf_grid_cumulant;
pmf_grid_cumulant = NULL;
}
if (grad_grid_exp_avg) {
delete grad_grid_exp_avg;
grad_grid_exp_avg = NULL;
}
if (grad_grid_cumulant) {
delete grad_grid_cumulant;
grad_grid_cumulant = NULL;
}
}
int colvarbias_reweightaMD::init(std::string const &conf) {
if (cvm::proxy->accelMD_enabled() == false) {
cvm::error("Error: accelerated MD in your MD engine is not enabled.\n", COLVARS_INPUT_ERROR);
}
cvm::main()->cite_feature("reweightaMD colvar bias implementation (NAMD)");
int baseclass_init_code = colvarbias_histogram::init(conf);
get_keyval(conf, "CollectAfterSteps", start_after_steps, 0);
get_keyval(conf, "CumulantExpansion", b_use_cumulant_expansion, true);
get_keyval(conf, "WritePMFGradients", b_write_gradients, true);
get_keyval(conf, "historyFreq", history_freq, 0);
b_history_files = (history_freq > 0);
grid_count = new colvar_grid_scalar(colvars);
grid_count->request_actual_value();
grid->request_actual_value();
pmf_grid_exp_avg = new colvar_grid_scalar(colvars);
if (b_write_gradients) {
grad_grid_exp_avg = new colvar_grid_gradient(colvars);
}
if (b_use_cumulant_expansion) {
grid_dV = new colvar_grid_scalar(colvars);
grid_dV_square = new colvar_grid_scalar(colvars);
pmf_grid_cumulant = new colvar_grid_scalar(colvars);
grid_dV->request_actual_value();
grid_dV_square->request_actual_value();
if (b_write_gradients) {
grad_grid_cumulant = new colvar_grid_gradient(colvars);
}
}
previous_bin.assign(num_variables(), -1);
return baseclass_init_code;
}
int colvarbias_reweightaMD::update() {
int error_code = COLVARS_OK;
if (cvm::step_relative() >= start_after_steps) {
// update base class
error_code |= colvarbias::update();
if (cvm::debug()) {
cvm::log("Updating histogram bias " + this->name);
}
if (cvm::step_relative() > 0) {
previous_bin = bin;
}
// assign a valid bin size
bin.assign(num_variables(), 0);
if (colvar_array_size == 0) {
// update indices for scalar values
size_t i;
for (i = 0; i < num_variables(); i++) {
bin[i] = grid->current_bin_scalar(i);
}
if (grid->index_ok(previous_bin) && cvm::step_relative() > 0) {
const cvm::real reweighting_factor = cvm::proxy->get_accelMD_factor();
grid_count->acc_value(previous_bin, 1.0);
grid->acc_value(previous_bin, reweighting_factor);
if (b_use_cumulant_expansion) {
const cvm::real dV = cvm::logn(reweighting_factor) *
cvm::temperature() * cvm::boltzmann();
grid_dV->acc_value(previous_bin, dV);
grid_dV_square->acc_value(previous_bin, dV * dV);
}
}
} else {
// update indices for vector/array values
size_t iv, i;
for (iv = 0; iv < colvar_array_size; iv++) {
for (i = 0; i < num_variables(); i++) {
bin[i] = grid->current_bin_scalar(i, iv);
}
if (grid->index_ok(previous_bin) && cvm::step_relative() > 0) {
const cvm::real reweighting_factor = cvm::proxy->get_accelMD_factor();
grid_count->acc_value(previous_bin, 1.0);
grid->acc_value(previous_bin, reweighting_factor);
if (b_use_cumulant_expansion) {
const cvm::real dV = cvm::logn(reweighting_factor) *
cvm::temperature() * cvm::boltzmann();
grid_dV->acc_value(previous_bin, dV);
grid_dV_square->acc_value(previous_bin, dV * dV);
}
}
}
}
previous_bin.assign(num_variables(), 0);
if (output_freq && (cvm::step_absolute() % output_freq) == 0) {
write_output_files();
}
error_code |= cvm::get_error();
}
return error_code;
}
int colvarbias_reweightaMD::write_output_files() {
int error_code = COLVARS_OK;
// error_code |= colvarbias_histogram::write_output_files();
const std::string out_name_pmf = cvm::output_prefix() + "." +
this->name + ".reweight";
error_code |= write_exponential_reweighted_pmf(out_name_pmf);
const std::string out_count_prefix = cvm::output_prefix() + "." +
this->name;
error_code |= write_count(out_count_prefix);
const bool write_history = b_history_files &&
(cvm::step_absolute() % history_freq) == 0;
if (write_history) {
error_code |= write_exponential_reweighted_pmf(
out_name_pmf + ".hist", (cvm::step_relative() > 0));
error_code |= write_count(out_count_prefix + ".hist",
(cvm::step_relative() > 0));
}
if (b_use_cumulant_expansion) {
const std::string out_name_cumulant_pmf = cvm::output_prefix() + "." +
this->name + ".cumulant";
error_code |= write_cumulant_expansion_pmf(out_name_cumulant_pmf);
if (write_history) {
error_code |= write_cumulant_expansion_pmf(
out_name_cumulant_pmf + ".hist", (cvm::step_relative() > 0));
}
}
error_code |= cvm::get_error();
return error_code;
}
int colvarbias_reweightaMD::write_exponential_reweighted_pmf(
const std::string& p_output_prefix, bool append) {
const std::string output_pmf = p_output_prefix + ".pmf";
cvm::log("Writing the accelerated MD PMF file \"" + output_pmf + "\".\n");
if (!append) {
cvm::backup_file(output_pmf.c_str());
}
const std::ios::openmode mode = (append ? std::ios::app : std::ios::out);
std::ostream *pmf_grid_os = cvm::proxy->output_stream(output_pmf, mode);
if (!pmf_grid_os) {
return cvm::error("Error opening PMF file " + output_pmf +
" for writing.\n", COLVARS_FILE_ERROR);
}
pmf_grid_exp_avg->copy_grid(*grid);
// compute the average
for (size_t i = 0; i < pmf_grid_exp_avg->raw_data_num(); ++i) {
const double count = grid_count->value(i);
if (count > 0) {
const double tmp = pmf_grid_exp_avg->value(i);
pmf_grid_exp_avg->set_value(i, tmp / count);
}
}
hist_to_pmf(pmf_grid_exp_avg, grid_count);
pmf_grid_exp_avg->write_multicol(*pmf_grid_os);
cvm::proxy->close_output_stream(output_pmf);
if (b_write_gradients) {
const std::string output_grad = p_output_prefix + ".grad";
cvm::log("Writing the accelerated MD gradients file \"" + output_grad +
"\".\n");
if (!append) {
cvm::backup_file(output_grad.c_str());
}
std::ostream *grad_grid_os = cvm::proxy->output_stream(output_grad, mode);
if (!grad_grid_os) {
return cvm::error("Error opening grad file " + output_grad +
" for writing.\n", COLVARS_FILE_ERROR);
}
for (std::vector<int> ix = grad_grid_exp_avg->new_index();
grad_grid_exp_avg->index_ok(ix); grad_grid_exp_avg->incr(ix)) {
for (size_t n = 0; n < grad_grid_exp_avg->multiplicity(); n++) {
grad_grid_exp_avg->set_value(
ix, pmf_grid_exp_avg->gradient_finite_diff(ix, n), n);
}
}
grad_grid_exp_avg->write_multicol(*grad_grid_os);
cvm::proxy->close_output_stream(output_grad);
}
return COLVARS_OK;
}
int colvarbias_reweightaMD::write_cumulant_expansion_pmf(
const std::string& p_output_prefix, bool append) {
const std::string output_pmf = p_output_prefix + ".pmf";
cvm::log("Writing the accelerated MD PMF file using cumulant expansion: \"" + output_pmf + "\".\n");
if (!append) cvm::backup_file(output_pmf.c_str());
const std::ios::openmode mode = (append ? std::ios::app : std::ios::out);
std::ostream *pmf_grid_cumulant_os = cvm::proxy->output_stream(output_pmf, mode);
if (!pmf_grid_cumulant_os) {
return cvm::error("Error opening PMF file " + output_pmf +
" for writing.\n", COLVARS_FILE_ERROR);
}
compute_cumulant_expansion_factor(grid_dV, grid_dV_square,
grid_count, pmf_grid_cumulant);
hist_to_pmf(pmf_grid_cumulant, grid_count);
pmf_grid_cumulant->write_multicol(*pmf_grid_cumulant_os);
cvm::proxy->close_output_stream(output_pmf);
if (b_write_gradients) {
const std::string output_grad = p_output_prefix + ".grad";
cvm::log("Writing the accelerated MD gradients file \"" + output_grad + "\".\n");
if (!append) {
cvm::backup_file(output_grad.c_str());
}
std::ostream *grad_grid_os = cvm::proxy->output_stream(output_grad, mode);
if (!grad_grid_os) {
return cvm::error("Error opening grad file " + output_grad +
" for writing.\n", COLVARS_FILE_ERROR);
}
for (std::vector<int> ix = grad_grid_cumulant->new_index();
grad_grid_cumulant->index_ok(ix); grad_grid_cumulant->incr(ix)) {
for (size_t n = 0; n < grad_grid_cumulant->multiplicity(); n++) {
grad_grid_cumulant->set_value(
ix, pmf_grid_cumulant->gradient_finite_diff(ix, n), n);
}
}
grad_grid_cumulant->write_multicol(*grad_grid_os);
cvm::proxy->close_output_stream(output_grad);
}
return COLVARS_OK;
}
int colvarbias_reweightaMD::write_count(const std::string& p_output_prefix, bool append) {
const std::string output_name = p_output_prefix + ".count";
cvm::log("Writing the accelerated MD count file \""+output_name+"\".\n");
if (!append) cvm::backup_file(output_name.c_str());
const std::ios::openmode mode = (append ? std::ios::app : std::ios::out);
std::ostream *grid_count_os = cvm::proxy->output_stream(output_name, mode);
if (!grid_count_os) {
return cvm::error("Error opening count file "+output_name+
" for writing.\n", COLVARS_FILE_ERROR);
}
grid_count->write_multicol(*grid_count_os);
cvm::proxy->close_output_stream(output_name);
return COLVARS_OK;
}
void colvarbias_reweightaMD::hist_to_pmf(
colvar_grid_scalar* hist, const colvar_grid_scalar* hist_count) const {
if (hist->raw_data_num() == 0) return;
const cvm::real kbt = cvm::boltzmann() * cvm::temperature();
bool first_min_element = true;
bool first_max_element = true;
cvm::real min_element = 0;
cvm::real max_element = 0;
size_t i = 0;
// the first loop: using logarithm to compute PMF
for (i = 0; i < hist->raw_data_num(); ++i) {
const cvm::real count = hist_count->value(i);
if (count > 0) {
const cvm::real x = hist->value(i);
const cvm::real pmf_value = -1.0 * kbt * cvm::logn(x);
hist->set_value(i, pmf_value);
// find the minimum PMF value
if (first_min_element) {
// assign current PMF value to min_element at the first time
min_element = pmf_value;
first_min_element = false;
} else {
// if this is not the first time, then
min_element = (pmf_value < min_element) ? pmf_value : min_element;
}
// do the same to the maximum
if (first_max_element) {
max_element = pmf_value;
first_max_element = false;
} else {
max_element = (pmf_value > max_element) ? pmf_value : max_element;
}
}
}
// the second loop: bringing the minimum PMF value to zero
for (i = 0; i < hist->raw_data_num(); ++i) {
const cvm::real count = hist_count->value(i);
if (count > 0) {
// bins that have samples
const cvm::real x = hist->value(i);
hist->set_value(i, x - min_element);
} else {
hist->set_value(i, max_element - min_element);
}
}
}
void colvarbias_reweightaMD::compute_cumulant_expansion_factor(
const colvar_grid_scalar* hist_dV,
const colvar_grid_scalar* hist_dV_square,
const colvar_grid_scalar* hist_count,
colvar_grid_scalar* cumulant_expansion_factor) const {
const cvm::real beta = 1.0 / (cvm::boltzmann() * cvm::temperature());
size_t i = 0;
for (i = 0; i < hist_dV->raw_data_num(); ++i) {
const cvm::real count = hist_count->value(i);
if (count > 0) {
const cvm::real dV_avg = hist_dV->value(i) / count;
const cvm::real dV_square_avg = hist_dV_square->value(i) / count;
const cvm::real factor = cvm::exp(beta * dV_avg + 0.5 * beta * beta * (dV_square_avg - dV_avg * dV_avg));
cumulant_expansion_factor->set_value(i, factor);
}
}
}
std::ostream & colvarbias_reweightaMD::write_state_data(std::ostream& os)
{
std::ios::fmtflags flags(os.flags());
os.setf(std::ios::fmtflags(0), std::ios::floatfield);
os << "grid\n";
grid->write_raw(os, 8);
os << "grid_count\n";
grid_count->write_raw(os, 8);
os << "grid_dV\n";
grid_dV->write_raw(os, 8);
os << "grid_dV_square\n";
grid_dV_square->write_raw(os, 8);
os.flags(flags);
return os;
}
std::istream & colvarbias_reweightaMD::read_state_data(std::istream& is)
{
if (! read_state_data_key(is, "grid")) {
return is;
}
if (! grid->read_raw(is)) {
return is;
}
if (! read_state_data_key(is, "grid_count")) {
return is;
}
if (! grid_count->read_raw(is)) {
return is;
}
if (! read_state_data_key(is, "grid_dV")) {
return is;
}
if (! grid_dV->read_raw(is)) {
return is;
}
if (! read_state_data_key(is, "grid_dV_square")) {
return is;
}
if (! grid_dV_square->read_raw(is)) {
return is;
}
return is;
}

View File

@ -0,0 +1,104 @@
// -*- c++ -*-
// 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
// 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.
#ifndef COLVARBIAS_HISTOGRAM_REWEIGHT_AMD
#define COLVARBIAS_HISTOGRAM_REWEIGHT_AMD
#include "colvarbias_histogram.h"
/// Reweighted histogram for accelerated molecular dynamics (aMD) or
/// Gaussian aMD (GaMD)
class colvarbias_reweightaMD : public colvarbias_histogram {
public:
colvarbias_reweightaMD(char const *key);
virtual ~colvarbias_reweightaMD();
#if (__cplusplus >= 201103L)
virtual int init(std::string const &conf) override;
virtual int update() override;
virtual int write_output_files() override;
#else
virtual int init(std::string const &conf);
virtual int update();
virtual int write_output_files();
#endif
/// @brief convert histogram to PMF by taking logarithm and multiplying
/// it with -1/beta
/// @param[in,out] hist the origin histogram and also the output PMF
/// @param[in] hist_count the sampling or biased histogram
void hist_to_pmf(
colvar_grid_scalar* hist,
const colvar_grid_scalar* hist_count) const;
/// @brief calculate the cumulant expansion to second order
/// @param[in] hist_dV the histogram of the boosting potential, ΔV(ξ)
/// @param[in] hist_dV_square the histogram of the square of boosting
/// potential
/// @param[in] hist_count the sampling or biased histogram
/// @param[out] cumulant_expansion_factor the factor of the cumulant
/// expansion to second order
void compute_cumulant_expansion_factor(
const colvar_grid_scalar* hist_dV,
const colvar_grid_scalar* hist_dV_square,
const colvar_grid_scalar* hist_count,
colvar_grid_scalar* cumulant_expansion_factor) const;
/// @brief output the PMF by the exponential average estimator
/// @param[in] p_output_prefix the prefix of the output file
/// @param[in] append append the output to a .hist file if true
virtual int write_exponential_reweighted_pmf(
const std::string& p_output_prefix, bool append = false);
/// @brief output the PMF by the cumulant expansion estimator
/// @param[in] p_output_prefix the prefix of the output file
/// @param[in] append append the output to a .hist file if true
virtual int write_cumulant_expansion_pmf(
const std::string& p_output_prefix, bool append = false);
/// @brief output the biased sampling
/// @param[in] p_output_prefix the prefix of the output file
/// @param[in] append append the output to a .hist file if true
virtual int write_count(
const std::string& p_output_prefix, bool append = false);
protected:
/// Current accelMD factor is the from previous frame
std::vector<int> previous_bin;
/// Start collecting samples after N steps
colvarmodule::step_number start_after_steps;
/// Use cumulant expansion to second order?
bool b_use_cumulant_expansion;
colvar_grid_scalar* grid_count;
colvar_grid_scalar* grid_dV;
colvar_grid_scalar* grid_dV_square;
/// Number of timesteps between recording data in history files (if non-zero)
size_t history_freq;
bool b_history_files;
/// Write gradients of the PMF?
bool b_write_gradients;
/// save and restore
#if (__cplusplus >= 201103L)
virtual std::istream & read_state_data(std::istream &is) override;
virtual std::ostream & write_state_data(std::ostream &os) override;
#else
virtual std::istream & read_state_data(std::istream &is);
virtual std::ostream & write_state_data(std::ostream &os);
#endif
private:
/// temporary grids for evaluating PMFs
colvar_grid_scalar *pmf_grid_exp_avg;
colvar_grid_scalar *pmf_grid_cumulant;
colvar_grid_gradient *grad_grid_exp_avg;
colvar_grid_gradient *grad_grid_cumulant;
};
#endif // COLVARBIAS_HISTOGRAM_REWEIGHT_AMD

View File

@ -38,6 +38,7 @@ colvarbias_meta::colvarbias_meta(char const *key)
new_hills_begin = hills.end(); new_hills_begin = hills.end();
hills_traj_os = NULL; hills_traj_os = NULL;
hill_weight = 0.0;
hill_width = 0.0; hill_width = 0.0;
new_hill_freq = 1000; new_hill_freq = 1000;
@ -71,13 +72,15 @@ int colvarbias_meta::init(std::string const &conf)
error_code |= colvarbias::init(conf); error_code |= colvarbias::init(conf);
error_code |= colvarbias_ti::init(conf); error_code |= colvarbias_ti::init(conf);
cvm::main()->cite_feature("Metadynamics colvar bias implementation");
enable(f_cvb_calc_pmf); enable(f_cvb_calc_pmf);
get_keyval(conf, "hillWeight", hill_weight, 0.0); get_keyval(conf, "hillWeight", hill_weight, hill_weight);
if (hill_weight > 0.0) { if (hill_weight > 0.0) {
enable(f_cvb_apply_force); enable(f_cvb_apply_force);
} else { } else {
cvm::error("Error: hillWeight must be provided, and a positive number.\n", INPUT_ERROR); cvm::error("Error: hillWeight must be provided, and a positive number.\n", COLVARS_INPUT_ERROR);
} }
get_keyval(conf, "newHillFrequency", new_hill_freq, new_hill_freq); get_keyval(conf, "newHillFrequency", new_hill_freq, new_hill_freq);
@ -94,7 +97,7 @@ int colvarbias_meta::init(std::string const &conf)
if ((colvar_sigmas.size() > 0) && (hill_width > 0.0)) { if ((colvar_sigmas.size() > 0) && (hill_width > 0.0)) {
error_code |= cvm::error("Error: hillWidth and gaussianSigmas are " error_code |= cvm::error("Error: hillWidth and gaussianSigmas are "
"mutually exclusive.", INPUT_ERROR); "mutually exclusive.", COLVARS_INPUT_ERROR);
} }
if (hill_width > 0.0) { if (hill_width > 0.0) {
@ -111,16 +114,18 @@ int colvarbias_meta::init(std::string const &conf)
if (colvar_sigmas.size() == 0) { if (colvar_sigmas.size() == 0) {
error_code |= cvm::error("Error: positive values are required for " error_code |= cvm::error("Error: positive values are required for "
"either hillWidth or gaussianSigmas.", "either hillWidth or gaussianSigmas.",
INPUT_ERROR); COLVARS_INPUT_ERROR);
} }
{ {
bool b_replicas = false; bool b_replicas = false;
get_keyval(conf, "multipleReplicas", b_replicas, false); get_keyval(conf, "multipleReplicas", b_replicas, false);
if (b_replicas) if (b_replicas) {
comm = multiple_replicas; cvm::main()->cite_feature("Multiple-walker metadynamics colvar bias implementation");
else comm = multiple_replicas;
} else {
comm = single_replica; comm = single_replica;
}
} }
get_keyval(conf, "useGrids", use_grids, use_grids); get_keyval(conf, "useGrids", use_grids, use_grids);
@ -174,7 +179,7 @@ int colvarbias_meta::init(std::string const &conf)
cvm::log("Done initializing the metadynamics bias \""+this->name+"\""+ cvm::log("Done initializing the metadynamics bias \""+this->name+"\""+
((comm != single_replica) ? ", replica \""+replica_id+"\"" : "")+".\n"); ((comm != single_replica) ? ", replica \""+replica_id+"\"" : "")+".\n");
return COLVARS_OK; return error_code;
} }
@ -209,7 +214,7 @@ int colvarbias_meta::init_replicas_params(std::string const &conf)
replica_id+".\n"); replica_id+".\n");
} else { } else {
return cvm::error("Error: using more than one replica, but replicaID " return cvm::error("Error: using more than one replica, but replicaID "
"could not be obtained.\n", INPUT_ERROR); "could not be obtained.\n", COLVARS_INPUT_ERROR);
} }
} }
@ -217,26 +222,26 @@ int colvarbias_meta::init_replicas_params(std::string const &conf)
replicas_registry_file); replicas_registry_file);
if (!replicas_registry_file.size()) { if (!replicas_registry_file.size()) {
return cvm::error("Error: the name of the \"replicasRegistry\" file " return cvm::error("Error: the name of the \"replicasRegistry\" file "
"must be provided.\n", INPUT_ERROR); "must be provided.\n", COLVARS_INPUT_ERROR);
} }
get_keyval(conf, "replicaUpdateFrequency", get_keyval(conf, "replicaUpdateFrequency",
replica_update_freq, replica_update_freq); replica_update_freq, replica_update_freq);
if (replica_update_freq == 0) { if (replica_update_freq == 0) {
return cvm::error("Error: replicaUpdateFrequency must be positive.\n", return cvm::error("Error: replicaUpdateFrequency must be positive.\n",
INPUT_ERROR); COLVARS_INPUT_ERROR);
} }
if (expand_grids) { if (expand_grids) {
return cvm::error("Error: expandBoundaries is not supported when " return cvm::error("Error: expandBoundaries is not supported when "
"using more than one replicas; please allocate " "using more than one replicas; please allocate "
"wide enough boundaries for each colvar" "wide enough boundaries for each colvar"
"ahead of time.\n", INPUT_ERROR); "ahead of time.\n", COLVARS_INPUT_ERROR);
} }
if (keep_hills) { if (keep_hills) {
return cvm::error("Error: multipleReplicas and keepHills are not " return cvm::error("Error: multipleReplicas and keepHills are not "
"supported together.\n", INPUT_ERROR); "supported together.\n", COLVARS_INPUT_ERROR);
} }
} }
@ -250,7 +255,8 @@ int colvarbias_meta::init_well_tempered_params(std::string const &conf)
get_keyval(conf, "wellTempered", well_tempered, false); get_keyval(conf, "wellTempered", well_tempered, false);
get_keyval(conf, "biasTemperature", bias_temperature, -1.0); get_keyval(conf, "biasTemperature", bias_temperature, -1.0);
if ((bias_temperature == -1.0) && well_tempered) { if ((bias_temperature == -1.0) && well_tempered) {
cvm::fatal_error("Error: biasTemperature is not set.\n"); cvm::error("Error: biasTemperature must be set to a positive value.\n",
COLVARS_INPUT_ERROR);
} }
if (well_tempered) { if (well_tempered) {
cvm::log("Well-tempered metadynamics is used.\n"); cvm::log("Well-tempered metadynamics is used.\n");
@ -266,11 +272,12 @@ int colvarbias_meta::init_ebmeta_params(std::string const &conf)
target_dist = NULL; target_dist = NULL;
get_keyval(conf, "ebMeta", ebmeta, false); get_keyval(conf, "ebMeta", ebmeta, false);
if(ebmeta){ if(ebmeta){
cvm::main()->cite_feature("Ensemble-biased metadynamics (ebMetaD)");
if (use_grids && expand_grids) { if (use_grids && expand_grids) {
cvm::fatal_error("Error: expandBoundaries is not supported with " cvm::error("Error: expandBoundaries is not supported with "
"ebMeta please allocate wide enough boundaries for " "ebMeta please allocate wide enough boundaries for "
"each colvar ahead of time and set targetdistfile " "each colvar ahead of time and set targetdistfile "
"accordingly. \n"); "accordingly.\n", COLVARS_INPUT_ERROR);
} }
target_dist = new colvar_grid_scalar(); target_dist = new colvar_grid_scalar();
target_dist->init_from_colvars(colvars); target_dist->init_from_colvars(colvars);
@ -282,7 +289,7 @@ int colvarbias_meta::init_ebmeta_params(std::string const &conf)
cvm::real max_val = target_dist->maximum_value(); cvm::real max_val = target_dist->maximum_value();
if(min_val<0){ if(min_val<0){
cvm::error("Error: Target distribution of EBMetaD " cvm::error("Error: Target distribution of EBMetaD "
"has negative values!.\n", INPUT_ERROR); "has negative values!.\n", COLVARS_INPUT_ERROR);
} }
cvm::real target_dist_min_val; cvm::real target_dist_min_val;
get_keyval(conf, "targetDistMinVal", target_dist_min_val, 1/1000000.0); get_keyval(conf, "targetDistMinVal", target_dist_min_val, 1/1000000.0);
@ -296,7 +303,7 @@ int colvarbias_meta::init_ebmeta_params(std::string const &conf)
cvm::real min_pos_val = target_dist->minimum_pos_value(); cvm::real min_pos_val = target_dist->minimum_pos_value();
if(min_pos_val<=0){ if(min_pos_val<=0){
cvm::error("Error: Target distribution of EBMetaD has negative " cvm::error("Error: Target distribution of EBMetaD has negative "
"or zero minimum positive value!.\n", INPUT_ERROR); "or zero minimum positive value!.\n", COLVARS_INPUT_ERROR);
} }
if(min_val==0){ if(min_val==0){
cvm::log("WARNING: Target distribution has zero values.\n"); cvm::log("WARNING: Target distribution has zero values.\n");
@ -304,7 +311,7 @@ int colvarbias_meta::init_ebmeta_params(std::string const &conf)
target_dist->remove_small_values(min_pos_val); target_dist->remove_small_values(min_pos_val);
} }
} else { } else {
cvm::error("Error: targetDistMinVal must be a value between 0 and 1!.\n", INPUT_ERROR); cvm::error("Error: targetDistMinVal must be a value between 0 and 1!.\n", COLVARS_INPUT_ERROR);
} }
} }
// normalize target distribution and multiply by effective volume = exp(differential entropy) // normalize target distribution and multiply by effective volume = exp(differential entropy)
@ -618,7 +625,7 @@ int colvarbias_meta::update_bias()
} else { } else {
return cvm::error("Error: in metadynamics bias \""+this->name+"\""+ return cvm::error("Error: in metadynamics bias \""+this->name+"\""+
((comm != single_replica) ? ", replica \""+replica_id+"\"" : "")+ ((comm != single_replica) ? ", replica \""+replica_id+"\"" : "")+
" while writing hills for the other replicas.\n", FILE_ERROR); " while writing hills for the other replicas.\n", COLVARS_FILE_ERROR);
} }
break; break;
} }
@ -936,7 +943,7 @@ void colvarbias_meta::project_hills(colvarbias_meta::hill_iter h_first,
} else { } else {
cvm::error("No grid object provided in metadynamics::project_hills()\n", cvm::error("No grid object provided in metadynamics::project_hills()\n",
BUG_ERROR); COLVARS_BUG_ERROR);
} }
if (print_progress) { if (print_progress) {
@ -1006,7 +1013,7 @@ void colvarbias_meta::update_replicas_registry()
replicas_registry.append(line+"\n"); replicas_registry.append(line+"\n");
} else { } else {
cvm::error("Error: failed to open file \""+replicas_registry_file+ cvm::error("Error: failed to open file \""+replicas_registry_file+
"\" for reading.\n", FILE_ERROR); "\" for reading.\n", COLVARS_FILE_ERROR);
} }
} }
@ -1075,7 +1082,7 @@ void colvarbias_meta::update_replicas_registry()
} }
} else { } else {
cvm::error("Error: cannot read the replicas registry file \""+ cvm::error("Error: cannot read the replicas registry file \""+
replicas_registry+"\".\n", FILE_ERROR); replicas_registry+"\".\n", COLVARS_FILE_ERROR);
} }
// now (re)read the list file of each replica // now (re)read the list file of each replica
@ -1277,7 +1284,7 @@ int colvarbias_meta::set_state_params(std::string const &state_conf)
return cvm::error("Error: in the state file , the " return cvm::error("Error: in the state file , the "
"\"metadynamics\" block has a different replicaID ("+ "\"metadynamics\" block has a different replicaID ("+
check_replica+" instead of "+replica_id+").\n", check_replica+" instead of "+replica_id+").\n",
INPUT_ERROR); COLVARS_INPUT_ERROR);
} }
return COLVARS_OK; return COLVARS_OK;
@ -1331,16 +1338,13 @@ std::istream & colvarbias_meta::read_state_data(std::istream& is)
is.clear(); is.clear();
is.seekg(hills_energy_pos, std::ios::beg); is.seekg(hills_energy_pos, std::ios::beg);
if (!rebin_grids) { if (!rebin_grids) {
if (hills_energy_backup == NULL) if ((hills_energy_backup == NULL) || (comm == single_replica)) {
cvm::fatal_error("Error: couldn't read the free energy grid for metadynamics bias \""+ cvm::error("Error: couldn't read the energy grid for metadynamics bias \""+
this->name+"\""+ this->name+"\""+
((comm != single_replica) ? ", replica \""+replica_id+"\"" : "")+ ((comm != single_replica) ? ", replica \""+replica_id+"\"" : "")+
"; if useGrids was off when the state file was written, " "; if useGrids was off when the state file was written, "
"enable rebinGrids now to regenerate the grids.\n"); "enable rebinGrids now to regenerate the grids.\n");
else { } else {
if (comm == single_replica)
cvm::log("Error: couldn't read the free energy grid for metadynamics bias \""+
this->name+"\".\n");
delete hills_energy; delete hills_energy;
delete hills_energy_gradients; delete hills_energy_gradients;
hills_energy = hills_energy_backup; hills_energy = hills_energy_backup;
@ -1368,16 +1372,13 @@ std::istream & colvarbias_meta::read_state_data(std::istream& is)
is.clear(); is.clear();
is.seekg(hills_energy_gradients_pos, std::ios::beg); is.seekg(hills_energy_gradients_pos, std::ios::beg);
if (!rebin_grids) { if (!rebin_grids) {
if (hills_energy_backup == NULL) if ((hills_energy_backup == NULL) || (comm == single_replica)) {
cvm::fatal_error("Error: couldn't read the free energy gradients grid for metadynamics bias \""+ cvm::error("Error: couldn't read the gradients grid for metadynamics bias \""+
this->name+"\""+ this->name+"\""+
((comm != single_replica) ? ", replica \""+replica_id+"\"" : "")+ ((comm != single_replica) ? ", replica \""+replica_id+"\"" : "")+
"; if useGrids was off when the state file was written, " "; if useGrids was off when the state file was written, "
"enable rebinGrids now to regenerate the grids.\n"); "enable rebinGrids now to regenerate the grids.\n");
else { } else {
if (comm == single_replica)
cvm::log("Error: couldn't read the free energy gradients grid for metadynamics bias \""+
this->name+"\".\n");
delete hills_energy; delete hills_energy;
delete hills_energy_gradients; delete hills_energy_gradients;
hills_energy = hills_energy_backup; hills_energy = hills_energy_backup;
@ -1393,6 +1394,8 @@ std::istream & colvarbias_meta::read_state_data(std::istream& is)
this->name+"\""+ this->name+"\""+
((comm != single_replica) ? ", replica \""+replica_id+"\"" : "")+"\n"); ((comm != single_replica) ? ", replica \""+replica_id+"\"" : "")+"\n");
cvm::log(" read biasing energy and forces from grids.\n");
if (hills_energy_backup != NULL) { if (hills_energy_backup != NULL) {
// now that we have successfully updated the grids, delete the // now that we have successfully updated the grids, delete the
// backup copies // backup copies
@ -1422,7 +1425,8 @@ std::istream & colvarbias_meta::read_state_data(std::istream& is)
} }
is.clear(); is.clear();
new_hills_begin = hills.end(); new_hills_begin = hills.end();
cvm::log("Read "+cvm::to_str(hills.size() - old_hills_size)+" hills.\n"); cvm::log(" read "+cvm::to_str(hills.size() - old_hills_size)+
" additional explicit hills.\n");
if (existing_hills) { if (existing_hills) {
hills.erase(hills.begin(), old_hills_end); hills.erase(hills.begin(), old_hills_end);
@ -1579,7 +1583,7 @@ std::istream & colvarbias_meta::read_hill(std::istream &is)
if (h_replica != replica_id) { if (h_replica != replica_id) {
cvm::error("Error: trying to read a hill created by replica \""+ cvm::error("Error: trying to read a hill created by replica \""+
h_replica+"\" for replica \""+replica_id+ h_replica+"\" for replica \""+replica_id+
"\"; did you swap output files?\n", INPUT_ERROR); "\"; did you swap output files?\n", COLVARS_INPUT_ERROR);
} }
} }
} }
@ -1623,7 +1627,7 @@ int colvarbias_meta::setup_output()
// TODO: one may want to specify the path manually for intricated filesystems? // TODO: one may want to specify the path manually for intricated filesystems?
char *pwd = new char[3001]; char *pwd = new char[3001];
if (GETCWD(pwd, 3000) == NULL) if (GETCWD(pwd, 3000) == NULL)
cvm::fatal_error("Error: cannot get the path of the current working directory.\n"); cvm::error("Error: cannot get the path of the current working directory.\n");
replica_list_file = replica_list_file =
(std::string(pwd)+std::string(PATHSEP)+ (std::string(pwd)+std::string(PATHSEP)+
this->name+"."+replica_id+".files.txt"); this->name+"."+replica_id+".files.txt");
@ -1902,7 +1906,7 @@ int colvarbias_meta::write_replica_state_file()
if (rep_state_os) { if (rep_state_os) {
if (!write_state(*rep_state_os)) { if (!write_state(*rep_state_os)) {
error_code |= cvm::error("Error: in writing to temporary file \""+ error_code |= cvm::error("Error: in writing to temporary file \""+
tmp_state_file+"\".\n", FILE_ERROR); tmp_state_file+"\".\n", COLVARS_FILE_ERROR);
} }
} }
error_code |= proxy->close_output_stream(tmp_state_file); error_code |= proxy->close_output_stream(tmp_state_file);
@ -1925,7 +1929,7 @@ int colvarbias_meta::reopen_replica_buffer_file()
if (replica_hills_os) { if (replica_hills_os) {
replica_hills_os->setf(std::ios::scientific, std::ios::floatfield); replica_hills_os->setf(std::ios::scientific, std::ios::floatfield);
} else { } else {
error_code |= FILE_ERROR; error_code |= COLVARS_FILE_ERROR;
} }
return error_code; return error_code;
} }
@ -2003,6 +2007,21 @@ colvarbias_meta::hill::hill(colvarbias_meta::hill const &h)
} }
colvarbias_meta::hill &
colvarbias_meta::hill::operator = (colvarbias_meta::hill const &h)
{
it = h.it;
hill_value = 0.0;
sW = 1.0;
W = h.W;
centers = h.centers;
sigmas = h.sigmas;
replica = h.replica;
hill_value = h.hill_value;
return *this;
}
colvarbias_meta::hill::~hill() colvarbias_meta::hill::~hill()
{} {}

View File

@ -313,6 +313,9 @@ public:
/// Destructor /// Destructor
~hill(); ~hill();
/// Assignment operator
hill & operator = (colvarbias_meta::hill const &h);
/// Get the energy /// Get the energy
inline cvm::real energy() inline cvm::real energy()
{ {

View File

@ -121,14 +121,14 @@ int colvarbias_restraint_centers::init(std::string const &conf)
if (null_centers) { if (null_centers) {
colvar_centers.clear(); colvar_centers.clear();
cvm::error("Error: must define the initial centers of the restraints.\n", INPUT_ERROR); cvm::error("Error: must define the initial centers of the restraints.\n", COLVARS_INPUT_ERROR);
return INPUT_ERROR; return COLVARS_INPUT_ERROR;
} }
if (colvar_centers.size() != num_variables()) { if (colvar_centers.size() != num_variables()) {
cvm::error("Error: number of centers does not match " cvm::error("Error: number of centers does not match "
"that of collective variables.\n", INPUT_ERROR); "that of collective variables.\n", COLVARS_INPUT_ERROR);
return INPUT_ERROR; return COLVARS_INPUT_ERROR;
} }
return COLVARS_OK; return COLVARS_OK;
@ -160,8 +160,8 @@ int colvarbias_restraint_k::init(std::string const &conf)
{ {
get_keyval(conf, "forceConstant", force_k, (force_k > 0.0 ? force_k : 1.0)); get_keyval(conf, "forceConstant", force_k, (force_k > 0.0 ? force_k : 1.0));
if (check_positive_k && (force_k < 0.0)) { if (check_positive_k && (force_k < 0.0)) {
cvm::error("Error: undefined or invalid force constant.\n", INPUT_ERROR); cvm::error("Error: undefined or invalid force constant.\n", COLVARS_INPUT_ERROR);
return INPUT_ERROR; return COLVARS_INPUT_ERROR;
} }
return COLVARS_OK; return COLVARS_OK;
} }
@ -190,21 +190,21 @@ int colvarbias_restraint_moving::init(std::string const &conf)
{ {
if (b_chg_centers && b_chg_force_k) { if (b_chg_centers && b_chg_force_k) {
cvm::error("Error: cannot specify both targetCenters and targetForceConstant.\n", cvm::error("Error: cannot specify both targetCenters and targetForceConstant.\n",
INPUT_ERROR); COLVARS_INPUT_ERROR);
return INPUT_ERROR; return COLVARS_INPUT_ERROR;
} }
if (b_chg_centers || b_chg_force_k) { if (b_chg_centers || b_chg_force_k) {
get_keyval(conf, "targetNumSteps", target_nsteps, target_nsteps); get_keyval(conf, "targetNumSteps", target_nsteps, target_nsteps);
if (!target_nsteps) { if (!target_nsteps) {
cvm::error("Error: targetNumSteps must be non-zero.\n", INPUT_ERROR); cvm::error("Error: targetNumSteps must be non-zero.\n", COLVARS_INPUT_ERROR);
return cvm::get_error(); return cvm::get_error();
} }
if (get_keyval(conf, "targetNumStages", target_nstages, target_nstages) && if (get_keyval(conf, "targetNumStages", target_nstages, target_nstages) &&
lambda_schedule.size()) { lambda_schedule.size()) {
cvm::error("Error: targetNumStages and lambdaSchedule are incompatible.\n", INPUT_ERROR); cvm::error("Error: targetNumStages and lambdaSchedule are incompatible.\n", COLVARS_INPUT_ERROR);
return cvm::get_error(); return cvm::get_error();
} }
@ -213,7 +213,7 @@ int colvarbias_restraint_moving::init(std::string const &conf)
is_enabled(f_cvb_output_acc_work)); is_enabled(f_cvb_output_acc_work));
if (is_enabled(f_cvb_output_acc_work) && (target_nstages > 0)) { if (is_enabled(f_cvb_output_acc_work) && (target_nstages > 0)) {
return cvm::error("Error: outputAccumulatedWork and targetNumStages " return cvm::error("Error: outputAccumulatedWork and targetNumStages "
"are incompatible.\n", INPUT_ERROR); "are incompatible.\n", COLVARS_INPUT_ERROR);
} }
} }
@ -273,7 +273,7 @@ int colvarbias_restraint_centers_moving::init(std::string const &conf)
if (get_keyval(conf, "targetCenters", target_centers, colvar_centers)) { if (get_keyval(conf, "targetCenters", target_centers, colvar_centers)) {
if (target_centers.size() != num_variables()) { if (target_centers.size() != num_variables()) {
cvm::error("Error: number of target centers does not match " cvm::error("Error: number of target centers does not match "
"that of collective variables.\n", INPUT_ERROR); "that of collective variables.\n", COLVARS_INPUT_ERROR);
} }
b_chg_centers = true; b_chg_centers = true;
for (i = 0; i < target_centers.size(); i++) { for (i = 0; i < target_centers.size(); i++) {
@ -525,7 +525,7 @@ int colvarbias_restraint_k_moving::init(std::string const &conf)
if (get_keyval(conf, "lambdaSchedule", lambda_schedule, lambda_schedule) && if (get_keyval(conf, "lambdaSchedule", lambda_schedule, lambda_schedule) &&
target_nstages > 0) { target_nstages > 0) {
cvm::error("Error: targetNumStages and lambdaSchedule are incompatible.\n", INPUT_ERROR); cvm::error("Error: targetNumStages and lambdaSchedule are incompatible.\n", COLVARS_INPUT_ERROR);
return cvm::get_error(); return cvm::get_error();
} }
@ -726,6 +726,8 @@ int colvarbias_restraint_harmonic::init(std::string const &conf)
colvarbias_restraint_centers_moving::init(conf); colvarbias_restraint_centers_moving::init(conf);
colvarbias_restraint_k_moving::init(conf); colvarbias_restraint_k_moving::init(conf);
cvm::main()->cite_feature("Harmonic colvar bias implementation");
for (size_t i = 0; i < num_variables(); i++) { for (size_t i = 0; i < num_variables(); i++) {
cvm::real const w = variables(i)->width; cvm::real const w = variables(i)->width;
cvm::log("The force constant for colvar \""+variables(i)->name+ cvm::log("The force constant for colvar \""+variables(i)->name+
@ -880,6 +882,8 @@ int colvarbias_restraint_harmonic_walls::init(std::string const &conf)
colvarbias_restraint_moving::init(conf); colvarbias_restraint_moving::init(conf);
colvarbias_restraint_k_moving::init(conf); colvarbias_restraint_k_moving::init(conf);
cvm::main()->cite_feature("harmonicWalls colvar bias implementation");
enable(f_cvb_scalar_variables); enable(f_cvb_scalar_variables);
size_t i; size_t i;
@ -915,7 +919,7 @@ int colvarbias_restraint_harmonic_walls::init(std::string const &conf)
} }
if ((lower_walls.size() == 0) && (upper_walls.size() == 0)) { if ((lower_walls.size() == 0) && (upper_walls.size() == 0)) {
return cvm::error("Error: no walls provided.\n", INPUT_ERROR); return cvm::error("Error: no walls provided.\n", COLVARS_INPUT_ERROR);
} }
if (lower_walls.size() > 0) { if (lower_walls.size() > 0) {
@ -931,7 +935,7 @@ int colvarbias_restraint_harmonic_walls::init(std::string const &conf)
for (i = 0; i < num_variables(); i++) { for (i = 0; i < num_variables(); i++) {
if (variables(i)->is_enabled(f_cv_periodic)) { if (variables(i)->is_enabled(f_cv_periodic)) {
return cvm::error("Error: at least one variable is periodic, " return cvm::error("Error: at least one variable is periodic, "
"both walls must be provided.\n", INPUT_ERROR); "both walls must be provided.\n", COLVARS_INPUT_ERROR);
} }
} }
} }
@ -943,19 +947,19 @@ int colvarbias_restraint_harmonic_walls::init(std::string const &conf)
cvm::to_str(upper_walls[i])+ cvm::to_str(upper_walls[i])+
", is not higher than the lower wall, "+ ", is not higher than the lower wall, "+
cvm::to_str(lower_walls[i])+".\n", cvm::to_str(lower_walls[i])+".\n",
INPUT_ERROR); COLVARS_INPUT_ERROR);
} }
if (variables(i)->dist2(lower_walls[i], upper_walls[i]) < 1.0e-12) { if (variables(i)->dist2(lower_walls[i], upper_walls[i]) < 1.0e-12) {
return cvm::error("Error: lower wall and upper wall are equal " return cvm::error("Error: lower wall and upper wall are equal "
"in the domain of the variable \""+ "in the domain of the variable \""+
variables(i)->name+"\".\n", INPUT_ERROR); variables(i)->name+"\".\n", COLVARS_INPUT_ERROR);
} }
} }
if (lower_wall_k * upper_wall_k == 0.0) { if (lower_wall_k * upper_wall_k == 0.0) {
cvm::error("Error: lowerWallConstant and upperWallConstant, " cvm::error("Error: lowerWallConstant and upperWallConstant, "
"when defined, must both be positive.\n", "when defined, must both be positive.\n",
INPUT_ERROR); COLVARS_INPUT_ERROR);
return INPUT_ERROR; return COLVARS_INPUT_ERROR;
} }
force_k = cvm::sqrt(lower_wall_k * upper_wall_k); force_k = cvm::sqrt(lower_wall_k * upper_wall_k);
// transform the two constants to relative values using gemetric mean as ref // transform the two constants to relative values using gemetric mean as ref
@ -1148,11 +1152,13 @@ int colvarbias_restraint_linear::init(std::string const &conf)
colvarbias_restraint_centers_moving::init(conf); colvarbias_restraint_centers_moving::init(conf);
colvarbias_restraint_k_moving::init(conf); colvarbias_restraint_k_moving::init(conf);
cvm::main()->cite_feature("harmonicWalls colvar bias implementation");
for (size_t i = 0; i < num_variables(); i++) { for (size_t i = 0; i < num_variables(); i++) {
if (variables(i)->is_enabled(f_cv_periodic)) { if (variables(i)->is_enabled(f_cv_periodic)) {
cvm::error("Error: linear biases cannot be applied to periodic variables.\n", cvm::error("Error: linear biases cannot be applied to periodic variables.\n",
INPUT_ERROR); COLVARS_INPUT_ERROR);
return INPUT_ERROR; return COLVARS_INPUT_ERROR;
} }
cvm::real const w = variables(i)->width; cvm::real const w = variables(i)->width;
cvm::log("The force constant for colvar \""+variables(i)->name+ cvm::log("The force constant for colvar \""+variables(i)->name+
@ -1299,12 +1305,14 @@ int colvarbias_restraint_histogram::init(std::string const &conf)
colvarbias::init(conf); colvarbias::init(conf);
enable(f_cvb_apply_force); enable(f_cvb_apply_force);
cvm::main()->cite_feature("histogramRestraint colvar bias implementation");
get_keyval(conf, "lowerBoundary", lower_boundary, lower_boundary); get_keyval(conf, "lowerBoundary", lower_boundary, lower_boundary);
get_keyval(conf, "upperBoundary", upper_boundary, upper_boundary); get_keyval(conf, "upperBoundary", upper_boundary, upper_boundary);
get_keyval(conf, "width", width, width); get_keyval(conf, "width", width, width);
if (width <= 0.0) { if (width <= 0.0) {
cvm::error("Error: \"width\" must be positive.\n", INPUT_ERROR); cvm::error("Error: \"width\" must be positive.\n", COLVARS_INPUT_ERROR);
} }
get_keyval(conf, "gaussianWidth", gaussian_width, 2.0 * width, colvarparse::parse_silent); get_keyval(conf, "gaussianWidth", gaussian_width, 2.0 * width, colvarparse::parse_silent);
@ -1315,7 +1323,7 @@ int colvarbias_restraint_histogram::init(std::string const &conf)
cvm::to_str(upper_boundary)+ cvm::to_str(upper_boundary)+
", is not higher than the lower boundary, "+ ", is not higher than the lower boundary, "+
cvm::to_str(lower_boundary)+".\n", cvm::to_str(lower_boundary)+".\n",
INPUT_ERROR); COLVARS_INPUT_ERROR);
} }
cvm::real const nbins = (upper_boundary - lower_boundary) / width; cvm::real const nbins = (upper_boundary - lower_boundary) / width;
@ -1340,7 +1348,7 @@ int colvarbias_restraint_histogram::init(std::string const &conf)
if (ref_p_file.size()) { if (ref_p_file.size()) {
if (inline_ref_p) { if (inline_ref_p) {
cvm::error("Error: cannot specify both refHistogram and refHistogramFile at the same time.\n", cvm::error("Error: cannot specify both refHistogram and refHistogramFile at the same time.\n",
INPUT_ERROR); COLVARS_INPUT_ERROR);
} else { } else {
std::ifstream is(ref_p_file.c_str()); std::ifstream is(ref_p_file.c_str());
std::string data_s = ""; std::string data_s = "";
@ -1349,7 +1357,7 @@ int colvarbias_restraint_histogram::init(std::string const &conf)
data_s.append(line+"\n"); data_s.append(line+"\n");
} }
if (data_s.size() == 0) { if (data_s.size() == 0) {
cvm::error("Error: file \""+ref_p_file+"\" empty or unreadable.\n", FILE_ERROR); cvm::error("Error: file \""+ref_p_file+"\" empty or unreadable.\n", COLVARS_FILE_ERROR);
} }
is.close(); is.close();
cvm::vector1d<cvm::real> data; cvm::vector1d<cvm::real> data;
@ -1366,7 +1374,7 @@ int colvarbias_restraint_histogram::init(std::string const &conf)
ref_p = data; ref_p = data;
} else { } else {
cvm::error("Error: file \""+ref_p_file+"\" contains a histogram of different length.\n", cvm::error("Error: file \""+ref_p_file+"\" contains a histogram of different length.\n",
INPUT_ERROR); COLVARS_INPUT_ERROR);
} }
} }
} }

View File

@ -12,6 +12,11 @@
#include "colvarbias.h" #include "colvarbias.h"
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable : 4250) // Silence diamond inheritance warning
#endif
/// \brief Most general definition of a colvar restraint: /// \brief Most general definition of a colvar restraint:
/// see derived classes for specific types /// see derived classes for specific types
/// (implementation of \link colvarbias \endlink) /// (implementation of \link colvarbias \endlink)
@ -359,5 +364,8 @@ protected:
bool b_write_histogram; bool b_write_histogram;
}; };
#ifdef _MSC_VER
#pragma warning(pop)
#endif
#endif #endif

View File

@ -25,7 +25,7 @@ colvar::cvc::cvc()
period = 0.0; period = 0.0;
wrap_center = 0.0; wrap_center = 0.0;
width = 0.0; width = 0.0;
init_dependencies(); cvc::init_dependencies();
} }
@ -39,7 +39,26 @@ colvar::cvc::cvc(std::string const &conf)
wrap_center = 0.0; wrap_center = 0.0;
width = 0.0; width = 0.0;
init_dependencies(); init_dependencies();
init(conf); colvar::cvc::init(conf);
}
int colvar::cvc::set_function_type(std::string const &type)
{
function_type = type;
if (function_types.size() == 0) {
function_types.push_back(function_type);
} else {
if (function_types.back() != function_type) {
function_types.push_back(function_type);
}
}
for (size_t i = function_types.size()-1; i > 0; i--) {
cvm::main()->cite_feature(function_types[i]+" colvar component"+
" (derived from "+function_types[i-1]+")");
}
cvm::main()->cite_feature(function_types[0]+" colvar component");
return COLVARS_OK;
} }
@ -63,13 +82,16 @@ int colvar::cvc::init(std::string const &conf)
if ((name != old_name) && (old_name.size() > 0)) { if ((name != old_name) && (old_name.size() > 0)) {
cvm::error("Error: cannot rename component \""+old_name+ cvm::error("Error: cannot rename component \""+old_name+
"\" after initialization (new name = \""+name+"\")", "\" after initialization (new name = \""+name+"\")",
INPUT_ERROR); COLVARS_INPUT_ERROR);
name = old_name; name = old_name;
} }
} }
get_keyval(conf, "componentCoeff", sup_coeff, sup_coeff); get_keyval(conf, "componentCoeff", sup_coeff, sup_coeff);
get_keyval(conf, "componentExp", sup_np, sup_np); get_keyval(conf, "componentExp", sup_np, sup_np);
if (sup_coeff != 1.0 || sup_np != 1) {
cvm::main()->cite_feature("Linear and polynomial combination of colvar components");
}
// TODO these could be condensed into get_keyval() // TODO these could be condensed into get_keyval()
register_param("componentCoeff", reinterpret_cast<void *>(&sup_coeff)); register_param("componentCoeff", reinterpret_cast<void *>(&sup_coeff));
register_param("componentExp", reinterpret_cast<void *>(&sup_np)); register_param("componentExp", reinterpret_cast<void *>(&sup_np));
@ -145,8 +167,8 @@ cvm::atom_group *colvar::cvc::parse_group(std::string const &conf,
if (is_available(f_cvc_scalable_com) if (is_available(f_cvc_scalable_com)
&& is_enabled(f_cvc_com_based) && is_enabled(f_cvc_com_based)
&& !is_enabled(f_cvc_debug_gradient)) { && !is_enabled(f_cvc_debug_gradient)) {
disable(f_cvc_explicit_gradient);
enable(f_cvc_scalable_com); enable(f_cvc_scalable_com);
enable(f_cvc_scalable);
// The CVC makes the feature available; // The CVC makes the feature available;
// the atom group will enable it unless it needs to compute a rotational fit // the atom group will enable it unless it needs to compute a rotational fit
group->provide(f_ag_scalable_com); group->provide(f_ag_scalable_com);
@ -158,7 +180,7 @@ cvm::atom_group *colvar::cvc::parse_group(std::string const &conf,
if (group_conf.size() == 0) { if (group_conf.size() == 0) {
cvm::error("Error: atom group \""+group->key+ cvm::error("Error: atom group \""+group->key+
"\" is set, but has no definition.\n", "\" is set, but has no definition.\n",
INPUT_ERROR); COLVARS_INPUT_ERROR);
return group; return group;
} }
@ -169,7 +191,7 @@ cvm::atom_group *colvar::cvc::parse_group(std::string const &conf,
group->check_keywords(group_conf, group_key); group->check_keywords(group_conf, group_key);
if (cvm::get_error()) { if (cvm::get_error()) {
cvm::error("Error parsing definition for atom group \""+ cvm::error("Error parsing definition for atom group \""+
std::string(group_key)+"\".", INPUT_ERROR); std::string(group_key)+"\".", COLVARS_INPUT_ERROR);
} }
cvm::decrease_depth(); cvm::decrease_depth();
@ -230,12 +252,18 @@ int colvar::cvc::init_dependencies() {
init_feature(f_cvc_pbc_minimum_image, "use_minimum-image_with_PBCs", f_type_user); init_feature(f_cvc_pbc_minimum_image, "use_minimum-image_with_PBCs", f_type_user);
init_feature(f_cvc_scalable, "scalable_calculation", f_type_static); init_feature(f_cvc_scalable, "scalable_calculation", f_type_dynamic);
require_feature_self(f_cvc_scalable, f_cvc_scalable_com); require_feature_self(f_cvc_scalable_com, f_cvc_scalable);
// CVC cannot compute atom-level gradients on rank 0 if colvar computation is distributed
exclude_feature_self(f_cvc_scalable, f_cvc_explicit_gradient);
init_feature(f_cvc_scalable_com, "scalable_calculation_of_centers_of_mass", f_type_static); init_feature(f_cvc_scalable_com, "scalable_calculation_of_centers_of_mass", f_type_static);
require_feature_self(f_cvc_scalable_com, f_cvc_com_based); require_feature_self(f_cvc_scalable_com, f_cvc_com_based);
// CVC cannot compute atom-level gradients if computed on atom group COM
exclude_feature_self(f_cvc_scalable_com, f_cvc_explicit_gradient);
init_feature(f_cvc_collect_atom_ids, "collect_atom_ids", f_type_dynamic);
require_feature_children(f_cvc_collect_atom_ids, f_ag_collect_atom_ids);
// TODO only enable this when f_ag_scalable can be turned on for a pre-initialized group // TODO only enable this when f_ag_scalable can be turned on for a pre-initialized group
// require_feature_children(f_cvc_scalable, f_ag_scalable); // require_feature_children(f_cvc_scalable, f_ag_scalable);
@ -262,17 +290,15 @@ int colvar::cvc::init_dependencies() {
// Each cvc specifies what other features are available // Each cvc specifies what other features are available
feature_states[f_cvc_active].available = true; feature_states[f_cvc_active].available = true;
feature_states[f_cvc_gradient].available = true; feature_states[f_cvc_gradient].available = true;
feature_states[f_cvc_collect_atom_ids].available = true;
// CVCs are enabled from the start - get disabled based on flags // CVCs are enabled from the start - get disabled based on flags
enable(f_cvc_active); enable(f_cvc_active);
// feature_states[f_cvc_active].enabled = true;
// Explicit gradients are implemented in mosts CVCs. Exceptions must be specified explicitly. // Explicit gradients are implemented in most CVCs. Exceptions must be specified explicitly.
// feature_states[f_cvc_explicit_gradient].enabled = true;
enable(f_cvc_explicit_gradient); enable(f_cvc_explicit_gradient);
// Use minimum-image distances by default // Use minimum-image distances by default
// feature_states[f_cvc_pbc_minimum_image].enabled = true;
enable(f_cvc_pbc_minimum_image); enable(f_cvc_pbc_minimum_image);
// Features that are implemented by default if their requirements are // Features that are implemented by default if their requirements are
@ -316,7 +342,16 @@ void colvar::cvc::init_as_distance()
void colvar::cvc::init_as_angle() void colvar::cvc::init_as_angle()
{ {
x.type(colvarvalue::type_scalar); x.type(colvarvalue::type_scalar);
init_scalar_boundaries(0.0, 180); init_scalar_boundaries(0.0, 180.0);
}
void colvar::cvc::init_as_periodic_angle()
{
x.type(colvarvalue::type_scalar);
enable(f_cvc_periodic);
period = 360.0;
init_scalar_boundaries(-180.0, 180.0);
} }

View File

@ -28,6 +28,7 @@
#if (__cplusplus >= 201103L) #if (__cplusplus >= 201103L)
// C++11-only functions // C++11-only functions
#include "colvar_geometricpath.h" #include "colvar_geometricpath.h"
#include <memory>
#include <functional> #include <functional>
#endif #endif
@ -110,6 +111,9 @@ public:
/// Calls the init() function of the class /// Calls the init() function of the class
cvc(std::string const &conf); cvc(std::string const &conf);
/// Set the value of \link function_type \endlink and its dependencies
int set_function_type(std::string const &type);
/// An init function should be defined for every class inheriting from cvc /// An init function should be defined for every class inheriting from cvc
/// \param conf Contents of the configuration file pertaining to this \link /// \param conf Contents of the configuration file pertaining to this \link
/// cvc \endlink /// cvc \endlink
@ -279,6 +283,9 @@ public:
protected: protected:
/// Record the type of this class as well as those it is derived from
std::vector<std::string> function_types;
/// \brief Cached value /// \brief Cached value
colvarvalue x; colvarvalue x;
@ -298,9 +305,12 @@ protected:
/// \brief Set data types for a scalar distance (convenience function) /// \brief Set data types for a scalar distance (convenience function)
void init_as_distance(); void init_as_distance();
/// \brief Set data types for a bounded angle (convenience function) /// \brief Set data types for a bounded angle (0° to 180°)
void init_as_angle(); void init_as_angle();
/// \brief Set data types for a periodic angle (-180° to 180°)
void init_as_periodic_angle();
/// \brief Set two scalar boundaries (convenience function) /// \brief Set two scalar boundaries (convenience function)
void init_scalar_boundaries(cvm::real lb, cvm::real ub); void init_scalar_boundaries(cvm::real lb, cvm::real ub);
@ -347,8 +357,6 @@ protected:
cvm::atom_group *group2; cvm::atom_group *group2;
/// Vector distance, cached to be recycled /// Vector distance, cached to be recycled
cvm::rvector dist_v; cvm::rvector dist_v;
/// Use absolute positions, ignoring PBCs when present
bool b_no_PBC;
public: public:
distance(std::string const &conf); distance(std::string const &conf);
distance(); distance();
@ -432,8 +440,6 @@ protected:
cvm::atom_group *ref1; cvm::atom_group *ref1;
/// Optional, second ref atom group /// Optional, second ref atom group
cvm::atom_group *ref2; cvm::atom_group *ref2;
/// Use absolute positions, ignoring PBCs when present
bool b_no_PBC;
/// Vector on which the distance vector is projected /// Vector on which the distance vector is projected
cvm::rvector axis; cvm::rvector axis;
/// Norm of the axis /// Norm of the axis
@ -560,8 +566,6 @@ protected:
cvm::atom_group *group2; cvm::atom_group *group2;
/// Components of the distance vector orthogonal to the axis /// Components of the distance vector orthogonal to the axis
int exponent; int exponent;
/// Use absolute positions, ignoring PBCs when present
bool b_no_PBC;
public: public:
distance_inv(std::string const &conf); distance_inv(std::string const &conf);
virtual ~distance_inv() {} virtual ~distance_inv() {}
@ -588,8 +592,6 @@ protected:
cvm::atom_group *group1; cvm::atom_group *group1;
/// Second atom group /// Second atom group
cvm::atom_group *group2; cvm::atom_group *group2;
/// Use absolute positions, ignoring PBCs when present
bool b_no_PBC;
public: public:
distance_pairs(std::string const &conf); distance_pairs(std::string const &conf);
distance_pairs(); distance_pairs();
@ -1500,6 +1502,29 @@ public:
}; };
// \brief Colvar component: alch_Flambda
// To communicate force on lambda with back-end in lambda-dynamics
class colvar::alch_Flambda
: public colvar::cvc
{
protected:
// No atom groups needed
public:
alch_Flambda(std::string const &conf);
alch_Flambda();
virtual ~alch_Flambda() {}
virtual void calc_value();
virtual void calc_gradients();
virtual void apply_force(colvarvalue const &force);
virtual cvm::real dist2(colvarvalue const &x1,
colvarvalue const &x2) const;
virtual colvarvalue dist2_lgrad(colvarvalue const &x1,
colvarvalue const &x2) const;
virtual colvarvalue dist2_rgrad(colvarvalue const &x1,
colvarvalue const &x2) const;
};
class colvar::componentDisabled class colvar::componentDisabled
: public colvar::cvc : public colvar::cvc
{ {
@ -1601,6 +1626,32 @@ public:
}; };
/// custom expression of colvars
class colvar::customColvar
: public colvar::linearCombination
{
protected:
bool use_custom_function;
#ifdef LEPTON
/// Vector of evaluators for custom functions using Lepton
std::vector<Lepton::CompiledExpression *> value_evaluators;
/// Vector of evaluators for gradients of custom functions
std::vector<Lepton::CompiledExpression *> gradient_evaluators;
/// Vector of references to cvc values to be passed to Lepton evaluators
std::vector<double *> value_eval_var_refs;
std::vector<double *> grad_eval_var_refs;
/// Unused value that is written to when a variable simplifies out of a Lepton expression
double dev_null;
#endif
public:
customColvar(std::string const &conf);
virtual ~customColvar();
virtual void calc_value();
virtual void calc_gradients();
virtual void apply_force(colvarvalue const &force);
};
class colvar::CVBasedPath class colvar::CVBasedPath
: public colvar::cvc : public colvar::cvc
{ {
@ -1689,6 +1740,27 @@ public:
virtual void apply_force(colvarvalue const &force); virtual void apply_force(colvarvalue const &force);
}; };
// forward declaration
namespace neuralnetworkCV {
class neuralNetworkCompute;
}
class colvar::neuralNetwork
: public linearCombination
{
protected:
/// actual computation happens in neuralnetworkCV::neuralNetworkCompute
std::unique_ptr<neuralnetworkCV::neuralNetworkCompute> nn;
/// the index of nn output components
size_t m_output_index;
public:
neuralNetwork(std::string const &conf);
virtual ~neuralNetwork();
virtual void calc_value();
virtual void calc_gradients();
virtual void apply_force(colvarvalue const &force);
};
#else // if the compiler doesn't support C++11 #else // if the compiler doesn't support C++11
class colvar::linearCombination class colvar::linearCombination
@ -1754,6 +1826,13 @@ public:
azpathCV(std::string const &conf) : componentDisabled(conf) {} azpathCV(std::string const &conf) : componentDisabled(conf) {}
}; };
class colvar::neuralNetwork
: public colvar::componentDisabled
{
public:
neuralNetwork(std::string const &conf) : componentDisabled(conf) {}
};
#endif // C++11 checking #endif // C++11 checking

View File

@ -20,7 +20,7 @@
colvar::alch_lambda::alch_lambda(std::string const &conf) colvar::alch_lambda::alch_lambda(std::string const &conf)
: cvc(conf) : cvc(conf)
{ {
function_type = "alch_lambda"; set_function_type("alchLambda");
disable(f_cvc_explicit_gradient); disable(f_cvc_explicit_gradient);
disable(f_cvc_gradient); disable(f_cvc_gradient);
@ -36,8 +36,12 @@ void colvar::alch_lambda::calc_value()
// Special workflow: // Special workflow:
// at the beginning of the timestep we get a force instead of calculating the value // at the beginning of the timestep we get a force instead of calculating the value
cvm::proxy->get_dE_dLambda(&ft.real_value); cvm::proxy->get_dE_dlambda(&ft.real_value);
ft.real_value *= -1.0; // Energy derivative to force ft.real_value *= -1.0; // Energy derivative to force
// Include any force due to bias on Flambda
ft.real_value += cvm::proxy->indirect_lambda_biasing_force;
cvm::proxy->indirect_lambda_biasing_force = 0.0;
} }
@ -46,11 +50,57 @@ void colvar::alch_lambda::calc_gradients()
} }
void colvar::alch_lambda::apply_force(colvarvalue const &force) void colvar::alch_lambda::apply_force(colvarvalue const & /* force */)
{ {
// Special workflow: // new value will be cached and sent at end of timestep
// at the end of the time step we send a new value cvm::proxy->set_alch_lambda(x.real_value);
cvm::proxy->set_alch_lambda(&x.real_value);
} }
simple_scalar_dist_functions(alch_lambda) simple_scalar_dist_functions(alch_lambda)
colvar::alch_Flambda::alch_Flambda(std::string const &conf)
: cvc(conf)
{
set_function_type("alch_Flambda");
disable(f_cvc_explicit_gradient);
disable(f_cvc_gradient);
x.type(colvarvalue::type_scalar);
}
void colvar::alch_Flambda::calc_value()
{
// Special workflow:
// at the beginning of the timestep we get a force instead of calculating the value
// Query initial value from back-end
cvm::proxy->get_dE_dlambda(&x.real_value);
x.real_value *= -1.0; // Energy derivative to force
}
void colvar::alch_Flambda::calc_gradients()
{
}
void colvar::alch_Flambda::apply_force(colvarvalue const &force)
{
// Convert force on Flambda to force on dE/dlambda
cvm::real f = -1.0 * force.real_value;
// Send scalar force to back-end, which will distribute it onto atoms
cvm::proxy->apply_force_dE_dlambda(&f);
// Propagate force on Flambda to lambda internally
cvm::real d2E_dlambda2;
cvm::proxy->get_d2E_dlambda2(&d2E_dlambda2);
// This accumulates a force, it needs to be zeroed when taken into account by lambda
cvm::proxy->indirect_lambda_biasing_force += d2E_dlambda2 * f;
}
simple_scalar_dist_functions(alch_Flambda)

View File

@ -15,7 +15,7 @@
colvar::angle::angle(std::string const &conf) colvar::angle::angle(std::string const &conf)
: cvc(conf) : cvc(conf)
{ {
function_type = "angle"; set_function_type("angle");
init_as_angle(); init_as_angle();
provide(f_cvc_inv_gradient); provide(f_cvc_inv_gradient);
@ -34,7 +34,7 @@ colvar::angle::angle(cvm::atom const &a1,
cvm::atom const &a2, cvm::atom const &a2,
cvm::atom const &a3) cvm::atom const &a3)
{ {
function_type = "angle"; set_function_type("angle");
init_as_angle(); init_as_angle();
provide(f_cvc_inv_gradient); provide(f_cvc_inv_gradient);
@ -140,7 +140,7 @@ simple_scalar_dist_functions(angle)
colvar::dipole_angle::dipole_angle(std::string const &conf) colvar::dipole_angle::dipole_angle(std::string const &conf)
: cvc(conf) : cvc(conf)
{ {
function_type = "dipole_angle"; set_function_type("dipoleAngle");
init_as_angle(); init_as_angle();
group1 = parse_group(conf, "group1"); group1 = parse_group(conf, "group1");
@ -155,7 +155,8 @@ colvar::dipole_angle::dipole_angle(cvm::atom const &a1,
cvm::atom const &a2, cvm::atom const &a2,
cvm::atom const &a3) cvm::atom const &a3)
{ {
function_type = "dipole_angle"; set_function_type("dipoleAngle");
init_as_angle();
group1 = new cvm::atom_group(std::vector<cvm::atom>(1, a1)); group1 = new cvm::atom_group(std::vector<cvm::atom>(1, a1));
group2 = new cvm::atom_group(std::vector<cvm::atom>(1, a2)); group2 = new cvm::atom_group(std::vector<cvm::atom>(1, a2));
@ -163,16 +164,13 @@ colvar::dipole_angle::dipole_angle(cvm::atom const &a1,
register_atom_group(group1); register_atom_group(group1);
register_atom_group(group2); register_atom_group(group2);
register_atom_group(group3); register_atom_group(group3);
x.type(colvarvalue::type_scalar);
} }
colvar::dipole_angle::dipole_angle() colvar::dipole_angle::dipole_angle()
{ {
function_type = "dipole_angle"; set_function_type("dipoleAngle");
init_as_angle(); init_as_angle();
x.type(colvarvalue::type_scalar);
} }
@ -251,9 +249,8 @@ simple_scalar_dist_functions(dipole_angle)
colvar::dihedral::dihedral(std::string const &conf) colvar::dihedral::dihedral(std::string const &conf)
: cvc(conf) : cvc(conf)
{ {
function_type = "dihedral"; set_function_type("dihedral");
period = 360.0; init_as_periodic_angle();
enable(f_cvc_periodic);
provide(f_cvc_inv_gradient); provide(f_cvc_inv_gradient);
provide(f_cvc_Jacobian); provide(f_cvc_Jacobian);
enable(f_cvc_com_based); enable(f_cvc_com_based);
@ -264,8 +261,6 @@ colvar::dihedral::dihedral(std::string const &conf)
group4 = parse_group(conf, "group4"); group4 = parse_group(conf, "group4");
init_total_force_params(conf); init_total_force_params(conf);
x.type(colvarvalue::type_scalar);
} }
@ -274,12 +269,8 @@ colvar::dihedral::dihedral(cvm::atom const &a1,
cvm::atom const &a3, cvm::atom const &a3,
cvm::atom const &a4) cvm::atom const &a4)
{ {
if (cvm::debug()) set_function_type("dihedral");
cvm::log("Initializing dihedral object from atom groups.\n"); init_as_periodic_angle();
function_type = "dihedral";
period = 360.0;
enable(f_cvc_periodic);
provide(f_cvc_inv_gradient); provide(f_cvc_inv_gradient);
provide(f_cvc_Jacobian); provide(f_cvc_Jacobian);
enable(f_cvc_com_based); enable(f_cvc_com_based);
@ -294,22 +285,16 @@ colvar::dihedral::dihedral(cvm::atom const &a1,
register_atom_group(group2); register_atom_group(group2);
register_atom_group(group3); register_atom_group(group3);
register_atom_group(group4); register_atom_group(group4);
x.type(colvarvalue::type_scalar);
if (cvm::debug())
cvm::log("Done initializing dihedral object from atom groups.\n");
} }
colvar::dihedral::dihedral() colvar::dihedral::dihedral()
{ {
function_type = "dihedral"; set_function_type("dihedral");
period = 360.0; init_as_periodic_angle();
enable(f_cvc_periodic); enable(f_cvc_periodic);
provide(f_cvc_inv_gradient); provide(f_cvc_inv_gradient);
provide(f_cvc_Jacobian); provide(f_cvc_Jacobian);
x.type(colvarvalue::type_scalar);
} }
@ -516,7 +501,7 @@ void colvar::dihedral::wrap(colvarvalue &x_unwrapped) const
colvar::polar_theta::polar_theta(std::string const &conf) colvar::polar_theta::polar_theta(std::string const &conf)
: cvc(conf) : cvc(conf)
{ {
function_type = "polar_theta"; set_function_type("polarTheta");
enable(f_cvc_com_based); enable(f_cvc_com_based);
atoms = parse_group(conf, "atoms"); atoms = parse_group(conf, "atoms");
@ -527,7 +512,7 @@ colvar::polar_theta::polar_theta(std::string const &conf)
colvar::polar_theta::polar_theta() colvar::polar_theta::polar_theta()
{ {
function_type = "polar_theta"; set_function_type("polarTheta");
x.type(colvarvalue::type_scalar); x.type(colvarvalue::type_scalar);
} }
@ -568,21 +553,19 @@ simple_scalar_dist_functions(polar_theta)
colvar::polar_phi::polar_phi(std::string const &conf) colvar::polar_phi::polar_phi(std::string const &conf)
: cvc(conf) : cvc(conf)
{ {
function_type = "polar_phi"; set_function_type("polarPhi");
period = 360.0; init_as_periodic_angle();
enable(f_cvc_com_based); enable(f_cvc_com_based);
atoms = parse_group(conf, "atoms"); atoms = parse_group(conf, "atoms");
init_total_force_params(conf); init_total_force_params(conf);
x.type(colvarvalue::type_scalar);
} }
colvar::polar_phi::polar_phi() colvar::polar_phi::polar_phi()
{ {
function_type = "polar_phi"; set_function_type("polarPhi");
period = 360.0; init_as_periodic_angle();
x.type(colvarvalue::type_scalar);
} }

View File

@ -13,7 +13,7 @@
#include "colvarcomp.h" #include "colvarcomp.h"
colvar::aspathCV::aspathCV(std::string const &conf): CVBasedPath(conf) { colvar::aspathCV::aspathCV(std::string const &conf): CVBasedPath(conf) {
function_type = "aspathCV"; set_function_type("aspathCV");
cvm::log(std::string("Total number of frames: ") + cvm::to_str(total_reference_frames) + std::string("\n")); cvm::log(std::string("Total number of frames: ") + cvm::to_str(total_reference_frames) + std::string("\n"));
std::vector<cvm::real> p_weights(cv.size(), 1.0); std::vector<cvm::real> p_weights(cv.size(), 1.0);
get_keyval(conf, "weights", p_weights, std::vector<cvm::real>(cv.size(), 1.0)); get_keyval(conf, "weights", p_weights, std::vector<cvm::real>(cv.size(), 1.0));
@ -67,9 +67,7 @@ void colvar::aspathCV::calc_gradients() {
computeDerivatives(); computeDerivatives();
for (size_t i_cv = 0; i_cv < cv.size(); ++i_cv) { for (size_t i_cv = 0; i_cv < cv.size(); ++i_cv) {
cv[i_cv]->calc_gradients(); cv[i_cv]->calc_gradients();
if ( cv[i_cv]->is_enabled(f_cvc_explicit_gradient) && if (cv[i_cv]->is_enabled(f_cvc_explicit_gradient)) {
!cv[i_cv]->is_enabled(f_cvc_scalable) &&
!cv[i_cv]->is_enabled(f_cvc_scalable_com)) {
cvm::real factor_polynomial = getPolynomialFactorOfCVGradient(i_cv); cvm::real factor_polynomial = getPolynomialFactorOfCVGradient(i_cv);
for (size_t j_elem = 0; j_elem < cv[i_cv]->value().size(); ++j_elem) { for (size_t j_elem = 0; j_elem < cv[i_cv]->value().size(); ++j_elem) {
for (size_t k_ag = 0 ; k_ag < cv[i_cv]->atom_groups.size(); ++k_ag) { for (size_t k_ag = 0 ; k_ag < cv[i_cv]->atom_groups.size(); ++k_ag) {
@ -84,10 +82,7 @@ void colvar::aspathCV::calc_gradients() {
void colvar::aspathCV::apply_force(colvarvalue const &force) { void colvar::aspathCV::apply_force(colvarvalue const &force) {
for (size_t i_cv = 0; i_cv < cv.size(); ++i_cv) { for (size_t i_cv = 0; i_cv < cv.size(); ++i_cv) {
if ( cv[i_cv]->is_enabled(f_cvc_explicit_gradient) && if (cv[i_cv]->is_enabled(f_cvc_explicit_gradient)) {
!cv[i_cv]->is_enabled(f_cvc_scalable) &&
!cv[i_cv]->is_enabled(f_cvc_scalable_com)
) {
for (size_t k_ag = 0 ; k_ag < cv[i_cv]->atom_groups.size(); ++k_ag) { for (size_t k_ag = 0 ; k_ag < cv[i_cv]->atom_groups.size(); ++k_ag) {
(cv[i_cv]->atom_groups)[k_ag]->apply_colvar_force(force.real_value); (cv[i_cv]->atom_groups)[k_ag]->apply_colvar_force(force.real_value);
} }
@ -102,7 +97,7 @@ void colvar::aspathCV::apply_force(colvarvalue const &force) {
colvar::aspathCV::~aspathCV() {} colvar::aspathCV::~aspathCV() {}
colvar::azpathCV::azpathCV(std::string const &conf): CVBasedPath(conf) { colvar::azpathCV::azpathCV(std::string const &conf): CVBasedPath(conf) {
function_type = "azpathCV"; set_function_type("azpathCV");
cvm::log(std::string("Total number of frames: ") + cvm::to_str(total_reference_frames) + std::string("\n")); cvm::log(std::string("Total number of frames: ") + cvm::to_str(total_reference_frames) + std::string("\n"));
std::vector<cvm::real> p_weights(cv.size(), 1.0); std::vector<cvm::real> p_weights(cv.size(), 1.0);
get_keyval(conf, "weights", p_weights, std::vector<cvm::real>(cv.size(), 1.0)); get_keyval(conf, "weights", p_weights, std::vector<cvm::real>(cv.size(), 1.0));
@ -156,9 +151,7 @@ void colvar::azpathCV::calc_gradients() {
computeDerivatives(); computeDerivatives();
for (size_t i_cv = 0; i_cv < cv.size(); ++i_cv) { for (size_t i_cv = 0; i_cv < cv.size(); ++i_cv) {
cv[i_cv]->calc_gradients(); cv[i_cv]->calc_gradients();
if ( cv[i_cv]->is_enabled(f_cvc_explicit_gradient) && if (cv[i_cv]->is_enabled(f_cvc_explicit_gradient)) {
!cv[i_cv]->is_enabled(f_cvc_scalable) &&
!cv[i_cv]->is_enabled(f_cvc_scalable_com)) {
cvm::real factor_polynomial = getPolynomialFactorOfCVGradient(i_cv); cvm::real factor_polynomial = getPolynomialFactorOfCVGradient(i_cv);
for (size_t j_elem = 0; j_elem < cv[i_cv]->value().size(); ++j_elem) { for (size_t j_elem = 0; j_elem < cv[i_cv]->value().size(); ++j_elem) {
for (size_t k_ag = 0 ; k_ag < cv[i_cv]->atom_groups.size(); ++k_ag) { for (size_t k_ag = 0 ; k_ag < cv[i_cv]->atom_groups.size(); ++k_ag) {
@ -174,10 +167,7 @@ void colvar::azpathCV::calc_gradients() {
void colvar::azpathCV::apply_force(colvarvalue const &force) { void colvar::azpathCV::apply_force(colvarvalue const &force) {
for (size_t i_cv = 0; i_cv < cv.size(); ++i_cv) { for (size_t i_cv = 0; i_cv < cv.size(); ++i_cv) {
if ( cv[i_cv]->is_enabled(f_cvc_explicit_gradient) && if (cv[i_cv]->is_enabled(f_cvc_explicit_gradient)) {
!cv[i_cv]->is_enabled(f_cvc_scalable) &&
!cv[i_cv]->is_enabled(f_cvc_scalable_com)
) {
for (size_t k_ag = 0 ; k_ag < cv[i_cv]->atom_groups.size(); ++k_ag) { for (size_t k_ag = 0 ; k_ag < cv[i_cv]->atom_groups.size(); ++k_ag) {
(cv[i_cv]->atom_groups)[k_ag]->apply_colvar_force(force.real_value); (cv[i_cv]->atom_groups)[k_ag]->apply_colvar_force(force.real_value);
} }

View File

@ -0,0 +1,323 @@
#if (__cplusplus >= 201103L)
// 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
// 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.
#include "colvarcomp.h"
colvar::linearCombination::linearCombination(std::string const &conf): cvc(conf) {
// Lookup all available sub-cvcs
for (auto it_cv_map = colvar::get_global_cvc_map().begin(); it_cv_map != colvar::get_global_cvc_map().end(); ++it_cv_map) {
if (key_lookup(conf, it_cv_map->first.c_str())) {
std::vector<std::string> sub_cvc_confs;
get_key_string_multi_value(conf, it_cv_map->first.c_str(), sub_cvc_confs);
for (auto it_sub_cvc_conf = sub_cvc_confs.begin(); it_sub_cvc_conf != sub_cvc_confs.end(); ++it_sub_cvc_conf) {
cv.push_back((it_cv_map->second)(*(it_sub_cvc_conf)));
}
}
}
// Sort all sub CVs by their names
std::sort(cv.begin(), cv.end(), colvar::compare_cvc);
for (auto it_sub_cv = cv.begin(); it_sub_cv != cv.end(); ++it_sub_cv) {
for (auto it_atom_group = (*it_sub_cv)->atom_groups.begin(); it_atom_group != (*it_sub_cv)->atom_groups.end(); ++it_atom_group) {
register_atom_group(*it_atom_group);
}
}
// Show useful error messages and prevent crashes if no sub CVC is found
if (cv.size() == 0) {
cvm::error("Error: the CV " + name +
" expects one or more nesting components.\n");
return;
} else {
// TODO: Maybe we can add an option to allow mixing scalar and vector types,
// but that's a bit complicated so we just require a consistent type
// of nesting CVs.
x.type(cv[0]->value());
x.reset();
for (size_t i_cv = 1; i_cv < cv.size(); ++i_cv) {
const auto type_i = cv[i_cv]->value().type();
if (type_i != x.type()) {
cvm::error("Error: the type of sub-CVC " + cv[i_cv]->name +
" is " + colvarvalue::type_desc(type_i) + ", which is "
"different to the type of the first sub-CVC. Currently "
"only sub-CVCs of the same type are supported to be "
"nested.\n");
return;
}
}
}
use_explicit_gradients = true;
for (size_t i_cv = 0; i_cv < cv.size(); ++i_cv) {
if (!cv[i_cv]->is_enabled(f_cvc_explicit_gradient)) {
use_explicit_gradients = false;
}
}
if (!use_explicit_gradients) {
disable(f_cvc_explicit_gradient);
}
}
cvm::real colvar::linearCombination::getPolynomialFactorOfCVGradient(size_t i_cv) const {
cvm::real factor_polynomial = 1.0;
if (cv[i_cv]->value().type() == colvarvalue::type_scalar) {
factor_polynomial = cv[i_cv]->sup_coeff * cv[i_cv]->sup_np * cvm::pow(cv[i_cv]->value().real_value, cv[i_cv]->sup_np - 1);
} else {
factor_polynomial = cv[i_cv]->sup_coeff;
}
return factor_polynomial;
}
colvar::linearCombination::~linearCombination() {
// Recall the steps we initialize the sub-CVCs:
// 1. Lookup all sub-CVCs and then register the atom groups for sub-CVCs
// in their constructors;
// 2. Iterate over all sub-CVCs, get the pointers of their atom groups
// groups, and register again in the parent (current) CVC.
// That being said, the atom groups become children of the sub-CVCs at
// first, and then become children of the parent CVC.
// So, to destruct this class (parent CVC class), we need to remove the
// dependencies of the atom groups to the parent CVC at first.
remove_all_children();
// Then we remove the dependencies of the atom groups to the sub-CVCs
// in their destructors.
for (auto it = cv.begin(); it != cv.end(); ++it) {
delete (*it);
}
// The last step is cleaning up the list of atom groups.
atom_groups.clear();
}
void colvar::linearCombination::calc_value() {
x.reset();
for (size_t i_cv = 0; i_cv < cv.size(); ++i_cv) {
cv[i_cv]->calc_value();
colvarvalue current_cv_value(cv[i_cv]->value());
// polynomial combination allowed
if (current_cv_value.type() == colvarvalue::type_scalar) {
x += cv[i_cv]->sup_coeff * (cvm::pow(current_cv_value.real_value, cv[i_cv]->sup_np));
} else {
x += cv[i_cv]->sup_coeff * current_cv_value;
}
}
}
void colvar::linearCombination::calc_gradients() {
for (size_t i_cv = 0; i_cv < cv.size(); ++i_cv) {
cv[i_cv]->calc_gradients();
if (cv[i_cv]->is_enabled(f_cvc_explicit_gradient)) {
cvm::real factor_polynomial = getPolynomialFactorOfCVGradient(i_cv);
for (size_t j_elem = 0; j_elem < cv[i_cv]->value().size(); ++j_elem) {
for (size_t k_ag = 0 ; k_ag < cv[i_cv]->atom_groups.size(); ++k_ag) {
for (size_t l_atom = 0; l_atom < (cv[i_cv]->atom_groups)[k_ag]->size(); ++l_atom) {
(*(cv[i_cv]->atom_groups)[k_ag])[l_atom].grad = factor_polynomial * (*(cv[i_cv]->atom_groups)[k_ag])[l_atom].grad;
}
}
}
}
}
}
void colvar::linearCombination::apply_force(colvarvalue const &force) {
for (size_t i_cv = 0; i_cv < cv.size(); ++i_cv) {
// If this CV us explicit gradients, then atomic gradients is already calculated
// We can apply the force to atom groups directly
if (cv[i_cv]->is_enabled(f_cvc_explicit_gradient)) {
for (size_t k_ag = 0 ; k_ag < cv[i_cv]->atom_groups.size(); ++k_ag) {
(cv[i_cv]->atom_groups)[k_ag]->apply_colvar_force(force.real_value);
}
} else {
// Compute factors for polynomial combinations
cvm::real factor_polynomial = getPolynomialFactorOfCVGradient(i_cv);
colvarvalue cv_force = force.real_value * factor_polynomial;
cv[i_cv]->apply_force(cv_force);
}
}
}
colvar::customColvar::customColvar(std::string const &conf): linearCombination(conf) {
use_custom_function = false;
// code swipe from colvar::init_custom_function
#ifdef LEPTON
std::string expr_in, expr;
std::vector<Lepton::ParsedExpression> pexprs;
Lepton::ParsedExpression pexpr;
double *ref;
size_t pos = 0; // current position in config string
if (key_lookup(conf, "customFunction", &expr_in, &pos)) {
use_custom_function = true;
cvm::log("This colvar uses a custom function.\n");
do {
expr = expr_in;
if (cvm::debug())
cvm::log("Parsing expression \"" + expr + "\".\n");
try {
pexpr = Lepton::Parser::parse(expr);
pexprs.push_back(pexpr);
} catch (...) {
cvm::error("Error parsing expression \"" + expr + "\".\n", COLVARS_INPUT_ERROR);
}
try {
value_evaluators.push_back(new Lepton::CompiledExpression(pexpr.createCompiledExpression()));
// Define variables for cvc values
for (size_t i = 0; i < cv.size(); ++i) {
for (size_t j = 0; j < cv[i]->value().size(); ++j) {
std::string vn = cv[i]->name + (cv[i]->value().size() > 1 ? cvm::to_str(j+1) : "");
try {
ref = &value_evaluators.back()->getVariableReference(vn);
} catch (...) {
ref = &dev_null;
cvm::log("Warning: Variable " + vn + " is absent from expression \"" + expr + "\".\n");
}
value_eval_var_refs.push_back(ref);
}
}
} catch (...) {
cvm::error("Error compiling expression \"" + expr + "\".\n", COLVARS_INPUT_ERROR);
}
} while (key_lookup(conf, "customFunction", &expr_in, &pos));
// Now define derivative with respect to each scalar sub-component
for (size_t i = 0; i < cv.size(); ++i) {
for (size_t j = 0; j < cv[i]->value().size(); ++j) {
std::string vn = cv[i]->name + (cv[i]->value().size() > 1 ? cvm::to_str(j+1) : "");
for (size_t c = 0; c < pexprs.size(); ++c) {
gradient_evaluators.push_back(new Lepton::CompiledExpression(pexprs[c].differentiate(vn).createCompiledExpression()));
for (size_t k = 0; k < cv.size(); ++k) {
for (size_t l = 0; l < cv[k]->value().size(); l++) {
std::string vvn = cv[k]->name + (cv[k]->value().size() > 1 ? cvm::to_str(l+1) : "");
try {
ref = &gradient_evaluators.back()->getVariableReference(vvn);
} catch (...) {
cvm::log("Warning: Variable " + vvn + " is absent from derivative of \"" + expr + "\" wrt " + vn + ".\n");
ref = &dev_null;
}
grad_eval_var_refs.push_back(ref);
}
}
}
}
}
if (value_evaluators.size() == 0) {
cvm::error("Error: no custom function defined.\n", COLVARS_INPUT_ERROR);
}
if (value_evaluators.size() != 1) {
x.type(colvarvalue::type_vector);
} else {
x.type(colvarvalue::type_scalar);
}
} else {
cvm::log(std::string{"Warning: no customFunction specified.\n"});
cvm::log(std::string{"Warning: use linear combination instead.\n"});
}
#endif
}
colvar::customColvar::~customColvar() {
#ifdef LEPTON
for (size_t i = 0; i < value_evaluators.size(); ++i) {
if (value_evaluators[i] != nullptr) delete value_evaluators[i];
}
for (size_t i = 0; i < gradient_evaluators.size(); ++i) {
if (gradient_evaluators[i] != nullptr) delete gradient_evaluators[i];
}
#endif
}
void colvar::customColvar::calc_value() {
#ifdef LEPTON
for (size_t i_cv = 0; i_cv < cv.size(); ++i_cv) {
cv[i_cv]->calc_value();
}
x.reset();
size_t l = 0;
for (size_t i = 0; i < x.size(); ++i) {
for (size_t i_cv = 0; i_cv < cv.size(); ++i_cv) {
const colvarvalue& current_cv_value = cv[i_cv]->value();
for (size_t j_elem = 0; j_elem < current_cv_value.size(); ++j_elem) {
if (current_cv_value.type() == colvarvalue::type_scalar) {
*(value_eval_var_refs[l++]) = cv[i_cv]->sup_coeff * (cvm::pow(current_cv_value.real_value, cv[i_cv]->sup_np));
} else {
*(value_eval_var_refs[l++]) = cv[i_cv]->sup_coeff * current_cv_value[j_elem];
}
}
}
x[i] = value_evaluators[i]->evaluate();
}
#endif
if (!use_custom_function) {
colvar::linearCombination::calc_value();
}
}
void colvar::customColvar::calc_gradients() {
#ifdef LEPTON
size_t r = 0; // index in the vector of variable references
size_t e = 0; // index of the gradient evaluator
for (size_t i_cv = 0; i_cv < cv.size(); ++i_cv) { // for each CV
cv[i_cv]->calc_gradients();
if (cv[i_cv]->is_enabled(f_cvc_explicit_gradient)) {
const colvarvalue& current_cv_value = cv[i_cv]->value();
const cvm::real factor_polynomial = getPolynomialFactorOfCVGradient(i_cv);
for (size_t j_elem = 0; j_elem < current_cv_value.size(); ++j_elem) { // for each element in this CV
for (size_t c = 0; c < x.size(); ++c) { // for each custom function expression
for (size_t k = 0; k < cv.size(); ++k) { // this is required since we need to feed all CV values to this expression
const cvm::real factor_polynomial_k = getPolynomialFactorOfCVGradient(k);
for (size_t l = 0; l < cv[k]->value().size(); ++l) {
*(grad_eval_var_refs[r++]) = factor_polynomial_k * cv[k]->value()[l];
}
}
const double expr_grad = gradient_evaluators[e++]->evaluate();
for (size_t k_ag = 0 ; k_ag < cv[i_cv]->atom_groups.size(); ++k_ag) {
for (size_t l_atom = 0; l_atom < (cv[i_cv]->atom_groups)[k_ag]->size(); ++l_atom) {
(*(cv[i_cv]->atom_groups)[k_ag])[l_atom].grad = expr_grad * factor_polynomial * (*(cv[i_cv]->atom_groups)[k_ag])[l_atom].grad;
}
}
}
}
}
}
#endif
if (!use_custom_function) {
colvar::linearCombination::calc_gradients();
}
}
void colvar::customColvar::apply_force(colvarvalue const &force) {
#ifdef LEPTON
size_t r = 0; // index in the vector of variable references
size_t e = 0; // index of the gradient evaluator
for (size_t i_cv = 0; i_cv < cv.size(); ++i_cv) {
// If this CV us explicit gradients, then atomic gradients is already calculated
// We can apply the force to atom groups directly
if (cv[i_cv]->is_enabled(f_cvc_explicit_gradient)) {
for (size_t k_ag = 0 ; k_ag < cv[i_cv]->atom_groups.size(); ++k_ag) {
(cv[i_cv]->atom_groups)[k_ag]->apply_colvar_force(force.real_value);
}
} else {
const colvarvalue& current_cv_value = cv[i_cv]->value();
colvarvalue cv_force(current_cv_value.type());
const cvm::real factor_polynomial = getPolynomialFactorOfCVGradient(i_cv);
for (size_t j_elem = 0; j_elem < current_cv_value.size(); ++j_elem) {
for (size_t c = 0; c < x.size(); ++c) {
for (size_t k = 0; k < cv.size(); ++k) {
const cvm::real factor_polynomial_k = getPolynomialFactorOfCVGradient(k);
for (size_t l = 0; l < cv[k]->value().size(); ++l) {
*(grad_eval_var_refs[r++]) = factor_polynomial_k * cv[k]->value()[l];
}
}
cv_force[j_elem] += factor_polynomial * gradient_evaluators[e++]->evaluate() * force.real_value;
}
}
cv[i_cv]->apply_force(cv_force);
}
}
#endif
if (!use_custom_function) {
colvar::linearCombination::apply_force(force);
}
}
#endif // __cplusplus >= 201103L

View File

@ -94,7 +94,7 @@ colvar::coordnum::coordnum(std::string const &conf)
: cvc(conf), b_anisotropic(false), pairlist(NULL) : cvc(conf), b_anisotropic(false), pairlist(NULL)
{ {
function_type = "coordnum"; set_function_type("coordNum");
x.type(colvarvalue::type_scalar); x.type(colvarvalue::type_scalar);
colvarproxy *proxy = cvm::main()->proxy; colvarproxy *proxy = cvm::main()->proxy;
@ -104,19 +104,19 @@ colvar::coordnum::coordnum(std::string const &conf)
if (group1 == NULL || group2 == NULL) { if (group1 == NULL || group2 == NULL) {
cvm::error("Error: failed to initialize atom groups.\n", cvm::error("Error: failed to initialize atom groups.\n",
INPUT_ERROR); COLVARS_INPUT_ERROR);
return; return;
} }
if (int atom_number = cvm::atom_group::overlap(*group1, *group2)) { if (int atom_number = cvm::atom_group::overlap(*group1, *group2)) {
cvm::error("Error: group1 and group2 share a common atom (number: " + cvm::error("Error: group1 and group2 share a common atom (number: " +
cvm::to_str(atom_number) + ")\n", INPUT_ERROR); cvm::to_str(atom_number) + ")\n", COLVARS_INPUT_ERROR);
return; return;
} }
if (group1->b_dummy) { if (group1->b_dummy) {
cvm::error("Error: only group2 is allowed to be a dummy atom\n", cvm::error("Error: only group2 is allowed to be a dummy atom\n",
INPUT_ERROR); COLVARS_INPUT_ERROR);
return; return;
} }
@ -130,7 +130,7 @@ colvar::coordnum::coordnum(std::string const &conf)
if (b_isotropic) { if (b_isotropic) {
cvm::error("Error: cannot specify \"cutoff\" and \"cutoff3\" " cvm::error("Error: cannot specify \"cutoff\" and \"cutoff3\" "
"at the same time.\n", "at the same time.\n",
INPUT_ERROR); COLVARS_INPUT_ERROR);
return; return;
} }
@ -146,12 +146,12 @@ colvar::coordnum::coordnum(std::string const &conf)
if ( (en%2) || (ed%2) ) { if ( (en%2) || (ed%2) ) {
cvm::error("Error: odd exponent(s) provided, can only use even ones.\n", cvm::error("Error: odd exponent(s) provided, can only use even ones.\n",
INPUT_ERROR); COLVARS_INPUT_ERROR);
} }
if ( (en <= 0) || (ed <= 0) ) { if ( (en <= 0) || (ed <= 0) ) {
cvm::error("Error: negative exponent(s) provided.\n", cvm::error("Error: negative exponent(s) provided.\n",
INPUT_ERROR); COLVARS_INPUT_ERROR);
} }
if (!is_enabled(f_cvc_pbc_minimum_image)) { if (!is_enabled(f_cvc_pbc_minimum_image)) {
@ -162,10 +162,11 @@ colvar::coordnum::coordnum(std::string const &conf)
get_keyval(conf, "tolerance", tolerance, 0.0); get_keyval(conf, "tolerance", tolerance, 0.0);
if (tolerance > 0) { if (tolerance > 0) {
cvm::main()->cite_feature("coordNum pairlist");
get_keyval(conf, "pairListFrequency", pairlist_freq, 100); get_keyval(conf, "pairListFrequency", pairlist_freq, 100);
if ( ! (pairlist_freq > 0) ) { if ( ! (pairlist_freq > 0) ) {
cvm::error("Error: non-positive pairlistfrequency provided.\n", cvm::error("Error: non-positive pairlistfrequency provided.\n",
INPUT_ERROR); COLVARS_INPUT_ERROR);
return; // and do not allocate the pairlists below return; // and do not allocate the pairlists below
} }
if (b_group2_center_only) { if (b_group2_center_only) {
@ -176,8 +177,10 @@ colvar::coordnum::coordnum(std::string const &conf)
} }
} }
init_scalar_boundaries(0.0, b_group2_center_only ? group1->size() : init_scalar_boundaries(0.0, b_group2_center_only ?
group1->size() * group2->size()); static_cast<cvm::real>(group1->size()) :
static_cast<cvm::real>(group1->size() *
group2->size()));
} }
@ -304,7 +307,7 @@ colvar::h_bond::h_bond(std::string const &conf)
if (cvm::debug()) if (cvm::debug())
cvm::log("Initializing h_bond object.\n"); cvm::log("Initializing h_bond object.\n");
function_type = "h_bond"; set_function_type("hBond");
x.type(colvarvalue::type_scalar); x.type(colvarvalue::type_scalar);
init_scalar_boundaries(0.0, 1.0); init_scalar_boundaries(0.0, 1.0);
@ -331,12 +334,12 @@ colvar::h_bond::h_bond(std::string const &conf)
if ( (en%2) || (ed%2) ) { if ( (en%2) || (ed%2) ) {
cvm::error("Error: odd exponent(s) provided, can only use even ones.\n", cvm::error("Error: odd exponent(s) provided, can only use even ones.\n",
INPUT_ERROR); COLVARS_INPUT_ERROR);
} }
if ( (en <= 0) || (ed <= 0) ) { if ( (en <= 0) || (ed <= 0) ) {
cvm::error("Error: negative exponent(s) provided.\n", cvm::error("Error: negative exponent(s) provided.\n",
INPUT_ERROR); COLVARS_INPUT_ERROR);
} }
if (cvm::debug()) if (cvm::debug())
@ -349,7 +352,7 @@ colvar::h_bond::h_bond(cvm::atom const &acceptor,
cvm::real r0_i, int en_i, int ed_i) cvm::real r0_i, int en_i, int ed_i)
: r0(r0_i), en(en_i), ed(ed_i) : r0(r0_i), en(en_i), ed(ed_i)
{ {
function_type = "h_bond"; set_function_type("hBond");
x.type(colvarvalue::type_scalar); x.type(colvarvalue::type_scalar);
init_scalar_boundaries(0.0, 1.0); init_scalar_boundaries(0.0, 1.0);
@ -395,7 +398,7 @@ simple_scalar_dist_functions(h_bond)
colvar::selfcoordnum::selfcoordnum(std::string const &conf) colvar::selfcoordnum::selfcoordnum(std::string const &conf)
: cvc(conf), pairlist(NULL) : cvc(conf), pairlist(NULL)
{ {
function_type = "selfcoordnum"; set_function_type("selfCoordNum");
x.type(colvarvalue::type_scalar); x.type(colvarvalue::type_scalar);
colvarproxy *proxy = cvm::main()->proxy; colvarproxy *proxy = cvm::main()->proxy;
@ -409,12 +412,12 @@ colvar::selfcoordnum::selfcoordnum(std::string const &conf)
if ( (en%2) || (ed%2) ) { if ( (en%2) || (ed%2) ) {
cvm::error("Error: odd exponent(s) provided, can only use even ones.\n", cvm::error("Error: odd exponent(s) provided, can only use even ones.\n",
INPUT_ERROR); COLVARS_INPUT_ERROR);
} }
if ( (en <= 0) || (ed <= 0) ) { if ( (en <= 0) || (ed <= 0) ) {
cvm::error("Error: negative exponent(s) provided.\n", cvm::error("Error: negative exponent(s) provided.\n",
INPUT_ERROR); COLVARS_INPUT_ERROR);
} }
if (!is_enabled(f_cvc_pbc_minimum_image)) { if (!is_enabled(f_cvc_pbc_minimum_image)) {
@ -426,13 +429,14 @@ colvar::selfcoordnum::selfcoordnum(std::string const &conf)
get_keyval(conf, "pairListFrequency", pairlist_freq, 100); get_keyval(conf, "pairListFrequency", pairlist_freq, 100);
if ( ! (pairlist_freq > 0) ) { if ( ! (pairlist_freq > 0) ) {
cvm::error("Error: non-positive pairlistfrequency provided.\n", cvm::error("Error: non-positive pairlistfrequency provided.\n",
INPUT_ERROR); COLVARS_INPUT_ERROR);
return; return;
} }
pairlist = new bool[(group1->size()-1) * (group1->size()-1)]; pairlist = new bool[(group1->size()-1) * (group1->size()-1)];
} }
init_scalar_boundaries(0.0, (group1->size()-1) * (group1->size()-1)); init_scalar_boundaries(0.0, static_cast<cvm::real>((group1->size()-1) *
(group1->size()-1)));
} }
@ -539,7 +543,7 @@ simple_scalar_dist_functions(selfcoordnum)
colvar::groupcoordnum::groupcoordnum(std::string const &conf) colvar::groupcoordnum::groupcoordnum(std::string const &conf)
: distance(conf), b_anisotropic(false) : distance(conf), b_anisotropic(false)
{ {
function_type = "groupcoordnum"; set_function_type("groupCoord");
x.type(colvarvalue::type_scalar); x.type(colvarvalue::type_scalar);
init_scalar_boundaries(0.0, 1.0); init_scalar_boundaries(0.0, 1.0);
@ -574,12 +578,12 @@ colvar::groupcoordnum::groupcoordnum(std::string const &conf)
if ( (en%2) || (ed%2) ) { if ( (en%2) || (ed%2) ) {
cvm::error("Error: odd exponent(s) provided, can only use even ones.\n", cvm::error("Error: odd exponent(s) provided, can only use even ones.\n",
INPUT_ERROR); COLVARS_INPUT_ERROR);
} }
if ( (en <= 0) || (ed <= 0) ) { if ( (en <= 0) || (ed <= 0) ) {
cvm::error("Error: negative exponent(s) provided.\n", cvm::error("Error: negative exponent(s) provided.\n",
INPUT_ERROR); COLVARS_INPUT_ERROR);
} }
if (!is_enabled(f_cvc_pbc_minimum_image)) { if (!is_enabled(f_cvc_pbc_minimum_image)) {

View File

@ -20,7 +20,7 @@
colvar::distance::distance(std::string const &conf) colvar::distance::distance(std::string const &conf)
: cvc(conf) : cvc(conf)
{ {
function_type = "distance"; set_function_type("distance");
init_as_distance(); init_as_distance();
provide(f_cvc_inv_gradient); provide(f_cvc_inv_gradient);
@ -37,7 +37,7 @@ colvar::distance::distance(std::string const &conf)
colvar::distance::distance() colvar::distance::distance()
: cvc() : cvc()
{ {
function_type = "distance"; set_function_type("distance");
init_as_distance(); init_as_distance();
provide(f_cvc_inv_gradient); provide(f_cvc_inv_gradient);
@ -101,7 +101,7 @@ simple_scalar_dist_functions(distance)
colvar::distance_vec::distance_vec(std::string const &conf) colvar::distance_vec::distance_vec(std::string const &conf)
: distance(conf) : distance(conf)
{ {
function_type = "distance_vec"; set_function_type("distanceVec");
enable(f_cvc_com_based); enable(f_cvc_com_based);
disable(f_cvc_explicit_gradient); disable(f_cvc_explicit_gradient);
x.type(colvarvalue::type_3vector); x.type(colvarvalue::type_3vector);
@ -111,7 +111,7 @@ colvar::distance_vec::distance_vec(std::string const &conf)
colvar::distance_vec::distance_vec() colvar::distance_vec::distance_vec()
: distance() : distance()
{ {
function_type = "distance_vec"; set_function_type("distanceVec");
enable(f_cvc_com_based); enable(f_cvc_com_based);
disable(f_cvc_explicit_gradient); disable(f_cvc_explicit_gradient);
x.type(colvarvalue::type_3vector); x.type(colvarvalue::type_3vector);
@ -171,7 +171,7 @@ colvarvalue colvar::distance_vec::dist2_rgrad(colvarvalue const &x1,
colvar::distance_z::distance_z(std::string const &conf) colvar::distance_z::distance_z(std::string const &conf)
: cvc(conf) : cvc(conf)
{ {
function_type = "distance_z"; set_function_type("distanceZ");
provide(f_cvc_inv_gradient); provide(f_cvc_inv_gradient);
provide(f_cvc_Jacobian); provide(f_cvc_Jacobian);
enable(f_cvc_com_based); enable(f_cvc_com_based);
@ -179,10 +179,11 @@ colvar::distance_z::distance_z(std::string const &conf)
// TODO detect PBC from MD engine (in simple cases) // TODO detect PBC from MD engine (in simple cases)
// and then update period in real time // and then update period in real time
if (period != 0.0) if (period != 0.0) {
enable(f_cvc_periodic); enable(f_cvc_periodic);
}
if ((wrap_center != 0.0) && (period == 0.0)) { if ((wrap_center != 0.0) && !is_enabled(f_cvc_periodic)) {
cvm::error("Error: wrapAround was defined in a distanceZ component," cvm::error("Error: wrapAround was defined in a distanceZ component,"
" but its period has not been set.\n"); " but its period has not been set.\n");
return; return;
@ -219,7 +220,7 @@ colvar::distance_z::distance_z(std::string const &conf)
colvar::distance_z::distance_z() colvar::distance_z::distance_z()
{ {
function_type = "distance_z"; set_function_type("distanceZ");
provide(f_cvc_inv_gradient); provide(f_cvc_inv_gradient);
provide(f_cvc_Jacobian); provide(f_cvc_Jacobian);
enable(f_cvc_com_based); enable(f_cvc_com_based);
@ -368,7 +369,7 @@ void colvar::distance_z::wrap(colvarvalue &x_unwrapped) const
colvar::distance_xy::distance_xy(std::string const &conf) colvar::distance_xy::distance_xy(std::string const &conf)
: distance_z(conf) : distance_z(conf)
{ {
function_type = "distance_xy"; set_function_type("distanceXY");
init_as_distance(); init_as_distance();
provide(f_cvc_inv_gradient); provide(f_cvc_inv_gradient);
@ -380,7 +381,7 @@ colvar::distance_xy::distance_xy(std::string const &conf)
colvar::distance_xy::distance_xy() colvar::distance_xy::distance_xy()
: distance_z() : distance_z()
{ {
function_type = "distance_xy"; set_function_type("distanceXY");
init_as_distance(); init_as_distance();
provide(f_cvc_inv_gradient); provide(f_cvc_inv_gradient);
@ -481,7 +482,7 @@ simple_scalar_dist_functions(distance_xy)
colvar::distance_dir::distance_dir(std::string const &conf) colvar::distance_dir::distance_dir(std::string const &conf)
: distance(conf) : distance(conf)
{ {
function_type = "distance_dir"; set_function_type("distanceDir");
enable(f_cvc_com_based); enable(f_cvc_com_based);
disable(f_cvc_explicit_gradient); disable(f_cvc_explicit_gradient);
x.type(colvarvalue::type_unit3vector); x.type(colvarvalue::type_unit3vector);
@ -491,7 +492,7 @@ colvar::distance_dir::distance_dir(std::string const &conf)
colvar::distance_dir::distance_dir() colvar::distance_dir::distance_dir()
: distance() : distance()
{ {
function_type = "distance_dir"; set_function_type("distanceDir");
enable(f_cvc_com_based); enable(f_cvc_com_based);
disable(f_cvc_explicit_gradient); disable(f_cvc_explicit_gradient);
x.type(colvarvalue::type_unit3vector); x.type(colvarvalue::type_unit3vector);
@ -559,7 +560,7 @@ colvarvalue colvar::distance_dir::dist2_rgrad(colvarvalue const &x1,
colvar::distance_inv::distance_inv(std::string const &conf) colvar::distance_inv::distance_inv(std::string const &conf)
: cvc(conf) : cvc(conf)
{ {
function_type = "distance_inv"; set_function_type("distanceInv");
init_as_distance(); init_as_distance();
group1 = parse_group(conf, "group1"); group1 = parse_group(conf, "group1");
@ -658,7 +659,7 @@ simple_scalar_dist_functions(distance_inv)
colvar::distance_pairs::distance_pairs(std::string const &conf) colvar::distance_pairs::distance_pairs(std::string const &conf)
: cvc(conf) : cvc(conf)
{ {
function_type = "distance_pairs"; set_function_type("distancePairs");
group1 = parse_group(conf, "group1"); group1 = parse_group(conf, "group1");
group2 = parse_group(conf, "group2"); group2 = parse_group(conf, "group2");
@ -671,7 +672,7 @@ colvar::distance_pairs::distance_pairs(std::string const &conf)
colvar::distance_pairs::distance_pairs() colvar::distance_pairs::distance_pairs()
{ {
function_type = "distance_pairs"; set_function_type("distancePairs");
disable(f_cvc_explicit_gradient); disable(f_cvc_explicit_gradient);
x.type(colvarvalue::type_vector); x.type(colvarvalue::type_vector);
} }
@ -743,7 +744,7 @@ void colvar::distance_pairs::apply_force(colvarvalue const &force)
colvar::dipole_magnitude::dipole_magnitude(std::string const &conf) colvar::dipole_magnitude::dipole_magnitude(std::string const &conf)
: cvc(conf) : cvc(conf)
{ {
function_type = "dipole_magnitude"; set_function_type("dipoleMagnitude");
atoms = parse_group(conf, "atoms"); atoms = parse_group(conf, "atoms");
init_total_force_params(conf); init_total_force_params(conf);
x.type(colvarvalue::type_scalar); x.type(colvarvalue::type_scalar);
@ -752,6 +753,7 @@ colvar::dipole_magnitude::dipole_magnitude(std::string const &conf)
colvar::dipole_magnitude::dipole_magnitude(cvm::atom const &a1) colvar::dipole_magnitude::dipole_magnitude(cvm::atom const &a1)
{ {
set_function_type("dipoleMagnitude");
atoms = new cvm::atom_group(std::vector<cvm::atom>(1, a1)); atoms = new cvm::atom_group(std::vector<cvm::atom>(1, a1));
register_atom_group(atoms); register_atom_group(atoms);
x.type(colvarvalue::type_scalar); x.type(colvarvalue::type_scalar);
@ -760,7 +762,7 @@ colvar::dipole_magnitude::dipole_magnitude(cvm::atom const &a1)
colvar::dipole_magnitude::dipole_magnitude() colvar::dipole_magnitude::dipole_magnitude()
{ {
function_type = "dipole_magnitude"; set_function_type("dipoleMagnitude");
x.type(colvarvalue::type_scalar); x.type(colvarvalue::type_scalar);
} }
@ -800,7 +802,7 @@ simple_scalar_dist_functions(dipole_magnitude)
colvar::gyration::gyration(std::string const &conf) colvar::gyration::gyration(std::string const &conf)
: cvc(conf) : cvc(conf)
{ {
function_type = "gyration"; set_function_type("gyration");
init_as_distance(); init_as_distance();
provide(f_cvc_inv_gradient); provide(f_cvc_inv_gradient);
@ -869,7 +871,7 @@ simple_scalar_dist_functions(gyration)
colvar::inertia::inertia(std::string const &conf) colvar::inertia::inertia(std::string const &conf)
: gyration(conf) : gyration(conf)
{ {
function_type = "inertia"; set_function_type("inertia");
init_as_distance(); init_as_distance();
} }
@ -905,11 +907,11 @@ simple_scalar_dist_functions(inertia_z)
colvar::inertia_z::inertia_z(std::string const &conf) colvar::inertia_z::inertia_z(std::string const &conf)
: inertia(conf) : inertia(conf)
{ {
function_type = "inertia_z"; set_function_type("inertiaZ");
init_as_distance(); init_as_distance();
if (get_keyval(conf, "axis", axis, cvm::rvector(0.0, 0.0, 1.0))) { if (get_keyval(conf, "axis", axis, cvm::rvector(0.0, 0.0, 1.0))) {
if (axis.norm2() == 0.0) { if (axis.norm2() == 0.0) {
cvm::error("Axis vector is zero!", INPUT_ERROR); cvm::error("Axis vector is zero!", COLVARS_INPUT_ERROR);
return; return;
} }
if (axis.norm2() != 1.0) { if (axis.norm2() != 1.0) {
@ -953,7 +955,7 @@ simple_scalar_dist_functions(inertia)
colvar::rmsd::rmsd(std::string const &conf) colvar::rmsd::rmsd(std::string const &conf)
: cvc(conf) : cvc(conf)
{ {
function_type = "rmsd"; set_function_type("rmsd");
init_as_distance(); init_as_distance();
provide(f_cvc_inv_gradient); provide(f_cvc_inv_gradient);
@ -1217,9 +1219,9 @@ simple_scalar_dist_functions(rmsd)
colvar::eigenvector::eigenvector(std::string const &conf) colvar::eigenvector::eigenvector(std::string const &conf)
: cvc(conf) : cvc(conf)
{ {
set_function_type("eigenvector");
provide(f_cvc_inv_gradient); provide(f_cvc_inv_gradient);
provide(f_cvc_Jacobian); provide(f_cvc_Jacobian);
function_type = "eigenvector";
x.type(colvarvalue::type_scalar); x.type(colvarvalue::type_scalar);
atoms = parse_group(conf, "atoms"); atoms = parse_group(conf, "atoms");
@ -1263,13 +1265,13 @@ colvar::eigenvector::eigenvector(std::string const &conf)
} }
if (ref_pos.size() == 0) { if (ref_pos.size() == 0) {
cvm::error("Error: reference positions were not provided.\n", INPUT_ERROR); cvm::error("Error: reference positions were not provided.\n", COLVARS_INPUT_ERROR);
return; return;
} }
if (ref_pos.size() != atoms->size()) { if (ref_pos.size() != atoms->size()) {
cvm::error("Error: reference positions do not " cvm::error("Error: reference positions do not "
"match the number of requested atoms.\n", INPUT_ERROR); "match the number of requested atoms.\n", COLVARS_INPUT_ERROR);
return; return;
} }
@ -1368,7 +1370,7 @@ colvar::eigenvector::eigenvector(std::string const &conf)
eigenvec[i] = atoms->rot.rotate(eigenvec[i]); eigenvec[i] = atoms->rot.rotate(eigenvec[i]);
} }
} }
cvm::log("\"differenceVector\" is on: subtracting the reference positions from the provided vector: v = v - x0.\n"); cvm::log("\"differenceVector\" is on: subtracting the reference positions from the provided vector: v = x_vec - x_ref.\n");
for (size_t i = 0; i < atoms->size(); i++) { for (size_t i = 0; i < atoms->size(); i++) {
eigenvec[i] -= ref_pos[i]; eigenvec[i] -= ref_pos[i];
} }
@ -1386,22 +1388,32 @@ colvar::eigenvector::eigenvector(std::string const &conf)
} }
} }
// cvm::log("The first three components(v1x, v1y, v1z) of the resulting vector are: "+cvm::to_str (eigenvec[0])+".\n"); // eigenvec_invnorm2 is used when computing inverse gradients
// for inverse gradients
eigenvec_invnorm2 = 0.0; eigenvec_invnorm2 = 0.0;
for (size_t ein = 0; ein < atoms->size(); ein++) { for (size_t ein = 0; ein < atoms->size(); ein++) {
eigenvec_invnorm2 += eigenvec[ein].norm2(); eigenvec_invnorm2 += eigenvec[ein].norm2();
} }
eigenvec_invnorm2 = 1.0 / eigenvec_invnorm2; eigenvec_invnorm2 = 1.0 / eigenvec_invnorm2;
if (b_difference_vector) { // Vector normalization overrides the default normalization for differenceVector
cvm::log("\"differenceVector\" is on: normalizing the vector.\n"); bool normalize = false;
get_keyval(conf, "normalizeVector", normalize, normalize);
if (normalize) {
cvm::log("Normalizing the vector so that |v| = 1.\n");
for (size_t i = 0; i < atoms->size(); i++) {
eigenvec[i] *= cvm::sqrt(eigenvec_invnorm2);
}
eigenvec_invnorm2 = 1.0;
} else if (b_difference_vector) {
cvm::log("Normalizing the vector so that the norm of the projection |v ⋅ (x_vec - x_ref)| = 1.\n");
for (size_t i = 0; i < atoms->size(); i++) { for (size_t i = 0; i < atoms->size(); i++) {
eigenvec[i] *= eigenvec_invnorm2; eigenvec[i] *= eigenvec_invnorm2;
} }
eigenvec_invnorm2 = 1.0/eigenvec_invnorm2;
} else { } else {
cvm::log("The norm of the vector is |v| = "+cvm::to_str(eigenvec_invnorm2)+".\n"); cvm::log("The norm of the vector is |v| = "+
cvm::to_str(1.0/cvm::sqrt(eigenvec_invnorm2))+".\n");
} }
} }
@ -1500,7 +1512,7 @@ simple_scalar_dist_functions(eigenvector)
colvar::cartesian::cartesian(std::string const &conf) colvar::cartesian::cartesian(std::string const &conf)
: cvc(conf) : cvc(conf)
{ {
function_type = "cartesian"; set_function_type("cartesian");
atoms = parse_group(conf, "atoms"); atoms = parse_group(conf, "atoms");
@ -1560,4 +1572,3 @@ void colvar::cartesian::apply_force(colvarvalue const &force)
} }
} }
} }

View File

@ -19,11 +19,6 @@
#include "colvar.h" #include "colvar.h"
#include "colvarcomp.h" #include "colvarcomp.h"
bool compareColvarComponent(colvar::cvc *i, colvar::cvc *j)
{
return i->name < j->name;
}
colvar::CartesianBasedPath::CartesianBasedPath(std::string const &conf): cvc(conf), atoms(nullptr), reference_frames(0) { colvar::CartesianBasedPath::CartesianBasedPath(std::string const &conf): cvc(conf), atoms(nullptr), reference_frames(0) {
// Parse selected atoms // Parse selected atoms
atoms = parse_group(conf, "atoms"); atoms = parse_group(conf, "atoms");
@ -79,7 +74,6 @@ colvar::CartesianBasedPath::CartesianBasedPath(std::string const &conf): cvc(con
cvm::atom_group* tmp_fitting_atoms = new cvm::atom_group(fitting_group_name.c_str()); cvm::atom_group* tmp_fitting_atoms = new cvm::atom_group(fitting_group_name.c_str());
tmp_fitting_atoms->parse(fitting_conf); tmp_fitting_atoms->parse(fitting_conf);
tmp_fitting_atoms->disable(f_ag_scalable); tmp_fitting_atoms->disable(f_ag_scalable);
tmp_fitting_atoms->disable(f_ag_scalable_com);
tmp_fitting_atoms->fit_gradients.assign(tmp_fitting_atoms->size(), cvm::atom_pos(0.0, 0.0, 0.0)); tmp_fitting_atoms->fit_gradients.assign(tmp_fitting_atoms->size(), cvm::atom_pos(0.0, 0.0, 0.0));
std::string reference_position_file_lookup = "refPositionsFile" + cvm::to_str(i_frame + 1); std::string reference_position_file_lookup = "refPositionsFile" + cvm::to_str(i_frame + 1);
std::string reference_position_filename; std::string reference_position_filename;
@ -91,7 +85,6 @@ colvar::CartesianBasedPath::CartesianBasedPath(std::string const &conf): cvc(con
tmp_atoms->enable(f_ag_rotate); tmp_atoms->enable(f_ag_rotate);
tmp_atoms->b_user_defined_fit = true; tmp_atoms->b_user_defined_fit = true;
tmp_atoms->disable(f_ag_scalable); tmp_atoms->disable(f_ag_scalable);
tmp_atoms->disable(f_ag_scalable_com);
tmp_atoms->ref_pos = reference_fitting_position; tmp_atoms->ref_pos = reference_fitting_position;
tmp_atoms->center_ref_pos(); tmp_atoms->center_ref_pos();
tmp_atoms->enable(f_ag_fit_gradients); tmp_atoms->enable(f_ag_fit_gradients);
@ -115,6 +108,7 @@ colvar::CartesianBasedPath::~CartesianBasedPath() {
(*it_comp_atoms) = nullptr; (*it_comp_atoms) = nullptr;
} }
} }
// Avoid double-freeing due to CVC-in-CVC construct
atom_groups.clear(); atom_groups.clear();
} }
@ -131,7 +125,7 @@ void colvar::CartesianBasedPath::computeDistanceToReferenceFrames(std::vector<cv
} }
colvar::gspath::gspath(std::string const &conf): CartesianBasedPath(conf) { colvar::gspath::gspath(std::string const &conf): CartesianBasedPath(conf) {
function_type = "gspath"; set_function_type("gspath");
get_keyval(conf, "useSecondClosestFrame", use_second_closest_frame, true); get_keyval(conf, "useSecondClosestFrame", use_second_closest_frame, true);
if (use_second_closest_frame == true) { if (use_second_closest_frame == true) {
cvm::log(std::string("Geometric path s(σ) will use the second closest frame to compute s_(m-1)\n")); cvm::log(std::string("Geometric path s(σ) will use the second closest frame to compute s_(m-1)\n"));
@ -146,6 +140,7 @@ colvar::gspath::gspath(std::string const &conf): CartesianBasedPath(conf) {
} }
if (total_reference_frames < 2) { if (total_reference_frames < 2) {
cvm::error("Error: you have specified " + cvm::to_str(total_reference_frames) + " reference frames, but gspath requires at least 2 frames.\n"); cvm::error("Error: you have specified " + cvm::to_str(total_reference_frames) + " reference frames, but gspath requires at least 2 frames.\n");
return;
} }
GeometricPathCV::GeometricPathBase<cvm::atom_pos, cvm::real, GeometricPathCV::path_sz::S>::initialize(atoms->size(), cvm::atom_pos(), total_reference_frames, use_second_closest_frame, use_third_closest_frame); GeometricPathCV::GeometricPathBase<cvm::atom_pos, cvm::real, GeometricPathCV::path_sz::S>::initialize(atoms->size(), cvm::atom_pos(), total_reference_frames, use_second_closest_frame, use_third_closest_frame);
cvm::log(std::string("Geometric pathCV(s) is initialized.\n")); cvm::log(std::string("Geometric pathCV(s) is initialized.\n"));
@ -170,8 +165,8 @@ void colvar::gspath::prepareVectors() {
reference_cog_1 += reference_frames[min_frame_index_1][i_atom]; reference_cog_1 += reference_frames[min_frame_index_1][i_atom];
reference_cog_2 += reference_frames[min_frame_index_2][i_atom]; reference_cog_2 += reference_frames[min_frame_index_2][i_atom];
} }
reference_cog_1 /= reference_frames[min_frame_index_1].size(); reference_cog_1 /= cvm::real(reference_frames[min_frame_index_1].size());
reference_cog_2 /= reference_frames[min_frame_index_2].size(); reference_cog_2 /= cvm::real(reference_frames[min_frame_index_2].size());
std::vector<cvm::atom_pos> tmp_reference_frame_1(reference_frames[min_frame_index_1].size()); std::vector<cvm::atom_pos> tmp_reference_frame_1(reference_frames[min_frame_index_1].size());
std::vector<cvm::atom_pos> tmp_reference_frame_2(reference_frames[min_frame_index_2].size()); std::vector<cvm::atom_pos> tmp_reference_frame_2(reference_frames[min_frame_index_2].size());
for (i_atom = 0; i_atom < atoms->size(); ++i_atom) { for (i_atom = 0; i_atom < atoms->size(); ++i_atom) {
@ -184,8 +179,8 @@ void colvar::gspath::prepareVectors() {
reference_fitting_cog_1 += reference_fitting_frames[min_frame_index_1][i_atom]; reference_fitting_cog_1 += reference_fitting_frames[min_frame_index_1][i_atom];
reference_fitting_cog_2 += reference_fitting_frames[min_frame_index_2][i_atom]; reference_fitting_cog_2 += reference_fitting_frames[min_frame_index_2][i_atom];
} }
reference_fitting_cog_1 /= reference_fitting_frames[min_frame_index_1].size(); reference_fitting_cog_1 /= cvm::real(reference_fitting_frames[min_frame_index_1].size());
reference_fitting_cog_2 /= reference_fitting_frames[min_frame_index_2].size(); reference_fitting_cog_2 /= cvm::real(reference_fitting_frames[min_frame_index_2].size());
std::vector<cvm::atom_pos> tmp_reference_fitting_frame_1(reference_fitting_frames[min_frame_index_1].size()); std::vector<cvm::atom_pos> tmp_reference_fitting_frame_1(reference_fitting_frames[min_frame_index_1].size());
std::vector<cvm::atom_pos> tmp_reference_fitting_frame_2(reference_fitting_frames[min_frame_index_2].size()); std::vector<cvm::atom_pos> tmp_reference_fitting_frame_2(reference_fitting_frames[min_frame_index_2].size());
for (i_atom = 0; i_atom < reference_fitting_frames[min_frame_index_1].size(); ++i_atom) { for (i_atom = 0; i_atom < reference_fitting_frames[min_frame_index_1].size(); ++i_atom) {
@ -205,8 +200,8 @@ void colvar::gspath::prepareVectors() {
reference_cog_1 += reference_frames[min_frame_index_1][i_atom]; reference_cog_1 += reference_frames[min_frame_index_1][i_atom];
reference_cog_3 += reference_frames[min_frame_index_3][i_atom]; reference_cog_3 += reference_frames[min_frame_index_3][i_atom];
} }
reference_cog_1 /= reference_frames[min_frame_index_1].size(); reference_cog_1 /= cvm::real(reference_frames[min_frame_index_1].size());
reference_cog_3 /= reference_frames[min_frame_index_3].size(); reference_cog_3 /= cvm::real(reference_frames[min_frame_index_3].size());
std::vector<cvm::atom_pos> tmp_reference_frame_1(reference_frames[min_frame_index_1].size()); std::vector<cvm::atom_pos> tmp_reference_frame_1(reference_frames[min_frame_index_1].size());
std::vector<cvm::atom_pos> tmp_reference_frame_3(reference_frames[min_frame_index_3].size()); std::vector<cvm::atom_pos> tmp_reference_frame_3(reference_frames[min_frame_index_3].size());
for (i_atom = 0; i_atom < atoms->size(); ++i_atom) { for (i_atom = 0; i_atom < atoms->size(); ++i_atom) {
@ -219,8 +214,8 @@ void colvar::gspath::prepareVectors() {
reference_fitting_cog_1 += reference_fitting_frames[min_frame_index_1][i_atom]; reference_fitting_cog_1 += reference_fitting_frames[min_frame_index_1][i_atom];
reference_fitting_cog_3 += reference_fitting_frames[min_frame_index_3][i_atom]; reference_fitting_cog_3 += reference_fitting_frames[min_frame_index_3][i_atom];
} }
reference_fitting_cog_1 /= reference_fitting_frames[min_frame_index_1].size(); reference_fitting_cog_1 /= cvm::real(reference_fitting_frames[min_frame_index_1].size());
reference_fitting_cog_3 /= reference_fitting_frames[min_frame_index_3].size(); reference_fitting_cog_3 /= cvm::real(reference_fitting_frames[min_frame_index_3].size());
std::vector<cvm::atom_pos> tmp_reference_fitting_frame_1(reference_fitting_frames[min_frame_index_1].size()); std::vector<cvm::atom_pos> tmp_reference_fitting_frame_1(reference_fitting_frames[min_frame_index_1].size());
std::vector<cvm::atom_pos> tmp_reference_fitting_frame_3(reference_fitting_frames[min_frame_index_3].size()); std::vector<cvm::atom_pos> tmp_reference_fitting_frame_3(reference_fitting_frames[min_frame_index_3].size());
for (i_atom = 0; i_atom < reference_fitting_frames[min_frame_index_1].size(); ++i_atom) { for (i_atom = 0; i_atom < reference_fitting_frames[min_frame_index_1].size(); ++i_atom) {
@ -272,7 +267,7 @@ void colvar::gspath::apply_force(colvarvalue const &force) {
} }
colvar::gzpath::gzpath(std::string const &conf): CartesianBasedPath(conf) { colvar::gzpath::gzpath(std::string const &conf): CartesianBasedPath(conf) {
function_type = "gzpath"; set_function_type("gzpath");
get_keyval(conf, "useSecondClosestFrame", use_second_closest_frame, true); get_keyval(conf, "useSecondClosestFrame", use_second_closest_frame, true);
if (use_second_closest_frame == true) { if (use_second_closest_frame == true) {
cvm::log(std::string("Geometric path z(σ) will use the second closest frame to compute s_(m-1)\n")); cvm::log(std::string("Geometric path z(σ) will use the second closest frame to compute s_(m-1)\n"));
@ -292,6 +287,7 @@ colvar::gzpath::gzpath(std::string const &conf): CartesianBasedPath(conf) {
} }
if (total_reference_frames < 2) { if (total_reference_frames < 2) {
cvm::error("Error: you have specified " + cvm::to_str(total_reference_frames) + " reference frames, but gzpath requires at least 2 frames.\n"); cvm::error("Error: you have specified " + cvm::to_str(total_reference_frames) + " reference frames, but gzpath requires at least 2 frames.\n");
return;
} }
GeometricPathCV::GeometricPathBase<cvm::atom_pos, cvm::real, GeometricPathCV::path_sz::Z>::initialize(atoms->size(), cvm::atom_pos(), total_reference_frames, use_second_closest_frame, use_third_closest_frame, b_use_z_square); GeometricPathCV::GeometricPathBase<cvm::atom_pos, cvm::real, GeometricPathCV::path_sz::Z>::initialize(atoms->size(), cvm::atom_pos(), total_reference_frames, use_second_closest_frame, use_third_closest_frame, b_use_z_square);
// Logging // Logging
@ -310,8 +306,8 @@ void colvar::gzpath::prepareVectors() {
reference_cog_1 += reference_frames[min_frame_index_1][i_atom]; reference_cog_1 += reference_frames[min_frame_index_1][i_atom];
reference_cog_2 += reference_frames[min_frame_index_2][i_atom]; reference_cog_2 += reference_frames[min_frame_index_2][i_atom];
} }
reference_cog_1 /= reference_frames[min_frame_index_1].size(); reference_cog_1 /= cvm::real(reference_frames[min_frame_index_1].size());
reference_cog_2 /= reference_frames[min_frame_index_2].size(); reference_cog_2 /= cvm::real(reference_frames[min_frame_index_2].size());
std::vector<cvm::atom_pos> tmp_reference_frame_1(reference_frames[min_frame_index_1].size()); std::vector<cvm::atom_pos> tmp_reference_frame_1(reference_frames[min_frame_index_1].size());
std::vector<cvm::atom_pos> tmp_reference_frame_2(reference_frames[min_frame_index_2].size()); std::vector<cvm::atom_pos> tmp_reference_frame_2(reference_frames[min_frame_index_2].size());
for (i_atom = 0; i_atom < atoms->size(); ++i_atom) { for (i_atom = 0; i_atom < atoms->size(); ++i_atom) {
@ -326,8 +322,8 @@ void colvar::gzpath::prepareVectors() {
reference_fitting_cog_1 += reference_fitting_frames[min_frame_index_1][i_atom]; reference_fitting_cog_1 += reference_fitting_frames[min_frame_index_1][i_atom];
reference_fitting_cog_2 += reference_fitting_frames[min_frame_index_2][i_atom]; reference_fitting_cog_2 += reference_fitting_frames[min_frame_index_2][i_atom];
} }
reference_fitting_cog_1 /= reference_fitting_frames[min_frame_index_1].size(); reference_fitting_cog_1 /= cvm::real(reference_fitting_frames[min_frame_index_1].size());
reference_fitting_cog_2 /= reference_fitting_frames[min_frame_index_2].size(); reference_fitting_cog_2 /= cvm::real(reference_fitting_frames[min_frame_index_2].size());
tmp_reference_fitting_frame_1.resize(reference_fitting_frames[min_frame_index_1].size()); tmp_reference_fitting_frame_1.resize(reference_fitting_frames[min_frame_index_1].size());
tmp_reference_fitting_frame_2.resize(reference_fitting_frames[min_frame_index_2].size()); tmp_reference_fitting_frame_2.resize(reference_fitting_frames[min_frame_index_2].size());
for (i_atom = 0; i_atom < reference_fitting_frames[min_frame_index_1].size(); ++i_atom) { for (i_atom = 0; i_atom < reference_fitting_frames[min_frame_index_1].size(); ++i_atom) {
@ -352,7 +348,7 @@ void colvar::gzpath::prepareVectors() {
for (i_atom = 0; i_atom < atoms->size(); ++i_atom) { for (i_atom = 0; i_atom < atoms->size(); ++i_atom) {
reference_cog_3 += reference_frames[min_frame_index_3][i_atom]; reference_cog_3 += reference_frames[min_frame_index_3][i_atom];
} }
reference_cog_3 /= reference_frames[min_frame_index_3].size(); reference_cog_3 /= cvm::real(reference_frames[min_frame_index_3].size());
std::vector<cvm::atom_pos> tmp_reference_frame_3(reference_frames[min_frame_index_3].size()); std::vector<cvm::atom_pos> tmp_reference_frame_3(reference_frames[min_frame_index_3].size());
for (i_atom = 0; i_atom < atoms->size(); ++i_atom) { for (i_atom = 0; i_atom < atoms->size(); ++i_atom) {
tmp_reference_frame_3[i_atom] = reference_frames[min_frame_index_3][i_atom] - reference_cog_3; tmp_reference_frame_3[i_atom] = reference_frames[min_frame_index_3][i_atom] - reference_cog_3;
@ -362,7 +358,7 @@ void colvar::gzpath::prepareVectors() {
for (i_atom = 0; i_atom < reference_fitting_frames[min_frame_index_3].size(); ++i_atom) { for (i_atom = 0; i_atom < reference_fitting_frames[min_frame_index_3].size(); ++i_atom) {
reference_fitting_cog_3 += reference_fitting_frames[min_frame_index_3][i_atom]; reference_fitting_cog_3 += reference_fitting_frames[min_frame_index_3][i_atom];
} }
reference_fitting_cog_3 /= reference_fitting_frames[min_frame_index_3].size(); reference_fitting_cog_3 /= cvm::real(reference_fitting_frames[min_frame_index_3].size());
std::vector<cvm::atom_pos> tmp_reference_fitting_frame_3(reference_fitting_frames[min_frame_index_3].size()); std::vector<cvm::atom_pos> tmp_reference_fitting_frame_3(reference_fitting_frames[min_frame_index_3].size());
for (i_atom = 0; i_atom < reference_fitting_frames[min_frame_index_3].size(); ++i_atom) { for (i_atom = 0; i_atom < reference_fitting_frames[min_frame_index_3].size(); ++i_atom) {
tmp_reference_fitting_frame_3[i_atom] = reference_fitting_frames[min_frame_index_3][i_atom] - reference_fitting_cog_3; tmp_reference_fitting_frame_3[i_atom] = reference_fitting_frames[min_frame_index_3][i_atom] - reference_fitting_cog_3;
@ -401,104 +397,6 @@ void colvar::gzpath::apply_force(colvarvalue const &force) {
(*(comp_atoms[min_frame_index_2])).apply_colvar_force(F); (*(comp_atoms[min_frame_index_2])).apply_colvar_force(F);
} }
colvar::linearCombination::linearCombination(std::string const &conf): cvc(conf) {
// Lookup all available sub-cvcs
for (auto it_cv_map = colvar::get_global_cvc_map().begin(); it_cv_map != colvar::get_global_cvc_map().end(); ++it_cv_map) {
if (key_lookup(conf, it_cv_map->first.c_str())) {
std::vector<std::string> sub_cvc_confs;
get_key_string_multi_value(conf, it_cv_map->first.c_str(), sub_cvc_confs);
for (auto it_sub_cvc_conf = sub_cvc_confs.begin(); it_sub_cvc_conf != sub_cvc_confs.end(); ++it_sub_cvc_conf) {
cv.push_back((it_cv_map->second)(*(it_sub_cvc_conf)));
}
}
}
// Sort all sub CVs by their names
std::sort(cv.begin(), cv.end(), compareColvarComponent);
for (auto it_sub_cv = cv.begin(); it_sub_cv != cv.end(); ++it_sub_cv) {
for (auto it_atom_group = (*it_sub_cv)->atom_groups.begin(); it_atom_group != (*it_sub_cv)->atom_groups.end(); ++it_atom_group) {
register_atom_group(*it_atom_group);
}
}
x.type(cv[0]->value());
x.reset();
use_explicit_gradients = true;
for (size_t i_cv = 0; i_cv < cv.size(); ++i_cv) {
if (!cv[i_cv]->is_enabled(f_cvc_explicit_gradient)) {
use_explicit_gradients = false;
}
}
if (!use_explicit_gradients) {
disable(f_cvc_explicit_gradient);
}
}
cvm::real colvar::linearCombination::getPolynomialFactorOfCVGradient(size_t i_cv) const {
cvm::real factor_polynomial = 1.0;
if (cv[i_cv]->value().type() == colvarvalue::type_scalar) {
factor_polynomial = cv[i_cv]->sup_coeff * cv[i_cv]->sup_np * cvm::pow(cv[i_cv]->value().real_value, cv[i_cv]->sup_np - 1);
} else {
factor_polynomial = cv[i_cv]->sup_coeff;
}
return factor_polynomial;
}
colvar::linearCombination::~linearCombination() {
for (auto it = cv.begin(); it != cv.end(); ++it) {
delete (*it);
}
}
void colvar::linearCombination::calc_value() {
x.reset();
for (size_t i_cv = 0; i_cv < cv.size(); ++i_cv) {
cv[i_cv]->calc_value();
colvarvalue current_cv_value(cv[i_cv]->value());
// polynomial combination allowed
if (current_cv_value.type() == colvarvalue::type_scalar) {
x += cv[i_cv]->sup_coeff * (cvm::pow(current_cv_value.real_value, cv[i_cv]->sup_np));
} else {
x += cv[i_cv]->sup_coeff * current_cv_value;
}
}
}
void colvar::linearCombination::calc_gradients() {
for (size_t i_cv = 0; i_cv < cv.size(); ++i_cv) {
cv[i_cv]->calc_gradients();
if ( cv[i_cv]->is_enabled(f_cvc_explicit_gradient) &&
!cv[i_cv]->is_enabled(f_cvc_scalable) &&
!cv[i_cv]->is_enabled(f_cvc_scalable_com)) {
cvm::real factor_polynomial = getPolynomialFactorOfCVGradient(i_cv);
for (size_t j_elem = 0; j_elem < cv[i_cv]->value().size(); ++j_elem) {
for (size_t k_ag = 0 ; k_ag < cv[i_cv]->atom_groups.size(); ++k_ag) {
for (size_t l_atom = 0; l_atom < (cv[i_cv]->atom_groups)[k_ag]->size(); ++l_atom) {
(*(cv[i_cv]->atom_groups)[k_ag])[l_atom].grad = factor_polynomial * (*(cv[i_cv]->atom_groups)[k_ag])[l_atom].grad;
}
}
}
}
}
}
void colvar::linearCombination::apply_force(colvarvalue const &force) {
for (size_t i_cv = 0; i_cv < cv.size(); ++i_cv) {
// If this CV us explicit gradients, then atomic gradients is already calculated
// We can apply the force to atom groups directly
if ( cv[i_cv]->is_enabled(f_cvc_explicit_gradient) &&
!cv[i_cv]->is_enabled(f_cvc_scalable) &&
!cv[i_cv]->is_enabled(f_cvc_scalable_com)
) {
for (size_t k_ag = 0 ; k_ag < cv[i_cv]->atom_groups.size(); ++k_ag) {
(cv[i_cv]->atom_groups)[k_ag]->apply_colvar_force(force.real_value);
}
} else {
// Compute factors for polynomial combinations
cvm::real factor_polynomial = getPolynomialFactorOfCVGradient(i_cv);
colvarvalue cv_force = force.real_value * factor_polynomial;
cv[i_cv]->apply_force(cv_force);
}
}
}
colvar::CVBasedPath::CVBasedPath(std::string const &conf): cvc(conf) { colvar::CVBasedPath::CVBasedPath(std::string const &conf): cvc(conf) {
// Lookup all available sub-cvcs // Lookup all available sub-cvcs
@ -512,7 +410,7 @@ colvar::CVBasedPath::CVBasedPath(std::string const &conf): cvc(conf) {
} }
} }
// Sort all sub CVs by their names // Sort all sub CVs by their names
std::sort(cv.begin(), cv.end(), compareColvarComponent); std::sort(cv.begin(), cv.end(), colvar::compare_cvc);
// Register atom groups and determine the colvar type for reference // Register atom groups and determine the colvar type for reference
std::vector<colvarvalue> tmp_cv; std::vector<colvarvalue> tmp_cv;
for (auto it_sub_cv = cv.begin(); it_sub_cv != cv.end(); ++it_sub_cv) { for (auto it_sub_cv = cv.begin(); it_sub_cv != cv.end(); ++it_sub_cv) {
@ -531,6 +429,7 @@ colvar::CVBasedPath::CVBasedPath(std::string const &conf): cvc(conf) {
std::ifstream ifs_path(path_filename); std::ifstream ifs_path(path_filename);
if (!ifs_path.is_open()) { if (!ifs_path.is_open()) {
cvm::error("Error: failed to open path file.\n"); cvm::error("Error: failed to open path file.\n");
return;
} }
std::string line; std::string line;
const std::string token(" "); const std::string token(" ");
@ -552,6 +451,7 @@ colvar::CVBasedPath::CVBasedPath(std::string const &conf): cvc(conf) {
} }
} else { } else {
cvm::error("Error: incorrect format of path file.\n"); cvm::error("Error: incorrect format of path file.\n");
return;
} }
} }
if (!fields.empty()) { if (!fields.empty()) {
@ -561,6 +461,12 @@ colvar::CVBasedPath::CVBasedPath(std::string const &conf): cvc(conf) {
} }
if (total_reference_frames <= 1) { if (total_reference_frames <= 1) {
cvm::error("Error: there is only 1 or 0 reference frame, which doesn't constitute a path.\n"); cvm::error("Error: there is only 1 or 0 reference frame, which doesn't constitute a path.\n");
return;
}
if (cv.size() == 0) {
cvm::error("Error: the CV " + name +
" expects one or more nesting components.\n");
return;
} }
x.type(colvarvalue::type_scalar); x.type(colvarvalue::type_scalar);
use_explicit_gradients = true; use_explicit_gradients = true;
@ -622,14 +528,27 @@ cvm::real colvar::CVBasedPath::getPolynomialFactorOfCVGradient(size_t i_cv) cons
} }
colvar::CVBasedPath::~CVBasedPath() { colvar::CVBasedPath::~CVBasedPath() {
// Recall the steps we initialize the sub-CVCs:
// 1. Lookup all sub-CVCs and then register the atom groups for sub-CVCs
// in their constructors;
// 2. Iterate over all sub-CVCs, get the pointers of their atom groups
// groups, and register again in the parent (current) CVC.
// That being said, the atom groups become children of the sub-CVCs at
// first, and then become children of the parent CVC.
// So, to destruct this class (parent CVC class), we need to remove the
// dependencies of the atom groups to the parent CVC at first.
remove_all_children();
// Then we remove the dependencies of the atom groups to the sub-CVCs
// in their destructors.
for (auto it = cv.begin(); it != cv.end(); ++it) { for (auto it = cv.begin(); it != cv.end(); ++it) {
delete (*it); delete (*it);
} }
// The last step is cleaning up the list of atom groups.
atom_groups.clear(); atom_groups.clear();
} }
colvar::gspathCV::gspathCV(std::string const &conf): CVBasedPath(conf) { colvar::gspathCV::gspathCV(std::string const &conf): CVBasedPath(conf) {
function_type = "gspathCV"; set_function_type("gspathCV");
cvm::log(std::string("Total number of frames: ") + cvm::to_str(total_reference_frames) + std::string("\n")); cvm::log(std::string("Total number of frames: ") + cvm::to_str(total_reference_frames) + std::string("\n"));
// Initialize variables for future calculation // Initialize variables for future calculation
get_keyval(conf, "useSecondClosestFrame", use_second_closest_frame, true); get_keyval(conf, "useSecondClosestFrame", use_second_closest_frame, true);
@ -646,19 +565,10 @@ colvar::gspathCV::gspathCV(std::string const &conf): CVBasedPath(conf) {
} }
if (total_reference_frames < 2) { if (total_reference_frames < 2) {
cvm::error("Error: you have specified " + cvm::to_str(total_reference_frames) + " reference frames, but gspathCV requires at least 2 frames.\n"); cvm::error("Error: you have specified " + cvm::to_str(total_reference_frames) + " reference frames, but gspathCV requires at least 2 frames.\n");
return;
} }
GeometricPathCV::GeometricPathBase<colvarvalue, cvm::real, GeometricPathCV::path_sz::S>::initialize(cv.size(), ref_cv[0], total_reference_frames, use_second_closest_frame, use_third_closest_frame); GeometricPathCV::GeometricPathBase<colvarvalue, cvm::real, GeometricPathCV::path_sz::S>::initialize(cv.size(), ref_cv[0], total_reference_frames, use_second_closest_frame, use_third_closest_frame);
x.type(colvarvalue::type_scalar); x.type(colvarvalue::type_scalar);
use_explicit_gradients = true;
for (size_t i_cv = 0; i_cv < cv.size(); ++i_cv) {
if (!cv[i_cv]->is_enabled(f_cvc_explicit_gradient)) {
use_explicit_gradients = false;
}
}
if (!use_explicit_gradients) {
cvm::log("Geometric path s(σ) will use implicit gradients.\n");
disable(f_cvc_explicit_gradient);
}
} }
colvar::gspathCV::~gspathCV() {} colvar::gspathCV::~gspathCV() {}
@ -710,9 +620,7 @@ void colvar::gspathCV::calc_gradients() {
// No matter whether the i-th cv uses implicit gradient, compute it first. // No matter whether the i-th cv uses implicit gradient, compute it first.
cv[i_cv]->calc_gradients(); cv[i_cv]->calc_gradients();
// If the gradient is not implicit, then add the gradients to its atom groups // If the gradient is not implicit, then add the gradients to its atom groups
if ( cv[i_cv]->is_enabled(f_cvc_explicit_gradient) && if (cv[i_cv]->is_enabled(f_cvc_explicit_gradient)) {
!cv[i_cv]->is_enabled(f_cvc_scalable) &&
!cv[i_cv]->is_enabled(f_cvc_scalable_com)) {
// Temporary variables storing gradients // Temporary variables storing gradients
colvarvalue tmp_cv_grad_v1(cv[i_cv]->value()); colvarvalue tmp_cv_grad_v1(cv[i_cv]->value());
colvarvalue tmp_cv_grad_v2(cv[i_cv]->value()); colvarvalue tmp_cv_grad_v2(cv[i_cv]->value());
@ -741,10 +649,7 @@ void colvar::gspathCV::apply_force(colvarvalue const &force) {
for (size_t i_cv = 0; i_cv < cv.size(); ++i_cv) { for (size_t i_cv = 0; i_cv < cv.size(); ++i_cv) {
// If this CV us explicit gradients, then atomic gradients is already calculated // If this CV us explicit gradients, then atomic gradients is already calculated
// We can apply the force to atom groups directly // We can apply the force to atom groups directly
if ( cv[i_cv]->is_enabled(f_cvc_explicit_gradient) && if (cv[i_cv]->is_enabled(f_cvc_explicit_gradient)) {
!cv[i_cv]->is_enabled(f_cvc_scalable) &&
!cv[i_cv]->is_enabled(f_cvc_scalable_com)
) {
for (size_t k_ag = 0 ; k_ag < cv[i_cv]->atom_groups.size(); ++k_ag) { for (size_t k_ag = 0 ; k_ag < cv[i_cv]->atom_groups.size(); ++k_ag) {
(cv[i_cv]->atom_groups)[k_ag]->apply_colvar_force(force.real_value); (cv[i_cv]->atom_groups)[k_ag]->apply_colvar_force(force.real_value);
} }
@ -766,7 +671,7 @@ void colvar::gspathCV::apply_force(colvarvalue const &force) {
} }
colvar::gzpathCV::gzpathCV(std::string const &conf): CVBasedPath(conf) { colvar::gzpathCV::gzpathCV(std::string const &conf): CVBasedPath(conf) {
function_type = "gzpathCV"; set_function_type("gzpathCV");
cvm::log(std::string("Total number of frames: ") + cvm::to_str(total_reference_frames) + std::string("\n")); cvm::log(std::string("Total number of frames: ") + cvm::to_str(total_reference_frames) + std::string("\n"));
// Initialize variables for future calculation // Initialize variables for future calculation
M = cvm::real(total_reference_frames - 1); M = cvm::real(total_reference_frames - 1);
@ -790,19 +695,10 @@ colvar::gzpathCV::gzpathCV(std::string const &conf): CVBasedPath(conf) {
} }
if (total_reference_frames < 2) { if (total_reference_frames < 2) {
cvm::error("Error: you have specified " + cvm::to_str(total_reference_frames) + " reference frames, but gzpathCV requires at least 2 frames.\n"); cvm::error("Error: you have specified " + cvm::to_str(total_reference_frames) + " reference frames, but gzpathCV requires at least 2 frames.\n");
return;
} }
GeometricPathCV::GeometricPathBase<colvarvalue, cvm::real, GeometricPathCV::path_sz::Z>::initialize(cv.size(), ref_cv[0], total_reference_frames, use_second_closest_frame, use_third_closest_frame, b_use_z_square); GeometricPathCV::GeometricPathBase<colvarvalue, cvm::real, GeometricPathCV::path_sz::Z>::initialize(cv.size(), ref_cv[0], total_reference_frames, use_second_closest_frame, use_third_closest_frame, b_use_z_square);
x.type(colvarvalue::type_scalar); x.type(colvarvalue::type_scalar);
use_explicit_gradients = true;
for (size_t i_cv = 0; i_cv < cv.size(); ++i_cv) {
if (!cv[i_cv]->is_enabled(f_cvc_explicit_gradient)) {
use_explicit_gradients = false;
}
}
if (!use_explicit_gradients) {
cvm::log("Geometric path z(σ) will use implicit gradients.\n");
disable(f_cvc_explicit_gradient);
}
} }
colvar::gzpathCV::~gzpathCV() { colvar::gzpathCV::~gzpathCV() {
@ -857,9 +753,7 @@ void colvar::gzpathCV::calc_gradients() {
// No matter whether the i-th cv uses implicit gradient, compute it first. // No matter whether the i-th cv uses implicit gradient, compute it first.
cv[i_cv]->calc_gradients(); cv[i_cv]->calc_gradients();
// If the gradient is not implicit, then add the gradients to its atom groups // If the gradient is not implicit, then add the gradients to its atom groups
if ( cv[i_cv]->is_enabled(f_cvc_explicit_gradient) && if (cv[i_cv]->is_enabled(f_cvc_explicit_gradient)) {
!cv[i_cv]->is_enabled(f_cvc_scalable) &&
!cv[i_cv]->is_enabled(f_cvc_scalable_com)) {
// Temporary variables storing gradients // Temporary variables storing gradients
colvarvalue tmp_cv_grad_v1 = -1.0 * dzdv1[i_cv]; colvarvalue tmp_cv_grad_v1 = -1.0 * dzdv1[i_cv];
colvarvalue tmp_cv_grad_v2 = 1.0 * dzdv2[i_cv]; colvarvalue tmp_cv_grad_v2 = 1.0 * dzdv2[i_cv];
@ -884,14 +778,11 @@ void colvar::gzpathCV::apply_force(colvarvalue const &force) {
for (size_t i_cv = 0; i_cv < cv.size(); ++i_cv) { for (size_t i_cv = 0; i_cv < cv.size(); ++i_cv) {
// If this CV us explicit gradients, then atomic gradients is already calculated // If this CV us explicit gradients, then atomic gradients is already calculated
// We can apply the force to atom groups directly // We can apply the force to atom groups directly
if ( cv[i_cv]->is_enabled(f_cvc_explicit_gradient) && if (cv[i_cv]->is_enabled(f_cvc_explicit_gradient)) {
!cv[i_cv]->is_enabled(f_cvc_scalable) &&
!cv[i_cv]->is_enabled(f_cvc_scalable_com)) {
for (size_t k_ag = 0 ; k_ag < cv[i_cv]->atom_groups.size(); ++k_ag) { for (size_t k_ag = 0 ; k_ag < cv[i_cv]->atom_groups.size(); ++k_ag) {
(cv[i_cv]->atom_groups)[k_ag]->apply_colvar_force(force.real_value); (cv[i_cv]->atom_groups)[k_ag]->apply_colvar_force(force.real_value);
} }
} } else {
else {
colvarvalue tmp_cv_grad_v1 = -1.0 * dzdv1[i_cv]; colvarvalue tmp_cv_grad_v1 = -1.0 * dzdv1[i_cv];
colvarvalue tmp_cv_grad_v2 = 1.0 * dzdv2[i_cv]; colvarvalue tmp_cv_grad_v2 = 1.0 * dzdv2[i_cv];
// Temporary variables storing gradients // Temporary variables storing gradients

View File

@ -0,0 +1,188 @@
#if (__cplusplus >= 201103L)
#include "colvarmodule.h"
#include "colvarvalue.h"
#include "colvarparse.h"
#include "colvar.h"
#include "colvarcomp.h"
#include "colvar_neuralnetworkcompute.h"
using namespace neuralnetworkCV;
colvar::neuralNetwork::neuralNetwork(std::string const &conf): linearCombination(conf) {
set_function_type("neuralNetwork");
// the output of neural network consists of multiple values
// read "output_component" key to determine it
get_keyval(conf, "output_component", m_output_index);
// read weight files
bool has_weight_files = true;
size_t num_layers_weight = 0;
std::vector<std::string> weight_files;
while (has_weight_files) {
std::string lookup_key = std::string{"layer"} + cvm::to_str(num_layers_weight + 1) + std::string{"_WeightsFile"};
if (key_lookup(conf, lookup_key.c_str())) {
std::string weight_filename;
get_keyval(conf, lookup_key.c_str(), weight_filename, std::string(""));
weight_files.push_back(weight_filename);
cvm::log(std::string{"Will read layer["} + cvm::to_str(num_layers_weight + 1) + std::string{"] weights from "} + weight_filename + '\n');
++num_layers_weight;
} else {
has_weight_files = false;
}
}
// read bias files
bool has_bias_files = true;
size_t num_layers_bias = 0;
std::vector<std::string> bias_files;
while (has_bias_files) {
std::string lookup_key = std::string{"layer"} + cvm::to_str(num_layers_bias + 1) + std::string{"_BiasesFile"};
if (key_lookup(conf, lookup_key.c_str())) {
std::string bias_filename;
get_keyval(conf, lookup_key.c_str(), bias_filename, std::string(""));
bias_files.push_back(bias_filename);
cvm::log(std::string{"Will read layer["} + cvm::to_str(num_layers_bias + 1) + std::string{"] biases from "} + bias_filename + '\n');
++num_layers_bias;
} else {
has_bias_files = false;
}
}
// read activation function strings
bool has_activation_functions = true;
size_t num_activation_functions = 0;
// pair(is_custom_function, function_string)
std::vector<std::pair<bool, std::string>> activation_functions;
while (has_activation_functions) {
std::string lookup_key = std::string{"layer"} + cvm::to_str(num_activation_functions + 1) + std::string{"_activation"};
std::string lookup_key_custom = std::string{"layer"} + cvm::to_str(num_activation_functions + 1) + std::string{"_custom_activation"};
if (key_lookup(conf, lookup_key.c_str())) {
// Ok, this is not a custom function
std::string function_name;
get_keyval(conf, lookup_key.c_str(), function_name, std::string(""));
if (activation_function_map.find(function_name) == activation_function_map.end()) {
cvm::error("Unknown activation function name: \"" + function_name + "\".\n");
return;
}
activation_functions.push_back(std::make_pair(false, function_name));
cvm::log(std::string{"The activation function for layer["} + cvm::to_str(num_activation_functions + 1) + std::string{"] is "} + function_name + '\n');
++num_activation_functions;
#ifdef LEPTON
} else if (key_lookup(conf, lookup_key_custom.c_str())) {
std::string function_expression;
get_keyval(conf, lookup_key_custom.c_str(), function_expression, std::string(""));
activation_functions.push_back(std::make_pair(true, function_expression));
cvm::log(std::string{"The custom activation function for layer["} + cvm::to_str(num_activation_functions + 1) + std::string{"] is "} + function_expression + '\n');
++num_activation_functions;
#endif
} else {
has_activation_functions = false;
}
}
// expect the three numbers are equal
if ((num_layers_weight != num_layers_bias) || (num_layers_bias != num_activation_functions)) {
cvm::error("Error: the numbers of weights, biases and activation functions do not match.\n");
return;
}
// nn = std::make_unique<neuralnetworkCV::neuralNetworkCompute>();
// std::make_unique is only available in C++14
nn = std::unique_ptr<neuralnetworkCV::neuralNetworkCompute>(new neuralnetworkCV::neuralNetworkCompute());
for (size_t i_layer = 0; i_layer < num_layers_weight; ++i_layer) {
denseLayer d;
#ifdef LEPTON
if (activation_functions[i_layer].first) {
// use custom function as activation function
try {
d = denseLayer(weight_files[i_layer], bias_files[i_layer], activation_functions[i_layer].second);
} catch (std::exception &ex) {
cvm::error("Error on initializing layer " + cvm::to_str(i_layer) + " (" + ex.what() + ")\n", COLVARS_INPUT_ERROR);
return;
}
} else {
#endif
// query the map of supported activation functions
const auto& f = activation_function_map[activation_functions[i_layer].second].first;
const auto& df = activation_function_map[activation_functions[i_layer].second].second;
try {
d = denseLayer(weight_files[i_layer], bias_files[i_layer], f, df);
} catch (std::exception &ex) {
cvm::error("Error on initializing layer " + cvm::to_str(i_layer) + " (" + ex.what() + ")\n", COLVARS_INPUT_ERROR);
return;
}
#ifdef LEPTON
}
#endif
// add a new dense layer to network
if (nn->addDenseLayer(d)) {
if (cvm::debug()) {
// show information about the neural network
cvm::log("Layer " + cvm::to_str(i_layer) + " : has " + cvm::to_str(d.getInputSize()) + " input nodes and " + cvm::to_str(d.getOutputSize()) + " output nodes.\n");
for (size_t i_output = 0; i_output < d.getOutputSize(); ++i_output) {
for (size_t j_input = 0; j_input < d.getInputSize(); ++j_input) {
cvm::log(" weights[" + cvm::to_str(i_output) + "][" + cvm::to_str(j_input) + "] = " + cvm::to_str(d.getWeight(i_output, j_input)));
}
cvm::log(" biases[" + cvm::to_str(i_output) + "] = " + cvm::to_str(d.getBias(i_output)) + "\n");
}
}
} else {
cvm::error("Error: error on adding a new dense layer.\n");
return;
}
}
nn->input().resize(cv.size());
}
colvar::neuralNetwork::~neuralNetwork() {
}
void colvar::neuralNetwork::calc_value() {
x.reset();
for (size_t i_cv = 0; i_cv < cv.size(); ++i_cv) {
cv[i_cv]->calc_value();
const colvarvalue& current_cv_value = cv[i_cv]->value();
// for current nn implementation we have to assume taht types are always scaler
if (current_cv_value.type() == colvarvalue::type_scalar) {
nn->input()[i_cv] = cv[i_cv]->sup_coeff * (cvm::pow(current_cv_value.real_value, cv[i_cv]->sup_np));
} else {
cvm::error("Error: using of non-scaler component.\n");
return;
}
}
nn->compute();
x = nn->getOutput(m_output_index);
}
void colvar::neuralNetwork::calc_gradients() {
for (size_t i_cv = 0; i_cv < cv.size(); ++i_cv) {
cv[i_cv]->calc_gradients();
if (cv[i_cv]->is_enabled(f_cvc_explicit_gradient)) {
const cvm::real factor = nn->getGradient(m_output_index, i_cv);
const cvm::real factor_polynomial = getPolynomialFactorOfCVGradient(i_cv);
for (size_t j_elem = 0; j_elem < cv[i_cv]->value().size(); ++j_elem) {
for (size_t k_ag = 0 ; k_ag < cv[i_cv]->atom_groups.size(); ++k_ag) {
for (size_t l_atom = 0; l_atom < (cv[i_cv]->atom_groups)[k_ag]->size(); ++l_atom) {
(*(cv[i_cv]->atom_groups)[k_ag])[l_atom].grad = factor_polynomial * factor * (*(cv[i_cv]->atom_groups)[k_ag])[l_atom].grad;
}
}
}
}
}
}
void colvar::neuralNetwork::apply_force(colvarvalue const &force) {
for (size_t i_cv = 0; i_cv < cv.size(); ++i_cv) {
// If this CV us explicit gradients, then atomic gradients is already calculated
// We can apply the force to atom groups directly
if (cv[i_cv]->is_enabled(f_cvc_explicit_gradient)) {
for (size_t k_ag = 0 ; k_ag < cv[i_cv]->atom_groups.size(); ++k_ag) {
(cv[i_cv]->atom_groups)[k_ag]->apply_colvar_force(force.real_value);
}
} else {
// Compute factors for polynomial combinations
const cvm::real factor_polynomial = getPolynomialFactorOfCVGradient(i_cv);
const cvm::real factor = nn->getGradient(m_output_index, i_cv);;
colvarvalue cv_force = force.real_value * factor * factor_polynomial;
cv[i_cv]->apply_force(cv_force);
}
}
}
#endif

View File

@ -16,17 +16,10 @@
#include "colvarcomp.h" #include "colvarcomp.h"
//////////////////////////////////////////////////////////////////////
// alpha component
//////////////////////////////////////////////////////////////////////
colvar::alpha_angles::alpha_angles(std::string const &conf) colvar::alpha_angles::alpha_angles(std::string const &conf)
: cvc(conf) : cvc(conf)
{ {
if (cvm::debug()) set_function_type("alpha");
cvm::log("Initializing alpha_angles object.\n");
function_type = "alpha_angles";
enable(f_cvc_explicit_gradient); enable(f_cvc_explicit_gradient);
x.type(colvarvalue::type_scalar); x.type(colvarvalue::type_scalar);
@ -110,16 +103,13 @@ colvar::alpha_angles::alpha_angles(std::string const &conf)
cvm::log("The hBondCoeff specified will disable the hydrogen bond terms.\n"); cvm::log("The hBondCoeff specified will disable the hydrogen bond terms.\n");
} }
} }
if (cvm::debug())
cvm::log("Done initializing alpha_angles object.\n");
} }
colvar::alpha_angles::alpha_angles() colvar::alpha_angles::alpha_angles()
: cvc() : cvc()
{ {
function_type = "alpha_angles"; set_function_type("alphaAngles");
enable(f_cvc_explicit_gradient); enable(f_cvc_explicit_gradient);
x.type(colvarvalue::type_scalar); x.type(colvarvalue::type_scalar);
} }
@ -297,7 +287,7 @@ colvar::dihedPC::dihedPC(std::string const &conf)
if (cvm::debug()) if (cvm::debug())
cvm::log("Initializing dihedral PC object.\n"); cvm::log("Initializing dihedral PC object.\n");
function_type = "dihedPC"; set_function_type("dihedPC");
// Supported through references to atom groups of children cvcs // Supported through references to atom groups of children cvcs
enable(f_cvc_explicit_gradient); enable(f_cvc_explicit_gradient);
x.type(colvarvalue::type_scalar); x.type(colvarvalue::type_scalar);
@ -428,7 +418,7 @@ colvar::dihedPC::dihedPC(std::string const &conf)
colvar::dihedPC::dihedPC() colvar::dihedPC::dihedPC()
: cvc() : cvc()
{ {
function_type = "dihedPC"; set_function_type("dihedPC");
// Supported through references to atom groups of children cvcs // Supported through references to atom groups of children cvcs
enable(f_cvc_explicit_gradient); enable(f_cvc_explicit_gradient);
x.type(colvarvalue::type_scalar); x.type(colvarvalue::type_scalar);

View File

@ -18,10 +18,10 @@
colvar::orientation::orientation(std::string const &conf) colvar::orientation::orientation(std::string const &conf)
: cvc() : cvc()
{ {
function_type = "orientation"; set_function_type("orientation");
disable(f_cvc_explicit_gradient); disable(f_cvc_explicit_gradient);
x.type(colvarvalue::type_quaternion); x.type(colvarvalue::type_quaternion);
init(conf); colvar::orientation::init(conf);
} }
@ -36,7 +36,7 @@ int colvar::orientation::init(std::string const &conf)
cvm::log("Using reference positions from input file.\n"); cvm::log("Using reference positions from input file.\n");
if (ref_pos.size() != atoms->size()) { if (ref_pos.size() != atoms->size()) {
return cvm::error("Error: reference positions do not " return cvm::error("Error: reference positions do not "
"match the number of requested atoms.\n", INPUT_ERROR); "match the number of requested atoms.\n", COLVARS_INPUT_ERROR);
} }
} }
@ -51,7 +51,7 @@ int colvar::orientation::init(std::string const &conf)
bool found = get_keyval(conf, "refPositionsColValue", file_col_value, 0.0); bool found = get_keyval(conf, "refPositionsColValue", file_col_value, 0.0);
if (found && file_col_value==0.0) { if (found && file_col_value==0.0) {
return cvm::error("Error: refPositionsColValue, " return cvm::error("Error: refPositionsColValue, "
"if provided, must be non-zero.\n", INPUT_ERROR); "if provided, must be non-zero.\n", COLVARS_INPUT_ERROR);
} }
} }
@ -63,7 +63,7 @@ int colvar::orientation::init(std::string const &conf)
if (!ref_pos.size()) { if (!ref_pos.size()) {
return cvm::error("Error: must define a set of " return cvm::error("Error: must define a set of "
"reference coordinates.\n", INPUT_ERROR); "reference coordinates.\n", COLVARS_INPUT_ERROR);
} }
@ -94,7 +94,7 @@ int colvar::orientation::init(std::string const &conf)
colvar::orientation::orientation() colvar::orientation::orientation()
: cvc() : cvc()
{ {
function_type = "orientation"; set_function_type("orientation");
disable(f_cvc_explicit_gradient); disable(f_cvc_explicit_gradient);
x.type(colvarvalue::type_quaternion); x.type(colvarvalue::type_quaternion);
} }
@ -163,10 +163,10 @@ colvarvalue colvar::orientation::dist2_rgrad(colvarvalue const &x1,
colvar::orientation_angle::orientation_angle(std::string const &conf) colvar::orientation_angle::orientation_angle(std::string const &conf)
: orientation() : orientation()
{ {
function_type = "orientation_angle"; set_function_type("orientationAngle");
init_as_angle(); init_as_angle();
enable(f_cvc_explicit_gradient); enable(f_cvc_explicit_gradient);
init(conf); orientation_angle::init(conf);
} }
@ -219,11 +219,11 @@ simple_scalar_dist_functions(orientation_angle)
colvar::orientation_proj::orientation_proj(std::string const &conf) colvar::orientation_proj::orientation_proj(std::string const &conf)
: orientation() : orientation()
{ {
function_type = "orientation_proj"; set_function_type("orientationProj");
enable(f_cvc_explicit_gradient); enable(f_cvc_explicit_gradient);
x.type(colvarvalue::type_scalar); x.type(colvarvalue::type_scalar);
init_scalar_boundaries(0.0, 1.0); init_scalar_boundaries(0.0, 1.0);
init(conf); orientation_proj::init(conf);
} }
@ -267,11 +267,11 @@ simple_scalar_dist_functions(orientation_proj)
colvar::tilt::tilt(std::string const &conf) colvar::tilt::tilt(std::string const &conf)
: orientation() : orientation()
{ {
function_type = "tilt"; set_function_type("tilt");
enable(f_cvc_explicit_gradient);
x.type(colvarvalue::type_scalar); x.type(colvarvalue::type_scalar);
enable(f_cvc_explicit_gradient);
init_scalar_boundaries(-1.0, 1.0); init_scalar_boundaries(-1.0, 1.0);
init(conf); tilt::init(conf);
} }
@ -331,12 +331,11 @@ simple_scalar_dist_functions(tilt)
colvar::spin_angle::spin_angle(std::string const &conf) colvar::spin_angle::spin_angle(std::string const &conf)
: orientation() : orientation()
{ {
function_type = "spin_angle"; set_function_type("spinAngle");
period = 360.0; init_as_periodic_angle();
enable(f_cvc_periodic); enable(f_cvc_periodic);
enable(f_cvc_explicit_gradient); enable(f_cvc_explicit_gradient);
x.type(colvarvalue::type_scalar); spin_angle::init(conf);
init(conf);
} }
@ -359,7 +358,7 @@ int colvar::spin_angle::init(std::string const &conf)
colvar::spin_angle::spin_angle() colvar::spin_angle::spin_angle()
: orientation() : orientation()
{ {
function_type = "spin_angle"; set_function_type("spinAngle");
period = 360.0; period = 360.0;
enable(f_cvc_periodic); enable(f_cvc_periodic);
enable(f_cvc_explicit_gradient); enable(f_cvc_explicit_gradient);
@ -447,23 +446,19 @@ void colvar::spin_angle::wrap(colvarvalue &x_unwrapped) const
colvar::euler_phi::euler_phi(std::string const &conf) colvar::euler_phi::euler_phi(std::string const &conf)
: orientation() : orientation()
{ {
function_type = "euler_phi"; set_function_type("eulerPhi");
period = 360.0; init_as_periodic_angle();
enable(f_cvc_periodic);
enable(f_cvc_explicit_gradient); enable(f_cvc_explicit_gradient);
x.type(colvarvalue::type_scalar); euler_phi::init(conf);
init(conf);
} }
colvar::euler_phi::euler_phi() colvar::euler_phi::euler_phi()
: orientation() : orientation()
{ {
function_type = "euler_phi"; set_function_type("eulerPhi");
period = 360.0; init_as_periodic_angle();
enable(f_cvc_periodic);
enable(f_cvc_explicit_gradient); enable(f_cvc_explicit_gradient);
x.type(colvarvalue::type_scalar);
} }
@ -566,23 +561,19 @@ void colvar::euler_phi::wrap(colvarvalue &x_unwrapped) const
colvar::euler_psi::euler_psi(std::string const &conf) colvar::euler_psi::euler_psi(std::string const &conf)
: orientation() : orientation()
{ {
function_type = "euler_psi"; set_function_type("eulerPsi");
period = 360.0; init_as_periodic_angle();
enable(f_cvc_periodic);
enable(f_cvc_explicit_gradient); enable(f_cvc_explicit_gradient);
x.type(colvarvalue::type_scalar); euler_psi::init(conf);
init(conf);
} }
colvar::euler_psi::euler_psi() colvar::euler_psi::euler_psi()
: orientation() : orientation()
{ {
function_type = "euler_psi"; set_function_type("eulerPsi");
period = 360.0; init_as_periodic_angle();
enable(f_cvc_periodic);
enable(f_cvc_explicit_gradient); enable(f_cvc_explicit_gradient);
x.type(colvarvalue::type_scalar);
} }
@ -685,19 +676,19 @@ void colvar::euler_psi::wrap(colvarvalue &x_unwrapped) const
colvar::euler_theta::euler_theta(std::string const &conf) colvar::euler_theta::euler_theta(std::string const &conf)
: orientation() : orientation()
{ {
function_type = "euler_theta"; set_function_type("eulerTheta");
init_as_angle();
enable(f_cvc_explicit_gradient); enable(f_cvc_explicit_gradient);
x.type(colvarvalue::type_scalar); euler_theta::init(conf);
init(conf);
} }
colvar::euler_theta::euler_theta() colvar::euler_theta::euler_theta()
: orientation() : orientation()
{ {
function_type = "euler_theta"; set_function_type("eulerTheta");
init_as_angle();
enable(f_cvc_explicit_gradient); enable(f_cvc_explicit_gradient);
x.type(colvarvalue::type_scalar);
} }

View File

@ -16,9 +16,9 @@
colvar::map_total::map_total() colvar::map_total::map_total()
: cvc(), volmap_index(-1) : cvc()
{ {
function_type = "map_total"; set_function_type("mapTotal");
volmap_id = -1; volmap_id = -1;
volmap_index = -1; volmap_index = -1;
atoms = NULL; atoms = NULL;
@ -27,9 +27,9 @@ colvar::map_total::map_total()
colvar::map_total::map_total(std::string const &conf) colvar::map_total::map_total(std::string const &conf)
: cvc(), volmap_index(-1) : cvc() // init() will take care of this
{ {
function_type = "map_total"; set_function_type("mapTotal");
volmap_id = -1; volmap_id = -1;
volmap_index = -1; volmap_index = -1;
atoms = NULL; atoms = NULL;
@ -46,6 +46,8 @@ int colvar::map_total::init(std::string const &conf)
get_keyval(conf, "mapID", volmap_id, volmap_id); get_keyval(conf, "mapID", volmap_id, volmap_id);
register_param("mapID", reinterpret_cast<void *>(&volmap_id)); register_param("mapID", reinterpret_cast<void *>(&volmap_id));
cvm::main()->cite_feature("Volumetric map-based collective variables");
if ((volmap_name.size() > 0) && (volmap_id >= 0)) { if ((volmap_name.size() > 0) && (volmap_id >= 0)) {
error_code |= error_code |=
cvm::error("Error: mapName and mapID are mutually exclusive.\n"); cvm::error("Error: mapName and mapID are mutually exclusive.\n");
@ -72,21 +74,21 @@ int colvar::map_total::init(std::string const &conf)
if (volmap_id >= 0) { if (volmap_id >= 0) {
volmap_index = proxy->init_volmap_by_id(volmap_id); volmap_index = proxy->init_volmap_by_id(volmap_id);
} }
error_code |= volmap_index > 0 ? COLVARS_OK : INPUT_ERROR; error_code |= volmap_index > 0 ? COLVARS_OK : COLVARS_INPUT_ERROR;
} }
if (get_keyval(conf, "atomWeights", atom_weights, atom_weights)) { if (get_keyval(conf, "atomWeights", atom_weights, atom_weights)) {
if (atoms == NULL) { if (atoms == NULL) {
error_code |= cvm::error("Error: weights can only be assigned when atoms " error_code |= cvm::error("Error: weights can only be assigned when atoms "
"are selected explicitly in Colvars.\n", "are selected explicitly in Colvars.\n",
INPUT_ERROR); COLVARS_INPUT_ERROR);
} else { } else {
if (atoms->size() != atom_weights.size()) { if (atoms->size() != atom_weights.size()) {
error_code |= cvm::error("Error: if defined, the number of weights ("+ error_code |= cvm::error("Error: if defined, the number of weights ("+
cvm::to_str(atom_weights.size())+ cvm::to_str(atom_weights.size())+
") must equal the number of atoms ("+ ") must equal the number of atoms ("+
cvm::to_str(atoms->size())+ cvm::to_str(atoms->size())+
").\n", INPUT_ERROR); ").\n", COLVARS_INPUT_ERROR);
} }
} }
} }

View File

@ -26,7 +26,7 @@ colvardeps::~colvardeps() {
if (parents.size()) { if (parents.size()) {
cvm::log("Warning: destroying \"" + description + "\" before its parents objects:"); cvm::log("Warning: destroying \"" + description + "\" before its parents objects:");
for (i=0; i<parents.size(); i++) { for (i=0; i<parents.size(); i++) {
cvm::log(parents[i]->description); cvm::log(parents[i]->description + "\n");
} }
} }
@ -157,10 +157,10 @@ int colvardeps::enable(int feature_id,
if (!dry_run) { if (!dry_run) {
if (toplevel) { if (toplevel) {
cvm::error("Error: " + feature_type_descr + " feature unavailable: \"" cvm::error("Error: " + feature_type_descr + " feature unavailable: \""
+ f->description + "\" in " + description + "."); + f->description + "\" in " + description + ".\n");
} else { } else {
cvm::log(feature_type_descr + " feature unavailable: \"" cvm::log(feature_type_descr + " feature unavailable: \""
+ f->description + "\" in " + description + "."); + f->description + "\" in " + description + ".\n");
} }
} }
return COLVARS_ERROR; return COLVARS_ERROR;
@ -169,7 +169,7 @@ int colvardeps::enable(int feature_id,
if (!toplevel && !is_dynamic(feature_id)) { if (!toplevel && !is_dynamic(feature_id)) {
if (!dry_run) { if (!dry_run) {
cvm::log(feature_type_descr + " feature \"" + f->description cvm::log(feature_type_descr + " feature \"" + f->description
+ "\" cannot be enabled automatically in " + description + "."); + "\" cannot be enabled automatically in " + description + ".\n");
if (is_user(feature_id)) { if (is_user(feature_id)) {
cvm::log("Try setting it manually.\n"); cvm::log("Try setting it manually.\n");
} }
@ -182,13 +182,13 @@ int colvardeps::enable(int feature_id,
for (i=0; i<f->requires_exclude.size(); i++) { for (i=0; i<f->requires_exclude.size(); i++) {
feature *g = features()[f->requires_exclude[i]]; feature *g = features()[f->requires_exclude[i]];
if (cvm::debug()) if (cvm::debug())
cvm::log(f->description + " requires exclude " + g->description); cvm::log(f->description + " requires exclude " + g->description + "\n");
if (is_enabled(f->requires_exclude[i])) { if (is_enabled(f->requires_exclude[i])) {
if (!dry_run) { if (!dry_run) {
cvm::log("Feature \"" + f->description + "\" is incompatible with \"" cvm::log("Feature \"" + f->description + "\" is incompatible with \""
+ g->description + "\" in " + description + "."); + g->description + "\" in " + description + ".\n");
if (toplevel) { if (toplevel) {
cvm::error("Error: Failed dependency in " + description + "."); cvm::error("Error: Failed dependency in " + description + ".\n");
} }
} }
return COLVARS_ERROR; return COLVARS_ERROR;
@ -198,13 +198,13 @@ int colvardeps::enable(int feature_id,
// 2) solve internal deps (self) // 2) solve internal deps (self)
for (i=0; i<f->requires_self.size(); i++) { for (i=0; i<f->requires_self.size(); i++) {
if (cvm::debug()) if (cvm::debug())
cvm::log(f->description + " requires self " + features()[f->requires_self[i]]->description); cvm::log(f->description + " requires self " + features()[f->requires_self[i]]->description + "\n");
res = enable(f->requires_self[i], dry_run, false); res = enable(f->requires_self[i], dry_run, false);
if (res != COLVARS_OK) { if (res != COLVARS_OK) {
if (!dry_run) { if (!dry_run) {
cvm::log("...required by \"" + f->description + "\" in " + description); cvm::log("...required by \"" + f->description + "\" in " + description + "\n");
if (toplevel) { if (toplevel) {
cvm::error("Error: Failed dependency in " + description + "."); cvm::error("Error: Failed dependency in " + description + ".\n");
} }
} }
return res; return res;
@ -219,7 +219,7 @@ int colvardeps::enable(int feature_id,
for (j=0; j<f->requires_alt[i].size(); j++) { for (j=0; j<f->requires_alt[i].size(); j++) {
int g = f->requires_alt[i][j]; int g = f->requires_alt[i][j];
if (cvm::debug()) if (cvm::debug())
cvm::log(f->description + " requires alt " + features()[g]->description); cvm::log(f->description + " requires alt " + features()[g]->description + "\n");
res = enable(g, true, false); // see if available res = enable(g, true, false); // see if available
if (res == COLVARS_OK) { if (res == COLVARS_OK) {
ok = true; ok = true;
@ -239,13 +239,13 @@ int colvardeps::enable(int feature_id,
cvm::increase_depth(); cvm::increase_depth();
for (j=0; j<f->requires_alt[i].size(); j++) { for (j=0; j<f->requires_alt[i].size(); j++) {
int g = f->requires_alt[i][j]; int g = f->requires_alt[i][j];
cvm::log(cvm::to_str(j+1) + ". " + features()[g]->description); cvm::log(cvm::to_str(j+1) + ". " + features()[g]->description + "\n");
enable(g, false, false); // Just for printing error output enable(g, false, false); // Just for printing error output
} }
cvm::decrease_depth(); cvm::decrease_depth();
cvm::log("-----------------------------------------\n"); cvm::log("-----------------------------------------\n");
if (toplevel) { if (toplevel) {
cvm::error("Error: Failed dependency in " + description + "."); cvm::error("Error: Failed dependency in " + description + ".\n");
} }
} }
return COLVARS_ERROR; return COLVARS_ERROR;
@ -262,9 +262,9 @@ int colvardeps::enable(int feature_id,
res = children[j]->enable(g, dry_run || !is_enabled(), false); res = children[j]->enable(g, dry_run || !is_enabled(), false);
if (res != COLVARS_OK) { if (res != COLVARS_OK) {
if (!dry_run) { if (!dry_run) {
cvm::log("...required by \"" + f->description + "\" in " + description); cvm::log("...required by \"" + f->description + "\" in " + description + "\n");
if (toplevel) { if (toplevel) {
cvm::error("Error: Failed dependency in " + description + "."); cvm::error("Error: Failed dependency in " + description + ".\n");
} }
} }
return res; return res;

View File

@ -194,7 +194,7 @@ public:
/// Enable a feature and recursively solve its dependencies. /// Enable a feature and recursively solve its dependencies.
/// For accurate reference counting, do not add spurious calls to enable() /// For accurate reference counting, do not add spurious calls to enable()
/// \param dry_run Recursively test if a feature is available, without enabling it /// \param dry_run Recursively test whether a feature is available, without enabling it
/// \param toplevel False if this is called as part of a chain of dependency resolution. /// \param toplevel False if this is called as part of a chain of dependency resolution.
/// This is used to diagnose failed dependencies by displaying the full stack: /// This is used to diagnose failed dependencies by displaying the full stack:
/// only the toplevel dependency will throw a fatal error. /// only the toplevel dependency will throw a fatal error.
@ -251,6 +251,8 @@ public:
f_cvb_write_ti_samples, f_cvb_write_ti_samples,
/// \brief whether this bias should write the TI PMF /// \brief whether this bias should write the TI PMF
f_cvb_write_ti_pmf, f_cvb_write_ti_pmf,
/// \brief whether this bias uses an external grid to scale the biasing forces
f_cvb_scale_biasing_force,
f_cvb_ntot f_cvb_ntot
}; };
@ -265,6 +267,8 @@ public:
/// \brief Collect atomic gradient data from all cvcs into vector /// \brief Collect atomic gradient data from all cvcs into vector
/// atomic_gradient /// atomic_gradient
f_cv_collect_gradient, f_cv_collect_gradient,
/// \brief Build list of atoms involved in CV calculation
f_cv_collect_atom_ids,
/// \brief Calculate the velocity with finite differences /// \brief Calculate the velocity with finite differences
f_cv_fdiff_velocity, f_cv_fdiff_velocity,
/// \brief The total force is calculated, projecting the atomic /// \brief The total force is calculated, projecting the atomic
@ -353,7 +357,7 @@ public:
f_cvc_upper_boundary, f_cvc_upper_boundary,
/// CVC calculates atom gradients /// CVC calculates atom gradients
f_cvc_gradient, f_cvc_gradient,
/// CVC calculates and stores explicit atom gradients /// CVC calculates and stores explicit atom gradients on rank 0
f_cvc_explicit_gradient, f_cvc_explicit_gradient,
/// CVC calculates and stores inverse atom gradients (used for total force) /// CVC calculates and stores inverse atom gradients (used for total force)
f_cvc_inv_gradient, f_cvc_inv_gradient,
@ -372,6 +376,8 @@ public:
f_cvc_scalable, f_cvc_scalable,
/// Centers-of-mass used in this CVC can be computed in parallel /// Centers-of-mass used in this CVC can be computed in parallel
f_cvc_scalable_com, f_cvc_scalable_com,
/// \brief Build list of atoms involved in CVC calculation
f_cvc_collect_atom_ids,
/// Number of CVC features /// Number of CVC features
f_cvc_ntot f_cvc_ntot
}; };
@ -391,6 +397,8 @@ public:
f_ag_atom_forces, f_ag_atom_forces,
f_ag_scalable, f_ag_scalable,
f_ag_scalable_com, f_ag_scalable_com,
/// \brief Build list of atoms involved in atom group
f_ag_collect_atom_ids,
f_ag_ntot f_ag_ntot
}; };
@ -418,12 +426,12 @@ public:
/// \brief print all enabled features and those of children, for debugging /// \brief print all enabled features and those of children, for debugging
void print_state(); void print_state();
/// \brief Check that a feature is enabled, raising BUG_ERROR if not /// \brief Check that a feature is enabled, raising COLVARS_BUG_ERROR if not
inline void check_enabled(int f, std::string const &reason) const inline void check_enabled(int f, std::string const &reason) const
{ {
if (! is_enabled(f)) { if (! is_enabled(f)) {
cvm::error("Error: "+reason+" requires that the feature \""+ cvm::error("Error: "+reason+" requires that the feature \""+
features()[f]->description+"\" is active.\n", BUG_ERROR); features()[f]->description+"\" is active.\n", COLVARS_BUG_ERROR);
} }
} }

View File

@ -170,7 +170,7 @@ colvar_grid_gradient::colvar_grid_gradient(std::string &filename)
if (nd > 50) { if (nd > 50) {
cvm::error("Error: excessive number of dimensions in file \""+ cvm::error("Error: excessive number of dimensions in file \""+
filename+"\". Please ensure that the file is not corrupt.\n", filename+"\". Please ensure that the file is not corrupt.\n",
INPUT_ERROR); COLVARS_INPUT_ERROR);
return; return;
} }
@ -271,6 +271,7 @@ integrate_potential::integrate_potential(std::vector<colvar *> &colvars, colvar_
// hence PMF grid is wider than gradient grid if non-PBC // hence PMF grid is wider than gradient grid if non-PBC
if (nd > 1) { if (nd > 1) {
cvm::main()->cite_feature("Poisson integration of 2D/3D free energy surfaces");
divergence.resize(nt); divergence.resize(nt);
// Compute inverse of Laplacian diagonal for Jacobi preconditioning // Compute inverse of Laplacian diagonal for Jacobi preconditioning
@ -425,7 +426,7 @@ void integrate_potential::get_grad(cvm::real * g, std::vector<int> &ix)
void integrate_potential::update_div_local(const std::vector<int> &ix0) void integrate_potential::update_div_local(const std::vector<int> &ix0)
{ {
const int linear_index = address(ix0); const size_t linear_index = address(ix0);
int i, j, k; int i, j, k;
std::vector<int> ix = ix0; std::vector<int> ix = ix0;

View File

@ -62,7 +62,7 @@ protected:
addr += ix[i]*static_cast<size_t>(nxc[i]); addr += ix[i]*static_cast<size_t>(nxc[i]);
if (cvm::debug()) { if (cvm::debug()) {
if (ix[i] >= nx[i]) { if (ix[i] >= nx[i]) {
cvm::error("Error: exceeding bounds in colvar_grid.\n", BUG_ERROR); cvm::error("Error: exceeding bounds in colvar_grid.\n", COLVARS_BUG_ERROR);
return 0; return 0;
} }
} }
@ -170,7 +170,7 @@ public:
for (int i = nd-1; i >= 0; i--) { for (int i = nd-1; i >= 0; i--) {
if (nx[i] <= 0) { if (nx[i] <= 0) {
cvm::error("Error: providing an invalid number of grid points, "+ cvm::error("Error: providing an invalid number of grid points, "+
cvm::to_str(nx[i])+".\n", BUG_ERROR); cvm::to_str(nx[i])+".\n", COLVARS_BUG_ERROR);
return COLVARS_ERROR; return COLVARS_ERROR;
} }
nxc[i] = nt; nxc[i] = nt;
@ -254,11 +254,11 @@ public:
bool add_extra_bin = false) bool add_extra_bin = false)
: has_parent_data(false), has_data(false) : has_parent_data(false), has_data(false)
{ {
this->init_from_colvars(colvars, t, mult_i, add_extra_bin); (void) t;
this->init_from_colvars(colvars, mult_i, add_extra_bin);
} }
int init_from_colvars(std::vector<colvar *> const &colvars, int init_from_colvars(std::vector<colvar *> const &colvars,
T const &t = T(),
size_t mult_i = 1, size_t mult_i = 1,
bool add_extra_bin = false) bool add_extra_bin = false)
{ {
@ -283,13 +283,13 @@ public:
cvm::error("Colvar grids can only be automatically " cvm::error("Colvar grids can only be automatically "
"constructed for scalar variables. " "constructed for scalar variables. "
"ABF and histogram can not be used; metadynamics " "ABF and histogram can not be used; metadynamics "
"can be used with useGrids disabled.\n", INPUT_ERROR); "can be used with useGrids disabled.\n", COLVARS_INPUT_ERROR);
return COLVARS_ERROR; return COLVARS_ERROR;
} }
if (cv[i]->width <= 0.0) { if (cv[i]->width <= 0.0) {
cvm::error("Tried to initialize a grid on a " cvm::error("Tried to initialize a grid on a "
"variable with negative or zero width.\n", INPUT_ERROR); "variable with negative or zero width.\n", COLVARS_INPUT_ERROR);
return COLVARS_ERROR; return COLVARS_ERROR;
} }
@ -340,6 +340,9 @@ public:
nt = 0; nt = 0;
for (size_t i = 0; i < lower_boundaries.size(); i++) { for (size_t i = 0; i < lower_boundaries.size(); i++) {
// Re-compute periodicity using current grid boundaries
periodic[i] = cv[i]->periodic_boundaries(lower_boundaries[i].real_value,
upper_boundaries[i].real_value);
cvm::real nbins = ( upper_boundaries[i].real_value - cvm::real nbins = ( upper_boundaries[i].real_value -
lower_boundaries[i].real_value ) / widths[i]; lower_boundaries[i].real_value ) / widths[i];
@ -375,7 +378,7 @@ public:
} else { } else {
if (ix[i] < 0 || ix[i] >= nx[i]) { if (ix[i] < 0 || ix[i] >= nx[i]) {
cvm::error("Trying to wrap illegal index vector (non-PBC) for a grid point: " cvm::error("Trying to wrap illegal index vector (non-PBC) for a grid point: "
+ cvm::to_str(ix), BUG_ERROR); + cvm::to_str(ix), COLVARS_BUG_ERROR);
return; return;
} }
} }
@ -542,12 +545,21 @@ public:
{ {
for (size_t i = 0; i < data.size(); i++) out_data[i] = data[i]; for (size_t i = 0; i < data.size(); i++) out_data[i] = data[i];
} }
void raw_data_out(std::vector<T>& out_data) const
{
out_data = data;
}
/// \brief Input the data as they are represented in memory. /// \brief Input the data as they are represented in memory.
void raw_data_in(const T* in_data) void raw_data_in(const T* in_data)
{ {
for (size_t i = 0; i < data.size(); i++) data[i] = in_data[i]; for (size_t i = 0; i < data.size(); i++) data[i] = in_data[i];
has_data = true; has_data = true;
} }
void raw_data_in(const std::vector<T>& in_data)
{
data = in_data;
has_data = true;
}
/// \brief Size of the data as they are represented in memory. /// \brief Size of the data as they are represented in memory.
size_t raw_data_num() const { return data.size(); } size_t raw_data_num() const { return data.size(); }
@ -1245,6 +1257,7 @@ public:
size_t const &imult = 0, size_t const &imult = 0,
bool add = false) bool add = false)
{ {
(void) imult;
if (add) { if (add) {
data[address(ix)] += t; data[address(ix)] += t;
if (this->has_parent_data) { if (this->has_parent_data) {
@ -1381,6 +1394,7 @@ public:
cvm::real const &new_value, cvm::real const &new_value,
size_t const &imult = 0) size_t const &imult = 0)
{ {
(void) imult;
// only legal value of imult here is 0 // only legal value of imult here is 0
data[address(ix)] += new_value; data[address(ix)] += new_value;
if (samples) if (samples)
@ -1441,6 +1455,49 @@ public:
} }
} }
/// \brief Return the gradient of discrete count from finite differences
/// on the *same* grid for dimension n
inline cvm::real gradient_finite_diff(const std::vector<int> &ix0,
int n = 0)
{
cvm::real A0, A1, A2;
std::vector<int> ix = ix0;
// FIXME this can be rewritten more concisely with wrap_edge()
if (periodic[n]) {
ix[n]--; wrap(ix);
A0 = value(ix);
ix = ix0;
ix[n]++; wrap(ix);
A1 = value(ix);
if (A0 * A1 == 0) {
return 0.; // can't handle empty bins
} else {
return (A1 - A0) / (widths[n] * 2.);
}
} else if (ix[n] > 0 && ix[n] < nx[n]-1) { // not an edge
ix[n]--;
A0 = value(ix);
ix = ix0;
ix[n]++;
A1 = value(ix);
if (A0 * A1 == 0) {
return 0.; // can't handle empty bins
} else {
return (A1 - A0) / (widths[n] * 2.);
}
} else {
// edge: use 2nd order derivative
int increment = (ix[n] == 0 ? 1 : -1);
// move right from left edge, or the other way around
A0 = value(ix);
ix[n] += increment; A1 = value(ix);
ix[n] += increment; A2 = value(ix);
return (-1.5 * A0 + 2. * A1
- 0.5 * A2) * increment / widths[n];
}
}
/// \brief Return the value of the function at ix divided by its /// \brief Return the value of the function at ix divided by its
/// number of samples (if the count grid is defined) /// number of samples (if the count grid is defined)
virtual cvm::real value_output(std::vector<int> const &ix, virtual cvm::real value_output(std::vector<int> const &ix,

View File

@ -9,6 +9,8 @@
#include <sstream> #include <sstream>
#include <cstring> #include <cstring>
#include <vector>
#include <map>
#include "colvarmodule.h" #include "colvarmodule.h"
#include "colvarparse.h" #include "colvarparse.h"
@ -18,6 +20,7 @@
#include "colvarbias_abf.h" #include "colvarbias_abf.h"
#include "colvarbias_alb.h" #include "colvarbias_alb.h"
#include "colvarbias_histogram.h" #include "colvarbias_histogram.h"
#include "colvarbias_histogram_reweight_amd.h"
#include "colvarbias_meta.h" #include "colvarbias_meta.h"
#include "colvarbias_restraint.h" #include "colvarbias_restraint.h"
#include "colvarscript.h" #include "colvarscript.h"
@ -25,6 +28,44 @@
#include "colvarcomp.h" #include "colvarcomp.h"
/// Track usage of Colvars features
class colvarmodule::usage {
public:
/// Constructor
usage();
/// Increment usage count for the given feature; return error if not found
int cite_feature(std::string const &feature);
/// Increment usage count for the given paper; return error if not found
int cite_paper(std::string const &paper);
/// Generate a report for used features (0 = URL, 1 = BibTeX)
std::string report(int flag);
protected:
/// Usage count for each feature
std::map<std::string, int> feature_count_;
/// Usage count for each cited paper
std::map<std::string, int> paper_count_;
/// URL for each paper
std::map<std::string, std::string> paper_url_;
/// BibTeX entry for each paper
std::map<std::string, std::string> paper_bibtex_;
/// Map code features to the relevant papers
std::map<std::string, std::string> feature_paper_map_;
};
colvarmodule::colvarmodule(colvarproxy *proxy_in) colvarmodule::colvarmodule(colvarproxy *proxy_in)
{ {
depth_s = 0; depth_s = 0;
@ -34,27 +75,33 @@ colvarmodule::colvarmodule(colvarproxy *proxy_in)
xyz_reader_use_count = 0; xyz_reader_use_count = 0;
num_biases_types_used_ =
reinterpret_cast<void *>(new std::map<std::string, int>());
restart_version_str.clear(); restart_version_str.clear();
restart_version_int = 0; restart_version_int = 0;
if (proxy == NULL) { usage_ = new usage();
proxy = proxy_in; // Pointer to the proxy object usage_->cite_feature("Colvars module");
parse = new colvarparse(); // Parsing object for global options
version_int = proxy->get_version_from_string(COLVARS_VERSION); if (proxy != NULL) {
} else {
// TODO relax this error to handle multiple molecules in VMD // TODO relax this error to handle multiple molecules in VMD
// once the module is not static anymore // once the module is not static anymore
cvm::error("Error: trying to allocate the collective " cvm::error("Error: trying to allocate the collective "
"variable module twice.\n", BUG_ERROR); "variable module twice.\n", COLVARS_BUG_ERROR);
return; return;
} }
proxy = proxy_in; // Pointer to the proxy object
parse = new colvarparse(); // Parsing object for global options
version_int = proxy->get_version_from_string(COLVARS_VERSION);
cvm::log(cvm::line_marker); cvm::log(cvm::line_marker);
cvm::log("Initializing the collective variables module, version "+ cvm::log("Initializing the collective variables module, version "+
version()+".\n"); version()+".\n");
cvm::log("Please cite Fiorin et al, Mol Phys 2013:\n " cvm::log("Please cite Fiorin et al, Mol Phys 2013:\n"
"https://dx.doi.org/10.1080/00268976.2013.813594\n" " https://doi.org/10.1080/00268976.2013.813594\n"
"in any publication based on this calculation.\n"); "as well as all other papers listed below for individual features used.\n");
if (proxy->smp_enabled() == COLVARS_OK) { if (proxy->smp_enabled() == COLVARS_OK) {
cvm::log("SMP parallelism is enabled; if needed, use \"smp off\" to override this.\n"); cvm::log("SMP parallelism is enabled; if needed, use \"smp off\" to override this.\n");
@ -65,7 +112,7 @@ colvarmodule::colvarmodule(colvarproxy *proxy_in)
#else #else
cvm::log("This version was built without the C++11 standard: some features are disabled.\n" cvm::log("This version was built without the C++11 standard: some features are disabled.\n"
"Please see the following link for details:\n" "Please see the following link for details:\n"
"https://colvars.github.io/README-c++11.html"); " https://colvars.github.io/README-c++11.html\n");
#endif #endif
// set initial default values // set initial default values
@ -87,8 +134,10 @@ colvarmodule::colvarmodule(colvarproxy *proxy_in)
// by default overwrite the existing trajectory file // by default overwrite the existing trajectory file
cv_traj_append = false; cv_traj_append = false;
cv_traj_write_labels = true; cv_traj_write_labels = true;
// Removes the need for proxy specializations to create this
proxy->script = new colvarscript(proxy, this);
} }
@ -145,7 +194,7 @@ int colvarmodule::read_config_file(char const *config_filename)
if (!config_s.is_open()) { if (!config_s.is_open()) {
cvm::error("Error: in opening configuration file \""+ cvm::error("Error: in opening configuration file \""+
std::string(config_filename)+"\".\n", std::string(config_filename)+"\".\n",
FILE_ERROR); COLVARS_FILE_ERROR);
return COLVARS_ERROR; return COLVARS_ERROR;
} }
@ -210,7 +259,7 @@ int colvarmodule::parse_config(std::string &conf)
// Check that the input has matching braces // Check that the input has matching braces
if (colvarparse::check_braces(conf, 0) != COLVARS_OK) { if (colvarparse::check_braces(conf, 0) != COLVARS_OK) {
return cvm::error("Error: unmatched curly braces in configuration.\n", return cvm::error("Error: unmatched curly braces in configuration.\n",
INPUT_ERROR); COLVARS_INPUT_ERROR);
} }
// Check that the input has only ASCII characters, and warn otherwise // Check that the input has only ASCII characters, and warn otherwise
@ -253,6 +302,10 @@ int colvarmodule::parse_config(std::string &conf)
// Update any necessary proxy data // Update any necessary proxy data
proxy->setup(); proxy->setup();
if (source_Tcl_script.size() > 0) {
run_tcl_script(source_Tcl_script);
}
return get_error(); return get_error();
} }
@ -342,20 +395,26 @@ int colvarmodule::parse_global_params(std::string const &conf)
parse->get_keyval(conf, "scriptingAfterBiases", parse->get_keyval(conf, "scriptingAfterBiases",
scripting_after_biases, scripting_after_biases); scripting_after_biases, scripting_after_biases);
if (use_scripted_forces && !proxy->force_script_defined) { #if defined(COLVARS_TCL)
if (proxy->simulation_running()) { parse->get_keyval(conf, "sourceTclFile", source_Tcl_script);
return cvm::error("User script for scripted colvar forces not found.", #endif
INPUT_ERROR);
} else {
// Not necessary if we are not applying biases in a real simulation (eg. VMD)
cvm::log("Warning: User script for scripted colvar forces not found.");
}
}
return cvm::get_error(); return cvm::get_error();
} }
int colvarmodule::run_tcl_script(std::string const &filename) {
int result = COLVARS_OK;
#if defined(COLVARS_TCL)
result = proxy->tcl_run_file(filename);
#endif
return result;
}
int colvarmodule::parse_colvars(std::string const &conf) int colvarmodule::parse_colvars(std::string const &conf)
{ {
if (cvm::debug()) if (cvm::debug())
@ -378,7 +437,7 @@ int colvarmodule::parse_colvars(std::string const &conf)
} }
cvm::decrease_depth(); cvm::decrease_depth();
} else { } else {
cvm::error("Error: \"colvar\" keyword found without any configuration.\n", INPUT_ERROR); cvm::error("Error: \"colvar\" keyword found without any configuration.\n", COLVARS_INPUT_ERROR);
return COLVARS_ERROR; return COLVARS_ERROR;
} }
cvm::decrease_depth(); cvm::decrease_depth();
@ -421,13 +480,27 @@ template <class bias_type>
int colvarmodule::parse_biases_type(std::string const &conf, int colvarmodule::parse_biases_type(std::string const &conf,
char const *keyword) char const *keyword)
{ {
// Allow camel case when calling, but use only lower case for parsing
std::string const &type_keyword = colvarparse::to_lower_cppstr(keyword);
// Check how many times this bias keyword was used, set default name
// accordingly
std::map<std::string, int> *num_biases_types_used =
reinterpret_cast<std::map<std::string, int> *>(num_biases_types_used_);
if (num_biases_types_used->count(type_keyword) == 0) {
(*num_biases_types_used)[type_keyword] = 0;
}
std::string bias_conf = ""; std::string bias_conf = "";
size_t conf_saved_pos = 0; size_t conf_saved_pos = 0;
while (parse->key_lookup(conf, keyword, &bias_conf, &conf_saved_pos)) { while (parse->key_lookup(conf, keyword, &bias_conf, &conf_saved_pos)) {
if (bias_conf.size()) { if (bias_conf.size()) {
cvm::log(cvm::line_marker); cvm::log(cvm::line_marker);
cvm::increase_depth(); cvm::increase_depth();
biases.push_back(new bias_type(keyword)); int &bias_count = (*num_biases_types_used)[type_keyword];
biases.push_back(new bias_type(type_keyword.c_str()));
bias_count += 1;
biases.back()->rank = bias_count;
biases.back()->init(bias_conf); biases.back()->init(bias_conf);
if (cvm::check_new_bias(bias_conf, keyword) != COLVARS_OK) { if (cvm::check_new_bias(bias_conf, keyword) != COLVARS_OK) {
return COLVARS_ERROR; return COLVARS_ERROR;
@ -435,7 +508,7 @@ int colvarmodule::parse_biases_type(std::string const &conf,
cvm::decrease_depth(); cvm::decrease_depth();
} else { } else {
cvm::error("Error: keyword \""+std::string(keyword)+"\" found without configuration.\n", cvm::error("Error: keyword \""+std::string(keyword)+"\" found without configuration.\n",
INPUT_ERROR); COLVARS_INPUT_ERROR);
return COLVARS_ERROR; return COLVARS_ERROR;
} }
bias_conf = ""; bias_conf = "";
@ -477,6 +550,9 @@ int colvarmodule::parse_biases(std::string const &conf)
/// initialize metadynamics instances /// initialize metadynamics instances
parse_biases_type<colvarbias_meta>(conf, "metadynamics"); parse_biases_type<colvarbias_meta>(conf, "metadynamics");
/// initialize reweightaMD instances
parse_biases_type<colvarbias_reweightaMD>(conf, "reweightaMD");
if (use_scripted_forces) { if (use_scripted_forces) {
cvm::log(cvm::line_marker); cvm::log(cvm::line_marker);
cvm::increase_depth(); cvm::increase_depth();
@ -580,8 +656,8 @@ int colvarmodule::catch_input_errors(int result)
{ {
if (result != COLVARS_OK || get_error()) { if (result != COLVARS_OK || get_error()) {
set_error_bits(result); set_error_bits(result);
set_error_bits(INPUT_ERROR); set_error_bits(COLVARS_INPUT_ERROR);
parse->init(); parse->clear();
return get_error(); return get_error();
} }
return COLVARS_OK; return COLVARS_OK;
@ -1017,7 +1093,7 @@ int colvarmodule::write_restart_file(std::string const &out_name)
std::ostream *restart_out_os = proxy->output_stream(out_name); std::ostream *restart_out_os = proxy->output_stream(out_name);
if (!restart_out_os) return cvm::get_error(); if (!restart_out_os) return cvm::get_error();
if (!write_restart(*restart_out_os)) { if (!write_restart(*restart_out_os)) {
return cvm::error("Error: in writing restart file.\n", FILE_ERROR); return cvm::error("Error: in writing restart file.\n", COLVARS_FILE_ERROR);
} }
proxy->close_output_stream(out_name); proxy->close_output_stream(out_name);
if (cv_traj_os != NULL) { if (cv_traj_os != NULL) {
@ -1033,7 +1109,7 @@ int colvarmodule::write_restart_string(std::string &output)
cvm::log("Saving state to output buffer.\n"); cvm::log("Saving state to output buffer.\n");
std::ostringstream os; std::ostringstream os;
if (!write_restart(os)) { if (!write_restart(os)) {
return cvm::error("Error: in writing restart to buffer.\n", FILE_ERROR); return cvm::error("Error: in writing restart to buffer.\n", COLVARS_FILE_ERROR);
} }
output = os.str(); output = os.str();
return COLVARS_OK; return COLVARS_OK;
@ -1156,8 +1232,17 @@ colvarmodule::~colvarmodule()
colvar::cvc::delete_features(); colvar::cvc::delete_features();
atom_group::delete_features(); atom_group::delete_features();
delete
reinterpret_cast<std::map<std::string, int> *>(num_biases_types_used_);
num_biases_types_used_ = NULL;
delete parse; delete parse;
parse = NULL; parse = NULL;
delete usage_;
usage_ = NULL;
// The proxy object will be deallocated last (if at all)
proxy = NULL; proxy = NULL;
} }
} }
@ -1167,7 +1252,7 @@ int colvarmodule::reset()
{ {
cvm::log("Resetting the Collective Variables module.\n"); cvm::log("Resetting the Collective Variables module.\n");
parse->init(); parse->clear();
// Iterate backwards because we are deleting the elements as we go // Iterate backwards because we are deleting the elements as we go
for (std::vector<colvarbias *>::reverse_iterator bi = biases.rbegin(); for (std::vector<colvarbias *>::reverse_iterator bi = biases.rbegin();
@ -1178,6 +1263,9 @@ int colvarmodule::reset()
biases.clear(); biases.clear();
biases_active_.clear(); biases_active_.clear();
// Reset counters tracking usage of each bias type
reinterpret_cast<std::map<std::string, int> *>(num_biases_types_used_)->clear();
// Iterate backwards because we are deleting the elements as we go // Iterate backwards because we are deleting the elements as we go
for (std::vector<colvar *>::reverse_iterator cvi = colvars.rbegin(); for (std::vector<colvar *>::reverse_iterator cvi = colvars.rbegin();
cvi != colvars.rend(); cvi != colvars.rend();
@ -1215,7 +1303,7 @@ int colvarmodule::setup_input()
if (!input_is.good()) { if (!input_is.good()) {
return cvm::error("Error: in opening input state file \""+ return cvm::error("Error: in opening input state file \""+
std::string(restart_in_name)+"\".\n", std::string(restart_in_name)+"\".\n",
FILE_ERROR); COLVARS_FILE_ERROR);
} else { } else {
cvm::log(cvm::line_marker); cvm::log(cvm::line_marker);
cvm::log("Loading state from file \""+restart_in_name+"\".\n"); cvm::log("Loading state from file \""+restart_in_name+"\".\n");
@ -1287,7 +1375,7 @@ int colvarmodule::setup_output()
} }
if (error_code != COLVARS_OK || cvm::get_error()) { if (error_code != COLVARS_OK || cvm::get_error()) {
set_error_bits(FILE_ERROR); set_error_bits(COLVARS_FILE_ERROR);
} }
return cvm::get_error(); return cvm::get_error();
@ -1301,7 +1389,7 @@ std::string colvarmodule::state_file_prefix(char const *filename)
filename_str.substr(0, filename_str.find(".colvars.state")); filename_str.substr(0, filename_str.find(".colvars.state"));
if (prefix.size() == 0) { if (prefix.size() == 0) {
cvm::error("Error: invalid filename/prefix value \""+filename_str+"\".", cvm::error("Error: invalid filename/prefix value \""+filename_str+"\".",
INPUT_ERROR); COLVARS_INPUT_ERROR);
} }
return prefix; return prefix;
} }
@ -1353,7 +1441,7 @@ std::istream & colvarmodule::read_restart(std::istream &is)
if ((proxy->units.size() > 0) && (units_restart != proxy->units)) { if ((proxy->units.size() > 0) && (units_restart != proxy->units)) {
cvm::error("Error: the state file has units \""+units_restart+ cvm::error("Error: the state file has units \""+units_restart+
"\", but the current unit system is \""+proxy->units+ "\", but the current unit system is \""+proxy->units+
"\".\n", INPUT_ERROR); "\".\n", COLVARS_INPUT_ERROR);
} }
} }
@ -1396,7 +1484,7 @@ std::istream & colvarmodule::read_objects_state(std::istream &is)
// state is corrupt; otherwise, the variable rewinds is silently // state is corrupt; otherwise, the variable rewinds is silently
cvm::error("Error: in reading restart configuration for " cvm::error("Error: in reading restart configuration for "
"collective variable \""+(*cvi)->name+"\".\n", "collective variable \""+(*cvi)->name+"\".\n",
INPUT_ERROR); COLVARS_INPUT_ERROR);
} }
if (is.tellg() > pos) break; // found it if (is.tellg() > pos) break; // found it
} }
@ -1417,7 +1505,7 @@ std::istream & colvarmodule::read_objects_state(std::istream &is)
// Same as above, an error means a match but the state is incorrect // Same as above, an error means a match but the state is incorrect
cvm::error("Error: in reading restart configuration for bias \""+ cvm::error("Error: in reading restart configuration for bias \""+
(*bi)->name+"\".\n", (*bi)->name+"\".\n",
INPUT_ERROR); COLVARS_INPUT_ERROR);
} }
if (is.tellg() > pos) break; // found it if (is.tellg() > pos) break; // found it
} }
@ -1455,7 +1543,7 @@ and load it to continue this simulation.\n");
output_prefix() = output_prefix()+".tmp"; output_prefix() = output_prefix()+".tmp";
write_restart_file(output_prefix()+".colvars.state"); write_restart_file(output_prefix()+".colvars.state");
return cvm::error("Exiting with error until issue is addressed.\n", return cvm::error("Exiting with error until issue is addressed.\n",
INPUT_ERROR); COLVARS_INPUT_ERROR);
} }
return COLVARS_OK; return COLVARS_OK;
@ -1533,7 +1621,7 @@ int colvarmodule::read_traj(char const *traj_filename,
std::cerr << "\n"; std::cerr << "\n";
cvm::error("Reached the end of the trajectory, " cvm::error("Reached the end of the trajectory, "
"read_end = "+cvm::to_str(traj_read_end)+"\n", "read_end = "+cvm::to_str(traj_read_end)+"\n",
FILE_ERROR); COLVARS_FILE_ERROR);
return COLVARS_ERROR; return COLVARS_ERROR;
} }
@ -1544,7 +1632,7 @@ int colvarmodule::read_traj(char const *traj_filename,
cvm::error("Error: in reading colvar \""+(*cvi)->name+ cvm::error("Error: in reading colvar \""+(*cvi)->name+
"\" from trajectory file \""+ "\" from trajectory file \""+
std::string(traj_filename)+"\".\n", std::string(traj_filename)+"\".\n",
FILE_ERROR); COLVARS_FILE_ERROR);
return COLVARS_ERROR; return COLVARS_ERROR;
} }
} }
@ -1613,7 +1701,7 @@ int colvarmodule::open_traj_file(std::string const &file_name)
if (cv_traj_os == NULL) { if (cv_traj_os == NULL) {
cvm::error("Error: cannot write to file \""+file_name+"\".\n", cvm::error("Error: cannot write to file \""+file_name+"\".\n",
FILE_ERROR); COLVARS_FILE_ERROR);
} }
return cvm::get_error(); return cvm::get_error();
@ -1739,7 +1827,7 @@ size_t & colvarmodule::depth()
void colvarmodule::set_error_bits(int code) void colvarmodule::set_error_bits(int code)
{ {
if (code < 0) { if (code < 0) {
cvm::fatal_error("Error: set_error_bits() received negative error code.\n"); cvm::log("Error: set_error_bits() received negative error code.\n");
return; return;
} }
proxy->smp_lock(); proxy->smp_lock();
@ -1771,19 +1859,13 @@ int colvarmodule::error(std::string const &message, int code)
} }
int colvarmodule::fatal_error(std::string const &message)
{
return error(message, FATAL_ERROR);
}
int cvm::read_index_file(char const *filename) int cvm::read_index_file(char const *filename)
{ {
std::ifstream is(filename, std::ios::binary); std::ifstream is(filename, std::ios::binary);
if (!is.good()) { if (!is.good()) {
cvm::error("Error: in opening index file \""+ return cvm::error("Error: in opening index file \""+
std::string(filename)+"\".\n", std::string(filename)+"\".\n",
FILE_ERROR); COLVARS_FILE_ERROR);
} else { } else {
index_file_names.push_back(std::string(filename)); index_file_names.push_back(std::string(filename));
} }
@ -1810,7 +1892,7 @@ int cvm::read_index_file(char const *filename)
} else { } else {
return cvm::error("Error: in parsing index file \""+ return cvm::error("Error: in parsing index file \""+
std::string(filename)+"\".\n", std::string(filename)+"\".\n",
INPUT_ERROR); COLVARS_INPUT_ERROR);
} }
std::vector<int> *old_index_group = index_groups[index_of_group]; std::vector<int> *old_index_group = index_groups[index_of_group];
@ -1836,7 +1918,7 @@ int cvm::read_index_file(char const *filename)
delete new_index_group; delete new_index_group;
new_index_group = NULL; new_index_group = NULL;
return cvm::error("Error: the index group \""+group_name+ return cvm::error("Error: the index group \""+group_name+
"\" was redefined.\n", INPUT_ERROR); "\" was redefined.\n", COLVARS_INPUT_ERROR);
} else { } else {
old_index_group->clear(); old_index_group->clear();
delete old_index_group; delete old_index_group;
@ -1912,7 +1994,7 @@ int cvm::load_coords(char const *file_name,
if (colvarparse::to_lower_cppstr(ext) == std::string(".xyz")) { if (colvarparse::to_lower_cppstr(ext) == std::string(".xyz")) {
if (pdb_field.size() > 0) { if (pdb_field.size() > 0) {
return cvm::error("Error: PDB column may not be specified " return cvm::error("Error: PDB column may not be specified "
"for XYZ coordinate files.\n", INPUT_ERROR); "for XYZ coordinate files.\n", COLVARS_INPUT_ERROR);
} }
// For XYZ files, use internal parser // For XYZ files, use internal parser
error_code |= cvm::main()->load_coords_xyz(file_name, &sorted_pos, atoms); error_code |= cvm::main()->load_coords_xyz(file_name, &sorted_pos, atoms);
@ -1946,7 +2028,7 @@ int cvm::load_coords_xyz(char const *filename,
std::string(filename)+"\".\n"); std::string(filename)+"\".\n");
if ( ! (xyz_is >> natoms) ) { if ( ! (xyz_is >> natoms) ) {
return cvm::error(error_msg, INPUT_ERROR); return cvm::error(error_msg, COLVARS_INPUT_ERROR);
} }
++xyz_reader_use_count; ++xyz_reader_use_count;
@ -1960,7 +2042,7 @@ int cvm::load_coords_xyz(char const *filename,
cvm::getline(xyz_is, line); cvm::getline(xyz_is, line);
xyz_is.width(255); xyz_is.width(255);
} else { } else {
return cvm::error(error_msg, INPUT_ERROR); return cvm::error(error_msg, COLVARS_INPUT_ERROR);
} }
std::vector<atom_pos>::iterator pos_i = pos->begin(); std::vector<atom_pos>::iterator pos_i = pos->begin();
@ -1983,7 +2065,7 @@ int cvm::load_coords_xyz(char const *filename,
(*pos_i)[2] = proxy->angstrom_to_internal(z); (*pos_i)[2] = proxy->angstrom_to_internal(z);
xyz_natoms++; xyz_natoms++;
} else { } else {
return cvm::error(error_msg, INPUT_ERROR); return cvm::error(error_msg, COLVARS_INPUT_ERROR);
} }
} }
@ -1998,7 +2080,7 @@ int cvm::load_coords_xyz(char const *filename,
(*pos_i)[2] = proxy->angstrom_to_internal(z); (*pos_i)[2] = proxy->angstrom_to_internal(z);
xyz_natoms++; xyz_natoms++;
} else { } else {
return cvm::error(error_msg, INPUT_ERROR); return cvm::error(error_msg, COLVARS_INPUT_ERROR);
} }
} }
} }
@ -2007,7 +2089,7 @@ int cvm::load_coords_xyz(char const *filename,
return cvm::error("Error: The number of positions read from file \""+ return cvm::error("Error: The number of positions read from file \""+
std::string(filename)+"\" does not match the number of "+ std::string(filename)+"\" does not match the number of "+
"positions required: "+cvm::to_str(xyz_natoms)+" vs. "+ "positions required: "+cvm::to_str(xyz_natoms)+" vs. "+
cvm::to_str(pos->size())+".\n", INPUT_ERROR); cvm::to_str(pos->size())+".\n", COLVARS_INPUT_ERROR);
} }
return COLVARS_OK; return COLVARS_OK;
@ -2230,6 +2312,89 @@ std::string cvm::wrap_string(std::string const &s, size_t nchars)
} }
int colvarmodule::cite_feature(std::string const &feature)
{
return usage_->cite_feature(feature);
}
std::string colvarmodule::feature_report(int flag)
{
return usage_->report(flag);
}
colvarmodule::usage::usage()
{
#include "colvarmodule_refs.h"
}
int colvarmodule::usage::cite_feature(std::string const &feature)
{
if (feature_count_.count(feature) > 0) {
feature_count_[feature] += 1;
return cite_paper(feature_paper_map_[feature]);
}
cvm::log("Warning: cannot cite unknown feature \""+feature+"\"\n");
return COLVARS_OK;
}
int colvarmodule::usage::cite_paper(std::string const &paper)
{
if (paper_count_.count(paper) > 0) {
paper_count_[paper] += 1;
return COLVARS_OK;
}
cvm::log("Warning: cannot cite unknown paper \""+paper+"\"\n");
return COLVARS_OK;
}
std::string colvarmodule::usage::report(int flag)
{
std::string result;
if (flag == 0) {
// Text
result += "SUMMARY OF COLVARS FEATURES USED SO FAR AND THEIR CITATIONS:\n";
}
if (flag == 1) {
// LAMMPS log friendly (one-line summary, lowercase message)
result += "Colvars module (Fiorin2013, plus other works listed for specific features)\n\n";
}
std::map<std::string, int>::iterator p_iter = paper_count_.begin();
for ( ; p_iter != paper_count_.end(); p_iter++) {
std::string const paper = p_iter->first;
int const count = p_iter->second;
if (count > 0) {
result += "\n";
std::map<std::string, std::string>::iterator f_iter =
feature_paper_map_.begin();
for ( ; f_iter != feature_paper_map_.end(); f_iter++) {
if ((f_iter->second == paper) &&
(feature_count_[f_iter->first] > 0)) {
if (flag == 0) {
// URL
result += "- " + f_iter->first + ":\n";
}
if (flag == 1) {
// BibTeX
result += "% " + f_iter->first + ":\n";
}
}
}
if (flag == 0) {
result += " " + paper + " " + paper_url_[paper] + "\n";
}
if (flag == 1) {
result += paper_bibtex_[paper] + "\n";
}
}
}
return result;
}
// shared pointer to the proxy object // shared pointer to the proxy object
colvarproxy *colvarmodule::proxy = NULL; colvarproxy *colvarmodule::proxy = NULL;

View File

@ -36,13 +36,11 @@ You can browse the class hierarchy or the list of source files.
#define COLVARS_OK 0 #define COLVARS_OK 0
#define COLVARS_ERROR 1 #define COLVARS_ERROR 1
#define COLVARS_NOT_IMPLEMENTED (1<<1) #define COLVARS_NOT_IMPLEMENTED (1<<1)
#define INPUT_ERROR (1<<2) // out of bounds or inconsistent input #define COLVARS_INPUT_ERROR (1<<2) // out of bounds or inconsistent input
#define BUG_ERROR (1<<3) // Inconsistent state indicating bug #define COLVARS_BUG_ERROR (1<<3) // Inconsistent state indicating bug
#define FILE_ERROR (1<<4) #define COLVARS_FILE_ERROR (1<<4)
#define MEMORY_ERROR (1<<5) #define COLVARS_MEMORY_ERROR (1<<5)
#define FATAL_ERROR (1<<6) // Should be set, or not, together with other bits #define COLVARS_NO_SUCH_FRAME (1<<6) // Cannot load the requested frame
//#define DELETE_COLVARS (1<<7) // Instruct the caller to delete cvm
#define COLVARS_NO_SUCH_FRAME (1<<8) // Cannot load the requested frame
#include <iostream> #include <iostream>
#include <iomanip> #include <iomanip>
@ -188,13 +186,13 @@ public:
return ::log(static_cast<double>(x)); return ::log(static_cast<double>(x));
} }
// Forward declarations
class rvector; class rvector;
template <class T> class vector1d; template <class T> class vector1d;
template <class T> class matrix2d; template <class T> class matrix2d;
class quaternion; class quaternion;
class rotation; class rotation;
class usage;
/// Residue identifier /// Residue identifier
typedef int residue_id; typedef int residue_id;
@ -322,6 +320,9 @@ public:
private: private:
/// Pointer to a map counting how many biases of each type were used
void *num_biases_types_used_;
/// Array of active collective variable biases /// Array of active collective variable biases
std::vector<colvarbias *> biases_active_; std::vector<colvarbias *> biases_active_;
@ -336,10 +337,11 @@ public:
return COLVARS_DEBUG; return COLVARS_DEBUG;
} }
/// \brief How many objects are configured yet? /// How many objects (variables and biases) are configured yet?
size_t size() const; size_t size() const;
/// \brief Constructor /// Constructor
/// \param Pointer to instance of the proxy class (communicate with engine)
colvarmodule(colvarproxy *proxy); colvarmodule(colvarproxy *proxy);
/// Destructor /// Destructor
@ -374,6 +376,9 @@ public:
/// Parse and initialize collective variables /// Parse and initialize collective variables
int parse_colvars(std::string const &conf); int parse_colvars(std::string const &conf);
/// Run provided Tcl script
int run_tcl_script(std::string const &filename);
/// Parse and initialize collective variable biases /// Parse and initialize collective variable biases
int parse_biases(std::string const &conf); int parse_biases(std::string const &conf);
@ -402,6 +407,9 @@ private:
/// on error, delete new bias /// on error, delete new bias
bool check_new_bias(std::string &conf, char const *key); bool check_new_bias(std::string &conf, char const *key);
/// Initialization Tcl script, user-provided
std::string source_Tcl_script;
public: public:
/// Return how many variables are defined /// Return how many variables are defined
@ -638,14 +646,17 @@ public:
/// Request calculation of total force from MD engine /// Request calculation of total force from MD engine
static void request_total_force(); static void request_total_force();
/// Track usage of the given Colvars feature
int cite_feature(std::string const &feature);
/// Report usage of the Colvars features
std::string feature_report(int flag = 0);
/// Print a message to the main log /// Print a message to the main log
/// \param message Message to print /// \param message Message to print
/// \param min_log_level Only print if cvm::log_level() >= min_log_level /// \param min_log_level Only print if cvm::log_level() >= min_log_level
static void log(std::string const &message, int min_log_level = 10); static void log(std::string const &message, int min_log_level = 10);
/// Print a message to the main log and exit with error code
static int fatal_error(std::string const &message);
/// Print a message to the main log and set global error code /// Print a message to the main log and set global error code
static int error(std::string const &message, int code = COLVARS_ERROR); static int error(std::string const &message, int code = COLVARS_ERROR);
@ -788,6 +799,9 @@ protected:
/// Track how many times the XYZ reader has been used /// Track how many times the XYZ reader has been used
int xyz_reader_use_count; int xyz_reader_use_count;
/// Track usage of Colvars features
usage *usage_;
public: public:
/// Version of the most recent state file read /// Version of the most recent state file read

View File

@ -0,0 +1,555 @@
paper_count_[std::string("Abraham2015")] = 0;
paper_url_[std::string("Abraham2015")] = "https://doi.org/10.1016/j.softx.2015.06.001";
paper_bibtex_[std::string("Abraham2015")] =
"\n"
"@article{Abraham2015,\n"
" title = {{GROMACS}: High performance molecular simulations through multi-level parallelism from laptops to supercomputers},\n"
" author = {Abraham, Mark J.{} and Murtola, Teemu and Schulz, Roland and Páll, Szil\\'ard and Smith, Jeremy C.{} and Hess, Berk and Lindahl, Erik},\n"
" journal = {{SoftwareX}},\n"
" volume = {1--2},\n"
" year = {2015},\n"
" pages = {19--25},\n"
" doi = {10.1016/j.softx.2015.06.001},\n"
" url = {https://doi.org/10.1016/j.softx.2015.06.001}\n"
"}\n";
paper_count_[std::string("Chen2021")] = 0;
paper_url_[std::string("Chen2021")] = "https://doi.org/10.1021/acs.jctc.1c00103";
paper_bibtex_[std::string("Chen2021")] =
"\n"
"@article{Chen2021,\n"
" author = {Chen, Haochuan and Fu, Haohao and Chipot, Christophe and Shao, Xueguang and Cai, Wensheng},\n"
" title = {Overcoming free-energy barriers with a seamless combination of a biasing force and a collective variable-independent boost potential},\n"
" journal = {J. Chem. Theory Comput.},\n"
" year = {2021},\n"
" volume = {17},\n"
" number = {7},\n"
" pages = {3886--3894},\n"
" doi = {10.1021/acs.jctc.1c00103},\n"
" url = {https://doi.org/10.1021/acs.jctc.1c00103}\n"
"}\n";
paper_count_[std::string("Chen2022")] = 0;
paper_url_[std::string("Chen2022")] = "https://doi.org/10.1021/acs.jcim.1c01010";
paper_bibtex_[std::string("Chen2022")] =
"\n"
"@article{Chen2022,\n"
" author = {Chen, Haochuan and Liu, Han and Feng, Heying and Fu, Haohao and Cai, Wensheng and Shao, Xueguang and Chipot, Christophe},\n"
" title = {MLCV: {Bridging} {Machine-Learning-Based} {Dimensionality} {Reduction} and {Free-Energy} {Calculation}},\n"
" journal = {J. Chem. Inf. Model.},\n"
" volume = {62},\n"
" number = {1},\n"
" pages = {1-8},\n"
" year = {2022},\n"
" doi = {10.1021/acs.jcim.1c01010},\n"
" URL = {https://doi.org/10.1021/acs.jcim.1c01010}\n"
"}\n";
paper_count_[std::string("Comer2014c")] = 0;
paper_url_[std::string("Comer2014c")] = "https://doi.org/10.1021/ct500874p";
paper_bibtex_[std::string("Comer2014c")] =
"\n"
"@article{Comer2014c,\n"
" author = {Comer, Jeffrey and Phillips, James C.{} and Schulten, Klaus and Chipot, Christophe},\n"
" title = {Multiple-walker strategies for free-energy calculations in {NAMD}: {Shared} adaptive biasing force and walker selection rules},\n"
" journal = {J. Chem. Theor. Comput.},\n"
" year = {2014},\n"
" volume = {10},\n"
" number = {12},\n"
" pages = {5276--5285},\n"
" doi = {10.1021/ct500874p},\n"
" pmid = {26583211},\n"
" url = {https://doi.org/10.1021/ct500874p}\n"
"}\n";
paper_count_[std::string("Fiorin2013")] = 0;
paper_url_[std::string("Fiorin2013")] = "https://doi.org/10.1080/00268976.2013.813594";
paper_bibtex_[std::string("Fiorin2013")] =
"\n"
"@article{Fiorin2013,\n"
" author = {Fiorin, Giacomo and Klein, Michael L.{} and H\\'enin, J\\'er\\^ome},\n"
" title = {Using collective variables to drive molecular dynamics simulations},\n"
" journal = {Mol. Phys.},\n"
" year = {2013},\n"
" volume = {111},\n"
" number = {22-23},\n"
" pages = {3345--3362},\n"
" publisher = {Taylor & Francis},\n"
" doi = {10.1080/00268976.2013.813594},\n"
" url = {https://doi.org/10.1080/00268976.2013.813594}\n"
"}\n";
paper_count_[std::string("Fiorin2020")] = 0;
paper_url_[std::string("Fiorin2020")] = "https://doi.org/10.1002/jcc.26075";
paper_bibtex_[std::string("Fiorin2020")] =
"\n"
"@article{Fiorin2020,\n"
" author = {Fiorin, Giacomo and Marinelli, Fabrizio and {Faraldo-G\\'omez}, Jos\\'e D.},\n"
" title = {Direct Derivation of Free Energies of Membrane Deformation and Other Solvent Density Variations From Enhanced Sampling Molecular Dynamics},\n"
" journal = {J. Comp. Chem.},\n"
" year = {2020},\n"
" volume = {41},\n"
" number = {5},\n"
" pages = {449--459},\n"
" doi = {10.1002/jcc.26075},\n"
" pmid = {31602694},\n"
" url = {https://doi.org/10.1002/jcc.26075}\n"
"}\n";
paper_count_[std::string("Fu2016")] = 0;
paper_url_[std::string("Fu2016")] = "https://doi.org/10.1021/acs.jctc.6b00447";
paper_bibtex_[std::string("Fu2016")] =
"\n"
"@article{Fu2016,\n"
" author = {Fu, Haohao and Shao, Xueguang and Chipot, Christophe and Cai, Wensheng},\n"
" title = {Extended adaptive biasing force algorithm. {An} on--the--fly implementation for accurate free--energy calculations},\n"
" journal = {J. Chem. Theory Comput.},\n"
" year = {2016},\n"
" volume = {12},\n"
" number = {8},\n"
" pages = {3506-3513},\n"
" pmid = {27398726},\n"
" doi = {10.1021/acs.jctc.6b00447},\n"
" pmid = {27398726},\n"
" url = {https://doi.org/10.1021/acs.jctc.6b00447}\n"
"}\n";
paper_count_[std::string("Fu2017")] = 0;
paper_url_[std::string("Fu2017")] = "https://doi.org/10.1021/acs.jctc.7b00791";
paper_bibtex_[std::string("Fu2017")] =
"\n"
"@article{Fu2017,\n"
" author = {Fu, Haohao and Cai, Wensheng and H\\'enin, J\\'er\\^ome and Roux, Beno\\^it and Chipot, Christophe},\n"
" title = {New Coarse Variables for the Accurate Determination of Standard Binding Free Energies},\n"
" journal = {J. Chem. Theory. Comput.},\n"
" year = {2017},\n"
" volume = {13},\n"
" number = {11},\n"
" pages = {5173-5178},\n"
" doi = {10.1021/acs.jctc.7b00791},\n"
" pmid = {28965398},\n"
" url = {https://doi.org/10.1021/acs.jctc.7b00791}\n"
"}\n";
paper_count_[std::string("Garate2019")] = 0;
paper_url_[std::string("Garate2019")] = "https://doi.org/10.1021/acs.jpcb.8b09374";
paper_bibtex_[std::string("Garate2019")] =
"\n"
"@article{Garate2019,\n"
" author = {Garate, Jos\\'e Antonio and Bernardin, Alejandro and Escalona, Yerko and Yanez, Carlos and English, Niall J.{} and {Perez-Acle}, Tomas},\n"
" title = {Orientational and Folding Thermodynamics via Electric Dipole Moment Restraining},\n"
" journal = {J. Phys. Chem. {B}},\n"
" year = {2019},\n"
" volume = {123},\n"
" number = {12},\n"
" pages = {2599--2608},\n"
" doi = {10.1021/acs.jpcb.8b09374},\n"
" pmid = {30831028},\n"
" url = {https://doi.org/10.1021/acs.jpcb.8b09374}\n"
"}\n";
paper_count_[std::string("Henin2010")] = 0;
paper_url_[std::string("Henin2010")] = "https://doi.org/10.1021/ct9004432";
paper_bibtex_[std::string("Henin2010")] =
"\n"
"@article{Henin2010,\n"
" author = {H\\'enin, J\\'er\\^ome and Fiorin, Giacomo and Chipot, Christophe and Klein, Michael L.},\n"
" title = {Exploring multidimensional free energy landscapes using time-dependent biases on collective variables},\n"
" journal = {J. Chem. Theory Comput.},\n"
" year = {2010},\n"
" volume = {6},\n"
" pages = {35-47},\n"
" number = {1},\n"
" doi = {10.1021/ct9004432},\n"
" pmid = {26614317},\n"
" url = {https://doi.org/10.1021/ct9004432}\n"
"}\n";
paper_count_[std::string("Humphrey1996")] = 0;
paper_url_[std::string("Humphrey1996")] = "https://doi.org/10.1016/0263-7855(96)00018-5";
paper_bibtex_[std::string("Humphrey1996")] =
"\n"
"@article{Humphrey1996,\n"
" title = {{VMD}: visual molecular dynamics},\n"
" author = {Humphrey, William and Dalke, Andrew and Schulten, Klaus},\n"
" journal = {J. Mol. Graph.},\n"
" year = {1996},\n"
" volume = {14},\n"
" number = {1},\n"
" pages = {33--38},\n"
" doi = {10.1016/0263-7855(96)00018-5},\n"
" url = {https://doi.org/10.1016/0263-7855(96)00018-5}\n"
"}\n";
paper_count_[std::string("Lesage2017")] = 0;
paper_url_[std::string("Lesage2017")] = "https://doi.org/10.1021/acs.jpcb.6b10055";
paper_bibtex_[std::string("Lesage2017")] =
"\n"
"@article{Lesage2017,\n"
" author = {Lesage, Adrien and Leli\\`evre, Tony and Stoltz, Gabriel and H\\'enin, J\\'er\\^ome},\n"
" title = {Smoothed biasing forces yield unbiased free energies with the extended-system adaptive biasing force method},\n"
" journal = {J. Phys. Chem. {B}},\n"
" year = {2017},\n"
" volume = {121},\n"
" number = {15},\n"
" pages = {3676-3685},\n"
" doi = {10.1021/acs.jpcb.6b10055},\n"
" pmid = {27959559},\n"
" url = {https://doi.org/10.1021/acs.jpcb.6b10055}\n"
"}\n";
paper_count_[std::string("Henin2021")] = 0;
paper_url_[std::string("Henin2021")] = "https://doi.org/10.1021/acs.jctc.1c00593";
paper_bibtex_[std::string("Henin2021")] =
"\n"
"@Article{Henin2021,\n"
" author = {H\\'enin, J.},\n"
" journal = {J. Chem. Theory Comput.},\n"
" title = {Fast and accurate multidimensional free energy integration},\n"
" year = {2021},\n"
" doi = {10.1021/acs.jctc.1c00593},\n"
" url = {https://doi.org/10.1021/acs.jctc.1c00593},\n"
"}\n";
paper_count_[std::string("Marinelli2015")] = 0;
paper_url_[std::string("Marinelli2015")] = "https://doi.org/10.1016/j.bpj.2015.05.024";
paper_bibtex_[std::string("Marinelli2015")] =
"\n"
"@article{Marinelli2015,\n"
" author = {Marinelli, Fabrizio and Faraldo-G\\'omez, Jos\\'e D.},\n"
" title = {Ensemble-Biased Metadynamics: A Molecular Simulation Method to Sample Experimental Distributions},\n"
" journal = {Biophys. J.},\n"
" year = {2015},\n"
" volume = {108},\n"
" number = {12},\n"
" pages = {2779--2782},\n"
" doi = {10.1016/j.bpj.2015.05.024},\n"
" pmid = {26083917},\n"
" url = {https://doi.org/10.1016/j.bpj.2015.05.024}\n"
"}\n";
paper_count_[std::string("Phillips2020")] = 0;
paper_url_[std::string("Phillips2020")] = "https://doi.org/10.1063/5.0014475";
paper_bibtex_[std::string("Phillips2020")] =
"\n"
"@article{Phillips2020,\n"
" author = {Phillips, James C.{} and Hardy, David J.{} and Maia, Julio D. C.{} and Stone, John E.{} and Ribeiro, Jo\\~ao V.{} and Bernardi, Rafael C.{} and Buch, Ronak and Fiorin, Giacomo and H\\'enin, J\\'er\\^ome and Jiang, Wei and McGreevy, Ryan and Melo, Marcelo C. R.{} and Radak, Brian K.{} and Skeel, Robert D.{} and Singharoy, Abhishek and Wang, Yi and Roux, Beno\\^it and Aksimentiev, Aleksei and Luthey-Schulten, Zaida and Kal\\'e, Laxmikant V.{} and Schulten, Klaus and Chipot, Christophe and Tajkhorshid, Emad},\n"
" title = {Scalable molecular dynamics on {CPU} and {GPU} architectures with {NAMD}},\n"
" journal = {J. Chem. Phys.},\n"
" year = {2020},\n"
" volume = {153},\n"
" number = {4},\n"
" pages = {044130},\n"
" doi = {10.1063/5.0014475},\n"
" pmid = {32752662},\n"
" url = {https://doi.org/10.1063/5.0014475}\n"
"}\n";
paper_count_[std::string("Plimpton1995")] = 0;
paper_url_[std::string("Plimpton1995")] = "https://doi.org/10.1006/jcph.1995.1039";
paper_bibtex_[std::string("Plimpton1995")] =
"\n"
"@article{Plimpton1995,\n"
" title = {Fast parallel algorithms for short-range molecular dynamics},\n"
" author = {Plimpton, Steve},\n"
" journal = {J. Comp. Phys.},\n"
" year = {1995},\n"
" volume = {117},\n"
" number = {1},\n"
" pages = {1--19},\n"
" doi = {10.1006/jcph.1995.1039},\n"
" url = {https://doi.org/10.1006/jcph.1995.1039}\n"
"}\n";
paper_count_[std::string("Shen2015")] = 0;
paper_url_[std::string("Shen2015")] = "https://doi.org/10.1371/journal.pcbi.1004368";
paper_bibtex_[std::string("Shen2015")] =
"\n"
"@article{Shen2015,\n"
" title = {Structural refinement of proteins by restrained molecular dynamics simulations with non-interacting molecular fragments},\n"
" author = {Shen, Rong and Han, Wei and Fiorin, Giacomo and Islam, Shahidul M and Schulten, Klaus and Roux, Beno{\\^\\i}t},\n"
" journal = {{PLoS} Comput. Biol.},\n"
" volume = {11},\n"
" year = {2015},\n"
" number = {10},\n"
" pages = {e1004368},\n"
" doi = {10.1371/journal.pcbi.1004368},\n"
" pmid = {26505197},\n"
" url = {https://doi.org/10.1371/journal.pcbi.1004368}\n"
"}\n";
paper_count_[std::string("Wells2007")] = 0;
paper_url_[std::string("Wells2007")] = "https://doi.org/10.1063/1.2770738";
paper_bibtex_[std::string("Wells2007")] =
"\n"
"@article{Wells2007,\n"
" author = {Wells, David B. and Abramkina, Volha and Aksimentiev, Aleksei},\n"
" title = {Exploring transmembrane transport through $\\alpha$-hemolysin with grid-steered molecular dynamics},\n"
" journal = {J. Chem. Phys.},\n"
" year = {2007},\n"
" volume = {127},\n"
" number = {12},\n"
" pages = {125101},\n"
" doi = {10.1063/1.2770738},\n"
" pmid = {17902937},\n"
" url = {https://doi.org/10.1063/1.2770738}\n"
"}\n";
paper_count_[std::string("White2014")] = 0;
paper_url_[std::string("White2014")] = "https://doi.org/10.1021/ct500320c";
paper_bibtex_[std::string("White2014")] =
"\n"
"@article{White2014,\n"
" author = {White, Andrew D.{} and Voth, Gregory A.{}},\n"
" title = {Efficient and minimal method to bias molecular simulations with experimental data},\n"
" journal = {J. Chem. Theory Comput.},\n"
" year = {2014},\n"
" volume = {10},\n"
" number = {8},\n"
" pages = {3023-3030},\n"
" doi = {10.1021/ct500320c},\n"
" pmid = {26588273},\n"
" url = {https://doi.org/10.1021/ct500320c}\n"
"}\n";
paper_count_[std::string("n/a")] = 0;
paper_url_[std::string("n/a")] = "";
paper_bibtex_[std::string("n/a")] = "";
feature_count_[std::string("GROMACS engine")] = 0;
feature_paper_map_[std::string("GROMACS engine")] = "Abraham2015";
feature_count_[std::string("reweightaMD colvar bias implementation (NAMD)")] = 0;
feature_paper_map_[std::string("reweightaMD colvar bias implementation (NAMD)")] = "Chen2021";
feature_count_[std::string("neuralNetwork colvar component")] = 0;
feature_paper_map_[std::string("neuralNetwork colvar component")] = "Chen2022";
feature_count_[std::string("Multiple-walker ABF implementation")] = 0;
feature_paper_map_[std::string("Multiple-walker ABF implementation")] = "Comer2014c";
feature_count_[std::string("Colvars module")] = 0;
feature_paper_map_[std::string("Colvars module")] = "Fiorin2013";
feature_count_[std::string("Colvars-NAMD interface")] = 0;
feature_paper_map_[std::string("Colvars-NAMD interface")] = "Fiorin2013";
feature_count_[std::string("Colvars-LAMMPS interface")] = 0;
feature_paper_map_[std::string("Colvars-LAMMPS interface")] = "Fiorin2013";
feature_count_[std::string("Colvars-VMD interface (command line)")] = 0;
feature_paper_map_[std::string("Colvars-VMD interface (command line)")] = "Fiorin2013";
feature_count_[std::string("distance colvar component")] = 0;
feature_paper_map_[std::string("distance colvar component")] = "Fiorin2013";
feature_count_[std::string("distanceXY colvar component (derived from distanceZ)")] = 0;
feature_paper_map_[std::string("distanceXY colvar component (derived from distanceZ)")] = "Fiorin2013";
feature_count_[std::string("distanceZ colvar component")] = 0;
feature_paper_map_[std::string("distanceZ colvar component")] = "Fiorin2013";
feature_count_[std::string("distanceVec colvar component (derived from distance)")] = 0;
feature_paper_map_[std::string("distanceVec colvar component (derived from distance)")] = "Fiorin2013";
feature_count_[std::string("distanceDir colvar component (derived from distance)")] = 0;
feature_paper_map_[std::string("distanceDir colvar component (derived from distance)")] = "Fiorin2013";
feature_count_[std::string("distanceInv colvar component")] = 0;
feature_paper_map_[std::string("distanceInv colvar component")] = "Fiorin2013";
feature_count_[std::string("angle colvar component")] = 0;
feature_paper_map_[std::string("angle colvar component")] = "Fiorin2013";
feature_count_[std::string("dihedral colvar component")] = 0;
feature_paper_map_[std::string("dihedral colvar component")] = "Fiorin2013";
feature_count_[std::string("coordNum colvar component")] = 0;
feature_paper_map_[std::string("coordNum colvar component")] = "Fiorin2013";
feature_count_[std::string("selfCoordNum colvar component")] = 0;
feature_paper_map_[std::string("selfCoordNum colvar component")] = "Fiorin2013";
feature_count_[std::string("groupCoord colvar component (derived from distance)")] = 0;
feature_paper_map_[std::string("groupCoord colvar component (derived from distance)")] = "Fiorin2013";
feature_count_[std::string("hBond colvar component")] = 0;
feature_paper_map_[std::string("hBond colvar component")] = "Fiorin2013";
feature_count_[std::string("rmsd colvar component")] = 0;
feature_paper_map_[std::string("rmsd colvar component")] = "Fiorin2013";
feature_count_[std::string("eigenvector colvar component")] = 0;
feature_paper_map_[std::string("eigenvector colvar component")] = "Fiorin2013";
feature_count_[std::string("gyration colvar component")] = 0;
feature_paper_map_[std::string("gyration colvar component")] = "Fiorin2013";
feature_count_[std::string("inertia colvar component (derived from gyration)")] = 0;
feature_paper_map_[std::string("inertia colvar component (derived from gyration)")] = "Fiorin2013";
feature_count_[std::string("inertiaZ colvar component (derived from inertia)")] = 0;
feature_paper_map_[std::string("inertiaZ colvar component (derived from inertia)")] = "Fiorin2013";
feature_count_[std::string("orientation colvar component")] = 0;
feature_paper_map_[std::string("orientation colvar component")] = "Fiorin2013";
feature_count_[std::string("Moving frame of reference")] = 0;
feature_paper_map_[std::string("Moving frame of reference")] = "Fiorin2013";
feature_count_[std::string("Optimal rotation via flexible fitting")] = 0;
feature_paper_map_[std::string("Optimal rotation via flexible fitting")] = "Fiorin2013";
feature_count_[std::string("orientationAngle colvar component (derived from orientation)")] = 0;
feature_paper_map_[std::string("orientationAngle colvar component (derived from orientation)")] = "Fiorin2013";
feature_count_[std::string("orientationProj colvar component (derived from orientation)")] = 0;
feature_paper_map_[std::string("orientationProj colvar component (derived from orientation)")] = "Fiorin2013";
feature_count_[std::string("spinAngle colvar component (derived from orientation)")] = 0;
feature_paper_map_[std::string("spinAngle colvar component (derived from orientation)")] = "Fiorin2013";
feature_count_[std::string("tilt colvar component (derived from orientation)")] = 0;
feature_paper_map_[std::string("tilt colvar component (derived from orientation)")] = "Fiorin2013";
feature_count_[std::string("alpha colvar component")] = 0;
feature_paper_map_[std::string("alpha colvar component")] = "Fiorin2013";
feature_count_[std::string("dihedralPC colvar component")] = 0;
feature_paper_map_[std::string("dihedralPC colvar component")] = "Fiorin2013";
feature_count_[std::string("cartesian colvar component")] = 0;
feature_paper_map_[std::string("cartesian colvar component")] = "Fiorin2013";
feature_count_[std::string("Linear and polynomial combination of colvar components")] = 0;
feature_paper_map_[std::string("Linear and polynomial combination of colvar components")] = "Fiorin2013";
feature_count_[std::string("Metadynamics colvar bias implementation")] = 0;
feature_paper_map_[std::string("Metadynamics colvar bias implementation")] = "Fiorin2013";
feature_count_[std::string("Multiple-walker metadynamics colvar bias implementation")] = 0;
feature_paper_map_[std::string("Multiple-walker metadynamics colvar bias implementation")] = "Fiorin2013";
feature_count_[std::string("Harmonic colvar bias implementation")] = 0;
feature_paper_map_[std::string("Harmonic colvar bias implementation")] = "Fiorin2013";
feature_count_[std::string("harmonicWalls colvar bias implementation")] = 0;
feature_paper_map_[std::string("harmonicWalls colvar bias implementation")] = "Fiorin2013";
feature_count_[std::string("Linear colvar bias implementation")] = 0;
feature_paper_map_[std::string("Linear colvar bias implementation")] = "Fiorin2013";
feature_count_[std::string("Histogram colvar bias implementation")] = 0;
feature_paper_map_[std::string("Histogram colvar bias implementation")] = "Fiorin2013";
feature_count_[std::string("mapTotal colvar component")] = 0;
feature_paper_map_[std::string("mapTotal colvar component")] = "Fiorin2020";
feature_count_[std::string("Volumetric map-based collective variables")] = 0;
feature_paper_map_[std::string("Volumetric map-based collective variables")] = "Fiorin2020";
feature_count_[std::string("Multi-Map collective variables")] = 0;
feature_paper_map_[std::string("Multi-Map collective variables")] = "Fiorin2020";
feature_count_[std::string("Umbrella-integration eABF estimator")] = 0;
feature_paper_map_[std::string("Umbrella-integration eABF estimator")] = "Fu2016";
feature_count_[std::string("polarTheta colvar component")] = 0;
feature_paper_map_[std::string("polarTheta colvar component")] = "Fu2017";
feature_count_[std::string("polarPhi colvar component")] = 0;
feature_paper_map_[std::string("polarPhi colvar component")] = "Fu2017";
feature_count_[std::string("eulerPhi colvar component (derived from orientation)")] = 0;
feature_paper_map_[std::string("eulerPhi colvar component (derived from orientation)")] = "Fu2017";
feature_count_[std::string("eulerTheta colvar component (derived from orientation)")] = 0;
feature_paper_map_[std::string("eulerTheta colvar component (derived from orientation)")] = "Fu2017";
feature_count_[std::string("eulerPsi colvar component (derived from orientation)")] = 0;
feature_paper_map_[std::string("eulerPsi colvar component (derived from orientation)")] = "Fu2017";
feature_count_[std::string("dipoleAngle colvar component")] = 0;
feature_paper_map_[std::string("dipoleAngle colvar component")] = "Garate2019";
feature_count_[std::string("dipoleMagnitude colvar component")] = 0;
feature_paper_map_[std::string("dipoleMagnitude colvar component")] = "Garate2019";
feature_count_[std::string("ABF colvar bias implementation")] = 0;
feature_paper_map_[std::string("ABF colvar bias implementation")] = "Henin2010";
feature_count_[std::string("Internal-forces free energy estimator")] = 0;
feature_paper_map_[std::string("Internal-forces free energy estimator")] = "Henin2010";
feature_count_[std::string("VMD engine")] = 0;
feature_paper_map_[std::string("VMD engine")] = "Humphrey1996";
feature_count_[std::string("eABF implementation")] = 0;
feature_paper_map_[std::string("eABF implementation")] = "Lesage2017";
feature_count_[std::string("CZAR eABF estimator")] = 0;
feature_paper_map_[std::string("CZAR eABF estimator")] = "Lesage2017";
feature_count_[std::string("Poisson integration of 2D/3D free energy surfaces")] = 0;
feature_paper_map_[std::string("Poisson integration of 2D/3D free energy surfaces")] = "Henin2021";
feature_count_[std::string("Ensemble-biased metadynamics (ebMetaD)")] = 0;
feature_paper_map_[std::string("Ensemble-biased metadynamics (ebMetaD)")] = "Marinelli2015";
feature_count_[std::string("NAMD engine")] = 0;
feature_paper_map_[std::string("NAMD engine")] = "Phillips2020";
feature_count_[std::string("Scalable center-of-mass computation (NAMD)")] = 0;
feature_paper_map_[std::string("Scalable center-of-mass computation (NAMD)")] = "Phillips2020";
feature_count_[std::string("LAMMPS engine")] = 0;
feature_paper_map_[std::string("LAMMPS engine")] = "Plimpton1995";
feature_count_[std::string("distancePairs colvar component")] = 0;
feature_paper_map_[std::string("distancePairs colvar component")] = "Shen2015";
feature_count_[std::string("histogramRestraint colvar bias implementation")] = 0;
feature_paper_map_[std::string("histogramRestraint colvar bias implementation")] = "Shen2015";
feature_count_[std::string("GridForces volumetric map implementation for NAMD")] = 0;
feature_paper_map_[std::string("GridForces volumetric map implementation for NAMD")] = "Wells2007";
feature_count_[std::string("ALB colvar bias implementation")] = 0;
feature_paper_map_[std::string("ALB colvar bias implementation")] = "White2014";
feature_count_[std::string("Colvars-GROMACS interface")] = 0;
feature_paper_map_[std::string("Colvars-GROMACS interface")] = "n/a";
feature_count_[std::string("Colvars Dashboard (Colvars-VMD graphical user interface)")] = 0;
feature_paper_map_[std::string("Colvars Dashboard (Colvars-VMD graphical user interface)")] = "n/a";
feature_count_[std::string("gspath colvar component")] = 0;
feature_paper_map_[std::string("gspath colvar component")] = "n/a";
feature_count_[std::string("gzpath colvar component")] = 0;
feature_paper_map_[std::string("gzpath colvar component")] = "n/a";
feature_count_[std::string("linearCombination colvar component")] = 0;
feature_paper_map_[std::string("linearCombination colvar component")] = "n/a";
feature_count_[std::string("gspathCV colvar component")] = 0;
feature_paper_map_[std::string("gspathCV colvar component")] = "n/a";
feature_count_[std::string("gzpathCV colvar component")] = 0;
feature_paper_map_[std::string("gzpathCV colvar component")] = "n/a";
feature_count_[std::string("aspathCV colvar component")] = 0;
feature_paper_map_[std::string("aspathCV colvar component")] = "n/a";
feature_count_[std::string("azpathCV colvar component")] = 0;
feature_paper_map_[std::string("azpathCV colvar component")] = "n/a";
feature_count_[std::string("coordNum pairlist")] = 0;
feature_paper_map_[std::string("coordNum pairlist")] = "n/a";
feature_count_[std::string("Custom functions (Lepton)")] = 0;
feature_paper_map_[std::string("Custom functions (Lepton)")] = "n/a";
feature_count_[std::string("Scripted functions (Tcl)")] = 0;
feature_paper_map_[std::string("Scripted functions (Tcl)")] = "n/a";

View File

@ -44,7 +44,7 @@ int colvarparams::param_exists(std::string const &param_name)
if (param_map.count(param_name) > 0) { if (param_map.count(param_name) > 0) {
return COLVARS_OK; return COLVARS_OK;
} }
return INPUT_ERROR; return COLVARS_INPUT_ERROR;
} }
@ -75,7 +75,7 @@ void const *colvarparams::get_param_ptr(std::string const &param_name)
if (param_map.count(param_name) > 0) { if (param_map.count(param_name) > 0) {
return param_map[param_name]; return param_map[param_name];
} }
cvm::error("Error: parameter \""+param_name+"\" not found.\n", INPUT_ERROR); cvm::error("Error: parameter \""+param_name+"\" not found.\n", COLVARS_INPUT_ERROR);
return NULL; return NULL;
} }
@ -86,7 +86,7 @@ void const *colvarparams::get_param_grad_ptr(std::string const &param_name)
return param_grad_map[param_name]; return param_grad_map[param_name];
} }
cvm::error("Error: gradient of parameter \""+param_name+"\" not found.\n", cvm::error("Error: gradient of parameter \""+param_name+"\" not found.\n",
INPUT_ERROR); COLVARS_INPUT_ERROR);
return NULL; return NULL;
} }
@ -100,12 +100,12 @@ cvm::real colvarparams::get_param(std::string const &param_name)
int colvarparams::set_param(std::string const &param_name, int colvarparams::set_param(std::string const &param_name,
void const *new_value) void const * /* new_value */)
{ {
if (param_map.count(param_name) > 0) { if (param_map.count(param_name) > 0) {
return cvm::error("Error: parameter \""+param_name+"\" cannot be " return cvm::error("Error: parameter \""+param_name+"\" cannot be "
"modified.\n", COLVARS_NOT_IMPLEMENTED); "modified.\n", COLVARS_NOT_IMPLEMENTED);
} }
return cvm::error("Error: parameter \""+param_name+"\" not found.\n", return cvm::error("Error: parameter \""+param_name+"\" not found.\n",
INPUT_ERROR); COLVARS_INPUT_ERROR);
} }

View File

@ -33,12 +33,14 @@ namespace {
colvarparse::colvarparse() colvarparse::colvarparse()
: keyword_delimiters_left("\n"+std::string(white_space)+"}"),
keyword_delimiters_right("\n"+std::string(white_space)+"{")
{ {
init(); colvarparse::clear();
} }
void colvarparse::init() void colvarparse::clear()
{ {
config_string.clear(); config_string.clear();
clear_keyword_registry(); clear_keyword_registry();
@ -46,15 +48,17 @@ void colvarparse::init()
colvarparse::colvarparse(const std::string& conf) colvarparse::colvarparse(const std::string& conf)
: keyword_delimiters_left("\n"+std::string(white_space)+"}"),
keyword_delimiters_right("\n"+std::string(white_space)+"{")
{ {
init(conf); colvarparse::set_string(conf);
} }
void colvarparse::init(std::string const &conf) void colvarparse::set_string(std::string const &conf)
{ {
if (! config_string.size()) { if (! config_string.size()) {
init(); colvarparse::clear();
config_string = conf; config_string = conf;
} }
} }
@ -62,7 +66,7 @@ void colvarparse::init(std::string const &conf)
colvarparse::~colvarparse() colvarparse::~colvarparse()
{ {
init(); colvarparse::clear();
} }
@ -86,7 +90,7 @@ bool colvarparse::get_key_string_value(std::string const &conf,
if (found_count > 1) { if (found_count > 1) {
cvm::error("Error: found more than one instance of \""+ cvm::error("Error: found more than one instance of \""+
std::string(key)+"\".\n", INPUT_ERROR); std::string(key)+"\".\n", COLVARS_INPUT_ERROR);
} }
return b_found_any; return b_found_any;
@ -153,10 +157,10 @@ void colvarparse::error_key_required(std::string const &key_str,
} }
if (parse_mode & parse_restart) { if (parse_mode & parse_restart) {
cvm::error("Error: keyword \""+key_str+ cvm::error("Error: keyword \""+key_str+
"\" is missing from the restart.\n", INPUT_ERROR); "\" is missing from the restart.\n", COLVARS_INPUT_ERROR);
} else { } else {
cvm::error("Error: keyword \""+key_str+ cvm::error("Error: keyword \""+key_str+
"\" is required.\n", INPUT_ERROR); "\" is required.\n", COLVARS_INPUT_ERROR);
} }
} }
@ -178,13 +182,13 @@ int colvarparse::_get_keyval_scalar_value_(std::string const &key_str,
if (value_count == 0) { if (value_count == 0) {
return cvm::error("Error: in parsing \""+ return cvm::error("Error: in parsing \""+
key_str+"\".\n", INPUT_ERROR); key_str+"\".\n", COLVARS_INPUT_ERROR);
} }
if (value_count > 1) { if (value_count > 1) {
return cvm::error("Error: multiple values " return cvm::error("Error: multiple values "
"are not allowed for keyword \""+ "are not allowed for keyword \""+
key_str+"\".\n", INPUT_ERROR); key_str+"\".\n", COLVARS_INPUT_ERROR);
} }
return COLVARS_OK; return COLVARS_OK;
@ -207,7 +211,7 @@ int colvarparse::_get_keyval_scalar_value_(std::string const &key_str,
set_bool(reinterpret_cast<void *>(&value), false); set_bool(reinterpret_cast<void *>(&value), false);
} else { } else {
return cvm::error("Error: boolean values only are allowed " return cvm::error("Error: boolean values only are allowed "
"for \""+key_str+"\".\n", INPUT_ERROR); "for \""+key_str+"\".\n", COLVARS_INPUT_ERROR);
} }
return COLVARS_OK; return COLVARS_OK;
} }
@ -219,7 +223,7 @@ int colvarparse::_get_keyval_scalar_novalue_(std::string const &key_str,
Parse_Mode const & /* parse_mode */) Parse_Mode const & /* parse_mode */)
{ {
return cvm::error("Error: improper or missing value " return cvm::error("Error: improper or missing value "
"for \""+key_str+"\".\n", INPUT_ERROR); "for \""+key_str+"\".\n", COLVARS_INPUT_ERROR);
} }
template<> template<>
@ -318,7 +322,7 @@ bool colvarparse::_get_keyval_vector_(std::string const &conf,
values[i] = x; values[i] = x;
} else { } else {
cvm::error("Error: in parsing \""+ cvm::error("Error: in parsing \""+
key_str+"\".\n", INPUT_ERROR); key_str+"\".\n", COLVARS_INPUT_ERROR);
} }
} }
} }
@ -329,13 +333,13 @@ bool colvarparse::_get_keyval_vector_(std::string const &conf,
if (b_found_any) { if (b_found_any) {
cvm::error("Error: improper or missing values for \""+ cvm::error("Error: improper or missing values for \""+
key_str+"\".\n", INPUT_ERROR); key_str+"\".\n", COLVARS_INPUT_ERROR);
} else { } else {
if ((values.size() > 0) && (values.size() != def_values.size())) { if ((values.size() > 0) && (values.size() != def_values.size())) {
cvm::error("Error: the number of default values for \""+ cvm::error("Error: the number of default values for \""+
key_str+"\" is different from the number of " key_str+"\" is different from the number of "
"current values.\n", BUG_ERROR); "current values.\n", COLVARS_BUG_ERROR);
} }
if (parse_mode & parse_required) { if (parse_mode & parse_required) {
@ -621,8 +625,8 @@ int colvarparse::check_keywords(std::string &conf, char const *key)
} }
if (!found_keyword) { if (!found_keyword) {
cvm::error("Error: keyword \""+uk+"\" is not supported, " cvm::error("Error: keyword \""+uk+"\" is not supported, "
"or not recognized in this context.\n", INPUT_ERROR); "or not recognized in this context.\n", COLVARS_INPUT_ERROR);
return INPUT_ERROR; return COLVARS_INPUT_ERROR;
} }
} }
@ -699,18 +703,26 @@ bool colvarparse::key_lookup(std::string const &conf,
bool b_isolated_left = true, b_isolated_right = true; bool b_isolated_left = true, b_isolated_right = true;
if (pos > 0) { if (pos > 0) {
if ( std::string("\n"+std::string(white_space)+ if (keyword_delimiters_left.find(conf[pos-1]) == std::string::npos) {
"}").find(conf[pos-1]) ==
std::string::npos ) {
// none of the valid delimiting characters is on the left of key // none of the valid delimiting characters is on the left of key
b_isolated_left = false; b_isolated_left = false;
} else {
size_t const pl = conf_lower.rfind("\n", pos);
size_t const line_begin = (pl == std::string::npos) ? 0 : pl+1;
size_t const pchar =
conf_lower.find_first_not_of(keyword_delimiters_left, line_begin);
size_t const first_text = (pchar == std::string::npos) ? pos : pchar;
if (first_text < pos) {
// There are some non-delimiting characters to the left of the
// keyword on the same line
b_isolated_left = false;
}
} }
} }
if (pos < conf.size()-key.size()-1) { if (pos < conf.size()-key.size()-1) {
if ( std::string("\n"+std::string(white_space)+ if (keyword_delimiters_right.find(conf[pos+key.size()]) ==
"{").find(conf[pos+key.size()]) == std::string::npos) {
std::string::npos ) {
// none of the valid delimiting characters is on the right of key // none of the valid delimiting characters is on the right of key
b_isolated_right = false; b_isolated_right = false;
} }
@ -739,7 +751,7 @@ bool colvarparse::key_lookup(std::string const &conf,
// get the remainder of the line // get the remainder of the line
size_t pl = conf.rfind("\n", pos); size_t pl = conf.rfind("\n", pos);
size_t line_begin = (pl == std::string::npos) ? 0 : pos; size_t line_begin = (pl == std::string::npos) ? 0 : pl+1;
size_t nl = conf.find("\n", pos); size_t nl = conf.find("\n", pos);
size_t line_end = (nl == std::string::npos) ? conf.size() : nl; size_t line_end = (nl == std::string::npos) ? conf.size() : nl;
std::string line(conf, line_begin, (line_end-line_begin)); std::string line(conf, line_begin, (line_end-line_begin));
@ -792,7 +804,7 @@ bool colvarparse::key_lookup(std::string const &conf,
cvm::error("Parse error: reached the end while " cvm::error("Parse error: reached the end while "
"looking for closing brace; until now " "looking for closing brace; until now "
"the following was parsed: \"\n"+ "the following was parsed: \"\n"+
line+"\".\n", INPUT_ERROR); line+"\".\n", COLVARS_INPUT_ERROR);
return false; return false;
} }
@ -810,7 +822,7 @@ bool colvarparse::key_lookup(std::string const &conf,
} }
if (brace_count < 0) { if (brace_count < 0) {
cvm::error("Error: found closing brace without opening brace.\n", INPUT_ERROR); cvm::error("Error: found closing brace without opening brace.\n", COLVARS_INPUT_ERROR);
} }
} }
@ -920,7 +932,7 @@ int colvarparse::check_braces(std::string const &conf,
if (conf[brace] == '}') brace_count--; if (conf[brace] == '}') brace_count--;
brace++; brace++;
} }
return (brace_count != 0) ? INPUT_ERROR : COLVARS_OK; return (brace_count != 0) ? COLVARS_INPUT_ERROR : COLVARS_OK;
} }

View File

@ -34,10 +34,10 @@ public:
colvarparse(const std::string& conf); colvarparse(const std::string& conf);
/// Set the object ready to parse a new configuration string /// Set the object ready to parse a new configuration string
void init(); void clear();
/// Set a new config string for this object /// Set a new config string for this object
void init(std::string const &conf); void set_string(std::string const &conf);
/// Default destructor /// Default destructor
virtual ~colvarparse(); virtual ~colvarparse();
@ -68,7 +68,7 @@ public:
/// The call is being executed from a read_restart() function /// The call is being executed from a read_restart() function
parse_restart = (1<<18), parse_restart = (1<<18),
/// Alias for old default behavior (should be phased out) /// Alias for old default behavior (should be phased out)
parse_normal = (1<<2) | (1<<1) | (1<<17), parse_normal = (1<<1) | (1<<2) | (1<<17),
/// Settings for a deprecated keyword /// Settings for a deprecated keyword
parse_deprecated = (1<<1) | (1<<3) | (1<<17) parse_deprecated = (1<<1) | (1<<3) | (1<<17)
}; };
@ -333,6 +333,12 @@ public:
protected: protected:
/// Characters allowed immediately to the left of a kewyord
std::string const keyword_delimiters_left;
/// Characters allowed immediately to the right of a kewyord
std::string const keyword_delimiters_right;
/// \brief List of legal keywords for this object: this is updated /// \brief List of legal keywords for this object: this is updated
/// by each call to colvarparse::get_keyval() or /// by each call to colvarparse::get_keyval() or
/// colvarparse::key_lookup() /// colvarparse::key_lookup()

View File

@ -7,9 +7,14 @@
// If you wish to distribute your changes, please submit them to the // If you wish to distribute your changes, please submit them to the
// Colvars repository at GitHub. // Colvars repository at GitHub.
// Using access() to check if a file exists (until we can assume C++14/17)
#if !defined(WIN32) || defined(__CYGWIN__) #if !defined(WIN32) || defined(__CYGWIN__)
#include <unistd.h> #include <unistd.h>
#endif #endif
#if defined(WIN32)
#include <io.h>
#endif
#include <cerrno> #include <cerrno>
#include <sstream> #include <sstream>
@ -34,6 +39,9 @@ colvarproxy_system::colvarproxy_system()
kcal_mol_value = 0.0; kcal_mol_value = 0.0;
boundaries_type = boundaries_unsupported; boundaries_type = boundaries_unsupported;
total_force_requested = false; total_force_requested = false;
indirect_lambda_biasing_force = 0.0;
cached_alch_lambda_changed = false;
cached_alch_lambda = -1.0;
reset_pbc_lattice(); reset_pbc_lattice();
} }
@ -117,7 +125,7 @@ void colvarproxy_system::update_pbc_lattice()
if (boundaries_type == boundaries_unsupported || if (boundaries_type == boundaries_unsupported ||
boundaries_type == boundaries_non_periodic) { boundaries_type == boundaries_non_periodic) {
cvm::error("Error: setting PBC lattice with unsupported boundaries.\n", cvm::error("Error: setting PBC lattice with unsupported boundaries.\n",
BUG_ERROR); COLVARS_BUG_ERROR);
return; return;
} }
@ -152,7 +160,7 @@ cvm::rvector colvarproxy_system::position_distance(cvm::atom_pos const &pos1,
const const
{ {
if (boundaries_type == boundaries_unsupported) { if (boundaries_type == boundaries_unsupported) {
cvm::error("Error: unsupported boundary conditions.\n", INPUT_ERROR); cvm::error("Error: unsupported boundary conditions.\n", COLVARS_INPUT_ERROR);
} }
cvm::rvector diff = (pos2 - pos1); cvm::rvector diff = (pos2 - pos1);
@ -182,23 +190,44 @@ int colvarproxy_system::get_molid(int &)
} }
int colvarproxy_system::get_alch_lambda(cvm::real* lambda) int colvarproxy_system::get_alch_lambda(cvm::real * /* lambda */)
{ {
return cvm::error("Error in get_alch_lambda: alchemical lambda dynamics is not supported by this build.", return cvm::error("Error in get_alch_lambda: alchemical lambda dynamics is not supported by this build.",
COLVARS_NOT_IMPLEMENTED); COLVARS_NOT_IMPLEMENTED);
} }
int colvarproxy_system::set_alch_lambda(cvm::real* lambda) void colvarproxy_system::set_alch_lambda(cvm::real lambda)
{
cached_alch_lambda = lambda;
cached_alch_lambda_changed = true;
}
int colvarproxy_system::send_alch_lambda()
{ {
return cvm::error("Error in set_alch_lambda: alchemical lambda dynamics is not supported by this build.", return cvm::error("Error in set_alch_lambda: alchemical lambda dynamics is not supported by this build.",
COLVARS_NOT_IMPLEMENTED); COLVARS_NOT_IMPLEMENTED);
} }
int colvarproxy_system::get_dE_dLambda(cvm::real* force) int colvarproxy_system::get_dE_dlambda(cvm::real * /* force */)
{ {
return cvm::error("Error in get_dE_dLambda: alchemical lambda dynamics is not supported by this build.", return cvm::error("Error in get_dE_dlambda: alchemical lambda dynamics is not supported by this build.",
COLVARS_NOT_IMPLEMENTED);
}
int colvarproxy_system::apply_force_dE_dlambda(cvm::real* /* force */)
{
return cvm::error("Error in apply_force_dE_dlambda: function is not implemented by this build.",
COLVARS_NOT_IMPLEMENTED);
}
int colvarproxy_system::get_d2E_dlambda2(cvm::real*)
{
return cvm::error("Error in get_d2E_dlambda2: function is not implemented by this build.",
COLVARS_NOT_IMPLEMENTED); COLVARS_NOT_IMPLEMENTED);
} }
@ -278,7 +307,7 @@ void colvarproxy_atoms::clear_atom(int index)
{ {
if (((size_t) index) >= atoms_ids.size()) { if (((size_t) index) >= atoms_ids.size()) {
cvm::error("Error: trying to disable an atom that was not previously requested.\n", cvm::error("Error: trying to disable an atom that was not previously requested.\n",
INPUT_ERROR); COLVARS_INPUT_ERROR);
} }
if (atoms_ncopies[index] > 0) { if (atoms_ncopies[index] > 0) {
atoms_ncopies[index] -= 1; atoms_ncopies[index] -= 1;
@ -396,7 +425,7 @@ void colvarproxy_atom_groups::clear_atom_group(int index)
if (((size_t) index) >= atom_groups_ids.size()) { if (((size_t) index) >= atom_groups_ids.size()) {
cvm::error("Error: trying to disable an atom group " cvm::error("Error: trying to disable an atom group "
"that was not previously requested.\n", "that was not previously requested.\n",
INPUT_ERROR); COLVARS_INPUT_ERROR);
} }
if (atom_groups_ncopies[index] > 0) { if (atom_groups_ncopies[index] > 0) {
atom_groups_ncopies[index] -= 1; atom_groups_ncopies[index] -= 1;
@ -424,7 +453,7 @@ colvarproxy_smp::colvarproxy_smp()
b_smp_active = true; // May be disabled by user option b_smp_active = true; // May be disabled by user option
omp_lock_state = NULL; omp_lock_state = NULL;
#if defined(_OPENMP) #if defined(_OPENMP)
if (smp_thread_id() == 0) { if (omp_get_thread_num() == 0) {
omp_lock_state = reinterpret_cast<void *>(new omp_lock_t); omp_lock_state = reinterpret_cast<void *>(new omp_lock_t);
omp_init_lock(reinterpret_cast<omp_lock_t *>(omp_lock_state)); omp_init_lock(reinterpret_cast<omp_lock_t *>(omp_lock_state));
} }
@ -435,7 +464,7 @@ colvarproxy_smp::colvarproxy_smp()
colvarproxy_smp::~colvarproxy_smp() colvarproxy_smp::~colvarproxy_smp()
{ {
#if defined(_OPENMP) #if defined(_OPENMP)
if (smp_thread_id() == 0) { if (omp_get_thread_num() == 0) {
if (omp_lock_state) { if (omp_lock_state) {
delete reinterpret_cast<omp_lock_t *>(omp_lock_state); delete reinterpret_cast<omp_lock_t *>(omp_lock_state);
} }
@ -586,12 +615,17 @@ int colvarproxy_smp::smp_unlock()
colvarproxy_script::colvarproxy_script() colvarproxy_script::colvarproxy_script()
{ {
script = NULL; script = NULL;
force_script_defined = false;
have_scripts = false; have_scripts = false;
} }
colvarproxy_script::~colvarproxy_script() {} colvarproxy_script::~colvarproxy_script()
{
if (script != NULL) {
delete script;
script = NULL;
}
}
int colvarproxy_script::run_force_callback() int colvarproxy_script::run_force_callback()
@ -639,10 +673,35 @@ int colvarproxy_io::set_frame(long int)
} }
int colvarproxy_io::backup_file(char const * /* filename */) int colvarproxy_io::backup_file(char const *filename)
{ {
// TODO implement this using rename_file() // Simplified version of NAMD_file_exists()
return COLVARS_NOT_IMPLEMENTED; int exit_code;
do {
#if defined(WIN32) && !defined(__CYGWIN__)
// We could use _access_s here, but it is probably too new
exit_code = _access(filename, 00);
#else
exit_code = access(filename, F_OK);
#endif
} while ((exit_code != 0) && (errno == EINTR));
if (exit_code != 0) {
if (errno == ENOENT) {
// File does not exist
return COLVARS_OK;
} else {
return cvm::error("Unknown error while checking if file \""+
std::string(filename)+"\" exists.\n", COLVARS_ERROR);
}
}
// The file exists, then rename it
if (std::string(filename).rfind(std::string(".colvars.state")) !=
std::string::npos) {
return rename_file(filename, (std::string(filename)+".old").c_str());
} else {
return rename_file(filename, (std::string(filename)+".BAK").c_str());
}
} }
@ -658,7 +717,7 @@ int colvarproxy_io::remove_file(char const *filename)
while ((rename_exit_code = std::rename(filename, while ((rename_exit_code = std::rename(filename,
renamed_file.c_str())) != 0) { renamed_file.c_str())) != 0) {
if (errno == EINTR) continue; if (errno == EINTR) continue;
error_code |= FILE_ERROR; error_code |= COLVARS_FILE_ERROR;
break; break;
} }
// Ask to remove filename.old, but ignore any errors raised // Ask to remove filename.old, but ignore any errors raised
@ -666,7 +725,7 @@ int colvarproxy_io::remove_file(char const *filename)
#else #else
if (std::remove(filename)) { if (std::remove(filename)) {
if (errno != ENOENT) { if (errno != ENOENT) {
error_code |= FILE_ERROR; error_code |= COLVARS_FILE_ERROR;
} }
} }
#endif #endif
@ -692,7 +751,7 @@ int colvarproxy_io::rename_file(char const *filename, char const *newfilename)
// Call log() instead of error to allow the next try // Call log() instead of error to allow the next try
cvm::log("Error: in renaming file \""+std::string(filename)+"\" to \""+ cvm::log("Error: in renaming file \""+std::string(filename)+"\" to \""+
std::string(newfilename)+"\".\n."); std::string(newfilename)+"\".\n.");
error_code |= FILE_ERROR; error_code |= COLVARS_FILE_ERROR;
if (errno == EXDEV) continue; if (errno == EXDEV) continue;
break; break;
} }
@ -707,12 +766,18 @@ colvarproxy::colvarproxy()
b_simulation_running = true; b_simulation_running = true;
b_simulation_continuing = false; b_simulation_continuing = false;
b_delete_requested = false; b_delete_requested = false;
version_int = -1;
features_hash = 0;
} }
colvarproxy::~colvarproxy() colvarproxy::~colvarproxy()
{ {
close_files(); close_files();
if (colvars != NULL) {
delete colvars;
colvars = NULL;
}
} }
@ -782,6 +847,10 @@ int colvarproxy::end_of_step()
compute_rms_volmaps_applied_force(); compute_rms_volmaps_applied_force();
compute_max_volmaps_applied_force(); compute_max_volmaps_applied_force();
if (cached_alch_lambda_changed) {
send_alch_lambda();
cached_alch_lambda_changed = false;
}
return COLVARS_OK; return COLVARS_OK;
} }
@ -798,6 +867,82 @@ int colvarproxy::post_run()
} }
void colvarproxy::print_input_atomic_data()
{
cvm::log(cvm::line_marker);
cvm::log("Step "+cvm::to_str(cvm::step_absolute())+", "+
"atoms_ids = "+cvm::to_str(atoms_ids)+"\n");
cvm::log("Step "+cvm::to_str(cvm::step_absolute())+", "+
"atoms_ncopies = "+cvm::to_str(atoms_ncopies)+"\n");
cvm::log("Step "+cvm::to_str(cvm::step_absolute())+", "+
"atoms_masses = "+cvm::to_str(atoms_masses)+"\n");
cvm::log("Step "+cvm::to_str(cvm::step_absolute())+", "+
"atoms_charges = "+cvm::to_str(atoms_charges)+"\n");
cvm::log("Step "+cvm::to_str(cvm::step_absolute())+", "+
"atoms_positions = "+cvm::to_str(atoms_positions,
cvm::cv_width,
cvm::cv_prec)+"\n");
cvm::log("Step "+cvm::to_str(cvm::step_absolute())+", "+
"atoms_total_forces = "+cvm::to_str(atoms_total_forces,
cvm::cv_width,
cvm::cv_prec)+"\n");
cvm::log(cvm::line_marker);
cvm::log("Step "+cvm::to_str(cvm::step_absolute())+", "+
"atom_groups_ids = "+cvm::to_str(atom_groups_ids)+"\n");
cvm::log("Step "+cvm::to_str(cvm::step_absolute())+", "+
"atom_groups_ncopies = "+cvm::to_str(atom_groups_ncopies)+"\n");
cvm::log("Step "+cvm::to_str(cvm::step_absolute())+", "+
"atom_groups_masses = "+cvm::to_str(atom_groups_masses)+"\n");
cvm::log("Step "+cvm::to_str(cvm::step_absolute())+", "+
"atom_groups_charges = "+cvm::to_str(atom_groups_charges)+"\n");
cvm::log("Step "+cvm::to_str(cvm::step_absolute())+", "+
"atom_groups_coms = "+cvm::to_str(atom_groups_coms,
cvm::cv_width,
cvm::cv_prec)+"\n");
cvm::log("Step "+cvm::to_str(cvm::step_absolute())+", "+
"atom_groups_total_forces = "+cvm::to_str(atom_groups_total_forces,
cvm::cv_width,
cvm::cv_prec)+"\n");
cvm::log(cvm::line_marker);
cvm::log("Step "+cvm::to_str(cvm::step_absolute())+", "+
"volmaps_ids = "+cvm::to_str(volmaps_ids)+"\n");
cvm::log("Step "+cvm::to_str(cvm::step_absolute())+", "+
"volmaps_values = "+cvm::to_str(volmaps_values)+"\n");
cvm::log(cvm::line_marker);
}
void colvarproxy::print_output_atomic_data()
{
cvm::log(cvm::line_marker);
cvm::log("Step "+cvm::to_str(cvm::step_absolute())+", "+
"atoms_new_colvar_forces = "+cvm::to_str(atoms_new_colvar_forces,
colvarmodule::cv_width,
colvarmodule::cv_prec)+"\n");
cvm::log(cvm::line_marker);
cvm::log("Step "+cvm::to_str(cvm::step_absolute())+", "+
"atom_groups_new_colvar_forces = "+
cvm::to_str(atom_groups_new_colvar_forces,
colvarmodule::cv_width,
colvarmodule::cv_prec)+"\n");
cvm::log(cvm::line_marker);
cvm::log("Step "+cvm::to_str(cvm::step_absolute())+", "+
"volmaps_new_colvar_forces = "+
cvm::to_str(volmaps_new_colvar_forces)+"\n");
cvm::log(cvm::line_marker);
}
void colvarproxy::log(std::string const &message) void colvarproxy::log(std::string const &message)
{ {
fprintf(stdout, "colvars: %s", message.c_str()); fprintf(stdout, "colvars: %s", message.c_str());
@ -847,7 +992,7 @@ void colvarproxy::smp_stream_error()
{ {
cvm::error("Error: trying to access an output stream from a " cvm::error("Error: trying to access an output stream from a "
"multi-threaded region (bug). For a quick workaround, use " "multi-threaded region (bug). For a quick workaround, use "
"\"smp off\" in the Colvars config.\n", BUG_ERROR); "\"smp off\" in the Colvars config.\n", COLVARS_BUG_ERROR);
} }
@ -867,7 +1012,7 @@ std::ostream * colvarproxy::output_stream(std::string const &output_name,
std::ofstream *osf = new std::ofstream(output_name.c_str(), mode); std::ofstream *osf = new std::ofstream(output_name.c_str(), mode);
if (!osf->is_open()) { if (!osf->is_open()) {
cvm::error("Error: cannot write to file/channel \""+output_name+"\".\n", cvm::error("Error: cannot write to file/channel \""+output_name+"\".\n",
FILE_ERROR); COLVARS_FILE_ERROR);
return NULL; return NULL;
} }
output_stream_names.push_back(output_name); output_stream_names.push_back(output_name);
@ -907,7 +1052,7 @@ int colvarproxy::flush_output_stream(std::ostream *os)
} }
} }
return cvm::error("Error: trying to flush an output file/channel " return cvm::error("Error: trying to flush an output file/channel "
"that wasn't open.\n", BUG_ERROR); "that wasn't open.\n", COLVARS_BUG_ERROR);
} }
@ -941,5 +1086,5 @@ int colvarproxy::close_output_stream(std::string const &output_name)
} }
} }
return cvm::error("Error: trying to close an output file/channel " return cvm::error("Error: trying to close an output file/channel "
"that wasn't open.\n", BUG_ERROR); "that wasn't open.\n", COLVARS_BUG_ERROR);
} }

View File

@ -135,13 +135,41 @@ public:
/// Get value of alchemical lambda parameter from back-end (if available) /// Get value of alchemical lambda parameter from back-end (if available)
virtual int get_alch_lambda(cvm::real* lambda); virtual int get_alch_lambda(cvm::real* lambda);
/// Set value of alchemical lambda parameter in back-end (if available) /// Set value of alchemical lambda parameter to be sent to back-end at end of timestep
virtual int set_alch_lambda(cvm::real* lambda); void set_alch_lambda(cvm::real lambda);
/// Send cached value of alchemical lambda parameter to back-end (if available)
virtual int send_alch_lambda();
/// Get energy derivative with respect to lambda (if available) /// Get energy derivative with respect to lambda (if available)
virtual int get_dE_dLambda(cvm::real* force); virtual int get_dE_dlambda(cvm::real* dE_dlambda);
/// Apply a scalar force on dE_dlambda (back-end distributes it onto atoms)
virtual int apply_force_dE_dlambda(cvm::real* force);
/// Get energy second derivative with respect to lambda (if available)
virtual int get_d2E_dlambda2(cvm::real* d2E_dlambda2);
/// Force to be applied onto alch. lambda, propagated from biasing forces on dE_dlambda
cvm::real indirect_lambda_biasing_force;
/// Get weight factor from accelMD
virtual cvm::real get_accelMD_factor() const {
cvm::error("Error: accessing the reweighting factor of accelerated MD "
"is not yet implemented in the MD engine.\n",
COLVARS_NOT_IMPLEMENTED);
return 1.0;
}
virtual bool accelMD_enabled() const {
return false;
}
protected: protected:
/// Next value of lambda to be sent to back-end
cvm::real cached_alch_lambda;
/// Whether lambda has been set and needs to be updated in backend
bool cached_alch_lambda_changed;
/// Whether the total forces have been requested /// Whether the total forces have been requested
bool total_force_requested; bool total_force_requested;
@ -652,9 +680,6 @@ public:
/// (does not need to be allocated in a new interface) /// (does not need to be allocated in a new interface)
colvarscript *script; colvarscript *script;
/// is a user force script defined?
bool force_script_defined;
/// Do we have a scripting interface? /// Do we have a scripting interface?
bool have_scripts; bool have_scripts;
@ -702,7 +727,7 @@ public:
} }
/// Remove the given file (on Windows only, rename to filename.old) /// Remove the given file (on Windows only, rename to filename.old)
int remove_file(char const *filename); virtual int remove_file(char const *filename);
/// Remove the given file (on Windows only, rename to filename.old) /// Remove the given file (on Windows only, rename to filename.old)
inline int remove_file(std::string const &filename) inline int remove_file(std::string const &filename)
@ -711,7 +736,7 @@ public:
} }
/// Rename the given file /// Rename the given file
int rename_file(char const *filename, char const *newfilename); virtual int rename_file(char const *filename, char const *newfilename);
/// Rename the given file /// Rename the given file
inline int rename_file(std::string const &filename, inline int rename_file(std::string const &filename,
@ -779,7 +804,6 @@ protected:
/// \brief Interface between the collective variables module and /// \brief Interface between the collective variables module and
/// the simulation or analysis program (NAMD, VMD, LAMMPS...). /// the simulation or analysis program (NAMD, VMD, LAMMPS...).
/// This is the base class: each interfaced program is supported by a derived class. /// This is the base class: each interfaced program is supported by a derived class.
/// Only pure virtual functions ("= 0") must be reimplemented to ensure baseline functionality.
class colvarproxy class colvarproxy
: public colvarproxy_system, : public colvarproxy_system,
public colvarproxy_atoms, public colvarproxy_atoms,
@ -864,6 +888,12 @@ public:
/// Called at the end of a simulation segment (i.e. "run" command) /// Called at the end of a simulation segment (i.e. "run" command)
int post_run(); int post_run();
/// Print a full list of all input atomic arrays for debug purposes
void print_input_atomic_data();
/// Print a full list of all applied forces for debug purposes
void print_output_atomic_data();
/// Convert a version string "YYYY-MM-DD" into an integer /// Convert a version string "YYYY-MM-DD" into an integer
int get_version_from_string(char const *version_string); int get_version_from_string(char const *version_string);
@ -910,6 +940,9 @@ protected:
/// Integer representing the version string (allows comparisons) /// Integer representing the version string (allows comparisons)
int version_int; int version_int;
/// Track which features have been acknowledged during the last run
size_t features_hash;
/// Raise when the output stream functions are used on threads other than 0 /// Raise when the output stream functions are used on threads other than 0
void smp_stream_error(); void smp_stream_error();

View File

@ -9,23 +9,22 @@
#include <sstream> #include <sstream>
#if defined(NAMD_TCL) || defined(VMDTCL)
#define COLVARS_TCL
#endif
#ifdef COLVARS_TCL
#include <tcl.h>
#endif
#include "colvarmodule.h" #include "colvarmodule.h"
#include "colvarproxy.h" #include "colvarproxy.h"
#include "colvarproxy_tcl.h" #include "colvarproxy_tcl.h"
#include "colvaratoms.h" #include "colvaratoms.h"
#ifdef COLVARS_TCL
#include <tcl.h>
#endif
colvarproxy_tcl::colvarproxy_tcl() colvarproxy_tcl::colvarproxy_tcl()
{ {
#ifdef COLVARS_TCL
tcl_interp_ = NULL; tcl_interp_ = NULL;
#endif
} }
@ -36,8 +35,18 @@ colvarproxy_tcl::~colvarproxy_tcl()
void colvarproxy_tcl::init_tcl_pointers() void colvarproxy_tcl::init_tcl_pointers()
{ {
cvm::error("Error: Tcl support is not available in this build.\n", // This is overloaded by NAMD and VMD proxies to use the local interpreters
COLVARS_NOT_IMPLEMENTED); #if defined(COLVARS_TCL)
if (tcl_interp_ == NULL) {
// Allocate a dedicated Tcl interpreter for Colvars
std::cout << "colvars: Allocating Tcl interpreter." << std::endl;
set_tcl_interp(Tcl_CreateInterp());
} else {
std::cerr << "Error: init_tcl_pointers called with non-NULL tcl_interp_" << std::endl;
}
#else
std::cerr << "Error: Tcl support is not available in this build." << std::endl;
#endif
} }
@ -46,22 +55,61 @@ char const *colvarproxy_tcl::tcl_get_str(void *obj)
#if defined(COLVARS_TCL) #if defined(COLVARS_TCL)
return Tcl_GetString(reinterpret_cast<Tcl_Obj *>(obj)); return Tcl_GetString(reinterpret_cast<Tcl_Obj *>(obj));
#else #else
(void) obj;
return NULL; return NULL;
#endif #endif
} }
int colvarproxy_tcl::tcl_run_script(std::string const &script)
{
#if defined(COLVARS_TCL)
Tcl_Interp *const interp = get_tcl_interp();
int err = Tcl_Eval(interp, script.c_str());
if (err != TCL_OK) {
cvm::log("Error while executing Tcl script:\n");
cvm::error(Tcl_GetStringResult(interp));
return COLVARS_ERROR;
}
return cvm::get_error();
#else
return COLVARS_NOT_IMPLEMENTED;
#endif
}
int colvarproxy_tcl::tcl_run_file(std::string const &fileName)
{
#if defined(COLVARS_TCL)
Tcl_Interp *const interp = get_tcl_interp();
int err = Tcl_EvalFile(interp, fileName.c_str());
if (err != TCL_OK) {
cvm::log("Error while executing Tcl script file" + fileName + ":\n");
cvm::error(Tcl_GetStringResult(interp));
return COLVARS_ERROR;
}
return cvm::get_error();
#else
return COLVARS_NOT_IMPLEMENTED;
#endif
}
int colvarproxy_tcl::tcl_run_force_callback() int colvarproxy_tcl::tcl_run_force_callback()
{ {
#if defined(COLVARS_TCL) #if defined(COLVARS_TCL)
Tcl_Interp *const tcl_interp = Tcl_Interp *const interp = get_tcl_interp();
reinterpret_cast<Tcl_Interp *>(get_tcl_interp()); if (Tcl_FindCommand(interp, "calc_colvar_forces", NULL, 0) == NULL) {
cvm::error("Error: Colvars force procedure calc_colvar_forces is not defined.\n");
return COLVARS_ERROR;
}
std::string cmd = std::string("calc_colvar_forces ") std::string cmd = std::string("calc_colvar_forces ")
+ cvm::to_str(cvm::step_absolute()); + cvm::to_str(cvm::step_absolute());
int err = Tcl_Eval(tcl_interp, cmd.c_str()); int err = Tcl_Eval(interp, cmd.c_str());
if (err != TCL_OK) { if (err != TCL_OK) {
cvm::log(std::string("Error while executing calc_colvar_forces:\n")); cvm::log("Error while executing calc_colvar_forces:\n");
cvm::error(Tcl_GetStringResult(tcl_interp)); cvm::error(Tcl_GetStringResult(interp));
return COLVARS_ERROR; return COLVARS_ERROR;
} }
return cvm::get_error(); return cvm::get_error();
@ -78,20 +126,25 @@ int colvarproxy_tcl::tcl_run_colvar_callback(
{ {
#if defined(COLVARS_TCL) #if defined(COLVARS_TCL)
Tcl_Interp *const tcl_interp = Tcl_Interp *const interp = get_tcl_interp();
reinterpret_cast<Tcl_Interp *>(get_tcl_interp());
size_t i; size_t i;
std::string cmd = std::string("calc_") + name; std::string cmd = std::string("calc_") + name;
if (Tcl_FindCommand(interp, cmd.c_str(), NULL, 0) == NULL) {
cvm::error("Error: scripted colvar procedure \"" + cmd + "\" is not defined.\n");
return COLVARS_ERROR;
}
for (i = 0; i < cvc_values.size(); i++) { for (i = 0; i < cvc_values.size(); i++) {
cmd += std::string(" {") + (*(cvc_values[i])).to_simple_string() + cmd += std::string(" {") + (*(cvc_values[i])).to_simple_string() +
std::string("}"); std::string("}");
} }
int err = Tcl_Eval(tcl_interp, cmd.c_str()); int err = Tcl_Eval(interp, cmd.c_str());
const char *result = Tcl_GetStringResult(tcl_interp); const char *result = Tcl_GetStringResult(interp);
if (err != TCL_OK) { if (err != TCL_OK) {
return cvm::error(std::string("Error while executing ") return cvm::error(std::string("Error while executing ")
+ cmd + std::string(":\n") + + cmd + std::string(":\n") +
std::string(Tcl_GetStringResult(tcl_interp)), std::string(Tcl_GetStringResult(interp)),
COLVARS_ERROR); COLVARS_ERROR);
} }
std::istringstream is(result); std::istringstream is(result);
@ -104,6 +157,9 @@ int colvarproxy_tcl::tcl_run_colvar_callback(
#else #else
(void) name;
(void) cvc_values;
(void) value;
return COLVARS_NOT_IMPLEMENTED; return COLVARS_NOT_IMPLEMENTED;
#endif #endif
@ -117,24 +173,29 @@ int colvarproxy_tcl::tcl_run_colvar_gradient_callback(
{ {
#if defined(COLVARS_TCL) #if defined(COLVARS_TCL)
Tcl_Interp *const tcl_interp = Tcl_Interp *const interp = get_tcl_interp();
reinterpret_cast<Tcl_Interp *>(get_tcl_interp());
size_t i; size_t i;
std::string cmd = std::string("calc_") + name + "_gradient"; std::string cmd = std::string("calc_") + name + "_gradient";
if (Tcl_FindCommand(interp, cmd.c_str(), NULL, 0) == NULL) {
cvm::error("Error: scripted colvar gradient procedure \"" + cmd + "\" is not defined.\n");
return COLVARS_ERROR;
}
for (i = 0; i < cvc_values.size(); i++) { for (i = 0; i < cvc_values.size(); i++) {
cmd += std::string(" {") + (*(cvc_values[i])).to_simple_string() + cmd += std::string(" {") + (*(cvc_values[i])).to_simple_string() +
std::string("}"); std::string("}");
} }
int err = Tcl_Eval(tcl_interp, cmd.c_str()); int err = Tcl_Eval(interp, cmd.c_str());
if (err != TCL_OK) { if (err != TCL_OK) {
return cvm::error(std::string("Error while executing ") return cvm::error(std::string("Error while executing ")
+ cmd + std::string(":\n") + + cmd + std::string(":\n") +
std::string(Tcl_GetStringResult(tcl_interp)), std::string(Tcl_GetStringResult(interp)),
COLVARS_ERROR); COLVARS_ERROR);
} }
Tcl_Obj **list; Tcl_Obj **list;
int n; int n;
Tcl_ListObjGetElements(tcl_interp, Tcl_GetObjResult(tcl_interp), Tcl_ListObjGetElements(interp, Tcl_GetObjResult(interp),
&n, &list); &n, &list);
if (n != int(gradient.size())) { if (n != int(gradient.size())) {
cvm::error("Error parsing list of gradient values from script: found " cvm::error("Error parsing list of gradient values from script: found "
@ -156,6 +217,9 @@ int colvarproxy_tcl::tcl_run_colvar_gradient_callback(
#else #else
(void) name;
(void) cvc_values;
(void) gradient;
return COLVARS_NOT_IMPLEMENTED; return COLVARS_NOT_IMPLEMENTED;
#endif #endif

View File

@ -10,6 +10,17 @@
#ifndef COLVARPROXY_TCL_H #ifndef COLVARPROXY_TCL_H
#define COLVARPROXY_TCL_H #define COLVARPROXY_TCL_H
#if defined(NAMD_TCL) || defined(VMDTCL)
#define COLVARS_TCL
#endif
#ifdef COLVARS_TCL
#include <tcl.h>
#else
// Allow for placeholders Tcl_Interp* variables
typedef void Tcl_Interp;
#endif
#include <vector> #include <vector>
@ -25,11 +36,21 @@ public:
virtual ~colvarproxy_tcl(); virtual ~colvarproxy_tcl();
/// Is Tcl available? (trigger initialization if needed) /// Is Tcl available? (trigger initialization if needed)
int tcl_available(); inline bool tcl_available() {
#if defined(COLVARS_TCL)
return true;
#else
return false;
#endif
}
/// Get a string representation of the Tcl object pointed to by obj /// Get a string representation of the Tcl object pointed to by obj
char const *tcl_get_str(void *obj); char const *tcl_get_str(void *obj);
int tcl_run_script(std::string const &script);
int tcl_run_file(std::string const &fileName);
/// Tcl implementation of run_force_callback() /// Tcl implementation of run_force_callback()
int tcl_run_force_callback(); int tcl_run_force_callback();
@ -46,25 +67,23 @@ public:
std::vector<cvm::matrix2d<cvm::real> > &gradient); std::vector<cvm::matrix2d<cvm::real> > &gradient);
/// Get a pointer to the Tcl interpreter /// Get a pointer to the Tcl interpreter
inline void *get_tcl_interp() inline Tcl_Interp *get_tcl_interp()
{ {
return tcl_interp_; return tcl_interp_;
} }
/// Set the pointer to the Tcl interpreter /// Set the pointer to the Tcl interpreter
inline void set_tcl_interp(void *interp) inline void set_tcl_interp(Tcl_Interp *interp)
{ {
tcl_interp_ = interp; tcl_interp_ = interp;
} }
protected:
/// Pointer to Tcl interpreter object
void *tcl_interp_;
/// Set Tcl pointers /// Set Tcl pointers
virtual void init_tcl_pointers(); virtual void init_tcl_pointers();
protected:
/// Pointer to Tcl interpreter object
Tcl_Interp *tcl_interp_;
}; };
#endif #endif

View File

@ -64,13 +64,13 @@ int colvarproxy_volmaps::check_volmap_by_name(const char * /* volmap_name */)
} }
int colvarproxy_volmaps::init_volmap_by_name(char const *volmap_name) int colvarproxy_volmaps::init_volmap_by_name(char const * /* volmap_name */)
{ {
return -1; return -1;
} }
int colvarproxy_volmaps::init_volmap_by_id(int volmap_id) int colvarproxy_volmaps::init_volmap_by_id(int /* volmap_id */)
{ {
return -1; return -1;
} }
@ -92,7 +92,7 @@ void colvarproxy_volmaps::clear_volmap(int index)
{ {
if (((size_t) index) >= volmaps_ids.size()) { if (((size_t) index) >= volmaps_ids.size()) {
cvm::error("Error: trying to unrequest a volumetric map that was not " cvm::error("Error: trying to unrequest a volumetric map that was not "
"previously requested.\n", INPUT_ERROR); "previously requested.\n", COLVARS_INPUT_ERROR);
} }
if (volmaps_ncopies[index] > 0) { if (volmaps_ncopies[index] > 0) {

View File

@ -1,3 +1,3 @@
#ifndef COLVARS_VERSION #ifndef COLVARS_VERSION
#define COLVARS_VERSION "2021-09-21" #define COLVARS_VERSION "2022-05-09"
#endif #endif

View File

@ -11,13 +11,6 @@
#include <cstring> #include <cstring>
#include <sstream> #include <sstream>
#if defined(NAMD_TCL) || defined(VMDTCL)
#define COLVARS_TCL
#endif
#ifdef COLVARS_TCL
#include <tcl.h>
#endif
#include "colvarproxy.h" #include "colvarproxy.h"
#include "colvardeps.h" #include "colvardeps.h"
#include "colvarscript.h" #include "colvarscript.h"
@ -38,20 +31,25 @@ extern "C" int tcl_run_colvarscript_command(ClientData clientData,
#endif #endif
colvarscript::colvarscript(colvarproxy *p) colvarscript::colvarscript(colvarproxy *p, colvarmodule *m)
: proxy_(p), : proxy_(p),
colvars(p->colvars), colvars(m)
proxy_error(0)
{ {
cmd_names = NULL; cmd_names = NULL;
init_commands(); init_commands();
#ifdef COLVARS_TCL #ifdef COLVARS_TCL
// must be called after constructing derived proxy class to allow for overloading
proxy()->init_tcl_pointers();
// TODO put this in backend functions so we don't have to delete // TODO put this in backend functions so we don't have to delete
Tcl_Interp *interp = reinterpret_cast<Tcl_Interp *>(proxy_->get_tcl_interp()); Tcl_Interp *const interp = proxy()->get_tcl_interp();
if (interp == NULL) {
cvm::error("Error: trying to construct colvarscript without a Tcl interpreter.\n");
return;
}
Tcl_DeleteCommand(interp, "cv"); Tcl_DeleteCommand(interp, "cv");
Tcl_CreateObjCommand(interp, "cv", tcl_run_colvarscript_command, Tcl_CreateObjCommand(interp, "cv", tcl_run_colvarscript_command,
(ClientData) this, (Tcl_CmdDeleteProc *) NULL); (ClientData) this, (Tcl_CmdDeleteProc *) NULL);
cvm::log("Redefining the Tcl \"cv\" command to the new script interface."); cvm::log("Redefining the Tcl \"cv\" command to the new script interface.\n");
#endif #endif
} }
@ -136,7 +134,7 @@ int colvarscript::init_command(colvarscript::command const &comm,
for (int iarg = 0; iarg < n_args_max; iarg++) { for (int iarg = 0; iarg < n_args_max; iarg++) {
if (! std::getline(is, line)) { if (! std::getline(is, line)) {
return cvm::error("Error: could not initialize help string for scripting " return cvm::error("Error: could not initialize help string for scripting "
"command \""+std::string(name)+"\".\n", BUG_ERROR); "command \""+std::string(name)+"\".\n", COLVARS_BUG_ERROR);
} }
cmd_arghelp[comm].push_back(line); cmd_arghelp[comm].push_back(line);
} }
@ -180,7 +178,7 @@ std::string colvarscript::get_cmd_prefix(colvarscript::Object_type t)
case use_bias: case use_bias:
return std::string("bias_"); break; return std::string("bias_"); break;
default: default:
cvm::error("Error: undefined colvarscript object type.", BUG_ERROR); cvm::error("Error: undefined colvarscript object type.", COLVARS_BUG_ERROR);
return std::string(""); return std::string("");
} }
} }
@ -194,7 +192,7 @@ char const *colvarscript::get_command_help(char const *cmd)
return cmd_help[c].c_str(); return cmd_help[c].c_str();
} }
cvm::error("Error: command "+std::string(cmd)+ cvm::error("Error: command "+std::string(cmd)+
" is not implemented.\n", INPUT_ERROR); " is not implemented.\n", COLVARS_INPUT_ERROR);
return NULL; return NULL;
} }
@ -206,7 +204,7 @@ char const *colvarscript::get_command_rethelp(char const *cmd)
return cmd_rethelp[c].c_str(); return cmd_rethelp[c].c_str();
} }
cvm::error("Error: command "+std::string(cmd)+ cvm::error("Error: command "+std::string(cmd)+
" is not implemented.\n", INPUT_ERROR); " is not implemented.\n", COLVARS_INPUT_ERROR);
return NULL; return NULL;
} }
@ -218,7 +216,7 @@ char const *colvarscript::get_command_arghelp(char const *cmd, int i)
return cmd_arghelp[c][i].c_str(); return cmd_arghelp[c][i].c_str();
} }
cvm::error("Error: command "+std::string(cmd)+ cvm::error("Error: command "+std::string(cmd)+
" is not implemented.\n", INPUT_ERROR); " is not implemented.\n", COLVARS_INPUT_ERROR);
return NULL; return NULL;
} }
@ -230,7 +228,7 @@ int colvarscript::get_command_n_args_min(char const *cmd)
return cmd_n_args_min[c]; return cmd_n_args_min[c];
} }
cvm::error("Error: command "+std::string(cmd)+ cvm::error("Error: command "+std::string(cmd)+
" is not implemented.\n", INPUT_ERROR); " is not implemented.\n", COLVARS_INPUT_ERROR);
return -1; return -1;
} }
@ -242,7 +240,7 @@ int colvarscript::get_command_n_args_max(char const *cmd)
return cmd_n_args_max[c]; return cmd_n_args_max[c];
} }
cvm::error("Error: command "+std::string(cmd)+ cvm::error("Error: command "+std::string(cmd)+
" is not implemented.\n", INPUT_ERROR); " is not implemented.\n", COLVARS_INPUT_ERROR);
return -1; return -1;
} }
@ -254,7 +252,7 @@ char const *colvarscript::get_command_full_help(char const *cmd)
return cmd_full_help[c].c_str(); return cmd_full_help[c].c_str();
} }
cvm::error("Error: command "+std::string(cmd)+ cvm::error("Error: command "+std::string(cmd)+
" is not implemented.\n", INPUT_ERROR); " is not implemented.\n", COLVARS_INPUT_ERROR);
return NULL; return NULL;
} }
@ -338,9 +336,8 @@ std::string colvarscript::get_command_cmdline_help(colvarscript::Object_type t,
return get_command_cmdline_syntax(t, c)+"\n\n"+ return get_command_cmdline_syntax(t, c)+"\n\n"+
get_command_full_help(cmd_names[c]); get_command_full_help(cmd_names[c]);
} }
cvm::error("Error: could not find scripting command \""+cmd+"\".", cvm::set_error_bits(COLVARS_INPUT_ERROR);
INPUT_ERROR); return std::string("Could not find scripting command \""+cmd+"\".");
return std::string("");
} }
@ -477,7 +474,7 @@ std::vector<std::string> colvarscript::obj_to_str_vector(unsigned char *obj)
i++; i++;
if (i >= str.length()) { if (i >= str.length()) {
cvm::error("Error: could not split the following string:\n"+ cvm::error("Error: could not split the following string:\n"+
str+"\n", INPUT_ERROR); str+"\n", COLVARS_INPUT_ERROR);
break; break;
} }
new_result.push_back(std::string("")); new_result.push_back(std::string(""));
@ -485,7 +482,7 @@ std::vector<std::string> colvarscript::obj_to_str_vector(unsigned char *obj)
new_result.back().append(1, str[i]); new_result.back().append(1, str[i]);
if (i >= str.length()) { if (i >= str.length()) {
cvm::error("Error: could not split the following string:\n"+ cvm::error("Error: could not split the following string:\n"+
str+"\n", INPUT_ERROR); str+"\n", COLVARS_INPUT_ERROR);
break; break;
} else { } else {
i++; i++;
@ -616,7 +613,7 @@ int run_colvarscript_command(int objc, unsigned char *const objv[])
colvarscript *script = cv ? cv->proxy->script : NULL; colvarscript *script = cv ? cv->proxy->script : NULL;
if (!script) { if (!script) {
cvm::error("Called run_colvarscript_command without a script object.\n", cvm::error("Called run_colvarscript_command without a script object.\n",
BUG_ERROR); COLVARS_BUG_ERROR);
return -1; return -1;
} }
int retval = script->run(objc, objv); int retval = script->run(objc, objv);
@ -644,13 +641,13 @@ int tcl_colvars_vmd_init(Tcl_Interp *interp, int molid);
#endif #endif
#if !defined(VMDTCL) && !defined(NAMD_TCL) #if !defined(VMDTCL) && !defined(NAMD_TCL)
// Initialize Colvars when loaded as a shared library into Tcl interpreter
extern "C" { extern "C" {
int Colvars_Init(Tcl_Interp *interp) { int Colvars_Init(Tcl_Interp *interp) {
colvarproxy *proxy = new colvarproxy(); colvarproxy *proxy = new colvarproxy();
colvarmodule *colvars = new colvarmodule(proxy); colvarmodule *colvars = new colvarmodule(proxy);
proxy->set_tcl_interp(reinterpret_cast<void *>(interp)); proxy->set_tcl_interp(interp);
proxy->colvars = colvars; proxy->colvars = colvars;
proxy->script = new colvarscript(proxy);
Tcl_CreateObjCommand(interp, "cv", tcl_run_colvarscript_command, Tcl_CreateObjCommand(interp, "cv", tcl_run_colvarscript_command,
(ClientData *) NULL, (Tcl_CmdDeleteProc *) NULL); (ClientData *) NULL, (Tcl_CmdDeleteProc *) NULL);
Tcl_EvalEx(interp, "package provide colvars", -1, 0); Tcl_EvalEx(interp, "package provide colvars", -1, 0);
@ -715,8 +712,7 @@ extern "C" int tcl_run_colvarscript_command(ClientData /* clientData */,
} }
colvarproxy *proxy = colvars->proxy; colvarproxy *proxy = colvars->proxy;
Tcl_Interp *interp = my_interp ? my_interp : Tcl_Interp *interp = my_interp ? my_interp : proxy->get_tcl_interp();
reinterpret_cast<Tcl_Interp *>(proxy->get_tcl_interp());
colvarscript *script = colvarscript_obj(); colvarscript *script = colvarscript_obj();
if (!script) { if (!script) {
char const *errstr = "Called tcl_run_colvarscript_command " char const *errstr = "Called tcl_run_colvarscript_command "
@ -744,8 +740,8 @@ extern "C" int tcl_run_colvarscript_command(ClientData /* clientData */,
Tcl_SetResult(interp, const_cast<char *>(result.c_str()), Tcl_SetResult(interp, const_cast<char *>(result.c_str()),
TCL_VOLATILE); TCL_VOLATILE);
if (proxy->delete_requested() || cvm::get_error_bit(FATAL_ERROR)) { if (proxy->delete_requested()) {
if (proxy->delete_requested() && !proxy->simulation_running()) { if (!proxy->simulation_running()) {
// Running in VMD // Running in VMD
Tcl_SetResult(interp, Tcl_SetResult(interp,
const_cast<char *>("Deleting Colvars module" const_cast<char *>("Deleting Colvars module"

View File

@ -38,14 +38,10 @@ public:
friend class colvarproxy; friend class colvarproxy;
colvarscript(colvarproxy *p); colvarscript(colvarproxy *p, colvarmodule *m);
~colvarscript(); ~colvarscript();
/// If an error is caught by the proxy through fatal_error(), this is set to
/// COLVARSCRIPT_ERROR
int proxy_error;
/// String representation of the result of a script call /// String representation of the result of a script call
std::string str_result_; std::string str_result_;

View File

@ -97,6 +97,11 @@ int cvscript_command_n_args_max(char const *c)
COLVARSCRIPT_OK) { \ COLVARSCRIPT_OK) { \
return COLVARSCRIPT_ERROR; \ return COLVARSCRIPT_ERROR; \
} \ } \
if (objc > 1) { \
/* Silence unused parameter warning */ \
(void) pobj; \
(void) objv[0]; \
} \
FN_BODY; \ FN_BODY; \
} }
#undef CVSCRIPT #undef CVSCRIPT

View File

@ -162,6 +162,14 @@ CVSCRIPT(cv_delete,
return script->proxy()->request_deletion(); return script->proxy()->request_deletion();
) )
CVSCRIPT(cv_featurereport,
"Return a summary of Colvars features used so far and their citations\n"
"report : string - Feature report and citations",
0, 0,
"",
return script->set_result_str(script->module()->feature_report());
)
CVSCRIPT(cv_frame, CVSCRIPT(cv_frame,
"Get or set current frame number (VMD only)\n" "Get or set current frame number (VMD only)\n"
"frame : integer - Frame number", "frame : integer - Frame number",
@ -226,9 +234,21 @@ CVSCRIPT(cv_getatomappliedforcesrms,
return COLVARS_OK; return COLVARS_OK;
) )
CVSCRIPT(cv_resetatomappliedforces,
"Reset forces applied by Colvars to atoms",
0, 0,
"",
size_t i;
std::vector<cvm::rvector> *f = script->proxy()->modify_atom_applied_forces();
for (i = 0; i < f->size(); i++) {
(*f)[i].reset();
}
return COLVARS_OK;
)
CVSCRIPT(cv_getatomids, CVSCRIPT(cv_getatomids,
"Get the list of indices of atoms used in Colvars\n" "Get the list of indices of atoms used in Colvars\n"
"indices : array of ints - Atomic indices", "indices : array of ints - Atom indices",
0, 0, 0, 0,
"", "",
script->set_result_int_vec(*(script->proxy()->get_atom_ids())); script->set_result_int_vec(*(script->proxy()->get_atom_ids()));
@ -317,6 +337,15 @@ CVSCRIPT(cv_help,
} }
) )
CVSCRIPT(cv_languageversion,
"Get the C++ language version number\n"
"version : string - C++ language version",
0, 0,
"",
script->set_result_int(__cplusplus);
return COLVARS_OK;
)
CVSCRIPT(cv_list, CVSCRIPT(cv_list,
"Return a list of all variables or biases\n" "Return a list of all variables or biases\n"
"list : sequence of strings - List of elements", "list : sequence of strings - List of elements",
@ -524,7 +553,7 @@ CVSCRIPT(cv_update,
) )
CVSCRIPT(cv_version, CVSCRIPT(cv_version,
"Get the Colvars Module version number\n" "Get the Colvars Module version string\n"
"version : string - Colvars version", "version : string - Colvars version",
0, 0, 0, 0,
"", "",

View File

@ -36,6 +36,10 @@
COLVARSCRIPT_OK) { \ COLVARSCRIPT_OK) { \
return COLVARSCRIPT_ERROR; \ return COLVARSCRIPT_ERROR; \
} \ } \
if (objc > 1) { \
/* Silence unused parameter warning */ \
(void) objv; \
} \
colvarbias *this_bias = colvarbias_obj(pobj); \ colvarbias *this_bias = colvarbias_obj(pobj); \
FN_BODY; \ FN_BODY; \
} }

View File

@ -99,7 +99,7 @@ CVSCRIPT(bias_help,
if (cmdstr.size()) { if (cmdstr.size()) {
script->set_result_str(script->get_command_cmdline_help(colvarscript::use_bias, script->set_result_str(script->get_command_cmdline_help(colvarscript::use_bias,
cmdstr)); cmdstr));
return COLVARS_OK; return cvm::get_error();
} else { } else {
return COLVARSCRIPT_ERROR; return COLVARSCRIPT_ERROR;
} }
@ -172,6 +172,15 @@ CVSCRIPT(bias_state,
return COLVARS_OK; return COLVARS_OK;
) )
CVSCRIPT(bias_type,
"Print the type of this bias object\n"
"type : string - Type of this bias object (e.g. metadynamics)",
0, 0,
"",
script->set_result_str(this_bias->bias_type);
return COLVARS_OK;
)
CVSCRIPT(bias_update, CVSCRIPT(bias_update,
"Recompute this bias and return its up-to-date energy\n" "Recompute this bias and return its up-to-date energy\n"
"E : float - Energy value", "E : float - Energy value",

View File

@ -36,6 +36,10 @@
COLVARSCRIPT_OK) { \ COLVARSCRIPT_OK) { \
return COLVARSCRIPT_ERROR; \ return COLVARSCRIPT_ERROR; \
} \ } \
if (objc > 1) { \
/* Silence unused parameter warning */ \
(void) objv[0]; \
} \
colvar *this_colvar = colvar_obj(pobj); \ colvar *this_colvar = colvar_obj(pobj); \
FN_BODY; \ FN_BODY; \
} }

View File

@ -28,6 +28,14 @@ CVSCRIPT(colvar_addforce,
return COLVARS_OK; return COLVARS_OK;
) )
CVSCRIPT(colvar_communicateforces,
"Communicate bias forces from this colvar to atoms",
0, 0,
"",
this_colvar->communicate_forces();
return COLVARS_OK;
)
CVSCRIPT(colvar_cvcflags, CVSCRIPT(colvar_cvcflags,
"Enable or disable individual components by setting their active flags", "Enable or disable individual components by setting their active flags",
1, 1, 1, 1,
@ -73,6 +81,14 @@ CVSCRIPT(colvar_getappliedforce,
return COLVARS_OK; return COLVARS_OK;
) )
CVSCRIPT(colvar_resetbiasforce,
"Return the total of the forces applied to this colvar",
0, 0,
"",
this_colvar->reset_bias_force();
return COLVARS_OK;
)
CVSCRIPT(colvar_getatomgroups, CVSCRIPT(colvar_getatomgroups,
"Return the atom indices used by this colvar as a list of lists\n" "Return the atom indices used by this colvar as a list of lists\n"
"groups : array of arrays of ints - Atom indices", "groups : array of arrays of ints - Atom indices",

View File

@ -253,10 +253,18 @@ namespace {
#endif #endif
colvarmodule::rotation::rotation() int colvarmodule::rotation::init()
{ {
b_debug_gradients = false; b_debug_gradients = false;
lambda = 0.0; lambda = 0.0;
cvm::main()->cite_feature("Optimal rotation via flexible fitting");
return COLVARS_OK;
}
colvarmodule::rotation::rotation()
{
init();
#ifdef COLVARS_LAMMPS #ifdef COLVARS_LAMMPS
jacobi = new_Jacobi_solver(4); jacobi = new_Jacobi_solver(4);
#else #else
@ -268,8 +276,7 @@ colvarmodule::rotation::rotation()
colvarmodule::rotation::rotation(cvm::quaternion const &qi) colvarmodule::rotation::rotation(cvm::quaternion const &qi)
: q(qi) : q(qi)
{ {
b_debug_gradients = false; init();
lambda = 0.0;
#ifdef COLVARS_LAMMPS #ifdef COLVARS_LAMMPS
jacobi = new_Jacobi_solver(4); jacobi = new_Jacobi_solver(4);
#else #else
@ -280,12 +287,11 @@ colvarmodule::rotation::rotation(cvm::quaternion const &qi)
colvarmodule::rotation::rotation(cvm::real angle, cvm::rvector const &axis) colvarmodule::rotation::rotation(cvm::real angle, cvm::rvector const &axis)
{ {
b_debug_gradients = false; init();
cvm::rvector const axis_n = axis.unit(); cvm::rvector const axis_n = axis.unit();
cvm::real const sina = cvm::sin(angle/2.0); cvm::real const sina = cvm::sin(angle/2.0);
q = cvm::quaternion(cvm::cos(angle/2.0), q = cvm::quaternion(cvm::cos(angle/2.0),
sina * axis_n.x, sina * axis_n.y, sina * axis_n.z); sina * axis_n.x, sina * axis_n.y, sina * axis_n.z);
lambda = 0.0;
#ifdef COLVARS_LAMMPS #ifdef COLVARS_LAMMPS
jacobi = new_Jacobi_solver(4); jacobi = new_Jacobi_solver(4);
#else #else

View File

@ -385,7 +385,7 @@ protected:
{ {
if (v.size() != length) { if (v.size() != length) {
return cvm::error("Error: setting a matrix row from a vector of " return cvm::error("Error: setting a matrix row from a vector of "
"incompatible size.\n", BUG_ERROR); "incompatible size.\n", COLVARS_BUG_ERROR);
} }
for (size_t i = 0; i < length; i++) data[i] = v[i]; for (size_t i = 0; i < length; i++) data[i] = v[i];
return COLVARS_OK; return COLVARS_OK;
@ -1294,8 +1294,7 @@ public:
if (cos_omega > 0.0) { if (cos_omega > 0.0) {
return 2.0*omega*grad1; return 2.0*omega*grad1;
} } else {
else {
return -2.0*(PI-omega)*grad1; return -2.0*(PI-omega)*grad1;
} }
} }
@ -1388,6 +1387,9 @@ public:
void calc_optimal_rotation(std::vector<atom_pos> const &pos1, void calc_optimal_rotation(std::vector<atom_pos> const &pos1,
std::vector<atom_pos> const &pos2); std::vector<atom_pos> const &pos2);
/// Initialize member data
int init();
/// Default constructor /// Default constructor
rotation(); rotation();

View File

@ -16,6 +16,95 @@
colvarvalue::colvarvalue()
: value_type(type_scalar), real_value(0.0)
{}
colvarvalue::colvarvalue(Type const &vti)
: value_type(vti), real_value(0.0)
{
reset();
}
colvarvalue::colvarvalue(cvm::real const &x)
: value_type(type_scalar), real_value(x)
{}
colvarvalue::colvarvalue(cvm::rvector const &v, colvarvalue::Type vti)
: value_type(vti), real_value(0.0), rvector_value(v)
{}
colvarvalue::colvarvalue(cvm::quaternion const &q, colvarvalue::Type vti)
: value_type(vti), real_value(0.0), quaternion_value(q)
{}
colvarvalue::colvarvalue(colvarvalue const &x)
: value_type(x.type()), real_value(0.0)
{
switch (x.type()) {
case type_scalar:
real_value = x.real_value;
break;
case type_3vector:
case type_unit3vector:
case type_unit3vectorderiv:
rvector_value = x.rvector_value;
break;
case type_quaternion:
case type_quaternionderiv:
quaternion_value = x.quaternion_value;
break;
case type_vector:
vector1d_value = x.vector1d_value;
elem_types = x.elem_types;
elem_indices = x.elem_indices;
elem_sizes = x.elem_sizes;
case type_notset:
default:
break;
}
}
colvarvalue::colvarvalue(cvm::vector1d<cvm::real> const &v,
colvarvalue::Type vti)
: real_value(0.0)
{
if ((vti != type_vector) && (v.size() != num_dimensions(vti))) {
cvm::error("Error: trying to initialize a variable of type \""+type_desc(vti)+
"\" using a vector of size "+cvm::to_str(v.size())+
".\n");
value_type = type_notset;
} else {
value_type = vti;
switch (vti) {
case type_scalar:
real_value = v[0];
break;
case type_3vector:
case type_unit3vector:
case type_unit3vectorderiv:
rvector_value = cvm::rvector(v);
break;
case type_quaternion:
case type_quaternionderiv:
quaternion_value = cvm::quaternion(v);
break;
case type_vector:
vector1d_value = v;
break;
case type_notset:
default:
break;
}
}
}
std::string const colvarvalue::type_desc(Type t) std::string const colvarvalue::type_desc(Type t)
{ {
switch (t) { switch (t) {
@ -223,68 +312,6 @@ void colvarvalue::is_derivative()
} }
colvarvalue::colvarvalue(colvarvalue const &x)
: value_type(x.type()), real_value(0.0)
{
switch (x.type()) {
case type_scalar:
real_value = x.real_value;
break;
case type_3vector:
case type_unit3vector:
case type_unit3vectorderiv:
rvector_value = x.rvector_value;
break;
case type_quaternion:
case type_quaternionderiv:
quaternion_value = x.quaternion_value;
break;
case type_vector:
vector1d_value = x.vector1d_value;
elem_types = x.elem_types;
elem_indices = x.elem_indices;
elem_sizes = x.elem_sizes;
case type_notset:
default:
break;
}
}
colvarvalue::colvarvalue(cvm::vector1d<cvm::real> const &v, Type vti)
: real_value(0.0)
{
if ((vti != type_vector) && (v.size() != num_dimensions(vti))) {
cvm::error("Error: trying to initialize a variable of type \""+type_desc(vti)+
"\" using a vector of size "+cvm::to_str(v.size())+
".\n");
value_type = type_notset;
} else {
value_type = vti;
switch (vti) {
case type_scalar:
real_value = v[0];
break;
case type_3vector:
case type_unit3vector:
case type_unit3vectorderiv:
rvector_value = cvm::rvector(v);
break;
case type_quaternion:
case type_quaternionderiv:
quaternion_value = cvm::quaternion(v);
break;
case type_vector:
vector1d_value = v;
break;
case type_notset:
default:
break;
}
}
}
void colvarvalue::add_elem(colvarvalue const &x) void colvarvalue::add_elem(colvarvalue const &x)
{ {
if (this->value_type != type_vector) { if (this->value_type != type_vector) {
@ -606,7 +633,7 @@ colvarvalue const colvarvalue::interpolate(colvarvalue const &x1,
if ((lambda < 0.0) || (lambda > 1.0)) { if ((lambda < 0.0) || (lambda > 1.0)) {
cvm::error("Error: trying to interpolate between two colvarvalues with a " cvm::error("Error: trying to interpolate between two colvarvalues with a "
"lamdba outside [0:1].\n", BUG_ERROR); "lamdba outside [0:1].\n", COLVARS_BUG_ERROR);
} }
colvarvalue interp = ((1.0-lambda)*x1 + lambda*x2); colvarvalue interp = ((1.0-lambda)*x1 + lambda*x2);
@ -626,7 +653,7 @@ colvarvalue const colvarvalue::interpolate(colvarvalue const &x1,
cvm::error("Error: interpolation between "+cvm::to_str(x1)+" and "+ cvm::error("Error: interpolation between "+cvm::to_str(x1)+" and "+
cvm::to_str(x2)+" with lambda = "+cvm::to_str(lambda)+ cvm::to_str(x2)+" with lambda = "+cvm::to_str(lambda)+
" is undefined: result = "+cvm::to_str(interp)+"\n", " is undefined: result = "+cvm::to_str(interp)+"\n",
INPUT_ERROR); COLVARS_INPUT_ERROR);
} }
interp.apply_constraints(); interp.apply_constraints();
return interp; return interp;

View File

@ -118,33 +118,21 @@ public:
/// \brief Default constructor: this class defaults to a scalar /// \brief Default constructor: this class defaults to a scalar
/// number and always behaves like it unless you change its type /// number and always behaves like it unless you change its type
inline colvarvalue() colvarvalue();
: value_type(type_scalar), real_value(0.0)
{}
/// Constructor from a type specification /// Constructor from a type specification
inline colvarvalue(Type const &vti) colvarvalue(Type const &vti);
: value_type(vti), real_value(0.0)
{
reset();
}
/// Copy constructor from real base type /// Copy constructor from real base type
inline colvarvalue(cvm::real const &x) colvarvalue(cvm::real const &x);
: value_type(type_scalar), real_value(x)
{}
/// \brief Copy constructor from rvector base type (Note: this sets /// \brief Copy constructor from rvector base type (Note: this sets
/// by default a type \link type_3vector \endlink , if you want a /// by default a type \link type_3vector \endlink , if you want a
/// \link type_unit3vector \endlink you must set it explicitly) /// \link type_unit3vector \endlink you must set it explicitly)
inline colvarvalue(cvm::rvector const &v, Type vti = type_3vector) colvarvalue(cvm::rvector const &v, Type vti = type_3vector);
: value_type(vti), real_value(0.0), rvector_value(v)
{}
/// \brief Copy constructor from quaternion base type /// \brief Copy constructor from quaternion base type
inline colvarvalue(cvm::quaternion const &q, Type vti = type_quaternion) colvarvalue(cvm::quaternion const &q, Type vti = type_quaternion);
: value_type(vti), real_value(0.0), quaternion_value(q)
{}
/// Copy constructor from vector1d base type /// Copy constructor from vector1d base type
colvarvalue(cvm::vector1d<cvm::real> const &v, Type vti = type_vector); colvarvalue(cvm::vector1d<cvm::real> const &v, Type vti = type_vector);
@ -390,7 +378,7 @@ inline cvm::real colvarvalue::operator [] (int const i) const
case colvarvalue::type_notset: case colvarvalue::type_notset:
default: default:
cvm::error("Error: trying to access a colvar value " cvm::error("Error: trying to access a colvar value "
"that is not initialized.\n", BUG_ERROR); "that is not initialized.\n", COLVARS_BUG_ERROR);
return 0.0; break; return 0.0; break;
case colvarvalue::type_scalar: case colvarvalue::type_scalar:
return real_value; break; return real_value; break;
@ -413,7 +401,7 @@ inline cvm::real & colvarvalue::operator [] (int const i)
case colvarvalue::type_notset: case colvarvalue::type_notset:
default: default:
cvm::error("Error: trying to access a colvar value " cvm::error("Error: trying to access a colvar value "
"that is not initialized.\n", BUG_ERROR); "that is not initialized.\n", COLVARS_BUG_ERROR);
return real_value; break; return real_value; break;
case colvarvalue::type_scalar: case colvarvalue::type_scalar:
return real_value; break; return real_value; break;

View File

@ -27,35 +27,6 @@
#define HASH_FAIL -1 #define HASH_FAIL -1
////////////////////////////////////////////////////////////////////////
// local helper functions
// safely move filename to filename.extension
static int my_backup_file(const char *filename, const char *extension)
{
struct stat sbuf;
if (stat(filename, &sbuf) == 0) {
if (!extension) extension = ".BAK";
char *backup = new char[strlen(filename)+strlen(extension)+1];
strcpy(backup, filename);
strcat(backup, extension);
#if defined(_WIN32) && !defined(__CYGWIN__)
remove(backup);
#endif
if (rename(filename,backup)) {
char *sys_err_msg = strerror(errno);
if (!sys_err_msg) sys_err_msg = (char *) "(unknown error)";
fprintf(stderr,"Error renaming file %s to %s: %s\n",
filename, backup, sys_err_msg);
delete [] backup;
return COLVARS_ERROR;
}
delete [] backup;
}
return COLVARS_OK;
}
////////////////////////////////////////////////////////////////////////
colvarproxy_lammps::colvarproxy_lammps(LAMMPS_NS::LAMMPS *lmp, colvarproxy_lammps::colvarproxy_lammps(LAMMPS_NS::LAMMPS *lmp,
const char *inp_name, const char *inp_name,
@ -75,10 +46,6 @@ colvarproxy_lammps::colvarproxy_lammps(LAMMPS_NS::LAMMPS *lmp,
t_target=temp; t_target=temp;
do_exit=false; do_exit=false;
// User-scripted forces are not available in LAMMPS
force_script_defined = false;
have_scripts = false;
// set input restart name and strip the extension, if present // set input restart name and strip the extension, if present
input_prefix_str = std::string(inp_name ? inp_name : ""); input_prefix_str = std::string(inp_name ? inp_name : "");
if (input_prefix_str.rfind(".colvars.state") != std::string::npos) if (input_prefix_str.rfind(".colvars.state") != std::string::npos)
@ -130,6 +97,9 @@ void colvarproxy_lammps::init(const char *conf_file)
cvm::log("Using LAMMPS interface, version "+ cvm::log("Using LAMMPS interface, version "+
cvm::to_str(COLVARPROXY_VERSION)+".\n"); cvm::to_str(COLVARPROXY_VERSION)+".\n");
colvars->cite_feature("LAMMPS engine");
colvars->cite_feature("Colvars-LAMMPS interface");
my_angstrom = _lmp->force->angstrom; my_angstrom = _lmp->force->angstrom;
// Front-end unit is the same as back-end // Front-end unit is the same as back-end
angstrom_value = my_angstrom; angstrom_value = my_angstrom;
@ -179,10 +149,6 @@ int colvarproxy_lammps::read_state_file(char const *state_filename)
colvarproxy_lammps::~colvarproxy_lammps() colvarproxy_lammps::~colvarproxy_lammps()
{ {
delete _random; delete _random;
if (colvars != nullptr) {
delete colvars;
colvars = nullptr;
}
} }
// re-initialize data where needed // re-initialize data where needed
@ -339,17 +305,6 @@ int colvarproxy_lammps::set_unit_system(std::string const &units_in, bool /*chec
} }
int colvarproxy_lammps::backup_file(char const *filename)
{
if (std::string(filename).rfind(std::string(".colvars.state"))
!= std::string::npos) {
return my_backup_file(filename, ".old");
} else {
return my_backup_file(filename, ".BAK");
}
}
// multi-replica support // multi-replica support
int colvarproxy_lammps::replica_enabled() int colvarproxy_lammps::replica_enabled()
@ -414,8 +369,8 @@ int colvarproxy_lammps::check_atom_id(int atom_number)
// TODO add upper boundary check? // TODO add upper boundary check?
if ((aid < 0)) { if ((aid < 0)) {
cvm::error("Error: invalid atom number specified, "+ cvm::error("Error: invalid atom number specified, "+
cvm::to_str(atom_number)+"\n", INPUT_ERROR); cvm::to_str(atom_number)+"\n", COLVARS_INPUT_ERROR);
return INPUT_ERROR; return COLVARS_INPUT_ERROR;
} }
return aid; return aid;

View File

@ -101,10 +101,7 @@ class colvarproxy_lammps : public colvarproxy {
void log(std::string const &message) override; void log(std::string const &message) override;
void error(std::string const &message) override; void error(std::string const &message) override;
cvm::rvector position_distance(cvm::atom_pos const &pos1, cvm::rvector position_distance(cvm::atom_pos const &pos1, cvm::atom_pos const &pos2) const override;
cvm::atom_pos const &pos2) const override;
int backup_file(char const *filename) override;
cvm::real rand_gaussian(void) override { return _random->gaussian(); }; cvm::real rand_gaussian(void) override { return _random->gaussian(); };

View File

@ -1,3 +1,3 @@
#ifndef COLVARPROXY_VERSION #ifndef COLVARPROXY_VERSION
#define COLVARPROXY_VERSION "2021-03-02" #define COLVARPROXY_VERSION "2022-05-09"
#endif #endif

View File

@ -38,23 +38,14 @@
#include "universe.h" #include "universe.h"
#include "update.h" #include "update.h"
#include "colvarproxy_lammps.h"
#include "colvarmodule.h"
#include <cstring> #include <cstring>
#include <iostream> #include <iostream>
#include <memory> #include <memory>
#include <vector>
#include "colvarproxy_lammps.h"
#include "colvarmodule.h"
static const char colvars_pub[] =
"fix colvars command:\n\n"
"@Article{fiorin13,\n"
" author = {G.~Fiorin and M.{\\,}L.~Klein and J.~H{\\'e}nin},\n"
" title = {Using collective variables to drive molecular"
" dynamics simulations},\n"
" journal = {Mol.~Phys.},\n"
" year = 2013,\n"
" note = {doi: 10.1080/00268976.2013.813594}\n"
"}\n\n";
/* struct for packed data communication of coordinates and forces. */ /* struct for packed data communication of coordinates and forces. */
struct LAMMPS_NS::commdata { struct LAMMPS_NS::commdata {
@ -349,8 +340,6 @@ FixColvars::FixColvars(LAMMPS *lmp, int narg, char **arg) :
/* storage required to communicate a single coordinate or force. */ /* storage required to communicate a single coordinate or force. */
size_one = sizeof(struct commdata); size_one = sizeof(struct commdata);
if (lmp->citeme) lmp->citeme->add(colvars_pub);
} }
/********************************* /*********************************
@ -978,6 +967,9 @@ void FixColvars::post_run()
{ {
if (me == 0) { if (me == 0) {
proxy->post_run(); proxy->post_run();
if (lmp->citeme) {
lmp->citeme->add(proxy->colvars->feature_report(1));
}
} }
} }