2016-06-18 07:07:51 +08:00
// -*- c++ -*-
2016-04-16 00:07:28 +08:00
2016-12-28 02:17:34 +08:00
// 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.
2016-04-16 00:07:28 +08:00
# ifndef COLVARDEPS_H
# define COLVARDEPS_H
2016-09-09 04:20:32 +08:00
# include "colvarmodule.h"
# include "colvarparse.h"
2017-03-10 22:16:58 +08:00
/// \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
/// programatically at initialization time.
///
2019-04-30 21:50:12 +08:00
/// 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
2017-07-20 02:10:43 +08:00
/// 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)
2016-09-09 04:20:32 +08:00
class colvardeps {
2016-04-16 00:07:28 +08:00
public :
2017-07-20 02:10:43 +08:00
colvardeps ( ) ;
2016-09-09 04:20:32 +08:00
virtual ~ colvardeps ( ) ;
2016-04-16 00:07:28 +08:00
// 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
2017-07-20 02:10:43 +08:00
// since the feature class only contains static properties
2016-04-16 00:07:28 +08:00
struct feature_state {
feature_state ( bool a , bool e )
2017-07-20 02:10:43 +08:00
: available ( a ) , enabled ( e ) , ref_count ( 0 ) { }
2016-04-16 00:07:28 +08:00
2017-03-10 22:16:58 +08:00
/// Feature may be enabled, subject to possible dependencies
2016-04-16 00:07:28 +08:00
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
2017-07-20 02:10:43 +08:00
2016-04-16 00:07:28 +08:00
// bool enabledOnce; // this should trigger an update when object is evaluated
2017-07-20 02:10:43 +08:00
/// 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 ;
2016-04-16 00:07:28 +08:00
} ;
2017-07-20 02:10:43 +08:00
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 ;
2017-03-10 22:16:58 +08:00
/// 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 :
2017-07-20 02:10:43 +08:00
/// \brief returns time_step_factor
inline int get_time_step_factor ( ) const { return time_step_factor ; }
2017-03-10 22:16:58 +08:00
/// Pair a numerical feature ID with a description and type
2019-04-30 21:50:12 +08:00
void init_feature ( int feature_id , const char * description , feature_type type ) ;
2016-04-16 00:07:28 +08:00
2017-07-20 02:10:43 +08:00
/// Describes a feature and its dependencies
2016-04-16 00:07:28 +08:00
/// used in a static array within each subclass
class feature {
public :
2019-04-30 21:50:12 +08:00
feature ( ) : type ( f_type_not_set ) { }
2016-04-16 00:07:28 +08:00
~ 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 ;
2017-03-10 22:16:58 +08:00
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 ;
2016-04-16 00:07:28 +08:00
} ;
2019-04-30 21:50:12 +08:00
inline bool is_not_set ( int id ) { return features ( ) [ id ] - > type = = f_type_not_set ; }
2017-03-10 22:16:58 +08:00
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 ; }
2016-04-16 00:07:28 +08:00
// 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
2019-04-30 21:50:12 +08:00
virtual const std : : vector < feature * > & features ( ) const = 0 ;
2017-08-10 21:22:53 +08:00
virtual std : : vector < feature * > & modify_features ( ) = 0 ;
2016-04-16 00:07:28 +08:00
2016-09-09 04:20:32 +08:00
void add_child ( colvardeps * child ) ;
2016-04-16 00:07:28 +08:00
2016-09-09 04:20:32 +08:00
void remove_child ( colvardeps * child ) ;
2016-04-16 00:07:28 +08:00
/// 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 :
2017-03-10 22:16:58 +08:00
2017-07-20 02:10:43 +08:00
/// 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
2016-09-09 04:20:32 +08:00
std : : vector < colvardeps * > children ;
2016-04-16 00:07:28 +08:00
2017-07-20 02:10:43 +08:00
/// pointers to objects that depend on this object
/// the size of this array is in effect a reference counter
2016-09-09 04:20:32 +08:00
std : : vector < colvardeps * > parents ;
2016-04-16 00:07:28 +08:00
public :
// Checks whether given feature is enabled
// Defaults to querying f_*_active
inline bool is_enabled ( int f = f_cv_active ) const {
2017-03-10 22:16:58 +08:00
return feature_states [ f ] . enabled ;
2016-04-16 00:07:28 +08:00
}
// Checks whether given feature is available
// Defaults to querying f_*_active
inline bool is_available ( int f = f_cv_active ) const {
2017-03-10 22:16:58 +08:00
return feature_states [ f ] . available ;
2016-04-16 00:07:28 +08:00
}
2017-03-10 22:16:58 +08:00
/// 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 ) ;
2017-07-20 02:10:43 +08:00
/// Enable or disable, depending on flag value
2017-03-10 22:16:58 +08:00
void set_enabled ( int feature_id , bool truefalse = true ) ;
protected :
2016-09-09 04:20:32 +08:00
/// 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 ) ;
2017-03-10 22:16:58 +08:00
public :
2019-04-30 21:50:12 +08:00
/// Enable a feature and recursively solve its dependencies.
/// For accurate reference counting, do not add spurious calls to enable()
/// \param dry_run Recursively test if 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.
2017-07-20 02:10:43 +08:00
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 ( ) ;
2016-04-16 00:07:28 +08:00
2017-07-20 02:10:43 +08:00
/// Decrement the reference count of a feature
/// disabling it if it's dynamic and count reaches zero
int decr_ref_count ( int f ) ;
2016-04-16 00:07:28 +08:00
2017-07-20 02:10:43 +08:00
/// 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 ) { }
2016-04-16 00:07:28 +08:00
// NOTE that all feature enums should start with f_*_active
enum features_biases {
/// \brief Bias is active
f_cvb_active ,
2017-07-20 02:10:43 +08:00
/// \brief Bias is awake (active on its own accord) this timestep
f_cvb_awake ,
/// \brief will apply forces
f_cvb_apply_force ,
/// \brief requires total forces
f_cvb_get_total_force ,
2018-02-23 21:34:53 +08:00
/// \brief whether this bias should record the accumulated work
f_cvb_output_acc_work ,
2017-07-20 02:10:43 +08:00
/// \brief depends on simulation history
f_cvb_history_dependent ,
2017-10-14 01:25:02 +08:00
/// \brief depends on time
f_cvb_time_dependent ,
2017-07-20 02:10:43 +08:00
/// \brief requires scalar colvars
f_cvb_scalar_variables ,
/// \brief whether this bias will compute a PMF
f_cvb_calc_pmf ,
2017-10-14 01:25:02 +08:00
/// \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 ,
2016-04-16 00:07:28 +08:00
f_cvb_ntot
} ;
enum features_colvar {
/// \brief Calculate colvar
f_cv_active ,
2017-07-20 02:10:43 +08:00
/// \brief Colvar is awake (active on its own accord) this timestep
f_cv_awake ,
2016-04-16 00:07:28 +08:00
/// \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 Calculate the velocity with finite differences
f_cv_fdiff_velocity ,
2016-09-09 04:20:32 +08:00
/// \brief The total force is calculated, projecting the atomic
2016-04-16 00:07:28 +08:00
/// forces on the inverse gradient
2016-09-09 04:20:32 +08:00
f_cv_total_force ,
/// \brief Calculate total force from atomic forces
f_cv_total_force_calc ,
2016-09-30 20:15:44 +08:00
/// \brief Subtract the applied force from the total force
f_cv_subtract_applied_force ,
2016-04-16 00:07:28 +08:00
/// \brief Estimate Jacobian derivative
f_cv_Jacobian ,
2016-09-09 04:20:32 +08:00
/// \brief Do not report the Jacobian force as part of the total force
2016-04-16 00:07:28 +08:00
/// 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 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 ,
2016-09-09 04:20:32 +08:00
/// \brief Output the total force to the trajectory file
f_cv_output_total_force ,
2016-04-16 00:07:28 +08:00
/// \brief A lower boundary is defined
f_cv_lower_boundary ,
/// \brief An upper boundary is defined
f_cv_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 ,
2017-07-20 02:10:43 +08:00
/// \brief Value and gradient computed by user function through Lepton
f_cv_custom_function ,
2016-04-16 00:07:28 +08:00
/// \brief Colvar is periodic
f_cv_periodic ,
/// \brief is scalar
f_cv_scalar ,
f_cv_linear ,
f_cv_homogeneous ,
2017-07-20 02:10:43 +08:00
/// \brief multiple timestep through time_step_factor
f_cv_multiple_ts ,
2016-04-16 00:07:28 +08:00
/// \brief Number of colvar features
f_cv_ntot
} ;
enum features_cvc {
f_cvc_active ,
f_cvc_scalar ,
f_cvc_gradient ,
2019-04-30 21:50:12 +08:00
/// \brief CVC calculates and stores explicit atom gradients
f_cvc_explicit_gradient ,
2016-04-16 00:07:28 +08:00
f_cvc_inv_gradient ,
/// \brief If enabled, calc_gradients() will call debug_gradients() for every group needed
f_cvc_debug_gradient ,
f_cvc_Jacobian ,
2017-07-20 02:10:43 +08:00
f_cvc_pbc_minimum_image ,
2016-09-30 20:15:44 +08:00
f_cvc_one_site_total_force ,
2016-04-16 00:07:28 +08:00
f_cvc_com_based ,
f_cvc_scalable ,
f_cvc_scalable_com ,
f_cvc_ntot
} ;
enum features_atomgroup {
f_ag_active ,
f_ag_center ,
f_ag_rotate ,
2016-06-18 07:07:51 +08:00
f_ag_fitting_group ,
2016-04-16 00:07:28 +08:00
/// Perform a standard minimum msd fit for given atoms
/// ie. not using refpositionsgroup
// f_ag_min_msd_fit,
2017-07-20 02:10:43 +08:00
/// \brief Does not have explicit atom gradients from parent CVC
2019-04-30 21:50:12 +08:00
f_ag_explicit_gradient ,
2017-07-20 02:10:43 +08:00
f_ag_fit_gradients ,
2016-04-16 00:07:28 +08:00
f_ag_atom_forces ,
f_ag_scalable ,
f_ag_scalable_com ,
f_ag_ntot
} ;
2019-04-30 21:50:12 +08:00
/// 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 ) ;
2016-04-16 00:07:28 +08:00
/// \brief print all enabled features and those of children, for debugging
void print_state ( ) ;
2019-04-30 21:50:12 +08:00
/// \brief Check that a feature is enabled, raising 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 " , BUG_ERROR ) ;
}
}
2016-04-16 00:07:28 +08:00
} ;
# endif