Update Colvars to version 2020-07-07

This update contains several fixes and small new features or usability
improvements.  Descriptions and authorship information can be accessed from
the pull requests listed below.

Skip the zero-step also when multiple run commands are executed in sequence (@giacomofiorin)
https://github.com/Colvars/colvars/pull/357

Do not accumulate data at step 0 (@giacomofiorin)
https://github.com/Colvars/colvars/pull/345

Support for symmetry permutations of atoms in RMSD (@jhenin)
https://github.com/Colvars/colvars/pull/344

Detect new grid parameters (@jhenin)
https://github.com/Colvars/colvars/pull/341

Only access the output streams in non-threaded regions (@giacomofiorin)
https://github.com/Colvars/colvars/pull/338

Fix incomplete setting of default colvarsRestartFrequency (@giacomofiorin)
https://github.com/Colvars/colvars/pull/334

Fix typo (@e-kwsm)
https://github.com/Colvars/colvars/pull/333

Convert the input keyword to lowercase in read_state_data_key (@HanatoK)
https://github.com/Colvars/colvars/pull/332

Implement reflecting b.c. for ext Lagrangian (@jhenin)
https://github.com/Colvars/colvars/pull/329
This commit is contained in:
Giacomo Fiorin
2020-09-04 14:46:27 -04:00
parent d995ed0d87
commit 85c394453c
45 changed files with 3238 additions and 1582 deletions

View File

@ -20,11 +20,6 @@
#include <omp.h>
#endif
#if defined(NAMD_TCL) || defined(VMDTCL)
#define COLVARS_TCL
#include <tcl.h>
#endif
#include "colvarmodule.h"
#include "colvarproxy.h"
#include "colvarscript.h"
@ -33,8 +28,9 @@
colvarproxy_system::colvarproxy_system()
: angstrom_value(0.)
{
angstrom_value = 0.0;
total_force_requested = false;
reset_pbc_lattice();
}
@ -67,7 +63,7 @@ bool colvarproxy_system::total_forces_same_step() const
inline int round_to_integer(cvm::real x)
{
return cvm::floor(x+0.5);
return int(cvm::floor(x+0.5));
}
@ -135,6 +131,14 @@ cvm::rvector colvarproxy_system::position_distance(cvm::atom_pos const &pos1,
}
int colvarproxy_system::get_molid(int &)
{
cvm::error("Error: only VMD allows the use of multiple \"molecules\", "
"i.e. multiple molecular systems.", COLVARS_NOT_IMPLEMENTED);
return -1;
}
colvarproxy_atoms::colvarproxy_atoms()
{
@ -505,144 +509,12 @@ int colvarproxy_script::run_colvar_gradient_callback(std::string const & /* name
colvarproxy_tcl::colvarproxy_tcl()
colvarproxy_io::colvarproxy_io()
{
tcl_interp_ = NULL;
input_buffer_ = NULL;
}
colvarproxy_tcl::~colvarproxy_tcl()
{
}
void colvarproxy_tcl::init_tcl_pointers()
{
cvm::error("Error: Tcl support is currently unavailable "
"outside NAMD or VMD.\n", COLVARS_NOT_IMPLEMENTED);
}
char const *colvarproxy_tcl::tcl_obj_to_str(unsigned char *obj)
{
#if defined(COLVARS_TCL)
return Tcl_GetString(reinterpret_cast<Tcl_Obj *>(obj));
#else
return NULL;
#endif
}
int colvarproxy_tcl::tcl_run_force_callback()
{
#if defined(COLVARS_TCL)
Tcl_Interp *const tcl_interp = reinterpret_cast<Tcl_Interp *>(tcl_interp_);
std::string cmd = std::string("calc_colvar_forces ")
+ cvm::to_str(cvm::step_absolute());
int err = Tcl_Eval(tcl_interp, cmd.c_str());
if (err != TCL_OK) {
cvm::log(std::string("Error while executing calc_colvar_forces:\n"));
cvm::error(Tcl_GetStringResult(tcl_interp));
return COLVARS_ERROR;
}
return cvm::get_error();
#else
return COLVARS_NOT_IMPLEMENTED;
#endif
}
int colvarproxy_tcl::tcl_run_colvar_callback(
std::string const & name,
std::vector<const colvarvalue *> const & cvc_values,
colvarvalue & value)
{
#if defined(COLVARS_TCL)
Tcl_Interp *const tcl_interp = reinterpret_cast<Tcl_Interp *>(tcl_interp_);
size_t i;
std::string cmd = std::string("calc_") + name;
for (i = 0; i < cvc_values.size(); i++) {
cmd += std::string(" {") + (*(cvc_values[i])).to_simple_string() +
std::string("}");
}
int err = Tcl_Eval(tcl_interp, cmd.c_str());
const char *result = Tcl_GetStringResult(tcl_interp);
if (err != TCL_OK) {
return cvm::error(std::string("Error while executing ")
+ cmd + std::string(":\n") +
std::string(Tcl_GetStringResult(tcl_interp)), COLVARS_ERROR);
}
std::istringstream is(result);
if (value.from_simple_string(is.str()) != COLVARS_OK) {
cvm::log("Error parsing colvar value from script:");
cvm::error(result);
return COLVARS_ERROR;
}
return cvm::get_error();
#else
return COLVARS_NOT_IMPLEMENTED;
#endif
}
int colvarproxy_tcl::tcl_run_colvar_gradient_callback(
std::string const & name,
std::vector<const colvarvalue *> const & cvc_values,
std::vector<cvm::matrix2d<cvm::real> > & gradient)
{
#if defined(COLVARS_TCL)
Tcl_Interp *const tcl_interp = reinterpret_cast<Tcl_Interp *>(tcl_interp_);
size_t i;
std::string cmd = std::string("calc_") + name + "_gradient";
for (i = 0; i < cvc_values.size(); i++) {
cmd += std::string(" {") + (*(cvc_values[i])).to_simple_string() +
std::string("}");
}
int err = Tcl_Eval(tcl_interp, cmd.c_str());
if (err != TCL_OK) {
return cvm::error(std::string("Error while executing ")
+ cmd + std::string(":\n") +
std::string(Tcl_GetStringResult(tcl_interp)), COLVARS_ERROR);
}
Tcl_Obj **list;
int n;
Tcl_ListObjGetElements(tcl_interp, Tcl_GetObjResult(tcl_interp),
&n, &list);
if (n != int(gradient.size())) {
cvm::error("Error parsing list of gradient values from script: found "
+ cvm::to_str(n) + " values instead of " +
cvm::to_str(gradient.size()));
return COLVARS_ERROR;
}
for (i = 0; i < gradient.size(); i++) {
std::istringstream is(Tcl_GetString(list[i]));
if (gradient[i].from_simple_string(is.str()) != COLVARS_OK) {
cvm::log("Gradient matrix size: " + cvm::to_str(gradient[i].size()));
cvm::log("Gradient string: " + cvm::to_str(Tcl_GetString(list[i])));
cvm::error("Error parsing gradient value from script", COLVARS_ERROR);
return COLVARS_ERROR;
}
}
return cvm::get_error();
#else
return COLVARS_NOT_IMPLEMENTED;
#endif
}
colvarproxy_io::colvarproxy_io() {}
colvarproxy_io::~colvarproxy_io() {}
@ -658,78 +530,6 @@ int colvarproxy_io::set_frame(long int)
}
std::ostream * colvarproxy_io::output_stream(std::string const &output_name,
std::ios_base::openmode mode)
{
if (cvm::debug()) {
cvm::log("Using colvarproxy::output_stream()\n");
}
std::ostream *os = get_output_stream(output_name);
if (os != NULL) return os;
if (!(mode & (std::ios_base::app | std::ios_base::ate))) {
backup_file(output_name);
}
std::ofstream *osf = new std::ofstream(output_name.c_str(), mode);
if (!osf->is_open()) {
cvm::error("Error: cannot write to file/channel \""+output_name+"\".\n",
FILE_ERROR);
return NULL;
}
output_stream_names.push_back(output_name);
output_files.push_back(osf);
return osf;
}
std::ostream *colvarproxy_io::get_output_stream(std::string const &output_name)
{
std::list<std::ostream *>::iterator osi = output_files.begin();
std::list<std::string>::iterator osni = output_stream_names.begin();
for ( ; osi != output_files.end(); osi++, osni++) {
if (*osni == output_name) {
return *osi;
}
}
return NULL;
}
int colvarproxy_io::flush_output_stream(std::ostream *os)
{
std::list<std::ostream *>::iterator osi = output_files.begin();
std::list<std::string>::iterator osni = output_stream_names.begin();
for ( ; osi != output_files.end(); osi++, osni++) {
if (*osi == os) {
((std::ofstream *) (*osi))->flush();
return COLVARS_OK;
}
}
return cvm::error("Error: trying to flush an output file/channel "
"that wasn't open.\n", BUG_ERROR);
}
int colvarproxy_io::close_output_stream(std::string const &output_name)
{
std::list<std::ostream *>::iterator osi = output_files.begin();
std::list<std::string>::iterator osni = output_stream_names.begin();
for ( ; osi != output_files.end(); osi++, osni++) {
if (*osni == output_name) {
((std::ofstream *) (*osi))->close();
delete *osi;
output_files.erase(osi);
output_stream_names.erase(osni);
return COLVARS_OK;
}
}
return cvm::error("Error: trying to close an output file/channel "
"that wasn't open.\n", BUG_ERROR);
}
int colvarproxy_io::backup_file(char const * /* filename */)
{
// TODO implement this using rename_file()
@ -796,11 +596,33 @@ colvarproxy::colvarproxy()
{
colvars = NULL;
b_simulation_running = true;
b_simulation_continuing = false;
b_delete_requested = false;
}
colvarproxy::~colvarproxy() {}
colvarproxy::~colvarproxy()
{
close_files();
}
int colvarproxy::close_files()
{
if (smp_enabled() == COLVARS_OK && smp_thread_id() > 0) {
// Nothing to do on non-master threads
return COLVARS_OK;
}
std::list<std::string>::iterator osni = output_stream_names.begin();
std::list<std::ostream *>::iterator osi = output_files.begin();
for ( ; osi != output_files.end(); osi++, osni++) {
((std::ofstream *) (*osi))->close();
delete *osi;
}
output_files.clear();
output_stream_names.clear();
return COLVARS_OK;
}
int colvarproxy::reset()
@ -838,9 +660,37 @@ int colvarproxy::update_output()
}
size_t colvarproxy::restart_frequency()
int colvarproxy::post_run()
{
return 0;
int error_code = COLVARS_OK;
if (colvars->output_prefix().size()) {
error_code |= colvars->write_restart_file(cvm::output_prefix()+".colvars.state");
error_code |= colvars->write_output_files();
}
error_code |= flush_output_streams();
return error_code;
}
void colvarproxy::add_error_msg(std::string const &message)
{
std::istringstream is(message);
std::string line;
while (std::getline(is, line)) {
error_output += line+"\n";
}
}
void colvarproxy::clear_error_msgs()
{
error_output.clear();
}
std::string const & colvarproxy::get_error_msgs()
{
return error_output;
}
@ -852,3 +702,105 @@ int colvarproxy::get_version_from_string(char const *version_string)
is >> newint;
return newint;
}
void colvarproxy::smp_stream_error()
{
cvm::error("Error: trying to access an output stream from a "
"multi-threaded region (bug). For a quick workaround, use "
"\"smp off\" in the Colvars config.\n", BUG_ERROR);
}
std::ostream * colvarproxy::output_stream(std::string const &output_name,
std::ios_base::openmode mode)
{
if (cvm::debug()) {
cvm::log("Using colvarproxy::output_stream()\n");
}
std::ostream *os = get_output_stream(output_name);
if (os != NULL) return os;
if (!(mode & (std::ios_base::app | std::ios_base::ate))) {
backup_file(output_name);
}
std::ofstream *osf = new std::ofstream(output_name.c_str(), mode);
if (!osf->is_open()) {
cvm::error("Error: cannot write to file/channel \""+output_name+"\".\n",
FILE_ERROR);
return NULL;
}
output_stream_names.push_back(output_name);
output_files.push_back(osf);
return osf;
}
std::ostream *colvarproxy::get_output_stream(std::string const &output_name)
{
if (smp_enabled() == COLVARS_OK) {
if (smp_thread_id() > 0) smp_stream_error();
}
std::list<std::ostream *>::iterator osi = output_files.begin();
std::list<std::string>::iterator osni = output_stream_names.begin();
for ( ; osi != output_files.end(); osi++, osni++) {
if (*osni == output_name) {
return *osi;
}
}
return NULL;
}
int colvarproxy::flush_output_stream(std::ostream *os)
{
if (smp_enabled() == COLVARS_OK) {
if (smp_thread_id() > 0) smp_stream_error();
}
std::list<std::ostream *>::iterator osi = output_files.begin();
std::list<std::string>::iterator osni = output_stream_names.begin();
for ( ; osi != output_files.end(); osi++, osni++) {
if (*osi == os) {
((std::ofstream *) (*osi))->flush();
return COLVARS_OK;
}
}
return cvm::error("Error: trying to flush an output file/channel "
"that wasn't open.\n", BUG_ERROR);
}
int colvarproxy::flush_output_streams()
{
if (smp_enabled() == COLVARS_OK && smp_thread_id() > 0)
return COLVARS_OK;
std::list<std::ostream *>::iterator osi = output_files.begin();
for ( ; osi != output_files.end(); osi++) {
((std::ofstream *) (*osi))->flush();
}
return COLVARS_OK;
}
int colvarproxy::close_output_stream(std::string const &output_name)
{
if (smp_enabled() == COLVARS_OK) {
if (smp_thread_id() > 0) smp_stream_error();
}
std::list<std::ostream *>::iterator osi = output_files.begin();
std::list<std::string>::iterator osni = output_stream_names.begin();
for ( ; osi != output_files.end(); osi++, osni++) {
if (*osni == output_name) {
((std::ofstream *) (*osi))->close();
delete *osi;
output_files.erase(osi);
output_stream_names.erase(osni);
return COLVARS_OK;
}
}
return cvm::error("Error: trying to close an output file/channel "
"that wasn't open.\n", BUG_ERROR);
}