Update Colvars library to version 2023-05-01

This update consists exclusively of bugfixes or maintenance-related changes.

The following is a list of pull requests in the Colvars repository since the previous update to LAMMPS:

- 532 Add XYZ trajectory reading feature
  https://github.com/Colvars/colvars/pull/532 (@jhenin, @giacomofiorin)

- 531 Delete objects quietly, unless explicitly requested via script (including VMD)
  https://github.com/Colvars/colvars/pull/531 (@giacomofiorin)

- 530 Append newline to log and error messages if not already present
  https://github.com/Colvars/colvars/pull/530 (@giacomofiorin)

- 528 Forward-declare OpenMP lock
  https://github.com/Colvars/colvars/pull/528 (@giacomofiorin)

- 527 Remove unneeded STL container
  https://github.com/Colvars/colvars/pull/527 (@giacomofiorin)

- 526 Allow collecting configuration files and strings before setting up interface
  https://github.com/Colvars/colvars/pull/526 (@giacomofiorin, @jhenin)

- 523 Fallback to linearCombination when customFunction is missing in customColvar
  https://github.com/Colvars/colvars/pull/523 (@HanatoK, @giacomofiorin)

- 522 Use iostream::fail() to check for I/O error
  https://github.com/Colvars/colvars/pull/522 (@jhenin)

- 520 Fix ref count
  https://github.com/Colvars/colvars/pull/520 (@giacomofiorin)

- 513 Set target temperature through a common code path
  https://github.com/Colvars/colvars/pull/513 (@giacomofiorin, @jhenin)

- 509 Safer detection of Windows with recent Microsoft Visual Studio versions
  https://github.com/Colvars/colvars/pull/509 (@akohlmey)

- 508 Update LAMMPS patching method to reflect Lepton availability
  https://github.com/Colvars/colvars/pull/508 (@giacomofiorin)

- 497 Increase the precision of write_multicol
  https://github.com/Colvars/colvars/pull/497 (@HanatoK)

- 496 Only perform MTS automatic enable/disable for timeStepFactor > 1
  https://github.com/Colvars/colvars/pull/496 (@giacomofiorin)

- 493 Remove unused branch of quaternion input function
  https://github.com/Colvars/colvars/pull/493 (@giacomofiorin)

- 489 Ensure there are spaces between the fields in the header
  https://github.com/Colvars/colvars/pull/489 (@HanatoK)

- 487 Use map of output streams, and return references to its elements
  https://github.com/Colvars/colvars/pull/487 (@giacomofiorin, @jhenin)

- 486 Remember first step of moving restraint
  https://github.com/Colvars/colvars/pull/486 (@jhenin)

- 485 Add decoupling option for moving restraints
  https://github.com/Colvars/colvars/pull/485 (@jhenin)

- 483 Update Lepton via patching procedure
  https://github.com/Colvars/colvars/pull/483 (@giacomofiorin)

- 481 Make file-reading operations of input data abstractable
  https://github.com/Colvars/colvars/pull/481 (@giacomofiorin)

Authors: @akohlmey, @giacomofiorin, @HanatoK, @jhenin
This commit is contained in:
Giacomo Fiorin
2023-05-17 13:29:00 -04:00
parent 166301180b
commit 377c652a83
53 changed files with 2575 additions and 2273 deletions

View File

@ -36,7 +36,6 @@ colvarbias_meta::colvarbias_meta(char const *key)
: colvarbias(key), colvarbias_ti(key)
{
new_hills_begin = hills.end();
hills_traj_os = NULL;
hill_weight = 0.0;
hill_width = 0.0;
@ -268,28 +267,31 @@ int colvarbias_meta::init_well_tempered_params(std::string const &conf)
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)");
if (use_grids && expand_grids) {
cvm::error("Error: expandBoundaries is not supported with "
"ebMeta please allocate wide enough boundaries for "
"each colvar ahead of time and set targetdistfile "
"accordingly.\n", COLVARS_INPUT_ERROR);
error_code |= cvm::error("Error: expandBoundaries is not supported with "
"ebMeta; please allocate wide enough boundaries "
"for each colvar ahead of time and set "
"targetDistFile accordingly.\n",
COLVARS_INPUT_ERROR);
}
target_dist = new colvar_grid_scalar();
target_dist->init_from_colvars(colvars);
error_code |= target_dist->init_from_colvars(colvars);
std::string target_dist_file;
get_keyval(conf, "targetDistFile", target_dist_file);
std::ifstream targetdiststream(target_dist_file.c_str());
target_dist->read_multicol(targetdiststream);
error_code |= target_dist->read_multicol(target_dist_file,
"ebMeta target histogram");
cvm::real min_val = target_dist->minimum_value();
cvm::real max_val = target_dist->maximum_value();
if(min_val<0){
cvm::error("Error: Target distribution of EBMetaD "
"has negative values!.\n", COLVARS_INPUT_ERROR);
if (min_val < 0.0) {
error_code |= cvm::error("Error: Target distribution of EBMetaD "
"has negative values!.\n",
COLVARS_INPUT_ERROR);
}
cvm::real target_dist_min_val;
get_keyval(conf, "targetDistMinVal", target_dist_min_val, 1/1000000.0);
@ -301,17 +303,19 @@ int colvarbias_meta::init_ebmeta_params(std::string const &conf)
cvm::log("NOTE: targetDistMinVal is set to zero, the minimum value of the target \n");
cvm::log(" distribution will be set as the minimum positive value.\n");
cvm::real min_pos_val = target_dist->minimum_pos_value();
if(min_pos_val<=0){
cvm::error("Error: Target distribution of EBMetaD has negative "
"or zero minimum positive value!.\n", COLVARS_INPUT_ERROR);
if (min_pos_val <= 0.0){
error_code |= cvm::error("Error: Target distribution of EBMetaD has "
"negative or zero minimum positive value.\n",
COLVARS_INPUT_ERROR);
}
if(min_val==0){
if (min_val == 0.0){
cvm::log("WARNING: Target distribution has zero values.\n");
cvm::log("Zeros will be converted to the minimum positive value.\n");
target_dist->remove_small_values(min_pos_val);
}
} else {
cvm::error("Error: targetDistMinVal must be a value between 0 and 1!.\n", COLVARS_INPUT_ERROR);
error_code |= 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)
@ -321,23 +325,18 @@ int colvarbias_meta::init_ebmeta_params(std::string const &conf)
get_keyval(conf, "ebMetaEquilSteps", ebmeta_equil_steps, ebmeta_equil_steps);
}
return COLVARS_OK;
return error_code;
}
colvarbias_meta::~colvarbias_meta()
{
colvarbias_meta::clear_state_data();
colvarproxy *proxy = cvm::proxy;
colvarproxy *proxy = cvm::main()->proxy;
if (proxy->get_output_stream(replica_hills_file)) {
proxy->close_output_stream(replica_hills_file);
}
proxy->close_output_stream(replica_hills_file);
if (hills_traj_os) {
proxy->close_output_stream(hills_traj_file_name());
hills_traj_os = NULL;
}
proxy->close_output_stream(hills_traj_file_name());
if (target_dist) {
delete target_dist;
@ -392,9 +391,12 @@ colvarbias_meta::add_hill(colvarbias_meta::hill const &h)
}
// output to trajectory (if specified)
if (hills_traj_os) {
*hills_traj_os << (hills.back()).output_traj();
cvm::proxy->flush_output_stream(hills_traj_os);
if (b_hills_traj) {
// Open trajectory file or access the one already open
std::ostream &hills_traj_os =
cvm::proxy->output_stream(hills_traj_file_name());
hills_traj_os << (hills.back()).output_traj();
cvm::proxy->flush_output_stream(hills_traj_file_name());
}
has_data = true;
@ -424,12 +426,14 @@ colvarbias_meta::delete_hill(hill_iter &h)
}
}
if (hills_traj_os) {
if (b_hills_traj) {
// output to the trajectory
*hills_traj_os << "# DELETED this hill: "
<< (hills.back()).output_traj()
<< "\n";
cvm::proxy->flush_output_stream(hills_traj_os);
std::ostream &hills_traj_os =
cvm::proxy->output_stream(hills_traj_file_name());
hills_traj_os << "# DELETED this hill: "
<< (hills.back()).output_traj()
<< "\n";
cvm::proxy->flush_output_stream(hills_traj_file_name());
}
return hills.erase(h);
@ -573,6 +577,7 @@ int colvarbias_meta::update_grid_params()
int colvarbias_meta::update_bias()
{
colvarproxy *proxy = cvm::main()->proxy;
// add a new hill if the required time interval has passed
if (((cvm::step_absolute() % new_hill_freq) == 0) &&
can_accumulate_data() && is_enabled(f_cvb_history_dependent)) {
@ -603,7 +608,7 @@ int colvarbias_meta::update_bias()
} else {
calc_hills(new_hills_begin, hills.end(), hills_energy_sum_here, NULL);
}
hills_scale *= cvm::exp(-1.0*hills_energy_sum_here/(bias_temperature*cvm::boltzmann()));
hills_scale *= cvm::exp(-1.0*hills_energy_sum_here/(bias_temperature*proxy->boltzmann()));
}
switch (comm) {
@ -618,10 +623,10 @@ int colvarbias_meta::update_bias()
case multiple_replicas:
add_hill(hill(cvm::step_absolute(), hill_weight*hills_scale,
colvar_values, colvar_sigmas, replica_id));
std::ostream *replica_hills_os =
cvm::proxy->get_output_stream(replica_hills_file);
std::ostream &replica_hills_os =
cvm::proxy->output_stream(replica_hills_file);
if (replica_hills_os) {
*replica_hills_os << hills.back();
replica_hills_os << hills.back();
} else {
return cvm::error("Error: in metadynamics bias \""+this->name+"\""+
((comm != single_replica) ? ", replica \""+replica_id+"\"" : "")+
@ -979,25 +984,24 @@ void colvarbias_meta::recount_hills_off_grid(colvarbias_meta::hill_iter h_first
int colvarbias_meta::replica_share()
{
int error_code = COLVARS_OK;
colvarproxy *proxy = cvm::proxy;
// sync with the other replicas (if needed)
if (comm == multiple_replicas) {
// reread the replicas registry
update_replicas_registry();
error_code |= update_replicas_registry();
// empty the output buffer
std::ostream *replica_hills_os =
proxy->get_output_stream(replica_hills_file);
if (replica_hills_os) {
proxy->flush_output_stream(replica_hills_os);
}
read_replica_files();
error_code |= proxy->flush_output_stream(replica_hills_file);
error_code |= read_replica_files();
}
return COLVARS_OK;
return error_code;
}
void colvarbias_meta::update_replicas_registry()
int colvarbias_meta::update_replicas_registry()
{
int error_code = COLVARS_OK;
if (cvm::debug())
cvm::log("Metadynamics bias \""+this->name+"\""+
": updating the list of replicas, currently containing "+
@ -1012,8 +1016,9 @@ void colvarbias_meta::update_replicas_registry()
while (colvarparse::getline_nocomments(reg_file, line))
replicas_registry.append(line+"\n");
} else {
cvm::error("Error: failed to open file \""+replicas_registry_file+
"\" for reading.\n", COLVARS_FILE_ERROR);
error_code |= cvm::error("Error: failed to open file \""+
replicas_registry_file+"\" for reading.\n",
COLVARS_FILE_ERROR);
}
}
@ -1081,8 +1086,8 @@ void colvarbias_meta::update_replicas_registry()
}
}
} else {
cvm::error("Error: cannot read the replicas registry file \""+
replicas_registry+"\".\n", COLVARS_FILE_ERROR);
error_code |= cvm::error("Error: cannot read the replicas registry file \""+
replicas_registry+"\".\n", COLVARS_FILE_ERROR);
}
// now (re)read the list file of each replica
@ -1122,10 +1127,12 @@ void colvarbias_meta::update_replicas_registry()
if (cvm::debug())
cvm::log("Metadynamics bias \""+this->name+"\": the list of replicas contains "+
cvm::to_str(replicas.size())+" elements.\n");
return error_code;
}
void colvarbias_meta::read_replica_files()
int colvarbias_meta::read_replica_files()
{
// Note: we start from the 2nd replica.
for (size_t ir = 1; ir < replicas.size(); ir++) {
@ -1250,6 +1257,7 @@ void colvarbias_meta::read_replica_files()
" steps. Ensure that it is still running.\n");
}
}
return COLVARS_OK;
}
@ -1413,6 +1421,10 @@ std::istream & colvarbias_meta::read_state_data(std::istream& is)
size_t const old_hills_size = hills.size();
hill_iter old_hills_end = hills.end();
hill_iter old_hills_off_grid_end = hills_off_grid.end();
if (cvm::debug()) {
cvm::log("Before reading hills from the state file, there are "+
cvm::to_str(hills.size())+" hills in memory.\n");
}
// Read any hills following the grid data (if any)
while (read_hill(is)) {
@ -1431,6 +1443,10 @@ std::istream & colvarbias_meta::read_state_data(std::istream& is)
if (existing_hills) {
hills.erase(hills.begin(), old_hills_end);
hills_off_grid.erase(hills_off_grid.begin(), old_hills_off_grid_end);
if (cvm::debug()) {
cvm::log("After pruning the old hills, there are now "+
cvm::to_str(hills.size())+" hills in memory.\n");
}
}
if (rebin_grids) {
@ -1614,6 +1630,8 @@ std::istream & colvarbias_meta::read_hill(std::istream &is)
int colvarbias_meta::setup_output()
{
int error_code = COLVARS_OK;
output_prefix = cvm::output_prefix();
if (cvm::main()->num_biases_feature(colvardeps::f_cvb_calc_pmf) > 1) {
// if this is not the only free energy integrator, append
@ -1626,8 +1644,11 @@ int colvarbias_meta::setup_output()
// TODO: one may want to specify the path manually for intricated filesystems?
char *pwd = new char[3001];
if (GETCWD(pwd, 3000) == NULL)
cvm::error("Error: cannot get the path of the current working directory.\n");
if (GETCWD(pwd, 3000) == NULL) {
return cvm::error("Error: cannot get the path of the current working directory.\n",
COLVARS_BUG_ERROR);
}
replica_list_file =
(std::string(pwd)+std::string(PATHSEP)+
this->name+"."+replica_id+".files.txt");
@ -1680,38 +1701,35 @@ int colvarbias_meta::setup_output()
// if we're running without grids, use a growing list of "hills" files
// otherwise, just one state file and one "hills" file as buffer
std::ostream *list_os =
cvm::proxy->output_stream(replica_list_file,
(use_grids ? std::ios_base::trunc :
std::ios_base::app));
if (!list_os) {
return cvm::get_error();
std::ostream &list_os = cvm::proxy->output_stream(replica_list_file);
if (list_os) {
list_os << "stateFile " << replica_state_file << "\n";
list_os << "hillsFile " << replica_hills_file << "\n";
cvm::proxy->close_output_stream(replica_list_file);
} else {
error_code |= COLVARS_FILE_ERROR;
}
*list_os << "stateFile " << replica_state_file << "\n";
*list_os << "hillsFile " << replica_hills_file << "\n";
cvm::proxy->close_output_stream(replica_list_file);
// finally, add a new record for this replica to the registry
if (! registered_replica) {
std::ostream *reg_os =
cvm::proxy->output_stream(replicas_registry_file,
std::ios::app);
std::ofstream reg_os(replicas_registry_file.c_str(), std::ios::app);
if (!reg_os) {
return cvm::get_error();
}
*reg_os << replica_id << " " << replica_list_file << "\n";
reg_os << replica_id << " " << replica_list_file << "\n";
cvm::proxy->close_output_stream(replicas_registry_file);
}
}
if (b_hills_traj) {
std::ostream &hills_traj_os =
cvm::proxy->output_stream(hills_traj_file_name());
if (!hills_traj_os) {
hills_traj_os = cvm::proxy->output_stream(hills_traj_file_name());
if (!hills_traj_os) return cvm::get_error();
error_code |= COLVARS_FILE_ERROR;
}
}
return (cvm::get_error() ? COLVARS_ERROR : COLVARS_OK);
return error_code;
}
@ -1804,6 +1822,7 @@ int colvarbias_meta::write_output_files()
void colvarbias_meta::write_pmf()
{
colvarproxy *proxy = cvm::main()->proxy;
// allocate a new grid to store the pmf
colvar_grid_scalar *pmf = new colvar_grid_scalar(*hills_energy);
pmf->setup();
@ -1820,7 +1839,7 @@ void colvarbias_meta::write_pmf()
cvm::real target_val=target_dist->value(i);
if (target_val>0) {
pmf_val=pmf->value(i);
pmf_val=pmf_val+cvm::temperature() * cvm::boltzmann() * cvm::logn(target_val);
pmf_val=pmf_val + proxy->target_temperature() * proxy->boltzmann() * cvm::logn(target_val);
}
pmf->set_value(i,pmf_val);
}
@ -1830,7 +1849,7 @@ void colvarbias_meta::write_pmf()
pmf->add_constant(-1.0 * max);
pmf->multiply_constant(-1.0);
if (well_tempered) {
cvm::real const well_temper_scale = (bias_temperature + cvm::temperature()) / bias_temperature;
cvm::real const well_temper_scale = (bias_temperature + proxy->target_temperature()) / bias_temperature;
pmf->multiply_constant(well_temper_scale);
}
{
@ -1839,10 +1858,7 @@ void colvarbias_meta::write_pmf()
(dump_fes_save ?
"."+cvm::to_str(cvm::step_absolute()) : "") +
".pmf");
cvm::proxy->backup_file(fes_file_name);
std::ostream *fes_os = cvm::proxy->output_stream(fes_file_name);
pmf->write_multicol(*fes_os);
cvm::proxy->close_output_stream(fes_file_name);
pmf->write_multicol(fes_file_name, "PMF file");
}
}
@ -1861,7 +1877,7 @@ void colvarbias_meta::write_pmf()
cvm::real target_val=target_dist->value(i);
if (target_val>0) {
pmf_val=pmf->value(i);
pmf_val=pmf_val+cvm::temperature() * cvm::boltzmann() * cvm::logn(target_val);
pmf_val=pmf_val + proxy->target_temperature() * proxy->boltzmann() * cvm::logn(target_val);
}
pmf->set_value(i,pmf_val);
}
@ -1871,17 +1887,14 @@ void colvarbias_meta::write_pmf()
pmf->add_constant(-1.0 * max);
pmf->multiply_constant(-1.0);
if (well_tempered) {
cvm::real const well_temper_scale = (bias_temperature + cvm::temperature()) / bias_temperature;
cvm::real const well_temper_scale = (bias_temperature + proxy->target_temperature()) / bias_temperature;
pmf->multiply_constant(well_temper_scale);
}
std::string const fes_file_name(this->output_prefix +
(dump_fes_save ?
"."+cvm::to_str(cvm::step_absolute()) : "") +
".pmf");
cvm::proxy->backup_file(fes_file_name);
std::ostream *fes_os = cvm::proxy->output_stream(fes_file_name);
pmf->write_multicol(*fes_os);
cvm::proxy->close_output_stream(fes_file_name);
pmf->write_multicol(fes_file_name, "partial PMF file");
}
delete pmf;
@ -1902,9 +1915,9 @@ int colvarbias_meta::write_replica_state_file()
// Write to temporary state file
std::string const tmp_state_file(replica_state_file+".tmp");
error_code |= proxy->remove_file(tmp_state_file);
std::ostream *rep_state_os = cvm::proxy->output_stream(tmp_state_file);
std::ostream &rep_state_os = cvm::proxy->output_stream(tmp_state_file);
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 \""+
tmp_state_file+"\".\n", COLVARS_FILE_ERROR);
}
@ -1921,13 +1934,13 @@ int colvarbias_meta::reopen_replica_buffer_file()
{
int error_code = COLVARS_OK;
colvarproxy *proxy = cvm::proxy;
if (proxy->get_output_stream(replica_hills_file) != NULL) {
if (proxy->output_stream(replica_hills_file)) {
error_code |= proxy->close_output_stream(replica_hills_file);
}
error_code |= proxy->remove_file(replica_hills_file);
std::ostream *replica_hills_os = proxy->output_stream(replica_hills_file);
std::ostream &replica_hills_os = proxy->output_stream(replica_hills_file);
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 {
error_code |= COLVARS_FILE_ERROR;
}