1 // -*- c++ -*-
2 
3 #ifndef COLVARATOMS_H
4 #define COLVARATOMS_H
5 
6 #include "colvarmodule.h"
7 #include "colvarparse.h"
8 
9 /// \brief Stores numeric id, mass and all mutable data for an atom,
10 /// mostly used by a \link cvc \endlink
11 ///
12 /// This class may be used (although not necessarily) to keep atomic
13 /// data (id, mass, position and collective variable derivatives)
14 /// altogether.  There may be multiple instances with identical
15 /// numeric id, all acting independently: forces communicated through
16 /// these instances will be summed together.
17 ///
18 /// Read/write operations depend on the underlying code: hence, some
19 /// member functions are defined in colvarproxy_xxx.h.
20 class colvarmodule::atom {
21 
22 protected:
23 
24   /// \brief Index in the list of atoms involved by the colvars (\b
25   /// NOT in the global topology!)
26   int           index;
27 
28 public:
29 
30   /// Internal identifier (zero-based)
31   int              id;
32 
33   /// Mass
34   cvm::real      mass;
35 
36   /// \brief Current position (copied from the program, can be
37   /// manipulated)
38   cvm::atom_pos   pos;
39 
40   /// \brief Current velocity (copied from the program, can be
41   /// manipulated)
42   cvm::rvector    vel;
43 
44   /// \brief System force at the previous step (copied from the
45   /// program, can be manipulated)
46   cvm::rvector    system_force;
47 
48   /// \brief Gradient of a scalar collective variable with respect
49   /// to this atom
50   ///
51   /// This can only handle a scalar collective variable (i.e. when
52   /// the \link colvarvalue::real_value \endlink member is used
53   /// from the \link colvarvalue \endlink class), which is also the
54   /// most frequent case. For more complex types of \link
55   /// colvarvalue \endlink objects, atomic gradients should be
56   /// defined within the specific \link cvc \endlink
57   /// implementation
58   cvm::rvector   grad;
59 
60   /// \brief Default constructor, setting id and index to invalid numbers
atom()61   atom() : id (-1), index (-1) { reset_data(); }
62 
63   /// \brief Initialize an atom for collective variable calculation
64   /// and get its internal identifier \param atom_number Atom index in
65   /// the system topology (starting from 1)
66   atom (int const &atom_number);
67 
68   /// \brief Initialize an atom for collective variable calculation
69   /// and get its internal identifier \param residue Residue number
70   /// \param atom_name Name of the atom in the residue \param
71   /// segment_id For PSF topologies, the segment identifier; for other
72   /// type of topologies, may not be required
73   atom (cvm::residue_id const &residue,
74         std::string const     &atom_name,
75         std::string const     &segment_id = std::string (""));
76 
77   /// Copy constructor
78   atom (atom const &a);
79 
80   /// Destructor
81   ~atom();
82 
83   /// Set non-constant data (everything except id and mass) to zero
reset_data()84   inline void reset_data() {
85     pos = atom_pos (0.0);
86     vel = grad = system_force = rvector (0.0);
87   }
88 
89   /// Get the current position
90   void read_position();
91 
92   /// Get the current velocity
93   void read_velocity();
94 
95   /// Get the system force
96   void read_system_force();
97 
98   /// \brief Apply a force to the atom
99   ///
100   /// The force will be used later by the MD integrator, the
101   /// collective variables module does not integrate equations of
102   /// motion.  Multiple calls to this function by either the same
103   /// \link atom \endlink object or different objects with identical
104   /// \link id \endlink, will all add to the existing MD force.
105   void apply_force (cvm::rvector const &new_force);
106 };
107 
108 
109 
110 
111 /// \brief Group of \link atom \endlink objects, mostly used by a
112 /// \link cvc \endlink
113 ///
114 /// This class inherits from \link colvarparse \endlink and from
115 /// std::vector<colvarmodule::atom>, and hence all functions and
116 /// operators (including the bracket operator, group[i]) can be used
117 /// on an \link atom_group \endlink object.  It can be initialized as
118 /// a vector, or by parsing a keyword in the configuration.
119 class colvarmodule::atom_group
120   : public std::vector<cvm::atom>,
121     public colvarparse
122 {
123 public:
124   // Note: all members here are kept public, to allow any
125   // object accessing and manipulating them
126 
127 
128   /// \brief If this option is on, this group merely acts as a wrapper
129   /// for a fixed position; any calls to atoms within or to
130   /// functions that return disaggregated data will fail
131   bool b_dummy;
132   /// \brief dummy atom position
133   cvm::atom_pos dummy_atom_pos;
134 
135   /// Sorted list of zero-based (internal) atom ids
136   /// (populated on-demand by create_sorted_ids)
137   std::vector<int> sorted_ids;
138 
139   /// Allocates and populates the sorted list of atom ids
140   void create_sorted_ids (void);
141 
142 
143   /// \brief When updating atomic coordinates, translate them to align with the
144   /// center of mass of the reference coordinates
145   bool b_center;
146 
147   /// \brief When updating atom coordinates (and after
148   /// centering them if b_center is set), rotate the group to
149   /// align with the reference coordinates.
150   ///
151   /// Note: gradients will be calculated in the rotated frame: when
152   /// forces will be applied, they will rotated back to the original
153   /// frame
154   bool b_rotate;
155   /// The rotation calculated automatically if b_rotate is defined
156   cvm::rotation rot;
157 
158   /// \brief Indicates that the user has explicitly set centerReference or
159   /// rotateReference, and the corresponding reference:
160   /// cvc's (eg rmsd, eigenvector) will not override the user's choice
161   bool b_user_defined_fit;
162 
163   /// \brief Whether or not the derivatives of the roto-translation
164   /// should be included when calculating the colvar's gradients (default: no)
165   bool b_fit_gradients;
166 
167   /// \brief use reference coordinates for b_center or b_rotate
168   std::vector<cvm::atom_pos> ref_pos;
169 
170   /// \brief Center of geometry of the reference coordinates; regardless
171   /// of whether b_center is true, ref_pos is centered to zero at
172   /// initialization, and ref_pos_cog serves to center the positions
173   cvm::atom_pos              ref_pos_cog;
174 
175   /// \brief If b_center or b_rotate is true, use this group to
176   /// define the transformation (default: this group itself)
177   atom_group                *ref_pos_group;
178 
179   /// Total mass of the atom group
180   cvm::real total_mass;
181 
182   /// \brief Don't apply any force on this group (use its coordinates
183   /// only to calculate a colvar)
184   bool        noforce;
185 
186 
187   /// \brief Initialize the group by looking up its configuration
188   /// string in conf and parsing it; this is actually done by parse(),
189   /// which is a member function so that a group can be initialized
190   /// also after construction
191   atom_group (std::string const &conf,
192               char const        *key);
193 
194   /// \brief Initialize the group by looking up its configuration
195   /// string in conf and parsing it
196   void parse (std::string const &conf,
197               char const        *key);
198 
199   /// \brief Initialize the group after a temporary vector of atoms
200   atom_group (std::vector<cvm::atom> const &atoms);
201 
202   /// \brief Add an atom to this group
203   void add_atom (cvm::atom const &a);
204 
205   /// \brief Re-initialize the total mass of a group.
206   /// This is needed in case the hosting MD code has an option to
207   /// change atom masses after their initialization.
208   void reset_mass (std::string &name, int i, int j);
209 
210   /// \brief Default constructor
211   atom_group();
212 
213   /// \brief Destructor
214   ~atom_group();
215 
216   /// \brief Get the current positions; if b_center or b_rotate are
217   /// true, calc_apply_roto_translation() will be called too
218   void read_positions();
219 
220   /// \brief (Re)calculate the optimal roto-translation
221   void calc_apply_roto_translation();
222 
223   /// \brief Save center of geometry fo ref positions,
224   /// then subtract it
225   void center_ref_pos();
226 
227   /// \brief Move all positions
228   void apply_translation (cvm::rvector const &t);
229 
230   /// \brief Rotate all positions
231   void apply_rotation (cvm::rotation const &q);
232 
233 
234   /// \brief Get the current velocities; this must be called always
235   /// *after* read_positions(); if b_rotate is defined, the same
236   /// rotation applied to the coordinates will be used
237   void read_velocities();
238 
239   /// \brief Get the current system_forces; this must be called always
240   /// *after* read_positions(); if b_rotate is defined, the same
241   /// rotation applied to the coordinates will be used
242   void read_system_forces();
243 
244   /// Call reset_data() for each atom
reset_atoms_data()245   inline void reset_atoms_data()
246   {
247     for (cvm::atom_iter ai = this->begin(); ai != this->end(); ai++)
248       ai->reset_data();
249     if (ref_pos_group)
250       ref_pos_group->reset_atoms_data();
251   }
252 
253   /// \brief Return a copy of the current atom positions
254   std::vector<cvm::atom_pos> positions() const;
255 
256   /// \brief Return a copy of the current atom positions, shifted by a constant vector
257   std::vector<cvm::atom_pos> positions_shifted (cvm::rvector const &shift) const;
258 
259   /// \brief Return the center of geometry of the positions, assuming
260   /// that coordinates are already pbc-wrapped
261   cvm::atom_pos center_of_geometry() const;
262 
263   /// \brief Return the center of mass of the positions, assuming that
264   /// coordinates are already pbc-wrapped
265   cvm::atom_pos center_of_mass() const;
266 
267   /// \brief Atom positions at the previous step
268   std::vector<cvm::atom_pos> old_pos;
269 
270 
271   /// \brief Return a copy of the current atom velocities
272   std::vector<cvm::rvector> velocities() const;
273 
274 
275   /// \brief Return a copy of the system forces
276   std::vector<cvm::rvector> system_forces() const;
277   /// \brief Return a copy of the aggregated total force on the group
278   cvm::rvector system_force() const;
279 
280 
281   /// \brief Shorthand: save the specified gradient on each atom,
282   /// weighting with the atom mass (mostly used in combination with
283   /// \link center_of_mass() \endlink)
284   void set_weighted_gradient (cvm::rvector const &grad);
285 
286   /// \brief Calculate the derivatives of the fitting transformation
287   void calc_fit_gradients();
288 
289   /// \brief Derivatives of the fitting transformation
290   std::vector<cvm::atom_pos> fit_gradients;
291 
292   /// \brief Used by a (scalar) colvar to apply its force on its \link
293   /// atom_group \endlink members
294   ///
295   /// The (scalar) force is multiplied by the colvar gradient for each
296   /// atom; this should be used when a colvar with scalar \link
297   /// colvarvalue \endlink type is used (this is the most frequent
298   /// case: for colvars with a non-scalar type, the most convenient
299   /// solution is to sum together the Cartesian forces from all the
300   /// colvar components, and use apply_force() or apply_forces()).  If
301   /// the group is being rotated to a reference frame (e.g. to express
302   /// the colvar independently from the solute rotation), the
303   /// gradients are temporarily rotated to the original frame.
304   void apply_colvar_force (cvm::real const &force);
305 
306   /// \brief Apply a force "to the center of mass", i.e. the force is
307   /// distributed on each atom according to its mass
308   ///
309   /// If the group is being rotated to a reference frame (e.g. to
310   /// express the colvar independently from the solute rotation), the
311   /// force is rotated back to the original frame.  Colvar gradients
312   /// are not used, either because they were not defined (e.g because
313   /// the colvar has not a scalar value) or the biases require to
314   /// micromanage the force.
315   void apply_force (cvm::rvector const &force);
316 
317   /// \brief Apply an array of forces directly on the individual
318   /// atoms; the length of the specified vector must be the same of
319   /// this \link atom_group \endlink.
320   ///
321   /// If the group is being rotated to a reference frame (e.g. to
322   /// express the colvar independently from the solute rotation), the
323   /// forces are rotated back to the original frame.  Colvar gradients
324   /// are not used, either because they were not defined (e.g because
325   /// the colvar has not a scalar value) or the biases require to
326   /// micromanage the forces.
327   void apply_forces (std::vector<cvm::rvector> const &forces);
328 
329 };
330 
331 
332 #endif
333