4 * This source code is part of
8 * GROningen MAchine for Chemical Simulations
11 * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
12 * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
13 * Copyright (c) 2001-2004, The GROMACS development team,
14 * check out http://www.gromacs.org for more information.
16 * This program is free software; you can redistribute it and/or
17 * modify it under the terms of the GNU General Public License
18 * as published by the Free Software Foundation; either version 2
19 * of the License, or (at your option) any later version.
21 * If you want to redistribute modifications, please consider that
22 * scientific software is very special. Version control is crucial -
23 * bugs must be traceable. We will be happy to consider code for
24 * inclusion in the official distribution, but derived work must not
25 * be called official GROMACS. Details are found in the README & COPYING
26 * files - if they are missing, get the official version at www.gromacs.org.
28 * To help us fund GROMACS development, we humbly ask that you cite
29 * the papers on the package - you can find them in the top README file.
31 * For more info, check our website at http://www.gromacs.org
34 * Green Red Orange Magenta Azure Cyan Skyblue
59 #define FACTOR 1000.0 /* Convert nm^2/ps to 10e-5 cm^2/s */
60 /* NORMAL = total diffusion coefficient (default). X,Y,Z is diffusion
61 coefficient in X,Y,Z direction. LATERAL is diffusion coefficient in
62 plane perpendicular to axis
64 enum { NOT_USED
, NORMAL
, X
, Y
, Z
, LATERAL
};
67 real t0
,delta_t
,dim_factor
;
68 real
**data
,*time
,*data_x
,*data_y
,*data_z
,*data_xy
,*mass
;
72 int type
,axis
,natoms
,nrestart
,nnx
,nframes
,nlast
,ngrp
;
77 typedef real
t_calc_func(t_corr
*,int,atom_id
[],int,rvec
[]);
78 typedef void t_prep_data_func(t_corr
*this,int gnx
,atom_id index
[],
79 rvec xcur
[],rvec xprev
[],matrix box
);
81 static real
thistime(t_corr
*this)
83 return this->time
[this->nframes
];
86 static bool in_data(t_corr
*this,int nx00
)
88 return this->nframes
-this->n_offs
[nx00
];
91 t_corr
*init_corr(int nrgrp
,int type
,int axis
,real dim_factor
,
92 bool bMass
,bool bMol
,real dt
,t_topology
*top
)
108 this->dim_factor
= dim_factor
;
110 snew(this->ndata
,nrgrp
);
111 snew(this->data
,nrgrp
);
112 for(i
=0; (i
<nrgrp
); i
++) {
113 this->ndata
[i
] = NULL
;
114 this->data
[i
] = NULL
;
120 snew(this->mass
,atoms
->nr
);
121 for(i
=0; (i
<atoms
->nr
); i
++) {
122 this->mass
[i
]=atoms
->atom
[i
].m
;
126 this->mols
= &(top
->blocks
[ebMOLS
]);
131 static void done_corr(t_corr
*this)
136 for(i
=0; (i
<this->nrestart
); i
++)
141 static void init_restart(t_corr
*this)
147 srenew(this->x0
,this->nrestart
);
148 snew(this->x0
[this->nrestart
-1],this->natoms
);
149 srenew(this->n_offs
,this->nrestart
);
152 static void corr_print(t_corr
*this,char *fn
,char *title
,char *yaxis
,
153 real beginfit
,real endfit
,
154 real
*DD
,real
*SigmaD
,char *grpname
[])
159 out
=xvgropen(fn
,title
,xvgr_tlabel(),yaxis
);
161 fprintf(out
,"# Diffusion constants fitted from time %g to %g (%s)\n",
162 beginfit
,endfit
,time_unit());
163 for(i
=0; i
<this->ngrp
; i
++)
164 fprintf(out
,"# D[%10s] = %.3f (+/- %.3f) (1e-5 cm^2/s)\n",
165 grpname
[i
],DD
[i
],SigmaD
[i
]);
167 for(i
=0; i
<this->nframes
; i
++) {
168 fprintf(out
,"%10g",convert_time(this->time
[i
]));
169 for(j
=0; j
<this->ngrp
; j
++)
170 fprintf(out
," %10g",this->data
[j
][i
]);
176 /* called from corr_loop, to do the main calculations */
177 static void calc_corr(t_corr
*this,int nr
,int nx
,atom_id index
[],rvec xc
[],
183 /* Check for new starting point */
184 if (this->nlast
< this->nrestart
) {
185 if ((thistime(this) >= (this->nlast
*this->delta_t
)) && (nr
==0)) {
186 memcpy(this->x0
[this->nlast
],xc
,this->natoms
*sizeof(xc
[0]));
187 this->n_offs
[this->nlast
]=this->nframes
;
192 /* nx0 appears to be the number of new starting points,
193 * so for all starting points, call calc1.
195 for(nx0
=0; (nx0
<this->nlast
); nx0
++) {
196 g
= calc1(this,nx
,index
,nx0
,xc
);
198 printf("g[%d]=%g\n",nx0
,g
);
200 this->data
[nr
][in_data(this,nx0
)]+=g
;
201 this->ndata
[nr
][in_data(this,nx0
)]++;
205 static real
calc1_norm(t_corr
*this,int nx
,atom_id index
[],int nx0
,rvec xc
[])
212 for(i
=0; (i
<nx
); i
++) {
215 switch (this->type
) {
217 for(m
=0; (m
<DIM
); m
++) {
218 r
= this->x0
[nx0
][ix
][m
]-xc
[ix
][m
];
225 r
= this->x0
[nx0
][ix
][this->type
-X
]-xc
[ix
][this->type
-X
];
228 for(m
=0; (m
<DIM
); m
++) {
229 if (m
!= this->axis
) {
230 r
= this->x0
[nx0
][ix
][m
]-xc
[ix
][m
];
236 fatal_error(0,"Error: did not expect option value %d",this->type
);
245 /* this is the mean loop for the correlation type functions
246 * fx and nx are file pointers to things like read_first_x and
249 void corr_loop(t_corr
*this,char *fn
,int gnx
[],atom_id
*index
[],
250 t_calc_func
*calc1
,t_prep_data_func
*prep1
,real dt
)
254 int i
,j
,status
,cur
=0,maxframes
=0;
258 this->natoms
=read_first_x(&status
,fn
,&this->t0
,&(x
[prev
]),box
);
260 fprintf(stderr
,"Read %d atoms for first frame\n",this->natoms
);
263 snew(x
[cur
],this->natoms
);
265 /* init_restart(this,nrestart,dt); */
266 memcpy(x
[cur
],x
[prev
],this->natoms
*sizeof(x
[prev
][0]));
269 if (bRmod(t
,this->t0
,dt
))
271 if (this->nframes
>= maxframes
-1) {
273 for(i
=0; (i
<this->ngrp
); i
++) {
274 this->ndata
[i
] = NULL
;
275 this->data
[i
] = NULL
;
280 for(i
=0; (i
<this->ngrp
); i
++) {
281 srenew(this->ndata
[i
],maxframes
);
282 srenew(this->data
[i
],maxframes
);
283 for(j
=maxframes
-10; j
<maxframes
; j
++) {
288 srenew(this->time
,maxframes
);
291 this->time
[this->nframes
] = t
- this->t0
;
293 /* loop over all groups in index file */
294 for(i
=0; (i
<this->ngrp
); i
++) {
295 /* nice for putting things in boxes and such */
296 prep1(this,gnx
[i
],index
[i
],x
[cur
],x
[prev
],box
);
297 /* calculate something useful, like mean square displacements */
298 calc_corr(this,i
,gnx
[i
],index
[i
],x
[cur
],calc1
);
303 } while (read_next_x(status
,&t
,this->natoms
,x
[cur
],box
));
304 fprintf(stderr
,"\nUsed %d restart points spaced %g %s over %g %s\n\n",
306 convert_time(dt
), time_unit(),
307 convert_time(this->time
[this->nframes
-1]), time_unit() );
312 static void prep_data_mol(t_corr
*this,int gnx
,atom_id index
[],
313 rvec xcur
[],rvec xprev
[],matrix box
)
318 /* Remove periodicity */
319 for(m
=0; (m
<DIM
); m
++)
320 hbox
[m
]=0.5*box
[m
][m
];
321 for(i
=0; i
<gnx
; i
++) {
323 for(j
=this->mols
->index
[ind
]; j
<this->mols
->index
[ind
+1]; j
++) {
325 for(m
=DIM
-1; m
>=0; m
--) {
326 while (xcur
[k
][m
]-xprev
[k
][m
] <= -hbox
[m
])
328 xcur
[k
][d
] += box
[m
][d
];
329 while (xcur
[k
][m
]-xprev
[k
][m
] > hbox
[m
])
331 xcur
[k
][d
] -= box
[m
][d
];
337 static real
calc_one_mw(t_corr
*this,int ix
,int nx0
,rvec xc
[],real
*tm
)
345 (*tm
)+=this->mass
[ix
];
347 switch (this->type
) {
349 for(m
=0; (m
<DIM
); m
++) {
350 r
= this->x0
[nx0
][ix
][m
]-xc
[ix
][m
];
351 r2
+= this->mass
[ix
]*r
*r
;
357 r
= this->x0
[nx0
][ix
][this->type
-X
]-xc
[ix
][this->type
-X
];
358 r2
= this->mass
[ix
]*r
*r
;
361 for(m
=0; (m
<DIM
); m
++) {
362 if (m
!= this->axis
) {
363 r
= this->x0
[nx0
][ix
][m
]-xc
[ix
][m
];
364 r2
+= this->mass
[ix
]*r
*r
;
369 fatal_error(0,"Options got screwed. Did not expect value %d\n",this->type
);
374 static real
calc1_mw(t_corr
*this,int nx
,atom_id index
[],int nx0
,rvec xc
[])
380 for(i
=0; (i
<nx
); i
++)
381 g
+=calc_one_mw(this,index
[i
],nx0
,xc
,&tm
);
388 static void prep_data_norm(t_corr
*this,int gnx
,atom_id index
[],
389 rvec xcur
[],rvec xprev
[],matrix box
)
394 /* Remove periodicity */
395 for(m
=0; (m
<DIM
); m
++)
396 hbox
[m
]=0.5*box
[m
][m
];
397 for(i
=0; (i
<gnx
); i
++) {
399 for(m
=DIM
-1; m
>=0; m
--) {
400 while(xcur
[ind
][m
]-xprev
[ind
][m
] <= hbox
[m
])
401 rvec_inc(xcur
[ind
],box
[m
]);
402 while(xcur
[ind
][m
]-xprev
[ind
][m
] > hbox
[m
])
403 rvec_dec(xcur
[ind
],box
[m
]);
408 static real
calc1_mol(t_corr
*this,int nx
,atom_id index
[],int nx0
,rvec xc
[])
413 if (this->lsq
== NULL
) {
415 snew(this->lsq
,this->nrestart
);
416 for(i
=0; (i
<this->nrestart
); i
++)
417 snew(this->lsq
[i
],nx
);
419 tt
=this->time
[in_data(this,nx0
)];
421 for(i
=0; (i
<nx
); i
++) {
424 for(j
=this->mols
->index
[ii
]; (j
<this->mols
->index
[ii
+1]); j
++)
425 g
+= calc_one_mw(this,this->mols
->a
[j
],nx0
,xc
,&mm
);
429 add_lsq(&(this->lsq
[nx0
][i
]),tt
,g
);
434 void printmol(t_corr
*this,char *fn
)
440 real a
,b
,*D
,Dav
,D2av
,VarD
;
442 out
=xvgropen(fn
,"Diffusion Coefficients / Molecule","Molecule","D");
446 for(i
=0; (i
<this->nnx
); i
++) {
448 for(j
=0; (j
<this->nrestart
); j
++) {
449 lsq1
.sx
+=this->lsq
[j
][i
].sx
;
450 lsq1
.sy
+=this->lsq
[j
][i
].sy
;
451 lsq1
.xx
+=this->lsq
[j
][i
].xx
;
452 lsq1
.yx
+=this->lsq
[j
][i
].yx
;
453 lsq1
.np
+=this->lsq
[j
][i
].np
;
455 get_lsq_ab(&lsq1
,&a
,&b
);
456 D
[i
] = a
*FACTOR
/this->dim_factor
;
459 fprintf(out
,"%10d %10g\n",i
,D
[i
]);
462 do_view(fn
,"-graphtype bar");
464 /* Compute variance, stddev and error */
467 VarD
= D2av
- sqr(Dav
);
468 printf("<D> = %.3f Std. Dev. = %.3f Error = %.3f\n",
469 Dav
,sqrt(VarD
),sqrt(VarD
/this->nnx
));
474 void do_corr(char *trx_file
, char *ndx_file
, char *msd_file
, char *mol_file
,
475 int nrgrp
, t_topology
*top
,bool bMW
,
476 int type
,real dim_factor
,int axis
,
477 real dt
,real beginfit
,real endfit
)
484 real
*DD
,*SigmaD
,a
,a2
,b
;
490 if (mol_file
&& !ndx_file
) {
491 gnx
[0] = top
->blocks
[ebMOLS
].nr
;
492 snew(index
[0],gnx
[0]);
493 grpname
[0] = "Molecules";
494 for(i
=0; (i
<gnx
[0]); i
++)
498 get_index(&top
->atoms
,ndx_file
,nrgrp
,gnx
,index
,grpname
);
500 msd
= init_corr(nrgrp
,type
,axis
,dim_factor
,bMW
,(mol_file
!=NULL
),dt
,top
);
502 corr_loop(msd
,trx_file
,gnx
,index
,
503 (mol_file
!=NULL
) ? calc1_mol
: (bMW
? calc1_mw
: calc1_norm
),
504 (mol_file
!=NULL
) ? prep_data_mol
: prep_data_norm
,dt
);
506 /* Correct for the number of points */
507 for(j
=0; (j
<msd
->ngrp
); j
++)
508 for(i
=0; (i
<msd
->nframes
); i
++)
509 msd
->data
[j
][i
] /= msd
->ndata
[j
][i
];
512 printmol(msd
,mol_file
);
516 for(i0
=0; i0
<msd
->nframes
&& msd
->time
[i0
]<beginfit
; i0
++)
520 endfit
= msd
->time
[i1
-1];
522 for(i1
=i0
; i1
<msd
->nframes
&& msd
->time
[i1
]<=endfit
; i1
++)
526 fprintf(stdout
,"Not enough points for fitting (%d).\n"
527 "Can not determine the diffusion constant.\n",N
);
530 snew(SigmaD
,msd
->ngrp
);
531 for(j
=0; j
<msd
->ngrp
; j
++) {
533 lsq_y_ax_b(N
/2,&(msd
->time
[i0
]),&(msd
->data
[j
][i0
]),&a
,&b
);
534 lsq_y_ax_b(N
/2,&(msd
->time
[i0
+N
/2]),&(msd
->data
[j
][i0
+N
/2]),&a2
,&b
);
535 SigmaD
[j
] = fabs(a
-a2
);
538 lsq_y_ax_b(N
,&(msd
->time
[i0
]),&(msd
->data
[j
][i0
]),&(DD
[j
]),&b
);
539 DD
[j
] *= FACTOR
/msd
->dim_factor
;
540 SigmaD
[j
] *= FACTOR
/msd
->dim_factor
;
541 fprintf(stdout
,"D[%10s] %.3f (+/- %.3f) 1e-5 cm^2/s\n",
542 grpname
[j
],DD
[j
],SigmaD
[j
]);
545 /* Print mean square displacement */
546 corr_print(msd
,msd_file
,
547 "Mean Square Displacement",
549 beginfit
,endfit
,DD
,SigmaD
,grpname
);
552 int gmx_msd(int argc
,char *argv
[])
554 static char *desc
[] = {
555 "g_msd computes the mean square displacement (MSD) of atoms from",
556 "their initial positions. This provides an easy way to compute",
557 "the diffusion constant using the Einstein relation.",
558 "The diffusion constant is calculated by least squares fitting a",
559 "straight line through the MSD from [TT]-beginfit[tt] to",
560 "[TT]-endfit[tt]. An error estimate given, which is the difference",
561 "of the diffusion coefficients obtained from fits over the two halfs",
562 "of the fit interval.[PAR]",
563 "Option [TT]-mol[tt] plots the MSD for molecules, this implies",
564 "[TT]-mw[tt], i.e. for each inidividual molecule an diffusion constant",
565 "is computed. When using an index file, it should contain molecule",
566 "numbers instead of atom numbers.",
567 "Using this option one also gets an accurate error estimate",
568 "based on the statistics between individual molecules. Since one usually",
569 "is interested in self-diffusion at infinite dilution this is probably",
570 "the most useful number.[PAR]",
572 static char *normtype
[]= { NULL
,"no","x","y","z",NULL
};
573 static char *axtitle
[] = { NULL
,"no","x","y","z",NULL
};
574 static int ngroup
= 1;
576 static real beginfit
= 0;
577 static real endfit
= -1;
578 static bool bMW
= TRUE
;
580 { "-type", FALSE
, etENUM
, {normtype
},
581 "Compute diffusion coefficient in one direction" },
582 { "-lateral", FALSE
, etENUM
, {axtitle
},
583 "Calculate the lateral diffusion in a plane perpendicular to" },
584 { "-ngroup", FALSE
, etINT
, {&ngroup
},
585 "Number of groups to calculate MSD for" },
586 { "-mw", FALSE
, etBOOL
, {&bMW
},
587 "Mass weighted MSD" },
588 { "-trestart",FALSE
, etTIME
, {&dt
},
589 "Time between restarting points in trajectory (%t)" },
590 { "-beginfit",FALSE
, etTIME
, {&beginfit
},
591 "Start time for fitting the MSD (%t)" },
592 { "-endfit",FALSE
, etTIME
, {&endfit
},
593 "End time for fitting the MSD (%t), -1 is till end" }
597 { efTRX
, NULL
, NULL
, ffREAD
},
598 { efTPS
, NULL
, NULL
, ffREAD
},
599 { efNDX
, NULL
, NULL
, ffOPTRD
},
600 { efXVG
, NULL
, "msd", ffWRITE
},
601 { efXVG
, "-mol", "diff_mol",ffOPTWR
}
603 #define NFILE asize(fnm)
608 char *trx_file
, *tps_file
, *ndx_file
, *msd_file
, *mol_file
;
614 CopyRight(stderr
,argv
[0]);
616 parse_common_args(&argc
,argv
,PCA_CAN_VIEW
| PCA_CAN_TIME
| PCA_TIME_UNIT
| PCA_BE_NICE
,
617 NFILE
,fnm
,asize(pa
),pa
,asize(desc
),desc
,0,NULL
);
618 trx_file
= ftp2fn_null(efTRX
,NFILE
,fnm
);
619 tps_file
= ftp2fn_null(efTPS
,NFILE
,fnm
);
620 ndx_file
= ftp2fn_null(efNDX
,NFILE
,fnm
);
621 msd_file
= ftp2fn_null(efXVG
,NFILE
,fnm
);
622 mol_file
= opt2fn_null("-mol",NFILE
,fnm
);
625 fatal_error(0,"Must have at least 1 group (now %d)",ngroup
);
629 fprintf(stderr
,"Calculating diffusion coefficients for molecules.\n");
632 if (normtype
[0][0]!='n') {
633 type
= normtype
[0][0] - 'x' + X
; /* See defines above */
640 if ((type
==NORMAL
) && (axtitle
[0][0]!='n')) {
643 axis
= (axtitle
[0][0] - 'x'); /* See defines above */
647 bTop
=read_tps_conf(tps_file
,title
,&top
,&xdum
,NULL
,box
,bMW
);
648 if (mol_file
&& !bTop
)
649 fatal_error(0,"Could not read a topology from %s. Try a tpr file instead.",
652 do_corr(trx_file
,ndx_file
,msd_file
,mol_file
,ngroup
,
653 &top
,bMW
,type
,dim_factor
,axis
,dt
,beginfit
,endfit
);
655 view_all(NFILE
, fnm
);