Files
lammps/lib/colvars/colvardeps.h
Giacomo Fiorin 1220bea011 Update Colvars to version 2022-05-09
This update includes one new feature (neural-network based collective
variables), several small enhancements (including an automatic definition of
grid boundaries for angle-based CVs, and a normalization option for
eigenvector-based CVs), bugfixes and documentation improvements.

Usage information for specific features included in the Colvars library
(i.e. not just the library as a whole) is now also reported to the screen or
LAMMPS logfile (as is done already in other LAMMPS classes).

Notable to LAMMPS code development are the removals of duplicated code and of
ambiguously-named preprocessor defines in the Colvars headers.  Since the
last PR, the existing regression tests have also been running automatically
via GitHub Actions.

The following pull requests in the Colvars repository are relevant to LAMMPS:

- 475 Remove fatal error condition
  https://github.com/Colvars/colvars/pull/475 (@jhenin, @giacomofiorin)

- 474 Allow normalizing eigenvector vector components to deal with unit change
  https://github.com/Colvars/colvars/pull/474 (@giacomofiorin, @jhenin)

- 470 Better error handling in the initialization of NeuralNetwork CV
  https://github.com/Colvars/colvars/pull/470 (@HanatoK)

- 468 Add examples of histogram configuration, with and without explicit grid parameters
  https://github.com/Colvars/colvars/pull/468 (@giacomofiorin)

- 464 Fix #463 using more fine-grained features
  https://github.com/Colvars/colvars/pull/464 (@jhenin, @giacomofiorin)

- 447 [RFC] New option "scaledBiasingForce" for colvarbias
  https://github.com/Colvars/colvars/pull/447 (@HanatoK, @jhenin)

- 444 [RFC] Implementation of dense neural network as CV
  https://github.com/Colvars/colvars/pull/444 (@HanatoK, @giacomofiorin, @jhenin)

- 443 Fix explicit gradient dependency of sub-CVs
  https://github.com/Colvars/colvars/pull/443 (@HanatoK, @jhenin)

- 442 Persistent bias count
  https://github.com/Colvars/colvars/pull/442 (@jhenin, @giacomofiorin)

- 437 Return type of bias from scripting interface
  https://github.com/Colvars/colvars/pull/437 (@giacomofiorin)

- 434 More flexible use of boundaries from colvars by grids
  https://github.com/Colvars/colvars/pull/434 (@jhenin)

- 433 Prevent double-free in linearCombination
  https://github.com/Colvars/colvars/pull/433 (@HanatoK)

- 428 More complete documentation for index file format (NDX)
  https://github.com/Colvars/colvars/pull/428 (@giacomofiorin)

- 426 Integrate functional version of backup_file() into base proxy class
  https://github.com/Colvars/colvars/pull/426 (@giacomofiorin)

- 424 Track CVC inheritance when documenting feature usage
  https://github.com/Colvars/colvars/pull/424 (@giacomofiorin)

- 419 Generate citation report while running computations
  https://github.com/Colvars/colvars/pull/419 (@giacomofiorin, @jhenin)

- 415 Rebin metadynamics bias from explicit hills when available
  https://github.com/Colvars/colvars/pull/415 (@giacomofiorin)

- 312 Ignore a keyword if it has content to the left of it (regardless of braces)
  https://github.com/Colvars/colvars/pull/312 (@giacomofiorin)

Authors: @giacomofiorin, @HanatoK, @jhenin
2022-05-10 11:24:54 -04:00

443 lines
17 KiB
C++

// -*- c++ -*-
// This file is part of the Collective Variables module (Colvars).
// The original version of Colvars and its updates are located at:
// https://github.com/Colvars/colvars
// Please update all Colvars source files before making any changes.
// If you wish to distribute your changes, please submit them to the
// Colvars repository at GitHub.
#ifndef COLVARDEPS_H
#define COLVARDEPS_H
#include "colvarmodule.h"
#include "colvarparse.h"
/// \brief Parent class for a member object of a bias, cv or cvc etc. containing features and
/// their dependencies, and handling dependency resolution
///
/// There are 3 kinds of features:
/// 1. Dynamic features are under the control of the dependency resolution
/// system. They may be enabled or disabled depending on dependencies.
/// 2. User features may be enabled based on user input (they may trigger a failure upon dependency resolution, though)
/// 3. Static features are static properties of the object, determined
/// programmatically at initialization time.
///
/// The following diagram summarizes the dependency tree at the bias, colvar, and colvarcomp levels.
/// Isolated and atom group features are not shown to save space.
/// @image html deps_2019.svg
///
/// In all classes, feature 0 is `active`. When an object is inactivated
/// all its children dependencies are dereferenced (free_children_deps)
/// While the object is inactive, no dependency solving is done on children
/// it is done when the object is activated back (restore_children_deps)
class colvardeps {
public:
colvardeps();
virtual ~colvardeps();
// Subclasses should initialize the following members:
std::string description; // reference to object name (cv, cvc etc.)
/// This contains the current state of each feature for each object
// since the feature class only contains static properties
struct feature_state {
feature_state(bool a, bool e)
: available(a), enabled(e), ref_count(0) {}
/// Feature may be enabled, subject to possible dependencies
bool available;
/// Currently enabled - this flag is subject to change dynamically
/// TODO consider implications for dependency solving: anyone who disables
/// it should trigger a refresh of parent objects
bool enabled; // see if this should be private depending on implementation
// bool enabledOnce; // this should trigger an update when object is evaluated
/// Number of features requiring this one as a dependency
/// When it falls to zero:
/// - a dynamic feature is disabled automatically
/// - other features may be disabled statically
int ref_count;
/// List of features that were enabled by this one
/// as part of an alternate requirement (for ref counting purposes)
/// This is necessary because we don't know which feature in the list
/// we enabled, otherwise
std::vector<int> alternate_refs;
};
protected:
/// Time step multiplier (for coarse-timestep biases & colvars)
/// Biases and colvars will only be calculated at those times
/// (f_cvb_awake and f_cv_awake); a
/// Biases use this to apply "impulse" biasing forces at the outer timestep
/// Unused by lower-level objects (cvcs and atom groups)
int time_step_factor;
/// List of the states of all features
std::vector<feature_state> feature_states;
/// Enum of possible feature types
enum feature_type {
f_type_not_set,
f_type_dynamic,
f_type_user,
f_type_static
};
public:
/// \brief returns time_step_factor
inline int get_time_step_factor() const {return time_step_factor;}
/// Pair a numerical feature ID with a description and type
void init_feature(int feature_id, const char *description, feature_type type);
/// Describes a feature and its dependencies
/// used in a static array within each subclass
class feature {
public:
feature() : type(f_type_not_set) {}
~feature() {}
std::string description; // Set by derived object initializer
// features that this feature requires in the same object
// NOTE: we have no safety mechanism against circular dependencies, however, they would have to be internal to an object (ie. requires_self or requires_alt)
std::vector<int> requires_self;
// Features that are incompatible, ie. required disabled
// if enabled, they will cause a dependency failure (they will not be disabled)
// To enforce these dependencies regardless of the order in which they
// are enabled, they are always set in a symmetric way, so whichever is enabled
// second will cause the dependency to fail
std::vector<int> requires_exclude;
// sets of features that are required in an alternate way
// when parent feature is enabled, if none are enabled, the first one listed that is available will be enabled
std::vector<std::vector<int> > requires_alt;
// features that this feature requires in children
std::vector<int> requires_children;
inline bool is_dynamic() { return type == f_type_dynamic; }
inline bool is_static() { return type == f_type_static; }
inline bool is_user() { return type == f_type_user; }
/// Type of this feature, from the enum feature_type
feature_type type;
};
inline bool is_not_set(int id) { return features()[id]->type == f_type_not_set; }
inline bool is_dynamic(int id) { return features()[id]->type == f_type_dynamic; }
inline bool is_static(int id) { return features()[id]->type == f_type_static; }
inline bool is_user(int id) { return features()[id]->type == f_type_user; }
// Accessor to array of all features with deps, static in most derived classes
// Subclasses with dynamic dependency trees may override this
// with a non-static array
// Intermediate classes (colvarbias and colvarcomp, which are also base classes)
// implement this as virtual to allow overriding
virtual const std::vector<feature *> &features() const = 0;
virtual std::vector<feature *>&modify_features() = 0;
void add_child(colvardeps *child);
void remove_child(colvardeps *child);
/// Used before deleting an object, if not handled by that object's destructor
/// (useful for cvcs because their children are member objects)
void remove_all_children();
private:
/// pointers to objects this object depends on
/// list should be maintained by any code that modifies the object
/// this could be secured by making lists of colvars / cvcs / atom groups private and modified through accessor functions
std::vector<colvardeps *> children;
/// pointers to objects that depend on this object
/// the size of this array is in effect a reference counter
std::vector<colvardeps *> parents;
public:
// Checks whether given feature is enabled
// Defaults to querying f_*_active
inline bool is_enabled(int f = f_cv_active) const {
return feature_states[f].enabled;
}
// Checks whether given feature is available
// Defaults to querying f_*_active
inline bool is_available(int f = f_cv_active) const {
return feature_states[f].available;
}
/// Set the feature's available flag, without checking
/// To be used for dynamic properties
/// dependencies will be checked by enable()
void provide(int feature_id, bool truefalse = true);
/// Enable or disable, depending on flag value
void set_enabled(int feature_id, bool truefalse = true);
protected:
/// Parse a keyword and enable a feature accordingly
bool get_keyval_feature(colvarparse *cvp,
std::string const &conf, char const *key,
int feature_id, bool const &def_value,
colvarparse::Parse_Mode const parse_mode = colvarparse::parse_normal);
public:
/// Enable a feature and recursively solve its dependencies.
/// For accurate reference counting, do not add spurious calls to enable()
/// \param dry_run Recursively test whether a feature is available, without enabling it
/// \param toplevel False if this is called as part of a chain of dependency resolution.
/// This is used to diagnose failed dependencies by displaying the full stack:
/// only the toplevel dependency will throw a fatal error.
int enable(int f, bool dry_run = false, bool toplevel = true);
/// Disable a feature, decrease the reference count of its dependencies
/// and recursively disable them as applicable
int disable(int f);
/// disable all enabled features to free their dependencies
/// to be done when deleting the object
/// Cannot be in the base class destructor because it needs the derived class features()
void free_children_deps();
/// re-enable children features (to be used when object becomes active)
void restore_children_deps();
/// Decrement the reference count of a feature
/// disabling it if it's dynamic and count reaches zero
int decr_ref_count(int f);
/// Implements possible actions to be carried out
/// when a given feature is enabled
/// Base function does nothing, can be overloaded
virtual void do_feature_side_effects(int /* id */) {}
// NOTE that all feature enums should start with f_*_active
enum features_biases {
/// \brief Bias is active
f_cvb_active,
/// \brief Bias is awake (active on its own accord) this timestep
f_cvb_awake,
/// Accumulates data starting from step 0 of a simulation run
f_cvb_step_zero_data,
/// \brief will apply forces
f_cvb_apply_force,
/// \brief force this bias to act on actual value for extended-Lagrangian coordinates
f_cvb_bypass_ext_lagrangian,
/// \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
f_cvb_time_dependent,
/// \brief requires scalar colvars
f_cvb_scalar_variables,
/// \brief whether this bias will compute a PMF
f_cvb_calc_pmf,
/// \brief whether this bias will compute TI samples
f_cvb_calc_ti_samples,
/// \brief whether this bias will write TI samples
f_cvb_write_ti_samples,
/// \brief whether this bias should write the TI PMF
f_cvb_write_ti_pmf,
/// \brief whether this bias uses an external grid to scale the biasing forces
f_cvb_scale_biasing_force,
f_cvb_ntot
};
enum features_colvar {
/// \brief Calculate colvar
f_cv_active,
/// \brief Colvar is awake (active on its own accord) this timestep
f_cv_awake,
/// \brief Gradients are calculated and temporarily stored, so
/// that external forces can be applied
f_cv_gradient,
/// \brief Collect atomic gradient data from all cvcs into vector
/// atomic_gradient
f_cv_collect_gradient,
/// \brief Build list of atoms involved in CV calculation
f_cv_collect_atom_ids,
/// \brief Calculate the velocity with finite differences
f_cv_fdiff_velocity,
/// \brief The total force is calculated, projecting the atomic
/// forces on the inverse gradient
f_cv_total_force,
/// \brief Calculate total force from atomic forces
f_cv_total_force_calc,
/// \brief Subtract the applied force from the total force
f_cv_subtract_applied_force,
/// \brief Estimate Jacobian derivative
f_cv_Jacobian,
/// \brief Do not report the Jacobian force as part of the total force
/// instead, apply a correction internally to cancel it
f_cv_hide_Jacobian,
/// \brief The variable has a harmonic restraint around a moving
/// center with fictitious mass; bias forces will be applied to
/// the center
f_cv_extended_Lagrangian,
/// \brief An extended variable that sets an external variable in the
/// back-end (eg. an alchemical coupling parameter for lambda-dynamics)
/// Can have a single component
f_cv_external,
/// \brief The extended system coordinate undergoes Langevin dynamics
f_cv_Langevin,
/// \brief Output the potential and kinetic energies
/// (for extended Lagrangian colvars only)
f_cv_output_energy,
/// \brief Output the value to the trajectory file (on by default)
f_cv_output_value,
/// \brief Output the velocity to the trajectory file
f_cv_output_velocity,
/// \brief Output the applied force to the trajectory file
f_cv_output_applied_force,
/// \brief Output the total force to the trajectory file
f_cv_output_total_force,
/// \brief A lower boundary is defined
f_cv_lower_boundary,
/// \brief An upper boundary is defined
f_cv_upper_boundary,
/// \brief The lower boundary is not defined from user's choice
f_cv_hard_lower_boundary,
/// \brief The upper boundary is not defined from user's choice
f_cv_hard_upper_boundary,
/// \brief Reflecting lower boundary condition
f_cv_reflecting_lower_boundary,
/// \brief Reflecting upper boundary condition
f_cv_reflecting_upper_boundary,
/// \brief Provide a discretization of the values of the colvar to
/// be used by the biases or in analysis (needs lower and upper
/// boundary)
f_cv_grid,
/// \brief Compute running average
f_cv_runave,
/// \brief Compute time correlation function
f_cv_corrfunc,
/// \brief Value and gradient computed by user script
f_cv_scripted,
/// \brief Value and gradient computed by user function through Lepton
f_cv_custom_function,
/// \brief Colvar is periodic
f_cv_periodic,
/// \brief The colvar has only one component
f_cv_single_cvc,
/// \brief is scalar
f_cv_scalar,
f_cv_linear,
f_cv_homogeneous,
/// \brief multiple timestep through time_step_factor
f_cv_multiple_ts,
/// \brief Number of colvar features
f_cv_ntot
};
enum features_cvc {
/// Computation of this CVC is enabled
f_cvc_active,
/// This CVC computes a scalar value
f_cvc_scalar,
/// Values of this CVC lie in a periodic interval
f_cvc_periodic,
/// This CVC provides a default value for the colvar's width
f_cvc_width,
/// This CVC provides a default value for the colvar's lower boundary
f_cvc_lower_boundary,
/// This CVC provides a default value for the colvar's upper boundary
f_cvc_upper_boundary,
/// CVC calculates atom gradients
f_cvc_gradient,
/// CVC calculates and stores explicit atom gradients on rank 0
f_cvc_explicit_gradient,
/// CVC calculates and stores inverse atom gradients (used for total force)
f_cvc_inv_gradient,
/// CVC calculates the Jacobian term of the total-force expression
f_cvc_Jacobian,
/// The total force for this CVC will be computed from one group only
f_cvc_one_site_total_force,
/// calc_gradients() will call debug_gradients() for every group needed
f_cvc_debug_gradient,
/// With PBCs, minimum-image convention will be used for distances
/// (does not affect the periodicity of CVC values, e.g. angles)
f_cvc_pbc_minimum_image,
/// This CVC is a function of centers of mass
f_cvc_com_based,
/// This CVC can be computed in parallel
f_cvc_scalable,
/// Centers-of-mass used in this CVC can be computed in parallel
f_cvc_scalable_com,
/// \brief Build list of atoms involved in CVC calculation
f_cvc_collect_atom_ids,
/// Number of CVC features
f_cvc_ntot
};
enum features_atomgroup {
f_ag_active,
f_ag_center,
f_ag_center_origin,
f_ag_rotate,
f_ag_fitting_group,
/// Perform a standard minimum msd fit for given atoms
/// ie. not using refpositionsgroup
// f_ag_min_msd_fit,
/// \brief Does not have explicit atom gradients from parent CVC
f_ag_explicit_gradient,
f_ag_fit_gradients,
f_ag_atom_forces,
f_ag_scalable,
f_ag_scalable_com,
/// \brief Build list of atoms involved in atom group
f_ag_collect_atom_ids,
f_ag_ntot
};
/// Initialize dependency tree for object of a derived class
virtual int init_dependencies() = 0;
/// Make feature f require feature g within the same object
void require_feature_self(int f, int g);
/// Make features f and g mutually exclusive within the same object
void exclude_feature_self(int f, int g);
/// Make feature f require feature g within children
void require_feature_children(int f, int g);
/// Make feature f require either g or h within the same object
void require_feature_alt(int f, int g, int h);
/// Make feature f require any of g, h, or i within the same object
void require_feature_alt(int f, int g, int h, int i);
/// Make feature f require any of g, h, i, or j within the same object
void require_feature_alt(int f, int g, int h, int i, int j);
/// \brief print all enabled features and those of children, for debugging
void print_state();
/// \brief Check that a feature is enabled, raising COLVARS_BUG_ERROR if not
inline void check_enabled(int f, std::string const &reason) const
{
if (! is_enabled(f)) {
cvm::error("Error: "+reason+" requires that the feature \""+
features()[f]->description+"\" is active.\n", COLVARS_BUG_ERROR);
}
}
};
#endif