All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
Gyration.cpp
Go to the documentation of this file.
1 /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2  Copyright (c) 2013 The plumed team
3  (see the PEOPLE file at the root of the distribution for a list of names)
4 
5  See http://www.plumed-code.org for more information.
6 
7  This file is part of plumed, version 2.0.
8 
9  plumed is free software: you can redistribute it and/or modify
10  it under the terms of the GNU Lesser General Public License as published by
11  the Free Software Foundation, either version 3 of the License, or
12  (at your option) any later version.
13 
14  plumed is distributed in the hope that it will be useful,
15  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  GNU Lesser General Public License for more details.
18 
19  You should have received a copy of the GNU Lesser General Public License
20  along with plumed. If not, see <http://www.gnu.org/licenses/>.
21 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
22 #include "Colvar.h"
23 #include "ActionRegister.h"
24 #include "core/PlumedMain.h"
25 #include "tools/Matrix.h"
26 
27 #include <string>
28 #include <cmath>
29 
30 using namespace std;
31 
32 namespace PLMD{
33 namespace colvar{
34 
35 //+PLUMEDOC COLVAR GYRATION
36 /*
37 Calculate the radius of gyration, or other properties related to it.
38 
39 The different properties can be calculated and selected by the TYPE keyword:
40 the Radius of Gyration (RADIUS); the Trace of the Gyration Tensor (TRACE);
41 the Largest Principal Moment of the Gyration Tensor (GTPC_1); the middle Principal Moment of the Gyration Tensor (GTPC_2);
42 the Smallest Principal Moment of the Gyration Tensor (GTPC_3); the Asphericiry (ASPHERICITY); the Acylindricity (ACYLINDRICITY);
43 the Relative Shape Anisotropy (KAPPA2); the Smallest Principal Radius Of Gyration (GYRATION_3);
44 the Middle Principal Radius of Gyration (GYRATION_2); the Largest Principal Radius of Gyration (GYRATION_1).
45 A derivation of all these different variants can be found in \cite Vymetal:2011gv
46 
47 The radius of gyration is calculated using:
48 
49 \f[
50 s_{\rm Gyr}=\Big ( \frac{\sum_i^{n}
51  m_i \vert {r}_i -{r}_{\rm COM} \vert ^2 }{\sum_i^{n} m_i} \Big)^{1/2}
52 \f]
53 
54 with the position of the center of mass \f${r}_{\rm COM}\f$ given by:
55 
56 \f[
57 {r}_{\rm COM}=\frac{\sum_i^{n} {r}_i\ m_i }{\sum_i^{n} m_i}
58 \f]
59 
60 The radius of gyration is calculated without applying periodic boundary conditions so the atoms used for the calculation
61 should all be part of the same molecule that should be made whole before calculating the cv, \ref WHOLEMOLECULES.
62 
63 \par Examples
64 
65 The following input tells plumed to print the radius of gyration of the
66 chain containing atoms 10 to 20.
67 \verbatim
68 WHOLEMOLECULES ENTITY0=10-20
69 GYRATION TYPE=RADIUS ATOMS=10-20 LABEL=rg
70 PRINT ARG=rg STRIDE=1 FILE=colvar
71 \endverbatim
72 (See also \ref PRINT)
73 
74 */
75 //+ENDPLUMEDOC
76 
77 class Gyration : public Colvar {
78 private:
79  enum CV_TYPE {RADIUS, TRACE, GTPC_1, GTPC_2, GTPC_3, ASPHERICITY, ACYLINDRICITY, KAPPA2, GYRATION_3, GYRATION_2, GYRATION_1, TOT};
80  int rg_type;
81  bool use_masses;
82 public:
83  static void registerKeywords(Keywords& keys);
84  Gyration(const ActionOptions&);
85  virtual void calculate();
86 };
87 
88 PLUMED_REGISTER_ACTION(Gyration,"GYRATION")
89 
90 void Gyration::registerKeywords(Keywords& keys){
91  Colvar::registerKeywords(keys);
92  keys.remove("NOPBC");
93  keys.add("atoms","ATOMS","the group of atoms that you are calculating the Gyration Tensor for");
94  keys.add("compulsory","TYPE","RADIUS","The type of calculation relative to the Gyration Tensor you want to perform");
95  keys.addFlag("NOT_MASS_WEIGHTED",false,"set the masses of all the atoms equal to one");
96 }
97 
98 Gyration::Gyration(const ActionOptions&ao):
100 use_masses(true)
101 {
102  std::vector<AtomNumber> atoms;
103  parseAtomList("ATOMS",atoms);
104  if(atoms.size()==0) error("no atoms specified");
105  bool not_use_masses=!use_masses;
106  parseFlag("NOT_MASS_WEIGHTED",not_use_masses);
107  use_masses=!not_use_masses;
108  std::string Type;
109  parse("TYPE",Type);
110  checkRead();
111 
112  if(Type=="RADIUS") rg_type=RADIUS;
113  else if(Type=="TRACE") rg_type=TRACE;
114  else if(Type=="GTPC_1") rg_type=GTPC_1;
115  else if(Type=="GTPC_2") rg_type=GTPC_2;
116  else if(Type=="GTPC_3") rg_type=GTPC_3;
117  else if(Type=="ASPHERICITY") rg_type=ASPHERICITY;
118  else if(Type=="ACYLINDRICITY") rg_type=ACYLINDRICITY;
119  else if(Type=="KAPPA2") rg_type=KAPPA2;
120  else if(Type=="RGYR_3") rg_type=GYRATION_3;
121  else if(Type=="RGYR_2") rg_type=GYRATION_2;
122  else if(Type=="RGYR_1") rg_type=GYRATION_1;
123  else error("Unknown GYRATION type");
124 
125  switch(rg_type)
126  {
127  case RADIUS: log.printf(" GYRATION RADIUS (Rg);"); break;
128  case TRACE: log.printf(" TRACE OF THE GYRATION TENSOR;"); break;
129  case GTPC_1: log.printf(" THE LARGEST PRINCIPAL MOMENT OF THE GYRATION TENSOR (S'_1);"); break;
130  case GTPC_2: log.printf(" THE MIDDLE PRINCIPAL MOMENT OF THE GYRATION TENSOR (S'_2);"); break;
131  case GTPC_3: log.printf(" THE SMALLEST PRINCIPAL MOMENT OF THE GYRATION TENSOR (S'_3);"); break;
132  case ASPHERICITY: log.printf(" THE ASPHERICITY (b');"); break;
133  case ACYLINDRICITY: log.printf(" THE ACYLINDRICITY (c');"); break;
134  case KAPPA2: log.printf(" THE RELATIVE SHAPE ANISOTROPY (kappa^2);"); break;
135  case GYRATION_3: log.printf(" THE SMALLEST PRINCIPAL RADIUS OF GYRATION (r_g3);"); break;
136  case GYRATION_2: log.printf(" THE MIDDLE PRINCIPAL RADIUS OF GYRATION (r_g2);"); break;
137  case GYRATION_1: log.printf(" THE LARGEST PRINCIPAL RADIUS OF GYRATION (r_g1);"); break;
138  }
139  if(rg_type>TRACE) log<<" Bibliography "<<plumed.cite("Jirí Vymetal and Jirí Vondrasek, J. Phys. Chem. A 115, 11455 (2011)"); log<<"\n";
140 
141  log.printf(" atoms involved : ");
142  for(unsigned i=0;i<atoms.size();++i) log.printf("%d ",atoms[i].serial());
143  log.printf("\n");
144 
146  requestAtoms(atoms);
147 }
148 
150 
151  std::vector<Vector> derivatives( getNumberOfAtoms() );
152  double totmass = 0.;
153  double d=0., rgyr=0.;
154  Vector pos0, com, diff;
155  Matrix<double> gyr_tens(3,3);
156  for(unsigned i=0;i<3;i++) for(unsigned j=0;j<3;j++) gyr_tens(i,j)=0.;
157 
158  // Find the center of mass
159  pos0=getPosition(0);
160  com.zero();
161  if(use_masses) {
162  totmass=getMass(0);
163  for(unsigned i=1;i<getNumberOfAtoms();i++){
164  diff=delta( pos0, getPosition(i) );
165  totmass += getMass(i);
166  com += getMass(i)*diff;
167  }
168  } else {
169  totmass=(double)getNumberOfAtoms();
170  for(unsigned i=1;i<getNumberOfAtoms();i++){
171  diff=delta( pos0, getPosition(i) );
172  com += diff;
173  }
174  }
175  com = com / totmass + pos0;
176 
177  switch(rg_type) {
178  case RADIUS:
179  case TRACE:
180  // Now compute radius of gyration
181  if( use_masses ){
182  for(unsigned i=0;i<getNumberOfAtoms();i++){
183  diff=delta( com, getPosition(i) );
184  d=diff.modulo();
185  rgyr += getMass(i)*d*d;
186  derivatives[i]=diff*getMass(i);
187  }
188  } else {
189  for(unsigned i=0;i<getNumberOfAtoms();i++){
190  diff=delta( com, getPosition(i) );
191  d=diff.modulo();
192  rgyr += d*d;
193  derivatives[i]=diff;
194  }
195  }
196  break;
197  default:
198  //calculate gyration tensor
199  if( use_masses ) {
200  for(unsigned i=0;i<getNumberOfAtoms();i++){
201  diff=delta( com, getPosition(i) );
202  gyr_tens[0][0]+=getMass(i)*diff[0]*diff[0];
203  gyr_tens[1][1]+=getMass(i)*diff[1]*diff[1];
204  gyr_tens[2][2]+=getMass(i)*diff[2]*diff[2];
205  gyr_tens[0][1]+=getMass(i)*diff[0]*diff[1];
206  gyr_tens[0][2]+=getMass(i)*diff[0]*diff[2];
207  gyr_tens[1][2]+=getMass(i)*diff[1]*diff[2];
208  }
209  } else {
210  for(unsigned i=0;i<getNumberOfAtoms();i++){
211  diff=delta( com, getPosition(i) );
212  gyr_tens[0][0]+=diff[0]*diff[0];
213  gyr_tens[1][1]+=diff[1]*diff[1];
214  gyr_tens[2][2]+=diff[2]*diff[2];
215  gyr_tens[0][1]+=diff[0]*diff[1];
216  gyr_tens[0][2]+=diff[0]*diff[2];
217  gyr_tens[1][2]+=diff[1]*diff[2];
218  }
219  }
220  break;
221  }
222 
223  switch(rg_type) {
224  case RADIUS:
225  {
226  rgyr=sqrt(rgyr/totmass);
227  double fact=1./(rgyr*totmass);
228  for(unsigned i=0;i<getNumberOfAtoms();i++){
229  derivatives[i] *= fact;
230  setAtomsDerivatives(i,derivatives[i]);
231  }
232  break;
233  }
234  case TRACE:
235  {
236  rgyr *= 2.;
237  for(unsigned i=0;i<getNumberOfAtoms();i++) {
238  derivatives[i] *= 4.;
239  setAtomsDerivatives(i,derivatives[i]);
240  }
241  break;
242  }
243  default:
244  {
245  // first make the matrix symmetric
246  gyr_tens[1][0] = gyr_tens[0][1];
247  gyr_tens[2][0] = gyr_tens[0][2];
248  gyr_tens[2][1] = gyr_tens[1][2];
249 
250  Matrix<double> ttransf(3,3), transf(3,3);
251  std::vector<double> princ_comp(3), prefactor(3);
252  prefactor[0]=prefactor[1]=prefactor[2]=0.;
253 
254  //diagonalize gyration tensor
255  diagMat(gyr_tens, princ_comp, ttransf);
256  transpose(ttransf, transf);
257  //sort eigenvalues and eigenvectors
258  if (princ_comp[0]<princ_comp[1]){
259  double tmp=princ_comp[0]; princ_comp[0]=princ_comp[1]; princ_comp[1]=tmp;
260  for (unsigned i=0; i<3; i++){tmp=transf[i][0]; transf[i][0]=transf[i][1]; transf[i][1]=tmp;}
261  }
262  if (princ_comp[1]<princ_comp[2]){
263  double tmp=princ_comp[1]; princ_comp[1]=princ_comp[2]; princ_comp[2]=tmp;
264  for (unsigned i=0; i<3; i++){tmp=transf[i][1]; transf[i][1]=transf[i][2]; transf[i][2]=tmp;}
265  }
266  if (princ_comp[0]<princ_comp[1]){
267  double tmp=princ_comp[0]; princ_comp[0]=princ_comp[1]; princ_comp[1]=tmp;
268  for (unsigned i=0; i<3; i++){tmp=transf[i][0]; transf[i][0]=transf[i][1]; transf[i][1]=tmp;}
269  }
270  //calculate determinant of transformation matrix
271  double det;
272  det = transf[0][0]*transf[1][1]*transf[2][2]+transf[0][1]*transf[1][2]*transf[2][0]+
273  transf[0][2]*transf[1][0]*transf[2][1]-transf[0][2]*transf[1][1]*transf[2][0]-
274  transf[0][1]*transf[1][0]*transf[2][2]-transf[0][0]*transf[1][2]*transf[2][1];
275  // trasformation matrix for rotation must have positive determinant, otherwise multiply one column by (-1)
276  if(det<0) {
277  for(unsigned j=0;j<3;j++) transf[j][2]=-transf[j][2];
278  det = -det;
279  }
280  if(fabs(det-1.)>0.0001) error("Plumed Error: Cannot diagonalize gyration tensor\n");
281  switch(rg_type) {
282  case GTPC_1:
283  case GTPC_2:
284  case GTPC_3:
285  {
286  int pc_index = rg_type-2; //index of principal component
287  rgyr=sqrt(princ_comp[pc_index]/totmass);
288  double rm = rgyr*totmass;
289  if(rm>1e-6) prefactor[pc_index]=1.0/rm; //some parts of derivate
290  break;
291  }
292  case GYRATION_3: //the smallest principal radius of gyration
293  {
294  rgyr=sqrt((princ_comp[1]+princ_comp[2])/totmass);
295  double rm = rgyr*totmass;
296  if (rm>1e-6){
297  prefactor[1]=1.0/rm;
298  prefactor[2]=1.0/rm;
299  }
300  break;
301  }
302  case GYRATION_2: //the midle principal radius of gyration
303  {
304  rgyr=sqrt((princ_comp[0]+princ_comp[2])/totmass);
305  double rm = rgyr*totmass;
306  if (rm>1e-6){
307  prefactor[0]=1.0/rm;
308  prefactor[2]=1.0/rm;
309  }
310  break;
311  }
312  case GYRATION_1: //the largest principal radius of gyration
313  {
314  rgyr=sqrt((princ_comp[0]+princ_comp[1])/totmass);
315  double rm = rgyr*totmass;
316  if (rm>1e-6){
317  prefactor[0]=1.0/rm;
318  prefactor[1]=1.0/rm;
319  }
320  break;
321  }
322  case ASPHERICITY:
323  {
324  rgyr=sqrt((princ_comp[0]-0.5*(princ_comp[1]+princ_comp[2]))/totmass);
325  double rm = rgyr*totmass;
326  if (rm>1e-6){
327  prefactor[0]= 1.0/rm;
328  prefactor[1]=-0.5/rm;
329  prefactor[2]=-0.5/rm;
330  }
331  break;
332  }
333  case ACYLINDRICITY:
334  {
335  rgyr=sqrt((princ_comp[1]-princ_comp[2])/totmass);
336  double rm = rgyr*totmass;
337  if (rm>1e-6){ //avoid division by zero
338  prefactor[1]= 1.0/rm;
339  prefactor[2]=-1.0/rm;
340  }
341  break;
342  }
343  case KAPPA2: // relative shape anisotropy
344  {
345  double trace = princ_comp[0]+princ_comp[1]+princ_comp[2];
346  double tmp=princ_comp[0]*princ_comp[1]+ princ_comp[1]*princ_comp[2]+ princ_comp[0]*princ_comp[2];
347  rgyr=1.0-3*(tmp/(trace*trace));
348  if (rgyr>1e-6){
349  prefactor[0]= -3*((princ_comp[1]+princ_comp[2])-2*tmp/trace)/(trace*trace) *2;
350  prefactor[1]= -3*((princ_comp[0]+princ_comp[2])-2*tmp/trace)/(trace*trace) *2;
351  prefactor[2]= -3*((princ_comp[0]+princ_comp[1])-2*tmp/trace)/(trace*trace) *2;
352  }
353  break;
354  }
355  }
356  if(use_masses) {
357  for(unsigned i=0;i<getNumberOfAtoms();i++){
358  Vector tX;
359  diff=delta( com,getPosition(i) );
360  //project atomic postional vectors to diagonalized frame
361  for(unsigned j=0;j<3;j++) tX[j]=transf[0][j]*diff[0]+transf[1][j]*diff[1]+transf[2][j]*diff[2];
362  for(unsigned j=0;j<3;j++) derivatives[i][j]=getMass(i)*(prefactor[0]*transf[j][0]*tX[0]+
363  prefactor[1]*transf[j][1]*tX[1]+
364  prefactor[2]*transf[j][2]*tX[2]);
365  setAtomsDerivatives(i,derivatives[i]);
366  }
367  } else {
368  for(unsigned i=0;i<getNumberOfAtoms();i++){
369  Vector tX;
370  diff=delta( com,getPosition(i) );
371  //project atomic postional vectors to diagonalized frame
372  for(unsigned j=0;j<3;j++) tX[j]=transf[0][j]*diff[0]+transf[1][j]*diff[1]+transf[2][j]*diff[2];
373  for(unsigned j=0;j<3;j++) derivatives[i][j]=prefactor[0]*transf[j][0]*tX[0]+
374  prefactor[1]*transf[j][1]*tX[1]+
375  prefactor[2]*transf[j][2]*tX[2];
376  setAtomsDerivatives(i,derivatives[i]);
377  }
378  }
379  break;
380  }
381  }
382  setValue(rgyr);
384 }
385 
386 }
387 }
const Vector & getPosition(int) const
Get position of i-th atom.
void parseFlag(const std::string &key, bool &t)
Parse one keyword as boolean flag.
Definition: Action.cpp:104
void setNotPeriodic()
Set your default value to have no periodicity.
Log & log
Reference to the log stream.
Definition: Action.h:93
double modulo() const
Compute the modulo.
Definition: Vector.h:325
Class implementing fixed size vectors of doubles.
Definition: Vector.h:74
void setAtomsDerivatives(int, const Vector &)
Definition: Colvar.h:97
void error(const std::string &msg) const
Crash calculation and print documentation.
Definition: Action.cpp:195
void checkRead()
Check if Action was properly read.
Definition: Action.cpp:161
STL namespace.
void parseAtomList(const std::string &key, std::vector< AtomNumber > &t)
Parse a list of atoms without a numbered keyword.
void addValueWithDerivatives()
Add a value with the name label that has derivatives.
void requestAtoms(const std::vector< AtomNumber > &a)
Definition: Colvar.cpp:44
void zero()
set it to zero
Definition: Vector.h:173
void transpose(const Matrix< T > &A, Matrix< T > &AT)
Definition: Matrix.h:185
#define PLUMED_COLVAR_INIT(ao)
Definition: Colvar.h:29
virtual void calculate()
Calculate an Action.
Definition: Gyration.cpp:149
void parse(const std::string &key, T &t)
Parse one keyword as generic type.
Definition: Action.h:273
This class holds the keywords and their documentation.
Definition: Keywords.h:36
Provides the keyword GYRATION
Definition: Gyration.cpp:77
This class is used to bring the relevant information to the Action constructor.
Definition: Action.h:41
int printf(const char *fmt,...)
Formatted output with explicit format - a la printf.
Definition: OFile.cpp:82
This is the abstract base class to use for implementing new collective variables, within it there is ...
Definition: Colvar.h:39
VectorGeneric< n > delta(const VectorGeneric< n > &v1, const VectorGeneric< n > &v2)
Definition: Vector.h:262
void setValue(const double &d)
Set the default value (the one without name)
int diagMat(const Matrix< T > &A, std::vector< double > &eigenvals, Matrix< double > &eigenvecs)
Definition: Matrix.h:203
void setBoxDerivativesNoPbc()
Set box derivatives automatically.
Definition: Colvar.h:107
Main plumed object.
Definition: Plumed.h:201
unsigned getNumberOfAtoms() const
Get number of available atoms.
double getMass(int i) const
Get mass of i-th atom.