Files
lammps/lib/colvars/colvarscript.cpp
Giacomo Fiorin 1220bea011 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
2022-05-10 11:24:54 -04:00

918 lines
27 KiB
C++

// -*- 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 <cstdlib>
#include <cstring>
#include <sstream>
#include "colvarproxy.h"
#include "colvardeps.h"
#include "colvarscript.h"
#include "colvarscript_commands.h"
#ifdef COLVARS_TCL
/// Run the script API via Tcl command-line interface
/// \param clientData Not used
/// \param my_interp Pointer to Tcl_Interp object (read from Colvars if NULL)
/// \param objc Number of Tcl command parameters
/// \param objv Array of command parameters
/// \return Result of the script command
extern "C" int tcl_run_colvarscript_command(ClientData clientData,
Tcl_Interp *interp_in,
int objc, Tcl_Obj *const objv[]);
#endif
colvarscript::colvarscript(colvarproxy *p, colvarmodule *m)
: proxy_(p),
colvars(m)
{
cmd_names = NULL;
init_commands();
#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
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_CreateObjCommand(interp, "cv", tcl_run_colvarscript_command,
(ClientData) this, (Tcl_CmdDeleteProc *) NULL);
cvm::log("Redefining the Tcl \"cv\" command to the new script interface.\n");
#endif
}
colvarscript::~colvarscript()
{
if (cmd_names) {
delete [] cmd_names;
cmd_names = NULL;
}
}
int colvarscript::init_commands()
{
if (cvm::debug()) {
cvm::log("Called colvarcript::init_commands()\n");
}
cmd_help.resize(colvarscript::cv_n_commands);
cmd_rethelp.resize(colvarscript::cv_n_commands);
cmd_n_args_min.resize(colvarscript::cv_n_commands);
cmd_n_args_max.resize(colvarscript::cv_n_commands);
cmd_arghelp.resize(colvarscript::cv_n_commands);
cmd_full_help.resize(colvarscript::cv_n_commands);
cmd_fns.resize(colvarscript::cv_n_commands);
if (cmd_names) {
delete [] cmd_names;
cmd_names = NULL;
}
cmd_names = new char const * [colvarscript::cv_n_commands];
#undef COLVARSCRIPT_COMMANDS_H // disable include guard
#if defined(CVSCRIPT)
#undef CVSCRIPT // disable default macro
#endif
#define CVSCRIPT_COMM_INIT(COMM,HELP,N_ARGS_MIN,N_ARGS_MAX,ARGHELP) { \
init_command(COMM,#COMM,HELP,N_ARGS_MIN,N_ARGS_MAX,ARGHELP,&(CVSCRIPT_COMM_FNAME(COMM))); \
}
#define CVSCRIPT(COMM,HELP,N_ARGS_MIN,N_ARGS_MAX,ARGS,FN_BODY) \
CVSCRIPT_COMM_INIT(COMM,HELP,N_ARGS_MIN,N_ARGS_MAX,ARGS)
#include "colvarscript_commands.h"
#undef CVSCRIPT_COMM_INIT
#undef CVSCRIPT
return COLVARS_OK;
}
int colvarscript::init_command(colvarscript::command const &comm,
char const *name, char const *help,
int n_args_min, int n_args_max,
char const *arghelp,
int (*fn)(void *, int, unsigned char * const *))
{
cmd_str_map[std::string(name)] = comm;
cmd_names[comm] = name;
// Initialize short help string and return-value help string (if present)
{
std::string const help_str(help);
std::istringstream is(help_str);
std::string line;
std::getline(is, line);
cmd_help[comm] = line;
cmd_rethelp[comm] = "";
while (std::getline(is, line)) {
cmd_rethelp[comm] += line + "\n";
}
}
// Initialize arguments' help strings
cmd_n_args_min[comm] = n_args_min;
cmd_n_args_max[comm] = n_args_max;
{
std::string const arghelp_str(arghelp);
std::istringstream is(arghelp_str);
std::string line;
for (int iarg = 0; iarg < n_args_max; iarg++) {
if (! std::getline(is, line)) {
return cvm::error("Error: could not initialize help string for scripting "
"command \""+std::string(name)+"\".\n", COLVARS_BUG_ERROR);
}
cmd_arghelp[comm].push_back(line);
}
}
cmd_full_help[comm] = cmd_help[comm]+"\n";
if (cmd_n_args_min[comm] > 0) {
cmd_full_help[comm] += "\nParameters\n";
cmd_full_help[comm] += "----------\n\n";
size_t i;
for (i = 0; i < cmd_n_args_min[comm]; i++) {
cmd_full_help[comm] += cmd_arghelp[comm][i]+"\n";
}
for (i = cmd_n_args_min[comm]; i < cmd_n_args_max[comm]; i++) {
cmd_full_help[comm] += cmd_arghelp[comm][i]+" (optional)\n";
}
}
if (cmd_rethelp[comm].size() > 0) {
cmd_full_help[comm] += "\nReturns\n";
cmd_full_help[comm] += "-------\n\n";
cmd_full_help[comm] += cmd_rethelp[comm]+"\n";
}
cmd_fns[comm] = fn;
if (cvm::debug()) {
cvm::log("Defined command \""+std::string(name)+"\", with help string:\n");
cvm::log(get_command_full_help(name));
}
return COLVARS_OK;
}
std::string colvarscript::get_cmd_prefix(colvarscript::Object_type t)
{
switch (t) {
case use_module:
return std::string("cv_"); break;
case use_colvar:
return std::string("colvar_"); break;
case use_bias:
return std::string("bias_"); break;
default:
cvm::error("Error: undefined colvarscript object type.", COLVARS_BUG_ERROR);
return std::string("");
}
}
char const *colvarscript::get_command_help(char const *cmd)
{
if (cmd_str_map.count(cmd) > 0) {
colvarscript::command const c = cmd_str_map[std::string(cmd)];
return cmd_help[c].c_str();
}
cvm::error("Error: command "+std::string(cmd)+
" is not implemented.\n", COLVARS_INPUT_ERROR);
return NULL;
}
char const *colvarscript::get_command_rethelp(char const *cmd)
{
if (cmd_str_map.count(cmd) > 0) {
colvarscript::command const c = cmd_str_map[std::string(cmd)];
return cmd_rethelp[c].c_str();
}
cvm::error("Error: command "+std::string(cmd)+
" is not implemented.\n", COLVARS_INPUT_ERROR);
return NULL;
}
char const *colvarscript::get_command_arghelp(char const *cmd, int i)
{
if (cmd_str_map.count(cmd) > 0) {
colvarscript::command const c = cmd_str_map[std::string(cmd)];
return cmd_arghelp[c][i].c_str();
}
cvm::error("Error: command "+std::string(cmd)+
" is not implemented.\n", COLVARS_INPUT_ERROR);
return NULL;
}
int colvarscript::get_command_n_args_min(char const *cmd)
{
if (cmd_str_map.count(cmd) > 0) {
colvarscript::command const c = cmd_str_map[std::string(cmd)];
return cmd_n_args_min[c];
}
cvm::error("Error: command "+std::string(cmd)+
" is not implemented.\n", COLVARS_INPUT_ERROR);
return -1;
}
int colvarscript::get_command_n_args_max(char const *cmd)
{
if (cmd_str_map.count(cmd) > 0) {
colvarscript::command const c = cmd_str_map[std::string(cmd)];
return cmd_n_args_max[c];
}
cvm::error("Error: command "+std::string(cmd)+
" is not implemented.\n", COLVARS_INPUT_ERROR);
return -1;
}
char const *colvarscript::get_command_full_help(char const *cmd)
{
if (cmd_str_map.count(cmd) > 0) {
colvarscript::command const c = cmd_str_map[std::string(cmd)];
return cmd_full_help[c].c_str();
}
cvm::error("Error: command "+std::string(cmd)+
" is not implemented.\n", COLVARS_INPUT_ERROR);
return NULL;
}
std::string colvarscript::get_command_cmdline_syntax(colvarscript::Object_type t,
colvarscript::command cmd)
{
std::string const prefix = get_cmd_prefix(t);
std::string const cmdstr(cmd_names[cmd]);
// Get the sub-command as used in the command line
std::string const cmdline_cmd(cmdstr, prefix.size());
std::string cmdline_args;
size_t i;
for (i = 0; i < cmd_n_args_min[cmd]; i++) {
std::string const &arghelp = cmd_arghelp[cmd][i];
size_t space = arghelp.find(" : ");
cmdline_args += " <"+cmd_arghelp[cmd][i].substr(0, space)+">";
}
for (i = cmd_n_args_min[cmd]; i < cmd_n_args_max[cmd]; i++) {
std::string const &arghelp = cmd_arghelp[cmd][i];
size_t space = arghelp.find(" : ");
cmdline_args += " ["+cmd_arghelp[cmd][i].substr(0, space)+"]";
}
switch (t) {
case use_module:
return std::string("cv "+cmdline_cmd+cmdline_args); break;
case use_colvar:
return std::string("cv colvar name "+cmdline_cmd+cmdline_args); break;
case use_bias:
return std::string("cv bias name "+cmdline_cmd+cmdline_args); break;
default:
// Already handled, but silence the warning
return std::string("");
}
return std::string("");
}
std::string colvarscript::get_cmdline_help_summary(colvarscript::Object_type t)
{
std::string output;
output += "List of commands:\n\n";
for (size_t i = 0; i < cmd_help.size(); i++) {
std::string const prefix = get_cmd_prefix(t);
command const c = cmd_str_map[std::string(cmd_names[i])];
if (std::string(cmd_names[i], prefix.size()) == prefix) {
output += get_command_cmdline_syntax(t, c)+std::string("\n");
}
}
if (t == use_module) {
output += "\nFor detailed help on each command use:\n"
" cv help <command>\n";
output += "\nTo list all commands acting on collective variables use:\n"
" cv help colvar\n";
output += "\nTo list all commands acting on biases use:\n"
" cv help bias\n";
}
if (t == use_colvar) {
output += "\nFor detailed help on each command use:\n"
" cv colvar name help <command> (\"name\" does not need to exist)\n";
}
if (t == use_bias) {
output += "\nFor detailed help on each command use:\n"
" cv bias name help <command> (\"name\" does not need to exist)\n";
}
return output;
}
std::string colvarscript::get_command_cmdline_help(colvarscript::Object_type t,
std::string const &cmd)
{
std::string const cmdkey(get_cmd_prefix(t)+cmd);
if (cmd_str_map.count(cmdkey) > 0) {
command const c = cmd_str_map[cmdkey];
return get_command_cmdline_syntax(t, c)+"\n\n"+
get_command_full_help(cmd_names[c]);
}
cvm::set_error_bits(COLVARS_INPUT_ERROR);
return std::string("Could not find scripting command \""+cmd+"\".");
}
int colvarscript::run(int objc, unsigned char *const objv[])
{
clear_str_result();
if (cvm::debug()) {
cvm::log("Called script run with " + cvm::to_str(objc) + " args:");
for (int i = 0; i < objc; i++) {
cvm::log(obj_to_str(objv[i]));
}
}
if (objc < 2) {
set_result_str("No commands given: use \"cv help\" "
"for a list of commands.");
return COLVARSCRIPT_ERROR;
}
// Main command; usually "cv"
std::string const main_cmd(std::string(obj_to_str(objv[0])));
// Name of the (sub)command
std::string const cmd(obj_to_str(objv[1]));
// Build a safe-to-print command line to print in case of error
std::string cmdline(main_cmd+std::string(" ")+cmd);
// Pointer to the function implementing it
int (*cmd_fn)(void *, int, unsigned char * const *) = NULL;
// Pointer to object handling the command (the functions are C)
void *obj_for_cmd = NULL;
if (cmd == "colvar") {
if (objc < 4) {
add_error_msg("Missing parameters: use \""+main_cmd+
" help colvar\" for a summary");
return COLVARSCRIPT_ERROR;
}
std::string const name(obj_to_str(objv[2]));
std::string const subcmd(obj_to_str(objv[3]));
obj_for_cmd = reinterpret_cast<void *>(cvm::colvar_by_name(name));
if (obj_for_cmd == NULL) {
if (subcmd != std::string("help")) {
// Unless asking for help, a valid colvar name must be given
add_error_msg("Colvar not found: " + name);
return COLVARSCRIPT_ERROR;
}
}
cmd_fn = get_cmd_fn(get_cmd_prefix(use_colvar)+subcmd);
cmdline += std::string(" name ")+subcmd;
if (objc > 4) {
cmdline += " ...";
}
} else if (cmd == "bias") {
if (objc < 4) {
add_error_msg("Missing parameters: use \""+main_cmd+
" help bias\" for a summary");
return COLVARSCRIPT_ERROR;
}
std::string const name(obj_to_str(objv[2]));
std::string const subcmd(obj_to_str(objv[3]));
obj_for_cmd = reinterpret_cast<void *>(cvm::bias_by_name(name));
if (obj_for_cmd == NULL) {
if ((subcmd == "") || (subcmd != std::string("help"))) {
// Unless asking for help, a valid bias name must be given
add_error_msg("Bias not found: " + name);
return COLVARSCRIPT_ERROR;
}
}
cmd_fn = get_cmd_fn(get_cmd_prefix(use_bias)+subcmd);
cmdline += std::string(" name ")+subcmd;
if (objc > 4) {
cmdline += " ...";
}
} else {
cmd_fn = get_cmd_fn(get_cmd_prefix(use_module)+cmd);
obj_for_cmd = reinterpret_cast<void *>(this);
if (objc > 2) {
cmdline += " ...";
}
}
int error_code = COLVARS_OK;
// If command was found in map, execute it
if (cmd_fn) {
error_code = (*cmd_fn)(obj_for_cmd, objc, objv);
} else {
add_error_msg("Syntax error: "+cmdline+"\n"
" Run \"cv help\" or \"cv help <command>\" "
"to get the correct syntax.\n");
error_code = COLVARSCRIPT_ERROR;
}
return error_code;
}
char *colvarscript::obj_to_str(unsigned char *obj)
{
char *strobj = reinterpret_cast<char *>(obj);
if (cvm::debug()) {
cvm::log("Using simple-cast script::obj_to_str(): result = \"" +
(strobj ? std::string(strobj) : std::string("(null)")) + "\"");
}
return strobj;
}
std::vector<std::string> colvarscript::obj_to_str_vector(unsigned char *obj)
{
if (cvm::debug()) {
cvm::log("Using simple-cast colvarscript::obj_to_str_vector().\n");
}
std::vector<std::string> new_result;
std::string const str(reinterpret_cast<char *>(obj));
// TODO get rid of this once colvarscript can handle both fix_modify and Tcl?
// LAMMPS has a nicer function in the utils class
for (size_t i = 0; i < str.length(); i++) {
char const c = str[i];
if (c == '\"') {
i++;
if (i >= str.length()) {
cvm::error("Error: could not split the following string:\n"+
str+"\n", COLVARS_INPUT_ERROR);
break;
}
new_result.push_back(std::string(""));
while (str[i] != '\"') {
new_result.back().append(1, str[i]);
if (i >= str.length()) {
cvm::error("Error: could not split the following string:\n"+
str+"\n", COLVARS_INPUT_ERROR);
break;
} else {
i++;
}
}
}
}
if (cvm::debug()) {
cvm::log("result = "+cvm::to_str(new_result)+".\n");
}
return new_result;
}
int colvarscript::proc_features(colvardeps *obj,
int objc, unsigned char *const objv[]) {
// size was already checked before calling
std::string const subcmd(obj_to_str(objv[3]));
if (cvm::debug()) {
cvm::log("Called proc_features() with " + cvm::to_str(objc) + " args:");
for (int i = 0; i < objc; i++) {
cvm::log(obj_to_str(objv[i]));
}
}
if ((subcmd == "get") || (subcmd == "set")) {
std::vector<colvardeps::feature *> const &features = obj->features();
std::string const req_feature(obj_to_str(objv[4]));
colvardeps::feature *f = NULL;
int fid = 0;
for (fid = 0; fid < int(features.size()); fid++) {
if (features[fid]->description ==
colvarparse::to_lower_cppstr(req_feature)) {
f = features[fid];
break;
}
}
if (f == NULL) {
add_error_msg("Error: feature \""+req_feature+"\" does not exist.\n");
return COLVARSCRIPT_ERROR;
} else {
if (! obj->is_available(fid)) {
add_error_msg("Error: feature \""+req_feature+"\" is unavailable.\n");
return COLVARSCRIPT_ERROR;
}
if (subcmd == "get") {
set_result_str(cvm::to_str(obj->is_enabled(fid) ? 1 : 0));
return COLVARS_OK;
}
if (subcmd == "set") {
if (objc == 6) {
std::string const yesno =
colvarparse::to_lower_cppstr(std::string(obj_to_str(objv[5])));
if ((yesno == std::string("yes")) ||
(yesno == std::string("on")) ||
(yesno == std::string("1"))) {
obj->enable(fid);
return COLVARS_OK;
} else if ((yesno == std::string("no")) ||
(yesno == std::string("off")) ||
(yesno == std::string("0"))) {
obj->disable(fid);
return COLVARS_OK;
}
}
add_error_msg("Missing value when setting feature \""+req_feature+
"\".\n");
return COLVARSCRIPT_ERROR;
}
}
}
// This shouldn't be reached any more
return COLVARSCRIPT_ERROR;
}
int colvarscript::unsupported_op()
{
return cvm::error("Error: unsupported script operation.\n",
COLVARS_NOT_IMPLEMENTED);
}
int colvarscript::set_result_str(std::string const &s)
{
if (cvm::get_error() != COLVARS_OK) {
// Avoid overwriting the error message
modify_str_result() += s;
} else {
modify_str_result() = s;
}
return COLVARS_OK;
}
void colvarscript::add_error_msg(std::string const &s)
{
modify_str_result() += s;
// Ensure terminating newlines
if (s[s.size()-1] != '\n') {
modify_str_result() += "\n";
}
}
int colvarscript::clear_str_result()
{
modify_str_result().clear();
return COLVARS_OK;
}
extern "C"
int run_colvarscript_command(int objc, unsigned char *const objv[])
{
colvarmodule *cv = cvm::main();
colvarscript *script = cv ? cv->proxy->script : NULL;
if (!script) {
cvm::error("Called run_colvarscript_command without a script object.\n",
COLVARS_BUG_ERROR);
return -1;
}
int retval = script->run(objc, objv);
return retval;
}
extern "C"
const char * get_colvarscript_result()
{
colvarscript *script = colvarscript_obj();
if (!script) {
cvm::error("Called get_colvarscript_result without a script object.\n");
return NULL;
}
return script->str_result().c_str();
}
#if defined(COLVARS_TCL)
#if defined(VMDTCL)
// Function used by VMD to set up the module
int tcl_colvars_vmd_init(Tcl_Interp *interp, int molid);
#endif
#if !defined(VMDTCL) && !defined(NAMD_TCL)
// Initialize Colvars when loaded as a shared library into Tcl interpreter
extern "C" {
int Colvars_Init(Tcl_Interp *interp) {
colvarproxy *proxy = new colvarproxy();
colvarmodule *colvars = new colvarmodule(proxy);
proxy->set_tcl_interp(interp);
proxy->colvars = colvars;
Tcl_CreateObjCommand(interp, "cv", tcl_run_colvarscript_command,
(ClientData *) NULL, (Tcl_CmdDeleteProc *) NULL);
Tcl_EvalEx(interp, "package provide colvars", -1, 0);
return TCL_OK;
}
}
#endif
extern "C" int tcl_run_colvarscript_command(ClientData /* clientData */,
Tcl_Interp *my_interp,
int objc, Tcl_Obj *const objv[])
{
colvarmodule *colvars = cvm::main();
if (!colvars) {
#if defined(VMDTCL)
if (objc == 2) {
if (!strcmp(Tcl_GetString(objv[1]), "molid")) {
// return invalid molid
Tcl_SetResult(my_interp, (char *) "-1", TCL_STATIC);
}
if (!strcmp(Tcl_GetString(objv[1]), "delete") ||
!strcmp(Tcl_GetString(objv[1]), "reset")) {
// nothing to delete or reset
Tcl_SetResult(my_interp, NULL, TCL_STATIC);
}
if (!strcmp(Tcl_GetString(objv[1]), "help")) {
// print message
Tcl_SetResult(my_interp,
(char *) "First, setup the Colvars module with: "
"cv molid <id>|top", TCL_STATIC);
}
return TCL_OK;
}
if (objc >= 3) {
// require a molid to create the module
if (!strcmp(Tcl_GetString(objv[1]), "molid")) {
int molid = -(1<<16); // This value is used to indicate "top"
if (strcmp(Tcl_GetString(objv[2]), "top")) {
// If this is not "top", get the integer value
Tcl_GetIntFromObj(my_interp, objv[2], &molid);
}
return tcl_colvars_vmd_init(my_interp, molid);
} else {
Tcl_SetResult(my_interp, (char *) "Syntax error. First, setup the Colvars module with cv molid <id>|top", TCL_STATIC);
return TCL_ERROR;
}
}
Tcl_SetResult(my_interp, (char *) "First, setup the Colvars module with: "
"cv molid <id>|top", TCL_STATIC);
#else
Tcl_SetResult(my_interp,
const_cast<char *>("Error: Colvars module not yet initialized"),
TCL_STATIC);
#endif
return TCL_ERROR;
}
colvarproxy *proxy = colvars->proxy;
Tcl_Interp *interp = my_interp ? my_interp : proxy->get_tcl_interp();
colvarscript *script = colvarscript_obj();
if (!script) {
char const *errstr = "Called tcl_run_colvarscript_command "
"without a Colvars script interface set up.\n";
Tcl_SetResult(interp, const_cast<char *>(errstr), TCL_VOLATILE);
return TCL_ERROR;
}
cvm::clear_error();
unsigned char * arg_pointers_[100];
if (objc > 100) {
std::string const errstr = "Too many positional arguments ("+
cvm::to_str(objc)+") passed to the \"cv\" command.\n";
Tcl_SetResult(interp, const_cast<char *>(errstr.c_str()), TCL_VOLATILE);
return TCL_ERROR;
}
for (int i = 0; i < objc; i++) {
arg_pointers_[i] = reinterpret_cast<unsigned char *>(const_cast<char *>(proxy->tcl_get_str(objv[i])));
}
int retval = script->run(objc, arg_pointers_);
std::string result = proxy->get_error_msgs() + script->str_result();
Tcl_SetResult(interp, const_cast<char *>(result.c_str()),
TCL_VOLATILE);
if (proxy->delete_requested()) {
if (!proxy->simulation_running()) {
// Running in VMD
Tcl_SetResult(interp,
const_cast<char *>("Deleting Colvars module"
": to recreate, use cv molid <molecule ID>"),
TCL_STATIC);
}
delete proxy;
proxy = NULL;
}
return (retval == COLVARS_OK) ? TCL_OK : TCL_ERROR;
}
#endif // #if defined(COLVARS_TCL)
int colvarscript::set_result_text_from_str(std::string const &x_str,
unsigned char *obj) {
if (obj) {
strcpy(reinterpret_cast<char *>(obj), x_str.c_str());
} else {
set_result_str(x_str);
}
return COLVARS_OK;
}
// Template to convert everything to string and use the above
template <typename T>
int colvarscript::set_result_text(T const &x, unsigned char *obj) {
std::string const x_str = x.to_simple_string();
return set_result_text_from_str(x_str, obj);
}
template <typename T>
int colvarscript::pack_vector_elements_text(std::vector<T> const &x,
std::string &x_str) {
x_str.clear();
for (size_t i = 0; i < x.size(); ++i) {
if (i > 0) x_str.append(1, ' ');
x_str += cvm::to_str(x[i]);
}
return COLVARS_OK;
}
// Specializations for plain old data types that don't have a stringifier member
template <>
int colvarscript::set_result_text(int const &x, unsigned char *obj) {
std::string const x_str = cvm::to_str(x);
return set_result_text_from_str(x_str, obj);
}
template <>
int colvarscript::set_result_text(std::vector<int> const &x,
unsigned char *obj) {
std::string x_str("");
pack_vector_elements_text<int>(x, x_str);
return set_result_text_from_str(x_str, obj);
}
template <>
int colvarscript::set_result_text(long int const &x, unsigned char *obj) {
std::string const x_str = cvm::to_str(x);
return set_result_text_from_str(x_str, obj);
}
template <>
int colvarscript::set_result_text(std::vector<long int> const &x,
unsigned char *obj) {
std::string x_str("");
pack_vector_elements_text<long int>(x, x_str);
return set_result_text_from_str(x_str, obj);
}
template <>
int colvarscript::set_result_text(cvm::real const &x, unsigned char *obj) {
std::string const x_str = cvm::to_str(x);
return set_result_text_from_str(x_str, obj);
}
template <>
int colvarscript::set_result_text(std::vector<cvm::real> const &x,
unsigned char *obj) {
std::string x_str("");
pack_vector_elements_text<cvm::real>(x, x_str);
return set_result_text_from_str(x_str, obj);
}
// TODO these can be removed after the Tcl backend is ready (otherwise, the
// default template syntax may break scripts or the Dashboard)
template <>
int colvarscript::set_result_text(std::vector<cvm::rvector> const &x,
unsigned char *obj) {
std::string x_str("");
for (size_t i = 0; i < x.size(); i++) {
if (i > 0) x_str.append(1, ' ');
x_str += "{ "+x[i].to_simple_string()+" }";
}
return set_result_text_from_str(x_str, obj);
}
template <>
int colvarscript::set_result_text(std::vector<colvarvalue> const &x,
unsigned char *obj) {
std::string x_str("");
for (size_t i = 0; i < x.size(); i++) {
if (i > 0) x_str.append(1, ' ');
x_str += "{ "+x[i].to_simple_string()+" }";
}
return set_result_text_from_str(x_str, obj);
}
// Member functions to set script results for each typexc
int colvarscript::set_result_int(int const &x, unsigned char *obj) {
return set_result_text<int>(x, obj);
}
int colvarscript::set_result_int_vec(std::vector<int> const &x,
unsigned char *obj) {
return set_result_text< std::vector<int> >(x, obj);
}
int colvarscript::set_result_long_int(long int const &x, unsigned char *obj) {
return set_result_text<long int>(x, obj);
}
int colvarscript::set_result_long_int_vec(std::vector<long int> const &x,
unsigned char *obj) {
return set_result_text< std::vector<long int> >(x, obj);
}
int colvarscript::set_result_real(cvm::real const &x, unsigned char *obj) {
return set_result_text<cvm::real>(x, obj);
}
int colvarscript::set_result_real_vec(std::vector<cvm::real> const &x,
unsigned char *obj) {
return set_result_text< std::vector<cvm::real> >(x, obj);
}
int colvarscript::set_result_rvector(cvm::rvector const &x, unsigned char *obj) {
return set_result_text<cvm::rvector>(x, obj);
}
int colvarscript::set_result_rvector_vec(std::vector<cvm::rvector> const &x,
unsigned char *obj) {
return set_result_text< std::vector<cvm::rvector> >(x, obj);
}
int colvarscript::set_result_colvarvalue(colvarvalue const &x,
unsigned char *obj) {
return set_result_text<colvarvalue>(x, obj);
}
int colvarscript::set_result_colvarvalue_vec(std::vector<colvarvalue> const &x,
unsigned char *obj) {
return set_result_text< std::vector<colvarvalue> >(x, obj);
}