4 * This source code is part of
8 * GROningen MAchine for Chemical Simulations
11 * Copyright (c) 1991-2001, University of Groningen, The Netherlands
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * If you want to redistribute modifications, please consider that
18 * scientific software is very special. Version control is crucial -
19 * bugs must be traceable. We will be happy to consider code for
20 * inclusion in the official distribution, but derived work must not
21 * be called official GROMACS. Details are found in the README & COPYING
22 * files - if they are missing, get the official version at www.gromacs.org.
24 * To help us fund GROMACS development, we humbly ask that you cite
25 * the papers on the package - you can find them in the top README file.
27 * For more info, check our website at http://www.gromacs.org
30 * Gromacs Runs One Microsecond At Cannonball Speeds
52 #define FACTOR 1000.0 /* Convert nm^2/ps to 10e-5 cm^2/s */
53 /* NORMAL = total diffusion coefficient (default). X,Y,Z is diffusion
54 coefficient in X,Y,Z direction. LATERAL is diffusion coefficient in
55 plane perpendicular to axis
57 enum { NOT_USED
, NORMAL
, X
, Y
, Z
, LATERAL
};
60 real t0
,delta_t
,dim_factor
;
61 real
**data
,*time
,*data_x
,*data_y
,*data_z
,*data_xy
,*mass
;
65 int type
,axis
,natoms
,nrestart
,nnx
,nframes
,nlast
,ngrp
;
70 typedef real
t_calc_func(t_corr
*,int,atom_id
[],int,rvec
[]);
71 typedef void t_prep_data_func(t_corr
*this,int gnx
,atom_id index
[],
72 rvec xcur
[],rvec xprev
[],matrix box
);
74 static real
thistime(t_corr
*this)
76 return this->time
[this->nframes
];
79 static bool in_data(t_corr
*this,int nx00
)
81 return this->nframes
-this->n_offs
[nx00
];
84 t_corr
*init_corr(int nrgrp
,int type
,int axis
,real dim_factor
,
85 bool bMass
,bool bMol
,real dt
,t_topology
*top
)
101 this->dim_factor
= dim_factor
;
103 snew(this->ndata
,nrgrp
);
104 snew(this->data
,nrgrp
);
105 for(i
=0; (i
<nrgrp
); i
++) {
106 this->ndata
[i
] = NULL
;
107 this->data
[i
] = NULL
;
113 snew(this->mass
,atoms
->nr
);
114 for(i
=0; (i
<atoms
->nr
); i
++) {
115 this->mass
[i
]=atoms
->atom
[i
].m
;
119 this->mols
= &(top
->blocks
[ebMOLS
]);
124 static void done_corr(t_corr
*this)
129 for(i
=0; (i
<this->nrestart
); i
++)
134 static void init_restart(t_corr
*this)
140 srenew(this->x0
,this->nrestart
);
141 snew(this->x0
[this->nrestart
-1],this->natoms
);
142 srenew(this->n_offs
,this->nrestart
);
145 static void corr_print(t_corr
*this,char *fn
,char *title
,char *yaxis
,
146 real beginfit
,real endfit
,
147 real
*DD
,real
*SigmaD
,char *grpname
[])
152 out
=xvgropen(fn
,title
,xvgr_tlabel(),yaxis
);
154 fprintf(out
,"# Diffusion constants fitted from time %g to %g (%s)\n",
155 beginfit
,endfit
,time_unit());
156 for(i
=0; i
<this->ngrp
; i
++)
157 fprintf(out
,"# D[%10s] = %.3f (+/- %.3f) (1e-5 cm^2/s)\n",
158 grpname
[i
],DD
[i
],SigmaD
[i
]);
160 for(i
=0; i
<this->nframes
; i
++) {
161 fprintf(out
,"%10g",convert_time(this->time
[i
]));
162 for(j
=0; j
<this->ngrp
; j
++)
163 fprintf(out
," %10g",this->data
[j
][i
]);
169 /* called from corr_loop, to do the main calculations */
170 static void calc_corr(t_corr
*this,int nr
,int nx
,atom_id index
[],rvec xc
[],
176 /* Check for new starting point */
177 if (this->nlast
< this->nrestart
) {
178 if ((thistime(this) >= (this->nlast
*this->delta_t
)) && (nr
==0)) {
179 memcpy(this->x0
[this->nlast
],xc
,this->natoms
*sizeof(xc
[0]));
180 this->n_offs
[this->nlast
]=this->nframes
;
185 /* nx0 appears to be the number of new starting points,
186 * so for all starting points, call calc1.
188 for(nx0
=0; (nx0
<this->nlast
); nx0
++) {
189 g
= calc1(this,nx
,index
,nx0
,xc
);
191 printf("g[%d]=%g\n",nx0
,g
);
193 this->data
[nr
][in_data(this,nx0
)]+=g
;
194 this->ndata
[nr
][in_data(this,nx0
)]++;
198 static real
calc1_norm(t_corr
*this,int nx
,atom_id index
[],int nx0
,rvec xc
[])
205 for(i
=0; (i
<nx
); i
++) {
208 switch (this->type
) {
210 for(m
=0; (m
<DIM
); m
++) {
211 r
= this->x0
[nx0
][ix
][m
]-xc
[ix
][m
];
218 r
= this->x0
[nx0
][ix
][this->type
-X
]-xc
[ix
][this->type
-X
];
221 for(m
=0; (m
<DIM
); m
++) {
222 if (m
!= this->axis
) {
223 r
= this->x0
[nx0
][ix
][m
]-xc
[ix
][m
];
229 fatal_error(0,"Error: did not expect option value %d",this->type
);
238 /* this is the mean loop for the correlation type functions
239 * fx and nx are file pointers to things like read_first_x and
242 void corr_loop(t_corr
*this,char *fn
,int gnx
[],atom_id
*index
[],
243 t_calc_func
*calc1
,t_prep_data_func
*prep1
,real dt
)
247 int i
,j
,status
,cur
=0,maxframes
=0;
251 this->natoms
=read_first_x(&status
,fn
,&this->t0
,&(x
[prev
]),box
);
253 fprintf(stderr
,"Read %d atoms for first frame\n",this->natoms
);
256 snew(x
[cur
],this->natoms
);
258 /* init_restart(this,nrestart,dt); */
259 memcpy(x
[cur
],x
[prev
],this->natoms
*sizeof(x
[prev
][0]));
262 if (bRmod(t
-this->t0
,dt
))
264 if (this->nframes
>= maxframes
-1) {
266 for(i
=0; (i
<this->ngrp
); i
++) {
267 this->ndata
[i
] = NULL
;
268 this->data
[i
] = NULL
;
273 for(i
=0; (i
<this->ngrp
); i
++) {
274 srenew(this->ndata
[i
],maxframes
);
275 srenew(this->data
[i
],maxframes
);
276 for(j
=maxframes
-10; j
<maxframes
; j
++) {
281 srenew(this->time
,maxframes
);
284 this->time
[this->nframes
] = t
- this->t0
;
286 /* loop over all groups in index file */
287 for(i
=0; (i
<this->ngrp
); i
++) {
288 /* nice for putting things in boxes and such */
289 prep1(this,gnx
[i
],index
[i
],x
[cur
],x
[prev
],box
);
290 /* calculate something useful, like mean square displacements */
291 calc_corr(this,i
,gnx
[i
],index
[i
],x
[cur
],calc1
);
296 } while (read_next_x(status
,&t
,this->natoms
,x
[cur
],box
));
297 fprintf(stderr
,"\nUsed %d restart points spaced %g %s over %g %s\n\n",
299 convert_time(dt
), time_unit(),
300 convert_time(this->time
[this->nframes
-1]), time_unit() );
305 static void prep_data_mol(t_corr
*this,int gnx
,atom_id index
[],
306 rvec xcur
[],rvec xprev
[],matrix box
)
311 /* Remove periodicity */
312 for(m
=0; (m
<DIM
); m
++)
313 hbox
[m
]=0.5*box
[m
][m
];
314 for(i
=0; i
<gnx
; i
++) {
316 for(j
=this->mols
->index
[ind
]; j
<this->mols
->index
[ind
+1]; j
++) {
318 for(m
=DIM
-1; m
>=0; m
--) {
319 while (xcur
[k
][m
]-xprev
[k
][m
] <= -hbox
[m
])
321 xcur
[k
][d
] += box
[m
][d
];
322 while (xcur
[k
][m
]-xprev
[k
][m
] > hbox
[m
])
324 xcur
[k
][d
] -= box
[m
][d
];
330 static real
calc_one_mw(t_corr
*this,int ix
,int nx0
,rvec xc
[],real
*tm
)
338 (*tm
)+=this->mass
[ix
];
340 switch (this->type
) {
342 for(m
=0; (m
<DIM
); m
++) {
343 r
= this->x0
[nx0
][ix
][m
]-xc
[ix
][m
];
344 r2
+= this->mass
[ix
]*r
*r
;
350 r
= this->x0
[nx0
][ix
][this->type
-X
]-xc
[ix
][this->type
-X
];
351 r2
= this->mass
[ix
]*r
*r
;
354 for(m
=0; (m
<DIM
); m
++) {
355 if (m
!= this->axis
) {
356 r
= this->x0
[nx0
][ix
][m
]-xc
[ix
][m
];
357 r2
+= this->mass
[ix
]*r
*r
;
362 fatal_error(0,"Options got screwed. Did not expect value %d\n",this->type
);
367 static real
calc1_mw(t_corr
*this,int nx
,atom_id index
[],int nx0
,rvec xc
[])
373 for(i
=0; (i
<nx
); i
++)
374 g
+=calc_one_mw(this,index
[i
],nx0
,xc
,&tm
);
381 static void prep_data_norm(t_corr
*this,int gnx
,atom_id index
[],
382 rvec xcur
[],rvec xprev
[],matrix box
)
387 /* Remove periodicity */
388 for(m
=0; (m
<DIM
); m
++)
389 hbox
[m
]=0.5*box
[m
][m
];
390 for(i
=0; (i
<gnx
); i
++) {
392 for(m
=DIM
-1; m
>=0; m
--) {
393 while(xcur
[ind
][m
]-xprev
[ind
][m
] <= hbox
[m
])
394 rvec_inc(xcur
[ind
],box
[m
]);
395 while(xcur
[ind
][m
]-xprev
[ind
][m
] > hbox
[m
])
396 rvec_dec(xcur
[ind
],box
[m
]);
401 static real
calc1_mol(t_corr
*this,int nx
,atom_id index
[],int nx0
,rvec xc
[])
406 if (this->lsq
== NULL
) {
408 snew(this->lsq
,this->nrestart
);
409 for(i
=0; (i
<this->nrestart
); i
++)
410 snew(this->lsq
[i
],nx
);
412 tt
=this->time
[in_data(this,nx0
)];
414 for(i
=0; (i
<nx
); i
++) {
417 for(j
=this->mols
->index
[ii
]; (j
<this->mols
->index
[ii
+1]); j
++)
418 g
+= calc_one_mw(this,this->mols
->a
[j
],nx0
,xc
,&mm
);
422 add_lsq(&(this->lsq
[nx0
][i
]),tt
,g
);
427 void printmol(t_corr
*this,char *fn
)
433 real a
,b
,*D
,Dav
,D2av
,VarD
;
435 out
=xvgropen(fn
,"Diffusion Coefficients / Molecule","Molecule","D");
439 for(i
=0; (i
<this->nnx
); i
++) {
441 for(j
=0; (j
<this->nrestart
); j
++) {
442 lsq1
.sx
+=this->lsq
[j
][i
].sx
;
443 lsq1
.sy
+=this->lsq
[j
][i
].sy
;
444 lsq1
.xx
+=this->lsq
[j
][i
].xx
;
445 lsq1
.yx
+=this->lsq
[j
][i
].yx
;
446 lsq1
.np
+=this->lsq
[j
][i
].np
;
448 get_lsq_ab(&lsq1
,&a
,&b
);
449 D
[i
] = a
*FACTOR
/this->dim_factor
;
452 fprintf(out
,"%10d %10g\n",i
,D
[i
]);
455 do_view(fn
,"-graphtype bar");
457 /* Compute variance, stddev and error */
460 VarD
= D2av
- sqr(Dav
);
461 printf("<D> = %.3f Std. Dev. = %.3f Error = %.3f\n",
462 Dav
,sqrt(VarD
),sqrt(VarD
/this->nnx
));
467 void do_corr(char *trx_file
, char *ndx_file
, char *msd_file
, char *mol_file
,
468 int nrgrp
, t_topology
*top
,bool bMW
,
469 int type
,real dim_factor
,int axis
,
470 real dt
,real beginfit
,real endfit
)
477 real
*DD
,*SigmaD
,a
,a2
,b
;
483 if (mol_file
&& !ndx_file
) {
484 gnx
[0] = top
->blocks
[ebMOLS
].nr
;
485 snew(index
[0],gnx
[0]);
486 grpname
[0] = "Molecules";
487 for(i
=0; (i
<gnx
[0]); i
++)
491 get_index(&top
->atoms
,ndx_file
,nrgrp
,gnx
,index
,grpname
);
493 msd
= init_corr(nrgrp
,type
,axis
,dim_factor
,bMW
,(mol_file
!=NULL
),dt
,top
);
495 corr_loop(msd
,trx_file
,gnx
,index
,
496 (mol_file
!=NULL
) ? calc1_mol
: (bMW
? calc1_mw
: calc1_norm
),
497 (mol_file
!=NULL
) ? prep_data_mol
: prep_data_norm
,dt
);
499 /* Correct for the number of points */
500 for(j
=0; (j
<msd
->ngrp
); j
++)
501 for(i
=0; (i
<msd
->nframes
); i
++)
502 msd
->data
[j
][i
] /= msd
->ndata
[j
][i
];
505 printmol(msd
,mol_file
);
509 for(i0
=0; i0
<msd
->nframes
&& msd
->time
[i0
]<beginfit
; i0
++)
513 endfit
= msd
->time
[i1
-1];
515 for(i1
=i0
; i1
<msd
->nframes
&& msd
->time
[i1
]<=endfit
; i1
++)
519 fprintf(stdout
,"Not enough points for fitting (%d).\n"
520 "Can not determine the diffusion constant.\n",N
);
523 snew(SigmaD
,msd
->ngrp
);
524 for(j
=0; j
<msd
->ngrp
; j
++) {
526 lsq_y_ax_b(N
/2,&(msd
->time
[i0
]),&(msd
->data
[j
][i0
]),&a
,&b
);
527 lsq_y_ax_b(N
/2,&(msd
->time
[i0
+N
/2]),&(msd
->data
[j
][i0
+N
/2]),&a2
,&b
);
528 SigmaD
[j
] = fabs(a
-a2
);
531 lsq_y_ax_b(N
,&(msd
->time
[i0
]),&(msd
->data
[j
][i0
]),&(DD
[j
]),&b
);
532 DD
[j
] *= FACTOR
/msd
->dim_factor
;
533 SigmaD
[j
] *= FACTOR
/msd
->dim_factor
;
534 fprintf(stdout
,"D[%10s] %.3f (+/- %.3f) 1e-5 cm^2/s\n",
535 grpname
[j
],DD
[j
],SigmaD
[j
]);
538 /* Print mean square displacement */
539 corr_print(msd
,msd_file
,
540 "Mean Square Displacement",
542 beginfit
,endfit
,DD
,SigmaD
,grpname
);
545 int main(int argc
,char *argv
[])
547 static char *desc
[] = {
548 "g_msd computes the mean square displacement (MSD) of atoms from",
549 "their initial positions. This provides an easy way to compute",
550 "the diffusion constant using the Einstein relation.",
551 "The diffusion constant is calculated by least squares fitting a",
552 "straight line through the MSD from [TT]-beginfit[tt] to",
553 "[TT]-endfit[tt]. An error estimate given, which is the difference",
554 "of the diffusion coefficients obtained from fits over the two halfs",
555 "of the fit interval.[PAR]",
556 "Option [TT]-mol[tt] plots the MSD for molecules, this implies",
557 "[TT]-mw[tt], i.e. for each inidividual molecule an diffusion constant",
558 "is computed. When using an index file, it should contain molecule",
559 "numbers instead of atom numbers.",
560 "Using this option one also gets an accurate error estimate",
561 "based on the statistics between individual molecules. Since one usually",
562 "is interested in self-diffusion at infinite dilution this is probably",
563 "the most useful number.[PAR]",
565 static char *normtype
[]= { NULL
,"no","x","y","z",NULL
};
566 static char *axtitle
[] = { NULL
,"no","x","y","z",NULL
};
567 static int ngroup
= 1;
569 static real beginfit
= 0;
570 static real endfit
= -1;
571 static bool bMW
= TRUE
;
573 { "-type", FALSE
, etENUM
, {normtype
},
574 "Compute diffusion coefficient in one direction" },
575 { "-lateral", FALSE
, etENUM
, {axtitle
},
576 "Calculate the lateral diffusion in a plane perpendicular to" },
577 { "-ngroup", FALSE
, etINT
, {&ngroup
},
578 "Number of groups to calculate MSD for" },
579 { "-mw", FALSE
, etBOOL
, {&bMW
},
580 "Mass weighted MSD" },
581 { "-trestart",FALSE
, etTIME
, {&dt
},
582 "Time between restarting points in trajectory (%t)" },
583 { "-beginfit",FALSE
, etTIME
, {&beginfit
},
584 "Start time for fitting the MSD (%t)" },
585 { "-endfit",FALSE
, etTIME
, {&endfit
},
586 "End time for fitting the MSD (%t), -1 is till end" }
590 { efTRX
, NULL
, NULL
, ffREAD
},
591 { efTPS
, NULL
, NULL
, ffREAD
},
592 { efNDX
, NULL
, NULL
, ffOPTRD
},
593 { efXVG
, NULL
, "msd", ffWRITE
},
594 { efXVG
, "-mol", "diff_mol",ffOPTWR
}
596 #define NFILE asize(fnm)
601 char *trx_file
, *tps_file
, *ndx_file
, *msd_file
, *mol_file
;
607 CopyRight(stderr
,argv
[0]);
609 parse_common_args(&argc
,argv
,PCA_CAN_VIEW
| PCA_CAN_TIME
| PCA_TIME_UNIT
| PCA_BE_NICE
,
610 NFILE
,fnm
,asize(pa
),pa
,asize(desc
),desc
,0,NULL
);
611 trx_file
= ftp2fn_null(efTRX
,NFILE
,fnm
);
612 tps_file
= ftp2fn_null(efTPS
,NFILE
,fnm
);
613 ndx_file
= ftp2fn_null(efNDX
,NFILE
,fnm
);
614 msd_file
= ftp2fn_null(efXVG
,NFILE
,fnm
);
615 mol_file
= opt2fn_null("-mol",NFILE
,fnm
);
618 fatal_error(0,"Must have at least 1 group (now %d)",ngroup
);
622 fprintf(stderr
,"Calculating diffusion coefficients for molecules.\n");
625 if (normtype
[0][0]!='n') {
626 type
= normtype
[0][0] - 'x' + X
; /* See defines above */
633 if ((type
==NORMAL
) && (axtitle
[0][0]!='n')) {
636 axis
= (axtitle
[0][0] - 'x'); /* See defines above */
640 bTop
=read_tps_conf(tps_file
,title
,&top
,&xdum
,NULL
,box
,bMW
);
641 if (mol_file
&& !bTop
)
642 fatal_error(0,"Could not read a topology from %s. Try a tpr file instead.",
645 do_corr(trx_file
,ndx_file
,msd_file
,mol_file
,ngroup
,
646 &top
,bMW
,type
,dim_factor
,axis
,dt
,beginfit
,endfit
);
648 view_all(NFILE
, fnm
);