The following is a list of pull requests relevant to LAMMPS in the Colvars repository since 2024-08-06: - 752 New tool poisson_integrator_conv https://github.com/Colvars/colvars/pull/752 (@jhenin) - 733 Custom grids for all biases https://github.com/Colvars/colvars/pull/733 (@giacomofiorin, @jhenin) - 776 Avoid error in acos and asin with fast-math https://github.com/Colvars/colvars/pull/776 (@jhenin) - 773 fix: fix the clang build test failure of OPES https://github.com/Colvars/colvars/pull/773 (@HanatoK) - 768 fix: clamp the input values of asin and acos in case of fast math on aarch64 https://github.com/Colvars/colvars/pull/768 (@HanatoK) - 761 Add debug code for the Jacobi failure https://github.com/Colvars/colvars/pull/761 (@HanatoK) - 759 min_image fix; Saves long runs from crashes; https://github.com/Colvars/colvars/pull/759 (@PolyachenkoYA) - 757 Fix MSVC OpenMP issue https://github.com/Colvars/colvars/pull/757 (@HanatoK) - 755 Fix indentation of 'Init CVC' message in standard output https://github.com/Colvars/colvars/pull/755 (@jhenin) - 750 Optimize and simplify the calculation of dihedral gradients https://github.com/Colvars/colvars/pull/750 (@HanatoK) - 749 Add references to new Colvars paper https://github.com/Colvars/colvars/pull/749 (@jhenin, @giacomofiorin) - 740 Report the specific C++ standard at init time, stop warning about C++97/03 https://github.com/Colvars/colvars/pull/740 (@giacomofiorin) - 731 Improve detection of hard/mathematical boundaries https://github.com/Colvars/colvars/pull/731 (@giacomofiorin) - 729 Optimize the fit gradients https://github.com/Colvars/colvars/pull/729 (@HanatoK, @jhenin) - 728 Fix undefined behavior when getting the current working directory from std::filesystem https://github.com/Colvars/colvars/pull/728 (@giacomofiorin) - 727 Add patchversion scripting command https://github.com/Colvars/colvars/pull/727 (@giacomofiorin) - 724 Fix gradients and metric functions of distanceDir https://github.com/Colvars/colvars/pull/724 (@giacomofiorin) - 715 Add missing rotation in orientation component https://github.com/Colvars/colvars/pull/715 (@giacomofiorin) - 713 fix: try to solve #87 for non-scala components https://github.com/Colvars/colvars/pull/713 (@HanatoK) - 709 Implementation of OPES in Colvars https://github.com/Colvars/colvars/pull/709 (@HanatoK, @giacomofiorin, @jhenin) - 706 BUGFIX for Segmentation fault in colvarbias_meta::calc_energy() with useGrids off https://github.com/Colvars/colvars/pull/706 (@alphataubio) - 570 enable use of CVs defined by PyTorch neural network models https://github.com/Colvars/colvars/pull/570 (@zwpku, @giacomofiorin, @HanatoK, @jhenin) Authors: @alphataubio, @EzryStIago, @giacomofiorin, @HanatoK, @jhenin, @PolyachenkoYA, @zwpku
1103 lines
30 KiB
C++
1103 lines
30 KiB
C++
// -*- c++ -*-
|
|
|
|
// 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.
|
|
|
|
#include <vector>
|
|
|
|
#include "colvarmodule.h"
|
|
#include "colvarvalue.h"
|
|
#include "colvars_memstream.h"
|
|
|
|
|
|
|
|
colvarvalue::colvarvalue()
|
|
: value_type(type_scalar), real_value(0.0)
|
|
{}
|
|
|
|
|
|
colvarvalue::colvarvalue(Type const &vti)
|
|
: value_type(vti), real_value(0.0)
|
|
{
|
|
reset();
|
|
}
|
|
|
|
colvarvalue::colvarvalue(cvm::real const &x)
|
|
: value_type(type_scalar), real_value(x)
|
|
{}
|
|
|
|
|
|
colvarvalue::colvarvalue(cvm::rvector const &v, colvarvalue::Type vti)
|
|
: value_type(vti), real_value(0.0), rvector_value(v)
|
|
{}
|
|
|
|
|
|
colvarvalue::colvarvalue(cvm::quaternion const &q, colvarvalue::Type vti)
|
|
: value_type(vti), real_value(0.0), quaternion_value(q)
|
|
{}
|
|
|
|
|
|
colvarvalue::colvarvalue(colvarvalue const &x)
|
|
: value_type(x.type()), real_value(0.0)
|
|
{
|
|
switch (x.type()) {
|
|
case type_scalar:
|
|
real_value = x.real_value;
|
|
break;
|
|
case type_3vector:
|
|
case type_unit3vector:
|
|
case type_unit3vectorderiv:
|
|
rvector_value = x.rvector_value;
|
|
break;
|
|
case type_quaternion:
|
|
case type_quaternionderiv:
|
|
quaternion_value = x.quaternion_value;
|
|
break;
|
|
case type_vector:
|
|
vector1d_value = x.vector1d_value;
|
|
elem_types = x.elem_types;
|
|
elem_indices = x.elem_indices;
|
|
elem_sizes = x.elem_sizes;
|
|
case type_notset:
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
colvarvalue::colvarvalue(cvm::vector1d<cvm::real> const &v,
|
|
colvarvalue::Type vti)
|
|
: real_value(0.0)
|
|
{
|
|
if ((vti != type_vector) && (v.size() != num_dimensions(vti))) {
|
|
cvm::error("Error: trying to initialize a variable of type \""+type_desc(vti)+
|
|
"\" using a vector of size "+cvm::to_str(v.size())+
|
|
".\n");
|
|
value_type = type_notset;
|
|
} else {
|
|
value_type = vti;
|
|
switch (vti) {
|
|
case type_scalar:
|
|
real_value = v[0];
|
|
break;
|
|
case type_3vector:
|
|
case type_unit3vector:
|
|
case type_unit3vectorderiv:
|
|
rvector_value = cvm::rvector(v);
|
|
break;
|
|
case type_quaternion:
|
|
case type_quaternionderiv:
|
|
quaternion_value = cvm::quaternion(v);
|
|
break;
|
|
case type_vector:
|
|
vector1d_value = v;
|
|
break;
|
|
case type_notset:
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
std::string const colvarvalue::type_desc(Type t)
|
|
{
|
|
switch (t) {
|
|
case colvarvalue::type_scalar:
|
|
return "scalar number"; break;
|
|
case colvarvalue::type_3vector:
|
|
return "3-dimensional vector"; break;
|
|
case colvarvalue::type_unit3vector:
|
|
return "3-dimensional unit vector"; break;
|
|
case colvarvalue::type_unit3vectorderiv:
|
|
return "derivative of a 3-dimensional unit vector"; break;
|
|
case colvarvalue::type_quaternion:
|
|
return "4-dimensional unit quaternion"; break;
|
|
case colvarvalue::type_quaternionderiv:
|
|
return "4-dimensional tangent vector"; break;
|
|
case colvarvalue::type_vector:
|
|
return "n-dimensional vector"; break;
|
|
case colvarvalue::type_notset:
|
|
// fallthrough
|
|
default:
|
|
return "not set"; break;
|
|
}
|
|
}
|
|
|
|
|
|
std::string const colvarvalue::type_keyword(Type t)
|
|
{
|
|
switch (t) {
|
|
case colvarvalue::type_notset:
|
|
default:
|
|
return "not_set"; break;
|
|
case colvarvalue::type_scalar:
|
|
return "scalar"; break;
|
|
case colvarvalue::type_3vector:
|
|
return "vector3"; break;
|
|
case colvarvalue::type_unit3vector:
|
|
return "unit_vector3"; break;
|
|
case colvarvalue::type_unit3vectorderiv:
|
|
return ""; break;
|
|
case colvarvalue::type_quaternion:
|
|
return "unit_quaternion"; break;
|
|
case colvarvalue::type_quaternionderiv:
|
|
return ""; break;
|
|
case colvarvalue::type_vector:
|
|
return "vector"; break;
|
|
}
|
|
}
|
|
|
|
|
|
size_t colvarvalue::num_dimensions(Type t)
|
|
{
|
|
switch (t) {
|
|
case colvarvalue::type_notset:
|
|
default:
|
|
return 0; break;
|
|
case colvarvalue::type_scalar:
|
|
return 1; break;
|
|
case colvarvalue::type_3vector:
|
|
case colvarvalue::type_unit3vector:
|
|
case colvarvalue::type_unit3vectorderiv:
|
|
return 3; break;
|
|
case colvarvalue::type_quaternion:
|
|
case colvarvalue::type_quaternionderiv:
|
|
return 4; break;
|
|
case colvarvalue::type_vector:
|
|
// the size of a vector is unknown without its object
|
|
return 0; break;
|
|
}
|
|
}
|
|
|
|
|
|
void colvarvalue::reset()
|
|
{
|
|
switch (value_type) {
|
|
case colvarvalue::type_scalar:
|
|
real_value = 0.0;
|
|
break;
|
|
case colvarvalue::type_3vector:
|
|
case colvarvalue::type_unit3vector:
|
|
case colvarvalue::type_unit3vectorderiv:
|
|
rvector_value.reset();
|
|
break;
|
|
case colvarvalue::type_quaternion:
|
|
case colvarvalue::type_quaternionderiv:
|
|
quaternion_value.reset();
|
|
break;
|
|
case colvarvalue::type_vector:
|
|
vector1d_value.reset();
|
|
break;
|
|
case colvarvalue::type_notset:
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
void colvarvalue::apply_constraints()
|
|
{
|
|
switch (value_type) {
|
|
case colvarvalue::type_scalar:
|
|
case colvarvalue::type_3vector:
|
|
case colvarvalue::type_unit3vectorderiv:
|
|
case colvarvalue::type_quaternionderiv:
|
|
break;
|
|
case colvarvalue::type_unit3vector:
|
|
rvector_value /= cvm::sqrt(rvector_value.norm2());
|
|
break;
|
|
case colvarvalue::type_quaternion:
|
|
quaternion_value /= cvm::sqrt(quaternion_value.norm2());
|
|
break;
|
|
case colvarvalue::type_vector:
|
|
if (elem_types.size() > 0) {
|
|
// if we have information about non-scalar types, use it
|
|
size_t i;
|
|
for (i = 0; i < elem_types.size(); i++) {
|
|
if (elem_sizes[i] == 1) continue; // TODO this can be optimized further
|
|
colvarvalue cvtmp(vector1d_value.slice(elem_indices[i],
|
|
elem_indices[i] + elem_sizes[i]), elem_types[i]);
|
|
cvtmp.apply_constraints();
|
|
set_elem(i, cvtmp);
|
|
}
|
|
}
|
|
break;
|
|
case colvarvalue::type_notset:
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
void colvarvalue::type(Type const &vti)
|
|
{
|
|
if (vti != value_type) {
|
|
// reset the value based on the previous type
|
|
reset();
|
|
if ((value_type == type_vector) && (vti != type_vector)) {
|
|
vector1d_value.clear();
|
|
}
|
|
value_type = vti;
|
|
}
|
|
}
|
|
|
|
|
|
void colvarvalue::type(colvarvalue const &x)
|
|
{
|
|
if (x.type() != value_type) {
|
|
// reset the value based on the previous type
|
|
reset();
|
|
if (value_type == type_vector) {
|
|
vector1d_value.clear();
|
|
}
|
|
value_type = x.type();
|
|
}
|
|
|
|
if (x.type() == type_vector) {
|
|
vector1d_value.resize(x.vector1d_value.size());
|
|
}
|
|
}
|
|
|
|
|
|
void colvarvalue::is_derivative()
|
|
{
|
|
switch (value_type) {
|
|
case colvarvalue::type_scalar:
|
|
case colvarvalue::type_3vector:
|
|
case colvarvalue::type_unit3vectorderiv:
|
|
case colvarvalue::type_quaternionderiv:
|
|
break;
|
|
case colvarvalue::type_unit3vector:
|
|
type(colvarvalue::type_unit3vectorderiv);
|
|
break;
|
|
case colvarvalue::type_quaternion:
|
|
type(colvarvalue::type_quaternionderiv);
|
|
break;
|
|
case colvarvalue::type_vector:
|
|
// TODO
|
|
break;
|
|
case colvarvalue::type_notset:
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
void colvarvalue::add_elem(colvarvalue const &x)
|
|
{
|
|
if (this->value_type != type_vector) {
|
|
cvm::error("Error: trying to set an element for a variable that is not set to be a vector.\n");
|
|
return;
|
|
}
|
|
size_t const n = vector1d_value.size();
|
|
size_t const nd = num_dimensions(x.value_type);
|
|
elem_types.push_back(x.value_type);
|
|
elem_indices.push_back(n);
|
|
elem_sizes.push_back(nd);
|
|
vector1d_value.resize(n + nd);
|
|
set_elem(n, x);
|
|
}
|
|
|
|
|
|
colvarvalue const colvarvalue::get_elem(int const i_begin, int const i_end, Type const vt) const
|
|
{
|
|
if (vector1d_value.size() > 0) {
|
|
cvm::vector1d<cvm::real> const v(vector1d_value.slice(i_begin, i_end));
|
|
return colvarvalue(v, vt);
|
|
} else {
|
|
cvm::error("Error: trying to get an element from a variable that is not a vector.\n");
|
|
return colvarvalue(type_notset);
|
|
}
|
|
}
|
|
|
|
|
|
void colvarvalue::set_elem(int const i_begin, int const i_end, colvarvalue const &x)
|
|
{
|
|
if (vector1d_value.size() > 0) {
|
|
vector1d_value.sliceassign(i_begin, i_end, x.as_vector());
|
|
} else {
|
|
cvm::error("Error: trying to set an element for a variable that is not a vector.\n");
|
|
}
|
|
}
|
|
|
|
|
|
colvarvalue const colvarvalue::get_elem(int const icv) const
|
|
{
|
|
if (elem_types.size() > 0) {
|
|
return get_elem(elem_indices[icv], elem_indices[icv] + elem_sizes[icv],
|
|
elem_types[icv]);
|
|
} else {
|
|
cvm::error("Error: trying to get a colvarvalue element from a vector colvarvalue that was initialized as a plain array.\n");
|
|
return colvarvalue(type_notset);
|
|
}
|
|
}
|
|
|
|
|
|
void colvarvalue::set_elem(int const icv, colvarvalue const &x)
|
|
{
|
|
if (elem_types.size() > 0) {
|
|
check_types_assign(elem_types[icv], x.value_type);
|
|
set_elem(elem_indices[icv], elem_indices[icv] + elem_sizes[icv], x);
|
|
} else {
|
|
cvm::error("Error: trying to set a colvarvalue element for a colvarvalue that was initialized as a plain array.\n");
|
|
}
|
|
}
|
|
|
|
|
|
void colvarvalue::set_random()
|
|
{
|
|
size_t ic;
|
|
switch (this->type()) {
|
|
case colvarvalue::type_scalar:
|
|
this->real_value = cvm::rand_gaussian();
|
|
break;
|
|
case colvarvalue::type_3vector:
|
|
case colvarvalue::type_unit3vector:
|
|
case colvarvalue::type_unit3vectorderiv:
|
|
this->rvector_value.x = cvm::rand_gaussian();
|
|
this->rvector_value.y = cvm::rand_gaussian();
|
|
this->rvector_value.z = cvm::rand_gaussian();
|
|
break;
|
|
case colvarvalue::type_quaternion:
|
|
case colvarvalue::type_quaternionderiv:
|
|
this->quaternion_value.q0 = cvm::rand_gaussian();
|
|
this->quaternion_value.q1 = cvm::rand_gaussian();
|
|
this->quaternion_value.q2 = cvm::rand_gaussian();
|
|
this->quaternion_value.q3 = cvm::rand_gaussian();
|
|
break;
|
|
case colvarvalue::type_vector:
|
|
for (ic = 0; ic < this->vector1d_value.size(); ic++) {
|
|
this->vector1d_value[ic] = cvm::rand_gaussian();
|
|
}
|
|
break;
|
|
case colvarvalue::type_notset:
|
|
default:
|
|
undef_op();
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
void colvarvalue::set_ones(cvm::real assigned_value)
|
|
{
|
|
size_t ic;
|
|
switch (this->type()) {
|
|
case colvarvalue::type_scalar:
|
|
this->real_value = assigned_value;
|
|
break;
|
|
case colvarvalue::type_3vector:
|
|
case colvarvalue::type_unit3vector:
|
|
case colvarvalue::type_unit3vectorderiv:
|
|
this->rvector_value.x = assigned_value;
|
|
this->rvector_value.y = assigned_value;
|
|
this->rvector_value.z = assigned_value;
|
|
break;
|
|
case colvarvalue::type_quaternion:
|
|
case colvarvalue::type_quaternionderiv:
|
|
this->quaternion_value.q0 = assigned_value;
|
|
this->quaternion_value.q1 = assigned_value;
|
|
this->quaternion_value.q2 = assigned_value;
|
|
this->quaternion_value.q3 = assigned_value;
|
|
break;
|
|
case colvarvalue::type_vector:
|
|
for (ic = 0; ic < this->vector1d_value.size(); ic++) {
|
|
this->vector1d_value[ic] = assigned_value;
|
|
}
|
|
break;
|
|
case colvarvalue::type_notset:
|
|
default:
|
|
undef_op();
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
void colvarvalue::undef_op() const
|
|
{
|
|
cvm::error("Error: Undefined operation on a colvar of type \""+
|
|
type_desc(this->type())+"\".\n");
|
|
}
|
|
|
|
|
|
// binary operations between two colvarvalues
|
|
|
|
colvarvalue operator + (colvarvalue const &x1,
|
|
colvarvalue const &x2)
|
|
{
|
|
colvarvalue::check_types(x1, x2);
|
|
|
|
switch (x1.value_type) {
|
|
case colvarvalue::type_scalar:
|
|
return colvarvalue(x1.real_value + x2.real_value);
|
|
case colvarvalue::type_3vector:
|
|
return colvarvalue(x1.rvector_value + x2.rvector_value);
|
|
case colvarvalue::type_unit3vector:
|
|
case colvarvalue::type_unit3vectorderiv:
|
|
return colvarvalue(x1.rvector_value + x2.rvector_value,
|
|
colvarvalue::type_unit3vector);
|
|
case colvarvalue::type_quaternion:
|
|
case colvarvalue::type_quaternionderiv:
|
|
return colvarvalue(x1.quaternion_value + x2.quaternion_value);
|
|
case colvarvalue::type_vector:
|
|
return colvarvalue(x1.vector1d_value + x2.vector1d_value, colvarvalue::type_vector);
|
|
case colvarvalue::type_notset:
|
|
default:
|
|
x1.undef_op();
|
|
return colvarvalue(colvarvalue::type_notset);
|
|
};
|
|
}
|
|
|
|
|
|
colvarvalue operator - (colvarvalue const &x1,
|
|
colvarvalue const &x2)
|
|
{
|
|
colvarvalue::check_types(x1, x2);
|
|
|
|
switch (x1.value_type) {
|
|
case colvarvalue::type_scalar:
|
|
return colvarvalue(x1.real_value - x2.real_value);
|
|
case colvarvalue::type_3vector:
|
|
return colvarvalue(x1.rvector_value - x2.rvector_value);
|
|
case colvarvalue::type_unit3vector:
|
|
case colvarvalue::type_unit3vectorderiv:
|
|
return colvarvalue(x1.rvector_value - x2.rvector_value,
|
|
colvarvalue::type_unit3vector);
|
|
case colvarvalue::type_quaternion:
|
|
case colvarvalue::type_quaternionderiv:
|
|
return colvarvalue(x1.quaternion_value - x2.quaternion_value);
|
|
case colvarvalue::type_vector:
|
|
return colvarvalue(x1.vector1d_value - x2.vector1d_value, colvarvalue::type_vector);
|
|
case colvarvalue::type_notset:
|
|
default:
|
|
x1.undef_op();
|
|
return colvarvalue(colvarvalue::type_notset);
|
|
};
|
|
}
|
|
|
|
|
|
// binary operations with real numbers
|
|
|
|
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_3vector:
|
|
return colvarvalue(a * x.rvector_value);
|
|
case colvarvalue::type_unit3vector:
|
|
case colvarvalue::type_unit3vectorderiv:
|
|
return colvarvalue(a * x.rvector_value,
|
|
colvarvalue::type_unit3vector);
|
|
case colvarvalue::type_quaternion:
|
|
case colvarvalue::type_quaternionderiv:
|
|
return colvarvalue(a * x.quaternion_value);
|
|
case colvarvalue::type_vector:
|
|
return colvarvalue(x.vector1d_value * a, colvarvalue::type_vector);
|
|
case colvarvalue::type_notset:
|
|
default:
|
|
x.undef_op();
|
|
return colvarvalue(colvarvalue::type_notset);
|
|
}
|
|
}
|
|
|
|
|
|
colvarvalue operator * (colvarvalue const &x,
|
|
cvm::real const &a)
|
|
{
|
|
return a * x;
|
|
}
|
|
|
|
|
|
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_3vector:
|
|
return colvarvalue(x.rvector_value / a);
|
|
case colvarvalue::type_unit3vector:
|
|
case colvarvalue::type_unit3vectorderiv:
|
|
return colvarvalue(x.rvector_value / a,
|
|
colvarvalue::type_unit3vector);
|
|
case colvarvalue::type_quaternion:
|
|
case colvarvalue::type_quaternionderiv:
|
|
return colvarvalue(x.quaternion_value / a);
|
|
case colvarvalue::type_vector:
|
|
return colvarvalue(x.vector1d_value / a, colvarvalue::type_vector);
|
|
case colvarvalue::type_notset:
|
|
default:
|
|
x.undef_op();
|
|
return colvarvalue(colvarvalue::type_notset);
|
|
}
|
|
}
|
|
|
|
|
|
// inner product between two colvarvalues
|
|
|
|
cvm::real operator * (colvarvalue const &x1,
|
|
colvarvalue const &x2)
|
|
{
|
|
colvarvalue::check_types(x1, x2);
|
|
|
|
switch (x1.value_type) {
|
|
case colvarvalue::type_scalar:
|
|
return (x1.real_value * x2.real_value);
|
|
case colvarvalue::type_3vector:
|
|
case colvarvalue::type_unit3vector:
|
|
case colvarvalue::type_unit3vectorderiv:
|
|
return (x1.rvector_value * x2.rvector_value);
|
|
case colvarvalue::type_quaternion:
|
|
case colvarvalue::type_quaternionderiv:
|
|
// 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_vector:
|
|
return (x1.vector1d_value * x2.vector1d_value);
|
|
case colvarvalue::type_notset:
|
|
default:
|
|
x1.undef_op();
|
|
return 0.0;
|
|
};
|
|
}
|
|
|
|
|
|
cvm::real colvarvalue::norm2() const
|
|
{
|
|
switch (value_type) {
|
|
case colvarvalue::type_scalar:
|
|
return (this->real_value)*(this->real_value);
|
|
case colvarvalue::type_3vector:
|
|
case colvarvalue::type_unit3vector:
|
|
case colvarvalue::type_unit3vectorderiv:
|
|
return (this->rvector_value).norm2();
|
|
case colvarvalue::type_quaternion:
|
|
case colvarvalue::type_quaternionderiv:
|
|
return (this->quaternion_value).norm2();
|
|
case colvarvalue::type_vector:
|
|
if (elem_types.size() > 0) {
|
|
// if we have information about non-scalar types, use it
|
|
cvm::real result = 0.0;
|
|
size_t i;
|
|
for (i = 0; i < elem_types.size(); i++) {
|
|
result += (this->get_elem(i)).norm2();
|
|
}
|
|
return result;
|
|
} else {
|
|
return vector1d_value.norm2();
|
|
}
|
|
break;
|
|
case colvarvalue::type_notset:
|
|
default:
|
|
return 0.0;
|
|
}
|
|
}
|
|
|
|
|
|
cvm::real colvarvalue::sum() const
|
|
{
|
|
switch (value_type) {
|
|
case colvarvalue::type_scalar:
|
|
return (this->real_value);
|
|
case colvarvalue::type_3vector:
|
|
case colvarvalue::type_unit3vector:
|
|
case colvarvalue::type_unit3vectorderiv:
|
|
return (this->rvector_value).x + (this->rvector_value).y +
|
|
(this->rvector_value).z;
|
|
case colvarvalue::type_quaternion:
|
|
case colvarvalue::type_quaternionderiv:
|
|
return (this->quaternion_value).q0 + (this->quaternion_value).q1 +
|
|
(this->quaternion_value).q2 + (this->quaternion_value).q3;
|
|
case colvarvalue::type_vector:
|
|
return (this->vector1d_value).sum();
|
|
case colvarvalue::type_notset:
|
|
default:
|
|
return 0.0;
|
|
}
|
|
}
|
|
|
|
|
|
cvm::real colvarvalue::dist2(colvarvalue const &x2) const
|
|
{
|
|
colvarvalue::check_types(*this, x2);
|
|
|
|
switch (this->type()) {
|
|
case colvarvalue::type_scalar:
|
|
return (this->real_value - x2.real_value) * (this->real_value - x2.real_value);
|
|
case colvarvalue::type_3vector:
|
|
return (this->rvector_value - x2.rvector_value).norm2();
|
|
case colvarvalue::type_unit3vector: {
|
|
cvm::rvector const &v1 = this->rvector_value;
|
|
cvm::rvector const &v2 = x2.rvector_value;
|
|
cvm::real const theta = cvm::acos(v1 * v2);
|
|
return theta * theta;
|
|
}
|
|
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_vector:
|
|
return (this->vector1d_value - x2.vector1d_value).norm2();
|
|
case colvarvalue::type_unit3vectorderiv:
|
|
case colvarvalue::type_quaternionderiv:
|
|
cvm::error("Error: computing a squared-distance between two variables of type \"" +
|
|
type_desc(this->type()) + "\", for which it is not defined.\n",
|
|
COLVARS_BUG_ERROR);
|
|
case colvarvalue::type_notset:
|
|
default:
|
|
this->undef_op();
|
|
return 0.0;
|
|
};
|
|
|
|
return 0.0;
|
|
}
|
|
|
|
|
|
colvarvalue colvarvalue::dist2_grad(colvarvalue const &x2) const
|
|
{
|
|
colvarvalue::check_types(*this, x2);
|
|
|
|
// Compute derivative with respect to (*this)
|
|
|
|
switch (this->value_type) {
|
|
case colvarvalue::type_scalar:
|
|
return 2.0 * (this->real_value - x2.real_value);
|
|
case colvarvalue::type_3vector:
|
|
return 2.0 * (this->rvector_value - x2.rvector_value);
|
|
case colvarvalue::type_unit3vector: {
|
|
cvm::rvector const &v1 = this->rvector_value;
|
|
cvm::rvector const &v2 = x2.rvector_value;
|
|
cvm::real const cos_t = v1 * v2;
|
|
return colvarvalue(2.0 * cvm::acos(cos_t) * -1.0 / cvm::sqrt(1.0 - cos_t * cos_t) * v2,
|
|
colvarvalue::type_unit3vectorderiv);
|
|
}
|
|
case colvarvalue::type_quaternion:
|
|
return this->quaternion_value.dist2_grad(x2.quaternion_value);
|
|
case colvarvalue::type_vector:
|
|
return colvarvalue(2.0 * (this->vector1d_value - x2.vector1d_value), colvarvalue::type_vector);
|
|
break;
|
|
case colvarvalue::type_unit3vectorderiv:
|
|
case colvarvalue::type_quaternionderiv:
|
|
cvm::error("Error: computing a squared-distance gradient between two variables of type \"" +
|
|
type_desc(this->type()) + "\", for which it is not defined.\n",
|
|
COLVARS_BUG_ERROR);
|
|
case colvarvalue::type_notset:
|
|
default:
|
|
this->undef_op();
|
|
return colvarvalue(colvarvalue::type_notset);
|
|
};
|
|
|
|
return colvarvalue(colvarvalue::type_notset);
|
|
}
|
|
|
|
|
|
/// Return the midpoint between x1 and x2, optionally weighted by lambda
|
|
/// (which must be between 0.0 and 1.0)
|
|
colvarvalue const colvarvalue::interpolate(colvarvalue const &x1,
|
|
colvarvalue const &x2,
|
|
cvm::real const lambda)
|
|
{
|
|
colvarvalue::check_types(x1, x2);
|
|
|
|
if ((lambda < 0.0) || (lambda > 1.0)) {
|
|
cvm::error("Error: trying to interpolate between two colvarvalues with a "
|
|
"lamdba outside [0:1].\n", COLVARS_BUG_ERROR);
|
|
}
|
|
|
|
colvarvalue interp = ((1.0-lambda)*x1 + lambda*x2);
|
|
cvm::real const d2 = x1.dist2(x2);
|
|
|
|
switch (x1.type()) {
|
|
case colvarvalue::type_scalar:
|
|
case colvarvalue::type_3vector:
|
|
case colvarvalue::type_vector:
|
|
case colvarvalue::type_unit3vectorderiv:
|
|
case colvarvalue::type_quaternionderiv:
|
|
return interp;
|
|
break;
|
|
case colvarvalue::type_unit3vector:
|
|
case colvarvalue::type_quaternion:
|
|
if (interp.norm()/cvm::sqrt(d2) < 1.0e-6) {
|
|
cvm::error("Error: interpolation between "+cvm::to_str(x1)+" and "+
|
|
cvm::to_str(x2)+" with lambda = "+cvm::to_str(lambda)+
|
|
" is undefined: result = "+cvm::to_str(interp)+"\n",
|
|
COLVARS_INPUT_ERROR);
|
|
}
|
|
interp.apply_constraints();
|
|
return interp;
|
|
break;
|
|
case colvarvalue::type_notset:
|
|
default:
|
|
x1.undef_op();
|
|
break;
|
|
}
|
|
return colvarvalue(colvarvalue::type_notset);
|
|
}
|
|
|
|
|
|
std::string colvarvalue::to_simple_string() const
|
|
{
|
|
switch (type()) {
|
|
case colvarvalue::type_scalar:
|
|
return cvm::to_str(real_value, 0, cvm::cv_prec);
|
|
break;
|
|
case colvarvalue::type_3vector:
|
|
case colvarvalue::type_unit3vector:
|
|
case colvarvalue::type_unit3vectorderiv:
|
|
return rvector_value.to_simple_string();
|
|
break;
|
|
case colvarvalue::type_quaternion:
|
|
case colvarvalue::type_quaternionderiv:
|
|
return quaternion_value.to_simple_string();
|
|
break;
|
|
case colvarvalue::type_vector:
|
|
return vector1d_value.to_simple_string();
|
|
break;
|
|
case colvarvalue::type_notset:
|
|
default:
|
|
undef_op();
|
|
break;
|
|
}
|
|
return std::string();
|
|
}
|
|
|
|
|
|
int colvarvalue::from_simple_string(std::string const &s)
|
|
{
|
|
switch (type()) {
|
|
case colvarvalue::type_scalar:
|
|
return ((std::istringstream(s) >> real_value)
|
|
? COLVARS_OK : COLVARS_ERROR);
|
|
break;
|
|
case colvarvalue::type_3vector:
|
|
case colvarvalue::type_unit3vector:
|
|
case colvarvalue::type_unit3vectorderiv:
|
|
return rvector_value.from_simple_string(s);
|
|
break;
|
|
case colvarvalue::type_quaternion:
|
|
case colvarvalue::type_quaternionderiv:
|
|
return quaternion_value.from_simple_string(s);
|
|
break;
|
|
case colvarvalue::type_vector:
|
|
return vector1d_value.from_simple_string(s);
|
|
break;
|
|
case colvarvalue::type_notset:
|
|
default:
|
|
undef_op();
|
|
break;
|
|
}
|
|
return COLVARS_ERROR;
|
|
}
|
|
|
|
|
|
template <typename OST> void colvarvalue::write_to_stream_template_(OST &os) const
|
|
{
|
|
switch (type()) {
|
|
case colvarvalue::type_scalar:
|
|
os << real_value;
|
|
break;
|
|
case colvarvalue::type_3vector:
|
|
case colvarvalue::type_unit3vector:
|
|
case colvarvalue::type_unit3vectorderiv:
|
|
os << rvector_value;
|
|
break;
|
|
case colvarvalue::type_quaternion:
|
|
case colvarvalue::type_quaternionderiv:
|
|
os << quaternion_value;
|
|
break;
|
|
case colvarvalue::type_vector:
|
|
os << vector1d_value;
|
|
break;
|
|
case colvarvalue::type_notset:
|
|
default:
|
|
os << "not set";
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
std::ostream & operator << (std::ostream &os, colvarvalue const &x)
|
|
{
|
|
x.write_to_stream_template_<std::ostream>(os);
|
|
return os;
|
|
}
|
|
|
|
|
|
cvm::memory_stream & operator << (cvm::memory_stream &os, colvarvalue const &x)
|
|
{
|
|
x.write_to_stream_template_<cvm::memory_stream>(os);
|
|
return os;
|
|
}
|
|
|
|
|
|
std::ostream & operator << (std::ostream &os, std::vector<colvarvalue> const &v)
|
|
{
|
|
size_t i;
|
|
for (i = 0; i < v.size(); i++) {
|
|
os << v[i];
|
|
}
|
|
return os;
|
|
}
|
|
|
|
|
|
template <typename IST> void colvarvalue::read_from_stream_template_(IST &is)
|
|
{
|
|
if (type() == colvarvalue::type_notset) {
|
|
cvm::error("Trying to read from a stream a colvarvalue, "
|
|
"which has not yet been assigned a data type.\n");
|
|
}
|
|
|
|
switch (type()) {
|
|
case colvarvalue::type_scalar:
|
|
is >> real_value;
|
|
break;
|
|
case colvarvalue::type_3vector:
|
|
case colvarvalue::type_unit3vectorderiv:
|
|
is >> rvector_value;
|
|
break;
|
|
case colvarvalue::type_unit3vector:
|
|
is >> rvector_value;
|
|
apply_constraints();
|
|
break;
|
|
case colvarvalue::type_quaternion:
|
|
is >> quaternion_value;
|
|
apply_constraints();
|
|
break;
|
|
case colvarvalue::type_quaternionderiv:
|
|
is >> quaternion_value;
|
|
break;
|
|
case colvarvalue::type_vector:
|
|
is >> vector1d_value;
|
|
break;
|
|
case colvarvalue::type_notset:
|
|
default:
|
|
undef_op();
|
|
}
|
|
}
|
|
|
|
|
|
std::istream & operator >> (std::istream &is, colvarvalue &x)
|
|
{
|
|
x.read_from_stream_template_<std::istream>(is);
|
|
return is;
|
|
}
|
|
|
|
|
|
cvm::memory_stream & operator >> (cvm::memory_stream &is, colvarvalue &x)
|
|
{
|
|
x.read_from_stream_template_<cvm::memory_stream>(is);
|
|
return is;
|
|
}
|
|
|
|
size_t colvarvalue::output_width(size_t const &real_width) const
|
|
{
|
|
switch (this->value_type) {
|
|
case colvarvalue::type_scalar:
|
|
return real_width;
|
|
case colvarvalue::type_3vector:
|
|
case colvarvalue::type_unit3vector:
|
|
case colvarvalue::type_unit3vectorderiv:
|
|
return cvm::rvector::output_width(real_width);
|
|
case colvarvalue::type_quaternion:
|
|
case colvarvalue::type_quaternionderiv:
|
|
return cvm::quaternion::output_width(real_width);
|
|
case colvarvalue::type_vector:
|
|
// note how this depends on the vector's size
|
|
return vector1d_value.output_width(real_width);
|
|
case colvarvalue::type_notset:
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
void colvarvalue::inner_opt(colvarvalue const &x,
|
|
std::vector<colvarvalue>::iterator &xv,
|
|
std::vector<colvarvalue>::iterator const &xv_end,
|
|
std::vector<cvm::real>::iterator &result)
|
|
{
|
|
// doing type check only once, here
|
|
colvarvalue::check_types(x, *xv);
|
|
|
|
std::vector<colvarvalue>::iterator &xvi = xv;
|
|
std::vector<cvm::real>::iterator &ii = result;
|
|
|
|
switch (x.value_type) {
|
|
case colvarvalue::type_scalar:
|
|
while (xvi != xv_end) {
|
|
*(ii++) += (xvi++)->real_value * x.real_value;
|
|
}
|
|
break;
|
|
case colvarvalue::type_3vector:
|
|
case colvarvalue::type_unit3vector:
|
|
case colvarvalue::type_unit3vectorderiv:
|
|
while (xvi != xv_end) {
|
|
*(ii++) += (xvi++)->rvector_value * x.rvector_value;
|
|
}
|
|
break;
|
|
case colvarvalue::type_quaternion:
|
|
case colvarvalue::type_quaternionderiv:
|
|
while (xvi != xv_end) {
|
|
*(ii++) += ((xvi++)->quaternion_value).cosine(x.quaternion_value);
|
|
}
|
|
break;
|
|
case colvarvalue::type_vector:
|
|
while (xvi != xv_end) {
|
|
*(ii++) += (xvi++)->vector1d_value * x.vector1d_value;
|
|
}
|
|
break;
|
|
default:
|
|
x.undef_op();
|
|
};
|
|
}
|
|
|
|
|
|
void colvarvalue::inner_opt(colvarvalue const &x,
|
|
std::list<colvarvalue>::iterator &xv,
|
|
std::list<colvarvalue>::iterator const &xv_end,
|
|
std::vector<cvm::real>::iterator &result)
|
|
{
|
|
// doing type check only once, here
|
|
colvarvalue::check_types(x, *xv);
|
|
|
|
std::list<colvarvalue>::iterator &xvi = xv;
|
|
std::vector<cvm::real>::iterator &ii = result;
|
|
|
|
switch (x.value_type) {
|
|
case colvarvalue::type_scalar:
|
|
while (xvi != xv_end) {
|
|
*(ii++) += (xvi++)->real_value * x.real_value;
|
|
}
|
|
break;
|
|
case colvarvalue::type_3vector:
|
|
case colvarvalue::type_unit3vector:
|
|
case colvarvalue::type_unit3vectorderiv:
|
|
while (xvi != xv_end) {
|
|
*(ii++) += (xvi++)->rvector_value * x.rvector_value;
|
|
}
|
|
break;
|
|
case colvarvalue::type_quaternion:
|
|
case colvarvalue::type_quaternionderiv:
|
|
while (xvi != xv_end) {
|
|
*(ii++) += ((xvi++)->quaternion_value).cosine(x.quaternion_value);
|
|
}
|
|
break;
|
|
case colvarvalue::type_vector:
|
|
while (xvi != xv_end) {
|
|
*(ii++) += (xvi++)->vector1d_value * x.vector1d_value;
|
|
}
|
|
break;
|
|
default:
|
|
x.undef_op();
|
|
};
|
|
}
|
|
|
|
|
|
void colvarvalue::p2leg_opt(colvarvalue const &x,
|
|
std::vector<colvarvalue>::iterator &xv,
|
|
std::vector<colvarvalue>::iterator const &xv_end,
|
|
std::vector<cvm::real>::iterator &result)
|
|
{
|
|
// doing type check only once, here
|
|
colvarvalue::check_types(x, *xv);
|
|
|
|
std::vector<colvarvalue>::iterator &xvi = xv;
|
|
std::vector<cvm::real>::iterator &ii = result;
|
|
|
|
switch (x.value_type) {
|
|
case colvarvalue::type_scalar:
|
|
cvm::error("Error: cannot calculate Legendre polynomials "
|
|
"for scalar variables.\n");
|
|
return;
|
|
break;
|
|
case colvarvalue::type_3vector:
|
|
while (xvi != xv_end) {
|
|
cvm::real const cosine =
|
|
((xvi)->rvector_value * x.rvector_value) /
|
|
((xvi)->rvector_value.norm() * x.rvector_value.norm());
|
|
xvi++;
|
|
*(ii++) += 1.5*cosine*cosine - 0.5;
|
|
}
|
|
break;
|
|
case colvarvalue::type_unit3vector:
|
|
case colvarvalue::type_unit3vectorderiv:
|
|
while (xvi != xv_end) {
|
|
cvm::real const cosine = (xvi++)->rvector_value * x.rvector_value;
|
|
*(ii++) += 1.5*cosine*cosine - 0.5;
|
|
}
|
|
break;
|
|
case colvarvalue::type_quaternion:
|
|
case colvarvalue::type_quaternionderiv:
|
|
while (xvi != xv_end) {
|
|
cvm::real const cosine = (xvi++)->quaternion_value.cosine(x.quaternion_value);
|
|
*(ii++) += 1.5*cosine*cosine - 0.5;
|
|
}
|
|
break;
|
|
case colvarvalue::type_vector:
|
|
while (xvi != xv_end) {
|
|
cvm::real const cosine =
|
|
((xvi)->vector1d_value * x.vector1d_value) /
|
|
((xvi)->vector1d_value.norm() * x.rvector_value.norm());
|
|
xvi++;
|
|
*(ii++) += 1.5*cosine*cosine - 0.5;
|
|
}
|
|
break;
|
|
default:
|
|
x.undef_op();
|
|
};
|
|
}
|
|
|
|
|
|
void colvarvalue::p2leg_opt(colvarvalue const &x,
|
|
std::list<colvarvalue>::iterator &xv,
|
|
std::list<colvarvalue>::iterator const &xv_end,
|
|
std::vector<cvm::real>::iterator &result)
|
|
{
|
|
// doing type check only once, here
|
|
colvarvalue::check_types(x, *xv);
|
|
|
|
std::list<colvarvalue>::iterator &xvi = xv;
|
|
std::vector<cvm::real>::iterator &ii = result;
|
|
|
|
switch (x.value_type) {
|
|
case colvarvalue::type_scalar:
|
|
cvm::error("Error: cannot calculate Legendre polynomials "
|
|
"for scalar variables.\n");
|
|
break;
|
|
case colvarvalue::type_3vector:
|
|
while (xvi != xv_end) {
|
|
cvm::real const cosine =
|
|
((xvi)->rvector_value * x.rvector_value) /
|
|
((xvi)->rvector_value.norm() * x.rvector_value.norm());
|
|
xvi++;
|
|
*(ii++) += 1.5*cosine*cosine - 0.5;
|
|
}
|
|
break;
|
|
case colvarvalue::type_unit3vector:
|
|
case colvarvalue::type_unit3vectorderiv:
|
|
while (xvi != xv_end) {
|
|
cvm::real const cosine = (xvi++)->rvector_value * x.rvector_value;
|
|
*(ii++) += 1.5*cosine*cosine - 0.5;
|
|
}
|
|
break;
|
|
case colvarvalue::type_quaternion:
|
|
case colvarvalue::type_quaternionderiv:
|
|
while (xvi != xv_end) {
|
|
cvm::real const cosine = (xvi++)->quaternion_value.cosine(x.quaternion_value);
|
|
*(ii++) += 1.5*cosine*cosine - 0.5;
|
|
}
|
|
break;
|
|
default:
|
|
x.undef_op();
|
|
};
|
|
}
|
|
|
|
|
|
|