forked from lijiext/lammps
728 lines
22 KiB
C++
728 lines
22 KiB
C++
#ifndef COLVARVALUE_H
|
|
#define COLVARVALUE_H
|
|
|
|
#include "colvarmodule.h"
|
|
|
|
|
|
/// \brief Value of a collective variable: this is a metatype which
|
|
/// can be set at runtime. By default it is set to be a scalar
|
|
/// number, and can be treated like that in all operations (this is
|
|
/// done by most \link cvc \endlink implementations).
|
|
///
|
|
/// \link colvarvalue \endlink allows \link colvar \endlink to be
|
|
/// treat different data types. By default, a \link colvarvalue
|
|
/// \endlink variable is a scalar number. If you want to use it as
|
|
/// another type, you should declare and initialize a variable as
|
|
/// \code colvarvalue x (colvarvalue::type_xxx); \endcode where
|
|
/// type_xxx is a value within the \link Type \endlink enum.
|
|
/// Alternatively, initialize x with \link x.type
|
|
/// (colvarvalue::type_xxx) \endlink at a later stage.
|
|
///
|
|
/// Given a colvarvalue variable x which is not yet assigned (and
|
|
/// thus has not yet a type) it is also possible to correctly assign
|
|
/// the type with \code x = y; \endcode if y is correctly set.
|
|
/// Otherwise, an error will be raised if the \link Type \endlink of x
|
|
/// is different from the \link Type \endlink of y.
|
|
///
|
|
/// Also, every operator (either unary or binary) on a \link
|
|
/// colvarvalue \endlink object performs one or more checks on the
|
|
/// \link Type \endlink to avoid errors such as initializing a
|
|
/// three-dimensional vector with a scalar number (legal otherwise).
|
|
///
|
|
/// \b Special \b case: when reading from a stream, there is no way to
|
|
/// detect the \link Type \endlink and safely handle errors at the
|
|
/// same time. Hence, when using \code is >> x; \endcode x \b MUST
|
|
/// already have a type correcly set up for properly parsing the
|
|
/// stream. An error will be raised otherwise. Usually this is not
|
|
/// the problem, because \link colvarvalue \endlink objects are first
|
|
/// initialized in the configuration, and the stream operation will be
|
|
/// performed only when reading restart files.
|
|
///
|
|
/// No problem of course with the output streams: \code os << x;
|
|
/// \endcode will print a different output according to the value of
|
|
/// colvarvalue::value_type, and the width of such output is returned
|
|
/// by colvarvalue::output_width()
|
|
///
|
|
/// \em Note \em on \em performance: at every operation between two
|
|
/// \link colvarvalue \endlink objects, their two \link Type \endlink
|
|
/// flags will be checked for a match. In a long array of \link
|
|
/// colvarvalue \endlink objects this is time consuming: a few static
|
|
/// functions are defined ("xxx_opt" functions) within the \link
|
|
/// colvarvalue \endlink class, which only check the matching once for
|
|
/// a large array, and execute different loops according to the type.
|
|
/// You should do the same for every time consuming loop involving
|
|
/// operations on \link colvarvalue \endlink objects if you want
|
|
/// e.g. to optimize your colvar bias.
|
|
|
|
class colvarvalue {
|
|
|
|
public:
|
|
|
|
/// \brief Possible types of value
|
|
///
|
|
/// These three cover most possibilities of data type one can
|
|
/// devise. If you need to implement a new colvar with a very
|
|
/// complex data type, it's better to put an allocatable class here
|
|
enum Type {
|
|
/// Undefined type
|
|
type_notset,
|
|
/// Scalar number, implemented as \link colvarmodule::real \endlink (default)
|
|
type_scalar,
|
|
/// 3-dimensional vector, implemented as \link colvarmodule::rvector \endlink
|
|
type_vector,
|
|
/// 3-dimensional unit vector, implemented as \link colvarmodule::rvector \endlink
|
|
type_unitvector,
|
|
/// 4-dimensional unit vector representing a rotation, implemented as \link colvarmodule::quaternion \endlink
|
|
type_quaternion
|
|
};
|
|
|
|
/// Runtime description of value types
|
|
std::string static const type_desc[colvarvalue::type_quaternion+1];
|
|
|
|
/// Number of degrees of freedom for each type
|
|
size_t static const dof_num[ colvarvalue::type_quaternion+1];
|
|
|
|
/// \brief Real data member
|
|
cvm::real real_value;
|
|
|
|
/// \brief Vector data member
|
|
cvm::rvector rvector_value;
|
|
|
|
/// \brief Quaternion data member
|
|
cvm::quaternion quaternion_value;
|
|
|
|
/// Current type of this colvarvalue object
|
|
Type value_type;
|
|
|
|
static inline bool type_checking()
|
|
{
|
|
return true;
|
|
}
|
|
|
|
/// \brief Default constructor: this class defaults to a scalar
|
|
/// number and always behaves like it unless you change its type
|
|
inline colvarvalue()
|
|
: real_value (0.0), value_type (type_scalar)
|
|
{}
|
|
|
|
/// Constructor from a type specification
|
|
inline colvarvalue (Type const &vti)
|
|
: value_type (vti)
|
|
{
|
|
reset();
|
|
}
|
|
|
|
/// Copy constructor from real base type
|
|
inline colvarvalue (cvm::real const &x)
|
|
: real_value (x), value_type (type_scalar)
|
|
{}
|
|
|
|
/// \brief Copy constructor from rvector base type (Note: this sets
|
|
/// automatically a type \link type_vector \endlink , if you want a
|
|
/// \link type_unitvector \endlink you must set it explicitly)
|
|
inline colvarvalue (cvm::rvector const &v)
|
|
: rvector_value (v), value_type (type_vector)
|
|
{}
|
|
|
|
/// \brief Copy constructor from rvector base type (additional
|
|
/// argument to make possible to choose a \link type_unitvector
|
|
/// \endlink
|
|
inline colvarvalue (cvm::rvector const &v, Type const &vti)
|
|
: rvector_value (v), value_type (vti)
|
|
{}
|
|
|
|
/// \brief Copy constructor from quaternion base type
|
|
inline colvarvalue (cvm::quaternion const &q)
|
|
: quaternion_value (q), value_type (type_quaternion)
|
|
{}
|
|
|
|
/// Copy constructor from another \link colvarvalue \endlink
|
|
inline colvarvalue (colvarvalue const &x)
|
|
: value_type (x.value_type)
|
|
{
|
|
reset();
|
|
|
|
switch (x.value_type) {
|
|
case type_scalar:
|
|
real_value = x.real_value;
|
|
break;
|
|
case type_vector:
|
|
case type_unitvector:
|
|
rvector_value = x.rvector_value;
|
|
break;
|
|
case type_quaternion:
|
|
quaternion_value = x.quaternion_value;
|
|
break;
|
|
case type_notset:
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/// Set to the null value for the data type currently defined
|
|
void reset();
|
|
|
|
|
|
/// \brief If the variable has constraints (e.g. unitvector or
|
|
/// quaternion), transform it to satisfy them; use it when the \link
|
|
/// colvarvalue \endlink is not calculated from \link cvc
|
|
/// \endlink objects, but manipulated by you
|
|
void apply_constraints();
|
|
|
|
|
|
/// Get the current type
|
|
inline Type type() const
|
|
{
|
|
return value_type;
|
|
}
|
|
|
|
/// Set the type explicitly
|
|
inline void type (Type const &vti)
|
|
{
|
|
reset();
|
|
value_type = vti;
|
|
reset();
|
|
}
|
|
|
|
/// Set the type after another \link colvarvalue \endlink
|
|
inline void type (colvarvalue const &x)
|
|
{
|
|
reset();
|
|
value_type = x.value_type;
|
|
reset();
|
|
}
|
|
|
|
/// Square norm of this colvarvalue
|
|
cvm::real norm2() const;
|
|
|
|
/// Norm of this colvarvalue
|
|
inline cvm::real norm() const
|
|
{
|
|
return std::sqrt (this->norm2());
|
|
}
|
|
|
|
/// \brief Return the value whose scalar product with this value is
|
|
/// 1
|
|
inline colvarvalue inverse() const;
|
|
|
|
/// Square distance between this \link colvarvalue \endlink and another
|
|
cvm::real dist2 (colvarvalue const &x2) const;
|
|
|
|
/// Derivative with respect to this \link colvarvalue \endlink of the square distance
|
|
colvarvalue dist2_grad (colvarvalue const &x2) const;
|
|
|
|
/// Assignment operator (type of x is checked)
|
|
colvarvalue & operator = (colvarvalue const &x);
|
|
|
|
void operator += (colvarvalue const &x);
|
|
void operator -= (colvarvalue const &x);
|
|
void operator *= (cvm::real const &a);
|
|
void operator /= (cvm::real const &a);
|
|
|
|
|
|
// Casting operator
|
|
inline operator cvm::real() const
|
|
{
|
|
if (value_type != type_scalar) error_rside (type_scalar);
|
|
return real_value;
|
|
}
|
|
|
|
// Casting operator
|
|
inline operator cvm::rvector() const
|
|
{
|
|
if ( (value_type != type_vector) && (value_type != type_unitvector))
|
|
error_rside (type_vector);
|
|
return rvector_value;
|
|
}
|
|
|
|
// Casting operator
|
|
inline operator cvm::quaternion() const
|
|
{
|
|
if (value_type != type_quaternion) error_rside (type_quaternion);
|
|
return quaternion_value;
|
|
}
|
|
|
|
/// Special case when the variable is a real number, and all operations are defined
|
|
inline bool is_scalar()
|
|
{
|
|
return (value_type == type_scalar);
|
|
}
|
|
|
|
|
|
/// Ensure that the two types are the same within a binary operator
|
|
void static check_types (colvarvalue const &x1, colvarvalue const &x2);
|
|
|
|
/// Undefined operation
|
|
void undef_op() const;
|
|
|
|
/// Trying to assign this \link colvarvalue \endlink object to
|
|
/// another object set with a different type
|
|
void error_lside (Type const &vt) const;
|
|
|
|
/// Trying to assign another \link colvarvalue \endlink object set
|
|
/// with a different type to this object
|
|
void error_rside (Type const &vt) const;
|
|
|
|
/// Give the number of characters required to output this
|
|
/// colvarvalue, given the current type assigned and the number of
|
|
/// characters for a real number
|
|
size_t output_width (size_t const &real_width) const;
|
|
|
|
|
|
// optimized routines for operations with an array; xv and inner as
|
|
// vectors are assumed to have the same number of elements (i.e. the
|
|
// end for inner comes together with xv_end in the loop)
|
|
|
|
/// \brief Optimized routine for the inner product of one collective
|
|
/// variable with an array
|
|
void static inner_opt (colvarvalue const &x,
|
|
std::vector<colvarvalue>::iterator &xv,
|
|
std::vector<colvarvalue>::iterator const &xv_end,
|
|
std::vector<cvm::real>::iterator &inner);
|
|
|
|
/// \brief Optimized routine for the inner product of one collective
|
|
/// variable with an array
|
|
void static inner_opt (colvarvalue const &x,
|
|
std::list<colvarvalue>::iterator &xv,
|
|
std::list<colvarvalue>::iterator const &xv_end,
|
|
std::vector<cvm::real>::iterator &inner);
|
|
|
|
/// \brief Optimized routine for the second order Legendre
|
|
/// polynomial, (3cos^2(w)-1)/2, of one collective variable with an
|
|
/// array
|
|
void static p2leg_opt (colvarvalue const &x,
|
|
std::vector<colvarvalue>::iterator &xv,
|
|
std::vector<colvarvalue>::iterator const &xv_end,
|
|
std::vector<cvm::real>::iterator &inner);
|
|
|
|
/// \brief Optimized routine for the second order Legendre
|
|
/// polynomial of one collective variable with an array
|
|
void static p2leg_opt (colvarvalue const &x,
|
|
std::list<colvarvalue>::iterator &xv,
|
|
std::list<colvarvalue>::iterator const &xv_end,
|
|
std::vector<cvm::real>::iterator &inner);
|
|
|
|
};
|
|
|
|
|
|
|
|
inline void colvarvalue::reset()
|
|
{
|
|
switch (value_type) {
|
|
case colvarvalue::type_scalar:
|
|
real_value = cvm::real (0.0);
|
|
break;
|
|
case colvarvalue::type_vector:
|
|
case colvarvalue::type_unitvector:
|
|
rvector_value = cvm::rvector (0.0, 0.0, 0.0);
|
|
break;
|
|
case colvarvalue::type_quaternion:
|
|
quaternion_value = cvm::quaternion (0.0, 0.0, 0.0, 0.0);
|
|
break;
|
|
case colvarvalue::type_notset:
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
inline void colvarvalue::apply_constraints()
|
|
{
|
|
switch (value_type) {
|
|
case colvarvalue::type_scalar:
|
|
break;
|
|
case colvarvalue::type_vector:
|
|
break;
|
|
case colvarvalue::type_unitvector:
|
|
rvector_value /= std::sqrt (rvector_value.norm2());
|
|
break;
|
|
case colvarvalue::type_quaternion:
|
|
quaternion_value /= std::sqrt (quaternion_value.norm2());
|
|
break;
|
|
case colvarvalue::type_notset:
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
inline cvm::real colvarvalue::norm2() const
|
|
{
|
|
switch (value_type) {
|
|
case colvarvalue::type_scalar:
|
|
return (this->real_value)*(this->real_value);
|
|
case colvarvalue::type_vector:
|
|
case colvarvalue::type_unitvector:
|
|
return (this->rvector_value).norm2();
|
|
case colvarvalue::type_quaternion:
|
|
return (this->quaternion_value).norm2();
|
|
case colvarvalue::type_notset:
|
|
default:
|
|
return 0.0;
|
|
}
|
|
}
|
|
|
|
|
|
inline colvarvalue colvarvalue::inverse() const
|
|
{
|
|
switch (value_type) {
|
|
case colvarvalue::type_scalar:
|
|
return colvarvalue (1.0/real_value);
|
|
case colvarvalue::type_vector:
|
|
return colvarvalue (cvm::rvector (1.0/rvector_value.x,
|
|
1.0/rvector_value.y,
|
|
1.0/rvector_value.z));
|
|
case colvarvalue::type_quaternion:
|
|
return colvarvalue (cvm::quaternion (1.0/quaternion_value.q0,
|
|
1.0/quaternion_value.q1,
|
|
1.0/quaternion_value.q2,
|
|
1.0/quaternion_value.q3));
|
|
case colvarvalue::type_notset:
|
|
default:
|
|
undef_op();
|
|
}
|
|
return colvarvalue();
|
|
}
|
|
|
|
|
|
inline colvarvalue & colvarvalue::operator = (colvarvalue const &x)
|
|
{
|
|
if (this->value_type != type_notset)
|
|
if (this->value_type != x.value_type)
|
|
error_lside (x.value_type);
|
|
|
|
this->value_type = x.value_type;
|
|
|
|
switch (this->value_type) {
|
|
case colvarvalue::type_scalar:
|
|
this->real_value = x.real_value;
|
|
break;
|
|
case colvarvalue::type_vector:
|
|
case colvarvalue::type_unitvector:
|
|
this->rvector_value = x.rvector_value;
|
|
break;
|
|
case colvarvalue::type_quaternion:
|
|
this->quaternion_value = x.quaternion_value;
|
|
break;
|
|
case colvarvalue::type_notset:
|
|
default:
|
|
undef_op();
|
|
break;
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
inline void colvarvalue::operator += (colvarvalue const &x)
|
|
{
|
|
if (colvarvalue::type_checking())
|
|
colvarvalue::check_types (*this, x);
|
|
|
|
switch (this->value_type) {
|
|
case colvarvalue::type_scalar:
|
|
this->real_value += x.real_value;
|
|
break;
|
|
case colvarvalue::type_vector:
|
|
case colvarvalue::type_unitvector:
|
|
this->rvector_value += x.rvector_value;
|
|
break;
|
|
case colvarvalue::type_quaternion:
|
|
this->quaternion_value += x.quaternion_value;
|
|
break;
|
|
case colvarvalue::type_notset:
|
|
default:
|
|
undef_op();
|
|
}
|
|
}
|
|
|
|
inline void colvarvalue::operator -= (colvarvalue const &x)
|
|
{
|
|
if (colvarvalue::type_checking())
|
|
colvarvalue::check_types (*this, x);
|
|
|
|
switch (value_type) {
|
|
case colvarvalue::type_scalar:
|
|
real_value -= x.real_value; break;
|
|
case colvarvalue::type_vector:
|
|
case colvarvalue::type_unitvector:
|
|
rvector_value -= x.rvector_value; break;
|
|
case colvarvalue::type_quaternion:
|
|
quaternion_value -= x.quaternion_value; break;
|
|
case colvarvalue::type_notset:
|
|
default:
|
|
undef_op();
|
|
}
|
|
}
|
|
|
|
inline void colvarvalue::operator *= (cvm::real const &a)
|
|
{
|
|
switch (value_type) {
|
|
case colvarvalue::type_scalar:
|
|
real_value *= a;
|
|
break;
|
|
case colvarvalue::type_vector:
|
|
case colvarvalue::type_unitvector:
|
|
rvector_value *= a;
|
|
break;
|
|
case colvarvalue::type_quaternion:
|
|
quaternion_value *= a;
|
|
break;
|
|
case colvarvalue::type_notset:
|
|
default:
|
|
undef_op();
|
|
}
|
|
}
|
|
|
|
inline void colvarvalue::operator /= (cvm::real const &a)
|
|
{
|
|
switch (value_type) {
|
|
case colvarvalue::type_scalar:
|
|
real_value /= a; break;
|
|
case colvarvalue::type_vector:
|
|
case colvarvalue::type_unitvector:
|
|
rvector_value /= a; break;
|
|
case colvarvalue::type_quaternion:
|
|
quaternion_value /= a; break;
|
|
case colvarvalue::type_notset:
|
|
default:
|
|
undef_op();
|
|
}
|
|
}
|
|
|
|
|
|
// binary operations between two colvarvalues
|
|
|
|
inline colvarvalue operator + (colvarvalue const &x1,
|
|
colvarvalue const &x2)
|
|
{
|
|
if (colvarvalue::type_checking())
|
|
colvarvalue::check_types (x1, x2);
|
|
|
|
switch (x1.value_type) {
|
|
case colvarvalue::type_scalar:
|
|
return colvarvalue (x1.real_value + x2.real_value);
|
|
case colvarvalue::type_vector:
|
|
return colvarvalue (x1.rvector_value + x2.rvector_value);
|
|
case colvarvalue::type_unitvector:
|
|
return colvarvalue (x1.rvector_value + x2.rvector_value,
|
|
colvarvalue::type_unitvector);
|
|
case colvarvalue::type_quaternion:
|
|
return colvarvalue (x1.quaternion_value + x2.quaternion_value);
|
|
case colvarvalue::type_notset:
|
|
default:
|
|
x1.undef_op();
|
|
return colvarvalue (colvarvalue::type_notset);
|
|
};
|
|
}
|
|
|
|
inline colvarvalue operator - (colvarvalue const &x1,
|
|
colvarvalue const &x2)
|
|
{
|
|
if (colvarvalue::type_checking())
|
|
colvarvalue::check_types (x1, x2);
|
|
|
|
switch (x1.value_type) {
|
|
case colvarvalue::type_scalar:
|
|
return colvarvalue (x1.real_value - x2.real_value);
|
|
case colvarvalue::type_vector:
|
|
return colvarvalue (x1.rvector_value - x2.rvector_value);
|
|
case colvarvalue::type_unitvector:
|
|
return colvarvalue (x1.rvector_value - x2.rvector_value,
|
|
colvarvalue::type_unitvector);
|
|
case colvarvalue::type_quaternion:
|
|
return colvarvalue (x1.quaternion_value - x2.quaternion_value);
|
|
default:
|
|
x1.undef_op();
|
|
return colvarvalue (colvarvalue::type_notset);
|
|
};
|
|
}
|
|
|
|
|
|
// binary operations with real numbers
|
|
|
|
inline colvarvalue operator * (cvm::real const &a,
|
|
colvarvalue const &x)
|
|
{
|
|
switch (x.value_type) {
|
|
case colvarvalue::type_scalar:
|
|
return colvarvalue (a * x.real_value);
|
|
case colvarvalue::type_vector:
|
|
return colvarvalue (a * x.rvector_value);
|
|
case colvarvalue::type_unitvector:
|
|
return colvarvalue (a * x.rvector_value,
|
|
colvarvalue::type_unitvector);
|
|
case colvarvalue::type_quaternion:
|
|
return colvarvalue (a * x.quaternion_value);
|
|
case colvarvalue::type_notset:
|
|
default:
|
|
x.undef_op();
|
|
return colvarvalue (colvarvalue::type_notset);
|
|
}
|
|
}
|
|
|
|
inline colvarvalue operator * (colvarvalue const &x,
|
|
cvm::real const &a)
|
|
{
|
|
switch (x.value_type) {
|
|
case colvarvalue::type_scalar:
|
|
return colvarvalue (x.real_value * a);
|
|
case colvarvalue::type_vector:
|
|
return colvarvalue (x.rvector_value * a);
|
|
case colvarvalue::type_unitvector:
|
|
return colvarvalue (x.rvector_value * a,
|
|
colvarvalue::type_unitvector);
|
|
case colvarvalue::type_quaternion:
|
|
return colvarvalue (x.quaternion_value * a);
|
|
case colvarvalue::type_notset:
|
|
default:
|
|
x.undef_op();
|
|
return colvarvalue (colvarvalue::type_notset);
|
|
}
|
|
}
|
|
|
|
inline colvarvalue operator / (colvarvalue const &x,
|
|
cvm::real const &a)
|
|
{
|
|
switch (x.value_type) {
|
|
case colvarvalue::type_scalar:
|
|
return colvarvalue (x.real_value / a);
|
|
case colvarvalue::type_vector:
|
|
return colvarvalue (x.rvector_value / a);
|
|
case colvarvalue::type_unitvector:
|
|
return colvarvalue (x.rvector_value / a,
|
|
colvarvalue::type_unitvector);
|
|
case colvarvalue::type_quaternion:
|
|
return colvarvalue (x.quaternion_value / a);
|
|
case colvarvalue::type_notset:
|
|
default:
|
|
x.undef_op();
|
|
return colvarvalue (colvarvalue::type_notset);
|
|
}
|
|
}
|
|
|
|
|
|
// inner product between two colvarvalues
|
|
|
|
inline cvm::real operator * (colvarvalue const &x1,
|
|
colvarvalue const &x2)
|
|
{
|
|
if (colvarvalue::type_checking())
|
|
colvarvalue::check_types (x1, x2);
|
|
|
|
switch (x1.value_type) {
|
|
case colvarvalue::type_scalar:
|
|
return (x1.real_value * x2.real_value);
|
|
case colvarvalue::type_vector:
|
|
case colvarvalue::type_unitvector:
|
|
return (x1.rvector_value * x2.rvector_value);
|
|
case colvarvalue::type_quaternion:
|
|
// the "*" product is the quaternion product, here the inner
|
|
// member function is used instead
|
|
return (x1.quaternion_value.inner (x2.quaternion_value));
|
|
case colvarvalue::type_notset:
|
|
default:
|
|
x1.undef_op();
|
|
return 0.0;
|
|
};
|
|
}
|
|
|
|
|
|
|
|
inline cvm::real colvarvalue::dist2 (colvarvalue const &x2) const
|
|
{
|
|
if (colvarvalue::type_checking())
|
|
colvarvalue::check_types (*this, x2);
|
|
|
|
switch (this->value_type) {
|
|
case colvarvalue::type_scalar:
|
|
return (this->real_value - x2.real_value)*(this->real_value - x2.real_value);
|
|
case colvarvalue::type_vector:
|
|
return (this->rvector_value - x2.rvector_value).norm2();
|
|
case colvarvalue::type_unitvector:
|
|
// angle between (*this) and x2 is the distance
|
|
return std::acos (this->rvector_value * x2.rvector_value) * std::acos (this->rvector_value * x2.rvector_value);
|
|
case colvarvalue::type_quaternion:
|
|
// angle between (*this) and x2 is the distance, the quaternion
|
|
// object has it implemented internally
|
|
return this->quaternion_value.dist2 (x2.quaternion_value);
|
|
case colvarvalue::type_notset:
|
|
default:
|
|
this->undef_op();
|
|
return 0.0;
|
|
};
|
|
}
|
|
|
|
|
|
inline colvarvalue colvarvalue::dist2_grad (colvarvalue const &x2) const
|
|
{
|
|
if (colvarvalue::type_checking())
|
|
colvarvalue::check_types (*this, x2);
|
|
|
|
switch (this->value_type) {
|
|
case colvarvalue::type_scalar:
|
|
return 2.0 * (this->real_value - x2.real_value);
|
|
case colvarvalue::type_vector:
|
|
return 2.0 * (this->rvector_value - x2.rvector_value);
|
|
case colvarvalue::type_unitvector:
|
|
{
|
|
cvm::rvector const &v1 = this->rvector_value;
|
|
cvm::rvector const &v2 = x2.rvector_value;
|
|
cvm::real const cos_t = v1 * v2;
|
|
cvm::real const sin_t = std::sqrt (1.0 - cos_t*cos_t);
|
|
return colvarvalue ( 2.0 * sin_t *
|
|
cvm::rvector ( (-1.0) * sin_t * v2.x +
|
|
cos_t/sin_t * (v1.x - cos_t*v2.x),
|
|
(-1.0) * sin_t * v2.y +
|
|
cos_t/sin_t * (v1.y - cos_t*v2.y),
|
|
(-1.0) * sin_t * v2.z +
|
|
cos_t/sin_t * (v1.z - cos_t*v2.z)
|
|
),
|
|
colvarvalue::type_unitvector );
|
|
}
|
|
case colvarvalue::type_quaternion:
|
|
return this->quaternion_value.dist2_grad (x2.quaternion_value);
|
|
case colvarvalue::type_notset:
|
|
default:
|
|
this->undef_op();
|
|
return colvarvalue (colvarvalue::type_notset);
|
|
};
|
|
}
|
|
|
|
|
|
inline void colvarvalue::check_types (colvarvalue const &x1,
|
|
colvarvalue const &x2)
|
|
{
|
|
if (x1.value_type != x2.value_type) {
|
|
cvm::log ("x1 type = "+cvm::to_str (x1.value_type)+
|
|
", x2 type = "+cvm::to_str (x2.value_type)+"\n");
|
|
cvm::fatal_error ("Performing an operation between two colvar "
|
|
"values with different types, \""+
|
|
colvarvalue::type_desc[x1.value_type]+
|
|
"\" and \""+
|
|
colvarvalue::type_desc[x2.value_type]+
|
|
"\".\n");
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
std::ostream & operator << (std::ostream &os, colvarvalue const &x);
|
|
std::ostream & operator << (std::ostream &os, std::vector<colvarvalue> const &v);
|
|
|
|
std::istream & operator >> (std::istream &is, colvarvalue &x);
|
|
|
|
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
// Emacs
|
|
// Local Variables:
|
|
// mode: C++
|
|
// End:
|