Files
lammps/lib/colvars/colvar_geometricpath.h
Giacomo Fiorin 377c652a83 Update Colvars library to version 2023-05-01
This update consists exclusively of bugfixes or maintenance-related changes.

The following is a list of pull requests in the Colvars repository since the previous update to LAMMPS:

- 532 Add XYZ trajectory reading feature
  https://github.com/Colvars/colvars/pull/532 (@jhenin, @giacomofiorin)

- 531 Delete objects quietly, unless explicitly requested via script (including VMD)
  https://github.com/Colvars/colvars/pull/531 (@giacomofiorin)

- 530 Append newline to log and error messages if not already present
  https://github.com/Colvars/colvars/pull/530 (@giacomofiorin)

- 528 Forward-declare OpenMP lock
  https://github.com/Colvars/colvars/pull/528 (@giacomofiorin)

- 527 Remove unneeded STL container
  https://github.com/Colvars/colvars/pull/527 (@giacomofiorin)

- 526 Allow collecting configuration files and strings before setting up interface
  https://github.com/Colvars/colvars/pull/526 (@giacomofiorin, @jhenin)

- 523 Fallback to linearCombination when customFunction is missing in customColvar
  https://github.com/Colvars/colvars/pull/523 (@HanatoK, @giacomofiorin)

- 522 Use iostream::fail() to check for I/O error
  https://github.com/Colvars/colvars/pull/522 (@jhenin)

- 520 Fix ref count
  https://github.com/Colvars/colvars/pull/520 (@giacomofiorin)

- 513 Set target temperature through a common code path
  https://github.com/Colvars/colvars/pull/513 (@giacomofiorin, @jhenin)

- 509 Safer detection of Windows with recent Microsoft Visual Studio versions
  https://github.com/Colvars/colvars/pull/509 (@akohlmey)

- 508 Update LAMMPS patching method to reflect Lepton availability
  https://github.com/Colvars/colvars/pull/508 (@giacomofiorin)

- 497 Increase the precision of write_multicol
  https://github.com/Colvars/colvars/pull/497 (@HanatoK)

- 496 Only perform MTS automatic enable/disable for timeStepFactor > 1
  https://github.com/Colvars/colvars/pull/496 (@giacomofiorin)

- 493 Remove unused branch of quaternion input function
  https://github.com/Colvars/colvars/pull/493 (@giacomofiorin)

- 489 Ensure there are spaces between the fields in the header
  https://github.com/Colvars/colvars/pull/489 (@HanatoK)

- 487 Use map of output streams, and return references to its elements
  https://github.com/Colvars/colvars/pull/487 (@giacomofiorin, @jhenin)

- 486 Remember first step of moving restraint
  https://github.com/Colvars/colvars/pull/486 (@jhenin)

- 485 Add decoupling option for moving restraints
  https://github.com/Colvars/colvars/pull/485 (@jhenin)

- 483 Update Lepton via patching procedure
  https://github.com/Colvars/colvars/pull/483 (@giacomofiorin)

- 481 Make file-reading operations of input data abstractable
  https://github.com/Colvars/colvars/pull/481 (@giacomofiorin)

Authors: @akohlmey, @giacomofiorin, @HanatoK, @jhenin
2023-05-17 13:29:00 -04:00

259 lines
11 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#ifndef GEOMETRICPATHCV_H
#define GEOMETRICPATHCV_H
// 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 "colvarmodule.h"
#include <vector>
#include <cmath>
#include <algorithm>
#include <string>
namespace GeometricPathCV {
enum path_sz {S, Z};
template <typename element_type, typename scalar_type, path_sz path_type>
class GeometricPathBase {
private:
struct doCompareFrameDistance {
doCompareFrameDistance(const GeometricPathBase& obj): m_obj(obj) {}
const GeometricPathBase& m_obj;
bool operator()(const size_t& i1, const size_t& i2) {
return m_obj.frame_distances[i1] < m_obj.frame_distances[i2];
}
};
protected:
scalar_type v1v1;
scalar_type v2v2;
scalar_type v3v3;
scalar_type v4v4;
scalar_type v1v3;
scalar_type v1v4;
scalar_type f;
scalar_type dx;
scalar_type s;
scalar_type z;
scalar_type zz;
std::vector<element_type> v1;
std::vector<element_type> v2;
std::vector<element_type> v3;
std::vector<element_type> v4;
std::vector<element_type> dfdv1;
std::vector<element_type> dfdv2;
std::vector<element_type> dzdv1;
std::vector<element_type> dzdv2;
std::vector<scalar_type> frame_distances;
std::vector<size_t> frame_index;
bool use_second_closest_frame;
bool use_third_closest_frame;
bool use_z_square;
long min_frame_index_1;
long min_frame_index_2;
long min_frame_index_3;
long sign;
double M;
double m;
public:
GeometricPathBase(size_t vector_size, const element_type& element = element_type(), size_t total_frames = 1, bool p_use_second_closest_frame = true, bool p_use_third_closest_frame = false, bool p_use_z_square = false);
GeometricPathBase(size_t vector_size, const std::vector<element_type>& elements, size_t total_frames = 1, bool p_use_second_closest_frame = true, bool p_use_third_closest_frame = false, bool p_use_z_square = false);
GeometricPathBase() {}
virtual ~GeometricPathBase() {}
virtual void initialize(size_t vector_size, const element_type& element = element_type(), size_t total_frames = 1, bool p_use_second_closest_frame = true, bool p_use_third_closest_frame = false, bool p_use_z_square = false);
virtual void initialize(size_t vector_size, const std::vector<element_type>& elements, size_t total_frames = 1, bool p_use_second_closest_frame = true, bool p_use_third_closest_frame = false, bool p_use_z_square = false);
virtual void prepareVectors() = 0;
virtual void updateDistanceToReferenceFrames() = 0;
virtual void compute();
virtual void determineClosestFrames();
virtual void computeValue();
virtual void computeDerivatives();
};
template <typename element_type, typename scalar_type, path_sz path_type>
GeometricPathBase<element_type, scalar_type, path_type>::GeometricPathBase(size_t vector_size, const element_type& element, size_t total_frames, bool p_use_second_closest_frame, bool p_use_third_closest_frame, bool p_use_z_square) {
initialize(vector_size, element, total_frames, p_use_second_closest_frame, p_use_third_closest_frame, p_use_z_square);
}
template <typename element_type, typename scalar_type, path_sz path_type>
GeometricPathBase<element_type, scalar_type, path_type>::GeometricPathBase(size_t vector_size, const std::vector<element_type>& elements, size_t total_frames, bool p_use_second_closest_frame, bool p_use_third_closest_frame, bool p_use_z_square) {
initialize(vector_size, elements, total_frames, p_use_second_closest_frame, p_use_third_closest_frame, p_use_z_square);
}
template <typename element_type, typename scalar_type, path_sz path_type>
void GeometricPathBase<element_type, scalar_type, path_type>::initialize(size_t vector_size, const element_type& element, size_t total_frames, bool p_use_second_closest_frame, bool p_use_third_closest_frame, bool p_use_z_square) {
v1v1 = scalar_type();
v2v2 = scalar_type();
v3v3 = scalar_type();
v4v4 = scalar_type();
v1v3 = scalar_type();
v1v4 = scalar_type();
f = scalar_type();
dx = scalar_type();
z = scalar_type();
zz = scalar_type();
sign = 0;
v1.resize(vector_size, element);
v2.resize(vector_size, element);
v3.resize(vector_size, element);
v4.resize(vector_size, element);
dfdv1.resize(vector_size, element);
dfdv2.resize(vector_size, element);
dzdv1.resize(vector_size, element);
dzdv2.resize(vector_size, element);
frame_distances.resize(total_frames);
frame_index.resize(total_frames);
for (size_t i_frame = 0; i_frame < frame_index.size(); ++i_frame) {
frame_index[i_frame] = i_frame;
}
use_second_closest_frame = p_use_second_closest_frame;
use_third_closest_frame = p_use_third_closest_frame;
use_z_square = p_use_z_square;
M = static_cast<scalar_type>(total_frames - 1);
m = static_cast<scalar_type>(1.0);
}
template <typename element_type, typename scalar_type, path_sz path_type>
void GeometricPathBase<element_type, scalar_type, path_type>::initialize(size_t /* vector_size */, const std::vector<element_type>& elements, size_t total_frames, bool p_use_second_closest_frame, bool p_use_third_closest_frame, bool p_use_z_square) {
v1v1 = scalar_type();
v2v2 = scalar_type();
v3v3 = scalar_type();
v4v4 = scalar_type();
v1v3 = scalar_type();
v1v4 = scalar_type();
f = scalar_type();
dx = scalar_type();
z = scalar_type();
zz = scalar_type();
sign = 0;
v1 = elements;
v2 = elements;
v3 = elements;
v4 = elements;
dfdv1 = elements;
dfdv2 = elements;
dzdv1 = elements;
dzdv2 = elements;
frame_distances.resize(total_frames);
frame_index.resize(total_frames);
for (size_t i_frame = 0; i_frame < frame_index.size(); ++i_frame) {
frame_index[i_frame] = i_frame;
}
use_second_closest_frame = p_use_second_closest_frame;
use_third_closest_frame = p_use_third_closest_frame;
use_z_square = p_use_z_square;
M = static_cast<scalar_type>(total_frames - 1);
m = static_cast<scalar_type>(1.0);
}
template <typename element_type, typename scalar_type, path_sz path_type>
void GeometricPathBase<element_type, scalar_type, path_type>::compute() {
computeValue();
computeDerivatives();
}
template <typename element_type, typename scalar_type, path_sz path_type>
void GeometricPathBase<element_type, scalar_type, path_type>::determineClosestFrames() {
// Find the closest and the second closest frames
std::sort(frame_index.begin(), frame_index.end(), doCompareFrameDistance(*this));
// Determine the sign
sign = static_cast<long>(frame_index[0]) - static_cast<long>(frame_index[1]);
if (sign > 1) {
// sigma(z) is on the left side of the closest frame
sign = 1;
} else if (sign < -1) {
// sigma(z) is on the right side of the closest frame
sign = -1;
}
if (cvm::fabs(static_cast<long>(frame_index[0]) - static_cast<long>(frame_index[1])) > 1) {
std::cout << "Warning: Geometrical pathCV relies on the assumption that the second closest frame is the neighbouring frame\n";
std::cout << " Please check your configuration or increase restraint on z(σ)\n";
for (size_t i_frame = 0; i_frame < frame_index.size(); ++i_frame) {
std::cout << "Frame index: " << frame_index[i_frame] << " ; optimal RMSD = " << frame_distances[frame_index[i_frame]] << "\n";
}
}
min_frame_index_1 = frame_index[0]; // s_m
min_frame_index_2 = use_second_closest_frame ? frame_index[1] : min_frame_index_1 - sign; // s_(m-1)
min_frame_index_3 = use_third_closest_frame ? frame_index[2] : min_frame_index_1 + sign; // s_(m+1)
m = static_cast<double>(frame_index[0]);
}
template <typename element_type, typename scalar_type, path_sz path_type>
void GeometricPathBase<element_type, scalar_type, path_type>::computeValue() {
updateDistanceToReferenceFrames();
determineClosestFrames();
prepareVectors();
v1v1 = scalar_type();
v2v2 = scalar_type();
v3v3 = scalar_type();
v1v3 = scalar_type();
if (path_type == Z) {
v1v4 = scalar_type();
v4v4 = scalar_type();
}
for (size_t i_elem = 0; i_elem < v1.size(); ++i_elem) {
v1v1 += v1[i_elem] * v1[i_elem];
v2v2 += v2[i_elem] * v2[i_elem];
v3v3 += v3[i_elem] * v3[i_elem];
v1v3 += v1[i_elem] * v3[i_elem];
if (path_type == Z) {
v1v4 += v1[i_elem] * v4[i_elem];
v4v4 += v4[i_elem] * v4[i_elem];
}
}
f = (cvm::sqrt(v1v3 * v1v3 - v3v3 * (v1v1 - v2v2)) - v1v3) / v3v3;
if (path_type == Z) {
dx = 0.5 * (f - 1);
zz = v1v1 + 2 * dx * v1v4 + dx * dx * v4v4;
if (use_z_square) {
z = zz;
} else {
z = cvm::sqrt(cvm::fabs(zz));
}
}
if (path_type == S) {
s = m/M + static_cast<double>(sign) * ((f - 1) / (2 * M));
}
}
template <typename element_type, typename scalar_type, path_sz path_type>
void GeometricPathBase<element_type, scalar_type, path_type>::computeDerivatives() {
const scalar_type factor1 = 1.0 / (2.0 * v3v3 * cvm::sqrt(v1v3 * v1v3 - v3v3 * (v1v1 - v2v2)));
const scalar_type factor2 = 1.0 / v3v3;
for (size_t i_elem = 0; i_elem < v1.size(); ++i_elem) {
// Compute the derivative of f with vector v1
dfdv1[i_elem] = factor1 * (2.0 * v1v3 * v3[i_elem] - 2.0 * v3v3 * v1[i_elem]) - factor2 * v3[i_elem];
// Compute the derivative of f with respect to vector v2
dfdv2[i_elem] = factor1 * (2.0 * v3v3 * v2[i_elem]);
// dZ(v1(r), v2(r), v3) / dr = ∂Z/∂v1 * dv1/dr + ∂Z/∂v2 * dv2/dr
// dv1/dr = [fitting matrix 1][-1, ..., -1]
// dv2/dr = [fitting matrix 2][1, ..., 1]
// ∂Z/∂v1 = 1/(2*z) * (2v1 + (f-1)v4 + (v1⋅v4)∂f/∂v1 + v4^2 * 1/4 * 2(f-1) * ∂f/∂v1)
// ∂Z/∂v2 = 1/(2*z) * ((v1⋅v4)∂f/∂v2 + v4^2 * 1/4 * 2(f-1) * ∂f/∂v2)
if (path_type == Z) {
if (use_z_square) {
dzdv1[i_elem] = 2.0 * v1[i_elem] + (f-1) * v4[i_elem] + v1v4 * dfdv1[i_elem] + v4v4 * 0.25 * 2.0 * (f-1) * dfdv1[i_elem];
dzdv2[i_elem] = v1v4 * dfdv2[i_elem] + v4v4 * 0.25 * 2.0 * (f-1) * dfdv2[i_elem];
} else {
if (z > static_cast<scalar_type>(0)) {
dzdv1[i_elem] = (1.0 / (2.0 * z)) * (2.0 * v1[i_elem] + (f-1) * v4[i_elem] + v1v4 * dfdv1[i_elem] + v4v4 * 0.25 * 2.0 * (f-1) * dfdv1[i_elem]);
dzdv2[i_elem] = (1.0 / (2.0 * z)) * (v1v4 * dfdv2[i_elem] + v4v4 * 0.25 * 2.0 * (f-1) * dfdv2[i_elem]);
} else {
// workaround at z = 0
dzdv1[i_elem] = 0;
dzdv2[i_elem] = 0;
}
}
}
}
}
}
#endif // GEOMETRICPATHCV_H