// -*- 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 #include #include #include "colvarscript.h" #include "colvardeps.h" colvarscript::colvarscript(colvarproxy *p) : proxy(p), colvars(p->colvars), proxy_error(0) { } extern "C" { // Generic hooks; NAMD and VMD have Tcl-specific versions in the respective proxies int run_colvarscript_command(int argc, const char **argv) { colvarproxy *cvp = cvm::proxy; if (!cvp) { return -1; } if (!cvp->script) { cvm::error("Called run_colvarscript_command without a script object initialized.\n"); return -1; } return cvp->script->run(argc, argv); } const char * get_colvarscript_result() { colvarproxy *cvp = cvm::proxy; if (!cvp->script) { cvm::error("Called run_colvarscript_command without a script object initialized.\n"); return ""; } return cvp->script->result.c_str(); } } /// Run method based on given arguments int colvarscript::run(int argc, char const *argv[]) { result = ""; if (cvm::debug()) { cvm::log("Called script run with " + cvm::to_str(argc) + " args"); for (int i = 0; i < argc; i++) { cvm::log(argv[i]); } } if (argc < 2) { result = help_string(); return COLVARS_OK; } std::string cmd = argv[1]; int error_code = COLVARS_OK; if (cmd == "colvar") { return proc_colvar(argc-1, &(argv[1])); } if (cmd == "bias") { return proc_bias(argc-1, &(argv[1])); } if (cmd == "version") { result = COLVARS_VERSION; return COLVARS_OK; } if (cmd == "reset") { /// Delete every child object colvars->reset(); return COLVARS_OK; } if (cmd == "delete") { // Note: the delete bit may be ignored by some backends // it is mostly useful in VMD colvars->set_error_bits(DELETE_COLVARS); return COLVARS_OK; } if (cmd == "update") { error_code |= proxy->update_input(); error_code |= colvars->calc(); error_code |= proxy->update_output(); if (error_code) { result += "Error updating the colvars module.\n"; } return error_code; } if (cmd == "list") { if (argc == 2) { for (std::vector::iterator cvi = colvars->colvars.begin(); cvi != colvars->colvars.end(); ++cvi) { result += (cvi == colvars->colvars.begin() ? "" : " ") + (*cvi)->name; } return COLVARS_OK; } else if (argc == 3 && !strcmp(argv[2], "biases")) { for (std::vector::iterator bi = colvars->biases.begin(); bi != colvars->biases.end(); ++bi) { result += (bi == colvars->biases.begin() ? "" : " ") + (*bi)->name; } return COLVARS_OK; } else { result = "Wrong arguments to command \"list\"\n" + help_string(); return COLVARSCRIPT_ERROR; } } /// Parse config from file if (cmd == "configfile") { if (argc < 3) { result = "Missing arguments\n" + help_string(); return COLVARSCRIPT_ERROR; } if (colvars->read_config_file(argv[2]) == COLVARS_OK) { return COLVARS_OK; } else { result = "Error parsing configuration file"; return COLVARSCRIPT_ERROR; } } /// Parse config from string if (cmd == "config") { if (argc < 3) { result = "Missing arguments\n" + help_string(); return COLVARSCRIPT_ERROR; } std::string conf = argv[2]; if (colvars->read_config_string(conf) == COLVARS_OK) { return COLVARS_OK; } else { result = "Error parsing configuration string"; return COLVARSCRIPT_ERROR; } } /// Load an input state file if (cmd == "load") { if (argc < 3) { result = "Missing arguments\n" + help_string(); return COLVARSCRIPT_ERROR; } proxy->input_prefix() = argv[2]; if (colvars->setup_input() == COLVARS_OK) { return COLVARS_OK; } else { result = "Error loading state file"; return COLVARSCRIPT_ERROR; } } /// Save to an output state file if (cmd == "save") { if (argc < 3) { result = "Missing arguments"; return COLVARSCRIPT_ERROR; } proxy->output_prefix_str = argv[2]; int error = 0; error |= colvars->setup_output(); error |= colvars->write_output_files(); return error ? COLVARSCRIPT_ERROR : COLVARS_OK; } /// Print the values that would go on colvars.traj if (cmd == "printframelabels") { std::ostringstream os; colvars->write_traj_label(os); result = os.str(); return COLVARS_OK; } if (cmd == "printframe") { std::ostringstream os; colvars->write_traj(os); result = os.str(); return COLVARS_OK; } if (cmd == "frame") { if (argc == 2) { long int f; int error = proxy->get_frame(f); if (error == COLVARS_OK) { result = cvm::to_str(f); return COLVARS_OK; } else { result = "Frame number is not available"; return COLVARSCRIPT_ERROR; } } else if (argc == 3) { // Failure of this function does not trigger an error, but // returns nonzero, to let scripts detect available frames int error = proxy->set_frame(strtol(argv[2], NULL, 10)); result = cvm::to_str(error == COLVARS_OK ? 0 : -1); return COLVARS_OK; } else { result = "Wrong arguments to command \"frame\"\n" + help_string(); return COLVARSCRIPT_ERROR; } } if (cmd == "addenergy") { if (argc == 3) { colvars->total_bias_energy += strtod(argv[2], NULL); return COLVARS_OK; } else { result = "Wrong arguments to command \"addenergy\"\n" + help_string(); return COLVARSCRIPT_ERROR; } } result = "Syntax error\n" + help_string(); return COLVARSCRIPT_ERROR; } int colvarscript::proc_colvar(int argc, char const *argv[]) { if (argc < 3) { result = "Missing parameters\n" + help_string(); return COLVARSCRIPT_ERROR; } std::string name = argv[1]; colvar *cv = cvm::colvar_by_name(name); if (cv == NULL) { result = "Colvar not found: " + name; return COLVARSCRIPT_ERROR; } std::string subcmd = argv[2]; if (subcmd == "value") { result = (cv->value()).to_simple_string(); return COLVARS_OK; } if (subcmd == "width") { result = cvm::to_str(cv->width, 0, cvm::cv_prec); return COLVARS_OK; } if (subcmd == "type") { result = cv->value().type_desc(cv->value().value_type); return COLVARS_OK; } if (subcmd == "update") { cv->calc(); cv->update_forces_energy(); result = (cv->value()).to_simple_string(); return COLVARS_OK; } if (subcmd == "delete") { size_t i; for (i = 0; i < cv->biases.size(); i++) { delete cv->biases[i]; } cv->biases.resize(0); // colvar destructor is tasked with the cleanup delete cv; // TODO this could be done by the destructors colvars->write_traj_label(colvars->cv_traj_os); return COLVARS_OK; } if (subcmd == "getconfig") { result = cv->get_config(); return COLVARS_OK; } if (subcmd == "getappliedforce") { result = (cv->applied_force()).to_simple_string(); return COLVARS_OK; } if (subcmd == "getsystemforce") { // TODO warning here result = (cv->total_force()).to_simple_string(); return COLVARS_OK; } if (subcmd == "gettotalforce") { result = (cv->total_force()).to_simple_string(); return COLVARS_OK; } if (subcmd == "addforce") { if (argc < 4) { result = "addforce: missing parameter: force value\n" + help_string(); return COLVARSCRIPT_ERROR; } std::string f_str = argv[3]; std::istringstream is(f_str); is.width(cvm::cv_width); is.precision(cvm::cv_prec); colvarvalue force(cv->value()); force.is_derivative(); if (force.from_simple_string(is.str()) != COLVARS_OK) { result = "addforce : error parsing force value"; return COLVARSCRIPT_ERROR; } cv->add_bias_force(force); result = force.to_simple_string(); return COLVARS_OK; } if (subcmd == "cvcflags") { if (argc < 4) { result = "cvcflags: missing parameter: vector of flags"; return COLVARSCRIPT_ERROR; } std::string flags_str = argv[3]; std::istringstream is(flags_str); std::vector flags; int flag; while (is >> flag) { flags.push_back(flag != 0); } int res = cv->set_cvc_flags(flags); if (res != COLVARS_OK) { result = "Error setting CVC flags"; return COLVARSCRIPT_ERROR; } result = "0"; return COLVARS_OK; } if ((subcmd == "get") || (subcmd == "set") || (subcmd == "state")) { return proc_features(cv, argc, argv); } result = "Syntax error\n" + help_string(); return COLVARSCRIPT_ERROR; } int colvarscript::proc_bias(int argc, char const *argv[]) { if (argc < 3) { result = "Missing parameters\n" + help_string(); return COLVARSCRIPT_ERROR; } std::string name = argv[1]; colvarbias *b = cvm::bias_by_name(name); if (b == NULL) { result = "Bias not found: " + name; return COLVARSCRIPT_ERROR; } std::string subcmd = argv[2]; if (subcmd == "energy") { result = cvm::to_str(b->get_energy()); return COLVARS_OK; } if (subcmd == "update") { b->update(); result = cvm::to_str(b->get_energy()); return COLVARS_OK; } if (subcmd == "getconfig") { result = b->get_config(); return COLVARS_OK; } // Subcommands for MW ABF if (subcmd == "bin") { int r = b->current_bin(); result = cvm::to_str(r); return COLVARS_OK; } if (subcmd == "binnum") { int r = b->bin_num(); if (r < 0) { result = "Error: calling bin_num() for bias " + b->name; return COLVARSCRIPT_ERROR; } result = cvm::to_str(r); return COLVARS_OK; } if (subcmd == "share") { int r = b->replica_share(); if (r < 0) { result = "Error: calling replica_share() for bias " + b->name; return COLVARSCRIPT_ERROR; } result = cvm::to_str(r); return COLVARS_OK; } // End commands for MW ABF if (subcmd == "delete") { // the bias destructor takes care of the cleanup at cvm level delete b; // TODO this could be done by the destructors colvars->write_traj_label(colvars->cv_traj_os); return COLVARS_OK; } if ((subcmd == "get") || (subcmd == "set") || (subcmd == "state")) { return proc_features(b, argc, argv); } if (argc >= 4) { std::string param = argv[3]; if (subcmd == "count") { int index; if (!(std::istringstream(param) >> index)) { result = "bin_count: error parsing bin index"; return COLVARSCRIPT_ERROR; } result = cvm::to_str(b->bin_count(index)); return COLVARS_OK; } result = "Syntax error\n" + help_string(); return COLVARSCRIPT_ERROR; } result = "Syntax error\n" + help_string(); return COLVARSCRIPT_ERROR; } int colvarscript::proc_features(colvardeps *obj, int argc, char const *argv[]) { // size was already checked before calling std::string subcmd = argv[2]; if (argc == 3) { if (subcmd == "state") { // TODO make this returned as result? obj->print_state(); return COLVARS_OK; } // get and set commands require more arguments result = "Syntax error\n" + help_string(); return COLVARSCRIPT_ERROR; } if ((subcmd == "get") || (subcmd == "set")) { std::vector &features = obj->features(); std::string const req_feature(argv[3]); 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) { result = "Error: feature \""+req_feature+"\" does not exist.\n"; return COLVARSCRIPT_ERROR; } else { if (! obj->is_available(fid)) { result = "Error: feature \""+req_feature+"\" is unavailable.\n"; return COLVARSCRIPT_ERROR; } if (subcmd == "get") { result = cvm::to_str(obj->is_enabled(fid) ? 1 : 0); return COLVARS_OK; } if (subcmd == "set") { if (argc == 5) { std::string const yesno = colvarparse::to_lower_cppstr(std::string(argv[4])); 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"))) { // TODO disable() function does not exist yet, // dependencies will not be resolved // obj->disable(fid); obj->set_enabled(fid, false); return COLVARS_OK; } } result = "Syntax error\n" + help_string(); return COLVARSCRIPT_ERROR; } } } result = "Syntax error\n" + help_string(); return COLVARSCRIPT_ERROR; } std::string colvarscript::help_string() { std::string buf; buf = "Usage: cv [args...]\n\ \n\ Managing the colvars module:\n\ configfile -- read configuration from a file\n\ config -- read configuration from the given string\n\ reset -- delete all internal configuration\n\ delete -- delete this colvars module instance\n\ version -- return version of colvars code\n\ \n\ Input and output:\n\ list -- return a list of all variables\n\ list biases -- return a list of all biases\n\ load -- load a state file (requires configuration)\n\ save -- save a state file (requires configuration)\n\ update -- recalculate colvars and biases\n\ addenergy -- add to the total bias energy\n\ printframe -- return a summary of the current frame\n\ printframelabels -- return labels to annotate printframe's output\n"; long int tmp; if (proxy->get_frame(tmp) != COLVARS_NOT_IMPLEMENTED) { buf += "\ frame -- return current frame number\n\ frame -- set frame number\n"; } buf += "\n\ Accessing collective variables:\n\ colvar value -- return the current value of colvar \n\ colvar update -- recalculate colvar \n\ colvar type -- return the type of colvar \n\ colvar delete -- delete colvar \n\ colvar addforce -- apply given force on colvar \n\ colvar getconfig -- return config string of colvar \n\ colvar cvcflags -- enable or disable cvcs according to 0/1 flags\n\ colvar get -- get the value of the colvar feature \n\ colvar set -- set the value of the colvar feature \n\ \n\ Accessing biases:\n\ bias energy -- return the current energy of bias \n\ bias update -- recalculate bias \n\ bias delete -- delete bias \n\ bias getconfig -- return config string of bias \n\ bias get -- get the value of the bias feature \n\ bias set -- set the value of the bias feature \n\ "; return buf; }