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