Update Colvars library to version 2024-06-04

This commit is contained in:
Giacomo Fiorin
2024-08-06 01:07:43 +02:00
parent 278accd9ea
commit 133dee9ac1
74 changed files with 7343 additions and 4676 deletions

View File

@ -13,10 +13,12 @@
#include <sstream>
#include <iomanip>
#include "colvardeps.h"
#include "colvarmodule.h"
#include "colvarproxy.h"
#include "colvarparse.h"
#include "colvaratoms.h"
#include "colvar_rotation_derivative.h"
cvm::atom::atom()
@ -118,6 +120,11 @@ cvm::atom_group::~atom_group()
fitting_group = NULL;
}
if (rot_deriv != nullptr) {
delete rot_deriv;
rot_deriv = nullptr;
}
cvm::main()->unregister_named_atom_group(this);
}
@ -226,6 +233,7 @@ int cvm::atom_group::init()
b_dummy = false;
b_user_defined_fit = false;
fitting_group = NULL;
rot_deriv = nullptr;
noforce = false;
@ -278,7 +286,7 @@ int cvm::atom_group::init_dependencies() {
// Initialize feature_states for each instance
// default as unavailable, not enabled
feature_states.reserve(f_ag_ntot);
for (i = 0; i < colvardeps::f_ag_ntot; i++) {
for (i = feature_states.size(); i < colvardeps::f_ag_ntot; i++) {
feature_states.push_back(feature_state(false, false));
}
@ -317,6 +325,13 @@ int cvm::atom_group::setup()
return COLVARS_OK;
}
void cvm::atom_group::setup_rotation_derivative() {
if (rot_deriv != nullptr) delete rot_deriv;
rot_deriv = new rotation_derivative<cvm::atom, cvm::atom_pos>(
rot, fitting_group ? fitting_group->atoms : this->atoms, ref_pos
);
}
void cvm::atom_group::update_total_mass()
{
@ -383,7 +398,7 @@ int cvm::atom_group::parse(std::string const &group_conf)
// }
// colvarparse::Parse_Mode mode = parse_normal;
int parse_error = COLVARS_OK;
int error_code = COLVARS_OK;
// Optional group name will let other groups reuse atom definition
if (get_keyval(group_conf, "name", name)) {
@ -433,7 +448,7 @@ int cvm::atom_group::parse(std::string const &group_conf)
cvm::error("Error: cannot find atom group with name " + atoms_of + ".\n");
return COLVARS_ERROR;
}
parse_error |= add_atoms_of_group(ag);
error_code |= add_atoms_of_group(ag);
}
}
@ -447,7 +462,7 @@ int cvm::atom_group::parse(std::string const &group_conf)
std::string numbers_conf = "";
size_t pos = 0;
while (key_lookup(group_conf, "atomNumbers", &numbers_conf, &pos)) {
parse_error |= add_atom_numbers(numbers_conf);
error_code |= add_atom_numbers(numbers_conf);
numbers_conf = "";
}
}
@ -456,7 +471,7 @@ int cvm::atom_group::parse(std::string const &group_conf)
std::string index_group_name;
if (get_keyval(group_conf, "indexGroup", index_group_name)) {
// use an index group from the index file read globally
parse_error |= add_index_group(index_group_name);
error_code |= add_index_group(index_group_name);
}
}
@ -465,7 +480,7 @@ int cvm::atom_group::parse(std::string const &group_conf)
size_t pos = 0;
while (key_lookup(group_conf, "atomNumbersRange",
&range_conf, &pos)) {
parse_error |= add_atom_numbers_range(range_conf);
error_code |= add_atom_numbers_range(range_conf);
range_conf = "";
}
}
@ -492,7 +507,7 @@ int cvm::atom_group::parse(std::string const &group_conf)
cvm::error("Error: more instances of \"atomNameResidueRange\" than "
"values of \"psfSegID\".\n", COLVARS_INPUT_ERROR);
} else {
parse_error |= add_atom_name_residue_range(psf_segids.size() ?
error_code |= add_atom_name_residue_range(psf_segids.size() ?
*psii : std::string(""), range_conf);
if (psf_segids.size()) psii++;
}
@ -517,26 +532,26 @@ int cvm::atom_group::parse(std::string const &group_conf)
cvm::error("Error: atomsColValue, if provided, must be non-zero.\n", COLVARS_INPUT_ERROR);
}
// NOTE: calls to add_atom() and/or add_atom_id() are in the proxy-implemented function
parse_error |= cvm::load_atoms(atoms_file_name.c_str(), *this, atoms_col, atoms_col_value);
error_code |= cvm::main()->proxy->load_atoms_pdb(atoms_file_name.c_str(), *this, atoms_col,
atoms_col_value);
}
}
// Catch any errors from all the initialization steps above
if (parse_error || cvm::get_error()) return (parse_error || cvm::get_error());
if (error_code || cvm::get_error()) return (error_code || cvm::get_error());
// checks of doubly-counted atoms have been handled by add_atom() already
if (get_keyval(group_conf, "dummyAtom", dummy_atom_pos, cvm::atom_pos())) {
parse_error |= set_dummy();
parse_error |= set_dummy_pos(dummy_atom_pos);
error_code |= set_dummy();
error_code |= set_dummy_pos(dummy_atom_pos);
} else {
if (!(atoms_ids.size())) {
parse_error |= cvm::error("Error: no atoms defined for atom group \""+
key+"\".\n", COLVARS_INPUT_ERROR);
error_code |= cvm::error("Error: no atoms defined for atom group \"" + key + "\".\n",
COLVARS_INPUT_ERROR);
}
// whether these atoms will ever receive forces or not
@ -546,7 +561,7 @@ int cvm::atom_group::parse(std::string const &group_conf)
}
// Now that atoms are defined we can parse the detailed fitting options
parse_error |= parse_fitting_options(group_conf);
error_code |= parse_fitting_options(group_conf);
if (is_enabled(f_ag_scalable) && !b_dummy) {
cvm::log("Enabling scalable calculation for group \""+this->key+"\".\n");
@ -583,7 +598,9 @@ int cvm::atom_group::parse(std::string const &group_conf)
cvm::log(print_atom_ids());
}
return (cvm::get_error() ? COLVARS_ERROR : COLVARS_OK);
if (is_enabled(f_ag_rotate)) setup_rotation_derivative();
return error_code;
}
@ -883,8 +900,6 @@ int cvm::atom_group::parse_fitting_options(std::string const &group_conf)
"to its radius of gyration), the optimal rotation and its gradients may become discontinuous. "
"If that happens, use fittingGroup (or a different definition for it if already defined) "
"to align the coordinates.\n");
// initialize rot member data
rot.request_group1_gradients(group_for_fit->size());
}
}
@ -912,7 +927,6 @@ void cvm::atom_group::do_feature_side_effects(int id)
if (is_enabled(f_ag_center) || is_enabled(f_ag_rotate)) {
atom_group *group_for_fit = fitting_group ? fitting_group : this;
group_for_fit->fit_gradients.assign(group_for_fit->size(), cvm::atom_pos(0.0, 0.0, 0.0));
rot.request_group1_gradients(group_for_fit->size());
}
break;
}
@ -1045,17 +1059,18 @@ void cvm::atom_group::calc_apply_roto_translation()
// rotate the group (around the center of geometry if f_ag_center is
// enabled, around the origin otherwise)
rot.calc_optimal_rotation(fitting_group ?
fitting_group->positions() :
this->positions(),
fitting_group->atoms:
this->atoms,
ref_pos);
const auto rot_mat = rot.matrix();
cvm::atom_iter ai;
for (ai = this->begin(); ai != this->end(); ai++) {
ai->pos = rot.rotate(ai->pos);
ai->pos = rot_mat * ai->pos;
}
if (fitting_group) {
for (ai = fitting_group->begin(); ai != fitting_group->end(); ai++) {
ai->pos = rot.rotate(ai->pos);
ai->pos = rot_mat * ai->pos;
}
}
}
@ -1095,9 +1110,10 @@ void cvm::atom_group::read_velocities()
if (is_enabled(f_ag_rotate)) {
const auto rot_mat = rot.matrix();
for (cvm::atom_iter ai = this->begin(); ai != this->end(); ai++) {
ai->read_velocity();
ai->vel = rot.rotate(ai->vel);
ai->vel = rot_mat * ai->vel;
}
} else {
@ -1116,9 +1132,10 @@ void cvm::atom_group::read_total_forces()
if (is_enabled(f_ag_rotate)) {
const auto rot_mat = rot.matrix();
for (cvm::atom_iter ai = this->begin(); ai != this->end(); ai++) {
ai->read_total_force();
ai->total_force = rot.rotate(ai->total_force);
ai->total_force = rot_mat * ai->total_force;
}
} else {
@ -1200,52 +1217,71 @@ void cvm::atom_group::calc_fit_gradients()
if (cvm::debug())
cvm::log("Calculating fit gradients.\n");
cvm::atom_group *group_for_fit = fitting_group ? fitting_group : this;
if (is_enabled(f_ag_center)) {
// add the center of geometry contribution to the gradients
cvm::rvector atom_grad;
for (size_t i = 0; i < this->size(); i++) {
atom_grad += atoms[i].grad;
}
if (is_enabled(f_ag_rotate)) atom_grad = (rot.inverse()).rotate(atom_grad);
atom_grad *= (-1.0)/(cvm::real(group_for_fit->size()));
for (size_t j = 0; j < group_for_fit->size(); j++) {
group_for_fit->fit_gradients[j] = atom_grad;
}
}
if (is_enabled(f_ag_rotate)) {
// add the rotation matrix contribution to the gradients
cvm::rotation const rot_inv = rot.inverse();
for (size_t i = 0; i < this->size(); i++) {
// compute centered, unrotated position
cvm::atom_pos const pos_orig =
rot_inv.rotate((is_enabled(f_ag_center) ? (atoms[i].pos - ref_pos_cog) : (atoms[i].pos)));
// calculate \partial(R(q) \vec{x}_i)/\partial q) \cdot \partial\xi/\partial\vec{x}_i
cvm::quaternion const dxdq =
rot.q.position_derivative_inner(pos_orig, atoms[i].grad);
for (size_t j = 0; j < group_for_fit->size(); j++) {
// multiply by {\partial q}/\partial\vec{x}_j and add it to the fit gradients
for (size_t iq = 0; iq < 4; iq++) {
group_for_fit->fit_gradients[j] += dxdq[iq] * rot.dQ0_1[j][iq];
}
}
}
}
if (is_enabled(f_ag_center) && is_enabled(f_ag_rotate))
calc_fit_gradients_impl<true, true>();
if (is_enabled(f_ag_center) && !is_enabled(f_ag_rotate))
calc_fit_gradients_impl<true, false>();
if (!is_enabled(f_ag_center) && is_enabled(f_ag_rotate))
calc_fit_gradients_impl<false, true>();
if (!is_enabled(f_ag_center) && !is_enabled(f_ag_rotate))
calc_fit_gradients_impl<false, false>();
if (cvm::debug())
cvm::log("Done calculating fit gradients.\n");
}
template <bool B_ag_center, bool B_ag_rotate>
void cvm::atom_group::calc_fit_gradients_impl() {
cvm::atom_group *group_for_fit = fitting_group ? fitting_group : this;
// the center of geometry contribution to the gradients
cvm::rvector atom_grad;
// the rotation matrix contribution to the gradients
const auto rot_inv = rot.inverse().matrix();
// temporary variables for computing and summing derivatives
cvm::real sum_dxdq[4] = {0, 0, 0, 0};
cvm::vector1d<cvm::rvector> dq0_1(4);
// loop 1: iterate over the current atom group
for (size_t i = 0; i < size(); i++) {
cvm::atom_pos pos_orig;
if (B_ag_center) {
atom_grad += atoms[i].grad;
if (B_ag_rotate) pos_orig = rot_inv * (atoms[i].pos - ref_pos_cog);
} else {
if (B_ag_rotate) pos_orig = atoms[i].pos;
}
if (B_ag_rotate) {
// calculate \partial(R(q) \vec{x}_i)/\partial q) \cdot \partial\xi/\partial\vec{x}_i
cvm::quaternion const dxdq =
rot.q.position_derivative_inner(pos_orig, atoms[i].grad);
sum_dxdq[0] += dxdq[0];
sum_dxdq[1] += dxdq[1];
sum_dxdq[2] += dxdq[2];
sum_dxdq[3] += dxdq[3];
}
}
if (B_ag_center) {
if (B_ag_rotate) atom_grad = rot.inverse().matrix() * atom_grad;
atom_grad *= (-1.0)/(cvm::real(group_for_fit->size()));
}
// loop 2: iterate over the fitting group
if (B_ag_rotate) rot_deriv->prepare_derivative(rotation_derivative_dldq::use_dq);
for (size_t j = 0; j < group_for_fit->size(); j++) {
if (B_ag_center) {
group_for_fit->fit_gradients[j] = atom_grad;
}
if (B_ag_rotate) {
rot_deriv->calc_derivative_wrt_group1(j, nullptr, &dq0_1);
// multiply by {\partial q}/\partial\vec{x}_j and add it to the fit gradients
group_for_fit->fit_gradients[j] += sum_dxdq[0] * dq0_1[0] +
sum_dxdq[1] * dq0_1[1] +
sum_dxdq[2] * dq0_1[2] +
sum_dxdq[3] * dq0_1[3];
}
}
}
std::vector<cvm::atom_pos> cvm::atom_group::positions() const
{
if (b_dummy) {
@ -1373,9 +1409,9 @@ void cvm::atom_group::apply_colvar_force(cvm::real const &force)
if (is_enabled(f_ag_rotate)) {
// rotate forces back to the original frame
cvm::rotation const rot_inv = rot.inverse();
const auto rot_inv = rot.inverse().matrix();
for (cvm::atom_iter ai = this->begin(); ai != this->end(); ai++) {
ai->apply_force(rot_inv.rotate(force * ai->grad));
ai->apply_force(rot_inv * (force * ai->grad));
}
} else {
@ -1418,9 +1454,9 @@ void cvm::atom_group::apply_force(cvm::rvector const &force)
if (is_enabled(f_ag_rotate)) {
cvm::rotation const rot_inv = rot.inverse();
const auto rot_inv = rot.inverse().matrix();
for (cvm::atom_iter ai = this->begin(); ai != this->end(); ai++) {
ai->apply_force(rot_inv.rotate((ai->mass/total_mass) * force));
ai->apply_force(rot_inv * ((ai->mass/total_mass) * force));
}
} else {