Update Colvars library to version 2025-04-18

The following is a list of pull requests relevant to LAMMPS in the Colvars repository since 2024-08-06:

- 752 New tool poisson_integrator_conv
  https://github.com/Colvars/colvars/pull/752 (@jhenin)

- 733 Custom grids for all biases
  https://github.com/Colvars/colvars/pull/733 (@giacomofiorin, @jhenin)

- 776 Avoid error in acos and asin with fast-math
  https://github.com/Colvars/colvars/pull/776 (@jhenin)

- 773 fix: fix the clang build test failure of OPES
  https://github.com/Colvars/colvars/pull/773 (@HanatoK)

- 768 fix: clamp the input values of asin and acos in case of fast math on aarch64
  https://github.com/Colvars/colvars/pull/768 (@HanatoK)

- 761 Add debug code for the Jacobi failure
  https://github.com/Colvars/colvars/pull/761 (@HanatoK)

- 759 min_image fix; Saves long runs from crashes;
  https://github.com/Colvars/colvars/pull/759 (@PolyachenkoYA)

- 757 Fix MSVC OpenMP issue
  https://github.com/Colvars/colvars/pull/757 (@HanatoK)

- 755 Fix indentation of 'Init CVC' message in standard output
  https://github.com/Colvars/colvars/pull/755 (@jhenin)

- 750 Optimize and simplify the calculation of dihedral gradients
  https://github.com/Colvars/colvars/pull/750 (@HanatoK)

- 749 Add references to new Colvars paper
  https://github.com/Colvars/colvars/pull/749 (@jhenin, @giacomofiorin)

- 740 Report the specific C++ standard at init time, stop warning about C++97/03
  https://github.com/Colvars/colvars/pull/740 (@giacomofiorin)

- 731 Improve detection of hard/mathematical boundaries
  https://github.com/Colvars/colvars/pull/731 (@giacomofiorin)

- 729 Optimize the fit gradients
  https://github.com/Colvars/colvars/pull/729 (@HanatoK, @jhenin)

- 728 Fix undefined behavior when getting the current working directory from std::filesystem
  https://github.com/Colvars/colvars/pull/728 (@giacomofiorin)

- 727 Add patchversion scripting command
  https://github.com/Colvars/colvars/pull/727 (@giacomofiorin)

- 724 Fix gradients and metric functions of distanceDir
  https://github.com/Colvars/colvars/pull/724 (@giacomofiorin)

- 715 Add missing rotation in orientation component
  https://github.com/Colvars/colvars/pull/715 (@giacomofiorin)

- 713 fix: try to solve #87 for non-scala components
  https://github.com/Colvars/colvars/pull/713 (@HanatoK)

- 709 Implementation of OPES in Colvars
  https://github.com/Colvars/colvars/pull/709 (@HanatoK, @giacomofiorin, @jhenin)

- 706 BUGFIX for Segmentation fault in colvarbias_meta::calc_energy() with useGrids off
  https://github.com/Colvars/colvars/pull/706 (@alphataubio)

- 570 enable use of CVs defined by PyTorch neural network models
  https://github.com/Colvars/colvars/pull/570 (@zwpku, @giacomofiorin, @HanatoK, @jhenin)

Authors: @alphataubio, @EzryStIago, @giacomofiorin, @HanatoK, @jhenin, @PolyachenkoYA, @zwpku
This commit is contained in:
Giacomo Fiorin
2025-04-08 12:18:07 -04:00
parent 440e24c60e
commit cba479bf6e
57 changed files with 4346 additions and 1199 deletions

View File

@ -11,27 +11,10 @@
#include <iomanip>
#include <algorithm>
// Define function to get the absolute path of a replica file
#if defined(_WIN32) && !defined(__CYGWIN__)
#include <direct.h>
#define GETCWD(BUF, SIZE) ::_getcwd(BUF, SIZE)
#define PATHSEP "\\"
#else
#include <unistd.h>
#define GETCWD(BUF, SIZE) ::getcwd(BUF, SIZE)
#define PATHSEP "/"
#endif
#ifdef __cpp_lib_filesystem
// When std::filesystem is available, use it
#include <filesystem>
#undef GETCWD
#define GETCWD(BUF, SIZE) (std::filesystem::current_path().string().c_str())
#endif
#include "colvarmodule.h"
#include "colvarproxy.h"
#include "colvar.h"
#include "colvargrid.h"
#include "colvarbias_meta.h"
#include "colvars_memstream.h"
@ -49,8 +32,6 @@ colvarbias_meta::colvarbias_meta(char const *key)
use_grids = true;
grids_freq = 0;
rebin_grids = false;
hills_energy = NULL;
hills_energy_gradients = NULL;
dump_fes = true;
keep_hills = false;
@ -161,9 +142,9 @@ int colvarbias_meta::init(std::string const &conf)
get_keyval(conf, "keepHills", keep_hills, keep_hills);
get_keyval(conf, "keepFreeEnergyFiles", dump_fes_save, dump_fes_save);
if (hills_energy == NULL) {
hills_energy = new colvar_grid_scalar(colvars);
hills_energy_gradients = new colvar_grid_gradient(colvars);
if (!hills_energy) {
hills_energy.reset(new colvar_grid_scalar(colvars, nullptr, false, grid_conf));
hills_energy_gradients.reset(new colvar_grid_gradient(colvars, nullptr, hills_energy));
}
} else {
@ -209,7 +190,7 @@ int colvarbias_meta::init_replicas_params(std::string const &conf)
get_keyval(conf, "replicaID", replica_id, replica_id);
if (!replica_id.size()) {
if (proxy->replica_enabled() == COLVARS_OK) {
if (proxy->check_replicas_enabled() == COLVARS_OK) {
// Obtain replicaID from the communicator
replica_id = cvm::to_str(proxy->replica_index());
cvm::log("Setting replicaID from communication layer: replicaID = "+
@ -272,7 +253,6 @@ int colvarbias_meta::init_ebmeta_params(std::string const &conf)
{
int error_code = COLVARS_OK;
// for ebmeta
target_dist = NULL;
get_keyval(conf, "ebMeta", ebmeta, false);
if(ebmeta){
cvm::main()->cite_feature("Ensemble-biased metadynamics (ebMetaD)");
@ -283,7 +263,7 @@ int colvarbias_meta::init_ebmeta_params(std::string const &conf)
"targetDistFile accordingly.\n",
COLVARS_INPUT_ERROR);
}
target_dist = new colvar_grid_scalar();
target_dist.reset(new colvar_grid_scalar());
error_code |= target_dist->init_from_colvars(colvars);
std::string target_dist_file;
get_keyval(conf, "targetDistFile", target_dist_file);
@ -336,33 +316,15 @@ colvarbias_meta::~colvarbias_meta()
{
colvarbias_meta::clear_state_data();
colvarproxy *proxy = cvm::main()->proxy;
proxy->close_output_stream(replica_hills_file);
proxy->close_output_stream(hills_traj_file_name());
if (target_dist) {
delete target_dist;
target_dist = NULL;
}
}
int colvarbias_meta::clear_state_data()
{
if (hills_energy) {
delete hills_energy;
hills_energy = NULL;
}
if (hills_energy_gradients) {
delete hills_energy_gradients;
hills_energy_gradients = NULL;
}
hills.clear();
hills_off_grid.clear();
return COLVARS_OK;
}
@ -451,8 +413,11 @@ int colvarbias_meta::update()
error_code |= update_grid_params();
// add new biasing energy/forces
error_code |= update_bias();
// update grid content to reflect new bias
error_code |= update_grid_data();
if (use_grids) {
// update grid content to reflect new bias
error_code |= update_grid_data();
}
if (comm != single_replica &&
(cvm::step_absolute() % replica_update_freq) == 0) {
@ -539,9 +504,9 @@ int colvarbias_meta::update_grid_params()
// map everything into new grids
colvar_grid_scalar *new_hills_energy =
new colvar_grid_scalar(*hills_energy);
new colvar_grid_scalar(*hills_energy);
colvar_grid_gradient *new_hills_energy_gradients =
new colvar_grid_gradient(*hills_energy_gradients);
new colvar_grid_gradient(*hills_energy_gradients);
// supply new boundaries to the new grids
@ -556,10 +521,8 @@ int colvarbias_meta::update_grid_params()
new_hills_energy->map_grid(*hills_energy);
new_hills_energy_gradients->map_grid(*hills_energy_gradients);
delete hills_energy;
delete hills_energy_gradients;
hills_energy = new_hills_energy;
hills_energy_gradients = new_hills_energy_gradients;
hills_energy.reset(new_hills_energy);
hills_energy_gradients.reset(new_hills_energy_gradients);
curr_bin = hills_energy->get_colvars_index();
if (cvm::debug())
@ -641,8 +604,7 @@ int colvarbias_meta::update_grid_data()
{
if ((cvm::step_absolute() % grids_freq) == 0) {
// map the most recent gaussians to the grids
project_hills(new_hills_begin, hills.end(),
hills_energy, hills_energy_gradients);
project_hills(new_hills_begin, hills.end(), hills_energy.get(), hills_energy_gradients.get());
new_hills_begin = hills.end();
// TODO: we may want to condense all into one replicas array,
@ -651,8 +613,8 @@ int colvarbias_meta::update_grid_data()
for (size_t ir = 0; ir < replicas.size(); ir++) {
replicas[ir]->project_hills(replicas[ir]->new_hills_begin,
replicas[ir]->hills.end(),
replicas[ir]->hills_energy,
replicas[ir]->hills_energy_gradients);
replicas[ir]->hills_energy.get(),
replicas[ir]->hills_energy_gradients.get());
replicas[ir]->new_hills_begin = replicas[ir]->hills.end();
}
}
@ -670,11 +632,20 @@ int colvarbias_meta::calc_energy(std::vector<colvarvalue> const *values)
replicas[ir]->bias_energy = 0.0;
}
std::vector<int> const curr_bin = values ?
hills_energy->get_colvars_index(*values) :
hills_energy->get_colvars_index();
bool index_ok = false;
std::vector<int> curr_bin;
if (hills_energy->index_ok(curr_bin)) {
if (use_grids) {
curr_bin = values ?
hills_energy->get_colvars_index(*values) :
hills_energy->get_colvars_index();
index_ok = hills_energy->index_ok(curr_bin);
}
if ( index_ok ) {
// index is within the grid: get the energy from there
for (ir = 0; ir < replicas.size(); ir++) {
@ -723,11 +694,20 @@ int colvarbias_meta::calc_forces(std::vector<colvarvalue> const *values)
}
}
std::vector<int> const curr_bin = values ?
hills_energy->get_colvars_index(*values) :
hills_energy->get_colvars_index();
bool index_ok = false;
std::vector<int> curr_bin;
if (hills_energy->index_ok(curr_bin)) {
if (use_grids) {
curr_bin = values ?
hills_energy->get_colvars_index(*values) :
hills_energy->get_colvars_index();
index_ok = hills_energy->index_ok(curr_bin);
}
if ( index_ok ) {
for (ir = 0; ir < replicas.size(); ir++) {
cvm::real const *f = &(replicas[ir]->hills_energy_gradients->value(curr_bin));
for (ic = 0; ic < num_variables(); ic++) {
@ -959,8 +939,7 @@ void colvarbias_meta::project_hills(colvarbias_meta::hill_iter h_first,
void colvarbias_meta::recount_hills_off_grid(colvarbias_meta::hill_iter h_first,
colvarbias_meta::hill_iter h_last,
colvar_grid_scalar * /* he */)
colvarbias_meta::hill_iter h_last)
{
hills_off_grid.clear();
@ -1078,9 +1057,13 @@ int colvarbias_meta::update_replicas_registry()
(replicas.back())->comm = multiple_replicas;
if (use_grids) {
(replicas.back())->hills_energy = new colvar_grid_scalar(colvars);
(replicas.back())->hills_energy_gradients = new colvar_grid_gradient(colvars);
(replicas.back())
->hills_energy.reset(new colvar_grid_scalar(colvars, hills_energy));
(replicas.back())
->hills_energy_gradients.reset(
new colvar_grid_gradient(colvars, nullptr, hills_energy));
}
if (is_enabled(f_cvb_calc_ti_samples)) {
(replicas.back())->enable(f_cvb_calc_ti_samples);
(replicas.back())->colvarbias_ti::init_grids();
@ -1336,34 +1319,40 @@ template <typename IST> IST &colvarbias_meta::read_state_data_template_(IST &is)
{
if (use_grids) {
colvar_grid_scalar *hills_energy_backup = NULL;
colvar_grid_gradient *hills_energy_gradients_backup = NULL;
std::shared_ptr<colvar_grid_scalar> hills_energy_backup;
std::shared_ptr<colvar_grid_gradient> hills_energy_gradients_backup;
if (has_data) {
bool const need_backup = has_data;
if (need_backup) {
if (cvm::debug())
cvm::log("Backupping grids for metadynamics bias \""+
this->name+"\""+
((comm != single_replica) ? ", replica \""+replica_id+"\"" : "")+".\n");
hills_energy_backup = hills_energy;
hills_energy_gradients_backup = hills_energy_gradients;
hills_energy = new colvar_grid_scalar(colvars);
hills_energy_gradients = new colvar_grid_gradient(colvars);
cvm::log("Backing up grids for metadynamics bias \"" + this->name + "\"" +
((comm != single_replica) ? ", replica \"" + replica_id + "\"" : "") + ".\n");
hills_energy_backup = std::move(hills_energy);
hills_energy_gradients_backup = std::move(hills_energy_gradients);
hills_energy.reset(new colvar_grid_scalar(colvars, hills_energy));
hills_energy_gradients.reset(new colvar_grid_gradient(colvars, nullptr, hills_energy));
}
read_grid_data_template_<IST, colvar_grid_scalar>(is, "hills_energy", hills_energy,
hills_energy_backup);
read_grid_data_template_<IST, colvar_grid_scalar>(is, "hills_energy", hills_energy.get(),
hills_energy_backup.get());
read_grid_data_template_<IST, colvar_grid_gradient>(
is, "hills_energy_gradients", hills_energy_gradients, hills_energy_gradients_backup);
read_grid_data_template_<IST, colvar_grid_gradient>(is, "hills_energy_gradients",
hills_energy_gradients.get(),
hills_energy_gradients_backup.get());
if (is) {
cvm::log(" successfully read the biasing potential and its gradients from grids.\n");
if (hills_energy_backup != nullptr) {
// Now that we have successfully updated the grids, delete the backup copies
delete hills_energy_backup;
delete hills_energy_gradients_backup;
}
} else {
if (need_backup) {
if (cvm::debug())
cvm::log("Restoring grids from backup for metadynamics bias \"" + this->name + "\"" +
((comm != single_replica) ? ", replica \"" + replica_id + "\"" : "") + ".\n");
// Restoring content from original grid
hills_energy->copy_grid(*hills_energy_backup);
hills_energy_gradients->copy_grid(*hills_energy_gradients_backup);
}
return is;
}
}
@ -1451,10 +1440,12 @@ void colvarbias_meta::rebin_grids_after_restart()
// read from the configuration file), and project onto them the
// grids just read from the restart file
colvar_grid_scalar *new_hills_energy =
new colvar_grid_scalar(colvars);
colvar_grid_gradient *new_hills_energy_gradients =
new colvar_grid_gradient(colvars);
// Create new grids based on the configuration parameters, because reading from the state
// file automatically sets the old parameters
std::shared_ptr<colvar_grid_scalar> new_hills_energy(
new colvar_grid_scalar(colvars, nullptr, false, grid_conf));
std::shared_ptr<colvar_grid_gradient> new_hills_energy_gradients(
new colvar_grid_gradient(colvars, nullptr, new_hills_energy));
if (cvm::debug()) {
std::ostringstream tmp_os;
@ -1468,9 +1459,9 @@ void colvarbias_meta::rebin_grids_after_restart()
if (restart_keep_hills && !hills.empty()) {
// if there are hills, recompute the new grids from them
cvm::log("Rebinning the energy and forces grids from "+
cvm::to_str(hills.size())+" hills (this may take a while)...\n");
project_hills(hills.begin(), hills.end(),
new_hills_energy, new_hills_energy_gradients, true);
cvm::to_str(hills.size())+" hills (this may take a bit)...\n");
project_hills(hills.begin(), hills.end(), new_hills_energy.get(),
new_hills_energy_gradients.get(), true);
cvm::log("rebinning done.\n");
} else {
@ -1481,15 +1472,13 @@ void colvarbias_meta::rebin_grids_after_restart()
new_hills_energy_gradients->map_grid(*hills_energy_gradients);
}
delete hills_energy;
delete hills_energy_gradients;
hills_energy = new_hills_energy;
hills_energy_gradients = new_hills_energy_gradients;
hills_energy = std::move(new_hills_energy);
hills_energy_gradients = std::move(new_hills_energy_gradients);
// assuming that some boundaries have expanded, eliminate those
// off-grid hills that aren't necessary any more
if (!hills.empty())
recount_hills_off_grid(hills.begin(), hills.end(), hills_energy);
recount_hills_off_grid(hills.begin(), hills.end());
}
}
@ -1718,29 +1707,17 @@ int colvarbias_meta::setup_output()
if (comm == multiple_replicas) {
// TODO: one may want to specify the path manually for intricated filesystems?
char *pwd = new char[3001];
if (GETCWD(pwd, 3000) == nullptr) {
if (pwd != nullptr) { //
delete[] pwd;
}
return cvm::error("Error: cannot get the path of the current working directory.\n",
COLVARS_BUG_ERROR);
}
auto const pwd = cvm::main()->proxy->get_current_work_dir();
replica_list_file =
(std::string(pwd)+std::string(PATHSEP)+
this->name+"."+replica_id+".files.txt");
cvm::main()->proxy->join_paths(pwd, this->name + "." + replica_id + ".files.txt");
// replica_hills_file and replica_state_file are those written
// by the current replica; within the mirror biases, they are
// those by another replica
replica_hills_file =
(std::string(pwd)+std::string(PATHSEP)+
cvm::output_prefix()+".colvars."+this->name+"."+replica_id+".hills");
replica_state_file =
(std::string(pwd)+std::string(PATHSEP)+
cvm::output_prefix()+".colvars."+this->name+"."+replica_id+".state");
delete[] pwd;
replica_hills_file = cvm::main()->proxy->join_paths(
pwd, cvm::output_prefix() + ".colvars." + this->name + "." + replica_id + ".hills");
replica_state_file = cvm::main()->proxy->join_paths(
pwd, cvm::output_prefix() + ".colvars." + this->name + "." + replica_id + ".state");
// now register this replica
@ -1842,7 +1819,7 @@ template <typename OST> OST &colvarbias_meta::write_state_data_template_(OST &os
// this is a very good time to project hills, if you haven't done
// it already!
project_hills(new_hills_begin, hills.end(), hills_energy, hills_energy_gradients);
project_hills(new_hills_begin, hills.end(), hills_energy.get(), hills_energy_gradients.get());
new_hills_begin = hills.end();
// write down the grids to the restart file