2016-06-18 07:07:51 +08:00
|
|
|
// -*- c++ -*-
|
2014-10-08 04:30:25 +08:00
|
|
|
|
2016-12-28 02:17:34 +08:00
|
|
|
// 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.
|
|
|
|
|
2012-05-24 00:20:04 +08:00
|
|
|
#include <cmath>
|
|
|
|
|
|
|
|
#include "colvarmodule.h"
|
|
|
|
#include "colvarvalue.h"
|
|
|
|
#include "colvarparse.h"
|
|
|
|
#include "colvar.h"
|
|
|
|
#include "colvarcomp.h"
|
|
|
|
|
|
|
|
|
|
|
|
|
2016-06-18 07:07:51 +08:00
|
|
|
colvar::distance::distance(std::string const &conf)
|
2014-12-02 10:09:53 +08:00
|
|
|
: cvc(conf)
|
2012-05-24 00:20:04 +08:00
|
|
|
{
|
|
|
|
function_type = "distance";
|
2016-04-16 00:07:01 +08:00
|
|
|
provide(f_cvc_inv_gradient);
|
|
|
|
provide(f_cvc_Jacobian);
|
2017-03-10 22:16:58 +08:00
|
|
|
enable(f_cvc_com_based);
|
2016-04-16 00:07:01 +08:00
|
|
|
|
2016-09-30 20:15:44 +08:00
|
|
|
group1 = parse_group(conf, "group1");
|
|
|
|
group2 = parse_group(conf, "group2");
|
|
|
|
|
|
|
|
init_total_force_params(conf);
|
2016-06-18 07:07:51 +08:00
|
|
|
|
2014-12-02 10:09:53 +08:00
|
|
|
x.type(colvarvalue::type_scalar);
|
2012-05-24 00:20:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
colvar::distance::distance()
|
2014-12-02 10:09:53 +08:00
|
|
|
: cvc()
|
2012-05-24 00:20:04 +08:00
|
|
|
{
|
|
|
|
function_type = "distance";
|
2016-04-16 00:07:01 +08:00
|
|
|
provide(f_cvc_inv_gradient);
|
|
|
|
provide(f_cvc_Jacobian);
|
2017-03-10 22:16:58 +08:00
|
|
|
enable(f_cvc_com_based);
|
2014-12-02 10:09:53 +08:00
|
|
|
x.type(colvarvalue::type_scalar);
|
2012-05-24 00:20:04 +08:00
|
|
|
}
|
|
|
|
|
2016-04-16 00:07:01 +08:00
|
|
|
|
2012-05-24 00:20:04 +08:00
|
|
|
void colvar::distance::calc_value()
|
|
|
|
{
|
2017-07-20 02:10:43 +08:00
|
|
|
if (!is_enabled(f_cvc_pbc_minimum_image)) {
|
2016-04-16 00:07:01 +08:00
|
|
|
dist_v = group2->center_of_mass() - group1->center_of_mass();
|
2012-05-24 00:20:04 +08:00
|
|
|
} else {
|
2016-04-16 00:07:01 +08:00
|
|
|
dist_v = cvm::position_distance(group1->center_of_mass(),
|
2017-07-20 02:10:43 +08:00
|
|
|
group2->center_of_mass());
|
2012-05-24 00:20:04 +08:00
|
|
|
}
|
|
|
|
x.real_value = dist_v.norm();
|
|
|
|
}
|
|
|
|
|
2016-04-16 00:07:01 +08:00
|
|
|
|
2012-05-24 00:20:04 +08:00
|
|
|
void colvar::distance::calc_gradients()
|
|
|
|
{
|
|
|
|
cvm::rvector const u = dist_v.unit();
|
2016-04-16 00:07:01 +08:00
|
|
|
group1->set_weighted_gradient(-1.0 * u);
|
|
|
|
group2->set_weighted_gradient( u);
|
2012-05-24 00:20:04 +08:00
|
|
|
}
|
|
|
|
|
2016-04-16 00:07:01 +08:00
|
|
|
|
2012-05-24 00:20:04 +08:00
|
|
|
void colvar::distance::calc_force_invgrads()
|
|
|
|
{
|
2016-09-09 04:20:32 +08:00
|
|
|
group1->read_total_forces();
|
2016-09-30 20:15:44 +08:00
|
|
|
if (is_enabled(f_cvc_one_site_total_force)) {
|
2016-09-09 04:20:32 +08:00
|
|
|
ft.real_value = -1.0 * (group1->total_force() * dist_v.unit());
|
2012-05-24 00:20:04 +08:00
|
|
|
} else {
|
2016-09-09 04:20:32 +08:00
|
|
|
group2->read_total_forces();
|
|
|
|
ft.real_value = 0.5 * ((group2->total_force() - group1->total_force()) * dist_v.unit());
|
2012-05-24 00:20:04 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-16 00:07:01 +08:00
|
|
|
|
2012-05-24 00:20:04 +08:00
|
|
|
void colvar::distance::calc_Jacobian_derivative()
|
|
|
|
{
|
|
|
|
jd.real_value = x.real_value ? (2.0 / x.real_value) : 0.0;
|
|
|
|
}
|
|
|
|
|
2016-04-16 00:07:01 +08:00
|
|
|
|
2014-12-02 10:09:53 +08:00
|
|
|
void colvar::distance::apply_force(colvarvalue const &force)
|
2012-05-24 00:20:04 +08:00
|
|
|
{
|
2016-04-16 00:07:01 +08:00
|
|
|
if (!group1->noforce)
|
|
|
|
group1->apply_colvar_force(force.real_value);
|
2012-05-24 00:20:04 +08:00
|
|
|
|
2016-04-16 00:07:01 +08:00
|
|
|
if (!group2->noforce)
|
|
|
|
group2->apply_colvar_force(force.real_value);
|
2012-05-24 00:20:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-12-28 02:17:34 +08:00
|
|
|
simple_scalar_dist_functions(distance)
|
|
|
|
|
|
|
|
|
2012-05-24 00:20:04 +08:00
|
|
|
|
2014-12-02 10:09:53 +08:00
|
|
|
colvar::distance_vec::distance_vec(std::string const &conf)
|
|
|
|
: distance(conf)
|
2012-05-24 00:20:04 +08:00
|
|
|
{
|
|
|
|
function_type = "distance_vec";
|
2017-03-10 22:16:58 +08:00
|
|
|
enable(f_cvc_com_based);
|
2017-07-20 02:10:43 +08:00
|
|
|
enable(f_cvc_implicit_gradient);
|
2014-12-02 10:09:53 +08:00
|
|
|
x.type(colvarvalue::type_3vector);
|
2012-05-24 00:20:04 +08:00
|
|
|
}
|
|
|
|
|
2016-04-16 00:07:01 +08:00
|
|
|
|
2012-05-24 00:20:04 +08:00
|
|
|
colvar::distance_vec::distance_vec()
|
|
|
|
: distance()
|
|
|
|
{
|
|
|
|
function_type = "distance_vec";
|
2017-03-10 22:16:58 +08:00
|
|
|
enable(f_cvc_com_based);
|
2017-07-20 02:10:43 +08:00
|
|
|
enable(f_cvc_implicit_gradient);
|
2014-12-02 10:09:53 +08:00
|
|
|
x.type(colvarvalue::type_3vector);
|
2012-05-24 00:20:04 +08:00
|
|
|
}
|
|
|
|
|
2016-04-16 00:07:01 +08:00
|
|
|
|
2012-05-24 00:20:04 +08:00
|
|
|
void colvar::distance_vec::calc_value()
|
|
|
|
{
|
2017-07-20 02:10:43 +08:00
|
|
|
if (!is_enabled(f_cvc_pbc_minimum_image)) {
|
2016-04-16 00:07:01 +08:00
|
|
|
x.rvector_value = group2->center_of_mass() - group1->center_of_mass();
|
2012-05-24 00:20:04 +08:00
|
|
|
} else {
|
2016-04-16 00:07:01 +08:00
|
|
|
x.rvector_value = cvm::position_distance(group1->center_of_mass(),
|
2017-07-20 02:10:43 +08:00
|
|
|
group2->center_of_mass());
|
2012-05-24 00:20:04 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-16 00:07:01 +08:00
|
|
|
|
2012-05-24 00:20:04 +08:00
|
|
|
void colvar::distance_vec::calc_gradients()
|
2013-06-28 06:48:27 +08:00
|
|
|
{
|
2012-05-24 00:20:04 +08:00
|
|
|
// gradients are not stored: a 3x3 matrix for each atom would be
|
|
|
|
// needed to store just the identity matrix
|
|
|
|
}
|
|
|
|
|
2016-04-16 00:07:01 +08:00
|
|
|
|
2014-12-02 10:09:53 +08:00
|
|
|
void colvar::distance_vec::apply_force(colvarvalue const &force)
|
2012-05-24 00:20:04 +08:00
|
|
|
{
|
2016-04-16 00:07:01 +08:00
|
|
|
if (!group1->noforce)
|
|
|
|
group1->apply_force(-1.0 * force.rvector_value);
|
2012-05-24 00:20:04 +08:00
|
|
|
|
2016-04-16 00:07:01 +08:00
|
|
|
if (!group2->noforce)
|
|
|
|
group2->apply_force( force.rvector_value);
|
2012-05-24 00:20:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-12-28 02:17:34 +08:00
|
|
|
cvm::real colvar::distance_vec::dist2(colvarvalue const &x1,
|
|
|
|
colvarvalue const &x2) const
|
|
|
|
{
|
2018-05-03 02:57:41 +08:00
|
|
|
return (cvm::position_distance(x1.rvector_value, x2.rvector_value)).norm2();
|
2016-12-28 02:17:34 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
colvarvalue colvar::distance_vec::dist2_lgrad(colvarvalue const &x1,
|
|
|
|
colvarvalue const &x2) const
|
|
|
|
{
|
|
|
|
return 2.0 * cvm::position_distance(x2.rvector_value, x1.rvector_value);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
colvarvalue colvar::distance_vec::dist2_rgrad(colvarvalue const &x1,
|
|
|
|
colvarvalue const &x2) const
|
|
|
|
{
|
|
|
|
return 2.0 * cvm::position_distance(x2.rvector_value, x1.rvector_value);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-05-24 00:20:04 +08:00
|
|
|
|
2014-12-02 10:09:53 +08:00
|
|
|
colvar::distance_z::distance_z(std::string const &conf)
|
|
|
|
: cvc(conf)
|
2012-05-24 00:20:04 +08:00
|
|
|
{
|
|
|
|
function_type = "distance_z";
|
2016-04-16 00:07:01 +08:00
|
|
|
provide(f_cvc_inv_gradient);
|
|
|
|
provide(f_cvc_Jacobian);
|
2017-03-10 22:16:58 +08:00
|
|
|
enable(f_cvc_com_based);
|
2014-12-02 10:09:53 +08:00
|
|
|
x.type(colvarvalue::type_scalar);
|
2012-05-24 00:20:04 +08:00
|
|
|
|
|
|
|
// TODO detect PBC from MD engine (in simple cases)
|
|
|
|
// and then update period in real time
|
|
|
|
if (period != 0.0)
|
2013-06-28 06:48:27 +08:00
|
|
|
b_periodic = true;
|
2012-05-24 00:20:04 +08:00
|
|
|
|
|
|
|
if ((wrap_center != 0.0) && (period == 0.0)) {
|
2014-12-02 10:09:53 +08:00
|
|
|
cvm::error("Error: wrapAround was defined in a distanceZ component,"
|
2014-10-08 04:30:25 +08:00
|
|
|
" but its period has not been set.\n");
|
|
|
|
return;
|
2012-05-24 00:20:04 +08:00
|
|
|
}
|
|
|
|
|
2016-04-16 00:07:01 +08:00
|
|
|
main = parse_group(conf, "main");
|
|
|
|
ref1 = parse_group(conf, "ref");
|
2012-05-24 00:20:04 +08:00
|
|
|
// this group is optional
|
2016-04-16 00:07:01 +08:00
|
|
|
ref2 = parse_group(conf, "ref2", true);
|
2013-06-28 06:48:27 +08:00
|
|
|
|
2018-05-03 02:57:41 +08:00
|
|
|
if ( ref2 ) {
|
2014-12-02 10:09:53 +08:00
|
|
|
cvm::log("Using axis joining the centers of mass of groups \"ref\" and \"ref2\"");
|
2012-05-24 00:20:04 +08:00
|
|
|
fixed_axis = false;
|
2014-12-02 10:09:53 +08:00
|
|
|
if (key_lookup(conf, "axis"))
|
|
|
|
cvm::log("Warning: explicit axis definition will be ignored!");
|
2012-05-24 00:20:04 +08:00
|
|
|
} else {
|
2014-12-02 10:09:53 +08:00
|
|
|
if (get_keyval(conf, "axis", axis, cvm::rvector(0.0, 0.0, 1.0))) {
|
2014-10-08 04:30:25 +08:00
|
|
|
if (axis.norm2() == 0.0) {
|
2014-12-02 10:09:53 +08:00
|
|
|
cvm::error("Axis vector is zero!");
|
2014-10-08 04:30:25 +08:00
|
|
|
return;
|
|
|
|
}
|
2012-08-23 21:09:47 +08:00
|
|
|
if (axis.norm2() != 1.0) {
|
|
|
|
axis = axis.unit();
|
2014-12-02 10:09:53 +08:00
|
|
|
cvm::log("The normalized axis is: "+cvm::to_str(axis)+".\n");
|
2012-08-23 21:09:47 +08:00
|
|
|
}
|
2012-05-24 00:20:04 +08:00
|
|
|
}
|
|
|
|
fixed_axis = true;
|
|
|
|
}
|
|
|
|
|
2016-09-30 20:15:44 +08:00
|
|
|
init_total_force_params(conf);
|
|
|
|
|
2012-05-24 00:20:04 +08:00
|
|
|
}
|
|
|
|
|
2016-12-28 02:17:34 +08:00
|
|
|
|
2012-05-24 00:20:04 +08:00
|
|
|
colvar::distance_z::distance_z()
|
|
|
|
{
|
|
|
|
function_type = "distance_z";
|
2016-04-16 00:07:01 +08:00
|
|
|
provide(f_cvc_inv_gradient);
|
|
|
|
provide(f_cvc_Jacobian);
|
2017-03-10 22:16:58 +08:00
|
|
|
enable(f_cvc_com_based);
|
2014-12-02 10:09:53 +08:00
|
|
|
x.type(colvarvalue::type_scalar);
|
2012-05-24 00:20:04 +08:00
|
|
|
}
|
|
|
|
|
2016-12-28 02:17:34 +08:00
|
|
|
|
2012-05-24 00:20:04 +08:00
|
|
|
void colvar::distance_z::calc_value()
|
|
|
|
{
|
|
|
|
if (fixed_axis) {
|
2017-07-20 02:10:43 +08:00
|
|
|
if (!is_enabled(f_cvc_pbc_minimum_image)) {
|
2016-04-16 00:07:01 +08:00
|
|
|
dist_v = main->center_of_mass() - ref1->center_of_mass();
|
2012-05-24 00:20:04 +08:00
|
|
|
} else {
|
2016-04-16 00:07:01 +08:00
|
|
|
dist_v = cvm::position_distance(ref1->center_of_mass(),
|
2017-07-20 02:10:43 +08:00
|
|
|
main->center_of_mass());
|
2012-05-24 00:20:04 +08:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
|
2017-07-20 02:10:43 +08:00
|
|
|
if (!is_enabled(f_cvc_pbc_minimum_image)) {
|
2016-04-16 00:07:01 +08:00
|
|
|
dist_v = main->center_of_mass() -
|
|
|
|
(0.5 * (ref1->center_of_mass() + ref2->center_of_mass()));
|
|
|
|
axis = ref2->center_of_mass() - ref1->center_of_mass();
|
2012-05-24 00:20:04 +08:00
|
|
|
} else {
|
2016-04-16 00:07:01 +08:00
|
|
|
dist_v = cvm::position_distance(0.5 * (ref1->center_of_mass() +
|
2017-07-20 02:10:43 +08:00
|
|
|
ref2->center_of_mass()),
|
|
|
|
main->center_of_mass());
|
|
|
|
axis = cvm::position_distance(ref1->center_of_mass(),
|
|
|
|
ref2->center_of_mass());
|
2012-05-24 00:20:04 +08:00
|
|
|
}
|
|
|
|
axis_norm = axis.norm();
|
|
|
|
axis = axis.unit();
|
|
|
|
}
|
|
|
|
x.real_value = axis * dist_v;
|
2014-12-02 10:09:53 +08:00
|
|
|
this->wrap(x);
|
2012-05-24 00:20:04 +08:00
|
|
|
}
|
|
|
|
|
2016-12-28 02:17:34 +08:00
|
|
|
|
2012-05-24 00:20:04 +08:00
|
|
|
void colvar::distance_z::calc_gradients()
|
|
|
|
{
|
2016-04-16 00:07:01 +08:00
|
|
|
main->set_weighted_gradient( axis );
|
2012-05-24 00:20:04 +08:00
|
|
|
|
|
|
|
if (fixed_axis) {
|
2016-04-16 00:07:01 +08:00
|
|
|
ref1->set_weighted_gradient(-1.0 * axis);
|
2012-05-24 00:20:04 +08:00
|
|
|
} else {
|
2017-07-20 02:10:43 +08:00
|
|
|
if (!is_enabled(f_cvc_pbc_minimum_image)) {
|
|
|
|
ref1->set_weighted_gradient( 1.0 / axis_norm *
|
|
|
|
(main->center_of_mass() - ref2->center_of_mass() -
|
2012-05-24 00:20:04 +08:00
|
|
|
x.real_value * axis ));
|
2017-07-20 02:10:43 +08:00
|
|
|
ref2->set_weighted_gradient( 1.0 / axis_norm *
|
|
|
|
(ref1->center_of_mass() - main->center_of_mass() +
|
2012-05-24 00:20:04 +08:00
|
|
|
x.real_value * axis ));
|
|
|
|
} else {
|
2016-04-16 00:07:01 +08:00
|
|
|
ref1->set_weighted_gradient( 1.0 / axis_norm * (
|
2017-07-20 02:10:43 +08:00
|
|
|
cvm::position_distance(ref2->center_of_mass(),
|
|
|
|
main->center_of_mass()) - x.real_value * axis ));
|
2016-04-16 00:07:01 +08:00
|
|
|
ref2->set_weighted_gradient( 1.0 / axis_norm * (
|
2017-07-20 02:10:43 +08:00
|
|
|
cvm::position_distance(main->center_of_mass(),
|
|
|
|
ref1->center_of_mass()) + x.real_value * axis ));
|
2012-05-24 00:20:04 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-28 02:17:34 +08:00
|
|
|
|
2012-05-24 00:20:04 +08:00
|
|
|
void colvar::distance_z::calc_force_invgrads()
|
|
|
|
{
|
2016-09-09 04:20:32 +08:00
|
|
|
main->read_total_forces();
|
2012-05-24 00:20:04 +08:00
|
|
|
|
2016-09-30 20:15:44 +08:00
|
|
|
if (fixed_axis && !is_enabled(f_cvc_one_site_total_force)) {
|
2016-09-09 04:20:32 +08:00
|
|
|
ref1->read_total_forces();
|
|
|
|
ft.real_value = 0.5 * ((main->total_force() - ref1->total_force()) * axis);
|
2012-05-24 00:20:04 +08:00
|
|
|
} else {
|
2016-09-09 04:20:32 +08:00
|
|
|
ft.real_value = main->total_force() * axis;
|
2012-05-24 00:20:04 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-28 02:17:34 +08:00
|
|
|
|
2012-05-24 00:20:04 +08:00
|
|
|
void colvar::distance_z::calc_Jacobian_derivative()
|
|
|
|
{
|
|
|
|
jd.real_value = 0.0;
|
|
|
|
}
|
|
|
|
|
2016-12-28 02:17:34 +08:00
|
|
|
|
2014-12-02 10:09:53 +08:00
|
|
|
void colvar::distance_z::apply_force(colvarvalue const &force)
|
2012-05-24 00:20:04 +08:00
|
|
|
{
|
2016-04-16 00:07:01 +08:00
|
|
|
if (!ref1->noforce)
|
|
|
|
ref1->apply_colvar_force(force.real_value);
|
2012-05-24 00:20:04 +08:00
|
|
|
|
2018-05-03 02:57:41 +08:00
|
|
|
if (ref2 && !ref2->noforce)
|
2016-04-16 00:07:01 +08:00
|
|
|
ref2->apply_colvar_force(force.real_value);
|
2012-05-24 00:20:04 +08:00
|
|
|
|
2016-04-16 00:07:01 +08:00
|
|
|
if (!main->noforce)
|
|
|
|
main->apply_colvar_force(force.real_value);
|
2012-05-24 00:20:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-12-28 02:17:34 +08:00
|
|
|
// Differences should always be wrapped around 0 (ignoring wrap_center)
|
|
|
|
cvm::real colvar::distance_z::dist2(colvarvalue const &x1,
|
|
|
|
colvarvalue const &x2) const
|
|
|
|
{
|
|
|
|
cvm::real diff = x1.real_value - x2.real_value;
|
|
|
|
if (b_periodic) {
|
|
|
|
cvm::real shift = std::floor(diff/period + 0.5);
|
|
|
|
diff -= shift * period;
|
|
|
|
}
|
|
|
|
return diff * diff;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
colvarvalue colvar::distance_z::dist2_lgrad(colvarvalue const &x1,
|
|
|
|
colvarvalue const &x2) const
|
|
|
|
{
|
|
|
|
cvm::real diff = x1.real_value - x2.real_value;
|
|
|
|
if (b_periodic) {
|
|
|
|
cvm::real shift = std::floor(diff/period + 0.5);
|
|
|
|
diff -= shift * period;
|
|
|
|
}
|
|
|
|
return 2.0 * diff;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
colvarvalue colvar::distance_z::dist2_rgrad(colvarvalue const &x1,
|
|
|
|
colvarvalue const &x2) const
|
|
|
|
{
|
|
|
|
cvm::real diff = x1.real_value - x2.real_value;
|
|
|
|
if (b_periodic) {
|
|
|
|
cvm::real shift = std::floor(diff/period + 0.5);
|
|
|
|
diff -= shift * period;
|
|
|
|
}
|
|
|
|
return (-2.0) * diff;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void colvar::distance_z::wrap(colvarvalue &x) const
|
|
|
|
{
|
|
|
|
if (!b_periodic) {
|
|
|
|
// don't wrap if the period has not been set
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
cvm::real shift = std::floor((x.real_value - wrap_center) / period + 0.5);
|
|
|
|
x.real_value -= shift * period;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-05-24 00:20:04 +08:00
|
|
|
|
2014-12-02 10:09:53 +08:00
|
|
|
colvar::distance_xy::distance_xy(std::string const &conf)
|
|
|
|
: distance_z(conf)
|
2012-05-24 00:20:04 +08:00
|
|
|
{
|
|
|
|
function_type = "distance_xy";
|
2016-04-16 00:07:01 +08:00
|
|
|
provide(f_cvc_inv_gradient);
|
|
|
|
provide(f_cvc_Jacobian);
|
2017-03-10 22:16:58 +08:00
|
|
|
enable(f_cvc_com_based);
|
2014-12-02 10:09:53 +08:00
|
|
|
x.type(colvarvalue::type_scalar);
|
2012-05-24 00:20:04 +08:00
|
|
|
}
|
|
|
|
|
2016-12-28 02:17:34 +08:00
|
|
|
|
2012-05-24 00:20:04 +08:00
|
|
|
colvar::distance_xy::distance_xy()
|
|
|
|
: distance_z()
|
|
|
|
{
|
|
|
|
function_type = "distance_xy";
|
2016-04-16 00:07:01 +08:00
|
|
|
provide(f_cvc_inv_gradient);
|
|
|
|
provide(f_cvc_Jacobian);
|
2017-03-10 22:16:58 +08:00
|
|
|
enable(f_cvc_com_based);
|
2014-12-02 10:09:53 +08:00
|
|
|
x.type(colvarvalue::type_scalar);
|
2012-05-24 00:20:04 +08:00
|
|
|
}
|
|
|
|
|
2016-12-28 02:17:34 +08:00
|
|
|
|
2012-05-24 00:20:04 +08:00
|
|
|
void colvar::distance_xy::calc_value()
|
|
|
|
{
|
2017-07-20 02:10:43 +08:00
|
|
|
if (!is_enabled(f_cvc_pbc_minimum_image)) {
|
2016-04-16 00:07:01 +08:00
|
|
|
dist_v = main->center_of_mass() - ref1->center_of_mass();
|
2012-05-24 00:20:04 +08:00
|
|
|
} else {
|
2016-04-16 00:07:01 +08:00
|
|
|
dist_v = cvm::position_distance(ref1->center_of_mass(),
|
2017-07-20 02:10:43 +08:00
|
|
|
main->center_of_mass());
|
2012-05-24 00:20:04 +08:00
|
|
|
}
|
|
|
|
if (!fixed_axis) {
|
2017-07-20 02:10:43 +08:00
|
|
|
if (!is_enabled(f_cvc_pbc_minimum_image)) {
|
2016-04-16 00:07:01 +08:00
|
|
|
v12 = ref2->center_of_mass() - ref1->center_of_mass();
|
2012-05-24 00:20:04 +08:00
|
|
|
} else {
|
2017-07-20 02:10:43 +08:00
|
|
|
v12 = cvm::position_distance(ref1->center_of_mass(),
|
|
|
|
ref2->center_of_mass());
|
2012-05-24 00:20:04 +08:00
|
|
|
}
|
|
|
|
axis_norm = v12.norm();
|
|
|
|
axis = v12.unit();
|
|
|
|
}
|
|
|
|
|
|
|
|
dist_v_ortho = dist_v - (dist_v * axis) * axis;
|
|
|
|
x.real_value = dist_v_ortho.norm();
|
|
|
|
}
|
|
|
|
|
2016-12-28 02:17:34 +08:00
|
|
|
|
2012-05-24 00:20:04 +08:00
|
|
|
void colvar::distance_xy::calc_gradients()
|
|
|
|
{
|
|
|
|
// Intermediate quantity (r_P3 / r_12 where P is the projection
|
2014-12-02 10:09:53 +08:00
|
|
|
// of 3(main) on the plane orthogonal to 12, containing 1 (ref1))
|
2012-05-24 00:20:04 +08:00
|
|
|
cvm::real A;
|
|
|
|
cvm::real x_inv;
|
|
|
|
|
|
|
|
if (x.real_value == 0.0) return;
|
|
|
|
x_inv = 1.0 / x.real_value;
|
|
|
|
|
|
|
|
if (fixed_axis) {
|
2016-04-16 00:07:01 +08:00
|
|
|
ref1->set_weighted_gradient(-1.0 * x_inv * dist_v_ortho);
|
|
|
|
main->set_weighted_gradient( x_inv * dist_v_ortho);
|
2012-05-24 00:20:04 +08:00
|
|
|
} else {
|
2017-07-20 02:10:43 +08:00
|
|
|
if (!is_enabled(f_cvc_pbc_minimum_image)) {
|
2016-04-16 00:07:01 +08:00
|
|
|
v13 = main->center_of_mass() - ref1->center_of_mass();
|
2012-05-24 00:20:04 +08:00
|
|
|
} else {
|
2017-07-20 02:10:43 +08:00
|
|
|
v13 = cvm::position_distance(ref1->center_of_mass(),
|
|
|
|
main->center_of_mass());
|
2012-05-24 00:20:04 +08:00
|
|
|
}
|
|
|
|
A = (dist_v * axis) / axis_norm;
|
|
|
|
|
2016-04-16 00:07:01 +08:00
|
|
|
ref1->set_weighted_gradient( (A - 1.0) * x_inv * dist_v_ortho);
|
|
|
|
ref2->set_weighted_gradient( -A * x_inv * dist_v_ortho);
|
|
|
|
main->set_weighted_gradient( 1.0 * x_inv * dist_v_ortho);
|
2012-05-24 00:20:04 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-28 02:17:34 +08:00
|
|
|
|
2012-05-24 00:20:04 +08:00
|
|
|
void colvar::distance_xy::calc_force_invgrads()
|
|
|
|
{
|
2016-09-09 04:20:32 +08:00
|
|
|
main->read_total_forces();
|
2012-05-24 00:20:04 +08:00
|
|
|
|
2016-09-30 20:15:44 +08:00
|
|
|
if (fixed_axis && !is_enabled(f_cvc_one_site_total_force)) {
|
2016-09-09 04:20:32 +08:00
|
|
|
ref1->read_total_forces();
|
|
|
|
ft.real_value = 0.5 / x.real_value * ((main->total_force() - ref1->total_force()) * dist_v_ortho);
|
2012-05-24 00:20:04 +08:00
|
|
|
} else {
|
2016-09-09 04:20:32 +08:00
|
|
|
ft.real_value = 1.0 / x.real_value * main->total_force() * dist_v_ortho;
|
2012-05-24 00:20:04 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-28 02:17:34 +08:00
|
|
|
|
2012-05-24 00:20:04 +08:00
|
|
|
void colvar::distance_xy::calc_Jacobian_derivative()
|
|
|
|
{
|
|
|
|
jd.real_value = x.real_value ? (1.0 / x.real_value) : 0.0;
|
|
|
|
}
|
|
|
|
|
2016-12-28 02:17:34 +08:00
|
|
|
|
2014-12-02 10:09:53 +08:00
|
|
|
void colvar::distance_xy::apply_force(colvarvalue const &force)
|
2012-05-24 00:20:04 +08:00
|
|
|
{
|
2016-04-16 00:07:01 +08:00
|
|
|
if (!ref1->noforce)
|
|
|
|
ref1->apply_colvar_force(force.real_value);
|
2012-05-24 00:20:04 +08:00
|
|
|
|
2018-05-03 02:57:41 +08:00
|
|
|
if (ref2 && !ref2->noforce)
|
2016-04-16 00:07:01 +08:00
|
|
|
ref2->apply_colvar_force(force.real_value);
|
2012-05-24 00:20:04 +08:00
|
|
|
|
2016-04-16 00:07:01 +08:00
|
|
|
if (!main->noforce)
|
|
|
|
main->apply_colvar_force(force.real_value);
|
2012-05-24 00:20:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-12-28 02:17:34 +08:00
|
|
|
simple_scalar_dist_functions(distance_xy)
|
|
|
|
|
|
|
|
|
2012-05-24 00:20:04 +08:00
|
|
|
|
2014-12-02 10:09:53 +08:00
|
|
|
colvar::distance_dir::distance_dir(std::string const &conf)
|
|
|
|
: distance(conf)
|
2012-05-24 00:20:04 +08:00
|
|
|
{
|
2012-06-30 01:52:31 +08:00
|
|
|
function_type = "distance_dir";
|
2017-03-10 22:16:58 +08:00
|
|
|
enable(f_cvc_com_based);
|
2017-07-20 02:10:43 +08:00
|
|
|
enable(f_cvc_implicit_gradient);
|
2014-12-02 10:09:53 +08:00
|
|
|
x.type(colvarvalue::type_unit3vector);
|
2012-05-24 00:20:04 +08:00
|
|
|
}
|
|
|
|
|
2012-06-30 01:52:31 +08:00
|
|
|
|
|
|
|
colvar::distance_dir::distance_dir()
|
2012-05-24 00:20:04 +08:00
|
|
|
: distance()
|
|
|
|
{
|
2012-06-30 01:52:31 +08:00
|
|
|
function_type = "distance_dir";
|
2017-03-10 22:16:58 +08:00
|
|
|
enable(f_cvc_com_based);
|
2017-07-20 02:10:43 +08:00
|
|
|
enable(f_cvc_implicit_gradient);
|
2014-12-02 10:09:53 +08:00
|
|
|
x.type(colvarvalue::type_unit3vector);
|
2012-05-24 00:20:04 +08:00
|
|
|
}
|
|
|
|
|
2012-06-30 01:52:31 +08:00
|
|
|
|
|
|
|
void colvar::distance_dir::calc_value()
|
2012-05-24 00:20:04 +08:00
|
|
|
{
|
2017-07-20 02:10:43 +08:00
|
|
|
if (!is_enabled(f_cvc_pbc_minimum_image)) {
|
2016-04-16 00:07:01 +08:00
|
|
|
dist_v = group2->center_of_mass() - group1->center_of_mass();
|
2012-06-30 01:52:31 +08:00
|
|
|
} else {
|
2016-04-16 00:07:01 +08:00
|
|
|
dist_v = cvm::position_distance(group1->center_of_mass(),
|
2016-12-28 02:17:34 +08:00
|
|
|
group2->center_of_mass());
|
2012-05-24 00:20:04 +08:00
|
|
|
}
|
2012-06-30 01:52:31 +08:00
|
|
|
x.rvector_value = dist_v.unit();
|
2012-05-24 00:20:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-06-30 01:52:31 +08:00
|
|
|
void colvar::distance_dir::calc_gradients()
|
|
|
|
{
|
|
|
|
// gradients are computed on the fly within apply_force()
|
|
|
|
// Note: could be a problem if a future bias relies on gradient
|
|
|
|
// calculations...
|
2016-04-16 00:07:01 +08:00
|
|
|
// TODO in new deps system: remove dependency of biasing force to gradient?
|
|
|
|
// That way we could tell apart an explicit gradient dependency
|
2012-05-24 00:20:04 +08:00
|
|
|
}
|
|
|
|
|
2012-06-30 01:52:31 +08:00
|
|
|
|
2014-12-02 10:09:53 +08:00
|
|
|
void colvar::distance_dir::apply_force(colvarvalue const &force)
|
2012-05-24 00:20:04 +08:00
|
|
|
{
|
2012-06-30 01:52:31 +08:00
|
|
|
// remove the radial force component
|
|
|
|
cvm::real const iprod = force.rvector_value * x.rvector_value;
|
|
|
|
cvm::rvector const force_tang = force.rvector_value - iprod * x.rvector_value;
|
|
|
|
|
2016-04-16 00:07:01 +08:00
|
|
|
if (!group1->noforce)
|
|
|
|
group1->apply_force(-1.0 * force_tang);
|
2012-05-24 00:20:04 +08:00
|
|
|
|
2016-04-16 00:07:01 +08:00
|
|
|
if (!group2->noforce)
|
|
|
|
group2->apply_force( force_tang);
|
2012-05-24 00:20:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-03-10 22:16:58 +08:00
|
|
|
cvm::real colvar::distance_dir::dist2(colvarvalue const &x1,
|
|
|
|
colvarvalue const &x2) const
|
|
|
|
{
|
|
|
|
return (x1.rvector_value - x2.rvector_value).norm2();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
colvarvalue colvar::distance_dir::dist2_lgrad(colvarvalue const &x1,
|
|
|
|
colvarvalue const &x2) const
|
|
|
|
{
|
2017-07-20 02:10:43 +08:00
|
|
|
return colvarvalue((x1.rvector_value - x2.rvector_value), colvarvalue::type_unit3vectorderiv);
|
2017-03-10 22:16:58 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
colvarvalue colvar::distance_dir::dist2_rgrad(colvarvalue const &x1,
|
|
|
|
colvarvalue const &x2) const
|
|
|
|
{
|
2017-07-20 02:10:43 +08:00
|
|
|
return colvarvalue((x2.rvector_value - x1.rvector_value), colvarvalue::type_unit3vectorderiv);
|
2017-03-10 22:16:58 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-05-24 00:20:04 +08:00
|
|
|
|
2014-12-02 10:09:53 +08:00
|
|
|
colvar::distance_inv::distance_inv(std::string const &conf)
|
2017-07-20 02:10:43 +08:00
|
|
|
: cvc(conf)
|
2012-05-24 00:20:04 +08:00
|
|
|
{
|
2012-08-23 21:09:47 +08:00
|
|
|
function_type = "distance_inv";
|
2017-07-20 02:10:43 +08:00
|
|
|
|
|
|
|
group1 = parse_group(conf, "group1");
|
|
|
|
group2 = parse_group(conf, "group2");
|
|
|
|
|
2014-12-02 10:09:53 +08:00
|
|
|
get_keyval(conf, "exponent", exponent, 6);
|
2012-08-23 21:09:47 +08:00
|
|
|
if (exponent%2) {
|
2014-12-02 10:09:53 +08:00
|
|
|
cvm::error("Error: odd exponent provided, can only use even ones.\n");
|
2014-10-08 04:30:25 +08:00
|
|
|
return;
|
2012-08-23 21:09:47 +08:00
|
|
|
}
|
|
|
|
if (exponent <= 0) {
|
2014-12-02 10:09:53 +08:00
|
|
|
cvm::error("Error: negative or zero exponent provided.\n");
|
2014-10-08 04:30:25 +08:00
|
|
|
return;
|
2012-08-23 21:09:47 +08:00
|
|
|
}
|
|
|
|
|
2016-04-16 00:07:01 +08:00
|
|
|
for (cvm::atom_iter ai1 = group1->begin(); ai1 != group1->end(); ai1++) {
|
|
|
|
for (cvm::atom_iter ai2 = group2->begin(); ai2 != group2->end(); ai2++) {
|
2015-02-20 02:20:52 +08:00
|
|
|
if (ai1->id == ai2->id) {
|
|
|
|
cvm::error("Error: group1 and group2 have some atoms in common: this is not allowed for distanceInv.\n");
|
|
|
|
return;
|
|
|
|
}
|
2012-10-24 00:57:29 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-23 21:34:53 +08:00
|
|
|
if (is_enabled(f_cvc_debug_gradient)) {
|
|
|
|
cvm::log("Warning: debugGradients will not give correct results "
|
|
|
|
"for distanceInv, because its value and gradients are computed "
|
|
|
|
"simultaneously.\n");
|
|
|
|
}
|
|
|
|
|
2014-12-02 10:09:53 +08:00
|
|
|
x.type(colvarvalue::type_scalar);
|
2012-05-24 00:20:04 +08:00
|
|
|
}
|
|
|
|
|
2016-12-28 02:17:34 +08:00
|
|
|
|
2012-08-23 21:09:47 +08:00
|
|
|
colvar::distance_inv::distance_inv()
|
2012-05-24 00:20:04 +08:00
|
|
|
{
|
2012-08-23 21:09:47 +08:00
|
|
|
function_type = "distance_inv";
|
|
|
|
exponent = 6;
|
2014-12-02 10:09:53 +08:00
|
|
|
x.type(colvarvalue::type_scalar);
|
2012-05-24 00:20:04 +08:00
|
|
|
}
|
|
|
|
|
2016-12-28 02:17:34 +08:00
|
|
|
|
2012-08-23 21:09:47 +08:00
|
|
|
void colvar::distance_inv::calc_value()
|
2012-05-24 00:20:04 +08:00
|
|
|
{
|
2012-06-30 01:52:31 +08:00
|
|
|
x.real_value = 0.0;
|
2017-07-20 02:10:43 +08:00
|
|
|
if (!is_enabled(f_cvc_pbc_minimum_image)) {
|
2016-04-16 00:07:01 +08:00
|
|
|
for (cvm::atom_iter ai1 = group1->begin(); ai1 != group1->end(); ai1++) {
|
|
|
|
for (cvm::atom_iter ai2 = group2->begin(); ai2 != group2->end(); ai2++) {
|
2012-06-30 01:52:31 +08:00
|
|
|
cvm::rvector const dv = ai2->pos - ai1->pos;
|
|
|
|
cvm::real const d2 = dv.norm2();
|
2018-02-23 21:34:53 +08:00
|
|
|
cvm::real const dinv = cvm::integer_power(d2, -1*(exponent/2));
|
2012-08-23 21:09:47 +08:00
|
|
|
x.real_value += dinv;
|
2018-02-23 21:34:53 +08:00
|
|
|
cvm::rvector const dsumddv = -1.0*(exponent/2) * dinv/d2 * 2.0 * dv;
|
2012-06-30 01:52:31 +08:00
|
|
|
ai1->grad += -1.0 * dsumddv;
|
|
|
|
ai2->grad += dsumddv;
|
|
|
|
}
|
|
|
|
}
|
2012-05-24 00:20:04 +08:00
|
|
|
} else {
|
2016-04-16 00:07:01 +08:00
|
|
|
for (cvm::atom_iter ai1 = group1->begin(); ai1 != group1->end(); ai1++) {
|
|
|
|
for (cvm::atom_iter ai2 = group2->begin(); ai2 != group2->end(); ai2++) {
|
2014-12-02 10:09:53 +08:00
|
|
|
cvm::rvector const dv = cvm::position_distance(ai1->pos, ai2->pos);
|
2012-06-30 01:52:31 +08:00
|
|
|
cvm::real const d2 = dv.norm2();
|
2018-02-23 21:34:53 +08:00
|
|
|
cvm::real const dinv = cvm::integer_power(d2, -1*(exponent/2));
|
2012-08-23 21:09:47 +08:00
|
|
|
x.real_value += dinv;
|
2018-02-23 21:34:53 +08:00
|
|
|
cvm::rvector const dsumddv = -1.0*(exponent/2) * dinv/d2 * 2.0 * dv;
|
2012-06-30 01:52:31 +08:00
|
|
|
ai1->grad += -1.0 * dsumddv;
|
|
|
|
ai2->grad += dsumddv;
|
|
|
|
}
|
|
|
|
}
|
2012-05-24 00:20:04 +08:00
|
|
|
}
|
|
|
|
|
2016-04-16 00:07:01 +08:00
|
|
|
x.real_value *= 1.0 / cvm::real(group1->size() * group2->size());
|
2018-02-23 21:34:53 +08:00
|
|
|
x.real_value = std::pow(x.real_value, -1.0/cvm::real(exponent));
|
2012-05-24 00:20:04 +08:00
|
|
|
|
2018-02-23 21:34:53 +08:00
|
|
|
cvm::real const dxdsum = (-1.0/(cvm::real(exponent))) *
|
|
|
|
cvm::integer_power(x.real_value, exponent+1) /
|
|
|
|
cvm::real(group1->size() * group2->size());
|
2016-04-16 00:07:01 +08:00
|
|
|
for (cvm::atom_iter ai1 = group1->begin(); ai1 != group1->end(); ai1++) {
|
2012-08-23 21:09:47 +08:00
|
|
|
ai1->grad *= dxdsum;
|
|
|
|
}
|
2016-04-16 00:07:01 +08:00
|
|
|
for (cvm::atom_iter ai2 = group2->begin(); ai2 != group2->end(); ai2++) {
|
2012-08-23 21:09:47 +08:00
|
|
|
ai2->grad *= dxdsum;
|
|
|
|
}
|
2012-05-24 00:20:04 +08:00
|
|
|
}
|
|
|
|
|
2016-12-28 02:17:34 +08:00
|
|
|
|
2018-02-23 21:34:53 +08:00
|
|
|
void colvar::distance_inv::calc_gradients()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-12-02 10:09:53 +08:00
|
|
|
void colvar::distance_inv::apply_force(colvarvalue const &force)
|
2012-05-24 00:20:04 +08:00
|
|
|
{
|
2016-04-16 00:07:01 +08:00
|
|
|
if (!group1->noforce)
|
|
|
|
group1->apply_colvar_force(force.real_value);
|
2012-05-24 00:20:04 +08:00
|
|
|
|
2016-04-16 00:07:01 +08:00
|
|
|
if (!group2->noforce)
|
|
|
|
group2->apply_colvar_force(force.real_value);
|
2012-05-24 00:20:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-12-28 02:17:34 +08:00
|
|
|
simple_scalar_dist_functions(distance_inv)
|
|
|
|
|
|
|
|
|
2012-05-24 00:20:04 +08:00
|
|
|
|
2014-12-02 10:09:53 +08:00
|
|
|
colvar::distance_pairs::distance_pairs(std::string const &conf)
|
|
|
|
: cvc(conf)
|
|
|
|
{
|
|
|
|
function_type = "distance_pairs";
|
|
|
|
|
2016-04-16 00:07:01 +08:00
|
|
|
group1 = parse_group(conf, "group1");
|
|
|
|
group2 = parse_group(conf, "group2");
|
2014-12-02 10:09:53 +08:00
|
|
|
|
|
|
|
x.type(colvarvalue::type_vector);
|
2017-07-20 02:10:43 +08:00
|
|
|
enable(f_cvc_implicit_gradient);
|
2016-04-16 00:07:01 +08:00
|
|
|
x.vector1d_value.resize(group1->size() * group2->size());
|
2014-12-02 10:09:53 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
colvar::distance_pairs::distance_pairs()
|
|
|
|
{
|
|
|
|
function_type = "distance_pairs";
|
2017-07-20 02:10:43 +08:00
|
|
|
enable(f_cvc_implicit_gradient);
|
2014-12-02 10:09:53 +08:00
|
|
|
x.type(colvarvalue::type_vector);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void colvar::distance_pairs::calc_value()
|
|
|
|
{
|
2016-04-16 00:07:01 +08:00
|
|
|
x.vector1d_value.resize(group1->size() * group2->size());
|
2014-12-02 10:09:53 +08:00
|
|
|
|
2017-07-20 02:10:43 +08:00
|
|
|
if (!is_enabled(f_cvc_pbc_minimum_image)) {
|
2014-12-02 10:09:53 +08:00
|
|
|
size_t i1, i2;
|
2016-04-16 00:07:01 +08:00
|
|
|
for (i1 = 0; i1 < group1->size(); i1++) {
|
|
|
|
for (i2 = 0; i2 < group2->size(); i2++) {
|
|
|
|
cvm::rvector const dv = (*group2)[i2].pos - (*group1)[i1].pos;
|
2014-12-02 10:09:53 +08:00
|
|
|
cvm::real const d = dv.norm();
|
2016-04-16 00:07:01 +08:00
|
|
|
x.vector1d_value[i1*group2->size() + i2] = d;
|
|
|
|
(*group1)[i1].grad = -1.0 * dv.unit();
|
|
|
|
(*group2)[i2].grad = dv.unit();
|
2014-12-02 10:09:53 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
size_t i1, i2;
|
2016-04-16 00:07:01 +08:00
|
|
|
for (i1 = 0; i1 < group1->size(); i1++) {
|
|
|
|
for (i2 = 0; i2 < group2->size(); i2++) {
|
2017-07-20 02:10:43 +08:00
|
|
|
cvm::rvector const dv = cvm::position_distance((*group1)[i1].pos,
|
|
|
|
(*group2)[i2].pos);
|
2014-12-02 10:09:53 +08:00
|
|
|
cvm::real const d = dv.norm();
|
2016-04-16 00:07:01 +08:00
|
|
|
x.vector1d_value[i1*group2->size() + i2] = d;
|
|
|
|
(*group1)[i1].grad = -1.0 * dv.unit();
|
|
|
|
(*group2)[i2].grad = dv.unit();
|
2014-12-02 10:09:53 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-28 02:17:34 +08:00
|
|
|
|
2014-12-02 10:09:53 +08:00
|
|
|
void colvar::distance_pairs::calc_gradients()
|
|
|
|
{
|
|
|
|
// will be calculated on the fly in apply_force()
|
|
|
|
}
|
|
|
|
|
2016-12-28 02:17:34 +08:00
|
|
|
|
2014-12-02 10:09:53 +08:00
|
|
|
void colvar::distance_pairs::apply_force(colvarvalue const &force)
|
|
|
|
{
|
2017-07-20 02:10:43 +08:00
|
|
|
if (!is_enabled(f_cvc_pbc_minimum_image)) {
|
2014-12-02 10:09:53 +08:00
|
|
|
size_t i1, i2;
|
2016-04-16 00:07:01 +08:00
|
|
|
for (i1 = 0; i1 < group1->size(); i1++) {
|
|
|
|
for (i2 = 0; i2 < group2->size(); i2++) {
|
|
|
|
cvm::rvector const dv = (*group2)[i2].pos - (*group1)[i1].pos;
|
|
|
|
(*group1)[i1].apply_force(force[i1*group2->size() + i2] * (-1.0) * dv.unit());
|
|
|
|
(*group2)[i2].apply_force(force[i1*group2->size() + i2] * dv.unit());
|
2014-12-02 10:09:53 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
size_t i1, i2;
|
2016-04-16 00:07:01 +08:00
|
|
|
for (i1 = 0; i1 < group1->size(); i1++) {
|
|
|
|
for (i2 = 0; i2 < group2->size(); i2++) {
|
2017-07-20 02:10:43 +08:00
|
|
|
cvm::rvector const dv = cvm::position_distance((*group1)[i1].pos,
|
|
|
|
(*group2)[i2].pos);
|
2016-04-16 00:07:01 +08:00
|
|
|
(*group1)[i1].apply_force(force[i1*group2->size() + i2] * (-1.0) * dv.unit());
|
|
|
|
(*group2)[i2].apply_force(force[i1*group2->size() + i2] * dv.unit());
|
2014-12-02 10:09:53 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-12-28 02:17:34 +08:00
|
|
|
|
2014-12-02 10:09:53 +08:00
|
|
|
colvar::gyration::gyration(std::string const &conf)
|
|
|
|
: cvc(conf)
|
2012-05-24 00:20:04 +08:00
|
|
|
{
|
|
|
|
function_type = "gyration";
|
2016-04-16 00:07:01 +08:00
|
|
|
provide(f_cvc_inv_gradient);
|
|
|
|
provide(f_cvc_Jacobian);
|
|
|
|
atoms = parse_group(conf, "atoms");
|
2013-02-02 06:39:47 +08:00
|
|
|
|
2016-04-16 00:07:01 +08:00
|
|
|
if (atoms->b_user_defined_fit) {
|
2014-12-02 10:09:53 +08:00
|
|
|
cvm::log("WARNING: explicit fitting parameters were provided for atom group \"atoms\".");
|
2013-02-02 06:39:47 +08:00
|
|
|
} else {
|
2016-04-16 00:07:01 +08:00
|
|
|
atoms->b_center = true;
|
|
|
|
atoms->ref_pos.assign(1, cvm::atom_pos(0.0, 0.0, 0.0));
|
2016-12-28 02:17:02 +08:00
|
|
|
atoms->fit_gradients.assign(atoms->size(), cvm::rvector(0.0, 0.0, 0.0));
|
2013-02-02 06:39:47 +08:00
|
|
|
}
|
|
|
|
|
2014-12-02 10:09:53 +08:00
|
|
|
x.type(colvarvalue::type_scalar);
|
2012-05-24 00:20:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
colvar::gyration::gyration()
|
|
|
|
{
|
|
|
|
function_type = "gyration";
|
2016-04-16 00:07:01 +08:00
|
|
|
provide(f_cvc_inv_gradient);
|
|
|
|
provide(f_cvc_Jacobian);
|
2014-12-02 10:09:53 +08:00
|
|
|
x.type(colvarvalue::type_scalar);
|
2012-05-24 00:20:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void colvar::gyration::calc_value()
|
|
|
|
{
|
|
|
|
x.real_value = 0.0;
|
2016-04-16 00:07:01 +08:00
|
|
|
for (cvm::atom_iter ai = atoms->begin(); ai != atoms->end(); ai++) {
|
2012-06-30 01:52:31 +08:00
|
|
|
x.real_value += (ai->pos).norm2();
|
2012-05-24 00:20:04 +08:00
|
|
|
}
|
2016-04-16 00:07:01 +08:00
|
|
|
x.real_value = std::sqrt(x.real_value / cvm::real(atoms->size()));
|
2012-05-24 00:20:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void colvar::gyration::calc_gradients()
|
|
|
|
{
|
2016-04-16 00:07:01 +08:00
|
|
|
cvm::real const drdx = 1.0/(cvm::real(atoms->size()) * x.real_value);
|
|
|
|
for (cvm::atom_iter ai = atoms->begin(); ai != atoms->end(); ai++) {
|
2012-05-24 00:20:04 +08:00
|
|
|
ai->grad = drdx * ai->pos;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void colvar::gyration::calc_force_invgrads()
|
|
|
|
{
|
2016-09-09 04:20:32 +08:00
|
|
|
atoms->read_total_forces();
|
2012-05-24 00:20:04 +08:00
|
|
|
|
|
|
|
cvm::real const dxdr = 1.0/x.real_value;
|
|
|
|
ft.real_value = 0.0;
|
|
|
|
|
2016-04-16 00:07:01 +08:00
|
|
|
for (cvm::atom_iter ai = atoms->begin(); ai != atoms->end(); ai++) {
|
2016-09-09 04:20:32 +08:00
|
|
|
ft.real_value += dxdr * ai->pos * ai->total_force;
|
2012-05-24 00:20:04 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void colvar::gyration::calc_Jacobian_derivative()
|
|
|
|
{
|
2016-04-16 00:07:01 +08:00
|
|
|
jd = x.real_value ? (3.0 * cvm::real(atoms->size()) - 4.0) / x.real_value : 0.0;
|
2012-05-24 00:20:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-12-02 10:09:53 +08:00
|
|
|
void colvar::gyration::apply_force(colvarvalue const &force)
|
2012-05-24 00:20:04 +08:00
|
|
|
{
|
2016-04-16 00:07:01 +08:00
|
|
|
if (!atoms->noforce)
|
|
|
|
atoms->apply_colvar_force(force.real_value);
|
2012-05-24 00:20:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-12-28 02:17:34 +08:00
|
|
|
simple_scalar_dist_functions(gyration)
|
|
|
|
|
|
|
|
|
2012-05-24 00:20:04 +08:00
|
|
|
|
2014-12-02 10:09:53 +08:00
|
|
|
colvar::inertia::inertia(std::string const &conf)
|
|
|
|
: gyration(conf)
|
2012-06-30 01:52:31 +08:00
|
|
|
{
|
|
|
|
function_type = "inertia";
|
2014-12-02 10:09:53 +08:00
|
|
|
x.type(colvarvalue::type_scalar);
|
2012-06-30 01:52:31 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
colvar::inertia::inertia()
|
|
|
|
{
|
|
|
|
function_type = "inertia";
|
2014-12-02 10:09:53 +08:00
|
|
|
x.type(colvarvalue::type_scalar);
|
2012-06-30 01:52:31 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void colvar::inertia::calc_value()
|
|
|
|
{
|
|
|
|
x.real_value = 0.0;
|
2016-04-16 00:07:01 +08:00
|
|
|
for (cvm::atom_iter ai = atoms->begin(); ai != atoms->end(); ai++) {
|
2013-04-24 03:03:56 +08:00
|
|
|
x.real_value += (ai->pos).norm2();
|
2012-06-30 01:52:31 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void colvar::inertia::calc_gradients()
|
|
|
|
{
|
2016-04-16 00:07:01 +08:00
|
|
|
for (cvm::atom_iter ai = atoms->begin(); ai != atoms->end(); ai++) {
|
2013-04-24 03:03:56 +08:00
|
|
|
ai->grad = 2.0 * ai->pos;
|
2012-06-30 01:52:31 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-12-02 10:09:53 +08:00
|
|
|
void colvar::inertia::apply_force(colvarvalue const &force)
|
2012-06-30 01:52:31 +08:00
|
|
|
{
|
2016-04-16 00:07:01 +08:00
|
|
|
if (!atoms->noforce)
|
|
|
|
atoms->apply_colvar_force(force.real_value);
|
2012-06-30 01:52:31 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-12-28 02:17:34 +08:00
|
|
|
simple_scalar_dist_functions(inertia_z)
|
|
|
|
|
|
|
|
|
|
|
|
|
2014-12-02 10:09:53 +08:00
|
|
|
colvar::inertia_z::inertia_z(std::string const &conf)
|
|
|
|
: inertia(conf)
|
2012-06-30 01:52:31 +08:00
|
|
|
{
|
|
|
|
function_type = "inertia_z";
|
2014-12-02 10:09:53 +08:00
|
|
|
if (get_keyval(conf, "axis", axis, cvm::rvector(0.0, 0.0, 1.0))) {
|
2014-10-08 04:30:25 +08:00
|
|
|
if (axis.norm2() == 0.0) {
|
2014-12-02 10:09:53 +08:00
|
|
|
cvm::error("Axis vector is zero!");
|
2014-10-08 04:30:25 +08:00
|
|
|
return;
|
|
|
|
}
|
2012-08-23 21:09:47 +08:00
|
|
|
if (axis.norm2() != 1.0) {
|
|
|
|
axis = axis.unit();
|
2014-12-02 10:09:53 +08:00
|
|
|
cvm::log("The normalized axis is: "+cvm::to_str(axis)+".\n");
|
2012-08-23 21:09:47 +08:00
|
|
|
}
|
2012-06-30 01:52:31 +08:00
|
|
|
}
|
2014-12-02 10:09:53 +08:00
|
|
|
x.type(colvarvalue::type_scalar);
|
2012-06-30 01:52:31 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
colvar::inertia_z::inertia_z()
|
|
|
|
{
|
|
|
|
function_type = "inertia_z";
|
2014-12-02 10:09:53 +08:00
|
|
|
x.type(colvarvalue::type_scalar);
|
2012-06-30 01:52:31 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void colvar::inertia_z::calc_value()
|
|
|
|
{
|
|
|
|
x.real_value = 0.0;
|
2016-04-16 00:07:01 +08:00
|
|
|
for (cvm::atom_iter ai = atoms->begin(); ai != atoms->end(); ai++) {
|
2012-06-30 01:52:31 +08:00
|
|
|
cvm::real const iprod = ai->pos * axis;
|
2013-04-24 03:03:56 +08:00
|
|
|
x.real_value += iprod * iprod;
|
2012-06-30 01:52:31 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void colvar::inertia_z::calc_gradients()
|
|
|
|
{
|
2016-04-16 00:07:01 +08:00
|
|
|
for (cvm::atom_iter ai = atoms->begin(); ai != atoms->end(); ai++) {
|
2013-04-24 03:03:56 +08:00
|
|
|
ai->grad = 2.0 * (ai->pos * axis) * axis;
|
2012-06-30 01:52:31 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-12-02 10:09:53 +08:00
|
|
|
void colvar::inertia_z::apply_force(colvarvalue const &force)
|
2012-06-30 01:52:31 +08:00
|
|
|
{
|
2016-04-16 00:07:01 +08:00
|
|
|
if (!atoms->noforce)
|
|
|
|
atoms->apply_colvar_force(force.real_value);
|
2012-06-30 01:52:31 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-12-28 02:17:34 +08:00
|
|
|
simple_scalar_dist_functions(inertia)
|
|
|
|
|
|
|
|
|
|
|
|
|
2012-06-30 01:52:31 +08:00
|
|
|
|
2014-12-02 10:09:53 +08:00
|
|
|
colvar::rmsd::rmsd(std::string const &conf)
|
|
|
|
: cvc(conf)
|
2012-05-24 00:20:04 +08:00
|
|
|
{
|
2016-04-16 00:07:01 +08:00
|
|
|
provide(f_cvc_inv_gradient);
|
2012-05-24 00:20:04 +08:00
|
|
|
function_type = "rmsd";
|
2014-12-02 10:09:53 +08:00
|
|
|
x.type(colvarvalue::type_scalar);
|
2012-05-24 00:20:04 +08:00
|
|
|
|
2016-04-16 00:07:01 +08:00
|
|
|
atoms = parse_group(conf, "atoms");
|
2012-10-24 00:57:29 +08:00
|
|
|
|
2016-04-28 22:48:56 +08:00
|
|
|
if (!atoms || atoms->size() == 0) {
|
2016-04-16 00:07:01 +08:00
|
|
|
cvm::error("Error: \"atoms\" must contain at least 1 atom to compute RMSD.");
|
2014-10-08 04:30:25 +08:00
|
|
|
return;
|
|
|
|
}
|
2012-10-24 00:57:29 +08:00
|
|
|
|
2016-04-16 00:07:01 +08:00
|
|
|
bool b_Jacobian_derivative = true;
|
2016-06-18 07:07:51 +08:00
|
|
|
if (atoms->fitting_group != NULL && b_Jacobian_derivative) {
|
2018-11-03 05:45:20 +08:00
|
|
|
cvm::log("The option \"fittingGroup\" (alternative group for fitting) was enabled: "
|
2013-02-02 06:39:47 +08:00
|
|
|
"Jacobian derivatives of the RMSD will not be calculated.\n");
|
|
|
|
b_Jacobian_derivative = false;
|
2012-10-24 00:57:29 +08:00
|
|
|
}
|
2016-04-16 00:07:01 +08:00
|
|
|
if (b_Jacobian_derivative) provide(f_cvc_Jacobian);
|
2012-10-24 00:57:29 +08:00
|
|
|
|
2013-02-02 06:39:47 +08:00
|
|
|
// the following is a simplified version of the corresponding atom group options;
|
|
|
|
// we need this because the reference coordinates defined inside the atom group
|
2016-06-18 07:07:51 +08:00
|
|
|
// may be used only for fitting, and even more so if fitting_group is used
|
2014-12-02 10:09:53 +08:00
|
|
|
if (get_keyval(conf, "refPositions", ref_pos, ref_pos)) {
|
|
|
|
cvm::log("Using reference positions from configuration file to calculate the variable.\n");
|
2016-04-16 00:07:01 +08:00
|
|
|
if (ref_pos.size() != atoms->size()) {
|
2014-12-02 10:09:53 +08:00
|
|
|
cvm::error("Error: the number of reference positions provided ("+
|
|
|
|
cvm::to_str(ref_pos.size())+
|
2014-10-08 04:30:25 +08:00
|
|
|
") does not match the number of atoms of group \"atoms\" ("+
|
2016-04-16 00:07:01 +08:00
|
|
|
cvm::to_str(atoms->size())+").\n");
|
2014-10-08 04:30:25 +08:00
|
|
|
return;
|
2012-10-24 00:57:29 +08:00
|
|
|
}
|
2012-05-24 00:20:04 +08:00
|
|
|
}
|
2012-10-24 00:57:29 +08:00
|
|
|
{
|
|
|
|
std::string ref_pos_file;
|
2014-12-02 10:09:53 +08:00
|
|
|
if (get_keyval(conf, "refPositionsFile", ref_pos_file, std::string(""))) {
|
2012-10-24 00:57:29 +08:00
|
|
|
|
|
|
|
if (ref_pos.size()) {
|
2014-12-02 10:09:53 +08:00
|
|
|
cvm::error("Error: cannot specify \"refPositionsFile\" and "
|
2012-10-24 00:57:29 +08:00
|
|
|
"\"refPositions\" at the same time.\n");
|
2014-10-08 04:30:25 +08:00
|
|
|
return;
|
2012-10-24 00:57:29 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
std::string ref_pos_col;
|
2015-04-30 22:09:42 +08:00
|
|
|
double ref_pos_col_value=0.0;
|
2013-06-28 06:48:27 +08:00
|
|
|
|
2014-12-02 10:09:53 +08:00
|
|
|
if (get_keyval(conf, "refPositionsCol", ref_pos_col, std::string(""))) {
|
2012-10-24 00:57:29 +08:00
|
|
|
// if provided, use PDB column to select coordinates
|
2014-12-02 10:09:53 +08:00
|
|
|
bool found = get_keyval(conf, "refPositionsColValue", ref_pos_col_value, 0.0);
|
2015-04-30 22:09:42 +08:00
|
|
|
if (found && ref_pos_col_value==0.0) {
|
2014-12-02 10:09:53 +08:00
|
|
|
cvm::error("Error: refPositionsColValue, "
|
2015-02-20 02:20:52 +08:00
|
|
|
"if provided, must be non-zero.\n");
|
2014-10-08 04:30:25 +08:00
|
|
|
return;
|
2015-02-20 02:20:52 +08:00
|
|
|
}
|
2012-10-24 00:57:29 +08:00
|
|
|
}
|
2012-12-01 02:03:00 +08:00
|
|
|
|
2018-05-03 02:57:41 +08:00
|
|
|
ref_pos.resize(atoms->size());
|
|
|
|
|
|
|
|
cvm::load_coords(ref_pos_file.c_str(), &ref_pos, atoms,
|
|
|
|
ref_pos_col, ref_pos_col_value);
|
2012-10-24 00:57:29 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-16 00:07:01 +08:00
|
|
|
if (ref_pos.size() != atoms->size()) {
|
2016-04-14 06:25:46 +08:00
|
|
|
cvm::error("Error: found " + cvm::to_str(ref_pos.size()) +
|
2016-04-16 00:07:01 +08:00
|
|
|
" reference positions; expected " + cvm::to_str(atoms->size()));
|
2016-04-14 06:25:46 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-04-16 00:07:01 +08:00
|
|
|
if (atoms->b_user_defined_fit) {
|
2014-12-02 10:09:53 +08:00
|
|
|
cvm::log("WARNING: explicit fitting parameters were provided for atom group \"atoms\".");
|
2013-02-02 06:39:47 +08:00
|
|
|
} else {
|
|
|
|
// Default: fit everything
|
2014-12-02 10:09:53 +08:00
|
|
|
cvm::log("Enabling \"centerReference\" and \"rotateReference\", to minimize RMSD before calculating it as a variable: "
|
2013-04-24 03:03:56 +08:00
|
|
|
"if this is not the desired behavior, disable them explicitly within the \"atoms\" block.\n");
|
2016-04-16 00:07:01 +08:00
|
|
|
atoms->b_center = true;
|
|
|
|
atoms->b_rotate = true;
|
2013-02-02 06:39:47 +08:00
|
|
|
// default case: reference positions for calculating the rmsd are also those used
|
2012-12-01 02:03:00 +08:00
|
|
|
// for fitting
|
2016-04-16 00:07:01 +08:00
|
|
|
atoms->ref_pos = ref_pos;
|
|
|
|
atoms->center_ref_pos();
|
2013-02-02 06:39:47 +08:00
|
|
|
|
2014-12-02 10:09:53 +08:00
|
|
|
cvm::log("This is a standard minimum RMSD, derivatives of the optimal rotation "
|
2014-10-29 03:53:17 +08:00
|
|
|
"will not be computed as they cancel out in the gradients.");
|
2017-07-20 02:10:43 +08:00
|
|
|
atoms->disable(f_ag_fit_gradients);
|
2014-10-29 03:53:17 +08:00
|
|
|
|
2013-02-02 06:39:47 +08:00
|
|
|
// request the calculation of the derivatives of the rotation defined by the atom group
|
2016-04-16 00:07:01 +08:00
|
|
|
atoms->rot.request_group1_gradients(atoms->size());
|
2013-02-02 06:39:47 +08:00
|
|
|
// request derivatives of optimal rotation wrt reference coordinates for Jacobian:
|
2016-04-28 22:48:56 +08:00
|
|
|
// this is only required for ABF, but we do both groups here for better caching
|
2016-04-16 00:07:01 +08:00
|
|
|
atoms->rot.request_group2_gradients(atoms->size());
|
2012-12-01 02:03:00 +08:00
|
|
|
}
|
2012-05-24 00:20:04 +08:00
|
|
|
}
|
|
|
|
|
2013-06-28 06:48:27 +08:00
|
|
|
|
2012-05-24 00:20:04 +08:00
|
|
|
void colvar::rmsd::calc_value()
|
|
|
|
{
|
2013-02-02 06:39:47 +08:00
|
|
|
// rotational-translational fit is handled by the atom group
|
2012-05-24 00:20:04 +08:00
|
|
|
|
2012-10-24 00:57:29 +08:00
|
|
|
x.real_value = 0.0;
|
2016-04-16 00:07:01 +08:00
|
|
|
for (size_t ia = 0; ia < atoms->size(); ia++) {
|
|
|
|
x.real_value += ((*atoms)[ia].pos - ref_pos[ia]).norm2();
|
2012-10-24 00:57:29 +08:00
|
|
|
}
|
2016-04-16 00:07:01 +08:00
|
|
|
x.real_value /= cvm::real(atoms->size()); // MSD
|
2014-12-02 10:09:53 +08:00
|
|
|
x.real_value = std::sqrt(x.real_value);
|
2012-05-24 00:20:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void colvar::rmsd::calc_gradients()
|
|
|
|
{
|
|
|
|
cvm::real const drmsddx2 = (x.real_value > 0.0) ?
|
2016-04-16 00:07:01 +08:00
|
|
|
0.5 / (x.real_value * cvm::real(atoms->size())) :
|
2012-05-24 00:20:04 +08:00
|
|
|
0.0;
|
|
|
|
|
2016-04-16 00:07:01 +08:00
|
|
|
for (size_t ia = 0; ia < atoms->size(); ia++) {
|
|
|
|
(*atoms)[ia].grad = (drmsddx2 * 2.0 * ((*atoms)[ia].pos - ref_pos[ia]));
|
2012-05-24 00:20:04 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-12-02 10:09:53 +08:00
|
|
|
void colvar::rmsd::apply_force(colvarvalue const &force)
|
2012-05-24 00:20:04 +08:00
|
|
|
{
|
2016-04-16 00:07:01 +08:00
|
|
|
if (!atoms->noforce)
|
|
|
|
atoms->apply_colvar_force(force.real_value);
|
2012-05-24 00:20:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void colvar::rmsd::calc_force_invgrads()
|
|
|
|
{
|
2016-09-09 04:20:32 +08:00
|
|
|
atoms->read_total_forces();
|
2012-05-24 00:20:04 +08:00
|
|
|
ft.real_value = 0.0;
|
2013-06-28 06:48:27 +08:00
|
|
|
|
2012-05-24 00:20:04 +08:00
|
|
|
// Note: gradient square norm is 1/N_atoms
|
2013-06-28 06:48:27 +08:00
|
|
|
|
2016-04-16 00:07:01 +08:00
|
|
|
for (size_t ia = 0; ia < atoms->size(); ia++) {
|
2016-09-09 04:20:32 +08:00
|
|
|
ft.real_value += (*atoms)[ia].grad * (*atoms)[ia].total_force;
|
2012-05-24 00:20:04 +08:00
|
|
|
}
|
2016-04-16 00:07:01 +08:00
|
|
|
ft.real_value *= atoms->size();
|
2012-05-24 00:20:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void colvar::rmsd::calc_Jacobian_derivative()
|
|
|
|
{
|
2012-10-24 00:57:29 +08:00
|
|
|
// divergence of the rotated coordinates (including only derivatives of the rotation matrix)
|
2017-10-14 01:25:02 +08:00
|
|
|
cvm::real rotation_term = 0.0;
|
2012-05-24 00:20:04 +08:00
|
|
|
|
2017-10-14 01:25:02 +08:00
|
|
|
// The rotation term only applies is coordinates are rotated
|
2016-04-16 00:07:01 +08:00
|
|
|
if (atoms->b_rotate) {
|
2012-05-24 00:20:04 +08:00
|
|
|
|
2012-10-24 00:57:29 +08:00
|
|
|
// gradient of the rotation matrix
|
2014-12-02 10:09:53 +08:00
|
|
|
cvm::matrix2d<cvm::rvector> grad_rot_mat(3, 3);
|
2013-06-28 06:48:27 +08:00
|
|
|
// gradients of products of 2 quaternion components
|
2012-10-24 00:57:29 +08:00
|
|
|
cvm::rvector g11, g22, g33, g01, g02, g03, g12, g13, g23;
|
2016-04-16 00:07:01 +08:00
|
|
|
for (size_t ia = 0; ia < atoms->size(); ia++) {
|
2012-10-24 00:57:29 +08:00
|
|
|
|
|
|
|
// Gradient of optimal quaternion wrt current Cartesian position
|
2016-04-16 00:07:01 +08:00
|
|
|
cvm::vector1d<cvm::rvector> &dq = atoms->rot.dQ0_1[ia];
|
|
|
|
|
|
|
|
g11 = 2.0 * (atoms->rot.q)[1]*dq[1];
|
|
|
|
g22 = 2.0 * (atoms->rot.q)[2]*dq[2];
|
|
|
|
g33 = 2.0 * (atoms->rot.q)[3]*dq[3];
|
|
|
|
g01 = (atoms->rot.q)[0]*dq[1] + (atoms->rot.q)[1]*dq[0];
|
|
|
|
g02 = (atoms->rot.q)[0]*dq[2] + (atoms->rot.q)[2]*dq[0];
|
|
|
|
g03 = (atoms->rot.q)[0]*dq[3] + (atoms->rot.q)[3]*dq[0];
|
|
|
|
g12 = (atoms->rot.q)[1]*dq[2] + (atoms->rot.q)[2]*dq[1];
|
|
|
|
g13 = (atoms->rot.q)[1]*dq[3] + (atoms->rot.q)[3]*dq[1];
|
|
|
|
g23 = (atoms->rot.q)[2]*dq[3] + (atoms->rot.q)[3]*dq[2];
|
2012-10-24 00:57:29 +08:00
|
|
|
|
|
|
|
// Gradient of the rotation matrix wrt current Cartesian position
|
2013-06-28 06:48:27 +08:00
|
|
|
grad_rot_mat[0][0] = -2.0 * (g22 + g33);
|
|
|
|
grad_rot_mat[1][0] = 2.0 * (g12 + g03);
|
|
|
|
grad_rot_mat[2][0] = 2.0 * (g13 - g02);
|
|
|
|
grad_rot_mat[0][1] = 2.0 * (g12 - g03);
|
|
|
|
grad_rot_mat[1][1] = -2.0 * (g11 + g33);
|
|
|
|
grad_rot_mat[2][1] = 2.0 * (g01 + g23);
|
|
|
|
grad_rot_mat[0][2] = 2.0 * (g02 + g13);
|
|
|
|
grad_rot_mat[1][2] = 2.0 * (g23 - g01);
|
|
|
|
grad_rot_mat[2][2] = -2.0 * (g11 + g22);
|
2012-10-24 00:57:29 +08:00
|
|
|
|
2013-02-02 06:39:47 +08:00
|
|
|
cvm::atom_pos &y = ref_pos[ia];
|
2012-10-24 00:57:29 +08:00
|
|
|
|
2013-02-02 06:39:47 +08:00
|
|
|
for (size_t alpha = 0; alpha < 3; alpha++) {
|
|
|
|
for (size_t beta = 0; beta < 3; beta++) {
|
2017-10-14 01:25:02 +08:00
|
|
|
rotation_term += grad_rot_mat[beta][alpha][alpha] * y[beta];
|
2013-02-02 06:39:47 +08:00
|
|
|
// Note: equation was derived for inverse rotation (see colvars paper)
|
|
|
|
// so here the matrix is transposed
|
|
|
|
// (eq would give divergence += grad_rot_mat[alpha][beta][alpha] * y[beta];)
|
2012-10-24 00:57:29 +08:00
|
|
|
}
|
2012-05-24 00:20:04 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-10-14 01:25:02 +08:00
|
|
|
|
|
|
|
// The translation term only applies is coordinates are centered
|
|
|
|
cvm::real translation_term = atoms->b_center ? 3.0 : 0.0;
|
|
|
|
|
|
|
|
jd.real_value = x.real_value > 0.0 ?
|
|
|
|
(3.0 * atoms->size() - 1.0 - translation_term - rotation_term) / x.real_value :
|
|
|
|
0.0;
|
2012-05-24 00:20:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-12-28 02:17:34 +08:00
|
|
|
simple_scalar_dist_functions(rmsd)
|
|
|
|
|
2012-05-24 00:20:04 +08:00
|
|
|
|
|
|
|
|
2014-12-02 10:09:53 +08:00
|
|
|
colvar::eigenvector::eigenvector(std::string const &conf)
|
|
|
|
: cvc(conf)
|
2012-05-24 00:20:04 +08:00
|
|
|
{
|
2016-04-16 00:07:01 +08:00
|
|
|
provide(f_cvc_inv_gradient);
|
|
|
|
provide(f_cvc_Jacobian);
|
2012-05-24 00:20:04 +08:00
|
|
|
function_type = "eigenvector";
|
2014-12-02 10:09:53 +08:00
|
|
|
x.type(colvarvalue::type_scalar);
|
2012-05-24 00:20:04 +08:00
|
|
|
|
2016-04-16 00:07:01 +08:00
|
|
|
atoms = parse_group(conf, "atoms");
|
2012-05-24 00:20:04 +08:00
|
|
|
|
2013-02-02 06:39:47 +08:00
|
|
|
{
|
2014-12-02 10:09:53 +08:00
|
|
|
bool const b_inline = get_keyval(conf, "refPositions", ref_pos, ref_pos);
|
2013-02-02 06:39:47 +08:00
|
|
|
|
|
|
|
if (b_inline) {
|
2014-12-02 10:09:53 +08:00
|
|
|
cvm::log("Using reference positions from input file.\n");
|
2016-04-16 00:07:01 +08:00
|
|
|
if (ref_pos.size() != atoms->size()) {
|
2014-12-02 10:09:53 +08:00
|
|
|
cvm::error("Error: reference positions do not "
|
2016-04-28 22:48:56 +08:00
|
|
|
"match the number of requested atoms.\n");
|
2014-10-08 04:30:25 +08:00
|
|
|
return;
|
2013-02-02 06:39:47 +08:00
|
|
|
}
|
2012-05-24 00:20:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
std::string file_name;
|
2014-12-02 10:09:53 +08:00
|
|
|
if (get_keyval(conf, "refPositionsFile", file_name)) {
|
2012-05-24 00:20:04 +08:00
|
|
|
|
2014-10-08 04:30:25 +08:00
|
|
|
if (b_inline) {
|
2014-12-02 10:09:53 +08:00
|
|
|
cvm::error("Error: refPositions and refPositionsFile cannot be specified at the same time.\n");
|
2014-10-08 04:30:25 +08:00
|
|
|
return;
|
|
|
|
}
|
2013-02-02 06:39:47 +08:00
|
|
|
|
2012-05-24 00:20:04 +08:00
|
|
|
std::string file_col;
|
2015-04-30 22:09:42 +08:00
|
|
|
double file_col_value=0.0;
|
2014-12-02 10:09:53 +08:00
|
|
|
if (get_keyval(conf, "refPositionsCol", file_col, std::string(""))) {
|
2012-05-24 00:20:04 +08:00
|
|
|
// use PDB flags if column is provided
|
2014-12-02 10:09:53 +08:00
|
|
|
bool found = get_keyval(conf, "refPositionsColValue", file_col_value, 0.0);
|
2015-04-30 22:09:42 +08:00
|
|
|
if (found && file_col_value==0.0) {
|
2014-12-02 10:09:53 +08:00
|
|
|
cvm::error("Error: refPositionsColValue, "
|
2012-05-24 00:20:04 +08:00
|
|
|
"if provided, must be non-zero.\n");
|
2014-10-08 04:30:25 +08:00
|
|
|
return;
|
|
|
|
}
|
2012-05-24 00:20:04 +08:00
|
|
|
}
|
|
|
|
|
2016-04-16 00:07:01 +08:00
|
|
|
ref_pos.resize(atoms->size());
|
2018-05-03 02:57:41 +08:00
|
|
|
cvm::load_coords(file_name.c_str(), &ref_pos, atoms,
|
|
|
|
file_col, file_col_value);
|
2012-05-24 00:20:04 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-28 22:48:56 +08:00
|
|
|
if (ref_pos.size() == 0) {
|
|
|
|
cvm::error("Error: reference positions were not provided.\n", INPUT_ERROR);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-04-16 00:07:01 +08:00
|
|
|
if (ref_pos.size() != atoms->size()) {
|
2016-04-28 22:48:56 +08:00
|
|
|
cvm::error("Error: reference positions do not "
|
|
|
|
"match the number of requested atoms.\n", INPUT_ERROR);
|
2016-04-14 06:25:46 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-02-02 06:39:47 +08:00
|
|
|
// save for later the geometric center of the provided positions (may not be the origin)
|
2014-12-02 10:09:53 +08:00
|
|
|
cvm::rvector ref_pos_center(0.0, 0.0, 0.0);
|
2016-04-16 00:07:01 +08:00
|
|
|
for (size_t i = 0; i < atoms->size(); i++) {
|
2013-02-02 06:39:47 +08:00
|
|
|
ref_pos_center += ref_pos[i];
|
|
|
|
}
|
2016-04-16 00:07:01 +08:00
|
|
|
ref_pos_center *= 1.0 / atoms->size();
|
2013-02-02 06:39:47 +08:00
|
|
|
|
2016-04-16 00:07:01 +08:00
|
|
|
if (atoms->b_user_defined_fit) {
|
2014-12-02 10:09:53 +08:00
|
|
|
cvm::log("WARNING: explicit fitting parameters were provided for atom group \"atoms\".\n");
|
2013-02-02 06:39:47 +08:00
|
|
|
} else {
|
|
|
|
// default: fit everything
|
2014-12-02 10:09:53 +08:00
|
|
|
cvm::log("Enabling \"centerReference\" and \"rotateReference\", to minimize RMSD before calculating the vector projection: "
|
2013-04-24 03:03:56 +08:00
|
|
|
"if this is not the desired behavior, disable them explicitly within the \"atoms\" block.\n");
|
2016-04-16 00:07:01 +08:00
|
|
|
atoms->b_center = true;
|
|
|
|
atoms->b_rotate = true;
|
|
|
|
atoms->ref_pos = ref_pos;
|
|
|
|
atoms->center_ref_pos();
|
2017-07-20 02:10:43 +08:00
|
|
|
atoms->disable(f_ag_fit_gradients); // cancel out if group is fitted on itself
|
|
|
|
// and cvc is translationally invariant
|
2013-02-02 06:39:47 +08:00
|
|
|
|
|
|
|
// request the calculation of the derivatives of the rotation defined by the atom group
|
2016-04-16 00:07:01 +08:00
|
|
|
atoms->rot.request_group1_gradients(atoms->size());
|
2013-02-02 06:39:47 +08:00
|
|
|
// request derivatives of optimal rotation wrt reference coordinates for Jacobian:
|
|
|
|
// this is only required for ABF, but we do both groups here for better caching
|
2016-04-16 00:07:01 +08:00
|
|
|
atoms->rot.request_group2_gradients(atoms->size());
|
2012-05-24 00:20:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
{
|
2014-12-02 10:09:53 +08:00
|
|
|
bool const b_inline = get_keyval(conf, "vector", eigenvec, eigenvec);
|
2013-02-02 06:39:47 +08:00
|
|
|
// now load the eigenvector
|
|
|
|
if (b_inline) {
|
2014-12-02 10:09:53 +08:00
|
|
|
cvm::log("Using vector components from input file.\n");
|
2016-04-16 00:07:01 +08:00
|
|
|
if (eigenvec.size() != atoms->size()) {
|
2017-07-20 02:10:43 +08:00
|
|
|
cvm::error("Error: vector components do not "
|
2016-04-16 00:07:01 +08:00
|
|
|
"match the number of requested atoms->\n");
|
2017-07-20 02:10:43 +08:00
|
|
|
return;
|
2013-02-02 06:39:47 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-05-24 00:20:04 +08:00
|
|
|
std::string file_name;
|
2014-12-02 10:09:53 +08:00
|
|
|
if (get_keyval(conf, "vectorFile", file_name)) {
|
2012-05-24 00:20:04 +08:00
|
|
|
|
2014-10-08 04:30:25 +08:00
|
|
|
if (b_inline) {
|
2014-12-02 10:09:53 +08:00
|
|
|
cvm::error("Error: vector and vectorFile cannot be specified at the same time.\n");
|
2014-10-08 04:30:25 +08:00
|
|
|
return;
|
|
|
|
}
|
2012-05-24 00:20:04 +08:00
|
|
|
|
2013-02-02 06:39:47 +08:00
|
|
|
std::string file_col;
|
2015-04-30 22:09:42 +08:00
|
|
|
double file_col_value=0.0;
|
2014-12-02 10:09:53 +08:00
|
|
|
if (get_keyval(conf, "vectorCol", file_col, std::string(""))) {
|
2013-02-02 06:39:47 +08:00
|
|
|
// use PDB flags if column is provided
|
2014-12-02 10:09:53 +08:00
|
|
|
bool found = get_keyval(conf, "vectorColValue", file_col_value, 0.0);
|
2015-04-30 22:09:42 +08:00
|
|
|
if (found && file_col_value==0.0) {
|
2014-12-02 10:09:53 +08:00
|
|
|
cvm::error("Error: vectorColValue, if provided, must be non-zero.\n");
|
2014-10-08 04:30:25 +08:00
|
|
|
return;
|
|
|
|
}
|
2013-02-02 06:39:47 +08:00
|
|
|
}
|
2012-05-24 00:20:04 +08:00
|
|
|
|
2016-04-16 00:07:01 +08:00
|
|
|
eigenvec.resize(atoms->size());
|
2018-05-03 02:57:41 +08:00
|
|
|
cvm::load_coords(file_name.c_str(), &eigenvec, atoms,
|
|
|
|
file_col, file_col_value);
|
2012-05-24 00:20:04 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!ref_pos.size() || !eigenvec.size()) {
|
2014-12-02 10:09:53 +08:00
|
|
|
cvm::error("Error: both reference coordinates"
|
2012-05-24 00:20:04 +08:00
|
|
|
"and eigenvector must be defined.\n");
|
2014-10-08 04:30:25 +08:00
|
|
|
return;
|
2012-05-24 00:20:04 +08:00
|
|
|
}
|
|
|
|
|
2014-12-02 10:09:53 +08:00
|
|
|
cvm::atom_pos eig_center(0.0, 0.0, 0.0);
|
2016-04-16 00:07:01 +08:00
|
|
|
for (size_t eil = 0; eil < atoms->size(); eil++) {
|
2014-10-08 04:30:25 +08:00
|
|
|
eig_center += eigenvec[eil];
|
2013-02-02 06:39:47 +08:00
|
|
|
}
|
2016-04-16 00:07:01 +08:00
|
|
|
eig_center *= 1.0 / atoms->size();
|
2014-12-02 10:09:53 +08:00
|
|
|
cvm::log("Geometric center of the provided vector: "+cvm::to_str(eig_center)+"\n");
|
2013-02-02 06:39:47 +08:00
|
|
|
|
2013-04-24 03:03:56 +08:00
|
|
|
bool b_difference_vector = false;
|
2014-12-02 10:09:53 +08:00
|
|
|
get_keyval(conf, "differenceVector", b_difference_vector, false);
|
2013-02-02 06:39:47 +08:00
|
|
|
|
2013-04-24 03:03:56 +08:00
|
|
|
if (b_difference_vector) {
|
2013-02-02 06:39:47 +08:00
|
|
|
|
2016-04-16 00:07:01 +08:00
|
|
|
if (atoms->b_center) {
|
2013-02-02 06:39:47 +08:00
|
|
|
// both sets should be centered on the origin for fitting
|
2016-04-16 00:07:01 +08:00
|
|
|
for (size_t i = 0; i < atoms->size(); i++) {
|
2013-02-02 06:39:47 +08:00
|
|
|
eigenvec[i] -= eig_center;
|
|
|
|
ref_pos[i] -= ref_pos_center;
|
|
|
|
}
|
|
|
|
}
|
2016-04-16 00:07:01 +08:00
|
|
|
if (atoms->b_rotate) {
|
|
|
|
atoms->rot.calc_optimal_rotation(eigenvec, ref_pos);
|
|
|
|
for (size_t i = 0; i < atoms->size(); i++) {
|
|
|
|
eigenvec[i] = atoms->rot.rotate(eigenvec[i]);
|
2013-02-02 06:39:47 +08:00
|
|
|
}
|
|
|
|
}
|
2014-12-02 10:09:53 +08:00
|
|
|
cvm::log("\"differenceVector\" is on: subtracting the reference positions from the provided vector: v = v - x0.\n");
|
2016-04-16 00:07:01 +08:00
|
|
|
for (size_t i = 0; i < atoms->size(); i++) {
|
2013-04-24 03:03:56 +08:00
|
|
|
eigenvec[i] -= ref_pos[i];
|
|
|
|
}
|
2016-04-16 00:07:01 +08:00
|
|
|
if (atoms->b_center) {
|
2013-02-02 06:39:47 +08:00
|
|
|
// bring back the ref positions to where they were
|
2016-04-16 00:07:01 +08:00
|
|
|
for (size_t i = 0; i < atoms->size(); i++) {
|
2013-04-24 03:03:56 +08:00
|
|
|
ref_pos[i] += ref_pos_center;
|
2013-02-02 06:39:47 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
2014-12-02 10:09:53 +08:00
|
|
|
cvm::log("Centering the provided vector to zero.\n");
|
2016-04-16 00:07:01 +08:00
|
|
|
for (size_t i = 0; i < atoms->size(); i++) {
|
2013-02-02 06:39:47 +08:00
|
|
|
eigenvec[i] -= eig_center;
|
|
|
|
}
|
2012-05-24 00:20:04 +08:00
|
|
|
}
|
|
|
|
|
2014-12-02 10:09:53 +08:00
|
|
|
// cvm::log("The first three components(v1x, v1y, v1z) of the resulting vector are: "+cvm::to_str (eigenvec[0])+".\n");
|
2012-05-24 00:20:04 +08:00
|
|
|
|
2013-02-02 06:39:47 +08:00
|
|
|
// for inverse gradients
|
|
|
|
eigenvec_invnorm2 = 0.0;
|
2016-04-16 00:07:01 +08:00
|
|
|
for (size_t ein = 0; ein < atoms->size(); ein++) {
|
2014-10-08 04:30:25 +08:00
|
|
|
eigenvec_invnorm2 += eigenvec[ein].norm2();
|
2012-05-24 00:20:04 +08:00
|
|
|
}
|
|
|
|
eigenvec_invnorm2 = 1.0 / eigenvec_invnorm2;
|
2013-04-24 03:03:56 +08:00
|
|
|
|
|
|
|
if (b_difference_vector) {
|
2014-12-02 10:09:53 +08:00
|
|
|
cvm::log("\"differenceVector\" is on: normalizing the vector.\n");
|
2016-04-16 00:07:01 +08:00
|
|
|
for (size_t i = 0; i < atoms->size(); i++) {
|
2013-04-24 03:03:56 +08:00
|
|
|
eigenvec[i] *= eigenvec_invnorm2;
|
|
|
|
}
|
|
|
|
} else {
|
2014-12-02 10:09:53 +08:00
|
|
|
cvm::log("The norm of the vector is |v| = "+cvm::to_str(eigenvec_invnorm2)+".\n");
|
2013-04-24 03:03:56 +08:00
|
|
|
}
|
2012-05-24 00:20:04 +08:00
|
|
|
}
|
|
|
|
|
2013-06-28 06:48:27 +08:00
|
|
|
|
2012-05-24 00:20:04 +08:00
|
|
|
void colvar::eigenvector::calc_value()
|
|
|
|
{
|
|
|
|
x.real_value = 0.0;
|
2016-04-16 00:07:01 +08:00
|
|
|
for (size_t i = 0; i < atoms->size(); i++) {
|
|
|
|
x.real_value += ((*atoms)[i].pos - ref_pos[i]) * eigenvec[i];
|
2012-05-24 00:20:04 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void colvar::eigenvector::calc_gradients()
|
|
|
|
{
|
2016-04-16 00:07:01 +08:00
|
|
|
for (size_t ia = 0; ia < atoms->size(); ia++) {
|
|
|
|
(*atoms)[ia].grad = eigenvec[ia];
|
2012-05-24 00:20:04 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-12-02 10:09:53 +08:00
|
|
|
void colvar::eigenvector::apply_force(colvarvalue const &force)
|
2012-05-24 00:20:04 +08:00
|
|
|
{
|
2016-04-16 00:07:01 +08:00
|
|
|
if (!atoms->noforce)
|
|
|
|
atoms->apply_colvar_force(force.real_value);
|
2012-05-24 00:20:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void colvar::eigenvector::calc_force_invgrads()
|
|
|
|
{
|
2016-09-09 04:20:32 +08:00
|
|
|
atoms->read_total_forces();
|
2012-05-24 00:20:04 +08:00
|
|
|
ft.real_value = 0.0;
|
2013-06-28 06:48:27 +08:00
|
|
|
|
2016-04-16 00:07:01 +08:00
|
|
|
for (size_t ia = 0; ia < atoms->size(); ia++) {
|
|
|
|
ft.real_value += eigenvec_invnorm2 * (*atoms)[ia].grad *
|
2016-09-09 04:20:32 +08:00
|
|
|
(*atoms)[ia].total_force;
|
2012-05-24 00:20:04 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void colvar::eigenvector::calc_Jacobian_derivative()
|
|
|
|
{
|
|
|
|
// gradient of the rotation matrix
|
2014-12-02 10:09:53 +08:00
|
|
|
cvm::matrix2d<cvm::rvector> grad_rot_mat(3, 3);
|
2016-04-16 00:07:01 +08:00
|
|
|
cvm::quaternion &quat0 = atoms->rot.q;
|
2012-05-24 00:20:04 +08:00
|
|
|
|
2013-06-28 06:48:27 +08:00
|
|
|
// gradients of products of 2 quaternion components
|
2012-05-24 00:20:04 +08:00
|
|
|
cvm::rvector g11, g22, g33, g01, g02, g03, g12, g13, g23;
|
|
|
|
|
|
|
|
cvm::real sum = 0.0;
|
|
|
|
|
2016-04-16 00:07:01 +08:00
|
|
|
for (size_t ia = 0; ia < atoms->size(); ia++) {
|
2012-05-24 00:20:04 +08:00
|
|
|
|
|
|
|
// Gradient of optimal quaternion wrt current Cartesian position
|
|
|
|
// trick: d(R^-1)/dx = d(R^t)/dx = (dR/dx)^t
|
|
|
|
// we can just transpose the derivatives of the direct matrix
|
2016-04-16 00:07:01 +08:00
|
|
|
cvm::vector1d<cvm::rvector> &dq_1 = atoms->rot.dQ0_1[ia];
|
2012-05-24 00:20:04 +08:00
|
|
|
|
|
|
|
g11 = 2.0 * quat0[1]*dq_1[1];
|
|
|
|
g22 = 2.0 * quat0[2]*dq_1[2];
|
|
|
|
g33 = 2.0 * quat0[3]*dq_1[3];
|
|
|
|
g01 = quat0[0]*dq_1[1] + quat0[1]*dq_1[0];
|
|
|
|
g02 = quat0[0]*dq_1[2] + quat0[2]*dq_1[0];
|
|
|
|
g03 = quat0[0]*dq_1[3] + quat0[3]*dq_1[0];
|
|
|
|
g12 = quat0[1]*dq_1[2] + quat0[2]*dq_1[1];
|
|
|
|
g13 = quat0[1]*dq_1[3] + quat0[3]*dq_1[1];
|
|
|
|
g23 = quat0[2]*dq_1[3] + quat0[3]*dq_1[2];
|
|
|
|
|
|
|
|
// Gradient of the inverse rotation matrix wrt current Cartesian position
|
|
|
|
// (transpose of the gradient of the direct rotation)
|
2013-06-28 06:48:27 +08:00
|
|
|
grad_rot_mat[0][0] = -2.0 * (g22 + g33);
|
|
|
|
grad_rot_mat[0][1] = 2.0 * (g12 + g03);
|
|
|
|
grad_rot_mat[0][2] = 2.0 * (g13 - g02);
|
|
|
|
grad_rot_mat[1][0] = 2.0 * (g12 - g03);
|
|
|
|
grad_rot_mat[1][1] = -2.0 * (g11 + g33);
|
|
|
|
grad_rot_mat[1][2] = 2.0 * (g01 + g23);
|
|
|
|
grad_rot_mat[2][0] = 2.0 * (g02 + g13);
|
|
|
|
grad_rot_mat[2][1] = 2.0 * (g23 - g01);
|
|
|
|
grad_rot_mat[2][2] = -2.0 * (g11 + g22);
|
2012-05-24 00:20:04 +08:00
|
|
|
|
|
|
|
for (size_t i = 0; i < 3; i++) {
|
|
|
|
for (size_t j = 0; j < 3; j++) {
|
|
|
|
sum += grad_rot_mat[i][j][i] * eigenvec[ia][j];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-02 10:09:53 +08:00
|
|
|
jd.real_value = sum * std::sqrt(eigenvec_invnorm2);
|
2012-05-24 00:20:04 +08:00
|
|
|
}
|
2012-06-30 01:52:31 +08:00
|
|
|
|
|
|
|
|
2016-12-28 02:17:34 +08:00
|
|
|
simple_scalar_dist_functions(eigenvector)
|
|
|
|
|
|
|
|
|
|
|
|
|
2014-12-02 10:09:53 +08:00
|
|
|
colvar::cartesian::cartesian(std::string const &conf)
|
|
|
|
: cvc(conf)
|
|
|
|
{
|
|
|
|
function_type = "cartesian";
|
|
|
|
|
2016-04-16 00:07:01 +08:00
|
|
|
atoms = parse_group(conf, "atoms");
|
2014-12-02 10:09:53 +08:00
|
|
|
|
2015-02-20 02:20:52 +08:00
|
|
|
bool use_x, use_y, use_z;
|
|
|
|
get_keyval(conf, "useX", use_x, true);
|
|
|
|
get_keyval(conf, "useY", use_y, true);
|
|
|
|
get_keyval(conf, "useZ", use_z, true);
|
|
|
|
|
|
|
|
axes.clear();
|
|
|
|
if (use_x) axes.push_back(0);
|
|
|
|
if (use_y) axes.push_back(1);
|
|
|
|
if (use_z) axes.push_back(2);
|
|
|
|
|
|
|
|
if (axes.size() == 0) {
|
|
|
|
cvm::error("Error: a \"cartesian\" component was defined with all three axes disabled.\n");
|
2016-04-28 22:48:56 +08:00
|
|
|
return;
|
2015-02-20 02:20:52 +08:00
|
|
|
}
|
|
|
|
|
2014-12-02 10:09:53 +08:00
|
|
|
x.type(colvarvalue::type_vector);
|
2017-07-20 02:10:43 +08:00
|
|
|
enable(f_cvc_implicit_gradient);
|
2016-04-16 00:07:01 +08:00
|
|
|
x.vector1d_value.resize(atoms->size() * axes.size());
|
2014-12-02 10:09:53 +08:00
|
|
|
}
|
2012-06-30 01:52:31 +08:00
|
|
|
|
2013-02-02 06:39:47 +08:00
|
|
|
|
2014-12-02 10:09:53 +08:00
|
|
|
void colvar::cartesian::calc_value()
|
|
|
|
{
|
2015-02-20 02:20:52 +08:00
|
|
|
size_t const dim = axes.size();
|
|
|
|
size_t ia, j;
|
2016-04-16 00:07:01 +08:00
|
|
|
for (ia = 0; ia < atoms->size(); ia++) {
|
2015-02-20 02:20:52 +08:00
|
|
|
for (j = 0; j < dim; j++) {
|
2016-04-16 00:07:01 +08:00
|
|
|
x.vector1d_value[dim*ia + j] = (*atoms)[ia].pos[axes[j]];
|
2015-02-20 02:20:52 +08:00
|
|
|
}
|
|
|
|
}
|
2014-12-02 10:09:53 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void colvar::cartesian::calc_gradients()
|
|
|
|
{
|
|
|
|
// we're not using the "grad" member of each
|
|
|
|
// atom object, because it only can represent the gradient of a
|
|
|
|
// scalar colvar
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void colvar::cartesian::apply_force(colvarvalue const &force)
|
|
|
|
{
|
2015-02-20 02:20:52 +08:00
|
|
|
size_t const dim = axes.size();
|
|
|
|
size_t ia, j;
|
2016-04-16 00:07:01 +08:00
|
|
|
if (!atoms->noforce) {
|
2014-12-02 10:09:53 +08:00
|
|
|
cvm::rvector f;
|
2016-04-16 00:07:01 +08:00
|
|
|
for (ia = 0; ia < atoms->size(); ia++) {
|
2015-04-30 22:09:42 +08:00
|
|
|
for (j = 0; j < dim; j++) {
|
|
|
|
f[axes[j]] = force.vector1d_value[dim*ia + j];
|
2014-12-02 10:09:53 +08:00
|
|
|
}
|
2016-04-16 00:07:01 +08:00
|
|
|
(*atoms)[ia].apply_force(f);
|
2014-12-02 10:09:53 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|