1 // -*- c++ -*- 2 3 // This file is part of the Collective Variables module (Colvars). 4 // The original version of Colvars and its updates are located at: 5 // https://github.com/Colvars/colvars 6 // Please update all Colvars source files before making any changes. 7 // If you wish to distribute your changes, please submit them to the 8 // Colvars repository at GitHub. 9 10 #ifndef COLVARDEPS_H 11 #define COLVARDEPS_H 12 13 #include "colvarmodule.h" 14 #include "colvarparse.h" 15 16 /// \brief Parent class for a member object of a bias, cv or cvc etc. containing features and 17 /// their dependencies, and handling dependency resolution 18 /// 19 /// There are 3 kinds of features: 20 /// 1. Dynamic features are under the control of the dependency resolution 21 /// system. They may be enabled or disabled depending on dependencies. 22 /// 2. User features may be enabled based on user input (they may trigger a failure upon dependency resolution, though) 23 /// 3. Static features are static properties of the object, determined 24 /// programmatically at initialization time. 25 /// 26 /// The following diagram summarizes the dependency tree at the bias, colvar, and colvarcomp levels. 27 /// Isolated and atom group features are not shown to save space. 28 /// @image html deps_2019.svg 29 /// 30 /// In all classes, feature 0 is `active`. When an object is inactivated 31 /// all its children dependencies are dereferenced (free_children_deps) 32 /// While the object is inactive, no dependency solving is done on children 33 /// it is done when the object is activated back (restore_children_deps) 34 class colvardeps { 35 public: 36 37 colvardeps(); 38 virtual ~colvardeps(); 39 40 // Subclasses should initialize the following members: 41 42 std::string description; // reference to object name (cv, cvc etc.) 43 44 /// This contains the current state of each feature for each object 45 // since the feature class only contains static properties 46 struct feature_state { feature_statefeature_state47 feature_state(bool a, bool e) 48 : available(a), enabled(e), ref_count(0) {} 49 50 /// Feature may be enabled, subject to possible dependencies 51 bool available; 52 /// Currently enabled - this flag is subject to change dynamically 53 /// TODO consider implications for dependency solving: anyone who disables 54 /// it should trigger a refresh of parent objects 55 bool enabled; // see if this should be private depending on implementation 56 57 // bool enabledOnce; // this should trigger an update when object is evaluated 58 59 /// Number of features requiring this one as a dependency 60 /// When it falls to zero: 61 /// - a dynamic feature is disabled automatically 62 /// - other features may be disabled statically 63 int ref_count; 64 /// List of features that were enabled by this one 65 /// as part of an alternate requirement (for ref counting purposes) 66 /// This is necessary because we don't know which feature in the list 67 /// we enabled, otherwise 68 std::vector<int> alternate_refs; 69 }; 70 71 protected: 72 /// Time step multiplier (for coarse-timestep biases & colvars) 73 /// Biases and colvars will only be calculated at those times 74 /// (f_cvb_awake and f_cv_awake); a 75 /// Biases use this to apply "impulse" biasing forces at the outer timestep 76 /// Unused by lower-level objects (cvcs and atom groups) 77 int time_step_factor; 78 79 /// List of the states of all features 80 std::vector<feature_state> feature_states; 81 82 /// Enum of possible feature types 83 enum feature_type { 84 f_type_not_set, 85 f_type_dynamic, 86 f_type_user, 87 f_type_static 88 }; 89 90 public: 91 /// \brief returns time_step_factor get_time_step_factor()92 inline int get_time_step_factor() const {return time_step_factor;} 93 94 /// Pair a numerical feature ID with a description and type 95 void init_feature(int feature_id, const char *description, feature_type type); 96 97 /// Describes a feature and its dependencies 98 /// used in a static array within each subclass 99 class feature { 100 101 public: feature()102 feature() : type(f_type_not_set) {} ~feature()103 ~feature() {} 104 105 std::string description; // Set by derived object initializer 106 107 // features that this feature requires in the same object 108 // 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) 109 std::vector<int> requires_self; 110 111 // Features that are incompatible, ie. required disabled 112 // if enabled, they will cause a dependency failure (they will not be disabled) 113 // To enforce these dependencies regardless of the order in which they 114 // are enabled, they are always set in a symmetric way, so whichever is enabled 115 // second will cause the dependency to fail 116 std::vector<int> requires_exclude; 117 118 // sets of features that are required in an alternate way 119 // when parent feature is enabled, if none are enabled, the first one listed that is available will be enabled 120 std::vector<std::vector<int> > requires_alt; 121 122 // features that this feature requires in children 123 std::vector<int> requires_children; 124 is_dynamic()125 inline bool is_dynamic() { return type == f_type_dynamic; } is_static()126 inline bool is_static() { return type == f_type_static; } is_user()127 inline bool is_user() { return type == f_type_user; } 128 /// Type of this feature, from the enum feature_type 129 feature_type type; 130 }; 131 is_not_set(int id)132 inline bool is_not_set(int id) { return features()[id]->type == f_type_not_set; } is_dynamic(int id)133 inline bool is_dynamic(int id) { return features()[id]->type == f_type_dynamic; } is_static(int id)134 inline bool is_static(int id) { return features()[id]->type == f_type_static; } is_user(int id)135 inline bool is_user(int id) { return features()[id]->type == f_type_user; } 136 137 // Accessor to array of all features with deps, static in most derived classes 138 // Subclasses with dynamic dependency trees may override this 139 // with a non-static array 140 // Intermediate classes (colvarbias and colvarcomp, which are also base classes) 141 // implement this as virtual to allow overriding 142 virtual const std::vector<feature *> &features() const = 0; 143 virtual std::vector<feature *>&modify_features() = 0; 144 145 void add_child(colvardeps *child); 146 147 void remove_child(colvardeps *child); 148 149 /// Used before deleting an object, if not handled by that object's destructor 150 /// (useful for cvcs because their children are member objects) 151 void remove_all_children(); 152 153 private: 154 155 /// pointers to objects this object depends on 156 /// list should be maintained by any code that modifies the object 157 /// this could be secured by making lists of colvars / cvcs / atom groups private and modified through accessor functions 158 std::vector<colvardeps *> children; 159 160 /// pointers to objects that depend on this object 161 /// the size of this array is in effect a reference counter 162 std::vector<colvardeps *> parents; 163 164 public: 165 // Checks whether given feature is enabled 166 // Defaults to querying f_*_active 167 inline bool is_enabled(int f = f_cv_active) const { 168 return feature_states[f].enabled; 169 } 170 171 // Checks whether given feature is available 172 // Defaults to querying f_*_active 173 inline bool is_available(int f = f_cv_active) const { 174 return feature_states[f].available; 175 } 176 177 /// Set the feature's available flag, without checking 178 /// To be used for dynamic properties 179 /// dependencies will be checked by enable() 180 void provide(int feature_id, bool truefalse = true); 181 182 /// Enable or disable, depending on flag value 183 void set_enabled(int feature_id, bool truefalse = true); 184 185 protected: 186 187 /// Parse a keyword and enable a feature accordingly 188 bool get_keyval_feature(colvarparse *cvp, 189 std::string const &conf, char const *key, 190 int feature_id, bool const &def_value, 191 colvarparse::Parse_Mode const parse_mode = colvarparse::parse_normal); 192 193 public: 194 195 /// Enable a feature and recursively solve its dependencies. 196 /// For accurate reference counting, do not add spurious calls to enable() 197 /// \param dry_run Recursively test if a feature is available, without enabling it 198 /// \param toplevel False if this is called as part of a chain of dependency resolution. 199 /// This is used to diagnose failed dependencies by displaying the full stack: 200 /// only the toplevel dependency will throw a fatal error. 201 int enable(int f, bool dry_run = false, bool toplevel = true); 202 203 /// Disable a feature, decrease the reference count of its dependencies 204 /// and recursively disable them as applicable 205 int disable(int f); 206 207 /// disable all enabled features to free their dependencies 208 /// to be done when deleting the object 209 /// Cannot be in the base class destructor because it needs the derived class features() 210 void free_children_deps(); 211 212 /// re-enable children features (to be used when object becomes active) 213 void restore_children_deps(); 214 215 /// Decrement the reference count of a feature 216 /// disabling it if it's dynamic and count reaches zero 217 int decr_ref_count(int f); 218 219 /// Implements possible actions to be carried out 220 /// when a given feature is enabled 221 /// Base function does nothing, can be overloaded do_feature_side_effects(int)222 virtual void do_feature_side_effects(int /* id */) {} 223 224 // NOTE that all feature enums should start with f_*_active 225 enum features_biases { 226 /// \brief Bias is active 227 f_cvb_active, 228 /// \brief Bias is awake (active on its own accord) this timestep 229 f_cvb_awake, 230 /// Accumulates data starting from step 0 of a simulation run 231 f_cvb_step_zero_data, 232 /// \brief will apply forces 233 f_cvb_apply_force, 234 /// \brief force this bias to act on actual value for extended-Lagrangian coordinates 235 f_cvb_bypass_ext_lagrangian, 236 /// \brief requires total forces 237 f_cvb_get_total_force, 238 /// \brief whether this bias should record the accumulated work 239 f_cvb_output_acc_work, 240 /// \brief depends on simulation history 241 f_cvb_history_dependent, 242 /// \brief depends on time 243 f_cvb_time_dependent, 244 /// \brief requires scalar colvars 245 f_cvb_scalar_variables, 246 /// \brief whether this bias will compute a PMF 247 f_cvb_calc_pmf, 248 /// \brief whether this bias will compute TI samples 249 f_cvb_calc_ti_samples, 250 /// \brief whether this bias will write TI samples 251 f_cvb_write_ti_samples, 252 /// \brief whether this bias should write the TI PMF 253 f_cvb_write_ti_pmf, 254 f_cvb_ntot 255 }; 256 257 enum features_colvar { 258 /// \brief Calculate colvar 259 f_cv_active, 260 /// \brief Colvar is awake (active on its own accord) this timestep 261 f_cv_awake, 262 /// \brief Gradients are calculated and temporarily stored, so 263 /// that external forces can be applied 264 f_cv_gradient, 265 /// \brief Collect atomic gradient data from all cvcs into vector 266 /// atomic_gradient 267 f_cv_collect_gradient, 268 /// \brief Calculate the velocity with finite differences 269 f_cv_fdiff_velocity, 270 /// \brief The total force is calculated, projecting the atomic 271 /// forces on the inverse gradient 272 f_cv_total_force, 273 /// \brief Calculate total force from atomic forces 274 f_cv_total_force_calc, 275 /// \brief Subtract the applied force from the total force 276 f_cv_subtract_applied_force, 277 /// \brief Estimate Jacobian derivative 278 f_cv_Jacobian, 279 /// \brief Do not report the Jacobian force as part of the total force 280 /// instead, apply a correction internally to cancel it 281 f_cv_hide_Jacobian, 282 /// \brief The variable has a harmonic restraint around a moving 283 /// center with fictitious mass; bias forces will be applied to 284 /// the center 285 f_cv_extended_Lagrangian, 286 /// \brief An extended variable that sets an external variable in the 287 /// back-end (eg. an alchemical coupling parameter for lambda-dynamics) 288 /// Can have a single component 289 f_cv_external, 290 /// \brief The extended system coordinate undergoes Langevin dynamics 291 f_cv_Langevin, 292 /// \brief Output the potential and kinetic energies 293 /// (for extended Lagrangian colvars only) 294 f_cv_output_energy, 295 /// \brief Output the value to the trajectory file (on by default) 296 f_cv_output_value, 297 /// \brief Output the velocity to the trajectory file 298 f_cv_output_velocity, 299 /// \brief Output the applied force to the trajectory file 300 f_cv_output_applied_force, 301 /// \brief Output the total force to the trajectory file 302 f_cv_output_total_force, 303 /// \brief A lower boundary is defined 304 f_cv_lower_boundary, 305 /// \brief An upper boundary is defined 306 f_cv_upper_boundary, 307 /// \brief The lower boundary is not defined from user's choice 308 f_cv_hard_lower_boundary, 309 /// \brief The upper boundary is not defined from user's choice 310 f_cv_hard_upper_boundary, 311 /// \brief Reflecting lower boundary condition 312 f_cv_reflecting_lower_boundary, 313 /// \brief Reflecting upper boundary condition 314 f_cv_reflecting_upper_boundary, 315 /// \brief Provide a discretization of the values of the colvar to 316 /// be used by the biases or in analysis (needs lower and upper 317 /// boundary) 318 f_cv_grid, 319 /// \brief Compute running average 320 f_cv_runave, 321 /// \brief Compute time correlation function 322 f_cv_corrfunc, 323 /// \brief Value and gradient computed by user script 324 f_cv_scripted, 325 /// \brief Value and gradient computed by user function through Lepton 326 f_cv_custom_function, 327 /// \brief Colvar is periodic 328 f_cv_periodic, 329 /// \brief The colvar has only one component 330 f_cv_single_cvc, 331 /// \brief is scalar 332 f_cv_scalar, 333 f_cv_linear, 334 f_cv_homogeneous, 335 /// \brief multiple timestep through time_step_factor 336 f_cv_multiple_ts, 337 /// \brief Number of colvar features 338 f_cv_ntot 339 }; 340 341 enum features_cvc { 342 /// Computation of this CVC is enabled 343 f_cvc_active, 344 /// This CVC computes a scalar value 345 f_cvc_scalar, 346 /// Values of this CVC lie in a periodic interval 347 f_cvc_periodic, 348 /// This CVC provides a default value for the colvar's width 349 f_cvc_width, 350 /// This CVC provides a default value for the colvar's lower boundary 351 f_cvc_lower_boundary, 352 /// This CVC provides a default value for the colvar's upper boundary 353 f_cvc_upper_boundary, 354 /// CVC calculates atom gradients 355 f_cvc_gradient, 356 /// CVC calculates and stores explicit atom gradients 357 f_cvc_explicit_gradient, 358 /// CVC calculates and stores inverse atom gradients (used for total force) 359 f_cvc_inv_gradient, 360 /// CVC calculates the Jacobian term of the total-force expression 361 f_cvc_Jacobian, 362 /// The total force for this CVC will be computed from one group only 363 f_cvc_one_site_total_force, 364 /// calc_gradients() will call debug_gradients() for every group needed 365 f_cvc_debug_gradient, 366 /// With PBCs, minimum-image convention will be used for distances 367 /// (does not affect the periodicity of CVC values, e.g. angles) 368 f_cvc_pbc_minimum_image, 369 /// This CVC is a function of centers of mass 370 f_cvc_com_based, 371 /// This CVC can be computed in parallel 372 f_cvc_scalable, 373 /// Centers-of-mass used in this CVC can be computed in parallel 374 f_cvc_scalable_com, 375 /// Number of CVC features 376 f_cvc_ntot 377 }; 378 379 enum features_atomgroup { 380 f_ag_active, 381 f_ag_center, 382 f_ag_center_origin, 383 f_ag_rotate, 384 f_ag_fitting_group, 385 /// Perform a standard minimum msd fit for given atoms 386 /// ie. not using refpositionsgroup 387 // f_ag_min_msd_fit, 388 /// \brief Does not have explicit atom gradients from parent CVC 389 f_ag_explicit_gradient, 390 f_ag_fit_gradients, 391 f_ag_atom_forces, 392 f_ag_scalable, 393 f_ag_scalable_com, 394 f_ag_ntot 395 }; 396 397 /// Initialize dependency tree for object of a derived class 398 virtual int init_dependencies() = 0; 399 400 /// Make feature f require feature g within the same object 401 void require_feature_self(int f, int g); 402 403 /// Make features f and g mutually exclusive within the same object 404 void exclude_feature_self(int f, int g); 405 406 /// Make feature f require feature g within children 407 void require_feature_children(int f, int g); 408 409 /// Make feature f require either g or h within the same object 410 void require_feature_alt(int f, int g, int h); 411 412 /// Make feature f require any of g, h, or i within the same object 413 void require_feature_alt(int f, int g, int h, int i); 414 415 /// Make feature f require any of g, h, i, or j within the same object 416 void require_feature_alt(int f, int g, int h, int i, int j); 417 418 /// \brief print all enabled features and those of children, for debugging 419 void print_state(); 420 421 /// \brief Check that a feature is enabled, raising BUG_ERROR if not check_enabled(int f,std::string const & reason)422 inline void check_enabled(int f, std::string const &reason) const 423 { 424 if (! is_enabled(f)) { 425 cvm::error("Error: "+reason+" requires that the feature \""+ 426 features()[f]->description+"\" is active.\n", BUG_ERROR); 427 } 428 } 429 430 }; 431 432 #endif 433 434 435