Update Colvars library to version 2024-06-04
This commit is contained in:
@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user