Collected fixes and updates to Colvars library
This commit includes several fixes to moving restraints; also added is support for runtime integration of 2D and 3D PMFs from ABF. Mostly changes to existing member functions, with few additions in classes not directly accessible by LAMMPS. Also removed are calls to std::pow(), replaced by a copy of MathSpecial::powint(). Relevant commits in Colvars repository: 7307b5c 2017-12-14 Doc improvements [Giacomo Fiorin] 7f86f37 2017-12-14 Allow K-changing restraints computing accumulated work; fix staged-k TI estimator [Giacomo Fiorin] 7c1c175 2017-12-14 Fix 1D ABF trying to do pABF [Jérôme Hénin] b94aa7e 2017-11-16 Unify PMF output for 1D, 2D and 3D in ABF [Jérôme Hénin] 771a88f 2017-11-15 Poisson integration for all BC in 2d and 3d [Jérôme Hénin] 6af4d60 2017-12-01 Print message when issuing cv delete in VMD [Giacomo Fiorin] 4413972 2017-11-30 Check for homogeneous colvar to set it periodic [Jérôme Hénin] 95fe4b2 2017-11-06 Allow abf_integrate to start in bin with 1 sample [Jérôme Hénin] 06eea27 2017-10-23 Shorten a few constructs by using the power function [Giacomo Fiorin] 3165dfb 2017-10-20 Move includes of colvarproxy.h from headers to files [Giacomo Fiorin] 32a867b 2017-10-20 Add optimized powint function from LAMMPS headers [Giacomo Fiorin] 3ad070a 2017-10-20 Remove some unused includes, isolate calls to std::pow() [Giacomo Fiorin] 0aaf540 2017-10-20 Replace all calls to std::pow() where the exponent is not an integer [Giacomo Fiorin]
This commit is contained in:
Binary file not shown.
@ -195,7 +195,7 @@ int colvar::init(std::string const &conf)
|
||||
// - it is homogeneous
|
||||
// - all cvcs are periodic
|
||||
// - all cvcs have the same period
|
||||
if (cvcs[0]->b_periodic) { // TODO make this a CVC feature
|
||||
if (is_enabled(f_cv_homogeneous) && cvcs[0]->b_periodic) { // TODO make this a CVC feature
|
||||
bool b_periodic = true;
|
||||
period = cvcs[0]->period;
|
||||
for (i = 1; i < cvcs.size(); i++) {
|
||||
|
||||
@ -11,8 +11,6 @@
|
||||
#define COLVAR_H
|
||||
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <cmath>
|
||||
|
||||
#include "colvarmodule.h"
|
||||
#include "colvarvalue.h"
|
||||
@ -61,6 +59,9 @@ public:
|
||||
/// \brief Current actual value (not extended DOF)
|
||||
colvarvalue const & actual_value() const;
|
||||
|
||||
/// \brief Current running average (if calculated as set by analysis flag)
|
||||
colvarvalue const & run_ave() const;
|
||||
|
||||
/// \brief Force constant of the spring
|
||||
cvm::real const & force_constant() const;
|
||||
|
||||
@ -516,7 +517,7 @@ public:
|
||||
// collective variable component base class
|
||||
class cvc;
|
||||
|
||||
// currently available collective variable components
|
||||
// list of available collective variable components
|
||||
|
||||
// scalar colvar components
|
||||
class distance;
|
||||
@ -611,12 +612,15 @@ inline colvarvalue const & colvar::value() const
|
||||
return x_reported;
|
||||
}
|
||||
|
||||
|
||||
inline colvarvalue const & colvar::actual_value() const
|
||||
{
|
||||
return x;
|
||||
}
|
||||
|
||||
inline colvarvalue const & colvar::run_ave() const
|
||||
{
|
||||
return runave;
|
||||
}
|
||||
|
||||
inline colvarvalue const & colvar::velocity() const
|
||||
{
|
||||
|
||||
@ -45,7 +45,7 @@ namespace UIestimator {
|
||||
this->width = width;
|
||||
this->dimension = lowerboundary.size();
|
||||
this->y_size = y_size; // keep in mind the internal (spare) matrix is stored in diagonal form
|
||||
this->y_total_size = int(pow(double(y_size), dimension) + EPSILON);
|
||||
this->y_total_size = int(std::pow(double(y_size), double(dimension)) + EPSILON);
|
||||
|
||||
// the range of the matrix is [lowerboundary, upperboundary]
|
||||
x_total_size = 1;
|
||||
@ -121,7 +121,7 @@ namespace UIestimator {
|
||||
int index = 0;
|
||||
for (i = 0; i < dimension; i++) {
|
||||
if (i + 1 < dimension)
|
||||
index += temp[i] * int(pow(double(y_size), dimension - i - 1) + EPSILON);
|
||||
index += temp[i] * int(std::pow(double(y_size), double(dimension - i - 1)) + EPSILON);
|
||||
else
|
||||
index += temp[i];
|
||||
}
|
||||
|
||||
@ -8,9 +8,11 @@
|
||||
// Colvars repository at GitHub.
|
||||
|
||||
#include "colvarmodule.h"
|
||||
#include "colvarproxy.h"
|
||||
#include "colvarparse.h"
|
||||
#include "colvaratoms.h"
|
||||
|
||||
|
||||
cvm::atom::atom()
|
||||
{
|
||||
index = -1;
|
||||
|
||||
@ -11,6 +11,7 @@
|
||||
#define COLVARATOMS_H
|
||||
|
||||
#include "colvarmodule.h"
|
||||
#include "colvarproxy.h"
|
||||
#include "colvarparse.h"
|
||||
#include "colvardeps.h"
|
||||
|
||||
|
||||
@ -8,6 +8,7 @@
|
||||
// Colvars repository at GitHub.
|
||||
|
||||
#include "colvarmodule.h"
|
||||
#include "colvarproxy.h"
|
||||
#include "colvarvalue.h"
|
||||
#include "colvarbias.h"
|
||||
#include "colvargrid.h"
|
||||
|
||||
@ -8,6 +8,7 @@
|
||||
// Colvars repository at GitHub.
|
||||
|
||||
#include "colvarmodule.h"
|
||||
#include "colvarproxy.h"
|
||||
#include "colvar.h"
|
||||
#include "colvarbias_abf.h"
|
||||
|
||||
@ -18,16 +19,18 @@ colvarbias_abf::colvarbias_abf(char const *key)
|
||||
b_CZAR_estimator(false),
|
||||
system_force(NULL),
|
||||
gradients(NULL),
|
||||
pmf(NULL),
|
||||
samples(NULL),
|
||||
z_gradients(NULL),
|
||||
z_samples(NULL),
|
||||
czar_gradients(NULL),
|
||||
czar_pmf(NULL),
|
||||
last_gradients(NULL),
|
||||
last_samples(NULL)
|
||||
last_samples(NULL),
|
||||
pabf_freq(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
int colvarbias_abf::init(std::string const &conf)
|
||||
{
|
||||
colvarbias::init(conf);
|
||||
@ -91,7 +94,7 @@ int colvarbias_abf::init(std::string const &conf)
|
||||
|
||||
// ************* checking the associated colvars *******************
|
||||
|
||||
if (colvars.size() == 0) {
|
||||
if (num_variables() == 0) {
|
||||
cvm::error("Error: no collective variables specified for the ABF bias.\n");
|
||||
return COLVARS_ERROR;
|
||||
}
|
||||
@ -102,7 +105,8 @@ int colvarbias_abf::init(std::string const &conf)
|
||||
}
|
||||
|
||||
bool b_extended = false;
|
||||
for (size_t i = 0; i < colvars.size(); i++) {
|
||||
size_t i;
|
||||
for (i = 0; i < num_variables(); i++) {
|
||||
|
||||
if (colvars[i]->value().type() != colvarvalue::type_scalar) {
|
||||
cvm::error("Error: ABF bias can only use scalar-type variables.\n");
|
||||
@ -132,10 +136,10 @@ int colvarbias_abf::init(std::string const &conf)
|
||||
}
|
||||
|
||||
if (get_keyval(conf, "maxForce", max_force)) {
|
||||
if (max_force.size() != colvars.size()) {
|
||||
if (max_force.size() != num_variables()) {
|
||||
cvm::error("Error: Number of parameters to maxForce does not match number of colvars.");
|
||||
}
|
||||
for (size_t i = 0; i < colvars.size(); i++) {
|
||||
for (i = 0; i < num_variables(); i++) {
|
||||
if (max_force[i] < 0.0) {
|
||||
cvm::error("Error: maxForce should be non-negative.");
|
||||
}
|
||||
@ -145,9 +149,9 @@ int colvarbias_abf::init(std::string const &conf)
|
||||
cap_force = false;
|
||||
}
|
||||
|
||||
bin.assign(colvars.size(), 0);
|
||||
force_bin.assign(colvars.size(), 0);
|
||||
system_force = new cvm::real [colvars.size()];
|
||||
bin.assign(num_variables(), 0);
|
||||
force_bin.assign(num_variables(), 0);
|
||||
system_force = new cvm::real [num_variables()];
|
||||
|
||||
// Construct empty grids based on the colvars
|
||||
if (cvm::debug()) {
|
||||
@ -159,14 +163,14 @@ int colvarbias_abf::init(std::string const &conf)
|
||||
gradients->samples = samples;
|
||||
samples->has_parent_data = true;
|
||||
|
||||
// Data for eABF z-based estimator
|
||||
if (b_extended) {
|
||||
// Data for eAB F z-based estimator
|
||||
if ( b_extended ) {
|
||||
get_keyval(conf, "CZARestimator", b_CZAR_estimator, true);
|
||||
// CZAR output files for stratified eABF
|
||||
get_keyval(conf, "writeCZARwindowFile", b_czar_window_file, false,
|
||||
colvarparse::parse_silent);
|
||||
|
||||
z_bin.assign(colvars.size(), 0);
|
||||
z_bin.assign(num_variables(), 0);
|
||||
z_samples = new colvar_grid_count(colvars);
|
||||
z_samples->request_actual_value();
|
||||
z_gradients = new colvar_grid_gradient(colvars);
|
||||
@ -176,6 +180,27 @@ int colvarbias_abf::init(std::string const &conf)
|
||||
czar_gradients = new colvar_grid_gradient(colvars);
|
||||
}
|
||||
|
||||
// For now, we integrate on-the-fly iff the grid is < 3D
|
||||
if ( num_variables() <= 3 ) {
|
||||
pmf = new integrate_potential(colvars, gradients);
|
||||
if ( b_CZAR_estimator ) {
|
||||
czar_pmf = new integrate_potential(colvars, czar_gradients);
|
||||
}
|
||||
get_keyval(conf, "integrate", b_integrate, true); // Integrate for output
|
||||
if ( num_variables() > 1 ) {
|
||||
// Projected ABF
|
||||
get_keyval(conf, "pABFintegrateFreq", pabf_freq, 0);
|
||||
// Parameters for integrating initial (and final) gradient data
|
||||
get_keyval(conf, "integrateInitSteps", integrate_initial_steps, 1e4);
|
||||
get_keyval(conf, "integrateInitTol", integrate_initial_tol, 1e-6);
|
||||
// for updating the integrated PMF on the fly
|
||||
get_keyval(conf, "integrateSteps", integrate_steps, 100);
|
||||
get_keyval(conf, "integrateTol", integrate_tol, 1e-4);
|
||||
}
|
||||
} else {
|
||||
b_integrate = false;
|
||||
}
|
||||
|
||||
// For shared ABF, we store a second set of grids.
|
||||
// This used to be only if "shared" was defined,
|
||||
// but now we allow calling share externally (e.g. from Tcl).
|
||||
@ -188,6 +213,8 @@ int colvarbias_abf::init(std::string const &conf)
|
||||
// If custom grids are provided, read them
|
||||
if ( input_prefix.size() > 0 ) {
|
||||
read_gradients_samples();
|
||||
// Update divergence to account for input data
|
||||
pmf->set_div();
|
||||
}
|
||||
|
||||
// if extendedLangrangian is on, then call UI estimator
|
||||
@ -202,7 +229,7 @@ int colvarbias_abf::init(std::string const &conf)
|
||||
|
||||
bool UI_restart = (input_prefix.size() > 0);
|
||||
|
||||
for (size_t i = 0; i < colvars.size(); i++)
|
||||
for (i = 0; i < num_variables(); i++)
|
||||
{
|
||||
UI_lowerboundary.push_back(colvars[i]->lower_boundary);
|
||||
UI_upperboundary.push_back(colvars[i]->upper_boundary);
|
||||
@ -238,6 +265,11 @@ colvarbias_abf::~colvarbias_abf()
|
||||
gradients = NULL;
|
||||
}
|
||||
|
||||
if (pmf) {
|
||||
delete pmf;
|
||||
pmf = NULL;
|
||||
}
|
||||
|
||||
if (z_samples) {
|
||||
delete z_samples;
|
||||
z_samples = NULL;
|
||||
@ -253,6 +285,11 @@ colvarbias_abf::~colvarbias_abf()
|
||||
czar_gradients = NULL;
|
||||
}
|
||||
|
||||
if (czar_pmf) {
|
||||
delete czar_pmf;
|
||||
czar_pmf = NULL;
|
||||
}
|
||||
|
||||
// shared ABF
|
||||
// We used to only do this if "shared" was defined,
|
||||
// but now we can call shared externally
|
||||
@ -278,44 +315,48 @@ colvarbias_abf::~colvarbias_abf()
|
||||
|
||||
int colvarbias_abf::update()
|
||||
{
|
||||
int iter;
|
||||
|
||||
if (cvm::debug()) cvm::log("Updating ABF bias " + this->name);
|
||||
|
||||
if (cvm::step_relative() == 0) {
|
||||
size_t i;
|
||||
for (i = 0; i < num_variables(); i++) {
|
||||
bin[i] = samples->current_bin_scalar(i);
|
||||
}
|
||||
if (cvm::proxy->total_forces_same_step()) {
|
||||
// e.g. in LAMMPS, total forces are current
|
||||
force_bin = bin;
|
||||
}
|
||||
|
||||
// At first timestep, do only:
|
||||
// initialization stuff (file operations relying on n_abf_biases
|
||||
// compute current value of colvars
|
||||
if (cvm::step_relative() > 0 || cvm::proxy->total_forces_same_step()) {
|
||||
|
||||
for (size_t i = 0; i < colvars.size(); i++) {
|
||||
bin[i] = samples->current_bin_scalar(i);
|
||||
}
|
||||
if (update_bias) {
|
||||
// if (b_adiabatic_reweighting) {
|
||||
// // Update gradients non-locally based on conditional distribution of
|
||||
// // fictitious variable TODO
|
||||
//
|
||||
// } else
|
||||
if (samples->index_ok(force_bin)) {
|
||||
// Only if requested and within bounds of the grid...
|
||||
|
||||
} else {
|
||||
|
||||
for (size_t i = 0; i < colvars.size(); i++) {
|
||||
bin[i] = samples->current_bin_scalar(i);
|
||||
}
|
||||
|
||||
if ( update_bias && samples->index_ok(force_bin) ) {
|
||||
// Only if requested and within bounds of the grid...
|
||||
|
||||
for (size_t i = 0; i < colvars.size(); i++) {
|
||||
// get total forces (lagging by 1 timestep) from colvars
|
||||
// and subtract previous ABF force if necessary
|
||||
update_system_force(i);
|
||||
for (i = 0; i < num_variables(); i++) {
|
||||
// get total forces (lagging by 1 timestep) from colvars
|
||||
// and subtract previous ABF force if necessary
|
||||
update_system_force(i);
|
||||
}
|
||||
gradients->acc_force(force_bin, system_force);
|
||||
if ( b_integrate ) {
|
||||
pmf->update_div_neighbors(force_bin);
|
||||
}
|
||||
}
|
||||
if (cvm::proxy->total_forces_same_step()) {
|
||||
// e.g. in LAMMPS, total forces are current
|
||||
force_bin = bin;
|
||||
}
|
||||
gradients->acc_force(force_bin, system_force);
|
||||
}
|
||||
|
||||
if ( z_gradients && update_bias ) {
|
||||
for (size_t i = 0; i < colvars.size(); i++) {
|
||||
for (i = 0; i < num_variables(); i++) {
|
||||
z_bin[i] = z_samples->current_bin_scalar(i);
|
||||
}
|
||||
if ( z_samples->index_ok(z_bin) ) {
|
||||
for (size_t i = 0; i < colvars.size(); i++) {
|
||||
for (i = 0; i < num_variables(); i++) {
|
||||
// If we are outside the range of xi, the force has not been obtained above
|
||||
// the function is just an accessor, so cheap to call again anyway
|
||||
update_system_force(i);
|
||||
@ -323,6 +364,14 @@ int colvarbias_abf::update()
|
||||
z_gradients->acc_force(z_bin, system_force);
|
||||
}
|
||||
}
|
||||
|
||||
if ( b_integrate ) {
|
||||
if ( pabf_freq && cvm::step_relative() % pabf_freq == 0 ) {
|
||||
cvm::real err;
|
||||
iter = pmf->integrate(integrate_steps, integrate_tol, err);
|
||||
pmf->set_zero_minimum(); // TODO: do this only when necessary
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!cvm::proxy->total_forces_same_step()) {
|
||||
@ -332,14 +381,14 @@ int colvarbias_abf::update()
|
||||
}
|
||||
|
||||
// Reset biasing forces from previous timestep
|
||||
for (size_t i = 0; i < colvars.size(); i++) {
|
||||
for (i = 0; i < num_variables(); i++) {
|
||||
colvar_forces[i].reset();
|
||||
}
|
||||
|
||||
// Compute and apply the new bias, if applicable
|
||||
if (is_enabled(f_cvb_apply_force) && samples->index_ok(bin)) {
|
||||
|
||||
size_t count = samples->value(bin);
|
||||
cvm::real count = samples->value(bin);
|
||||
cvm::real fact = 1.0;
|
||||
|
||||
// Factor that ensures smooth introduction of the force
|
||||
@ -348,21 +397,34 @@ int colvarbias_abf::update()
|
||||
(cvm::real(count - min_samples)) / (cvm::real(full_samples - min_samples));
|
||||
}
|
||||
|
||||
const cvm::real * grad = &(gradients->value(bin));
|
||||
std::vector<cvm::real> grad(num_variables());
|
||||
|
||||
if ( pabf_freq ) {
|
||||
// In projected ABF, the force is the PMF gradient estimate
|
||||
pmf->vector_gradient_finite_diff(bin, grad);
|
||||
} else {
|
||||
// Normal ABF
|
||||
gradients->vector_value(bin, grad);
|
||||
}
|
||||
|
||||
// if ( b_adiabatic_reweighting) {
|
||||
// // Average of force according to conditional distribution of fictitious variable
|
||||
// // need freshly integrated PMF, gradient TODO
|
||||
// } else
|
||||
if ( fact != 0.0 ) {
|
||||
if ( (colvars.size() == 1) && colvars[0]->periodic_boundaries() ) {
|
||||
if ( (num_variables() == 1) && colvars[0]->periodic_boundaries() ) {
|
||||
// Enforce a zero-mean bias on periodic, 1D coordinates
|
||||
// in other words: boundary condition is that the biasing potential is periodic
|
||||
colvar_forces[0].real_value = fact * (grad[0] / cvm::real(count) - gradients->average());
|
||||
// This is enforced naturally if using integrated PMF
|
||||
colvar_forces[0].real_value = fact * (grad[0] - gradients->average ());
|
||||
} else {
|
||||
for (size_t i = 0; i < colvars.size(); i++) {
|
||||
for (size_t i = 0; i < num_variables(); i++) {
|
||||
// subtracting the mean force (opposite of the FE gradient) means adding the gradient
|
||||
colvar_forces[i].real_value = fact * grad[i] / cvm::real(count);
|
||||
colvar_forces[i].real_value = fact * grad[i];
|
||||
}
|
||||
}
|
||||
if (cap_force) {
|
||||
for (size_t i = 0; i < colvars.size(); i++) {
|
||||
for (size_t i = 0; i < num_variables(); i++) {
|
||||
if ( colvar_forces[i].real_value * colvar_forces[i].real_value > max_force[i] * max_force[i] ) {
|
||||
colvar_forces[i].real_value = (colvar_forces[i].real_value > 0 ? max_force[i] : -1.0 * max_force[i]);
|
||||
}
|
||||
@ -407,9 +469,9 @@ int colvarbias_abf::update()
|
||||
// update UI estimator every step
|
||||
if (b_UI_estimator)
|
||||
{
|
||||
std::vector<double> x(colvars.size(),0);
|
||||
std::vector<double> y(colvars.size(),0);
|
||||
for (size_t i = 0; i < colvars.size(); i++)
|
||||
std::vector<double> x(num_variables(),0);
|
||||
std::vector<double> y(num_variables(),0);
|
||||
for (size_t i = 0; i < num_variables(); i++)
|
||||
{
|
||||
x[i] = colvars[i]->actual_value();
|
||||
y[i] = colvars[i]->value();
|
||||
@ -509,26 +571,60 @@ void colvarbias_abf::write_gradients_samples(const std::string &prefix, bool app
|
||||
cvm::proxy->output_stream(samples_out_name, mode);
|
||||
if (!samples_os) {
|
||||
cvm::error("Error opening ABF samples file " + samples_out_name + " for writing");
|
||||
return;
|
||||
}
|
||||
samples->write_multicol(*samples_os);
|
||||
cvm::proxy->close_output_stream(samples_out_name);
|
||||
|
||||
// In dimension higher than 2, dx is easier to handle and visualize
|
||||
if (num_variables() > 2) {
|
||||
std::string samples_dx_out_name = prefix + ".count.dx";
|
||||
std::ostream *samples_dx_os = cvm::proxy->output_stream(samples_dx_out_name, mode);
|
||||
if (!samples_os) {
|
||||
cvm::error("Error opening samples file " + samples_dx_out_name + " for writing");
|
||||
return;
|
||||
}
|
||||
samples->write_opendx(*samples_dx_os);
|
||||
*samples_dx_os << std::endl;
|
||||
cvm::proxy->close_output_stream(samples_dx_out_name);
|
||||
}
|
||||
|
||||
std::ostream *gradients_os =
|
||||
cvm::proxy->output_stream(gradients_out_name, mode);
|
||||
if (!gradients_os) {
|
||||
cvm::error("Error opening ABF gradient file " + gradients_out_name + " for writing");
|
||||
return;
|
||||
}
|
||||
gradients->write_multicol(*gradients_os);
|
||||
cvm::proxy->close_output_stream(gradients_out_name);
|
||||
|
||||
if (colvars.size() == 1) {
|
||||
// Do numerical integration and output a PMF
|
||||
if (b_integrate) {
|
||||
// Do numerical integration (to high precision) and output a PMF
|
||||
cvm::real err;
|
||||
pmf->integrate(integrate_initial_steps, integrate_initial_tol, err);
|
||||
pmf->set_zero_minimum();
|
||||
|
||||
std::string pmf_out_name = prefix + ".pmf";
|
||||
std::ostream *pmf_os = cvm::proxy->output_stream(pmf_out_name, mode);
|
||||
if (!pmf_os) {
|
||||
cvm::error("Error opening pmf file " + pmf_out_name + " for writing");
|
||||
return;
|
||||
}
|
||||
gradients->write_1D_integral(*pmf_os);
|
||||
pmf->write_multicol(*pmf_os);
|
||||
|
||||
// In dimension higher than 2, dx is easier to handle and visualize
|
||||
if (num_variables() > 2) {
|
||||
std::string pmf_dx_out_name = prefix + ".pmf.dx";
|
||||
std::ostream *pmf_dx_os = cvm::proxy->output_stream(pmf_dx_out_name, mode);
|
||||
if (!pmf_dx_os) {
|
||||
cvm::error("Error opening pmf file " + pmf_dx_out_name + " for writing");
|
||||
return;
|
||||
}
|
||||
pmf->write_opendx(*pmf_dx_os);
|
||||
*pmf_dx_os << std::endl;
|
||||
cvm::proxy->close_output_stream(pmf_dx_out_name);
|
||||
}
|
||||
|
||||
*pmf_os << std::endl;
|
||||
cvm::proxy->close_output_stream(pmf_out_name);
|
||||
}
|
||||
@ -542,6 +638,7 @@ void colvarbias_abf::write_gradients_samples(const std::string &prefix, bool app
|
||||
cvm::proxy->output_stream(z_samples_out_name, mode);
|
||||
if (!z_samples_os) {
|
||||
cvm::error("Error opening eABF z-histogram file " + z_samples_out_name + " for writing");
|
||||
return;
|
||||
}
|
||||
z_samples->write_multicol(*z_samples_os);
|
||||
cvm::proxy->close_output_stream(z_samples_out_name);
|
||||
@ -553,6 +650,7 @@ void colvarbias_abf::write_gradients_samples(const std::string &prefix, bool app
|
||||
cvm::proxy->output_stream(z_gradients_out_name, mode);
|
||||
if (!z_gradients_os) {
|
||||
cvm::error("Error opening eABF z-gradient file " + z_gradients_out_name + " for writing");
|
||||
return;
|
||||
}
|
||||
z_gradients->write_multicol(*z_gradients_os);
|
||||
cvm::proxy->close_output_stream(z_gradients_out_name);
|
||||
@ -563,8 +661,7 @@ void colvarbias_abf::write_gradients_samples(const std::string &prefix, bool app
|
||||
czar_gradients->index_ok(ix); czar_gradients->incr(ix)) {
|
||||
for (size_t n = 0; n < czar_gradients->multiplicity(); n++) {
|
||||
czar_gradients->set_value(ix, z_gradients->value_output(ix, n)
|
||||
- cvm::temperature() * cvm::boltzmann() * z_samples->log_gradient_finite_diff(ix, n),
|
||||
n);
|
||||
- cvm::temperature() * cvm::boltzmann() * z_samples->log_gradient_finite_diff(ix, n), n);
|
||||
}
|
||||
}
|
||||
|
||||
@ -574,17 +671,39 @@ void colvarbias_abf::write_gradients_samples(const std::string &prefix, bool app
|
||||
cvm::proxy->output_stream(czar_gradients_out_name, mode);
|
||||
if (!czar_gradients_os) {
|
||||
cvm::error("Error opening CZAR gradient file " + czar_gradients_out_name + " for writing");
|
||||
return;
|
||||
}
|
||||
czar_gradients->write_multicol(*czar_gradients_os);
|
||||
cvm::proxy->close_output_stream(czar_gradients_out_name);
|
||||
|
||||
if (colvars.size() == 1) {
|
||||
// Do numerical integration and output a PMF
|
||||
if (b_integrate) {
|
||||
// Do numerical integration (to high precision) and output a PMF
|
||||
cvm::real err;
|
||||
czar_pmf->set_div();
|
||||
czar_pmf->integrate(integrate_initial_steps, integrate_initial_tol, err);
|
||||
czar_pmf->set_zero_minimum();
|
||||
|
||||
std::string czar_pmf_out_name = prefix + ".czar.pmf";
|
||||
std::ostream *czar_pmf_os =
|
||||
cvm::proxy->output_stream(czar_pmf_out_name, mode);
|
||||
if (!czar_pmf_os) cvm::error("Error opening CZAR pmf file " + czar_pmf_out_name + " for writing");
|
||||
czar_gradients->write_1D_integral(*czar_pmf_os);
|
||||
std::ostream *czar_pmf_os = cvm::proxy->output_stream(czar_pmf_out_name, mode);
|
||||
if (!czar_pmf_os) {
|
||||
cvm::error("Error opening CZAR pmf file " + czar_pmf_out_name + " for writing");
|
||||
return;
|
||||
}
|
||||
czar_pmf->write_multicol(*czar_pmf_os);
|
||||
|
||||
// In dimension higher than 2, dx is easier to handle and visualize
|
||||
if (num_variables() > 2) {
|
||||
std::string czar_pmf_dx_out_name = prefix + ".czar.pmf.dx";
|
||||
std::ostream *czar_pmf_dx_os = cvm::proxy->output_stream(czar_pmf_dx_out_name, mode);
|
||||
if (!czar_pmf_dx_os) {
|
||||
cvm::error("Error opening CZAR pmf file " + czar_pmf_dx_out_name + " for writing");
|
||||
return;
|
||||
}
|
||||
czar_pmf->write_opendx(*czar_pmf_dx_os);
|
||||
*czar_pmf_dx_os << std::endl;
|
||||
cvm::proxy->close_output_stream(czar_pmf_dx_out_name);
|
||||
}
|
||||
|
||||
*czar_pmf_os << std::endl;
|
||||
cvm::proxy->close_output_stream(czar_pmf_out_name);
|
||||
}
|
||||
@ -708,6 +827,10 @@ std::istream & colvarbias_abf::read_state_data(std::istream& is)
|
||||
if (! gradients->read_raw(is)) {
|
||||
return is;
|
||||
}
|
||||
if (b_integrate) {
|
||||
// Update divergence to account for restart data
|
||||
pmf->set_div();
|
||||
}
|
||||
|
||||
if (b_CZAR_estimator) {
|
||||
|
||||
|
||||
@ -40,28 +40,44 @@ private:
|
||||
/// Base filename(s) for reading previous gradient data (replaces data from restart file)
|
||||
std::vector<std::string> input_prefix;
|
||||
|
||||
bool update_bias;
|
||||
bool hide_Jacobian;
|
||||
size_t full_samples;
|
||||
size_t min_samples;
|
||||
bool update_bias;
|
||||
bool hide_Jacobian;
|
||||
bool b_integrate;
|
||||
|
||||
size_t full_samples;
|
||||
size_t min_samples;
|
||||
/// frequency for updating output files
|
||||
int output_freq;
|
||||
int output_freq;
|
||||
/// Write combined files with a history of all output data?
|
||||
bool b_history_files;
|
||||
bool b_history_files;
|
||||
/// Write CZAR output file for stratified eABF (.zgrad)
|
||||
bool b_czar_window_file;
|
||||
size_t history_freq;
|
||||
bool b_czar_window_file;
|
||||
size_t history_freq;
|
||||
/// Umbrella Integration estimator of free energy from eABF
|
||||
UIestimator::UIestimator eabf_UI;
|
||||
// Run UI estimator?
|
||||
bool b_UI_estimator;
|
||||
// Run CZAR estimator?
|
||||
bool b_CZAR_estimator;
|
||||
/// Run UI estimator?
|
||||
bool b_UI_estimator;
|
||||
/// Run CZAR estimator?
|
||||
bool b_CZAR_estimator;
|
||||
|
||||
/// Cap applied biasing force?
|
||||
/// Frequency for updating pABF PMF (if zero, pABF is not used)
|
||||
int pabf_freq;
|
||||
/// Max number of CG iterations for integrating PMF at startup and for file output
|
||||
int integrate_initial_steps;
|
||||
/// Tolerance for integrating PMF at startup and for file output
|
||||
cvm::real integrate_initial_tol;
|
||||
/// Max number of CG iterations for integrating PMF at on-the-fly pABF updates
|
||||
int integrate_steps;
|
||||
/// Tolerance for integrating PMF at on-the-fly pABF updates
|
||||
cvm::real integrate_tol;
|
||||
|
||||
/// Cap the biasing force to be applied?
|
||||
bool cap_force;
|
||||
std::vector<cvm::real> max_force;
|
||||
|
||||
// Frequency for updating 2D gradients
|
||||
int integrate_freq;
|
||||
|
||||
// Internal data and methods
|
||||
|
||||
std::vector<int> bin, force_bin, z_bin;
|
||||
@ -71,12 +87,16 @@ private:
|
||||
colvar_grid_gradient *gradients;
|
||||
/// n-dim grid of number of samples
|
||||
colvar_grid_count *samples;
|
||||
/// n-dim grid of pmf (dimension 1 to 3)
|
||||
integrate_potential *pmf;
|
||||
/// n-dim grid: average force on "real" coordinate for eABF z-based estimator
|
||||
colvar_grid_gradient *z_gradients;
|
||||
/// n-dim grid of number of samples on "real" coordinate for eABF z-based estimator
|
||||
colvar_grid_count *z_samples;
|
||||
/// n-dim grid contining CZAR estimator of "real" free energy gradients
|
||||
colvar_grid_gradient *czar_gradients;
|
||||
/// n-dim grid of CZAR pmf (dimension 1 to 3)
|
||||
integrate_potential *czar_pmf;
|
||||
|
||||
inline int update_system_force(size_t i)
|
||||
{
|
||||
@ -96,9 +116,9 @@ private:
|
||||
}
|
||||
|
||||
// shared ABF
|
||||
bool shared_on;
|
||||
size_t shared_freq;
|
||||
int shared_last_step;
|
||||
bool shared_on;
|
||||
size_t shared_freq;
|
||||
int shared_last_step;
|
||||
// Share between replicas -- may be called independently of update
|
||||
virtual int replica_share();
|
||||
|
||||
@ -114,12 +134,12 @@ private:
|
||||
//// Give the count at a given bin index.
|
||||
virtual int bin_count(int bin_index);
|
||||
|
||||
/// Write human-readable FE gradients and sample count
|
||||
void write_gradients_samples(const std::string &prefix, bool append = false);
|
||||
void write_last_gradients_samples(const std::string &prefix, bool append = false);
|
||||
/// Write human-readable FE gradients and sample count, and DX file in dim > 2
|
||||
void write_gradients_samples(const std::string &prefix, bool append = false);
|
||||
void write_last_gradients_samples(const std::string &prefix, bool append = false);
|
||||
|
||||
/// Read human-readable FE gradients and sample count (if not using restart)
|
||||
void read_gradients_samples();
|
||||
void read_gradients_samples();
|
||||
|
||||
std::istream& read_state_data(std::istream&);
|
||||
std::ostream& write_state_data(std::ostream&);
|
||||
|
||||
@ -7,13 +7,11 @@
|
||||
// If you wish to distribute your changes, please submit them to the
|
||||
// Colvars repository at GitHub.
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <cstdlib>
|
||||
|
||||
#include "colvarmodule.h"
|
||||
#include "colvarbias_alb.h"
|
||||
#include "colvarbias.h"
|
||||
#include "colvarbias_alb.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#if _MSC_VER <= 1700
|
||||
@ -45,22 +43,22 @@ int colvarbias_alb::init(std::string const &conf)
|
||||
size_t i;
|
||||
|
||||
// get the initial restraint centers
|
||||
colvar_centers.resize(colvars.size());
|
||||
colvar_centers.resize(num_variables());
|
||||
|
||||
means.resize(colvars.size());
|
||||
ssd.resize(colvars.size()); //sum of squares of differences from mean
|
||||
means.resize(num_variables());
|
||||
ssd.resize(num_variables()); //sum of squares of differences from mean
|
||||
|
||||
//setup force vectors
|
||||
max_coupling_range.resize(colvars.size());
|
||||
max_coupling_rate.resize(colvars.size());
|
||||
coupling_accum.resize(colvars.size());
|
||||
set_coupling.resize(colvars.size());
|
||||
current_coupling.resize(colvars.size());
|
||||
coupling_rate.resize(colvars.size());
|
||||
max_coupling_range.resize(num_variables());
|
||||
max_coupling_rate.resize(num_variables());
|
||||
coupling_accum.resize(num_variables());
|
||||
set_coupling.resize(num_variables());
|
||||
current_coupling.resize(num_variables());
|
||||
coupling_rate.resize(num_variables());
|
||||
|
||||
enable(f_cvb_apply_force);
|
||||
|
||||
for (i = 0; i < colvars.size(); i++) {
|
||||
for (i = 0; i < num_variables(); i++) {
|
||||
colvar_centers[i].type(colvars[i]->value());
|
||||
//zero moments
|
||||
means[i] = ssd[i] = 0;
|
||||
@ -70,7 +68,7 @@ int colvarbias_alb::init(std::string const &conf)
|
||||
|
||||
}
|
||||
if (get_keyval(conf, "centers", colvar_centers, colvar_centers)) {
|
||||
for (i = 0; i < colvars.size(); i++) {
|
||||
for (i = 0; i < num_variables(); i++) {
|
||||
colvar_centers[i].apply_constraints();
|
||||
}
|
||||
} else {
|
||||
@ -78,7 +76,7 @@ int colvarbias_alb::init(std::string const &conf)
|
||||
cvm::fatal_error("Error: must define the initial centers of adaptive linear bias .\n");
|
||||
}
|
||||
|
||||
if (colvar_centers.size() != colvars.size())
|
||||
if (colvar_centers.size() != num_variables())
|
||||
cvm::fatal_error("Error: number of centers does not match "
|
||||
"that of collective variables.\n");
|
||||
|
||||
@ -100,17 +98,17 @@ int colvarbias_alb::init(std::string const &conf)
|
||||
|
||||
//initial guess
|
||||
if (!get_keyval(conf, "forceConstant", set_coupling, set_coupling))
|
||||
for (i =0 ; i < colvars.size(); i++)
|
||||
for (i =0 ; i < num_variables(); i++)
|
||||
set_coupling[i] = 0.;
|
||||
|
||||
//how we're going to increase to that point
|
||||
for (i = 0; i < colvars.size(); i++)
|
||||
for (i = 0; i < num_variables(); i++)
|
||||
coupling_rate[i] = (set_coupling[i] - current_coupling[i]) / update_freq;
|
||||
|
||||
|
||||
if (!get_keyval(conf, "forceRange", max_coupling_range, max_coupling_range)) {
|
||||
//set to default
|
||||
for (i = 0; i < colvars.size(); i++) {
|
||||
for (i = 0; i < num_variables(); i++) {
|
||||
if (cvm::temperature() > 0)
|
||||
max_coupling_range[i] = 3 * cvm::temperature() * cvm::boltzmann();
|
||||
else
|
||||
@ -120,7 +118,7 @@ int colvarbias_alb::init(std::string const &conf)
|
||||
|
||||
if (!get_keyval(conf, "rateMax", max_coupling_rate, max_coupling_rate)) {
|
||||
//set to default
|
||||
for (i = 0; i < colvars.size(); i++) {
|
||||
for (i = 0; i < num_variables(); i++) {
|
||||
max_coupling_rate[i] = max_coupling_range[i] / (10 * update_freq);
|
||||
}
|
||||
}
|
||||
@ -151,7 +149,7 @@ int colvarbias_alb::update()
|
||||
// Force and energy calculation
|
||||
bool finished_equil_flag = 1;
|
||||
cvm::real delta;
|
||||
for (size_t i = 0; i < colvars.size(); i++) {
|
||||
for (size_t i = 0; i < num_variables(); i++) {
|
||||
colvar_forces[i] = -1.0 * restraint_force(restraint_convert_k(current_coupling[i], colvars[i]->width),
|
||||
colvars[i],
|
||||
colvar_centers[i]);
|
||||
@ -168,7 +166,9 @@ int colvarbias_alb::update()
|
||||
|
||||
} else {
|
||||
//check if we've reached the setpoint
|
||||
if (coupling_rate[i] == 0 || pow(current_coupling[i] - set_coupling[i],2) < pow(coupling_rate[i],2)) {
|
||||
cvm::real const coupling_diff = current_coupling[i] - set_coupling[i];
|
||||
if ((coupling_rate[i] == 0) ||
|
||||
((coupling_diff*coupling_diff) < (coupling_rate[i]*coupling_rate[i]))) {
|
||||
finished_equil_flag &= 1; //we continue equilibrating as long as we haven't reached all the set points
|
||||
}
|
||||
else {
|
||||
@ -209,7 +209,7 @@ int colvarbias_alb::update()
|
||||
cvm::real temp;
|
||||
|
||||
//reset means and sum of squares of differences
|
||||
for (size_t i = 0; i < colvars.size(); i++) {
|
||||
for (size_t i = 0; i < num_variables(); i++) {
|
||||
|
||||
temp = 2. * (means[i] / (static_cast<cvm::real> (colvar_centers[i])) - 1) * ssd[i] / (update_calls - 1);
|
||||
|
||||
@ -222,7 +222,7 @@ int colvarbias_alb::update()
|
||||
ssd[i] = 0;
|
||||
|
||||
//stochastic if we do that update or not
|
||||
if (colvars.size() == 1 || rand() < RAND_MAX / ((int) colvars.size())) {
|
||||
if (num_variables() == 1 || rand() < RAND_MAX / ((int) num_variables())) {
|
||||
coupling_accum[i] += step_size * step_size;
|
||||
current_coupling[i] = set_coupling[i];
|
||||
set_coupling[i] += max_coupling_range[i] / sqrt(coupling_accum[i]) * step_size;
|
||||
@ -284,37 +284,37 @@ std::string const colvarbias_alb::get_state_params() const
|
||||
std::ostringstream os;
|
||||
os << " setCoupling ";
|
||||
size_t i;
|
||||
for (i = 0; i < colvars.size(); i++) {
|
||||
for (i = 0; i < num_variables(); i++) {
|
||||
os << std::setprecision(cvm::en_prec)
|
||||
<< std::setw(cvm::en_width) << set_coupling[i] << "\n";
|
||||
}
|
||||
os << " currentCoupling ";
|
||||
for (i = 0; i < colvars.size(); i++) {
|
||||
for (i = 0; i < num_variables(); i++) {
|
||||
os << std::setprecision(cvm::en_prec)
|
||||
<< std::setw(cvm::en_width) << current_coupling[i] << "\n";
|
||||
}
|
||||
os << " maxCouplingRange ";
|
||||
for (i = 0; i < colvars.size(); i++) {
|
||||
for (i = 0; i < num_variables(); i++) {
|
||||
os << std::setprecision(cvm::en_prec)
|
||||
<< std::setw(cvm::en_width) << max_coupling_range[i] << "\n";
|
||||
}
|
||||
os << " couplingRate ";
|
||||
for (i = 0; i < colvars.size(); i++) {
|
||||
for (i = 0; i < num_variables(); i++) {
|
||||
os << std::setprecision(cvm::en_prec)
|
||||
<< std::setw(cvm::en_width) << coupling_rate[i] << "\n";
|
||||
}
|
||||
os << " couplingAccum ";
|
||||
for (i = 0; i < colvars.size(); i++) {
|
||||
for (i = 0; i < num_variables(); i++) {
|
||||
os << std::setprecision(cvm::en_prec)
|
||||
<< std::setw(cvm::en_width) << coupling_accum[i] << "\n";
|
||||
}
|
||||
os << " mean ";
|
||||
for (i = 0; i < colvars.size(); i++) {
|
||||
for (i = 0; i < num_variables(); i++) {
|
||||
os << std::setprecision(cvm::en_prec)
|
||||
<< std::setw(cvm::en_width) << means[i] << "\n";
|
||||
}
|
||||
os << " ssd ";
|
||||
for (i = 0; i < colvars.size(); i++) {
|
||||
for (i = 0; i < num_variables(); i++) {
|
||||
os << std::setprecision(cvm::en_prec)
|
||||
<< std::setw(cvm::en_width) << ssd[i] << "\n";
|
||||
}
|
||||
@ -350,7 +350,7 @@ std::ostream & colvarbias_alb::write_traj_label(std::ostream &os)
|
||||
}
|
||||
|
||||
if (b_output_centers)
|
||||
for (size_t i = 0; i < colvars.size(); i++) {
|
||||
for (size_t i = 0; i < num_variables(); i++) {
|
||||
size_t const this_cv_width = (colvars[i]->value()).output_width(cvm::cv_width);
|
||||
os << " x0_"
|
||||
<< cvm::wrap_string(colvars[i]->name, this_cv_width-3);
|
||||
@ -378,7 +378,7 @@ std::ostream & colvarbias_alb::write_traj(std::ostream &os)
|
||||
|
||||
|
||||
if (b_output_centers)
|
||||
for (size_t i = 0; i < colvars.size(); i++) {
|
||||
for (size_t i = 0; i < num_variables(); i++) {
|
||||
os << " "
|
||||
<< std::setprecision(cvm::cv_prec) << std::setw(cvm::cv_width)
|
||||
<< colvar_centers[i];
|
||||
|
||||
@ -8,10 +8,10 @@
|
||||
// Colvars repository at GitHub.
|
||||
|
||||
#include "colvarmodule.h"
|
||||
#include "colvarproxy.h"
|
||||
#include "colvar.h"
|
||||
#include "colvarbias_histogram.h"
|
||||
|
||||
/// Histogram "bias" constructor
|
||||
|
||||
colvarbias_histogram::colvarbias_histogram(char const *key)
|
||||
: colvarbias(key),
|
||||
@ -44,7 +44,7 @@ int colvarbias_histogram::init(std::string const &conf)
|
||||
get_keyval(conf, "gatherVectorColvars", colvar_array, colvar_array);
|
||||
|
||||
if (colvar_array) {
|
||||
for (i = 0; i < colvars.size(); i++) { // should be all vector
|
||||
for (i = 0; i < num_variables(); i++) { // should be all vector
|
||||
if (colvars[i]->value().type() != colvarvalue::type_vector) {
|
||||
cvm::error("Error: used gatherVectorColvars with non-vector colvar.\n", INPUT_ERROR);
|
||||
return INPUT_ERROR;
|
||||
@ -63,7 +63,7 @@ int colvarbias_histogram::init(std::string const &conf)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < colvars.size(); i++) { // should be all scalar
|
||||
for (i = 0; i < num_variables(); i++) { // should be all scalar
|
||||
if (colvars[i]->value().type() != colvarvalue::type_scalar) {
|
||||
cvm::error("Error: only scalar colvars are supported when gatherVectorColvars is off.\n", INPUT_ERROR);
|
||||
return INPUT_ERROR;
|
||||
@ -77,7 +77,7 @@ int colvarbias_histogram::init(std::string const &conf)
|
||||
get_keyval(conf, "weights", weights, weights);
|
||||
}
|
||||
|
||||
for (i = 0; i < colvars.size(); i++) {
|
||||
for (i = 0; i < num_variables(); i++) {
|
||||
colvars[i]->enable(f_cv_grid);
|
||||
}
|
||||
|
||||
@ -116,7 +116,7 @@ int colvarbias_histogram::update()
|
||||
}
|
||||
|
||||
// assign a valid bin size
|
||||
bin.assign(colvars.size(), 0);
|
||||
bin.assign(num_variables(), 0);
|
||||
|
||||
if (out_name.size() == 0) {
|
||||
// At the first timestep, we need to assign out_name since
|
||||
@ -137,7 +137,7 @@ int colvarbias_histogram::update()
|
||||
if (colvar_array_size == 0) {
|
||||
// update indices for scalar values
|
||||
size_t i;
|
||||
for (i = 0; i < colvars.size(); i++) {
|
||||
for (i = 0; i < num_variables(); i++) {
|
||||
bin[i] = grid->current_bin_scalar(i);
|
||||
}
|
||||
|
||||
@ -148,7 +148,7 @@ int colvarbias_histogram::update()
|
||||
// update indices for vector/array values
|
||||
size_t iv, i;
|
||||
for (iv = 0; iv < colvar_array_size; iv++) {
|
||||
for (i = 0; i < colvars.size(); i++) {
|
||||
for (i = 0; i < num_variables(); i++) {
|
||||
bin[i] = grid->current_bin_scalar(i, iv);
|
||||
}
|
||||
|
||||
|
||||
@ -27,7 +27,8 @@
|
||||
#define PATHSEP "/"
|
||||
#endif
|
||||
|
||||
|
||||
#include "colvarmodule.h"
|
||||
#include "colvarproxy.h"
|
||||
#include "colvar.h"
|
||||
#include "colvarbias_meta.h"
|
||||
|
||||
|
||||
@ -7,7 +7,10 @@
|
||||
// If you wish to distribute your changes, please submit them to the
|
||||
// Colvars repository at GitHub.
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include "colvarmodule.h"
|
||||
#include "colvarproxy.h"
|
||||
#include "colvarvalue.h"
|
||||
#include "colvarbias_restraint.h"
|
||||
|
||||
@ -150,13 +153,14 @@ colvarbias_restraint_k::colvarbias_restraint_k(char const *key)
|
||||
: colvarbias(key), colvarbias_ti(key), colvarbias_restraint(key)
|
||||
{
|
||||
force_k = -1.0;
|
||||
check_positive_k = true;
|
||||
}
|
||||
|
||||
|
||||
int colvarbias_restraint_k::init(std::string const &conf)
|
||||
{
|
||||
get_keyval(conf, "forceConstant", force_k, (force_k > 0.0 ? force_k : 1.0));
|
||||
if (force_k < 0.0) {
|
||||
if (check_positive_k && (force_k < 0.0)) {
|
||||
cvm::error("Error: undefined or invalid force constant.\n", INPUT_ERROR);
|
||||
return INPUT_ERROR;
|
||||
}
|
||||
@ -177,6 +181,7 @@ colvarbias_restraint_moving::colvarbias_restraint_moving(char const *key)
|
||||
target_nstages = 0;
|
||||
target_nsteps = 0;
|
||||
stage = 0;
|
||||
acc_work = 0.0;
|
||||
b_chg_centers = false;
|
||||
b_chg_force_k = false;
|
||||
}
|
||||
@ -203,6 +208,14 @@ int colvarbias_restraint_moving::init(std::string const &conf)
|
||||
cvm::error("Error: targetNumStages and lambdaSchedule are incompatible.\n", INPUT_ERROR);
|
||||
return cvm::get_error();
|
||||
}
|
||||
|
||||
get_keyval_feature(this, conf, "outputAccumulatedWork",
|
||||
f_cvb_output_acc_work,
|
||||
is_enabled(f_cvb_output_acc_work));
|
||||
if (is_enabled(f_cvb_output_acc_work) && (target_nstages > 0)) {
|
||||
return cvm::error("Error: outputAccumulatedWork and targetNumStages "
|
||||
"are incompatible.\n", INPUT_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
return COLVARS_OK;
|
||||
@ -246,8 +259,6 @@ colvarbias_restraint_centers_moving::colvarbias_restraint_centers_moving(char co
|
||||
{
|
||||
b_chg_centers = false;
|
||||
b_output_centers = false;
|
||||
b_output_acc_work = false;
|
||||
acc_work = 0.0;
|
||||
}
|
||||
|
||||
|
||||
@ -288,9 +299,6 @@ int colvarbias_restraint_centers_moving::init(std::string const &conf)
|
||||
0.5);
|
||||
}
|
||||
|
||||
get_keyval(conf, "outputAccumulatedWork", b_output_acc_work,
|
||||
b_output_acc_work); // TODO this conflicts with stages
|
||||
|
||||
} else {
|
||||
target_centers.clear();
|
||||
}
|
||||
@ -382,12 +390,14 @@ int colvarbias_restraint_centers_moving::update()
|
||||
|
||||
int colvarbias_restraint_centers_moving::update_acc_work()
|
||||
{
|
||||
if (b_output_acc_work) {
|
||||
if ((cvm::step_relative() > 0) &&
|
||||
(cvm::step_absolute() <= target_nsteps)) {
|
||||
for (size_t i = 0; i < num_variables(); i++) {
|
||||
// project forces on the calculated increments at this step
|
||||
acc_work += colvar_forces[i] * centers_incr[i];
|
||||
if (b_chg_centers) {
|
||||
if (is_enabled(f_cvb_output_acc_work)) {
|
||||
if ((cvm::step_relative() > 0) &&
|
||||
(cvm::step_absolute() <= target_nsteps)) {
|
||||
for (size_t i = 0; i < num_variables(); i++) {
|
||||
// project forces on the calculated increments at this step
|
||||
acc_work += colvar_forces[i] * centers_incr[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -410,7 +420,7 @@ std::string const colvarbias_restraint_centers_moving::get_state_params() const
|
||||
}
|
||||
os << "\n";
|
||||
|
||||
if (b_output_acc_work) {
|
||||
if (is_enabled(f_cvb_output_acc_work)) {
|
||||
os << "accumulatedWork "
|
||||
<< std::setprecision(cvm::en_prec) << std::setw(cvm::en_width)
|
||||
<< acc_work << "\n";
|
||||
@ -429,7 +439,7 @@ int colvarbias_restraint_centers_moving::set_state_params(std::string const &con
|
||||
// cvm::log ("Reading the updated restraint centers from the restart.\n");
|
||||
if (!get_keyval(conf, "centers", colvar_centers))
|
||||
cvm::error("Error: restraint centers are missing from the restart.\n");
|
||||
if (b_output_acc_work) {
|
||||
if (is_enabled(f_cvb_output_acc_work)) {
|
||||
if (!get_keyval(conf, "accumulatedWork", acc_work))
|
||||
cvm::error("Error: accumulatedWork is missing from the restart.\n");
|
||||
}
|
||||
@ -449,7 +459,7 @@ std::ostream & colvarbias_restraint_centers_moving::write_traj_label(std::ostrea
|
||||
}
|
||||
}
|
||||
|
||||
if (b_output_acc_work) {
|
||||
if (b_chg_centers && is_enabled(f_cvb_output_acc_work)) {
|
||||
os << " W_"
|
||||
<< cvm::wrap_string(this->name, cvm::en_width-2);
|
||||
}
|
||||
@ -468,7 +478,7 @@ std::ostream & colvarbias_restraint_centers_moving::write_traj(std::ostream &os)
|
||||
}
|
||||
}
|
||||
|
||||
if (b_output_acc_work) {
|
||||
if (b_chg_centers && is_enabled(f_cvb_output_acc_work)) {
|
||||
os << " "
|
||||
<< std::setprecision(cvm::en_prec) << std::setw(cvm::en_width)
|
||||
<< acc_work;
|
||||
@ -488,10 +498,11 @@ colvarbias_restraint_k_moving::colvarbias_restraint_k_moving(char const *key)
|
||||
{
|
||||
b_chg_force_k = false;
|
||||
target_equil_steps = 0;
|
||||
target_force_k = 0.0;
|
||||
starting_force_k = 0.0;
|
||||
target_force_k = -1.0;
|
||||
starting_force_k = -1.0;
|
||||
force_k_exp = 1.0;
|
||||
restraint_FE = 0.0;
|
||||
force_k_incr = 0.0;
|
||||
}
|
||||
|
||||
|
||||
@ -569,14 +580,13 @@ int colvarbias_restraint_k_moving::update()
|
||||
if (target_equil_steps == 0 || cvm::step_absolute() % target_nsteps >= target_equil_steps) {
|
||||
// Start averaging after equilibration period, if requested
|
||||
|
||||
// Square distance normalized by square colvar width
|
||||
cvm::real dist_sq = 0.0;
|
||||
// Derivative of energy with respect to force_k
|
||||
cvm::real dU_dk = 0.0;
|
||||
for (size_t i = 0; i < num_variables(); i++) {
|
||||
dist_sq += d_restraint_potential_dk(i);
|
||||
dU_dk += d_restraint_potential_dk(i);
|
||||
}
|
||||
|
||||
restraint_FE += 0.5 * force_k_exp * std::pow(lambda, force_k_exp - 1.0)
|
||||
* (target_force_k - starting_force_k) * dist_sq;
|
||||
restraint_FE += force_k_exp * std::pow(lambda, force_k_exp - 1.0)
|
||||
* (target_force_k - starting_force_k) * dU_dk;
|
||||
}
|
||||
|
||||
// Finish current stage...
|
||||
@ -607,10 +617,13 @@ int colvarbias_restraint_k_moving::update()
|
||||
|
||||
} else if (cvm::step_absolute() <= target_nsteps) {
|
||||
|
||||
|
||||
// update force constant (slow growth)
|
||||
lambda = cvm::real(cvm::step_absolute()) / cvm::real(target_nsteps);
|
||||
cvm::real const force_k_old = force_k;
|
||||
force_k = starting_force_k + (target_force_k - starting_force_k)
|
||||
* std::pow(lambda, force_k_exp);
|
||||
force_k_incr = force_k - force_k_old;
|
||||
}
|
||||
}
|
||||
|
||||
@ -618,6 +631,23 @@ int colvarbias_restraint_k_moving::update()
|
||||
}
|
||||
|
||||
|
||||
int colvarbias_restraint_k_moving::update_acc_work()
|
||||
{
|
||||
if (b_chg_force_k) {
|
||||
if (is_enabled(f_cvb_output_acc_work)) {
|
||||
if (cvm::step_relative() > 0) {
|
||||
cvm::real dU_dk = 0.0;
|
||||
for (size_t i = 0; i < num_variables(); i++) {
|
||||
dU_dk += d_restraint_potential_dk(i);
|
||||
}
|
||||
acc_work += dU_dk * force_k_incr;
|
||||
}
|
||||
}
|
||||
}
|
||||
return COLVARS_OK;
|
||||
}
|
||||
|
||||
|
||||
std::string const colvarbias_restraint_k_moving::get_state_params() const
|
||||
{
|
||||
std::ostringstream os;
|
||||
@ -626,6 +656,12 @@ std::string const colvarbias_restraint_k_moving::get_state_params() const
|
||||
os << "forceConstant "
|
||||
<< std::setprecision(cvm::en_prec)
|
||||
<< std::setw(cvm::en_width) << force_k << "\n";
|
||||
|
||||
if (is_enabled(f_cvb_output_acc_work)) {
|
||||
os << "accumulatedWork "
|
||||
<< std::setprecision(cvm::en_prec) << std::setw(cvm::en_width)
|
||||
<< acc_work << "\n";
|
||||
}
|
||||
}
|
||||
return os.str();
|
||||
}
|
||||
@ -639,6 +675,10 @@ int colvarbias_restraint_k_moving::set_state_params(std::string const &conf)
|
||||
// cvm::log ("Reading the updated force constant from the restart.\n");
|
||||
if (!get_keyval(conf, "forceConstant", force_k, force_k))
|
||||
cvm::error("Error: force constant is missing from the restart.\n");
|
||||
if (is_enabled(f_cvb_output_acc_work)) {
|
||||
if (!get_keyval(conf, "accumulatedWork", acc_work))
|
||||
cvm::error("Error: accumulatedWork is missing from the restart.\n");
|
||||
}
|
||||
}
|
||||
|
||||
return COLVARS_OK;
|
||||
@ -647,12 +687,21 @@ int colvarbias_restraint_k_moving::set_state_params(std::string const &conf)
|
||||
|
||||
std::ostream & colvarbias_restraint_k_moving::write_traj_label(std::ostream &os)
|
||||
{
|
||||
if (b_chg_force_k && is_enabled(f_cvb_output_acc_work)) {
|
||||
os << " W_"
|
||||
<< cvm::wrap_string(this->name, cvm::en_width-2);
|
||||
}
|
||||
return os;
|
||||
}
|
||||
|
||||
|
||||
std::ostream & colvarbias_restraint_k_moving::write_traj(std::ostream &os)
|
||||
{
|
||||
if (b_chg_force_k && is_enabled(f_cvb_output_acc_work)) {
|
||||
os << " "
|
||||
<< std::setprecision(cvm::en_prec) << std::setw(cvm::en_width)
|
||||
<< acc_work;
|
||||
}
|
||||
return os;
|
||||
}
|
||||
|
||||
@ -765,6 +814,7 @@ int colvarbias_restraint_harmonic::update()
|
||||
|
||||
// update accumulated work using the current forces
|
||||
error_code |= colvarbias_restraint_centers_moving::update_acc_work();
|
||||
error_code |= colvarbias_restraint_k_moving::update_acc_work();
|
||||
|
||||
return error_code;
|
||||
}
|
||||
@ -876,8 +926,8 @@ colvarbias_restraint_harmonic_walls::colvarbias_restraint_harmonic_walls(char co
|
||||
colvarbias_restraint_moving(key),
|
||||
colvarbias_restraint_k_moving(key)
|
||||
{
|
||||
lower_wall_k = 0.0;
|
||||
upper_wall_k = 0.0;
|
||||
lower_wall_k = -1.0;
|
||||
upper_wall_k = -1.0;
|
||||
}
|
||||
|
||||
|
||||
@ -887,26 +937,6 @@ int colvarbias_restraint_harmonic_walls::init(std::string const &conf)
|
||||
colvarbias_restraint_moving::init(conf);
|
||||
colvarbias_restraint_k_moving::init(conf);
|
||||
|
||||
get_keyval(conf, "lowerWallConstant", lower_wall_k,
|
||||
(lower_wall_k > 0.0) ? lower_wall_k : force_k);
|
||||
get_keyval(conf, "upperWallConstant", upper_wall_k,
|
||||
(upper_wall_k > 0.0) ? upper_wall_k : force_k);
|
||||
|
||||
if (lower_wall_k * upper_wall_k > 0.0) {
|
||||
for (size_t i = 0; i < num_variables(); i++) {
|
||||
if (variables(i)->width != 1.0)
|
||||
cvm::log("The lower and upper wall force constants for colvar \""+
|
||||
variables(i)->name+
|
||||
"\" will be rescaled to "+
|
||||
cvm::to_str(lower_wall_k /
|
||||
(variables(i)->width * variables(i)->width))+
|
||||
" and "+
|
||||
cvm::to_str(upper_wall_k /
|
||||
(variables(i)->width * variables(i)->width))+
|
||||
" according to the specified width.\n");
|
||||
}
|
||||
}
|
||||
|
||||
enable(f_cvb_scalar_variables);
|
||||
|
||||
size_t i;
|
||||
@ -942,16 +972,23 @@ int colvarbias_restraint_harmonic_walls::init(std::string const &conf)
|
||||
}
|
||||
|
||||
if ((lower_walls.size() == 0) && (upper_walls.size() == 0)) {
|
||||
cvm::error("Error: no walls provided.\n", INPUT_ERROR);
|
||||
return INPUT_ERROR;
|
||||
return cvm::error("Error: no walls provided.\n", INPUT_ERROR);
|
||||
}
|
||||
|
||||
if (lower_walls.size() > 0) {
|
||||
get_keyval(conf, "lowerWallConstant", lower_wall_k,
|
||||
(lower_wall_k > 0.0) ? lower_wall_k : force_k);
|
||||
}
|
||||
if (upper_walls.size() > 0) {
|
||||
get_keyval(conf, "upperWallConstant", upper_wall_k,
|
||||
(upper_wall_k > 0.0) ? upper_wall_k : force_k);
|
||||
}
|
||||
|
||||
if ((lower_walls.size() == 0) || (upper_walls.size() == 0)) {
|
||||
for (i = 0; i < num_variables(); i++) {
|
||||
if (variables(i)->is_enabled(f_cv_periodic)) {
|
||||
cvm::error("Error: at least one variable is periodic, "
|
||||
"both walls must be provided.\n", INPUT_ERROR);
|
||||
return INPUT_ERROR;
|
||||
return cvm::error("Error: at least one variable is periodic, "
|
||||
"both walls must be provided.\n", INPUT_ERROR);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -972,19 +1009,49 @@ int colvarbias_restraint_harmonic_walls::init(std::string const &conf)
|
||||
INPUT_ERROR);
|
||||
return INPUT_ERROR;
|
||||
}
|
||||
force_k = lower_wall_k * upper_wall_k;
|
||||
// transform the two constants to relative values
|
||||
force_k = std::sqrt(lower_wall_k * upper_wall_k);
|
||||
// transform the two constants to relative values using gemetric mean as ref
|
||||
// to preserve force_k if provided as single parameter
|
||||
// (allow changing both via force_k)
|
||||
lower_wall_k /= force_k;
|
||||
upper_wall_k /= force_k;
|
||||
} else {
|
||||
// If only one wall is defined, need to rescale as well
|
||||
if (lower_walls.size() > 0) {
|
||||
force_k = lower_wall_k;
|
||||
lower_wall_k = 1.0;
|
||||
}
|
||||
if (upper_walls.size() > 0) {
|
||||
force_k = upper_wall_k;
|
||||
upper_wall_k = 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < num_variables(); i++) {
|
||||
if (variables(i)->width != 1.0)
|
||||
cvm::log("The force constant for colvar \""+variables(i)->name+
|
||||
"\" will be rescaled to "+
|
||||
cvm::to_str(force_k / (variables(i)->width * variables(i)->width))+
|
||||
" according to the specified width.\n");
|
||||
// Initialize starting value of the force constant (in case it's changing)
|
||||
starting_force_k = force_k;
|
||||
|
||||
if (lower_walls.size() > 0) {
|
||||
for (i = 0; i < num_variables(); i++) {
|
||||
if (variables(i)->width != 1.0)
|
||||
cvm::log("The lower wall force constant for colvar \""+
|
||||
variables(i)->name+
|
||||
"\" will be rescaled to "+
|
||||
cvm::to_str(lower_wall_k * force_k /
|
||||
(variables(i)->width * variables(i)->width))+
|
||||
" according to the specified width.\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (upper_walls.size() > 0) {
|
||||
for (i = 0; i < num_variables(); i++) {
|
||||
if (variables(i)->width != 1.0)
|
||||
cvm::log("The upper wall force constant for colvar \""+
|
||||
variables(i)->name+
|
||||
"\" will be rescaled to "+
|
||||
cvm::to_str(upper_wall_k * force_k /
|
||||
(variables(i)->width * variables(i)->width))+
|
||||
" according to the specified width.\n");
|
||||
}
|
||||
}
|
||||
|
||||
return COLVARS_OK;
|
||||
@ -1001,6 +1068,8 @@ int colvarbias_restraint_harmonic_walls::update()
|
||||
|
||||
error_code |= colvarbias_restraint::update();
|
||||
|
||||
error_code |= colvarbias_restraint_k_moving::update_acc_work();
|
||||
|
||||
return error_code;
|
||||
}
|
||||
|
||||
@ -1134,6 +1203,7 @@ colvarbias_restraint_linear::colvarbias_restraint_linear(char const *key)
|
||||
colvarbias_restraint_centers_moving(key),
|
||||
colvarbias_restraint_k_moving(key)
|
||||
{
|
||||
check_positive_k = false;
|
||||
}
|
||||
|
||||
|
||||
@ -1177,6 +1247,7 @@ int colvarbias_restraint_linear::update()
|
||||
|
||||
// update accumulated work using the current forces
|
||||
error_code |= colvarbias_restraint_centers_moving::update_acc_work();
|
||||
error_code |= colvarbias_restraint_k_moving::update_acc_work();
|
||||
|
||||
return error_code;
|
||||
}
|
||||
|
||||
@ -89,8 +89,12 @@ public:
|
||||
virtual int change_configuration(std::string const &conf);
|
||||
|
||||
protected:
|
||||
|
||||
/// \brief Restraint force constant
|
||||
cvm::real force_k;
|
||||
|
||||
/// \brief Whether the force constant should be positive
|
||||
bool check_positive_k;
|
||||
};
|
||||
|
||||
|
||||
@ -129,6 +133,9 @@ protected:
|
||||
/// \brief Number of steps required to reach the target force constant
|
||||
/// or restraint centers
|
||||
long target_nsteps;
|
||||
|
||||
/// \brief Accumulated work (computed when outputAccumulatedWork == true)
|
||||
cvm::real acc_work;
|
||||
};
|
||||
|
||||
|
||||
@ -157,8 +164,7 @@ protected:
|
||||
/// \brief Initial value of the restraint centers
|
||||
std::vector<colvarvalue> initial_centers;
|
||||
|
||||
/// \brief Amplitude of the restraint centers' increment at each step
|
||||
/// towards the new values (calculated from target_nsteps)
|
||||
/// \brief Increment of the restraint centers at each step
|
||||
std::vector<colvarvalue> centers_incr;
|
||||
|
||||
/// \brief Update the centers by interpolating between initial and target
|
||||
@ -167,12 +173,6 @@ protected:
|
||||
/// Whether to write the current restraint centers to the trajectory file
|
||||
bool b_output_centers;
|
||||
|
||||
/// Whether to write the current accumulated work to the trajectory file
|
||||
bool b_output_acc_work;
|
||||
|
||||
/// \brief Accumulated work
|
||||
cvm::real acc_work;
|
||||
|
||||
/// Update the accumulated work
|
||||
int update_acc_work();
|
||||
};
|
||||
@ -212,6 +212,12 @@ protected:
|
||||
|
||||
/// \brief Equilibration steps for restraint FE calculation through TI
|
||||
cvm::real target_equil_steps;
|
||||
|
||||
/// \brief Increment of the force constant at each step
|
||||
cvm::real force_k_incr;
|
||||
|
||||
/// Update the accumulated work
|
||||
int update_acc_work();
|
||||
};
|
||||
|
||||
|
||||
|
||||
@ -20,52 +20,48 @@
|
||||
// simple_scalar_dist_functions (derived_class)
|
||||
|
||||
|
||||
#include <fstream>
|
||||
#include <cmath>
|
||||
|
||||
|
||||
#include "colvarmodule.h"
|
||||
#include "colvar.h"
|
||||
#include "colvaratoms.h"
|
||||
|
||||
|
||||
/// \brief Colvar component (base class); most implementations of
|
||||
/// \link cvc \endlink utilize one or more \link
|
||||
/// colvarmodule::atom \endlink or \link colvarmodule::atom_group
|
||||
/// \endlink objects to access atoms.
|
||||
/// \brief Colvar component (base class for collective variables)
|
||||
///
|
||||
/// A \link cvc \endlink object (or an object of a
|
||||
/// cvc-derived class) specifies how to calculate a collective
|
||||
/// variable, its gradients and other related physical quantities
|
||||
/// which do not depend only on the numeric value (the \link colvar
|
||||
/// \endlink class already serves this purpose).
|
||||
/// cvc-derived class) implements the calculation of a collective
|
||||
/// variable, its gradients and any other related physical quantities
|
||||
/// that depend on microscopic degrees of freedom.
|
||||
///
|
||||
/// No restriction is set to what kind of calculation a \link
|
||||
/// cvc \endlink object performs (usually calculate an
|
||||
/// analytical function of atomic coordinates). The only constraint
|
||||
/// is that the value calculated is implemented as a \link colvarvalue
|
||||
/// \endlink object. This serves to provide a unique way to calculate
|
||||
/// scalar and non-scalar collective variables, and specify if and how
|
||||
/// they can be combined together by the parent \link colvar \endlink
|
||||
/// object.
|
||||
/// No restriction is set to what kind of calculation a \link cvc \endlink
|
||||
/// object performs (usually an analytical function of atomic coordinates).
|
||||
/// The only constraints are that: \par
|
||||
///
|
||||
/// - The value is calculated by the \link calc_value() \endlink
|
||||
/// method, and is an object of \link colvarvalue \endlink class. This
|
||||
/// provides a transparent way to treat scalar and non-scalar variables
|
||||
/// alike, and allows an automatic selection of the applicable algorithms.
|
||||
///
|
||||
/// - The object provides an implementation \link apply_force() \endlink to
|
||||
/// apply forces to atoms. Typically, one or more \link cvm::atom_group
|
||||
/// \endlink objects are used, but this is not a requirement for as long as
|
||||
/// the \link cvc \endlink object communicates with the simulation program.
|
||||
///
|
||||
/// <b> If you wish to implement a new collective variable component, you
|
||||
/// should write your own class by inheriting directly from \link
|
||||
/// cvc \endlink, or one of its derived classes (for instance,
|
||||
/// \link distance \endlink is frequently used, because it provides
|
||||
/// colvar::cvc \endlink, or one of its derived classes (for instance,
|
||||
/// \link colvar::distance \endlink is frequently used, because it provides
|
||||
/// useful data and function members for any colvar based on two
|
||||
/// atom groups). The steps are: \par
|
||||
/// 1. add the name of this class under colvar.h \par
|
||||
/// 2. add a call to the parser in colvar.C, within the function colvar::colvar() \par
|
||||
/// 3. declare the class in colvarcomp.h \par
|
||||
/// 4. implement the class in one of the files colvarcomp_*.C
|
||||
/// atom groups).</b>
|
||||
///
|
||||
/// The steps are: \par
|
||||
/// 1. Declare the new class as a derivative of \link colvar::cvc \endlink
|
||||
/// in the file \link colvarcomp.h \endlink
|
||||
/// 2. Implement the new class in a file named colvarcomp_<something>.cpp
|
||||
/// 3. Declare the name of the new class inside the \link colvar \endlink class
|
||||
/// in \link colvar.h \endlink (see "list of available components")
|
||||
/// 4. Add a call for the new class in colvar::init_components()
|
||||
//// (file: colvar.cpp)
|
||||
///
|
||||
/// </b>
|
||||
/// The cvm::atom and cvm::atom_group classes are available to
|
||||
/// transparently communicate with the simulation program. However,
|
||||
/// they are not strictly needed, as long as all the degrees of
|
||||
/// freedom associated to the cvc are properly evolved by a simple
|
||||
/// call to e.g. apply_force().
|
||||
|
||||
class colvar::cvc
|
||||
: public colvarparse, public colvardeps
|
||||
@ -155,7 +151,7 @@ public:
|
||||
|
||||
/// \brief Calculate the atomic gradients, to be reused later in
|
||||
/// order to apply forces
|
||||
virtual void calc_gradients() = 0;
|
||||
virtual void calc_gradients() {}
|
||||
|
||||
/// \brief Calculate the atomic fit gradients
|
||||
void calc_fit_gradients();
|
||||
|
||||
@ -581,6 +581,12 @@ colvar::distance_inv::distance_inv(std::string const &conf)
|
||||
}
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
x.type(colvarvalue::type_scalar);
|
||||
}
|
||||
|
||||
@ -601,11 +607,9 @@ void colvar::distance_inv::calc_value()
|
||||
for (cvm::atom_iter ai2 = group2->begin(); ai2 != group2->end(); ai2++) {
|
||||
cvm::rvector const dv = ai2->pos - ai1->pos;
|
||||
cvm::real const d2 = dv.norm2();
|
||||
cvm::real dinv = 1.0;
|
||||
for (int ne = 0; ne < exponent/2; ne++)
|
||||
dinv *= 1.0/d2;
|
||||
cvm::real const dinv = cvm::integer_power(d2, -1*(exponent/2));
|
||||
x.real_value += dinv;
|
||||
cvm::rvector const dsumddv = -(cvm::real(exponent)) * dinv/d2 * dv;
|
||||
cvm::rvector const dsumddv = -1.0*(exponent/2) * dinv/d2 * 2.0 * dv;
|
||||
ai1->grad += -1.0 * dsumddv;
|
||||
ai2->grad += dsumddv;
|
||||
}
|
||||
@ -615,11 +619,9 @@ void colvar::distance_inv::calc_value()
|
||||
for (cvm::atom_iter ai2 = group2->begin(); ai2 != group2->end(); ai2++) {
|
||||
cvm::rvector const dv = cvm::position_distance(ai1->pos, ai2->pos);
|
||||
cvm::real const d2 = dv.norm2();
|
||||
cvm::real dinv = 1.0;
|
||||
for (int ne = 0; ne < exponent/2; ne++)
|
||||
dinv *= 1.0/d2;
|
||||
cvm::real const dinv = cvm::integer_power(d2, -1*(exponent/2));
|
||||
x.real_value += dinv;
|
||||
cvm::rvector const dsumddv = -(cvm::real(exponent)) * dinv/d2 * dv;
|
||||
cvm::rvector const dsumddv = -1.0*(exponent/2) * dinv/d2 * 2.0 * dv;
|
||||
ai1->grad += -1.0 * dsumddv;
|
||||
ai2->grad += dsumddv;
|
||||
}
|
||||
@ -627,13 +629,11 @@ void colvar::distance_inv::calc_value()
|
||||
}
|
||||
|
||||
x.real_value *= 1.0 / cvm::real(group1->size() * group2->size());
|
||||
x.real_value = std::pow(x.real_value, -1.0/(cvm::real(exponent)));
|
||||
}
|
||||
x.real_value = std::pow(x.real_value, -1.0/cvm::real(exponent));
|
||||
|
||||
|
||||
void colvar::distance_inv::calc_gradients()
|
||||
{
|
||||
cvm::real const dxdsum = (-1.0/(cvm::real(exponent))) * std::pow(x.real_value, exponent+1) / cvm::real(group1->size() * group2->size());
|
||||
cvm::real const dxdsum = (-1.0/(cvm::real(exponent))) *
|
||||
cvm::integer_power(x.real_value, exponent+1) /
|
||||
cvm::real(group1->size() * group2->size());
|
||||
for (cvm::atom_iter ai1 = group1->begin(); ai1 != group1->end(); ai1++) {
|
||||
ai1->grad *= dxdsum;
|
||||
}
|
||||
@ -643,6 +643,11 @@ void colvar::distance_inv::calc_gradients()
|
||||
}
|
||||
|
||||
|
||||
void colvar::distance_inv::calc_gradients()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void colvar::distance_inv::apply_force(colvarvalue const &force)
|
||||
{
|
||||
if (!group1->noforce)
|
||||
|
||||
@ -8,10 +8,16 @@
|
||||
// Colvars repository at GitHub.
|
||||
|
||||
|
||||
#include "colvarmodule.h"
|
||||
#include "colvarproxy.h"
|
||||
#include "colvardeps.h"
|
||||
|
||||
|
||||
colvardeps::colvardeps()
|
||||
: time_step_factor (1) {}
|
||||
{
|
||||
time_step_factor = 1;
|
||||
}
|
||||
|
||||
|
||||
colvardeps::~colvardeps() {
|
||||
size_t i;
|
||||
@ -416,6 +422,9 @@ void colvardeps::init_cvb_requires() {
|
||||
init_feature(f_cvb_get_total_force, "obtain total force", f_type_dynamic);
|
||||
f_req_children(f_cvb_get_total_force, f_cv_total_force);
|
||||
|
||||
init_feature(f_cvb_output_acc_work, "output accumulated work", f_type_user);
|
||||
f_req_self(f_cvb_output_acc_work, f_cvb_apply_force);
|
||||
|
||||
init_feature(f_cvb_history_dependent, "history-dependent", f_type_static);
|
||||
|
||||
init_feature(f_cvb_time_dependent, "time-dependent", f_type_static);
|
||||
|
||||
@ -225,6 +225,8 @@ public:
|
||||
f_cvb_apply_force,
|
||||
/// \brief requires total forces
|
||||
f_cvb_get_total_force,
|
||||
/// \brief whether this bias should record the accumulated work
|
||||
f_cvb_output_acc_work,
|
||||
/// \brief depends on simulation history
|
||||
f_cvb_history_dependent,
|
||||
/// \brief depends on time
|
||||
|
||||
@ -14,6 +14,7 @@
|
||||
#include "colvarcomp.h"
|
||||
#include "colvargrid.h"
|
||||
|
||||
#include <ctime>
|
||||
|
||||
colvar_grid_count::colvar_grid_count()
|
||||
: colvar_grid<size_t>()
|
||||
@ -22,43 +23,37 @@ colvar_grid_count::colvar_grid_count()
|
||||
}
|
||||
|
||||
colvar_grid_count::colvar_grid_count(std::vector<int> const &nx_i,
|
||||
size_t const &def_count)
|
||||
size_t const &def_count)
|
||||
: colvar_grid<size_t>(nx_i, def_count, 1)
|
||||
{}
|
||||
|
||||
colvar_grid_count::colvar_grid_count(std::vector<colvar *> &colvars,
|
||||
size_t const &def_count)
|
||||
: colvar_grid<size_t>(colvars, def_count, 1)
|
||||
size_t const &def_count,
|
||||
bool margin)
|
||||
: colvar_grid<size_t>(colvars, def_count, 1, margin)
|
||||
{}
|
||||
|
||||
colvar_grid_scalar::colvar_grid_scalar()
|
||||
: colvar_grid<cvm::real>(), samples(NULL), grad(NULL)
|
||||
: colvar_grid<cvm::real>(), samples(NULL)
|
||||
{}
|
||||
|
||||
colvar_grid_scalar::colvar_grid_scalar(colvar_grid_scalar const &g)
|
||||
: colvar_grid<cvm::real>(g), samples(NULL), grad(NULL)
|
||||
: colvar_grid<cvm::real>(g), samples(NULL)
|
||||
{
|
||||
grad = new cvm::real[nd];
|
||||
}
|
||||
|
||||
colvar_grid_scalar::colvar_grid_scalar(std::vector<int> const &nx_i)
|
||||
: colvar_grid<cvm::real>(nx_i, 0.0, 1), samples(NULL), grad(NULL)
|
||||
: colvar_grid<cvm::real>(nx_i, 0.0, 1), samples(NULL)
|
||||
{
|
||||
grad = new cvm::real[nd];
|
||||
}
|
||||
|
||||
colvar_grid_scalar::colvar_grid_scalar(std::vector<colvar *> &colvars, bool margin)
|
||||
: colvar_grid<cvm::real>(colvars, 0.0, 1, margin), samples(NULL), grad(NULL)
|
||||
: colvar_grid<cvm::real>(colvars, 0.0, 1, margin), samples(NULL)
|
||||
{
|
||||
grad = new cvm::real[nd];
|
||||
}
|
||||
|
||||
colvar_grid_scalar::~colvar_grid_scalar()
|
||||
{
|
||||
if (grad) {
|
||||
delete [] grad;
|
||||
grad = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
cvm::real colvar_grid_scalar::maximum_value() const
|
||||
@ -143,18 +138,18 @@ void colvar_grid_gradient::write_1D_integral(std::ostream &os)
|
||||
|
||||
os << "# xi A(xi)\n";
|
||||
|
||||
if ( cv.size() != 1 ) {
|
||||
if (cv.size() != 1) {
|
||||
cvm::error("Cannot write integral for multi-dimensional gradient grids.");
|
||||
return;
|
||||
}
|
||||
|
||||
integral = 0.0;
|
||||
int_vals.push_back( 0.0 );
|
||||
int_vals.push_back(0.0);
|
||||
min = 0.0;
|
||||
|
||||
// correction for periodic colvars, so that the PMF is periodic
|
||||
cvm::real corr;
|
||||
if ( periodic[0] ) {
|
||||
if (periodic[0]) {
|
||||
corr = average();
|
||||
} else {
|
||||
corr = 0.0;
|
||||
@ -171,7 +166,7 @@ void colvar_grid_gradient::write_1D_integral(std::ostream &os)
|
||||
}
|
||||
|
||||
if ( integral < min ) min = integral;
|
||||
int_vals.push_back( integral );
|
||||
int_vals.push_back(integral);
|
||||
}
|
||||
|
||||
bin = 0.0;
|
||||
@ -192,3 +187,670 @@ void colvar_grid_gradient::write_1D_integral(std::ostream &os)
|
||||
|
||||
|
||||
|
||||
integrate_potential::integrate_potential(std::vector<colvar *> &colvars, colvar_grid_gradient * gradients)
|
||||
: colvar_grid_scalar(colvars, true),
|
||||
gradients(gradients)
|
||||
{
|
||||
// parent class colvar_grid_scalar is constructed with margin option set to true
|
||||
// hence PMF grid is wider than gradient grid if non-PBC
|
||||
|
||||
if (nd > 1) {
|
||||
divergence.resize(nt);
|
||||
|
||||
// Compute inverse of Laplacian diagonal for Jacobi preconditioning
|
||||
// For now all code related to preconditioning is commented out
|
||||
// until a method better than Jacobi is implemented
|
||||
// cvm::log("Preparing inverse diagonal for preconditioning...");
|
||||
// inv_lap_diag.resize(nt);
|
||||
// std::vector<cvm::real> id(nt), lap_col(nt);
|
||||
// for (int i = 0; i < nt; i++) {
|
||||
// if (i % (nt / 100) == 0)
|
||||
// cvm::log(cvm::to_str(i));
|
||||
// id[i] = 1.;
|
||||
// atimes(id, lap_col);
|
||||
// id[i] = 0.;
|
||||
// inv_lap_diag[i] = 1. / lap_col[i];
|
||||
// }
|
||||
// cvm::log("Done.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int integrate_potential::integrate(const int itmax, const cvm::real &tol, cvm::real & err)
|
||||
{
|
||||
int iter = 0;
|
||||
|
||||
if (nd == 1) {
|
||||
|
||||
cvm::real sum = 0.0;
|
||||
cvm::real corr;
|
||||
if ( periodic[0] ) {
|
||||
corr = gradients->average(); // Enforce PBC by subtracting average gradient
|
||||
} else {
|
||||
corr = 0.0;
|
||||
}
|
||||
|
||||
std::vector<int> ix;
|
||||
// Iterate over valid indices in gradient grid
|
||||
for (ix = new_index(); gradients->index_ok(ix); incr(ix)) {
|
||||
set_value(ix, sum);
|
||||
sum += (gradients->value_output(ix) - corr) * widths[0];
|
||||
}
|
||||
if (index_ok(ix)) {
|
||||
// This will happen if non-periodic: then PMF grid has one extra bin wrt gradient grid
|
||||
set_value(ix, sum);
|
||||
}
|
||||
|
||||
} else if (nd <= 3) {
|
||||
|
||||
nr_linbcg_sym(divergence, data, tol, itmax, iter, err);
|
||||
cvm::log("Integrated in " + cvm::to_str(iter) + " steps, error: " + cvm::to_str(err));
|
||||
|
||||
} else {
|
||||
cvm::error("Cannot integrate PMF in dimension > 3\n");
|
||||
}
|
||||
|
||||
return iter;
|
||||
}
|
||||
|
||||
|
||||
void integrate_potential::set_div()
|
||||
{
|
||||
if (nd == 1) return;
|
||||
for (std::vector<int> ix = new_index(); index_ok(ix); incr(ix)) {
|
||||
update_div_local(ix);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void integrate_potential::update_div_neighbors(const std::vector<int> &ix0)
|
||||
{
|
||||
std::vector<int> ix(ix0);
|
||||
int i, j, k;
|
||||
|
||||
// If not periodic, expanded grid ensures that neighbors of ix0 are valid grid points
|
||||
if (nd == 1) {
|
||||
return;
|
||||
|
||||
} else if (nd == 2) {
|
||||
|
||||
update_div_local(ix);
|
||||
ix[0]++; wrap(ix);
|
||||
update_div_local(ix);
|
||||
ix[1]++; wrap(ix);
|
||||
update_div_local(ix);
|
||||
ix[0]--; wrap(ix);
|
||||
update_div_local(ix);
|
||||
|
||||
} else if (nd == 3) {
|
||||
|
||||
for (i = 0; i<2; i++) {
|
||||
ix[1] = ix0[1];
|
||||
for (j = 0; j<2; j++) {
|
||||
ix[2] = ix0[2];
|
||||
for (k = 0; k<2; k++) {
|
||||
wrap(ix);
|
||||
update_div_local(ix);
|
||||
ix[2]++;
|
||||
}
|
||||
ix[1]++;
|
||||
}
|
||||
ix[0]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void integrate_potential::get_grad(cvm::real * g, std::vector<int> &ix)
|
||||
{
|
||||
size_t count, i;
|
||||
bool edge = gradients->wrap_edge(ix); // Detect edge if non-PBC
|
||||
|
||||
if (gradients->samples) {
|
||||
count = gradients->samples->value(ix);
|
||||
} else {
|
||||
count = 1;
|
||||
}
|
||||
|
||||
if (!edge && count) {
|
||||
cvm::real const *grad = &(gradients->value(ix));
|
||||
cvm::real const fact = 1.0 / count;
|
||||
for ( i = 0; i<nd; i++ ) {
|
||||
g[i] = fact * grad[i];
|
||||
}
|
||||
} else {
|
||||
for ( i = 0; i<nd; i++ ) {
|
||||
g[i] = 0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void integrate_potential::update_div_local(const std::vector<int> &ix0)
|
||||
{
|
||||
const int linear_index = address(ix0);
|
||||
int i, j, k;
|
||||
std::vector<int> ix = ix0;
|
||||
const cvm::real * g;
|
||||
|
||||
if (nd == 2) {
|
||||
// gradients at grid points surrounding the current scalar grid point
|
||||
cvm::real g00[2], g01[2], g10[2], g11[2];
|
||||
|
||||
get_grad(g11, ix);
|
||||
ix[0] = ix0[0] - 1;
|
||||
get_grad(g01, ix);
|
||||
ix[1] = ix0[1] - 1;
|
||||
get_grad(g00, ix);
|
||||
ix[0] = ix0[0];
|
||||
get_grad(g10, ix);
|
||||
|
||||
divergence[linear_index] = ((g10[0]-g00[0] + g11[0]-g01[0]) / widths[0]
|
||||
+ (g01[1]-g00[1] + g11[1]-g10[1]) / widths[1]) * 0.5;
|
||||
} else if (nd == 3) {
|
||||
cvm::real gc[24]; // stores 3d gradients in 8 contiguous bins
|
||||
int index = 0;
|
||||
|
||||
ix[0] = ix0[0] - 1;
|
||||
for (i = 0; i<2; i++) {
|
||||
ix[1] = ix0[1] - 1;
|
||||
for (j = 0; j<2; j++) {
|
||||
ix[2] = ix0[2] - 1;
|
||||
for (k = 0; k<2; k++) {
|
||||
get_grad(gc + index, ix);
|
||||
index += 3;
|
||||
ix[2]++;
|
||||
}
|
||||
ix[1]++;
|
||||
}
|
||||
ix[0]++;
|
||||
}
|
||||
|
||||
divergence[linear_index] =
|
||||
((gc[3*4]-gc[0] + gc[3*5]-gc[3*1] + gc[3*6]-gc[3*2] + gc[3*7]-gc[3*3])
|
||||
/ widths[0]
|
||||
+ (gc[3*2+1]-gc[0+1] + gc[3*3+1]-gc[3*1+1] + gc[3*6+1]-gc[3*4+1] + gc[3*7+1]-gc[3*5+1])
|
||||
/ widths[1]
|
||||
+ (gc[3*1+2]-gc[0+2] + gc[3*3+2]-gc[3*2+2] + gc[3*5+2]-gc[3*4+2] + gc[3*7+2]-gc[3*6+2])
|
||||
/ widths[2]) * 0.25;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Multiplication by sparse matrix representing Laplacian
|
||||
/// NOTE: Laplacian must be symmetric for solving with CG
|
||||
void integrate_potential::atimes(const std::vector<cvm::real> &A, std::vector<cvm::real> &LA)
|
||||
{
|
||||
if (nd == 2) {
|
||||
// DIMENSION 2
|
||||
|
||||
size_t index, index2;
|
||||
int i, j;
|
||||
cvm::real fact;
|
||||
const cvm::real ffx = 1.0 / (widths[0] * widths[0]);
|
||||
const cvm::real ffy = 1.0 / (widths[1] * widths[1]);
|
||||
const int h = nx[1];
|
||||
const int w = nx[0];
|
||||
// offsets for 4 reference points of the Laplacian stencil
|
||||
int xm = -h;
|
||||
int xp = h;
|
||||
int ym = -1;
|
||||
int yp = 1;
|
||||
|
||||
// NOTE on performance: this version is slightly sub-optimal because
|
||||
// it contains two double loops on the core of the array (for x and y terms)
|
||||
// The slightly faster version is in commit 0254cb5a2958cb2e135f268371c4b45fad34866b
|
||||
// yet it is much uglier, and probably horrible to extend to dimension 3
|
||||
// All terms in the matrix are assigned (=) during the x loops, then updated (+=)
|
||||
// with the y (and z) contributions
|
||||
|
||||
|
||||
// All x components except on x edges
|
||||
index = h; // Skip first column
|
||||
|
||||
// Halve the term on y edges (if any) to preserve symmetry of the Laplacian matrix
|
||||
// (Long Chen, Finite Difference Methods, UCI, 2017)
|
||||
fact = periodic[1] ? 1.0 : 0.5;
|
||||
|
||||
for (i=1; i<w-1; i++) {
|
||||
// Full range of j, but factor may change on y edges (j == 0 and j == h-1)
|
||||
LA[index] = fact * ffx * (A[index + xm] + A[index + xp] - 2.0 * A[index]);
|
||||
index++;
|
||||
for (j=1; j<h-1; j++) {
|
||||
LA[index] = ffx * (A[index + xm] + A[index + xp] - 2.0 * A[index]);
|
||||
index++;
|
||||
}
|
||||
LA[index] = fact * ffx * (A[index + xm] + A[index + xp] - 2.0 * A[index]);
|
||||
index++;
|
||||
}
|
||||
// Edges along x (x components only)
|
||||
index = 0; // Follows left edge
|
||||
index2 = h * (w - 1); // Follows right edge
|
||||
if (periodic[0]) {
|
||||
xm = h * (w - 1);
|
||||
xp = h;
|
||||
fact = periodic[1] ? 1.0 : 0.5;
|
||||
LA[index] = fact * ffx * (A[index + xm] + A[index + xp] - 2.0 * A[index]);
|
||||
LA[index2] = fact * ffx * (A[index2 - xp] + A[index2 - xm] - 2.0 * A[index2]);
|
||||
index++;
|
||||
index2++;
|
||||
for (j=1; j<h-1; j++) {
|
||||
LA[index] = ffx * (A[index + xm] + A[index + xp] - 2.0 * A[index]);
|
||||
LA[index2] = ffx * (A[index2 - xp] + A[index2 - xm] - 2.0 * A[index2]);
|
||||
index++;
|
||||
index2++;
|
||||
}
|
||||
LA[index] = fact * ffx * (A[index + xm] + A[index + xp] - 2.0 * A[index]);
|
||||
LA[index2] = fact * ffx * (A[index2 - xp] + A[index2 - xm] - 2.0 * A[index2]);
|
||||
} else {
|
||||
xm = -h;
|
||||
xp = h;
|
||||
fact = periodic[1] ? 1.0 : 0.5; // Halve in corners in full PBC only
|
||||
// lower corner, "j == 0"
|
||||
LA[index] = fact * ffx * (A[index + xp] - A[index]);
|
||||
LA[index2] = fact * ffx * (A[index2 + xm] - A[index2]);
|
||||
index++;
|
||||
index2++;
|
||||
for (j=1; j<h-1; j++) {
|
||||
// x gradient (+ y term of laplacian, calculated below)
|
||||
LA[index] = ffx * (A[index + xp] - A[index]);
|
||||
LA[index2] = ffx * (A[index2 + xm] - A[index2]);
|
||||
index++;
|
||||
index2++;
|
||||
}
|
||||
// upper corner, j == h-1
|
||||
LA[index] = fact * ffx * (A[index + xp] - A[index]);
|
||||
LA[index2] = fact * ffx * (A[index2 + xm] - A[index2]);
|
||||
}
|
||||
|
||||
// Now adding all y components
|
||||
// All y components except on y edges
|
||||
index = 1; // Skip first element (in first row)
|
||||
|
||||
fact = periodic[0] ? 1.0 : 0.5; // for i == 0
|
||||
for (i=0; i<w; i++) {
|
||||
// Factor of 1/2 on x edges if non-periodic
|
||||
if (i == 1) fact = 1.0;
|
||||
if (i == w - 1) fact = periodic[0] ? 1.0 : 0.5;
|
||||
for (j=1; j<h-1; j++) {
|
||||
LA[index] += fact * ffy * (A[index + ym] + A[index + yp] - 2.0 * A[index]);
|
||||
index++;
|
||||
}
|
||||
index += 2; // skip the edges and move to next column
|
||||
}
|
||||
// Edges along y (y components only)
|
||||
index = 0; // Follows bottom edge
|
||||
index2 = h - 1; // Follows top edge
|
||||
if (periodic[1]) {
|
||||
fact = periodic[0] ? 1.0 : 0.5;
|
||||
ym = h - 1;
|
||||
yp = 1;
|
||||
LA[index] += fact * ffy * (A[index + ym] + A[index + yp] - 2.0 * A[index]);
|
||||
LA[index2] += fact * ffy * (A[index2 - yp] + A[index2 - ym] - 2.0 * A[index2]);
|
||||
index += h;
|
||||
index2 += h;
|
||||
for (i=1; i<w-1; i++) {
|
||||
LA[index] += ffy * (A[index + ym] + A[index + yp] - 2.0 * A[index]);
|
||||
LA[index2] += ffy * (A[index2 - yp] + A[index2 - ym] - 2.0 * A[index2]);
|
||||
index += h;
|
||||
index2 += h;
|
||||
}
|
||||
LA[index] += fact * ffy * (A[index + ym] + A[index + yp] - 2.0 * A[index]);
|
||||
LA[index2] += fact * ffy * (A[index2 - yp] + A[index2 - ym] - 2.0 * A[index2]);
|
||||
} else {
|
||||
ym = -1;
|
||||
yp = 1;
|
||||
fact = periodic[0] ? 1.0 : 0.5; // Halve in corners in full PBC only
|
||||
// Left corner
|
||||
LA[index] += fact * ffy * (A[index + yp] - A[index]);
|
||||
LA[index2] += fact * ffy * (A[index2 + ym] - A[index2]);
|
||||
index += h;
|
||||
index2 += h;
|
||||
for (i=1; i<w-1; i++) {
|
||||
// y gradient (+ x term of laplacian, calculated above)
|
||||
LA[index] += ffy * (A[index + yp] - A[index]);
|
||||
LA[index2] += ffy * (A[index2 + ym] - A[index2]);
|
||||
index += h;
|
||||
index2 += h;
|
||||
}
|
||||
// Right corner
|
||||
LA[index] += fact * ffy * (A[index + yp] - A[index]);
|
||||
LA[index2] += fact * ffy * (A[index2 + ym] - A[index2]);
|
||||
}
|
||||
|
||||
} else if (nd == 3) {
|
||||
// DIMENSION 3
|
||||
|
||||
int i, j, k;
|
||||
size_t index, index2;
|
||||
cvm::real fact = 1.0;
|
||||
const cvm::real ffx = 1.0 / (widths[0] * widths[0]);
|
||||
const cvm::real ffy = 1.0 / (widths[1] * widths[1]);
|
||||
const cvm::real ffz = 1.0 / (widths[2] * widths[2]);
|
||||
const int h = nx[2]; // height
|
||||
const int d = nx[1]; // depth
|
||||
const int w = nx[0]; // width
|
||||
// offsets for 6 reference points of the Laplacian stencil
|
||||
int xm = -d * h;
|
||||
int xp = d * h;
|
||||
int ym = -h;
|
||||
int yp = h;
|
||||
int zm = -1;
|
||||
int zp = 1;
|
||||
|
||||
cvm::real factx = periodic[0] ? 1 : 0.5; // factor to be applied on x edges
|
||||
cvm::real facty = periodic[1] ? 1 : 0.5; // same for y
|
||||
cvm::real factz = periodic[2] ? 1 : 0.5; // same for z
|
||||
cvm::real ifactx = 1 / factx;
|
||||
cvm::real ifacty = 1 / facty;
|
||||
cvm::real ifactz = 1 / factz;
|
||||
|
||||
// All x components except on x edges
|
||||
index = d * h; // Skip left slab
|
||||
fact = facty * factz;
|
||||
for (i=1; i<w-1; i++) {
|
||||
for (j=0; j<d; j++) { // full range of y
|
||||
if (j == 1) fact *= ifacty;
|
||||
if (j == d-1) fact *= facty;
|
||||
LA[index] = fact * ffx * (A[index + xm] + A[index + xp] - 2.0 * A[index]);
|
||||
index++;
|
||||
fact *= ifactz;
|
||||
for (k=1; k<h-1; k++) { // full range of z
|
||||
LA[index] = fact * ffx * (A[index + xm] + A[index + xp] - 2.0 * A[index]);
|
||||
index++;
|
||||
}
|
||||
fact *= factz;
|
||||
LA[index] = fact * ffx * (A[index + xm] + A[index + xp] - 2.0 * A[index]);
|
||||
index++;
|
||||
}
|
||||
}
|
||||
// Edges along x (x components only)
|
||||
index = 0; // Follows left slab
|
||||
index2 = d * h * (w - 1); // Follows right slab
|
||||
if (periodic[0]) {
|
||||
xm = d * h * (w - 1);
|
||||
xp = d * h;
|
||||
fact = facty * factz;
|
||||
for (j=0; j<d; j++) {
|
||||
if (j == 1) fact *= ifacty;
|
||||
if (j == d-1) fact *= facty;
|
||||
LA[index] = fact * ffx * (A[index + xm] + A[index + xp] - 2.0 * A[index]);
|
||||
LA[index2] = fact * ffx * (A[index2 - xp] + A[index2 - xm] - 2.0 * A[index2]);
|
||||
index++;
|
||||
index2++;
|
||||
fact *= ifactz;
|
||||
for (k=1; k<h-1; k++) {
|
||||
LA[index] = fact * ffx * (A[index + xm] + A[index + xp] - 2.0 * A[index]);
|
||||
LA[index2] = fact * ffx * (A[index2 - xp] + A[index2 - xm] - 2.0 * A[index2]);
|
||||
index++;
|
||||
index2++;
|
||||
}
|
||||
fact *= factz;
|
||||
LA[index] = fact * ffx * (A[index + xm] + A[index + xp] - 2.0 * A[index]);
|
||||
LA[index2] = fact * ffx * (A[index2 - xp] + A[index2 - xm] - 2.0 * A[index2]);
|
||||
index++;
|
||||
index2++;
|
||||
}
|
||||
} else {
|
||||
xm = -d * h;
|
||||
xp = d * h;
|
||||
fact = facty * factz;
|
||||
for (j=0; j<d; j++) {
|
||||
if (j == 1) fact *= ifacty;
|
||||
if (j == d-1) fact *= facty;
|
||||
LA[index] = fact * ffx * (A[index + xp] - A[index]);
|
||||
LA[index2] = fact * ffx * (A[index2 + xm] - A[index2]);
|
||||
index++;
|
||||
index2++;
|
||||
fact *= ifactz;
|
||||
for (k=1; k<h-1; k++) {
|
||||
// x gradient (+ y, z terms of laplacian, calculated below)
|
||||
LA[index] = fact * ffx * (A[index + xp] - A[index]);
|
||||
LA[index2] = fact * ffx * (A[index2 + xm] - A[index2]);
|
||||
index++;
|
||||
index2++;
|
||||
}
|
||||
fact *= factz;
|
||||
LA[index] = fact * ffx * (A[index + xp] - A[index]);
|
||||
LA[index2] = fact * ffx * (A[index2 + xm] - A[index2]);
|
||||
index++;
|
||||
index2++;
|
||||
}
|
||||
}
|
||||
|
||||
// Now adding all y components
|
||||
// All y components except on y edges
|
||||
index = h; // Skip first column (in front slab)
|
||||
fact = factx * factz;
|
||||
for (i=0; i<w; i++) { // full range of x
|
||||
if (i == 1) fact *= ifactx;
|
||||
if (i == w-1) fact *= factx;
|
||||
for (j=1; j<d-1; j++) {
|
||||
LA[index] += fact * ffy * (A[index + ym] + A[index + yp] - 2.0 * A[index]);
|
||||
index++;
|
||||
fact *= ifactz;
|
||||
for (k=1; k<h-1; k++) {
|
||||
LA[index] += fact * ffy * (A[index + ym] + A[index + yp] - 2.0 * A[index]);
|
||||
index++;
|
||||
}
|
||||
fact *= factz;
|
||||
LA[index] += fact * ffy * (A[index + ym] + A[index + yp] - 2.0 * A[index]);
|
||||
index++;
|
||||
}
|
||||
index += 2 * h; // skip columns in front and back slabs
|
||||
}
|
||||
// Edges along y (y components only)
|
||||
index = 0; // Follows front slab
|
||||
index2 = h * (d - 1); // Follows back slab
|
||||
if (periodic[1]) {
|
||||
ym = h * (d - 1);
|
||||
yp = h;
|
||||
fact = factx * factz;
|
||||
for (i=0; i<w; i++) {
|
||||
if (i == 1) fact *= ifactx;
|
||||
if (i == w-1) fact *= factx;
|
||||
LA[index] += fact * ffy * (A[index + ym] + A[index + yp] - 2.0 * A[index]);
|
||||
LA[index2] += fact * ffy * (A[index2 - yp] + A[index2 - ym] - 2.0 * A[index2]);
|
||||
index++;
|
||||
index2++;
|
||||
fact *= ifactz;
|
||||
for (k=1; k<h-1; k++) {
|
||||
LA[index] += fact * ffy * (A[index + ym] + A[index + yp] - 2.0 * A[index]);
|
||||
LA[index2] += fact * ffy * (A[index2 - yp] + A[index2 - ym] - 2.0 * A[index2]);
|
||||
index++;
|
||||
index2++;
|
||||
}
|
||||
fact *= factz;
|
||||
LA[index] += fact * ffy * (A[index + ym] + A[index + yp] - 2.0 * A[index]);
|
||||
LA[index2] += fact * ffy * (A[index2 - yp] + A[index2 - ym] - 2.0 * A[index2]);
|
||||
index++;
|
||||
index2++;
|
||||
index += h * (d - 1);
|
||||
index2 += h * (d - 1);
|
||||
}
|
||||
} else {
|
||||
ym = -h;
|
||||
yp = h;
|
||||
fact = factx * factz;
|
||||
for (i=0; i<w; i++) {
|
||||
if (i == 1) fact *= ifactx;
|
||||
if (i == w-1) fact *= factx;
|
||||
LA[index] += fact * ffy * (A[index + yp] - A[index]);
|
||||
LA[index2] += fact * ffy * (A[index2 + ym] - A[index2]);
|
||||
index++;
|
||||
index2++;
|
||||
fact *= ifactz;
|
||||
for (k=1; k<h-1; k++) {
|
||||
// y gradient (+ x, z terms of laplacian, calculated above and below)
|
||||
LA[index] += fact * ffy * (A[index + yp] - A[index]);
|
||||
LA[index2] += fact * ffy * (A[index2 + ym] - A[index2]);
|
||||
index++;
|
||||
index2++;
|
||||
}
|
||||
fact *= factz;
|
||||
LA[index] += fact * ffy * (A[index + yp] - A[index]);
|
||||
LA[index2] += fact * ffy * (A[index2 + ym] - A[index2]);
|
||||
index++;
|
||||
index2++;
|
||||
index += h * (d - 1);
|
||||
index2 += h * (d - 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Now adding all z components
|
||||
// All z components except on z edges
|
||||
index = 1; // Skip first element (in bottom slab)
|
||||
fact = factx * facty;
|
||||
for (i=0; i<w; i++) { // full range of x
|
||||
if (i == 1) fact *= ifactx;
|
||||
if (i == w-1) fact *= factx;
|
||||
for (k=1; k<h-1; k++) {
|
||||
LA[index] += fact * ffz * (A[index + zm] + A[index + zp] - 2.0 * A[index]);
|
||||
index++;
|
||||
}
|
||||
fact *= ifacty;
|
||||
index += 2; // skip edge slabs
|
||||
for (j=1; j<d-1; j++) { // full range of y
|
||||
for (k=1; k<h-1; k++) {
|
||||
LA[index] += fact * ffz * (A[index + zm] + A[index + zp] - 2.0 * A[index]);
|
||||
index++;
|
||||
}
|
||||
index += 2; // skip edge slabs
|
||||
}
|
||||
fact *= facty;
|
||||
for (k=1; k<h-1; k++) {
|
||||
LA[index] += fact * ffz * (A[index + zm] + A[index + zp] - 2.0 * A[index]);
|
||||
index++;
|
||||
}
|
||||
index += 2; // skip edge slabs
|
||||
}
|
||||
// Edges along z (z components onlz)
|
||||
index = 0; // Follows bottom slab
|
||||
index2 = h - 1; // Follows top slab
|
||||
if (periodic[2]) {
|
||||
zm = h - 1;
|
||||
zp = 1;
|
||||
fact = factx * facty;
|
||||
for (i=0; i<w; i++) {
|
||||
if (i == 1) fact *= ifactx;
|
||||
if (i == w-1) fact *= factx;
|
||||
LA[index] += fact * ffz * (A[index + zm] + A[index + zp] - 2.0 * A[index]);
|
||||
LA[index2] += fact * ffz * (A[index2 - zp] + A[index2 - zm] - 2.0 * A[index2]);
|
||||
index += h;
|
||||
index2 += h;
|
||||
fact *= ifacty;
|
||||
for (j=1; j<d-1; j++) {
|
||||
LA[index] += fact * ffz * (A[index + zm] + A[index + zp] - 2.0 * A[index]);
|
||||
LA[index2] += fact * ffz * (A[index2 - zp] + A[index2 - zm] - 2.0 * A[index2]);
|
||||
index += h;
|
||||
index2 += h;
|
||||
}
|
||||
fact *= facty;
|
||||
LA[index] += fact * ffz * (A[index + zm] + A[index + zp] - 2.0 * A[index]);
|
||||
LA[index2] += fact * ffz * (A[index2 - zp] + A[index2 - zm] - 2.0 * A[index2]);
|
||||
index += h;
|
||||
index2 += h;
|
||||
}
|
||||
} else {
|
||||
zm = -1;
|
||||
zp = 1;
|
||||
fact = factx * facty;
|
||||
for (i=0; i<w; i++) {
|
||||
if (i == 1) fact *= ifactx;
|
||||
if (i == w-1) fact *= factx;
|
||||
LA[index] += fact * ffz * (A[index + zp] - A[index]);
|
||||
LA[index2] += fact * ffz * (A[index2 + zm] - A[index2]);
|
||||
index += h;
|
||||
index2 += h;
|
||||
fact *= ifacty;
|
||||
for (j=1; j<d-1; j++) {
|
||||
// z gradient (+ x, y terms of laplacian, calculated above)
|
||||
LA[index] += fact * ffz * (A[index + zp] - A[index]);
|
||||
LA[index2] += fact * ffz * (A[index2 + zm] - A[index2]);
|
||||
index += h;
|
||||
index2 += h;
|
||||
}
|
||||
fact *= facty;
|
||||
LA[index] += fact * ffz * (A[index + zp] - A[index]);
|
||||
LA[index2] += fact * ffz * (A[index2 + zm] - A[index2]);
|
||||
index += h;
|
||||
index2 += h;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
/// Inversion of preconditioner matrix (e.g. diagonal of the Laplacian)
|
||||
void integrate_potential::asolve(const std::vector<cvm::real> &b, std::vector<cvm::real> &x)
|
||||
{
|
||||
for (size_t i=0; i<nt; i++) {
|
||||
x[i] = b[i] * inv_lap_diag[i]; // Jacobi preconditioner - little benefit in tests so far
|
||||
}
|
||||
return;
|
||||
}*/
|
||||
|
||||
|
||||
// b : RHS of equation
|
||||
// x : initial guess for the solution; output is solution
|
||||
// itol : convergence criterion
|
||||
void integrate_potential::nr_linbcg_sym(const std::vector<cvm::real> &b, std::vector<cvm::real> &x, const cvm::real &tol,
|
||||
const int itmax, int &iter, cvm::real &err)
|
||||
{
|
||||
cvm::real ak,akden,bk,bkden,bknum,bnrm;
|
||||
const cvm::real EPS=1.0e-14;
|
||||
int j;
|
||||
std::vector<cvm::real> p(nt), r(nt), z(nt);
|
||||
|
||||
iter=0;
|
||||
atimes(x,r);
|
||||
for (j=0;j<nt;j++) {
|
||||
r[j]=b[j]-r[j];
|
||||
}
|
||||
bnrm=l2norm(b);
|
||||
if (bnrm < EPS) {
|
||||
return; // Target is zero, will break relative error calc
|
||||
}
|
||||
// asolve(r,z); // precon
|
||||
bkden = 1.0;
|
||||
while (iter < itmax) {
|
||||
++iter;
|
||||
for (bknum=0.0,j=0;j<nt;j++) {
|
||||
bknum += r[j]*r[j]; // precon: z[j]*r[j]
|
||||
}
|
||||
if (iter == 1) {
|
||||
for (j=0;j<nt;j++) {
|
||||
p[j] = r[j]; // precon: p[j] = z[j]
|
||||
}
|
||||
} else {
|
||||
bk=bknum/bkden;
|
||||
for (j=0;j<nt;j++) {
|
||||
p[j] = bk*p[j] + r[j]; // precon: bk*p[j] + z[j]
|
||||
}
|
||||
}
|
||||
bkden = bknum;
|
||||
atimes(p,z);
|
||||
for (akden=0.0,j=0;j<nt;j++) {
|
||||
akden += z[j]*p[j];
|
||||
}
|
||||
ak = bknum/akden;
|
||||
for (j=0;j<nt;j++) {
|
||||
x[j] += ak*p[j];
|
||||
r[j] -= ak*z[j];
|
||||
}
|
||||
// asolve(r,z); // precon
|
||||
err = l2norm(r)/bnrm;
|
||||
if (cvm::debug())
|
||||
std::cout << "iter=" << std::setw(4) << iter+1 << std::setw(12) << err << std::endl;
|
||||
if (err <= tol)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
cvm::real integrate_potential::l2norm(const std::vector<cvm::real> &x)
|
||||
{
|
||||
size_t i;
|
||||
cvm::real sum = 0.0;
|
||||
for (i=0;i<x.size();i++)
|
||||
sum += x[i]*x[i];
|
||||
return sqrt(sum);
|
||||
}
|
||||
|
||||
@ -97,8 +97,8 @@ public:
|
||||
/// Whether this grid has been filled with data or is still empty
|
||||
bool has_data;
|
||||
|
||||
/// Return the number of colvars
|
||||
inline size_t number_of_colvars() const
|
||||
/// Return the number of colvar objects
|
||||
inline size_t num_variables() const
|
||||
{
|
||||
return nd;
|
||||
}
|
||||
@ -374,6 +374,20 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
/// Wrap an index vector around periodic boundary conditions
|
||||
/// or detects edges if non-periodic
|
||||
inline bool wrap_edge(std::vector<int> & ix) const
|
||||
{
|
||||
bool edge = false;
|
||||
for (size_t i = 0; i < nd; i++) {
|
||||
if (periodic[i]) {
|
||||
ix[i] = (ix[i] + nx[i]) % nx[i]; //to ensure non-negative result
|
||||
} else if (ix[i] == -1 || ix[i] == nx[i]) {
|
||||
edge = true;
|
||||
}
|
||||
}
|
||||
return edge;
|
||||
}
|
||||
|
||||
/// \brief Report the bin corresponding to the current value of variable i
|
||||
inline int current_bin_scalar(int const i) const
|
||||
@ -445,6 +459,12 @@ public:
|
||||
has_data = true;
|
||||
}
|
||||
|
||||
/// Set the value at the point with linear address i (for speed)
|
||||
inline void set_value(size_t i, T const &t)
|
||||
{
|
||||
data[i] = t;
|
||||
}
|
||||
|
||||
/// \brief Get the change from this to other_grid
|
||||
/// and store the result in this.
|
||||
/// this_grid := other_grid - this_grid
|
||||
@ -518,6 +538,11 @@ public:
|
||||
return data[this->address(ix) + imult];
|
||||
}
|
||||
|
||||
/// \brief Get the binned value indexed by linear address i
|
||||
inline T const & value(size_t i) const
|
||||
{
|
||||
return data[i];
|
||||
}
|
||||
|
||||
/// \brief Add a constant to all elements (fast loop)
|
||||
inline void add_constant(T const &t)
|
||||
@ -1110,20 +1135,20 @@ public:
|
||||
// write the header
|
||||
os << "object 1 class gridpositions counts";
|
||||
size_t icv;
|
||||
for (icv = 0; icv < number_of_colvars(); icv++) {
|
||||
for (icv = 0; icv < num_variables(); icv++) {
|
||||
os << " " << number_of_points(icv);
|
||||
}
|
||||
os << "\n";
|
||||
|
||||
os << "origin";
|
||||
for (icv = 0; icv < number_of_colvars(); icv++) {
|
||||
for (icv = 0; icv < num_variables(); icv++) {
|
||||
os << " " << (lower_boundaries[icv].real_value + 0.5 * widths[icv]);
|
||||
}
|
||||
os << "\n";
|
||||
|
||||
for (icv = 0; icv < number_of_colvars(); icv++) {
|
||||
for (icv = 0; icv < num_variables(); icv++) {
|
||||
os << "delta";
|
||||
for (size_t icv2 = 0; icv2 < number_of_colvars(); icv2++) {
|
||||
for (size_t icv2 = 0; icv2 < num_variables(); icv2++) {
|
||||
if (icv == icv2) os << " " << widths[icv];
|
||||
else os << " " << 0.0;
|
||||
}
|
||||
@ -1131,7 +1156,7 @@ public:
|
||||
}
|
||||
|
||||
os << "object 2 class gridconnections counts";
|
||||
for (icv = 0; icv < number_of_colvars(); icv++) {
|
||||
for (icv = 0; icv < num_variables(); icv++) {
|
||||
os << " " << number_of_points(icv);
|
||||
}
|
||||
os << "\n";
|
||||
@ -1167,7 +1192,8 @@ public:
|
||||
|
||||
/// Constructor from a vector of colvars
|
||||
colvar_grid_count(std::vector<colvar *> &colvars,
|
||||
size_t const &def_count = 0);
|
||||
size_t const &def_count = 0,
|
||||
bool margin = false);
|
||||
|
||||
/// Increment the counter at given position
|
||||
inline void incr_count(std::vector<int> const &ix)
|
||||
@ -1210,12 +1236,13 @@ public:
|
||||
int A0, A1, A2;
|
||||
std::vector<int> ix = ix0;
|
||||
|
||||
// TODO this can be rewritten more concisely with wrap_edge()
|
||||
if (periodic[n]) {
|
||||
ix[n]--; wrap(ix);
|
||||
A0 = data[address(ix)];
|
||||
A0 = value(ix);
|
||||
ix = ix0;
|
||||
ix[n]++; wrap(ix);
|
||||
A1 = data[address(ix)];
|
||||
A1 = value(ix);
|
||||
if (A0 * A1 == 0) {
|
||||
return 0.; // can't handle empty bins
|
||||
} else {
|
||||
@ -1224,10 +1251,10 @@ public:
|
||||
}
|
||||
} else if (ix[n] > 0 && ix[n] < nx[n]-1) { // not an edge
|
||||
ix[n]--;
|
||||
A0 = data[address(ix)];
|
||||
A0 = value(ix);
|
||||
ix = ix0;
|
||||
ix[n]++;
|
||||
A1 = data[address(ix)];
|
||||
A1 = value(ix);
|
||||
if (A0 * A1 == 0) {
|
||||
return 0.; // can't handle empty bins
|
||||
} else {
|
||||
@ -1238,9 +1265,9 @@ public:
|
||||
// edge: use 2nd order derivative
|
||||
int increment = (ix[n] == 0 ? 1 : -1);
|
||||
// move right from left edge, or the other way around
|
||||
A0 = data[address(ix)];
|
||||
ix[n] += increment; A1 = data[address(ix)];
|
||||
ix[n] += increment; A2 = data[address(ix)];
|
||||
A0 = value(ix);
|
||||
ix[n] += increment; A1 = value(ix);
|
||||
ix[n] += increment; A2 = value(ix);
|
||||
if (A0 * A1 * A2 == 0) {
|
||||
return 0.; // can't handle empty bins
|
||||
} else {
|
||||
@ -1249,6 +1276,49 @@ public:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief Return the gradient of discrete count from finite differences
|
||||
/// on the *same* grid for dimension n
|
||||
inline cvm::real gradient_finite_diff(const std::vector<int> &ix0,
|
||||
int n = 0)
|
||||
{
|
||||
int A0, A1, A2;
|
||||
std::vector<int> ix = ix0;
|
||||
|
||||
// FIXME this can be rewritten more concisely with wrap_edge()
|
||||
if (periodic[n]) {
|
||||
ix[n]--; wrap(ix);
|
||||
A0 = value(ix);
|
||||
ix = ix0;
|
||||
ix[n]++; wrap(ix);
|
||||
A1 = value(ix);
|
||||
if (A0 * A1 == 0) {
|
||||
return 0.; // can't handle empty bins
|
||||
} else {
|
||||
return cvm::real(A1 - A0) / (widths[n] * 2.);
|
||||
}
|
||||
} else if (ix[n] > 0 && ix[n] < nx[n]-1) { // not an edge
|
||||
ix[n]--;
|
||||
A0 = value(ix);
|
||||
ix = ix0;
|
||||
ix[n]++;
|
||||
A1 = value(ix);
|
||||
if (A0 * A1 == 0) {
|
||||
return 0.; // can't handle empty bins
|
||||
} else {
|
||||
return cvm::real(A1 - A0) / (widths[n] * 2.);
|
||||
}
|
||||
} else {
|
||||
// edge: use 2nd order derivative
|
||||
int increment = (ix[n] == 0 ? 1 : -1);
|
||||
// move right from left edge, or the other way around
|
||||
A0 = value(ix);
|
||||
ix[n] += increment; A1 = value(ix);
|
||||
ix[n] += increment; A2 = value(ix);
|
||||
return (-1.5 * cvm::real(A0) + 2. * cvm::real(A1)
|
||||
- 0.5 * cvm::real(A2)) * increment / widths[n];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -1289,27 +1359,57 @@ public:
|
||||
has_data = true;
|
||||
}
|
||||
|
||||
/// Return the gradient of the scalar field from finite differences
|
||||
inline const cvm::real * gradient_finite_diff( const std::vector<int> &ix0 )
|
||||
/// \brief Return the gradient of the scalar field from finite differences
|
||||
/// Input coordinates are those of gradient grid, shifted wrt scalar grid
|
||||
/// Should not be called on edges of scalar grid, provided the latter has margins
|
||||
/// wrt gradient grid
|
||||
inline void vector_gradient_finite_diff( const std::vector<int> &ix0, std::vector<cvm::real> &grad)
|
||||
{
|
||||
cvm::real A0, A1;
|
||||
std::vector<int> ix;
|
||||
if (nd != 2) {
|
||||
cvm::error("Finite differences available in dimension 2 only.");
|
||||
return grad;
|
||||
}
|
||||
for (unsigned int n = 0; n < nd; n++) {
|
||||
size_t i, j, k, n;
|
||||
|
||||
if (nd == 2) {
|
||||
for (n = 0; n < 2; n++) {
|
||||
ix = ix0;
|
||||
A0 = value(ix);
|
||||
ix[n]++; wrap(ix);
|
||||
A1 = value(ix);
|
||||
ix[1-n]++; wrap(ix);
|
||||
A1 += value(ix);
|
||||
ix[n]--; wrap(ix);
|
||||
A0 += value(ix);
|
||||
grad[n] = 0.5 * (A1 - A0) / widths[n];
|
||||
}
|
||||
} else if (nd == 3) {
|
||||
|
||||
cvm::real p[8]; // potential values within cube, indexed in binary (4 i + 2 j + k)
|
||||
ix = ix0;
|
||||
A0 = data[address(ix)];
|
||||
ix[n]++; wrap(ix);
|
||||
A1 = data[address(ix)];
|
||||
ix[1-n]++; wrap(ix);
|
||||
A1 += data[address(ix)];
|
||||
ix[n]--; wrap(ix);
|
||||
A0 += data[address(ix)];
|
||||
grad[n] = 0.5 * (A1 - A0) / widths[n];
|
||||
int index = 0;
|
||||
for (i = 0; i<2; i++) {
|
||||
ix[1] = ix0[1];
|
||||
for (j = 0; j<2; j++) {
|
||||
ix[2] = ix0[2];
|
||||
for (k = 0; k<2; k++) {
|
||||
wrap(ix);
|
||||
p[index++] = value(ix);
|
||||
ix[2]++;
|
||||
}
|
||||
ix[1]++;
|
||||
}
|
||||
ix[0]++;
|
||||
}
|
||||
|
||||
// The following would be easier to read using binary literals
|
||||
// 100 101 110 111 000 001 010 011
|
||||
grad[0] = 0.25 * ((p[4] + p[5] + p[6] + p[7]) - (p[0] + p[1] + p[2] + p[3])) / widths[0];
|
||||
// 010 011 110 111 000 001 100 101
|
||||
grad[1] = 0.25 * ((p[2] + p[3] + p[6] + p[7]) - (p[0] + p[1] + p[4] + p[5])) / widths[0];
|
||||
// 001 011 101 111 000 010 100 110
|
||||
grad[2] = 0.25 * ((p[1] + p[3] + p[5] + p[7]) - (p[0] + p[2] + p[4] + p[6])) / widths[0];
|
||||
} else {
|
||||
cvm::error("Finite differences available in dimension 2 and 3 only.");
|
||||
}
|
||||
return grad;
|
||||
}
|
||||
|
||||
/// \brief Return the value of the function at ix divided by its
|
||||
@ -1373,10 +1473,6 @@ public:
|
||||
/// \brief Assuming that the map is a normalized probability density,
|
||||
/// calculates the entropy (uses widths if they are defined)
|
||||
cvm::real entropy() const;
|
||||
|
||||
private:
|
||||
// gradient
|
||||
cvm::real * grad;
|
||||
};
|
||||
|
||||
|
||||
@ -1390,6 +1486,10 @@ public:
|
||||
/// should be divided
|
||||
colvar_grid_count *samples;
|
||||
|
||||
/// \brief Provide the floating point weights by which each binned value
|
||||
/// should be divided (alternate to samples, only one should be non-null)
|
||||
colvar_grid_scalar *weights;
|
||||
|
||||
/// Default constructor
|
||||
colvar_grid_gradient();
|
||||
|
||||
@ -1403,6 +1503,29 @@ public:
|
||||
/// Constructor from a vector of colvars
|
||||
colvar_grid_gradient(std::vector<colvar *> &colvars);
|
||||
|
||||
/// \brief Get a vector with the binned value(s) indexed by ix, normalized if applicable
|
||||
inline void vector_value(std::vector<int> const &ix, std::vector<cvm::real> &v) const
|
||||
{
|
||||
cvm::real const * p = &value(ix);
|
||||
if (samples) {
|
||||
int count = samples->value(ix);
|
||||
if (count) {
|
||||
cvm::real invcount = 1.0 / count;
|
||||
for (size_t i = 0; i < mult; i++) {
|
||||
v[i] = invcount * p[i];
|
||||
}
|
||||
} else {
|
||||
for (size_t i = 0; i < mult; i++) {
|
||||
v[i] = 0.0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (size_t i = 0; i < mult; i++) {
|
||||
v[i] = p[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief Accumulate the value
|
||||
inline void acc_value(std::vector<int> const &ix, std::vector<colvarvalue> const &values) {
|
||||
for (size_t imult = 0; imult < mult; imult++) {
|
||||
@ -1412,15 +1535,6 @@ public:
|
||||
samples->incr_count(ix);
|
||||
}
|
||||
|
||||
/// \brief Accumulate the gradient
|
||||
inline void acc_grad(std::vector<int> const &ix, cvm::real const *grads) {
|
||||
for (size_t imult = 0; imult < mult; imult++) {
|
||||
data[address(ix) + imult] += grads[imult];
|
||||
}
|
||||
if (samples)
|
||||
samples->incr_count(ix);
|
||||
}
|
||||
|
||||
/// \brief Accumulate the gradient based on the force (i.e. sums the
|
||||
/// opposite of the force)
|
||||
inline void acc_force(std::vector<int> const &ix, cvm::real const *forces) {
|
||||
@ -1431,6 +1545,17 @@ public:
|
||||
samples->incr_count(ix);
|
||||
}
|
||||
|
||||
/// \brief Accumulate the gradient based on the force (i.e. sums the
|
||||
/// opposite of the force) with a non-integer weight
|
||||
inline void acc_force_weighted(std::vector<int> const &ix,
|
||||
cvm::real const *forces,
|
||||
cvm::real weight) {
|
||||
for (size_t imult = 0; imult < mult; imult++) {
|
||||
data[address(ix) + imult] -= forces[imult] * weight;
|
||||
}
|
||||
weights->acc_value(ix, weight);
|
||||
}
|
||||
|
||||
/// \brief Return the value of the function at ix divided by its
|
||||
/// number of samples (if the count grid is defined)
|
||||
virtual inline cvm::real value_output(std::vector<int> const &ix,
|
||||
@ -1498,5 +1623,70 @@ public:
|
||||
};
|
||||
|
||||
|
||||
|
||||
/// Integrate (1D, 2D or 3D) gradients
|
||||
|
||||
class integrate_potential : public colvar_grid_scalar
|
||||
{
|
||||
public:
|
||||
|
||||
integrate_potential();
|
||||
|
||||
virtual ~integrate_potential()
|
||||
{}
|
||||
|
||||
/// Constructor from a vector of colvars + gradient grid
|
||||
integrate_potential (std::vector<colvar *> &colvars, colvar_grid_gradient * gradients);
|
||||
|
||||
/// \brief Calculate potential from divergence (in 2D); return number of steps
|
||||
int integrate (const int itmax, const cvm::real & tol, cvm::real & err);
|
||||
|
||||
/// \brief Update matrix containing divergence and boundary conditions
|
||||
/// based on new gradient point value, in neighboring bins
|
||||
void update_div_neighbors(const std::vector<int> &ix);
|
||||
|
||||
/// \brief Set matrix containing divergence and boundary conditions
|
||||
/// based on complete gradient grid
|
||||
void set_div();
|
||||
|
||||
/// \brief Add constant to potential so that its minimum value is zero
|
||||
/// Useful e.g. for output
|
||||
inline void set_zero_minimum() {
|
||||
add_constant(-1.0 * minimum_value());
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
// Reference to gradient grid
|
||||
colvar_grid_gradient *gradients;
|
||||
|
||||
/// Array holding divergence + boundary terms (modified Neumann) if not periodic
|
||||
std::vector<cvm::real> divergence;
|
||||
|
||||
// std::vector<cvm::real> inv_lap_diag; // Inverse of the diagonal of the Laplacian; for conditioning
|
||||
|
||||
/// \brief Update matrix containing divergence and boundary conditions
|
||||
/// called by update_div_neighbors
|
||||
void update_div_local(const std::vector<int> &ix);
|
||||
|
||||
/// Obtain the gradient vector at given location ix, if available
|
||||
/// or zero if it is on the edge of the gradient grid
|
||||
/// ix gets wrapped in PBC
|
||||
void get_grad(cvm::real * g, std::vector<int> &ix);
|
||||
|
||||
/// \brief Solve linear system based on CG, valid for symmetric matrices only
|
||||
void nr_linbcg_sym(const std::vector<cvm::real> &b, std::vector<cvm::real> &x,
|
||||
const cvm::real &tol, const int itmax, int &iter, cvm::real &err);
|
||||
|
||||
/// l2 norm of a vector
|
||||
cvm::real l2norm(const std::vector<cvm::real> &x);
|
||||
|
||||
/// Multiplication by sparse matrix representing Lagrangian (or its transpose)
|
||||
void atimes(const std::vector<cvm::real> &x, std::vector<cvm::real> &r);
|
||||
|
||||
// /// Inversion of preconditioner matrix
|
||||
// void asolve(const std::vector<cvm::real> &b, std::vector<cvm::real> &x);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@ -24,6 +24,7 @@
|
||||
#include "colvaratoms.h"
|
||||
#include "colvarcomp.h"
|
||||
|
||||
|
||||
colvarmodule::colvarmodule(colvarproxy *proxy_in)
|
||||
{
|
||||
depth_s = 0;
|
||||
@ -417,10 +418,10 @@ int colvarmodule::parse_biases(std::string const &conf)
|
||||
"Please ensure that their forces do not counteract each other.\n");
|
||||
}
|
||||
|
||||
if (biases.size() || use_scripted_forces) {
|
||||
if (num_biases() || use_scripted_forces) {
|
||||
cvm::log(cvm::line_marker);
|
||||
cvm::log("Collective variables biases initialized, "+
|
||||
cvm::to_str(biases.size())+" in total.\n");
|
||||
cvm::to_str(num_biases())+" in total.\n");
|
||||
} else {
|
||||
if (!use_scripted_forces) {
|
||||
cvm::log("No collective variables biases were defined.\n");
|
||||
@ -431,12 +432,37 @@ int colvarmodule::parse_biases(std::string const &conf)
|
||||
}
|
||||
|
||||
|
||||
int colvarmodule::num_variables() const
|
||||
{
|
||||
return colvars.size();
|
||||
}
|
||||
|
||||
|
||||
int colvarmodule::num_variables_feature(int feature_id) const
|
||||
{
|
||||
size_t n = 0;
|
||||
for (std::vector<colvar *>::const_iterator cvi = colvars.begin();
|
||||
cvi != colvars.end();
|
||||
cvi++) {
|
||||
if ((*cvi)->is_enabled(feature_id)) {
|
||||
n++;
|
||||
}
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
int colvarmodule::num_biases() const
|
||||
{
|
||||
return biases.size();
|
||||
}
|
||||
|
||||
|
||||
int colvarmodule::num_biases_feature(int feature_id) const
|
||||
{
|
||||
colvarmodule *cv = cvm::main();
|
||||
size_t n = 0;
|
||||
for (std::vector<colvarbias *>::iterator bi = cv->biases.begin();
|
||||
bi != cv->biases.end();
|
||||
for (std::vector<colvarbias *>::const_iterator bi = biases.begin();
|
||||
bi != biases.end();
|
||||
bi++) {
|
||||
if ((*bi)->is_enabled(feature_id)) {
|
||||
n++;
|
||||
@ -448,10 +474,9 @@ int colvarmodule::num_biases_feature(int feature_id) const
|
||||
|
||||
int colvarmodule::num_biases_type(std::string const &type) const
|
||||
{
|
||||
colvarmodule *cv = cvm::main();
|
||||
size_t n = 0;
|
||||
for (std::vector<colvarbias *>::iterator bi = cv->biases.begin();
|
||||
bi != cv->biases.end();
|
||||
for (std::vector<colvarbias *>::const_iterator bi = biases.begin();
|
||||
bi != biases.end();
|
||||
bi++) {
|
||||
if ((*bi)->bias_type == type) {
|
||||
n++;
|
||||
@ -465,7 +490,7 @@ std::vector<std::string> const colvarmodule::time_dependent_biases() const
|
||||
{
|
||||
size_t i;
|
||||
std::vector<std::string> biases_names;
|
||||
for (i = 0; i < biases.size(); i++) {
|
||||
for (i = 0; i < num_biases(); i++) {
|
||||
if (biases[i]->is_enabled(colvardeps::f_cvb_apply_force) &&
|
||||
biases[i]->is_enabled(colvardeps::f_cvb_active) &&
|
||||
(biases[i]->is_enabled(colvardeps::f_cvb_history_dependent) ||
|
||||
@ -790,7 +815,7 @@ int colvarmodule::calc_biases()
|
||||
{
|
||||
// update the biases and communicate their forces to the collective
|
||||
// variables
|
||||
if (cvm::debug() && biases.size())
|
||||
if (cvm::debug() && num_biases())
|
||||
cvm::log("Updating collective variable biases.\n");
|
||||
|
||||
std::vector<colvarbias *>::iterator bi;
|
||||
@ -852,7 +877,7 @@ int colvarmodule::update_colvar_forces()
|
||||
std::vector<colvarbias *>::iterator bi;
|
||||
|
||||
// sum the forces from all biases for each collective variable
|
||||
if (cvm::debug() && biases.size())
|
||||
if (cvm::debug() && num_biases())
|
||||
cvm::log("Collecting forces from all biases.\n");
|
||||
cvm::increase_depth();
|
||||
for (bi = biases_active()->begin(); bi != biases_active()->end(); bi++) {
|
||||
@ -1073,8 +1098,6 @@ int colvarmodule::reset()
|
||||
|
||||
int colvarmodule::setup_input()
|
||||
{
|
||||
if (this->size() == 0) return cvm::get_error();
|
||||
|
||||
std::string restart_in_name("");
|
||||
|
||||
// read the restart configuration, if available
|
||||
@ -1107,14 +1130,12 @@ int colvarmodule::setup_input()
|
||||
}
|
||||
}
|
||||
|
||||
return (cvm::get_error() ? COLVARS_ERROR : COLVARS_OK);
|
||||
return cvm::get_error();
|
||||
}
|
||||
|
||||
|
||||
int colvarmodule::setup_output()
|
||||
{
|
||||
if (this->size() == 0) return cvm::get_error();
|
||||
|
||||
int error_code = COLVARS_OK;
|
||||
|
||||
// output state file (restart)
|
||||
@ -1123,7 +1144,8 @@ int colvarmodule::setup_output()
|
||||
std::string("");
|
||||
|
||||
if (restart_out_name.size()) {
|
||||
cvm::log("The restart output state file will be \""+restart_out_name+"\".\n");
|
||||
cvm::log("The restart output state file will be \""+
|
||||
restart_out_name+"\".\n");
|
||||
}
|
||||
|
||||
output_prefix() = proxy->output_prefix();
|
||||
@ -1154,7 +1176,7 @@ int colvarmodule::setup_output()
|
||||
set_error_bits(FILE_ERROR);
|
||||
}
|
||||
|
||||
return (cvm::get_error() ? COLVARS_ERROR : COLVARS_OK);
|
||||
return cvm::get_error();
|
||||
}
|
||||
|
||||
|
||||
@ -1738,6 +1760,89 @@ int cvm::load_coords_xyz(char const *filename,
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Wrappers to proxy functions: these may go in the future
|
||||
|
||||
cvm::real cvm::unit_angstrom()
|
||||
{
|
||||
return proxy->unit_angstrom();
|
||||
}
|
||||
|
||||
|
||||
cvm::real cvm::boltzmann()
|
||||
{
|
||||
return proxy->boltzmann();
|
||||
}
|
||||
|
||||
|
||||
cvm::real cvm::temperature()
|
||||
{
|
||||
return proxy->temperature();
|
||||
}
|
||||
|
||||
|
||||
cvm::real cvm::dt()
|
||||
{
|
||||
return proxy->dt();
|
||||
}
|
||||
|
||||
|
||||
void cvm::request_total_force()
|
||||
{
|
||||
proxy->request_total_force(true);
|
||||
}
|
||||
|
||||
cvm::rvector cvm::position_distance(atom_pos const &pos1,
|
||||
atom_pos const &pos2)
|
||||
{
|
||||
return proxy->position_distance(pos1, pos2);
|
||||
}
|
||||
|
||||
cvm::real cvm::position_dist2(cvm::atom_pos const &pos1,
|
||||
cvm::atom_pos const &pos2)
|
||||
{
|
||||
return proxy->position_dist2(pos1, pos2);
|
||||
}
|
||||
|
||||
cvm::real cvm::rand_gaussian(void)
|
||||
{
|
||||
return proxy->rand_gaussian();
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool cvm::replica_enabled()
|
||||
{
|
||||
return proxy->replica_enabled();
|
||||
}
|
||||
|
||||
int cvm::replica_index()
|
||||
{
|
||||
return proxy->replica_index();
|
||||
}
|
||||
|
||||
int cvm::replica_num()
|
||||
{
|
||||
return proxy->replica_num();
|
||||
}
|
||||
|
||||
void cvm::replica_comm_barrier()
|
||||
{
|
||||
return proxy->replica_comm_barrier();
|
||||
}
|
||||
|
||||
int cvm::replica_comm_recv(char* msg_data, int buf_len, int src_rep)
|
||||
{
|
||||
return proxy->replica_comm_recv(msg_data,buf_len,src_rep);
|
||||
}
|
||||
|
||||
int cvm::replica_comm_send(char* msg_data, int msg_len, int dest_rep)
|
||||
{
|
||||
return proxy->replica_comm_send(msg_data,msg_len,dest_rep);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// shared pointer to the proxy object
|
||||
colvarproxy *colvarmodule::proxy = NULL;
|
||||
|
||||
|
||||
@ -39,16 +39,14 @@ You can browse the class hierarchy or the list of source files.
|
||||
#define FILE_ERROR (1<<4)
|
||||
#define MEMORY_ERROR (1<<5)
|
||||
#define FATAL_ERROR (1<<6) // Should be set, or not, together with other bits
|
||||
#define DELETE_COLVARS (1<<7) // Instruct the caller to delete cvm
|
||||
//#define DELETE_COLVARS (1<<7) // Instruct the caller to delete cvm
|
||||
#define COLVARS_NO_SUCH_FRAME (1<<8) // Cannot load the requested frame
|
||||
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
#include <cmath>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <list>
|
||||
|
||||
@ -84,12 +82,18 @@ public:
|
||||
/// Defining an abstract real number allows to switch precision
|
||||
typedef double real;
|
||||
|
||||
/// Override std::pow with a product for n positive integer
|
||||
static inline real integer_power(real x, int n)
|
||||
/// Override std::pow with a product for n integer
|
||||
static inline real integer_power(real const &x, int const n)
|
||||
{
|
||||
real result = 1.0;
|
||||
for (int i = 0; i < n; i++) result *= x;
|
||||
return result;
|
||||
// Original code: math_special.h in LAMMPS
|
||||
double yy, ww;
|
||||
if (x == 0.0) return 0.0;
|
||||
int nn = (n > 0) ? n : -n;
|
||||
ww = x;
|
||||
for (yy = 1.0; nn != 0; nn >>= 1, ww *=ww) {
|
||||
if (nn & 1) yy *= ww;
|
||||
}
|
||||
return (n > 0) ? yy : 1.0/yy;
|
||||
}
|
||||
|
||||
/// Residue identifier
|
||||
@ -301,13 +305,23 @@ private:
|
||||
|
||||
public:
|
||||
|
||||
/// Return how many variables are defined
|
||||
int num_variables() const;
|
||||
|
||||
/// Return how many variables have this feature enabled
|
||||
int num_variables_feature(int feature_id) const;
|
||||
|
||||
/// Return how many biases are defined
|
||||
int num_biases() const;
|
||||
|
||||
/// Return how many biases have this feature enabled
|
||||
int num_biases_feature(int feature_id) const;
|
||||
|
||||
/// Return how many biases are defined with this type
|
||||
/// Return how many biases of this type are defined
|
||||
int num_biases_type(std::string const &type) const;
|
||||
|
||||
/// Return the names of time-dependent biases with forces enabled
|
||||
/// Return the names of time-dependent biases with forces enabled (ABF,
|
||||
/// metadynamics, etc)
|
||||
std::vector<std::string> const time_dependent_biases() const;
|
||||
|
||||
private:
|
||||
@ -602,16 +616,14 @@ public:
|
||||
typedef colvarmodule cvm;
|
||||
|
||||
|
||||
#include "colvartypes.h"
|
||||
|
||||
|
||||
std::ostream & operator << (std::ostream &os, cvm::rvector const &v);
|
||||
std::istream & operator >> (std::istream &is, cvm::rvector &v);
|
||||
|
||||
|
||||
template<typename T> std::string cvm::to_str(T const &x,
|
||||
size_t const &width,
|
||||
size_t const &prec) {
|
||||
size_t const &width,
|
||||
size_t const &prec) {
|
||||
std::ostringstream os;
|
||||
if (width) os.width(width);
|
||||
if (prec) {
|
||||
@ -622,9 +634,10 @@ template<typename T> std::string cvm::to_str(T const &x,
|
||||
return os.str();
|
||||
}
|
||||
|
||||
|
||||
template<typename T> std::string cvm::to_str(std::vector<T> const &x,
|
||||
size_t const &width,
|
||||
size_t const &prec) {
|
||||
size_t const &width,
|
||||
size_t const &prec) {
|
||||
if (!x.size()) return std::string("");
|
||||
std::ostringstream os;
|
||||
if (prec) {
|
||||
@ -645,70 +658,4 @@ template<typename T> std::string cvm::to_str(std::vector<T> const &x,
|
||||
}
|
||||
|
||||
|
||||
#include "colvarproxy.h"
|
||||
|
||||
|
||||
inline cvm::real cvm::unit_angstrom()
|
||||
{
|
||||
return proxy->unit_angstrom();
|
||||
}
|
||||
|
||||
inline cvm::real cvm::boltzmann()
|
||||
{
|
||||
return proxy->boltzmann();
|
||||
}
|
||||
|
||||
inline cvm::real cvm::temperature()
|
||||
{
|
||||
return proxy->temperature();
|
||||
}
|
||||
|
||||
inline cvm::real cvm::dt()
|
||||
{
|
||||
return proxy->dt();
|
||||
}
|
||||
|
||||
// Replica exchange commands
|
||||
inline bool cvm::replica_enabled() {
|
||||
return proxy->replica_enabled();
|
||||
}
|
||||
inline int cvm::replica_index() {
|
||||
return proxy->replica_index();
|
||||
}
|
||||
inline int cvm::replica_num() {
|
||||
return proxy->replica_num();
|
||||
}
|
||||
inline void cvm::replica_comm_barrier() {
|
||||
return proxy->replica_comm_barrier();
|
||||
}
|
||||
inline int cvm::replica_comm_recv(char* msg_data, int buf_len, int src_rep) {
|
||||
return proxy->replica_comm_recv(msg_data,buf_len,src_rep);
|
||||
}
|
||||
inline int cvm::replica_comm_send(char* msg_data, int msg_len, int dest_rep) {
|
||||
return proxy->replica_comm_send(msg_data,msg_len,dest_rep);
|
||||
}
|
||||
|
||||
|
||||
inline void cvm::request_total_force()
|
||||
{
|
||||
proxy->request_total_force(true);
|
||||
}
|
||||
|
||||
inline cvm::rvector cvm::position_distance(atom_pos const &pos1,
|
||||
atom_pos const &pos2)
|
||||
{
|
||||
return proxy->position_distance(pos1, pos2);
|
||||
}
|
||||
|
||||
inline cvm::real cvm::position_dist2(cvm::atom_pos const &pos1,
|
||||
cvm::atom_pos const &pos2)
|
||||
{
|
||||
return proxy->position_dist2(pos1, pos2);
|
||||
}
|
||||
|
||||
inline cvm::real cvm::rand_gaussian(void)
|
||||
{
|
||||
return proxy->rand_gaussian();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@ -553,7 +553,8 @@ bool colvarparse::key_lookup(std::string const &conf,
|
||||
size_t *save_pos)
|
||||
{
|
||||
if (cvm::debug()) {
|
||||
cvm::log("Looking for the keyword \""+std::string(key_in)+"\" and its value.\n");
|
||||
cvm::log("Looking for the keyword \""+std::string(key_in)+
|
||||
"\" and its value.\n");
|
||||
}
|
||||
|
||||
// add this keyword to the register (in its camelCase version)
|
||||
|
||||
@ -14,6 +14,11 @@
|
||||
#include <omp.h>
|
||||
#endif
|
||||
|
||||
#if defined(NAMD_TCL) || defined(VMDTCL)
|
||||
#define COLVARS_TCL
|
||||
#include <tcl.h>
|
||||
#endif
|
||||
|
||||
#include "colvarmodule.h"
|
||||
#include "colvarproxy.h"
|
||||
#include "colvarscript.h"
|
||||
@ -420,8 +425,10 @@ colvarproxy_script::colvarproxy_script()
|
||||
colvarproxy_script::~colvarproxy_script() {}
|
||||
|
||||
|
||||
char *colvarproxy_script::script_obj_to_str(unsigned char *obj)
|
||||
char const *colvarproxy_script::script_obj_to_str(unsigned char *obj)
|
||||
{
|
||||
cvm::error("Error: trying to print a script object without a scripting "
|
||||
"language interface.\n", BUG_ERROR);
|
||||
return reinterpret_cast<char *>(obj);
|
||||
}
|
||||
|
||||
@ -451,6 +458,140 @@ int colvarproxy_script::run_colvar_gradient_callback(
|
||||
|
||||
|
||||
|
||||
colvarproxy_tcl::colvarproxy_tcl()
|
||||
{
|
||||
_tcl_interp = NULL;
|
||||
}
|
||||
|
||||
|
||||
colvarproxy_tcl::~colvarproxy_tcl()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void colvarproxy_tcl::init_tcl_pointers()
|
||||
{
|
||||
cvm::error("Error: Tcl support is currently unavailable "
|
||||
"outside NAMD or VMD.\n", COLVARS_NOT_IMPLEMENTED);
|
||||
}
|
||||
|
||||
|
||||
char const *colvarproxy_tcl::tcl_obj_to_str(unsigned char *obj)
|
||||
{
|
||||
#if defined(COLVARS_TCL)
|
||||
return Tcl_GetString(reinterpret_cast<Tcl_Obj *>(obj));
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int colvarproxy_tcl::tcl_run_force_callback()
|
||||
{
|
||||
#if defined(COLVARS_TCL)
|
||||
Tcl_Interp *const tcl_interp = reinterpret_cast<Tcl_Interp *>(_tcl_interp);
|
||||
std::string cmd = std::string("calc_colvar_forces ")
|
||||
+ cvm::to_str(cvm::step_absolute());
|
||||
int err = Tcl_Eval(tcl_interp, cmd.c_str());
|
||||
if (err != TCL_OK) {
|
||||
cvm::log(std::string("Error while executing calc_colvar_forces:\n"));
|
||||
cvm::error(Tcl_GetStringResult(tcl_interp));
|
||||
return COLVARS_ERROR;
|
||||
}
|
||||
return cvm::get_error();
|
||||
#else
|
||||
return COLVARS_NOT_IMPLEMENTED;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int colvarproxy_tcl::tcl_run_colvar_callback(
|
||||
std::string const &name,
|
||||
std::vector<const colvarvalue *> const &cvc_values,
|
||||
colvarvalue &value)
|
||||
{
|
||||
#if defined(COLVARS_TCL)
|
||||
|
||||
Tcl_Interp *const tcl_interp = reinterpret_cast<Tcl_Interp *>(_tcl_interp);
|
||||
size_t i;
|
||||
std::string cmd = std::string("calc_") + name;
|
||||
for (i = 0; i < cvc_values.size(); i++) {
|
||||
cmd += std::string(" {") + (*(cvc_values[i])).to_simple_string() +
|
||||
std::string("}");
|
||||
}
|
||||
int err = Tcl_Eval(tcl_interp, cmd.c_str());
|
||||
const char *result = Tcl_GetStringResult(tcl_interp);
|
||||
if (err != TCL_OK) {
|
||||
return cvm::error(std::string("Error while executing ")
|
||||
+ cmd + std::string(":\n") +
|
||||
std::string(Tcl_GetStringResult(tcl_interp)), COLVARS_ERROR);
|
||||
}
|
||||
std::istringstream is(result);
|
||||
if (value.from_simple_string(is.str()) != COLVARS_OK) {
|
||||
cvm::log("Error parsing colvar value from script:");
|
||||
cvm::error(result);
|
||||
return COLVARS_ERROR;
|
||||
}
|
||||
return cvm::get_error();
|
||||
|
||||
#else
|
||||
|
||||
return COLVARS_NOT_IMPLEMENTED;
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int colvarproxy_tcl::tcl_run_colvar_gradient_callback(
|
||||
std::string const &name,
|
||||
std::vector<const colvarvalue *> const &cvc_values,
|
||||
std::vector<cvm::matrix2d<cvm::real> > &gradient)
|
||||
{
|
||||
#if defined(COLVARS_TCL)
|
||||
|
||||
Tcl_Interp *const tcl_interp = reinterpret_cast<Tcl_Interp *>(_tcl_interp);
|
||||
size_t i;
|
||||
std::string cmd = std::string("calc_") + name + "_gradient";
|
||||
for (i = 0; i < cvc_values.size(); i++) {
|
||||
cmd += std::string(" {") + (*(cvc_values[i])).to_simple_string() +
|
||||
std::string("}");
|
||||
}
|
||||
int err = Tcl_Eval(tcl_interp, cmd.c_str());
|
||||
if (err != TCL_OK) {
|
||||
return cvm::error(std::string("Error while executing ")
|
||||
+ cmd + std::string(":\n") +
|
||||
std::string(Tcl_GetStringResult(tcl_interp)), COLVARS_ERROR);
|
||||
}
|
||||
Tcl_Obj **list;
|
||||
int n;
|
||||
Tcl_ListObjGetElements(tcl_interp, Tcl_GetObjResult(tcl_interp),
|
||||
&n, &list);
|
||||
if (n != int(gradient.size())) {
|
||||
cvm::error("Error parsing list of gradient values from script: found "
|
||||
+ cvm::to_str(n) + " values instead of " +
|
||||
cvm::to_str(gradient.size()));
|
||||
return COLVARS_ERROR;
|
||||
}
|
||||
for (i = 0; i < gradient.size(); i++) {
|
||||
std::istringstream is(Tcl_GetString(list[i]));
|
||||
if (gradient[i].from_simple_string(is.str()) != COLVARS_OK) {
|
||||
cvm::log("Gradient matrix size: " + cvm::to_str(gradient[i].size()));
|
||||
cvm::log("Gradient string: " + cvm::to_str(Tcl_GetString(list[i])));
|
||||
cvm::error("Error parsing gradient value from script", COLVARS_ERROR);
|
||||
return COLVARS_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
return cvm::get_error();
|
||||
|
||||
#else
|
||||
|
||||
return COLVARS_NOT_IMPLEMENTED;
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
colvarproxy_io::colvarproxy_io() {}
|
||||
|
||||
@ -541,6 +682,7 @@ colvarproxy::colvarproxy()
|
||||
{
|
||||
colvars = NULL;
|
||||
b_simulation_running = true;
|
||||
b_delete_requested = false;
|
||||
}
|
||||
|
||||
|
||||
@ -556,6 +698,14 @@ int colvarproxy::reset()
|
||||
}
|
||||
|
||||
|
||||
int colvarproxy::request_deletion()
|
||||
{
|
||||
return cvm::error("Error: \"delete\" command is only available in VMD; "
|
||||
"please use \"reset\" instead.\n",
|
||||
COLVARS_NOT_IMPLEMENTED);
|
||||
}
|
||||
|
||||
|
||||
int colvarproxy::setup()
|
||||
{
|
||||
return COLVARS_OK;
|
||||
@ -579,13 +729,3 @@ size_t colvarproxy::restart_frequency()
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -415,7 +415,7 @@ public:
|
||||
};
|
||||
|
||||
|
||||
/// Method for scripting language interface (Tcl or Python)
|
||||
/// Methods for scripting language interface (Tcl or Python)
|
||||
class colvarproxy_script {
|
||||
|
||||
public:
|
||||
@ -427,7 +427,7 @@ public:
|
||||
virtual ~colvarproxy_script();
|
||||
|
||||
/// Convert a script object (Tcl or Python call argument) to a C string
|
||||
virtual char *script_obj_to_str(unsigned char *obj);
|
||||
virtual char const *script_obj_to_str(unsigned char *obj);
|
||||
|
||||
/// Pointer to the scripting interface object
|
||||
/// (does not need to be allocated in a new interface)
|
||||
@ -454,6 +454,46 @@ public:
|
||||
};
|
||||
|
||||
|
||||
/// Methods for using Tcl within Colvars
|
||||
class colvarproxy_tcl {
|
||||
|
||||
public:
|
||||
|
||||
/// Constructor
|
||||
colvarproxy_tcl();
|
||||
|
||||
/// Destructor
|
||||
virtual ~colvarproxy_tcl();
|
||||
|
||||
/// Is Tcl available? (trigger initialization if needed)
|
||||
int tcl_available();
|
||||
|
||||
/// Tcl implementation of script_obj_to_str()
|
||||
char const *tcl_obj_to_str(unsigned char *obj);
|
||||
|
||||
/// Run a user-defined colvar forces script
|
||||
int tcl_run_force_callback();
|
||||
|
||||
int tcl_run_colvar_callback(
|
||||
std::string const &name,
|
||||
std::vector<const colvarvalue *> const &cvcs,
|
||||
colvarvalue &value);
|
||||
|
||||
int tcl_run_colvar_gradient_callback(
|
||||
std::string const &name,
|
||||
std::vector<const colvarvalue *> const &cvcs,
|
||||
std::vector<cvm::matrix2d<cvm::real> > &gradient);
|
||||
|
||||
protected:
|
||||
|
||||
/// Pointer to Tcl interpreter object
|
||||
void *_tcl_interp;
|
||||
|
||||
/// Set Tcl pointers
|
||||
virtual void init_tcl_pointers();
|
||||
};
|
||||
|
||||
|
||||
/// Methods for data input/output
|
||||
class colvarproxy_io {
|
||||
|
||||
@ -540,6 +580,7 @@ class colvarproxy
|
||||
public colvarproxy_smp,
|
||||
public colvarproxy_replicas,
|
||||
public colvarproxy_script,
|
||||
public colvarproxy_tcl,
|
||||
public colvarproxy_io
|
||||
{
|
||||
|
||||
@ -554,6 +595,15 @@ public:
|
||||
/// Destructor
|
||||
virtual ~colvarproxy();
|
||||
|
||||
/// Request deallocation of the module (currently only implemented by VMD)
|
||||
virtual int request_deletion();
|
||||
|
||||
/// Whether deallocation was requested
|
||||
inline bool delete_requested()
|
||||
{
|
||||
return b_delete_requested;
|
||||
}
|
||||
|
||||
/// \brief Reset proxy state, e.g. requested atoms
|
||||
virtual int reset();
|
||||
|
||||
@ -591,6 +641,9 @@ protected:
|
||||
/// Whether a simulation is running (warn against irrecovarable errors)
|
||||
bool b_simulation_running;
|
||||
|
||||
/// Whether the entire module should be deallocated by the host engine
|
||||
bool b_delete_requested;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
#ifndef COLVARS_VERSION
|
||||
#define COLVARS_VERSION "2017-10-20"
|
||||
#define COLVARS_VERSION "2018-01-17"
|
||||
// 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
|
||||
|
||||
@ -74,7 +74,9 @@ int colvarscript::run(int objc, unsigned char *const objv[])
|
||||
}
|
||||
|
||||
if (objc < 2) {
|
||||
return exec_command(cv_help, NULL, objc, objv);
|
||||
set_str_result("No commands given: use \"cv help\" "
|
||||
"for a list of commands.");
|
||||
return COLVARSCRIPT_ERROR;
|
||||
}
|
||||
|
||||
std::string const cmd(obj_to_str(objv[1]));
|
||||
@ -123,8 +125,7 @@ int colvarscript::run(int objc, unsigned char *const objv[])
|
||||
if (cmd == "delete") {
|
||||
// Note: the delete bit may be ignored by some backends
|
||||
// it is mostly useful in VMD
|
||||
colvars->set_error_bits(DELETE_COLVARS);
|
||||
return COLVARS_OK;
|
||||
return proxy->request_deletion();
|
||||
}
|
||||
|
||||
if (cmd == "update") {
|
||||
@ -272,6 +273,11 @@ int colvarscript::proc_colvar(colvar *cv, int objc, unsigned char *const objv[])
|
||||
return COLVARS_OK;
|
||||
}
|
||||
|
||||
if (subcmd == "run_ave") {
|
||||
result = (cv->run_ave()).to_simple_string();
|
||||
return COLVARS_OK;
|
||||
}
|
||||
|
||||
if (subcmd == "width") {
|
||||
result = cvm::to_str(cv->width, 0, cvm::cv_prec);
|
||||
return COLVARS_OK;
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
#ifndef COLVARPROXY_VERSION
|
||||
#define COLVARPROXY_VERSION "2017-10-20"
|
||||
#define COLVARPROXY_VERSION "2017-12-01"
|
||||
// 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
|
||||
|
||||
Reference in New Issue
Block a user