4 * This source code is part of
8 * GROningen MAchine for Chemical Simulations
12 * Copyright (c) 1991-1999
13 * BIOSON Research Institute, Dept. of Biophysical Chemistry
14 * University of Groningen, The Netherlands
17 * GROMACS: A message-passing parallel molecular dynamics implementation
18 * H.J.C. Berendsen, D. van der Spoel and R. van Drunen
19 * Comp. Phys. Comm. 91, 43-56 (1995)
21 * Also check out our WWW page:
22 * http://md.chem.rug.nl/~gmx
27 * GRowing Old MAkes el Chrono Sweat
29 static char *SRCID_g_msd_c
= "$Id$";
48 #define FACTOR 1000.0 /* Convert nm^2/ps to 10e-5 cm^2/s */
49 /* NORMAL = total diffusion coefficient (default). X,Y,Z is diffusion
50 coefficient in X,Y,Z direction. LATERAL is diffusion coefficient in
51 plane perpendicular to axis
53 enum { NOT_USED
, NORMAL
, X
, Y
, Z
, LATERAL
};
56 real t0
,delta_t
,dim_factor
;
57 real
**data
,*time
,*data_x
,*data_y
,*data_z
,*data_xy
,*mass
;
61 int type
,axis
,natoms
,nrestart
,nnx
,nframes
,nlast
,ngrp
;
66 typedef real
t_calc_func(t_corr
*,int,atom_id
[],int,rvec
[]);
67 typedef void t_prep_data_func(t_corr
*this,int gnx
,atom_id index
[],
68 rvec xcur
[],rvec xprev
[],matrix box
);
70 static real
thistime(t_corr
*this)
72 return this->time
[this->nframes
];
75 static bool in_data(t_corr
*this,int nx00
)
77 return this->nframes
-this->n_offs
[nx00
];
80 t_corr
*init_corr(int nrgrp
,int type
,int axis
,real dim_factor
,
81 bool bMass
,bool bMol
,t_topology
*top
)
93 snew(this->ndata
,nrgrp
);
94 snew(this->data
,nrgrp
);
95 for(i
=0; (i
<nrgrp
); i
++) {
96 this->ndata
[i
] = NULL
;
103 snew(this->mass
,atoms
->nr
);
104 for(i
=0; (i
<atoms
->nr
); i
++) {
105 this->mass
[i
]=atoms
->atom
[i
].m
;
109 this->mols
= &(top
->blocks
[ebMOLS
]);
115 static void done_corr(t_corr
*this)
120 for(i
=0; (i
<this->nrestart
); i
++)
125 static void init_restart(t_corr
*this,int nrestart
,real dt
)
129 this->nrestart
= max(1,nrestart
);
130 this->delta_t
= (nrestart
> 1) ? dt
: 0;
132 printf("\nThe number of starting points you requested takes %lu"
134 (unsigned long) this->natoms
*this->nrestart
*sizeof(rvec
));
136 snew(this->x0
,this->nrestart
);
137 for(i
=0; (i
<this->nrestart
); i
++)
138 snew(this->x0
[i
],this->natoms
);
139 snew(this->n_offs
,this->nrestart
);
142 void lsq_y_ax_b2(int n
, real x
[], real y
[], real
*a
, real
*b
,
146 double yx
,xx
,sx
,sy
,sa2
;
149 for (i
=0; (i
< n
); i
++) {
155 *a
=(n
*yx
-sy
*sx
)/(n
*xx
-sx
*sx
);
158 for(i
=0; (i
<n
); i
++) {
159 real tmp
=(y
[i
]-(*a
)*x
[i
]-(*b
));
162 *sa
=sqrt((sa2
/(n
*(n
-2)))*(1.0/(xx
/n
-(sx
/n
)*(sx
/n
))));
163 *sb
=(*sa
)*sqrt(xx
/n
);
166 static void subtitle(FILE *out
,t_corr
*this)
171 for(i
=0; (i
<this->ngrp
); i
++) {
172 lsq_y_ax_b2(this->nframes
,this->time
,this->data
[i
],&aa
,&bb
,&da
,&db
);
173 D
=aa
*FACTOR
/this->dim_factor
;
174 fprintf(out
,"# D[%d] = %.4f (1e-5 cm^2 s^-1)\n",i
,D
);
178 static void corr_print(t_corr
*this,char *fn
,char *title
,char *yaxis
,
179 bool bXvgr
,bool bDiff
)
187 /* err_fac=sqrt(2.0/3.0*sqrt(M_PI)); */
188 for(j
=0; (j
<this->ngrp
); j
++)
189 for(i
=0; (i
<this->nframes
); i
++)
190 this->data
[j
][i
]/=this->ndata
[j
][i
];
191 out
=xvgropen(fn
,title
,"Time (ps)",yaxis
);
195 lsq_y_ax_b2(this->nframes
,this->time
,this->data
[0],&aa
,&bb
,&da
,&db
);
200 for(i
=imin
; (i
<this->nframes
); i
++) {
201 t
= this->time
[i
]-this->time
[0];
202 fprintf(out
,"%10g",t
);
203 for(j
=0; (j
<this->ngrp
); j
++)
205 bDiff
? 1000*this->data
[j
][i
]/(6*t
) : this->data
[j
][i
]);
211 /* called from corr_loop, to do the main calculations */
212 static void calc_corr(t_corr
*this,int nr
,int nx
,atom_id index
[],rvec xc
[],
218 /* Check for new starting point */
219 if (this->nlast
< this->nrestart
) {
220 if ((thistime(this) >= (this->t0
+this->nlast
*this->delta_t
)) && (nr
==0)) {
221 printf("New starting point\n");
222 memcpy(this->x0
[this->nlast
],xc
,this->natoms
*sizeof(xc
[0]));
223 this->n_offs
[this->nlast
]=this->nframes
;
228 /* nx0 appears to be the number of new starting points,
229 * so for all starting points, call calc1.
231 for(nx0
=0; (nx0
<this->nlast
); nx0
++) {
232 g
= calc1(this,nx
,index
,nx0
,xc
);
234 printf("g[%d]=%g\n",nx0
,g
);
236 this->data
[nr
][in_data(this,nx0
)]+=g
;
237 this->ndata
[nr
][in_data(this,nx0
)]++;
241 static real
calc1_norm(t_corr
*this,int nx
,atom_id index
[],int nx0
,rvec xc
[])
248 for(i
=0; (i
<nx
); i
++) {
251 switch (this->type
) {
253 for(m
=0; (m
<DIM
); m
++) {
254 r
= this->x0
[nx0
][ix
][m
]-xc
[ix
][m
];
261 r
= this->x0
[nx0
][ix
][this->type
-1]-xc
[ix
][this->type
-1];
264 for(m
=0; (m
<DIM
); m
++) {
265 if (m
!= this->axis
) {
266 r
= this->x0
[nx0
][ix
][m
]-xc
[ix
][m
];
272 fatal_error(0,"Error: did not expect option value %d",this->type
);
281 /* this is the mean loop for the correlation type functions
282 * fx and nx are file pointers to things like read_first_x and
285 void corr_loop(t_corr
*this,char *fn
,int gnx
[],atom_id
*index
[],
286 t_calc_func
*calc1
,t_prep_data_func
*prep1
,
287 int nrestart
,real dt
,
288 t_first_x
*fx
,t_next_x
*nx
)
292 int i
,j
,status
,cur
=0,maxframes
=0;
296 this->natoms
=fx(&status
,fn
,&this->t0
,&(x
[prev
]),box
);
298 fprintf(stderr
,"Read %d atoms for first frame\n",this->natoms
);
301 snew(x
[cur
],this->natoms
);
303 init_restart(this,nrestart
,dt
);
304 memcpy(x
[cur
],x
[prev
],this->natoms
*sizeof(x
[prev
][0]));
307 if (this->nframes
>= maxframes
-1) {
309 for(i
=0; (i
<this->ngrp
); i
++) {
310 this->ndata
[i
] = NULL
;
311 this->data
[i
] = NULL
;
316 for(i
=0; (i
<this->ngrp
); i
++) {
317 srenew(this->ndata
[i
],maxframes
);
318 srenew(this->data
[i
],maxframes
);
319 for(j
=maxframes
-10; j
<maxframes
; j
++) {
324 srenew(this->time
,maxframes
);
327 this->time
[this->nframes
]=t
;
329 /* loop over all groups in index file */
330 for(i
=0; (i
<this->ngrp
); i
++) {
331 /* nice for putting things in boxes and such */
332 prep1(this,gnx
[i
],index
[i
],x
[cur
],x
[prev
],box
);
333 /* calculate something useful, like mean square displacements */
334 calc_corr(this,i
,gnx
[i
],index
[i
],x
[cur
],calc1
);
339 } while (nx(status
,&t
,this->natoms
,x
[cur
],box
));
340 fprintf(stderr
,"\n");
345 static void prep_data_mol(t_corr
*this,int gnx
,atom_id index
[],
346 rvec xcur
[],rvec xprev
[],matrix box
)
351 /* Remove periodicity */
352 for(m
=0; (m
<DIM
); m
++)
353 hbox
[m
]=0.5*box
[m
][m
];
354 for(i
=0; (i
<gnx
); i
++) {
356 for(j
=this->mols
->index
[ind
]; (j
<this->mols
->index
[ind
+1]); j
++) {
358 for(m
=0; (m
<DIM
); m
++) {
359 while(xcur
[k
][m
]-xprev
[k
][m
] <= hbox
[m
])
360 xcur
[k
][m
] += box
[m
][m
];
361 while(xcur
[k
][m
]-xprev
[k
][m
] > hbox
[m
])
362 xcur
[k
][m
] -= box
[m
][m
];
368 static real
calc_one_mw(t_corr
*this,int ix
,int nx0
,rvec xc
[],real
*tm
)
376 (*tm
)+=this->mass
[ix
];
378 switch (this->type
) {
380 for(m
=0; (m
<DIM
); m
++) {
381 r
= this->x0
[nx0
][ix
][m
]-xc
[ix
][m
];
382 r2
+= this->mass
[ix
]*r
*r
;
388 r
= this->x0
[nx0
][ix
][this->type
-1]-xc
[ix
][this->type
-1];
389 r2
= this->mass
[ix
]*r
*r
;
392 for(m
=0; (m
<DIM
); m
++) {
393 if (m
!= this->axis
) {
394 r
= this->x0
[nx0
][ix
][m
]-xc
[ix
][m
];
395 r2
+= this->mass
[ix
]*r
*r
;
400 fatal_error(0,"Options got screwed. Did not expect value %d\n",this->type
);
405 static real
calc1_mw(t_corr
*this,int nx
,atom_id index
[],int nx0
,rvec xc
[])
411 for(i
=0; (i
<nx
); i
++)
412 g
+=calc_one_mw(this,index
[i
],nx0
,xc
,&tm
);
419 static void prep_data_norm(t_corr
*this,int gnx
,atom_id index
[],
420 rvec xcur
[],rvec xprev
[],matrix box
)
425 /* Remove periodicity */
426 for(m
=0; (m
<DIM
); m
++)
427 hbox
[m
]=0.5*box
[m
][m
];
428 for(i
=0; (i
<gnx
); i
++) {
430 for(m
=0; (m
<DIM
); m
++) {
431 while(xcur
[ind
][m
]-xprev
[ind
][m
] <= hbox
[m
])
432 xcur
[ind
][m
] += box
[m
][m
];
433 while(xcur
[ind
][m
]-xprev
[ind
][m
] > hbox
[m
])
434 xcur
[ind
][m
] -= box
[m
][m
];
439 static real
calc1_mol(t_corr
*this,int nx
,atom_id index
[],int nx0
,rvec xc
[])
444 if (this->lsq
== NULL
) {
446 snew(this->lsq
,this->nrestart
);
447 for(i
=0; (i
<this->nrestart
); i
++)
448 snew(this->lsq
[i
],nx
);
450 tt
=this->time
[in_data(this,nx0
)];
452 for(i
=0; (i
<nx
); i
++) {
455 for(j
=this->mols
->index
[ii
]; (j
<this->mols
->index
[ii
+1]); j
++)
456 g
+= calc_one_mw(this,this->mols
->a
[j
],nx0
,xc
,&mm
);
460 add_lsq(&(this->lsq
[nx0
][i
]),tt
,g
);
465 void printdist(t_corr
*this,char *fn
,char *difn
)
470 real
*diff
,mind
=0,maxd
=0,dav
,a
,b
;
474 out
=xvgropen(difn
,"Diffusion Coefficients / Molecule","Molecule","D");
477 snew(diff
,this->nnx
);
478 for(i
=0; (i
<this->nnx
); i
++) {
480 for(j
=0; (j
<this->nrestart
); j
++) {
481 lsq1
.sx
+=this->lsq
[j
][i
].sx
;
482 lsq1
.sy
+=this->lsq
[j
][i
].sy
;
483 lsq1
.xx
+=this->lsq
[j
][i
].xx
;
484 lsq1
.yx
+=this->lsq
[j
][i
].yx
;
485 lsq1
.np
+=this->lsq
[j
][i
].np
;
487 get_lsq_ab(&lsq1
,&a
,&b
);
488 diff
[i
]=a
*FACTOR
/this->dim_factor
;
489 fprintf(out
,"%10d %10g\n",i
,diff
[i
]);
491 mind
=maxd
=dav
=diff
[i
];
494 mind
=min(mind
,diff
[i
]);
495 maxd
=max(maxd
,diff
[i
]);
501 xvgr_file(difn
,"-graphtype bar");
503 ndist
=(int *)calloc(NDIST
+1,sizeof(*ndist
));
504 for(i
=0; i
<NDIST
+1; i
++)
506 for(i
=0; (i
<this->nnx
); i
++) {
507 int index
=(int)(0.5+NDIST
*(diff
[i
]-mind
)/(maxd
-mind
));
508 if ((index
>= 0) && (index
<= NDIST
))
511 out
=xvgropen(fn
,"Distribution of Diffusion Constants","D ()","Number");
512 for(i
=0; (i
<=NDIST
); i
++)
513 fprintf(out
,"%10g %10d\n",
514 mind
+(i
*(maxd
-mind
))/NDIST
,ndist
[i
]);
520 void do_corr(int NFILE
, t_filenm fnm
[],int nrgrp
,
521 t_topology
*top
,bool bMol
,bool bMW
,
522 int type
,real dim_factor
,int axis
,
523 int nrestart
,real dt
)
535 gnx
= (int *)calloc(nrgrp
,sizeof(int));
536 index
= (atom_id
**)calloc(nrgrp
,sizeof(atom_id
*));
537 grpname
= (char **)calloc(nrgrp
,sizeof(char *));
539 get_index(&top
->atoms
,ftp2fn_null(efNDX
,NFILE
,fnm
),nrgrp
,gnx
,index
,grpname
);
541 msd
= init_corr(nrgrp
,type
,axis
,dim_factor
,bMW
,bMol
,top
);
543 corr_loop(msd
,ftp2fn(efTRX
,NFILE
,fnm
),gnx
,index
,
544 bMW
? calc1_mw
: (bMol
? calc1_mol
: calc1_norm
),
545 bMol
? prep_data_mol
: prep_data_norm
,nrestart
,dt
,
548 if (opt2bSet("-d",NFILE
,fnm
))
549 corr_print(msd
,opt2fn("-d",NFILE
,fnm
),"Diffusion constant",
550 "D (10\\S5\\Ncm\\S2\\Ns\\S-1\\N)",TRUE
,TRUE
);
551 corr_print(msd
,opt2fn("-o",NFILE
,fnm
),
552 "Mean Square Displacement",
553 "MSD (nm\\S2\\N)",TRUE
,FALSE
);
555 xvgr_file(ftp2fn(efXVG
,NFILE
,fnm
),"-nxy");
557 printdist(msd
,opt2fn("-m",NFILE
,fnm
),opt2fn("-d",NFILE
,fnm
));
560 int main(int argc
,char *argv
[])
562 static char *desc
[] = {
563 "g_msd computes the mean square displacement (MSD) of atoms from",
564 "their initial positions. This provides an easy way to compute",
565 "the diffusion constant using the Einstein relation.[PAR]",
566 "If the -d option is given, the diffusion constant will be printed in",
567 "addition to the MSD[PAR]",
568 "Mean Square Displacement calculations and Correlation functions",
569 "can be calculated more accurately, when using multiple starting",
570 "points (see also Gromacs Manual). You can select the number of",
571 "starting points, and the interval (in picoseconds) between starting",
572 "points. More starting points implies more CPU time."
574 static char *normtype
[]= { NULL
,"no","x","y","z",NULL
};
575 static char *axtitle
[] = { NULL
,"no","x","y","z",NULL
};
576 static int ngroup
= 1;
577 static int nrestart
= 1;
579 static bool bMW
= TRUE
;
581 { "-type", FALSE
, etENUM
, {normtype
},
582 "Compute diffusion coefficient in one direction" },
583 { "-lateral", FALSE
, etENUM
, {axtitle
},
584 "Calculate the lateral diffusion in a plane perpendicular to" },
585 { "-ngroup", FALSE
, etINT
, {&ngroup
},
586 "Number of groups to calculate MSD for" },
587 { "-mw", FALSE
, etBOOL
, {&bMW
},
588 "Mass weighted MSD" },
589 { "-nrestart",FALSE
, etINT
, {&nrestart
},
590 "Number of restarting points in trajectory" },
591 { "-dt", FALSE
, etREAL
, {&dt
},
592 "Time between restarting points in trajectory (only with -nrestart > 1)" }
594 static char *bugs
[] = {
595 "The diffusion constant given in the title of the graph for lateral"
596 " diffusion has to be multiplied by 6/4"
600 { efTRX
, NULL
, NULL
, ffREAD
},
601 { efTPS
, NULL
, NULL
, ffREAD
},
602 { efNDX
, NULL
, NULL
, ffOPTRD
},
603 { efXVG
, NULL
, "msd", ffWRITE
},
604 { efXVG
, "-m", "mol", ffOPTWR
},
605 { efXVG
, "-d", "diff",ffOPTWR
}
607 #define NFILE asize(fnm)
617 CopyRight(stdout
,argv
[0]);
619 parse_common_args(&argc
,argv
,PCA_CAN_VIEW
| PCA_CAN_TIME
,TRUE
,
620 NFILE
,fnm
,asize(pa
),pa
,asize(desc
),desc
,asize(bugs
),bugs
);
623 fatal_error(0,"Must have at least 1 group (now %d)",ngroup
);
625 bMol
= opt2bSet("-m",NFILE
,fnm
);
627 if (normtype
[0][0]!='n') {
628 type
= normtype
[0][0] - 'x'+1; /* See defines above */
635 if ((type
==NORMAL
) && (axtitle
[0][0]!='n')) {
638 axis
= (axtitle
[0][0] - 'x'); /* See defines above */
642 fprintf(stderr
,"type = %d, axis = %d, dim_factor = %g\n",
643 type
,axis
,dim_factor
);
644 bTop
=read_tps_conf(ftp2fn(efTPS
,NFILE
,fnm
),title
,&top
,&xdum
,NULL
,box
,bMW
);
646 fatal_error(0,"Could not read a topology form %s. Try a tpr file instead.",
647 ftp2fn(efTPS
,NFILE
,fnm
));
649 do_corr(NFILE
,fnm
,ngroup
,&top
,bMol
,bMW
,type
,dim_factor
,axis
,nrestart
,dt
);